53633 lines
1.5 MiB
53633 lines
1.5 MiB
From: Isaac Hermida <isaac.hermida@digi.com>
|
|
Date: Tue, 1 Apr 2025 11:13:34 +0200
|
|
Subject: [PATCH] add RT support based on latest linux_6.6.36
|
|
|
|
Add a unique patch with the RT functionality between NXP lf-6.6.36-2.1.0
|
|
and realtime/linux_6.6.36 in https://github.com/nxp-real-time-edge-sw/real-time-edge-linux.git
|
|
|
|
https://onedigi.atlassian.net/browse/DEL-9324
|
|
|
|
Signed-off-by: Isaac Hermida <isaac.hermida@digi.com>
|
|
---
|
|
.../mailbox/generic-software-mbox.yaml | 65 +
|
|
.../devicetree/bindings/net/fsl,fec.yaml | 24 +
|
|
.../devicetree/bindings/tty/rpmsg_tty.yaml | 67 +
|
|
Documentation/printk-ringbuffer.txt | 377 ++
|
|
arch/arm/Kconfig | 6 +-
|
|
arch/arm/boot/dts/nxp/imx/Makefile | 9 +
|
|
.../dts/nxp/imx/imx6ul-14x14-evk-ecat.dts | 11 +
|
|
.../boot/dts/nxp/imx/imx6ul-14x14-evk-igh.dts | 11 +
|
|
.../dts/nxp/imx/imx6ull-14x14-evk-avb-mcr.dts | 59 +
|
|
.../dts/nxp/imx/imx6ull-14x14-evk-avb.dts | 29 +
|
|
.../dts/nxp/imx/imx6ull-14x14-evk-ecat.dts | 11 +
|
|
.../dts/nxp/imx/imx6ull-14x14-evk-igh.dts | 11 +
|
|
.../dts/nxp/imx/imx6ull-14x14-evk-lpuart.dts | 25 +
|
|
.../dts/nxp/imx/imx6ull-14x14-evk-reve.dtso | 11 +
|
|
arch/arm/boot/dts/nxp/ls/Makefile | 3 +-
|
|
arch/arm/boot/dts/nxp/ls/ls1021a-iot-bm.dts | 259 ++
|
|
arch/arm/boot/dts/nxp/ls/ls1021a.dtsi | 4 +-
|
|
arch/arm/configs/imx6ullevk-plc.config | 3333 +++++++++++++++++
|
|
arch/arm/configs/imx_avb.config | 8 +
|
|
arch/arm/configs/imx_up.config | 2 +
|
|
arch/arm/configs/imx_v6_v7_defconfig | 3 +-
|
|
arch/arm/configs/imx_v7_defconfig | 9 +-
|
|
arch/arm/configs/lsdk.config | 20 +
|
|
arch/arm/configs/multi_v7_defconfig | 2 +
|
|
arch/arm/kernel/smp.c | 22 +
|
|
arch/arm/mach-imx/Kconfig | 10 +
|
|
arch/arm/mm/fault.c | 6 +
|
|
arch/arm/vfp/vfpmodule.c | 74 +-
|
|
arch/arm64/Kconfig | 1 +
|
|
arch/arm64/Kconfig.platforms | 30 +
|
|
arch/arm64/boot/dts/freescale/Makefile | 104 +-
|
|
.../boot/dts/freescale/fii-ls1028a-tsn.dts | 325 ++
|
|
.../fsl-ls1028a-rdb-dsa-swp5-eno3.dts | 37 +
|
|
...sl-ls1028a-rdb-jailhouse-without-enetc.dts | 98 +
|
|
.../freescale/fsl-ls1028a-rdb-jailhouse.dts | 59 +
|
|
.../dts/freescale/fsl-ls1028a-rdb-sdk-bm.dts | 15 +
|
|
.../boot/dts/freescale/fsl-ls1028a-rdb.dts | 25 +
|
|
.../arm64/boot/dts/freescale/fsl-ls1028a.dtsi | 2 +-
|
|
.../dts/freescale/fsl-ls1043a-rdb-sdk-bm.dts | 44 +
|
|
...sl-ls1043a-rdb-sdk-jailhouse-with-dpaa.dts | 263 ++
|
|
.../fsl-ls1043a-rdb-sdk-jailhouse.dts | 267 ++
|
|
.../arm64/boot/dts/freescale/fsl-ls1043a.dtsi | 2 +-
|
|
.../dts/freescale/fsl-ls1046a-rdb-sdk-bm.dts | 47 +
|
|
...sl-ls1046a-rdb-sdk-jailhouse-with-dpaa.dts | 274 ++
|
|
.../fsl-ls1046a-rdb-sdk-jailhouse.dts | 278 ++
|
|
.../arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 2 +-
|
|
.../boot/dts/freescale/imx8-ss-audio.dtsi | 20 +
|
|
.../dts/freescale/imx8dxl-evk-enet0-avb.dts | 9 +
|
|
.../dts/freescale/imx8dxl-evk-enet0-avb.dtsi | 54 +
|
|
.../freescale/imx8dxl-evk-enet0-sja1105.dts | 168 +
|
|
.../imx8dxl-evk-enet0-tja1100-avb.dts | 9 +
|
|
arch/arm64/boot/dts/freescale/imx8dxl-evk.dts | 58 +
|
|
.../boot/dts/freescale/imx8dxl-ss-adma.dtsi | 1 +
|
|
.../dts/freescale/imx8m-generic-mbox-1.dtsi | 27 +
|
|
.../dts/freescale/imx8m-generic-mbox.dtsi | 27 +
|
|
.../dts/freescale/imx8m-rpmsg-ca53-1.dtsi | 37 +
|
|
.../boot/dts/freescale/imx8m-rpmsg-ca53.dtsi | 37 +
|
|
.../boot/dts/freescale/imx8m-rproc-ca53.dtsi | 34 +
|
|
.../boot/dts/freescale/imx8mm-evk-avb.dts | 37 +
|
|
.../dts/freescale/imx8mm-evk-baremetal.dts | 39 +
|
|
.../freescale/imx8mm-evk-ecat-userspace.dts | 15 +
|
|
.../boot/dts/freescale/imx8mm-evk-ecat.dts | 10 +
|
|
.../dts/freescale/imx8mm-evk-harpoon-avb.dts | 11 +
|
|
.../imx8mm-evk-harpoon-industrial.dts | 11 +
|
|
.../imx8mm-evk-harpoon-virtio-net.dts | 11 +
|
|
.../boot/dts/freescale/imx8mm-evk-harpoon.dts | 31 +
|
|
.../boot/dts/freescale/imx8mm-evk-igh.dts | 10 +
|
|
.../freescale/imx8mm-evk-multicore-rpmsg.dts | 80 +
|
|
.../freescale/imx8mm-evk-multicore-rtos.dts | 78 +
|
|
.../imx8mm-evk-qca-wifi-harpoon-avb.dts | 7 +
|
|
...imx8mm-evk-qca-wifi-harpoon-industrial.dts | 7 +
|
|
...imx8mm-evk-qca-wifi-harpoon-virtio-net.dts | 7 +
|
|
.../freescale/imx8mm-evk-qca-wifi-harpoon.dts | 7 +
|
|
.../dts/freescale/imx8mm-evk-qca-wifi.dts | 123 +-
|
|
.../dts/freescale/imx8mm-evk-qca-wifi.dtsi | 124 +
|
|
.../dts/freescale/imx8mm-evk-rpmsg-8m-buf.dts | 228 ++
|
|
.../dts/freescale/imx8mm-evk-rpmsg-ca53.dts | 40 +
|
|
.../boot/dts/freescale/imx8mm-evk-rpmsg.dts | 96 +-
|
|
.../freescale/imx8mm-evk-virtio-net-ca53.dts | 83 +
|
|
.../freescale/imx8mm-evk-virtio-net-cm4.dts | 74 +
|
|
.../freescale/imx8mm-evk-virtio-perf-ca53.dts | 79 +
|
|
.../freescale/imx8mm-evk-virtio-perf-cm4.dts | 63 +
|
|
.../dts/freescale/imx8mm-virtio-ca53.dtsi | 46 +
|
|
arch/arm64/boot/dts/freescale/imx8mm.dtsi | 11 +
|
|
.../dts/freescale/imx8mn-evk-harpoon-avb.dts | 11 +
|
|
.../imx8mn-evk-harpoon-industrial.dts | 11 +
|
|
.../boot/dts/freescale/imx8mn-evk-harpoon.dts | 31 +
|
|
.../boot/dts/freescale/imx8mp-evk-avb.dts | 42 +
|
|
.../dts/freescale/imx8mp-evk-baremetal.dts | 37 +
|
|
.../dts/freescale/imx8mp-evk-dsa-enetc.dts | 17 +
|
|
.../dts/freescale/imx8mp-evk-dsa-fec-swp0.dts | 92 +
|
|
.../dts/freescale/imx8mp-evk-dsa-fec-swp3.dts | 92 +
|
|
.../boot/dts/freescale/imx8mp-evk-dsa.dts | 92 +
|
|
.../freescale/imx8mp-evk-ecat-userspace.dts | 33 +
|
|
.../boot/dts/freescale/imx8mp-evk-ecat.dts | 10 +
|
|
.../dts/freescale/imx8mp-evk-harpoon-avb.dts | 11 +
|
|
.../imx8mp-evk-harpoon-industrial.dts | 15 +
|
|
.../imx8mp-evk-harpoon-virtio-net.dts | 40 +
|
|
.../boot/dts/freescale/imx8mp-evk-harpoon.dts | 35 +
|
|
.../boot/dts/freescale/imx8mp-evk-igh.dts | 10 +
|
|
.../freescale/imx8mp-evk-multicore-lwip.dts | 21 +
|
|
.../freescale/imx8mp-evk-multicore-rpmsg.dts | 179 +
|
|
.../freescale/imx8mp-evk-multicore-rtos.dts | 80 +
|
|
.../dts/freescale/imx8mp-evk-rpmsg-ca53.dts | 45 +
|
|
.../freescale/imx8mp-evk-virtio-net-ca53.dts | 82 +
|
|
.../freescale/imx8mp-evk-virtio-net-cm7.dts | 85 +
|
|
.../freescale/imx8mp-evk-virtio-perf-ca53.dts | 69 +
|
|
.../freescale/imx8mp-evk-virtio-perf-cm7.dts | 69 +
|
|
.../dts/freescale/imx8mp-generic-mbox-1.dtsi | 27 +
|
|
.../dts/freescale/imx8mp-generic-mbox.dtsi | 27 +
|
|
.../dts/freescale/imx8mp-rpmsg-ca53-1.dtsi | 37 +
|
|
.../boot/dts/freescale/imx8mp-rpmsg-ca53.dtsi | 37 +
|
|
.../dts/freescale/imx93-11x11-evk-avb.dts | 9 +
|
|
.../freescale/imx93-11x11-evk-baremetal.dts | 31 +
|
|
.../dts/freescale/imx93-11x11-evk-dpdk.dts | 16 +
|
|
.../freescale/imx93-11x11-evk-dsa-enetc.dts | 17 +
|
|
.../imx93-11x11-evk-dsa-fec-swp0.dts | 108 +
|
|
.../imx93-11x11-evk-dsa-fec-swp3.dts | 108 +
|
|
.../dts/freescale/imx93-11x11-evk-dsa.dts | 108 +
|
|
.../imx93-11x11-evk-ecat-userspace.dts | 16 +
|
|
.../dts/freescale/imx93-11x11-evk-ecat.dts | 11 +
|
|
.../freescale/imx93-11x11-evk-harpoon-avb.dts | 10 +
|
|
.../imx93-11x11-evk-harpoon-industrial.dts | 19 +
|
|
.../imx93-11x11-evk-harpoon-virtio-net.dts | 46 +
|
|
.../dts/freescale/imx93-11x11-evk-harpoon.dts | 35 +
|
|
.../dts/freescale/imx93-11x11-evk-igh.dts | 11 +
|
|
.../imx93-11x11-evk-multicore-rpmsg.dts | 47 +
|
|
.../imx93-11x11-evk-multicore-rtos.dts | 39 +
|
|
.../imx93-11x11-evk-uart-sharing-cm33.dts | 96 +
|
|
.../imx93-11x11-evk-virtio-net-ca55.dts | 56 +
|
|
.../imx93-11x11-evk-virtio-net-cm33.dts | 58 +
|
|
.../boot/dts/freescale/imx93-11x11-evk.dts | 60 +-
|
|
.../freescale/imx93-14x14-evk-aud-hat-avb.dts | 9 +
|
|
.../dts/freescale/imx93-14x14-evk-aud-hat.dts | 2 +-
|
|
.../imx93-14x14-evk-imxai2eth-ath.dts | 126 +
|
|
.../dts/freescale/imx93-14x14-evk-mqs.dts | 70 +-
|
|
.../dts/freescale/imx93-14x14-evk-mqs.dtsi | 71 +
|
|
.../imx93-14x14-evk-multicore-rpmsg.dts | 47 +
|
|
.../imx93-14x14-evk-multicore-rtos.dts | 39 +
|
|
.../freescale/imx93-14x14-evk-sja1105-avb.dts | 8 +
|
|
.../dts/freescale/imx93-14x14-evk-sja1105.dts | 3 +-
|
|
.../dts/freescale/imx93-14x14-evk-tja1103.dts | 63 +-
|
|
.../imx93-14x14-evk-uart-sharing-cm33.dts | 96 +
|
|
.../imx93-14x14-evk-virtio-net-ca55.dts | 56 +
|
|
.../imx93-14x14-evk-virtio-net-cm33.dts | 58 +
|
|
.../dts/freescale/imx93-9x9-qsb-baremetal.dts | 31 +
|
|
.../dts/freescale/imx93-9x9-qsb-inmate.dts | 151 +
|
|
.../boot/dts/freescale/imx93-9x9-qsb-root.dts | 54 +
|
|
.../imx93-9x9-qsb-uart-sharing-cm33.dts | 96 +
|
|
.../boot/dts/freescale/imx93-9x9-qsb.dts | 58 +
|
|
.../boot/dts/freescale/imx93-evk-avb.dtsi | 37 +
|
|
.../dts/freescale/imx93-generic-mbox.dtsi | 27 +
|
|
.../boot/dts/freescale/imx93-rpmsg-ca55.dtsi | 37 +
|
|
.../boot/dts/freescale/imx93-rproc-ca55.dtsi | 14 +
|
|
.../imx95-15x15-evk-harpoon-industrial.dts | 25 +
|
|
.../dts/freescale/imx95-15x15-evk-harpoon.dts | 19 +
|
|
.../imx95-15x15-evk-multicore-rtos.dts | 29 +
|
|
.../imx95-19x19-evk-harpoon-industrial.dts | 29 +
|
|
.../dts/freescale/imx95-19x19-evk-harpoon.dts | 19 +
|
|
.../imx95-19x19-evk-multicore-rtos.dts | 29 +
|
|
.../dts/freescale/imx95-generic-mbox.dtsi | 27 +
|
|
.../boot/dts/freescale/imx95-rpmsg-ca55.dtsi | 37 +
|
|
.../boot/dts/freescale/imx95-rproc-ca55.dtsi | 48 +
|
|
arch/arm64/configs/imx_avb.config | 8 +
|
|
arch/arm64/configs/imx_v8_defconfig | 30 +-
|
|
arch/arm64/configs/linux-dpaa-ethercat.config | 1 +
|
|
arch/arm64/configs/linux-rpmsg-8m-buf.config | 1 +
|
|
arch/arm64/configs/lsdk.config | 25 +-
|
|
arch/arm64/kernel/smp.c | 25 +
|
|
arch/powerpc/Kconfig | 2 +
|
|
arch/powerpc/include/asm/stackprotector.h | 7 +-
|
|
arch/powerpc/kernel/traps.c | 7 +-
|
|
arch/powerpc/kvm/Kconfig | 1 +
|
|
arch/powerpc/platforms/pseries/Kconfig | 1 +
|
|
arch/powerpc/platforms/pseries/iommu.c | 31 +-
|
|
arch/riscv/Kconfig | 2 +
|
|
arch/riscv/include/asm/cpufeature.h | 2 -
|
|
arch/riscv/include/asm/thread_info.h | 2 +
|
|
arch/riscv/kernel/cpufeature.c | 90 +-
|
|
arch/riscv/kernel/smpboot.c | 1 -
|
|
arch/x86/Kconfig | 2 +
|
|
arch/x86/include/asm/thread_info.h | 6 +-
|
|
drivers/acpi/processor_idle.c | 2 +-
|
|
drivers/base/Kconfig | 2 +-
|
|
drivers/block/zram/zram_drv.c | 37 +
|
|
drivers/block/zram/zram_drv.h | 3 +
|
|
drivers/clk/imx/Makefile | 1 +
|
|
drivers/clk/imx/clk-frac-pll.c | 130 +
|
|
drivers/clk/imx/clk-fracn-gppll.c | 209 +-
|
|
drivers/clk/imx/clk-imx8-acm.c | 46 +
|
|
drivers/clk/imx/clk-imx8mq.c | 2 +-
|
|
drivers/clk/imx/clk-pll.c | 83 +
|
|
drivers/clk/imx/clk-pll.h | 33 +
|
|
drivers/clk/imx/clk-pll14xx.c | 120 +
|
|
drivers/clk/imx/clk-pllv3.c | 109 +
|
|
drivers/clk/imx/clk-scu.c | 86 +
|
|
.../gpu/drm/amd/display/amdgpu_dm/dc_fpu.c | 53 +-
|
|
.../drm/amd/display/dc/dcn20/dcn20_resource.c | 10 +-
|
|
.../drm/amd/display/dc/dcn21/dcn21_resource.c | 10 +-
|
|
.../drm/amd/display/dc/dml/dcn20/dcn20_fpu.c | 23 +-
|
|
.../drm/amd/display/dc/dml/dcn20/dcn20_fpu.h | 10 +-
|
|
drivers/gpu/drm/i915/Kconfig | 1 -
|
|
drivers/gpu/drm/i915/display/intel_crtc.c | 15 +-
|
|
drivers/gpu/drm/i915/display/intel_vblank.c | 6 +-
|
|
drivers/gpu/drm/i915/gt/intel_breadcrumbs.c | 7 +-
|
|
.../drm/i915/gt/intel_execlists_submission.c | 17 +-
|
|
drivers/gpu/drm/i915/gt/intel_reset.c | 12 +-
|
|
drivers/gpu/drm/i915/gt/uc/intel_guc.h | 2 +-
|
|
drivers/gpu/drm/i915/i915_request.c | 2 -
|
|
drivers/gpu/drm/i915/i915_trace.h | 6 +-
|
|
drivers/gpu/drm/i915/i915_utils.h | 2 +-
|
|
drivers/irqchip/Kconfig | 4 +
|
|
drivers/irqchip/Makefile | 1 +
|
|
drivers/irqchip/ipi-baremetal.c | 454 +++
|
|
drivers/irqchip/irq-gic-v3.c | 10 +-
|
|
drivers/irqchip/irq-gic.c | 4 +-
|
|
drivers/mailbox/Kconfig | 9 +
|
|
drivers/mailbox/Makefile | 2 +
|
|
drivers/mailbox/generic-software-mailbox.c | 322 ++
|
|
drivers/mailbox/mailbox.c | 2 +-
|
|
drivers/mxc/ipu3/ipu_common.c | 10 +-
|
|
drivers/mxc/ipu3/ipu_device.c | 2 +-
|
|
drivers/net/dsa/Kconfig | 2 +
|
|
drivers/net/dsa/Makefile | 1 +
|
|
drivers/net/dsa/netc/Kconfig | 18 +
|
|
drivers/net/dsa/netc/Makefile | 14 +
|
|
drivers/net/dsa/netc/netc.h | 131 +
|
|
drivers/net/dsa/netc/netc_config.c | 696 ++++
|
|
drivers/net/dsa/netc/netc_config.h | 557 +++
|
|
drivers/net/dsa/netc/netc_devlink.c | 107 +
|
|
drivers/net/dsa/netc/netc_ethtool.c | 344 ++
|
|
drivers/net/dsa/netc/netc_main.c | 1439 +++++++
|
|
drivers/net/dsa/netc/netc_ptp.c | 375 ++
|
|
drivers/net/dsa/netc/netc_ptp.h | 77 +
|
|
drivers/net/dsa/netc/netc_spi.c | 147 +
|
|
drivers/net/dsa/ocelot/felix.c | 183 +-
|
|
drivers/net/dsa/ocelot/felix.h | 5 +
|
|
drivers/net/dsa/ocelot/felix_tsn.c | 6 +-
|
|
drivers/net/dsa/ocelot/felix_vsc9959.c | 99 +-
|
|
drivers/net/dsa/sja1105/sja1105.h | 5 +
|
|
drivers/net/dsa/sja1105/sja1105_clocking.c | 21 +-
|
|
drivers/net/dsa/sja1105/sja1105_main.c | 68 +-
|
|
drivers/net/dsa/sja1105/sja1105_tas.c | 4 +
|
|
drivers/net/ethernet/freescale/Kconfig | 20 +
|
|
drivers/net/ethernet/freescale/Makefile | 2 +
|
|
drivers/net/ethernet/freescale/enetc/enetc.c | 6 +-
|
|
drivers/net/ethernet/freescale/enetc/enetc.h | 8 +
|
|
.../ethernet/freescale/enetc/enetc_ethtool.c | 153 +
|
|
.../net/ethernet/freescale/enetc/enetc_pf.c | 1 +
|
|
.../net/ethernet/freescale/enetc/enetc_ptp.c | 15 +-
|
|
.../net/ethernet/freescale/enetc/enetc_qos.c | 5 +-
|
|
.../net/ethernet/freescale/enetc/enetc_tsn.c | 179 +-
|
|
drivers/net/ethernet/freescale/fec.h | 100 +-
|
|
drivers/net/ethernet/freescale/fec_ecat.c | 3063 +++++++++++++++
|
|
drivers/net/ethernet/freescale/fec_ecat.h | 718 ++++
|
|
drivers/net/ethernet/freescale/fec_main.c | 1452 ++++++-
|
|
drivers/net/ethernet/freescale/fec_ptp.c | 445 ++-
|
|
drivers/net/ethernet/freescale/fec_uio.c | 4 +-
|
|
.../net/ethernet/freescale/gianfar_ethtool.c | 29 +
|
|
.../net/ethernet/freescale/sdk_dpaa/Kconfig | 11 +-
|
|
.../net/ethernet/freescale/sdk_dpaa/Makefile | 3 +
|
|
.../ethernet/freescale/sdk_dpaa/dpaa_eth.h | 13 +-
|
|
.../freescale/sdk_dpaa/dpaa_eth_common.c | 56 +
|
|
.../ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c | 28 +-
|
|
.../freescale/sdk_dpaa/dpaa_ethercat.c | 1216 ++++++
|
|
drivers/net/ethernet/mscc/ocelot.c | 45 +-
|
|
drivers/net/ethernet/mscc/ocelot_flower.c | 30 +-
|
|
drivers/net/ethernet/mscc/ocelot_ptp.c | 125 +-
|
|
drivers/net/ethernet/mscc/ocelot_vcap.c | 173 +-
|
|
.../net/ethernet/stmicro/stmmac/dwmac4_core.c | 2 +
|
|
drivers/net/ethernet/stmicro/stmmac/dwmac5.c | 19 +-
|
|
drivers/net/ethernet/stmicro/stmmac/dwmac5.h | 6 +-
|
|
.../ethernet/stmicro/stmmac/dwxgmac2_core.c | 3 +-
|
|
drivers/net/ethernet/stmicro/stmmac/hwif.h | 11 +-
|
|
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 1 +
|
|
.../ethernet/stmicro/stmmac/stmmac_ethtool.c | 106 +
|
|
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 36 +-
|
|
.../net/ethernet/stmicro/stmmac/stmmac_tc.c | 38 +-
|
|
drivers/net/phy/phy.c | 5 +-
|
|
drivers/nfc/Kconfig | 1 +
|
|
drivers/nfc/Makefile | 1 +
|
|
drivers/nfc/pn5xx/Kconfig | 12 +
|
|
drivers/nfc/pn5xx/Makefile | 6 +
|
|
drivers/nfc/pn5xx/README.md | 2 +
|
|
drivers/nfc/pn5xx/pn5xx_i2c.c | 669 ++++
|
|
drivers/nfc/pn5xx/pn5xx_i2c.h | 38 +
|
|
drivers/nfc/pn5xx/sample_devicetree.txt | 17 +
|
|
drivers/pmdomain/imx/scu-pd.c | 1 +
|
|
drivers/ptp/ptp_chardev.c | 23 +
|
|
drivers/ptp/ptp_clock.c | 19 +
|
|
drivers/ptp/ptp_private.h | 18 +
|
|
drivers/ptp/ptp_sysfs.c | 16 +-
|
|
drivers/ptp/ptp_vclock.c | 204 +-
|
|
drivers/remoteproc/imx_rproc.c | 196 +-
|
|
drivers/remoteproc/imx_rproc.h | 2 +
|
|
drivers/remoteproc/remoteproc_core.c | 8 +-
|
|
drivers/rpmsg/Kconfig | 16 +-
|
|
drivers/rpmsg/Makefile | 1 +
|
|
drivers/rpmsg/imx_rpmsg.c | 57 +-
|
|
drivers/rpmsg/imx_rpmsg_tty.c | 18 +-
|
|
drivers/rpmsg/rpmsg_perf.c | 545 +++
|
|
drivers/rpmsg/virtio_rpmsg_bus.c | 5 +
|
|
drivers/rtc/Kconfig | 1 +
|
|
drivers/staging/fsl_qbman/qman_driver.c | 49 +
|
|
drivers/staging/fsl_qbman/qman_high.c | 39 +
|
|
drivers/staging/fsl_qbman/qman_private.h | 7 +
|
|
drivers/tty/rpmsg_tty.c | 191 +-
|
|
drivers/tty/serial/21285.c | 8 +-
|
|
drivers/tty/serial/8250/8250_aspeed_vuart.c | 6 +-
|
|
drivers/tty/serial/8250/8250_bcm7271.c | 28 +-
|
|
drivers/tty/serial/8250/8250_core.c | 54 +-
|
|
drivers/tty/serial/8250/8250_dma.c | 8 +-
|
|
drivers/tty/serial/8250/8250_dw.c | 8 +-
|
|
drivers/tty/serial/8250/8250_exar.c | 4 +-
|
|
drivers/tty/serial/8250/8250_fsl.c | 6 +-
|
|
drivers/tty/serial/8250/8250_mtk.c | 8 +-
|
|
drivers/tty/serial/8250/8250_omap.c | 52 +-
|
|
drivers/tty/serial/8250/8250_pci1xxxx.c | 8 +-
|
|
drivers/tty/serial/8250/8250_port.c | 259 +-
|
|
drivers/tty/serial/altera_jtaguart.c | 28 +-
|
|
drivers/tty/serial/altera_uart.c | 20 +-
|
|
drivers/tty/serial/amba-pl010.c | 20 +-
|
|
drivers/tty/serial/amba-pl011.c | 78 +-
|
|
drivers/tty/serial/apbuart.c | 8 +-
|
|
drivers/tty/serial/ar933x_uart.c | 26 +-
|
|
drivers/tty/serial/arc_uart.c | 16 +-
|
|
drivers/tty/serial/atmel_serial.c | 24 +-
|
|
drivers/tty/serial/bcm63xx_uart.c | 22 +-
|
|
drivers/tty/serial/cpm_uart.c | 8 +-
|
|
drivers/tty/serial/digicolor-usart.c | 18 +-
|
|
drivers/tty/serial/dz.c | 32 +-
|
|
drivers/tty/serial/fsl_linflexuart.c | 26 +-
|
|
drivers/tty/serial/fsl_lpuart.c | 88 +-
|
|
drivers/tty/serial/icom.c | 26 +-
|
|
drivers/tty/serial/imx.c | 84 +-
|
|
drivers/tty/serial/ip22zilog.c | 36 +-
|
|
drivers/tty/serial/jsm/jsm_neo.c | 4 +-
|
|
drivers/tty/serial/jsm/jsm_tty.c | 16 +-
|
|
drivers/tty/serial/liteuart.c | 20 +-
|
|
drivers/tty/serial/lpc32xx_hs.c | 26 +-
|
|
drivers/tty/serial/ma35d1_serial.c | 22 +-
|
|
drivers/tty/serial/mcf.c | 20 +-
|
|
drivers/tty/serial/men_z135_uart.c | 8 +-
|
|
drivers/tty/serial/meson_uart.c | 30 +-
|
|
drivers/tty/serial/milbeaut_usio.c | 16 +-
|
|
drivers/tty/serial/mpc52xx_uart.c | 12 +-
|
|
drivers/tty/serial/mps2-uart.c | 16 +-
|
|
drivers/tty/serial/msm_serial.c | 38 +-
|
|
drivers/tty/serial/mvebu-uart.c | 18 +-
|
|
drivers/tty/serial/omap-serial.c | 44 +-
|
|
drivers/tty/serial/owl-uart.c | 26 +-
|
|
drivers/tty/serial/pch_uart.c | 10 +-
|
|
drivers/tty/serial/pic32_uart.c | 20 +-
|
|
drivers/tty/serial/pmac_zilog.c | 52 +-
|
|
drivers/tty/serial/pxa.c | 30 +-
|
|
drivers/tty/serial/qcom_geni_serial.c | 8 +-
|
|
drivers/tty/serial/rda-uart.c | 34 +-
|
|
drivers/tty/serial/rp2.c | 20 +-
|
|
drivers/tty/serial/sa1100.c | 20 +-
|
|
drivers/tty/serial/samsung_tty.c | 50 +-
|
|
drivers/tty/serial/sb1250-duart.c | 12 +-
|
|
drivers/tty/serial/sc16is7xx.c | 5 +
|
|
drivers/tty/serial/serial-tegra.c | 32 +-
|
|
drivers/tty/serial/serial_core.c | 92 +-
|
|
drivers/tty/serial/serial_mctrl_gpio.c | 4 +-
|
|
drivers/tty/serial/serial_port.c | 4 +-
|
|
drivers/tty/serial/serial_txx9.c | 26 +-
|
|
drivers/tty/serial/sh-sci.c | 68 +-
|
|
drivers/tty/serial/sifive.c | 16 +-
|
|
drivers/tty/serial/sprd_serial.c | 30 +-
|
|
drivers/tty/serial/st-asc.c | 18 +-
|
|
drivers/tty/serial/stm32-usart.c | 38 +-
|
|
drivers/tty/serial/sunhv.c | 28 +-
|
|
drivers/tty/serial/sunplus-uart.c | 26 +-
|
|
drivers/tty/serial/sunsab.c | 34 +-
|
|
drivers/tty/serial/sunsu.c | 46 +-
|
|
drivers/tty/serial/sunzilog.c | 42 +-
|
|
drivers/tty/serial/timbuart.c | 8 +-
|
|
drivers/tty/serial/uartlite.c | 18 +-
|
|
drivers/tty/serial/ucc_uart.c | 4 +-
|
|
drivers/tty/serial/vt8500_serial.c | 8 +-
|
|
drivers/tty/serial/xilinx_uartps.c | 56 +-
|
|
drivers/tty/tty_io.c | 11 +-
|
|
drivers/virtio/Kconfig | 8 +
|
|
drivers/virtio/Makefile | 1 +
|
|
drivers/virtio/virtio_mmio.c | 306 +-
|
|
drivers/virtio/virtio_ring.c | 2 -
|
|
drivers/virtio/virtio_trans.c | 793 ++++
|
|
fs/proc/consoles.c | 14 +-
|
|
include/dt-bindings/clock/imx8-clock.h | 10 +
|
|
include/dt-bindings/rpmsg/imx_srtm.h | 20 +
|
|
include/linux/bottom_half.h | 2 +
|
|
include/linux/clk/imx-pll.h | 26 +
|
|
include/linux/console.h | 150 +
|
|
include/linux/dsa/netc.h | 69 +
|
|
include/linux/dsa/sja1105.h | 2 +
|
|
include/linux/entry-common.h | 2 +-
|
|
include/linux/entry-kvm.h | 2 +-
|
|
include/linux/ethtool.h | 7 +
|
|
include/linux/fec.h | 120 +
|
|
include/linux/fsl_qman.h | 8 +
|
|
include/linux/interrupt.h | 29 +
|
|
include/linux/ipi_baremetal.h | 27 +
|
|
include/linux/net.h | 2 +
|
|
include/linux/netdevice.h | 48 +
|
|
include/linux/printk.h | 30 +-
|
|
include/linux/rpmsg/imx_srtm.h | 65 +
|
|
include/linux/sched.h | 16 +-
|
|
include/linux/sched/idle.h | 8 +-
|
|
include/linux/sched/rt.h | 4 +
|
|
include/linux/serial_8250.h | 6 +
|
|
include/linux/serial_core.h | 43 +-
|
|
include/linux/thread_info.h | 24 +
|
|
include/linux/trace_events.h | 8 +-
|
|
include/net/dsa.h | 18 +
|
|
include/net/flow_offload.h | 9 +
|
|
include/net/switchdev.h | 1 +
|
|
include/net/tc_act/tc_frer.h | 52 +
|
|
include/soc/mscc/ocelot.h | 12 +-
|
|
include/soc/mscc/ocelot_ptp.h | 3 -
|
|
include/soc/mscc/ocelot_vcap.h | 1 +
|
|
include/uapi/linux/ethtool.h | 30 +
|
|
include/uapi/linux/ethtool_netlink.h | 21 +
|
|
include/uapi/linux/if_ether.h | 1 +
|
|
include/uapi/linux/pkt_cls.h | 1 +
|
|
include/uapi/linux/ptp_clock.h | 12 +
|
|
include/uapi/linux/tc_act/tc_frer.h | 50 +
|
|
include/uapi/linux/virtio_ids.h | 1 +
|
|
include/uapi/linux/virtio_mmio.h | 7 +-
|
|
include/uapi/linux/virtio_trans.h | 60 +
|
|
kernel/Kconfig.preempt | 17 +-
|
|
kernel/dma/coherent.c | 15 +-
|
|
kernel/entry/common.c | 4 +-
|
|
kernel/entry/kvm.c | 2 +-
|
|
kernel/futex/pi.c | 87 +-
|
|
kernel/futex/requeue.c | 6 +-
|
|
kernel/ksysfs.c | 12 +
|
|
kernel/locking/lockdep.c | 5 +
|
|
kernel/locking/rtmutex.c | 37 +-
|
|
kernel/locking/rwbase_rt.c | 19 +
|
|
kernel/locking/rwsem.c | 8 +-
|
|
kernel/locking/spinlock_rt.c | 6 +
|
|
kernel/locking/ww_rt_mutex.c | 2 +-
|
|
kernel/panic.c | 9 +
|
|
kernel/printk/Makefile | 2 +-
|
|
kernel/printk/internal.h | 121 +
|
|
kernel/printk/nbcon.c | 1665 ++++++++
|
|
kernel/printk/printk.c | 750 +++-
|
|
kernel/printk/printk_ringbuffer.c | 360 +-
|
|
kernel/printk/printk_ringbuffer.h | 54 +-
|
|
kernel/printk/printk_safe.c | 12 +
|
|
kernel/rcu/rcutorture.c | 6 +
|
|
kernel/rcu/tree_stall.h | 5 +
|
|
kernel/sched/core.c | 127 +-
|
|
kernel/sched/debug.c | 19 +
|
|
kernel/sched/fair.c | 46 +-
|
|
kernel/sched/features.h | 2 +
|
|
kernel/sched/idle.c | 3 +-
|
|
kernel/sched/rt.c | 5 +-
|
|
kernel/sched/sched.h | 1 +
|
|
kernel/signal.c | 30 +-
|
|
kernel/softirq.c | 95 +-
|
|
kernel/time/hrtimer.c | 4 +-
|
|
kernel/time/tick-sched.c | 2 +-
|
|
kernel/time/timer.c | 11 +-
|
|
kernel/trace/trace.c | 2 +
|
|
kernel/trace/trace_output.c | 16 +-
|
|
localversion-rt | 1 +
|
|
net/bridge/br_switchdev.c | 24 +
|
|
net/core/dev.c | 62 +-
|
|
net/core/skbuff.c | 7 +-
|
|
net/dsa/Kconfig | 6 +
|
|
net/dsa/Makefile | 1 +
|
|
net/dsa/slave.c | 49 +-
|
|
net/dsa/tag_netc.c | 489 +++
|
|
net/dsa/tag_sja1105.c | 3 +-
|
|
net/ethtool/Makefile | 2 +-
|
|
net/ethtool/ioctl.c | 55 +
|
|
net/ethtool/netlink.c | 17 +
|
|
net/ethtool/netlink.h | 3 +
|
|
net/ethtool/preempt.c | 191 +
|
|
net/packet/af_packet.c | 11 +-
|
|
net/sched/Kconfig | 13 +
|
|
net/sched/Makefile | 1 +
|
|
net/sched/act_frer.c | 731 ++++
|
|
net/sched/sch_cbs.c | 5 +
|
|
net/socket.c | 27 +
|
|
net/tsn/genl_tsn.c | 12 +-
|
|
tools/virtio/vt_test.sh | 79 +
|
|
489 files changed, 35912 insertions(+), 2267 deletions(-)
|
|
create mode 100644 Documentation/devicetree/bindings/mailbox/generic-software-mbox.yaml
|
|
create mode 100644 Documentation/devicetree/bindings/tty/rpmsg_tty.yaml
|
|
create mode 100644 Documentation/printk-ringbuffer.txt
|
|
create mode 100644 arch/arm/boot/dts/nxp/imx/imx6ul-14x14-evk-ecat.dts
|
|
create mode 100644 arch/arm/boot/dts/nxp/imx/imx6ul-14x14-evk-igh.dts
|
|
create mode 100644 arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-avb-mcr.dts
|
|
create mode 100644 arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-avb.dts
|
|
create mode 100644 arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-ecat.dts
|
|
create mode 100644 arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-igh.dts
|
|
create mode 100644 arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-lpuart.dts
|
|
create mode 100644 arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-reve.dtso
|
|
create mode 100644 arch/arm/boot/dts/nxp/ls/ls1021a-iot-bm.dts
|
|
create mode 100644 arch/arm/configs/imx6ullevk-plc.config
|
|
create mode 100644 arch/arm/configs/imx_avb.config
|
|
create mode 100644 arch/arm/configs/imx_up.config
|
|
create mode 100644 arch/arm64/boot/dts/freescale/fii-ls1028a-tsn.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-dsa-swp5-eno3.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-jailhouse-without-enetc.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-jailhouse.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-sdk-bm.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-bm.dts
|
|
create mode 100755 arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-jailhouse-with-dpaa.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-jailhouse.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-bm.dts
|
|
create mode 100755 arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-jailhouse-with-dpaa.dts
|
|
create mode 100755 arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-jailhouse.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-avb.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-avb.dtsi
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-sja1105.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-tja1100-avb.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8m-generic-mbox-1.dtsi
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8m-generic-mbox.dtsi
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8m-rpmsg-ca53-1.dtsi
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8m-rpmsg-ca53.dtsi
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8m-rproc-ca53.dtsi
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-avb.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-baremetal.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-ecat-userspace.dts
|
|
create mode 100755 arch/arm64/boot/dts/freescale/imx8mm-evk-ecat.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-harpoon-avb.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-harpoon-industrial.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-harpoon-virtio-net.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-harpoon.dts
|
|
create mode 100755 arch/arm64/boot/dts/freescale/imx8mm-evk-igh.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-multicore-rpmsg.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-multicore-rtos.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi-harpoon-avb.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi-harpoon-industrial.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi-harpoon-virtio-net.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi-harpoon.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi.dtsi
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg-8m-buf.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg-ca53.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-net-ca53.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-net-cm4.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-perf-ca53.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-perf-cm4.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mm-virtio-ca53.dtsi
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-evk-harpoon-avb.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-evk-harpoon-industrial.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mn-evk-harpoon.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-avb.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-baremetal.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-dsa-enetc.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-dsa-fec-swp0.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-dsa-fec-swp3.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-dsa.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-ecat-userspace.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-ecat.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-harpoon-avb.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-harpoon-industrial.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-harpoon-virtio-net.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-harpoon.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-igh.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-lwip.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-rpmsg.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-rtos.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-rpmsg-ca53.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-net-ca53.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-net-cm7.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-perf-ca53.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-perf-cm7.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-generic-mbox-1.dtsi
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-generic-mbox.dtsi
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-rpmsg-ca53-1.dtsi
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx8mp-rpmsg-ca53.dtsi
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-avb.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-baremetal.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-dpdk.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa-enetc.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa-fec-swp0.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa-fec-swp3.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-ecat-userspace.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-ecat.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-harpoon-avb.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-harpoon-industrial.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-harpoon-virtio-net.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-harpoon.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-igh.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-multicore-rpmsg.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-multicore-rtos.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-uart-sharing-cm33.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-virtio-net-ca55.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-evk-virtio-net-cm33.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-14x14-evk-aud-hat-avb.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-14x14-evk-imxai2eth-ath.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-14x14-evk-mqs.dtsi
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-14x14-evk-multicore-rpmsg.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-14x14-evk-multicore-rtos.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-14x14-evk-sja1105-avb.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-14x14-evk-uart-sharing-cm33.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-14x14-evk-virtio-net-ca55.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-14x14-evk-virtio-net-cm33.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-9x9-qsb-baremetal.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-9x9-qsb-inmate.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-9x9-qsb-root.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-9x9-qsb-uart-sharing-cm33.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-evk-avb.dtsi
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-generic-mbox.dtsi
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-rpmsg-ca55.dtsi
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx93-rproc-ca55.dtsi
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx95-15x15-evk-harpoon-industrial.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx95-15x15-evk-harpoon.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx95-15x15-evk-multicore-rtos.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx95-19x19-evk-harpoon-industrial.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx95-19x19-evk-harpoon.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx95-19x19-evk-multicore-rtos.dts
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx95-generic-mbox.dtsi
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx95-rpmsg-ca55.dtsi
|
|
create mode 100644 arch/arm64/boot/dts/freescale/imx95-rproc-ca55.dtsi
|
|
create mode 100644 arch/arm64/configs/imx_avb.config
|
|
create mode 100644 arch/arm64/configs/linux-dpaa-ethercat.config
|
|
create mode 100644 arch/arm64/configs/linux-rpmsg-8m-buf.config
|
|
create mode 100644 drivers/clk/imx/clk-pll.c
|
|
create mode 100644 drivers/clk/imx/clk-pll.h
|
|
create mode 100644 drivers/irqchip/ipi-baremetal.c
|
|
create mode 100644 drivers/mailbox/generic-software-mailbox.c
|
|
create mode 100644 drivers/net/dsa/netc/Kconfig
|
|
create mode 100644 drivers/net/dsa/netc/Makefile
|
|
create mode 100644 drivers/net/dsa/netc/netc.h
|
|
create mode 100644 drivers/net/dsa/netc/netc_config.c
|
|
create mode 100644 drivers/net/dsa/netc/netc_config.h
|
|
create mode 100644 drivers/net/dsa/netc/netc_devlink.c
|
|
create mode 100644 drivers/net/dsa/netc/netc_ethtool.c
|
|
create mode 100644 drivers/net/dsa/netc/netc_main.c
|
|
create mode 100644 drivers/net/dsa/netc/netc_ptp.c
|
|
create mode 100644 drivers/net/dsa/netc/netc_ptp.h
|
|
create mode 100644 drivers/net/dsa/netc/netc_spi.c
|
|
create mode 100644 drivers/net/ethernet/freescale/fec_ecat.c
|
|
create mode 100644 drivers/net/ethernet/freescale/fec_ecat.h
|
|
create mode 100644 drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethercat.c
|
|
create mode 100644 drivers/nfc/pn5xx/Kconfig
|
|
create mode 100644 drivers/nfc/pn5xx/Makefile
|
|
create mode 100644 drivers/nfc/pn5xx/README.md
|
|
create mode 100644 drivers/nfc/pn5xx/pn5xx_i2c.c
|
|
create mode 100644 drivers/nfc/pn5xx/pn5xx_i2c.h
|
|
create mode 100644 drivers/nfc/pn5xx/sample_devicetree.txt
|
|
create mode 100644 drivers/rpmsg/rpmsg_perf.c
|
|
create mode 100644 drivers/virtio/virtio_trans.c
|
|
create mode 100644 include/dt-bindings/rpmsg/imx_srtm.h
|
|
create mode 100644 include/linux/clk/imx-pll.h
|
|
create mode 100644 include/linux/dsa/netc.h
|
|
create mode 100644 include/linux/ipi_baremetal.h
|
|
create mode 100644 include/linux/rpmsg/imx_srtm.h
|
|
create mode 100644 include/net/tc_act/tc_frer.h
|
|
create mode 100644 include/uapi/linux/tc_act/tc_frer.h
|
|
create mode 100644 include/uapi/linux/virtio_trans.h
|
|
create mode 100644 kernel/printk/nbcon.c
|
|
create mode 100644 localversion-rt
|
|
create mode 100644 net/dsa/tag_netc.c
|
|
create mode 100644 net/ethtool/preempt.c
|
|
create mode 100644 net/sched/act_frer.c
|
|
create mode 100755 tools/virtio/vt_test.sh
|
|
|
|
diff --git a/Documentation/devicetree/bindings/mailbox/generic-software-mbox.yaml b/Documentation/devicetree/bindings/mailbox/generic-software-mbox.yaml
|
|
new file mode 100644
|
|
index 000000000000..57c91ab2c80a
|
|
--- /dev/null
|
|
+++ b/Documentation/devicetree/bindings/mailbox/generic-software-mbox.yaml
|
|
@@ -0,0 +1,65 @@
|
|
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
|
+%YAML 1.2
|
|
+---
|
|
+$id: http://devicetree.org/schemas/mailbox/generic-software-mbox.yaml#
|
|
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
|
+
|
|
+title: Generic Software Mailbox
|
|
+
|
|
+maintainers:
|
|
+ - Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
|
|
+
|
|
+description: |
|
|
+ The Generic Software Mailbox is a virtual device, which uses unused
|
|
+ interrupt line to notify remote side and shared memory to emulate
|
|
+ device MMIO registers.
|
|
+
|
|
+properties:
|
|
+ compatible:
|
|
+ oneOf:
|
|
+ - const: fsl,generic-software-mbox
|
|
+ reg:
|
|
+ maxItems: 1
|
|
+
|
|
+ "#mbox-cells":
|
|
+ description: |
|
|
+ <&phandle type channel ack>
|
|
+ phandle : Label name of controller
|
|
+ type : Channel type
|
|
+ channel : Channel index
|
|
+ ack : 0: Receiver doesn't trigger an ACK interrupt to sender after receive message
|
|
+ 1: Receiver triggers an ACK interrupt to sender after receive message
|
|
+
|
|
+ This mailbox support 3 type of unidirectional channels, each type
|
|
+ has 32 channels. Following types are supported:
|
|
+ 0 - TX channel with 32bit transmit register
|
|
+ 1 - RX channel with 32bit receive register and IRQ support
|
|
+ 2 - RX doorbell channel.
|
|
+ const: 2
|
|
+
|
|
+required:
|
|
+ - compatible
|
|
+ - reg
|
|
+ - "#mbox-cells"
|
|
+ - interrupts
|
|
+ - interrupt-names
|
|
+
|
|
+additionalProperties: false
|
|
+
|
|
+examples:
|
|
+ - |
|
|
+ reserved-memory {
|
|
+ gen-sw-mbox@b8500000 {
|
|
+ no-map;
|
|
+ reg = <0 0xb8500000 0 0x1000>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ generic-software-mailbox@b8500000 {
|
|
+ compatible = "fsl,generic-software-mbox";
|
|
+ reg = <0 0xb8500000 0 0x1000>;
|
|
+ #mbox-cells = <3>;
|
|
+ interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>,
|
|
+ <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "irq", "remote_irq";
|
|
+ };
|
|
diff --git a/Documentation/devicetree/bindings/net/fsl,fec.yaml b/Documentation/devicetree/bindings/net/fsl,fec.yaml
|
|
index ab1575b781dd..eb4924742dc2 100644
|
|
--- a/Documentation/devicetree/bindings/net/fsl,fec.yaml
|
|
+++ b/Documentation/devicetree/bindings/net/fsl,fec.yaml
|
|
@@ -186,6 +186,30 @@ properties:
|
|
description:
|
|
Register bits of stop mode control, the format is <&gpr req_gpr req_bit>.
|
|
|
|
+ fsl,rx-phy-delay-100-ns:
|
|
+ $ref: /schemas/types.yaml#/definitions/uint32
|
|
+ description:
|
|
+ If present, should specify the delay (MAC-PHY) compensation
|
|
+ in ns to be applied on packets timestamps on receive for 100 Mbps link speed
|
|
+
|
|
+ fsl,tx-phy-delay-100-ns:
|
|
+ $ref: /schemas/types.yaml#/definitions/uint32
|
|
+ description:
|
|
+ If present, should specify the delay (MAC-PHY) compensation
|
|
+ in ns to be applied on packets timestamps on transmit for 100 Mbps link speed
|
|
+
|
|
+ fsl,rx-phy-delay-1000-ns:
|
|
+ $ref: /schemas/types.yaml#/definitions/uint32
|
|
+ description:
|
|
+ If present, should specify the delay (MAC-PHY) compensation
|
|
+ in ns to be applied on packets timestamps on receive for 1 Gbps link speed
|
|
+
|
|
+ fsl,tx-phy-delay-1000-ns:
|
|
+ $ref: /schemas/types.yaml#/definitions/uint32
|
|
+ description:
|
|
+ If present, should specify the delay (MAC-PHY) compensation
|
|
+ in ns to be applied on packets timestamps on transmit for 1 Gbps link speed
|
|
+
|
|
mii-exclusive:
|
|
$ref: /schemas/types.yaml#/definitions/flag
|
|
description:
|
|
diff --git a/Documentation/devicetree/bindings/tty/rpmsg_tty.yaml b/Documentation/devicetree/bindings/tty/rpmsg_tty.yaml
|
|
new file mode 100644
|
|
index 000000000000..9e11fadd16eb
|
|
--- /dev/null
|
|
+++ b/Documentation/devicetree/bindings/tty/rpmsg_tty.yaml
|
|
@@ -0,0 +1,67 @@
|
|
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
|
+%YAML 1.2
|
|
+---
|
|
+$id: http://devicetree.org/schemas/tty/rpmsg_tty.yaml#
|
|
+$schema: http://devicetree.org/meta-schemas/core.yaml#
|
|
+
|
|
+title: rpmsg tty driver
|
|
+
|
|
+maintainers:
|
|
+ - Biwen Li <biwen.li@nxp.com>
|
|
+
|
|
+properties:
|
|
+ compatible:
|
|
+ const: fsl,uart-rpbus
|
|
+
|
|
+ bus_id:
|
|
+ items:
|
|
+ - description: Used for imx srtm uart application protocol. Specify which real uart(LPUARTx/UARTx, x is instance number) will be used by a virtual tty(/dev/ttyRPMSGx), bus_id = 0xff when bus_id is not specified in dts and specified the flag(IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG).
|
|
+ maxItems: 1
|
|
+
|
|
+ flags:
|
|
+ items:
|
|
+ - description: used for imx srtm uart application protocol(IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG: support multi uart message protocol; IMX_SRTM_UART_SPECIFY_PORT_NUM_MASK: whether specify destination uart id; IMX_SRTM_UART_PORT_NUM_MASK: which destination uart id will be used)
|
|
+ maxItems: 1
|
|
+
|
|
+ status:
|
|
+ maxItems: 1
|
|
+
|
|
+examples:
|
|
+ - |
|
|
+ #include <dt-bindings/rpmsg/imx_srtm.h>
|
|
+
|
|
+ uart-rpbus-0 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ }; /* /dev/ttyRPMSG0 on linux(running on acore) <--SRTM PROTOCOL--> srtm uart channel 0(endpoint on mcore) <---MULTI UART MSG PROTOCOL---> UART3(mcore is the owner) */
|
|
+
|
|
+ uart-rpbus-1 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ }; /* /dev/ttyRPMSG1 on linux(running on acore) <--SRTM PROTOCOL--> srtm uart channel 1(endpoint on mcore) <---MULTI UART MSG PROTOCOL---> UART3(mcore is the owner) */
|
|
+
|
|
+ uart-rpbus-2 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <2>; /* use uart2 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ }; /* /dev/ttyRPMSG2 on linux(running on acore) <--SRTM PROTOCOL--> srtm uart channel 2(endpoint on mcore) <---MULTI UART MSG PROTOCOL---> UART2(mcore is the owner) */
|
|
+
|
|
+ uart-rpbus-3 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <4>; /* use uart4 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG | IMX_SRTM_UART_SPECIFY_PORT_NUM_MASK | IMX_SRTM_UART_PORT_NUM_MASK(0x8)>;
|
|
+ status = "okay";
|
|
+ }; /* [/dev/ttyRPMSG3 on linux(running on acore) <--SRTM PROTOCOL--> srtm uart channel 3(endpoint on mcore) <---MULTI UART MSG PROTOCOL---> UART4(mcore is the owner), first board] <---MULTI UART MSG PROTOCOL--> [UARTx(mcore is the owner) <---MULTI UART MSG PROTOCOL---> srtm uart channel 8 <---SRTM PROTOCOL--> /dev/ttyRPMSG8 on linux(running on acore), second board ] */
|
|
+
|
|
+ uart-rpbus-4 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use uart5 */
|
|
+ status = "okay";
|
|
+ }; /* /dev/ttyRPMSG4 on linux(running on acore) <--SRTM PROTOCOL--> srtm uart channel 4(endpoint on mcore) <-----> UART5(mcore is the owner) <----> GPS device(The device have exclusive use of the UART5, other virtual tty cannot use UART5) */
|
|
+
|
|
+ /* Note: when nothing is specified(include compatible, bus_id, flags, status), it's a normal rpmsg tty. /dev/ttyRPMSG7(running on acore) <--RPMSG--> rpmsg endpoint(running on mcore) */
|
|
diff --git a/Documentation/printk-ringbuffer.txt b/Documentation/printk-ringbuffer.txt
|
|
new file mode 100644
|
|
index 000000000000..6bde5dbd8545
|
|
--- /dev/null
|
|
+++ b/Documentation/printk-ringbuffer.txt
|
|
@@ -0,0 +1,377 @@
|
|
+struct printk_ringbuffer
|
|
+------------------------
|
|
+John Ogness <john.ogness@linutronix.de>
|
|
+
|
|
+Overview
|
|
+~~~~~~~~
|
|
+As the name suggests, this ring buffer was implemented specifically to serve
|
|
+the needs of the printk() infrastructure. The ring buffer itself is not
|
|
+specific to printk and could be used for other purposes. _However_, the
|
|
+requirements and semantics of printk are rather unique. If you intend to use
|
|
+this ring buffer for anything other than printk, you need to be very clear on
|
|
+its features, behavior, and pitfalls.
|
|
+
|
|
+Features
|
|
+^^^^^^^^
|
|
+The printk ring buffer has the following features:
|
|
+
|
|
+- single global buffer
|
|
+- resides in initialized data section (available at early boot)
|
|
+- lockless readers
|
|
+- supports multiple writers
|
|
+- supports multiple non-consuming readers
|
|
+- safe from any context (including NMI)
|
|
+- groups bytes into variable length blocks (referenced by entries)
|
|
+- entries tagged with sequence numbers
|
|
+
|
|
+Behavior
|
|
+^^^^^^^^
|
|
+Since the printk ring buffer readers are lockless, there exists no
|
|
+synchronization between readers and writers. Basically writers are the tasks
|
|
+in control and may overwrite any and all committed data at any time and from
|
|
+any context. For this reason readers can miss entries if they are overwritten
|
|
+before the reader was able to access the data. The reader API implementation
|
|
+is such that reader access to entries is atomic, so there is no risk of
|
|
+readers having to deal with partial or corrupt data. Also, entries are
|
|
+tagged with sequence numbers so readers can recognize if entries were missed.
|
|
+
|
|
+Writing to the ring buffer consists of 2 steps. First a writer must reserve
|
|
+an entry of desired size. After this step the writer has exclusive access
|
|
+to the memory region. Once the data has been written to memory, it needs to
|
|
+be committed to the ring buffer. After this step the entry has been inserted
|
|
+into the ring buffer and assigned an appropriate sequence number.
|
|
+
|
|
+Once committed, a writer must no longer access the data directly. This is
|
|
+because the data may have been overwritten and no longer exists. If a
|
|
+writer must access the data, it should either keep a private copy before
|
|
+committing the entry or use the reader API to gain access to the data.
|
|
+
|
|
+Because of how the data backend is implemented, entries that have been
|
|
+reserved but not yet committed act as barriers, preventing future writers
|
|
+from filling the ring buffer beyond the location of the reserved but not
|
|
+yet committed entry region. For this reason it is *important* that writers
|
|
+perform both reserve and commit as quickly as possible. Also, be aware that
|
|
+preemption and local interrupts are disabled and writing to the ring buffer
|
|
+is processor-reentrant locked during the reserve/commit window. Writers in
|
|
+NMI contexts can still preempt any other writers, but as long as these
|
|
+writers do not write a large amount of data with respect to the ring buffer
|
|
+size, this should not become an issue.
|
|
+
|
|
+API
|
|
+~~~
|
|
+
|
|
+Declaration
|
|
+^^^^^^^^^^^
|
|
+The printk ring buffer can be instantiated as a static structure:
|
|
+
|
|
+ /* declare a static struct printk_ringbuffer */
|
|
+ #define DECLARE_STATIC_PRINTKRB(name, szbits, cpulockptr)
|
|
+
|
|
+The value of szbits specifies the size of the ring buffer in bits. The
|
|
+cpulockptr field is a pointer to a prb_cpulock struct that is used to
|
|
+perform processor-reentrant spin locking for the writers. It is specified
|
|
+externally because it may be used for multiple ring buffers (or other
|
|
+code) to synchronize writers without risk of deadlock.
|
|
+
|
|
+Here is an example of a declaration of a printk ring buffer specifying a
|
|
+32KB (2^15) ring buffer:
|
|
+
|
|
+....
|
|
+DECLARE_STATIC_PRINTKRB_CPULOCK(rb_cpulock);
|
|
+DECLARE_STATIC_PRINTKRB(rb, 15, &rb_cpulock);
|
|
+....
|
|
+
|
|
+If writers will be using multiple ring buffers and the ordering of that usage
|
|
+is not clear, the same prb_cpulock should be used for both ring buffers.
|
|
+
|
|
+Writer API
|
|
+^^^^^^^^^^
|
|
+The writer API consists of 2 functions. The first is to reserve an entry in
|
|
+the ring buffer, the second is to commit that data to the ring buffer. The
|
|
+reserved entry information is stored within a provided `struct prb_handle`.
|
|
+
|
|
+ /* reserve an entry */
|
|
+ char *prb_reserve(struct prb_handle *h, struct printk_ringbuffer *rb,
|
|
+ unsigned int size);
|
|
+
|
|
+ /* commit a reserved entry to the ring buffer */
|
|
+ void prb_commit(struct prb_handle *h);
|
|
+
|
|
+Here is an example of a function to write data to a ring buffer:
|
|
+
|
|
+....
|
|
+int write_data(struct printk_ringbuffer *rb, char *data, int size)
|
|
+{
|
|
+ struct prb_handle h;
|
|
+ char *buf;
|
|
+
|
|
+ buf = prb_reserve(&h, rb, size);
|
|
+ if (!buf)
|
|
+ return -1;
|
|
+ memcpy(buf, data, size);
|
|
+ prb_commit(&h);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+....
|
|
+
|
|
+Pitfalls
|
|
+++++++++
|
|
+Be aware that prb_reserve() can fail. A retry might be successful, but it
|
|
+depends entirely on whether or not the next part of the ring buffer to
|
|
+overwrite belongs to reserved but not yet committed entries of other writers.
|
|
+Writers can use the prb_inc_lost() function to allow readers to notice that a
|
|
+message was lost.
|
|
+
|
|
+Reader API
|
|
+^^^^^^^^^^
|
|
+The reader API utilizes a `struct prb_iterator` to track the reader's
|
|
+position in the ring buffer.
|
|
+
|
|
+ /* declare a pre-initialized static iterator for a ring buffer */
|
|
+ #define DECLARE_STATIC_PRINTKRB_ITER(name, rbaddr)
|
|
+
|
|
+ /* initialize iterator for a ring buffer (if static macro NOT used) */
|
|
+ void prb_iter_init(struct prb_iterator *iter,
|
|
+ struct printk_ringbuffer *rb, u64 *seq);
|
|
+
|
|
+ /* make a deep copy of an iterator */
|
|
+ void prb_iter_copy(struct prb_iterator *dest,
|
|
+ struct prb_iterator *src);
|
|
+
|
|
+ /* non-blocking, advance to next entry (and read the data) */
|
|
+ int prb_iter_next(struct prb_iterator *iter, char *buf,
|
|
+ int size, u64 *seq);
|
|
+
|
|
+ /* blocking, advance to next entry (and read the data) */
|
|
+ int prb_iter_wait_next(struct prb_iterator *iter, char *buf,
|
|
+ int size, u64 *seq);
|
|
+
|
|
+ /* position iterator at the entry seq */
|
|
+ int prb_iter_seek(struct prb_iterator *iter, u64 seq);
|
|
+
|
|
+ /* read data at current position */
|
|
+ int prb_iter_data(struct prb_iterator *iter, char *buf,
|
|
+ int size, u64 *seq);
|
|
+
|
|
+Typically prb_iter_data() is not needed because the data can be retrieved
|
|
+directly with prb_iter_next().
|
|
+
|
|
+Here is an example of a non-blocking function that will read all the data in
|
|
+a ring buffer:
|
|
+
|
|
+....
|
|
+void read_all_data(struct printk_ringbuffer *rb, char *buf, int size)
|
|
+{
|
|
+ struct prb_iterator iter;
|
|
+ u64 prev_seq = 0;
|
|
+ u64 seq;
|
|
+ int ret;
|
|
+
|
|
+ prb_iter_init(&iter, rb, NULL);
|
|
+
|
|
+ for (;;) {
|
|
+ ret = prb_iter_next(&iter, buf, size, &seq);
|
|
+ if (ret > 0) {
|
|
+ if (seq != ++prev_seq) {
|
|
+ /* "seq - prev_seq" entries missed */
|
|
+ prev_seq = seq;
|
|
+ }
|
|
+ /* process buf here */
|
|
+ } else if (ret == 0) {
|
|
+ /* hit the end, done */
|
|
+ break;
|
|
+ } else if (ret < 0) {
|
|
+ /*
|
|
+ * iterator is invalid, a writer overtook us, reset the
|
|
+ * iterator and keep going, entries were missed
|
|
+ */
|
|
+ prb_iter_init(&iter, rb, NULL);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+....
|
|
+
|
|
+Pitfalls
|
|
+++++++++
|
|
+The reader's iterator can become invalid at any time because the reader was
|
|
+overtaken by a writer. Typically the reader should reset the iterator back
|
|
+to the current oldest entry (which will be newer than the entry the reader
|
|
+was at) and continue, noting the number of entries that were missed.
|
|
+
|
|
+Utility API
|
|
+^^^^^^^^^^^
|
|
+Several functions are available as convenience for external code.
|
|
+
|
|
+ /* query the size of the data buffer */
|
|
+ int prb_buffer_size(struct printk_ringbuffer *rb);
|
|
+
|
|
+ /* skip a seq number to signify a lost record */
|
|
+ void prb_inc_lost(struct printk_ringbuffer *rb);
|
|
+
|
|
+ /* processor-reentrant spin lock */
|
|
+ void prb_lock(struct prb_cpulock *cpu_lock, unsigned int *cpu_store);
|
|
+
|
|
+ /* processor-reentrant spin unlock */
|
|
+ void prb_lock(struct prb_cpulock *cpu_lock, unsigned int *cpu_store);
|
|
+
|
|
+Pitfalls
|
|
+++++++++
|
|
+Although the value returned by prb_buffer_size() does represent an absolute
|
|
+upper bound, the amount of data that can be stored within the ring buffer
|
|
+is actually less because of the additional storage space of a header for each
|
|
+entry.
|
|
+
|
|
+The prb_lock() and prb_unlock() functions can be used to synchronize between
|
|
+ring buffer writers and other external activities. The function of a
|
|
+processor-reentrant spin lock is to disable preemption and local interrupts
|
|
+and synchronize against other processors. It does *not* protect against
|
|
+multiple contexts of a single processor, i.e NMI.
|
|
+
|
|
+Implementation
|
|
+~~~~~~~~~~~~~~
|
|
+This section describes several of the implementation concepts and details to
|
|
+help developers better understand the code.
|
|
+
|
|
+Entries
|
|
+^^^^^^^
|
|
+All ring buffer data is stored within a single static byte array. The reason
|
|
+for this is to ensure that any pointers to the data (past and present) will
|
|
+always point to valid memory. This is important because the lockless readers
|
|
+may be preempted for long periods of time and when they resume may be working
|
|
+with expired pointers.
|
|
+
|
|
+Entries are identified by start index and size. (The start index plus size
|
|
+is the start index of the next entry.) The start index is not simply an
|
|
+offset into the byte array, but rather a logical position (lpos) that maps
|
|
+directly to byte array offsets.
|
|
+
|
|
+For example, for a byte array of 1000, an entry may have have a start index
|
|
+of 100. Another entry may have a start index of 1100. And yet another 2100.
|
|
+All of these entry are pointing to the same memory region, but only the most
|
|
+recent entry is valid. The other entries are pointing to valid memory, but
|
|
+represent entries that have been overwritten.
|
|
+
|
|
+Note that due to overflowing, the most recent entry is not necessarily the one
|
|
+with the highest lpos value. Indeed, the printk ring buffer initializes its
|
|
+data such that an overflow happens relatively quickly in order to validate the
|
|
+handling of this situation. The implementation assumes that an lpos (unsigned
|
|
+long) will never completely wrap while a reader is preempted. If this were to
|
|
+become an issue, the seq number (which never wraps) could be used to increase
|
|
+the robustness of handling this situation.
|
|
+
|
|
+Buffer Wrapping
|
|
+^^^^^^^^^^^^^^^
|
|
+If an entry starts near the end of the byte array but would extend beyond it,
|
|
+a special terminating entry (size = -1) is inserted into the byte array and
|
|
+the real entry is placed at the beginning of the byte array. This can waste
|
|
+space at the end of the byte array, but simplifies the implementation by
|
|
+allowing writers to always work with contiguous buffers.
|
|
+
|
|
+Note that the size field is the first 4 bytes of the entry header. Also note
|
|
+that calc_next() always ensures that there are at least 4 bytes left at the
|
|
+end of the byte array to allow room for a terminating entry.
|
|
+
|
|
+Ring Buffer Pointers
|
|
+^^^^^^^^^^^^^^^^^^^^
|
|
+Three pointers (lpos values) are used to manage the ring buffer:
|
|
+
|
|
+ - _tail_: points to the oldest entry
|
|
+ - _head_: points to where the next new committed entry will be
|
|
+ - _reserve_: points to where the next new reserved entry will be
|
|
+
|
|
+These pointers always maintain a logical ordering:
|
|
+
|
|
+ tail <= head <= reserve
|
|
+
|
|
+The reserve pointer moves forward when a writer reserves a new entry. The
|
|
+head pointer moves forward when a writer commits a new entry.
|
|
+
|
|
+The reserve pointer cannot overwrite the tail pointer in a wrap situation. In
|
|
+such a situation, the tail pointer must be "pushed forward", thus
|
|
+invalidating that oldest entry. Readers identify if they are accessing a
|
|
+valid entry by ensuring their entry pointer is `>= tail && < head`.
|
|
+
|
|
+If the tail pointer is equal to the head pointer, it cannot be pushed and any
|
|
+reserve operation will fail. The only resolution is for writers to commit
|
|
+their reserved entries.
|
|
+
|
|
+Processor-Reentrant Locking
|
|
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
+The purpose of the processor-reentrant locking is to limit the interruption
|
|
+scenarios of writers to 2 contexts. This allows for a simplified
|
|
+implementation where:
|
|
+
|
|
+- The reserve/commit window only exists on 1 processor at a time. A reserve
|
|
+ can never fail due to uncommitted entries of other processors.
|
|
+
|
|
+- When committing entries, it is trivial to handle the situation when
|
|
+ subsequent entries have already been committed, i.e. managing the head
|
|
+ pointer.
|
|
+
|
|
+Performance
|
|
+~~~~~~~~~~~
|
|
+Some basic tests were performed on a quad Intel(R) Xeon(R) CPU E5-2697 v4 at
|
|
+2.30GHz (36 cores / 72 threads). All tests involved writing a total of
|
|
+32,000,000 records at an average of 33 bytes each. Each writer was pinned to
|
|
+its own CPU and would write as fast as it could until a total of 32,000,000
|
|
+records were written. All tests involved 2 readers that were both pinned
|
|
+together to another CPU. Each reader would read as fast as it could and track
|
|
+how many of the 32,000,000 records it could read. All tests used a ring buffer
|
|
+of 16KB in size, which holds around 350 records (header + data for each
|
|
+entry).
|
|
+
|
|
+The only difference between the tests is the number of writers (and thus also
|
|
+the number of records per writer). As more writers are added, the time to
|
|
+write a record increases. This is because data pointers, modified via cmpxchg,
|
|
+and global data access in general become more contended.
|
|
+
|
|
+1 writer
|
|
+^^^^^^^^
|
|
+ runtime: 0m 18s
|
|
+ reader1: 16219900/32000000 (50%) records
|
|
+ reader2: 16141582/32000000 (50%) records
|
|
+
|
|
+2 writers
|
|
+^^^^^^^^^
|
|
+ runtime: 0m 32s
|
|
+ reader1: 16327957/32000000 (51%) records
|
|
+ reader2: 16313988/32000000 (50%) records
|
|
+
|
|
+4 writers
|
|
+^^^^^^^^^
|
|
+ runtime: 0m 42s
|
|
+ reader1: 16421642/32000000 (51%) records
|
|
+ reader2: 16417224/32000000 (51%) records
|
|
+
|
|
+8 writers
|
|
+^^^^^^^^^
|
|
+ runtime: 0m 43s
|
|
+ reader1: 16418300/32000000 (51%) records
|
|
+ reader2: 16432222/32000000 (51%) records
|
|
+
|
|
+16 writers
|
|
+^^^^^^^^^^
|
|
+ runtime: 0m 54s
|
|
+ reader1: 16539189/32000000 (51%) records
|
|
+ reader2: 16542711/32000000 (51%) records
|
|
+
|
|
+32 writers
|
|
+^^^^^^^^^^
|
|
+ runtime: 1m 13s
|
|
+ reader1: 16731808/32000000 (52%) records
|
|
+ reader2: 16735119/32000000 (52%) records
|
|
+
|
|
+Comments
|
|
+^^^^^^^^
|
|
+It is particularly interesting to compare/contrast the 1-writer and 32-writer
|
|
+tests. Despite the writing of the 32,000,000 records taking over 4 times
|
|
+longer, the readers (which perform no cmpxchg) were still unable to keep up.
|
|
+This shows that the memory contention between the increasing number of CPUs
|
|
+also has a dramatic effect on readers.
|
|
+
|
|
+It should also be noted that in all cases each reader was able to read >=50%
|
|
+of the records. This means that a single reader would have been able to keep
|
|
+up with the writer(s) in all cases, becoming slightly easier as more writers
|
|
+are added. This was the purpose of pinning 2 readers to 1 CPU: to observe how
|
|
+maximum reader performance changes.
|
|
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
|
|
index 0694e03e20f8..98fc1c4aaade 100644
|
|
--- a/arch/arm/Kconfig
|
|
+++ b/arch/arm/Kconfig
|
|
@@ -34,6 +34,7 @@ config ARM
|
|
select ARCH_OPTIONAL_KERNEL_RWX_DEFAULT if CPU_V7
|
|
select ARCH_SUPPORTS_ATOMIC_RMW
|
|
select ARCH_SUPPORTS_HUGETLBFS if ARM_LPAE
|
|
+ select ARCH_SUPPORTS_RT if HAVE_POSIX_CPU_TIMERS_TASK_WORK
|
|
select ARCH_USE_BUILTIN_BSWAP
|
|
select ARCH_USE_CMPXCHG_LOCKREF
|
|
select ARCH_USE_MEMTEST
|
|
@@ -73,7 +74,7 @@ config ARM
|
|
select HAS_IOPORT
|
|
select HAVE_ARCH_AUDITSYSCALL if AEABI && !OABI_COMPAT
|
|
select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6
|
|
- select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU
|
|
+ select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU && !PREEMPT_RT
|
|
select HAVE_ARCH_KFENCE if MMU && !XIP_KERNEL
|
|
select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32 && MMU
|
|
select HAVE_ARCH_KASAN if MMU && !XIP_KERNEL
|
|
@@ -96,7 +97,7 @@ config ARM
|
|
select HAVE_DYNAMIC_FTRACE_WITH_REGS if HAVE_DYNAMIC_FTRACE
|
|
select HAVE_EFFICIENT_UNALIGNED_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && MMU
|
|
select HAVE_EXIT_THREAD
|
|
- select HAVE_FAST_GUP if ARM_LPAE
|
|
+ select HAVE_FAST_GUP if ARM_LPAE && !(PREEMPT_RT && HIGHPTE)
|
|
select HAVE_FTRACE_MCOUNT_RECORD if !XIP_KERNEL
|
|
select HAVE_FUNCTION_ERROR_INJECTION
|
|
select HAVE_FUNCTION_GRAPH_TRACER
|
|
@@ -118,6 +119,7 @@ config ARM
|
|
select HAVE_PERF_EVENTS
|
|
select HAVE_PERF_REGS
|
|
select HAVE_PERF_USER_STACK_DUMP
|
|
+ select HAVE_POSIX_CPU_TIMERS_TASK_WORK if !KVM
|
|
select MMU_GATHER_RCU_TABLE_FREE if SMP && ARM_LPAE
|
|
select HAVE_REGS_AND_STACK_ACCESS_API
|
|
select HAVE_RSEQ
|
|
diff --git a/arch/arm/boot/dts/nxp/imx/Makefile b/arch/arm/boot/dts/nxp/imx/Makefile
|
|
index 12e091dc4c4c..65faf0074601 100644
|
|
--- a/arch/arm/boot/dts/nxp/imx/Makefile
|
|
+++ b/arch/arm/boot/dts/nxp/imx/Makefile
|
|
@@ -336,6 +336,8 @@ dtb-$(CONFIG_SOC_IMX6SX) += \
|
|
imx6sx-udoo-neo-full.dtb
|
|
dtb-$(CONFIG_SOC_IMX6UL) += \
|
|
imx6ul-14x14-evk.dtb \
|
|
+ imx6ul-14x14-evk-ecat.dtb \
|
|
+ imx6ul-14x14-evk-igh.dtb \
|
|
imx6ul-14x14-evk-csi.dtb \
|
|
imx6ul-14x14-evk-emmc.dtb \
|
|
imx6ul-14x14-evk-btwifi.dtb \
|
|
@@ -367,6 +369,11 @@ dtb-$(CONFIG_SOC_IMX6UL) += \
|
|
imx6ul-tx6ul-0011.dtb \
|
|
imx6ul-tx6ul-mainboard.dtb \
|
|
imx6ull-14x14-evk.dtb \
|
|
+ imx6ull-14x14-evk-ecat.dtb \
|
|
+ imx6ull-14x14-evk-igh.dtb \
|
|
+ imx6ull-14x14-evk-lpuart.dtb \
|
|
+ imx6ull-14x14-evk-avb.dtb \
|
|
+ imx6ull-14x14-evk-avb-mcr.dtb \
|
|
imx6ull-14x14-evk-emmc.dtb \
|
|
imx6ull-14x14-evk-btwifi.dtb \
|
|
imx6ull-14x14-evk-gpmi-weim.dtb \
|
|
@@ -418,6 +425,7 @@ imx6ul-14x14-evk-reve-ecspi-slave-dtbs := imx6ul-14x14-evk-ecspi-slave.dtb imx6u
|
|
imx6ul-14x14-evk-reve-ecspi-dtbs := imx6ul-14x14-evk-ecspi.dtb imx6ul-14x14-evk-reve.dtbo
|
|
imx6ul-14x14-evk-reve-gpmi-weim-dtbs := imx6ul-14x14-evk-gpmi-weim.dtb imx6ul-14x14-evk-reve.dtbo
|
|
imx6ull-14x14-evk-reve-dtbs := imx6ull-14x14-evk.dtb imx6ul-14x14-evk-reve.dtbo
|
|
+imx6ull-14x14-evk-reve-avb-dtbs := imx6ull-14x14-evk-avb.dtb imx6ul-14x14-evk-reve.dtbo imx6ull-14x14-evk-reve.dtbo
|
|
imx6ull-14x14-evk-reve-emmc-dtbs := imx6ull-14x14-evk-emmc.dtb imx6ul-14x14-evk-reve.dtbo
|
|
imx6ull-14x14-evk-reve-btwifi-dtbs := imx6ull-14x14-evk-btwifi.dtb imx6ul-14x14-evk-reve.dtbo
|
|
imx6ull-14x14-evk-reve-gpmi-weim-dtbs := imx6ull-14x14-evk-gpmi-weim.dtb imx6ul-14x14-evk-reve.dtbo
|
|
@@ -434,6 +442,7 @@ dtb-$(CONFIG_SOC_IMX6UL) += \
|
|
imx6ul-14x14-evk-reve-ecspi.dtb \
|
|
imx6ul-14x14-evk-reve-gpmi-weim.dtb \
|
|
imx6ull-14x14-evk-reve.dtb \
|
|
+ imx6ull-14x14-evk-reve-avb.dtb \
|
|
imx6ull-14x14-evk-reve-emmc.dtb \
|
|
imx6ull-14x14-evk-reve-btwifi.dtb \
|
|
imx6ull-14x14-evk-reve-gpmi-weim.dtb \
|
|
diff --git a/arch/arm/boot/dts/nxp/imx/imx6ul-14x14-evk-ecat.dts b/arch/arm/boot/dts/nxp/imx/imx6ul-14x14-evk-ecat.dts
|
|
new file mode 100644
|
|
index 000000000000..2a99ab3960f1
|
|
--- /dev/null
|
|
+++ b/arch/arm/boot/dts/nxp/imx/imx6ul-14x14-evk-ecat.dts
|
|
@@ -0,0 +1,11 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx6ul-14x14-evk.dts"
|
|
+
|
|
+
|
|
+&fec1 {
|
|
+ compatible = "fsl,imx6ul-fec-ecat", "fsl,imx6q-fec-ecat";
|
|
+};
|
|
diff --git a/arch/arm/boot/dts/nxp/imx/imx6ul-14x14-evk-igh.dts b/arch/arm/boot/dts/nxp/imx/imx6ul-14x14-evk-igh.dts
|
|
new file mode 100644
|
|
index 000000000000..01b4bc6b4fa7
|
|
--- /dev/null
|
|
+++ b/arch/arm/boot/dts/nxp/imx/imx6ul-14x14-evk-igh.dts
|
|
@@ -0,0 +1,11 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx6ul-14x14-evk.dts"
|
|
+
|
|
+
|
|
+&fec1 {
|
|
+ compatible = "fsl,imx6ul-fec-igh-native", "fsl,imx6q-fec-igh-native";
|
|
+};
|
|
diff --git a/arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-avb-mcr.dts b/arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-avb-mcr.dts
|
|
new file mode 100644
|
|
index 000000000000..e06167bd96bc
|
|
--- /dev/null
|
|
+++ b/arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-avb-mcr.dts
|
|
@@ -0,0 +1,59 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+//
|
|
+// Copyright 2022 NXP
|
|
+
|
|
+#include "imx6ull-14x14-evk-avb.dts"
|
|
+
|
|
+/******************************************************************************************
|
|
+* This dts adds the media clock recovery capability for AVB to the imx6ull-14x14-evk board.
|
|
+* A hardware rework is necessary for this feature:
|
|
+* -connect SD1_DATA2 and GPIO1_IO05 pads (can be done by connecting R1728 and TP2120)
|
|
+* -connect JTAG_MOD and JTAG_TMS (SAI2_MCLK) pads (can be done by connecting R1023 and
|
|
+* JTAG pin number 7)
|
|
+*
|
|
+* Warning: this will prevent using SD1 Slot.
|
|
+*******************************************************************************************/
|
|
+
|
|
+&iomuxc {
|
|
+ pinctrl_avb: avbgrp {
|
|
+ fsl,pins = <
|
|
+ MX6UL_PAD_SD1_DATA2__GPT2_CAPTURE1 0x110b0
|
|
+ MX6UL_PAD_GPIO1_IO05__ENET2_1588_EVENT0_OUT 0x88
|
|
+ MX6UL_PAD_JTAG_MOD__GPT2_CLK 0x1f0b0
|
|
+ >;
|
|
+ };
|
|
+};
|
|
+
|
|
+/* AVB MCR timer */
|
|
+&gpt2 {
|
|
+ compatible = "fsl,avb-gpt";
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&pinctrl_avb>;
|
|
+ prescale = <1>;
|
|
+
|
|
+ rec-channel = <1 0 0>; /* capture channel, eth port, ENET TC id */
|
|
+ domain = <0>;
|
|
+
|
|
+ clocks = <&clks IMX6UL_CLK_GPT2_BUS>, <&clks IMX6UL_CLK_GPT2_SERIAL>,
|
|
+ <&clks IMX6UL_CLK_SAI2>, <&clks IMX6UL_CLK_PLL4>;
|
|
+ clock-names = "ipg", "per", "clk_in", "audio_pll";
|
|
+
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+/* Pin conflict on GPIO1_IO05 */
|
|
+&usdhc1 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+/* Set PERCLK parent to IPG to make sure that GPT_CLK set above is lower
|
|
+ * than 1/4 of frequency of the peripheral clock
|
|
+ * (Keep previsouly set, from included dts files, clocks in the node)
|
|
+ */
|
|
+&clks {
|
|
+ assigned-clocks = <&clks IMX6UL_CLK_PERCLK_SEL>,
|
|
+ <&clks IMX6UL_CLK_PLL3_PFD2>,
|
|
+ <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
|
|
+ assigned-clock-parents = <&clks IMX6UL_CLK_IPG>;
|
|
+ assigned-clock-rates = <0>, <320000000>, <786432000>;
|
|
+};
|
|
diff --git a/arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-avb.dts b/arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-avb.dts
|
|
new file mode 100644
|
|
index 000000000000..09af5531b3e0
|
|
--- /dev/null
|
|
+++ b/arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-avb.dts
|
|
@@ -0,0 +1,29 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+//
|
|
+// Copyright 2018 NXP
|
|
+
|
|
+#include "imx6ull-14x14-evk.dts"
|
|
+
|
|
+/* AVB HW timer*/
|
|
+&epit1 {
|
|
+ compatible = "fsl,avb-epit";
|
|
+ clocks = <&clks IMX6UL_CLK_EPIT1>;
|
|
+ clock-names = "epit1";
|
|
+
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&fec1 {
|
|
+ fsl,rx-phy-delay-100-ns = <670>;
|
|
+ fsl,tx-phy-delay-100-ns = <670>;
|
|
+ fsl,rx-phy-delay-1000-ns = <0>;
|
|
+ fsl,tx-phy-delay-1000-ns = <0>;
|
|
+};
|
|
+
|
|
+&fec2 {
|
|
+ fsl,rx-phy-delay-100-ns = <670>;
|
|
+ fsl,tx-phy-delay-100-ns = <670>;
|
|
+ fsl,rx-phy-delay-1000-ns = <0>;
|
|
+ fsl,tx-phy-delay-1000-ns = <0>;
|
|
+};
|
|
+
|
|
diff --git a/arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-ecat.dts b/arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-ecat.dts
|
|
new file mode 100644
|
|
index 000000000000..67df18babf56
|
|
--- /dev/null
|
|
+++ b/arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-ecat.dts
|
|
@@ -0,0 +1,11 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx6ull-14x14-evk.dts"
|
|
+
|
|
+
|
|
+&fec1 {
|
|
+ compatible = "fsl,imx6ul-fec-ecat", "fsl,imx6q-fec-ecat";
|
|
+};
|
|
diff --git a/arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-igh.dts b/arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-igh.dts
|
|
new file mode 100644
|
|
index 000000000000..5eabf5eab1ab
|
|
--- /dev/null
|
|
+++ b/arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-igh.dts
|
|
@@ -0,0 +1,11 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx6ull-14x14-evk.dts"
|
|
+
|
|
+
|
|
+&fec1 {
|
|
+ compatible = "fsl,imx6ul-fec-igh-native", "fsl,imx6q-fec-igh-native";
|
|
+};
|
|
diff --git a/arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-lpuart.dts b/arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-lpuart.dts
|
|
new file mode 100644
|
|
index 000000000000..d7a378c5349c
|
|
--- /dev/null
|
|
+++ b/arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-lpuart.dts
|
|
@@ -0,0 +1,25 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx6ull-14x14-evk.dts"
|
|
+
|
|
+/* Unbind lpuart2 from Bluetooth, use it for lpuart test. */
|
|
+&uart2 {
|
|
+ /delete-node/ bluetooth;
|
|
+};
|
|
+
|
|
+/*
|
|
+ * uart test port1. Note: don't use Bluetooth at the sametime.
|
|
+ * J1703: Pin1--RX Pin2--TX
|
|
+ */
|
|
+&pinctrl_uart2 {
|
|
+ fsl,pins = <
|
|
+ MX6UL_PAD_UART2_TX_DATA__UART2_DCE_TX 0x1b0b1
|
|
+ MX6UL_PAD_UART2_RX_DATA__UART2_DCE_RX 0x1b0b1
|
|
+ MX6UL_PAD_UART3_RX_DATA__UART2_DCE_RTS 0x1b0b1
|
|
+ MX6UL_PAD_UART3_TX_DATA__UART2_DCE_CTS 0x1b0b1
|
|
+ >;
|
|
+};
|
|
+
|
|
diff --git a/arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-reve.dtso b/arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-reve.dtso
|
|
new file mode 100644
|
|
index 000000000000..e135f3f6e17b
|
|
--- /dev/null
|
|
+++ b/arch/arm/boot/dts/nxp/imx/imx6ull-14x14-evk-reve.dtso
|
|
@@ -0,0 +1,11 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+/plugin/;
|
|
+
|
|
+&{/} {
|
|
+ model = "Freescale i.MX6 ULL 14x14 RevE EVK Board";
|
|
+};
|
|
diff --git a/arch/arm/boot/dts/nxp/ls/Makefile b/arch/arm/boot/dts/nxp/ls/Makefile
|
|
index 14759331dba2..766e8dbce535 100644
|
|
--- a/arch/arm/boot/dts/nxp/ls/Makefile
|
|
+++ b/arch/arm/boot/dts/nxp/ls/Makefile
|
|
@@ -5,4 +5,5 @@ dtb-$(CONFIG_SOC_LS1021A) += \
|
|
ls1021a-qds.dtb \
|
|
ls1021a-tqmls1021a-mbls1021a.dtb \
|
|
ls1021a-tsn.dtb \
|
|
- ls1021a-twr.dtb
|
|
+ ls1021a-twr.dtb \
|
|
+ ls1021a-iot.dtb
|
|
diff --git a/arch/arm/boot/dts/nxp/ls/ls1021a-iot-bm.dts b/arch/arm/boot/dts/nxp/ls/ls1021a-iot-bm.dts
|
|
new file mode 100644
|
|
index 000000000000..3a23b97f0081
|
|
--- /dev/null
|
|
+++ b/arch/arm/boot/dts/nxp/ls/ls1021a-iot-bm.dts
|
|
@@ -0,0 +1,259 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * DTS file for NXP Layerscape baremetal
|
|
+ *
|
|
+ * Copyright 2018-2023 NXP
|
|
+ *
|
|
+ * Author: Changming Huang <jerry.huang@nxp.com>
|
|
+ *
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "ls1021a.dtsi"
|
|
+
|
|
+/ {
|
|
+ model = "LS1021A IOT Board";
|
|
+
|
|
+ sys_mclk: clock-mclk {
|
|
+ compatible = "fixed-clock";
|
|
+ #clock-cells = <0>;
|
|
+ clock-frequency = <24576000>;
|
|
+ };
|
|
+
|
|
+ regulators {
|
|
+ compatible = "simple-bus";
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ reg_3p3v: regulator@0 {
|
|
+ compatible = "regulator-fixed";
|
|
+ reg = <0>;
|
|
+ regulator-name = "3P3V";
|
|
+ regulator-min-microvolt = <3300000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ reg_2p5v: regulator@1 {
|
|
+ compatible = "regulator-fixed";
|
|
+ reg = <1>;
|
|
+ regulator-name = "2P5V";
|
|
+ regulator-min-microvolt = <2500000>;
|
|
+ regulator-max-microvolt = <2500000>;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ sound {
|
|
+ compatible = "simple-audio-card";
|
|
+ simple-audio-card,format = "i2s";
|
|
+ simple-audio-card,widgets =
|
|
+ "Microphone", "Microphone Jack",
|
|
+ "Headphone", "Headphone Jack",
|
|
+ "Speaker", "Speaker Ext",
|
|
+ "Line", "Line In Jack";
|
|
+ simple-audio-card,routing =
|
|
+ "MIC_IN", "Microphone Jack",
|
|
+ "Microphone Jack", "Mic Bias",
|
|
+ "LINE_IN", "Line In Jack",
|
|
+ "Headphone Jack", "HP_OUT",
|
|
+ "Speaker Ext", "LINE_OUT";
|
|
+
|
|
+ simple-audio-card,cpu {
|
|
+ sound-dai = <&sai2>;
|
|
+ frame-master;
|
|
+ bitclock-master;
|
|
+ };
|
|
+
|
|
+ simple-audio-card,codec {
|
|
+ sound-dai = <&codec>;
|
|
+ frame-master;
|
|
+ bitclock-master;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ firmware {
|
|
+ optee {
|
|
+ compatible = "linaro,optee-tz";
|
|
+ method = "smc";
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&enet0 {
|
|
+ tbi-handle = <&tbi1>;
|
|
+ phy-handle = <&phy1>;
|
|
+ phy-connection-type = "sgmii";
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&enet1 {
|
|
+ tbi-handle = <&tbi1>;
|
|
+ phy-handle = <&phy3>;
|
|
+ phy-connection-type = "sgmii";
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&enet2 {
|
|
+ fixed-link = <0 1 1000 0 0>;
|
|
+ phy-connection-type = "rgmii-id";
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&can0{
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&can1{
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&can2{
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&can3{
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&esdhc{
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&i2c0 {
|
|
+ status = "okay";
|
|
+
|
|
+ max1239@35 {
|
|
+ compatible = "maxim,max1239";
|
|
+ reg = <0x35>;
|
|
+ #io-channel-cells = <1>;
|
|
+ };
|
|
+
|
|
+ codec: sgtl5000@2a {
|
|
+ #sound-dai-cells=<0x0>;
|
|
+ compatible = "fsl,sgtl5000";
|
|
+ reg = <0x2a>;
|
|
+ VDDA-supply = <®_3p3v>;
|
|
+ VDDIO-supply = <®_2p5v>;
|
|
+ clocks = <&sys_mclk 1>;
|
|
+ };
|
|
+
|
|
+ pca9555: pca9555@23 {
|
|
+ compatible = "nxp,pca9555";
|
|
+ gpio-controller;
|
|
+ #gpio-cells = <2>;
|
|
+ interrupt-controller;
|
|
+ #interrupt-cells = <2>;
|
|
+ reg = <0x23>;
|
|
+ };
|
|
+
|
|
+ ina220@44 {
|
|
+ compatible = "ti,ina220";
|
|
+ reg = <0x44>;
|
|
+ shunt-resistor = <1000>;
|
|
+ };
|
|
+
|
|
+ ina220@45 {
|
|
+ compatible = "ti,ina220";
|
|
+ reg = <0x45>;
|
|
+ shunt-resistor = <1000>;
|
|
+ };
|
|
+
|
|
+ lm75b@48 {
|
|
+ compatible = "nxp,lm75a";
|
|
+ reg = <0x48>;
|
|
+ };
|
|
+
|
|
+ adt7461a@4c {
|
|
+ compatible = "adt7461a";
|
|
+ reg = <0x4c>;
|
|
+ };
|
|
+
|
|
+ hdmi: sii9022a@39 {
|
|
+ compatible = "fsl,sii902x";
|
|
+ reg = <0x39>;
|
|
+ interrupts = <GIC_SPI 163 IRQ_TYPE_EDGE_RISING>;
|
|
+ };
|
|
+};
|
|
+
|
|
+&i2c1 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&ifc {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&lpuart0 {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&mdio0 {
|
|
+ phy0: ethernet-phy@0 {
|
|
+ reg = <0x0>;
|
|
+ };
|
|
+ phy1: ethernet-phy@1 {
|
|
+ reg = <0x1>;
|
|
+ };
|
|
+ phy2: ethernet-phy@2 {
|
|
+ reg = <0x2>;
|
|
+ };
|
|
+ phy3: ethernet-phy@3 {
|
|
+ reg = <0x3>;
|
|
+ };
|
|
+ tbi1: tbi-phy@1f {
|
|
+ reg = <0x1f>;
|
|
+ device_type = "tbi-phy";
|
|
+ };
|
|
+};
|
|
+
|
|
+&sai2 {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&uart0 {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&uart1 {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&dcu {
|
|
+ display = <&display>;
|
|
+ status = "okay";
|
|
+
|
|
+ display: display@0 {
|
|
+ bits-per-pixel = <24>;
|
|
+
|
|
+ display-timings {
|
|
+ native-mode = <&timing0>;
|
|
+
|
|
+ timing0: mode0 {
|
|
+ clock-frequency = <25000000>;
|
|
+ hactive = <640>;
|
|
+ vactive = <480>;
|
|
+ hback-porch = <80>;
|
|
+ hfront-porch = <80>;
|
|
+ vback-porch = <16>;
|
|
+ vfront-porch = <16>;
|
|
+ hsync-len = <12>;
|
|
+ vsync-len = <2>;
|
|
+ hsync-active = <1>;
|
|
+ vsync-active = <1>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&usb3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&pcie1 {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&pcie2 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm/boot/dts/nxp/ls/ls1021a.dtsi b/arch/arm/boot/dts/nxp/ls/ls1021a.dtsi
|
|
index cd0d699985c6..f1657b7c6e8b 100644
|
|
--- a/arch/arm/boot/dts/nxp/ls/ls1021a.dtsi
|
|
+++ b/arch/arm/boot/dts/nxp/ls/ls1021a.dtsi
|
|
@@ -815,7 +815,7 @@ usb3: usb@3100000 {
|
|
snps,host-vbus-glitches;
|
|
};
|
|
|
|
- pcie@3400000 {
|
|
+ pcie1: pcie@3400000 {
|
|
compatible = "fsl,ls1021a-pcie";
|
|
reg = <0x00 0x03400000 0x0 0x00010000>, /* controller registers */
|
|
<0x40 0x00000000 0x0 0x00002000>; /* configuration space */
|
|
@@ -841,7 +841,7 @@ pcie@3400000 {
|
|
status = "disabled";
|
|
};
|
|
|
|
- pcie@3500000 {
|
|
+ pcie2: pcie@3500000 {
|
|
compatible = "fsl,ls1021a-pcie";
|
|
reg = <0x00 0x03500000 0x0 0x00010000>, /* controller registers */
|
|
<0x48 0x00000000 0x0 0x00002000>; /* configuration space */
|
|
diff --git a/arch/arm/configs/imx6ullevk-plc.config b/arch/arm/configs/imx6ullevk-plc.config
|
|
new file mode 100644
|
|
index 000000000000..7a309a93b547
|
|
--- /dev/null
|
|
+++ b/arch/arm/configs/imx6ullevk-plc.config
|
|
@@ -0,0 +1,3333 @@
|
|
+#
|
|
+# General setup
|
|
+#
|
|
+CONFIG_BROKEN_ON_SMP=y
|
|
+CONFIG_INIT_ENV_ARG_LIMIT=32
|
|
+# CONFIG_COMPILE_TEST is not set
|
|
+# CONFIG_WERROR is not set
|
|
+CONFIG_LOCALVERSION=""
|
|
+CONFIG_LOCALVERSION_AUTO=y
|
|
+CONFIG_BUILD_SALT=""
|
|
+CONFIG_HAVE_KERNEL_GZIP=y
|
|
+CONFIG_HAVE_KERNEL_LZMA=y
|
|
+CONFIG_HAVE_KERNEL_XZ=y
|
|
+CONFIG_HAVE_KERNEL_LZO=y
|
|
+CONFIG_HAVE_KERNEL_LZ4=y
|
|
+# CONFIG_KERNEL_GZIP is not set
|
|
+# CONFIG_KERNEL_LZMA is not set
|
|
+# CONFIG_KERNEL_XZ is not set
|
|
+CONFIG_KERNEL_LZO=y
|
|
+# CONFIG_KERNEL_LZ4 is not set
|
|
+CONFIG_DEFAULT_INIT=""
|
|
+CONFIG_DEFAULT_HOSTNAME="(none)"
|
|
+# CONFIG_SWAP is not set
|
|
+CONFIG_SYSVIPC=y
|
|
+CONFIG_SYSVIPC_SYSCTL=y
|
|
+CONFIG_POSIX_MQUEUE=y
|
|
+CONFIG_POSIX_MQUEUE_SYSCTL=y
|
|
+# CONFIG_WATCH_QUEUE is not set
|
|
+CONFIG_CROSS_MEMORY_ATTACH=y
|
|
+# CONFIG_USELIB is not set
|
|
+# CONFIG_AUDIT is not set
|
|
+CONFIG_HAVE_ARCH_AUDITSYSCALL=y
|
|
+
|
|
+#
|
|
+# IRQ subsystem
|
|
+#
|
|
+CONFIG_GENERIC_IRQ_PROBE=y
|
|
+CONFIG_GENERIC_IRQ_SHOW=y
|
|
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
|
|
+CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
|
|
+CONFIG_HARDIRQS_SW_RESEND=y
|
|
+CONFIG_GENERIC_IRQ_CHIP=y
|
|
+CONFIG_IRQ_DOMAIN=y
|
|
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
|
|
+CONFIG_HANDLE_DOMAIN_IRQ=y
|
|
+CONFIG_IRQ_FORCED_THREADING=y
|
|
+CONFIG_SPARSE_IRQ=y
|
|
+# end of IRQ subsystem
|
|
+
|
|
+CONFIG_GENERIC_IRQ_MULTI_HANDLER=y
|
|
+CONFIG_GENERIC_TIME_VSYSCALL=y
|
|
+CONFIG_GENERIC_CLOCKEVENTS=y
|
|
+CONFIG_HAVE_POSIX_CPU_TIMERS_TASK_WORK=y
|
|
+CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y
|
|
+
|
|
+#
|
|
+# Timers subsystem
|
|
+#
|
|
+CONFIG_TICK_ONESHOT=y
|
|
+CONFIG_NO_HZ_COMMON=y
|
|
+# CONFIG_HZ_PERIODIC is not set
|
|
+CONFIG_NO_HZ_IDLE=y
|
|
+# CONFIG_NO_HZ is not set
|
|
+CONFIG_HIGH_RES_TIMERS=y
|
|
+# end of Timers subsystem
|
|
+
|
|
+CONFIG_BPF=y
|
|
+CONFIG_HAVE_EBPF_JIT=y
|
|
+
|
|
+#
|
|
+# BPF subsystem
|
|
+#
|
|
+# CONFIG_BPF_SYSCALL is not set
|
|
+# CONFIG_BPF_JIT is not set
|
|
+# end of BPF subsystem
|
|
+
|
|
+CONFIG_HAVE_PREEMPT_LAZY=y
|
|
+CONFIG_PREEMPT_LAZY=y
|
|
+# CONFIG_PREEMPT_NONE is not set
|
|
+# CONFIG_PREEMPT_VOLUNTARY is not set
|
|
+# CONFIG_PREEMPT is not set
|
|
+CONFIG_PREEMPT_RT=y
|
|
+CONFIG_PREEMPT_COUNT=y
|
|
+CONFIG_PREEMPTION=y
|
|
+
|
|
+#
|
|
+# CPU/Task time and stats accounting
|
|
+#
|
|
+CONFIG_TICK_CPU_ACCOUNTING=y
|
|
+# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
|
|
+# CONFIG_IRQ_TIME_ACCOUNTING is not set
|
|
+# CONFIG_BSD_PROCESS_ACCT is not set
|
|
+# CONFIG_TASKSTATS is not set
|
|
+# CONFIG_PSI is not set
|
|
+# end of CPU/Task time and stats accounting
|
|
+
|
|
+#
|
|
+# RCU Subsystem
|
|
+#
|
|
+CONFIG_TREE_RCU=y
|
|
+CONFIG_PREEMPT_RCU=y
|
|
+# CONFIG_RCU_EXPERT is not set
|
|
+CONFIG_SRCU=y
|
|
+CONFIG_TREE_SRCU=y
|
|
+CONFIG_TASKS_RCU_GENERIC=y
|
|
+CONFIG_TASKS_RCU=y
|
|
+CONFIG_RCU_STALL_COMMON=y
|
|
+CONFIG_RCU_NEED_SEGCBLIST=y
|
|
+CONFIG_RCU_BOOST=y
|
|
+CONFIG_RCU_BOOST_DELAY=500
|
|
+# end of RCU Subsystem
|
|
+
|
|
+CONFIG_IKCONFIG=y
|
|
+CONFIG_IKCONFIG_PROC=y
|
|
+# CONFIG_IKHEADERS is not set
|
|
+CONFIG_LOG_BUF_SHIFT=18
|
|
+CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13
|
|
+CONFIG_GENERIC_SCHED_CLOCK=y
|
|
+
|
|
+#
|
|
+# Scheduler features
|
|
+#
|
|
+# end of Scheduler features
|
|
+
|
|
+# CONFIG_CGROUPS is not set
|
|
+CONFIG_NAMESPACES=y
|
|
+# CONFIG_UTS_NS is not set
|
|
+# CONFIG_IPC_NS is not set
|
|
+# CONFIG_USER_NS is not set
|
|
+# CONFIG_PID_NS is not set
|
|
+# CONFIG_NET_NS is not set
|
|
+# CONFIG_CHECKPOINT_RESTORE is not set
|
|
+# CONFIG_SCHED_AUTOGROUP is not set
|
|
+# CONFIG_SYSFS_DEPRECATED is not set
|
|
+CONFIG_RELAY=y
|
|
+# CONFIG_BLK_DEV_INITRD is not set
|
|
+# CONFIG_BOOT_CONFIG is not set
|
|
+CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
|
|
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
|
|
+CONFIG_LD_ORPHAN_WARN=y
|
|
+CONFIG_SYSCTL=y
|
|
+CONFIG_HAVE_UID16=y
|
|
+CONFIG_EXPERT=y
|
|
+CONFIG_UID16=y
|
|
+CONFIG_MULTIUSER=y
|
|
+# CONFIG_SGETMASK_SYSCALL is not set
|
|
+CONFIG_SYSFS_SYSCALL=y
|
|
+CONFIG_FHANDLE=y
|
|
+CONFIG_POSIX_TIMERS=y
|
|
+CONFIG_PRINTK=y
|
|
+CONFIG_BUG=y
|
|
+CONFIG_ELF_CORE=y
|
|
+CONFIG_BASE_FULL=y
|
|
+CONFIG_FUTEX=y
|
|
+CONFIG_FUTEX_PI=y
|
|
+CONFIG_HAVE_FUTEX_CMPXCHG=y
|
|
+CONFIG_EPOLL=y
|
|
+CONFIG_SIGNALFD=y
|
|
+CONFIG_TIMERFD=y
|
|
+CONFIG_EVENTFD=y
|
|
+CONFIG_SHMEM=y
|
|
+CONFIG_AIO=y
|
|
+CONFIG_IO_URING=y
|
|
+CONFIG_ADVISE_SYSCALLS=y
|
|
+CONFIG_MEMBARRIER=y
|
|
+CONFIG_KALLSYMS=y
|
|
+# CONFIG_KALLSYMS_ALL is not set
|
|
+CONFIG_KALLSYMS_BASE_RELATIVE=y
|
|
+# CONFIG_USERFAULTFD is not set
|
|
+CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
|
|
+CONFIG_KCMP=y
|
|
+CONFIG_RSEQ=y
|
|
+# CONFIG_DEBUG_RSEQ is not set
|
|
+CONFIG_EMBEDDED=y
|
|
+CONFIG_HAVE_PERF_EVENTS=y
|
|
+CONFIG_PERF_USE_VMALLOC=y
|
|
+# CONFIG_PC104 is not set
|
|
+
|
|
+#
|
|
+# Kernel Performance Events And Counters
|
|
+#
|
|
+# CONFIG_PERF_EVENTS is not set
|
|
+# end of Kernel Performance Events And Counters
|
|
+
|
|
+# CONFIG_VM_EVENT_COUNTERS is not set
|
|
+# CONFIG_SLUB_DEBUG is not set
|
|
+# CONFIG_COMPAT_BRK is not set
|
|
+CONFIG_SLUB=y
|
|
+# CONFIG_SLAB_MERGE_DEFAULT is not set
|
|
+# CONFIG_SLAB_FREELIST_RANDOM is not set
|
|
+# CONFIG_SLAB_FREELIST_HARDENED is not set
|
|
+# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set
|
|
+# CONFIG_PROFILING is not set
|
|
+# end of General setup
|
|
+
|
|
+CONFIG_ARM=y
|
|
+CONFIG_ARM_HAS_SG_CHAIN=y
|
|
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
|
|
+CONFIG_HAVE_PROC_CPU=y
|
|
+CONFIG_STACKTRACE_SUPPORT=y
|
|
+CONFIG_LOCKDEP_SUPPORT=y
|
|
+CONFIG_FIX_EARLYCON_MEM=y
|
|
+CONFIG_GENERIC_HWEIGHT=y
|
|
+CONFIG_GENERIC_CALIBRATE_DELAY=y
|
|
+CONFIG_ARCH_SUPPORTS_UPROBES=y
|
|
+CONFIG_ARM_PATCH_PHYS_VIRT=y
|
|
+CONFIG_GENERIC_BUG=y
|
|
+CONFIG_PGTABLE_LEVELS=2
|
|
+
|
|
+#
|
|
+# System Type
|
|
+#
|
|
+CONFIG_MMU=y
|
|
+CONFIG_ARCH_MMAP_RND_BITS_MIN=8
|
|
+CONFIG_ARCH_MMAP_RND_BITS_MAX=15
|
|
+CONFIG_ARCH_MULTIPLATFORM=y
|
|
+# CONFIG_ARCH_EP93XX is not set
|
|
+# CONFIG_ARCH_FOOTBRIDGE is not set
|
|
+# CONFIG_ARCH_IOP32X is not set
|
|
+# CONFIG_ARCH_IXP4XX is not set
|
|
+# CONFIG_ARCH_DOVE is not set
|
|
+# CONFIG_ARCH_PXA is not set
|
|
+# CONFIG_ARCH_RPC is not set
|
|
+# CONFIG_ARCH_SA1100 is not set
|
|
+# CONFIG_ARCH_S3C24XX is not set
|
|
+# CONFIG_ARCH_OMAP1 is not set
|
|
+
|
|
+#
|
|
+# Multiple platform selection
|
|
+#
|
|
+
|
|
+#
|
|
+# CPU Core family selection
|
|
+#
|
|
+# CONFIG_ARCH_MULTI_V6 is not set
|
|
+CONFIG_ARCH_MULTI_V7=y
|
|
+CONFIG_ARCH_MULTI_V6_V7=y
|
|
+# end of Multiple platform selection
|
|
+
|
|
+# CONFIG_ARCH_VIRT is not set
|
|
+# CONFIG_ARCH_ACTIONS is not set
|
|
+# CONFIG_ARCH_ALPINE is not set
|
|
+# CONFIG_ARCH_ARTPEC is not set
|
|
+# CONFIG_ARCH_ASPEED is not set
|
|
+# CONFIG_ARCH_AT91 is not set
|
|
+# CONFIG_ARCH_BCM is not set
|
|
+# CONFIG_ARCH_BERLIN is not set
|
|
+# CONFIG_ARCH_DIGICOLOR is not set
|
|
+# CONFIG_ARCH_EXYNOS is not set
|
|
+# CONFIG_ARCH_HIGHBANK is not set
|
|
+# CONFIG_ARCH_HISI is not set
|
|
+CONFIG_ARCH_MXC=y
|
|
+CONFIG_HAVE_IMX_ANATOP=y
|
|
+CONFIG_HAVE_IMX_GPC=y
|
|
+CONFIG_HAVE_IMX_GPCV2=y
|
|
+CONFIG_HAVE_IMX_MMDC=y
|
|
+CONFIG_HAVE_IMX_AMP=y
|
|
+CONFIG_HAVE_IMX_DDRC=y
|
|
+CONFIG_HAVE_IMX_BUSFREQ=y
|
|
+CONFIG_HAVE_IMX_MU=y
|
|
+CONFIG_HAVE_IMX_RPMSG=y
|
|
+CONFIG_HAVE_IMX_SRC=y
|
|
+
|
|
+#
|
|
+# Cortex-A platforms
|
|
+#
|
|
+# CONFIG_SOC_IMX50 is not set
|
|
+# CONFIG_SOC_IMX51 is not set
|
|
+# CONFIG_SOC_IMX53 is not set
|
|
+CONFIG_SOC_IMX6=y
|
|
+CONFIG_SOC_IMX6Q=y
|
|
+CONFIG_SOC_IMX6SL=y
|
|
+CONFIG_SOC_IMX6SLL=y
|
|
+CONFIG_SOC_IMX6SX=y
|
|
+CONFIG_SOC_IMX6UL=y
|
|
+# CONFIG_SOC_LS1021A is not set
|
|
+# CONFIG_SOC_IMX6Q_BAREMETAL is not set
|
|
+
|
|
+#
|
|
+# Cortex-A/Cortex-M asymmetric multiprocessing platforms
|
|
+#
|
|
+CONFIG_SOC_IMX7D_CA7=y
|
|
+CONFIG_SOC_IMX7D=y
|
|
+# CONFIG_SOC_IMX7ULP is not set
|
|
+# CONFIG_SOC_VF610 is not set
|
|
+# CONFIG_ARCH_KEYSTONE is not set
|
|
+# CONFIG_ARCH_MEDIATEK is not set
|
|
+# CONFIG_ARCH_MESON is not set
|
|
+# CONFIG_ARCH_MILBEAUT is not set
|
|
+# CONFIG_ARCH_MMP is not set
|
|
+# CONFIG_ARCH_MSTARV7 is not set
|
|
+# CONFIG_ARCH_MVEBU is not set
|
|
+# CONFIG_ARCH_NPCM is not set
|
|
+
|
|
+#
|
|
+# TI OMAP/AM/DM/DRA Family
|
|
+#
|
|
+# CONFIG_ARCH_OMAP3 is not set
|
|
+# CONFIG_ARCH_OMAP4 is not set
|
|
+# CONFIG_SOC_OMAP5 is not set
|
|
+# CONFIG_SOC_AM33XX is not set
|
|
+# CONFIG_SOC_AM43XX is not set
|
|
+# CONFIG_SOC_DRA7XX is not set
|
|
+# end of TI OMAP/AM/DM/DRA Family
|
|
+
|
|
+# CONFIG_ARCH_QCOM is not set
|
|
+# CONFIG_ARCH_RDA is not set
|
|
+# CONFIG_ARCH_REALTEK is not set
|
|
+# CONFIG_ARCH_REALVIEW is not set
|
|
+# CONFIG_ARCH_ROCKCHIP is not set
|
|
+# CONFIG_ARCH_S5PV210 is not set
|
|
+# CONFIG_ARCH_RENESAS is not set
|
|
+# CONFIG_ARCH_INTEL_SOCFPGA is not set
|
|
+# CONFIG_PLAT_SPEAR is not set
|
|
+# CONFIG_ARCH_STI is not set
|
|
+# CONFIG_ARCH_STM32 is not set
|
|
+# CONFIG_ARCH_SUNXI is not set
|
|
+# CONFIG_ARCH_TEGRA is not set
|
|
+# CONFIG_ARCH_UNIPHIER is not set
|
|
+# CONFIG_ARCH_U8500 is not set
|
|
+# CONFIG_ARCH_VEXPRESS is not set
|
|
+# CONFIG_ARCH_WM8850 is not set
|
|
+# CONFIG_ARCH_ZYNQ is not set
|
|
+
|
|
+#
|
|
+# Processor Type
|
|
+#
|
|
+CONFIG_CPU_V7=y
|
|
+CONFIG_CPU_THUMB_CAPABLE=y
|
|
+CONFIG_CPU_32v6K=y
|
|
+CONFIG_CPU_32v7=y
|
|
+CONFIG_CPU_ABRT_EV7=y
|
|
+CONFIG_CPU_PABRT_V7=y
|
|
+CONFIG_CPU_CACHE_V7=y
|
|
+CONFIG_CPU_CACHE_VIPT=y
|
|
+CONFIG_CPU_COPY_V6=y
|
|
+CONFIG_CPU_TLB_V7=y
|
|
+CONFIG_CPU_HAS_ASID=y
|
|
+CONFIG_CPU_CP15=y
|
|
+CONFIG_CPU_CP15_MMU=y
|
|
+
|
|
+#
|
|
+# Processor Features
|
|
+#
|
|
+# CONFIG_ARM_LPAE is not set
|
|
+CONFIG_ARM_THUMB=y
|
|
+# CONFIG_ARM_THUMBEE is not set
|
|
+CONFIG_ARM_VIRT_EXT=y
|
|
+# CONFIG_SWP_EMULATE is not set
|
|
+# CONFIG_CPU_BIG_ENDIAN is not set
|
|
+# CONFIG_CPU_ICACHE_DISABLE is not set
|
|
+# CONFIG_CPU_DCACHE_DISABLE is not set
|
|
+# CONFIG_CPU_BPREDICT_DISABLE is not set
|
|
+CONFIG_CPU_SPECTRE=y
|
|
+CONFIG_HARDEN_BRANCH_PREDICTOR=y
|
|
+CONFIG_HARDEN_BRANCH_HISTORY=y
|
|
+CONFIG_KUSER_HELPERS=y
|
|
+CONFIG_VDSO=y
|
|
+CONFIG_OUTER_CACHE=y
|
|
+CONFIG_OUTER_CACHE_SYNC=y
|
|
+CONFIG_MIGHT_HAVE_CACHE_L2X0=y
|
|
+CONFIG_CACHE_L2X0=y
|
|
+# CONFIG_PL310_ERRATA_588369 is not set
|
|
+# CONFIG_PL310_ERRATA_727915 is not set
|
|
+# CONFIG_PL310_ERRATA_753970 is not set
|
|
+CONFIG_PL310_ERRATA_769419=y
|
|
+CONFIG_ARM_L1_CACHE_SHIFT_6=y
|
|
+CONFIG_ARM_L1_CACHE_SHIFT=6
|
|
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
|
|
+CONFIG_ARM_HEAVY_MB=y
|
|
+CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
|
|
+# CONFIG_DEBUG_ALIGN_RODATA is not set
|
|
+# CONFIG_ARM_ERRATA_430973 is not set
|
|
+# CONFIG_ARM_ERRATA_720789 is not set
|
|
+CONFIG_ARM_ERRATA_754322=y
|
|
+CONFIG_ARM_ERRATA_775420=y
|
|
+# CONFIG_ARM_ERRATA_773022 is not set
|
|
+# CONFIG_ARM_ERRATA_818325_852422 is not set
|
|
+# CONFIG_ARM_ERRATA_821420 is not set
|
|
+# CONFIG_ARM_ERRATA_825619 is not set
|
|
+# CONFIG_ARM_ERRATA_857271 is not set
|
|
+# CONFIG_ARM_ERRATA_852421 is not set
|
|
+# CONFIG_ARM_ERRATA_852423 is not set
|
|
+# CONFIG_ARM_ERRATA_857272 is not set
|
|
+# end of System Type
|
|
+
|
|
+#
|
|
+# Bus support
|
|
+#
|
|
+CONFIG_ARM_ERRATA_814220=y
|
|
+# end of Bus support
|
|
+
|
|
+#
|
|
+# Kernel Features
|
|
+#
|
|
+CONFIG_HAVE_SMP=y
|
|
+# CONFIG_SMP is not set
|
|
+CONFIG_HAVE_ARM_ARCH_TIMER=y
|
|
+CONFIG_HAVE_ARM_TWD=y
|
|
+# CONFIG_VMSPLIT_3G is not set
|
|
+# CONFIG_VMSPLIT_3G_OPT is not set
|
|
+CONFIG_VMSPLIT_2G=y
|
|
+# CONFIG_VMSPLIT_1G is not set
|
|
+CONFIG_PAGE_OFFSET=0x80000000
|
|
+CONFIG_ARM_PSCI=y
|
|
+CONFIG_ARCH_NR_GPIO=0
|
|
+CONFIG_HZ_FIXED=0
|
|
+CONFIG_HZ_100=y
|
|
+# CONFIG_HZ_200 is not set
|
|
+# CONFIG_HZ_250 is not set
|
|
+# CONFIG_HZ_300 is not set
|
|
+# CONFIG_HZ_500 is not set
|
|
+# CONFIG_HZ_1000 is not set
|
|
+CONFIG_HZ=100
|
|
+CONFIG_SCHED_HRTICK=y
|
|
+# CONFIG_THUMB2_KERNEL is not set
|
|
+CONFIG_ARM_PATCH_IDIV=y
|
|
+CONFIG_AEABI=y
|
|
+# CONFIG_OABI_COMPAT is not set
|
|
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
|
|
+CONFIG_ARCH_FLATMEM_ENABLE=y
|
|
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
|
|
+# CONFIG_HIGHMEM is not set
|
|
+# CONFIG_CPU_SW_DOMAIN_PAN is not set
|
|
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
|
|
+CONFIG_ARM_MODULE_PLTS=y
|
|
+CONFIG_FORCE_MAX_ZONEORDER=14
|
|
+CONFIG_ALIGNMENT_TRAP=y
|
|
+# CONFIG_UACCESS_WITH_MEMCPY is not set
|
|
+# CONFIG_PARAVIRT is not set
|
|
+# CONFIG_PARAVIRT_TIME_ACCOUNTING is not set
|
|
+# CONFIG_XEN is not set
|
|
+# end of Kernel Features
|
|
+
|
|
+#
|
|
+# Boot options
|
|
+#
|
|
+CONFIG_USE_OF=y
|
|
+CONFIG_ATAGS=y
|
|
+# CONFIG_DEPRECATED_PARAM_STRUCT is not set
|
|
+CONFIG_ZBOOT_ROM_TEXT=0x0
|
|
+CONFIG_ZBOOT_ROM_BSS=0x0
|
|
+# CONFIG_ARM_APPENDED_DTB is not set
|
|
+CONFIG_CMDLINE="noinitrd console=ttymxc0,115200"
|
|
+CONFIG_CMDLINE_FROM_BOOTLOADER=y
|
|
+# CONFIG_CMDLINE_EXTEND is not set
|
|
+# CONFIG_CMDLINE_FORCE is not set
|
|
+# CONFIG_KEXEC is not set
|
|
+# CONFIG_CRASH_DUMP is not set
|
|
+CONFIG_AUTO_ZRELADDR=y
|
|
+# CONFIG_EFI is not set
|
|
+# end of Boot options
|
|
+
|
|
+#
|
|
+# CPU Power Management
|
|
+#
|
|
+
|
|
+#
|
|
+# CPU Frequency scaling
|
|
+#
|
|
+CONFIG_CPU_FREQ=y
|
|
+# CONFIG_CPU_FREQ_STAT is not set
|
|
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
|
|
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
|
|
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
|
|
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
|
|
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
|
|
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
|
|
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
|
|
+# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
|
|
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
|
|
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
|
|
+
|
|
+#
|
|
+# CPU frequency scaling drivers
|
|
+#
|
|
+# CONFIG_CPUFREQ_DT is not set
|
|
+CONFIG_ARM_IMX6Q_CPUFREQ=y
|
|
+# end of CPU Frequency scaling
|
|
+
|
|
+#
|
|
+# CPU Idle
|
|
+#
|
|
+# CONFIG_CPU_IDLE is not set
|
|
+# end of CPU Idle
|
|
+# end of CPU Power Management
|
|
+
|
|
+#
|
|
+# Floating point emulation
|
|
+#
|
|
+
|
|
+#
|
|
+# At least one emulation must be selected
|
|
+#
|
|
+CONFIG_VFP=y
|
|
+CONFIG_VFPv3=y
|
|
+CONFIG_NEON=y
|
|
+CONFIG_KERNEL_MODE_NEON=y
|
|
+# end of Floating point emulation
|
|
+
|
|
+#
|
|
+# Power management options
|
|
+#
|
|
+# CONFIG_SUSPEND is not set
|
|
+# CONFIG_PM is not set
|
|
+# CONFIG_APM_EMULATION is not set
|
|
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
|
+CONFIG_ARM_CPU_SUSPEND=y
|
|
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
|
+# end of Power management options
|
|
+
|
|
+CONFIG_ARM_CRYPTO=y
|
|
+CONFIG_CRYPTO_SHA1_ARM=y
|
|
+# CONFIG_CRYPTO_SHA1_ARM_NEON is not set
|
|
+# CONFIG_CRYPTO_SHA1_ARM_CE is not set
|
|
+# CONFIG_CRYPTO_SHA2_ARM_CE is not set
|
|
+CONFIG_CRYPTO_SHA256_ARM=y
|
|
+CONFIG_CRYPTO_SHA512_ARM=y
|
|
+CONFIG_CRYPTO_BLAKE2S_ARM=y
|
|
+# CONFIG_CRYPTO_BLAKE2B_NEON is not set
|
|
+CONFIG_CRYPTO_AES_ARM=y
|
|
+# CONFIG_CRYPTO_AES_ARM_BS is not set
|
|
+# CONFIG_CRYPTO_AES_ARM_CE is not set
|
|
+# CONFIG_CRYPTO_GHASH_ARM_CE is not set
|
|
+# CONFIG_CRYPTO_CRCT10DIF_ARM_CE is not set
|
|
+# CONFIG_CRYPTO_CRC32_ARM_CE is not set
|
|
+CONFIG_CRYPTO_CHACHA20_NEON=y
|
|
+CONFIG_CRYPTO_POLY1305_ARM=y
|
|
+# CONFIG_CRYPTO_NHPOLY1305_NEON is not set
|
|
+# CONFIG_CRYPTO_CURVE25519_NEON is not set
|
|
+CONFIG_AS_VFP_VMRS_FPINST=y
|
|
+
|
|
+#
|
|
+# General architecture-dependent options
|
|
+#
|
|
+CONFIG_SET_FS=y
|
|
+# CONFIG_KPROBES is not set
|
|
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
|
|
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
|
|
+CONFIG_HAVE_KPROBES=y
|
|
+CONFIG_HAVE_KRETPROBES=y
|
|
+CONFIG_HAVE_OPTPROBES=y
|
|
+CONFIG_HAVE_NMI=y
|
|
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
|
|
+CONFIG_HAVE_ARCH_TRACEHOOK=y
|
|
+CONFIG_HAVE_DMA_CONTIGUOUS=y
|
|
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
|
|
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
|
|
+CONFIG_ARCH_HAS_FORTIFY_SOURCE=y
|
|
+CONFIG_ARCH_HAS_KEEPINITRD=y
|
|
+CONFIG_ARCH_HAS_SET_MEMORY=y
|
|
+CONFIG_HAVE_ARCH_THREAD_STRUCT_WHITELIST=y
|
|
+CONFIG_ARCH_32BIT_OFF_T=y
|
|
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
|
|
+CONFIG_HAVE_RSEQ=y
|
|
+CONFIG_HAVE_PERF_REGS=y
|
|
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
|
|
+CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
|
|
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
|
|
+CONFIG_HAVE_ARCH_SECCOMP=y
|
|
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
|
|
+CONFIG_SECCOMP=y
|
|
+CONFIG_SECCOMP_FILTER=y
|
|
+# CONFIG_SECCOMP_CACHE_DEBUG is not set
|
|
+CONFIG_HAVE_STACKPROTECTOR=y
|
|
+CONFIG_STACKPROTECTOR=y
|
|
+# CONFIG_STACKPROTECTOR_STRONG is not set
|
|
+CONFIG_LTO_NONE=y
|
|
+CONFIG_HAVE_CONTEXT_TRACKING=y
|
|
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
|
|
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
|
|
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
|
|
+CONFIG_MODULES_USE_ELF_REL=y
|
|
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
|
|
+CONFIG_HAVE_ARCH_MMAP_RND_BITS=y
|
|
+CONFIG_HAVE_EXIT_THREAD=y
|
|
+CONFIG_ARCH_MMAP_RND_BITS=8
|
|
+CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y
|
|
+CONFIG_CLONE_BACKWARDS=y
|
|
+CONFIG_OLD_SIGSUSPEND3=y
|
|
+CONFIG_OLD_SIGACTION=y
|
|
+CONFIG_COMPAT_32BIT_TIME=y
|
|
+CONFIG_ARCH_SUPPORTS_RT=y
|
|
+CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y
|
|
+CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y
|
|
+CONFIG_ARCH_HAS_STRICT_KERNEL_RWX=y
|
|
+CONFIG_STRICT_KERNEL_RWX=y
|
|
+CONFIG_ARCH_HAS_STRICT_MODULE_RWX=y
|
|
+# CONFIG_STRICT_MODULE_RWX is not set
|
|
+CONFIG_ARCH_HAS_PHYS_TO_DMA=y
|
|
+CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y
|
|
+CONFIG_HAVE_ARCH_PFN_VALID=y
|
|
+
|
|
+#
|
|
+# GCOV-based kernel profiling
|
|
+#
|
|
+CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
|
|
+# end of GCOV-based kernel profiling
|
|
+
|
|
+CONFIG_HAVE_GCC_PLUGINS=y
|
|
+# CONFIG_GCC_PLUGINS is not set
|
|
+# end of General architecture-dependent options
|
|
+
|
|
+CONFIG_RT_MUTEXES=y
|
|
+CONFIG_BASE_SMALL=0
|
|
+CONFIG_MODULES=y
|
|
+# CONFIG_MODULE_FORCE_LOAD is not set
|
|
+# CONFIG_MODULE_UNLOAD is not set
|
|
+# CONFIG_MODVERSIONS is not set
|
|
+# CONFIG_MODULE_SRCVERSION_ALL is not set
|
|
+# CONFIG_MODULE_SIG is not set
|
|
+CONFIG_MODULE_COMPRESS_NONE=y
|
|
+# CONFIG_MODULE_COMPRESS_GZIP is not set
|
|
+# CONFIG_MODULE_COMPRESS_XZ is not set
|
|
+# CONFIG_MODULE_COMPRESS_ZSTD is not set
|
|
+# CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS is not set
|
|
+CONFIG_MODPROBE_PATH="/sbin/modprobe"
|
|
+# CONFIG_TRIM_UNUSED_KSYMS is not set
|
|
+CONFIG_BLOCK=y
|
|
+# CONFIG_BLK_DEV_BSGLIB is not set
|
|
+# CONFIG_BLK_DEV_INTEGRITY is not set
|
|
+# CONFIG_BLK_DEV_ZONED is not set
|
|
+# CONFIG_BLK_WBT is not set
|
|
+# CONFIG_BLK_SED_OPAL is not set
|
|
+# CONFIG_BLK_INLINE_ENCRYPTION is not set
|
|
+
|
|
+#
|
|
+# Partition Types
|
|
+#
|
|
+# CONFIG_PARTITION_ADVANCED is not set
|
|
+CONFIG_MSDOS_PARTITION=y
|
|
+CONFIG_EFI_PARTITION=y
|
|
+# end of Partition Types
|
|
+
|
|
+CONFIG_BLK_MQ_VIRTIO=y
|
|
+
|
|
+#
|
|
+# IO Schedulers
|
|
+#
|
|
+CONFIG_MQ_IOSCHED_DEADLINE=y
|
|
+# CONFIG_MQ_IOSCHED_KYBER is not set
|
|
+# CONFIG_IOSCHED_BFQ is not set
|
|
+# end of IO Schedulers
|
|
+
|
|
+CONFIG_ASN1=y
|
|
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
|
|
+CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE=y
|
|
+
|
|
+#
|
|
+# Executable file formats
|
|
+#
|
|
+CONFIG_BINFMT_ELF=y
|
|
+# CONFIG_BINFMT_ELF_FDPIC is not set
|
|
+CONFIG_ELFCORE=y
|
|
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
|
|
+CONFIG_BINFMT_SCRIPT=y
|
|
+CONFIG_ARCH_HAS_BINFMT_FLAT=y
|
|
+# CONFIG_BINFMT_FLAT is not set
|
|
+CONFIG_BINFMT_FLAT_ARGVP_ENVP_ON_STACK=y
|
|
+# CONFIG_BINFMT_MISC is not set
|
|
+CONFIG_COREDUMP=y
|
|
+# end of Executable file formats
|
|
+
|
|
+#
|
|
+# Memory Management options
|
|
+#
|
|
+CONFIG_SELECT_MEMORY_MODEL=y
|
|
+CONFIG_FLATMEM_MANUAL=y
|
|
+# CONFIG_SPARSEMEM_MANUAL is not set
|
|
+CONFIG_FLATMEM=y
|
|
+CONFIG_ARCH_KEEP_MEMBLOCK=y
|
|
+CONFIG_MEMORY_ISOLATION=y
|
|
+CONFIG_SPLIT_PTLOCK_CPUS=4
|
|
+# CONFIG_COMPACTION is not set
|
|
+# CONFIG_PAGE_REPORTING is not set
|
|
+CONFIG_MIGRATION=y
|
|
+CONFIG_CONTIG_ALLOC=y
|
|
+# CONFIG_KSM is not set
|
|
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
|
|
+CONFIG_NEED_PER_CPU_KM=y
|
|
+# CONFIG_CLEANCACHE is not set
|
|
+CONFIG_CMA=y
|
|
+# CONFIG_CMA_DEBUG is not set
|
|
+# CONFIG_CMA_SYSFS is not set
|
|
+CONFIG_CMA_AREAS=7
|
|
+# CONFIG_ZPOOL is not set
|
|
+# CONFIG_ZSMALLOC is not set
|
|
+CONFIG_GENERIC_EARLY_IOREMAP=y
|
|
+# CONFIG_IDLE_PAGE_TRACKING is not set
|
|
+# CONFIG_PERCPU_STATS is not set
|
|
+
|
|
+#
|
|
+# GUP_TEST needs to have DEBUG_FS enabled
|
|
+#
|
|
+
|
|
+#
|
|
+# Data Access Monitoring
|
|
+#
|
|
+# CONFIG_DAMON is not set
|
|
+# end of Data Access Monitoring
|
|
+# end of Memory Management options
|
|
+
|
|
+CONFIG_NET=y
|
|
+
|
|
+#
|
|
+# Networking options
|
|
+#
|
|
+CONFIG_PACKET=y
|
|
+# CONFIG_PACKET_DIAG is not set
|
|
+CONFIG_UNIX=y
|
|
+CONFIG_UNIX_SCM=y
|
|
+CONFIG_AF_UNIX_OOB=y
|
|
+# CONFIG_UNIX_DIAG is not set
|
|
+CONFIG_TLS=y
|
|
+CONFIG_TLS_DEVICE=y
|
|
+# CONFIG_TLS_TOE is not set
|
|
+# CONFIG_XFRM_USER is not set
|
|
+# CONFIG_NET_KEY is not set
|
|
+CONFIG_INET=y
|
|
+CONFIG_IP_MULTICAST=y
|
|
+# CONFIG_IP_ADVANCED_ROUTER is not set
|
|
+CONFIG_IP_PNP=y
|
|
+CONFIG_IP_PNP_DHCP=y
|
|
+# CONFIG_IP_PNP_BOOTP is not set
|
|
+# CONFIG_IP_PNP_RARP is not set
|
|
+# CONFIG_NET_IPIP is not set
|
|
+# CONFIG_NET_IPGRE_DEMUX is not set
|
|
+# CONFIG_IP_MROUTE is not set
|
|
+# CONFIG_SYN_COOKIES is not set
|
|
+# CONFIG_NET_IPVTI is not set
|
|
+# CONFIG_NET_FOU is not set
|
|
+# CONFIG_INET_AH is not set
|
|
+# CONFIG_INET_ESP is not set
|
|
+# CONFIG_INET_IPCOMP is not set
|
|
+CONFIG_INET_DIAG=y
|
|
+CONFIG_INET_TCP_DIAG=y
|
|
+# CONFIG_INET_UDP_DIAG is not set
|
|
+# CONFIG_INET_RAW_DIAG is not set
|
|
+# CONFIG_INET_DIAG_DESTROY is not set
|
|
+# CONFIG_TCP_CONG_ADVANCED is not set
|
|
+CONFIG_TCP_CONG_CUBIC=y
|
|
+CONFIG_DEFAULT_TCP_CONG="cubic"
|
|
+# CONFIG_TCP_MD5SIG is not set
|
|
+# CONFIG_IPV6 is not set
|
|
+# CONFIG_MPTCP is not set
|
|
+# CONFIG_NETWORK_SECMARK is not set
|
|
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
|
|
+# CONFIG_NETFILTER is not set
|
|
+# CONFIG_BPFILTER is not set
|
|
+# CONFIG_IP_DCCP is not set
|
|
+# CONFIG_IP_SCTP is not set
|
|
+# CONFIG_RDS is not set
|
|
+# CONFIG_TIPC is not set
|
|
+# CONFIG_ATM is not set
|
|
+# CONFIG_L2TP is not set
|
|
+# CONFIG_BRIDGE is not set
|
|
+# CONFIG_NET_DSA is not set
|
|
+CONFIG_VLAN_8021Q=y
|
|
+# CONFIG_VLAN_8021Q_GVRP is not set
|
|
+# CONFIG_VLAN_8021Q_MVRP is not set
|
|
+# CONFIG_DECNET is not set
|
|
+CONFIG_LLC=y
|
|
+CONFIG_LLC2=y
|
|
+# CONFIG_ATALK is not set
|
|
+# CONFIG_X25 is not set
|
|
+# CONFIG_LAPB is not set
|
|
+# CONFIG_PHONET is not set
|
|
+# CONFIG_IEEE802154 is not set
|
|
+# CONFIG_NET_SCHED is not set
|
|
+# CONFIG_DCB is not set
|
|
+# CONFIG_BATMAN_ADV is not set
|
|
+# CONFIG_OPENVSWITCH is not set
|
|
+# CONFIG_VSOCKETS is not set
|
|
+# CONFIG_NETLINK_DIAG is not set
|
|
+# CONFIG_MPLS is not set
|
|
+# CONFIG_NET_NSH is not set
|
|
+# CONFIG_HSR is not set
|
|
+# CONFIG_NET_SWITCHDEV is not set
|
|
+# CONFIG_NET_L3_MASTER_DEV is not set
|
|
+# CONFIG_QRTR is not set
|
|
+# CONFIG_NET_NCSI is not set
|
|
+CONFIG_SOCK_RX_QUEUE_MAPPING=y
|
|
+CONFIG_BQL=y
|
|
+
|
|
+#
|
|
+# Network testing
|
|
+#
|
|
+# CONFIG_NET_PKTGEN is not set
|
|
+# end of Network testing
|
|
+# end of Networking options
|
|
+
|
|
+# CONFIG_HAMRADIO is not set
|
|
+# CONFIG_CAN is not set
|
|
+# CONFIG_BT is not set
|
|
+# CONFIG_AF_RXRPC is not set
|
|
+# CONFIG_AF_KCM is not set
|
|
+CONFIG_STREAM_PARSER=y
|
|
+# CONFIG_MCTP is not set
|
|
+# CONFIG_WIRELESS is not set
|
|
+# CONFIG_RFKILL is not set
|
|
+# CONFIG_NET_9P is not set
|
|
+# CONFIG_CAIF is not set
|
|
+# CONFIG_CEPH_LIB is not set
|
|
+# CONFIG_NFC is not set
|
|
+# CONFIG_PSAMPLE is not set
|
|
+# CONFIG_NET_IFE is not set
|
|
+# CONFIG_LWTUNNEL is not set
|
|
+CONFIG_SOCK_VALIDATE_XMIT=y
|
|
+CONFIG_NET_SELFTESTS=y
|
|
+CONFIG_NET_SOCK_MSG=y
|
|
+# CONFIG_FAILOVER is not set
|
|
+CONFIG_ETHTOOL_NETLINK=y
|
|
+
|
|
+#
|
|
+# Device Drivers
|
|
+#
|
|
+CONFIG_HAVE_PCI=y
|
|
+# CONFIG_PCI is not set
|
|
+# CONFIG_PCCARD is not set
|
|
+
|
|
+#
|
|
+# Generic Driver Options
|
|
+#
|
|
+# CONFIG_UEVENT_HELPER is not set
|
|
+CONFIG_DEVTMPFS=y
|
|
+CONFIG_DEVTMPFS_MOUNT=y
|
|
+# CONFIG_STANDALONE is not set
|
|
+CONFIG_PREVENT_FIRMWARE_BUILD=y
|
|
+
|
|
+#
|
|
+# Firmware loader
|
|
+#
|
|
+CONFIG_FW_LOADER=y
|
|
+CONFIG_FW_LOADER_PAGED_BUF=y
|
|
+CONFIG_EXTRA_FIRMWARE=""
|
|
+CONFIG_FW_LOADER_USER_HELPER=y
|
|
+CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
|
|
+# CONFIG_FW_LOADER_COMPRESS is not set
|
|
+# end of Firmware loader
|
|
+
|
|
+CONFIG_ALLOW_DEV_COREDUMP=y
|
|
+# CONFIG_DEBUG_DRIVER is not set
|
|
+# CONFIG_DEBUG_DEVRES is not set
|
|
+# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set
|
|
+# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set
|
|
+CONFIG_GENERIC_CPU_AUTOPROBE=y
|
|
+CONFIG_GENERIC_CPU_VULNERABILITIES=y
|
|
+CONFIG_SOC_BUS=y
|
|
+CONFIG_REGMAP=y
|
|
+CONFIG_REGMAP_I2C=y
|
|
+CONFIG_REGMAP_MMIO=y
|
|
+CONFIG_REGMAP_IRQ=y
|
|
+CONFIG_DMA_SHARED_BUFFER=y
|
|
+# CONFIG_DMA_FENCE_TRACE is not set
|
|
+# end of Generic Driver Options
|
|
+
|
|
+#
|
|
+# Bus devices
|
|
+#
|
|
+# CONFIG_BRCMSTB_GISB_ARB is not set
|
|
+CONFIG_IMX_WEIM=y
|
|
+# CONFIG_VEXPRESS_CONFIG is not set
|
|
+# CONFIG_FSL_MC_BUS is not set
|
|
+# CONFIG_MHI_BUS is not set
|
|
+# end of Bus devices
|
|
+
|
|
+# CONFIG_CONNECTOR is not set
|
|
+
|
|
+#
|
|
+# Firmware Drivers
|
|
+#
|
|
+
|
|
+#
|
|
+# ARM System Control and Management Interface Protocol
|
|
+#
|
|
+# CONFIG_ARM_SCMI_PROTOCOL is not set
|
|
+# end of ARM System Control and Management Interface Protocol
|
|
+
|
|
+# CONFIG_ARM_SCPI_PROTOCOL is not set
|
|
+# CONFIG_FIRMWARE_MEMMAP is not set
|
|
+# CONFIG_FW_CFG_SYSFS is not set
|
|
+# CONFIG_TRUSTED_FOUNDATIONS is not set
|
|
+# CONFIG_GOOGLE_FIRMWARE is not set
|
|
+# CONFIG_IMX_DSP is not set
|
|
+# CONFIG_IMX_SCU is not set
|
|
+# CONFIG_IMX_SECO_MU is not set
|
|
+# CONFIG_IMX_EL_ENCLAVE is not set
|
|
+CONFIG_ARM_PSCI_FW=y
|
|
+CONFIG_HAVE_ARM_SMCCC=y
|
|
+CONFIG_HAVE_ARM_SMCCC_DISCOVERY=y
|
|
+CONFIG_ARM_SMCCC_SOC_ID=y
|
|
+
|
|
+#
|
|
+# Tegra firmware driver
|
|
+#
|
|
+# end of Tegra firmware driver
|
|
+# end of Firmware Drivers
|
|
+
|
|
+# CONFIG_GNSS is not set
|
|
+# CONFIG_MTD is not set
|
|
+CONFIG_DTC=y
|
|
+CONFIG_OF=y
|
|
+# CONFIG_OF_UNITTEST is not set
|
|
+CONFIG_OF_FLATTREE=y
|
|
+CONFIG_OF_EARLY_FLATTREE=y
|
|
+CONFIG_OF_KOBJ=y
|
|
+CONFIG_OF_DYNAMIC=y
|
|
+CONFIG_OF_ADDRESS=y
|
|
+CONFIG_OF_IRQ=y
|
|
+CONFIG_OF_RESERVED_MEM=y
|
|
+CONFIG_OF_RESOLVE=y
|
|
+CONFIG_OF_OVERLAY=y
|
|
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
|
|
+# CONFIG_PARPORT is not set
|
|
+CONFIG_BLK_DEV=y
|
|
+# CONFIG_BLK_DEV_NULL_BLK is not set
|
|
+# CONFIG_BLK_DEV_LOOP is not set
|
|
+# CONFIG_BLK_DEV_DRBD is not set
|
|
+# CONFIG_BLK_DEV_NBD is not set
|
|
+# CONFIG_BLK_DEV_RAM is not set
|
|
+# CONFIG_CDROM_PKTCDVD is not set
|
|
+# CONFIG_ATA_OVER_ETH is not set
|
|
+# CONFIG_VIRTIO_BLK is not set
|
|
+# CONFIG_BLK_DEV_RBD is not set
|
|
+
|
|
+#
|
|
+# NVME Support
|
|
+#
|
|
+# CONFIG_NVME_FC is not set
|
|
+# CONFIG_NVME_TCP is not set
|
|
+# CONFIG_NVME_TARGET is not set
|
|
+# end of NVME Support
|
|
+
|
|
+#
|
|
+# Misc devices
|
|
+#
|
|
+# CONFIG_AD525X_DPOT is not set
|
|
+# CONFIG_DUMMY_IRQ is not set
|
|
+# CONFIG_ICS932S401 is not set
|
|
+# CONFIG_ENCLOSURE_SERVICES is not set
|
|
+# CONFIG_APDS9802ALS is not set
|
|
+# CONFIG_ISL29003 is not set
|
|
+# CONFIG_ISL29020 is not set
|
|
+# CONFIG_SENSORS_TSL2550 is not set
|
|
+# CONFIG_SENSORS_BH1770 is not set
|
|
+# CONFIG_SENSORS_APDS990X is not set
|
|
+# CONFIG_HMC6352 is not set
|
|
+# CONFIG_DS1682 is not set
|
|
+CONFIG_SRAM=y
|
|
+CONFIG_SRAM_EXEC=y
|
|
+# CONFIG_XILINX_SDFEC is not set
|
|
+# CONFIG_C2PORT is not set
|
|
+
|
|
+#
|
|
+# EEPROM support
|
|
+#
|
|
+CONFIG_EEPROM_AT24=y
|
|
+# CONFIG_EEPROM_LEGACY is not set
|
|
+# CONFIG_EEPROM_MAX6875 is not set
|
|
+# CONFIG_EEPROM_93CX6 is not set
|
|
+# CONFIG_EEPROM_IDT_89HPESX is not set
|
|
+# CONFIG_EEPROM_EE1004 is not set
|
|
+# end of EEPROM support
|
|
+
|
|
+#
|
|
+# Texas Instruments shared transport line discipline
|
|
+#
|
|
+# CONFIG_TI_ST is not set
|
|
+# end of Texas Instruments shared transport line discipline
|
|
+
|
|
+# CONFIG_SENSORS_LIS3_I2C is not set
|
|
+# CONFIG_ALTERA_STAPL is not set
|
|
+# CONFIG_ECHO is not set
|
|
+# CONFIG_PVPANIC is not set
|
|
+# end of Misc devices
|
|
+
|
|
+#
|
|
+# SCSI device support
|
|
+#
|
|
+CONFIG_SCSI_MOD=y
|
|
+# CONFIG_RAID_ATTRS is not set
|
|
+# CONFIG_SCSI is not set
|
|
+# end of SCSI device support
|
|
+
|
|
+# CONFIG_ATA is not set
|
|
+# CONFIG_MD is not set
|
|
+# CONFIG_TARGET_CORE is not set
|
|
+CONFIG_NETDEVICES=y
|
|
+CONFIG_NET_CORE=y
|
|
+# CONFIG_BONDING is not set
|
|
+# CONFIG_DUMMY is not set
|
|
+# CONFIG_WIREGUARD is not set
|
|
+# CONFIG_EQUALIZER is not set
|
|
+# CONFIG_NET_TEAM is not set
|
|
+# CONFIG_MACVLAN is not set
|
|
+# CONFIG_IPVLAN is not set
|
|
+# CONFIG_VXLAN is not set
|
|
+# CONFIG_GENEVE is not set
|
|
+# CONFIG_BAREUDP is not set
|
|
+# CONFIG_GTP is not set
|
|
+# CONFIG_MACSEC is not set
|
|
+# CONFIG_NETCONSOLE is not set
|
|
+# CONFIG_TUN is not set
|
|
+# CONFIG_TUN_VNET_CROSS_LE is not set
|
|
+# CONFIG_VETH is not set
|
|
+# CONFIG_VIRTIO_NET is not set
|
|
+# CONFIG_NLMON is not set
|
|
+CONFIG_ETHERNET=y
|
|
+# CONFIG_NET_VENDOR_ALACRITECH is not set
|
|
+# CONFIG_ALTERA_TSE is not set
|
|
+# CONFIG_NET_VENDOR_AMAZON is not set
|
|
+# CONFIG_NET_VENDOR_AQUANTIA is not set
|
|
+# CONFIG_NET_VENDOR_ARC is not set
|
|
+# CONFIG_NET_VENDOR_BROADCOM is not set
|
|
+# CONFIG_NET_VENDOR_CADENCE is not set
|
|
+# CONFIG_NET_VENDOR_CAVIUM is not set
|
|
+# CONFIG_NET_VENDOR_CIRRUS is not set
|
|
+# CONFIG_NET_VENDOR_CORTINA is not set
|
|
+# CONFIG_DM9000 is not set
|
|
+# CONFIG_DNET is not set
|
|
+# CONFIG_NET_VENDOR_EZCHIP is not set
|
|
+# CONFIG_NET_VENDOR_FARADAY is not set
|
|
+CONFIG_NET_VENDOR_FREESCALE=y
|
|
+CONFIG_FEC=y
|
|
+CONFIG_FEC_ECAT=y
|
|
+# CONFIG_FEC_UIO is not set
|
|
+# CONFIG_AVB_SUPPORT is not set
|
|
+# CONFIG_FSL_PQ_MDIO is not set
|
|
+# CONFIG_FSL_XGMAC_MDIO is not set
|
|
+# CONFIG_GIANFAR is not set
|
|
+
|
|
+#
|
|
+# Frame Manager support
|
|
+#
|
|
+# end of Frame Manager support
|
|
+
|
|
+# CONFIG_FSL_ENETC_IERB is not set
|
|
+# CONFIG_NET_VENDOR_GOOGLE is not set
|
|
+# CONFIG_NET_VENDOR_HISILICON is not set
|
|
+# CONFIG_NET_VENDOR_HUAWEI is not set
|
|
+# CONFIG_NET_VENDOR_INTEL is not set
|
|
+# CONFIG_NET_VENDOR_LITEX is not set
|
|
+# CONFIG_NET_VENDOR_MARVELL is not set
|
|
+# CONFIG_NET_VENDOR_MELLANOX is not set
|
|
+# CONFIG_NET_VENDOR_MICREL is not set
|
|
+# CONFIG_NET_VENDOR_MICROCHIP is not set
|
|
+# CONFIG_NET_VENDOR_MICROSEMI is not set
|
|
+# CONFIG_NET_VENDOR_MICROSOFT is not set
|
|
+# CONFIG_NET_VENDOR_NI is not set
|
|
+# CONFIG_NET_VENDOR_NATSEMI is not set
|
|
+# CONFIG_NET_VENDOR_NETRONOME is not set
|
|
+# CONFIG_ETHOC is not set
|
|
+# CONFIG_NET_VENDOR_PENSANDO is not set
|
|
+# CONFIG_NET_VENDOR_QUALCOMM is not set
|
|
+# CONFIG_NET_VENDOR_RENESAS is not set
|
|
+# CONFIG_NET_VENDOR_ROCKER is not set
|
|
+# CONFIG_NET_VENDOR_SAMSUNG is not set
|
|
+# CONFIG_NET_VENDOR_SEEQ is not set
|
|
+# CONFIG_NET_VENDOR_SOLARFLARE is not set
|
|
+# CONFIG_NET_VENDOR_SMSC is not set
|
|
+# CONFIG_NET_VENDOR_SOCIONEXT is not set
|
|
+# CONFIG_NET_VENDOR_STMICRO is not set
|
|
+# CONFIG_NET_VENDOR_SYNOPSYS is not set
|
|
+# CONFIG_NET_VENDOR_VIA is not set
|
|
+# CONFIG_NET_VENDOR_WIZNET is not set
|
|
+# CONFIG_NET_VENDOR_XILINX is not set
|
|
+CONFIG_PHYLIB=y
|
|
+CONFIG_SWPHY=y
|
|
+CONFIG_FIXED_PHY=y
|
|
+
|
|
+#
|
|
+# MII PHY device drivers
|
|
+#
|
|
+# CONFIG_AMD_PHY is not set
|
|
+# CONFIG_ADIN_PHY is not set
|
|
+# CONFIG_AQUANTIA_PHY is not set
|
|
+CONFIG_AX88796B_PHY=y
|
|
+# CONFIG_BROADCOM_PHY is not set
|
|
+# CONFIG_BCM54140_PHY is not set
|
|
+# CONFIG_BCM7XXX_PHY is not set
|
|
+# CONFIG_BCM84881_PHY is not set
|
|
+# CONFIG_BCM87XX_PHY is not set
|
|
+# CONFIG_CICADA_PHY is not set
|
|
+# CONFIG_CORTINA_PHY is not set
|
|
+# CONFIG_DAVICOM_PHY is not set
|
|
+# CONFIG_ICPLUS_PHY is not set
|
|
+# CONFIG_LXT_PHY is not set
|
|
+# CONFIG_INPHI_PHY is not set
|
|
+# CONFIG_INTEL_XWAY_PHY is not set
|
|
+# CONFIG_LSI_ET1011C_PHY is not set
|
|
+# CONFIG_MARVELL_PHY is not set
|
|
+# CONFIG_MARVELL_10G_PHY is not set
|
|
+# CONFIG_MARVELL_88X2222_PHY is not set
|
|
+# CONFIG_MAXLINEAR_GPHY is not set
|
|
+# CONFIG_MEDIATEK_GE_PHY is not set
|
|
+CONFIG_MICREL_PHY=y
|
|
+CONFIG_MICROCHIP_PHY=y
|
|
+# CONFIG_MICROCHIP_T1_PHY is not set
|
|
+# CONFIG_MICROSEMI_PHY is not set
|
|
+# CONFIG_MOTORCOMM_PHY is not set
|
|
+# CONFIG_NATIONAL_PHY is not set
|
|
+# CONFIG_NXP_C45_TJA11XX_PHY is not set
|
|
+# CONFIG_NXP_TJA11XX_PHY is not set
|
|
+CONFIG_AT803X_PHY=y
|
|
+# CONFIG_QSEMI_PHY is not set
|
|
+# CONFIG_REALTEK_PHY is not set
|
|
+# CONFIG_RENESAS_PHY is not set
|
|
+# CONFIG_ROCKCHIP_PHY is not set
|
|
+CONFIG_SMSC_PHY=y
|
|
+# CONFIG_STE10XP is not set
|
|
+# CONFIG_TERANETICS_PHY is not set
|
|
+# CONFIG_DP83822_PHY is not set
|
|
+# CONFIG_DP83TC811_PHY is not set
|
|
+# CONFIG_DP83848_PHY is not set
|
|
+# CONFIG_DP83867_PHY is not set
|
|
+# CONFIG_DP83869_PHY is not set
|
|
+# CONFIG_VITESSE_PHY is not set
|
|
+# CONFIG_XILINX_GMII2RGMII is not set
|
|
+CONFIG_MDIO_DEVICE=y
|
|
+CONFIG_MDIO_BUS=y
|
|
+CONFIG_FWNODE_MDIO=y
|
|
+CONFIG_OF_MDIO=y
|
|
+CONFIG_MDIO_DEVRES=y
|
|
+# CONFIG_MDIO_BITBANG is not set
|
|
+# CONFIG_MDIO_BCM_UNIMAC is not set
|
|
+# CONFIG_MDIO_HISI_FEMAC is not set
|
|
+# CONFIG_MDIO_MSCC_MIIM is not set
|
|
+# CONFIG_MDIO_IPQ4019 is not set
|
|
+# CONFIG_MDIO_IPQ8064 is not set
|
|
+
|
|
+#
|
|
+# MDIO Multiplexers
|
|
+#
|
|
+# CONFIG_MDIO_BUS_MUX_GPIO is not set
|
|
+# CONFIG_MDIO_BUS_MUX_MULTIPLEXER is not set
|
|
+# CONFIG_MDIO_BUS_MUX_MMIOREG is not set
|
|
+
|
|
+#
|
|
+# PCS device drivers
|
|
+#
|
|
+# CONFIG_PCS_XPCS is not set
|
|
+# end of PCS device drivers
|
|
+
|
|
+# CONFIG_PPP is not set
|
|
+# CONFIG_SLIP is not set
|
|
+
|
|
+#
|
|
+# Host-side USB support is needed for USB Network Adapter support
|
|
+#
|
|
+# CONFIG_WLAN is not set
|
|
+# CONFIG_WAN is not set
|
|
+
|
|
+#
|
|
+# Wireless WAN
|
|
+#
|
|
+# CONFIG_WWAN is not set
|
|
+# end of Wireless WAN
|
|
+
|
|
+# CONFIG_NET_FAILOVER is not set
|
|
+# CONFIG_IMX_SHMEM_NET is not set
|
|
+# CONFIG_ISDN is not set
|
|
+
|
|
+#
|
|
+# Input device support
|
|
+#
|
|
+CONFIG_INPUT=y
|
|
+# CONFIG_INPUT_FF_MEMLESS is not set
|
|
+# CONFIG_INPUT_SPARSEKMAP is not set
|
|
+# CONFIG_INPUT_MATRIXKMAP is not set
|
|
+
|
|
+#
|
|
+# Userland interfaces
|
|
+#
|
|
+# CONFIG_INPUT_MOUSEDEV is not set
|
|
+# CONFIG_INPUT_JOYDEV is not set
|
|
+# CONFIG_INPUT_EVDEV is not set
|
|
+# CONFIG_INPUT_EVBUG is not set
|
|
+
|
|
+#
|
|
+# Input Device Drivers
|
|
+#
|
|
+# CONFIG_INPUT_KEYBOARD is not set
|
|
+CONFIG_KEYBOARD_SNVS_PWRKEY=y
|
|
+# CONFIG_INPUT_MOUSE is not set
|
|
+# CONFIG_INPUT_JOYSTICK is not set
|
|
+# CONFIG_INPUT_TABLET is not set
|
|
+# CONFIG_INPUT_TOUCHSCREEN is not set
|
|
+# CONFIG_TOUCHSCREEN_FTS is not set
|
|
+# CONFIG_INPUT_MISC is not set
|
|
+# CONFIG_RMI4_CORE is not set
|
|
+
|
|
+#
|
|
+# Hardware I/O ports
|
|
+#
|
|
+# CONFIG_SERIO is not set
|
|
+# CONFIG_GAMEPORT is not set
|
|
+# end of Hardware I/O ports
|
|
+# end of Input device support
|
|
+
|
|
+#
|
|
+# Character devices
|
|
+#
|
|
+CONFIG_TTY=y
|
|
+CONFIG_VT=y
|
|
+CONFIG_CONSOLE_TRANSLATIONS=y
|
|
+CONFIG_VT_CONSOLE=y
|
|
+CONFIG_HW_CONSOLE=y
|
|
+CONFIG_VT_HW_CONSOLE_BINDING=y
|
|
+CONFIG_UNIX98_PTYS=y
|
|
+# CONFIG_LEGACY_PTYS is not set
|
|
+CONFIG_LDISC_AUTOLOAD=y
|
|
+
|
|
+#
|
|
+# Serial drivers
|
|
+#
|
|
+CONFIG_SERIAL_EARLYCON=y
|
|
+# CONFIG_SERIAL_8250 is not set
|
|
+
|
|
+#
|
|
+# Non-8250 serial port support
|
|
+#
|
|
+# CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set
|
|
+CONFIG_SERIAL_IMX=y
|
|
+CONFIG_SERIAL_IMX_CONSOLE=y
|
|
+CONFIG_SERIAL_IMX_EARLYCON=y
|
|
+# CONFIG_SERIAL_UARTLITE is not set
|
|
+CONFIG_SERIAL_CORE=y
|
|
+CONFIG_SERIAL_CORE_CONSOLE=y
|
|
+# CONFIG_SERIAL_SIFIVE is not set
|
|
+# CONFIG_SERIAL_SCCNXP is not set
|
|
+# CONFIG_SERIAL_SC16IS7XX is not set
|
|
+# CONFIG_SERIAL_BCM63XX is not set
|
|
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
|
|
+# CONFIG_SERIAL_ALTERA_UART is not set
|
|
+# CONFIG_SERIAL_XILINX_PS_UART is not set
|
|
+# CONFIG_SERIAL_ARC is not set
|
|
+CONFIG_SERIAL_FSL_LPUART=y
|
|
+CONFIG_SERIAL_FSL_LPUART_CONSOLE=y
|
|
+# CONFIG_SERIAL_FSL_LINFLEXUART is not set
|
|
+# CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set
|
|
+# CONFIG_SERIAL_ST_ASC is not set
|
|
+# CONFIG_SERIAL_SPRD is not set
|
|
+# end of Serial drivers
|
|
+
|
|
+CONFIG_SERIAL_MCTRL_GPIO=y
|
|
+# CONFIG_SERIAL_NONSTANDARD is not set
|
|
+# CONFIG_N_GSM is not set
|
|
+# CONFIG_NULL_TTY is not set
|
|
+# CONFIG_HVC_DCC is not set
|
|
+# CONFIG_RPMSG_TTY is not set
|
|
+CONFIG_SERIAL_DEV_BUS=y
|
|
+CONFIG_SERIAL_DEV_CTRL_TTYPORT=y
|
|
+# CONFIG_TTY_PRINTK is not set
|
|
+# CONFIG_VIRTIO_CONSOLE is not set
|
|
+# CONFIG_IPMI_HANDLER is not set
|
|
+# CONFIG_IPMB_DEVICE_INTERFACE is not set
|
|
+CONFIG_HW_RANDOM=y
|
|
+# CONFIG_HW_RANDOM_TIMERIOMEM is not set
|
|
+# CONFIG_HW_RANDOM_BA431 is not set
|
|
+# CONFIG_HW_RANDOM_VIRTIO is not set
|
|
+CONFIG_HW_RANDOM_IMX_RNGC=y
|
|
+CONFIG_HW_RANDOM_OPTEE=y
|
|
+# CONFIG_HW_RANDOM_CCTRNG is not set
|
|
+# CONFIG_HW_RANDOM_XIPHERA is not set
|
|
+CONFIG_HW_RANDOM_ARM_SMCCC_TRNG=y
|
|
+# CONFIG_DEVMEM is not set
|
|
+# CONFIG_TCG_TPM is not set
|
|
+# CONFIG_XILLYBUS is not set
|
|
+CONFIG_IMX_SEMA4=y
|
|
+CONFIG_RANDOM_TRUST_BOOTLOADER=y
|
|
+# end of Character devices
|
|
+
|
|
+#
|
|
+# I2C support
|
|
+#
|
|
+CONFIG_I2C=y
|
|
+CONFIG_I2C_BOARDINFO=y
|
|
+# CONFIG_I2C_COMPAT is not set
|
|
+CONFIG_I2C_CHARDEV=y
|
|
+CONFIG_I2C_MUX=y
|
|
+
|
|
+#
|
|
+# Multiplexer I2C Chip support
|
|
+#
|
|
+# CONFIG_I2C_ARB_GPIO_CHALLENGE is not set
|
|
+CONFIG_I2C_MUX_GPIO=y
|
|
+# CONFIG_I2C_MUX_GPMUX is not set
|
|
+# CONFIG_I2C_MUX_LTC4306 is not set
|
|
+# CONFIG_I2C_MUX_PCA9541 is not set
|
|
+# CONFIG_I2C_MUX_PCA954x is not set
|
|
+# CONFIG_I2C_MUX_PINCTRL is not set
|
|
+# CONFIG_I2C_MUX_REG is not set
|
|
+# CONFIG_I2C_DEMUX_PINCTRL is not set
|
|
+# CONFIG_I2C_MUX_MLXCPLD is not set
|
|
+# end of Multiplexer I2C Chip support
|
|
+
|
|
+# CONFIG_I2C_HELPER_AUTO is not set
|
|
+# CONFIG_I2C_SMBUS is not set
|
|
+
|
|
+#
|
|
+# I2C Algorithms
|
|
+#
|
|
+CONFIG_I2C_ALGOBIT=y
|
|
+CONFIG_I2C_ALGOPCF=y
|
|
+CONFIG_I2C_ALGOPCA=y
|
|
+# end of I2C Algorithms
|
|
+
|
|
+#
|
|
+# I2C Hardware Bus support
|
|
+#
|
|
+
|
|
+#
|
|
+# I2C system bus drivers (mostly embedded / system-on-chip)
|
|
+#
|
|
+# CONFIG_I2C_CBUS_GPIO is not set
|
|
+# CONFIG_I2C_DESIGNWARE_PLATFORM is not set
|
|
+# CONFIG_I2C_EMEV2 is not set
|
|
+CONFIG_I2C_GPIO=y
|
|
+# CONFIG_I2C_GPIO_FAULT_INJECTOR is not set
|
|
+CONFIG_I2C_IMX=y
|
|
+CONFIG_I2C_IMX_LPI2C=y
|
|
+CONFIG_I2C_IMX_FLEXIO=y
|
|
+# CONFIG_I2C_OCORES is not set
|
|
+# CONFIG_I2C_PCA_PLATFORM is not set
|
|
+# CONFIG_I2C_RK3X is not set
|
|
+# CONFIG_I2C_RPBUS is not set
|
|
+# CONFIG_I2C_SIMTEC is not set
|
|
+# CONFIG_I2C_XILINX is not set
|
|
+
|
|
+#
|
|
+# External I2C/SMBus adapter drivers
|
|
+#
|
|
+# CONFIG_I2C_TAOS_EVM is not set
|
|
+
|
|
+#
|
|
+# Other I2C/SMBus bus drivers
|
|
+#
|
|
+# CONFIG_I2C_VIRTIO is not set
|
|
+# end of I2C Hardware Bus support
|
|
+
|
|
+# CONFIG_I2C_STUB is not set
|
|
+CONFIG_I2C_SLAVE=y
|
|
+# CONFIG_I2C_SLAVE_EEPROM is not set
|
|
+# CONFIG_I2C_SLAVE_TESTUNIT is not set
|
|
+# CONFIG_I2C_DEBUG_CORE is not set
|
|
+# CONFIG_I2C_DEBUG_ALGO is not set
|
|
+# CONFIG_I2C_DEBUG_BUS is not set
|
|
+# end of I2C support
|
|
+
|
|
+# CONFIG_I3C is not set
|
|
+# CONFIG_SPI is not set
|
|
+# CONFIG_SPMI is not set
|
|
+# CONFIG_HSI is not set
|
|
+CONFIG_PPS=y
|
|
+# CONFIG_PPS_DEBUG is not set
|
|
+
|
|
+#
|
|
+# PPS clients support
|
|
+#
|
|
+# CONFIG_PPS_CLIENT_KTIMER is not set
|
|
+# CONFIG_PPS_CLIENT_LDISC is not set
|
|
+# CONFIG_PPS_CLIENT_GPIO is not set
|
|
+
|
|
+#
|
|
+# PPS generators support
|
|
+#
|
|
+
|
|
+#
|
|
+# PTP clock support
|
|
+#
|
|
+# CONFIG_PTP_1588_CLOCK is not set
|
|
+CONFIG_PTP_1588_CLOCK_OPTIONAL=y
|
|
+
|
|
+#
|
|
+# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
|
|
+#
|
|
+# end of PTP clock support
|
|
+
|
|
+CONFIG_PINCTRL=y
|
|
+CONFIG_GENERIC_PINCTRL_GROUPS=y
|
|
+CONFIG_PINMUX=y
|
|
+CONFIG_GENERIC_PINMUX_FUNCTIONS=y
|
|
+CONFIG_PINCONF=y
|
|
+CONFIG_GENERIC_PINCONF=y
|
|
+# CONFIG_DEBUG_PINCTRL is not set
|
|
+# CONFIG_PINCTRL_DA9062 is not set
|
|
+# CONFIG_PINCTRL_MCP23S08 is not set
|
|
+# CONFIG_PINCTRL_SINGLE is not set
|
|
+# CONFIG_PINCTRL_SX150X is not set
|
|
+# CONFIG_PINCTRL_STMFX is not set
|
|
+# CONFIG_PINCTRL_OCELOT is not set
|
|
+# CONFIG_PINCTRL_MICROCHIP_SGPIO is not set
|
|
+CONFIG_PINCTRL_IMX=y
|
|
+CONFIG_PINCTRL_IMX6Q=y
|
|
+CONFIG_PINCTRL_IMX6SL=y
|
|
+CONFIG_PINCTRL_IMX6SLL=y
|
|
+CONFIG_PINCTRL_IMX6SX=y
|
|
+CONFIG_PINCTRL_IMX6UL=y
|
|
+CONFIG_PINCTRL_IMX7D=y
|
|
+# CONFIG_PINCTRL_IMX8MM is not set
|
|
+# CONFIG_PINCTRL_IMX8MN is not set
|
|
+# CONFIG_PINCTRL_IMX8MP is not set
|
|
+# CONFIG_PINCTRL_IMX8MQ is not set
|
|
+# CONFIG_PINCTRL_IMX8ULP is not set
|
|
+# CONFIG_PINCTRL_IMX93 is not set
|
|
+# CONFIG_PINCTRL_S32V_CORE is not set
|
|
+
|
|
+#
|
|
+# Renesas pinctrl drivers
|
|
+#
|
|
+# end of Renesas pinctrl drivers
|
|
+
|
|
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
|
|
+CONFIG_GPIOLIB=y
|
|
+CONFIG_GPIOLIB_FASTPATH_LIMIT=512
|
|
+CONFIG_OF_GPIO=y
|
|
+CONFIG_GPIOLIB_IRQCHIP=y
|
|
+# CONFIG_DEBUG_GPIO is not set
|
|
+# CONFIG_GPIO_SYSFS is not set
|
|
+CONFIG_GPIO_CDEV=y
|
|
+CONFIG_GPIO_CDEV_V1=y
|
|
+CONFIG_GPIO_GENERIC=y
|
|
+
|
|
+#
|
|
+# Memory mapped GPIO drivers
|
|
+#
|
|
+# CONFIG_GPIO_74XX_MMIO is not set
|
|
+# CONFIG_GPIO_ALTERA is not set
|
|
+# CONFIG_GPIO_CADENCE is not set
|
|
+# CONFIG_GPIO_DWAPB is not set
|
|
+# CONFIG_GPIO_FTGPIO010 is not set
|
|
+# CONFIG_GPIO_GENERIC_PLATFORM is not set
|
|
+# CONFIG_GPIO_GRGPIO is not set
|
|
+# CONFIG_GPIO_HLWD is not set
|
|
+# CONFIG_GPIO_LOGICVC is not set
|
|
+# CONFIG_GPIO_MB86S7X is not set
|
|
+# CONFIG_GPIO_MPC8XXX is not set
|
|
+CONFIG_GPIO_MXC=y
|
|
+# CONFIG_GPIO_SAMA5D2_PIOBU is not set
|
|
+# CONFIG_GPIO_SIFIVE is not set
|
|
+# CONFIG_GPIO_SYSCON is not set
|
|
+CONFIG_GPIO_VF610=y
|
|
+CONFIG_GPIO_IMX_RPMSG=y
|
|
+# CONFIG_GPIO_XILINX is not set
|
|
+# CONFIG_GPIO_ZEVIO is not set
|
|
+# CONFIG_GPIO_AMD_FCH is not set
|
|
+# end of Memory mapped GPIO drivers
|
|
+
|
|
+#
|
|
+# I2C GPIO expanders
|
|
+#
|
|
+# CONFIG_GPIO_ADP5588 is not set
|
|
+# CONFIG_GPIO_ADNP is not set
|
|
+# CONFIG_GPIO_GW_PLD is not set
|
|
+# CONFIG_GPIO_MAX7300 is not set
|
|
+CONFIG_GPIO_MAX732X=y
|
|
+# CONFIG_GPIO_MAX732X_IRQ is not set
|
|
+CONFIG_GPIO_PCA953X=y
|
|
+# CONFIG_GPIO_PCA953X_IRQ is not set
|
|
+# CONFIG_GPIO_PCA9570 is not set
|
|
+CONFIG_GPIO_PCF857X=y
|
|
+# CONFIG_GPIO_TPIC2810 is not set
|
|
+# CONFIG_GPIO_TS4900 is not set
|
|
+# end of I2C GPIO expanders
|
|
+
|
|
+#
|
|
+# MFD GPIO expanders
|
|
+#
|
|
+# CONFIG_GPIO_DA9052 is not set
|
|
+# CONFIG_HTC_EGPIO is not set
|
|
+# CONFIG_GPIO_WM8994 is not set
|
|
+# end of MFD GPIO expanders
|
|
+
|
|
+#
|
|
+# Virtual GPIO drivers
|
|
+#
|
|
+# CONFIG_GPIO_AGGREGATOR is not set
|
|
+# CONFIG_GPIO_MOCKUP is not set
|
|
+# CONFIG_GPIO_VIRTIO is not set
|
|
+# end of Virtual GPIO drivers
|
|
+
|
|
+# CONFIG_W1 is not set
|
|
+CONFIG_POWER_RESET=y
|
|
+# CONFIG_POWER_RESET_BRCMKONA is not set
|
|
+# CONFIG_POWER_RESET_BRCMSTB is not set
|
|
+# CONFIG_POWER_RESET_GPIO is not set
|
|
+# CONFIG_POWER_RESET_GPIO_RESTART is not set
|
|
+# CONFIG_POWER_RESET_LTC2952 is not set
|
|
+# CONFIG_POWER_RESET_REGULATOR is not set
|
|
+# CONFIG_POWER_RESET_RESTART is not set
|
|
+# CONFIG_POWER_RESET_VERSATILE is not set
|
|
+CONFIG_POWER_RESET_SYSCON=y
|
|
+CONFIG_POWER_RESET_SYSCON_POWEROFF=y
|
|
+# CONFIG_SYSCON_REBOOT_MODE is not set
|
|
+# CONFIG_NVMEM_REBOOT_MODE is not set
|
|
+CONFIG_POWER_SUPPLY=y
|
|
+# CONFIG_POWER_SUPPLY_DEBUG is not set
|
|
+# CONFIG_POWER_SUPPLY_HWMON is not set
|
|
+# CONFIG_PDA_POWER is not set
|
|
+# CONFIG_TEST_POWER is not set
|
|
+# CONFIG_CHARGER_ADP5061 is not set
|
|
+# CONFIG_BATTERY_CW2015 is not set
|
|
+# CONFIG_BATTERY_DS2780 is not set
|
|
+# CONFIG_BATTERY_DS2781 is not set
|
|
+# CONFIG_BATTERY_DS2782 is not set
|
|
+# CONFIG_BATTERY_SBS is not set
|
|
+# CONFIG_CHARGER_SBS is not set
|
|
+# CONFIG_MANAGER_SBS is not set
|
|
+# CONFIG_BATTERY_BQ27XXX is not set
|
|
+# CONFIG_BATTERY_DA9052 is not set
|
|
+# CONFIG_BATTERY_MAX17040 is not set
|
|
+# CONFIG_BATTERY_MAX17042 is not set
|
|
+# CONFIG_CHARGER_MAX8903 is not set
|
|
+# CONFIG_CHARGER_LP8727 is not set
|
|
+# CONFIG_CHARGER_GPIO is not set
|
|
+# CONFIG_CHARGER_MANAGER is not set
|
|
+# CONFIG_CHARGER_LT3651 is not set
|
|
+# CONFIG_CHARGER_LTC4162L is not set
|
|
+# CONFIG_CHARGER_DETECTOR_MAX14656 is not set
|
|
+# CONFIG_CHARGER_BQ2415X is not set
|
|
+# CONFIG_CHARGER_BQ24190 is not set
|
|
+# CONFIG_CHARGER_BQ24257 is not set
|
|
+# CONFIG_CHARGER_BQ24735 is not set
|
|
+# CONFIG_CHARGER_BQ2515X is not set
|
|
+# CONFIG_CHARGER_BQ25890 is not set
|
|
+# CONFIG_CHARGER_BQ25980 is not set
|
|
+# CONFIG_CHARGER_BQ256XX is not set
|
|
+# CONFIG_CHARGER_SMB347 is not set
|
|
+# CONFIG_BATTERY_GAUGE_LTC2941 is not set
|
|
+# CONFIG_BATTERY_GOLDFISH is not set
|
|
+# CONFIG_BATTERY_RT5033 is not set
|
|
+# CONFIG_CHARGER_RT9455 is not set
|
|
+# CONFIG_CHARGER_UCS1002 is not set
|
|
+# CONFIG_CHARGER_BD99954 is not set
|
|
+CONFIG_HWMON=y
|
|
+# CONFIG_HWMON_DEBUG_CHIP is not set
|
|
+
|
|
+#
|
|
+# Native drivers
|
|
+#
|
|
+# CONFIG_SENSORS_AD7414 is not set
|
|
+# CONFIG_SENSORS_AD7418 is not set
|
|
+# CONFIG_SENSORS_ADM1021 is not set
|
|
+# CONFIG_SENSORS_ADM1025 is not set
|
|
+# CONFIG_SENSORS_ADM1026 is not set
|
|
+# CONFIG_SENSORS_ADM1029 is not set
|
|
+# CONFIG_SENSORS_ADM1031 is not set
|
|
+# CONFIG_SENSORS_ADM1177 is not set
|
|
+# CONFIG_SENSORS_ADM9240 is not set
|
|
+# CONFIG_SENSORS_ADT7410 is not set
|
|
+# CONFIG_SENSORS_ADT7411 is not set
|
|
+# CONFIG_SENSORS_ADT7462 is not set
|
|
+# CONFIG_SENSORS_ADT7470 is not set
|
|
+# CONFIG_SENSORS_ADT7475 is not set
|
|
+# CONFIG_SENSORS_AHT10 is not set
|
|
+# CONFIG_SENSORS_AS370 is not set
|
|
+# CONFIG_SENSORS_ASC7621 is not set
|
|
+# CONFIG_SENSORS_AXI_FAN_CONTROL is not set
|
|
+# CONFIG_SENSORS_ASPEED is not set
|
|
+# CONFIG_SENSORS_ATXP1 is not set
|
|
+# CONFIG_SENSORS_CORSAIR_CPRO is not set
|
|
+# CONFIG_SENSORS_CORSAIR_PSU is not set
|
|
+# CONFIG_SENSORS_DS620 is not set
|
|
+# CONFIG_SENSORS_DS1621 is not set
|
|
+# CONFIG_SENSORS_DA9052_ADC is not set
|
|
+# CONFIG_SENSORS_F71805F is not set
|
|
+# CONFIG_SENSORS_F71882FG is not set
|
|
+# CONFIG_SENSORS_F75375S is not set
|
|
+CONFIG_SENSORS_MC13783_ADC=y
|
|
+# CONFIG_SENSORS_FTSTEUTATES is not set
|
|
+# CONFIG_SENSORS_GL518SM is not set
|
|
+# CONFIG_SENSORS_GL520SM is not set
|
|
+# CONFIG_SENSORS_G760A is not set
|
|
+# CONFIG_SENSORS_G762 is not set
|
|
+CONFIG_SENSORS_GPIO_FAN=y
|
|
+# CONFIG_SENSORS_HIH6130 is not set
|
|
+# CONFIG_SENSORS_IT87 is not set
|
|
+# CONFIG_SENSORS_JC42 is not set
|
|
+# CONFIG_SENSORS_POWR1220 is not set
|
|
+# CONFIG_SENSORS_LINEAGE is not set
|
|
+# CONFIG_SENSORS_LTC2945 is not set
|
|
+# CONFIG_SENSORS_LTC2947_I2C is not set
|
|
+# CONFIG_SENSORS_LTC2990 is not set
|
|
+# CONFIG_SENSORS_LTC2992 is not set
|
|
+# CONFIG_SENSORS_LTC4151 is not set
|
|
+# CONFIG_SENSORS_LTC4215 is not set
|
|
+# CONFIG_SENSORS_LTC4222 is not set
|
|
+# CONFIG_SENSORS_LTC4245 is not set
|
|
+# CONFIG_SENSORS_LTC4260 is not set
|
|
+# CONFIG_SENSORS_LTC4261 is not set
|
|
+# CONFIG_SENSORS_MAX127 is not set
|
|
+# CONFIG_SENSORS_MAX16065 is not set
|
|
+# CONFIG_SENSORS_MAX1619 is not set
|
|
+# CONFIG_SENSORS_MAX1668 is not set
|
|
+CONFIG_SENSORS_MAX17135=y
|
|
+# CONFIG_SENSORS_MAX197 is not set
|
|
+# CONFIG_SENSORS_MAX31730 is not set
|
|
+# CONFIG_SENSORS_MAX6621 is not set
|
|
+# CONFIG_SENSORS_MAX6639 is not set
|
|
+# CONFIG_SENSORS_MAX6642 is not set
|
|
+# CONFIG_SENSORS_MAX6650 is not set
|
|
+# CONFIG_SENSORS_MAX6697 is not set
|
|
+# CONFIG_SENSORS_MAX31790 is not set
|
|
+# CONFIG_SENSORS_MCP3021 is not set
|
|
+# CONFIG_SENSORS_TC654 is not set
|
|
+# CONFIG_SENSORS_TPS23861 is not set
|
|
+# CONFIG_SENSORS_MR75203 is not set
|
|
+# CONFIG_SENSORS_LM63 is not set
|
|
+# CONFIG_SENSORS_LM73 is not set
|
|
+# CONFIG_SENSORS_LM75 is not set
|
|
+# CONFIG_SENSORS_LM77 is not set
|
|
+# CONFIG_SENSORS_LM78 is not set
|
|
+# CONFIG_SENSORS_LM80 is not set
|
|
+# CONFIG_SENSORS_LM83 is not set
|
|
+# CONFIG_SENSORS_LM85 is not set
|
|
+# CONFIG_SENSORS_LM87 is not set
|
|
+# CONFIG_SENSORS_LM90 is not set
|
|
+# CONFIG_SENSORS_LM92 is not set
|
|
+# CONFIG_SENSORS_LM93 is not set
|
|
+# CONFIG_SENSORS_LM95234 is not set
|
|
+# CONFIG_SENSORS_LM95241 is not set
|
|
+# CONFIG_SENSORS_LM95245 is not set
|
|
+# CONFIG_SENSORS_PC87360 is not set
|
|
+# CONFIG_SENSORS_PC87427 is not set
|
|
+# CONFIG_SENSORS_NTC_THERMISTOR is not set
|
|
+# CONFIG_SENSORS_NCT6683 is not set
|
|
+# CONFIG_SENSORS_NCT6775 is not set
|
|
+# CONFIG_SENSORS_NCT7802 is not set
|
|
+# CONFIG_SENSORS_NCT7904 is not set
|
|
+# CONFIG_SENSORS_NPCM7XX is not set
|
|
+# CONFIG_SENSORS_OCC_P8_I2C is not set
|
|
+# CONFIG_SENSORS_PCF8591 is not set
|
|
+# CONFIG_PMBUS is not set
|
|
+# CONFIG_SENSORS_SBTSI is not set
|
|
+# CONFIG_SENSORS_SBRMI is not set
|
|
+# CONFIG_SENSORS_SHT15 is not set
|
|
+# CONFIG_SENSORS_SHT21 is not set
|
|
+# CONFIG_SENSORS_SHT3x is not set
|
|
+# CONFIG_SENSORS_SHT4x is not set
|
|
+# CONFIG_SENSORS_SHTC1 is not set
|
|
+# CONFIG_SENSORS_DME1737 is not set
|
|
+# CONFIG_SENSORS_EMC1403 is not set
|
|
+# CONFIG_SENSORS_EMC2103 is not set
|
|
+# CONFIG_SENSORS_EMC6W201 is not set
|
|
+# CONFIG_SENSORS_SMSC47M1 is not set
|
|
+# CONFIG_SENSORS_SMSC47M192 is not set
|
|
+# CONFIG_SENSORS_SMSC47B397 is not set
|
|
+# CONFIG_SENSORS_SCH5627 is not set
|
|
+# CONFIG_SENSORS_SCH5636 is not set
|
|
+# CONFIG_SENSORS_STTS751 is not set
|
|
+# CONFIG_SENSORS_SMM665 is not set
|
|
+# CONFIG_SENSORS_ADC128D818 is not set
|
|
+# CONFIG_SENSORS_ADS7828 is not set
|
|
+# CONFIG_SENSORS_AMC6821 is not set
|
|
+# CONFIG_SENSORS_INA209 is not set
|
|
+# CONFIG_SENSORS_INA2XX is not set
|
|
+# CONFIG_SENSORS_INA3221 is not set
|
|
+# CONFIG_SENSORS_TC74 is not set
|
|
+# CONFIG_SENSORS_THMC50 is not set
|
|
+# CONFIG_SENSORS_TMP102 is not set
|
|
+# CONFIG_SENSORS_TMP103 is not set
|
|
+# CONFIG_SENSORS_TMP108 is not set
|
|
+# CONFIG_SENSORS_TMP401 is not set
|
|
+# CONFIG_SENSORS_TMP421 is not set
|
|
+# CONFIG_SENSORS_TMP513 is not set
|
|
+# CONFIG_SENSORS_VT1211 is not set
|
|
+# CONFIG_SENSORS_W83773G is not set
|
|
+# CONFIG_SENSORS_W83781D is not set
|
|
+# CONFIG_SENSORS_W83791D is not set
|
|
+# CONFIG_SENSORS_W83792D is not set
|
|
+# CONFIG_SENSORS_W83793 is not set
|
|
+# CONFIG_SENSORS_W83795 is not set
|
|
+# CONFIG_SENSORS_W83L785TS is not set
|
|
+# CONFIG_SENSORS_W83L786NG is not set
|
|
+# CONFIG_SENSORS_W83627HF is not set
|
|
+# CONFIG_SENSORS_W83627EHF is not set
|
|
+CONFIG_THERMAL=y
|
|
+# CONFIG_THERMAL_NETLINK is not set
|
|
+CONFIG_THERMAL_STATISTICS=y
|
|
+CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
|
|
+CONFIG_THERMAL_HWMON=y
|
|
+CONFIG_THERMAL_OF=y
|
|
+CONFIG_THERMAL_WRITABLE_TRIPS=y
|
|
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
|
|
+# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
|
|
+# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
|
|
+# CONFIG_THERMAL_GOV_FAIR_SHARE is not set
|
|
+CONFIG_THERMAL_GOV_STEP_WISE=y
|
|
+# CONFIG_THERMAL_GOV_BANG_BANG is not set
|
|
+# CONFIG_THERMAL_GOV_USER_SPACE is not set
|
|
+CONFIG_CPU_THERMAL=y
|
|
+CONFIG_CPU_FREQ_THERMAL=y
|
|
+# CONFIG_THERMAL_EMULATION is not set
|
|
+# CONFIG_THERMAL_MMIO is not set
|
|
+CONFIG_IMX_THERMAL=y
|
|
+# CONFIG_IMX8MM_THERMAL is not set
|
|
+CONFIG_DEVICE_THERMAL=y
|
|
+# CONFIG_DA9062_THERMAL is not set
|
|
+CONFIG_WATCHDOG=y
|
|
+CONFIG_WATCHDOG_CORE=y
|
|
+# CONFIG_WATCHDOG_NOWAYOUT is not set
|
|
+CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED=y
|
|
+CONFIG_WATCHDOG_OPEN_TIMEOUT=0
|
|
+# CONFIG_WATCHDOG_SYSFS is not set
|
|
+# CONFIG_WATCHDOG_HRTIMER_PRETIMEOUT is not set
|
|
+
|
|
+#
|
|
+# Watchdog Pretimeout Governors
|
|
+#
|
|
+# CONFIG_WATCHDOG_PRETIMEOUT_GOV is not set
|
|
+
|
|
+#
|
|
+# Watchdog Device Drivers
|
|
+#
|
|
+# CONFIG_SOFT_WATCHDOG is not set
|
|
+# CONFIG_DA9052_WATCHDOG is not set
|
|
+CONFIG_DA9063_WATCHDOG=y
|
|
+CONFIG_DA9062_WATCHDOG=y
|
|
+# CONFIG_GPIO_WATCHDOG is not set
|
|
+# CONFIG_XILINX_WATCHDOG is not set
|
|
+# CONFIG_ZIIRAVE_WATCHDOG is not set
|
|
+# CONFIG_CADENCE_WATCHDOG is not set
|
|
+# CONFIG_FTWDT010_WATCHDOG is not set
|
|
+# CONFIG_DW_WATCHDOG is not set
|
|
+CONFIG_RN5T618_WATCHDOG=y
|
|
+# CONFIG_MAX63XX_WATCHDOG is not set
|
|
+CONFIG_IMX2_WDT=y
|
|
+CONFIG_IMX7ULP_WDT=y
|
|
+# CONFIG_ARM_SMC_WATCHDOG is not set
|
|
+# CONFIG_MEN_A21_WDT is not set
|
|
+CONFIG_SSB_POSSIBLE=y
|
|
+# CONFIG_SSB is not set
|
|
+CONFIG_BCMA_POSSIBLE=y
|
|
+# CONFIG_BCMA is not set
|
|
+
|
|
+#
|
|
+# Multifunction device drivers
|
|
+#
|
|
+CONFIG_MFD_CORE=y
|
|
+# CONFIG_MFD_ADP5585 is not set
|
|
+# CONFIG_MFD_ACT8945A is not set
|
|
+# CONFIG_MFD_AS3711 is not set
|
|
+# CONFIG_MFD_AS3722 is not set
|
|
+# CONFIG_PMIC_ADP5520 is not set
|
|
+# CONFIG_MFD_AAT2870_CORE is not set
|
|
+# CONFIG_MFD_ATMEL_FLEXCOM is not set
|
|
+# CONFIG_MFD_ATMEL_HLCDC is not set
|
|
+# CONFIG_MFD_BCM590XX is not set
|
|
+# CONFIG_MFD_BD9571MWV is not set
|
|
+# CONFIG_MFD_AXP20X_I2C is not set
|
|
+# CONFIG_MFD_MADERA is not set
|
|
+# CONFIG_MFD_ASIC3 is not set
|
|
+# CONFIG_PMIC_DA903X is not set
|
|
+CONFIG_PMIC_DA9052=y
|
|
+CONFIG_MFD_DA9052_I2C=y
|
|
+# CONFIG_MFD_DA9055 is not set
|
|
+CONFIG_MFD_DA9062=y
|
|
+CONFIG_MFD_DA9063=y
|
|
+# CONFIG_MFD_DA9150 is not set
|
|
+# CONFIG_MFD_GATEWORKS_GSC is not set
|
|
+CONFIG_MFD_MC13XXX=y
|
|
+CONFIG_MFD_MC13XXX_I2C=y
|
|
+# CONFIG_MFD_MP2629 is not set
|
|
+# CONFIG_MFD_IMX_MIX is not set
|
|
+CONFIG_MFD_MXC_HDMI=y
|
|
+# CONFIG_MFD_HI6421_PMIC is not set
|
|
+# CONFIG_HTC_PASIC3 is not set
|
|
+# CONFIG_HTC_I2CPLD is not set
|
|
+# CONFIG_MFD_IQS62X is not set
|
|
+# CONFIG_MFD_KEMPLD is not set
|
|
+# CONFIG_MFD_88PM800 is not set
|
|
+# CONFIG_MFD_88PM805 is not set
|
|
+# CONFIG_MFD_88PM860X is not set
|
|
+# CONFIG_MFD_MAX14577 is not set
|
|
+CONFIG_MFD_MAX17135=y
|
|
+# CONFIG_MFD_FP9931 is not set
|
|
+# CONFIG_MFD_MAX77620 is not set
|
|
+# CONFIG_MFD_MAX77650 is not set
|
|
+# CONFIG_MFD_MAX77686 is not set
|
|
+# CONFIG_MFD_MAX77693 is not set
|
|
+# CONFIG_MFD_MAX77843 is not set
|
|
+# CONFIG_MFD_MAX8907 is not set
|
|
+# CONFIG_MFD_MAX8925 is not set
|
|
+# CONFIG_MFD_MAX8997 is not set
|
|
+# CONFIG_MFD_MAX8998 is not set
|
|
+# CONFIG_MFD_MT6360 is not set
|
|
+# CONFIG_MFD_MT6397 is not set
|
|
+# CONFIG_MFD_MENF21BMC is not set
|
|
+# CONFIG_MFD_NTXEC is not set
|
|
+# CONFIG_MFD_RETU is not set
|
|
+# CONFIG_MFD_PCF50633 is not set
|
|
+# CONFIG_MFD_PM8XXX is not set
|
|
+# CONFIG_MFD_RT4831 is not set
|
|
+# CONFIG_MFD_RT5033 is not set
|
|
+# CONFIG_MFD_RC5T583 is not set
|
|
+# CONFIG_MFD_RK808 is not set
|
|
+CONFIG_MFD_RN5T618=y
|
|
+# CONFIG_MFD_SEC_CORE is not set
|
|
+CONFIG_MFD_SI476X_CORE=y
|
|
+# CONFIG_MFD_SM501 is not set
|
|
+# CONFIG_MFD_SKY81452 is not set
|
|
+# CONFIG_MFD_STMPE is not set
|
|
+CONFIG_MFD_SYSCON=y
|
|
+# CONFIG_MFD_TI_AM335X_TSCADC is not set
|
|
+# CONFIG_MFD_LP3943 is not set
|
|
+# CONFIG_MFD_LP8788 is not set
|
|
+# CONFIG_MFD_TI_LMU is not set
|
|
+# CONFIG_MFD_PALMAS is not set
|
|
+# CONFIG_TPS6105X is not set
|
|
+# CONFIG_TPS65010 is not set
|
|
+# CONFIG_TPS6507X is not set
|
|
+# CONFIG_MFD_TPS65086 is not set
|
|
+# CONFIG_MFD_TPS65090 is not set
|
|
+# CONFIG_MFD_TPS65217 is not set
|
|
+# CONFIG_MFD_TI_LP873X is not set
|
|
+# CONFIG_MFD_TI_LP87565 is not set
|
|
+# CONFIG_MFD_TPS65218 is not set
|
|
+# CONFIG_MFD_TPS6586X is not set
|
|
+# CONFIG_MFD_TPS65910 is not set
|
|
+# CONFIG_MFD_TPS65912_I2C is not set
|
|
+# CONFIG_MFD_TPS80031 is not set
|
|
+# CONFIG_TWL4030_CORE is not set
|
|
+# CONFIG_TWL6040_CORE is not set
|
|
+# CONFIG_MFD_WL1273_CORE is not set
|
|
+# CONFIG_MFD_LM3533 is not set
|
|
+# CONFIG_MFD_TC3589X is not set
|
|
+# CONFIG_MFD_T7L66XB is not set
|
|
+# CONFIG_MFD_TC6387XB is not set
|
|
+# CONFIG_MFD_TC6393XB is not set
|
|
+# CONFIG_MFD_TQMX86 is not set
|
|
+# CONFIG_MFD_LOCHNAGAR is not set
|
|
+# CONFIG_MFD_ARIZONA_I2C is not set
|
|
+# CONFIG_MFD_WM8400 is not set
|
|
+# CONFIG_MFD_WM831X_I2C is not set
|
|
+# CONFIG_MFD_WM8350_I2C is not set
|
|
+CONFIG_MFD_WM8994=y
|
|
+# CONFIG_MFD_ROHM_BD718XX is not set
|
|
+# CONFIG_MFD_ROHM_BD70528 is not set
|
|
+# CONFIG_MFD_ROHM_BD71828 is not set
|
|
+# CONFIG_MFD_ROHM_BD957XMUF is not set
|
|
+# CONFIG_MFD_STPMIC1 is not set
|
|
+# CONFIG_MFD_STMFX is not set
|
|
+# CONFIG_MFD_ATC260X_I2C is not set
|
|
+# CONFIG_MFD_QCOM_PM8008 is not set
|
|
+# CONFIG_RAVE_SP_CORE is not set
|
|
+# CONFIG_MFD_RSMU_I2C is not set
|
|
+# end of Multifunction device drivers
|
|
+
|
|
+CONFIG_REGULATOR=y
|
|
+# CONFIG_REGULATOR_DEBUG is not set
|
|
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
|
|
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
|
|
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
|
|
+# CONFIG_REGULATOR_88PG86X is not set
|
|
+# CONFIG_REGULATOR_ACT8865 is not set
|
|
+# CONFIG_REGULATOR_AD5398 is not set
|
|
+CONFIG_REGULATOR_ANATOP=y
|
|
+CONFIG_REGULATOR_DA9052=y
|
|
+CONFIG_REGULATOR_DA9062=y
|
|
+CONFIG_REGULATOR_DA9063=y
|
|
+# CONFIG_REGULATOR_DA9121 is not set
|
|
+# CONFIG_REGULATOR_DA9210 is not set
|
|
+# CONFIG_REGULATOR_DA9211 is not set
|
|
+# CONFIG_REGULATOR_FAN53555 is not set
|
|
+# CONFIG_REGULATOR_FAN53880 is not set
|
|
+CONFIG_REGULATOR_GPIO=y
|
|
+# CONFIG_REGULATOR_ISL9305 is not set
|
|
+# CONFIG_REGULATOR_ISL6271A is not set
|
|
+# CONFIG_REGULATOR_LP3971 is not set
|
|
+# CONFIG_REGULATOR_LP3972 is not set
|
|
+# CONFIG_REGULATOR_LP872X is not set
|
|
+# CONFIG_REGULATOR_LP8755 is not set
|
|
+# CONFIG_REGULATOR_LTC3589 is not set
|
|
+CONFIG_REGULATOR_LTC3676=y
|
|
+# CONFIG_REGULATOR_MAX1586 is not set
|
|
+CONFIG_REGULATOR_MAX17135=y
|
|
+# CONFIG_REGULATOR_MAX8649 is not set
|
|
+# CONFIG_REGULATOR_MAX8660 is not set
|
|
+# CONFIG_REGULATOR_MAX8893 is not set
|
|
+# CONFIG_REGULATOR_MAX8952 is not set
|
|
+# CONFIG_REGULATOR_MAX8973 is not set
|
|
+# CONFIG_REGULATOR_MAX77826 is not set
|
|
+CONFIG_REGULATOR_MC13XXX_CORE=y
|
|
+CONFIG_REGULATOR_MC13783=y
|
|
+CONFIG_REGULATOR_MC13892=y
|
|
+# CONFIG_REGULATOR_MCP16502 is not set
|
|
+# CONFIG_REGULATOR_MP5416 is not set
|
|
+# CONFIG_REGULATOR_MP8859 is not set
|
|
+# CONFIG_REGULATOR_MP886X is not set
|
|
+# CONFIG_REGULATOR_MPQ7920 is not set
|
|
+# CONFIG_REGULATOR_MT6311 is not set
|
|
+# CONFIG_REGULATOR_PCA9450 is not set
|
|
+# CONFIG_REGULATOR_PF8X00 is not set
|
|
+# CONFIG_REGULATOR_PF1550_RPMSG is not set
|
|
+CONFIG_REGULATOR_PFUZE100=y
|
|
+# CONFIG_REGULATOR_PV88060 is not set
|
|
+# CONFIG_REGULATOR_PV88080 is not set
|
|
+# CONFIG_REGULATOR_PV88090 is not set
|
|
+# CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY is not set
|
|
+CONFIG_REGULATOR_RN5T618=y
|
|
+# CONFIG_REGULATOR_RT4801 is not set
|
|
+# CONFIG_REGULATOR_RT6160 is not set
|
|
+# CONFIG_REGULATOR_RT6245 is not set
|
|
+# CONFIG_REGULATOR_RTQ2134 is not set
|
|
+# CONFIG_REGULATOR_RTMV20 is not set
|
|
+# CONFIG_REGULATOR_RTQ6752 is not set
|
|
+# CONFIG_REGULATOR_SLG51000 is not set
|
|
+# CONFIG_REGULATOR_SY8106A is not set
|
|
+# CONFIG_REGULATOR_SY8824X is not set
|
|
+# CONFIG_REGULATOR_SY8827N is not set
|
|
+# CONFIG_REGULATOR_TPS51632 is not set
|
|
+# CONFIG_REGULATOR_TPS62360 is not set
|
|
+# CONFIG_REGULATOR_TPS65023 is not set
|
|
+# CONFIG_REGULATOR_TPS6507X is not set
|
|
+# CONFIG_REGULATOR_TPS65132 is not set
|
|
+# CONFIG_REGULATOR_VCTRL is not set
|
|
+# CONFIG_REGULATOR_WM8994 is not set
|
|
+# CONFIG_RC_CORE is not set
|
|
+# CONFIG_MEDIA_CEC_SUPPORT is not set
|
|
+# CONFIG_MEDIA_SUPPORT is not set
|
|
+
|
|
+#
|
|
+# Graphics support
|
|
+#
|
|
+# CONFIG_IMX_IPUV3_CORE is not set
|
|
+# CONFIG_IMX_DPU_CORE is not set
|
|
+# CONFIG_IMX_LCDIF_CORE is not set
|
|
+# CONFIG_IMX_LCDIFV3_CORE is not set
|
|
+CONFIG_DRM=y
|
|
+# CONFIG_DRM_DP_AUX_CHARDEV is not set
|
|
+# CONFIG_DRM_DEBUG_MM is not set
|
|
+# CONFIG_DRM_DEBUG_SELFTEST is not set
|
|
+CONFIG_DRM_KMS_HELPER=y
|
|
+# CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS is not set
|
|
+# CONFIG_DRM_LOAD_EDID_FIRMWARE is not set
|
|
+# CONFIG_DRM_DP_CEC is not set
|
|
+
|
|
+#
|
|
+# I2C encoder or helper chips
|
|
+#
|
|
+# CONFIG_DRM_I2C_CH7006 is not set
|
|
+# CONFIG_DRM_I2C_SIL164 is not set
|
|
+# CONFIG_DRM_I2C_NXP_TDA998X is not set
|
|
+# CONFIG_DRM_I2C_NXP_TDA9950 is not set
|
|
+# end of I2C encoder or helper chips
|
|
+
|
|
+#
|
|
+# ARM devices
|
|
+#
|
|
+# CONFIG_DRM_HDLCD is not set
|
|
+# CONFIG_DRM_MALI_DISPLAY is not set
|
|
+# CONFIG_DRM_KOMEDA is not set
|
|
+# end of ARM devices
|
|
+
|
|
+# CONFIG_DRM_VGEM is not set
|
|
+# CONFIG_DRM_VKMS is not set
|
|
+# CONFIG_DRM_EXYNOS is not set
|
|
+# CONFIG_DRM_ARMADA is not set
|
|
+# CONFIG_DRM_RCAR_DW_HDMI is not set
|
|
+# CONFIG_DRM_RCAR_LVDS is not set
|
|
+# CONFIG_DRM_OMAP is not set
|
|
+# CONFIG_DRM_TILCDC is not set
|
|
+# CONFIG_DRM_FSL_DCU is not set
|
|
+# CONFIG_DRM_STM is not set
|
|
+CONFIG_DRM_PANEL=y
|
|
+
|
|
+#
|
|
+# Display Panels
|
|
+#
|
|
+# CONFIG_DRM_PANEL_ARM_VERSATILE is not set
|
|
+CONFIG_DRM_PANEL_LVDS=y
|
|
+# CONFIG_DRM_PANEL_OLIMEX_LCD_OLINUXINO is not set
|
|
+# CONFIG_DRM_PANEL_SAMSUNG_S6E63M0 is not set
|
|
+# CONFIG_DRM_PANEL_SAMSUNG_S6E88A0_AMS452EF01 is not set
|
|
+# CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set
|
|
+CONFIG_DRM_PANEL_SEIKO_43WVF1G=y
|
|
+# CONFIG_DRM_PANEL_SHARP_LS037V7DW01 is not set
|
|
+# CONFIG_DRM_PANEL_WKS_101WX001 is not set
|
|
+# end of Display Panels
|
|
+
|
|
+CONFIG_DRM_BRIDGE=y
|
|
+CONFIG_DRM_PANEL_BRIDGE=y
|
|
+
|
|
+#
|
|
+# Display Interface Bridges
|
|
+#
|
|
+# CONFIG_DRM_CDNS_DSI is not set
|
|
+# CONFIG_DRM_CHIPONE_ICN6211 is not set
|
|
+# CONFIG_DRM_CHRONTEL_CH7033 is not set
|
|
+# CONFIG_DRM_DISPLAY_CONNECTOR is not set
|
|
+# CONFIG_DRM_LONTIUM_LT8912B is not set
|
|
+# CONFIG_DRM_LONTIUM_LT9611 is not set
|
|
+# CONFIG_DRM_LONTIUM_LT9611UXC is not set
|
|
+# CONFIG_DRM_ITE_IT66121 is not set
|
|
+# CONFIG_DRM_FSL_IMX_LVDS_BRIDGE is not set
|
|
+# CONFIG_DRM_LVDS_CODEC is not set
|
|
+# CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW is not set
|
|
+# CONFIG_DRM_NWL_MIPI_DSI is not set
|
|
+# CONFIG_DRM_SEC_MIPI_DSIM is not set
|
|
+# CONFIG_DRM_NXP_SEIKO_43WVFIG is not set
|
|
+# CONFIG_DRM_NXP_PTN3460 is not set
|
|
+# CONFIG_DRM_PARADE_PS8622 is not set
|
|
+# CONFIG_DRM_PARADE_PS8640 is not set
|
|
+# CONFIG_DRM_SIL_SII8620 is not set
|
|
+# CONFIG_DRM_SII902X is not set
|
|
+# CONFIG_DRM_SII9234 is not set
|
|
+# CONFIG_DRM_SIMPLE_BRIDGE is not set
|
|
+# CONFIG_DRM_THINE_THC63LVD1024 is not set
|
|
+# CONFIG_DRM_TOSHIBA_TC358762 is not set
|
|
+# CONFIG_DRM_TOSHIBA_TC358764 is not set
|
|
+# CONFIG_DRM_TOSHIBA_TC358767 is not set
|
|
+# CONFIG_DRM_TOSHIBA_TC358768 is not set
|
|
+# CONFIG_DRM_TOSHIBA_TC358775 is not set
|
|
+CONFIG_DRM_TI_TFP410=y
|
|
+# CONFIG_DRM_TI_SN65DSI83 is not set
|
|
+# CONFIG_DRM_TI_SN65DSI86 is not set
|
|
+# CONFIG_DRM_TI_TPD12S015 is not set
|
|
+# CONFIG_DRM_ANALOGIX_ANX6345 is not set
|
|
+# CONFIG_DRM_ANALOGIX_ANX78XX is not set
|
|
+# CONFIG_DRM_ANALOGIX_ANX7625 is not set
|
|
+# CONFIG_DRM_I2C_ADV7511 is not set
|
|
+# CONFIG_DRM_CDNS_MHDP8546 is not set
|
|
+# CONFIG_DRM_CDNS_MHDP is not set
|
|
+# CONFIG_DRM_CDNS_HDMI_CEC is not set
|
|
+# CONFIG_DRM_ITE_IT6263 is not set
|
|
+# CONFIG_DRM_ITE_IT6161 is not set
|
|
+# end of Display Interface Bridges
|
|
+
|
|
+# CONFIG_DRM_STI is not set
|
|
+# CONFIG_IMX8MP_HDMI_PAVI is not set
|
|
+# CONFIG_DRM_IMX_DCNANO is not set
|
|
+# CONFIG_DRM_ETNAVIV is not set
|
|
+# CONFIG_DRM_MXSFB is not set
|
|
+# CONFIG_DRM_ARCPGU is not set
|
|
+# CONFIG_DRM_SIMPLEDRM is not set
|
|
+# CONFIG_DRM_PL111 is not set
|
|
+# CONFIG_DRM_TVE200 is not set
|
|
+# CONFIG_DRM_LIMA is not set
|
|
+# CONFIG_DRM_PANFROST is not set
|
|
+# CONFIG_DRM_MCDE is not set
|
|
+# CONFIG_DRM_TIDSS is not set
|
|
+# CONFIG_DRM_LEGACY is not set
|
|
+CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=y
|
|
+
|
|
+#
|
|
+# Frame buffer Devices
|
|
+#
|
|
+CONFIG_FB_CMDLINE=y
|
|
+# CONFIG_FB is not set
|
|
+# CONFIG_FB_MXC_DISP_FRAMEWORK is not set
|
|
+# end of Frame buffer Devices
|
|
+
|
|
+#
|
|
+# Backlight & LCD device support
|
|
+#
|
|
+CONFIG_LCD_CLASS_DEVICE=y
|
|
+CONFIG_LCD_PLATFORM=y
|
|
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
|
|
+# CONFIG_BACKLIGHT_KTD253 is not set
|
|
+# CONFIG_BACKLIGHT_DA9052 is not set
|
|
+# CONFIG_BACKLIGHT_QCOM_WLED is not set
|
|
+# CONFIG_BACKLIGHT_ADP8860 is not set
|
|
+# CONFIG_BACKLIGHT_ADP8870 is not set
|
|
+# CONFIG_BACKLIGHT_LM3639 is not set
|
|
+CONFIG_BACKLIGHT_GPIO=y
|
|
+# CONFIG_BACKLIGHT_LV5207LP is not set
|
|
+# CONFIG_BACKLIGHT_BD6107 is not set
|
|
+# CONFIG_BACKLIGHT_ARCXCNN is not set
|
|
+# end of Backlight & LCD device support
|
|
+
|
|
+CONFIG_VIDEOMODE_HELPERS=y
|
|
+CONFIG_HDMI=y
|
|
+
|
|
+#
|
|
+# Console display driver support
|
|
+#
|
|
+CONFIG_DUMMY_CONSOLE=y
|
|
+# end of Console display driver support
|
|
+# end of Graphics support
|
|
+
|
|
+# CONFIG_SOUND is not set
|
|
+
|
|
+#
|
|
+# HID support
|
|
+#
|
|
+CONFIG_HID=y
|
|
+# CONFIG_HID_BATTERY_STRENGTH is not set
|
|
+# CONFIG_HIDRAW is not set
|
|
+# CONFIG_UHID is not set
|
|
+CONFIG_HID_GENERIC=y
|
|
+
|
|
+#
|
|
+# Special HID drivers
|
|
+#
|
|
+# CONFIG_HID_A4TECH is not set
|
|
+# CONFIG_HID_ACRUX is not set
|
|
+# CONFIG_HID_APPLE is not set
|
|
+# CONFIG_HID_AUREAL is not set
|
|
+# CONFIG_HID_BELKIN is not set
|
|
+# CONFIG_HID_CHERRY is not set
|
|
+# CONFIG_HID_COUGAR is not set
|
|
+# CONFIG_HID_MACALLY is not set
|
|
+# CONFIG_HID_CMEDIA is not set
|
|
+# CONFIG_HID_CYPRESS is not set
|
|
+# CONFIG_HID_DRAGONRISE is not set
|
|
+# CONFIG_HID_EMS_FF is not set
|
|
+# CONFIG_HID_ELECOM is not set
|
|
+# CONFIG_HID_EZKEY is not set
|
|
+# CONFIG_HID_GEMBIRD is not set
|
|
+# CONFIG_HID_GFRM is not set
|
|
+# CONFIG_HID_GLORIOUS is not set
|
|
+# CONFIG_HID_VIVALDI is not set
|
|
+# CONFIG_HID_KEYTOUCH is not set
|
|
+# CONFIG_HID_KYE is not set
|
|
+# CONFIG_HID_WALTOP is not set
|
|
+# CONFIG_HID_VIEWSONIC is not set
|
|
+# CONFIG_HID_GYRATION is not set
|
|
+# CONFIG_HID_ICADE is not set
|
|
+# CONFIG_HID_ITE is not set
|
|
+# CONFIG_HID_JABRA is not set
|
|
+# CONFIG_HID_TWINHAN is not set
|
|
+# CONFIG_HID_KENSINGTON is not set
|
|
+# CONFIG_HID_LCPOWER is not set
|
|
+# CONFIG_HID_LENOVO is not set
|
|
+# CONFIG_HID_MAGICMOUSE is not set
|
|
+# CONFIG_HID_MALTRON is not set
|
|
+# CONFIG_HID_MAYFLASH is not set
|
|
+# CONFIG_HID_REDRAGON is not set
|
|
+# CONFIG_HID_MICROSOFT is not set
|
|
+# CONFIG_HID_MONTEREY is not set
|
|
+CONFIG_HID_MULTITOUCH=y
|
|
+# CONFIG_HID_NTI is not set
|
|
+# CONFIG_HID_ORTEK is not set
|
|
+# CONFIG_HID_PANTHERLORD is not set
|
|
+# CONFIG_HID_PETALYNX is not set
|
|
+# CONFIG_HID_PICOLCD is not set
|
|
+# CONFIG_HID_PLANTRONICS is not set
|
|
+# CONFIG_HID_PLAYSTATION is not set
|
|
+# CONFIG_HID_PRIMAX is not set
|
|
+# CONFIG_HID_SAITEK is not set
|
|
+# CONFIG_HID_SEMITEK is not set
|
|
+# CONFIG_HID_SPEEDLINK is not set
|
|
+# CONFIG_HID_STEAM is not set
|
|
+# CONFIG_HID_STEELSERIES is not set
|
|
+# CONFIG_HID_SUNPLUS is not set
|
|
+# CONFIG_HID_RMI is not set
|
|
+# CONFIG_HID_GREENASIA is not set
|
|
+# CONFIG_HID_SMARTJOYPLUS is not set
|
|
+# CONFIG_HID_TIVO is not set
|
|
+# CONFIG_HID_TOPSEED is not set
|
|
+# CONFIG_HID_UDRAW_PS3 is not set
|
|
+# CONFIG_HID_XINMO is not set
|
|
+# CONFIG_HID_ZEROPLUS is not set
|
|
+# CONFIG_HID_ZYDACRON is not set
|
|
+# CONFIG_HID_SENSOR_HUB is not set
|
|
+# CONFIG_HID_ALPS is not set
|
|
+# end of Special HID drivers
|
|
+
|
|
+#
|
|
+# I2C HID support
|
|
+#
|
|
+# CONFIG_I2C_HID_OF is not set
|
|
+# CONFIG_I2C_HID_OF_GOODIX is not set
|
|
+# end of I2C HID support
|
|
+# end of HID support
|
|
+
|
|
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
|
|
+# CONFIG_USB_SUPPORT is not set
|
|
+CONFIG_MMC=y
|
|
+CONFIG_PWRSEQ_EMMC=y
|
|
+CONFIG_PWRSEQ_SIMPLE=y
|
|
+CONFIG_MMC_BLOCK=y
|
|
+CONFIG_MMC_BLOCK_MINORS=8
|
|
+# CONFIG_SDIO_UART is not set
|
|
+# CONFIG_MMC_TEST is not set
|
|
+
|
|
+#
|
|
+# MMC/SD/SDIO Host Controller Drivers
|
|
+#
|
|
+# CONFIG_MMC_DEBUG is not set
|
|
+CONFIG_MMC_SDHCI=y
|
|
+CONFIG_MMC_SDHCI_IO_ACCESSORS=y
|
|
+CONFIG_MMC_SDHCI_PLTFM=y
|
|
+# CONFIG_MMC_SDHCI_OF_ARASAN is not set
|
|
+# CONFIG_MMC_SDHCI_OF_ASPEED is not set
|
|
+# CONFIG_MMC_SDHCI_OF_AT91 is not set
|
|
+# CONFIG_MMC_SDHCI_OF_ESDHC is not set
|
|
+# CONFIG_MMC_SDHCI_OF_DWCMSHC is not set
|
|
+# CONFIG_MMC_SDHCI_CADENCE is not set
|
|
+CONFIG_MMC_SDHCI_ESDHC_IMX=y
|
|
+# CONFIG_MMC_SDHCI_F_SDH30 is not set
|
|
+# CONFIG_MMC_SDHCI_MILBEAUT is not set
|
|
+# CONFIG_MMC_MXC is not set
|
|
+# CONFIG_MMC_DW is not set
|
|
+# CONFIG_MMC_USDHI6ROL0 is not set
|
|
+CONFIG_MMC_CQHCI=y
|
|
+# CONFIG_MMC_HSQ is not set
|
|
+# CONFIG_MMC_MTK is not set
|
|
+# CONFIG_MMC_SDHCI_XENON is not set
|
|
+# CONFIG_MMC_SDHCI_OMAP is not set
|
|
+# CONFIG_MMC_SDHCI_AM654 is not set
|
|
+# CONFIG_MEMSTICK is not set
|
|
+# CONFIG_NEW_LEDS is not set
|
|
+# CONFIG_ACCESSIBILITY is not set
|
|
+# CONFIG_INFINIBAND is not set
|
|
+CONFIG_EDAC_ATOMIC_SCRUB=y
|
|
+CONFIG_EDAC_SUPPORT=y
|
|
+CONFIG_RTC_LIB=y
|
|
+CONFIG_RTC_CLASS=y
|
|
+CONFIG_RTC_HCTOSYS=y
|
|
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
|
|
+CONFIG_RTC_SYSTOHC=y
|
|
+CONFIG_RTC_SYSTOHC_DEVICE="rtc0"
|
|
+# CONFIG_RTC_DEBUG is not set
|
|
+CONFIG_RTC_NVMEM=y
|
|
+
|
|
+#
|
|
+# RTC interfaces
|
|
+#
|
|
+CONFIG_RTC_INTF_SYSFS=y
|
|
+CONFIG_RTC_INTF_PROC=y
|
|
+CONFIG_RTC_INTF_DEV=y
|
|
+CONFIG_RTC_INTF_DEV_UIE_EMUL=y
|
|
+# CONFIG_RTC_DRV_TEST is not set
|
|
+
|
|
+#
|
|
+# I2C RTC drivers
|
|
+#
|
|
+# CONFIG_RTC_DRV_ABB5ZES3 is not set
|
|
+# CONFIG_RTC_DRV_ABEOZ9 is not set
|
|
+# CONFIG_RTC_DRV_ABX80X is not set
|
|
+CONFIG_RTC_DRV_DS1307=y
|
|
+# CONFIG_RTC_DRV_DS1307_CENTURY is not set
|
|
+# CONFIG_RTC_DRV_DS1374 is not set
|
|
+# CONFIG_RTC_DRV_DS1672 is not set
|
|
+# CONFIG_RTC_DRV_HYM8563 is not set
|
|
+# CONFIG_RTC_DRV_MAX6900 is not set
|
|
+# CONFIG_RTC_DRV_RS5C372 is not set
|
|
+CONFIG_RTC_DRV_ISL1208=y
|
|
+# CONFIG_RTC_DRV_ISL12022 is not set
|
|
+# CONFIG_RTC_DRV_ISL12026 is not set
|
|
+# CONFIG_RTC_DRV_X1205 is not set
|
|
+CONFIG_RTC_DRV_PCF8523=y
|
|
+# CONFIG_RTC_DRV_PCF85063 is not set
|
|
+# CONFIG_RTC_DRV_PCF85363 is not set
|
|
+CONFIG_RTC_DRV_PCF8563=y
|
|
+# CONFIG_RTC_DRV_PCF8583 is not set
|
|
+CONFIG_RTC_DRV_M41T80=y
|
|
+# CONFIG_RTC_DRV_M41T80_WDT is not set
|
|
+# CONFIG_RTC_DRV_BQ32K is not set
|
|
+CONFIG_RTC_DRV_RC5T619=y
|
|
+# CONFIG_RTC_DRV_S35390A is not set
|
|
+# CONFIG_RTC_DRV_FM3130 is not set
|
|
+# CONFIG_RTC_DRV_RX8010 is not set
|
|
+# CONFIG_RTC_DRV_RX8581 is not set
|
|
+# CONFIG_RTC_DRV_RX8025 is not set
|
|
+# CONFIG_RTC_DRV_EM3027 is not set
|
|
+# CONFIG_RTC_DRV_RV3028 is not set
|
|
+# CONFIG_RTC_DRV_RV3032 is not set
|
|
+# CONFIG_RTC_DRV_RV8803 is not set
|
|
+# CONFIG_RTC_DRV_SD3078 is not set
|
|
+
|
|
+#
|
|
+# SPI RTC drivers
|
|
+#
|
|
+CONFIG_RTC_I2C_AND_SPI=y
|
|
+
|
|
+#
|
|
+# SPI and I2C RTC drivers
|
|
+#
|
|
+# CONFIG_RTC_DRV_DS3232 is not set
|
|
+# CONFIG_RTC_DRV_PCF2127 is not set
|
|
+# CONFIG_RTC_DRV_RV3029C2 is not set
|
|
+# CONFIG_RTC_DRV_RX6110 is not set
|
|
+
|
|
+#
|
|
+# Platform RTC drivers
|
|
+#
|
|
+# CONFIG_RTC_DRV_CMOS is not set
|
|
+# CONFIG_RTC_DRV_DS1286 is not set
|
|
+# CONFIG_RTC_DRV_DS1511 is not set
|
|
+# CONFIG_RTC_DRV_DS1553 is not set
|
|
+# CONFIG_RTC_DRV_DS1685_FAMILY is not set
|
|
+# CONFIG_RTC_DRV_DS1742 is not set
|
|
+# CONFIG_RTC_DRV_DS2404 is not set
|
|
+# CONFIG_RTC_DRV_DA9052 is not set
|
|
+CONFIG_RTC_DRV_DA9063=y
|
|
+# CONFIG_RTC_DRV_STK17TA8 is not set
|
|
+# CONFIG_RTC_DRV_M48T86 is not set
|
|
+# CONFIG_RTC_DRV_M48T35 is not set
|
|
+# CONFIG_RTC_DRV_M48T59 is not set
|
|
+# CONFIG_RTC_DRV_MSM6242 is not set
|
|
+# CONFIG_RTC_DRV_BQ4802 is not set
|
|
+# CONFIG_RTC_DRV_RP5C01 is not set
|
|
+# CONFIG_RTC_DRV_V3020 is not set
|
|
+# CONFIG_RTC_DRV_ZYNQMP is not set
|
|
+
|
|
+#
|
|
+# on-CPU RTC drivers
|
|
+#
|
|
+# CONFIG_RTC_DRV_IMXDI is not set
|
|
+# CONFIG_RTC_DRV_CADENCE is not set
|
|
+# CONFIG_RTC_DRV_FTRTC010 is not set
|
|
+CONFIG_RTC_DRV_MC13XXX=y
|
|
+CONFIG_RTC_DRV_MXC=y
|
|
+CONFIG_RTC_DRV_MXC_V2=y
|
|
+CONFIG_RTC_DRV_SNVS=y
|
|
+# CONFIG_RTC_DRV_BBNSM is not set
|
|
+CONFIG_RTC_DRV_IMX_RPMSG=y
|
|
+# CONFIG_RTC_DRV_R7301 is not set
|
|
+
|
|
+#
|
|
+# HID Sensor RTC drivers
|
|
+#
|
|
+# CONFIG_RTC_DRV_GOLDFISH is not set
|
|
+CONFIG_DMADEVICES=y
|
|
+# CONFIG_DMADEVICES_DEBUG is not set
|
|
+
|
|
+#
|
|
+# DMA Devices
|
|
+#
|
|
+CONFIG_DMA_ENGINE=y
|
|
+CONFIG_DMA_VIRTUAL_CHANNELS=y
|
|
+CONFIG_DMA_OF=y
|
|
+# CONFIG_ALTERA_MSGDMA is not set
|
|
+# CONFIG_CRYPTO_DEV_FSL_CAAM_DMA is not set
|
|
+# CONFIG_DW_AXI_DMAC is not set
|
|
+CONFIG_FSL_EDMA=y
|
|
+# CONFIG_FSL_QDMA is not set
|
|
+# CONFIG_FSL_EDMA_V3 is not set
|
|
+# CONFIG_IMX_DMA is not set
|
|
+CONFIG_IMX_SDMA=y
|
|
+# CONFIG_INTEL_IDMA64 is not set
|
|
+CONFIG_MXS_DMA=y
|
|
+# CONFIG_MXC_PXP_V2 is not set
|
|
+# CONFIG_MXC_PXP_V3 is not set
|
|
+# CONFIG_MX3_IPU is not set
|
|
+# CONFIG_NBPFAXI_DMA is not set
|
|
+# CONFIG_XILINX_ZYNQMP_DPDMA is not set
|
|
+# CONFIG_QCOM_HIDMA_MGMT is not set
|
|
+# CONFIG_QCOM_HIDMA is not set
|
|
+# CONFIG_DW_DMAC is not set
|
|
+# CONFIG_SF_PDMA is not set
|
|
+
|
|
+#
|
|
+# DMA Clients
|
|
+#
|
|
+# CONFIG_ASYNC_TX_DMA is not set
|
|
+# CONFIG_DMATEST is not set
|
|
+
|
|
+#
|
|
+# DMABUF options
|
|
+#
|
|
+CONFIG_SYNC_FILE=y
|
|
+# CONFIG_UDMABUF is not set
|
|
+# CONFIG_DMABUF_MOVE_NOTIFY is not set
|
|
+# CONFIG_DMABUF_DEBUG is not set
|
|
+# CONFIG_DMABUF_SELFTESTS is not set
|
|
+# CONFIG_DMABUF_HEAPS is not set
|
|
+# CONFIG_DMABUF_SYSFS_STATS is not set
|
|
+# end of DMABUF options
|
|
+
|
|
+# CONFIG_AUXDISPLAY is not set
|
|
+# CONFIG_UIO is not set
|
|
+# CONFIG_VFIO is not set
|
|
+# CONFIG_VIRT_DRIVERS is not set
|
|
+CONFIG_VIRTIO=y
|
|
+# CONFIG_VIRTIO_MENU is not set
|
|
+# CONFIG_VDPA is not set
|
|
+# CONFIG_VHOST_MENU is not set
|
|
+
|
|
+#
|
|
+# Microsoft Hyper-V guest support
|
|
+#
|
|
+# end of Microsoft Hyper-V guest support
|
|
+
|
|
+# CONFIG_GREYBUS is not set
|
|
+# CONFIG_COMEDI is not set
|
|
+# CONFIG_STAGING is not set
|
|
+# CONFIG_GOLDFISH is not set
|
|
+# CONFIG_CHROME_PLATFORMS is not set
|
|
+# CONFIG_MELLANOX_PLATFORM is not set
|
|
+CONFIG_HAVE_CLK=y
|
|
+CONFIG_HAVE_CLK_PREPARE=y
|
|
+CONFIG_COMMON_CLK=y
|
|
+
|
|
+#
|
|
+# Clock driver for ARM Reference designs
|
|
+#
|
|
+# CONFIG_ICST is not set
|
|
+# CONFIG_CLK_SP810 is not set
|
|
+# end of Clock driver for ARM Reference designs
|
|
+
|
|
+# CONFIG_COMMON_CLK_MAX9485 is not set
|
|
+# CONFIG_COMMON_CLK_SI5341 is not set
|
|
+# CONFIG_COMMON_CLK_SI5351 is not set
|
|
+# CONFIG_COMMON_CLK_SI514 is not set
|
|
+# CONFIG_COMMON_CLK_SI544 is not set
|
|
+# CONFIG_COMMON_CLK_SI570 is not set
|
|
+# CONFIG_COMMON_CLK_CDCE706 is not set
|
|
+# CONFIG_COMMON_CLK_CDCE925 is not set
|
|
+# CONFIG_COMMON_CLK_CS2000_CP is not set
|
|
+# CONFIG_COMMON_CLK_AXI_CLKGEN is not set
|
|
+# CONFIG_COMMON_CLK_VC5 is not set
|
|
+# CONFIG_COMMON_CLK_FIXED_MMIO is not set
|
|
+CONFIG_MXC_CLK=y
|
|
+CONFIG_CLK_IMX6Q=y
|
|
+CONFIG_CLK_IMX6SL=y
|
|
+CONFIG_CLK_IMX6SLL=y
|
|
+CONFIG_CLK_IMX6SX=y
|
|
+CONFIG_CLK_IMX6UL=y
|
|
+CONFIG_CLK_IMX7D=y
|
|
+# CONFIG_CLK_IMX8MM is not set
|
|
+# CONFIG_CLK_IMX8MN is not set
|
|
+# CONFIG_CLK_IMX8MP is not set
|
|
+# CONFIG_CLK_IMX8MQ is not set
|
|
+# CONFIG_CLK_IMX8ULP is not set
|
|
+# CONFIG_CLK_IMX93 is not set
|
|
+# CONFIG_ARCH_S32_CLK is not set
|
|
+# CONFIG_XILINX_VCU is not set
|
|
+# CONFIG_HWSPINLOCK is not set
|
|
+
|
|
+#
|
|
+# Clock Source drivers
|
|
+#
|
|
+CONFIG_TIMER_OF=y
|
|
+CONFIG_TIMER_PROBE=y
|
|
+CONFIG_CLKSRC_MMIO=y
|
|
+CONFIG_ARM_ARCH_TIMER=y
|
|
+CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
|
|
+CONFIG_CLKSRC_IMX_GPT=y
|
|
+# CONFIG_MICROCHIP_PIT64B is not set
|
|
+# end of Clock Source drivers
|
|
+
|
|
+CONFIG_MAILBOX=y
|
|
+CONFIG_IMX_MBOX=y
|
|
+# CONFIG_PLATFORM_MHU is not set
|
|
+# CONFIG_ALTERA_MBOX is not set
|
|
+# CONFIG_MAILBOX_TEST is not set
|
|
+CONFIG_IOMMU_SUPPORT=y
|
|
+
|
|
+#
|
|
+# Generic IOMMU Pagetable Support
|
|
+#
|
|
+# CONFIG_IOMMU_IO_PGTABLE_LPAE is not set
|
|
+# CONFIG_IOMMU_IO_PGTABLE_ARMV7S is not set
|
|
+# end of Generic IOMMU Pagetable Support
|
|
+
|
|
+# CONFIG_ARM_SMMU is not set
|
|
+
|
|
+#
|
|
+# Remoteproc drivers
|
|
+#
|
|
+# CONFIG_REMOTEPROC is not set
|
|
+# end of Remoteproc drivers
|
|
+
|
|
+#
|
|
+# Rpmsg drivers
|
|
+#
|
|
+CONFIG_RPMSG=y
|
|
+# CONFIG_RPMSG_CHAR is not set
|
|
+# CONFIG_RPMSG_CTRL is not set
|
|
+CONFIG_RPMSG_NS=y
|
|
+# CONFIG_RPMSG_QCOM_GLINK_RPM is not set
|
|
+CONFIG_RPMSG_VIRTIO=y
|
|
+# CONFIG_IMX_RPMSG_PINGPONG is not set
|
|
+# CONFIG_IMX_RPMSG_TTY is not set
|
|
+# end of Rpmsg drivers
|
|
+
|
|
+# CONFIG_SOUNDWIRE is not set
|
|
+
|
|
+#
|
|
+# SOC (System On Chip) specific Drivers
|
|
+#
|
|
+
|
|
+#
|
|
+# Amlogic SoC drivers
|
|
+#
|
|
+# end of Amlogic SoC drivers
|
|
+
|
|
+#
|
|
+# Broadcom SoC drivers
|
|
+#
|
|
+# CONFIG_SOC_BRCMSTB is not set
|
|
+# end of Broadcom SoC drivers
|
|
+
|
|
+#
|
|
+# NXP/Freescale QorIQ SoC drivers
|
|
+#
|
|
+# CONFIG_QUICC_ENGINE is not set
|
|
+# CONFIG_FSL_QIXIS is not set
|
|
+# end of NXP/Freescale QorIQ SoC drivers
|
|
+
|
|
+#
|
|
+# i.MX SoC drivers
|
|
+#
|
|
+# CONFIG_SOC_IMX_MU is not set
|
|
+# CONFIG_SOC_IMX9 is not set
|
|
+# CONFIG_SOC_IMX8M is not set
|
|
+# CONFIG_RPMSG_LIFE_CYCLE is not set
|
|
+# CONFIG_IMX8ULP_LPM_CTRL is not set
|
|
+# end of i.MX SoC drivers
|
|
+
|
|
+#
|
|
+# Enable LiteX SoC Builder specific drivers
|
|
+#
|
|
+# CONFIG_LITEX_SOC_CONTROLLER is not set
|
|
+# end of Enable LiteX SoC Builder specific drivers
|
|
+
|
|
+#
|
|
+# Qualcomm SoC drivers
|
|
+#
|
|
+# end of Qualcomm SoC drivers
|
|
+
|
|
+# CONFIG_SOC_TI is not set
|
|
+
|
|
+#
|
|
+# Xilinx SoC drivers
|
|
+#
|
|
+# end of Xilinx SoC drivers
|
|
+# end of SOC (System On Chip) specific Drivers
|
|
+
|
|
+# CONFIG_PM_DEVFREQ is not set
|
|
+CONFIG_EXTCON=y
|
|
+
|
|
+#
|
|
+# Extcon Device Drivers
|
|
+#
|
|
+# CONFIG_EXTCON_FSA9480 is not set
|
|
+# CONFIG_EXTCON_GPIO is not set
|
|
+# CONFIG_EXTCON_MAX3355 is not set
|
|
+# CONFIG_EXTCON_PTN5150 is not set
|
|
+# CONFIG_EXTCON_RT8973A is not set
|
|
+# CONFIG_EXTCON_SM5502 is not set
|
|
+CONFIG_EXTCON_USB_GPIO=y
|
|
+# CONFIG_EXTCON_USBC_TUSB320 is not set
|
|
+# CONFIG_MEMORY is not set
|
|
+# CONFIG_IIO is not set
|
|
+# CONFIG_PWM is not set
|
|
+
|
|
+#
|
|
+# IRQ chip support
|
|
+#
|
|
+CONFIG_IRQCHIP=y
|
|
+CONFIG_ARM_GIC=y
|
|
+CONFIG_ARM_GIC_MAX_NR=1
|
|
+# CONFIG_AL_FIC is not set
|
|
+CONFIG_IMX_GPCV2=y
|
|
+# CONFIG_IMX_IRQSTEER is not set
|
|
+CONFIG_IMX_INTMUX=y
|
|
+# end of IRQ chip support
|
|
+
|
|
+# CONFIG_IPACK_BUS is not set
|
|
+CONFIG_ARCH_HAS_RESET_CONTROLLER=y
|
|
+CONFIG_RESET_CONTROLLER=y
|
|
+CONFIG_RESET_DISPMIX=y
|
|
+CONFIG_RESET_IMX7=y
|
|
+# CONFIG_RESET_IMX8ULP_SIM is not set
|
|
+CONFIG_RESET_GPIO=y
|
|
+# CONFIG_RESET_TI_SYSCON is not set
|
|
+
|
|
+#
|
|
+# PHY Subsystem
|
|
+#
|
|
+CONFIG_GENERIC_PHY=y
|
|
+# CONFIG_PHY_CAN_TRANSCEIVER is not set
|
|
+# CONFIG_PHY_MIXEL_LVDS is not set
|
|
+# CONFIG_PHY_MIXEL_LVDS_COMBO is not set
|
|
+# CONFIG_BCM_KONA_USB2_PHY is not set
|
|
+# CONFIG_PHY_CADENCE_TORRENT is not set
|
|
+# CONFIG_PHY_CADENCE_DPHY is not set
|
|
+# CONFIG_PHY_CADENCE_SIERRA is not set
|
|
+# CONFIG_PHY_CADENCE_SALVO is not set
|
|
+# CONFIG_PHY_FSL_IMX8MP_LVDS is not set
|
|
+# CONFIG_PHY_FSL_IMX8MQ_USB is not set
|
|
+# CONFIG_PHY_FSL_IMX93_MIPI_DPHY is not set
|
|
+# CONFIG_PHY_MIXEL_MIPI_DPHY is not set
|
|
+# CONFIG_PHY_SAMSUNG_HDMI_PHY is not set
|
|
+CONFIG_PHY_FSL_IMX_PCIE=y
|
|
+# CONFIG_PHY_FSL_LYNX_28G is not set
|
|
+# CONFIG_PHY_PXA_28NM_HSIC is not set
|
|
+# CONFIG_PHY_PXA_28NM_USB2 is not set
|
|
+# CONFIG_PHY_OCELOT_SERDES is not set
|
|
+# end of PHY Subsystem
|
|
+
|
|
+# CONFIG_POWERCAP is not set
|
|
+# CONFIG_MCB is not set
|
|
+# CONFIG_RAS is not set
|
|
+
|
|
+#
|
|
+# Android
|
|
+#
|
|
+# CONFIG_ANDROID is not set
|
|
+# end of Android
|
|
+
|
|
+# CONFIG_DAX is not set
|
|
+CONFIG_NVMEM=y
|
|
+CONFIG_NVMEM_SYSFS=y
|
|
+# CONFIG_NVMEM_IMX_IIM is not set
|
|
+CONFIG_NVMEM_IMX_OCOTP=y
|
|
+CONFIG_NVMEM_SNVS_LPGPR=y
|
|
+# CONFIG_NVMEM_RMEM is not set
|
|
+
|
|
+#
|
|
+# HW tracing support
|
|
+#
|
|
+# CONFIG_STM is not set
|
|
+# CONFIG_INTEL_TH is not set
|
|
+# end of HW tracing support
|
|
+
|
|
+# CONFIG_FPGA is not set
|
|
+# CONFIG_FSI is not set
|
|
+CONFIG_TEE=y
|
|
+
|
|
+#
|
|
+# TEE drivers
|
|
+#
|
|
+CONFIG_OPTEE=y
|
|
+CONFIG_OPTEE_SHM_NUM_PRIV_PAGES=1
|
|
+# end of TEE drivers
|
|
+
|
|
+CONFIG_PM_OPP=y
|
|
+# CONFIG_SIOX is not set
|
|
+# CONFIG_SLIMBUS is not set
|
|
+# CONFIG_INTERCONNECT is not set
|
|
+# CONFIG_COUNTER is not set
|
|
+# CONFIG_MOST is not set
|
|
+
|
|
+#
|
|
+# MXC support drivers
|
|
+#
|
|
+# CONFIG_MXC_SIM is not set
|
|
+# CONFIG_MXC_IPU is not set
|
|
+
|
|
+#
|
|
+# MXC Vivante GPU support
|
|
+#
|
|
+# CONFIG_MXC_GPU_VIV is not set
|
|
+# end of MXC Vivante GPU support
|
|
+
|
|
+#
|
|
+# MXC SIM Support
|
|
+#
|
|
+# end of MXC SIM Support
|
|
+
|
|
+#
|
|
+# MXC Media Local Bus Driver
|
|
+#
|
|
+CONFIG_MXC_MLB=y
|
|
+CONFIG_MXC_MLB150=y
|
|
+# end of MXC Media Local Bus Driver
|
|
+
|
|
+#
|
|
+# MXC HDMI CEC (Consumer Electronics Control) support
|
|
+#
|
|
+# end of MXC HDMI CEC (Consumer Electronics Control) support
|
|
+
|
|
+#
|
|
+# MXC MIPI Support
|
|
+#
|
|
+CONFIG_MXC_MIPI_CSI2=y
|
|
+# end of MXC MIPI Support
|
|
+
|
|
+#
|
|
+# MXC VPU(Video Processing Unit) support
|
|
+#
|
|
+CONFIG_MXC_VPU=y
|
|
+# CONFIG_MXC_VPU_DEBUG is not set
|
|
+# CONFIG_MX6_VPU_352M is not set
|
|
+# end of MXC VPU(Video Processing Unit) support
|
|
+# end of MXC support drivers
|
|
+# end of Device Drivers
|
|
+
|
|
+#
|
|
+# File systems
|
|
+#
|
|
+CONFIG_DCACHE_WORD_ACCESS=y
|
|
+# CONFIG_VALIDATE_FS_PARSER is not set
|
|
+CONFIG_FS_IOMAP=y
|
|
+CONFIG_EXT2_FS=y
|
|
+# CONFIG_EXT2_FS_XATTR is not set
|
|
+# CONFIG_EXT3_FS is not set
|
|
+CONFIG_EXT4_FS=y
|
|
+CONFIG_EXT4_FS_POSIX_ACL=y
|
|
+CONFIG_EXT4_FS_SECURITY=y
|
|
+# CONFIG_EXT4_DEBUG is not set
|
|
+CONFIG_JBD2=y
|
|
+# CONFIG_JBD2_DEBUG is not set
|
|
+CONFIG_FS_MBCACHE=y
|
|
+# CONFIG_REISERFS_FS is not set
|
|
+# CONFIG_JFS_FS is not set
|
|
+# CONFIG_XFS_FS is not set
|
|
+# CONFIG_GFS2_FS is not set
|
|
+# CONFIG_OCFS2_FS is not set
|
|
+# CONFIG_BTRFS_FS is not set
|
|
+# CONFIG_NILFS2_FS is not set
|
|
+# CONFIG_F2FS_FS is not set
|
|
+CONFIG_FS_POSIX_ACL=y
|
|
+CONFIG_EXPORTFS=y
|
|
+# CONFIG_EXPORTFS_BLOCK_OPS is not set
|
|
+CONFIG_FILE_LOCKING=y
|
|
+# CONFIG_FS_ENCRYPTION is not set
|
|
+# CONFIG_FS_VERITY is not set
|
|
+# CONFIG_DNOTIFY is not set
|
|
+# CONFIG_INOTIFY_USER is not set
|
|
+# CONFIG_FANOTIFY is not set
|
|
+# CONFIG_QUOTA is not set
|
|
+# CONFIG_AUTOFS4_FS is not set
|
|
+# CONFIG_AUTOFS_FS is not set
|
|
+# CONFIG_FUSE_FS is not set
|
|
+# CONFIG_OVERLAY_FS is not set
|
|
+
|
|
+#
|
|
+# Caches
|
|
+#
|
|
+# CONFIG_FSCACHE is not set
|
|
+# end of Caches
|
|
+
|
|
+#
|
|
+# CD-ROM/DVD Filesystems
|
|
+#
|
|
+# CONFIG_ISO9660_FS is not set
|
|
+# CONFIG_UDF_FS is not set
|
|
+# end of CD-ROM/DVD Filesystems
|
|
+
|
|
+#
|
|
+# DOS/FAT/EXFAT/NT Filesystems
|
|
+#
|
|
+CONFIG_FAT_FS=y
|
|
+CONFIG_MSDOS_FS=y
|
|
+CONFIG_VFAT_FS=y
|
|
+CONFIG_FAT_DEFAULT_CODEPAGE=437
|
|
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
|
|
+# CONFIG_FAT_DEFAULT_UTF8 is not set
|
|
+# CONFIG_EXFAT_FS is not set
|
|
+# CONFIG_NTFS_FS is not set
|
|
+# CONFIG_NTFS3_FS is not set
|
|
+# end of DOS/FAT/EXFAT/NT Filesystems
|
|
+
|
|
+#
|
|
+# Pseudo filesystems
|
|
+#
|
|
+CONFIG_PROC_FS=y
|
|
+CONFIG_PROC_SYSCTL=y
|
|
+CONFIG_PROC_PAGE_MONITOR=y
|
|
+CONFIG_PROC_CHILDREN=y
|
|
+CONFIG_KERNFS=y
|
|
+CONFIG_SYSFS=y
|
|
+CONFIG_TMPFS=y
|
|
+CONFIG_TMPFS_POSIX_ACL=y
|
|
+CONFIG_TMPFS_XATTR=y
|
|
+CONFIG_MEMFD_CREATE=y
|
|
+CONFIG_CONFIGFS_FS=y
|
|
+# end of Pseudo filesystems
|
|
+
|
|
+# CONFIG_MISC_FILESYSTEMS is not set
|
|
+# CONFIG_NETWORK_FILESYSTEMS is not set
|
|
+CONFIG_NLS=y
|
|
+CONFIG_NLS_DEFAULT="cp437"
|
|
+CONFIG_NLS_CODEPAGE_437=y
|
|
+# CONFIG_NLS_CODEPAGE_737 is not set
|
|
+# CONFIG_NLS_CODEPAGE_775 is not set
|
|
+# CONFIG_NLS_CODEPAGE_850 is not set
|
|
+# CONFIG_NLS_CODEPAGE_852 is not set
|
|
+# CONFIG_NLS_CODEPAGE_855 is not set
|
|
+# CONFIG_NLS_CODEPAGE_857 is not set
|
|
+# CONFIG_NLS_CODEPAGE_860 is not set
|
|
+# CONFIG_NLS_CODEPAGE_861 is not set
|
|
+# CONFIG_NLS_CODEPAGE_862 is not set
|
|
+# CONFIG_NLS_CODEPAGE_863 is not set
|
|
+# CONFIG_NLS_CODEPAGE_864 is not set
|
|
+# CONFIG_NLS_CODEPAGE_865 is not set
|
|
+# CONFIG_NLS_CODEPAGE_866 is not set
|
|
+# CONFIG_NLS_CODEPAGE_869 is not set
|
|
+# CONFIG_NLS_CODEPAGE_936 is not set
|
|
+# CONFIG_NLS_CODEPAGE_950 is not set
|
|
+# CONFIG_NLS_CODEPAGE_932 is not set
|
|
+# CONFIG_NLS_CODEPAGE_949 is not set
|
|
+# CONFIG_NLS_CODEPAGE_874 is not set
|
|
+# CONFIG_NLS_ISO8859_8 is not set
|
|
+# CONFIG_NLS_CODEPAGE_1250 is not set
|
|
+# CONFIG_NLS_CODEPAGE_1251 is not set
|
|
+CONFIG_NLS_ASCII=y
|
|
+CONFIG_NLS_ISO8859_1=y
|
|
+# CONFIG_NLS_ISO8859_2 is not set
|
|
+# CONFIG_NLS_ISO8859_3 is not set
|
|
+# CONFIG_NLS_ISO8859_4 is not set
|
|
+# CONFIG_NLS_ISO8859_5 is not set
|
|
+# CONFIG_NLS_ISO8859_6 is not set
|
|
+# CONFIG_NLS_ISO8859_7 is not set
|
|
+# CONFIG_NLS_ISO8859_9 is not set
|
|
+# CONFIG_NLS_ISO8859_13 is not set
|
|
+# CONFIG_NLS_ISO8859_14 is not set
|
|
+CONFIG_NLS_ISO8859_15=y
|
|
+# CONFIG_NLS_KOI8_R is not set
|
|
+# CONFIG_NLS_KOI8_U is not set
|
|
+# CONFIG_NLS_MAC_ROMAN is not set
|
|
+# CONFIG_NLS_MAC_CELTIC is not set
|
|
+# CONFIG_NLS_MAC_CENTEURO is not set
|
|
+# CONFIG_NLS_MAC_CROATIAN is not set
|
|
+# CONFIG_NLS_MAC_CYRILLIC is not set
|
|
+# CONFIG_NLS_MAC_GAELIC is not set
|
|
+# CONFIG_NLS_MAC_GREEK is not set
|
|
+# CONFIG_NLS_MAC_ICELAND is not set
|
|
+# CONFIG_NLS_MAC_INUIT is not set
|
|
+# CONFIG_NLS_MAC_ROMANIAN is not set
|
|
+# CONFIG_NLS_MAC_TURKISH is not set
|
|
+CONFIG_NLS_UTF8=y
|
|
+# CONFIG_DLM is not set
|
|
+# CONFIG_UNICODE is not set
|
|
+CONFIG_IO_WQ=y
|
|
+# end of File systems
|
|
+
|
|
+#
|
|
+# Security options
|
|
+#
|
|
+# CONFIG_KEYS is not set
|
|
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
|
|
+# CONFIG_SECURITY is not set
|
|
+# CONFIG_SECURITYFS is not set
|
|
+CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y
|
|
+# CONFIG_HARDENED_USERCOPY is not set
|
|
+# CONFIG_FORTIFY_SOURCE is not set
|
|
+# CONFIG_STATIC_USERMODEHELPER is not set
|
|
+CONFIG_DEFAULT_SECURITY_DAC=y
|
|
+CONFIG_LSM="landlock,lockdown,yama,loadpin,safesetid,integrity,bpf"
|
|
+
|
|
+#
|
|
+# Kernel hardening options
|
|
+#
|
|
+
|
|
+#
|
|
+# Memory initialization
|
|
+#
|
|
+CONFIG_INIT_STACK_NONE=y
|
|
+# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set
|
|
+# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
|
|
+CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y
|
|
+# CONFIG_ZERO_CALL_USED_REGS is not set
|
|
+# end of Memory initialization
|
|
+# end of Kernel hardening options
|
|
+# end of Security options
|
|
+
|
|
+CONFIG_CRYPTO=y
|
|
+
|
|
+#
|
|
+# Crypto core or helper
|
|
+#
|
|
+CONFIG_CRYPTO_ALGAPI=y
|
|
+CONFIG_CRYPTO_ALGAPI2=y
|
|
+CONFIG_CRYPTO_AEAD=y
|
|
+CONFIG_CRYPTO_AEAD2=y
|
|
+CONFIG_CRYPTO_SKCIPHER=y
|
|
+CONFIG_CRYPTO_SKCIPHER2=y
|
|
+CONFIG_CRYPTO_HASH=y
|
|
+CONFIG_CRYPTO_HASH2=y
|
|
+CONFIG_CRYPTO_RNG=y
|
|
+CONFIG_CRYPTO_RNG2=y
|
|
+CONFIG_CRYPTO_RNG_DEFAULT=y
|
|
+CONFIG_CRYPTO_AKCIPHER2=y
|
|
+CONFIG_CRYPTO_AKCIPHER=y
|
|
+CONFIG_CRYPTO_KPP2=y
|
|
+CONFIG_CRYPTO_KPP=y
|
|
+CONFIG_CRYPTO_ACOMP2=y
|
|
+CONFIG_CRYPTO_MANAGER=y
|
|
+CONFIG_CRYPTO_MANAGER2=y
|
|
+CONFIG_CRYPTO_USER=y
|
|
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
|
|
+CONFIG_CRYPTO_GF128MUL=y
|
|
+CONFIG_CRYPTO_NULL=y
|
|
+CONFIG_CRYPTO_NULL2=y
|
|
+# CONFIG_CRYPTO_CRYPTD is not set
|
|
+CONFIG_CRYPTO_AUTHENC=y
|
|
+# CONFIG_CRYPTO_TEST is not set
|
|
+CONFIG_CRYPTO_ENGINE=y
|
|
+
|
|
+#
|
|
+# Public-key cryptography
|
|
+#
|
|
+CONFIG_CRYPTO_RSA=y
|
|
+# CONFIG_CRYPTO_DH is not set
|
|
+CONFIG_CRYPTO_ECC=y
|
|
+CONFIG_CRYPTO_ECDH=y
|
|
+# CONFIG_CRYPTO_ECDSA is not set
|
|
+# CONFIG_CRYPTO_ECRDSA is not set
|
|
+# CONFIG_CRYPTO_SM2 is not set
|
|
+# CONFIG_CRYPTO_CURVE25519 is not set
|
|
+
|
|
+#
|
|
+# Authenticated Encryption with Associated Data
|
|
+#
|
|
+CONFIG_CRYPTO_CCM=y
|
|
+CONFIG_CRYPTO_GCM=y
|
|
+# CONFIG_CRYPTO_CHACHA20POLY1305 is not set
|
|
+# CONFIG_CRYPTO_AEGIS128 is not set
|
|
+# CONFIG_CRYPTO_SEQIV is not set
|
|
+CONFIG_CRYPTO_ECHAINIV=y
|
|
+CONFIG_CRYPTO_TLS=y
|
|
+
|
|
+#
|
|
+# Block modes
|
|
+#
|
|
+CONFIG_CRYPTO_CBC=y
|
|
+CONFIG_CRYPTO_CFB=y
|
|
+CONFIG_CRYPTO_CTR=y
|
|
+CONFIG_CRYPTO_CTS=y
|
|
+CONFIG_CRYPTO_ECB=y
|
|
+CONFIG_CRYPTO_LRW=y
|
|
+CONFIG_CRYPTO_OFB=y
|
|
+CONFIG_CRYPTO_PCBC=y
|
|
+CONFIG_CRYPTO_XTS=y
|
|
+# CONFIG_CRYPTO_KEYWRAP is not set
|
|
+# CONFIG_CRYPTO_ADIANTUM is not set
|
|
+CONFIG_CRYPTO_ESSIV=y
|
|
+
|
|
+#
|
|
+# Hash modes
|
|
+#
|
|
+CONFIG_CRYPTO_CMAC=y
|
|
+CONFIG_CRYPTO_HMAC=y
|
|
+CONFIG_CRYPTO_XCBC=y
|
|
+CONFIG_CRYPTO_VMAC=y
|
|
+
|
|
+#
|
|
+# Digest
|
|
+#
|
|
+CONFIG_CRYPTO_CRC32C=y
|
|
+# CONFIG_CRYPTO_CRC32 is not set
|
|
+CONFIG_CRYPTO_XXHASH=y
|
|
+CONFIG_CRYPTO_BLAKE2B=y
|
|
+CONFIG_CRYPTO_BLAKE2S=y
|
|
+CONFIG_CRYPTO_CRCT10DIF=y
|
|
+CONFIG_CRYPTO_GHASH=y
|
|
+# CONFIG_CRYPTO_POLY1305 is not set
|
|
+CONFIG_CRYPTO_MD4=y
|
|
+CONFIG_CRYPTO_MD5=y
|
|
+CONFIG_CRYPTO_MICHAEL_MIC=y
|
|
+CONFIG_CRYPTO_RMD160=y
|
|
+CONFIG_CRYPTO_SHA1=y
|
|
+CONFIG_CRYPTO_SHA256=y
|
|
+CONFIG_CRYPTO_SHA512=y
|
|
+CONFIG_CRYPTO_SHA3=y
|
|
+CONFIG_CRYPTO_SM3=y
|
|
+CONFIG_CRYPTO_STREEBOG=y
|
|
+CONFIG_CRYPTO_WP512=y
|
|
+
|
|
+#
|
|
+# Ciphers
|
|
+#
|
|
+CONFIG_CRYPTO_AES=y
|
|
+# CONFIG_CRYPTO_AES_TI is not set
|
|
+CONFIG_CRYPTO_ANUBIS=y
|
|
+CONFIG_CRYPTO_ARC4=y
|
|
+CONFIG_CRYPTO_BLOWFISH=y
|
|
+CONFIG_CRYPTO_BLOWFISH_COMMON=y
|
|
+CONFIG_CRYPTO_CAMELLIA=y
|
|
+CONFIG_CRYPTO_CAST_COMMON=y
|
|
+CONFIG_CRYPTO_CAST5=y
|
|
+CONFIG_CRYPTO_CAST6=y
|
|
+CONFIG_CRYPTO_DES=y
|
|
+CONFIG_CRYPTO_FCRYPT=y
|
|
+CONFIG_CRYPTO_KHAZAD=y
|
|
+# CONFIG_CRYPTO_CHACHA20 is not set
|
|
+CONFIG_CRYPTO_SEED=y
|
|
+CONFIG_CRYPTO_SERPENT=y
|
|
+CONFIG_CRYPTO_SM4=y
|
|
+CONFIG_CRYPTO_TEA=y
|
|
+CONFIG_CRYPTO_TWOFISH=y
|
|
+CONFIG_CRYPTO_TWOFISH_COMMON=y
|
|
+
|
|
+#
|
|
+# Compression
|
|
+#
|
|
+CONFIG_CRYPTO_DEFLATE=y
|
|
+CONFIG_CRYPTO_LZO=y
|
|
+# CONFIG_CRYPTO_842 is not set
|
|
+# CONFIG_CRYPTO_LZ4 is not set
|
|
+# CONFIG_CRYPTO_LZ4HC is not set
|
|
+CONFIG_CRYPTO_ZSTD=y
|
|
+
|
|
+#
|
|
+# Random Number Generation
|
|
+#
|
|
+CONFIG_CRYPTO_ANSI_CPRNG=y
|
|
+CONFIG_CRYPTO_DRBG_MENU=y
|
|
+CONFIG_CRYPTO_DRBG_HMAC=y
|
|
+# CONFIG_CRYPTO_DRBG_HASH is not set
|
|
+# CONFIG_CRYPTO_DRBG_CTR is not set
|
|
+CONFIG_CRYPTO_DRBG=y
|
|
+CONFIG_CRYPTO_JITTERENTROPY=y
|
|
+CONFIG_CRYPTO_USER_API=y
|
|
+CONFIG_CRYPTO_USER_API_HASH=y
|
|
+CONFIG_CRYPTO_USER_API_SKCIPHER=y
|
|
+CONFIG_CRYPTO_USER_API_RNG=y
|
|
+# CONFIG_CRYPTO_USER_API_RNG_CAVP is not set
|
|
+CONFIG_CRYPTO_USER_API_AEAD=y
|
|
+CONFIG_CRYPTO_USER_API_ENABLE_OBSOLETE=y
|
|
+# CONFIG_CRYPTO_STATS is not set
|
|
+CONFIG_CRYPTO_HW=y
|
|
+CONFIG_CRYPTO_DEV_FSL_CAAM_COMMON=y
|
|
+CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC=y
|
|
+CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC=y
|
|
+CONFIG_CRYPTO_DEV_FSL_CAAM_KEYBLOB_API_DESC=y
|
|
+CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO=y
|
|
+CONFIG_CRYPTO_DEV_FSL_CAAM=y
|
|
+# CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG is not set
|
|
+CONFIG_CRYPTO_DEV_FSL_CAAM_JR=y
|
|
+CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE=9
|
|
+# CONFIG_CRYPTO_DEV_FSL_CAAM_INTC is not set
|
|
+CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API=y
|
|
+CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API=y
|
|
+CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API=y
|
|
+CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API=y
|
|
+CONFIG_CRYPTO_DEV_FSL_CAAM_PRNG_API=y
|
|
+CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API=y
|
|
+# CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API_TEST is not set
|
|
+# CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_TEST is not set
|
|
+CONFIG_CRYPTO_DEV_FSL_CAAM_SM=y
|
|
+CONFIG_CRYPTO_DEV_FSL_CAAM_SM_SLOTSIZE=7
|
|
+# CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST is not set
|
|
+CONFIG_CRYPTO_DEV_SAHARA=y
|
|
+# CONFIG_CRYPTO_DEV_ATMEL_ECC is not set
|
|
+# CONFIG_CRYPTO_DEV_ATMEL_SHA204A is not set
|
|
+CONFIG_CRYPTO_DEV_MXS_DCP=y
|
|
+# CONFIG_CRYPTO_DEV_VIRTIO is not set
|
|
+# CONFIG_CRYPTO_DEV_SAFEXCEL is not set
|
|
+# CONFIG_CRYPTO_DEV_CCREE is not set
|
|
+# CONFIG_CRYPTO_DEV_AMLOGIC_GXL is not set
|
|
+
|
|
+#
|
|
+# Certificates for signature checking
|
|
+#
|
|
+# end of Certificates for signature checking
|
|
+
|
|
+#
|
|
+# Library routines
|
|
+#
|
|
+CONFIG_LINEAR_RANGES=y
|
|
+# CONFIG_PACKING is not set
|
|
+CONFIG_BITREVERSE=y
|
|
+CONFIG_HAVE_ARCH_BITREVERSE=y
|
|
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
|
|
+CONFIG_GENERIC_STRNLEN_USER=y
|
|
+CONFIG_GENERIC_NET_UTILS=y
|
|
+# CONFIG_CORDIC is not set
|
|
+# CONFIG_PRIME_NUMBERS is not set
|
|
+CONFIG_RATIONAL=y
|
|
+CONFIG_GENERIC_PCI_IOMAP=y
|
|
+CONFIG_STMP_DEVICE=y
|
|
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
|
|
+
|
|
+#
|
|
+# Crypto library routines
|
|
+#
|
|
+CONFIG_CRYPTO_LIB_AES=y
|
|
+CONFIG_CRYPTO_LIB_ARC4=y
|
|
+CONFIG_CRYPTO_ARCH_HAVE_LIB_BLAKE2S=y
|
|
+CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
|
|
+CONFIG_CRYPTO_ARCH_HAVE_LIB_CHACHA=y
|
|
+# CONFIG_CRYPTO_LIB_CHACHA is not set
|
|
+# CONFIG_CRYPTO_LIB_CURVE25519 is not set
|
|
+CONFIG_CRYPTO_LIB_DES=y
|
|
+CONFIG_CRYPTO_LIB_POLY1305_RSIZE=9
|
|
+CONFIG_CRYPTO_ARCH_HAVE_LIB_POLY1305=y
|
|
+# CONFIG_CRYPTO_LIB_POLY1305 is not set
|
|
+# CONFIG_CRYPTO_LIB_CHACHA20POLY1305 is not set
|
|
+CONFIG_CRYPTO_LIB_SHA256=y
|
|
+CONFIG_CRYPTO_LIB_SM4=y
|
|
+# end of Crypto library routines
|
|
+
|
|
+CONFIG_LIB_MEMNEQ=y
|
|
+CONFIG_CRC_CCITT=y
|
|
+CONFIG_CRC16=y
|
|
+CONFIG_CRC_T10DIF=y
|
|
+CONFIG_CRC_ITU_T=y
|
|
+CONFIG_CRC32=y
|
|
+# CONFIG_CRC32_SELFTEST is not set
|
|
+CONFIG_CRC32_SLICEBY8=y
|
|
+# CONFIG_CRC32_SLICEBY4 is not set
|
|
+# CONFIG_CRC32_SARWATE is not set
|
|
+# CONFIG_CRC32_BIT is not set
|
|
+# CONFIG_CRC64 is not set
|
|
+# CONFIG_CRC4 is not set
|
|
+CONFIG_CRC7=y
|
|
+CONFIG_LIBCRC32C=y
|
|
+# CONFIG_CRC8 is not set
|
|
+CONFIG_XXHASH=y
|
|
+# CONFIG_RANDOM32_SELFTEST is not set
|
|
+CONFIG_ZLIB_INFLATE=y
|
|
+CONFIG_ZLIB_DEFLATE=y
|
|
+CONFIG_LZO_COMPRESS=y
|
|
+CONFIG_LZO_DECOMPRESS=y
|
|
+CONFIG_ZSTD_COMPRESS=y
|
|
+CONFIG_ZSTD_DECOMPRESS=y
|
|
+CONFIG_XZ_DEC=y
|
|
+CONFIG_XZ_DEC_X86=y
|
|
+CONFIG_XZ_DEC_POWERPC=y
|
|
+CONFIG_XZ_DEC_IA64=y
|
|
+CONFIG_XZ_DEC_ARM=y
|
|
+CONFIG_XZ_DEC_ARMTHUMB=y
|
|
+CONFIG_XZ_DEC_SPARC=y
|
|
+CONFIG_XZ_DEC_BCJ=y
|
|
+# CONFIG_XZ_DEC_TEST is not set
|
|
+CONFIG_GENERIC_ALLOCATOR=y
|
|
+CONFIG_HAS_IOMEM=y
|
|
+CONFIG_HAS_IOPORT_MAP=y
|
|
+CONFIG_HAS_DMA=y
|
|
+CONFIG_DMA_OPS=y
|
|
+CONFIG_NEED_DMA_MAP_STATE=y
|
|
+CONFIG_DMA_DECLARE_COHERENT=y
|
|
+CONFIG_ARCH_HAS_SETUP_DMA_OPS=y
|
|
+CONFIG_ARCH_HAS_TEARDOWN_DMA_OPS=y
|
|
+CONFIG_DMA_NONCOHERENT_MMAP=y
|
|
+CONFIG_DMA_REMAP=y
|
|
+CONFIG_DMA_CMA=y
|
|
+# CONFIG_DMA_PERNUMA_CMA is not set
|
|
+
|
|
+#
|
|
+# Default contiguous memory area size:
|
|
+#
|
|
+CONFIG_CMA_SIZE_MBYTES=16
|
|
+CONFIG_CMA_SIZE_SEL_MBYTES=y
|
|
+# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
|
|
+# CONFIG_CMA_SIZE_SEL_MIN is not set
|
|
+# CONFIG_CMA_SIZE_SEL_MAX is not set
|
|
+CONFIG_CMA_ALIGNMENT=8
|
|
+# CONFIG_DMA_API_DEBUG is not set
|
|
+CONFIG_SGL_ALLOC=y
|
|
+CONFIG_DQL=y
|
|
+CONFIG_GLOB=y
|
|
+# CONFIG_GLOB_SELFTEST is not set
|
|
+CONFIG_NLATTR=y
|
|
+CONFIG_CLZ_TAB=y
|
|
+# CONFIG_IRQ_POLL is not set
|
|
+CONFIG_MPILIB=y
|
|
+CONFIG_LIBFDT=y
|
|
+CONFIG_HAVE_GENERIC_VDSO=y
|
|
+CONFIG_GENERIC_GETTIMEOFDAY=y
|
|
+CONFIG_GENERIC_VDSO_32=y
|
|
+CONFIG_SBITMAP=y
|
|
+# end of Library routines
|
|
+
|
|
+CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y
|
|
+
|
|
+#
|
|
+# Kernel hacking
|
|
+#
|
|
+
|
|
+#
|
|
+# printk and dmesg options
|
|
+#
|
|
+# CONFIG_PRINTK_TIME is not set
|
|
+# CONFIG_PRINTK_CALLER is not set
|
|
+# CONFIG_STACKTRACE_BUILD_ID is not set
|
|
+CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7
|
|
+CONFIG_CONSOLE_LOGLEVEL_QUIET=4
|
|
+CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
|
|
+# CONFIG_BOOT_PRINTK_DELAY is not set
|
|
+# CONFIG_DYNAMIC_DEBUG is not set
|
|
+# CONFIG_DYNAMIC_DEBUG_CORE is not set
|
|
+# CONFIG_SYMBOLIC_ERRNAME is not set
|
|
+CONFIG_DEBUG_BUGVERBOSE=y
|
|
+# end of printk and dmesg options
|
|
+
|
|
+#
|
|
+# Compile-time checks and compiler options
|
|
+#
|
|
+# CONFIG_DEBUG_INFO is not set
|
|
+CONFIG_FRAME_WARN=1024
|
|
+# CONFIG_STRIP_ASM_SYMS is not set
|
|
+# CONFIG_READABLE_ASM is not set
|
|
+# CONFIG_HEADERS_INSTALL is not set
|
|
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
|
|
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
|
|
+# CONFIG_VMLINUX_MAP is not set
|
|
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
|
|
+# end of Compile-time checks and compiler options
|
|
+
|
|
+#
|
|
+# Generic Kernel Debugging Instruments
|
|
+#
|
|
+CONFIG_MAGIC_SYSRQ=y
|
|
+CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
|
|
+CONFIG_MAGIC_SYSRQ_SERIAL=y
|
|
+CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE=""
|
|
+# CONFIG_DEBUG_FS is not set
|
|
+CONFIG_HAVE_ARCH_KGDB=y
|
|
+# CONFIG_KGDB is not set
|
|
+# CONFIG_UBSAN is not set
|
|
+CONFIG_HAVE_KCSAN_COMPILER=y
|
|
+# end of Generic Kernel Debugging Instruments
|
|
+
|
|
+CONFIG_DEBUG_KERNEL=y
|
|
+CONFIG_DEBUG_MISC=y
|
|
+
|
|
+#
|
|
+# Memory Debugging
|
|
+#
|
|
+# CONFIG_PAGE_EXTENSION is not set
|
|
+# CONFIG_DEBUG_PAGEALLOC is not set
|
|
+# CONFIG_PAGE_OWNER is not set
|
|
+# CONFIG_PAGE_POISONING is not set
|
|
+# CONFIG_DEBUG_RODATA_TEST is not set
|
|
+# CONFIG_DEBUG_WX is not set
|
|
+# CONFIG_DEBUG_OBJECTS is not set
|
|
+# CONFIG_SLUB_STATS is not set
|
|
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
|
|
+# CONFIG_DEBUG_KMEMLEAK is not set
|
|
+# CONFIG_DEBUG_STACK_USAGE is not set
|
|
+# CONFIG_SCHED_STACK_END_CHECK is not set
|
|
+# CONFIG_DEBUG_VM is not set
|
|
+CONFIG_ARCH_HAS_DEBUG_VIRTUAL=y
|
|
+# CONFIG_DEBUG_VIRTUAL is not set
|
|
+# CONFIG_DEBUG_MEMORY_INIT is not set
|
|
+CONFIG_HAVE_ARCH_KASAN=y
|
|
+CONFIG_CC_HAS_KASAN_GENERIC=y
|
|
+CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y
|
|
+# CONFIG_KASAN is not set
|
|
+# end of Memory Debugging
|
|
+
|
|
+# CONFIG_DEBUG_SHIRQ is not set
|
|
+
|
|
+#
|
|
+# Debug Oops, Lockups and Hangs
|
|
+#
|
|
+# CONFIG_PANIC_ON_OOPS is not set
|
|
+CONFIG_PANIC_ON_OOPS_VALUE=0
|
|
+CONFIG_PANIC_TIMEOUT=0
|
|
+# CONFIG_SOFTLOCKUP_DETECTOR is not set
|
|
+# CONFIG_DETECT_HUNG_TASK is not set
|
|
+# CONFIG_WQ_WATCHDOG is not set
|
|
+# CONFIG_TEST_LOCKUP is not set
|
|
+# end of Debug Oops, Lockups and Hangs
|
|
+
|
|
+#
|
|
+# Scheduler Debugging
|
|
+#
|
|
+CONFIG_SCHED_DEBUG=y
|
|
+# CONFIG_SCHEDSTATS is not set
|
|
+# end of Scheduler Debugging
|
|
+
|
|
+# CONFIG_DEBUG_TIMEKEEPING is not set
|
|
+CONFIG_DEBUG_PREEMPT=y
|
|
+
|
|
+#
|
|
+# Lock Debugging (spinlocks, mutexes, etc...)
|
|
+#
|
|
+CONFIG_LOCK_DEBUGGING_SUPPORT=y
|
|
+# CONFIG_PROVE_LOCKING is not set
|
|
+# CONFIG_LOCK_STAT is not set
|
|
+# CONFIG_DEBUG_RT_MUTEXES is not set
|
|
+# CONFIG_DEBUG_SPINLOCK is not set
|
|
+# CONFIG_DEBUG_WW_MUTEX_SLOWPATH is not set
|
|
+# CONFIG_DEBUG_RWSEMS is not set
|
|
+# CONFIG_DEBUG_LOCK_ALLOC is not set
|
|
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
|
|
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
|
|
+# CONFIG_LOCK_TORTURE_TEST is not set
|
|
+# CONFIG_WW_MUTEX_SELFTEST is not set
|
|
+# CONFIG_SCF_TORTURE_TEST is not set
|
|
+# end of Lock Debugging (spinlocks, mutexes, etc...)
|
|
+
|
|
+# CONFIG_DEBUG_IRQFLAGS is not set
|
|
+# CONFIG_STACKTRACE is not set
|
|
+# CONFIG_WARN_ALL_UNSEEDED_RANDOM is not set
|
|
+# CONFIG_DEBUG_KOBJECT is not set
|
|
+
|
|
+#
|
|
+# Debug kernel data structures
|
|
+#
|
|
+# CONFIG_DEBUG_LIST is not set
|
|
+# CONFIG_DEBUG_PLIST is not set
|
|
+# CONFIG_DEBUG_SG is not set
|
|
+# CONFIG_DEBUG_NOTIFIERS is not set
|
|
+# CONFIG_BUG_ON_DATA_CORRUPTION is not set
|
|
+# end of Debug kernel data structures
|
|
+
|
|
+# CONFIG_DEBUG_CREDENTIALS is not set
|
|
+
|
|
+#
|
|
+# RCU Debugging
|
|
+#
|
|
+# CONFIG_RCU_SCALE_TEST is not set
|
|
+# CONFIG_RCU_TORTURE_TEST is not set
|
|
+# CONFIG_RCU_REF_SCALE_TEST is not set
|
|
+CONFIG_RCU_CPU_STALL_TIMEOUT=21
|
|
+CONFIG_RCU_TRACE=y
|
|
+# CONFIG_RCU_EQS_DEBUG is not set
|
|
+# end of RCU Debugging
|
|
+
|
|
+# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
|
|
+# CONFIG_LATENCYTOP is not set
|
|
+CONFIG_HAVE_FUNCTION_TRACER=y
|
|
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
|
|
+CONFIG_HAVE_DYNAMIC_FTRACE=y
|
|
+CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
|
|
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
|
|
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
|
|
+CONFIG_HAVE_C_RECORDMCOUNT=y
|
|
+CONFIG_TRACE_CLOCK=y
|
|
+CONFIG_TRACING_SUPPORT=y
|
|
+# CONFIG_FTRACE is not set
|
|
+# CONFIG_SAMPLES is not set
|
|
+
|
|
+#
|
|
+# arm Debugging
|
|
+#
|
|
+# CONFIG_ARM_PTDUMP_DEBUGFS is not set
|
|
+# CONFIG_UNWINDER_FRAME_POINTER is not set
|
|
+CONFIG_UNWINDER_ARM=y
|
|
+CONFIG_ARM_UNWIND=y
|
|
+# CONFIG_DEBUG_USER is not set
|
|
+# CONFIG_DEBUG_LL is not set
|
|
+CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
|
|
+CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
|
|
+# CONFIG_PID_IN_CONTEXTIDR is not set
|
|
+# CONFIG_CORESIGHT is not set
|
|
+# end of arm Debugging
|
|
+
|
|
+#
|
|
+# Kernel Testing and Coverage
|
|
+#
|
|
+# CONFIG_KUNIT is not set
|
|
+# CONFIG_NOTIFIER_ERROR_INJECTION is not set
|
|
+# CONFIG_FAULT_INJECTION is not set
|
|
+CONFIG_ARCH_HAS_KCOV=y
|
|
+CONFIG_CC_HAS_SANCOV_TRACE_PC=y
|
|
+# CONFIG_KCOV is not set
|
|
+# CONFIG_RUNTIME_TESTING_MENU is not set
|
|
+CONFIG_ARCH_USE_MEMTEST=y
|
|
+# CONFIG_MEMTEST is not set
|
|
+# end of Kernel Testing and Coverage
|
|
+# end of Kernel hacking
|
|
diff --git a/arch/arm/configs/imx_avb.config b/arch/arm/configs/imx_avb.config
|
|
new file mode 100644
|
|
index 000000000000..49b8d258c306
|
|
--- /dev/null
|
|
+++ b/arch/arm/configs/imx_avb.config
|
|
@@ -0,0 +1,8 @@
|
|
+CONFIG_EXPERT=y
|
|
+CONFIG_PREEMPT_RT=y
|
|
+CONFIG_AVB_SUPPORT=y
|
|
+CONFIG_NET_SWITCHDEV=y
|
|
+CONFIG_DEBUG_INFO=y
|
|
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
|
|
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
|
|
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
|
|
diff --git a/arch/arm/configs/imx_up.config b/arch/arm/configs/imx_up.config
|
|
new file mode 100644
|
|
index 000000000000..18b877a41fa7
|
|
--- /dev/null
|
|
+++ b/arch/arm/configs/imx_up.config
|
|
@@ -0,0 +1,2 @@
|
|
+CONFIG_SMP=n
|
|
+CONFIG_HIGHMEM=n
|
|
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
|
|
index b5a304ce400a..f223f5d9970a 100644
|
|
--- a/arch/arm/configs/imx_v6_v7_defconfig
|
|
+++ b/arch/arm/configs/imx_v6_v7_defconfig
|
|
@@ -49,7 +49,8 @@ CONFIG_CMDLINE="noinitrd console=ttymxc0,115200"
|
|
CONFIG_KEXEC=y
|
|
CONFIG_CPU_FREQ=y
|
|
CONFIG_CPU_FREQ_STAT=y
|
|
-CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
|
+CONFIG_CPU_FREQ_STAT_DETAILS=y
|
|
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
|
|
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
|
|
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
|
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
|
|
diff --git a/arch/arm/configs/imx_v7_defconfig b/arch/arm/configs/imx_v7_defconfig
|
|
index 472dff26b4b3..8c1ba26181b8 100644
|
|
--- a/arch/arm/configs/imx_v7_defconfig
|
|
+++ b/arch/arm/configs/imx_v7_defconfig
|
|
@@ -25,7 +25,7 @@ CONFIG_SOC_IMX6SLL=y
|
|
CONFIG_SOC_IMX6SX=y
|
|
CONFIG_SOC_IMX6UL=y
|
|
CONFIG_SOC_IMX7D=y
|
|
-CONFIG_SOC_IMX7ULP=y
|
|
+# CONFIG_SOC_IMX7ULP is not set
|
|
CONFIG_SMP=y
|
|
CONFIG_VMSPLIT_2G=y
|
|
CONFIG_ARM_PSCI=y
|
|
@@ -35,7 +35,8 @@ CONFIG_CMDLINE="noinitrd console=ttymxc0,115200"
|
|
CONFIG_KEXEC=y
|
|
CONFIG_CPU_FREQ=y
|
|
CONFIG_CPU_FREQ_STAT=y
|
|
-CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
|
|
+CONFIG_CPU_FREQ_STAT_DETAILS=y
|
|
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
|
|
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
|
|
CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
|
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
|
|
@@ -287,7 +288,7 @@ CONFIG_REGULATOR_LTC3676=y
|
|
CONFIG_REGULATOR_MAX17135=y
|
|
CONFIG_REGULATOR_MC13783=y
|
|
CONFIG_REGULATOR_MC13892=y
|
|
-CONFIG_REGULATOR_PF1550_RPMSG=y
|
|
+# CONFIG_REGULATOR_PF1550_RPMSG is not set
|
|
CONFIG_REGULATOR_PFUZE100=y
|
|
CONFIG_REGULATOR_RN5T618=y
|
|
CONFIG_RC_CORE=y
|
|
@@ -595,3 +596,5 @@ CONFIG_CRYPTO_SM4_GENERIC=m
|
|
CONFIG_CRYPTO_ARIA=m
|
|
CONFIG_CRYPTO_HCTR2=m
|
|
CONFIG_CRYPTO_SM3_GENERIC=m
|
|
+
|
|
+CONFIG_PREEMPT_RT=y
|
|
diff --git a/arch/arm/configs/lsdk.config b/arch/arm/configs/lsdk.config
|
|
index d10724fbff81..1fcf47b5c19d 100644
|
|
--- a/arch/arm/configs/lsdk.config
|
|
+++ b/arch/arm/configs/lsdk.config
|
|
@@ -64,6 +64,26 @@ CONFIG_IP6_NF_NAT=y
|
|
CONFIG_IP6_NF_FILTER=y
|
|
CONFIG_NETFILTER_XT_MATCH_COMMENT=y
|
|
|
|
+# can
|
|
+CONFIG_CAN_FLEXCAN=y
|
|
+# dspi
|
|
+CONFIG_SPI_BITBANG=y
|
|
+CONFIG_SPI_FSL_DSPI=y
|
|
+# watchdog
|
|
+CONFIG_IMX2_WDT=y
|
|
+# sound
|
|
+CONFIG_SND_MIXER_OSS=y
|
|
+CONFIG_SND_PCM_OSS=y
|
|
+CONFIG_SND_SOC_FSL_SAI=y
|
|
+CONFIG_SND_SOC_SGTL5000=y
|
|
+CONFIG_SND_SIMPLE_CARD=y
|
|
+# Video
|
|
+CONFIG_FB=y
|
|
+CONFIG_FB_FSL_DCU=y
|
|
+CONFIG_FB_FSL_SII902X=y
|
|
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
|
|
+CONFIG_LOGO=y
|
|
+CONFIG_SOC_VF610=n
|
|
# filesystems
|
|
CONFIG_EXT4_FS_POSIX_ACL=y
|
|
CONFIG_EXT4_FS_SECURITY=y
|
|
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
|
|
index c42c2372b339..b3ae89407dd3 100644
|
|
--- a/arch/arm/configs/multi_v7_defconfig
|
|
+++ b/arch/arm/configs/multi_v7_defconfig
|
|
@@ -1316,3 +1316,5 @@ CONFIG_CMA_SIZE_MBYTES=64
|
|
CONFIG_PRINTK_TIME=y
|
|
CONFIG_MAGIC_SYSRQ=y
|
|
CONFIG_DEBUG_FS=y
|
|
+# PREEMPT RT
|
|
+CONFIG_PREEMPT_RT=y
|
|
\ No newline at end of file
|
|
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
|
|
index 3431c0553f45..3d44ece9ff74 100644
|
|
--- a/arch/arm/kernel/smp.c
|
|
+++ b/arch/arm/kernel/smp.c
|
|
@@ -50,6 +50,10 @@
|
|
|
|
#include <trace/events/ipi.h>
|
|
|
|
+#ifdef CONFIG_BAREMETAL
|
|
+#include <linux/ipi_baremetal.h>
|
|
+#endif
|
|
+
|
|
/*
|
|
* as from 2.5, kernels no longer have an init_tasks structure
|
|
* so we need some other way of telling a new secondary core
|
|
@@ -65,6 +69,9 @@ enum ipi_msg_type {
|
|
IPI_CPU_STOP,
|
|
IPI_IRQ_WORK,
|
|
IPI_COMPLETION,
|
|
+#ifdef CONFIG_BAREMETAL
|
|
+ IPI_BAREMETAL_COMM = 8,
|
|
+#endif
|
|
NR_IPI,
|
|
/*
|
|
* CPU_BACKTRACE is special and not included in NR_IPI
|
|
@@ -539,6 +546,9 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
|
|
[IPI_CPU_STOP] = "CPU stop interrupts",
|
|
[IPI_IRQ_WORK] = "IRQ work interrupts",
|
|
[IPI_COMPLETION] = "completion interrupts",
|
|
+#ifdef CONFIG_BAREMETAL
|
|
+ [IPI_BAREMETAL_COMM] = "Baremetal inter-core interrupts",
|
|
+#endif
|
|
};
|
|
|
|
static void smp_cross_call(const struct cpumask *target, unsigned int ipinr);
|
|
@@ -669,6 +679,18 @@ static void do_handle_IPI(int ipinr)
|
|
ipi_complete(cpu);
|
|
break;
|
|
|
|
+#ifdef CONFIG_BAREMETAL
|
|
+#define GICC_IAR_MASK 0x1fff
|
|
+ case IPI_BAREMETAL_COMM: {
|
|
+ /* FIXME: use the fixed source coreID from core1 */
|
|
+ int irqsrc = 1;
|
|
+ /*linux core is 0 core, so iterate from 1 core.*/
|
|
+ for(irqsrc = 1; irqsrc < CONFIG_MAX_CPUS; irqsrc++)
|
|
+ ipi_baremetal_handle(ipinr, irqsrc);
|
|
+ }
|
|
+ break;
|
|
+#endif
|
|
+
|
|
case IPI_CPU_BACKTRACE:
|
|
printk_deferred_enter();
|
|
nmi_cpu_backtrace(get_irq_regs());
|
|
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
|
|
index 0e672fc9a80f..1ee568a27ff5 100644
|
|
--- a/arch/arm/mach-imx/Kconfig
|
|
+++ b/arch/arm/mach-imx/Kconfig
|
|
@@ -217,6 +217,16 @@ config SOC_LS1021A
|
|
help
|
|
This enables support for Freescale LS1021A processor.
|
|
|
|
+config LS1021A_BAREMETAL
|
|
+ bool "NXP LS1021A baremetal support"
|
|
+ depends on SOC_LS1021A
|
|
+ select BAREMETAL
|
|
+
|
|
+config SOC_IMX6Q_BAREMETAL
|
|
+ bool "NXP IMX6Q baremetal support"
|
|
+ depends on SOC_IMX6Q
|
|
+ select BAREMETAL
|
|
+
|
|
endif
|
|
|
|
if ARCH_MULTI_V7 || ARM_SINGLE_ARMV7M
|
|
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
|
|
index fef62e4a9edd..622a30243f4a 100644
|
|
--- a/arch/arm/mm/fault.c
|
|
+++ b/arch/arm/mm/fault.c
|
|
@@ -404,6 +404,9 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
|
|
if (addr < TASK_SIZE)
|
|
return do_page_fault(addr, fsr, regs);
|
|
|
|
+ if (interrupts_enabled(regs))
|
|
+ local_irq_enable();
|
|
+
|
|
if (user_mode(regs))
|
|
goto bad_area;
|
|
|
|
@@ -474,6 +477,9 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
|
|
static int
|
|
do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
|
|
{
|
|
+ if (interrupts_enabled(regs))
|
|
+ local_irq_enable();
|
|
+
|
|
do_bad_area(addr, fsr, regs);
|
|
return 0;
|
|
}
|
|
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
|
|
index 7e8773a2d99d..9fde36fcb80c 100644
|
|
--- a/arch/arm/vfp/vfpmodule.c
|
|
+++ b/arch/arm/vfp/vfpmodule.c
|
|
@@ -55,6 +55,34 @@ extern unsigned int VFP_arch_feroceon __alias(VFP_arch);
|
|
*/
|
|
union vfp_state *vfp_current_hw_state[NR_CPUS];
|
|
|
|
+/*
|
|
+ * Claim ownership of the VFP unit.
|
|
+ *
|
|
+ * The caller may change VFP registers until vfp_unlock() is called.
|
|
+ *
|
|
+ * local_bh_disable() is used to disable preemption and to disable VFP
|
|
+ * processing in softirq context. On PREEMPT_RT kernels local_bh_disable() is
|
|
+ * not sufficient because it only serializes soft interrupt related sections
|
|
+ * via a local lock, but stays preemptible. Disabling preemption is the right
|
|
+ * choice here as bottom half processing is always in thread context on RT
|
|
+ * kernels so it implicitly prevents bottom half processing as well.
|
|
+ */
|
|
+static void vfp_lock(void)
|
|
+{
|
|
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT))
|
|
+ local_bh_disable();
|
|
+ else
|
|
+ preempt_disable();
|
|
+}
|
|
+
|
|
+static void vfp_unlock(void)
|
|
+{
|
|
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT))
|
|
+ local_bh_enable();
|
|
+ else
|
|
+ preempt_enable();
|
|
+}
|
|
+
|
|
/*
|
|
* Is 'thread's most up to date state stored in this CPUs hardware?
|
|
* Must be called from non-preemptible context.
|
|
@@ -240,7 +268,7 @@ static void vfp_panic(char *reason, u32 inst)
|
|
/*
|
|
* Process bitmask of exception conditions.
|
|
*/
|
|
-static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_regs *regs)
|
|
+static int vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr)
|
|
{
|
|
int si_code = 0;
|
|
|
|
@@ -248,8 +276,7 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_
|
|
|
|
if (exceptions == VFP_EXCEPTION_ERROR) {
|
|
vfp_panic("unhandled bounce", inst);
|
|
- vfp_raise_sigfpe(FPE_FLTINV, regs);
|
|
- return;
|
|
+ return FPE_FLTINV;
|
|
}
|
|
|
|
/*
|
|
@@ -277,8 +304,7 @@ static void vfp_raise_exceptions(u32 exceptions, u32 inst, u32 fpscr, struct pt_
|
|
RAISE(FPSCR_OFC, FPSCR_OFE, FPE_FLTOVF);
|
|
RAISE(FPSCR_IOC, FPSCR_IOE, FPE_FLTINV);
|
|
|
|
- if (si_code)
|
|
- vfp_raise_sigfpe(si_code, regs);
|
|
+ return si_code;
|
|
}
|
|
|
|
/*
|
|
@@ -324,6 +350,8 @@ static u32 vfp_emulate_instruction(u32 inst, u32 fpscr, struct pt_regs *regs)
|
|
static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
|
|
{
|
|
u32 fpscr, orig_fpscr, fpsid, exceptions;
|
|
+ int si_code2 = 0;
|
|
+ int si_code = 0;
|
|
|
|
pr_debug("VFP: bounce: trigger %08x fpexc %08x\n", trigger, fpexc);
|
|
|
|
@@ -369,8 +397,8 @@ static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
|
|
* unallocated VFP instruction but with FPSCR.IXE set and not
|
|
* on VFP subarch 1.
|
|
*/
|
|
- vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr, regs);
|
|
- return;
|
|
+ si_code = vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr);
|
|
+ goto exit;
|
|
}
|
|
|
|
/*
|
|
@@ -394,14 +422,14 @@ static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
|
|
*/
|
|
exceptions = vfp_emulate_instruction(trigger, fpscr, regs);
|
|
if (exceptions)
|
|
- vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs);
|
|
+ si_code2 = vfp_raise_exceptions(exceptions, trigger, orig_fpscr);
|
|
|
|
/*
|
|
* If there isn't a second FP instruction, exit now. Note that
|
|
* the FPEXC.FP2V bit is valid only if FPEXC.EX is 1.
|
|
*/
|
|
if ((fpexc & (FPEXC_EX | FPEXC_FP2V)) != (FPEXC_EX | FPEXC_FP2V))
|
|
- return;
|
|
+ goto exit;
|
|
|
|
/*
|
|
* The barrier() here prevents fpinst2 being read
|
|
@@ -413,7 +441,13 @@ static void VFP_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
|
|
emulate:
|
|
exceptions = vfp_emulate_instruction(trigger, orig_fpscr, regs);
|
|
if (exceptions)
|
|
- vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs);
|
|
+ si_code = vfp_raise_exceptions(exceptions, trigger, orig_fpscr);
|
|
+exit:
|
|
+ vfp_unlock();
|
|
+ if (si_code2)
|
|
+ vfp_raise_sigfpe(si_code2, regs);
|
|
+ if (si_code)
|
|
+ vfp_raise_sigfpe(si_code, regs);
|
|
}
|
|
|
|
static void vfp_enable(void *unused)
|
|
@@ -512,11 +546,9 @@ static inline void vfp_pm_init(void) { }
|
|
*/
|
|
void vfp_sync_hwstate(struct thread_info *thread)
|
|
{
|
|
- unsigned int cpu = get_cpu();
|
|
+ vfp_lock();
|
|
|
|
- local_bh_disable();
|
|
-
|
|
- if (vfp_state_in_hw(cpu, thread)) {
|
|
+ if (vfp_state_in_hw(raw_smp_processor_id(), thread)) {
|
|
u32 fpexc = fmrx(FPEXC);
|
|
|
|
/*
|
|
@@ -527,8 +559,7 @@ void vfp_sync_hwstate(struct thread_info *thread)
|
|
fmxr(FPEXC, fpexc);
|
|
}
|
|
|
|
- local_bh_enable();
|
|
- put_cpu();
|
|
+ vfp_unlock();
|
|
}
|
|
|
|
/* Ensure that the thread reloads the hardware VFP state on the next use. */
|
|
@@ -683,7 +714,7 @@ static int vfp_support_entry(struct pt_regs *regs, u32 trigger)
|
|
if (!user_mode(regs))
|
|
return vfp_kmode_exception(regs, trigger);
|
|
|
|
- local_bh_disable();
|
|
+ vfp_lock();
|
|
fpexc = fmrx(FPEXC);
|
|
|
|
/*
|
|
@@ -748,6 +779,7 @@ static int vfp_support_entry(struct pt_regs *regs, u32 trigger)
|
|
* replay the instruction that trapped.
|
|
*/
|
|
fmxr(FPEXC, fpexc);
|
|
+ vfp_unlock();
|
|
} else {
|
|
/* Check for synchronous or asynchronous exceptions */
|
|
if (!(fpexc & (FPEXC_EX | FPEXC_DEX))) {
|
|
@@ -762,17 +794,17 @@ static int vfp_support_entry(struct pt_regs *regs, u32 trigger)
|
|
if (!(fpscr & FPSCR_IXE)) {
|
|
if (!(fpscr & FPSCR_LENGTH_MASK)) {
|
|
pr_debug("not VFP\n");
|
|
- local_bh_enable();
|
|
+ vfp_unlock();
|
|
return -ENOEXEC;
|
|
}
|
|
fpexc |= FPEXC_DEX;
|
|
}
|
|
}
|
|
bounce: regs->ARM_pc += 4;
|
|
+ /* VFP_bounce() will invoke vfp_unlock() */
|
|
VFP_bounce(trigger, fpexc, regs);
|
|
}
|
|
|
|
- local_bh_enable();
|
|
return 0;
|
|
}
|
|
|
|
@@ -819,7 +851,7 @@ void kernel_neon_begin(void)
|
|
unsigned int cpu;
|
|
u32 fpexc;
|
|
|
|
- local_bh_disable();
|
|
+ vfp_lock();
|
|
|
|
/*
|
|
* Kernel mode NEON is only allowed outside of hardirq context with
|
|
@@ -850,7 +882,7 @@ void kernel_neon_end(void)
|
|
{
|
|
/* Disable the NEON/VFP unit. */
|
|
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
|
|
- local_bh_enable();
|
|
+ vfp_unlock();
|
|
}
|
|
EXPORT_SYMBOL(kernel_neon_end);
|
|
|
|
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
|
|
index 1731a4c573e7..ff3ee8dc3c79 100644
|
|
--- a/arch/arm64/Kconfig
|
|
+++ b/arch/arm64/Kconfig
|
|
@@ -97,6 +97,7 @@ config ARM64
|
|
select ARCH_SUPPORTS_NUMA_BALANCING
|
|
select ARCH_SUPPORTS_PAGE_TABLE_CHECK
|
|
select ARCH_SUPPORTS_PER_VMA_LOCK
|
|
+ select ARCH_SUPPORTS_RT
|
|
select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
|
|
select ARCH_WANT_COMPAT_IPC_PARSE_VERSION if COMPAT
|
|
select ARCH_WANT_DEFAULT_BPF_JIT
|
|
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
|
|
index e3b0450229e9..314b08100c82 100644
|
|
--- a/arch/arm64/Kconfig.platforms
|
|
+++ b/arch/arm64/Kconfig.platforms
|
|
@@ -204,6 +204,24 @@ config ARCH_LAYERSCAPE
|
|
help
|
|
This enables support for the Freescale Layerscape SoC family.
|
|
|
|
+config LS104XA_BAREMETAL
|
|
+ bool "NXP LS1043A/LS1046A baremetal support"
|
|
+ select BAREMETAL
|
|
+ help
|
|
+ This enables support for Freescale LS1043A and LS1046A baremetal.
|
|
+
|
|
+config LS1028A_BAREMETAL
|
|
+ bool "NXP LS1028A baremetal support"
|
|
+ select BAREMETAL
|
|
+ help
|
|
+ This enables support for NXP LS1028A baremetal.
|
|
+
|
|
+config LX2160A_BAREMETAL
|
|
+ bool "NXP LX2160A baremetal support"
|
|
+ select BAREMETAL
|
|
+ help
|
|
+ This enables support for NXP LX2160A baremetal.
|
|
+
|
|
config ARCH_MXC
|
|
bool "NXP i.MX SoC family"
|
|
select ARM64_ERRATUM_843419
|
|
@@ -257,6 +275,18 @@ config ARCH_NPCM
|
|
General support for NPCM8xx BMC (Arbel).
|
|
Nuvoton NPCM8xx BMC based on the Cortex A35.
|
|
|
|
+config IMX8M_BAREMETAL
|
|
+ bool "NXP IMX8MM/IMX8MP baremetal support"
|
|
+ select BAREMETAL
|
|
+ help
|
|
+ This enables support for NXP i.MX8MM and i.MX8MP baremetal.
|
|
+
|
|
+config IMX93_BAREMETAL
|
|
+ bool "NXP IMX93 baremetal support"
|
|
+ select BAREMETAL
|
|
+ help
|
|
+ This enables support for NXP i.MX93 baremetal.
|
|
+
|
|
config ARCH_QCOM
|
|
bool "Qualcomm Platforms"
|
|
select GPIOLIB
|
|
diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
|
|
index efe32533733e..c4ad4060ad41 100644
|
|
--- a/arch/arm64/boot/dts/freescale/Makefile
|
|
+++ b/arch/arm64/boot/dts/freescale/Makefile
|
|
@@ -14,11 +14,19 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-kontron-sl28-var3-ads2.dtb
|
|
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-kontron-sl28-var4.dtb
|
|
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-qds.dtb
|
|
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-rdb.dtb
|
|
+dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-rdb-jailhouse.dtb
|
|
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-rdb-dpdk.dtb
|
|
+dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-rdb-jailhouse-without-enetc.dtb
|
|
+dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-rdb-sdk-bm.dtb
|
|
+dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1028a-rdb-dsa-swp5-eno3.dtb
|
|
+dtb-$(CONFIG_ARCH_LAYERSCAPE) += fii-ls1028a-tsn.dtb
|
|
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-qds.dtb
|
|
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-qds-sdk.dtb
|
|
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb.dtb
|
|
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb-sdk.dtb
|
|
+dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb-sdk-jailhouse.dtb
|
|
+dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb-sdk-jailhouse-with-dpaa.dtb
|
|
+dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb-sdk-bm.dtb
|
|
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-rdb-usdpaa.dtb
|
|
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-frwy.dtb
|
|
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-frwy-sdk.dtb
|
|
@@ -26,7 +34,10 @@ dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-frwy-usdpaa.dtb
|
|
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-qds.dtb
|
|
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-qds-sdk.dtb
|
|
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb.dtb
|
|
+dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb-sdk-bm.dtb
|
|
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb-sdk.dtb
|
|
+dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb-sdk-jailhouse.dtb
|
|
+dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb-sdk-jailhouse-with-dpaa.dtb
|
|
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb-usdpaa.dtb
|
|
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb-shared-mac9-only.dtb
|
|
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1046a-rdb-usdpaa-shared-mac10.dtb
|
|
@@ -75,13 +86,38 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mm-ab2.dtb imx8mm-ab2-m4.dtb imx8mm-ddr4-ab2.dtb i
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk.dtb imx8mm-evk-rpmsg.dtb imx8mm-evk-rm67191.dtb \
|
|
imx8mm-evk-root.dtb imx8mm-evk-inmate.dtb imx8mm-evk-revb-qca-wifi.dtb \
|
|
imx8mm-evk-ecspi-slave.dtb \
|
|
+ imx8mm-evk-baremetal.dtb \
|
|
+ imx8mm-evk-avb.dtb \
|
|
imx8mm-evk-pcie-ep.dtb \
|
|
imx8mm-evk-usd-wifi.dtb \
|
|
imx8mm-evk-qca-wifi.dtb \
|
|
imx8mm-evk-dpdk.dtb \
|
|
+ imx8mm-evk-harpoon.dtb imx8mm-evk-harpoon-industrial.dtb imx8mm-evk-harpoon-avb.dtb \
|
|
+ imx8mm-evk-harpoon-virtio-net.dtb \
|
|
+ imx8mm-evk-qca-wifi-harpoon.dtb imx8mm-evk-qca-wifi-harpoon-industrial.dtb \
|
|
+ imx8mm-evk-qca-wifi-harpoon-avb.dtb imx8mm-evk-qca-wifi-harpoon-virtio-net.dtb \
|
|
imx8mm-evk-rm67199.dtb imx8mm-evk-rm67191-cmd-ram.dtb imx8mm-evk-rm67199-cmd-ram.dtb \
|
|
- imx8mm-evk-lk.dtb imx8mm-evk-rpmsg-wm8524-lpv.dtb
|
|
+ imx8mm-evk-lk.dtb imx8mm-evk-rpmsg-wm8524-lpv.dtb \
|
|
+ imx8mm-evk-rpmsg-8m-buf.dtb \
|
|
+ imx8mm-evk-ecat.dtb \
|
|
+ imx8mm-evk-igh.dtb \
|
|
+ imx8mm-evk-ecat-userspace.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk-rpmsg-wm8524.dtb
|
|
+dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk-rpmsg-ca53.dtb \
|
|
+ imx8mm-evk-virtio-perf-ca53.dtb \
|
|
+ imx8mm-evk-virtio-perf-cm4.dtb \
|
|
+ imx8mm-evk-virtio-net-ca53.dtb \
|
|
+ imx8mm-evk-virtio-net-cm4.dtb \
|
|
+ imx8mm-evk-multicore-rtos.dtb \
|
|
+ imx8mm-evk-multicore-rpmsg.dtb \
|
|
+ imx8mp-evk-rpmsg-ca53.dtb \
|
|
+ imx8mp-evk-virtio-net-ca53.dtb \
|
|
+ imx8mp-evk-virtio-net-cm7.dtb \
|
|
+ imx8mp-evk-virtio-perf-ca53.dtb \
|
|
+ imx8mp-evk-virtio-perf-cm7.dtb \
|
|
+ imx8mp-evk-multicore-rtos.dtb \
|
|
+ imx8mp-evk-multicore-lwip.dtb \
|
|
+ imx8mp-evk-multicore-rpmsg.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk-ak4497.dtb imx8mm-evk-ak5558.dtb imx8mm-evk-audio-tdm.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mm-evk-8mic-revE.dtb imx8mm-evk-8mic-swpdm.dtb \
|
|
imx8mm-evk-iqaudio-dacplus.dtb imx8mm-evk-iqaudio-dacpro.dtb imx8mm-evk-hifiberry-dacplus.dtb \
|
|
@@ -115,7 +151,8 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mn-ddr4-evk.dtb imx8mn-ddr4-evk-rm67191.dtb imx8mn
|
|
imx8mn-ddr4-evk-usd-wifi.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mn-ddr4-evk-rpmsg.dtb imx8mn-ddr3l-evk-rpmsg.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mn-ddr4-evk-root.dtb imx8mn-ddr4-evk-inmate.dtb imx8mn-evk-root.dtb imx8mn-evk-inmate.dtb \
|
|
- imx8mn-evk-lk.dtb imx8mn-ddr4-evk-lk.dtb
|
|
+ imx8mn-evk-lk.dtb imx8mn-ddr4-evk-lk.dtb imx8mn-evk-harpoon.dtb imx8mn-evk-harpoon-industrial.dtb \
|
|
+ imx8mn-evk-harpoon-avb.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mn-ddr3l-evk-ak5558.dtb imx8mn-ddr4-evk-ak5558.dtb imx8mn-evk-ak5558.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mn-ab2.dtb imx8mn-ddr3l-ab2.dtb imx8mn-ddr4-ab2.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mn-evk-iqaudio-dacplus.dtb imx8mn-evk-iqaudio-dacpro.dtb imx8mn-evk-hifiberry-dacplus.dtb \
|
|
@@ -123,7 +160,9 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mn-evk-iqaudio-dacplus.dtb imx8mn-evk-iqaudio-dacp
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk.dtb imx8mp-evk-rm67191.dtb imx8mp-evk-it6263-lvds-dual-channel.dtb \
|
|
imx8mp-evk-pcie-ep.dtb imx8mp-evk-rpmsg.dtb imx8mp-evk-ecspi-slave.dtb \
|
|
imx8mp-evk-jdi-wuxga-lvds-panel.dtb imx8mp-evk-flexcan2.dtb \
|
|
- imx8mp-evk-root.dtb imx8mp-evk-inmate.dtb imx8mp-evk-ov2775.dtb \
|
|
+ imx8mp-evk-root.dtb imx8mp-evk-harpoon.dtb imx8mp-evk-harpoon-industrial.dtb imx8mp-evk-inmate.dtb \
|
|
+ imx8mp-evk-harpoon-avb.dtb imx8mp-evk-harpoon-virtio-net.dtb \
|
|
+ imx8mp-evk-ov2775.dtb \
|
|
imx8mp-evk-ov2775-ov5640.dtb imx8mp-evk-basler-ov5640.dtb imx8mp-evk-basler.dtb \
|
|
imx8mp-evk-basler-ov2775.dtb imx8mp-evk-dual-basler.dtb \
|
|
imx8mp-evk-dual-ov2775.dtb imx8mp-evk-spdif-lb.dtb imx8mp-evk-dsp.dtb \
|
|
@@ -133,13 +172,19 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk.dtb imx8mp-evk-rm67191.dtb imx8mp-evk-it626
|
|
imx8mp-evk-iqaudio-dacplus.dtb imx8mp-evk-iqaudio-dacpro.dtb imx8mp-evk-hifiberry-dacplus.dtb \
|
|
imx8mp-evk-hifiberry-dac2.dtb imx8mp-evk-hifiberry-dacplusadc.dtb \
|
|
imx8mp-evk-usdhc1-m2.dtb imx8mp-evk-rm67199.dtb \
|
|
- imx8mp-evk-dpdk.dtb imx8mp-evk-8mic-swpdm.dtb imx8mp-evk-rpmsg-lpv.dtb imx8mp-evk-revA3-8mic-revE.dtb
|
|
+ imx8mp-evk-dpdk.dtb imx8mp-evk-8mic-swpdm.dtb imx8mp-evk-rpmsg-lpv.dtb imx8mp-evk-revA3-8mic-revE.dtb \
|
|
+ imx8mp-evk-baremetal.dtb imx8mp-evk-avb.dtb \
|
|
+ imx8mp-evk-ecat.dtb imx8mp-evk-igh.dtb imx8mp-evk-ecat-userspace.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mp-msc-sm2s-ep1.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mp-phyboard-pollux-rdk.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mp-ab2.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mp-navq.dtb imx8mp-navq-ov5640-ov5645.dtb imx8mp-navq-ov5647-ov5640.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mp-ddr4-evk.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-ndm.dtb
|
|
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-dsa.dtb
|
|
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-dsa-enetc.dtb
|
|
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-dsa-fec-swp0.dtb
|
|
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-dsa-fec-swp3.dtb
|
|
|
|
imx8mp-evk-revb4-dtbs := imx8mp-evk.dtb imx8mp-evk-revb4.dtbo
|
|
imx8mp-evk-revb4-rm67191-dtbs := imx8mp-evk-rm67191.dtb imx8mp-evk-revb4.dtbo
|
|
@@ -172,6 +217,10 @@ imx8mp-evk-revb4-8mic-swpdm-dtbs := imx8mp-evk-8mic-swpdm.dtb imx8mp-evk-revb4.d
|
|
imx8mp-evk-revb4-8mic-revE-dtbs := imx8mp-evk-revA3-8mic-revE.dtb imx8mp-evk-revb4.dtbo
|
|
imx8mp-ddr4-evk-revb4-dtbs := imx8mp-ddr4-evk.dtb imx8mp-evk-revb4.dtbo
|
|
imx8mp-evk-revb4-ndm-dtbs := imx8mp-evk-ndm.dtb imx8mp-evk-revb4.dtbo
|
|
+imx8mp-evk-revb4-dsa-dtbs := imx8mp-evk-dsa.dtb imx8mp-evk-revb4.dtbo
|
|
+imx8mp-evk-revb4-dsa-enetc-dtbs := imx8mp-evk-dsa-enetc.dtb imx8mp-evk-revb4.dtbo
|
|
+imx8mp-evk-revb4-dsa-fec-swp0-dtbs := imx8mp-evk-dsa-fec-swp0.dtb imx8mp-evk-revb4.dtbo
|
|
+imx8mp-evk-revb4-dsa-fec-swp3-dtbs := imx8mp-evk-dsa-fec-swp3.dtb imx8mp-evk-revb4.dtbo
|
|
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-revb4.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-revb4-rm67191.dtb
|
|
@@ -207,6 +256,10 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-revb4-ndm.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-revb4-sof-wm8962.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-revb4-rpmsg.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-revb4-rpmsg-lpv.dtb
|
|
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-revb4-dsa.dtb
|
|
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-revb4-dsa-enetc.dtb
|
|
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-revb4-dsa-fec-swp0.dtb
|
|
+dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk-revb4-dsa-fec-swp3.dtb
|
|
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mq-evk.dtb imx8mq-evk-rpmsg.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8mq-evk.dtb imx8mq-evk-rpmsg.dtb imx8mq-evk-pcie1-m2.dtb imx8mq-evk-usd-wifi.dtb \
|
|
@@ -314,7 +367,8 @@ dtb-$(CONFIG_ARCH_MXC) += imx8ulp-evk.dtb imx8ulp-evk-lpspi-slave.dtb \
|
|
imx8ulp-9x9-evk-i3c.dtb imx8ulp-9x9-evk-sof-btsco.dtb \
|
|
imx8ulp-evk-lpa.dtb imx8ulp-9x9-evk-lpa.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8dxl-evk.dtb \
|
|
- imx8dxl-evk-enet0.dtb imx8dxl-evk-enet0-tja1100.dtb \
|
|
+ imx8dxl-evk-enet0.dtb imx8dxl-evk-enet0-tja1100.dtb imx8dxl-evk-enet0-tja1100-avb.dtb \
|
|
+ imx8dxl-evk-enet0-avb.dtb imx8dxl-evk-enet0-sja1105.dtb \
|
|
imx8dxl-evk-pcie-ep.dtb \
|
|
imx8dxl-evk-lcdif.dtb \
|
|
imx8dxl-evk-lpspi-slave.dtb \
|
|
@@ -370,13 +424,21 @@ dtb-$(CONFIG_ARCH_MXC) += imx8qxp-mek.dtb imx8qxp-mek-ov5640.dtb \
|
|
imx8qxp-17x17-val.dtb imx8dx-lpddr4-val.dtb imx8dx-17x17-val.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx8qxp-mek-dom0.dtb imx8qxp-mek-root.dtb \
|
|
imx8qxp-mek-inmate.dtb
|
|
-dtb-$(CONFIG_ARCH_MXC) += imx93-14x14-evk.dtb \
|
|
+dtb-$(CONFIG_ARCH_MXC) += imx93-14x14-evk.dtb imx93-14x14-evk-aud-hat-avb.dtb \
|
|
imx93-14x14-evk-tja1103.dtb imx93-14x14-evk-rm67199.dtb \
|
|
imx93-14x14-evk-mqs.dtb imx93-14x14-evk-aud-hat.dtb \
|
|
- imx93-14x14-evk-lvds-it6263.dtb imx93-14x14-evk-sja1105.dtb \
|
|
+ imx93-14x14-evk-lvds-it6263.dtb imx93-14x14-evk-sja1105.dtb imx93-14x14-evk-sja1105-avb.dtb \
|
|
imx93-14x14-evk-flexspi-m2.dtb imx93-14x14-evk-dsi-serdes.dtb \
|
|
- imx93-14x14-evk-i3c.dtb
|
|
+ imx93-14x14-evk-i3c.dtb imx93-14x14-evk-imxai2eth-ath.dtb \
|
|
+ imx93-14x14-evk-virtio-net-ca55.dtb \
|
|
+ imx93-14x14-evk-virtio-net-cm33.dtb \
|
|
+ imx93-14x14-evk-uart-sharing-cm33.dtb \
|
|
+ imx93-14x14-evk-multicore-rpmsg.dtb \
|
|
+ imx93-14x14-evk-multicore-rtos.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx93-11x11-evk.dtb \
|
|
+ imx93-11x11-evk-avb.dtb \
|
|
+ imx93-11x11-evk-harpoon.dtb imx93-11x11-evk-harpoon-industrial.dtb imx93-11x11-evk-harpoon-avb.dtb \
|
|
+ imx93-11x11-evk-harpoon-virtio-net.dtb \
|
|
imx93-11x11-evk-inmate.dtb imx93-11x11-evk-root.dtb imx93-11x11-evk-flexio-i2c.dtb \
|
|
imx93-11x11-evk-i2c-spi-slave.dtb \
|
|
imx93-11x11-evk-i3c.dtb imx93-11x11-evk-lpuart.dtb \
|
|
@@ -386,7 +448,21 @@ dtb-$(CONFIG_ARCH_MXC) += imx93-11x11-evk.dtb \
|
|
imx93-11x11-evk-mt9m114.dtb \
|
|
imx93-11x11-evk-ld.dtb \
|
|
imx93-11x11-evk-iw612-otbr.dtb \
|
|
- imx93-11x11-evk-rpmsg.dtb imx93-11x11-evk-rpmsg-lpv.dtb
|
|
+ imx93-11x11-evk-rpmsg.dtb imx93-11x11-evk-rpmsg-lpv.dtb \
|
|
+ imx93-11x11-evk-virtio-net-ca55.dtb \
|
|
+ imx93-11x11-evk-virtio-net-cm33.dtb \
|
|
+ imx93-11x11-evk-uart-sharing-cm33.dtb \
|
|
+ imx93-11x11-evk-baremetal.dtb \
|
|
+ imx93-11x11-evk-ecat.dtb \
|
|
+ imx93-11x11-evk-igh.dtb \
|
|
+ imx93-11x11-evk-ecat-userspace.dtb \
|
|
+ imx93-11x11-evk-multicore-rpmsg.dtb \
|
|
+ imx93-11x11-evk-multicore-rtos.dtb \
|
|
+ imx93-11x11-evk-dsa.dtb \
|
|
+ imx93-11x11-evk-dsa-enetc.dtb \
|
|
+ imx93-11x11-evk-dsa-fec-swp0.dtb \
|
|
+ imx93-11x11-evk-dsa-fec-swp3.dtb \
|
|
+ imx93-11x11-evk-dpdk.dtb
|
|
|
|
dtb-$(CONFIG_ARCH_MXC) += imx91-11x11-evk.dtb \
|
|
imx91-11x11-evk-flexspi-m2.dtb imx91-11x11-evk-flexspi-nand-m2.dtb \
|
|
@@ -438,9 +514,12 @@ dtb-$(CONFIG_ARCH_MXC) += imx93-9x9-qsb.dtb \
|
|
imx93-9x9-qsb-mt9m114.dtb \
|
|
imx93-9x9-qsb-i3c.dtb \
|
|
imx93-9x9-qsb-lpspi.dtb imx93-9x9-qsb-lpspi-slave.dtb \
|
|
+ imx93-9x9-qsb-baremetal.dtb \
|
|
imx93-9x9-qsb-aud-hat.dtb \
|
|
imx93-9x9-qsb-ld.dtb \
|
|
- imx93-9x9-qsb-rpmsg.dtb imx93-9x9-qsb-rpmsg-lpv.dtb
|
|
+ imx93-9x9-qsb-rpmsg.dtb imx93-9x9-qsb-rpmsg-lpv.dtb \
|
|
+ imx93-9x9-qsb-uart-sharing-cm33.dtb \
|
|
+ imx93-9x9-qsb-inmate.dts imx93-9x9-qsb-root.dts
|
|
dtb-$(CONFIG_ARCH_MXC) += imx93-tqma9352-mba93xxla.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx91-9x9-qsb.dtb \
|
|
imx91-9x9-qsb-can1.dtb \
|
|
@@ -456,8 +535,9 @@ dtb-$(CONFIG_ARCH_MXC) += imx91-9x9-qsb-i3c.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-evk.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-evk-flexspi-m2.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-evk-mqs.dtb
|
|
+dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-evk-multicore-rtos.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-evk-aud-hat.dtb
|
|
-dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-evk-root.dtb imx95-15x15-evk-inmate.dtb
|
|
+dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-evk-root.dtb imx95-15x15-evk-inmate.dtb imx95-15x15-evk-harpoon.dtb imx95-15x15-evk-harpoon-industrial.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-ab2.dtb
|
|
dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-evk-i2c-spi-slave.dtb
|
|
DTC_FLAGS_imx95-15x15-evk-boe-wxga-lvds0-panel := -@
|
|
@@ -516,6 +596,8 @@ DTC_FLAGS_imx95-15x15-evk-rpmsg-lpv := -@
|
|
dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-evk-rpmsg.dtb imx95-15x15-evk-rpmsg-lpv.dtb
|
|
|
|
dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-evk.dtb imx95-19x19-evk-root.dtb imx95-19x19-evk-inmate.dtb \
|
|
+ imx95-19x19-evk-harpoon.dtb imx95-19x19-evk-harpoon-industrial.dtb \
|
|
+ imx95-19x19-evk-multicore-rtos.dtb \
|
|
imx95-19x19-evk-lpspi-slave.dtb
|
|
|
|
imx95-15x15-evk-ox03c10-dtbs := imx95-15x15-evk.dtb imx95-15x15-evk-ox03c10.dtbo
|
|
diff --git a/arch/arm64/boot/dts/freescale/fii-ls1028a-tsn.dts b/arch/arm64/boot/dts/freescale/fii-ls1028a-tsn.dts
|
|
new file mode 100644
|
|
index 000000000000..a28b47206334
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/fii-ls1028a-tsn.dts
|
|
@@ -0,0 +1,325 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Device Tree file for Foxconn LS1028A TSN Board.
|
|
+ *
|
|
+ * Copyright 2020-2022 NXP
|
|
+ *
|
|
+ * Wes Li <wes.li@nxp.com>
|
|
+ * Vladimir Oltean <vladimir.oltean@nxp.com>
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "fsl-ls1028a.dtsi"
|
|
+
|
|
+/ {
|
|
+ model = "Foxconn LS1028A TSN Board";
|
|
+ compatible = "fsl,ls1028a-rdb", "fsl,ls1028a";
|
|
+
|
|
+ aliases {
|
|
+ crypto = &crypto;
|
|
+ serial0 = &duart0;
|
|
+ serial1 = &duart1;
|
|
+ };
|
|
+
|
|
+ chosen {
|
|
+ stdout-path = "serial0:115200n8";
|
|
+ };
|
|
+
|
|
+ memory@80000000 {
|
|
+ device_type = "memory";
|
|
+ reg = <0x0 0x80000000 0x1 0x0000000>;
|
|
+ };
|
|
+
|
|
+ sys_mclk: clock-mclk {
|
|
+ compatible = "fixed-clock";
|
|
+ #clock-cells = <0>;
|
|
+ clock-frequency = <25000000>;
|
|
+ };
|
|
+
|
|
+ reg_1p8v: regulator-1p8v {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "1P8V";
|
|
+ regulator-min-microvolt = <1800000>;
|
|
+ regulator-max-microvolt = <1800000>;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ sb_3v3: regulator-sb3v3 {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "3v3_vbus";
|
|
+ regulator-min-microvolt = <3300000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+};
|
|
+
|
|
+&dspi2 {
|
|
+ bus-num = <2>;
|
|
+ status = "okay";
|
|
+
|
|
+ sja1105_switch0: ethernet-switch@0 {
|
|
+ reg = <0x0>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ compatible = "nxp,sja1105s";
|
|
+ dsa,member = <1 1>;
|
|
+ /* 20 MHz */
|
|
+ spi-max-frequency = <20000000>;
|
|
+ /* Sample data on trailing clock edge */
|
|
+ spi-cpha;
|
|
+ /* SPI controller settings for SJA1105 timing requirements */
|
|
+ fsl,spi-cs-sck-delay = <1000>;
|
|
+ fsl,spi-sck-cs-delay = <1000>;
|
|
+
|
|
+ ports {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ port@0 {
|
|
+ label = "sw0p0";
|
|
+ phy-handle = <&sw0p0_rgmii_phy>;
|
|
+ phy-mode = "rgmii-id";
|
|
+ reg = <0>;
|
|
+ };
|
|
+
|
|
+ port@1 {
|
|
+ label = "sw0p1";
|
|
+ phy-handle = <&sw0p1_rgmii_phy>;
|
|
+ phy-mode = "rgmii-id";
|
|
+ reg = <1>;
|
|
+ };
|
|
+
|
|
+ port@2 {
|
|
+ label = "sw0p2";
|
|
+ phy-handle = <&sw0p2_rgmii_phy>;
|
|
+ phy-mode = "rgmii-id";
|
|
+ reg = <2>;
|
|
+ };
|
|
+
|
|
+ port@3 {
|
|
+ reg = <3>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ port@4 {
|
|
+ ethernet = <&mscc_felix_port0>;
|
|
+ phy-mode = "sgmii";
|
|
+ reg = <4>;
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+
|
|
+ /* Daughter card 1 */
|
|
+ sja1105_switch1: ethernet-switch@1 {
|
|
+ reg = <0x1>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ compatible = "nxp,sja1105s";
|
|
+ dsa,member = <2 2>;
|
|
+ /* 20 MHz */
|
|
+ spi-max-frequency = <20000000>;
|
|
+ spi-cpha;
|
|
+ fsl,spi-cs-sck-delay = <1000>;
|
|
+ fsl,spi-sck-cs-delay = <1000>;
|
|
+
|
|
+ ports {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ port@0 {
|
|
+ label = "sw1p0";
|
|
+ phy-handle = <&sw1p0_rgmii_phy>;
|
|
+ phy-mode = "rgmii-id";
|
|
+ reg = <0>;
|
|
+ };
|
|
+
|
|
+ port@1 {
|
|
+ label = "sw1p1";
|
|
+ phy-handle = <&sw1p1_rgmii_phy>;
|
|
+ phy-mode = "rgmii-id";
|
|
+ reg = <1>;
|
|
+ };
|
|
+
|
|
+ port@2 {
|
|
+ label = "sw1p2";
|
|
+ phy-handle = <&sw1p2_rgmii_phy>;
|
|
+ phy-mode = "rgmii-id";
|
|
+ reg = <2>;
|
|
+ };
|
|
+
|
|
+ port@3 {
|
|
+ label = "sw1p3";
|
|
+ phy-handle = <&sw1p3_rgmii_phy>;
|
|
+ phy-mode = "rgmii-id";
|
|
+ reg = <3>;
|
|
+ };
|
|
+
|
|
+ port@4 {
|
|
+ ethernet = <&mscc_felix_port2>;
|
|
+ phy-mode = "sgmii";
|
|
+ reg = <4>;
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&duart0 {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&duart1 {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&enetc_mdio_pf3 {
|
|
+ status = "okay";
|
|
+
|
|
+ /*
|
|
+ * PHYs on main board
|
|
+ */
|
|
+
|
|
+ /* RTL8211FSI */
|
|
+ sw0p0_rgmii_phy: ethernet-phy@7 {
|
|
+ reg = <0x7>;
|
|
+ };
|
|
+
|
|
+ /* VSC8502 SGMII dual PHY */
|
|
+ sw0p1_rgmii_phy: ethernet-phy@0 {
|
|
+ reg = <0x0>;
|
|
+ };
|
|
+
|
|
+ sw0p2_rgmii_phy: ethernet-phy@1 {
|
|
+ reg = <0x1>;
|
|
+ };
|
|
+
|
|
+ /*
|
|
+ * PHYs on daughter board 1
|
|
+ */
|
|
+
|
|
+ /* RTL8211FSI */
|
|
+ sw1p0_rgmii_phy: ethernet-phy@9 {
|
|
+ reg = <0x9>;
|
|
+ };
|
|
+
|
|
+ sw1p1_rgmii_phy: ethernet-phy@8 {
|
|
+ reg = <0x8>;
|
|
+ };
|
|
+
|
|
+ /* VSC8502 RGMII dual PHY */
|
|
+ sw1p2_rgmii_phy: ethernet-phy@5 {
|
|
+ reg = <0x5>;
|
|
+ };
|
|
+
|
|
+ sw1p3_rgmii_phy: ethernet-phy@4 {
|
|
+ reg = <0x4>;
|
|
+ };
|
|
+};
|
|
+
|
|
+&enetc_port0 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&enetc_port1 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&enetc_port2 {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&esdhc {
|
|
+ cap-sd-highspeed;
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&esdhc1 {
|
|
+ mmc-hs200-1_8v;
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&i2c0 {
|
|
+ status = "okay";
|
|
+
|
|
+ i2c-mux@77 {
|
|
+ compatible = "nxp,pca9847";
|
|
+ reg = <0x77>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ i2c@2 {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ reg = <0x02>;
|
|
+
|
|
+ current-monitor@40 {
|
|
+ compatible = "ti,ina220";
|
|
+ reg = <0x40>;
|
|
+ shunt-resistor = <500>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ i2c@3 {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ reg = <0x3>;
|
|
+
|
|
+ temperature-sensor@4c {
|
|
+ compatible = "nxp,sa56004";
|
|
+ reg = <0x4c>;
|
|
+ vcc-supply = <&sb_3v3>;
|
|
+ };
|
|
+
|
|
+ rtc@51 {
|
|
+ compatible = "nxp,pcf2129";
|
|
+ reg = <0x51>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&mscc_felix {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+/* Master for SJA1105 on main board */
|
|
+&mscc_felix_port0 {
|
|
+ phy-mode = "sgmii";
|
|
+ status = "okay";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+};
|
|
+
|
|
+/* Master for SJA1105 on daughter card 1 */
|
|
+&mscc_felix_port2 {
|
|
+ phy-mode = "sgmii";
|
|
+ status = "okay";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+};
|
|
+
|
|
+&mscc_felix_port4 {
|
|
+ ethernet = <&enetc_port2>;
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&hdptx0 {
|
|
+ lane-mapping = <0x4e>;
|
|
+ status = "okay";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-dsa-swp5-eno3.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-dsa-swp5-eno3.dts
|
|
new file mode 100644
|
|
index 000000000000..4a2eebbc9b43
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-dsa-swp5-eno3.dts
|
|
@@ -0,0 +1,37 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Device Tree file for NXP LS1028A RDB with dsa master swp5-eno3.
|
|
+ *
|
|
+ * Copyright 2018-2023 NXP
|
|
+ *
|
|
+ * Hongbo Wang <hongbo.wang@nxp.com>
|
|
+ *
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "fsl-ls1028a-rdb.dts"
|
|
+
|
|
+&enetc_port2 {
|
|
+ fixed-link {
|
|
+ pause;
|
|
+ };
|
|
+};
|
|
+
|
|
+&enetc_port3 {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&mscc_felix_port4 {
|
|
+ label = "swp4";
|
|
+ /delete-property/ ethernet;
|
|
+ status = "okay";
|
|
+
|
|
+ fixed-link {
|
|
+ pause;
|
|
+ };
|
|
+};
|
|
+
|
|
+&mscc_felix_port5 {
|
|
+ ethernet = <&enetc_port3>;
|
|
+ status = "okay";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-jailhouse-without-enetc.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-jailhouse-without-enetc.dts
|
|
new file mode 100644
|
|
index 000000000000..00ade901c736
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-jailhouse-without-enetc.dts
|
|
@@ -0,0 +1,98 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Device Tree file for NXP LS1028A RDB Board Jailhouse case.
|
|
+ *
|
|
+ * Copyright 2021-2023 NXP
|
|
+ *
|
|
+ * Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
|
|
+ */
|
|
+
|
|
+#include "fsl-ls1028a-rdb.dts"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ /* Reserve 832MB for Jailhouse from 0xc000,0000 */
|
|
+ /* 4MB */
|
|
+ jh_reserved: jh@0xc0000000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0000000 0x0 0x400000>;
|
|
+ };
|
|
+ /* 1MB */
|
|
+ loader_reserved: loader@0xc0400000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0400000 0x0 0x00100000>;
|
|
+ };
|
|
+ /* 2MB */
|
|
+ ivshmem_reserved: ivshmem@0xc0500000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0500000 0x0 0x00200000>;
|
|
+ };
|
|
+ /* 2MB */
|
|
+ pci_reserved: pci@0xc0700000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0700000 0x0 0x00200000>;
|
|
+ };
|
|
+ /* 823MB */
|
|
+ inmate_reserved: inmate@0xc0900000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0900000 0x0 0x33700000>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&duart0 {
|
|
+ status = "okay";
|
|
+ /delete-property/ interrupts;
|
|
+};
|
|
+
|
|
+&its {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&duart1 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&smmu {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&enetc_pcie {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&enetc_port0 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&enetc_port2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&mscc_felix {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&mscc_felix_port0 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&mscc_felix_port1 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&mscc_felix_port2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&mscc_felix_port3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&mscc_felix_port4 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-jailhouse.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-jailhouse.dts
|
|
new file mode 100644
|
|
index 000000000000..00a241511258
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-jailhouse.dts
|
|
@@ -0,0 +1,59 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Device Tree file for NXP LS1028A RDB Board Jailhouse case.
|
|
+ *
|
|
+ * Copyright 2018-2023 NXP
|
|
+ *
|
|
+ * Hongbo Wang <hongbo.wang@nxp.com>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include "fsl-ls1028a-rdb.dts"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ /* Reserve 832MB for Jailhouse from 0xc000,0000 */
|
|
+ /* 4MB */
|
|
+ jh_reserved: jh@0xc0000000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0000000 0x0 0x400000>;
|
|
+ };
|
|
+ /* 1MB */
|
|
+ loader_reserved: loader@0xc0400000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0400000 0x0 0x00100000>;
|
|
+ };
|
|
+ /* 2MB */
|
|
+ ivshmem_reserved: ivshmem@0xc0500000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0500000 0x0 0x00200000>;
|
|
+ };
|
|
+ /* 2MB */
|
|
+ pci_reserved: pci@0xc0700000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0700000 0x0 0x00200000>;
|
|
+ };
|
|
+ /* 823MB */
|
|
+ inmate_reserved: inmate@0xc0900000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0900000 0x0 0x33700000>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&duart0 {
|
|
+ status = "okay";
|
|
+ /delete-property/ interrupts;
|
|
+};
|
|
+
|
|
+&duart1 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&gpio3 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-sdk-bm.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-sdk-bm.dts
|
|
new file mode 100644
|
|
index 000000000000..dd9a9d7b425a
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb-sdk-bm.dts
|
|
@@ -0,0 +1,15 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * DTS file for NXP Layerscape baremetal
|
|
+ *
|
|
+ * Copyright 2019-2023 NXP
|
|
+ *
|
|
+ * Author: Hongbo Wang <hongbo.wang@nxp.com>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include "fsl-ls1028a-rdb.dts"
|
|
+
|
|
+&enetc_pcie {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
|
|
index 51218c553bd8..c65326e89be4 100644
|
|
--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
|
|
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a-rdb.dts
|
|
@@ -96,6 +96,19 @@ simple-audio-card,codec {
|
|
};
|
|
};
|
|
|
|
+&dspi2 {
|
|
+ bus-num = <2>;
|
|
+ status = "okay";
|
|
+
|
|
+ mikrobus@0 {
|
|
+ compatible = "semtech,sx1301";
|
|
+ reg = <0>;
|
|
+ spi-max-frequency = <2000000>;
|
|
+ fsl,spi-cs-sck-delay = <1000000>;
|
|
+ fsl,spi-sck-cs-delay = <50>;
|
|
+ };
|
|
+};
|
|
+
|
|
&can0 {
|
|
status = "okay";
|
|
|
|
@@ -252,6 +265,18 @@ rtc@51 {
|
|
reg = <0x51>;
|
|
};
|
|
};
|
|
+
|
|
+ i2c@6 {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ reg = <0x6>;
|
|
+
|
|
+ pn7120: pn7120@28 {
|
|
+ compatible = "nxp,pn7120", "nxp,pn544";
|
|
+ reg = <0x28>;
|
|
+ clock-frequency = <1000000>;
|
|
+ };
|
|
+ };
|
|
};
|
|
};
|
|
|
|
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
|
|
index 71890c8d3d56..e5f2553a7b7a 100644
|
|
--- a/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
|
|
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
|
|
@@ -1113,7 +1113,7 @@ tmu: tmu@1f80000 {
|
|
#thermal-sensor-cells = <1>;
|
|
};
|
|
|
|
- pcie@1f0000000 { /* Integrated Endpoint Root Complex */
|
|
+ enetc_pcie: pcie@1f0000000 { /* Integrated Endpoint Root Complex */
|
|
compatible = "pci-host-ecam-generic";
|
|
reg = <0x01 0xf0000000 0x0 0x100000>;
|
|
#address-cells = <3>;
|
|
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-bm.dts b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-bm.dts
|
|
new file mode 100644
|
|
index 000000000000..a7036efb1729
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-bm.dts
|
|
@@ -0,0 +1,44 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * DTS file for NXP Layerscape baremetal
|
|
+ *
|
|
+ * Copyright 2018-2023 NXP
|
|
+ *
|
|
+ * Author: Changming Huang <jerry.huang@nxp.com>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include "fsl-ls1043a-rdb-sdk.dts"
|
|
+
|
|
+
|
|
+&usb0 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&usb1 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&usb2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&pcie1 {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&pcie2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&pcie3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&optee {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&ifc {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-jailhouse-with-dpaa.dts b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-jailhouse-with-dpaa.dts
|
|
new file mode 100755
|
|
index 000000000000..77bd7c1e6ed1
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-jailhouse-with-dpaa.dts
|
|
@@ -0,0 +1,263 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * DTS file for NXP Layerscape-1043ARDB jailhouse case
|
|
+ *
|
|
+ * Copyright 2018-2023 NXP
|
|
+ *
|
|
+ * Author: Hongbo Wang <hongbo.wang@nxp.com>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include "fsl-ls1043a-rdb.dts"
|
|
+#include "qoriq-qman-portals-sdk.dtsi"
|
|
+#include "qoriq-bman-portals-sdk.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ /* Reserve 832MB for Jailhouse from 0xc000,0000 */
|
|
+ /* 4MB */
|
|
+ jh_reserved: jh@0xc0000000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0000000 0x0 0x400000>;
|
|
+ };
|
|
+ /* 1MB */
|
|
+ loader_reserved: loader@0xc0400000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0400000 0x0 0x00100000>;
|
|
+ };
|
|
+ /* 2MB */
|
|
+ ivshmem_reserved: ivshmem@0xc0500000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0500000 0x0 0x00200000>;
|
|
+ };
|
|
+ /* 2MB */
|
|
+ pci_reserved: pci@0xc0700000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0700000 0x0 0x00200000>;
|
|
+ };
|
|
+ /* 823MB */
|
|
+ inmate_reserved: inmate@0xc0900000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0900000 0x0 0x33700000>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&bman_fbpr {
|
|
+ compatible = "fsl,bman-fbpr";
|
|
+ alloc-ranges = <0 0 0x10000 0>;
|
|
+};
|
|
+&qman_fqd {
|
|
+ compatible = "fsl,qman-fqd";
|
|
+ alloc-ranges = <0 0 0x10000 0>;
|
|
+};
|
|
+&qman_pfdr {
|
|
+ compatible = "fsl,qman-pfdr";
|
|
+ alloc-ranges = <0 0 0x10000 0>;
|
|
+};
|
|
+
|
|
+&soc {
|
|
+/delete-property/ dma-coherent;
|
|
+
|
|
+#include "qoriq-dpaa-eth.dtsi"
|
|
+#include "qoriq-fman3-0-6oh.dtsi"
|
|
+
|
|
+pcie@3400000 {
|
|
+ /delete-property/ iommu-map;
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+pcie@3500000 {
|
|
+ /delete-property/ iommu-map;
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+pcie@3600000 {
|
|
+ /delete-property/ iommu-map;
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+/delete-node/ iommu@9000000;
|
|
+};
|
|
+
|
|
+&fman0 {
|
|
+ compatible = "fsl,fman", "simple-bus";
|
|
+};
|
|
+
|
|
+&clockgen {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&scfg {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&crypto {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&dcfg {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&ifc {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&qspi {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&esdhc {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&ddr {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&tmu {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&qman {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&bman {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&bportals {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&qportals {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&dspi0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&dspi1 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&i2c0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&i2c1 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&i2c2 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&i2c3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&duart0 {
|
|
+ dma-coherent;
|
|
+ /delete-property/ interrupts;
|
|
+};
|
|
+
|
|
+&duart1 {
|
|
+ dma-coherent;
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&duart2 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&duart3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&gpio1 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&gpio2 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&gpio3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&gpio4 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart1 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart2 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart4 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart5 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&ftm_alarm0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&wdog0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&edma0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&qdma {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&msi1 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&msi2 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&msi3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&fman0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&ptp_timer0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&fsldpaa {
|
|
+ dma-coherent;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-jailhouse.dts b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-jailhouse.dts
|
|
new file mode 100644
|
|
index 000000000000..a7335581c469
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a-rdb-sdk-jailhouse.dts
|
|
@@ -0,0 +1,267 @@
|
|
+ // SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * DTS file for NXP Layerscape-1043ARDB jailhouse case
|
|
+ *
|
|
+ * Copyright 2018-2023 NXP
|
|
+ *
|
|
+ * Author: Hongbo Wang <hongbo.wang@nxp.com>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include "fsl-ls1043a-rdb.dts"
|
|
+#include "qoriq-qman-portals-sdk.dtsi"
|
|
+#include "qoriq-bman-portals-sdk.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ /* Reserve 832MB for Jailhouse from 0xc000,0000 */
|
|
+ /* 4MB */
|
|
+ jh_reserved: jh@0xc0000000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0000000 0x0 0x400000>;
|
|
+ };
|
|
+ /* 1MB */
|
|
+ loader_reserved: loader@0xc0400000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0400000 0x0 0x00100000>;
|
|
+ };
|
|
+ /* 2MB */
|
|
+ ivshmem_reserved: ivshmem@0xc0500000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0500000 0x0 0x00200000>;
|
|
+ };
|
|
+ /* 2MB */
|
|
+ pci_reserved: pci@0xc0700000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0700000 0x0 0x00200000>;
|
|
+ };
|
|
+ /* 823MB */
|
|
+ inmate_reserved: inmate@0xc0900000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0900000 0x0 0x33700000>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&bman_fbpr {
|
|
+ compatible = "fsl,bman-fbpr";
|
|
+ alloc-ranges = <0 0 0x10000 0>;
|
|
+};
|
|
+&qman_fqd {
|
|
+ compatible = "fsl,qman-fqd";
|
|
+ alloc-ranges = <0 0 0x10000 0>;
|
|
+};
|
|
+&qman_pfdr {
|
|
+ compatible = "fsl,qman-pfdr";
|
|
+ alloc-ranges = <0 0 0x10000 0>;
|
|
+};
|
|
+
|
|
+&soc {
|
|
+/delete-property/ dma-coherent;
|
|
+
|
|
+#include "qoriq-dpaa-eth.dtsi"
|
|
+#include "qoriq-fman3-0-6oh.dtsi"
|
|
+
|
|
+pcie@3400000 {
|
|
+ /delete-property/ iommu-map;
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+pcie@3500000 {
|
|
+ /delete-property/ iommu-map;
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+pcie@3600000 {
|
|
+ /delete-property/ iommu-map;
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+/delete-node/ iommu@9000000;
|
|
+/delete-node/ qman@1880000;
|
|
+/delete-node/ bman@1890000;
|
|
+/delete-node/ bman-portals@508000000;
|
|
+/delete-node/ qman-portals@500000000;
|
|
+};
|
|
+
|
|
+&fman0 {
|
|
+ compatible = "fsl,fman", "simple-bus";
|
|
+};
|
|
+
|
|
+&clockgen {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&scfg {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&crypto {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&dcfg {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&ifc {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&qspi {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&esdhc {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&ddr {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&tmu {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&dspi0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&dspi1 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&i2c0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&i2c1 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&i2c2 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&i2c3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&duart0 {
|
|
+ dma-coherent;
|
|
+ /delete-property/ interrupts;
|
|
+};
|
|
+
|
|
+&duart1 {
|
|
+ dma-coherent;
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&duart2 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&duart3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&gpio1 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&gpio2 {
|
|
+ dma-coherent;
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&gpio3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&gpio4 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart1 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart2 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart4 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart5 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&ftm_alarm0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&wdog0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&edma0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&qdma {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&msi1 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&msi2 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&msi3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&fman0 {
|
|
+ dma-coherent;
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&ptp_timer0 {
|
|
+ dma-coherent;
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&fsldpaa {
|
|
+ dma-coherent;
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&bman_fbpr {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&qman_fqd {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&qman_pfdr {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
|
|
index 2d1e9ed7dac6..01e1194fff66 100644
|
|
--- a/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
|
|
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1043a.dtsi
|
|
@@ -1063,7 +1063,7 @@ ftm_alarm0: timer@29d0000 {
|
|
};
|
|
|
|
firmware {
|
|
- optee {
|
|
+ optee: optee {
|
|
compatible = "linaro,optee-tz";
|
|
method = "smc";
|
|
};
|
|
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-bm.dts b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-bm.dts
|
|
new file mode 100644
|
|
index 000000000000..097a95802919
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-bm.dts
|
|
@@ -0,0 +1,47 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * DTS file for NXP Layerscape baremetal
|
|
+ *
|
|
+ * Copyright 2018-2023 NXP
|
|
+ *
|
|
+ * Author: Changming Huang <jerry.huang@nxp.com>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include "fsl-ls1046a-rdb-sdk.dts"
|
|
+
|
|
+&usb0 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&usb1 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&usb2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&pcie1 {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&pcie2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&pcie3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&optee {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&ifc {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&gpio1 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-jailhouse-with-dpaa.dts b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-jailhouse-with-dpaa.dts
|
|
new file mode 100755
|
|
index 000000000000..35ec99ac4b3e
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-jailhouse-with-dpaa.dts
|
|
@@ -0,0 +1,274 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * DTS file for NXP Layerscape-1046ARDB jailhouse case
|
|
+ *
|
|
+ * Copyright 2018-2023 NXP
|
|
+ *
|
|
+ * Author: Hongbo Wang <hongbo.wang@nxp.com>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include "fsl-ls1046a-rdb.dts"
|
|
+#include "qoriq-qman-portals-sdk.dtsi"
|
|
+#include "qoriq-bman-portals-sdk.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ /* Reserve 832MB for Jailhouse from 0xc000,0000 */
|
|
+ /* 4MB */
|
|
+ jh_reserved: jh@0xc0000000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0000000 0x0 0x400000>;
|
|
+ };
|
|
+ /* 1MB */
|
|
+ loader_reserved: loader@0xc0400000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0400000 0x0 0x00100000>;
|
|
+ };
|
|
+ /* 2MB */
|
|
+ ivshmem_reserved: ivshmem@0xc0500000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0500000 0x0 0x00200000>;
|
|
+ };
|
|
+ /* 2MB */
|
|
+ pci_reserved: pci@0xc0700000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0700000 0x0 0x00200000>;
|
|
+ };
|
|
+ /* 823MB */
|
|
+ inmate_reserved: inmate@0xc0900000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0900000 0x0 0x33700000>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&bman_fbpr {
|
|
+ compatible = "fsl,bman-fbpr";
|
|
+ alloc-ranges = <0 0 0x10000 0>;
|
|
+};
|
|
+&qman_fqd {
|
|
+ compatible = "fsl,qman-fqd";
|
|
+ alloc-ranges = <0 0 0x10000 0>;
|
|
+};
|
|
+&qman_pfdr {
|
|
+ compatible = "fsl,qman-pfdr";
|
|
+ alloc-ranges = <0 0 0x10000 0>;
|
|
+};
|
|
+
|
|
+&soc {
|
|
+/delete-property/ dma-coherent;
|
|
+
|
|
+#include "qoriq-dpaa-eth.dtsi"
|
|
+#include "qoriq-fman3-0-6oh.dtsi"
|
|
+
|
|
+pcie@3400000 {
|
|
+ /delete-property/ iommu-map;
|
|
+};
|
|
+
|
|
+pcie@3500000 {
|
|
+ /delete-property/ iommu-map;
|
|
+};
|
|
+
|
|
+pcie@3600000 {
|
|
+ /delete-property/ iommu-map;
|
|
+};
|
|
+
|
|
+/delete-node/ iommu@9000000;
|
|
+};
|
|
+
|
|
+&fsldpaa {
|
|
+ ethernet@0 {
|
|
+ status = "disabled";
|
|
+ };
|
|
+ ethernet@1 {
|
|
+ status = "disabled";
|
|
+ };
|
|
+ ethernet@9 {
|
|
+ compatible = "fsl,dpa-ethernet";
|
|
+ fsl,fman-mac = <&enet7>;
|
|
+ dma-coherent;
|
|
+ };
|
|
+};
|
|
+
|
|
+&fman0 {
|
|
+ compatible = "fsl,fman", "simple-bus";
|
|
+};
|
|
+
|
|
+&clockgen {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&scfg {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&crypto {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&dcfg {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&ifc {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&qspi {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&esdhc {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&ddr {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&tmu {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&qman {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&bman {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&bportals {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&qportals {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&dspi {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&i2c0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&i2c1 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&i2c2 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&i2c3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&duart0 {
|
|
+ dma-coherent;
|
|
+ /delete-property/ interrupts;
|
|
+};
|
|
+
|
|
+&duart1 {
|
|
+ dma-coherent;
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&duart2 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&duart3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&gpio0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&gpio1 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&gpio2 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&gpio3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart1 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart2 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart4 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart5 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&ftm_alarm0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&wdog0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&edma0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&sata {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&qdma {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&msi1 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&msi2 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&msi3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&fman0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&ptp_timer0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&fsldpaa {
|
|
+ dma-coherent;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-jailhouse.dts b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-jailhouse.dts
|
|
new file mode 100755
|
|
index 000000000000..8bf8d3eb03ee
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb-sdk-jailhouse.dts
|
|
@@ -0,0 +1,278 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * DTS file for NXP Layerscape-1046ARDB jailhouse case
|
|
+ *
|
|
+ * Copyright 2018-2023 NXP
|
|
+ *
|
|
+ * Author: Hongbo Wang <hongbo.wang@nxp.com>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include "fsl-ls1046a-rdb.dts"
|
|
+#include "qoriq-qman-portals-sdk.dtsi"
|
|
+#include "qoriq-bman-portals-sdk.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ /* Reserve 832MB for Jailhouse from 0xc000,0000 */
|
|
+ /* 4MB */
|
|
+ jh_reserved: jh@0xc0000000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0000000 0x0 0x400000>;
|
|
+ };
|
|
+ /* 1MB */
|
|
+ loader_reserved: loader@0xc0400000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0400000 0x0 0x00100000>;
|
|
+ };
|
|
+ /* 2MB */
|
|
+ ivshmem_reserved: ivshmem@0xc0500000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0500000 0x0 0x00200000>;
|
|
+ };
|
|
+ /* 2MB */
|
|
+ pci_reserved: pci@0xc0700000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0700000 0x0 0x00200000>;
|
|
+ };
|
|
+ /* 823MB */
|
|
+ inmate_reserved: inmate@0xc0900000 {
|
|
+ no-map;
|
|
+ reg = <0x0 0xc0900000 0x0 0x33700000>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&bman_fbpr {
|
|
+ compatible = "fsl,bman-fbpr";
|
|
+ alloc-ranges = <0 0 0x10000 0>;
|
|
+};
|
|
+&qman_fqd {
|
|
+ compatible = "fsl,qman-fqd";
|
|
+ alloc-ranges = <0 0 0x10000 0>;
|
|
+};
|
|
+&qman_pfdr {
|
|
+ compatible = "fsl,qman-pfdr";
|
|
+ alloc-ranges = <0 0 0x10000 0>;
|
|
+};
|
|
+
|
|
+&soc {
|
|
+/delete-property/ dma-coherent;
|
|
+
|
|
+#include "qoriq-dpaa-eth.dtsi"
|
|
+#include "qoriq-fman3-0-6oh.dtsi"
|
|
+
|
|
+pcie@3400000 {
|
|
+ /delete-property/ iommu-map;
|
|
+};
|
|
+
|
|
+pcie@3500000 {
|
|
+ /delete-property/ iommu-map;
|
|
+};
|
|
+
|
|
+pcie@3600000 {
|
|
+ /delete-property/ iommu-map;
|
|
+};
|
|
+
|
|
+/delete-node/ iommu@9000000;
|
|
+/delete-node/ qman@1880000;
|
|
+/delete-node/ bman@1890000;
|
|
+/delete-node/ bman-portals@508000000;
|
|
+/delete-node/ qman-portals@500000000;
|
|
+};
|
|
+
|
|
+&fsldpaa {
|
|
+ ethernet@0 {
|
|
+ status = "disabled";
|
|
+ };
|
|
+ ethernet@1 {
|
|
+ status = "disabled";
|
|
+ };
|
|
+ ethernet@9 {
|
|
+ compatible = "fsl,dpa-ethernet";
|
|
+ fsl,fman-mac = <&enet7>;
|
|
+ dma-coherent;
|
|
+ };
|
|
+};
|
|
+
|
|
+&fman0 {
|
|
+ compatible = "fsl,fman", "simple-bus";
|
|
+};
|
|
+
|
|
+&clockgen {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&scfg {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&crypto {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&dcfg {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&ifc {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&qspi {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&esdhc {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&ddr {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&tmu {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&dspi {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&i2c0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&i2c1 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&i2c2 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&i2c3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&duart0 {
|
|
+ dma-coherent;
|
|
+ /delete-property/ interrupts;
|
|
+};
|
|
+
|
|
+&duart1 {
|
|
+ dma-coherent;
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&duart2 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&duart3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&gpio0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&gpio1 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&gpio2 {
|
|
+ dma-coherent;
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&gpio3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart1 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart2 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart4 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&lpuart5 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&ftm_alarm0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&wdog0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&edma0 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&sata {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&qdma {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&msi1 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&msi2 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&msi3 {
|
|
+ dma-coherent;
|
|
+};
|
|
+
|
|
+&fman0 {
|
|
+ dma-coherent;
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&ptp_timer0 {
|
|
+ dma-coherent;
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&fsldpaa {
|
|
+ dma-coherent;
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&bman_fbpr {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&qman_fqd {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&qman_pfdr {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
|
|
index 10922fea2fc5..981fd470a1b9 100644
|
|
--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
|
|
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
|
|
@@ -1049,7 +1049,7 @@ qman_pfdr: qman-pfdr {
|
|
};
|
|
|
|
firmware {
|
|
- optee {
|
|
+ optee: optee {
|
|
compatible = "linaro,optee-tz";
|
|
method = "smc";
|
|
};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi
|
|
index 1145f3298053..ff6cfe8971a0 100644
|
|
--- a/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8-ss-audio.dtsi
|
|
@@ -247,6 +247,15 @@ sai3: sai@59070000 {
|
|
status = "disabled";
|
|
};
|
|
|
|
+ gpt5: gpt@590b0000 {
|
|
+ reg = <0x590b0000 0x10000>;
|
|
+ clocks = <&gpt5_lpcg 1>,
|
|
+ <&gpt5_lpcg 1>;
|
|
+ clock-names = "ipg", "per";
|
|
+ power-domains = <&pd IMX_SC_R_GPT_5>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
asrc1: asrc@59800000 {
|
|
compatible = "fsl,imx8qm-asrc";
|
|
reg = <0x59800000 0x10000>;
|
|
@@ -567,6 +576,17 @@ sai3_lpcg: clock-controller@59470000 {
|
|
power-domains = <&pd IMX_SC_R_SAI_3>;
|
|
};
|
|
|
|
+ gpt5_lpcg: clock-controller@594b0000 {
|
|
+ compatible = "fsl,imx8qxp-lpcg";
|
|
+ reg = <0x594b0000 0x10000>;
|
|
+ #clock-cells = <1>;
|
|
+ clocks = <&acm IMX_ADMA_ACM_GPT0_MUX_CLK_SEL>,
|
|
+ <&audio_ipg_clk>;
|
|
+ bit-offset = <0 16>;
|
|
+ clock-output-names = "gpt5_lpcg_clk_in", "gpt5_lpcg_ipg_clk";
|
|
+ power-domains = <&pd IMX_SC_R_GPT_5>;
|
|
+ };
|
|
+
|
|
asrc1_lpcg: clock-controller@59c00000 {
|
|
compatible = "fsl,imx8qxp-lpcg";
|
|
reg = <0x59c00000 0x10000>;
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-avb.dts b/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-avb.dts
|
|
new file mode 100644
|
|
index 000000000000..36cc1a616a9a
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-avb.dts
|
|
@@ -0,0 +1,9 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2022-2023 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx8dxl-evk-enet0.dts"
|
|
+#include "imx8dxl-evk-enet0-avb.dtsi"
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-avb.dtsi b/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-avb.dtsi
|
|
new file mode 100644
|
|
index 000000000000..d7c268f056cc
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-avb.dtsi
|
|
@@ -0,0 +1,54 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+/* Set GPT Capture input to Ethernet 0 event */
|
|
+&acm {
|
|
+ gpt-capture-select = <IMX_ADMA_ACM_GPT0_CAPIN1_SEL IMX_ADMA_ACM_GPT_EVENT_INPUT_ETH0>;
|
|
+};
|
|
+
|
|
+/* AVB HW timer*/
|
|
+&gpt5 {
|
|
+ compatible = "fsl,avb-gpt";
|
|
+
|
|
+ clocks = <&gpt5_lpcg 1>,
|
|
+ <&gpt5_lpcg 1>,
|
|
+ <&gpt5_lpcg 0>,
|
|
+ <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_PLL>;
|
|
+ clock-names = "ipg", "per", "clk_in", "audio_pll";
|
|
+
|
|
+ /* - Set ACM_AUD_CLK0 source to ACM_AUD_REC_CLK0
|
|
+ * - Set clk_in to Audio PLL0 Divider
|
|
+ * - Enable Audio PLL and its Master Bus clock (AUD_REC_CLK0): keep this in sync with sai nodes
|
|
+ */
|
|
+
|
|
+ assigned-clocks = <&acm IMX_ADMA_ACM_AUD_CLK0_SEL>,
|
|
+ <&acm IMX_ADMA_ACM_GPT0_MUX_CLK_SEL>,
|
|
+ <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_PLL>,
|
|
+ <&clk IMX_SC_R_AUDIO_PLL_0 IMX_SC_PM_CLK_MST_BUS>;
|
|
+
|
|
+ assigned-clock-parents = <&aud_rec0_lpcg 0>,
|
|
+ <&acm IMX_ADMA_ACM_AUD_CLK0_SEL>;
|
|
+
|
|
+ assigned-clock-rates = <0>, <0>, <786432000>, <12288000>;
|
|
+
|
|
+ /* Audio PLL is controlled through SCU */
|
|
+ fsl,pll-scu-controlled;
|
|
+
|
|
+ timer-channel = <1>; /* Use output compare channel 1*/
|
|
+ prescale = <1>;
|
|
+ domain = <0>;
|
|
+ rec-channel = <1 0 1>; // capture channel, eth port, ENET TC id
|
|
+
|
|
+ interrupts = <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
|
|
+
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&fec1 {
|
|
+ fsl,rx-phy-delay-100-ns = <670>;
|
|
+ fsl,tx-phy-delay-100-ns = <670>;
|
|
+ fsl,rx-phy-delay-1000-ns = <0>;
|
|
+ fsl,tx-phy-delay-1000-ns = <0>;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-sja1105.dts b/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-sja1105.dts
|
|
new file mode 100644
|
|
index 000000000000..ddfdadfbe3f8
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-sja1105.dts
|
|
@@ -0,0 +1,168 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx8dxl-evk.dts"
|
|
+
|
|
+&iomuxc {
|
|
+ pinctrl_lpspi2: lpspi2grp {
|
|
+ fsl,pins = <
|
|
+ IMX8DXL_USDHC1_VSELECT_ADMA_SPI2_SDO 0x600004c
|
|
+ IMX8DXL_USDHC1_WP_ADMA_SPI2_SDI 0x600004c
|
|
+ IMX8DXL_USDHC1_RESET_B_ADMA_SPI2_SCK 0x600004c
|
|
+ >;
|
|
+ };
|
|
+
|
|
+ pinctrl_lpspi2_cs: lpspi2cs {
|
|
+ fsl,pins = <
|
|
+ IMX8DXL_USDHC1_CD_B_LSIO_GPIO4_IO22 0x21
|
|
+ >;
|
|
+ };
|
|
+};
|
|
+
|
|
+&lpspi2 {
|
|
+ fsl,spi-num-chipselects = <1>;
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&pinctrl_lpspi2 &pinctrl_lpspi2_cs>;
|
|
+ cs-gpios = <&lsio_gpio4 22 GPIO_ACTIVE_LOW>;
|
|
+ status = "okay";
|
|
+
|
|
+ sja1105p@0 {
|
|
+ compatible = "nxp,sja1105q";
|
|
+ spi-max-frequency = <12500000>;
|
|
+ /* SJA1105PQRS operates in SPI MODE 1 : CPOL=0 CPHA=1 */
|
|
+ spi-cpha;
|
|
+ /* use queue 5 for managment traffic */
|
|
+ hostprio = <5>;
|
|
+
|
|
+ reg = <0>;
|
|
+
|
|
+ ports {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ port@0 {
|
|
+ reg = <0>;
|
|
+ label = "cpu";
|
|
+ ethernet = <&fec1>;
|
|
+ phy-mode = "rgmii";
|
|
+ rx-internal-delay-ps = <2000>;
|
|
+ tx-internal-delay-ps = <2000>;
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ port@1 {
|
|
+ reg = <1>;
|
|
+ label = "swp0";
|
|
+ phy-handle = <&phy0>;
|
|
+ phy-mode = "mii";
|
|
+ };
|
|
+
|
|
+ port@2 {
|
|
+ reg = <2>;
|
|
+ label = "swp1";
|
|
+ phy-handle = <&phy1>;
|
|
+ phy-mode = "mii";
|
|
+ };
|
|
+
|
|
+ port@3 {
|
|
+ reg = <3>;
|
|
+ label = "swp2";
|
|
+ phy-handle = <&phy2>;
|
|
+ phy-mode = "rmii";
|
|
+ };
|
|
+
|
|
+ port@4 {
|
|
+ reg = <4>;
|
|
+ label = "swp3";
|
|
+ phy-handle = <&phy3>;
|
|
+ phy-mode = "rmii";
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+ðphy1 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&fec1 {
|
|
+ assigned-clocks = <&clk IMX_SC_R_ENET_0 IMX_SC_C_CLKDIV>;
|
|
+ assigned-clock-rates = <12000000>;
|
|
+ phy-supply = <&mii_select>;
|
|
+ status = "okay";
|
|
+
|
|
+ fsl,magic-packet;
|
|
+ phy-mode = "rgmii";
|
|
+ /delete-property/ rx-internal-delay-ps;
|
|
+ /delete-property/ phy-handle;
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+
|
|
+ mdio {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ /* SJA1105Q EVB switch ports : NXP TJA1102
|
|
+ the phys SMI addresses on EVB are hard coded giving
|
|
+ first TJA device at offset 0x8 and the 2nd once at offet 0xe */
|
|
+ phy0: ethernet-phy@8 {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ reg = <0x8>;
|
|
+ max-speed = <100>;
|
|
+ phy1: ethernet-phy@9 {
|
|
+ reg = <0x9>;
|
|
+ max-speed = <100>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ phy2: ethernet-phy@e {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ reg = <0xe>;
|
|
+ max-speed = <100>;
|
|
+ phy3: ethernet-phy@f {
|
|
+ reg = <0xf>;
|
|
+ max-speed = <100>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+®_fec1_sel {
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+/* This would set max7233 (0) to high (intented for PHY power on) and would
|
|
+ * enable LPC SPI/SMI on the switch EVB which interferes with
|
|
+ * SPI communcation between the iMX and the SJA1105
|
|
+*/
|
|
+®_fec1_io {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&max7322 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&mii_select {
|
|
+ /delete-property/ enable-active-high;
|
|
+};
|
|
+
|
|
+&eqos {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&usdhc2 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-tja1100-avb.dts b/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-tja1100-avb.dts
|
|
new file mode 100644
|
|
index 000000000000..121b506cbc8c
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8dxl-evk-enet0-tja1100-avb.dts
|
|
@@ -0,0 +1,9 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx8dxl-evk-enet0-tja1100.dts"
|
|
+#include "imx8dxl-evk-enet0-avb.dtsi"
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts b/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts
|
|
index 02a40cf803de..f71727fed226 100644
|
|
--- a/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8dxl-evk.dts
|
|
@@ -320,6 +320,9 @@ &eqos {
|
|
phy-handle = <ðphy0>;
|
|
nvmem-cells = <&fec_mac1>;
|
|
nvmem-cell-names = "mac-address";
|
|
+ snps,force_thresh_dma_mode;
|
|
+ snps,mtl-tx-config = <&mtl_tx_setup>;
|
|
+ snps,mtl-rx-config = <&mtl_rx_setup>;
|
|
status = "okay";
|
|
|
|
mdio {
|
|
@@ -343,6 +346,61 @@ vddio0: vddio-regulator {
|
|
};
|
|
};
|
|
};
|
|
+
|
|
+ mtl_tx_setup: tx-queues-config {
|
|
+ snps,tx-queues-to-use = <5>;
|
|
+ snps,tx-sched-sp;
|
|
+ queue0 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x1>;
|
|
+ };
|
|
+ queue1 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x2>;
|
|
+ };
|
|
+ queue2 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x4>;
|
|
+ };
|
|
+ queue3 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x8>;
|
|
+ };
|
|
+ queue4 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0xf0>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ mtl_rx_setup: rx-queues-config {
|
|
+ snps,rx-queues-to-use = <5>;
|
|
+ snps,rx-sched-sp;
|
|
+ queue0 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x1>;
|
|
+ snps,map-to-dma-channel = <0>;
|
|
+ };
|
|
+ queue1 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x2>;
|
|
+ snps,map-to-dma-channel = <1>;
|
|
+ };
|
|
+ queue2 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x4>;
|
|
+ snps,map-to-dma-channel = <2>;
|
|
+ };
|
|
+ queue3 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x8>;
|
|
+ snps,map-to-dma-channel = <3>;
|
|
+ };
|
|
+ queue4 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0xf0>;
|
|
+ snps,map-to-dma-channel = <4>;
|
|
+ };
|
|
+ };
|
|
};
|
|
|
|
/*
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8dxl-ss-adma.dtsi b/arch/arm64/boot/dts/freescale/imx8dxl-ss-adma.dtsi
|
|
index c8ec4328ee6e..7df83c1f9e59 100644
|
|
--- a/arch/arm64/boot/dts/freescale/imx8dxl-ss-adma.dtsi
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8dxl-ss-adma.dtsi
|
|
@@ -32,6 +32,7 @@ &acm {
|
|
<&pd IMX_SC_R_AUDIO_PLL_0>,
|
|
<&pd IMX_SC_R_AUDIO_PLL_1>,
|
|
<&pd IMX_SC_R_ASRC_0>,
|
|
+ <&pd IMX_SC_R_GPT_5>,
|
|
<&pd IMX_SC_R_SAI_0>,
|
|
<&pd IMX_SC_R_SAI_1>,
|
|
<&pd IMX_SC_R_SAI_2>,
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8m-generic-mbox-1.dtsi b/arch/arm64/boot/dts/freescale/imx8m-generic-mbox-1.dtsi
|
|
new file mode 100644
|
|
index 000000000000..428e9b8cb4ae
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8m-generic-mbox-1.dtsi
|
|
@@ -0,0 +1,27 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ gen_sw_mbox_1_reserved: gen-sw-mbox-1@b8501000 {
|
|
+ reg = <0 0xb8501000 0 0x1000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ };
|
|
+
|
|
+ gen_sw_mbox_1: generic-software-mailbox-1@b8501000 {
|
|
+ compatible = "fsl,generic-software-mbox";
|
|
+ reg = <0 0xb8501000 0 0x1000>;
|
|
+ #mbox-cells = <3>;
|
|
+ /* Use 2 unused SPI interrupts */
|
|
+ interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "irq", "remote_irq";
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8m-generic-mbox.dtsi b/arch/arm64/boot/dts/freescale/imx8m-generic-mbox.dtsi
|
|
new file mode 100644
|
|
index 000000000000..e97e82c78aaa
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8m-generic-mbox.dtsi
|
|
@@ -0,0 +1,27 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ gen_sw_mbox_reserved: gen-sw-mbox@b8500000 {
|
|
+ reg = <0 0xb8500000 0 0x1000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ };
|
|
+
|
|
+ gen_sw_mbox: generic-software-mailbox@b8500000 {
|
|
+ compatible = "fsl,generic-software-mbox";
|
|
+ reg = <0 0xb8500000 0 0x1000>;
|
|
+ #mbox-cells = <3>;
|
|
+ /* Use 2 unused SPI interrupts */
|
|
+ interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "irq", "remote_irq";
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8m-rpmsg-ca53-1.dtsi b/arch/arm64/boot/dts/freescale/imx8m-rpmsg-ca53-1.dtsi
|
|
new file mode 100644
|
|
index 000000000000..70e33e6d834b
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8m-rpmsg-ca53-1.dtsi
|
|
@@ -0,0 +1,37 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8m-generic-mbox-1.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ rpmsg_ca53_1_reserved: rpmsg-ca53-1@b8610000 {
|
|
+ reg = <0 0xb8610000 0 0x10000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdevbuffer_ca53_1: vdevbuffer-ca53-1@b8800000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xb8800000 0 0x100000>;
|
|
+ no-map;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ rpmsg-ca53-1 {
|
|
+ compatible = "fsl,imx8mm-rpmsg";
|
|
+ reg = <0x0 0xb8610000 0x0 0x10000>; /* 64K for one rpmsg instance */
|
|
+ dma-coherent;
|
|
+ memory-region = <&vdevbuffer_ca53_1>;
|
|
+ mbox-names = "tx", "rx", "rxdb";
|
|
+ mboxes = <&gen_sw_mbox_1 0 0 1 /* Tx channel with ACK */
|
|
+ &gen_sw_mbox_1 1 0 0 /* Rx channel without ACK */
|
|
+ &gen_sw_mbox_1 2 0 1>; /* RXDB channel with ACK */
|
|
+ vdev-nums = <1>;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8m-rpmsg-ca53.dtsi b/arch/arm64/boot/dts/freescale/imx8m-rpmsg-ca53.dtsi
|
|
new file mode 100644
|
|
index 000000000000..a3b0dbf563e8
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8m-rpmsg-ca53.dtsi
|
|
@@ -0,0 +1,37 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2022-2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8m-generic-mbox.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ rpmsg_ca53_reserved: rpmsg-ca53@b8600000 {
|
|
+ reg = <0 0xb8600000 0 0x10000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdevbuffer_ca53: vdevbuffer-ca53@b8700000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xb8700000 0 0x100000>;
|
|
+ no-map;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ rpmsg-ca53 {
|
|
+ compatible = "fsl,imx8mm-rpmsg";
|
|
+ reg = <0x0 0xb8600000 0x0 0x10000>; /* 64K for one rpmsg instance */
|
|
+ dma-coherent;
|
|
+ memory-region = <&vdevbuffer_ca53>;
|
|
+ mbox-names = "tx", "rx", "rxdb";
|
|
+ mboxes = <&gen_sw_mbox 0 0 1 /* Tx channel with ACK */
|
|
+ &gen_sw_mbox 1 0 0 /* Rx channel without ACK */
|
|
+ &gen_sw_mbox 2 0 1>; /* RXDB channel with ACK */
|
|
+ vdev-nums = <1>;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8m-rproc-ca53.dtsi b/arch/arm64/boot/dts/freescale/imx8m-rproc-ca53.dtsi
|
|
new file mode 100644
|
|
index 000000000000..c44e6a3d8cf0
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8m-rproc-ca53.dtsi
|
|
@@ -0,0 +1,34 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+/ {
|
|
+ ca53_1: remoteproc-ca53-1 {
|
|
+ compatible = "fsl,imx-rproc-psci";
|
|
+ /* bitmask:0b0010, assign A53 Core 1 */
|
|
+ fsl,cpus-bits = <0x2>;
|
|
+ memory-region = <&rtos_ca53_reserved>;
|
|
+ };
|
|
+
|
|
+ ca53_2: remoteproc-ca53-2 {
|
|
+ compatible = "fsl,imx-rproc-psci";
|
|
+ /* bitmask:0b0100, assign A53 Core 2 */
|
|
+ fsl,cpus-bits = <0x4>;
|
|
+ memory-region = <&rtos_ca53_reserved>;
|
|
+ };
|
|
+
|
|
+ ca53_3: remoteproc-ca53-3 {
|
|
+ compatible = "fsl,imx-rproc-psci";
|
|
+ /* bitmask:0b1000, assign A53 Core 3 */
|
|
+ fsl,cpus-bits = <0x8>;
|
|
+ memory-region = <&rtos_ca53_reserved>;
|
|
+ };
|
|
+
|
|
+ ca53_2_3: remoteproc-ca53-2-3 {
|
|
+ compatible = "fsl,imx-rproc-psci";
|
|
+ /* bitmask:0b1100, assign A53 Core 2 and Core 3 */
|
|
+ fsl,cpus-bits = <0xc>;
|
|
+ memory-region = <&rtos_ca53_reserved>;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-avb.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-avb.dts
|
|
new file mode 100644
|
|
index 000000000000..f5b15dddea51
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-avb.dts
|
|
@@ -0,0 +1,37 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2020-2021, 2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx8mm-evk.dts"
|
|
+
|
|
+/* AVB HW timer*/
|
|
+&gpt1 {
|
|
+ compatible = "fsl,avb-gpt";
|
|
+ timer-channel = <1>; /* Use output compare channel 1*/
|
|
+ prescale = <1>;
|
|
+ domain = <0>;
|
|
+
|
|
+ clocks = <&clk IMX8MM_CLK_GPT1_ROOT>,
|
|
+ <&clk IMX8MM_CLK_GPT1_ROOT>, <&clk IMX8MM_AUDIO_PLL1>;
|
|
+ clock-names = "ipg", "per", "audio_pll";
|
|
+
|
|
+ /* Make the GPT clk root derive from the audio PLL */
|
|
+ assigned-clocks = <&clk IMX8MM_CLK_GPT1>;
|
|
+ assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
|
|
+ assigned-clock-rates = <98304000>;
|
|
+
|
|
+ /* Enble SW sampling for media clock recovery on port 0 */
|
|
+ sw-recovery = <0>;
|
|
+
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&fec1 {
|
|
+ fsl,rx-phy-delay-100-ns = <670>;
|
|
+ fsl,tx-phy-delay-100-ns = <670>;
|
|
+ fsl,rx-phy-delay-1000-ns = <0>;
|
|
+ fsl,tx-phy-delay-1000-ns = <0>;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-baremetal.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-baremetal.dts
|
|
new file mode 100644
|
|
index 000000000000..4a36d0e0c7a1
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-baremetal.dts
|
|
@@ -0,0 +1,39 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2020-2023 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx8mm-evk.dts"
|
|
+
|
|
+/ {
|
|
+ model = "FSL i.MX8MM LPDDR4 EVK RevB board - Baremetal";
|
|
+
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ rpmsg_reserved: rpmsg@b8000000 {
|
|
+ no-map;
|
|
+ reg = <0 0xb8000000 0 0x400000>;
|
|
+ };
|
|
+ bm_reserved: baremetal@60000000 {
|
|
+ no-map;
|
|
+ reg = <0 0x60000000 0 0x10000000>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&fec1 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&gpio5 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&uart3 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-ecat-userspace.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-ecat-userspace.dts
|
|
new file mode 100644
|
|
index 000000000000..a2ff71b9c26b
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-ecat-userspace.dts
|
|
@@ -0,0 +1,15 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mm-evk.dts"
|
|
+
|
|
+ðphy0 {
|
|
+ /delete-property/ reset-assert-us;
|
|
+ /delete-property/ reset-deassert-us;
|
|
+};
|
|
+
|
|
+&fec1 {
|
|
+ compatible = "fsl,imx8mm-fec-uio";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-ecat.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-ecat.dts
|
|
new file mode 100755
|
|
index 000000000000..cde59ddaa3cf
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-ecat.dts
|
|
@@ -0,0 +1,10 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mm-evk.dts"
|
|
+
|
|
+&fec1 {
|
|
+ compatible = "fsl,imx8mm-fec-ecat", "fsl,imx8mq-fec-ecat", "fsl,imx6sx-fec-ecat";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-harpoon-avb.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-harpoon-avb.dts
|
|
new file mode 100644
|
|
index 000000000000..866a9a8c239b
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-harpoon-avb.dts
|
|
@@ -0,0 +1,11 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2022-2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mm-evk-harpoon.dts"
|
|
+#include "imx8m-rpmsg-ca53.dtsi"
|
|
+
|
|
+&fec1 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-harpoon-industrial.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-harpoon-industrial.dts
|
|
new file mode 100644
|
|
index 000000000000..bedfd8da1e70
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-harpoon-industrial.dts
|
|
@@ -0,0 +1,11 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2022-2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mm-evk-root.dts"
|
|
+#include "imx8m-rpmsg-ca53.dtsi"
|
|
+
|
|
+&fec1 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-harpoon-virtio-net.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-harpoon-virtio-net.dts
|
|
new file mode 100644
|
|
index 000000000000..e7a560c16aa3
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-harpoon-virtio-net.dts
|
|
@@ -0,0 +1,11 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mm-evk-root.dts"
|
|
+#include "imx8mm-virtio-ca53.dtsi"
|
|
+
|
|
+&fec1 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-harpoon.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-harpoon.dts
|
|
new file mode 100644
|
|
index 000000000000..70b2fa9b6b31
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-harpoon.dts
|
|
@@ -0,0 +1,31 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2021-2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mm-evk-root.dts"
|
|
+#include "imx8m-rpmsg-ca53.dtsi"
|
|
+
|
|
+&i2c3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai1 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai5 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai6 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-igh.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-igh.dts
|
|
new file mode 100755
|
|
index 000000000000..14bf12d0dd82
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-igh.dts
|
|
@@ -0,0 +1,10 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mm-evk.dts"
|
|
+
|
|
+&fec1 {
|
|
+ compatible = "fsl,imx8mm-fec-igh-native", "fsl,imx8mq-fec-igh-native", "fsl,imx6sx-fec-igh-native";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-multicore-rpmsg.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-multicore-rpmsg.dts
|
|
new file mode 100644
|
|
index 000000000000..c403173bd960
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-multicore-rpmsg.dts
|
|
@@ -0,0 +1,80 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2023, 2025 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx8mm-evk-multicore-rtos.dts"
|
|
+#include "imx8m-generic-mbox.dtsi"
|
|
+#include "imx8m-generic-mbox-1.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ vdev0vring0_ca53_2: vdev0vring0@b8600000 {
|
|
+ reg = <0 0xb8600000 0 0x8000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdev0vring1_ca53_2: vdev0vring1@b8608000 {
|
|
+ reg = <0 0xb8608000 0 0x8000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ rsc_table_ca53_2: rsc-table@b86f0000 {
|
|
+ reg = <0 0xb86f0000 0 0x1000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdev0buffer_ca53_2: vdev0buffer@b8700000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xb8700000 0 0x100000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdev0vring0_ca53_3: vdev0vring0@b8610000 {
|
|
+ reg = <0 0xb8610000 0 0x8000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdev0vring1_ca53_3: vdev0vring1@b8618000 {
|
|
+ reg = <0 0xb8618000 0 0x8000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ rsc_table_ca53_3: rsc-table@b86f1000 {
|
|
+ reg = <0 0xb86f1000 0 0x1000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdev0buffer_ca53_3: vdev0buffer@b8800000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xb8800000 0 0x100000>;
|
|
+ no-map;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&ca53_2 {
|
|
+ memory-region = <&vdev0buffer_ca53_2>, <&vdev0vring0_ca53_2>, <&vdev0vring1_ca53_2>, <&rsc_table_ca53_2>, <&rtos_ca53_reserved>;
|
|
+ dma-coherent;
|
|
+ mbox-names = "tx", "rx", "rxdb";
|
|
+ mboxes = <&gen_sw_mbox 0 0 1 /* Tx channel with ACK */
|
|
+ &gen_sw_mbox 1 0 0 /* Rx channel without ACK */
|
|
+ &gen_sw_mbox 2 0 1>; /* RXDB channel with ACK */
|
|
+ fsl,startup-delay-ms = <50>;
|
|
+};
|
|
+
|
|
+&ca53_3 {
|
|
+ memory-region = <&vdev0buffer_ca53_3>, <&vdev0vring0_ca53_3>, <&vdev0vring1_ca53_3>, <&rsc_table_ca53_3>, <&rtos_ca53_reserved>;
|
|
+ dma-coherent;
|
|
+ mbox-names = "tx", "rx", "rxdb";
|
|
+ mboxes = <&gen_sw_mbox_1 0 0 1 /* Tx channel with ACK */
|
|
+ &gen_sw_mbox_1 1 0 0 /* Rx channel without ACK */
|
|
+ &gen_sw_mbox_1 2 0 1>; /* RXDB channel with ACK */
|
|
+ fsl,startup-delay-ms = <50>;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-multicore-rtos.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-multicore-rtos.dts
|
|
new file mode 100644
|
|
index 000000000000..c00cf94ce50e
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-multicore-rtos.dts
|
|
@@ -0,0 +1,78 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx8mm-evk.dts"
|
|
+#include "imx8m-rproc-ca53.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ /*
|
|
+ * Reserve up to 48MB (16MB x 3) for three FreeRTOS instances running on
|
|
+ * three Cortex-A Cores when booting Linux on at least on Cortex-A Core.
|
|
+ */
|
|
+ rtos_ca53_reserved: rtos-ca53@93c00000 {
|
|
+ no-map;
|
|
+ reg = <0 0x93c00000 0x0 0x3000000>;
|
|
+ };
|
|
+
|
|
+ /* Reserve 16MB for FreeRTOS running on CM4 */
|
|
+ m4_reserved: m4@80000000 {
|
|
+ no-map;
|
|
+ reg = <0 0x80000000 0 0x1000000>;
|
|
+ };
|
|
+
|
|
+ vdev0vring0: vdev0vring0@b8000000 {
|
|
+ reg = <0 0xb8000000 0 0x8000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdev0vring1: vdev0vring1@b8008000 {
|
|
+ reg = <0 0xb8008000 0 0x8000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ rsc_table: rsc-table@b80ff000 {
|
|
+ reg = <0 0xb80ff000 0 0x1000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdevbuffer: vdevbuffer@b8400000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xb8400000 0 0x100000>;
|
|
+ no-map;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ imx8mm-cm4 {
|
|
+ compatible = "fsl,imx8mm-cm4";
|
|
+ rsc-da = <0xb8000000>;
|
|
+ clocks = <&clk IMX8MM_CLK_M4_DIV>;
|
|
+ mbox-names = "tx", "rx", "rxdb";
|
|
+ mboxes = <&mu 0 1
|
|
+ &mu 1 1
|
|
+ &mu 3 1>;
|
|
+ memory-region = <&vdevbuffer>, <&vdev0vring0>, <&vdev0vring1>, <&rsc_table>;
|
|
+ syscon = <&src>;
|
|
+ fsl,startup-delay-ms = <500>;
|
|
+ };
|
|
+};
|
|
+
|
|
+&{/busfreq} {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&uart4 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&clk {
|
|
+ init-on-array = <IMX8MM_CLK_UART4_ROOT>;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi-harpoon-avb.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi-harpoon-avb.dts
|
|
new file mode 100644
|
|
index 000000000000..20f26f3b642f
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi-harpoon-avb.dts
|
|
@@ -0,0 +1,7 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mm-evk-harpoon-avb.dts"
|
|
+#include "imx8mm-evk-qca-wifi.dtsi"
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi-harpoon-industrial.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi-harpoon-industrial.dts
|
|
new file mode 100644
|
|
index 000000000000..77aae065a883
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi-harpoon-industrial.dts
|
|
@@ -0,0 +1,7 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mm-evk-harpoon-industrial.dts"
|
|
+#include "imx8mm-evk-qca-wifi.dtsi"
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi-harpoon-virtio-net.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi-harpoon-virtio-net.dts
|
|
new file mode 100644
|
|
index 000000000000..caf41f260a50
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi-harpoon-virtio-net.dts
|
|
@@ -0,0 +1,7 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mm-evk-harpoon-virtio-net.dts"
|
|
+#include "imx8mm-evk-qca-wifi.dtsi"
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi-harpoon.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi-harpoon.dts
|
|
new file mode 100644
|
|
index 000000000000..01d7ef234886
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi-harpoon.dts
|
|
@@ -0,0 +1,7 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mm-evk-harpoon.dts"
|
|
+#include "imx8mm-evk-qca-wifi.dtsi"
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi.dts
|
|
index aa1a25f00f55..cba11387cb08 100644
|
|
--- a/arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi.dts
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi.dts
|
|
@@ -1,128 +1,9 @@
|
|
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
- * Copyright 2019 NXP
|
|
+ * Copyright 2019, 2024 NXP
|
|
*/
|
|
|
|
/dts-v1/;
|
|
|
|
#include "imx8mm-evk.dts"
|
|
-
|
|
-/ {
|
|
- model = "FSL i.MX8MM LPDDR4 EVK with QCA WIFI revC board ";
|
|
-};
|
|
-
|
|
-/delete-node/&pmic_nxp;
|
|
-
|
|
-&i2c1 {
|
|
- pmic_rohm: pmic@4b {
|
|
- compatible = "rohm,bd71847";
|
|
- reg = <0x4b>;
|
|
- pinctrl-0 = <&pinctrl_pmic>;
|
|
- pinctrl-names = "default";
|
|
- interrupt-parent = <&gpio1>;
|
|
- interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
|
|
- rohm,reset-snvs-powered;
|
|
-
|
|
- #clock-cells = <0>;
|
|
- clocks = <&osc_32k 0>;
|
|
- clock-output-names = "clk-32k-out";
|
|
-
|
|
- regulators {
|
|
- buck1_reg: BUCK1 {
|
|
- regulator-name = "BUCK1";
|
|
- regulator-min-microvolt = <700000>;
|
|
- regulator-max-microvolt = <1300000>;
|
|
- regulator-boot-on;
|
|
- regulator-always-on;
|
|
- regulator-ramp-delay = <1250>;
|
|
- };
|
|
-
|
|
- buck2_reg: BUCK2 {
|
|
- regulator-name = "BUCK2";
|
|
- regulator-min-microvolt = <700000>;
|
|
- regulator-max-microvolt = <1300000>;
|
|
- regulator-boot-on;
|
|
- regulator-always-on;
|
|
- regulator-ramp-delay = <1250>;
|
|
- rohm,dvs-run-voltage = <1000000>;
|
|
- rohm,dvs-idle-voltage = <900000>;
|
|
- };
|
|
-
|
|
- buck3_reg: BUCK3 {
|
|
- // BUCK5 in datasheet
|
|
- regulator-name = "BUCK3";
|
|
- regulator-min-microvolt = <700000>;
|
|
- regulator-max-microvolt = <1350000>;
|
|
- regulator-boot-on;
|
|
- regulator-always-on;
|
|
- };
|
|
-
|
|
- buck4_reg: BUCK4 {
|
|
- // BUCK6 in datasheet
|
|
- regulator-name = "BUCK4";
|
|
- regulator-min-microvolt = <3000000>;
|
|
- regulator-max-microvolt = <3300000>;
|
|
- regulator-boot-on;
|
|
- regulator-always-on;
|
|
- };
|
|
-
|
|
- buck5_reg: BUCK5 {
|
|
- // BUCK7 in datasheet
|
|
- regulator-name = "BUCK5";
|
|
- regulator-min-microvolt = <1605000>;
|
|
- regulator-max-microvolt = <1995000>;
|
|
- regulator-boot-on;
|
|
- regulator-always-on;
|
|
- };
|
|
-
|
|
- buck6_reg: BUCK6 {
|
|
- // BUCK8 in datasheet
|
|
- regulator-name = "BUCK6";
|
|
- regulator-min-microvolt = <800000>;
|
|
- regulator-max-microvolt = <1400000>;
|
|
- regulator-boot-on;
|
|
- regulator-always-on;
|
|
- };
|
|
-
|
|
- ldo1_reg: LDO1 {
|
|
- regulator-name = "LDO1";
|
|
- regulator-min-microvolt = <1600000>;
|
|
- regulator-max-microvolt = <3300000>;
|
|
- regulator-boot-on;
|
|
- regulator-always-on;
|
|
- };
|
|
-
|
|
- ldo2_reg: LDO2 {
|
|
- regulator-name = "LDO2";
|
|
- regulator-min-microvolt = <800000>;
|
|
- regulator-max-microvolt = <900000>;
|
|
- regulator-boot-on;
|
|
- regulator-always-on;
|
|
- };
|
|
-
|
|
- ldo3_reg: LDO3 {
|
|
- regulator-name = "LDO3";
|
|
- regulator-min-microvolt = <1800000>;
|
|
- regulator-max-microvolt = <3300000>;
|
|
- regulator-boot-on;
|
|
- regulator-always-on;
|
|
- };
|
|
-
|
|
- ldo4_reg: LDO4 {
|
|
- regulator-name = "LDO4";
|
|
- regulator-min-microvolt = <900000>;
|
|
- regulator-max-microvolt = <1800000>;
|
|
- regulator-boot-on;
|
|
- regulator-always-on;
|
|
- };
|
|
-
|
|
- ldo6_reg: LDO6 {
|
|
- regulator-name = "LDO6";
|
|
- regulator-min-microvolt = <900000>;
|
|
- regulator-max-microvolt = <1800000>;
|
|
- regulator-boot-on;
|
|
- regulator-always-on;
|
|
- };
|
|
- };
|
|
- };
|
|
-};
|
|
+#include "imx8mm-evk-qca-wifi.dtsi"
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi.dtsi
|
|
new file mode 100644
|
|
index 000000000000..13d3076ac94c
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-qca-wifi.dtsi
|
|
@@ -0,0 +1,124 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+/ {
|
|
+ model = "FSL i.MX8MM LPDDR4 EVK with QCA WIFI revC board ";
|
|
+};
|
|
+
|
|
+/delete-node/&pmic_nxp;
|
|
+
|
|
+&i2c1 {
|
|
+ pmic_rohm: pmic@4b {
|
|
+ compatible = "rohm,bd71847";
|
|
+ reg = <0x4b>;
|
|
+ pinctrl-0 = <&pinctrl_pmic>;
|
|
+ pinctrl-names = "default";
|
|
+ interrupt-parent = <&gpio1>;
|
|
+ interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
|
|
+ rohm,reset-snvs-powered;
|
|
+
|
|
+ #clock-cells = <0>;
|
|
+ clocks = <&osc_32k 0>;
|
|
+ clock-output-names = "clk-32k-out";
|
|
+
|
|
+ regulators {
|
|
+ buck1_reg: BUCK1 {
|
|
+ regulator-name = "BUCK1";
|
|
+ regulator-min-microvolt = <700000>;
|
|
+ regulator-max-microvolt = <1300000>;
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ regulator-ramp-delay = <1250>;
|
|
+ };
|
|
+
|
|
+ buck2_reg: BUCK2 {
|
|
+ regulator-name = "BUCK2";
|
|
+ regulator-min-microvolt = <700000>;
|
|
+ regulator-max-microvolt = <1300000>;
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ regulator-ramp-delay = <1250>;
|
|
+ rohm,dvs-run-voltage = <1000000>;
|
|
+ rohm,dvs-idle-voltage = <900000>;
|
|
+ };
|
|
+
|
|
+ buck3_reg: BUCK3 {
|
|
+ // BUCK5 in datasheet
|
|
+ regulator-name = "BUCK3";
|
|
+ regulator-min-microvolt = <700000>;
|
|
+ regulator-max-microvolt = <1350000>;
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ buck4_reg: BUCK4 {
|
|
+ // BUCK6 in datasheet
|
|
+ regulator-name = "BUCK4";
|
|
+ regulator-min-microvolt = <3000000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ buck5_reg: BUCK5 {
|
|
+ // BUCK7 in datasheet
|
|
+ regulator-name = "BUCK5";
|
|
+ regulator-min-microvolt = <1605000>;
|
|
+ regulator-max-microvolt = <1995000>;
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ buck6_reg: BUCK6 {
|
|
+ // BUCK8 in datasheet
|
|
+ regulator-name = "BUCK6";
|
|
+ regulator-min-microvolt = <800000>;
|
|
+ regulator-max-microvolt = <1400000>;
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ ldo1_reg: LDO1 {
|
|
+ regulator-name = "LDO1";
|
|
+ regulator-min-microvolt = <1600000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ ldo2_reg: LDO2 {
|
|
+ regulator-name = "LDO2";
|
|
+ regulator-min-microvolt = <800000>;
|
|
+ regulator-max-microvolt = <900000>;
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ ldo3_reg: LDO3 {
|
|
+ regulator-name = "LDO3";
|
|
+ regulator-min-microvolt = <1800000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ ldo4_reg: LDO4 {
|
|
+ regulator-name = "LDO4";
|
|
+ regulator-min-microvolt = <900000>;
|
|
+ regulator-max-microvolt = <1800000>;
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ ldo6_reg: LDO6 {
|
|
+ regulator-name = "LDO6";
|
|
+ regulator-min-microvolt = <900000>;
|
|
+ regulator-max-microvolt = <1800000>;
|
|
+ regulator-boot-on;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg-8m-buf.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg-8m-buf.dts
|
|
new file mode 100644
|
|
index 000000000000..ea5dbfd3b793
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg-8m-buf.dts
|
|
@@ -0,0 +1,228 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2019-2023 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include <dt-bindings/rpmsg/imx_srtm.h>
|
|
+#include "imx8mm-evk.dts"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ m4_reserved: m4@80000000 {
|
|
+ no-map;
|
|
+ reg = <0 0x80000000 0 0x1000000>;
|
|
+ };
|
|
+
|
|
+ vdev0vring0: vdev0vring0@b8000000 {
|
|
+ reg = <0 0xb8000000 0 0x100000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdev0vring1: vdev0vring1@b8100000 {
|
|
+ reg = <0 0xb8100000 0 0x100000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ rsc_table: rsc-table@b8a00000 {
|
|
+ reg = <0 0xb8a00000 0 0x1000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdevbuffer: vdevbuffer@b8200000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xb8200000 0 0x800000>;
|
|
+ no-map;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ bt_sco_codec: bt_sco_codec {
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ sound-bt-sco {
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ sound-wm8524 {
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ wm8524: audio-codec {
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ rpmsg_audio: rpmsg_audio {
|
|
+ compatible = "fsl,imx8mm-rpmsg-audio";
|
|
+ model = "ak4497-audio";
|
|
+ fsl,platform = "rpmsg-audio-channel";
|
|
+ fsl,enable-lpa;
|
|
+ fsl,rpmsg-out;
|
|
+ assigned-clocks = <&clk IMX8MM_CLK_SAI1>;
|
|
+ assigned-clock-parents = <&clk IMX8MM_AUDIO_PLL1_OUT>;
|
|
+ assigned-clock-rates = <49152000>;
|
|
+ clocks = <&clk IMX8MM_CLK_SAI1_IPG>,
|
|
+ <&clk IMX8MM_CLK_SAI1_ROOT>,
|
|
+ <&clk IMX8MM_CLK_SDMA3_ROOT>,
|
|
+ <&clk IMX8MM_AUDIO_PLL1_OUT>,
|
|
+ <&clk IMX8MM_AUDIO_PLL2_OUT>;
|
|
+ clock-names = "ipg", "mclk", "dma", "pll8k", "pll11k";
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_0: uart-rpbus-0 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_1: uart-rpbus-1 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_2: uart-rpbus-2 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_3: uart-rpbus-3 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_4: uart-rpbus-4 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_5: uart-rpbus-5 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_6: uart-rpbus-6 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_7: uart-rpbus-7 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_8: uart-rpbus-8 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_9: uart-rpbus-9 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_10: uart-rpbus-10 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ status = "okay"; /* mcore directly print data that receive from acore */
|
|
+ };
|
|
+
|
|
+ imx8mm-cm4 {
|
|
+ compatible = "fsl,imx8mm-cm4";
|
|
+ rsc-da = <0xb8000000>;
|
|
+ clocks = <&clk IMX8MM_CLK_M4_DIV>;
|
|
+ mbox-names = "tx", "rx", "rxdb";
|
|
+ mboxes = <&mu 0 1
|
|
+ &mu 1 1
|
|
+ &mu 3 1>;
|
|
+ memory-region = <&vdevbuffer>, <&vdev0vring0>, <&vdev0vring1>, <&rsc_table>;
|
|
+ syscon = <&src>;
|
|
+ fsl,startup-delay-ms = <500>;
|
|
+ };
|
|
+};
|
|
+
|
|
+&clk {
|
|
+ init-on-array = <IMX8MM_CLK_UART4_ROOT
|
|
+ IMX8MM_CLK_AHB IMX8MM_CLK_DRAM_CORE
|
|
+ IMX8MM_CLK_NOC IMX8MM_CLK_NOC_APB
|
|
+ IMX8MM_CLK_USB_BUS
|
|
+ IMX8MM_CLK_MAIN_AXI IMX8MM_CLK_AUDIO_AHB
|
|
+ IMX8MM_CLK_DRAM_APB IMX8MM_CLK_A53_DIV
|
|
+ IMX8MM_ARM_PLL_OUT IMX8MM_CLK_DISP_AXI
|
|
+ IMX8MM_CLK_DISP_APB
|
|
+ >;
|
|
+};
|
|
+
|
|
+/*
|
|
+ * ATTENTION: M4 may use IPs like below
|
|
+ * ECSPI0/ECSPI2, GPIO1/GPIO5, GPT1, I2C3, I2S3, WDOG1, UART3, UART4, PWM3, SDMA1
|
|
+ */
|
|
+
|
|
+&i2c3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+/* the uart3 is used by m4 to support srtm uart service */
|
|
+&uart3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&uart4 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sdma3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai1 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai6 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&flexspi {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg-ca53.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg-ca53.dts
|
|
new file mode 100644
|
|
index 000000000000..ef2732f6a4fc
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg-ca53.dts
|
|
@@ -0,0 +1,40 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx8mm-evk.dts"
|
|
+#include "imx8m-rpmsg-ca53.dtsi"
|
|
+#include "imx8m-rproc-ca53.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ rtos_ca53_reserved: rtos-ca53@93c00000 {
|
|
+ reg = <0 0x93c00000 0x0 0x24000000>;
|
|
+ no-map;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&clk {
|
|
+ init-on-array = <IMX8MM_CLK_UART4_ROOT
|
|
+ IMX8MM_CLK_AHB IMX8MM_CLK_DRAM_CORE
|
|
+ IMX8MM_CLK_NOC IMX8MM_CLK_NOC_APB
|
|
+ IMX8MM_CLK_MAIN_AXI IMX8MM_CLK_DRAM_APB
|
|
+ IMX8MM_CLK_A53_DIV IMX8MM_ARM_PLL_OUT
|
|
+ >;
|
|
+};
|
|
+
|
|
+/*
|
|
+ * ATTENTION: The isolated CA53 core uses IPs below
|
|
+ * UART4
|
|
+ */
|
|
+
|
|
+&uart4 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg.dts
|
|
index c59212d17112..9999e4b8d241 100644
|
|
--- a/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg.dts
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-rpmsg.dts
|
|
@@ -1,10 +1,10 @@
|
|
// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
/*
|
|
- * Copyright 2019 NXP
|
|
+ * Copyright 2019-2023 NXP
|
|
*/
|
|
|
|
/dts-v1/;
|
|
-
|
|
+#include <dt-bindings/rpmsg/imx_srtm.h>
|
|
#include "imx8mm-evk.dts"
|
|
|
|
/ {
|
|
@@ -73,6 +73,91 @@ rpmsg_audio: rpmsg_audio {
|
|
status = "okay";
|
|
};
|
|
|
|
+ uart_rpbus_0: uart-rpbus-0 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_1: uart-rpbus-1 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_2: uart-rpbus-2 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_3: uart-rpbus-3 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_4: uart-rpbus-4 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_5: uart-rpbus-5 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_6: uart-rpbus-6 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_7: uart-rpbus-7 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_8: uart-rpbus-8 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_9: uart-rpbus-9 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <3>; /* use uart3 */
|
|
+ //flags=<IMX_SRTM_UART_RPMSG_OVER_UART_FLAG>;
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_10: uart-rpbus-10 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ status = "okay"; /* mcore directly print data that receive from acore */
|
|
+ };
|
|
+
|
|
imx8mm-cm4 {
|
|
compatible = "fsl,imx8mm-cm4";
|
|
rsc-da = <0xb8000000>;
|
|
@@ -101,13 +186,18 @@ IMX8MM_CLK_DISP_APB
|
|
|
|
/*
|
|
* ATTENTION: M4 may use IPs like below
|
|
- * ECSPI0/ECSPI2, GPIO1/GPIO5, GPT1, I2C3, I2S3, WDOG1, UART4, PWM3, SDMA1
|
|
+ * ECSPI0/ECSPI2, GPIO1/GPIO5, GPT1, I2C3, I2S3, WDOG1, UART3, UART4, PWM3, SDMA1
|
|
*/
|
|
|
|
&i2c3 {
|
|
status = "disabled";
|
|
};
|
|
|
|
+/* the uart3 is used by m4 to support srtm uart service */
|
|
+&uart3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
&uart4 {
|
|
status = "disabled";
|
|
};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-net-ca53.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-net-ca53.dts
|
|
new file mode 100644
|
|
index 000000000000..4e599a5ea4da
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-net-ca53.dts
|
|
@@ -0,0 +1,83 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx8mm-evk.dts"
|
|
+#include "imx8m-generic-mbox.dtsi"
|
|
+#include "imx8m-rproc-ca53.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ virtio_reserved: virtio@b8400000 {
|
|
+ no-map;
|
|
+ reg = <0 0xb8400000 0x0 0x00100000>;
|
|
+ };
|
|
+
|
|
+ /* 512MB */
|
|
+ rtos_ca53_reserved: rtos-ca53@93c00000 {
|
|
+ no-map;
|
|
+ reg = <0 0x93c00000 0x0 0x20000000>;
|
|
+ };
|
|
+
|
|
+ virtio_buffer: virtio-buffer@b3c00000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xb3c00000 0 0x4000000>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ virtio_net@b8400000 {
|
|
+ compatible = "virtio,mmio";
|
|
+ reg = <0x0 0xb8400000 0x0 0x1000>;
|
|
+ dma-coherent;
|
|
+ hypervisor_less;
|
|
+ memory-region = <&virtio_buffer>;
|
|
+ mbox-names = "mmiowr", "mmioirq";
|
|
+ mboxes = <&gen_sw_mbox 0 1 1 /* TX channel with ACK */
|
|
+ &gen_sw_mbox 1 1 0>; /* RX channel without ACK */
|
|
+ };
|
|
+};
|
|
+
|
|
+&{/busfreq} {
|
|
+ /* Disable busfreq to avoid Linux busfreq crash multicore virtio backend */
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&uart4 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&clk {
|
|
+ init-on-array = <IMX8MM_CLK_USDHC3_ROOT
|
|
+ IMX8MM_CLK_NAND_USDHC_BUS
|
|
+ IMX8MM_CLK_UART4_ROOT>;
|
|
+};
|
|
+
|
|
+&iomuxc {
|
|
+ /*
|
|
+ * Used for the 2nd Linux.
|
|
+ * TODO: M4 may use these pins.
|
|
+ */
|
|
+ pinctrl_uart4: uart4grp {
|
|
+ fsl,pins = <
|
|
+ MX8MM_IOMUXC_UART4_RXD_UART4_DCE_RX 0x140
|
|
+ MX8MM_IOMUXC_UART4_TXD_UART4_DCE_TX 0x140
|
|
+ >;
|
|
+ };
|
|
+};
|
|
+
|
|
+&uart2 {
|
|
+ /* uart2 is used by the 2nd OS, so configure pin and clk */
|
|
+ pinctrl-0 = <&pinctrl_uart2>, <&pinctrl_uart4>;
|
|
+ assigned-clocks = <&clk IMX8MM_CLK_UART4>;
|
|
+ assigned-clock-parents = <&clk IMX8MM_CLK_24M>;
|
|
+};
|
|
+
|
|
+&fec1 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-net-cm4.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-net-cm4.dts
|
|
new file mode 100644
|
|
index 000000000000..f20b8fe94ef9
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-net-cm4.dts
|
|
@@ -0,0 +1,74 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx8mm-evk.dts"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ cm4_reserved: cm4@80000000 {
|
|
+ reg = <0 0x80000000 0x0 0x01000000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ virtio_buffer: virtio-buffer@b3c00000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xb3c00000 0 0x4000000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ virtio_reserved: virtio@b8400000 {
|
|
+ no-map;
|
|
+ reg = <0 0xb8400000 0x0 0x00100000>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ virtio_net@b8400000 {
|
|
+ compatible = "virtio,mmio";
|
|
+ reg = <0x0 0xb8400000 0x0 0x1000>;
|
|
+ hypervisor_less;
|
|
+ memory-region = <&virtio_buffer>;
|
|
+ interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>; //MU IRQ to CA53
|
|
+ mbox-names = "mmiowr", "mmioirq";
|
|
+ mboxes = <&mu 0 2
|
|
+ &mu 1 2>;
|
|
+ };
|
|
+
|
|
+ imx8mm-cm4 {
|
|
+ compatible = "fsl,imx8mm-cm4";
|
|
+ clocks = <&clk IMX8MM_CLK_M4_DIV>;
|
|
+ mbox-names = "tx", "rx", "rxdb";
|
|
+ mboxes = <&mu 0 1
|
|
+ &mu 1 1
|
|
+ &mu 3 1>;
|
|
+ memory-region = <&cm4_reserved>;
|
|
+ syscon = <&src>;
|
|
+ fsl,startup-delay-ms = <500>;
|
|
+ status = "okay";
|
|
+ };
|
|
+};
|
|
+
|
|
+&{/busfreq} {
|
|
+ /* Disable busfreq to avoid Linux busfreq crash multicore virtio backend */
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&uart4 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&clk {
|
|
+ init-on-array = <IMX8MM_CLK_USDHC3_ROOT
|
|
+ IMX8MM_CLK_NAND_USDHC_BUS
|
|
+ IMX8MM_CLK_UART4_ROOT>;
|
|
+};
|
|
+
|
|
+&fec1 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-perf-ca53.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-perf-ca53.dts
|
|
new file mode 100644
|
|
index 000000000000..c287fc44f0a1
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-perf-ca53.dts
|
|
@@ -0,0 +1,79 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2022-2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx8mm-evk.dts"
|
|
+#include "imx8m-generic-mbox.dtsi"
|
|
+#include "imx8m-rproc-ca53.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ virtio_reserved: virtio@b8400000 {
|
|
+ no-map;
|
|
+ reg = <0 0xb8400000 0x0 0x00100000>;
|
|
+ };
|
|
+
|
|
+ /* 512MB */
|
|
+ rtos_ca53_reserved: rtos-ca53@93c00000 {
|
|
+ no-map;
|
|
+ reg = <0 0x93c00000 0x0 0x20000000>;
|
|
+ };
|
|
+
|
|
+ virtio_buffer: virtio-buffer@b3c00000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xb3c00000 0 0x4000000>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ virtio_trans@b8400000 {
|
|
+ compatible = "virtio,mmio";
|
|
+ reg = <0x0 0xb8400000 0x0 0x1000>;
|
|
+ hypervisor_less;
|
|
+ dma-coherent;
|
|
+ memory-region = <&virtio_buffer>;
|
|
+ mbox-names = "mmiowr", "mmioirq";
|
|
+ mboxes = <&gen_sw_mbox 0 1 1 /* TX channel with ACK */
|
|
+ &gen_sw_mbox 1 1 0>; /* RX channel without ACK */
|
|
+ };
|
|
+};
|
|
+
|
|
+&{/busfreq} {
|
|
+ /* Disable busfreq to avoid Linux busfreq crash multicore virtio backend */
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&uart4 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&clk {
|
|
+ init-on-array = <IMX8MM_CLK_USDHC3_ROOT
|
|
+ IMX8MM_CLK_NAND_USDHC_BUS
|
|
+ IMX8MM_CLK_UART4_ROOT>;
|
|
+};
|
|
+
|
|
+&iomuxc {
|
|
+ /*
|
|
+ * Used for the 2nd Linux.
|
|
+ * TODO: M4 may use these pins.
|
|
+ */
|
|
+ pinctrl_uart4: uart4grp {
|
|
+ fsl,pins = <
|
|
+ MX8MM_IOMUXC_UART4_RXD_UART4_DCE_RX 0x140
|
|
+ MX8MM_IOMUXC_UART4_TXD_UART4_DCE_TX 0x140
|
|
+ >;
|
|
+ };
|
|
+};
|
|
+
|
|
+&uart2 {
|
|
+ /* uart2 is used by the 2nd OS, so configure pin and clk */
|
|
+ pinctrl-0 = <&pinctrl_uart2>, <&pinctrl_uart4>;
|
|
+ assigned-clocks = <&clk IMX8MM_CLK_UART4>;
|
|
+ assigned-clock-parents = <&clk IMX8MM_CLK_24M>;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-perf-cm4.dts b/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-perf-cm4.dts
|
|
new file mode 100644
|
|
index 000000000000..7b4254c60aa9
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-evk-virtio-perf-cm4.dts
|
|
@@ -0,0 +1,63 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2022-2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx8mm-evk.dts"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ cm4_reserved: cm4@80000000 {
|
|
+ reg = <0 0x80000000 0x0 0x01000000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ virtio_reserved: virtio@b8400000 {
|
|
+ no-map;
|
|
+ reg = <0 0xb8400000 0x0 0x00100000>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ virtio_trans@b8400000 {
|
|
+ compatible = "virtio,mmio";
|
|
+ reg = <0x0 0xb8400000 0x0 0x1000>;
|
|
+ hypervisor_less;
|
|
+ interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>; //MU IRQ to CA53
|
|
+ mbox-names = "mmiowr", "mmioirq";
|
|
+ mboxes = <&mu 0 2
|
|
+ &mu 1 2>;
|
|
+ };
|
|
+
|
|
+ imx8mm-cm4 {
|
|
+ compatible = "fsl,imx8mm-cm4";
|
|
+ clocks = <&clk IMX8MM_CLK_M4_DIV>;
|
|
+ mbox-names = "tx", "rx", "rxdb";
|
|
+ mboxes = <&mu 0 1
|
|
+ &mu 1 1
|
|
+ &mu 3 1>;
|
|
+ memory-region = <&cm4_reserved>;
|
|
+ syscon = <&src>;
|
|
+ fsl,startup-delay-ms = <500>;
|
|
+ status = "okay";
|
|
+ };
|
|
+};
|
|
+
|
|
+&{/busfreq} {
|
|
+ /* Disable busfreq to avoid Linux busfreq crash multicore virtio backend */
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&uart4 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&clk {
|
|
+ init-on-array = <IMX8MM_CLK_USDHC3_ROOT
|
|
+ IMX8MM_CLK_NAND_USDHC_BUS
|
|
+ IMX8MM_CLK_UART4_ROOT>;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm-virtio-ca53.dtsi b/arch/arm64/boot/dts/freescale/imx8mm-virtio-ca53.dtsi
|
|
new file mode 100644
|
|
index 000000000000..2202ca7b63f4
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm-virtio-ca53.dtsi
|
|
@@ -0,0 +1,46 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ virtio_reserved: virtio@b8400000 {
|
|
+ no-map;
|
|
+ reg = <0 0xb8400000 0x0 0x00100000>;
|
|
+ };
|
|
+
|
|
+ sw_mbox_reserved: gen-sw-mbox@b8500000 {
|
|
+ reg = <0 0xb8500000 0 0x1000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ virtio_buffer: virtio-buffer@b3c00000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xb3c00000 0 0x4000000>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ gen_sw_mbox: generic-software-mailbox@b8500000 {
|
|
+ compatible = "fsl,generic-software-mbox";
|
|
+ reg = <0 0xb8500000 0 0x1000>;
|
|
+ #mbox-cells = <3>;
|
|
+ /* Use 2 unused SPI interrupts */
|
|
+ interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "irq", "remote_irq";
|
|
+ };
|
|
+
|
|
+ virtio_net@b8400000 {
|
|
+ compatible = "virtio,mmio";
|
|
+ reg = <0x0 0xb8400000 0x0 0x1000>;
|
|
+ hypervisor_less;
|
|
+ memory-region = <&virtio_buffer>;
|
|
+ mbox-names = "mmiowr", "mmioirq";
|
|
+ mboxes = <&gen_sw_mbox 0 1 1 /* TX channel with ACK */
|
|
+ &gen_sw_mbox 1 1 0>; /* RX channel without ACK */
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mm.dtsi b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
|
|
index abd144c2ea7d..47b640f837f3 100644
|
|
--- a/arch/arm64/boot/dts/freescale/imx8mm.dtsi
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mm.dtsi
|
|
@@ -612,6 +612,17 @@ sdma3: dma-controller@302b0000 {
|
|
fsl,sdma-ram-script-name = "imx/sdma/sdma-imx7d.bin";
|
|
};
|
|
|
|
+ gpt1: gpt@302d0000 {
|
|
+ compatible = "fsl,imx8mq-gpt", "fsl,imx7d-gpt";
|
|
+ reg = <0x302d0000 0x10000>;
|
|
+ interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ clocks = <&clk IMX8MM_CLK_GPT1_ROOT>,
|
|
+ <&clk IMX8MM_CLK_GPT1_ROOT>,
|
|
+ <&clk IMX8MM_CLK_GPT_3M>;
|
|
+ clock-names = "ipg", "per", "osc_per";
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
iomuxc: pinctrl@30330000 {
|
|
compatible = "fsl,imx8mm-iomuxc";
|
|
reg = <0x30330000 0x10000>;
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-evk-harpoon-avb.dts b/arch/arm64/boot/dts/freescale/imx8mn-evk-harpoon-avb.dts
|
|
new file mode 100644
|
|
index 000000000000..faadcdf51e32
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mn-evk-harpoon-avb.dts
|
|
@@ -0,0 +1,11 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2022-2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mn-evk-harpoon.dts"
|
|
+#include "imx8m-rpmsg-ca53.dtsi"
|
|
+
|
|
+&fec1 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-evk-harpoon-industrial.dts b/arch/arm64/boot/dts/freescale/imx8mn-evk-harpoon-industrial.dts
|
|
new file mode 100644
|
|
index 000000000000..f3183f4e1a16
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mn-evk-harpoon-industrial.dts
|
|
@@ -0,0 +1,11 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2022-2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mn-evk-root.dts"
|
|
+#include "imx8m-rpmsg-ca53.dtsi"
|
|
+
|
|
+&fec1 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mn-evk-harpoon.dts b/arch/arm64/boot/dts/freescale/imx8mn-evk-harpoon.dts
|
|
new file mode 100644
|
|
index 000000000000..1581ea6e9ddc
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mn-evk-harpoon.dts
|
|
@@ -0,0 +1,31 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2021-2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mn-evk-root.dts"
|
|
+#include "imx8m-rpmsg-ca53.dtsi"
|
|
+
|
|
+&i2c3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai5 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai6 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai7 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-avb.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-avb.dts
|
|
new file mode 100644
|
|
index 000000000000..fbe9b5d8554f
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-avb.dts
|
|
@@ -0,0 +1,42 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2021, 2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx8mp-evk.dts"
|
|
+
|
|
+/* AVB HW timer*/
|
|
+&gpt1 {
|
|
+ compatible = "fsl,avb-gpt";
|
|
+ timer-channel = <1>; /* Use output compare channel 1*/
|
|
+ rec-channel = <1 0 1>; // capture channel, eth port, ENET TC id
|
|
+ prescale = <1>;
|
|
+ domain = <0>;
|
|
+
|
|
+ clocks = <&clk IMX8MP_CLK_GPT1_ROOT>,
|
|
+ <&clk IMX8MP_CLK_GPT1_ROOT>,
|
|
+ <&clk IMX8MP_AUDIO_PLL1>;
|
|
+ clock-names = "ipg", "per", "audio_pll";
|
|
+
|
|
+ /* Make the GPT clk root derive from the audio PLL*/
|
|
+ assigned-clocks = <&clk IMX8MP_CLK_GPT1>;
|
|
+ assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>;
|
|
+ assigned-clock-rates = <98304000>;
|
|
+
|
|
+ gpt1_capin1_sel = <&gpr 0x4 2>;
|
|
+
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&fec {
|
|
+ fsl,rx-phy-delay-100-ns = <670>;
|
|
+ fsl,tx-phy-delay-100-ns = <670>;
|
|
+ fsl,rx-phy-delay-1000-ns = <0>;
|
|
+ fsl,tx-phy-delay-1000-ns = <0>;
|
|
+};
|
|
+
|
|
+ðphy1 {
|
|
+ eee-broken-100tx;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-baremetal.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-baremetal.dts
|
|
new file mode 100644
|
|
index 000000000000..ce893a1d27c6
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-baremetal.dts
|
|
@@ -0,0 +1,37 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2020-2023 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx8mp-evk.dts"
|
|
+
|
|
+/ {
|
|
+ model = "NXP i.MX8MPlus EVK board - Baremetal";
|
|
+
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ rpmsg_reserved: rpmsg@55800000 {
|
|
+ no-map;
|
|
+ reg = <0 0x55800000 0 0x800000>;
|
|
+ };
|
|
+
|
|
+ /* baremetal: slave cores reserved memory */
|
|
+ bm_reserved: baremetal@60000000 {
|
|
+ no-map;
|
|
+ reg = <0 0x60000000 0 0x10000000>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&fec {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&uart3 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-dsa-enetc.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-dsa-enetc.dts
|
|
new file mode 100644
|
|
index 000000000000..29e5aeecaae9
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-dsa-enetc.dts
|
|
@@ -0,0 +1,17 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mp-evk-dsa.dts"
|
|
+
|
|
+&netcdsa_port3 {
|
|
+ label = "swp3";
|
|
+ /delete-property/ ethernet;
|
|
+};
|
|
+
|
|
+&netcdsa_port4 {
|
|
+ label = "cpu";
|
|
+ ethernet = <&eqos>;
|
|
+ status = "okay";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-dsa-fec-swp0.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-dsa-fec-swp0.dts
|
|
new file mode 100644
|
|
index 000000000000..11c0940c642d
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-dsa-fec-swp0.dts
|
|
@@ -0,0 +1,92 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mp-evk.dts"
|
|
+
|
|
+/delete-node/&spidev1;
|
|
+
|
|
+&ecspi2 {
|
|
+ status = "okay";
|
|
+
|
|
+ netcdsa: ethernet-switch@0 {
|
|
+ reg = <0x0>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ compatible = "nxp,imxrt1180-netc";
|
|
+ /* 500 kHz */
|
|
+ spi-max-frequency = <500000>;
|
|
+
|
|
+ netcdsa_ports: ports {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ netcdsa_port0: port@0 {
|
|
+ /* cpu port connected to fec */
|
|
+ ethernet = <&fec>;
|
|
+ label = "cpu";
|
|
+ reg = <0>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <100>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port1: port@1 {
|
|
+ label = "swp1";
|
|
+ reg = <1>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port2: port@2 {
|
|
+ label = "swp2";
|
|
+ reg = <2>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port3: port@3 {
|
|
+ label = "swp3";
|
|
+ reg = <3>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port4: port@4 {
|
|
+ label = "swp4";
|
|
+ reg = <4>;
|
|
+ phy-mode = "sgmii";
|
|
+ status = "disabled";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&pinctrl_ecspi2 {
|
|
+ fsl,pins = <
|
|
+ MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK 0x84
|
|
+ MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI 0x84
|
|
+ MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO 0x84
|
|
+ >;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-dsa-fec-swp3.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-dsa-fec-swp3.dts
|
|
new file mode 100644
|
|
index 000000000000..e572cb25511a
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-dsa-fec-swp3.dts
|
|
@@ -0,0 +1,92 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mp-evk.dts"
|
|
+
|
|
+/delete-node/&spidev1;
|
|
+
|
|
+&ecspi2 {
|
|
+ status = "okay";
|
|
+
|
|
+ netcdsa: ethernet-switch@0 {
|
|
+ reg = <0x0>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ compatible = "nxp,imxrt1180-netc";
|
|
+ /* 500 kHz */
|
|
+ spi-max-frequency = <500000>;
|
|
+
|
|
+ netcdsa_ports: ports {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ netcdsa_port0: port@0 {
|
|
+ label = "swp0";
|
|
+ reg = <0>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <100>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port1: port@1 {
|
|
+ label = "swp1";
|
|
+ reg = <1>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port2: port@2 {
|
|
+ label = "swp2";
|
|
+ reg = <2>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port3: port@3 {
|
|
+ /* cpu port connected to fec */
|
|
+ ethernet = <&fec>;
|
|
+ label = "cpu";
|
|
+ reg = <3>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port4: port@4 {
|
|
+ label = "swp4";
|
|
+ reg = <4>;
|
|
+ phy-mode = "sgmii";
|
|
+ status = "disabled";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&pinctrl_ecspi2 {
|
|
+ fsl,pins = <
|
|
+ MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK 0x84
|
|
+ MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI 0x84
|
|
+ MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO 0x84
|
|
+ >;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-dsa.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-dsa.dts
|
|
new file mode 100644
|
|
index 000000000000..1d25b520c503
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-dsa.dts
|
|
@@ -0,0 +1,92 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mp-evk.dts"
|
|
+
|
|
+/delete-node/&spidev1;
|
|
+
|
|
+&ecspi2 {
|
|
+ status = "okay";
|
|
+
|
|
+ netcdsa: ethernet-switch@0 {
|
|
+ reg = <0x0>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ compatible = "nxp,imxrt1180-netc";
|
|
+ /* 500 kHz */
|
|
+ spi-max-frequency = <500000>;
|
|
+
|
|
+ netcdsa_ports: ports {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ netcdsa_port0: port@0 {
|
|
+ label = "swp0";
|
|
+ reg = <0>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <100>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port1: port@1 {
|
|
+ label = "swp1";
|
|
+ reg = <1>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port2: port@2 {
|
|
+ label = "swp2";
|
|
+ reg = <2>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port3: port@3 {
|
|
+ /* cpu port connected to eqos */
|
|
+ ethernet = <&eqos>;
|
|
+ label = "cpu";
|
|
+ reg = <3>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port4: port@4 {
|
|
+ label = "swp4";
|
|
+ reg = <4>;
|
|
+ phy-mode = "sgmii";
|
|
+ status = "disabled";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&pinctrl_ecspi2 {
|
|
+ fsl,pins = <
|
|
+ MX8MP_IOMUXC_ECSPI2_SCLK__ECSPI2_SCLK 0x84
|
|
+ MX8MP_IOMUXC_ECSPI2_MOSI__ECSPI2_MOSI 0x84
|
|
+ MX8MP_IOMUXC_ECSPI2_MISO__ECSPI2_MISO 0x84
|
|
+ >;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-ecat-userspace.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-ecat-userspace.dts
|
|
new file mode 100644
|
|
index 000000000000..c60a00d8f084
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-ecat-userspace.dts
|
|
@@ -0,0 +1,33 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mp-evk.dts"
|
|
+
|
|
+/{
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+ /* Limit memory in 4G Bytes for user space EtherCAT */
|
|
+ ecat_reserved: ecat@142000000 {
|
|
+ no-map;
|
|
+ reg = <0x1 0x42000000 0x0 0x80000000>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+ðphy1 {
|
|
+ /delete-property/ reset-gpios;
|
|
+ /delete-property/ reset-assert-us;
|
|
+ /delete-property/ reset-deassert-us;
|
|
+};
|
|
+
|
|
+&fec {
|
|
+ compatible = "fsl,imx8mm-fec-uio";
|
|
+};
|
|
+
|
|
+&eqos {
|
|
+ compatible = "nxp,imx8mp-dwmac-eqos","snps,dwmac-5.10a";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-ecat.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-ecat.dts
|
|
new file mode 100644
|
|
index 000000000000..60d6028a240a
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-ecat.dts
|
|
@@ -0,0 +1,10 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mp-evk.dts"
|
|
+
|
|
+&fec {
|
|
+ compatible = "fsl,imx8mp-fec-ecat", "fsl,imx8mq-fec-ecat", "fsl,imx6sx-fec-ecat";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-harpoon-avb.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-harpoon-avb.dts
|
|
new file mode 100644
|
|
index 000000000000..4604d7e98644
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-harpoon-avb.dts
|
|
@@ -0,0 +1,11 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2022-2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mp-evk-harpoon.dts"
|
|
+#include "imx8mp-rpmsg-ca53.dtsi"
|
|
+
|
|
+&eqos {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-harpoon-industrial.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-harpoon-industrial.dts
|
|
new file mode 100644
|
|
index 000000000000..1bc31b6d52f7
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-harpoon-industrial.dts
|
|
@@ -0,0 +1,15 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2022-2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mp-evk-root.dts"
|
|
+#include "imx8mp-rpmsg-ca53.dtsi"
|
|
+
|
|
+&eqos {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&flexcan1 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-harpoon-virtio-net.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-harpoon-virtio-net.dts
|
|
new file mode 100644
|
|
index 000000000000..a3b3a25477c0
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-harpoon-virtio-net.dts
|
|
@@ -0,0 +1,40 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx8mp-evk-root.dts"
|
|
+#include "imx8mp-generic-mbox.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ virtio_reserved: virtio@fc700000 {
|
|
+ no-map;
|
|
+ reg = <0 0xfc700000 0x0 0x00100000>;
|
|
+ };
|
|
+
|
|
+ virtio_buffer: virtio-buffer@f8700000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xf8700000 0 0x4000000>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ virtio_net@fc700000 {
|
|
+ compatible = "virtio,mmio";
|
|
+ reg = <0x0 0xfc700000 0x0 0x1000>;
|
|
+ hypervisor_less;
|
|
+ memory-region = <&virtio_buffer>;
|
|
+ mbox-names = "mmiowr", "mmioirq";
|
|
+ mboxes = <&gen_sw_mbox 0 1 1 /* TX channel with ACK */
|
|
+ &gen_sw_mbox 1 1 0>; /* RX channel without ACK */
|
|
+ };
|
|
+};
|
|
+
|
|
+&fec {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-harpoon.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-harpoon.dts
|
|
new file mode 100644
|
|
index 000000000000..828d15424e8a
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-harpoon.dts
|
|
@@ -0,0 +1,35 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2021-2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mp-evk-root.dts"
|
|
+#include "imx8mp-rpmsg-ca53.dtsi"
|
|
+
|
|
+&i2c3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai1 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai5 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai6 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai7 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-igh.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-igh.dts
|
|
new file mode 100644
|
|
index 000000000000..7f21b27837b5
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-igh.dts
|
|
@@ -0,0 +1,10 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mp-evk.dts"
|
|
+
|
|
+&fec {
|
|
+ compatible = "fsl,imx8mp-fec-igh-native", "fsl,imx8mq-fec-igh-native", "fsl,imx6sx-fec-igh-native";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-lwip.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-lwip.dts
|
|
new file mode 100644
|
|
index 000000000000..06cf65278b98
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-lwip.dts
|
|
@@ -0,0 +1,21 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx8mp-evk-multicore-rtos.dts"
|
|
+
|
|
+&fec {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&eqos {
|
|
+ /delete-property/ clocks;
|
|
+ /delete-property/ clock-names;
|
|
+ clocks = <&clk IMX8MP_CLK_QOS_ENET_ROOT>,
|
|
+ <&clk IMX8MP_CLK_ENET_QOS_TIMER>,
|
|
+ <&clk IMX8MP_CLK_ENET_QOS>;
|
|
+ clock-names = "pclk", "ptp_ref", "tx";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-rpmsg.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-rpmsg.dts
|
|
new file mode 100644
|
|
index 000000000000..76e3ea45786d
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-rpmsg.dts
|
|
@@ -0,0 +1,179 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2023, 2025 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx8mp-evk-multicore-rtos.dts"
|
|
+#include "imx8mp-generic-mbox.dtsi"
|
|
+#include "imx8mp-generic-mbox-1.dtsi"
|
|
+
|
|
+/ {
|
|
+ aliases {
|
|
+ i2c0 = &i2c1;
|
|
+ i2c1 = &i2c2;
|
|
+ i2c2 = &i2c_rpbus_3;
|
|
+ };
|
|
+
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ vdev0vring0: vdev0vring0@55000000 {
|
|
+ reg = <0 0x55000000 0 0x8000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdev0vring1: vdev0vring1@55008000 {
|
|
+ reg = <0 0x55008000 0 0x8000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdevbuffer: vdevbuffer@55400000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0x55400000 0 0x100000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ rsc_table: rsc-table@550ff000 {
|
|
+ reg = <0 0x550ff000 0 0x1000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdev0vring0_ca53_2: vdev0vring0@fe100000 {
|
|
+ reg = <0 0xfe100000 0 0x8000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdev0vring1_ca53_2: vdev0vring1@fe108000 {
|
|
+ reg = <0 0xfe108000 0 0x8000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ rsc_table_ca53_2: rsc-table@fe1f0000 {
|
|
+ reg = <0 0xfe1f0000 0 0x1000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdev0buffer_ca53_2: vdev0buffer@fe200000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xfe200000 0 0x100000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdev0vring0_ca53_3: vdev0vring0@fe110000 {
|
|
+ reg = <0 0xfe110000 0 0x8000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdev0vring1_ca53_3: vdev0vring1@fe118000 {
|
|
+ reg = <0 0xfe118000 0 0x8000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ rsc_table_ca53_3: rsc-table@fe1f1000 {
|
|
+ reg = <0 0xfe1f1000 0 0x1000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdev0buffer_ca53_3: vdev0buffer@fe300000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xfe300000 0 0x100000>;
|
|
+ no-map;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ sound-wm8960 {
|
|
+ status = "disabled";
|
|
+ };
|
|
+
|
|
+ imx8mp-cm7 {
|
|
+ clocks = <&clk IMX8MP_CLK_M7_DIV>,
|
|
+ <&audio_blk_ctrl IMX8MP_CLK_AUDIOMIX_AUDPLL_ROOT>;
|
|
+ clock-names = "core", "audio";
|
|
+ };
|
|
+};
|
|
+
|
|
+&ca53_2 {
|
|
+ memory-region = <&vdev0buffer_ca53_2>, <&vdev0vring0_ca53_2>, <&vdev0vring1_ca53_2>, <&rsc_table_ca53_2>, <&rtos_ca53_reserved>;
|
|
+ dma-coherent;
|
|
+ mbox-names = "tx", "rx", "rxdb";
|
|
+ mboxes = <&gen_sw_mbox 0 0 1 /* Tx channel with ACK */
|
|
+ &gen_sw_mbox 1 0 0 /* Rx channel without ACK */
|
|
+ &gen_sw_mbox 2 0 1>; /* RXDB channel with ACK */
|
|
+ fsl,startup-delay-ms = <50>;
|
|
+};
|
|
+
|
|
+&ca53_3 {
|
|
+ memory-region = <&vdev0buffer_ca53_3>, <&vdev0vring0_ca53_3>, <&vdev0vring1_ca53_3>, <&rsc_table_ca53_3>, <&rtos_ca53_reserved>;
|
|
+ dma-coherent;
|
|
+ mbox-names = "tx", "rx", "rxdb";
|
|
+ mboxes = <&gen_sw_mbox_1 0 0 1 /* Tx channel with ACK */
|
|
+ &gen_sw_mbox_1 1 0 0 /* Rx channel without ACK */
|
|
+ &gen_sw_mbox_1 2 0 1>; /* RXDB channel with ACK */
|
|
+ fsl,startup-delay-ms = <50>;
|
|
+};
|
|
+
|
|
+&sai3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&clk {
|
|
+ init-on-array = <IMX8MP_CLK_USDHC3_ROOT
|
|
+ IMX8MP_CLK_NAND_USDHC_BUS
|
|
+ IMX8MP_CLK_HSIO_ROOT
|
|
+ IMX8MP_CLK_UART3_ROOT
|
|
+ IMX8MP_CLK_UART4_ROOT>;
|
|
+};
|
|
+
|
|
+/delete-node/ &i2c3;
|
|
+
|
|
+&i2c_rpbus_3 {
|
|
+ compatible = "fsl,i2c-rpbus";
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ status = "okay";
|
|
+
|
|
+ pca6416: gpio@20 {
|
|
+ compatible = "ti,tca6416";
|
|
+ reg = <0x20>;
|
|
+ gpio-controller;
|
|
+ #gpio-cells = <2>;
|
|
+ };
|
|
+
|
|
+ ov5640_1: ov5640_mipi@3c {
|
|
+ compatible = "ovti,ov5640";
|
|
+ reg = <0x3c>;
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&pinctrl_csi0_pwn>, <&pinctrl_csi0_rst>;
|
|
+ clocks = <&clk IMX8MP_CLK_IPP_DO_CLKO2>;
|
|
+ clock-names = "xclk";
|
|
+ assigned-clocks = <&clk IMX8MP_CLK_IPP_DO_CLKO2>;
|
|
+ assigned-clock-parents = <&clk IMX8MP_CLK_24M>;
|
|
+ assigned-clock-rates = <24000000>;
|
|
+ csi_id = <0>;
|
|
+ powerdown-gpios = <&gpio4 1 GPIO_ACTIVE_HIGH>;
|
|
+ reset-gpios = <&gpio4 0 GPIO_ACTIVE_LOW>;
|
|
+ mclk = <24000000>;
|
|
+ mclk_source = <0>;
|
|
+ mipi_csi;
|
|
+ status = "disabled";
|
|
+
|
|
+ port {
|
|
+ ov5640_mipi_1_ep: endpoint {
|
|
+ remote-endpoint = <&mipi_csi1_ep>;
|
|
+ data-lanes = <1 2>;
|
|
+ clock-lanes = <0>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+
|
|
+ codec: wm8960@1a {
|
|
+ compatible = "wlf,wm8960,lpa";
|
|
+ reg = <0x1a>;
|
|
+ wlf,shared-lrclk;
|
|
+ SPKVDD1-supply = <®_audio_pwr>;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-rtos.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-rtos.dts
|
|
new file mode 100644
|
|
index 000000000000..66ff72d1497c
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-multicore-rtos.dts
|
|
@@ -0,0 +1,80 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx8mp-evk.dts"
|
|
+#include "imx8m-rproc-ca53.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ /*
|
|
+ * Reserve up to 48MB (16MB x 3) for three FreeRTOS instances running on
|
|
+ * three Cortex-A Cores when booting Linux on at least on Cortex-A Core.
|
|
+ */
|
|
+ rtos_ca53_reserved: rtos-ca53@c0000000 {
|
|
+ no-map;
|
|
+ reg = <0 0xc0000000 0x0 0x3000000>;
|
|
+ };
|
|
+
|
|
+ /* Reserve 16MB for RTOS running on CM7 */
|
|
+ m7_reserved: m7@80000000 {
|
|
+ no-map;
|
|
+ reg = <0 0x80000000 0 0x1000000>;
|
|
+ };
|
|
+
|
|
+ vdev0vring0: vdev0vring0@55000000 {
|
|
+ reg = <0 0x55000000 0 0x8000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdev0vring1: vdev0vring1@55008000 {
|
|
+ reg = <0 0x55008000 0 0x8000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdevbuffer: vdevbuffer@55400000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0x55400000 0 0x100000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ rsc_table: rsc-table@550ff000 {
|
|
+ reg = <0 0x550ff000 0 0x1000>;
|
|
+ no-map;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ imx8mp-cm7 {
|
|
+ compatible = "fsl,imx8mn-cm7";
|
|
+ rsc-da = <0x55000000>;
|
|
+ clocks = <&clk IMX8MP_CLK_M7_DIV>;
|
|
+ clock-names = "core";
|
|
+ mbox-names = "tx", "rx", "rxdb";
|
|
+ mboxes = <&mu 0 1
|
|
+ &mu 1 1
|
|
+ &mu 3 1>;
|
|
+ memory-region = <&vdevbuffer>, <&vdev0vring0>, <&vdev0vring1>, <&rsc_table>;
|
|
+ status = "okay";
|
|
+ fsl,startup-delay-ms = <500>;
|
|
+ };
|
|
+};
|
|
+
|
|
+&{/busfreq} {
|
|
+ /* Disable busfreq to avoid Linux busfreq crash multicore virtio backend */
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&uart4 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&clk {
|
|
+ init-on-array = <IMX8MP_CLK_UART4_ROOT>;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-rpmsg-ca53.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-rpmsg-ca53.dts
|
|
new file mode 100644
|
|
index 000000000000..2ee7a41da41e
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-rpmsg-ca53.dts
|
|
@@ -0,0 +1,45 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx8mp-evk.dts"
|
|
+#include "imx8mp-rpmsg-ca53.dtsi"
|
|
+#include "imx8m-rproc-ca53.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ rtos_ca53_reserved: rtos-ca53@c0000000 {
|
|
+ reg = <0 0xc0000000 0x0 0x3000000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ };
|
|
+};
|
|
+
|
|
+&{/busfreq} {
|
|
+ /* Disable busfreq to avoid Linux busfreq crash multicore virtio backend */
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&uart3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&uart4 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&clk {
|
|
+ init-on-array = <IMX8MP_CLK_USDHC3_ROOT
|
|
+ IMX8MP_CLK_NAND_USDHC_BUS
|
|
+ IMX8MP_CLK_HSIO_ROOT
|
|
+ IMX8MP_CLK_UART3_ROOT
|
|
+ IMX8MP_CLK_UART4_ROOT>;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-net-ca53.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-net-ca53.dts
|
|
new file mode 100644
|
|
index 000000000000..630df227725f
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-net-ca53.dts
|
|
@@ -0,0 +1,82 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx8mp-evk.dts"
|
|
+#include "imx8mp-generic-mbox.dtsi"
|
|
+#include "imx8m-rproc-ca53.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ virtio_reserved: virtio@fc700000 {
|
|
+ no-map;
|
|
+ reg = <0 0xfc700000 0x0 0x00100000>;
|
|
+ };
|
|
+
|
|
+ /* 512MB */
|
|
+ rtos_ca53_reserved: rtos-ca53@c0000000 {
|
|
+ no-map;
|
|
+ reg = <0 0xc0000000 0x0 0x20000000>;
|
|
+ };
|
|
+
|
|
+ virtio_buffer: virtio-buffer@f8700000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xf8700000 0 0x4000000>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ virtio_net@fc700000 {
|
|
+ compatible = "virtio,mmio";
|
|
+ reg = <0x0 0xfc700000 0x0 0x1000>;
|
|
+ dma-coherent;
|
|
+ hypervisor_less;
|
|
+ memory-region = <&virtio_buffer>;
|
|
+ mbox-names = "mmiowr", "mmioirq";
|
|
+ mboxes = <&gen_sw_mbox 0 1 1 /* TX channel with ACK */
|
|
+ &gen_sw_mbox 1 1 0>; /* RX channel without ACK */
|
|
+ };
|
|
+};
|
|
+
|
|
+&{/busfreq} {
|
|
+ /* Disable busfreq to avoid Linux busfreq crash multicore virtio backend */
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&uart4 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&clk {
|
|
+ init-on-array = <IMX8MP_CLK_USDHC3_ROOT
|
|
+ IMX8MP_CLK_NAND_USDHC_BUS
|
|
+ IMX8MP_CLK_HSIO_ROOT
|
|
+ IMX8MP_CLK_UART4_ROOT>;
|
|
+};
|
|
+
|
|
+&iomuxc {
|
|
+ pinctrl_uart4: uart4grp {
|
|
+ fsl,pins = <
|
|
+ MX8MP_IOMUXC_UART4_RXD__UART4_DCE_RX 0x140
|
|
+ MX8MP_IOMUXC_UART4_TXD__UART4_DCE_TX 0x140
|
|
+ >;
|
|
+ };
|
|
+};
|
|
+
|
|
+&fec {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&eqos {
|
|
+ /delete-property/ clocks;
|
|
+ /delete-property/ clock-names;
|
|
+ clocks = <&clk IMX8MP_CLK_QOS_ENET_ROOT>,
|
|
+ <&clk IMX8MP_CLK_ENET_QOS_TIMER>,
|
|
+ <&clk IMX8MP_CLK_ENET_QOS>;
|
|
+ clock-names = "pclk", "ptp_ref", "tx";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-net-cm7.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-net-cm7.dts
|
|
new file mode 100644
|
|
index 000000000000..6fbb9549d143
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-net-cm7.dts
|
|
@@ -0,0 +1,85 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx8mp-evk.dts"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ cm7_reserved: cm7@80000000 {
|
|
+ reg = <0 0x80000000 0x0 0x01000000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ virtio_buffer: virtio-buffer@b3c00000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xb3c00000 0 0x4000000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ virtio_reserved: virtio@b8400000 {
|
|
+ no-map;
|
|
+ reg = <0 0xb8400000 0x0 0x00100000>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ virtio_net@b8400000 {
|
|
+ compatible = "virtio,mmio";
|
|
+ reg = <0x0 0xb8400000 0x0 0x1000>;
|
|
+ hypervisor_less;
|
|
+ memory-region = <&virtio_buffer>;
|
|
+ mbox-names = "mmiowr", "mmioirq";
|
|
+ mboxes = <&mu 0 2
|
|
+ &mu 1 2>;
|
|
+ };
|
|
+
|
|
+ imx8mp-cm7 {
|
|
+ compatible = "fsl,imx8mn-cm7";
|
|
+ clocks = <&clk IMX8MP_CLK_M7_DIV>;
|
|
+ clock-names = "core";
|
|
+ mbox-names = "tx", "rx", "rxdb";
|
|
+ mboxes = <&mu 0 1
|
|
+ &mu 1 1
|
|
+ &mu 3 1>;
|
|
+ memory-region = <&cm7_reserved>;
|
|
+ fsl,startup-delay-ms = <500>;
|
|
+ status = "okay";
|
|
+ };
|
|
+};
|
|
+
|
|
+&{/busfreq} {
|
|
+ /* Disable busfreq to avoid Linux busfreq crash multicore virtio backend */
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&uart4 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+
|
|
+&fec {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&eqos {
|
|
+ /delete-property/ clocks;
|
|
+ /delete-property/ clock-names;
|
|
+ clocks = <&clk IMX8MP_CLK_QOS_ENET_ROOT>,
|
|
+ <&clk IMX8MP_CLK_ENET_QOS_TIMER>,
|
|
+ <&clk IMX8MP_CLK_ENET_QOS>;
|
|
+ clock-names = "pclk", "ptp_ref", "tx";
|
|
+};
|
|
+
|
|
+&i2c3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai3 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-perf-ca53.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-perf-ca53.dts
|
|
new file mode 100644
|
|
index 000000000000..ccf566ec5fdd
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-perf-ca53.dts
|
|
@@ -0,0 +1,69 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx8mp-evk.dts"
|
|
+#include "imx8mp-generic-mbox.dtsi"
|
|
+#include "imx8m-rproc-ca53.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ virtio_reserved: virtio@fc700000 {
|
|
+ no-map;
|
|
+ reg = <0 0xfc700000 0x0 0x00100000>;
|
|
+ };
|
|
+
|
|
+ /* 512MB */
|
|
+ rtos_ca53_reserved: rtos-ca53@c0000000 {
|
|
+ no-map;
|
|
+ reg = <0 0xc0000000 0x0 0x20000000>;
|
|
+ };
|
|
+
|
|
+ virtio_buffer: virtio-buffer@f8700000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xf8700000 0 0x4000000>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ virtio_trans@fc700000 {
|
|
+ compatible = "virtio,mmio";
|
|
+ reg = <0x0 0xfc700000 0x0 0x1000>;
|
|
+ dma-coherent;
|
|
+ hypervisor_less;
|
|
+ memory-region = <&virtio_buffer>;
|
|
+ mbox-names = "mmiowr", "mmioirq";
|
|
+ mboxes = <&gen_sw_mbox 0 1 1 /* TX channel with ACK */
|
|
+ &gen_sw_mbox 1 1 0>; /* RX channel without ACK */
|
|
+ };
|
|
+};
|
|
+
|
|
+&{/busfreq} {
|
|
+ /* Disable busfreq to avoid Linux busfreq crash multicore virtio backend */
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&uart4 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&clk {
|
|
+ init-on-array = <IMX8MP_CLK_USDHC3_ROOT
|
|
+ IMX8MP_CLK_NAND_USDHC_BUS
|
|
+ IMX8MP_CLK_HSIO_ROOT
|
|
+ IMX8MP_CLK_UART4_ROOT>;
|
|
+};
|
|
+
|
|
+&iomuxc {
|
|
+ pinctrl_uart4: uart4grp {
|
|
+ fsl,pins = <
|
|
+ MX8MP_IOMUXC_UART4_RXD__UART4_DCE_RX 0x140
|
|
+ MX8MP_IOMUXC_UART4_TXD__UART4_DCE_TX 0x140
|
|
+ >;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-perf-cm7.dts b/arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-perf-cm7.dts
|
|
new file mode 100644
|
|
index 000000000000..5897c49fa04a
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-evk-virtio-perf-cm7.dts
|
|
@@ -0,0 +1,69 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx8mp-evk.dts"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ linux,cma {
|
|
+ size = <0 0x20000000>;
|
|
+ alloc-ranges = <0 0x40000000 0 0x80000000>;
|
|
+ };
|
|
+
|
|
+ cm7_reserved: cm7@80000000 {
|
|
+ reg = <0 0x80000000 0x0 0x01000000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ virtio_reserved: virtio@b8400000 {
|
|
+ no-map;
|
|
+ reg = <0 0xb8400000 0x0 0x00100000>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ virtio_trans@b8400000 {
|
|
+ compatible = "virtio,mmio";
|
|
+ reg = <0x0 0xb8400000 0x0 0x1000>;
|
|
+ hypervisor_less;
|
|
+ mbox-names = "mmiowr", "mmioirq";
|
|
+ mboxes = <&mu 0 2
|
|
+ &mu 1 2>;
|
|
+ };
|
|
+
|
|
+ imx8mp-cm7 {
|
|
+ compatible = "fsl,imx8mn-cm7";
|
|
+ clocks = <&clk IMX8MP_CLK_M7_DIV>;
|
|
+ clock-names = "core";
|
|
+ mbox-names = "tx", "rx", "rxdb";
|
|
+ mboxes = <&mu 0 1
|
|
+ &mu 1 1
|
|
+ &mu 3 1>;
|
|
+ memory-region = <&cm7_reserved>;
|
|
+ status = "okay";
|
|
+ fsl,startup-delay-ms = <500>;
|
|
+ };
|
|
+};
|
|
+
|
|
+&{/busfreq} {
|
|
+ /* Disable busfreq to avoid Linux busfreq crash multicore virtio backend */
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&uart4 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&i2c3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai3 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-generic-mbox-1.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-generic-mbox-1.dtsi
|
|
new file mode 100644
|
|
index 000000000000..5f8ba823c0bd
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-generic-mbox-1.dtsi
|
|
@@ -0,0 +1,27 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ gen_sw_mbox_1_reserved: gen-sw-mbox-1@fe001000 {
|
|
+ reg = <0 0xfe001000 0 0x1000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ };
|
|
+
|
|
+ gen_sw_mbox_1: generic-software-mailbox-1@fe001000 {
|
|
+ compatible = "fsl,generic-software-mbox";
|
|
+ reg = <0 0xfe001000 0 0x1000>;
|
|
+ #mbox-cells = <3>;
|
|
+ /* Use 2 unused SPI interrupts */
|
|
+ interrupts = <GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "irq", "remote_irq";
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-generic-mbox.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-generic-mbox.dtsi
|
|
new file mode 100644
|
|
index 000000000000..8709e076bcc0
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-generic-mbox.dtsi
|
|
@@ -0,0 +1,27 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ gen_sw_mbox_reserved: gen-sw-mbox@fe000000 {
|
|
+ reg = <0 0xfe000000 0 0x1000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ };
|
|
+
|
|
+ gen_sw_mbox: generic-software-mailbox@fe000000 {
|
|
+ compatible = "fsl,generic-software-mbox";
|
|
+ reg = <0 0xfe000000 0 0x1000>;
|
|
+ #mbox-cells = <3>;
|
|
+ /* Use 2 unused SPI interrupts */
|
|
+ interrupts = <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "irq", "remote_irq";
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-rpmsg-ca53-1.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-rpmsg-ca53-1.dtsi
|
|
new file mode 100644
|
|
index 000000000000..0e1f484209ff
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-rpmsg-ca53-1.dtsi
|
|
@@ -0,0 +1,37 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mp-generic-mbox-1.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ rpmsg_ca53_1_reserved: rpmsg-ca53-1@fe110000 {
|
|
+ reg = <0 0xfe110000 0 0x10000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdevbuffer_ca53_1: vdevbuffer-ca53-1@fe300000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xfe300000 0 0x100000>;
|
|
+ no-map;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ rpmsg-ca53-1 {
|
|
+ compatible = "fsl,imx8mm-rpmsg";
|
|
+ reg = <0x0 0xfe110000 0x0 0x10000>; /* 64K for one rpmsg instance */
|
|
+ dma-coherent;
|
|
+ memory-region = <&vdevbuffer_ca53_1>;
|
|
+ mbox-names = "tx", "rx", "rxdb";
|
|
+ mboxes = <&gen_sw_mbox_1 0 0 1 /* Tx channel with ACK */
|
|
+ &gen_sw_mbox_1 1 0 0 /* Rx channel without ACK */
|
|
+ &gen_sw_mbox_1 2 0 1>; /* RXDB channel with ACK */
|
|
+ vdev-nums = <1>;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx8mp-rpmsg-ca53.dtsi b/arch/arm64/boot/dts/freescale/imx8mp-rpmsg-ca53.dtsi
|
|
new file mode 100644
|
|
index 000000000000..32e127a6d203
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx8mp-rpmsg-ca53.dtsi
|
|
@@ -0,0 +1,37 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2022-2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx8mp-generic-mbox.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ rpmsg_ca53_reserved: rpmsg-ca53@fe100000 {
|
|
+ reg = <0 0xfe100000 0 0x10000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdevbuffer_ca53: vdevbuffer-ca53@fe200000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xfe200000 0 0x100000>;
|
|
+ no-map;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ rpmsg-ca53 {
|
|
+ compatible = "fsl,imx8mm-rpmsg";
|
|
+ reg = <0x0 0xfe100000 0x0 0x10000>; /* 64K for one rpmsg instance */
|
|
+ dma-coherent;
|
|
+ memory-region = <&vdevbuffer_ca53>;
|
|
+ mbox-names = "tx", "rx", "rxdb";
|
|
+ mboxes = <&gen_sw_mbox 0 0 1 /* Tx channel with ACK */
|
|
+ &gen_sw_mbox 1 0 0 /* Rx channel without ACK */
|
|
+ &gen_sw_mbox 2 0 1>; /* RXDB channel with ACK */
|
|
+ vdev-nums = <1>;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-avb.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-avb.dts
|
|
new file mode 100644
|
|
index 000000000000..5f2f0ee80e09
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-avb.dts
|
|
@@ -0,0 +1,9 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx93-11x11-evk.dts"
|
|
+#include "imx93-evk-avb.dtsi"
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-baremetal.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-baremetal.dts
|
|
new file mode 100644
|
|
index 000000000000..84f9700437a1
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-baremetal.dts
|
|
@@ -0,0 +1,31 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx93-11x11-evk.dts"
|
|
+
|
|
+/ {
|
|
+ model = "NXP i.MX93 11X11 EVK board - Baremetal";
|
|
+
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ bm_reserved: baremetal@b0000000 {
|
|
+ no-map;
|
|
+ reg = <0 0xb0000000 0 0x10000000>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&fec {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&lpuart2 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dpdk.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dpdk.dts
|
|
new file mode 100644
|
|
index 000000000000..5ac7f92b3a6b
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dpdk.dts
|
|
@@ -0,0 +1,16 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx93-11x11-evk.dts"
|
|
+
|
|
+ðphy2 {
|
|
+ /delete-property/ reset-gpios;
|
|
+ /delete-property/ reset-assert-us;
|
|
+ /delete-property/ reset-deassert-us;
|
|
+};
|
|
+
|
|
+&fec {
|
|
+ compatible = "fsl,imx8mm-fec-uio";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa-enetc.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa-enetc.dts
|
|
new file mode 100644
|
|
index 000000000000..f45760d6cd3e
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa-enetc.dts
|
|
@@ -0,0 +1,17 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx93-11x11-evk-dsa.dts"
|
|
+
|
|
+&netcdsa_port3 {
|
|
+ label = "swp3";
|
|
+ /delete-property/ ethernet;
|
|
+};
|
|
+
|
|
+&netcdsa_port4 {
|
|
+ label = "cpu";
|
|
+ ethernet = <&eqos>;
|
|
+ status = "okay";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa-fec-swp0.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa-fec-swp0.dts
|
|
new file mode 100644
|
|
index 000000000000..64e72b7aa9de
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa-fec-swp0.dts
|
|
@@ -0,0 +1,108 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx93-11x11-evk.dts"
|
|
+
|
|
+&flexcan2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&lpuart7 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&lpspi3 {
|
|
+ fsl,spi-num-chipselects = <1>;
|
|
+ pinctrl-names = "default", "sleep";
|
|
+ pinctrl-0 = <&pinctrl_lpspi3>;
|
|
+ pinctrl-1 = <&pinctrl_lpspi3>;
|
|
+ cs-gpios = <&gpio2 8 GPIO_ACTIVE_LOW>;
|
|
+ pinctrl-assert-gpios = <&adp5585gpio 4 GPIO_ACTIVE_HIGH>;
|
|
+ status = "okay";
|
|
+
|
|
+ netcdsa: ethernet-switch@0 {
|
|
+ reg = <0x0>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ compatible = "nxp,imxrt1180-netc";
|
|
+ /* 1 MHz */
|
|
+ spi-max-frequency = <1000000>;
|
|
+ /* Sample data on trailing clock edge */
|
|
+
|
|
+ netcdsa_ports: ports {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ netcdsa_port0: port@0 {
|
|
+ /* cpu port connected to fec */
|
|
+ ethernet = <&fec>;
|
|
+ label = "cpu";
|
|
+ reg = <0>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <100>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port1: port@1 {
|
|
+ label = "swp1";
|
|
+ reg = <1>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port2: port@2 {
|
|
+ label = "swp2";
|
|
+ reg = <2>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port3: port@3 {
|
|
+ label = "swp3";
|
|
+ reg = <3>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port4: port@4 {
|
|
+ label = "swp4";
|
|
+ reg = <4>;
|
|
+ phy-mode = "sgmii";
|
|
+ status = "disabled";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&iomuxc {
|
|
+ pinctrl_lpspi3: lpspi3grp {
|
|
+ fsl,pins = <
|
|
+ MX93_PAD_GPIO_IO08__GPIO2_IO08 0x3fe
|
|
+ MX93_PAD_GPIO_IO09__LPSPI3_SIN 0x3fe
|
|
+ MX93_PAD_GPIO_IO10__LPSPI3_SOUT 0x3fe
|
|
+ MX93_PAD_GPIO_IO11__LPSPI3_SCK 0x3fe
|
|
+ >;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa-fec-swp3.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa-fec-swp3.dts
|
|
new file mode 100644
|
|
index 000000000000..6ae448c99103
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa-fec-swp3.dts
|
|
@@ -0,0 +1,108 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx93-11x11-evk.dts"
|
|
+
|
|
+&flexcan2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&lpuart7 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&lpspi3 {
|
|
+ fsl,spi-num-chipselects = <1>;
|
|
+ pinctrl-names = "default", "sleep";
|
|
+ pinctrl-0 = <&pinctrl_lpspi3>;
|
|
+ pinctrl-1 = <&pinctrl_lpspi3>;
|
|
+ cs-gpios = <&gpio2 8 GPIO_ACTIVE_LOW>;
|
|
+ pinctrl-assert-gpios = <&adp5585gpio 4 GPIO_ACTIVE_HIGH>;
|
|
+ status = "okay";
|
|
+
|
|
+ netcdsa: ethernet-switch@0 {
|
|
+ reg = <0x0>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ compatible = "nxp,imxrt1180-netc";
|
|
+ /* 1 MHz */
|
|
+ spi-max-frequency = <1000000>;
|
|
+ /* Sample data on trailing clock edge */
|
|
+
|
|
+ netcdsa_ports: ports {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ netcdsa_port0: port@0 {
|
|
+ label = "swp0";
|
|
+ reg = <0>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <100>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port1: port@1 {
|
|
+ label = "swp1";
|
|
+ reg = <1>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port2: port@2 {
|
|
+ label = "swp2";
|
|
+ reg = <2>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port3: port@3 {
|
|
+ /* cpu port connected to fec */
|
|
+ ethernet = <&fec>;
|
|
+ label = "cpu";
|
|
+ reg = <3>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port4: port@4 {
|
|
+ label = "swp4";
|
|
+ reg = <4>;
|
|
+ phy-mode = "sgmii";
|
|
+ status = "disabled";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&iomuxc {
|
|
+ pinctrl_lpspi3: lpspi3grp {
|
|
+ fsl,pins = <
|
|
+ MX93_PAD_GPIO_IO08__GPIO2_IO08 0x3fe
|
|
+ MX93_PAD_GPIO_IO09__LPSPI3_SIN 0x3fe
|
|
+ MX93_PAD_GPIO_IO10__LPSPI3_SOUT 0x3fe
|
|
+ MX93_PAD_GPIO_IO11__LPSPI3_SCK 0x3fe
|
|
+ >;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa.dts
|
|
new file mode 100644
|
|
index 000000000000..940a7a4ac441
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-dsa.dts
|
|
@@ -0,0 +1,108 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx93-11x11-evk.dts"
|
|
+
|
|
+&flexcan2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&lpuart7 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&lpspi3 {
|
|
+ fsl,spi-num-chipselects = <1>;
|
|
+ pinctrl-names = "default", "sleep";
|
|
+ pinctrl-0 = <&pinctrl_lpspi3>;
|
|
+ pinctrl-1 = <&pinctrl_lpspi3>;
|
|
+ cs-gpios = <&gpio2 8 GPIO_ACTIVE_LOW>;
|
|
+ pinctrl-assert-gpios = <&adp5585gpio 4 GPIO_ACTIVE_HIGH>;
|
|
+ status = "okay";
|
|
+
|
|
+ netcdsa: ethernet-switch@0 {
|
|
+ reg = <0x0>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ compatible = "nxp,imxrt1180-netc";
|
|
+ /* 1 MHz */
|
|
+ spi-max-frequency = <1000000>;
|
|
+ /* Sample data on trailing clock edge */
|
|
+
|
|
+ netcdsa_ports: ports {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ netcdsa_port0: port@0 {
|
|
+ label = "swp0";
|
|
+ reg = <0>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <100>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port1: port@1 {
|
|
+ label = "swp1";
|
|
+ reg = <1>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port2: port@2 {
|
|
+ label = "swp2";
|
|
+ reg = <2>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port3: port@3 {
|
|
+ /* cpu port connected to eqos */
|
|
+ ethernet = <&eqos>;
|
|
+ label = "cpu";
|
|
+ reg = <3>;
|
|
+ phy-mode = "sgmii";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ netcdsa_port4: port@4 {
|
|
+ label = "swp4";
|
|
+ reg = <4>;
|
|
+ phy-mode = "sgmii";
|
|
+ status = "disabled";
|
|
+
|
|
+ fixed-link {
|
|
+ speed = <1000>;
|
|
+ full-duplex;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&iomuxc {
|
|
+ pinctrl_lpspi3: lpspi3grp {
|
|
+ fsl,pins = <
|
|
+ MX93_PAD_GPIO_IO08__GPIO2_IO08 0x3fe
|
|
+ MX93_PAD_GPIO_IO09__LPSPI3_SIN 0x3fe
|
|
+ MX93_PAD_GPIO_IO10__LPSPI3_SOUT 0x3fe
|
|
+ MX93_PAD_GPIO_IO11__LPSPI3_SCK 0x3fe
|
|
+ >;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-ecat-userspace.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-ecat-userspace.dts
|
|
new file mode 100644
|
|
index 000000000000..5ac7f92b3a6b
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-ecat-userspace.dts
|
|
@@ -0,0 +1,16 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx93-11x11-evk.dts"
|
|
+
|
|
+ðphy2 {
|
|
+ /delete-property/ reset-gpios;
|
|
+ /delete-property/ reset-assert-us;
|
|
+ /delete-property/ reset-deassert-us;
|
|
+};
|
|
+
|
|
+&fec {
|
|
+ compatible = "fsl,imx8mm-fec-uio";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-ecat.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-ecat.dts
|
|
new file mode 100644
|
|
index 000000000000..3626356fb9b6
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-ecat.dts
|
|
@@ -0,0 +1,11 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx93-11x11-evk.dts"
|
|
+
|
|
+
|
|
+&fec {
|
|
+ compatible = "fsl,imx93-fec-ecat", "fsl,imx8mp-fec-ecat", "fsl,imx8mq-fec-ecat";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-harpoon-avb.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-harpoon-avb.dts
|
|
new file mode 100644
|
|
index 000000000000..95a4d0578fcb
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-harpoon-avb.dts
|
|
@@ -0,0 +1,10 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx93-11x11-evk-harpoon.dts"
|
|
+
|
|
+&eqos {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-harpoon-industrial.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-harpoon-industrial.dts
|
|
new file mode 100644
|
|
index 000000000000..d0a18a1dd6dd
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-harpoon-industrial.dts
|
|
@@ -0,0 +1,19 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx93-11x11-evk-root.dts"
|
|
+#include "imx93-rpmsg-ca55.dtsi"
|
|
+
|
|
+&eqos {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&flexcan2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+®_can2_stby {
|
|
+ status = "disabled";
|
|
+};
|
|
\ No newline at end of file
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-harpoon-virtio-net.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-harpoon-virtio-net.dts
|
|
new file mode 100644
|
|
index 000000000000..75ff20e30ab6
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-harpoon-virtio-net.dts
|
|
@@ -0,0 +1,46 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx93-11x11-evk-root.dts"
|
|
+#include "imx93-generic-mbox.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ virtio_reserved: virtio@fc700000 {
|
|
+ no-map;
|
|
+ reg = <0 0xfc700000 0x0 0x00100000>;
|
|
+ };
|
|
+
|
|
+ /* 512MB */
|
|
+ freertos_reserved: inmate@d0000000 {
|
|
+ no-map;
|
|
+ reg = <0 0xd0000000 0x0 0x20000000>;
|
|
+ };
|
|
+
|
|
+ virtio_buffer: virtio-buffer@f8700000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xf8700000 0 0x4000000>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ virtio_net@fc700000 {
|
|
+ compatible = "virtio,mmio";
|
|
+ reg = <0x0 0xfc700000 0x0 0x1000>;
|
|
+ hypervisor_less;
|
|
+ memory-region = <&virtio_buffer>;
|
|
+ mbox-names = "mmiowr", "mmioirq";
|
|
+ mboxes = <&gen_sw_mbox 0 1 1 /* TX channel with ACK */
|
|
+ &gen_sw_mbox 1 1 0>; /* RX channel without ACK */
|
|
+ };
|
|
+};
|
|
+
|
|
+&fec {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-harpoon.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-harpoon.dts
|
|
new file mode 100644
|
|
index 000000000000..2f3ba10e7033
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-harpoon.dts
|
|
@@ -0,0 +1,35 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx93-11x11-evk-root.dts"
|
|
+#include "imx93-rpmsg-ca55.dtsi"
|
|
+
|
|
+&dsi {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&lpi2c1 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&lpi2c4 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai1 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&flexcan2 {
|
|
+ status = "disabled";
|
|
+};
|
|
\ No newline at end of file
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-igh.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-igh.dts
|
|
new file mode 100644
|
|
index 000000000000..c2648d5b2662
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-igh.dts
|
|
@@ -0,0 +1,11 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx93-11x11-evk.dts"
|
|
+
|
|
+
|
|
+&fec {
|
|
+ compatible = "fsl,imx93-fec-igh-native", "fsl,imx8mp-fec-igh-native", "fsl,imx8mq-fec-igh-native";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-multicore-rpmsg.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-multicore-rpmsg.dts
|
|
new file mode 100644
|
|
index 000000000000..0b5bdeb94367
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-multicore-rpmsg.dts
|
|
@@ -0,0 +1,47 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2025 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx93-11x11-evk-multicore-rtos.dts"
|
|
+#include "imx93-generic-mbox.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ vdev0vring0_ca55: vdev0vring0@fe100000 {
|
|
+ reg = <0 0xfe100000 0 0x8000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdev0vring1_ca55: vdev0vring1@fe108000 {
|
|
+ reg = <0 0xfe108000 0 0x8000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ rsc_table_ca55: rsc-table@fe1f0000 {
|
|
+ reg = <0 0xfe1f0000 0 0x1000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdev0buffer_ca55: vdev0buffer@fe200000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xfe200000 0 0x100000>;
|
|
+ no-map;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&ca55_1 {
|
|
+ memory-region = <&vdev0buffer_ca55>, <&vdev0vring0_ca55>, <&vdev0vring1_ca55>, <&rsc_table_ca55>, <&rtos_ca55_reserved>;
|
|
+ dma-coherent;
|
|
+ mbox-names = "tx", "rx", "rxdb";
|
|
+ mboxes = <&gen_sw_mbox 0 0 1 /* Tx channel with ACK */
|
|
+ &gen_sw_mbox 1 0 0 /* Rx channel without ACK */
|
|
+ &gen_sw_mbox 2 0 1>; /* RXDB channel with ACK */
|
|
+ fsl,startup-delay-ms = <50>;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-multicore-rtos.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-multicore-rtos.dts
|
|
new file mode 100644
|
|
index 000000000000..13db26b61ad1
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-multicore-rtos.dts
|
|
@@ -0,0 +1,39 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx93-11x11-evk.dts"
|
|
+#include "imx93-rproc-ca55.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ /*
|
|
+ * Reserve up to 16MB for one possible FreeRTOS instances running on
|
|
+ * one Cortex-A Cores when booting Linux on at least on Cortex-A Core.
|
|
+ */
|
|
+ rtos_ca55_reserved: rtos-ca55@d0000000 {
|
|
+ no-map;
|
|
+ reg = <0 0xd0000000 0x0 0x1000000>;
|
|
+ };
|
|
+
|
|
+ /* Reserve 16MB for FreeRTOS on M33 */
|
|
+ m33_reserved: m33@a5000000 {
|
|
+ no-map;
|
|
+ reg = <0 0xa5000000 0 0x1000000>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&lpuart2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&clk {
|
|
+ init-on-array = <IMX93_CLK_LPUART2_GATE>;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-uart-sharing-cm33.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-uart-sharing-cm33.dts
|
|
new file mode 100644
|
|
index 000000000000..e55552658d09
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-uart-sharing-cm33.dts
|
|
@@ -0,0 +1,96 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include <dt-bindings/rpmsg/imx_srtm.h>
|
|
+#include "imx93-11x11-evk.dts"
|
|
+
|
|
+/ {
|
|
+ uart_rpbus_0: uart-rpbus-0 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_1: uart-rpbus-1 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_2: uart-rpbus-2 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_3: uart-rpbus-3 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_4: uart-rpbus-4 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_5: uart-rpbus-5 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_6: uart-rpbus-6 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_7: uart-rpbus-7 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_8: uart-rpbus-8 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_9: uart-rpbus-9 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_10: uart-rpbus-10 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ status = "okay"; /* mcore directly print data that receive from acore */
|
|
+ };
|
|
+};
|
|
+
|
|
+/*
|
|
+ * ATTENTION: M33 may use IPs like below
|
|
+ * LPUART5
|
|
+ */
|
|
+
|
|
+/* the lpuart5 is used by m33 to support srtm uart service */
|
|
+&lpuart5 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-virtio-net-ca55.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-virtio-net-ca55.dts
|
|
new file mode 100644
|
|
index 000000000000..0783e2e025ca
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-virtio-net-ca55.dts
|
|
@@ -0,0 +1,56 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx93-11x11-evk.dts"
|
|
+#include "imx93-generic-mbox.dtsi"
|
|
+#include "imx93-rproc-ca55.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ virtio_reserved: virtio@fc700000 {
|
|
+ no-map;
|
|
+ reg = <0 0xfc700000 0x0 0x00100000>;
|
|
+ };
|
|
+
|
|
+ /* 512MB */
|
|
+ rtos_ca55_reserved: rtos-ca55@d0000000 {
|
|
+ no-map;
|
|
+ reg = <0 0xd0000000 0x0 0x20000000>;
|
|
+ };
|
|
+
|
|
+ virtio_buffer: virtio-buffer@f8700000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xf8700000 0 0x4000000>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ virtio_net@fc700000 {
|
|
+ compatible = "virtio,mmio";
|
|
+ reg = <0x0 0xfc700000 0x0 0x1000>;
|
|
+ dma-coherent;
|
|
+ hypervisor_less;
|
|
+ memory-region = <&virtio_buffer>;
|
|
+ mbox-names = "mmiowr", "mmioirq";
|
|
+ mboxes = <&gen_sw_mbox 0 1 1 /* TX channel with ACK */
|
|
+ &gen_sw_mbox 1 1 0>; /* RX channel without ACK */
|
|
+ };
|
|
+};
|
|
+
|
|
+&lpuart2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&clk {
|
|
+ init-on-array = <IMX93_CLK_LPUART2_GATE>;
|
|
+};
|
|
+
|
|
+&fec {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk-virtio-net-cm33.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-virtio-net-cm33.dts
|
|
new file mode 100644
|
|
index 000000000000..52a650c3ec25
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk-virtio-net-cm33.dts
|
|
@@ -0,0 +1,58 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx93-11x11-evk.dts"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ cm33_reserved: cm33@a0000000 {
|
|
+ reg = <0 0xa0000000 0x0 0x01000000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ virtio_buffer: virtio-buffer@a1000000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xa1000000 0 0x3000000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ virtio_reserved: virtio@a8400000 {
|
|
+ reg = <0 0xa8400000 0x0 0x00100000>;
|
|
+ no-map;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ virtio_net@a8400000 {
|
|
+ compatible = "virtio,mmio";
|
|
+ reg = <0x0 0xa8400000 0x0 0x1000>;
|
|
+ hypervisor_less;
|
|
+ memory-region = <&virtio_buffer>;
|
|
+ mbox-names = "mmiowr", "mmioirq";
|
|
+ mboxes = <&mu1 0 2
|
|
+ &mu1 1 2>;
|
|
+ };
|
|
+};
|
|
+
|
|
+&clk {
|
|
+ init-on-array = <IMX93_CLK_LPUART2_GATE>;
|
|
+};
|
|
+
|
|
+&lpuart2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&fec {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&cm33 {
|
|
+ memory-region = <&cm33_reserved>;
|
|
+ status = "okay";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts
|
|
index 4d1aa281f33e..1d022b134f38 100644
|
|
--- a/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-11x11-evk.dts
|
|
@@ -324,7 +324,7 @@ &xcvr {
|
|
assigned-clock-rates = <12288000>, <200000000>;
|
|
status = "okay";
|
|
};
|
|
-
|
|
+
|
|
&adc1 {
|
|
vref-supply = <®_vref_1v8>;
|
|
status = "okay";
|
|
@@ -381,6 +381,9 @@ &eqos {
|
|
pinctrl-1 = <&pinctrl_eqos_sleep>;
|
|
phy-mode = "rgmii-id";
|
|
phy-handle = <ðphy1>;
|
|
+ snps,force_thresh_dma_mode;
|
|
+ snps,mtl-tx-config = <&mtl_tx_setup>;
|
|
+ snps,mtl-rx-config = <&mtl_rx_setup>;
|
|
status = "okay";
|
|
|
|
mdio {
|
|
@@ -397,6 +400,61 @@ ethphy1: ethernet-phy@1 {
|
|
realtek,clkout-disable;
|
|
};
|
|
};
|
|
+
|
|
+ mtl_tx_setup: tx-queues-config {
|
|
+ snps,tx-queues-to-use = <5>;
|
|
+ snps,tx-sched-sp;
|
|
+ queue0 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x1>;
|
|
+ };
|
|
+ queue1 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x2>;
|
|
+ };
|
|
+ queue2 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x4>;
|
|
+ };
|
|
+ queue3 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x8>;
|
|
+ };
|
|
+ queue4 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0xf0>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ mtl_rx_setup: rx-queues-config {
|
|
+ snps,rx-queues-to-use = <5>;
|
|
+ snps,rx-sched-sp;
|
|
+ queue0 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x1>;
|
|
+ snps,map-to-dma-channel = <0>;
|
|
+ };
|
|
+ queue1 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x2>;
|
|
+ snps,map-to-dma-channel = <1>;
|
|
+ };
|
|
+ queue2 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x4>;
|
|
+ snps,map-to-dma-channel = <2>;
|
|
+ };
|
|
+ queue3 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x8>;
|
|
+ snps,map-to-dma-channel = <3>;
|
|
+ };
|
|
+ queue4 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0xf0>;
|
|
+ snps,map-to-dma-channel = <4>;
|
|
+ };
|
|
+ };
|
|
};
|
|
|
|
&fec {
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-14x14-evk-aud-hat-avb.dts b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-aud-hat-avb.dts
|
|
new file mode 100644
|
|
index 000000000000..332495ce5320
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-aud-hat-avb.dts
|
|
@@ -0,0 +1,9 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx93-14x14-evk-aud-hat.dts"
|
|
+#include "imx93-evk-avb.dtsi"
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-14x14-evk-aud-hat.dts b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-aud-hat.dts
|
|
index 8c4ede5931db..470641838b78 100644
|
|
--- a/arch/arm64/boot/dts/freescale/imx93-14x14-evk-aud-hat.dts
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-aud-hat.dts
|
|
@@ -209,7 +209,7 @@ cs42448: audio-codec@48 {
|
|
VA-supply = <®_audio_pwr>;
|
|
VD-supply = <®_audio_pwr>;
|
|
VLS-supply = <®_audio_pwr>;
|
|
- VLC-supply = <®_audio_pwr>;
|
|
+ VLC-supply = <®_exp_sel>;
|
|
reset-gpio = <&gpio2 25 GPIO_ACTIVE_LOW>;
|
|
status = "okay";
|
|
};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-14x14-evk-imxai2eth-ath.dts b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-imxai2eth-ath.dts
|
|
new file mode 100644
|
|
index 000000000000..84a9a16a06e3
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-imxai2eth-ath.dts
|
|
@@ -0,0 +1,126 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx93-14x14-evk.dts"
|
|
+
|
|
+&lpi2c2 {
|
|
+ max7322: gpio@68 {
|
|
+ compatible = "maxim,max7322";
|
|
+ reg = <0x68>;
|
|
+ gpio-controller;
|
|
+ #gpio-cells = <2>;
|
|
+ reset-gpios = <&pcal6524 15 GPIO_ACTIVE_LOW>;
|
|
+ };
|
|
+};
|
|
+
|
|
+&eqos {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&pinctrl_eqos_rgmii>;
|
|
+ phy-mode = "rgmii-id";
|
|
+ phy-handle = <&eqosphy>;
|
|
+ pinctrl-assert-gpios = <&max7322 0 GPIO_ACTIVE_HIGH>;
|
|
+ snps,force_thresh_dma_mode;
|
|
+ snps,mtl-tx-config = <&mtl_tx_setup>;
|
|
+ snps,mtl-rx-config = <&mtl_rx_setup>;
|
|
+
|
|
+ snps,clk-csr = <5>;
|
|
+ status = "okay";
|
|
+
|
|
+ mdio {
|
|
+ compatible = "snps,dwmac-mdio";
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+ clock-frequency = <2500000>;
|
|
+
|
|
+ eqosphy: ethernet-phy@1 {
|
|
+ compatible = "ethernet-phy-ieee802.3-c22";
|
|
+ reg = <1>;
|
|
+ qca,disable-smarteee;
|
|
+
|
|
+ vddio-supply = <&vddio1>;
|
|
+
|
|
+ vddio1: vddio-regulator {
|
|
+ regulator-min-microvolt = <1800000>;
|
|
+ regulator-max-microvolt = <1800000>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+
|
|
+ mtl_tx_setup: tx-queues-config {
|
|
+ snps,tx-queues-to-use = <5>;
|
|
+ snps,tx-sched-sp;
|
|
+ queue0 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x1>;
|
|
+ };
|
|
+ queue1 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x2>;
|
|
+ };
|
|
+ queue2 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x4>;
|
|
+ };
|
|
+ queue3 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x8>;
|
|
+ };
|
|
+ queue4 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0xf0>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ mtl_rx_setup: rx-queues-config {
|
|
+ snps,rx-queues-to-use = <5>;
|
|
+ snps,rx-sched-sp;
|
|
+ queue0 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x1>;
|
|
+ snps,map-to-dma-channel = <0>;
|
|
+ };
|
|
+ queue1 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x2>;
|
|
+ snps,map-to-dma-channel = <1>;
|
|
+ };
|
|
+ queue2 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x4>;
|
|
+ snps,map-to-dma-channel = <2>;
|
|
+ };
|
|
+ queue3 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x8>;
|
|
+ snps,map-to-dma-channel = <3>;
|
|
+ };
|
|
+ queue4 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0xf0>;
|
|
+ snps,map-to-dma-channel = <4>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&iomuxc {
|
|
+ pinctrl_eqos_rgmii: eqosrgmiigrp {
|
|
+ fsl,pins = <
|
|
+ MX93_PAD_ENET1_MDC__ENET_QOS_MDC 0x57e
|
|
+ MX93_PAD_ENET1_MDIO__ENET_QOS_MDIO 0x57e
|
|
+ MX93_PAD_ENET1_RD0__ENET_QOS_RGMII_RD0 0x57e
|
|
+ MX93_PAD_ENET1_RD1__ENET_QOS_RGMII_RD1 0x57e
|
|
+ MX93_PAD_ENET1_RD2__ENET_QOS_RGMII_RD2 0x57e
|
|
+ MX93_PAD_ENET1_RD3__ENET_QOS_RGMII_RD3 0x57e
|
|
+ MX93_PAD_ENET1_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK 0x57e
|
|
+ MX93_PAD_ENET1_RX_CTL__ENET_QOS_RGMII_RX_CTL 0x57e
|
|
+ MX93_PAD_ENET1_TD0__ENET_QOS_RGMII_TD0 0x57e
|
|
+ MX93_PAD_ENET1_TD1__ENET_QOS_RGMII_TD1 0x57e
|
|
+ MX93_PAD_ENET1_TD2__ENET_QOS_RGMII_TD2 0x57e
|
|
+ MX93_PAD_ENET1_TD3__ENET_QOS_RGMII_TD3 0x57e
|
|
+ MX93_PAD_ENET1_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK 0x57e
|
|
+ MX93_PAD_ENET1_TX_CTL__ENET_QOS_RGMII_TX_CTL 0x57e
|
|
+ >;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-14x14-evk-mqs.dts b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-mqs.dts
|
|
index e3920484ae87..50e5b35b2c75 100644
|
|
--- a/arch/arm64/boot/dts/freescale/imx93-14x14-evk-mqs.dts
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-mqs.dts
|
|
@@ -1,73 +1,7 @@
|
|
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
- * Copyright 2023 NXP
|
|
+ * Copyright 2023-2024 NXP
|
|
*/
|
|
|
|
#include "imx93-14x14-evk.dts"
|
|
-
|
|
-/ {
|
|
- reg_mqs_switch: regulator-mqs-switch {
|
|
- compatible = "regulator-fixed";
|
|
- regulator-name = "mqs-switch";
|
|
- regulator-min-microvolt = <3300000>;
|
|
- regulator-max-microvolt = <3300000>;
|
|
- gpio = <&pcal6524_2 2 GPIO_ACTIVE_HIGH>;
|
|
- enable-active-high;
|
|
- regulator-always-on;
|
|
- };
|
|
-
|
|
- reg_mqs_amp_en: regulator-mqs-amp-en {
|
|
- compatible = "regulator-fixed";
|
|
- regulator-name = "mqs-amp-en";
|
|
- regulator-min-microvolt = <3300000>;
|
|
- regulator-max-microvolt = <3300000>;
|
|
- gpio = <&pcal6524_2 1 GPIO_ACTIVE_HIGH>;
|
|
- enable-active-high;
|
|
- regulator-always-on;
|
|
- };
|
|
-
|
|
- sound-mqs {
|
|
- compatible = "fsl,imx6sx-sdb-mqs",
|
|
- "fsl,imx-audio-mqs";
|
|
- model = "mqs-audio";
|
|
- audio-cpu = <&sai1>;
|
|
- audio-codec = <&mqs1>;
|
|
- };
|
|
-
|
|
- sound-bt-sco {
|
|
- status = "disabled";
|
|
- };
|
|
-};
|
|
-
|
|
-&flexcan1 {
|
|
- status = "disabled";
|
|
-};
|
|
-
|
|
-&sai1 {
|
|
- #sound-dai-cells = <0>;
|
|
- clocks = <&clk IMX93_CLK_SAI1_IPG>, <&clk IMX93_CLK_DUMMY>,
|
|
- <&clk IMX93_CLK_SAI1_GATE>, <&clk IMX93_CLK_DUMMY>,
|
|
- <&clk IMX93_CLK_DUMMY>, <&clk IMX93_CLK_AUDIO_PLL>;
|
|
- clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3", "pll8k";
|
|
- assigned-clocks = <&clk IMX93_CLK_SAI1>;
|
|
- assigned-clock-parents = <&clk IMX93_CLK_AUDIO_PLL>;
|
|
- assigned-clock-rates = <24576000>;
|
|
- status = "okay";
|
|
-};
|
|
-
|
|
-&mqs1 {
|
|
- pinctrl-names = "default";
|
|
- pinctrl-0 = <&pinctrl_mqs1>;
|
|
- clocks = <&clk IMX93_CLK_MQS1_GATE>;
|
|
- clock-names = "mclk";
|
|
- status = "okay";
|
|
-};
|
|
-
|
|
-&iomuxc {
|
|
- pinctrl_mqs1: mqs1grp {
|
|
- fsl,pins = <
|
|
- MX93_PAD_PDM_CLK__MQS1_LEFT 0x31e
|
|
- MX93_PAD_PDM_BIT_STREAM0__MQS1_RIGHT 0x31e
|
|
- >;
|
|
- };
|
|
-};
|
|
+#include "imx93-14x14-evk-mqs.dtsi"
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-14x14-evk-mqs.dtsi b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-mqs.dtsi
|
|
new file mode 100644
|
|
index 000000000000..4cb9a3280128
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-mqs.dtsi
|
|
@@ -0,0 +1,71 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+/ {
|
|
+ reg_mqs_switch: regulator-mqs-switch {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "mqs-switch";
|
|
+ regulator-min-microvolt = <3300000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
+ gpio = <&pcal6524_2 2 GPIO_ACTIVE_HIGH>;
|
|
+ enable-active-high;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ reg_mqs_amp_en: regulator-mqs-amp-en {
|
|
+ compatible = "regulator-fixed";
|
|
+ regulator-name = "mqs-amp-en";
|
|
+ regulator-min-microvolt = <3300000>;
|
|
+ regulator-max-microvolt = <3300000>;
|
|
+ gpio = <&pcal6524_2 1 GPIO_ACTIVE_HIGH>;
|
|
+ enable-active-high;
|
|
+ regulator-always-on;
|
|
+ };
|
|
+
|
|
+ sound-mqs {
|
|
+ compatible = "fsl,imx6sx-sdb-mqs",
|
|
+ "fsl,imx-audio-mqs";
|
|
+ model = "mqs-audio";
|
|
+ audio-cpu = <&sai1>;
|
|
+ audio-codec = <&mqs1>;
|
|
+ };
|
|
+
|
|
+ sound-bt-sco {
|
|
+ status = "disabled";
|
|
+ };
|
|
+};
|
|
+
|
|
+&flexcan1 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&sai1 {
|
|
+ #sound-dai-cells = <0>;
|
|
+ clocks = <&clk IMX93_CLK_SAI1_IPG>, <&clk IMX93_CLK_DUMMY>,
|
|
+ <&clk IMX93_CLK_SAI1_GATE>, <&clk IMX93_CLK_DUMMY>,
|
|
+ <&clk IMX93_CLK_DUMMY>, <&clk IMX93_CLK_AUDIO_PLL>;
|
|
+ clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3", "pll8k";
|
|
+ assigned-clocks = <&clk IMX93_CLK_SAI1>;
|
|
+ assigned-clock-parents = <&clk IMX93_CLK_AUDIO_PLL>;
|
|
+ assigned-clock-rates = <24576000>;
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&mqs1 {
|
|
+ pinctrl-names = "default";
|
|
+ pinctrl-0 = <&pinctrl_mqs1>;
|
|
+ clocks = <&clk IMX93_CLK_MQS1_GATE>;
|
|
+ clock-names = "mclk";
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&iomuxc {
|
|
+ pinctrl_mqs1: mqs1grp {
|
|
+ fsl,pins = <
|
|
+ MX93_PAD_PDM_CLK__MQS1_LEFT 0x31e
|
|
+ MX93_PAD_PDM_BIT_STREAM0__MQS1_RIGHT 0x31e
|
|
+ >;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-14x14-evk-multicore-rpmsg.dts b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-multicore-rpmsg.dts
|
|
new file mode 100644
|
|
index 000000000000..d6d07c82a766
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-multicore-rpmsg.dts
|
|
@@ -0,0 +1,47 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2025 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx93-14x14-evk-multicore-rtos.dts"
|
|
+#include "imx93-generic-mbox.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ vdev0vring0_ca55: vdev0vring0@fe100000 {
|
|
+ reg = <0 0xfe100000 0 0x8000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdev0vring1_ca55: vdev0vring1@fe108000 {
|
|
+ reg = <0 0xfe108000 0 0x8000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ rsc_table_ca55: rsc-table@fe1f0000 {
|
|
+ reg = <0 0xfe1f0000 0 0x1000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdev0buffer_ca55: vdev0buffer@fe200000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xfe200000 0 0x100000>;
|
|
+ no-map;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&ca55_1 {
|
|
+ memory-region = <&vdev0buffer_ca55>, <&vdev0vring0_ca55>, <&vdev0vring1_ca55>, <&rsc_table_ca55>, <&rtos_ca55_reserved>;
|
|
+ dma-coherent;
|
|
+ mbox-names = "tx", "rx", "rxdb";
|
|
+ mboxes = <&gen_sw_mbox 0 0 1 /* Tx channel with ACK */
|
|
+ &gen_sw_mbox 1 0 0 /* Rx channel without ACK */
|
|
+ &gen_sw_mbox 2 0 1>; /* RXDB channel with ACK */
|
|
+ fsl,startup-delay-ms = <50>;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-14x14-evk-multicore-rtos.dts b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-multicore-rtos.dts
|
|
new file mode 100644
|
|
index 000000000000..7bed244c703c
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-multicore-rtos.dts
|
|
@@ -0,0 +1,39 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx93-14x14-evk.dts"
|
|
+#include "imx93-rproc-ca55.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ /*
|
|
+ * Reserve up to 16MB for one possible FreeRTOS instances running on
|
|
+ * one Cortex-A Cores when booting Linux on at least on Cortex-A Core.
|
|
+ */
|
|
+ rtos_ca55_reserved: rtos-ca55@d0000000 {
|
|
+ no-map;
|
|
+ reg = <0 0xd0000000 0x0 0x1000000>;
|
|
+ };
|
|
+
|
|
+ /* Reserve 16MB for FreeRTOS on M33 */
|
|
+ m33_reserved: m33@a5000000 {
|
|
+ no-map;
|
|
+ reg = <0 0xa5000000 0 0x1000000>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&lpuart2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&clk {
|
|
+ init-on-array = <IMX93_CLK_LPUART2_GATE>;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-14x14-evk-sja1105-avb.dts b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-sja1105-avb.dts
|
|
new file mode 100644
|
|
index 000000000000..693684a10a23
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-sja1105-avb.dts
|
|
@@ -0,0 +1,8 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx93-14x14-evk-sja1105.dts"
|
|
+#include "imx93-14x14-evk-mqs.dtsi"
|
|
+#include "imx93-evk-avb.dtsi"
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-14x14-evk-sja1105.dts b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-sja1105.dts
|
|
index 24bd885cd2fd..9da91fe35d74 100644
|
|
--- a/arch/arm64/boot/dts/freescale/imx93-14x14-evk-sja1105.dts
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-sja1105.dts
|
|
@@ -29,7 +29,7 @@ &eqos {
|
|
phy-mode = "rgmii-rxid";
|
|
phy-handle = <&fixed0>;
|
|
pinctrl-assert-gpios = <&max7322 0 GPIO_ACTIVE_LOW>;
|
|
- snps,clk-csr = <6>;
|
|
+ snps,clk-csr = <5>;
|
|
status = "okay";
|
|
|
|
fixed0: fixed-link {
|
|
@@ -90,6 +90,7 @@ sja1105@0 {
|
|
spi-cpha;
|
|
clocks = <&clock_sja1105>;
|
|
pinctrl-assert-gpios = <&max7322 0 GPIO_ACTIVE_LOW>;
|
|
+ hostprio = <5>;
|
|
|
|
ports {
|
|
#address-cells = <1>;
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-14x14-evk-tja1103.dts b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-tja1103.dts
|
|
index 7e049848c4c7..91bb3eec6fe2 100644
|
|
--- a/arch/arm64/boot/dts/freescale/imx93-14x14-evk-tja1103.dts
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-tja1103.dts
|
|
@@ -1,6 +1,6 @@
|
|
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
- * Copyright 2023 NXP
|
|
+ * Copyright 2023-2024 NXP
|
|
*/
|
|
|
|
#include "imx93-14x14-evk.dts"
|
|
@@ -10,13 +10,17 @@ &eqos {
|
|
pinctrl-0 = <&pinctrl_eqos_rmii>;
|
|
phy-mode = "rmii";
|
|
phy-handle = <&eqosphy>;
|
|
+ snps,force_thresh_dma_mode;
|
|
+ snps,mtl-tx-config = <&mtl_tx_setup>;
|
|
+ snps,mtl-rx-config = <&mtl_rx_setup>;
|
|
|
|
assigned-clocks = <&clk IMX93_CLK_ENET_TIMER2>,
|
|
<&clk IMX93_CLK_ENET>;
|
|
assigned-clock-parents = <&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>,
|
|
<&clk IMX93_CLK_SYS_PLL_PFD1_DIV2>;
|
|
assigned-clock-rates = <100000000>, <50000000>;
|
|
- snps,clk-csr = <6>;
|
|
+
|
|
+ snps,clk-csr = <5>;
|
|
status = "okay";
|
|
|
|
mdio {
|
|
@@ -32,6 +36,61 @@ eqosphy: ethernet-phy@2 {
|
|
reg = <2>;
|
|
};
|
|
};
|
|
+
|
|
+ mtl_tx_setup: tx-queues-config {
|
|
+ snps,tx-queues-to-use = <5>;
|
|
+ snps,tx-sched-sp;
|
|
+ queue0 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x1>;
|
|
+ };
|
|
+ queue1 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x2>;
|
|
+ };
|
|
+ queue2 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x4>;
|
|
+ };
|
|
+ queue3 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x8>;
|
|
+ };
|
|
+ queue4 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0xf0>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ mtl_rx_setup: rx-queues-config {
|
|
+ snps,rx-queues-to-use = <5>;
|
|
+ snps,rx-sched-sp;
|
|
+ queue0 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x1>;
|
|
+ snps,map-to-dma-channel = <0>;
|
|
+ };
|
|
+ queue1 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x2>;
|
|
+ snps,map-to-dma-channel = <1>;
|
|
+ };
|
|
+ queue2 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x4>;
|
|
+ snps,map-to-dma-channel = <2>;
|
|
+ };
|
|
+ queue3 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x8>;
|
|
+ snps,map-to-dma-channel = <3>;
|
|
+ };
|
|
+ queue4 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0xf0>;
|
|
+ snps,map-to-dma-channel = <4>;
|
|
+ };
|
|
+ };
|
|
};
|
|
|
|
&iomuxc {
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-14x14-evk-uart-sharing-cm33.dts b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-uart-sharing-cm33.dts
|
|
new file mode 100644
|
|
index 000000000000..7ff128fcf2b9
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-uart-sharing-cm33.dts
|
|
@@ -0,0 +1,96 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include <dt-bindings/rpmsg/imx_srtm.h>
|
|
+#include "imx93-14x14-evk.dts"
|
|
+
|
|
+/ {
|
|
+ uart_rpbus_0: uart-rpbus-0 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_1: uart-rpbus-1 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_2: uart-rpbus-2 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_3: uart-rpbus-3 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_4: uart-rpbus-4 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_5: uart-rpbus-5 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_6: uart-rpbus-6 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_7: uart-rpbus-7 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_8: uart-rpbus-8 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_9: uart-rpbus-9 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_10: uart-rpbus-10 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ status = "okay"; /* mcore directly print data that receive from acore */
|
|
+ };
|
|
+};
|
|
+
|
|
+/*
|
|
+ * ATTENTION: M33 may use IPs like below
|
|
+ * LPUART5
|
|
+ */
|
|
+
|
|
+/* the lpuart5 is used by m33 to support srtm uart service */
|
|
+&lpuart5 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-14x14-evk-virtio-net-ca55.dts b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-virtio-net-ca55.dts
|
|
new file mode 100644
|
|
index 000000000000..2dca2b07a972
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-virtio-net-ca55.dts
|
|
@@ -0,0 +1,56 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx93-14x14-evk.dts"
|
|
+#include "imx93-generic-mbox.dtsi"
|
|
+#include "imx93-rproc-ca55.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ virtio_reserved: virtio@fc700000 {
|
|
+ no-map;
|
|
+ reg = <0 0xfc700000 0x0 0x00100000>;
|
|
+ };
|
|
+
|
|
+ /* 512MB */
|
|
+ rtos_ca55_reserved: rtos-ca55@d0000000 {
|
|
+ no-map;
|
|
+ reg = <0 0xd0000000 0x0 0x20000000>;
|
|
+ };
|
|
+
|
|
+ virtio_buffer: virtio-buffer@f8700000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xf8700000 0 0x4000000>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ virtio_net@fc700000 {
|
|
+ compatible = "virtio,mmio";
|
|
+ reg = <0x0 0xfc700000 0x0 0x1000>;
|
|
+ dma-coherent;
|
|
+ hypervisor_less;
|
|
+ memory-region = <&virtio_buffer>;
|
|
+ mbox-names = "mmiowr", "mmioirq";
|
|
+ mboxes = <&gen_sw_mbox 0 1 1 /* TX channel with ACK */
|
|
+ &gen_sw_mbox 1 1 0>; /* RX channel without ACK */
|
|
+ };
|
|
+};
|
|
+
|
|
+&lpuart2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&clk {
|
|
+ init-on-array = <IMX93_CLK_LPUART2_GATE>;
|
|
+};
|
|
+
|
|
+&fec {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-14x14-evk-virtio-net-cm33.dts b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-virtio-net-cm33.dts
|
|
new file mode 100644
|
|
index 000000000000..8d699f7c8389
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-14x14-evk-virtio-net-cm33.dts
|
|
@@ -0,0 +1,58 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx93-14x14-evk.dts"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ cm33_reserved: cm33@a0000000 {
|
|
+ reg = <0 0xa0000000 0x0 0x01000000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ virtio_buffer: virtio-buffer@a1000000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xa1000000 0 0x3000000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ virtio_reserved: virtio@a8400000 {
|
|
+ reg = <0 0xa8400000 0x0 0x00100000>;
|
|
+ no-map;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ virtio_net@a8400000 {
|
|
+ compatible = "virtio,mmio";
|
|
+ reg = <0x0 0xa8400000 0x0 0x1000>;
|
|
+ hypervisor_less;
|
|
+ memory-region = <&virtio_buffer>;
|
|
+ mbox-names = "mmiowr", "mmioirq";
|
|
+ mboxes = <&mu1 0 2
|
|
+ &mu1 1 2>;
|
|
+ };
|
|
+};
|
|
+
|
|
+&clk {
|
|
+ init-on-array = <IMX93_CLK_LPUART2_GATE>;
|
|
+};
|
|
+
|
|
+&lpuart2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&fec {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&cm33 {
|
|
+ memory-region = <&cm33_reserved>;
|
|
+ status = "okay";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-baremetal.dts b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-baremetal.dts
|
|
new file mode 100644
|
|
index 000000000000..8b4cbd366ae6
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-baremetal.dts
|
|
@@ -0,0 +1,31 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx93-9x9-qsb.dts"
|
|
+
|
|
+/ {
|
|
+ model = "NXP i.MX93 9X9 QSB board - Baremetal";
|
|
+
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ bm_reserved: baremetal@b0000000 {
|
|
+ no-map;
|
|
+ reg = <0 0xb0000000 0 0x10000000>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&fec {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&lpuart2 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-inmate.dts b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-inmate.dts
|
|
new file mode 100644
|
|
index 000000000000..cd1f0e0cc401
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-inmate.dts
|
|
@@ -0,0 +1,151 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include <dt-bindings/interrupt-controller/arm-gic.h>
|
|
+
|
|
+/ {
|
|
+ model = "NXP i.MX93 9x9 QSB";
|
|
+ compatible = "fsl,imx93-9x9-qsb", "fsl,imx93";
|
|
+ interrupt-parent = <&gic>;
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+
|
|
+ aliases {
|
|
+ mmc0 = &usdhc1;
|
|
+ serial1 = &lpuart2;
|
|
+ };
|
|
+
|
|
+ cpus {
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ A55_0: cpu@0 {
|
|
+ device_type = "cpu";
|
|
+ compatible = "arm,cortex-a55";
|
|
+ reg = <0x0>;
|
|
+ enable-method = "psci";
|
|
+ #cooling-cells = <2>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ psci {
|
|
+ compatible = "arm,psci-1.0";
|
|
+ method = "smc";
|
|
+ };
|
|
+
|
|
+ gic: interrupt-controller@48000000 {
|
|
+ compatible = "arm,gic-v3";
|
|
+ reg = <0 0x48000000 0 0x10000>,
|
|
+ <0 0x48040000 0 0xc0000>;
|
|
+ #interrupt-cells = <3>;
|
|
+ interrupt-controller;
|
|
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-parent = <&gic>;
|
|
+ };
|
|
+
|
|
+ timer {
|
|
+ compatible = "arm,armv8-timer";
|
|
+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
|
|
+ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
|
|
+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
|
|
+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>;
|
|
+ clock-frequency = <24000000>;
|
|
+ };
|
|
+
|
|
+ clk_dummy: clock-dummy {
|
|
+ compatible = "fixed-clock";
|
|
+ #clock-cells = <0>;
|
|
+ clock-frequency = <0>;
|
|
+ clock-output-names = "clk_dummy";
|
|
+ };
|
|
+
|
|
+ clk_400m: clock-400m {
|
|
+ compatible = "fixed-clock";
|
|
+ #clock-cells = <0>;
|
|
+ clock-frequency = <200000000>;
|
|
+ clock-output-names = "200m";
|
|
+ };
|
|
+
|
|
+ osc_24m: clock-osc-24m {
|
|
+ compatible = "fixed-clock";
|
|
+ #clock-cells = <0>;
|
|
+ clock-frequency = <24000000>;
|
|
+ clock-output-names = "osc_24m";
|
|
+ };
|
|
+
|
|
+ pci@fd700000 {
|
|
+ compatible = "pci-host-ecam-generic";
|
|
+ device_type = "pci";
|
|
+ bus-range = <0 0>;
|
|
+ #address-cells = <3>;
|
|
+ #size-cells = <2>;
|
|
+ #interrupt-cells = <1>;
|
|
+ interrupt-map-mask = <0 0 0 7>;
|
|
+ interrupt-map = <0 0 0 1 &gic GIC_SPI 227 IRQ_TYPE_EDGE_RISING>,
|
|
+ <0 0 0 2 &gic GIC_SPI 228 IRQ_TYPE_EDGE_RISING>,
|
|
+ <0 0 0 3 &gic GIC_SPI 229 IRQ_TYPE_EDGE_RISING>,
|
|
+ <0 0 0 4 &gic GIC_SPI 230 IRQ_TYPE_EDGE_RISING>;
|
|
+ reg = <0x0 0xfd700000 0x0 0x100000>;
|
|
+ ranges = <0x02000000 0x00 0x10000000 0x0 0x10000000 0x00 0x10000>;
|
|
+ };
|
|
+
|
|
+ soc@0 {
|
|
+ compatible = "simple-bus";
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <1>;
|
|
+ ranges = <0x0 0x0 0x0 0x80000000>,
|
|
+ <0x28000000 0x0 0x28000000 0x10000000>;
|
|
+
|
|
+ aips1: bus@44000000 {
|
|
+ compatible = "fsl,aips-bus", "simple-bus";
|
|
+ reg = <0x44000000 0x800000>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <1>;
|
|
+ ranges;
|
|
+
|
|
+ lpuart2: serial@44390000 {
|
|
+ compatible = "fsl,imx93-lpuart", "fsl,imx8ulp-lpuart", "fsl,imx7ulp-lpuart";
|
|
+ reg = <0x44390000 0x1000>;
|
|
+ interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+ };
|
|
+
|
|
+ aips3: bus@42800000 {
|
|
+ compatible = "fsl,aips-bus", "simple-bus";
|
|
+ reg = <0x42800000 0x800000>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <1>;
|
|
+ ranges;
|
|
+
|
|
+ usdhc1: mmc@42850000 {
|
|
+ compatible = "fsl,imx93-usdhc", "fsl,imx8mm-usdhc";
|
|
+ reg = <0x42850000 0x10000>;
|
|
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ fsl,tuning-start-tap = <20>;
|
|
+ fsl,tuning-step= <2>;
|
|
+ status = "disabled";
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&lpuart2 {
|
|
+ clocks = <&osc_24m>;
|
|
+ clock-names = "ipg";
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&usdhc1 {
|
|
+ clocks = <&clk_dummy>,
|
|
+ <&clk_dummy>,
|
|
+ <&clk_400m>;
|
|
+ clock-names = "ipg", "ahb", "per";
|
|
+ bus-width = <8>;
|
|
+ non-removable;
|
|
+ status = "okay";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-root.dts b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-root.dts
|
|
new file mode 100644
|
|
index 000000000000..e61f46be93b7
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-root.dts
|
|
@@ -0,0 +1,54 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx93-9x9-qsb.dts"
|
|
+
|
|
+/{
|
|
+ interrupt-parent = <&gic>;
|
|
+
|
|
+ resmem: reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+ };
|
|
+};
|
|
+
|
|
+&clk {
|
|
+ init-on-array = <IMX93_CLK_LPUART2_GATE
|
|
+ IMX93_CLK_USDHC1_GATE>;
|
|
+};
|
|
+
|
|
+&iomuxc {
|
|
+ pinctrl_uart2: uart2grp {
|
|
+ fsl,pins = <
|
|
+ MX93_PAD_UART2_TXD__LPUART2_TX 0x31e
|
|
+ MX93_PAD_UART2_RXD__LPUART2_RX 0x31e
|
|
+ >;
|
|
+ };
|
|
+};
|
|
+
|
|
+&lpuart2 {
|
|
+ /delete-property/ dmas;
|
|
+ /delete-property/ dma-names;
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&lpuart1 {
|
|
+ pinctrl-0 = <&pinctrl_uart1>, <&pinctrl_uart2>;
|
|
+ assigned-clocks = <&clk IMX93_CLK_LPUART2>;
|
|
+ assigned-clock-parents = <&clk IMX93_CLK_24M>;
|
|
+};
|
|
+
|
|
+&usdhc1 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&usdhc2 {
|
|
+ pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>, <&pinctrl_usdhc1>;
|
|
+ pinctrl-1 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>, <&pinctrl_usdhc1>;
|
|
+ pinctrl-2 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>, <&pinctrl_usdhc1>;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-uart-sharing-cm33.dts b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-uart-sharing-cm33.dts
|
|
new file mode 100644
|
|
index 000000000000..c897b9e9ced2
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb-uart-sharing-cm33.dts
|
|
@@ -0,0 +1,96 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include <dt-bindings/rpmsg/imx_srtm.h>
|
|
+#include "imx93-9x9-qsb.dts"
|
|
+
|
|
+/ {
|
|
+ uart_rpbus_0: uart-rpbus-0 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_1: uart-rpbus-1 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_2: uart-rpbus-2 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_3: uart-rpbus-3 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_4: uart-rpbus-4 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_5: uart-rpbus-5 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_6: uart-rpbus-6 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_7: uart-rpbus-7 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_8: uart-rpbus-8 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_9: uart-rpbus-9 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ bus_id = <5>; /* use lpuart5 */
|
|
+ flags=<IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG>;
|
|
+ status = "okay";
|
|
+ };
|
|
+
|
|
+ uart_rpbus_10: uart-rpbus-10 {
|
|
+ compatible = "fsl,uart-rpbus";
|
|
+ status = "okay"; /* mcore directly print data that receive from acore */
|
|
+ };
|
|
+};
|
|
+
|
|
+/*
|
|
+ * ATTENTION: M33 may use IPs like below
|
|
+ * LPUART5
|
|
+ */
|
|
+
|
|
+/* the lpuart5 is used by m33 to support srtm uart service */
|
|
+&lpuart5 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dts b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dts
|
|
index 7798271da63b..9534747b6a09 100644
|
|
--- a/arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dts
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-9x9-qsb.dts
|
|
@@ -224,6 +224,9 @@ &eqos {
|
|
pinctrl-0 = <&pinctrl_eqos>;
|
|
phy-mode = "rgmii-id";
|
|
phy-handle = <ðphy1>;
|
|
+ snps,force_thresh_dma_mode;
|
|
+ snps,mtl-tx-config = <&mtl_tx_setup>;
|
|
+ snps,mtl-rx-config = <&mtl_rx_setup>;
|
|
status = "okay";
|
|
|
|
mdio {
|
|
@@ -241,6 +244,61 @@ ethphy1: ethernet-phy@1 {
|
|
realtek,clkout-disable;
|
|
};
|
|
};
|
|
+
|
|
+ mtl_tx_setup: tx-queues-config {
|
|
+ snps,tx-queues-to-use = <5>;
|
|
+ snps,tx-sched-sp;
|
|
+ queue0 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x1>;
|
|
+ };
|
|
+ queue1 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x2>;
|
|
+ };
|
|
+ queue2 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x4>;
|
|
+ };
|
|
+ queue3 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x8>;
|
|
+ };
|
|
+ queue4 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0xf0>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ mtl_rx_setup: rx-queues-config {
|
|
+ snps,rx-queues-to-use = <5>;
|
|
+ snps,rx-sched-sp;
|
|
+ queue0 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x1>;
|
|
+ snps,map-to-dma-channel = <0>;
|
|
+ };
|
|
+ queue1 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x2>;
|
|
+ snps,map-to-dma-channel = <1>;
|
|
+ };
|
|
+ queue2 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x4>;
|
|
+ snps,map-to-dma-channel = <2>;
|
|
+ };
|
|
+ queue3 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0x8>;
|
|
+ snps,map-to-dma-channel = <3>;
|
|
+ };
|
|
+ queue4 {
|
|
+ snps,dcb-algorithm;
|
|
+ snps,priority = <0xf0>;
|
|
+ snps,map-to-dma-channel = <4>;
|
|
+ };
|
|
+ };
|
|
};
|
|
|
|
&lpm {
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-evk-avb.dtsi b/arch/arm64/boot/dts/freescale/imx93-evk-avb.dtsi
|
|
new file mode 100644
|
|
index 000000000000..76bcb8a7979e
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-evk-avb.dtsi
|
|
@@ -0,0 +1,37 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+/* AVB HW timer*/
|
|
+&tpm4 {
|
|
+ compatible = "fsl,avb-tpm";
|
|
+ timer-channel = <1>; /* Use output compare channel 1*/
|
|
+ prescale = <1>;
|
|
+ domain = <0>;
|
|
+ interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
|
|
+
|
|
+ clocks = <&clk IMX93_CLK_BUS_WAKEUP>, <&clk IMX93_CLK_TPM4_GATE>, <&clk IMX93_CLK_AUDIO_PLL>;
|
|
+ clock-names = "ipg", "per", "audio_pll";
|
|
+
|
|
+ /* Set TPM4 clock root to Audio PLL. */
|
|
+ assigned-clocks = <&clk IMX93_CLK_TPM4>;
|
|
+ assigned-clock-parents = <&clk IMX93_CLK_AUDIO_PLL>;
|
|
+ assigned-clock-rates = <49152000>;
|
|
+
|
|
+ /* Enble SW sampling for media clock recovery on port 0 */
|
|
+ sw-recovery = <0>;
|
|
+
|
|
+ status = "okay";
|
|
+};
|
|
+
|
|
+&fec {
|
|
+ fsl,rx-phy-delay-100-ns = <670>;
|
|
+ fsl,tx-phy-delay-100-ns = <670>;
|
|
+ fsl,rx-phy-delay-1000-ns = <0>;
|
|
+ fsl,tx-phy-delay-1000-ns = <0>;
|
|
+};
|
|
+
|
|
+ðphy2 {
|
|
+ eee-broken-100tx;
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-generic-mbox.dtsi b/arch/arm64/boot/dts/freescale/imx93-generic-mbox.dtsi
|
|
new file mode 100644
|
|
index 000000000000..5e6e1723a05d
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-generic-mbox.dtsi
|
|
@@ -0,0 +1,27 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ gen_sw_mbox_reserved: gen-sw-mbox@fe000000 {
|
|
+ reg = <0 0xfe000000 0 0x1000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ };
|
|
+
|
|
+ gen_sw_mbox: generic-software-mailbox@fe000000 {
|
|
+ compatible = "fsl,generic-software-mbox";
|
|
+ reg = <0 0xfe000000 0 0x1000>;
|
|
+ #mbox-cells = <3>;
|
|
+ /* Use 2 unused SPI interrupts */
|
|
+ interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "irq", "remote_irq";
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-rpmsg-ca55.dtsi b/arch/arm64/boot/dts/freescale/imx93-rpmsg-ca55.dtsi
|
|
new file mode 100644
|
|
index 000000000000..5db78b628c44
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-rpmsg-ca55.dtsi
|
|
@@ -0,0 +1,37 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#include "imx93-generic-mbox.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ rpmsg_ca55_reserved: rpmsg-ca55@fe100000 {
|
|
+ reg = <0 0xfe100000 0 0x10000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdevbuffer_ca55: vdevbuffer-ca55@fe200000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xfe200000 0 0x100000>;
|
|
+ no-map;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ rpmsg-ca55 {
|
|
+ compatible = "fsl,imx8mm-rpmsg";
|
|
+ reg = <0x0 0xfe100000 0x0 0x10000>; /* 64K for one rpmsg instance */
|
|
+ dma-coherent;
|
|
+ memory-region = <&vdevbuffer_ca55>;
|
|
+ mbox-names = "tx", "rx", "rxdb";
|
|
+ mboxes = <&gen_sw_mbox 0 0 1 /* Tx channel with ACK */
|
|
+ &gen_sw_mbox 1 0 0 /* Rx channel without ACK */
|
|
+ &gen_sw_mbox 2 0 1>; /* RXDB channel with ACK */
|
|
+ vdev-nums = <1>;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx93-rproc-ca55.dtsi b/arch/arm64/boot/dts/freescale/imx93-rproc-ca55.dtsi
|
|
new file mode 100644
|
|
index 000000000000..4cc9342cf9a4
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx93-rproc-ca55.dtsi
|
|
@@ -0,0 +1,14 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+/ {
|
|
+ ca55_1: remoteproc-ca55-1 {
|
|
+ compatible = "fsl,imx-rproc-psci";
|
|
+ /* bitmask:0b10, assign A55 Core 1 */
|
|
+ fsl,cpus-bits = <0x2>;
|
|
+ memory-region = <&rtos_ca55_reserved>;
|
|
+ };
|
|
+};
|
|
+
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx95-15x15-evk-harpoon-industrial.dts b/arch/arm64/boot/dts/freescale/imx95-15x15-evk-harpoon-industrial.dts
|
|
new file mode 100644
|
|
index 000000000000..e3a6ce1bbff4
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx95-15x15-evk-harpoon-industrial.dts
|
|
@@ -0,0 +1,25 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2025 NXP
|
|
+ */
|
|
+
|
|
+#include "imx95-15x15-evk-root.dts"
|
|
+#include "imx95-rpmsg-ca55.dtsi"
|
|
+
|
|
+&lpuart3 {
|
|
+ /* To use this, needs dedicated SM to allow RTOS access lpuart3 and lpuart3 pinmux */
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+/* This Message Unit is used for communication between the RTOS cell and the SM */
|
|
+&mu3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&flexcan2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+®_can2_stby {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx95-15x15-evk-harpoon.dts b/arch/arm64/boot/dts/freescale/imx95-15x15-evk-harpoon.dts
|
|
new file mode 100644
|
|
index 000000000000..8838cd44871c
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx95-15x15-evk-harpoon.dts
|
|
@@ -0,0 +1,19 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx95-15x15-evk-root.dts"
|
|
+#include "imx95-rpmsg-ca55.dtsi"
|
|
+
|
|
+&lpuart3 {
|
|
+ /* To use this, needs dedicated SM to allow RTOS access lpuart3 and lpuart3 pinmux */
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+/* This Message Unit is used for communication between the RTOS cell and the SM */
|
|
+&mu3 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx95-15x15-evk-multicore-rtos.dts b/arch/arm64/boot/dts/freescale/imx95-15x15-evk-multicore-rtos.dts
|
|
new file mode 100644
|
|
index 000000000000..359a54275e9c
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx95-15x15-evk-multicore-rtos.dts
|
|
@@ -0,0 +1,29 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2025 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx95-15x15-evk.dts"
|
|
+#include "imx95-rproc-ca55.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ /*
|
|
+ * Reserve up to 3 x 16MB for three possible FreeRTOS instances running on
|
|
+ * Cortex-A Cores when booting Linux.
|
|
+ */
|
|
+ rtos_ca55_reserved: rtos-ca55@d0000000 {
|
|
+ no-map;
|
|
+ reg = <0 0xd0000000 0x0 0x3000000>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&lpuart3 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx95-19x19-evk-harpoon-industrial.dts b/arch/arm64/boot/dts/freescale/imx95-19x19-evk-harpoon-industrial.dts
|
|
new file mode 100644
|
|
index 000000000000..59fde8aa0a65
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx95-19x19-evk-harpoon-industrial.dts
|
|
@@ -0,0 +1,29 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx95-19x19-evk-root.dts"
|
|
+#include "imx95-rpmsg-ca55.dtsi"
|
|
+
|
|
+&lpuart3 {
|
|
+ /* To use this, needs dedicated SM to allow RTOS access lpuart3 and lpuart3 pinmux */
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+/* This Message Unit is used for communication between the RTOS cell and the SM */
|
|
+&mu3 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+&flexcan2 {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+®_can2_en {
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+®_can2_stby {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx95-19x19-evk-harpoon.dts b/arch/arm64/boot/dts/freescale/imx95-19x19-evk-harpoon.dts
|
|
new file mode 100644
|
|
index 000000000000..8f0e6f8c38e1
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx95-19x19-evk-harpoon.dts
|
|
@@ -0,0 +1,19 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+
|
|
+#include "imx95-19x19-evk-root.dts"
|
|
+#include "imx95-rpmsg-ca55.dtsi"
|
|
+
|
|
+&lpuart3 {
|
|
+ /* To use this, needs dedicated SM to allow RTOS access lpuart3 and lpuart3 pinmux */
|
|
+ status = "disabled";
|
|
+};
|
|
+
|
|
+/* This Message Unit is used for communication between the RTOS cell and the SM */
|
|
+&mu3 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx95-19x19-evk-multicore-rtos.dts b/arch/arm64/boot/dts/freescale/imx95-19x19-evk-multicore-rtos.dts
|
|
new file mode 100644
|
|
index 000000000000..b28f9d22dbc2
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx95-19x19-evk-multicore-rtos.dts
|
|
@@ -0,0 +1,29 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+/dts-v1/;
|
|
+#include "imx95-19x19-evk.dts"
|
|
+#include "imx95-rproc-ca55.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ /*
|
|
+ * Reserve up to 3 x 16MB for three possible FreeRTOS instances running on
|
|
+ * Cortex-A Cores when booting Linux.
|
|
+ */
|
|
+ rtos_ca55_reserved: rtos-ca55@d0000000 {
|
|
+ no-map;
|
|
+ reg = <0 0xd0000000 0x0 0x3000000>;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+&lpuart3 {
|
|
+ status = "disabled";
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx95-generic-mbox.dtsi b/arch/arm64/boot/dts/freescale/imx95-generic-mbox.dtsi
|
|
new file mode 100644
|
|
index 000000000000..81fd2a34faaf
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx95-generic-mbox.dtsi
|
|
@@ -0,0 +1,27 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ gen_sw_mbox_reserved: gen-sw-mbox@c0000000 {
|
|
+ reg = <0 0xc0000000 0 0x1000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ };
|
|
+
|
|
+ gen_sw_mbox: generic-software-mailbox@c0000000 {
|
|
+ compatible = "fsl,generic-software-mbox";
|
|
+ reg = <0 0xc0000000 0 0x1000>;
|
|
+ #mbox-cells = <3>;
|
|
+ /* Use 2 unused SPI interrupts */
|
|
+ interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
|
|
+ interrupt-names = "irq", "remote_irq";
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx95-rpmsg-ca55.dtsi b/arch/arm64/boot/dts/freescale/imx95-rpmsg-ca55.dtsi
|
|
new file mode 100644
|
|
index 000000000000..fc72fab7b791
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx95-rpmsg-ca55.dtsi
|
|
@@ -0,0 +1,37 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#include "imx95-generic-mbox.dtsi"
|
|
+
|
|
+/ {
|
|
+ reserved-memory {
|
|
+ #address-cells = <2>;
|
|
+ #size-cells = <2>;
|
|
+ ranges;
|
|
+
|
|
+ rpmsg_ca55_reserved: rpmsg-ca55@c0100000 {
|
|
+ reg = <0 0xc0100000 0 0x10000>;
|
|
+ no-map;
|
|
+ };
|
|
+
|
|
+ vdevbuffer_ca55: vdevbuffer-ca55@c0200000 {
|
|
+ compatible = "shared-dma-pool";
|
|
+ reg = <0 0xc0200000 0 0x100000>;
|
|
+ no-map;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ rpmsg-ca55 {
|
|
+ compatible = "fsl,imx8mm-rpmsg";
|
|
+ reg = <0x0 0xc0100000 0x0 0x10000>; /* 64K for one rpmsg instance */
|
|
+ dma-coherent;
|
|
+ memory-region = <&vdevbuffer_ca55>;
|
|
+ mbox-names = "tx", "rx", "rxdb";
|
|
+ mboxes = <&gen_sw_mbox 0 0 1 /* Tx channel with ACK */
|
|
+ &gen_sw_mbox 1 0 0 /* Rx channel without ACK */
|
|
+ &gen_sw_mbox 2 0 1>; /* RXDB channel with ACK */
|
|
+ vdev-nums = <1>;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/boot/dts/freescale/imx95-rproc-ca55.dtsi b/arch/arm64/boot/dts/freescale/imx95-rproc-ca55.dtsi
|
|
new file mode 100644
|
|
index 000000000000..94c5d9db84ad
|
|
--- /dev/null
|
|
+++ b/arch/arm64/boot/dts/freescale/imx95-rproc-ca55.dtsi
|
|
@@ -0,0 +1,48 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+/ {
|
|
+ ca55_1: remoteproc-ca55-1 {
|
|
+ compatible = "fsl,imx-rproc-psci";
|
|
+ /* bitmask:0b000010, assign A55 Core 1 */
|
|
+ fsl,cpus-bits = <0x2>;
|
|
+ memory-region = <&rtos_ca55_reserved>;
|
|
+ };
|
|
+
|
|
+ ca55_2: remoteproc-ca55-2 {
|
|
+ compatible = "fsl,imx-rproc-psci";
|
|
+ /* bitmask:0b000100, assign A55 Core 2 */
|
|
+ fsl,cpus-bits = <0x4>;
|
|
+ memory-region = <&rtos_ca55_reserved>;
|
|
+ };
|
|
+
|
|
+ ca55_3: remoteproc-ca55-3 {
|
|
+ compatible = "fsl,imx-rproc-psci";
|
|
+ /* bitmask:0b001000, assign A55 Core 3 */
|
|
+ fsl,cpus-bits = <0x8>;
|
|
+ memory-region = <&rtos_ca55_reserved>;
|
|
+ };
|
|
+
|
|
+ ca55_4: remoteproc-ca55-4 {
|
|
+ compatible = "fsl,imx-rproc-psci";
|
|
+ /* bitmask:0b010000, assign A55 Core 4 */
|
|
+ fsl,cpus-bits = <0x10>;
|
|
+ memory-region = <&rtos_ca55_reserved>;
|
|
+ };
|
|
+
|
|
+ ca55_5: remoteproc-ca55-5 {
|
|
+ compatible = "fsl,imx-rproc-psci";
|
|
+ /* bitmask:0b100000, assign A55 Core 5 */
|
|
+ fsl,cpus-bits = <0x20>;
|
|
+ memory-region = <&rtos_ca55_reserved>;
|
|
+ };
|
|
+
|
|
+ ca55_4_5: remoteproc-ca55-4-5 {
|
|
+ compatible = "fsl,imx-rproc-psci";
|
|
+ /* bitmask:0b110000, assign A55 Core 4 and 5 */
|
|
+ fsl,cpus-bits = <0x30>;
|
|
+ memory-region = <&rtos_ca55_reserved>;
|
|
+ };
|
|
+};
|
|
diff --git a/arch/arm64/configs/imx_avb.config b/arch/arm64/configs/imx_avb.config
|
|
new file mode 100644
|
|
index 000000000000..1c8ba04c0381
|
|
--- /dev/null
|
|
+++ b/arch/arm64/configs/imx_avb.config
|
|
@@ -0,0 +1,8 @@
|
|
+CONFIG_EXPERT=y
|
|
+CONFIG_PREEMPT_RT=y
|
|
+CONFIG_AVB_SUPPORT=y
|
|
+CONFIG_NET_SWITCHDEV=y
|
|
+CONFIG_DEBUG_INFO=y
|
|
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
|
|
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
|
|
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
|
|
diff --git a/arch/arm64/configs/imx_v8_defconfig b/arch/arm64/configs/imx_v8_defconfig
|
|
index f076bf99e0cd..f083f63a6ac9 100644
|
|
--- a/arch/arm64/configs/imx_v8_defconfig
|
|
+++ b/arch/arm64/configs/imx_v8_defconfig
|
|
@@ -6,6 +6,8 @@ CONFIG_NO_HZ_IDLE=y
|
|
CONFIG_HIGH_RES_TIMERS=y
|
|
CONFIG_BPF_SYSCALL=y
|
|
CONFIG_BPF_JIT=y
|
|
+CONFIG_BPF_JIT_ALWAYS_ON=y
|
|
+CONFIG_XDP_SOCKETS=y
|
|
CONFIG_PREEMPT=y
|
|
CONFIG_IRQ_TIME_ACCOUNTING=y
|
|
CONFIG_BSD_PROCESS_ACCT=y
|
|
@@ -137,6 +139,10 @@ CONFIG_BRIDGE_NF_EBTABLES=m
|
|
CONFIG_BRIDGE=y
|
|
CONFIG_BRIDGE_VLAN_FILTERING=y
|
|
CONFIG_NET_DSA=m
|
|
+CONFIG_NET_DSA_SJA1105=m
|
|
+CONFIG_NET_DSA_SJA1105_PTP=y
|
|
+CONFIG_NET_DSA_SJA1105_TAS=y
|
|
+CONFIG_NET_DSA_SJA1105_VL=y
|
|
CONFIG_VLAN_8021Q_GVRP=y
|
|
CONFIG_VLAN_8021Q_MVRP=y
|
|
CONFIG_LLC2=y
|
|
@@ -152,17 +158,22 @@ CONFIG_NET_CLS_U32=y
|
|
CONFIG_NET_CLS_FLOWER=y
|
|
CONFIG_NET_CLS_ACT=y
|
|
CONFIG_NET_ACT_GACT=m
|
|
-CONFIG_NET_ACT_MIRRED=m
|
|
+CONFIG_NET_ACT_MIRRED=y
|
|
CONFIG_NET_ACT_SKBEDIT=y
|
|
+CONFIG_NET_ACT_FRER=y
|
|
CONFIG_NET_ACT_GATE=y
|
|
CONFIG_NET_ACT_POLICE=y
|
|
+CONFIG_NET_EMATCH=y
|
|
+CONFIG_NET_EMATCH_STACK=32
|
|
+CONFIG_NET_EMATCH_U32=y
|
|
+CONFIG_NET_EMATCH_META=y
|
|
CONFIG_TSN=y
|
|
CONFIG_VSOCKETS=y
|
|
CONFIG_VIRTIO_VSOCKETS=y
|
|
CONFIG_QRTR=m
|
|
CONFIG_QRTR_SMD=m
|
|
CONFIG_QRTR_TUN=m
|
|
-CONFIG_NET_PKTGEN=m
|
|
+CONFIG_NET_PKTGEN=y
|
|
CONFIG_CAN=m
|
|
CONFIG_BT=y
|
|
CONFIG_BT_RFCOMM=y
|
|
@@ -292,8 +303,10 @@ CONFIG_MACVLAN=m
|
|
CONFIG_MACVTAP=m
|
|
CONFIG_TUN=y
|
|
CONFIG_VETH=m
|
|
-CONFIG_VIRTIO_NET=y
|
|
+CONFIG_VIRTIO_NET=m
|
|
CONFIG_NET_DSA_MSCC_FELIX=m
|
|
+CONFIG_NET_DSA_NETC=m
|
|
+CONFIG_NET_DSA_NETC_PTP=y
|
|
CONFIG_NET_DSA_SJA1105=m
|
|
CONFIG_NET_DSA_SJA1105_PTP=y
|
|
CONFIG_NET_DSA_SJA1105_TAS=y
|
|
@@ -306,6 +319,7 @@ CONFIG_SYSTEMPORT=m
|
|
CONFIG_MACB=y
|
|
CONFIG_THUNDER_NIC_PF=y
|
|
CONFIG_FEC=y
|
|
+CONFIG_FEC_ECAT=y
|
|
CONFIG_FEC_UIO=y
|
|
CONFIG_FSL_FMAN=y
|
|
CONFIG_FSL_DPAA_ETH=y
|
|
@@ -931,7 +945,7 @@ CONFIG_VFIO_FSL_MC=y
|
|
CONFIG_VIRTIO_PCI=y
|
|
CONFIG_VIRTIO_BALLOON=y
|
|
CONFIG_VIRTIO_INPUT=y
|
|
-CONFIG_VIRTIO_MMIO=y
|
|
+CONFIG_VIRTIO_MMIO=m
|
|
CONFIG_VIRTIO_IVSHMEM=y
|
|
CONFIG_VHOST_VSOCK=y
|
|
CONFIG_XEN_GNTDEV=y
|
|
@@ -1205,3 +1219,11 @@ CONFIG_MEMTEST=y
|
|
CONFIG_VHOST_NET=m
|
|
CONFIG_IMX_ISPMU=m
|
|
CONFIG_IMX_ISP_REMOTEPROC=m
|
|
+
|
|
+# Preempt RT, depend on CONFIG_EXPERT
|
|
+CONFIG_EXPERT=y
|
|
+CONFIG_PREEMPT_RT=y
|
|
+
|
|
+CONFIG_RPMSG_TTY=m
|
|
+CONFIG_GENERIC_SOFTWARE_MAILBOX=y
|
|
+CONFIG_VIRTIO_TRANS=m
|
|
diff --git a/arch/arm64/configs/linux-dpaa-ethercat.config b/arch/arm64/configs/linux-dpaa-ethercat.config
|
|
new file mode 100644
|
|
index 000000000000..15e4b306bc3d
|
|
--- /dev/null
|
|
+++ b/arch/arm64/configs/linux-dpaa-ethercat.config
|
|
@@ -0,0 +1 @@
|
|
+CONFIG_FSL_DPAA_ETHERCAT=y
|
|
diff --git a/arch/arm64/configs/linux-rpmsg-8m-buf.config b/arch/arm64/configs/linux-rpmsg-8m-buf.config
|
|
new file mode 100644
|
|
index 000000000000..d7780b2b8299
|
|
--- /dev/null
|
|
+++ b/arch/arm64/configs/linux-rpmsg-8m-buf.config
|
|
@@ -0,0 +1 @@
|
|
+CONFIG_RPMSG_8M_BUF=y
|
|
diff --git a/arch/arm64/configs/lsdk.config b/arch/arm64/configs/lsdk.config
|
|
index d97ef5280ed2..f17f9aef7868 100644
|
|
--- a/arch/arm64/configs/lsdk.config
|
|
+++ b/arch/arm64/configs/lsdk.config
|
|
@@ -84,6 +84,10 @@ CONFIG_BRIDGE_NF_EBTABLES=y
|
|
CONFIG_BRIDGE_EBT_T_NAT=y
|
|
CONFIG_BRIDGE_EBT_DNAT=y
|
|
CONFIG_BRIDGE_EBT_SNAT=y
|
|
+CONFIG_BRIDGE_EBT_BROUTE=y
|
|
+CONFIG_BRIDGE_EBT_802_3=y
|
|
+CONFIG_BRIDGE_EBT_IP=y
|
|
+CONFIG_BRIDGE_EBT_IP6=y
|
|
CONFIG_NETFILTER_XT_MATCH_COMMENT=y
|
|
CONFIG_SFP=y
|
|
CONFIG_PHY_FSL_LYNX_10G=y
|
|
@@ -92,6 +96,15 @@ CONFIG_MTIP_BACKPLANE_PHY=y
|
|
CONFIG_BPF_SYSCALL=y
|
|
CONFIG_BPF_JIT_ALWAYS_ON=y
|
|
CONFIG_XDP_SOCKETS=y
|
|
+CONFIG_NET_SCH_INGRESS=y
|
|
+CONFIG_NET_ACT_POLICE=y
|
|
+CONFIG_NET_ACT_GACT=y
|
|
+CONFIG_NET_ACT_GATE=y
|
|
+CONFIG_NET_CLS_MATCHALL=y
|
|
+CONFIG_NET_PKTGEN=y
|
|
+
|
|
+# Enable felix switch TSN
|
|
+CONFIG_MSCC_FELIX_SWITCH_TSN=y
|
|
|
|
# GPU
|
|
CONFIG_DRM=y
|
|
@@ -99,7 +112,6 @@ CONFIG_MXC_GPU_VIV=y
|
|
|
|
# disable unneeded options and override default options set by defconfig to deduce the size of modules
|
|
# CONFIG_NET_VENDOR_STMICRO is not set
|
|
-# CONFIG_MEDIA_SUPPORT is not set
|
|
# CONFIG_BACKLIGHT_GENERIC is not set
|
|
# CONFIG_TEGRA_HOST1X is not set
|
|
# CONFIG_BT is not set
|
|
@@ -183,6 +195,7 @@ CONFIG_NET_CLS_FLOWER=y
|
|
CONFIG_NET_EMATCH=y
|
|
CONFIG_NET_EMATCH_STACK=32
|
|
CONFIG_NET_EMATCH_U32=y
|
|
+CONFIG_NET_EMATCH_META=y
|
|
CONFIG_NET_CLS_ACT=y
|
|
CONFIG_NET_ACT_PEDIT=y
|
|
CONFIG_NET_ACT_SKBEDIT=y
|
|
@@ -194,10 +207,18 @@ CONFIG_USB_RTL8152=y
|
|
CONFIG_USB_USBNET=y
|
|
CONFIG_USB_NET_AX8817X=y
|
|
CONFIG_USB_NET_AX88179_178A=y
|
|
-# CONFIG_NET_PKTGEN is not set
|
|
|
|
#build-in drivers
|
|
CONFIG_FSL_DPAA2_SWITCH=y
|
|
CONFIG_QORIQ_THERMAL=y
|
|
CONFIG_FSL_IFC=y
|
|
CONFIG_MTD_NAND_FSL_IFC=y
|
|
+
|
|
+# Preempt RT, depend on CONFIG_EXPERT
|
|
+CONFIG_PREEMPT_RT=y
|
|
+
|
|
+CONFIG_NFC_NXP_PN5XX=m
|
|
+
|
|
+# IVSHMEM
|
|
+CONFIG_IVSHMEM_NET=y
|
|
+CONFIG_UIO_IVSHMEM=y
|
|
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
|
|
index be87f2f7f77c..1ad60cee856f 100644
|
|
--- a/arch/arm64/kernel/smp.c
|
|
+++ b/arch/arm64/kernel/smp.c
|
|
@@ -53,6 +53,10 @@
|
|
|
|
#include <trace/events/ipi.h>
|
|
|
|
+#ifdef CONFIG_BAREMETAL
|
|
+#include <linux/ipi_baremetal.h>
|
|
+#endif
|
|
+
|
|
DEFINE_PER_CPU_READ_MOSTLY(int, cpu_number);
|
|
EXPORT_PER_CPU_SYMBOL(cpu_number);
|
|
|
|
@@ -73,6 +77,13 @@ enum ipi_msg_type {
|
|
IPI_TIMER,
|
|
IPI_IRQ_WORK,
|
|
IPI_WAKEUP,
|
|
+#ifdef CONFIG_BAREMETAL
|
|
+#if defined(CONFIG_IMX8M_BAREMETAL) || defined(CONFIG_IMX93_BAREMETAL)
|
|
+ IPI_BAREMETAL_COMM = 9,
|
|
+#else
|
|
+ IPI_BAREMETAL_COMM = 8,
|
|
+#endif
|
|
+#endif
|
|
NR_IPI
|
|
};
|
|
|
|
@@ -767,6 +778,9 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
|
|
[IPI_TIMER] = "Timer broadcast interrupts",
|
|
[IPI_IRQ_WORK] = "IRQ work interrupts",
|
|
[IPI_WAKEUP] = "CPU wake-up interrupts",
|
|
+#ifdef CONFIG_BAREMETAL
|
|
+ [IPI_BAREMETAL_COMM] = "Baremetal inter-core interrupts",
|
|
+#endif
|
|
};
|
|
|
|
static void smp_cross_call(const struct cpumask *target, unsigned int ipinr);
|
|
@@ -907,6 +921,17 @@ static void do_handle_IPI(int ipinr)
|
|
break;
|
|
#endif
|
|
|
|
+#ifdef CONFIG_BAREMETAL
|
|
+ case IPI_BAREMETAL_COMM: {
|
|
+ /* FIXME: use the fixed source coreID from core1 */
|
|
+ int irqsrc = 1;
|
|
+ /*linux core is 0 core, so iterate from 1 core.*/
|
|
+ for(irqsrc = 1; irqsrc < CONFIG_MAX_CPUS; irqsrc++)
|
|
+ ipi_baremetal_handle(ipinr, irqsrc);
|
|
+ }
|
|
+ break;
|
|
+#endif
|
|
+
|
|
default:
|
|
pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr);
|
|
break;
|
|
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
|
|
index 61fb49dca45b..3c61d0541c99 100644
|
|
--- a/arch/powerpc/Kconfig
|
|
+++ b/arch/powerpc/Kconfig
|
|
@@ -166,6 +166,7 @@ config PPC
|
|
select ARCH_STACKWALK
|
|
select ARCH_SUPPORTS_ATOMIC_RMW
|
|
select ARCH_SUPPORTS_DEBUG_PAGEALLOC if PPC_BOOK3S || PPC_8xx || 40x
|
|
+ select ARCH_SUPPORTS_RT if HAVE_POSIX_CPU_TIMERS_TASK_WORK
|
|
select ARCH_USE_BUILTIN_BSWAP
|
|
select ARCH_USE_CMPXCHG_LOCKREF if PPC64
|
|
select ARCH_USE_MEMTEST
|
|
@@ -268,6 +269,7 @@ config PPC
|
|
select HAVE_PERF_USER_STACK_DUMP
|
|
select HAVE_REGS_AND_STACK_ACCESS_API
|
|
select HAVE_RELIABLE_STACKTRACE
|
|
+ select HAVE_POSIX_CPU_TIMERS_TASK_WORK if !KVM
|
|
select HAVE_RSEQ
|
|
select HAVE_SETUP_PER_CPU_AREA if PPC64
|
|
select HAVE_SOFTIRQ_ON_OWN_STACK
|
|
diff --git a/arch/powerpc/include/asm/stackprotector.h b/arch/powerpc/include/asm/stackprotector.h
|
|
index 283c34647856..4727f40052dd 100644
|
|
--- a/arch/powerpc/include/asm/stackprotector.h
|
|
+++ b/arch/powerpc/include/asm/stackprotector.h
|
|
@@ -19,8 +19,13 @@
|
|
*/
|
|
static __always_inline void boot_init_stack_canary(void)
|
|
{
|
|
- unsigned long canary = get_random_canary();
|
|
+ unsigned long canary;
|
|
|
|
+#ifndef CONFIG_PREEMPT_RT
|
|
+ canary = get_random_canary();
|
|
+#else
|
|
+ canary = ((unsigned long)&canary) & CANARY_MASK;
|
|
+#endif
|
|
current->stack_canary = canary;
|
|
#ifdef CONFIG_PPC64
|
|
get_paca()->canary = canary;
|
|
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
|
|
index 2de7f6dcd32b..739f5b179a7f 100644
|
|
--- a/arch/powerpc/kernel/traps.c
|
|
+++ b/arch/powerpc/kernel/traps.c
|
|
@@ -261,12 +261,17 @@ static char *get_mmu_str(void)
|
|
|
|
static int __die(const char *str, struct pt_regs *regs, long err)
|
|
{
|
|
+ const char *pr = "";
|
|
+
|
|
printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
|
|
|
|
+ if (IS_ENABLED(CONFIG_PREEMPTION))
|
|
+ pr = IS_ENABLED(CONFIG_PREEMPT_RT) ? " PREEMPT_RT" : " PREEMPT";
|
|
+
|
|
printk("%s PAGE_SIZE=%luK%s%s%s%s%s%s %s\n",
|
|
IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN) ? "LE" : "BE",
|
|
PAGE_SIZE / 1024, get_mmu_str(),
|
|
- IS_ENABLED(CONFIG_PREEMPT) ? " PREEMPT" : "",
|
|
+ pr,
|
|
IS_ENABLED(CONFIG_SMP) ? " SMP" : "",
|
|
IS_ENABLED(CONFIG_SMP) ? (" NR_CPUS=" __stringify(NR_CPUS)) : "",
|
|
debug_pagealloc_enabled() ? " DEBUG_PAGEALLOC" : "",
|
|
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig
|
|
index 902611954200..2f188137f830 100644
|
|
--- a/arch/powerpc/kvm/Kconfig
|
|
+++ b/arch/powerpc/kvm/Kconfig
|
|
@@ -224,6 +224,7 @@ config KVM_E500MC
|
|
config KVM_MPIC
|
|
bool "KVM in-kernel MPIC emulation"
|
|
depends on KVM && PPC_E500
|
|
+ depends on !PREEMPT_RT
|
|
select HAVE_KVM_IRQCHIP
|
|
select HAVE_KVM_IRQFD
|
|
select HAVE_KVM_IRQ_ROUTING
|
|
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
|
|
index 4ebf2ef2845d..381c3be3bec1 100644
|
|
--- a/arch/powerpc/platforms/pseries/Kconfig
|
|
+++ b/arch/powerpc/platforms/pseries/Kconfig
|
|
@@ -2,6 +2,7 @@
|
|
config PPC_PSERIES
|
|
depends on PPC64 && PPC_BOOK3S
|
|
bool "IBM pSeries & new (POWER5-based) iSeries"
|
|
+ select GENERIC_ALLOCATOR
|
|
select HAVE_PCSPKR_PLATFORM
|
|
select MPIC
|
|
select OF_DYNAMIC
|
|
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
|
|
index b1e6d275cda9..9a8d3970da3c 100644
|
|
--- a/arch/powerpc/platforms/pseries/iommu.c
|
|
+++ b/arch/powerpc/platforms/pseries/iommu.c
|
|
@@ -25,6 +25,7 @@
|
|
#include <linux/of_address.h>
|
|
#include <linux/iommu.h>
|
|
#include <linux/rculist.h>
|
|
+#include <linux/local_lock.h>
|
|
#include <asm/io.h>
|
|
#include <asm/prom.h>
|
|
#include <asm/rtas.h>
|
|
@@ -206,7 +207,13 @@ static int tce_build_pSeriesLP(unsigned long liobn, long tcenum, long tceshift,
|
|
return ret;
|
|
}
|
|
|
|
-static DEFINE_PER_CPU(__be64 *, tce_page);
|
|
+struct tce_page {
|
|
+ __be64 * page;
|
|
+ local_lock_t lock;
|
|
+};
|
|
+static DEFINE_PER_CPU(struct tce_page, tce_page) = {
|
|
+ .lock = INIT_LOCAL_LOCK(lock),
|
|
+};
|
|
|
|
static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
|
|
long npages, unsigned long uaddr,
|
|
@@ -229,9 +236,10 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
|
|
direction, attrs);
|
|
}
|
|
|
|
- local_irq_save(flags); /* to protect tcep and the page behind it */
|
|
+ /* to protect tcep and the page behind it */
|
|
+ local_lock_irqsave(&tce_page.lock, flags);
|
|
|
|
- tcep = __this_cpu_read(tce_page);
|
|
+ tcep = __this_cpu_read(tce_page.page);
|
|
|
|
/* This is safe to do since interrupts are off when we're called
|
|
* from iommu_alloc{,_sg}()
|
|
@@ -240,12 +248,12 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
|
|
tcep = (__be64 *)__get_free_page(GFP_ATOMIC);
|
|
/* If allocation fails, fall back to the loop implementation */
|
|
if (!tcep) {
|
|
- local_irq_restore(flags);
|
|
+ local_unlock_irqrestore(&tce_page.lock, flags);
|
|
return tce_build_pSeriesLP(tbl->it_index, tcenum,
|
|
tceshift,
|
|
npages, uaddr, direction, attrs);
|
|
}
|
|
- __this_cpu_write(tce_page, tcep);
|
|
+ __this_cpu_write(tce_page.page, tcep);
|
|
}
|
|
|
|
rpn = __pa(uaddr) >> tceshift;
|
|
@@ -275,7 +283,7 @@ static int tce_buildmulti_pSeriesLP(struct iommu_table *tbl, long tcenum,
|
|
tcenum += limit;
|
|
} while (npages > 0 && !rc);
|
|
|
|
- local_irq_restore(flags);
|
|
+ local_unlock_irqrestore(&tce_page.lock, flags);
|
|
|
|
if (unlikely(rc == H_NOT_ENOUGH_RESOURCES)) {
|
|
ret = (int)rc;
|
|
@@ -459,16 +467,17 @@ static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn,
|
|
DMA_BIDIRECTIONAL, 0);
|
|
}
|
|
|
|
- local_irq_disable(); /* to protect tcep and the page behind it */
|
|
- tcep = __this_cpu_read(tce_page);
|
|
+ /* to protect tcep and the page behind it */
|
|
+ local_lock_irq(&tce_page.lock);
|
|
+ tcep = __this_cpu_read(tce_page.page);
|
|
|
|
if (!tcep) {
|
|
tcep = (__be64 *)__get_free_page(GFP_ATOMIC);
|
|
if (!tcep) {
|
|
- local_irq_enable();
|
|
+ local_unlock_irq(&tce_page.lock);
|
|
return -ENOMEM;
|
|
}
|
|
- __this_cpu_write(tce_page, tcep);
|
|
+ __this_cpu_write(tce_page.page, tcep);
|
|
}
|
|
|
|
proto_tce = TCE_PCI_READ | TCE_PCI_WRITE;
|
|
@@ -511,7 +520,7 @@ static int tce_setrange_multi_pSeriesLP(unsigned long start_pfn,
|
|
|
|
/* error cleanup: caller will clear whole range */
|
|
|
|
- local_irq_enable();
|
|
+ local_unlock_irq(&tce_page.lock);
|
|
return rc;
|
|
}
|
|
|
|
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
|
|
index fe30b24d52e1..2bdf6a7d0f8c 100644
|
|
--- a/arch/riscv/Kconfig
|
|
+++ b/arch/riscv/Kconfig
|
|
@@ -49,6 +49,7 @@ config RISCV
|
|
select ARCH_SUPPORTS_HUGETLBFS if MMU
|
|
select ARCH_SUPPORTS_PAGE_TABLE_CHECK if MMU
|
|
select ARCH_SUPPORTS_PER_VMA_LOCK if MMU
|
|
+ select ARCH_SUPPORTS_RT
|
|
select ARCH_USE_MEMTEST
|
|
select ARCH_USE_QUEUED_RWLOCKS
|
|
select ARCH_USES_CFI_TRAPS if CFI_CLANG
|
|
@@ -136,6 +137,7 @@ config RISCV
|
|
select HAVE_PERF_USER_STACK_DUMP
|
|
select HAVE_POSIX_CPU_TIMERS_TASK_WORK
|
|
select HAVE_PREEMPT_DYNAMIC_KEY if !XIP_KERNEL
|
|
+ select HAVE_PREEMPT_AUTO
|
|
select HAVE_REGS_AND_STACK_ACCESS_API
|
|
select HAVE_RETHOOK if !XIP_KERNEL
|
|
select HAVE_RSEQ
|
|
diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
|
|
index d0345bd659c9..23fed53b8815 100644
|
|
--- a/arch/riscv/include/asm/cpufeature.h
|
|
+++ b/arch/riscv/include/asm/cpufeature.h
|
|
@@ -30,6 +30,4 @@ DECLARE_PER_CPU(long, misaligned_access_speed);
|
|
/* Per-cpu ISA extensions. */
|
|
extern struct riscv_isainfo hart_isa[NR_CPUS];
|
|
|
|
-void check_unaligned_access(int cpu);
|
|
-
|
|
#endif
|
|
diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h
|
|
index d18ce0113ca1..e18710fe51f0 100644
|
|
--- a/arch/riscv/include/asm/thread_info.h
|
|
+++ b/arch/riscv/include/asm/thread_info.h
|
|
@@ -82,6 +82,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
|
|
* - pending work-to-be-done flags are in lowest half-word
|
|
* - other flags in upper half-word(s)
|
|
*/
|
|
+#define TIF_ARCH_RESCHED_LAZY 0 /* Lazy rescheduling */
|
|
#define TIF_NOTIFY_RESUME 1 /* callback before returning to user */
|
|
#define TIF_SIGPENDING 2 /* signal pending */
|
|
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
|
|
@@ -96,6 +97,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
|
|
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
|
|
#define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL)
|
|
#define _TIF_UPROBE (1 << TIF_UPROBE)
|
|
+#define _TIF_ARCH_RESCHED_LAZY (1 << TIF_ARCH_RESCHED_LAZY)
|
|
|
|
#define _TIF_WORK_MASK \
|
|
(_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NEED_RESCHED | \
|
|
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
|
|
index e39a905aca24..dd118773e717 100644
|
|
--- a/arch/riscv/kernel/cpufeature.c
|
|
+++ b/arch/riscv/kernel/cpufeature.c
|
|
@@ -8,6 +8,7 @@
|
|
|
|
#include <linux/acpi.h>
|
|
#include <linux/bitmap.h>
|
|
+#include <linux/cpuhotplug.h>
|
|
#include <linux/ctype.h>
|
|
#include <linux/log2.h>
|
|
#include <linux/memory.h>
|
|
@@ -30,6 +31,7 @@
|
|
|
|
#define MISALIGNED_ACCESS_JIFFIES_LG2 1
|
|
#define MISALIGNED_BUFFER_SIZE 0x4000
|
|
+#define MISALIGNED_BUFFER_ORDER get_order(MISALIGNED_BUFFER_SIZE)
|
|
#define MISALIGNED_COPY_SIZE ((MISALIGNED_BUFFER_SIZE / 2) - 0x80)
|
|
|
|
unsigned long elf_hwcap __read_mostly;
|
|
@@ -571,14 +573,15 @@ unsigned long riscv_get_elf_hwcap(void)
|
|
return hwcap;
|
|
}
|
|
|
|
-void check_unaligned_access(int cpu)
|
|
+static int check_unaligned_access(void *param)
|
|
{
|
|
+ int cpu = smp_processor_id();
|
|
u64 start_cycles, end_cycles;
|
|
u64 word_cycles;
|
|
u64 byte_cycles;
|
|
int ratio;
|
|
unsigned long start_jiffies, now;
|
|
- struct page *page;
|
|
+ struct page *page = param;
|
|
void *dst;
|
|
void *src;
|
|
long speed = RISCV_HWPROBE_MISALIGNED_SLOW;
|
|
@@ -587,12 +590,6 @@ void check_unaligned_access(int cpu)
|
|
if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_UNKNOWN)
|
|
return;
|
|
|
|
- page = alloc_pages(GFP_NOWAIT, get_order(MISALIGNED_BUFFER_SIZE));
|
|
- if (!page) {
|
|
- pr_warn("Can't alloc pages to measure memcpy performance");
|
|
- return;
|
|
- }
|
|
-
|
|
/* Make an unaligned destination buffer. */
|
|
dst = (void *)((unsigned long)page_address(page) | 0x1);
|
|
/* Unalign src as well, but differently (off by 1 + 2 = 3). */
|
|
@@ -645,7 +642,7 @@ void check_unaligned_access(int cpu)
|
|
pr_warn("cpu%d: rdtime lacks granularity needed to measure unaligned access speed\n",
|
|
cpu);
|
|
|
|
- goto out;
|
|
+ return 0;
|
|
}
|
|
|
|
if (word_cycles < byte_cycles)
|
|
@@ -659,18 +656,83 @@ void check_unaligned_access(int cpu)
|
|
(speed == RISCV_HWPROBE_MISALIGNED_FAST) ? "fast" : "slow");
|
|
|
|
per_cpu(misaligned_access_speed, cpu) = speed;
|
|
+ return 0;
|
|
+}
|
|
|
|
-out:
|
|
- __free_pages(page, get_order(MISALIGNED_BUFFER_SIZE));
|
|
+static void check_unaligned_access_nonboot_cpu(void *param)
|
|
+{
|
|
+ unsigned int cpu = smp_processor_id();
|
|
+ struct page **pages = param;
|
|
+
|
|
+ if (smp_processor_id() != 0)
|
|
+ check_unaligned_access(pages[cpu]);
|
|
}
|
|
|
|
-static int check_unaligned_access_boot_cpu(void)
|
|
+static int riscv_online_cpu(unsigned int cpu)
|
|
{
|
|
- check_unaligned_access(0);
|
|
+ static struct page *buf;
|
|
+
|
|
+ /* We are already set since the last check */
|
|
+ if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_UNKNOWN)
|
|
+ return 0;
|
|
+
|
|
+ buf = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER);
|
|
+ if (!buf) {
|
|
+ pr_warn("Allocation failure, not measuring misaligned performance\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ check_unaligned_access(buf);
|
|
+ __free_pages(buf, MISALIGNED_BUFFER_ORDER);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Measure unaligned access on all CPUs present at boot in parallel. */
|
|
+static int check_unaligned_access_all_cpus(void)
|
|
+{
|
|
+ unsigned int cpu;
|
|
+ unsigned int cpu_count = num_possible_cpus();
|
|
+ struct page **bufs = kzalloc(cpu_count * sizeof(struct page *),
|
|
+ GFP_KERNEL);
|
|
+
|
|
+ if (!bufs) {
|
|
+ pr_warn("Allocation failure, not measuring misaligned performance\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Allocate separate buffers for each CPU so there's no fighting over
|
|
+ * cache lines.
|
|
+ */
|
|
+ for_each_cpu(cpu, cpu_online_mask) {
|
|
+ bufs[cpu] = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER);
|
|
+ if (!bufs[cpu]) {
|
|
+ pr_warn("Allocation failure, not measuring misaligned performance\n");
|
|
+ goto out;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Check everybody except 0, who stays behind to tend jiffies. */
|
|
+ on_each_cpu(check_unaligned_access_nonboot_cpu, bufs, 1);
|
|
+
|
|
+ /* Check core 0. */
|
|
+ smp_call_on_cpu(0, check_unaligned_access, bufs[0], true);
|
|
+
|
|
+ /* Setup hotplug callback for any new CPUs that come online. */
|
|
+ cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "riscv:online",
|
|
+ riscv_online_cpu, NULL);
|
|
+
|
|
+out:
|
|
+ for_each_cpu(cpu, cpu_online_mask) {
|
|
+ if (bufs[cpu])
|
|
+ __free_pages(bufs[cpu], MISALIGNED_BUFFER_ORDER);
|
|
+ }
|
|
+
|
|
+ kfree(bufs);
|
|
return 0;
|
|
}
|
|
|
|
-arch_initcall(check_unaligned_access_boot_cpu);
|
|
+arch_initcall(check_unaligned_access_all_cpus);
|
|
|
|
#ifdef CONFIG_RISCV_ALTERNATIVE
|
|
/*
|
|
diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c
|
|
index 1b8da4e40a4d..2cb5e651412c 100644
|
|
--- a/arch/riscv/kernel/smpboot.c
|
|
+++ b/arch/riscv/kernel/smpboot.c
|
|
@@ -246,7 +246,6 @@ asmlinkage __visible void smp_callin(void)
|
|
|
|
numa_add_cpu(curr_cpuid);
|
|
set_cpu_online(curr_cpuid, 1);
|
|
- check_unaligned_access(curr_cpuid);
|
|
|
|
if (has_vector()) {
|
|
if (riscv_v_setup_vsize())
|
|
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
|
|
index 82d12c93feab..7bbf835fe725 100644
|
|
--- a/arch/x86/Kconfig
|
|
+++ b/arch/x86/Kconfig
|
|
@@ -118,6 +118,7 @@ config X86
|
|
select ARCH_USES_CFI_TRAPS if X86_64 && CFI_CLANG
|
|
select ARCH_SUPPORTS_LTO_CLANG
|
|
select ARCH_SUPPORTS_LTO_CLANG_THIN
|
|
+ select ARCH_SUPPORTS_RT
|
|
select ARCH_USE_BUILTIN_BSWAP
|
|
select ARCH_USE_MEMTEST
|
|
select ARCH_USE_QUEUED_RWLOCKS
|
|
@@ -272,6 +273,7 @@ config X86
|
|
select HAVE_STATIC_CALL
|
|
select HAVE_STATIC_CALL_INLINE if HAVE_OBJTOOL
|
|
select HAVE_PREEMPT_DYNAMIC_CALL
|
|
+ select HAVE_PREEMPT_AUTO
|
|
select HAVE_RSEQ
|
|
select HAVE_RUST if X86_64
|
|
select HAVE_SYSCALL_TRACEPOINTS
|
|
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
|
|
index d63b02940747..1ff38ebbd588 100644
|
|
--- a/arch/x86/include/asm/thread_info.h
|
|
+++ b/arch/x86/include/asm/thread_info.h
|
|
@@ -81,8 +81,9 @@ struct thread_info {
|
|
#define TIF_NOTIFY_RESUME 1 /* callback before returning to user */
|
|
#define TIF_SIGPENDING 2 /* signal pending */
|
|
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
|
|
-#define TIF_SINGLESTEP 4 /* reenable singlestep on user return*/
|
|
-#define TIF_SSBD 5 /* Speculative store bypass disable */
|
|
+#define TIF_ARCH_RESCHED_LAZY 4 /* Lazy rescheduling */
|
|
+#define TIF_SINGLESTEP 5 /* reenable singlestep on user return*/
|
|
+#define TIF_SSBD 6 /* Speculative store bypass disable */
|
|
#define TIF_SPEC_IB 9 /* Indirect branch speculation mitigation */
|
|
#define TIF_SPEC_L1D_FLUSH 10 /* Flush L1D on mm switches (processes) */
|
|
#define TIF_USER_RETURN_NOTIFY 11 /* notify kernel of userspace return */
|
|
@@ -104,6 +105,7 @@ struct thread_info {
|
|
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
|
|
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
|
|
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
|
|
+#define _TIF_ARCH_RESCHED_LAZY (1 << TIF_ARCH_RESCHED_LAZY)
|
|
#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
|
|
#define _TIF_SSBD (1 << TIF_SSBD)
|
|
#define _TIF_SPEC_IB (1 << TIF_SPEC_IB)
|
|
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
|
|
index 831fa4a12159..5af3ebec0f74 100644
|
|
--- a/drivers/acpi/processor_idle.c
|
|
+++ b/drivers/acpi/processor_idle.c
|
|
@@ -107,7 +107,7 @@ static const struct dmi_system_id processor_power_dmi_table[] = {
|
|
*/
|
|
static void __cpuidle acpi_safe_halt(void)
|
|
{
|
|
- if (!tif_need_resched()) {
|
|
+ if (!need_resched()) {
|
|
raw_safe_halt();
|
|
raw_local_irq_disable();
|
|
}
|
|
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
|
|
index 2b8fd6bb7da0..0125f92bb805 100644
|
|
--- a/drivers/base/Kconfig
|
|
+++ b/drivers/base/Kconfig
|
|
@@ -199,7 +199,7 @@ source "drivers/base/regmap/Kconfig"
|
|
|
|
config DMA_SHARED_BUFFER
|
|
bool
|
|
- default n
|
|
+ default y
|
|
select IRQ_WORK
|
|
help
|
|
This option enables the framework for buffer-sharing between
|
|
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
|
|
index 06673c6ca255..a5d0f7c06342 100644
|
|
--- a/drivers/block/zram/zram_drv.c
|
|
+++ b/drivers/block/zram/zram_drv.c
|
|
@@ -57,6 +57,41 @@ static void zram_free_page(struct zram *zram, size_t index);
|
|
static int zram_read_page(struct zram *zram, struct page *page, u32 index,
|
|
struct bio *parent);
|
|
|
|
+#ifdef CONFIG_PREEMPT_RT
|
|
+static void zram_meta_init_table_locks(struct zram *zram, size_t num_pages)
|
|
+{
|
|
+ size_t index;
|
|
+
|
|
+ for (index = 0; index < num_pages; index++)
|
|
+ spin_lock_init(&zram->table[index].lock);
|
|
+}
|
|
+
|
|
+static int zram_slot_trylock(struct zram *zram, u32 index)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = spin_trylock(&zram->table[index].lock);
|
|
+ if (ret)
|
|
+ __set_bit(ZRAM_LOCK, &zram->table[index].flags);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void zram_slot_lock(struct zram *zram, u32 index)
|
|
+{
|
|
+ spin_lock(&zram->table[index].lock);
|
|
+ __set_bit(ZRAM_LOCK, &zram->table[index].flags);
|
|
+}
|
|
+
|
|
+static void zram_slot_unlock(struct zram *zram, u32 index)
|
|
+{
|
|
+ __clear_bit(ZRAM_LOCK, &zram->table[index].flags);
|
|
+ spin_unlock(&zram->table[index].lock);
|
|
+}
|
|
+
|
|
+#else
|
|
+
|
|
+static void zram_meta_init_table_locks(struct zram *zram, size_t num_pages) { }
|
|
+
|
|
static int zram_slot_trylock(struct zram *zram, u32 index)
|
|
{
|
|
return bit_spin_trylock(ZRAM_LOCK, &zram->table[index].flags);
|
|
@@ -71,6 +106,7 @@ static void zram_slot_unlock(struct zram *zram, u32 index)
|
|
{
|
|
bit_spin_unlock(ZRAM_LOCK, &zram->table[index].flags);
|
|
}
|
|
+#endif
|
|
|
|
static inline bool init_done(struct zram *zram)
|
|
{
|
|
@@ -1245,6 +1281,7 @@ static bool zram_meta_alloc(struct zram *zram, u64 disksize)
|
|
|
|
if (!huge_class_size)
|
|
huge_class_size = zs_huge_class_size(zram->mem_pool);
|
|
+ zram_meta_init_table_locks(zram, num_pages);
|
|
return true;
|
|
}
|
|
|
|
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h
|
|
index ca7a15bd4845..e64eb607eb45 100644
|
|
--- a/drivers/block/zram/zram_drv.h
|
|
+++ b/drivers/block/zram/zram_drv.h
|
|
@@ -69,6 +69,9 @@ struct zram_table_entry {
|
|
unsigned long element;
|
|
};
|
|
unsigned long flags;
|
|
+#ifdef CONFIG_PREEMPT_RT
|
|
+ spinlock_t lock;
|
|
+#endif
|
|
#ifdef CONFIG_ZRAM_MEMORY_TRACKING
|
|
ktime_t ac_time;
|
|
#endif
|
|
diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
|
|
index 9e62d3dd2e34..aab46cfd41cd 100644
|
|
--- a/drivers/clk/imx/Makefile
|
|
+++ b/drivers/clk/imx/Makefile
|
|
@@ -16,6 +16,7 @@ mxc-clk-objs += clk-gate-93.o
|
|
mxc-clk-objs += clk-gate-exclusive.o
|
|
mxc-clk-objs += clk-pfd.o
|
|
mxc-clk-objs += clk-pfdv2.o
|
|
+mxc-clk-objs += clk-pll.o
|
|
mxc-clk-objs += clk-pllv1.o
|
|
mxc-clk-objs += clk-pllv2.o
|
|
mxc-clk-objs += clk-pllv3.o
|
|
diff --git a/drivers/clk/imx/clk-frac-pll.c b/drivers/clk/imx/clk-frac-pll.c
|
|
index c703056fae85..2085d8e91ca8 100644
|
|
--- a/drivers/clk/imx/clk-frac-pll.c
|
|
+++ b/drivers/clk/imx/clk-frac-pll.c
|
|
@@ -17,6 +17,7 @@
|
|
#include <linux/bitfield.h>
|
|
|
|
#include "clk.h"
|
|
+#include "clk-pll.h"
|
|
|
|
#define PLL_CFG0 0x0
|
|
#define PLL_CFG1 0x4
|
|
@@ -35,7 +36,11 @@
|
|
#define PLL_FRAC_ACK_TIMEOUT 500000
|
|
|
|
struct clk_frac_pll {
|
|
+ u32 orig_divff;
|
|
+ u32 orig_divfi;
|
|
+ u32 orig_pllcfg0;
|
|
struct clk_hw hw;
|
|
+ struct clk_imx_pll imx_pll;
|
|
void __iomem *base;
|
|
};
|
|
|
|
@@ -202,6 +207,126 @@ static const struct clk_ops clk_frac_pll_ops = {
|
|
.set_rate = clk_pll_set_rate,
|
|
};
|
|
|
|
+/* This function fetches the original PLL parameters to use
|
|
+ * them later for ppb adjustment
|
|
+ */
|
|
+static void imx_frac_pll_init(struct clk_imx_pll *pll)
|
|
+{
|
|
+ struct clk_frac_pll *frac_pll;
|
|
+ u32 val;
|
|
+
|
|
+ frac_pll = (struct clk_frac_pll *) container_of(pll,
|
|
+ struct clk_frac_pll, imx_pll);
|
|
+
|
|
+ val = readl_relaxed(frac_pll->base + PLL_CFG1);
|
|
+
|
|
+ frac_pll->orig_divff = (val >> 7) & PLL_FRAC_DIV_MASK;
|
|
+ frac_pll->orig_divfi = val & PLL_INT_DIV_MASK;
|
|
+
|
|
+ frac_pll->orig_pllcfg0 = readl_relaxed(frac_pll->base + PLL_CFG0);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * imx_frac_pll_adjust - Adjust the Audio pll by ppb.
|
|
+ *
|
|
+ * This function adjust the audio pll by ppb (part per billion) and returns
|
|
+ * the exact number of ppb adjusted.
|
|
+ * The adjustment is done by only modifying the Fractional Divide part
|
|
+ * of the audio PLL.
|
|
+ * Since the pllout = parent_rate * 8 / 2 * (1 + DIVFI + DIVFF / 2^24)
|
|
+ * and the adjusted value is
|
|
+ * pllout_new = pllout * (1 + ppb/1e9) which equals:
|
|
+ * parent_rate * 8 / 2 * (1 + DIVFI + DIVFF_new / 2^24)
|
|
+ * The new divff is calculated as the following:
|
|
+ * DIVFF_new = ((1 + DIVFI) * ppb * 2^24 + DIVFF * 1e9 + DIVFF * ppb) / (1e9)
|
|
+ */
|
|
+
|
|
+static int imx_frac_pll_adjust(struct clk_imx_pll *pll, int *ppb)
|
|
+{
|
|
+ u64 temp64;
|
|
+ u32 val;
|
|
+ s64 applied_ppb;
|
|
+ struct clk_frac_pll *frac_pll;
|
|
+ int rc = IMX_CLK_PLL_SUCCESS;
|
|
+
|
|
+ int req_ppb = *ppb;
|
|
+
|
|
+ frac_pll = (struct clk_frac_pll *) container_of(pll,
|
|
+ struct clk_frac_pll, imx_pll);
|
|
+
|
|
+ /*Calcultate the new PLL Numerator*/
|
|
+ temp64 = ((u64) frac_pll->orig_divfi + 1) * PLL_FRAC_DENOM * req_ppb
|
|
+ + (u64) frac_pll->orig_divff * 1000000000
|
|
+ + (u64) frac_pll->orig_divff * req_ppb;
|
|
+
|
|
+ do_div(temp64, 1000000000);
|
|
+
|
|
+ if (temp64 >= PLL_FRAC_DENOM) {
|
|
+ rc = -IMX_CLK_PLL_PREC_ERR;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ /* clear the NEW_DIV_VAL */
|
|
+ val = frac_pll->orig_pllcfg0;
|
|
+ val &= ~PLL_NEWDIV_VAL;
|
|
+ writel_relaxed(val, frac_pll->base + PLL_CFG0);
|
|
+
|
|
+ /* Write the PLL control settings with the new DIVFF
|
|
+ * NOTE: This sets the reserved bit (bit 31) to zero
|
|
+ */
|
|
+
|
|
+ val = 0;
|
|
+ val |= (((u32)temp64 << 7) | frac_pll->orig_divfi);
|
|
+ writel_relaxed(val, frac_pll->base + PLL_CFG1);
|
|
+
|
|
+ /* Set the NEW_DIV_VAL to reload the DIVFI and DIVFF */
|
|
+ val = frac_pll->orig_pllcfg0;
|
|
+ val |= PLL_NEWDIV_VAL;
|
|
+ writel_relaxed(val, frac_pll->base + PLL_CFG0);
|
|
+
|
|
+ /*Calculate and return the actual applied ppb*/
|
|
+ applied_ppb = div64_s64((s64) (temp64 - frac_pll->orig_divff) * 1000000000,
|
|
+ frac_pll->orig_divff + ((s64) frac_pll->orig_divfi + 1) * PLL_FRAC_DENOM);
|
|
+
|
|
+ *ppb = (int) applied_ppb;
|
|
+
|
|
+ exit:
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static unsigned long imx_frac_pll_get_rate(struct clk_imx_pll *pll,
|
|
+ unsigned long parent_rate)
|
|
+{
|
|
+ struct clk_frac_pll *frac_pll;
|
|
+
|
|
+ frac_pll = (struct clk_frac_pll *) container_of(pll,
|
|
+ struct clk_frac_pll, imx_pll);
|
|
+
|
|
+ return clk_pll_recalc_rate(&frac_pll->hw, parent_rate);
|
|
+}
|
|
+
|
|
+static int imx_frac_pll_set_rate(struct clk_imx_pll *pll, unsigned long rate,
|
|
+ unsigned long parent_rate)
|
|
+{
|
|
+ struct clk_frac_pll *frac_pll;
|
|
+ int rc = IMX_CLK_PLL_SUCCESS;
|
|
+
|
|
+ frac_pll = (struct clk_frac_pll *) container_of(pll,
|
|
+ struct clk_frac_pll, imx_pll);
|
|
+
|
|
+ if (clk_pll_set_rate(&frac_pll->hw, rate, parent_rate) < 0)
|
|
+ rc = -IMX_CLK_PLL_INVALID_PARAM;
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static const struct clk_imx_pll_ops imx_clk_frac_pll_ops = {
|
|
+ .set_rate = imx_frac_pll_set_rate,
|
|
+ .get_rate = imx_frac_pll_get_rate,
|
|
+ .adjust = imx_frac_pll_adjust,
|
|
+ .init = imx_frac_pll_init,
|
|
+};
|
|
+
|
|
struct clk_hw *imx_clk_hw_frac_pll(const char *name,
|
|
const char *parent_name,
|
|
void __iomem *base)
|
|
@@ -232,6 +357,11 @@ struct clk_hw *imx_clk_hw_frac_pll(const char *name,
|
|
return ERR_PTR(ret);
|
|
}
|
|
|
|
+ pll->imx_pll.ops = &imx_clk_frac_pll_ops;
|
|
+
|
|
+ if (imx_pll_register(&pll->imx_pll, name) < 0)
|
|
+ pr_warn("Failed to register %s into imx pll\n", name);
|
|
+
|
|
return hw;
|
|
}
|
|
EXPORT_SYMBOL_GPL(imx_clk_hw_frac_pll);
|
|
diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c
|
|
index e8fa9170c68f..07a23f3fff19 100644
|
|
--- a/drivers/clk/imx/clk-fracn-gppll.c
|
|
+++ b/drivers/clk/imx/clk-fracn-gppll.c
|
|
@@ -13,6 +13,7 @@
|
|
#include <asm/div64.h>
|
|
|
|
#include "clk.h"
|
|
+#include "clk-pll.h"
|
|
|
|
#define PLL_CTRL 0x0
|
|
#define HW_CTRL_SEL BIT(16)
|
|
@@ -63,10 +64,20 @@
|
|
.odiv = (_odiv), \
|
|
}
|
|
|
|
+/* MFN : Numerator of the fractional part of divider (30-bits, signed) */
|
|
+#define MFN_MAX_VALUE ((s32)(GENMASK(29, 0) >> 1))
|
|
+#define MFN_MIN_VALUE ((s32)(-MFN_MAX_VALUE - 1))
|
|
+
|
|
struct clk_fracn_gppll {
|
|
struct clk_hw hw;
|
|
void __iomem *base;
|
|
const struct imx_fracn_gppll_rate_table *rate_table;
|
|
+ u32 orig_mfd;
|
|
+ u32 orig_mfi;
|
|
+ u32 orig_odiv;
|
|
+ u32 orig_rdiv;
|
|
+ s32 orig_mfn;
|
|
+ struct clk_imx_pll imx_pll;
|
|
int rate_count;
|
|
u32 flags;
|
|
};
|
|
@@ -87,7 +98,7 @@ static const struct imx_fracn_gppll_rate_table fracn_tbl[] = {
|
|
PLL_FRACN_GP(484000000U, 121, 0, 1, 0, 6),
|
|
PLL_FRACN_GP(445333333U, 167, 0, 1, 0, 9),
|
|
PLL_FRACN_GP(400000000U, 200, 0, 1, 0, 12),
|
|
- PLL_FRACN_GP(393216000U, 163, 84, 100, 0, 10),
|
|
+ PLL_FRACN_GP(393216000U, 163, 1680000, 2000000, 0, 10),
|
|
PLL_FRACN_GP(300000000U, 150, 0, 1, 0, 12)
|
|
};
|
|
|
|
@@ -150,18 +161,19 @@ static long clk_fracn_gppll_round_rate(struct clk_hw *hw, unsigned long rate,
|
|
return rate_table[pll->rate_count - 1].rate;
|
|
}
|
|
|
|
-static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
|
+/* This function calculates the actual rate based on the configured PLL registers */
|
|
+static unsigned long __clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
|
{
|
|
struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
|
|
- const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table;
|
|
u32 pll_numerator, pll_denominator, pll_div;
|
|
- u32 mfi, mfn, mfd, rdiv, odiv;
|
|
+ u32 mfi, mfd, rdiv, odiv;
|
|
+ s32 mfn;
|
|
u64 fvco = parent_rate;
|
|
- long rate = 0;
|
|
- int i;
|
|
|
|
pll_numerator = readl_relaxed(pll->base + PLL_NUMERATOR);
|
|
- mfn = FIELD_GET(PLL_MFN_MASK, pll_numerator);
|
|
+
|
|
+ /* Numerator is 30-bits signed value */
|
|
+ mfn = sign_extend32(FIELD_GET(PLL_MFN_MASK, pll_numerator), 29);
|
|
|
|
pll_denominator = readl_relaxed(pll->base + PLL_DENOMINATOR);
|
|
mfd = FIELD_GET(PLL_MFD_MASK, pll_denominator);
|
|
@@ -172,22 +184,6 @@ static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned lon
|
|
rdiv = FIELD_GET(PLL_RDIV_MASK, pll_div);
|
|
odiv = FIELD_GET(PLL_ODIV_MASK, pll_div);
|
|
|
|
- /*
|
|
- * Sometimes, the recalculated rate has deviation due to
|
|
- * the frac part. So find the accurate pll rate from the table
|
|
- * first, if no match rate in the table, use the rate calculated
|
|
- * from the equation below.
|
|
- */
|
|
- for (i = 0; i < pll->rate_count; i++) {
|
|
- if (rate_table[i].mfn == mfn && rate_table[i].mfi == mfi &&
|
|
- rate_table[i].mfd == mfd && rate_table[i].rdiv == rdiv &&
|
|
- rate_table[i].odiv == odiv)
|
|
- rate = rate_table[i].rate;
|
|
- }
|
|
-
|
|
- if (rate)
|
|
- return (unsigned long)rate;
|
|
-
|
|
if (!rdiv)
|
|
rdiv = rdiv + 1;
|
|
|
|
@@ -208,13 +204,50 @@ static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned lon
|
|
do_div(fvco, rdiv * odiv);
|
|
} else {
|
|
/* Fvco = (Fref / rdiv) * (MFI + MFN / MFD) */
|
|
- fvco = fvco * mfi * mfd + fvco * mfn;
|
|
+ fvco *= (mfi * mfd + mfn);
|
|
do_div(fvco, mfd * rdiv * odiv);
|
|
}
|
|
|
|
return (unsigned long)fvco;
|
|
}
|
|
|
|
+static unsigned long clk_fracn_gppll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
|
+{
|
|
+ struct clk_fracn_gppll *pll = to_clk_fracn_gppll(hw);
|
|
+ const struct imx_fracn_gppll_rate_table *rate_table = pll->rate_table;
|
|
+ u32 pll_numerator, pll_denominator, pll_div;
|
|
+ u32 mfi, mfn, mfd, rdiv, odiv;
|
|
+ long rate = 0;
|
|
+ int i;
|
|
+
|
|
+ pll_numerator = readl_relaxed(pll->base + PLL_NUMERATOR);
|
|
+ mfn = FIELD_GET(PLL_MFN_MASK, pll_numerator);
|
|
+
|
|
+ pll_denominator = readl_relaxed(pll->base + PLL_DENOMINATOR);
|
|
+ mfd = FIELD_GET(PLL_MFD_MASK, pll_denominator);
|
|
+
|
|
+ pll_div = readl_relaxed(pll->base + PLL_DIV);
|
|
+ mfi = FIELD_GET(PLL_MFI_MASK, pll_div);
|
|
+
|
|
+ rdiv = FIELD_GET(PLL_RDIV_MASK, pll_div);
|
|
+ odiv = FIELD_GET(PLL_ODIV_MASK, pll_div);
|
|
+
|
|
+ /*
|
|
+ * Sometimes, the recalculated rate has deviation due to
|
|
+ * the frac part. So find the accurate pll rate from the table
|
|
+ * first, if no match rate in the table, use the rate calculated
|
|
+ * from the equation below.
|
|
+ */
|
|
+ for (i = 0; i < pll->rate_count; i++) {
|
|
+ if (rate_table[i].mfn == mfn && rate_table[i].mfi == mfi &&
|
|
+ rate_table[i].mfd == mfd && rate_table[i].rdiv == rdiv &&
|
|
+ rate_table[i].odiv == odiv)
|
|
+ rate = rate_table[i].rate;
|
|
+ }
|
|
+
|
|
+ return rate ? (unsigned long) rate : __clk_fracn_gppll_recalc_rate(hw, parent_rate);
|
|
+}
|
|
+
|
|
static int clk_fracn_gppll_wait_lock(struct clk_fracn_gppll *pll)
|
|
{
|
|
u32 val;
|
|
@@ -232,6 +265,11 @@ static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate,
|
|
int ret;
|
|
|
|
rate = imx_get_pll_settings(pll, drate);
|
|
+ if (!rate) {
|
|
+ pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
|
|
+ drate, clk_hw_get_name(hw));
|
|
+ return -EINVAL;
|
|
+ }
|
|
|
|
/* Hardware control select disable. PLL is control by register */
|
|
tmp = readl_relaxed(pll->base + PLL_CTRL);
|
|
@@ -350,6 +388,122 @@ static const struct clk_ops clk_fracn_gppll_ops = {
|
|
.set_rate = clk_fracn_gppll_set_rate,
|
|
};
|
|
|
|
+/* This function fetches the original PLL parameters to use
|
|
+ * them later for ppb adjustment
|
|
+ */
|
|
+static void imx_fracn_gppll_init(struct clk_imx_pll *pll)
|
|
+{
|
|
+ struct clk_fracn_gppll *fracn_pll;
|
|
+ u32 pll_numerator, pll_denominator, pll_div, mfn;
|
|
+
|
|
+ fracn_pll = (struct clk_fracn_gppll *) container_of(pll,
|
|
+ struct clk_fracn_gppll, imx_pll);
|
|
+
|
|
+ pll_numerator = readl_relaxed(fracn_pll->base + PLL_NUMERATOR);
|
|
+ mfn = FIELD_GET(PLL_MFN_MASK, pll_numerator);
|
|
+
|
|
+ /* Numerator is 30-bits signed value */
|
|
+ fracn_pll->orig_mfn = sign_extend32(mfn, 29);
|
|
+
|
|
+ pll_denominator = readl_relaxed(fracn_pll->base + PLL_DENOMINATOR);
|
|
+ fracn_pll->orig_mfd = FIELD_GET(PLL_MFD_MASK, pll_denominator);
|
|
+
|
|
+ pll_div = readl_relaxed(fracn_pll->base + PLL_DIV);
|
|
+ fracn_pll->orig_mfi = FIELD_GET(PLL_MFI_MASK, pll_div);
|
|
+
|
|
+ fracn_pll->orig_rdiv = FIELD_GET(PLL_RDIV_MASK, pll_div);
|
|
+ fracn_pll->orig_odiv = FIELD_GET(PLL_ODIV_MASK, pll_div);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * imx_fracn_gppll_adjust - Adjust the Audio pll by ppb.
|
|
+ *
|
|
+ * This function adjusts the audio pll by ppb (part per billion) and returns
|
|
+ * the exact number of ppb adjusted.
|
|
+ * The adjustment is done by only modifying the numerator of the fractional part
|
|
+ * of the audio PLL.
|
|
+ * Since the pllout = (ref * (mfi + mfn/mfd)) / (rdiv * odiv)
|
|
+ * and the adjusted value is
|
|
+ * pllout_new = pllout * (1 + ppb/1e9) which equals:
|
|
+ * (ref * (mfi + mfn_new/mfd)) / (rdiv * odiv)
|
|
+ * The new numerator (mfn_new) is calculated as following:
|
|
+ * mfn_new = (1e9 * mfn + (mfi * mfd + mfn) * ppb) / (1e9)
|
|
+ */
|
|
+
|
|
+static int imx_fracn_gppll_adjust(struct clk_imx_pll *pll, int *ppb)
|
|
+{
|
|
+ s64 temp64;
|
|
+ s64 applied_ppb;
|
|
+ struct clk_fracn_gppll *fracn_pll;
|
|
+ int rc = IMX_CLK_PLL_SUCCESS;
|
|
+
|
|
+ int req_ppb = *ppb;
|
|
+
|
|
+ fracn_pll = (struct clk_fracn_gppll *) container_of(pll,
|
|
+ struct clk_fracn_gppll, imx_pll);
|
|
+
|
|
+ /* Calculate the new numerator value */
|
|
+ temp64 = ((s64) fracn_pll->orig_mfn * 1000000000)
|
|
+ + ((s64) fracn_pll->orig_mfi * fracn_pll->orig_mfd + (s64) fracn_pll->orig_mfn) * req_ppb;
|
|
+
|
|
+ temp64 = div_s64(temp64, 1000000000);
|
|
+
|
|
+ /* Sanity check on the new numerator value:
|
|
+ * - the value is inside the 30-bits signed values range
|
|
+ * - mfn/mfd should be in the range [-2, 2]
|
|
+ */
|
|
+ if (temp64 > MFN_MAX_VALUE || temp64 < MFN_MIN_VALUE || (abs(temp64) > (2 * fracn_pll->orig_mfd))) {
|
|
+ rc = -IMX_CLK_PLL_PREC_ERR;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ /* Write the PLL control settings with the new numerator */
|
|
+
|
|
+ writel_relaxed(FIELD_PREP(PLL_MFN_MASK, temp64), fracn_pll->base + PLL_NUMERATOR);
|
|
+
|
|
+ /* Calculate and return the actual applied ppb */
|
|
+ applied_ppb = div64_s64((s64) (temp64 - fracn_pll->orig_mfn) * 1000000000,
|
|
+ fracn_pll->orig_mfn + fracn_pll->orig_mfd * (s64) fracn_pll->orig_mfi);
|
|
+
|
|
+ *ppb = (int) applied_ppb;
|
|
+
|
|
+ exit:
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static unsigned long imx_fracn_gppll_get_rate(struct clk_imx_pll *pll,
|
|
+ unsigned long parent_rate)
|
|
+{
|
|
+ struct clk_fracn_gppll *fracn_pll;
|
|
+
|
|
+ fracn_pll = (struct clk_fracn_gppll *) container_of(pll,
|
|
+ struct clk_fracn_gppll, imx_pll);
|
|
+
|
|
+ return __clk_fracn_gppll_recalc_rate(&fracn_pll->hw, parent_rate);
|
|
+}
|
|
+
|
|
+static int imx_fracn_gppll_set_rate(struct clk_imx_pll *pll, unsigned long rate,
|
|
+ unsigned long parent_rate)
|
|
+{
|
|
+ struct clk_fracn_gppll *fracn_pll;
|
|
+ int rc = IMX_CLK_PLL_SUCCESS;
|
|
+
|
|
+ fracn_pll = (struct clk_fracn_gppll *) container_of(pll,
|
|
+ struct clk_fracn_gppll, imx_pll);
|
|
+
|
|
+ if (clk_fracn_gppll_set_rate(&fracn_pll->hw, rate, parent_rate) < 0)
|
|
+ rc = -IMX_CLK_PLL_INVALID_PARAM;
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static const struct clk_imx_pll_ops imx_clk_fracn_gppll_ops = {
|
|
+ .set_rate = imx_fracn_gppll_set_rate,
|
|
+ .get_rate = imx_fracn_gppll_get_rate,
|
|
+ .adjust = imx_fracn_gppll_adjust,
|
|
+ .init = imx_fracn_gppll_init,
|
|
+};
|
|
+
|
|
static struct clk_hw *_imx_clk_fracn_gppll(const char *name, const char *parent_name,
|
|
void __iomem *base,
|
|
const struct imx_fracn_gppll_clk *pll_clk,
|
|
@@ -385,6 +539,13 @@ static struct clk_hw *_imx_clk_fracn_gppll(const char *name, const char *parent_
|
|
return ERR_PTR(ret);
|
|
}
|
|
|
|
+ if (pll_flags & CLK_FRACN_GPPLL_FRACN) {
|
|
+ pll->imx_pll.ops = &imx_clk_fracn_gppll_ops;
|
|
+
|
|
+ if (imx_pll_register(&pll->imx_pll, name) < 0)
|
|
+ pr_warn("%s: failed to register %s into imx pll\n", __func__, name);
|
|
+ }
|
|
+
|
|
return hw;
|
|
}
|
|
|
|
diff --git a/drivers/clk/imx/clk-imx8-acm.c b/drivers/clk/imx/clk-imx8-acm.c
|
|
index 1c95ae905eec..e8ad426cd844 100644
|
|
--- a/drivers/clk/imx/clk-imx8-acm.c
|
|
+++ b/drivers/clk/imx/clk-imx8-acm.c
|
|
@@ -235,11 +235,20 @@ static const struct clk_parent_data imx8dxl_mclk_sels[] = {
|
|
{ .fw_name = "acm_aud_clk1_sel" },
|
|
};
|
|
|
|
+static const struct clk_parent_data imx8dxl_gpt_mux_clk_sels[] = {
|
|
+ { .fw_name = "aud_pll_div_clk0_lpcg_clk", .name = "aud_pll_div_clk0_lpcg_clk" },
|
|
+ { .fw_name = "aud_pll_div_clk1_lpcg_clk", .name = "aud_pll_div_clk1_lpcg_clk" },
|
|
+ { .fw_name = "acm_aud_clk0_sel", .name = "acm_aud_clk0_sel" },
|
|
+ { .fw_name = "acm_aud_clk1_sel", .name = "acm_aud_clk1_sel" },
|
|
+ { .index = -1 },
|
|
+};
|
|
+
|
|
static struct clk_imx8_acm_sel imx8dxl_sels[] = {
|
|
{ "acm_aud_clk0_sel", IMX_ADMA_ACM_AUD_CLK0_SEL, imx8dxl_aud_clk_sels, ARRAY_SIZE(imx8dxl_aud_clk_sels), 0x000000, 0, 5 },
|
|
{ "acm_aud_clk1_sel", IMX_ADMA_ACM_AUD_CLK1_SEL, imx8dxl_aud_clk_sels, ARRAY_SIZE(imx8dxl_aud_clk_sels), 0x010000, 0, 5 },
|
|
{ "acm_mclkout0_sel", IMX_ADMA_ACM_MCLKOUT0_SEL, imx8dxl_mclk_out_sels, ARRAY_SIZE(imx8dxl_mclk_out_sels), 0x020000, 0, 3 },
|
|
{ "acm_mclkout1_sel", IMX_ADMA_ACM_MCLKOUT1_SEL, imx8dxl_mclk_out_sels, ARRAY_SIZE(imx8dxl_mclk_out_sels), 0x030000, 0, 3 },
|
|
+ { "acm_gpt0_mux_clk_sel", IMX_ADMA_ACM_GPT0_MUX_CLK_SEL, imx8dxl_gpt_mux_clk_sels, ARRAY_SIZE(imx8dxl_gpt_mux_clk_sels), 0x080000, 0, 3 },
|
|
{ "acm_sai0_mclk_sel", IMX_ADMA_ACM_SAI0_MCLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x0E0000, 0, 2 },
|
|
{ "acm_sai1_mclk_sel", IMX_ADMA_ACM_SAI1_MCLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x0F0000, 0, 2 },
|
|
{ "acm_sai2_mclk_sel", IMX_ADMA_ACM_SAI2_MCLK_SEL, imx8dxl_mclk_sels, ARRAY_SIZE(imx8dxl_mclk_sels), 0x100000, 0, 2 },
|
|
@@ -326,6 +335,41 @@ static int clk_imx_acm_detach_pm_domains(struct device *dev,
|
|
return 0;
|
|
}
|
|
|
|
+/* The number of cells for the GPT capture device tree attribute */
|
|
+#define OF_GPT_CAPTURE_CELLS_NB 2
|
|
+
|
|
+static void clk_imx_acm_gpt_input_mux(struct device_node *np, struct imx8_acm_priv *priv)
|
|
+{
|
|
+ u32 len, reg_offset, event_sel_control, num_capture_select;
|
|
+ int i, offset;
|
|
+
|
|
+ if (!of_get_property(np, "gpt-capture-select", &len))
|
|
+ return;
|
|
+
|
|
+ num_capture_select = len / (sizeof(u32) * OF_GPT_CAPTURE_CELLS_NB);
|
|
+
|
|
+ for (i = 0; i < num_capture_select; i++) {
|
|
+ offset = i * OF_GPT_CAPTURE_CELLS_NB;
|
|
+ if (of_property_read_u32_index(np,
|
|
+ "gpt-capture-select",
|
|
+ offset, ®_offset)) {
|
|
+ pr_err("failed to read gpt register offset cell at offset %d\n",
|
|
+ offset);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (of_property_read_u32_index(np,
|
|
+ "gpt-capture-select",
|
|
+ offset + 1, &event_sel_control)) {
|
|
+ pr_err("failed to read gpt event select control cell at offset %d\n",
|
|
+ offset + 1);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ writel_relaxed(event_sel_control, priv->reg + reg_offset);
|
|
+ }
|
|
+}
|
|
+
|
|
static int imx8_acm_clk_probe(struct platform_device *pdev)
|
|
{
|
|
struct clk_hw_onecell_data *clk_hw_data;
|
|
@@ -386,6 +430,8 @@ static int imx8_acm_clk_probe(struct platform_device *pdev)
|
|
goto err_clk_register;
|
|
}
|
|
|
|
+ clk_imx_acm_gpt_input_mux(dev->of_node, priv);
|
|
+
|
|
pm_runtime_put_sync(&pdev->dev);
|
|
return 0;
|
|
|
|
diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c
|
|
index 10a4bfb825e3..8432477370e4 100644
|
|
--- a/drivers/clk/imx/clk-imx8mq.c
|
|
+++ b/drivers/clk/imx/clk-imx8mq.c
|
|
@@ -217,7 +217,7 @@ static const char * const imx8mq_pwm4_sels[] = {"osc_25m", "sys2_pll_100m", "sys
|
|
"sys3_pll_out", "clk_ext2", "sys1_pll_80m", "video_pll1_out", };
|
|
|
|
static const char * const imx8mq_gpt1_sels[] = {"osc_25m", "sys2_pll_100m", "sys1_pll_400m", "sys1_pll_40m",
|
|
- "sys1_pll_80m", "audio_pll1_out", "clk_ext1", };
|
|
+ "video_pll1_out", "sys1_pll_80m", "audio_pll1_out", "clk_ext1", };
|
|
|
|
static const char * const imx8mq_wdog_sels[] = {"osc_25m", "sys1_pll_133m", "sys1_pll_160m", "vpu_pll_out",
|
|
"sys2_pll_125m", "sys3_pll_out", "sys1_pll_80m", "sys2_pll_166m", };
|
|
diff --git a/drivers/clk/imx/clk-pll.c b/drivers/clk/imx/clk-pll.c
|
|
new file mode 100644
|
|
index 000000000000..b77375a11add
|
|
--- /dev/null
|
|
+++ b/drivers/clk/imx/clk-pll.c
|
|
@@ -0,0 +1,83 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2018 NXP
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <linux/clk/imx-pll.h>
|
|
+#include <linux/stddef.h>
|
|
+#include <linux/export.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/string.h>
|
|
+#include "clk-pll.h"
|
|
+
|
|
+
|
|
+static struct clk_imx_pll *clk_imx_pll_array[MAX_IMX_PLL_NUM] = { NULL };
|
|
+
|
|
+struct clk_imx_pll *clk_imx_pll_get_by_name(const char *name)
|
|
+{
|
|
+ int i;
|
|
+ struct clk_imx_pll *pll = NULL;
|
|
+
|
|
+ for (i = 0; i < MAX_IMX_PLL_NUM; i++) {
|
|
+ if (clk_imx_pll_array[i] && clk_imx_pll_array[i]->ops
|
|
+ && !strncmp(clk_imx_pll_array[i]->pll_name, name, MAX_PLL_NAME_SIZE)) {
|
|
+
|
|
+ pll = clk_imx_pll_array[i];
|
|
+
|
|
+ /* Init all PLL original parameters*/
|
|
+ if (pll && pll->ops && pll->ops->init)
|
|
+ pll->ops->init(pll);
|
|
+
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return pll;
|
|
+}
|
|
+EXPORT_SYMBOL(clk_imx_pll_get_by_name);
|
|
+
|
|
+int clk_imx_pll_adjust(struct clk_imx_pll *pll, int *ppb)
|
|
+{
|
|
+ if (pll && pll->ops && pll->ops->adjust)
|
|
+ return pll->ops->adjust(pll, ppb);
|
|
+
|
|
+ return -IMX_CLK_PLL_INVALID_PARAM;
|
|
+}
|
|
+EXPORT_SYMBOL(clk_imx_pll_adjust);
|
|
+
|
|
+unsigned long clk_imx_pll_get_rate(struct clk_imx_pll *pll,
|
|
+ unsigned long parent_rate)
|
|
+{
|
|
+ if (pll && pll->ops && pll->ops->get_rate)
|
|
+ return pll->ops->get_rate(pll, parent_rate);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(clk_imx_pll_get_rate);
|
|
+
|
|
+int clk_imx_pll_set_rate(struct clk_imx_pll *pll, unsigned long rate,
|
|
+ unsigned long parent_rate)
|
|
+{
|
|
+ if (pll && pll->ops && pll->ops->set_rate)
|
|
+ return pll->ops->set_rate(pll, rate, parent_rate);
|
|
+
|
|
+ return -IMX_CLK_PLL_INVALID_PARAM;
|
|
+}
|
|
+EXPORT_SYMBOL(clk_imx_pll_set_rate);
|
|
+
|
|
+int imx_pll_register(struct clk_imx_pll *pll, const char *name)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ strncpy(pll->pll_name, name, MAX_PLL_NAME_SIZE);
|
|
+
|
|
+ for (i = 0; i < MAX_IMX_PLL_NUM; i++) {
|
|
+ if (!clk_imx_pll_array[i]) {
|
|
+ clk_imx_pll_array[i] = pll;
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return -EINVAL;
|
|
+}
|
|
diff --git a/drivers/clk/imx/clk-pll.h b/drivers/clk/imx/clk-pll.h
|
|
new file mode 100644
|
|
index 000000000000..f12167842059
|
|
--- /dev/null
|
|
+++ b/drivers/clk/imx/clk-pll.h
|
|
@@ -0,0 +1,33 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2018 NXP
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef __IMX_CLK_PLL_H
|
|
+#define __IMX_CLK_PLL_H
|
|
+
|
|
+#include <linux/clk/imx-pll.h>
|
|
+
|
|
+#define MAX_IMX_PLL_NUM 16
|
|
+#define MAX_PLL_NAME_SIZE 64
|
|
+
|
|
+struct clk_imx_pll;
|
|
+
|
|
+struct clk_imx_pll_ops {
|
|
+ int (*set_rate)(struct clk_imx_pll *pll, unsigned long rate,
|
|
+ unsigned long parent_rate);
|
|
+ unsigned long (*get_rate)(struct clk_imx_pll *pll,
|
|
+ unsigned long parent_rate);
|
|
+ int (*adjust)(struct clk_imx_pll *pll, int *ppb);
|
|
+ void (*init)(struct clk_imx_pll *pll);
|
|
+};
|
|
+
|
|
+struct clk_imx_pll {
|
|
+ char pll_name[MAX_PLL_NAME_SIZE];
|
|
+ const struct clk_imx_pll_ops *ops;
|
|
+};
|
|
+
|
|
+int imx_pll_register(struct clk_imx_pll *pll, const char *name);
|
|
+
|
|
+#endif /*__IMX_CLK_PLL_H*/
|
|
diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c
|
|
index 6c17786ecb9f..e68030c4a24f 100644
|
|
--- a/drivers/clk/imx/clk-pll14xx.c
|
|
+++ b/drivers/clk/imx/clk-pll14xx.c
|
|
@@ -16,6 +16,7 @@
|
|
#include <linux/jiffies.h>
|
|
|
|
#include "clk.h"
|
|
+#include "clk-pll.h"
|
|
|
|
#define GNRL_CTL 0x0
|
|
#define DIV_CTL0 0x4
|
|
@@ -37,8 +38,13 @@
|
|
struct clk_pll14xx {
|
|
struct clk_hw hw;
|
|
void __iomem *base;
|
|
+ u32 orig_mdiv;
|
|
+ u32 orig_pdiv;
|
|
+ u32 orig_sdiv;
|
|
+ short int orig_kdiv;
|
|
enum imx_pll14xx_type type;
|
|
const struct imx_pll14xx_rate_table *rate_table;
|
|
+ struct clk_imx_pll imx_pll;
|
|
int rate_count;
|
|
};
|
|
|
|
@@ -536,6 +542,113 @@ static const struct clk_ops clk_pll1443x_ops = {
|
|
.set_rate = clk_pll1443x_set_rate,
|
|
};
|
|
|
|
+/* This function fetches the original PLL parameters to use
|
|
+ * them later for ppb adjustment
|
|
+ */
|
|
+static void imx_pll1443x_init(struct clk_imx_pll *pll)
|
|
+{
|
|
+ struct clk_pll14xx *pll14xx;
|
|
+ u32 pll_div_ctl0, pll_div_ctl1;
|
|
+
|
|
+ pll14xx = (struct clk_pll14xx *) container_of(pll,
|
|
+ struct clk_pll14xx, imx_pll);
|
|
+
|
|
+ pll_div_ctl0 = readl_relaxed(pll14xx->base + DIV_CTL0);
|
|
+ pll_div_ctl1 = readl_relaxed(pll14xx->base + DIV_CTL1);
|
|
+
|
|
+ pll14xx->orig_kdiv = FIELD_GET(KDIV_MASK, pll_div_ctl1);
|
|
+ pll14xx->orig_mdiv = FIELD_GET(MDIV_MASK, pll_div_ctl0);
|
|
+ pll14xx->orig_pdiv = FIELD_GET(PDIV_MASK, pll_div_ctl0);
|
|
+ pll14xx->orig_sdiv = FIELD_GET(SDIV_MASK, pll_div_ctl0);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * imx_pll1443x_adjust - Adjust the Audio pll by ppb.
|
|
+ *
|
|
+ * This function adjust the audio pll by ppb (part per billion) and returns
|
|
+ * the exact number of ppb adjusted.
|
|
+ * The adjustment is done by only modifying the delta-sigma modulator(DSM) part
|
|
+ * of the audio PLL.
|
|
+ * Since the pllout = (parent_rate * (m + k/65536)) / (p * 2^s)
|
|
+ * and the adjusted value is
|
|
+ * pllout_new = pllout * (1 + ppb/1e9) which equals:
|
|
+ * (parent_rate * (m + k_new/65536)) / (p * 2^s)
|
|
+ * The new DSM (k_new) is calculated as the following:
|
|
+ * k_new = (1e9 * k + (m * 65536 + k) * ppb) / (1e9)
|
|
+ */
|
|
+
|
|
+static int imx_pll1443x_adjust(struct clk_imx_pll *pll, int *ppb)
|
|
+{
|
|
+ s64 temp64;
|
|
+ s64 applied_ppb;
|
|
+ struct clk_pll14xx *pll14xx;
|
|
+ int rc = IMX_CLK_PLL_SUCCESS;
|
|
+
|
|
+ int req_ppb = *ppb;
|
|
+
|
|
+ pll14xx = (struct clk_pll14xx *) container_of(pll,
|
|
+ struct clk_pll14xx, imx_pll);
|
|
+
|
|
+ /* Calcultate the new DSM value */
|
|
+ temp64 = ((s64) pll14xx->orig_kdiv * 1000000000)
|
|
+ + ((s64) pll14xx->orig_mdiv * 65536 + (s64) pll14xx->orig_kdiv) * req_ppb;
|
|
+
|
|
+ temp64 = div_s64(temp64, 1000000000);
|
|
+
|
|
+ if (temp64 > KDIV_MAX || temp64 < KDIV_MIN) {
|
|
+ rc = -IMX_CLK_PLL_PREC_ERR;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ /* Write the PLL control settings with the new DSM
|
|
+ */
|
|
+
|
|
+ writel_relaxed(FIELD_PREP(KDIV_MASK, temp64), pll14xx->base + DIV_CTL1);
|
|
+
|
|
+ /* Calculate and return the actual applied ppb */
|
|
+ applied_ppb = div64_s64((s64) (temp64 - pll14xx->orig_kdiv) * 1000000000,
|
|
+ pll14xx->orig_kdiv + 65536 * (s64) pll14xx->orig_mdiv);
|
|
+
|
|
+ *ppb = (int) applied_ppb;
|
|
+
|
|
+ exit:
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static unsigned long imx_pll1443x_get_rate(struct clk_imx_pll *pll,
|
|
+ unsigned long parent_rate)
|
|
+{
|
|
+ struct clk_pll14xx *pll14xx;
|
|
+
|
|
+ pll14xx = (struct clk_pll14xx *) container_of(pll,
|
|
+ struct clk_pll14xx, imx_pll);
|
|
+
|
|
+ return clk_pll14xx_recalc_rate(&pll14xx->hw, parent_rate);
|
|
+}
|
|
+
|
|
+static int imx_pll1443x_set_rate(struct clk_imx_pll *pll, unsigned long rate,
|
|
+ unsigned long parent_rate)
|
|
+{
|
|
+ struct clk_pll14xx *pll14xx;
|
|
+ int rc = IMX_CLK_PLL_SUCCESS;
|
|
+
|
|
+ pll14xx = (struct clk_pll14xx *) container_of(pll,
|
|
+ struct clk_pll14xx, imx_pll);
|
|
+
|
|
+ if (clk_pll1443x_set_rate(&pll14xx->hw, rate, parent_rate) < 0)
|
|
+ rc = -IMX_CLK_PLL_INVALID_PARAM;
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static const struct clk_imx_pll_ops imx_clk_pll1443x_ops = {
|
|
+ .set_rate = imx_pll1443x_set_rate,
|
|
+ .get_rate = imx_pll1443x_get_rate,
|
|
+ .adjust = imx_pll1443x_adjust,
|
|
+ .init = imx_pll1443x_init,
|
|
+};
|
|
+
|
|
+
|
|
struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
|
|
const char *parent_name, void __iomem *base,
|
|
const struct imx_pll14xx_clk *pll_clk)
|
|
@@ -590,6 +703,13 @@ struct clk_hw *imx_dev_clk_hw_pll14xx(struct device *dev, const char *name,
|
|
return ERR_PTR(ret);
|
|
}
|
|
|
|
+ if (pll_clk->type == PLL_1443X) {
|
|
+ pll->imx_pll.ops = &imx_clk_pll1443x_ops;
|
|
+
|
|
+ if (imx_pll_register(&pll->imx_pll, name) < 0)
|
|
+ pr_warn("Failed to register %s into imx pll\n", name);
|
|
+ }
|
|
+
|
|
return hw;
|
|
}
|
|
EXPORT_SYMBOL_GPL(imx_dev_clk_hw_pll14xx);
|
|
diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c
|
|
index 6f6d4589f7eb..b74b48f3fc90 100644
|
|
--- a/drivers/clk/imx/clk-pllv3.c
|
|
+++ b/drivers/clk/imx/clk-pllv3.c
|
|
@@ -15,6 +15,7 @@
|
|
#include <linux/err.h>
|
|
#include <soc/imx/src.h>
|
|
#include "clk.h"
|
|
+#include "clk-pll.h"
|
|
|
|
#define PLL_NUM_OFFSET 0x10
|
|
#define PLL_DENOM_OFFSET 0x20
|
|
@@ -48,6 +49,10 @@
|
|
*/
|
|
struct clk_pllv3 {
|
|
struct clk_hw hw;
|
|
+ struct clk_imx_pll imx_pll;
|
|
+ u32 orig_num;
|
|
+ u32 orig_denom;
|
|
+ u32 orig_div;
|
|
void __iomem *base;
|
|
u32 power_bit;
|
|
bool powerup_set;
|
|
@@ -441,6 +446,106 @@ static const struct clk_ops clk_pllv3_vf610_ops = {
|
|
.set_rate = clk_pllv3_vf610_set_rate,
|
|
};
|
|
|
|
+/**
|
|
+ * imx_pllv3_av_adjust - Adjust the Audio pll by ppb.
|
|
+ *
|
|
+ * This function adjust the audio pll by ppb (part per billion) and returns
|
|
+ * the exact number of ppb adjusted.
|
|
+ * The adjustment is done by only modifying the Audio PLL Numerator.
|
|
+ * Since the pllout = parent * (div + num/denom) and the adjusted Value is
|
|
+ * pllout_new = PLL_out * (1 + ppb/1e9)
|
|
+ * Also pllout_new = parent * (div + new_num/denom)
|
|
+ * The new numerator is calculated as the following:
|
|
+ * new_num = (div * ppb * denom + num * 1e9 + num * ppb) / (1e9)
|
|
+ */
|
|
+
|
|
+static int imx_pllv3_av_adjust(struct clk_imx_pll *pll, int *ppb)
|
|
+{
|
|
+ struct clk_pllv3 *av_pll;
|
|
+ u64 temp64;
|
|
+ s32 applied_ppb;
|
|
+ int rc = IMX_CLK_PLL_SUCCESS;
|
|
+
|
|
+ int req_ppb = *ppb;
|
|
+
|
|
+ av_pll = (struct clk_pllv3 *) container_of(pll, struct clk_pllv3,
|
|
+ imx_pll);
|
|
+
|
|
+ /*Calcultate the new PLL Numerator*/
|
|
+ temp64 = (u64) av_pll->orig_denom * av_pll->orig_div * req_ppb
|
|
+ + (u64) av_pll->orig_num * 1000000000
|
|
+ + (u64) av_pll->orig_num * req_ppb;
|
|
+
|
|
+ do_div(temp64, 1000000000);
|
|
+
|
|
+ if (temp64 >= av_pll->orig_denom) {
|
|
+ rc = -IMX_CLK_PLL_PREC_ERR;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ /*Write the new PLL num*/
|
|
+ writel_relaxed((u32) temp64, av_pll->base + av_pll->num_offset);
|
|
+
|
|
+ /*Calculate and return the actual applied ppb*/
|
|
+ applied_ppb = div64_s64((s64) (temp64 - av_pll->orig_num) * 1000000000,
|
|
+ av_pll->orig_num
|
|
+ + (s64) av_pll->orig_denom * av_pll->orig_div);
|
|
+
|
|
+ *ppb = (int) applied_ppb;
|
|
+
|
|
+exit:
|
|
+ return rc;
|
|
+
|
|
+}
|
|
+
|
|
+/* This function fetches the original PLL parameters to use
|
|
+ * them later for ppb adjustment
|
|
+ */
|
|
+static void imx_pllv3_av_init(struct clk_imx_pll *pll)
|
|
+{
|
|
+ struct clk_pllv3 *av_pll;
|
|
+
|
|
+ av_pll = (struct clk_pllv3 *) container_of(pll, struct clk_pllv3,
|
|
+ imx_pll);
|
|
+
|
|
+ av_pll->orig_num = readl_relaxed(av_pll->base + av_pll->num_offset);
|
|
+ av_pll->orig_denom = readl_relaxed(av_pll->base + av_pll->denom_offset);
|
|
+ av_pll->orig_div = readl_relaxed(av_pll->base) & av_pll->div_mask;
|
|
+}
|
|
+
|
|
+static unsigned long imx_pllv3_av_get_rate(struct clk_imx_pll *pll,
|
|
+ unsigned long parent_rate)
|
|
+{
|
|
+ struct clk_pllv3 *av_pll;
|
|
+
|
|
+ av_pll = (struct clk_pllv3 *) container_of(pll, struct clk_pllv3,
|
|
+ imx_pll);
|
|
+
|
|
+ return clk_pllv3_av_recalc_rate(&av_pll->hw, parent_rate);
|
|
+}
|
|
+
|
|
+static int imx_pllv3_av_set_rate(struct clk_imx_pll *pll, unsigned long rate,
|
|
+ unsigned long parent_rate)
|
|
+{
|
|
+ struct clk_pllv3 *av_pll;
|
|
+ int rc = IMX_CLK_PLL_SUCCESS;
|
|
+
|
|
+ av_pll = (struct clk_pllv3 *) container_of(pll, struct clk_pllv3,
|
|
+ imx_pll);
|
|
+
|
|
+ if (clk_pllv3_av_set_rate(&av_pll->hw, rate, parent_rate) < 0)
|
|
+ rc = -IMX_CLK_PLL_INVALID_PARAM;
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static const struct clk_imx_pll_ops imx_clk_pllv3_av_ops = {
|
|
+ .set_rate = imx_pllv3_av_set_rate,
|
|
+ .get_rate = imx_pllv3_av_get_rate,
|
|
+ .adjust = imx_pllv3_av_adjust,
|
|
+ .init = imx_pllv3_av_init,
|
|
+};
|
|
+
|
|
static unsigned long clk_pllv3_enet_recalc_rate(struct clk_hw *hw,
|
|
unsigned long parent_rate)
|
|
{
|
|
@@ -496,6 +601,7 @@ struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name,
|
|
fallthrough;
|
|
case IMX_PLLV3_AV:
|
|
ops = &clk_pllv3_av_ops;
|
|
+ pll->imx_pll.ops = &imx_clk_pllv3_av_ops;
|
|
break;
|
|
case IMX_PLLV3_ENET_IMX7:
|
|
pll->power_bit = IMX7_ENET_PLL_POWER;
|
|
@@ -533,6 +639,9 @@ struct clk_hw *imx_clk_hw_pllv3(enum imx_pllv3_type type, const char *name,
|
|
return ERR_PTR(ret);
|
|
}
|
|
|
|
+ if (imx_pll_register(&pll->imx_pll, name) < 0)
|
|
+ pr_warn("Failed to register %s into imx pll\n", name);
|
|
+
|
|
return hw;
|
|
}
|
|
EXPORT_SYMBOL_GPL(imx_clk_hw_pllv3);
|
|
diff --git a/drivers/clk/imx/clk-scu.c b/drivers/clk/imx/clk-scu.c
|
|
index c790e82c24c8..d0765cf9c3bc 100644
|
|
--- a/drivers/clk/imx/clk-scu.c
|
|
+++ b/drivers/clk/imx/clk-scu.c
|
|
@@ -18,6 +18,7 @@
|
|
#include <xen/xen.h>
|
|
|
|
#include "clk-scu.h"
|
|
+#include "clk-pll.h"
|
|
|
|
#define IMX_SIP_CPUFREQ 0xC2000001
|
|
#define IMX_SIP_SET_CPUFREQ 0x00
|
|
@@ -56,6 +57,8 @@ struct clk_scu {
|
|
u8 parent_index;
|
|
bool is_enabled;
|
|
u32 rate;
|
|
+ unsigned long original_rate;
|
|
+ struct clk_imx_pll imx_pll;
|
|
};
|
|
|
|
/*
|
|
@@ -466,6 +469,82 @@ static const struct clk_ops clk_scu_pi_ops = {
|
|
.set_rate = clk_scu_set_rate,
|
|
};
|
|
|
|
+static void imx_scu_init(struct clk_imx_pll *pll)
|
|
+{
|
|
+ struct clk_scu *clk;
|
|
+
|
|
+ clk = (struct clk_scu *) container_of(pll, struct clk_scu, imx_pll);
|
|
+
|
|
+ clk->original_rate = clk_scu_recalc_rate(&clk->hw, 0);
|
|
+
|
|
+ pr_info("SCU clock %p for PLL API init with original rate %lu\n",
|
|
+ clk, clk->original_rate);
|
|
+
|
|
+ return;
|
|
+}
|
|
+
|
|
+/* SCU is stating possible variation of +/-250Khz which gives around 300 ppm @ 786MHz
|
|
+ * Set a maximum adjustement at 250 ppm
|
|
+ */
|
|
+#define IMX_SCU_MAX_PPB_ADJUSTEMENT 250000
|
|
+
|
|
+static int imx_scu_adjust(struct clk_imx_pll *pll, int *ppb)
|
|
+{
|
|
+ struct clk_scu * clk = (struct clk_scu *) container_of(pll,
|
|
+ struct clk_scu, imx_pll);
|
|
+ unsigned long new_rate;
|
|
+ int delta;
|
|
+
|
|
+ if (!clk->original_rate) {
|
|
+ pr_warn_once("failed to get original rate for clock\n");
|
|
+ return -IMX_CLK_PLL_LOCK_ERR;
|
|
+ }
|
|
+
|
|
+ if (abs(*ppb) > IMX_SCU_MAX_PPB_ADJUSTEMENT) {
|
|
+ return -IMX_CLK_PLL_PREC_ERR;
|
|
+ }
|
|
+
|
|
+ if (*ppb < 0)
|
|
+ delta = -1;
|
|
+ else
|
|
+ delta = 1;
|
|
+
|
|
+ delta *= (int)div64_u64((u64)clk->original_rate * (u64)abs(*ppb),
|
|
+ 1000000000);
|
|
+
|
|
+ new_rate = clk->original_rate + delta;
|
|
+
|
|
+ if (clk_scu_set_rate(&clk->hw, new_rate, 0) < 0)
|
|
+ return -IMX_CLK_PLL_INVALID_PARAM;
|
|
+
|
|
+ return IMX_CLK_PLL_SUCCESS;
|
|
+}
|
|
+
|
|
+static int imx_scu_set_rate(struct clk_imx_pll *pll, unsigned long rate,
|
|
+ unsigned long parent_rate)
|
|
+{
|
|
+ struct clk_scu * clk = (struct clk_scu *) container_of(pll,
|
|
+ struct clk_scu, imx_pll);
|
|
+
|
|
+ return clk_scu_set_rate(&clk->hw, rate, 0);
|
|
+}
|
|
+
|
|
+static unsigned long imx_scu_get_rate(struct clk_imx_pll *pll,
|
|
+ unsigned long parent_rate)
|
|
+{
|
|
+ struct clk_scu * clk = (struct clk_scu *) container_of(pll,
|
|
+ struct clk_scu, imx_pll);
|
|
+
|
|
+ return clk_scu_recalc_rate(&clk->hw, 0);
|
|
+}
|
|
+
|
|
+static const struct clk_imx_pll_ops imx_clk_scu_ops = {
|
|
+ .set_rate = imx_scu_set_rate,
|
|
+ .get_rate = imx_scu_get_rate,
|
|
+ .adjust = imx_scu_adjust,
|
|
+ .init = imx_scu_init,
|
|
+};
|
|
+
|
|
struct clk_hw *__imx_clk_scu(struct device *dev, const char *name,
|
|
const char * const *parents, int num_parents,
|
|
u32 rsrc_id, u8 clk_type)
|
|
@@ -514,6 +593,13 @@ struct clk_hw *__imx_clk_scu(struct device *dev, const char *name,
|
|
if (dev)
|
|
dev_set_drvdata(dev, clk);
|
|
|
|
+ if (rsrc_id == IMX_SC_R_AUDIO_PLL_0 && clk_type == IMX_SC_PM_CLK_PLL) {
|
|
+ clk->imx_pll.ops = &imx_clk_scu_ops;
|
|
+
|
|
+ if (imx_pll_register(&clk->imx_pll, name) < 0)
|
|
+ pr_warn("%s: failed to register %s into imx pll\n", __func__, name);
|
|
+ }
|
|
+
|
|
return hw;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
|
|
index 172aa10a8800..4ae4720535a5 100644
|
|
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
|
|
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/dc_fpu.c
|
|
@@ -60,11 +60,9 @@ static DEFINE_PER_CPU(int, fpu_recursion_depth);
|
|
*/
|
|
inline void dc_assert_fp_enabled(void)
|
|
{
|
|
- int *pcpu, depth = 0;
|
|
+ int depth;
|
|
|
|
- pcpu = get_cpu_ptr(&fpu_recursion_depth);
|
|
- depth = *pcpu;
|
|
- put_cpu_ptr(&fpu_recursion_depth);
|
|
+ depth = __this_cpu_read(fpu_recursion_depth);
|
|
|
|
ASSERT(depth >= 1);
|
|
}
|
|
@@ -84,33 +82,28 @@ inline void dc_assert_fp_enabled(void)
|
|
*/
|
|
void dc_fpu_begin(const char *function_name, const int line)
|
|
{
|
|
- int *pcpu;
|
|
+ int depth;
|
|
|
|
- pcpu = get_cpu_ptr(&fpu_recursion_depth);
|
|
- *pcpu += 1;
|
|
+ WARN_ON_ONCE(!in_task());
|
|
+ preempt_disable();
|
|
+ depth = __this_cpu_inc_return(fpu_recursion_depth);
|
|
|
|
- if (*pcpu == 1) {
|
|
+ if (depth == 1) {
|
|
#if defined(CONFIG_X86) || defined(CONFIG_LOONGARCH)
|
|
- migrate_disable();
|
|
kernel_fpu_begin();
|
|
#elif defined(CONFIG_PPC64)
|
|
- if (cpu_has_feature(CPU_FTR_VSX_COMP)) {
|
|
- preempt_disable();
|
|
+ if (cpu_has_feature(CPU_FTR_VSX_COMP))
|
|
enable_kernel_vsx();
|
|
- } else if (cpu_has_feature(CPU_FTR_ALTIVEC_COMP)) {
|
|
- preempt_disable();
|
|
+ else if (cpu_has_feature(CPU_FTR_ALTIVEC_COMP))
|
|
enable_kernel_altivec();
|
|
- } else if (!cpu_has_feature(CPU_FTR_FPU_UNAVAILABLE)) {
|
|
- preempt_disable();
|
|
+ else if (!cpu_has_feature(CPU_FTR_FPU_UNAVAILABLE))
|
|
enable_kernel_fp();
|
|
- }
|
|
#elif defined(CONFIG_ARM64)
|
|
kernel_neon_begin();
|
|
#endif
|
|
}
|
|
|
|
- TRACE_DCN_FPU(true, function_name, line, *pcpu);
|
|
- put_cpu_ptr(&fpu_recursion_depth);
|
|
+ TRACE_DCN_FPU(true, function_name, line, depth);
|
|
}
|
|
|
|
/**
|
|
@@ -125,30 +118,26 @@ void dc_fpu_begin(const char *function_name, const int line)
|
|
*/
|
|
void dc_fpu_end(const char *function_name, const int line)
|
|
{
|
|
- int *pcpu;
|
|
+ int depth;
|
|
|
|
- pcpu = get_cpu_ptr(&fpu_recursion_depth);
|
|
- *pcpu -= 1;
|
|
- if (*pcpu <= 0) {
|
|
+ depth = __this_cpu_dec_return(fpu_recursion_depth);
|
|
+ if (depth == 0) {
|
|
#if defined(CONFIG_X86) || defined(CONFIG_LOONGARCH)
|
|
kernel_fpu_end();
|
|
- migrate_enable();
|
|
#elif defined(CONFIG_PPC64)
|
|
- if (cpu_has_feature(CPU_FTR_VSX_COMP)) {
|
|
+ if (cpu_has_feature(CPU_FTR_VSX_COMP))
|
|
disable_kernel_vsx();
|
|
- preempt_enable();
|
|
- } else if (cpu_has_feature(CPU_FTR_ALTIVEC_COMP)) {
|
|
+ else if (cpu_has_feature(CPU_FTR_ALTIVEC_COMP))
|
|
disable_kernel_altivec();
|
|
- preempt_enable();
|
|
- } else if (!cpu_has_feature(CPU_FTR_FPU_UNAVAILABLE)) {
|
|
+ else if (!cpu_has_feature(CPU_FTR_FPU_UNAVAILABLE))
|
|
disable_kernel_fp();
|
|
- preempt_enable();
|
|
- }
|
|
#elif defined(CONFIG_ARM64)
|
|
kernel_neon_end();
|
|
#endif
|
|
+ } else {
|
|
+ WARN_ON_ONCE(depth < 0);
|
|
}
|
|
|
|
- TRACE_DCN_FPU(false, function_name, line, *pcpu);
|
|
- put_cpu_ptr(&fpu_recursion_depth);
|
|
+ TRACE_DCN_FPU(false, function_name, line, depth);
|
|
+ preempt_enable();
|
|
}
|
|
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
|
|
index d587f807dfd7..5036a3e60832 100644
|
|
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
|
|
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
|
|
@@ -2141,9 +2141,17 @@ bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context,
|
|
bool fast_validate)
|
|
{
|
|
bool voltage_supported;
|
|
+ display_e2e_pipe_params_st *pipes;
|
|
+
|
|
+ pipes = kcalloc(dc->res_pool->pipe_count, sizeof(display_e2e_pipe_params_st), GFP_KERNEL);
|
|
+ if (!pipes)
|
|
+ return false;
|
|
+
|
|
DC_FP_START();
|
|
- voltage_supported = dcn20_validate_bandwidth_fp(dc, context, fast_validate);
|
|
+ voltage_supported = dcn20_validate_bandwidth_fp(dc, context, fast_validate, pipes);
|
|
DC_FP_END();
|
|
+
|
|
+ kfree(pipes);
|
|
return voltage_supported;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
|
|
index d1a25fe6c44f..5674c3450fc3 100644
|
|
--- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
|
|
+++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
|
|
@@ -953,9 +953,17 @@ static bool dcn21_validate_bandwidth(struct dc *dc, struct dc_state *context,
|
|
bool fast_validate)
|
|
{
|
|
bool voltage_supported;
|
|
+ display_e2e_pipe_params_st *pipes;
|
|
+
|
|
+ pipes = kcalloc(dc->res_pool->pipe_count, sizeof(display_e2e_pipe_params_st), GFP_KERNEL);
|
|
+ if (!pipes)
|
|
+ return false;
|
|
+
|
|
DC_FP_START();
|
|
- voltage_supported = dcn21_validate_bandwidth_fp(dc, context, fast_validate);
|
|
+ voltage_supported = dcn21_validate_bandwidth_fp(dc, context, fast_validate, pipes);
|
|
DC_FP_END();
|
|
+
|
|
+ kfree(pipes);
|
|
return voltage_supported;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
|
|
index 8a5a038fd855..68970d6cf031 100644
|
|
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
|
|
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
|
|
@@ -2018,7 +2018,7 @@ void dcn20_patch_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st
|
|
}
|
|
|
|
static bool dcn20_validate_bandwidth_internal(struct dc *dc, struct dc_state *context,
|
|
- bool fast_validate)
|
|
+ bool fast_validate, display_e2e_pipe_params_st *pipes)
|
|
{
|
|
bool out = false;
|
|
|
|
@@ -2027,7 +2027,6 @@ static bool dcn20_validate_bandwidth_internal(struct dc *dc, struct dc_state *co
|
|
int vlevel = 0;
|
|
int pipe_split_from[MAX_PIPES];
|
|
int pipe_cnt = 0;
|
|
- display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_ATOMIC);
|
|
DC_LOGGER_INIT(dc->ctx->logger);
|
|
|
|
BW_VAL_TRACE_COUNT();
|
|
@@ -2062,16 +2061,14 @@ static bool dcn20_validate_bandwidth_internal(struct dc *dc, struct dc_state *co
|
|
out = false;
|
|
|
|
validate_out:
|
|
- kfree(pipes);
|
|
|
|
BW_VAL_TRACE_FINISH();
|
|
|
|
return out;
|
|
}
|
|
|
|
-bool dcn20_validate_bandwidth_fp(struct dc *dc,
|
|
- struct dc_state *context,
|
|
- bool fast_validate)
|
|
+bool dcn20_validate_bandwidth_fp(struct dc *dc, struct dc_state *context,
|
|
+ bool fast_validate, display_e2e_pipe_params_st *pipes)
|
|
{
|
|
bool voltage_supported = false;
|
|
bool full_pstate_supported = false;
|
|
@@ -2090,11 +2087,11 @@ bool dcn20_validate_bandwidth_fp(struct dc *dc,
|
|
ASSERT(context != dc->current_state);
|
|
|
|
if (fast_validate) {
|
|
- return dcn20_validate_bandwidth_internal(dc, context, true);
|
|
+ return dcn20_validate_bandwidth_internal(dc, context, true, pipes);
|
|
}
|
|
|
|
// Best case, we support full UCLK switch latency
|
|
- voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false);
|
|
+ voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false, pipes);
|
|
full_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support;
|
|
|
|
if (context->bw_ctx.dml.soc.dummy_pstate_latency_us == 0 ||
|
|
@@ -2106,7 +2103,8 @@ bool dcn20_validate_bandwidth_fp(struct dc *dc,
|
|
// Fallback: Try to only support G6 temperature read latency
|
|
context->bw_ctx.dml.soc.dram_clock_change_latency_us = context->bw_ctx.dml.soc.dummy_pstate_latency_us;
|
|
|
|
- voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false);
|
|
+ memset(pipes, 0, dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st));
|
|
+ voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false, pipes);
|
|
dummy_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support;
|
|
|
|
if (voltage_supported && (dummy_pstate_supported || !(context->stream_count))) {
|
|
@@ -2311,9 +2309,8 @@ static void dcn21_calculate_wm(struct dc *dc, struct dc_state *context,
|
|
&context->bw_ctx.dml, pipes, pipe_cnt);
|
|
}
|
|
|
|
-bool dcn21_validate_bandwidth_fp(struct dc *dc,
|
|
- struct dc_state *context,
|
|
- bool fast_validate)
|
|
+bool dcn21_validate_bandwidth_fp(struct dc *dc, struct dc_state *context,
|
|
+ bool fast_validate, display_e2e_pipe_params_st *pipes)
|
|
{
|
|
bool out = false;
|
|
|
|
@@ -2322,7 +2319,6 @@ bool dcn21_validate_bandwidth_fp(struct dc *dc,
|
|
int vlevel = 0;
|
|
int pipe_split_from[MAX_PIPES];
|
|
int pipe_cnt = 0;
|
|
- display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_ATOMIC);
|
|
DC_LOGGER_INIT(dc->ctx->logger);
|
|
|
|
BW_VAL_TRACE_COUNT();
|
|
@@ -2362,7 +2358,6 @@ bool dcn21_validate_bandwidth_fp(struct dc *dc,
|
|
out = false;
|
|
|
|
validate_out:
|
|
- kfree(pipes);
|
|
|
|
BW_VAL_TRACE_FINISH();
|
|
|
|
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h
|
|
index c51badf7b68a..b6c34198ddc8 100644
|
|
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h
|
|
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h
|
|
@@ -61,9 +61,8 @@ void dcn20_update_bounding_box(struct dc *dc,
|
|
unsigned int num_states);
|
|
void dcn20_patch_bounding_box(struct dc *dc,
|
|
struct _vcs_dpi_soc_bounding_box_st *bb);
|
|
-bool dcn20_validate_bandwidth_fp(struct dc *dc,
|
|
- struct dc_state *context,
|
|
- bool fast_validate);
|
|
+bool dcn20_validate_bandwidth_fp(struct dc *dc, struct dc_state *context,
|
|
+ bool fast_validate, display_e2e_pipe_params_st *pipes);
|
|
void dcn20_fpu_set_wm_ranges(int i,
|
|
struct pp_smu_wm_range_sets *ranges,
|
|
struct _vcs_dpi_soc_bounding_box_st *loaded_bb);
|
|
@@ -77,9 +76,8 @@ int dcn21_populate_dml_pipes_from_context(struct dc *dc,
|
|
struct dc_state *context,
|
|
display_e2e_pipe_params_st *pipes,
|
|
bool fast_validate);
|
|
-bool dcn21_validate_bandwidth_fp(struct dc *dc,
|
|
- struct dc_state *context,
|
|
- bool fast_validate);
|
|
+bool dcn21_validate_bandwidth_fp(struct dc *dc, struct dc_state *context, bool
|
|
+ fast_validate, display_e2e_pipe_params_st *pipes);
|
|
void dcn21_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
|
|
|
|
void dcn21_clk_mgr_set_bw_params_wm_table(struct clk_bw_params *bw_params);
|
|
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
|
|
index ce397a8797f7..98c3f532822d 100644
|
|
--- a/drivers/gpu/drm/i915/Kconfig
|
|
+++ b/drivers/gpu/drm/i915/Kconfig
|
|
@@ -3,7 +3,6 @@ config DRM_I915
|
|
tristate "Intel 8xx/9xx/G3x/G4x/HD Graphics"
|
|
depends on DRM
|
|
depends on X86 && PCI
|
|
- depends on !PREEMPT_RT
|
|
select INTEL_GTT if X86
|
|
select INTERVAL_TREE
|
|
# we need shmfs for the swappable backing store, and in particular
|
|
diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c b/drivers/gpu/drm/i915/display/intel_crtc.c
|
|
index cfbfbfed3f5e..da2becfbc86c 100644
|
|
--- a/drivers/gpu/drm/i915/display/intel_crtc.c
|
|
+++ b/drivers/gpu/drm/i915/display/intel_crtc.c
|
|
@@ -562,7 +562,8 @@ void intel_pipe_update_start(struct intel_atomic_state *state,
|
|
*/
|
|
intel_psr_wait_for_idle_locked(new_crtc_state);
|
|
|
|
- local_irq_disable();
|
|
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT))
|
|
+ local_irq_disable();
|
|
|
|
crtc->debug.min_vbl = min;
|
|
crtc->debug.max_vbl = max;
|
|
@@ -587,11 +588,13 @@ void intel_pipe_update_start(struct intel_atomic_state *state,
|
|
break;
|
|
}
|
|
|
|
- local_irq_enable();
|
|
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT))
|
|
+ local_irq_enable();
|
|
|
|
timeout = schedule_timeout(timeout);
|
|
|
|
- local_irq_disable();
|
|
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT))
|
|
+ local_irq_disable();
|
|
}
|
|
|
|
finish_wait(wq, &wait);
|
|
@@ -624,7 +627,8 @@ void intel_pipe_update_start(struct intel_atomic_state *state,
|
|
return;
|
|
|
|
irq_disable:
|
|
- local_irq_disable();
|
|
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT))
|
|
+ local_irq_disable();
|
|
}
|
|
|
|
#if IS_ENABLED(CONFIG_DRM_I915_DEBUG_VBLANK_EVADE)
|
|
@@ -728,7 +732,8 @@ void intel_pipe_update_end(struct intel_atomic_state *state,
|
|
*/
|
|
intel_vrr_send_push(new_crtc_state);
|
|
|
|
- local_irq_enable();
|
|
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT))
|
|
+ local_irq_enable();
|
|
|
|
if (intel_vgpu_active(dev_priv))
|
|
return;
|
|
diff --git a/drivers/gpu/drm/i915/display/intel_vblank.c b/drivers/gpu/drm/i915/display/intel_vblank.c
|
|
index f5659ebd08eb..5b6d2f55528d 100644
|
|
--- a/drivers/gpu/drm/i915/display/intel_vblank.c
|
|
+++ b/drivers/gpu/drm/i915/display/intel_vblank.c
|
|
@@ -294,7 +294,8 @@ static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc,
|
|
*/
|
|
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
|
|
|
|
- /* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
|
|
+ if (IS_ENABLED(CONFIG_PREEMPT_RT))
|
|
+ preempt_disable();
|
|
|
|
/* Get optional system timestamp before query. */
|
|
if (stime)
|
|
@@ -358,7 +359,8 @@ static bool i915_get_crtc_scanoutpos(struct drm_crtc *_crtc,
|
|
if (etime)
|
|
*etime = ktime_get();
|
|
|
|
- /* preempt_enable_rt() should go right here in PREEMPT_RT patchset. */
|
|
+ if (IS_ENABLED(CONFIG_PREEMPT_RT))
|
|
+ preempt_enable();
|
|
|
|
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
|
|
|
|
diff --git a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c
|
|
index f2973cd1a8aa..aa77f8601b8a 100644
|
|
--- a/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c
|
|
+++ b/drivers/gpu/drm/i915/gt/intel_breadcrumbs.c
|
|
@@ -315,7 +315,12 @@ void __intel_breadcrumbs_park(struct intel_breadcrumbs *b)
|
|
return;
|
|
|
|
/* Kick the work once more to drain the signalers, and disarm the irq */
|
|
- irq_work_queue(&b->irq_work);
|
|
+ irq_work_sync(&b->irq_work);
|
|
+ while (READ_ONCE(b->irq_armed) && !atomic_read(&b->active)) {
|
|
+ irq_work_queue(&b->irq_work);
|
|
+ cond_resched();
|
|
+ irq_work_sync(&b->irq_work);
|
|
+ }
|
|
}
|
|
|
|
void intel_breadcrumbs_free(struct kref *kref)
|
|
diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
|
|
index 2065be5a196b..73d815fc514b 100644
|
|
--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
|
|
+++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
|
|
@@ -1303,7 +1303,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
|
|
* and context switches) submission.
|
|
*/
|
|
|
|
- spin_lock(&sched_engine->lock);
|
|
+ spin_lock_irq(&sched_engine->lock);
|
|
|
|
/*
|
|
* If the queue is higher priority than the last
|
|
@@ -1403,7 +1403,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
|
|
* Even if ELSP[1] is occupied and not worthy
|
|
* of timeslices, our queue might be.
|
|
*/
|
|
- spin_unlock(&sched_engine->lock);
|
|
+ spin_unlock_irq(&sched_engine->lock);
|
|
return;
|
|
}
|
|
}
|
|
@@ -1429,7 +1429,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
|
|
|
|
if (last && !can_merge_rq(last, rq)) {
|
|
spin_unlock(&ve->base.sched_engine->lock);
|
|
- spin_unlock(&engine->sched_engine->lock);
|
|
+ spin_unlock_irq(&engine->sched_engine->lock);
|
|
return; /* leave this for another sibling */
|
|
}
|
|
|
|
@@ -1591,7 +1591,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
|
|
*/
|
|
sched_engine->queue_priority_hint = queue_prio(sched_engine);
|
|
i915_sched_engine_reset_on_empty(sched_engine);
|
|
- spin_unlock(&sched_engine->lock);
|
|
+ spin_unlock_irq(&sched_engine->lock);
|
|
|
|
/*
|
|
* We can skip poking the HW if we ended up with exactly the same set
|
|
@@ -1617,13 +1617,6 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
|
|
}
|
|
}
|
|
|
|
-static void execlists_dequeue_irq(struct intel_engine_cs *engine)
|
|
-{
|
|
- local_irq_disable(); /* Suspend interrupts across request submission */
|
|
- execlists_dequeue(engine);
|
|
- local_irq_enable(); /* flush irq_work (e.g. breadcrumb enabling) */
|
|
-}
|
|
-
|
|
static void clear_ports(struct i915_request **ports, int count)
|
|
{
|
|
memset_p((void **)ports, NULL, count);
|
|
@@ -2478,7 +2471,7 @@ static void execlists_submission_tasklet(struct tasklet_struct *t)
|
|
}
|
|
|
|
if (!engine->execlists.pending[0]) {
|
|
- execlists_dequeue_irq(engine);
|
|
+ execlists_dequeue(engine);
|
|
start_timeslice(engine);
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/i915/gt/intel_reset.c b/drivers/gpu/drm/i915/gt/intel_reset.c
|
|
index 13fb8e5042c5..b51fb0c97772 100644
|
|
--- a/drivers/gpu/drm/i915/gt/intel_reset.c
|
|
+++ b/drivers/gpu/drm/i915/gt/intel_reset.c
|
|
@@ -164,13 +164,13 @@ static int i915_do_reset(struct intel_gt *gt,
|
|
/* Assert reset for at least 20 usec, and wait for acknowledgement. */
|
|
pci_write_config_byte(pdev, I915_GDRST, GRDOM_RESET_ENABLE);
|
|
udelay(50);
|
|
- err = wait_for_atomic(i915_in_reset(pdev), 50);
|
|
+ err = _wait_for_atomic(i915_in_reset(pdev), 50, 0);
|
|
|
|
/* Clear the reset request. */
|
|
pci_write_config_byte(pdev, I915_GDRST, 0);
|
|
udelay(50);
|
|
if (!err)
|
|
- err = wait_for_atomic(!i915_in_reset(pdev), 50);
|
|
+ err = _wait_for_atomic(!i915_in_reset(pdev), 50, 0);
|
|
|
|
return err;
|
|
}
|
|
@@ -190,7 +190,7 @@ static int g33_do_reset(struct intel_gt *gt,
|
|
struct pci_dev *pdev = to_pci_dev(gt->i915->drm.dev);
|
|
|
|
pci_write_config_byte(pdev, I915_GDRST, GRDOM_RESET_ENABLE);
|
|
- return wait_for_atomic(g4x_reset_complete(pdev), 50);
|
|
+ return _wait_for_atomic(g4x_reset_complete(pdev), 50, 0);
|
|
}
|
|
|
|
static int g4x_do_reset(struct intel_gt *gt,
|
|
@@ -207,7 +207,7 @@ static int g4x_do_reset(struct intel_gt *gt,
|
|
|
|
pci_write_config_byte(pdev, I915_GDRST,
|
|
GRDOM_MEDIA | GRDOM_RESET_ENABLE);
|
|
- ret = wait_for_atomic(g4x_reset_complete(pdev), 50);
|
|
+ ret = _wait_for_atomic(g4x_reset_complete(pdev), 50, 0);
|
|
if (ret) {
|
|
GT_TRACE(gt, "Wait for media reset failed\n");
|
|
goto out;
|
|
@@ -215,7 +215,7 @@ static int g4x_do_reset(struct intel_gt *gt,
|
|
|
|
pci_write_config_byte(pdev, I915_GDRST,
|
|
GRDOM_RENDER | GRDOM_RESET_ENABLE);
|
|
- ret = wait_for_atomic(g4x_reset_complete(pdev), 50);
|
|
+ ret = _wait_for_atomic(g4x_reset_complete(pdev), 50, 0);
|
|
if (ret) {
|
|
GT_TRACE(gt, "Wait for render reset failed\n");
|
|
goto out;
|
|
@@ -785,9 +785,7 @@ int __intel_gt_reset(struct intel_gt *gt, intel_engine_mask_t engine_mask)
|
|
reset_mask = wa_14015076503_start(gt, engine_mask, !retry);
|
|
|
|
GT_TRACE(gt, "engine_mask=%x\n", reset_mask);
|
|
- preempt_disable();
|
|
ret = reset(gt, reset_mask, retry);
|
|
- preempt_enable();
|
|
|
|
wa_14015076503_end(gt, reset_mask);
|
|
}
|
|
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
|
|
index 8dc291ff0093..5b8d084c9c58 100644
|
|
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
|
|
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
|
|
@@ -317,7 +317,7 @@ static inline int intel_guc_send_busy_loop(struct intel_guc *guc,
|
|
{
|
|
int err;
|
|
unsigned int sleep_period_ms = 1;
|
|
- bool not_atomic = !in_atomic() && !irqs_disabled();
|
|
+ bool not_atomic = !in_atomic() && !irqs_disabled() && !rcu_preempt_depth();
|
|
|
|
/*
|
|
* FIXME: Have caller pass in if we are in an atomic context to avoid
|
|
diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
|
|
index f59081066a19..014d02029a41 100644
|
|
--- a/drivers/gpu/drm/i915/i915_request.c
|
|
+++ b/drivers/gpu/drm/i915/i915_request.c
|
|
@@ -609,7 +609,6 @@ bool __i915_request_submit(struct i915_request *request)
|
|
|
|
RQ_TRACE(request, "\n");
|
|
|
|
- GEM_BUG_ON(!irqs_disabled());
|
|
lockdep_assert_held(&engine->sched_engine->lock);
|
|
|
|
/*
|
|
@@ -718,7 +717,6 @@ void __i915_request_unsubmit(struct i915_request *request)
|
|
*/
|
|
RQ_TRACE(request, "\n");
|
|
|
|
- GEM_BUG_ON(!irqs_disabled());
|
|
lockdep_assert_held(&engine->sched_engine->lock);
|
|
|
|
/*
|
|
diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h
|
|
index ce1cbee1b39d..3c51620d011b 100644
|
|
--- a/drivers/gpu/drm/i915/i915_trace.h
|
|
+++ b/drivers/gpu/drm/i915/i915_trace.h
|
|
@@ -6,6 +6,10 @@
|
|
#if !defined(_I915_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
|
|
#define _I915_TRACE_H_
|
|
|
|
+#ifdef CONFIG_PREEMPT_RT
|
|
+#define NOTRACE
|
|
+#endif
|
|
+
|
|
#include <linux/stringify.h>
|
|
#include <linux/types.h>
|
|
#include <linux/tracepoint.h>
|
|
@@ -322,7 +326,7 @@ DEFINE_EVENT(i915_request, i915_request_add,
|
|
TP_ARGS(rq)
|
|
);
|
|
|
|
-#if defined(CONFIG_DRM_I915_LOW_LEVEL_TRACEPOINTS)
|
|
+#if defined(CONFIG_DRM_I915_LOW_LEVEL_TRACEPOINTS) && !defined(NOTRACE)
|
|
DEFINE_EVENT(i915_request, i915_request_guc_submit,
|
|
TP_PROTO(struct i915_request *rq),
|
|
TP_ARGS(rq)
|
|
diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h
|
|
index c61066498bf2..48e19e55d6b0 100644
|
|
--- a/drivers/gpu/drm/i915/i915_utils.h
|
|
+++ b/drivers/gpu/drm/i915/i915_utils.h
|
|
@@ -288,7 +288,7 @@ wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms)
|
|
#define wait_for(COND, MS) _wait_for((COND), (MS) * 1000, 10, 1000)
|
|
|
|
/* If CONFIG_PREEMPT_COUNT is disabled, in_atomic() always reports false. */
|
|
-#if defined(CONFIG_DRM_I915_DEBUG) && defined(CONFIG_PREEMPT_COUNT)
|
|
+#if defined(CONFIG_DRM_I915_DEBUG) && defined(CONFIG_PREEMPT_COUNT) && !defined(CONFIG_PREEMPT_RT)
|
|
# define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) WARN_ON_ONCE((ATOMIC) && !in_atomic())
|
|
#else
|
|
# define _WAIT_FOR_ATOMIC_CHECK(ATOMIC) do { } while (0)
|
|
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
|
|
index e575048af139..fa58ec612b67 100644
|
|
--- a/drivers/irqchip/Kconfig
|
|
+++ b/drivers/irqchip/Kconfig
|
|
@@ -689,4 +689,8 @@ config SUNPLUS_SP7021_INTC
|
|
chained controller, routing all interrupt source in P-Chip to
|
|
the primary controller on C-Chip.
|
|
|
|
+config BAREMETAL
|
|
+ bool
|
|
+ depends on ARM_GIC || ARM_GIC_V3
|
|
+
|
|
endmenu
|
|
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
|
|
index ffd945fe71aa..4d6fef2c9aee 100644
|
|
--- a/drivers/irqchip/Makefile
|
|
+++ b/drivers/irqchip/Makefile
|
|
@@ -120,3 +120,4 @@ obj-$(CONFIG_IRQ_IDT3243X) += irq-idt3243x.o
|
|
obj-$(CONFIG_APPLE_AIC) += irq-apple-aic.o
|
|
obj-$(CONFIG_MCHP_EIC) += irq-mchp-eic.o
|
|
obj-$(CONFIG_SUNPLUS_SP7021_INTC) += irq-sp7021-intc.o
|
|
+obj-$(CONFIG_BAREMETAL) += ipi-baremetal.o
|
|
\ No newline at end of file
|
|
diff --git a/drivers/irqchip/ipi-baremetal.c b/drivers/irqchip/ipi-baremetal.c
|
|
new file mode 100644
|
|
index 000000000000..58f88546b6f0
|
|
--- /dev/null
|
|
+++ b/drivers/irqchip/ipi-baremetal.c
|
|
@@ -0,0 +1,454 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * IPI for inter-core communiction for NXP Layerscape baremetal
|
|
+ *
|
|
+ * Copyright 2018-2023 NXP
|
|
+ *
|
|
+ */
|
|
+#include <linux/init.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/miscdevice.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <asm/siginfo.h>
|
|
+#include <linux/uaccess.h>
|
|
+#include <linux/mman.h>
|
|
+#include <linux/ipi_baremetal.h>
|
|
+
|
|
+int pid;
|
|
+int mycoreid;
|
|
+
|
|
+#undef IPI_BAREMETAL_SIGNAL
|
|
+
|
|
+#define DEVICE_NAME "ipi_bm"
|
|
+
|
|
+/*
|
|
+ * choose 50 as baremetal signal number.
|
|
+ * real-time signals are in the range of 33 to 64.
|
|
+ */
|
|
+#define SIG_BM 50
|
|
+
|
|
+#ifndef IPI_BAREMETAL_SIGNAL
|
|
+void __iomem *share_base;
|
|
+#ifdef CONFIG_SOC_IMX6Q_BAREMETAL
|
|
+#define GICD_BASE 0x00A01000
|
|
+#define GICD_SIZE 0x1000
|
|
+#define GICC_BASE 0x00A00100
|
|
+#define GICC_SIZE 0x1000
|
|
+#define GIC_DIST_IGROUP 0x080
|
|
+#define GIC_DIST_CTRL 0x000
|
|
+#define GIC_CPU_CTRL 0x00
|
|
+#define GICD_ENABLE 0x3
|
|
+#define GICC_ENABLE 0x7
|
|
+#endif
|
|
+#if defined(CONFIG_SOC_IMX6Q_BAREMETAL)
|
|
+#define CONFIG_SYS_DDR_SDRAM_BASE 0x10000000UL
|
|
+#define CONFIG_SYS_DDR_SDRAM_SLAVE_SIZE (128 * 1024 * 1024)
|
|
+#define CONFIG_SYS_DDR_SDRAM_MASTER_SIZE (512 * 1024 * 1024)
|
|
+#elif defined(CONFIG_LX2160A_BAREMETAL)
|
|
+#define CONFIG_SYS_DDR_SDRAM_BASE 0x80000000UL
|
|
+#define CONFIG_SYS_DDR_SDRAM_SLAVE_SIZE (64 * 1024 * 1024)
|
|
+#define CONFIG_SYS_DDR_SDRAM_MASTER_SIZE (512 * 1024 * 1024)
|
|
+#elif defined(CONFIG_IMX8M_BAREMETAL)
|
|
+#define CONFIG_SYS_DDR_SDRAM_SLAVE_ADDR (0x60000000)
|
|
+#define CONFIG_SYS_DDR_SDRAM_SLAVE_SIZE (32 * 1024 * 1024)
|
|
+#define CONFIG_SYS_DDR_SDRAM_SLAVE_RESERVE_SIZE (32 * 1024 *1024)
|
|
+#elif defined(CONFIG_IMX93_BAREMETAL)
|
|
+#define CONFIG_SYS_DDR_SDRAM_SLAVE_ADDR (0xb0000000)
|
|
+#define CONFIG_SYS_DDR_SDRAM_SLAVE_SIZE (32 * 1024 * 1024)
|
|
+#define CONFIG_SYS_DDR_SDRAM_SLAVE_RESERVE_SIZE (32 * 1024 *1024)
|
|
+#else
|
|
+#define CONFIG_SYS_DDR_SDRAM_BASE 0x80000000UL
|
|
+#define CONFIG_SYS_DDR_SDRAM_SLAVE_SIZE (256 * 1024 * 1024)
|
|
+#define CONFIG_SYS_DDR_SDRAM_MASTER_SIZE (512 * 1024 * 1024)
|
|
+#endif
|
|
+
|
|
+#if defined(CONFIG_IMX8M_BAREMETAL) || defined(CONFIG_IMX93_BAREMETAL)
|
|
+#define CONFIG_SYS_DDR_SDRAM_SHARE_BASE (CONFIG_SYS_DDR_SDRAM_SLAVE_ADDR \
|
|
+ + CONFIG_SYS_DDR_SDRAM_SLAVE_SIZE*(CONFIG_MAX_CPUS-1))
|
|
+#define CONFIG_SYS_DDR_SDRAM_SHARE_RESERVE_SIZE (4 * 1024 * 1024)
|
|
+#else
|
|
+#define CONFIG_SYS_DDR_SDRAM_SHARE_BASE \
|
|
+ (CONFIG_SYS_DDR_SDRAM_BASE + CONFIG_SYS_DDR_SDRAM_MASTER_SIZE \
|
|
+ + CONFIG_SYS_DDR_SDRAM_SLAVE_SIZE * (CONFIG_MAX_CPUS - 1))
|
|
+
|
|
+#define CONFIG_SYS_DDR_SDRAM_SHARE_RESERVE_SIZE (16 * 1024 * 1024)
|
|
+#endif
|
|
+
|
|
+#if defined(CONFIG_SOC_IMX6Q_BAREMETAL)
|
|
+#define CONFIG_SYS_DDR_SDRAM_SHARE_SIZE \
|
|
+ ((128 * 1024 * 1024) - CONFIG_SYS_DDR_SDRAM_SHARE_RESERVE_SIZE)
|
|
+#elif defined(CONFIG_LX2160A_BAREMETAL)
|
|
+#define CONFIG_SYS_DDR_SDRAM_SHARE_SIZE \
|
|
+ ((64 * 1024 * 1024) - CONFIG_SYS_DDR_SDRAM_SHARE_RESERVE_SIZE)
|
|
+#elif defined(CONFIG_IMX8M_BAREMETAL) || defined(CONFIG_IMX93_BAREMETAL)
|
|
+#define CONFIG_SYS_DDR_SDRAM_SHARE_SIZE (CONFIG_SYS_DDR_SDRAM_SLAVE_RESERVE_SIZE \
|
|
+ - CONFIG_SYS_DDR_SDRAM_SHARE_RESERVE_SIZE)
|
|
+#else
|
|
+#define CONFIG_SYS_DDR_SDRAM_SHARE_SIZE \
|
|
+ ((256 * 1024 * 1024) - CONFIG_SYS_DDR_SDRAM_SHARE_RESERVE_SIZE)
|
|
+#endif
|
|
+#define CONFIG_SYS_DDR_SDRAM_SHARE_RESERVE_BASE \
|
|
+ (CONFIG_SYS_DDR_SDRAM_SHARE_BASE + CONFIG_SYS_DDR_SDRAM_SHARE_SIZE)
|
|
+
|
|
+/* number of descriptor for each ring */
|
|
+#define ICC_RING_ENTRY 128
|
|
+/* size of each block */
|
|
+#define ICC_BLOCK_UNIT_SIZE (4 * 1024)
|
|
+/* 2M space for core's ring and desc struct */
|
|
+#define ICC_RING_DESC_SPACE (2 * 1024 * 1024)
|
|
+
|
|
+/* share memory size for each core icc */
|
|
+#define ICC_CORE_MEM_SPACE (CONFIG_SYS_DDR_SDRAM_SHARE_SIZE / CONFIG_MAX_CPUS)
|
|
+/* share memory base for core x */
|
|
+#define ICC_CORE_MEM_BASE_PHY(x) \
|
|
+ (CONFIG_SYS_DDR_SDRAM_SHARE_BASE + (x) * ICC_CORE_MEM_SPACE)
|
|
+/* share memory base for core x */
|
|
+#define ICC_CORE_MEM_BASE(x) \
|
|
+ ((unsigned long)share_base + (x) * ICC_CORE_MEM_SPACE)
|
|
+/* the ring struct addr of core x ring y */
|
|
+#define ICC_CORE_RING_BASE(x, y) \
|
|
+ (ICC_CORE_MEM_BASE(x) + (y) * sizeof(struct icc_ring))
|
|
+/* the desc struct addr of core x */
|
|
+#define ICC_CORE_DESC_BASE_PHY(x) \
|
|
+ (ICC_CORE_MEM_BASE_PHY(x) + CONFIG_MAX_CPUS * sizeof(struct icc_ring))
|
|
+/*
|
|
+ * The core x block memory base addr for icc data transfer.
|
|
+ * The beginning 2M space of core x icc memory is for
|
|
+ * core x ring and desc struct.
|
|
+ */
|
|
+#define ICC_CORE_BLOCK_BASE_PHY(x) \
|
|
+ (ICC_CORE_MEM_BASE_PHY(x) + ICC_RING_DESC_SPACE)
|
|
+#define ICC_CORE_BLOCK_BASE(x) (ICC_CORE_MEM_BASE(x) + ICC_RING_DESC_SPACE)
|
|
+#define ICC_CORE_BLOCK_END_PHY(x) \
|
|
+ (ICC_CORE_MEM_BASE_PHY(x) + ICC_CORE_MEM_SPACE)
|
|
+#define ICC_CORE_BLOCK_END(x) (ICC_CORE_MEM_BASE(x) + ICC_CORE_MEM_SPACE)
|
|
+#define ICC_CORE_BLOCK_COUNT \
|
|
+ ((ICC_CORE_MEM_SPACE - ICC_RING_DESC_SPACE)/ICC_BLOCK_UNIT_SIZE)
|
|
+
|
|
+#define ICC_PHY2VIRT(x) \
|
|
+ (((void *)x - ICC_CORE_MEM_BASE_PHY(mycoreid)) \
|
|
+ + ICC_CORE_MEM_BASE(mycoreid))
|
|
+#define ICC_VIRT2PHY(x) \
|
|
+ (((void *)x - ICC_CORE_MEM_BASE(mycoreid)) \
|
|
+ + ICC_CORE_MEM_BASE_PHY(mycoreid))
|
|
+
|
|
+#define IPIDEV_IOCIRQ 1
|
|
+
|
|
+#define ICC_CMD_TX_DATA 0x00
|
|
+#define ICC_CMD_DUMP_TIME 0x01
|
|
+
|
|
+struct icc_desc {
|
|
+ unsigned long block_addr; /* block address */
|
|
+ unsigned int byte_count; /* available bytes */
|
|
+ unsigned int option_mode; /* option mode for this icc irq */
|
|
+};
|
|
+
|
|
+struct icc_ring {
|
|
+ unsigned int src_coreid; /* which core created the ring */
|
|
+ unsigned int dest_coreid; /* which core the ring sends SGI to */
|
|
+ unsigned int interrupt; /* which interrupt (SGI) be used */
|
|
+ unsigned int desc_num; /* number of descriptor */
|
|
+ struct icc_desc *desc; /* pointer of the first descriptor */
|
|
+ unsigned int desc_head; /* modified by producer */
|
|
+ unsigned int desc_tail; /* modified by consumer */
|
|
+ unsigned long busy_counts; /* statistic: ring full */
|
|
+ unsigned long interrupt_counts; /* statistic: total sent number */
|
|
+ unsigned int irq_status; /* status of the ring, set by producer, reset by consumer */
|
|
+};
|
|
+#endif
|
|
+
|
|
+int ipi_baremetal_open(struct inode *inode, struct file *filp)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+ssize_t ipi_baremetal_read(struct file *file,
|
|
+ char __user *buff, size_t count, loff_t *offp)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+ssize_t ipi_baremetal_write(struct file *file,
|
|
+ const char __user *buff, size_t count, loff_t *offp)
|
|
+{
|
|
+ char mybuf[10];
|
|
+ int ret;
|
|
+
|
|
+ /* read the value from user space */
|
|
+ if (count > 10)
|
|
+ return -EINVAL;
|
|
+ copy_from_user(mybuf, buff, count);
|
|
+ ret = kstrtoint(mybuf, 0, &pid);
|
|
+ if (ret)
|
|
+ return -EINVAL;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int ipi_baremetal_release(struct inode *inode, struct file *file)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#ifndef CONFIG_LS1021A_BAREMETAL
|
|
+static long ipi_baremetal_ioctl(struct file *file,
|
|
+ unsigned int cmd, unsigned long arg)
|
|
+{
|
|
+ unsigned long val;
|
|
+ unsigned long __user *argp = (unsigned long __user *)arg;
|
|
+ int err;
|
|
+#if defined(CONFIG_LX2160A_BAREMETAL)
|
|
+ unsigned long i, cluster, mask;
|
|
+#endif
|
|
+
|
|
+ err = copy_from_user(&val, argp, sizeof(val));
|
|
+ if (err)
|
|
+ return -EFAULT;
|
|
+
|
|
+ val |= ((unsigned long)1 << 40);
|
|
+
|
|
+#if defined(CONFIG_LX2160A_BAREMETAL)
|
|
+ val = *(unsigned long *)arg;
|
|
+
|
|
+ for (i = 0; i < 16; i++) {
|
|
+ if ((val >> i) & 0x1) {
|
|
+ cluster = i / 2;
|
|
+ mask = i % 2;
|
|
+ val |= (1 << mask) | (cluster << 16);
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+ switch (cmd) {
|
|
+ case IPIDEV_IOCIRQ:
|
|
+ write_sysreg_s(val, SYS_ICC_SGI1R_EL1);
|
|
+ break;
|
|
+ default:
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
+static int icc_ring_empty(struct icc_ring *ring)
|
|
+{
|
|
+ if (ring->desc_tail == ring->desc_head)
|
|
+ return 1;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* how many rx blocks are valid waiting to be handled */
|
|
+static int icc_ring_valid(struct icc_ring *ring)
|
|
+{
|
|
+ int valid;
|
|
+
|
|
+ if (icc_ring_empty(ring))
|
|
+ return 0;
|
|
+
|
|
+ if (ring->desc_head > ring->desc_tail)
|
|
+ valid = ring->desc_head - ring->desc_tail;
|
|
+ else
|
|
+ valid = ring->desc_num - ring->desc_tail + ring->desc_head;
|
|
+ return valid;
|
|
+}
|
|
+
|
|
+int ipi_baremetal_handle(u32 irqnr, u32 irqsrc)
|
|
+{
|
|
+#ifdef IPI_BAREMETAL_SIGNAL
|
|
+ struct siginfo info;
|
|
+ struct task_struct *t;
|
|
+ int si_data;
|
|
+ int ret;
|
|
+
|
|
+ if (!pid)
|
|
+ return 0;
|
|
+
|
|
+ si_data = (irqnr << 16) | irqsrc;
|
|
+ /* send the signal */
|
|
+ memset(&info, 0, sizeof(struct siginfo));
|
|
+ info.si_signo = SIG_BM;
|
|
+ info.si_code = SI_QUEUE;
|
|
+ info.si_int = si_data;
|
|
+
|
|
+ rcu_read_lock();
|
|
+ /* find the task_struct associated with this pid */
|
|
+ t = find_task_by_vpid(pid);
|
|
+ if (t == NULL) {
|
|
+ pr_info("no such pid\n");
|
|
+ rcu_read_unlock();
|
|
+ return -ENODEV;
|
|
+ }
|
|
+ rcu_read_unlock();
|
|
+
|
|
+ /* send the signal */
|
|
+ ret = send_sig_info(SIG_BM, &info, t);
|
|
+ if (ret < 0) {
|
|
+ pr_info("error sending signal\n");
|
|
+ return ret;
|
|
+ }
|
|
+#else
|
|
+ struct icc_ring *ring;
|
|
+ struct icc_desc *desc;
|
|
+ struct icc_desc *desc_phy;
|
|
+ unsigned long block_addr;
|
|
+ unsigned int byte_count, option_mode;
|
|
+ int i, valid;
|
|
+ int hw_irq, src_coreid;
|
|
+
|
|
+ hw_irq = irqnr;
|
|
+ src_coreid = irqsrc;
|
|
+
|
|
+ if (src_coreid == mycoreid) {
|
|
+ pr_err("Do not support self-icc now!\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ /* get the ring for this core from source core */
|
|
+ ring = (struct icc_ring *)ICC_CORE_RING_BASE(src_coreid, mycoreid);
|
|
+ valid = icc_ring_valid(ring);
|
|
+ for (i = 0; i < valid; i++) {
|
|
+ desc_phy = ring->desc + ring->desc_tail;
|
|
+ desc = ICC_PHY2VIRT(desc_phy);
|
|
+ option_mode = desc->option_mode;
|
|
+
|
|
+ if (option_mode & ICC_CMD_DUMP_TIME) {
|
|
+ pr_info("Get the SGI from CoreID: %d\n", src_coreid);
|
|
+ } else {
|
|
+ block_addr = desc->block_addr;
|
|
+ byte_count = desc->byte_count;
|
|
+
|
|
+ if ((*(char *)ICC_PHY2VIRT(block_addr)) != 0x5a)
|
|
+ pr_info("Get the ICC from core %d; block: 0x%lx, bytes: %d, value: 0x%x\n",
|
|
+ src_coreid, block_addr, byte_count,
|
|
+ (*(char *)ICC_PHY2VIRT(block_addr)));
|
|
+ }
|
|
+
|
|
+ /* add desc_tail */
|
|
+ ring->desc_tail = (ring->desc_tail + 1) % ring->desc_num;
|
|
+ }
|
|
+#endif
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct vm_operations_struct shd_mmap_mem_ops = {
|
|
+#ifdef CONFIG_HAVE_IOREMAP_PROT
|
|
+ .access = generic_access_phys
|
|
+#endif
|
|
+};
|
|
+
|
|
+static int shd_mmap_mem(struct file *file, struct vm_area_struct *vma)
|
|
+{
|
|
+ size_t size = vma->vm_end - vma->vm_start;
|
|
+
|
|
+#if defined(CONFIG_LS1021A_BAREMETAL) || defined(CONFIG_SOC_IMX6Q_BAREMETAL)
|
|
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
|
+#else
|
|
+ vma->vm_page_prot = pgprot_cached(vma->vm_page_prot);
|
|
+#endif
|
|
+ vma->vm_ops = &shd_mmap_mem_ops;
|
|
+
|
|
+ /* Remap-pfn-range will mark the range VM_IO */
|
|
+ if (remap_pfn_range(vma,
|
|
+ vma->vm_start,
|
|
+ vma->vm_pgoff,
|
|
+ size,
|
|
+ vma->vm_page_prot)) {
|
|
+ return -EAGAIN;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+const struct file_operations ipi_bm_ops = {
|
|
+ .owner = THIS_MODULE,
|
|
+ .open = ipi_baremetal_open,
|
|
+ .release = ipi_baremetal_release,
|
|
+ .read = ipi_baremetal_read,
|
|
+ .write = ipi_baremetal_write,
|
|
+ .mmap = shd_mmap_mem,
|
|
+#ifndef CONFIG_LS1021A_BAREMETAL
|
|
+ .unlocked_ioctl = ipi_baremetal_ioctl,
|
|
+#endif
|
|
+};
|
|
+
|
|
+static struct miscdevice ipi_bm_misc = {
|
|
+ .minor = MISC_DYNAMIC_MINOR,
|
|
+ .name = DEVICE_NAME,
|
|
+ .fops = &ipi_bm_ops,
|
|
+};
|
|
+
|
|
+#ifdef CONFIG_SOC_IMX6Q_BAREMETAL
|
|
+void gic_enable_dist(void)
|
|
+{
|
|
+ void __iomem *gicd_base, *gicc_base;
|
|
+
|
|
+ gicd_base = ioremap((phys_addr_t)GICD_BASE, GICD_SIZE);
|
|
+ if (!gicd_base) {
|
|
+ pr_err("failed to remap gicd base for ICC\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ gicc_base = ioremap((phys_addr_t)GICC_BASE, GICC_SIZE);
|
|
+ if (!gicc_base) {
|
|
+ pr_err("failed to remap gicc base for ICC\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ /* set the SGI interrupts for this core to group 1 */
|
|
+ writel(0xffffffff, gicd_base + GIC_DIST_IGROUP);
|
|
+ writel(GICD_ENABLE, gicd_base + GIC_DIST_CTRL);
|
|
+ writel(GICC_ENABLE, gicc_base + GIC_CPU_CTRL);
|
|
+ iounmap(gicd_base);
|
|
+ iounmap(gicc_base);
|
|
+}
|
|
+#endif
|
|
+
|
|
+static int __init ipi_baremetal_init(void)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ pr_info("NXP inter-core communiction IRQ driver\n");
|
|
+#ifndef IPI_BAREMETAL_SIGNAL
|
|
+#if defined(CONFIG_LS1021A_BAREMETAL) || defined(CONFIG_SOC_IMX6Q_BAREMETAL)
|
|
+ share_base = ioremap((phys_addr_t)CONFIG_SYS_DDR_SDRAM_SHARE_BASE,
|
|
+ CONFIG_SYS_DDR_SDRAM_SHARE_SIZE);
|
|
+#else
|
|
+ share_base = ioremap_cache((phys_addr_t)CONFIG_SYS_DDR_SDRAM_SHARE_BASE,
|
|
+ CONFIG_SYS_DDR_SDRAM_SHARE_SIZE);
|
|
+#endif
|
|
+ if (!share_base) {
|
|
+ pr_err("failed to remap share base (%lu/%u) for ICC\n",
|
|
+ CONFIG_SYS_DDR_SDRAM_SHARE_BASE,
|
|
+ CONFIG_SYS_DDR_SDRAM_SHARE_SIZE);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ mycoreid = 0;
|
|
+#ifdef CONFIG_SOC_IMX6Q_BAREMETAL
|
|
+ gic_enable_dist();
|
|
+#endif
|
|
+#endif
|
|
+ ret = misc_register(&ipi_bm_misc);
|
|
+ if (ret < 0) {
|
|
+ pr_info("Register ipi_bm error! ret: %d\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+ pr_info("ipi_bm device created!\n");
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void __exit ipi_baremetal_exit(void)
|
|
+{
|
|
+ pid = 0;
|
|
+#ifndef IPI_BAREMETAL_SIGNAL
|
|
+ iounmap(share_base);
|
|
+#endif
|
|
+ misc_deregister(&ipi_bm_misc);
|
|
+ pr_info("ipi_bm device deleted!\n");
|
|
+}
|
|
+
|
|
+module_init(ipi_baremetal_init);
|
|
+module_exit(ipi_baremetal_exit);
|
|
+
|
|
+MODULE_LICENSE("GPL");
|
|
+MODULE_AUTHOR("NXP");
|
|
+MODULE_DESCRIPTION("NXP inter-core communiction IPI driver");
|
|
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
|
|
index a09883e5006c..7069a2bdab7e 100644
|
|
--- a/drivers/irqchip/irq-gic-v3.c
|
|
+++ b/drivers/irqchip/irq-gic-v3.c
|
|
@@ -28,6 +28,10 @@
|
|
#include <linux/bits.h>
|
|
#include <linux/arm-smccc.h>
|
|
|
|
+#ifdef CONFIG_BAREMETAL
|
|
+#include <linux/ipi_baremetal.h>
|
|
+#endif
|
|
+
|
|
#include <asm/cputype.h>
|
|
#include <asm/exception.h>
|
|
#include <asm/smp_plat.h>
|
|
@@ -1430,12 +1434,12 @@ static void __init gic_smp_init(void)
|
|
"irqchip/arm/gicv3:starting",
|
|
gic_starting_cpu, NULL);
|
|
|
|
- /* Register all 8 non-secure SGIs */
|
|
- base_sgi = irq_domain_alloc_irqs(gic_data.domain, 8, NUMA_NO_NODE, &sgi_fwspec);
|
|
+ /* Register all 16 non-secure SGIs */
|
|
+ base_sgi = irq_domain_alloc_irqs(gic_data.domain, 16, NUMA_NO_NODE, &sgi_fwspec);
|
|
if (WARN_ON(base_sgi <= 0))
|
|
return;
|
|
|
|
- set_smp_ipi_range(base_sgi, 8);
|
|
+ set_smp_ipi_range(base_sgi, 16);
|
|
}
|
|
|
|
static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
|
|
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
|
|
index 412196a7dad5..5448b1441577 100644
|
|
--- a/drivers/irqchip/irq-gic.c
|
|
+++ b/drivers/irqchip/irq-gic.c
|
|
@@ -868,11 +868,11 @@ static __init void gic_smp_init(void)
|
|
"irqchip/arm/gic:starting",
|
|
gic_starting_cpu, NULL);
|
|
|
|
- base_sgi = irq_domain_alloc_irqs(gic_data[0].domain, 8, NUMA_NO_NODE, &sgi_fwspec);
|
|
+ base_sgi = irq_domain_alloc_irqs(gic_data[0].domain, 16, NUMA_NO_NODE, &sgi_fwspec);
|
|
if (WARN_ON(base_sgi <= 0))
|
|
return;
|
|
|
|
- set_smp_ipi_range(base_sgi, 8);
|
|
+ set_smp_ipi_range(base_sgi, 16);
|
|
}
|
|
#else
|
|
#define gic_smp_init() do { } while(0)
|
|
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
|
|
index bc2e265cb02d..84158265ae08 100644
|
|
--- a/drivers/mailbox/Kconfig
|
|
+++ b/drivers/mailbox/Kconfig
|
|
@@ -295,4 +295,13 @@ config QCOM_IPCC
|
|
acts as an interrupt controller for receiving interrupts from clients.
|
|
Say Y here if you want to build this driver.
|
|
|
|
+config GENERIC_SOFTWARE_MAILBOX
|
|
+ tristate "Generic software Mailbox driver"
|
|
+ depends on OF
|
|
+ select GENERIC_IRQ_INJECTION
|
|
+ select GIC_GENTLE_CONFIG if ARM_GIC_V3
|
|
+ help
|
|
+ This driver leverages unused interrupt line and shared memory to
|
|
+ implement a mailbox, which is used to send messages between different
|
|
+ OSes.
|
|
endif
|
|
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
|
|
index fc9376117111..38d6994df5e1 100644
|
|
--- a/drivers/mailbox/Makefile
|
|
+++ b/drivers/mailbox/Makefile
|
|
@@ -62,3 +62,5 @@ obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o
|
|
obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o
|
|
|
|
obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o
|
|
+
|
|
+obj-$(CONFIG_GENERIC_SOFTWARE_MAILBOX) += generic-software-mailbox.o
|
|
diff --git a/drivers/mailbox/generic-software-mailbox.c b/drivers/mailbox/generic-software-mailbox.c
|
|
new file mode 100644
|
|
index 000000000000..1938f45de6ec
|
|
--- /dev/null
|
|
+++ b/drivers/mailbox/generic-software-mailbox.c
|
|
@@ -0,0 +1,322 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2022-2023 NXP
|
|
+ */
|
|
+
|
|
+#include <linux/device.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/mailbox_controller.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/slab.h>
|
|
+
|
|
+/*
|
|
+ * Generic software Registers:
|
|
+ *
|
|
+ * TX_STATUS[n]: TX channel n status
|
|
+ * RX_STATUS[n]: RX channel n status
|
|
+ * 0: indicates message in T/RX_CH[n] is invalid and channel ready.
|
|
+ * 1: indicates message in T/RX_CH[n] is valid and channel busy.
|
|
+ * 2: indicates message in T/RX_CH[n] has been received by the peer.
|
|
+ * RXDB_STATUS[n]: RX doorbell channel n status
|
|
+ * 0: indicates channel ready.
|
|
+ * 1: indicates channel busy.
|
|
+ * 2: indicates channel doorbell has been received by the peer.
|
|
+ * TX_CH[n]: Transmit data register for channel n
|
|
+ * RX_CH[n]: Receive data register for channel n
|
|
+ *
|
|
+ * To send a message:
|
|
+ * Update the data register TX_CH[n] with the message, then set the
|
|
+ * TX_STATUS[n] to 1, inject a interrupt to remote side; after the
|
|
+ * transmission done set the TX_STATUS[n] back to 0.
|
|
+ *
|
|
+ * When received a message:
|
|
+ * Get the received data from RX_CH[n] and then set the RX_STATUS[n] to
|
|
+ * 2 and inject a interrupt to notify the remote side transmission done.
|
|
+ */
|
|
+
|
|
+#define MBOX_TX_CHAN (4)
|
|
+#define MBOX_RX_CHAN (4)
|
|
+#define MBOX_RXDB_CHAN (4)
|
|
+#define RX_CHAN_SHFT (MBOX_TX_CHAN)
|
|
+#define RXDB_CHAN_SHFT (MBOX_TX_CHAN + MBOX_RX_CHAN)
|
|
+#define MBOX_CHAN_MAX (MBOX_TX_CHAN + MBOX_RX_CHAN + MBOX_RXDB_CHAN)
|
|
+
|
|
+struct sw_mbox_reg {
|
|
+ uint32_t tx_status[MBOX_TX_CHAN];
|
|
+ uint32_t rx_status[MBOX_RX_CHAN];
|
|
+ uint32_t rxdb_status[MBOX_RXDB_CHAN];
|
|
+ uint32_t tx_ch[MBOX_TX_CHAN];
|
|
+ uint32_t rx_ch[MBOX_RX_CHAN];
|
|
+ uint32_t rxdb_ch[MBOX_RX_CHAN];
|
|
+ uint32_t ch_ack_flags; /*from bit0 each bit for each channel(tx_ch, rx_ch, rxdb_ch), 1: ack, 0:noack */
|
|
+};
|
|
+
|
|
+enum sw_mbox_channel_status {
|
|
+ S_READY,
|
|
+ S_BUSY,
|
|
+ S_DONE,
|
|
+};
|
|
+
|
|
+enum sw_mbox_type {
|
|
+ SW_TYPE_TX, /* Tx */
|
|
+ SW_TYPE_RX, /* Rx */
|
|
+ SW_TYPE_RXDB, /* Rx doorbell */
|
|
+};
|
|
+
|
|
+struct sw_mbox_con_priv {
|
|
+ uint32_t idx;
|
|
+ enum sw_mbox_type type;
|
|
+ struct sw_mbox *priv;
|
|
+};
|
|
+
|
|
+struct sw_mbox {
|
|
+ struct device *dev;
|
|
+ struct sw_mbox_reg __iomem *base;
|
|
+ struct sw_mbox_con_priv cp[MBOX_CHAN_MAX];
|
|
+ struct mbox_chan chan[MBOX_CHAN_MAX];
|
|
+ struct mbox_controller controller;
|
|
+ int irq;
|
|
+ int remote_irq;
|
|
+};
|
|
+
|
|
+static int sw_mbox_send_data(struct mbox_chan *chan, void *msg)
|
|
+{
|
|
+ struct sw_mbox_con_priv *cp = chan->con_priv;
|
|
+ struct sw_mbox *mbox = cp->priv;
|
|
+ uint32_t idx = cp->idx;
|
|
+ uint32_t *data = msg;
|
|
+ int ret;
|
|
+
|
|
+ if (cp->type != SW_TYPE_TX) {
|
|
+ dev_err(mbox->dev, "Channel type error\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ writel(*data, &mbox->base->tx_ch[idx]);
|
|
+ writel(S_BUSY, &mbox->base->tx_status[idx]);
|
|
+ ret = irq_set_irqchip_state(mbox->remote_irq, IRQCHIP_STATE_PENDING,
|
|
+ true);
|
|
+ if (ret) {
|
|
+ dev_err(mbox->dev, "Fail to inject IRQ\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static irqreturn_t sw_mbox_interrupt(int irq, void *dev_id)
|
|
+{
|
|
+ struct sw_mbox *mbox = dev_id;
|
|
+ irqreturn_t ret = IRQ_NONE;
|
|
+ uint32_t rxdb_status;
|
|
+ uint32_t rx_status;
|
|
+ uint32_t tx_status;
|
|
+ uint32_t rx_ch;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < MBOX_TX_CHAN; i++) {
|
|
+ tx_status = readl(&mbox->base->tx_status[i]);
|
|
+ if (tx_status == S_DONE) {
|
|
+ writel(S_READY, &mbox->base->tx_status[i]);
|
|
+ mbox_chan_txdone(&mbox->chan[i], 0);
|
|
+ ret = IRQ_HANDLED;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < MBOX_RX_CHAN; i++) {
|
|
+ rx_status = readl(&mbox->base->rx_status[i]);
|
|
+ if (rx_status == S_BUSY) {
|
|
+ rx_ch = readl(&mbox->base->rx_ch[i]);
|
|
+ mbox_chan_received_data(&mbox->chan[i + RX_CHAN_SHFT],
|
|
+ (void *)&rx_ch);
|
|
+ if (mbox->base->ch_ack_flags & (1 << (i + RX_CHAN_SHFT))) {
|
|
+ /* Sender need ACK */
|
|
+ writel(S_DONE, &mbox->base->rx_status[i]);
|
|
+ irq_set_irqchip_state(mbox->remote_irq,
|
|
+ IRQCHIP_STATE_PENDING, true);
|
|
+ } else {
|
|
+ /* set status to be ready if sender doesn't need ACK */
|
|
+ writel(S_READY, &mbox->base->rx_status[i]);
|
|
+ }
|
|
+ ret = IRQ_HANDLED;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < MBOX_RXDB_CHAN; i++) {
|
|
+ rxdb_status = readl(&mbox->base->rxdb_status[i]);
|
|
+ if (rxdb_status == S_BUSY) {
|
|
+ mbox_chan_received_data(&mbox->chan[i + RXDB_CHAN_SHFT],
|
|
+ NULL);
|
|
+ if (mbox->base->ch_ack_flags & (1 << (i + RXDB_CHAN_SHFT))) {
|
|
+ /* Sender need ACK */
|
|
+ writel(S_DONE, &mbox->base->rxdb_status[i]);
|
|
+ irq_set_irqchip_state(mbox->remote_irq,
|
|
+ IRQCHIP_STATE_PENDING, true);
|
|
+ } else {
|
|
+ /* set status to be ready if sender doesn't need ACK */
|
|
+ writel(S_READY, &mbox->base->rxdb_status[i]);
|
|
+ }
|
|
+ ret = IRQ_HANDLED;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int sw_mbox_startup(struct mbox_chan *chan)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void sw_mbox_shutdown(struct mbox_chan *chan)
|
|
+{
|
|
+}
|
|
+
|
|
+static const struct mbox_chan_ops sw_mbox_ops = {
|
|
+ .send_data = sw_mbox_send_data,
|
|
+ .startup = sw_mbox_startup,
|
|
+ .shutdown = sw_mbox_shutdown,
|
|
+};
|
|
+
|
|
+
|
|
+static struct mbox_chan *sw_mbox_xlate(struct mbox_controller *mbox,
|
|
+ const struct of_phandle_args *sp)
|
|
+{
|
|
+ struct mbox_chan *chan;
|
|
+ struct sw_mbox_con_priv *cp;
|
|
+ struct sw_mbox *sw_mb;
|
|
+ uint32_t type, idx, chan_idx, ack;
|
|
+
|
|
+ if (sp->args_count != 3) {
|
|
+ dev_err(mbox->dev, "Invalid argument count %d\n",
|
|
+ sp->args_count);
|
|
+ return ERR_PTR(-EINVAL);
|
|
+ }
|
|
+
|
|
+ type = sp->args[0];
|
|
+ idx = sp->args[1];
|
|
+ ack = sp->args[2];
|
|
+
|
|
+ switch (type) {
|
|
+ case SW_TYPE_TX:
|
|
+ chan_idx = idx;
|
|
+ break;
|
|
+ case SW_TYPE_RX:
|
|
+ chan_idx = RX_CHAN_SHFT + idx;
|
|
+ break;
|
|
+ case SW_TYPE_RXDB:
|
|
+ chan_idx = RXDB_CHAN_SHFT + idx;
|
|
+ break;
|
|
+ default:
|
|
+ dev_err(mbox->dev, "Invalid chan type: %d\n", type);
|
|
+ return ERR_PTR(-EINVAL);
|
|
+ }
|
|
+
|
|
+ if (chan_idx >= MBOX_CHAN_MAX) {
|
|
+ dev_err(mbox->dev, "Not supported channel number: %d. (type: %d, idx: %d)\n",
|
|
+ chan_idx, type, idx);
|
|
+ return ERR_PTR(-EINVAL);
|
|
+ }
|
|
+
|
|
+ chan = &mbox->chans[chan_idx];
|
|
+ cp = chan->con_priv;
|
|
+ sw_mb = cp->priv;
|
|
+ if (ack)
|
|
+ sw_mb->base->ch_ack_flags |= 1 << chan_idx;
|
|
+ else
|
|
+ sw_mb->base->ch_ack_flags &= ~(1 << chan_idx);
|
|
+
|
|
+ return chan;
|
|
+}
|
|
+
|
|
+static const struct of_device_id sw_mbox_of_match[] = {
|
|
+ { .compatible = "fsl,generic-software-mbox", },
|
|
+ {},
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, sw_mbox_of_match);
|
|
+
|
|
+static int sw_mailbox_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct device *dev = &pdev->dev;
|
|
+ struct sw_mbox *mbox;
|
|
+ int err, i;
|
|
+
|
|
+ mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
|
|
+ if (!mbox)
|
|
+ return -ENOMEM;
|
|
+ mbox->dev = dev;
|
|
+
|
|
+ mbox->irq = platform_get_irq_byname(pdev, "irq");
|
|
+ if (mbox->irq <= 0) {
|
|
+ dev_err(dev, "Failed to get irq\n");
|
|
+ return mbox->irq;
|
|
+ }
|
|
+ mbox->remote_irq = platform_get_irq_byname(pdev, "remote_irq");
|
|
+ if (mbox->remote_irq <= 0) {
|
|
+ dev_err(dev, "Failed to get remote irq\n");
|
|
+ return mbox->remote_irq;
|
|
+ }
|
|
+
|
|
+ err = devm_request_irq(dev, mbox->irq, sw_mbox_interrupt, IRQF_SHARED,
|
|
+ pdev->name, mbox);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ mbox->base = devm_platform_ioremap_resource(pdev, 0);
|
|
+ if (IS_ERR(mbox->base))
|
|
+ return PTR_ERR(mbox->base);
|
|
+
|
|
+ memset_io(mbox->base->tx_status, 0, 4 * MBOX_TX_CHAN);
|
|
+ memset_io(mbox->base->rx_status, 0, 4 * MBOX_RX_CHAN);
|
|
+ memset_io(mbox->base->rxdb_status, 0, 4 * MBOX_RXDB_CHAN);
|
|
+
|
|
+ mbox->controller.dev = dev;
|
|
+ mbox->controller.chans = mbox->chan;
|
|
+ mbox->controller.num_chans = MBOX_CHAN_MAX;
|
|
+ mbox->controller.ops = &sw_mbox_ops;
|
|
+ mbox->controller.of_xlate = sw_mbox_xlate;
|
|
+ mbox->controller.txdone_irq = true;
|
|
+
|
|
+ for (i = 0; i < MBOX_CHAN_MAX; i++) {
|
|
+ mbox->chan[i].con_priv = &mbox->cp[i];
|
|
+ mbox->cp[i].priv = mbox;
|
|
+ mbox->cp[i].idx = i;
|
|
+ }
|
|
+
|
|
+ err = devm_mbox_controller_register(dev, &mbox->controller);
|
|
+ if (err) {
|
|
+ dev_err(dev, "Failed to register mailbox %d\n", err);
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ platform_set_drvdata(pdev, mbox);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct platform_driver sw_mbox_driver = {
|
|
+ .driver = {
|
|
+ .name = "generic-software-mailbox",
|
|
+ .of_match_table = sw_mbox_of_match,
|
|
+ },
|
|
+ .probe = sw_mailbox_probe,
|
|
+};
|
|
+
|
|
+static int __init sw_mbox_init(void)
|
|
+{
|
|
+ return platform_driver_register(&sw_mbox_driver);
|
|
+}
|
|
+
|
|
+static void __exit sw_mbox_exit(void)
|
|
+{
|
|
+ platform_driver_unregister(&sw_mbox_driver);
|
|
+}
|
|
+
|
|
+module_init(sw_mbox_init);
|
|
+module_exit(sw_mbox_exit);
|
|
+
|
|
+MODULE_DESCRIPTION("Generic Software mailbox driver");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
|
|
index ebff3baf3045..3b6f153e1523 100644
|
|
--- a/drivers/mailbox/mailbox.c
|
|
+++ b/drivers/mailbox/mailbox.c
|
|
@@ -159,7 +159,7 @@ static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)
|
|
void mbox_chan_received_data(struct mbox_chan *chan, void *mssg)
|
|
{
|
|
/* No buffering the received data */
|
|
- if (chan->cl->rx_callback)
|
|
+ if (chan->cl && chan->cl->rx_callback)
|
|
chan->cl->rx_callback(chan->cl, mssg);
|
|
}
|
|
EXPORT_SYMBOL_GPL(mbox_chan_received_data);
|
|
diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c
|
|
index 4ba7b6df7986..145fc0f1b4f9 100644
|
|
--- a/drivers/mxc/ipu3/ipu_common.c
|
|
+++ b/drivers/mxc/ipu3/ipu_common.c
|
|
@@ -2923,8 +2923,9 @@ static irqreturn_t ipu_sync_irq_handler(int irq, void *desc)
|
|
uint32_t line, bit, int_stat, int_ctrl;
|
|
irqreturn_t result = IRQ_NONE;
|
|
const int int_reg[] = { 1, 2, 3, 4, 11, 12, 13, 14, 15, 0 };
|
|
+ unsigned long flags;
|
|
|
|
- spin_lock(&ipu->int_reg_spin_lock);
|
|
+ spin_lock_irqsave(&ipu->int_reg_spin_lock, flags);
|
|
|
|
for (i = 0; int_reg[i] != 0; i++) {
|
|
int_stat = ipu_cm_read(ipu,
|
|
@@ -2949,7 +2950,7 @@ static irqreturn_t ipu_sync_irq_handler(int irq, void *desc)
|
|
}
|
|
}
|
|
|
|
- spin_unlock(&ipu->int_reg_spin_lock);
|
|
+ spin_unlock_irqrestore(&ipu->int_reg_spin_lock, flags);
|
|
|
|
return result;
|
|
}
|
|
@@ -2960,8 +2961,9 @@ static irqreturn_t ipu_err_irq_handler(int irq, void *desc)
|
|
int i;
|
|
uint32_t int_stat;
|
|
const int err_reg[] = { 5, 6, 9, 10, 0 };
|
|
+ unsigned long flags;
|
|
|
|
- spin_lock(&ipu->int_reg_spin_lock);
|
|
+ spin_lock_irqsave(&ipu->int_reg_spin_lock, flags);
|
|
|
|
for (i = 0; err_reg[i] != 0; i++) {
|
|
int_stat = ipu_cm_read(ipu,
|
|
@@ -2980,7 +2982,7 @@ static irqreturn_t ipu_err_irq_handler(int irq, void *desc)
|
|
}
|
|
}
|
|
|
|
- spin_unlock(&ipu->int_reg_spin_lock);
|
|
+ spin_unlock_irqrestore(&ipu->int_reg_spin_lock, flags);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
diff --git a/drivers/mxc/ipu3/ipu_device.c b/drivers/mxc/ipu3/ipu_device.c
|
|
index 925aaffc5d95..d9f521174ce0 100644
|
|
--- a/drivers/mxc/ipu3/ipu_device.c
|
|
+++ b/drivers/mxc/ipu3/ipu_device.c
|
|
@@ -3249,7 +3249,7 @@ static int ipu_task_thread(void *argv)
|
|
uint32_t size;
|
|
unsigned long flags;
|
|
unsigned int cpu;
|
|
- struct cpumask cpu_mask;
|
|
+ struct cpumask cpu_mask = CPU_MASK_NONE;
|
|
struct ipu_thread_data *data = (struct ipu_thread_data *)argv;
|
|
|
|
thread_id++;
|
|
diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
|
|
index f8c1d73b251d..6365e73296cf 100644
|
|
--- a/drivers/net/dsa/Kconfig
|
|
+++ b/drivers/net/dsa/Kconfig
|
|
@@ -89,6 +89,8 @@ source "drivers/net/dsa/xrs700x/Kconfig"
|
|
|
|
source "drivers/net/dsa/realtek/Kconfig"
|
|
|
|
+source "drivers/net/dsa/netc/Kconfig"
|
|
+
|
|
config NET_DSA_RZN1_A5PSW
|
|
tristate "Renesas RZ/N1 A5PSW Ethernet switch support"
|
|
depends on OF && ARCH_RZN1
|
|
diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
|
|
index cb9a97340e58..f641c13c533c 100644
|
|
--- a/drivers/net/dsa/Makefile
|
|
+++ b/drivers/net/dsa/Makefile
|
|
@@ -26,3 +26,4 @@ obj-y += qca/
|
|
obj-y += realtek/
|
|
obj-y += sja1105/
|
|
obj-y += xrs700x/
|
|
+obj-y += netc/
|
|
\ No newline at end of file
|
|
diff --git a/drivers/net/dsa/netc/Kconfig b/drivers/net/dsa/netc/Kconfig
|
|
new file mode 100644
|
|
index 000000000000..a665ab225e2b
|
|
--- /dev/null
|
|
+++ b/drivers/net/dsa/netc/Kconfig
|
|
@@ -0,0 +1,18 @@
|
|
+# SPDX-License-Identifier: GPL-2.0-only
|
|
+
|
|
+config NET_DSA_NETC
|
|
+ tristate "NXP NETC Ethernet switch family support"
|
|
+ depends on NET_DSA && SPI
|
|
+ select NET_DSA_TAG_NETC
|
|
+ help
|
|
+ This is the driver for the NXP ENTC Ethernet switch family.
|
|
+ These are managed over an SPI interface. Probing is handled
|
|
+ based on OF bindings and so is the linkage to PHYLINK.
|
|
+
|
|
+config NET_DSA_NETC_PTP
|
|
+ bool "Support for the PTP clock on the NXP NETC Ethernet switch"
|
|
+ depends on NET_DSA_NETC
|
|
+ depends on PTP_1588_CLOCK
|
|
+ help
|
|
+ This enables support for timestamping and PTP clock manipulations in
|
|
+ the NETC DSA driver.
|
|
\ No newline at end of file
|
|
diff --git a/drivers/net/dsa/netc/Makefile b/drivers/net/dsa/netc/Makefile
|
|
new file mode 100644
|
|
index 000000000000..f9eb97417999
|
|
--- /dev/null
|
|
+++ b/drivers/net/dsa/netc/Makefile
|
|
@@ -0,0 +1,14 @@
|
|
+# SPDX-License-Identifier: GPL-2.0-only
|
|
+
|
|
+obj-$(CONFIG_NET_DSA_NETC) += netcdsa.o
|
|
+
|
|
+netcdsa-objs := \
|
|
+ netc_spi.o \
|
|
+ netc_config.o \
|
|
+ netc_ethtool.o \
|
|
+ netc_devlink.o \
|
|
+ netc_main.o
|
|
+
|
|
+ifdef CONFIG_NET_DSA_NETC_PTP
|
|
+netcdsa-objs += netc_ptp.o
|
|
+endif
|
|
\ No newline at end of file
|
|
diff --git a/drivers/net/dsa/netc/netc.h b/drivers/net/dsa/netc/netc.h
|
|
new file mode 100644
|
|
index 000000000000..3c7a3f4a17a4
|
|
--- /dev/null
|
|
+++ b/drivers/net/dsa/netc/netc.h
|
|
@@ -0,0 +1,131 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#ifndef _NETC_H
|
|
+#define _NETC_H
|
|
+
|
|
+#include <linux/dsa/8021q.h>
|
|
+#include <linux/dsa/netc.h>
|
|
+#include <linux/mutex.h>
|
|
+#include <linux/ptp_clock_kernel.h>
|
|
+#include <linux/timecounter.h>
|
|
+#include <net/dsa.h>
|
|
+
|
|
+#include "netc_config.h"
|
|
+#include "netc_ptp.h"
|
|
+
|
|
+struct netc_private;
|
|
+
|
|
+enum {
|
|
+ NETC_SPEED_AUTO,
|
|
+ NETC_SPEED_10MBPS,
|
|
+ NETC_SPEED_100MBPS,
|
|
+ NETC_SPEED_1000MBPS,
|
|
+ NETC_SPEED_2500MBPS,
|
|
+ NETC_SPEED_MAX,
|
|
+};
|
|
+
|
|
+enum netc_internal_phy_t {
|
|
+ NETC_NO_PHY = 0,
|
|
+};
|
|
+
|
|
+struct netc_info {
|
|
+ const char *name;
|
|
+ int device_id;
|
|
+ int num_ports;
|
|
+ enum dsa_tag_protocol tag_proto;
|
|
+ int ptp_ts_bits;
|
|
+ bool multiple_cascade_ports;
|
|
+ bool can_limit_mcast_flood;
|
|
+};
|
|
+
|
|
+struct netc_psfp_list {
|
|
+ struct list_head stream_list;
|
|
+#define MAX_SSIDS 512
|
|
+ uint16_t ssids[MAX_SSIDS];
|
|
+ int num_ssids;
|
|
+ /* Serialize access to the lists */
|
|
+ struct mutex lock;
|
|
+};
|
|
+
|
|
+struct netc_private {
|
|
+ const struct netc_info *info;
|
|
+ struct netc_config config;
|
|
+ int cpu_port;
|
|
+ phy_interface_t phy_mode[NETC_MAX_NUM_PORTS];
|
|
+ bool fixed_link[NETC_MAX_NUM_PORTS];
|
|
+ unsigned long ucast_egress_floods;
|
|
+ unsigned long bcast_egress_floods;
|
|
+
|
|
+ size_t max_xfer_len;
|
|
+ struct spi_device *spidev;
|
|
+ struct dsa_switch *ds;
|
|
+ u16 bridge_pvid[NETC_MAX_NUM_PORTS];
|
|
+ u16 tag_8021q_pvid[NETC_MAX_NUM_PORTS];
|
|
+ /* Serializes transmission of management frames so that
|
|
+ * the switch doesn't confuse them with one another.
|
|
+ */
|
|
+ struct mutex mgmt_lock;
|
|
+ /* Serializes accesses to the FDB */
|
|
+ struct mutex fdb_lock;
|
|
+
|
|
+ struct devlink_region **regions;
|
|
+
|
|
+ /* PTP two-step TX timestamp ID, and its serialization lock */
|
|
+ spinlock_t ts_id_lock;
|
|
+ u32 ts_id;
|
|
+ unsigned long hwts_tx_en;
|
|
+ unsigned long hwts_rx_en;
|
|
+ struct netc_ptp_data ptp_data;
|
|
+
|
|
+ struct netc_psfp_list psfp;
|
|
+};
|
|
+
|
|
+int netc_vlan_filtering(struct dsa_switch *ds, int port, bool enabled,
|
|
+ struct netlink_ext_ack *extack);
|
|
+void netc_frame_memory_partitioning(struct netc_private *priv);
|
|
+
|
|
+/* From netc_devlink.c */
|
|
+int netc_devlink_setup(struct dsa_switch *ds);
|
|
+void netc_devlink_teardown(struct dsa_switch *ds);
|
|
+int netc_devlink_info_get(struct dsa_switch *ds,
|
|
+ struct devlink_info_req *req,
|
|
+ struct netlink_ext_ack *extack);
|
|
+
|
|
+/* From netc_spi.c */
|
|
+int netc_xfer_cmd(const struct netc_private *priv,
|
|
+ enum netc_spi_rw_mode rw, enum netc_cmd cmd,
|
|
+ void *param, size_t param_len,
|
|
+ void *resp, size_t resp_len,
|
|
+ struct ptp_system_timestamp *ptp_sts);
|
|
+int netc_xfer_set_cmd(const struct netc_private *priv,
|
|
+ enum netc_cmd cmd,
|
|
+ void *param, size_t param_len);
|
|
+int netc_xfer_get_cmd(const struct netc_private *priv,
|
|
+ enum netc_cmd cmd, uint32_t id,
|
|
+ void *resp, size_t resp_len);
|
|
+
|
|
+int netc_xfer_write_reg(const struct netc_private *priv,
|
|
+ uint32_t reg, uint32_t value);
|
|
+int netc_xfer_read_reg(const struct netc_private *priv,
|
|
+ uint32_t reg, uint32_t *value);
|
|
+int netc_xfer_write_u64(const struct netc_private *priv,
|
|
+ enum netc_cmd cmd, uint64_t value,
|
|
+ struct ptp_system_timestamp *ptp_sts);
|
|
+int netc_xfer_read_u64(const struct netc_private *priv,
|
|
+ enum netc_cmd cmd, uint64_t *value,
|
|
+ struct ptp_system_timestamp *ptp_sts);
|
|
+
|
|
+/* From netc_ethtool.c */
|
|
+void netc_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data);
|
|
+void netc_get_strings(struct dsa_switch *ds, int port,
|
|
+ uint32_t stringset, uint8_t *data);
|
|
+int netc_get_sset_count(struct dsa_switch *ds, int port, int sset);
|
|
+
|
|
+/* From netc_ptp.c */
|
|
+void netc_ptp_txtstamp_skb(struct dsa_switch *ds, int port,
|
|
+ struct sk_buff *skb);
|
|
+
|
|
+#endif /* _NETC_H */
|
|
diff --git a/drivers/net/dsa/netc/netc_config.c b/drivers/net/dsa/netc/netc_config.c
|
|
new file mode 100644
|
|
index 000000000000..e2bd3c1b29dc
|
|
--- /dev/null
|
|
+++ b/drivers/net/dsa/netc/netc_config.c
|
|
@@ -0,0 +1,696 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+#include <linux/slab.h>
|
|
+#include <linux/string.h>
|
|
+#include <linux/errno.h>
|
|
+#include <linux/etherdevice.h>
|
|
+#include "netc.h"
|
|
+
|
|
+int netc_get_devinfo(struct netc_private *priv, struct netc_config *config)
|
|
+{
|
|
+ struct netc_cmd_sysinfo info;
|
|
+ int rc;
|
|
+
|
|
+ rc = netc_xfer_get_cmd(priv, NETC_CMD_SYS_INFO_GET, 0,
|
|
+ &info, sizeof(info));
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ config->device_id = info.device_id;
|
|
+ config->vendor_id = info.vendor_id;
|
|
+ config->version_major = info.version_major;
|
|
+ config->version_minor = info.version_minor;
|
|
+ config->version_revision = info.version_revision;
|
|
+ config->cpu_port_mode = info.cpu_port;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_port_mtu_set(struct netc_private *priv, int port, int mtu)
|
|
+{
|
|
+ struct netc_cmd_port_mtu mtu_cmd = {0};
|
|
+
|
|
+ mtu_cmd.port = (uint8_t)port;
|
|
+ mtu_cmd.mtu = (uint16_t)mtu;
|
|
+
|
|
+ return netc_xfer_set_cmd(priv, NETC_CMD_PORT_MTU_SET,
|
|
+ &mtu_cmd, sizeof(mtu_cmd));
|
|
+}
|
|
+
|
|
+int netc_port_mtu_get(struct netc_private *priv, int port, int *mtu)
|
|
+{
|
|
+ int rc;
|
|
+ struct netc_cmd_port_mtu mtu_resp = {0};
|
|
+
|
|
+ rc = netc_xfer_get_cmd(priv, NETC_CMD_PORT_MTU_GET, port,
|
|
+ &mtu_resp, sizeof(mtu_resp));
|
|
+
|
|
+ if (rc != 0)
|
|
+ return rc;
|
|
+
|
|
+ *mtu = mtu_resp.mtu;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Set link speed in the MAC configuration for a specific port. */
|
|
+int netc_port_phylink_mode_set(struct netc_private *priv,
|
|
+ struct netc_mac_config *mac)
|
|
+{
|
|
+ struct device *dev = priv->ds->dev;
|
|
+ struct netc_cmd_port_phylink_mode phylink_mode = {0};
|
|
+ int rc;
|
|
+
|
|
+ phylink_mode.port = mac->port;
|
|
+ phylink_mode.duplex = mac->duplex;
|
|
+ phylink_mode.speed = mac->speed;
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_PORT_PHYLINK_MODE_SET,
|
|
+ &phylink_mode, sizeof(phylink_mode));
|
|
+ if (rc < 0) {
|
|
+ dev_err(dev, "Failed to write phylink_mode: %d\n", rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Get link speed in the MAC configuration for a specific port. */
|
|
+int netc_port_phylink_status_get(struct netc_private *priv,
|
|
+ struct netc_mac_config *mac)
|
|
+{
|
|
+ struct device *dev = priv->ds->dev;
|
|
+ struct netc_cmd_port_phylink_status phylink_status = {0};
|
|
+ int rc;
|
|
+
|
|
+ rc = netc_xfer_get_cmd(priv, NETC_CMD_PORT_PHYLINK_STATUS_GET,
|
|
+ mac->port,
|
|
+ &phylink_status, sizeof(phylink_status));
|
|
+ if (rc < 0) {
|
|
+ dev_err(dev, "Failed to get phylink status: %d\n", rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ mac->link = phylink_status.link;
|
|
+ mac->speed = phylink_status.speed;
|
|
+ mac->duplex = phylink_status.duplex;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_port_pvid_set(struct netc_private *priv, int port, uint16_t pvid)
|
|
+{
|
|
+ int rc = 0;
|
|
+ struct netc_cmd_port_pvid cmd_pvid = {0};
|
|
+
|
|
+ cmd_pvid.port = (uint8_t)port;
|
|
+ cmd_pvid.pvid = pvid;
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_PORT_PVID_SET,
|
|
+ &cmd_pvid, sizeof(cmd_pvid));
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int netc_port_link_set(struct netc_private *priv, int port, bool up)
|
|
+{
|
|
+ int rc = 0;
|
|
+ struct netc_cmd_port_link egress = {0};
|
|
+
|
|
+ egress.port = (uint8_t)port;
|
|
+ egress.link = up;
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_PORT_LINK_SET,
|
|
+ &egress, sizeof(egress));
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int netc_port_dropuntag_set(struct netc_private *priv, int port, bool drop)
|
|
+{
|
|
+ int rc = 0;
|
|
+ struct netc_cmd_port_dropuntag dropuntag = {0};
|
|
+
|
|
+ dropuntag.port = (uint8_t)port;
|
|
+ dropuntag.drop = (uint16_t)drop;
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_PORT_DROPUNTAG_SET,
|
|
+ &dropuntag, sizeof(dropuntag));
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int netc_port_dsa_add(struct netc_private *priv, int cpu_port,
|
|
+ int slave_port, const unsigned char *mac_addr)
|
|
+{
|
|
+ int rc = 0;
|
|
+ struct netc_cmd_port_dsa_add dsa_add = {0};
|
|
+
|
|
+ dsa_add.cpu_port = (uint8_t)cpu_port;
|
|
+ dsa_add.slave_port = (uint8_t)slave_port;
|
|
+ ether_addr_copy(dsa_add.mac_addr, mac_addr);
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_PORT_DSA_ADD,
|
|
+ &dsa_add, sizeof(dsa_add));
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int netc_port_dsa_del(struct netc_private *priv, int slave_port)
|
|
+{
|
|
+ int rc = 0;
|
|
+ struct netc_cmd_port_dsa_del dsa_del = {0};
|
|
+
|
|
+ dsa_del.slave_port = (uint8_t)slave_port;
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_PORT_DSA_DEL,
|
|
+ &dsa_del, sizeof(dsa_del));
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int netc_vlan_entry_add(struct netc_private *priv,
|
|
+ uint16_t vid, int port, bool untagged)
|
|
+{
|
|
+ struct device *dev = priv->ds->dev;
|
|
+ struct netc_cmd_vlan cmd_vlan = {0};
|
|
+ int rc;
|
|
+
|
|
+ cmd_vlan.vid = vid;
|
|
+ cmd_vlan.port = (uint8_t)port;
|
|
+ cmd_vlan.untagged = untagged;
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_VLAN_ADD,
|
|
+ &cmd_vlan, sizeof(cmd_vlan));
|
|
+ if (rc < 0) {
|
|
+ dev_err(dev, "Failed to add vlan entry: %d\n", rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_vlan_entry_del(struct netc_private *priv, uint16_t vid, int port)
|
|
+{
|
|
+ struct device *dev = priv->ds->dev;
|
|
+ struct netc_cmd_vlan cmd_vlan = {0};
|
|
+ int rc;
|
|
+
|
|
+ cmd_vlan.vid = vid;
|
|
+ cmd_vlan.port = (uint8_t)port;
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_VLAN_DEL,
|
|
+ &cmd_vlan, sizeof(cmd_vlan));
|
|
+ if (rc < 0) {
|
|
+ dev_err(dev, "Failed to add vlan entry: %d\n", rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_vlan_entry_read(struct netc_private *priv,
|
|
+ struct netc_vlan_entry *vlan,
|
|
+ uint32_t entry_id, uint32_t *next_id)
|
|
+{
|
|
+ struct device *dev = priv->ds->dev;
|
|
+ struct netc_cmd_vlan_dump vlan_dump = {0};
|
|
+ int rc;
|
|
+
|
|
+ rc = netc_xfer_get_cmd(priv, NETC_CMD_VLAN_DUMP, entry_id,
|
|
+ &vlan_dump, sizeof(vlan_dump));
|
|
+ if (rc < 0) {
|
|
+ dev_err(dev, "Failed to read vlan entry 0x%08x: %d\n",
|
|
+ entry_id, rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ vlan->entry_id = entry_id;
|
|
+ vlan->vid = vlan_dump.vid;
|
|
+ vlan->port_map = vlan_dump.port_map;
|
|
+ *next_id = vlan_dump.resume_entry_id;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_fdb_entry_add(struct netc_private *priv,
|
|
+ const unsigned char *mac_addr,
|
|
+ uint16_t vid, int port)
|
|
+{
|
|
+ struct device *dev = priv->ds->dev;
|
|
+ struct netc_cmd_fdb fdb_add = {0};
|
|
+ int rc;
|
|
+
|
|
+ ether_addr_copy(fdb_add.mac_addr, mac_addr);
|
|
+ fdb_add.vid = vid;
|
|
+ fdb_add.port = (uint8_t)port;
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_FDB_ADD,
|
|
+ &fdb_add, sizeof(fdb_add));
|
|
+ if (rc < 0) {
|
|
+ dev_err(dev, "Failed to add fdb: %d\n", rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_fdb_entry_del(struct netc_private *priv,
|
|
+ const unsigned char *mac_addr,
|
|
+ uint16_t vid, int port)
|
|
+{
|
|
+ struct device *dev = priv->ds->dev;
|
|
+ struct netc_cmd_fdb fdb_del = {0};
|
|
+ int rc;
|
|
+
|
|
+ ether_addr_copy(fdb_del.mac_addr, mac_addr);
|
|
+ fdb_del.vid = vid;
|
|
+ fdb_del.port = (uint8_t)port;;
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_FDB_DEL,
|
|
+ &fdb_del, sizeof(fdb_del));
|
|
+ if (rc < 0) {
|
|
+ dev_err(dev, "Failed to delete fdb: %d\n", rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_fdb_entry_get(struct netc_private *priv, struct netc_fdb_entry *fdb,
|
|
+ uint32_t entry_id, uint32_t *next_id)
|
|
+{
|
|
+ struct device *dev = priv->ds->dev;
|
|
+ struct netc_cmd_fdb_dump fdb_dump = {0};
|
|
+ int rc;
|
|
+
|
|
+ rc = netc_xfer_get_cmd(priv, NETC_CMD_FDB_DUMP, entry_id,
|
|
+ &fdb_dump, sizeof(fdb_dump));
|
|
+ if (rc < 0) {
|
|
+ dev_err(dev, "Failed to get fdb entry: %d\n", rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ *next_id = fdb_dump.resume_entry_id;
|
|
+
|
|
+ ether_addr_copy(fdb->mac_addr, fdb_dump.mac_addr);
|
|
+ fdb->vid = fdb_dump.vid;
|
|
+ fdb->port_map = fdb_dump.port_map;
|
|
+ fdb->dynamic = fdb_dump.dynamic;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_streamid_set(struct netc_private *priv, int port_mask, uint16_t handle,
|
|
+ const unsigned char *mac, uint16_t vid, tsn_cb_streamid_type type)
|
|
+{
|
|
+ struct device *dev = priv->ds->dev;
|
|
+ struct netc_cmd_nullstreamid streamid = {0};
|
|
+ int rc;
|
|
+
|
|
+ streamid.type = type;
|
|
+ streamid.handle = handle;
|
|
+ streamid.vid = vid;
|
|
+ streamid.port_mask = port_mask;
|
|
+ ether_addr_copy(streamid.mac_addr, mac);
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_STREAMID_SET, &streamid, sizeof(streamid));
|
|
+ if (rc < 0) {
|
|
+ dev_err(dev, "failed to add streamid: %d\n", handle);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_streamid_del(struct netc_private *priv, uint16_t stream_handle)
|
|
+{
|
|
+ struct device *dev = priv->ds->dev;
|
|
+ int rc;
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_STREAMID_DEL, &stream_handle, sizeof(stream_handle));
|
|
+ if (rc < 0) {
|
|
+ dev_err(dev, "failed to delete streamid: %d\n", stream_handle);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_port_priority_map(struct netc_private *priv, int port, uint8_t *map)
|
|
+{
|
|
+ struct netc_cmd_priority_map prio_map;
|
|
+ int rc;
|
|
+
|
|
+ prio_map.port = port;
|
|
+ memcpy(prio_map.map, map, sizeof(prio_map.map));
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_PRIORITY_MAP_SET, &prio_map, sizeof(prio_map));
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int netc_qbv_set(struct netc_private *priv, int port, int enable,
|
|
+ struct tc_taprio_qopt_offload *taprio)
|
|
+{
|
|
+ struct device *dev = priv->ds->dev;
|
|
+ struct netc_cmd_qbv_set_p1 qbvconf_p1 = {0};
|
|
+ struct netc_cmd_qbv_set_p2 qbvconf_p2 = {0};
|
|
+ struct netc_cmd_qbv_gcl qbvconf_gcl = {0};
|
|
+ uint8_t buffer[16];
|
|
+ uint8_t offset;
|
|
+ int rc;
|
|
+
|
|
+ qbvconf_p1.port = port;
|
|
+ qbvconf_p1.enabled = enable;
|
|
+ qbvconf_p1.base_time = taprio->base_time;
|
|
+ qbvconf_p1.cycle_time = taprio->cycle_time;
|
|
+ qbvconf_p1.gcl_len = taprio->num_entries;
|
|
+ if (enable)
|
|
+ qbvconf_p1.gcl_len = taprio->num_entries;
|
|
+ else
|
|
+ qbvconf_p1.gcl_len = 0;
|
|
+
|
|
+ if (qbvconf_p1.gcl_len > NETC_QBV_LIST_MAX_ENTRIES)
|
|
+ return -EINVAL;
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_QBV_SET_P1, &qbvconf_p1, sizeof(qbvconf_p1));
|
|
+ if (rc < 0)
|
|
+ goto err;
|
|
+
|
|
+ qbvconf_p2.cycle_time_ext = taprio->cycle_time_extension;
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_QBV_SET_P2, &qbvconf_p2, sizeof(qbvconf_p2));
|
|
+ if (rc < 0)
|
|
+ goto err;
|
|
+
|
|
+ offset = 0;
|
|
+ memset(buffer, 0, sizeof(buffer));
|
|
+ for (int i = 0; i < qbvconf_p1.gcl_len; i++) {
|
|
+ qbvconf_gcl.interval = taprio->entries[i].interval;
|
|
+ qbvconf_gcl.gate_mask = taprio->entries[i].gate_mask;
|
|
+ qbvconf_gcl.operation = taprio->entries[i].command;
|
|
+ memcpy(&buffer[offset], &qbvconf_gcl, sizeof(qbvconf_gcl));
|
|
+ if (offset) {
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_QBV_SET_GCL, buffer, sizeof(buffer));
|
|
+ if (rc < 0)
|
|
+ goto err;
|
|
+
|
|
+ offset = 0;
|
|
+ memset(buffer, 0, sizeof(buffer));
|
|
+ } else {
|
|
+ offset = sizeof(qbvconf_gcl);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (offset) {
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_QBV_SET_GCL, buffer, sizeof(buffer));
|
|
+ if (rc < 0)
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+err:
|
|
+ dev_err(dev, "failed to set qbv on port: %d\n", port);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int netc_port_set_preemptible_tcs(struct dsa_switch *ds, int port,
|
|
+ unsigned long preemptible_tcs)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct netc_cmd_qbu_set qbu_conf;
|
|
+
|
|
+ memset(&qbu_conf, 0, sizeof(qbu_conf));
|
|
+ qbu_conf.port = port;
|
|
+ qbu_conf.preemption_mask = (uint8_t)preemptible_tcs;
|
|
+
|
|
+ return netc_xfer_set_cmd(priv, NETC_CMD_QBU_SET,
|
|
+ &qbu_conf, sizeof(qbu_conf));
|
|
+}
|
|
+
|
|
+int netc_port_set_mm(struct dsa_switch *ds, int port,
|
|
+ struct ethtool_mm_cfg *cfg,
|
|
+ struct netlink_ext_ack *extack)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct netc_cmd_set_get_mm mm_conf;
|
|
+ u32 add_frag_size = 0;
|
|
+ int rc = 0;
|
|
+
|
|
+ memset(&mm_conf, 0, sizeof(mm_conf));
|
|
+ mm_conf.verify_time = (uint32_t)cfg->verify_time;
|
|
+ mm_conf.verify_enabled = cfg->verify_enabled ? 1 : 0;
|
|
+ mm_conf.tx_enabled = cfg->tx_enabled ? 1 : 0;
|
|
+ mm_conf.pmac_enabled = cfg->pmac_enabled ? 1 : 0;
|
|
+ mm_conf.port = (uint8_t)port;
|
|
+
|
|
+ rc = ethtool_mm_frag_size_min_to_add((u32)cfg->tx_min_frag_size,
|
|
+ &add_frag_size, extack);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
+ mm_conf.add_frag_size = (int32_t)add_frag_size;
|
|
+
|
|
+ return netc_xfer_set_cmd(priv, NETC_CMD_MM_SET, &mm_conf, sizeof(mm_conf));
|
|
+}
|
|
+
|
|
+int netc_port_get_mm(struct dsa_switch *ds, int port,
|
|
+ struct ethtool_mm_state *state)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct netc_cmd_set_get_mm mm_conf;
|
|
+ int rc;
|
|
+
|
|
+ memset(&mm_conf, 0, sizeof(mm_conf));
|
|
+ mm_conf.port = (uint8_t)port;
|
|
+ rc = netc_xfer_get_cmd(priv, NETC_CMD_MM_GET, port, &mm_conf, sizeof(mm_conf));
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
+ state->verify_time = (u32)mm_conf.verify_time;
|
|
+ state->max_verify_time = NETC_GET_MM_MAX_VERIFY_TIME;
|
|
+ state->verify_status = (enum ethtool_mm_verify_status)mm_conf.verify_status;
|
|
+ state->tx_enabled = !!mm_conf.tx_enabled;
|
|
+ state->tx_active = !!mm_conf.tx_active;
|
|
+ state->pmac_enabled = !!mm_conf.pmac_enabled;
|
|
+ state->verify_enabled = !!mm_conf.verify_enabled;
|
|
+ state->tx_min_frag_size =
|
|
+ ethtool_mm_frag_size_add_to_min(mm_conf.add_frag_size);
|
|
+ state->rx_min_frag_size = state->tx_min_frag_size;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int netc_qci_sg_set(struct netc_private *priv, struct netc_stream_filter *filter)
|
|
+{
|
|
+ struct action_gate_entry *entry = NULL;
|
|
+ struct netc_cmd_psfp_sg_p1 sg_p1 = {0};
|
|
+ struct netc_cmd_psfp_sg_p2 sg_p2 = {0};
|
|
+ struct netc_cmd_psfp_sgl sgl = {0};
|
|
+ int rc;
|
|
+
|
|
+ sg_p1.index = filter->stream_handle;
|
|
+ sg_p1.base_time = filter->qci.gate.basetime;
|
|
+ sg_p1.cycle_time = filter->qci.gate.cycletime;
|
|
+ sg_p1.gcl_len = filter->qci.gate.num_entries;
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_QCI_SG_SET_P1, &sg_p1, sizeof(sg_p1));
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ sg_p2.cycle_time_ext = filter->qci.gate.cycletimeext;
|
|
+ sg_p2.prio = filter->qci.gate.prio;
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_QCI_SG_SET_P2, &sg_p2, sizeof(sg_p2));
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ for (int i = 0; i < filter->qci.gate.num_entries; i++) {
|
|
+ entry = &filter->qci.gate.entries[i];
|
|
+ sgl.interval = entry->interval;
|
|
+ sgl.maxoctets = entry->maxoctets;
|
|
+ sgl.ipv = entry->ipv;
|
|
+ sgl.gate_state = entry->gate_state;
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_QCI_SG_SET_GCL, &sgl, sizeof(sgl));
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int netc_qci_fm_set(struct netc_private *priv, struct netc_stream_filter *filter)
|
|
+{
|
|
+ struct netc_cmd_psfp_fm fm = {0};
|
|
+ int rc;
|
|
+
|
|
+ fm.index = filter->stream_handle;
|
|
+ fm.rate = filter->qci.police.rate;
|
|
+ fm.burst = filter->qci.police.burst;
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_QCI_FM_SET, &fm, sizeof(fm));
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_qci_set(struct netc_private *priv, struct netc_stream_filter *filter, int port)
|
|
+{
|
|
+ struct device *dev = priv->ds->dev;
|
|
+ struct netc_cmd_psfp_sf sf = {0};
|
|
+ int rc;
|
|
+
|
|
+ sf.stream_handle = filter->stream_handle;
|
|
+ sf.priority_spec = filter->qci.priority_spec;
|
|
+ sf.port = port;
|
|
+ sf.maxsdu = filter->qci.maxsdu;
|
|
+ if (filter->qci.gate.num_entries) {
|
|
+ sf.sg_enable = 1;
|
|
+ rc = netc_qci_sg_set(priv, filter);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ if (filter->qci.police.rate) {
|
|
+ sf.fm_enable = 1;
|
|
+ rc = netc_qci_fm_set(priv, filter);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_QCI_SF_SET,
|
|
+ &sf, sizeof(sf));
|
|
+ if (rc < 0) {
|
|
+ dev_err(dev, "failed to set Qci setting: %d\n", rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_qci_del(struct netc_private *priv, uint16_t handle,
|
|
+ uint32_t port)
|
|
+{
|
|
+ struct device *dev = priv->ds->dev;
|
|
+ int rc;
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_QCI_DEL,
|
|
+ &handle, sizeof(handle));
|
|
+ if (rc < 0) {
|
|
+ dev_err(dev, "failed to delete Qci setting: %d\n", rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_qci_get(struct netc_private *priv, uint16_t handle, struct flow_stats *stats)
|
|
+{
|
|
+ struct netc_cmd_psfp_response psfp_resp = {0};
|
|
+ int rc;
|
|
+
|
|
+ rc = netc_xfer_get_cmd(priv, NETC_CMD_QCI_GET, handle,
|
|
+ &psfp_resp, sizeof(psfp_resp));
|
|
+
|
|
+ if (rc != 0)
|
|
+ return rc;
|
|
+
|
|
+ stats->pkts = psfp_resp.pkts;
|
|
+ stats->drops = psfp_resp.drops;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_frer_seqgen(struct netc_private *priv, struct netc_stream_filter *filter)
|
|
+{
|
|
+ struct device *dev = priv->ds->dev;
|
|
+ struct netc_cmd_frer_sg frer_sg = {0};
|
|
+ int rc;
|
|
+
|
|
+ frer_sg.stream_handle = filter->stream_handle;
|
|
+ frer_sg.iport = filter->seqgen.iport;
|
|
+ frer_sg.encap = filter->seqgen.enc;
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_FRER_SG_SET,
|
|
+ &frer_sg, sizeof(frer_sg));
|
|
+ if (rc < 0) {
|
|
+ dev_err(dev, "failed to set FRER sequence generation: %d\n", rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_frer_seqrec(struct netc_private *priv, struct netc_stream_filter *filter)
|
|
+{
|
|
+ struct device *dev = priv->ds->dev;
|
|
+ struct netc_cmd_frer_sr frer_sr = {0};
|
|
+ int rc;
|
|
+
|
|
+ frer_sr.stream_handle = filter->stream_handle;
|
|
+ frer_sr.eport = filter->seqrec.eport;
|
|
+ frer_sr.encap = filter->seqrec.enc;
|
|
+ frer_sr.alg = filter->seqrec.alg;
|
|
+ frer_sr.his_len = filter->seqrec.his_len;
|
|
+ frer_sr.reset_timeout = filter->seqrec.reset_timeout;
|
|
+ frer_sr.rtag_pop_en = filter->seqrec.rtag_pop_en;
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_FRER_SR_SET,
|
|
+ &frer_sr, sizeof(frer_sr));
|
|
+ if (rc < 0) {
|
|
+ dev_err(dev, "failed to set FRER sequence recovery: %d\n", rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_frer_sg_del(struct netc_private *priv, uint16_t stream_handle, uint32_t port)
|
|
+{
|
|
+ struct device *dev = priv->ds->dev;
|
|
+ int rc;
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_FRER_SG_DEL,
|
|
+ &stream_handle, sizeof(stream_handle));
|
|
+ if (rc < 0) {
|
|
+ dev_err(dev, "failed to delete FRER setting: %d\n", rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_frer_sr_del(struct netc_private *priv, uint16_t stream_handle, uint32_t port)
|
|
+{
|
|
+ struct device *dev = priv->ds->dev;
|
|
+ int rc;
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_FRER_SR_DEL,
|
|
+ &stream_handle, sizeof(stream_handle));
|
|
+ if (rc < 0) {
|
|
+ dev_err(dev, "failed to delete FRER setting: %d\n", rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_config_setup(struct netc_config *config)
|
|
+{
|
|
+ if (config->vlan_max_count) {
|
|
+ config->vlan = kcalloc(config->vlan_max_count,
|
|
+ sizeof(*config->vlan),
|
|
+ GFP_KERNEL);
|
|
+ if (!config->vlan)
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void netc_config_free(struct netc_config *config)
|
|
+{
|
|
+ kfree(config->vlan);
|
|
+}
|
|
diff --git a/drivers/net/dsa/netc/netc_config.h b/drivers/net/dsa/netc/netc_config.h
|
|
new file mode 100644
|
|
index 000000000000..8bd64a1e7142
|
|
--- /dev/null
|
|
+++ b/drivers/net/dsa/netc/netc_config.h
|
|
@@ -0,0 +1,557 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+#ifndef _NETC_CONFIG_H
|
|
+#define _NETC_CONFIG_H
|
|
+
|
|
+#include <net/tc_act/tc_gate.h>
|
|
+#include <net/pkt_sched.h>
|
|
+#include <linux/types.h>
|
|
+#include <asm/types.h>
|
|
+
|
|
+#define NETC_RT1180_DEVICE_ID 0xe001
|
|
+#define NETC_NUM_PORTS 5
|
|
+#define NETC_MAX_NUM_PORTS NETC_NUM_PORTS
|
|
+#define NETC_NUM_TC 8
|
|
+
|
|
+#define NETC_ETHTOOL_STATS_NUM_MAX 120
|
|
+#define NETC_QBV_LIST_MAX_ENTRIES 256
|
|
+
|
|
+#define NETC_SPI_WORD_BITS 8
|
|
+#define NETC_SPI_MSG_WORD_BYTES 4
|
|
+#define NETC_SPI_MSG_HEADER_SIZE 20
|
|
+#define NETC_SPI_MSG_PARAM_SIZE 16
|
|
+#define NETC_SPI_MSG_MAXLEN 4096
|
|
+#define NETC_SPI_MSG_RESPONSE_TIME 1000 /* us */
|
|
+
|
|
+#define NETC_CMD_DIR_SHIFT 31
|
|
+#define NETC_CMD_LEN_SHIFT 16
|
|
+
|
|
+#define NETC_GET_MM_MAX_VERIFY_TIME (128U)
|
|
+
|
|
+enum netc_spi_rw_mode {
|
|
+ SPI_READ = 0,
|
|
+ SPI_WRITE = 1,
|
|
+};
|
|
+
|
|
+struct netc_cmd_hdr {
|
|
+ uint32_t cmd;
|
|
+ uint8_t param[NETC_SPI_MSG_PARAM_SIZE];
|
|
+};
|
|
+
|
|
+/* Command */
|
|
+enum netc_cmd {
|
|
+ /* port related command */
|
|
+ NETC_CMD_SYS_INFO_GET = 0x1,
|
|
+ NETC_CMD_PORT_DSA_ADD,
|
|
+ NETC_CMD_PORT_DSA_DEL,
|
|
+ NETC_CMD_PORT_MTU_SET,
|
|
+ NETC_CMD_PORT_MTU_GET,
|
|
+ NETC_CMD_PORT_PHYLINK_MODE_SET,
|
|
+ NETC_CMD_PORT_PHYLINK_STATUS_GET,
|
|
+ NETC_CMD_PORT_ETHTOOL_STATS_GET,
|
|
+ NETC_CMD_PORT_PVID_SET,
|
|
+ NETC_CMD_PORT_LINK_SET,
|
|
+ NETC_CMD_PORT_DROPUNTAG_SET,
|
|
+
|
|
+ NETC_CMD_FDB_ADD = 0x1000,
|
|
+ NETC_CMD_FDB_DEL,
|
|
+ NETC_CMD_FDB_DUMP,
|
|
+ NETC_CMD_VLAN_ADD,
|
|
+ NETC_CMD_VLAN_DEL,
|
|
+ NETC_CMD_VLAN_DUMP,
|
|
+ NETC_CMD_FORWARD_MASK_SET,
|
|
+
|
|
+ NETC_CMD_PTP_SYNC_SET = 0x2000,
|
|
+ NETC_CMD_TIMER_CUR_SET,
|
|
+ NETC_CMD_TIMER_CUR_GET,
|
|
+ NETC_CMD_TIMER_RATE_SET,
|
|
+ NETC_CMD_TIMER_RATE_GET,
|
|
+ NETC_CMD_TIMER_ADJTIME_SET,
|
|
+ NETC_CMD_TIMER_ADJFINE_SET,
|
|
+ NETC_CMD_TIMER_PPS_START,
|
|
+ NETC_CMD_TIMER_PPS_STOP,
|
|
+ NETC_CMD_TIMER_EXTTS_START,
|
|
+ NETC_CMD_TIMER_EXTTS_STOP,
|
|
+
|
|
+ NETC_CMD_QBV_SET_P1 = 0x3000,
|
|
+ NETC_CMD_QBV_SET_P2,
|
|
+ NETC_CMD_QBV_SET_GCL,
|
|
+ NETC_CMD_QBU_SET,
|
|
+ NETC_CMD_MM_SET,
|
|
+ NETC_CMD_MM_GET,
|
|
+ NETC_CMD_QCI_SF_SET,
|
|
+ NETC_CMD_QCI_SG_SET_P1,
|
|
+ NETC_CMD_QCI_SG_SET_P2,
|
|
+ NETC_CMD_QCI_SG_SET_GCL,
|
|
+ NETC_CMD_QCI_FM_SET,
|
|
+ NETC_CMD_QCI_DEL,
|
|
+ NETC_CMD_QCI_GET,
|
|
+ NETC_CMD_FRER_SG_SET,
|
|
+ NETC_CMD_FRER_SG_DEL,
|
|
+ NETC_CMD_FRER_SR_SET,
|
|
+ NETC_CMD_FRER_SR_DEL,
|
|
+ NETC_CMD_STREAMID_SET,
|
|
+ NETC_CMD_STREAMID_DEL,
|
|
+ NETC_CMD_PRIORITY_MAP_SET,
|
|
+
|
|
+ NETC_CMD_REG_SET = 0x4000,
|
|
+ NETC_CMD_REG_GET,
|
|
+ NETC_CMD_MAX_NUM,
|
|
+};
|
|
+
|
|
+struct netc_cmd_sysinfo {
|
|
+ uint16_t device_id;
|
|
+ uint16_t vendor_id;
|
|
+ uint8_t version_major;
|
|
+ uint8_t version_minor;
|
|
+ uint8_t version_revision;
|
|
+ uint8_t cpu_port;
|
|
+};
|
|
+
|
|
+/* command data for NETC_CMD_PORT_DSA_ADD */
|
|
+struct netc_cmd_port_dsa_add {
|
|
+ uint8_t cpu_port; /* switch port 0, 1, 2 or 3 */
|
|
+ uint8_t slave_port; /* switch port 0, 1, 2 or 3 */
|
|
+ uint8_t mac_addr[ETH_ALEN]; /* MAC address of master interface */
|
|
+};
|
|
+
|
|
+/* command data for NETC_CMD_PORT_DSA_DEL */
|
|
+struct netc_cmd_port_dsa_del {
|
|
+ uint8_t slave_port; /* switch port 0, 1, 2 or 3 */
|
|
+ uint8_t reserved[3];
|
|
+};
|
|
+
|
|
+/* command data for NETC_CMD_PORT_MTU_SET */
|
|
+struct netc_cmd_port_mtu {
|
|
+ uint8_t port; /* switch port 0, 1, 2 or 3 */
|
|
+ uint8_t reserved;
|
|
+ uint16_t mtu;
|
|
+};
|
|
+
|
|
+/* command data for NETC_CMD_PORT_PHYLINK_MODE_SET */
|
|
+struct netc_cmd_port_phylink_mode {
|
|
+ uint8_t port; /* switch port 0, 1, 2 or 3 */
|
|
+ bool duplex; /* 0: half duplex; 1: full duplex */
|
|
+ uint16_t speed; /* 10: 10Mbps ; 100: 100Mbps ; 1000: 1000Mbps */
|
|
+};
|
|
+
|
|
+/* command data for NETC_CMD_PORT_PVID_SET */
|
|
+struct netc_cmd_port_pvid {
|
|
+ uint8_t port; /* switch port 0, 1, 2 or 3 */
|
|
+ uint8_t reserved;
|
|
+ uint16_t pvid;
|
|
+};
|
|
+
|
|
+/* command data for netc_cmd_port_link */
|
|
+struct netc_cmd_port_link {
|
|
+ uint8_t port; /* switch port 0, 1, 2 or 3 */
|
|
+ bool link; /* 0: down; 1: up */
|
|
+ uint8_t reserved[2];
|
|
+};
|
|
+
|
|
+/* command data for netc_cmd_port_dropuntag */
|
|
+struct netc_cmd_port_dropuntag {
|
|
+ uint8_t port; /* switch port 0, 1, 2 or 3 */
|
|
+ uint8_t reserved;
|
|
+ uint16_t drop;
|
|
+};
|
|
+
|
|
+/* command data for NETC_CMD_FDB_ADD */
|
|
+struct netc_cmd_fdb {
|
|
+ uint8_t mac_addr[ETH_ALEN];
|
|
+ uint16_t vid;
|
|
+ uint8_t port; /* switch port 0, 1, 2 or 3 */
|
|
+ uint8_t reserved[3];
|
|
+};
|
|
+
|
|
+/* command data for NETC_CMD_VLAN_ADD */
|
|
+struct netc_cmd_vlan {
|
|
+ uint16_t vid;
|
|
+ uint8_t port; /* switch port 0, 1, 2 or 3 */
|
|
+ bool untagged;
|
|
+};
|
|
+
|
|
+/* data returned for NETC_CMD_PORT_PHYLINK_STATUS_GET */
|
|
+struct netc_cmd_port_phylink_status {
|
|
+ uint8_t port; /* switch port 0, 1, 2 or 3 */
|
|
+ bool link;
|
|
+ uint16_t speed;
|
|
+ bool duplex; /* 0: down; 1: up */
|
|
+ uint8_t reserved[3];
|
|
+};
|
|
+
|
|
+/* command param */
|
|
+struct netc_cmd_read_param {
|
|
+ uint32_t id;
|
|
+};
|
|
+
|
|
+/* command data for NETC_CMD_REG_SET */
|
|
+struct netc_cmd_reg_cmd {
|
|
+ uint32_t reg;
|
|
+ uint32_t value;
|
|
+};
|
|
+
|
|
+/* data returned for NETC_CMD_FDB_DUMP */
|
|
+struct netc_cmd_fdb_dump {
|
|
+ uint8_t mac_addr[ETH_ALEN];
|
|
+ uint16_t vid;
|
|
+ /* bit 0: switch port 0 etc. */
|
|
+ uint32_t port_map;
|
|
+ bool dynamic;
|
|
+ uint8_t reserved[3];
|
|
+ /* non-zero means there are remaining entries, 0 means no more entries */
|
|
+ uint32_t resume_entry_id;
|
|
+};
|
|
+
|
|
+/* data returned for NETC_CMD_VLAN_DUMP */
|
|
+struct netc_cmd_vlan_dump {
|
|
+ uint16_t vid;
|
|
+ bool untagged;
|
|
+ uint8_t reserved;
|
|
+ /* bit 0: switch port 0 etc. */
|
|
+ uint32_t port_map;
|
|
+ /* non-zero means there are remaining entries, 0 means no more entries */
|
|
+ uint32_t resume_entry_id;
|
|
+};
|
|
+
|
|
+/* command param for NETC_CMD_TIMER_PPS_START */
|
|
+struct netc_cmd_timer_pps {
|
|
+ uint64_t pin_start;
|
|
+ uint32_t pin_duration32;
|
|
+};
|
|
+
|
|
+/* command param for NETC PTP */
|
|
+struct netc_ptp_ctl_param {
|
|
+ union {
|
|
+ uint64_t ns;
|
|
+ int64_t offset;
|
|
+ int64_t ppb;
|
|
+ };
|
|
+ uint8_t clock_id;
|
|
+};
|
|
+
|
|
+/* stream identification */
|
|
+typedef enum {
|
|
+ STREAMID_RESERVED = 0,
|
|
+ /* Null Stream identification */
|
|
+ STREAMID_NULL,
|
|
+ /* Source MAC and VLAN Stream identification */
|
|
+ STREAMID_SMAC_VLAN,
|
|
+ /* Active Destination MAC and VLAN stream identification */
|
|
+ STREAMID_DMAC_VLAN,
|
|
+ /* IP stream identification */
|
|
+ STREAMID_IP,
|
|
+} tsn_cb_streamid_type;
|
|
+
|
|
+enum netc_action_type {
|
|
+ NETC_STREAM_NULL,
|
|
+ NETC_STREAM_FRER_SEQGEN,
|
|
+ NETC_STREAM_FRER_SEQREC,
|
|
+ NETC_STREAM_QCI,
|
|
+};
|
|
+
|
|
+struct netc_stream {
|
|
+ struct list_head list;
|
|
+ unsigned long id;
|
|
+ int port_mask;
|
|
+ uint8_t mac[ETH_ALEN];
|
|
+ uint16_t vid;
|
|
+ tsn_cb_streamid_type type;
|
|
+ enum netc_action_type action;
|
|
+ uint16_t handle;
|
|
+ s8 prio;
|
|
+ bool update;
|
|
+};
|
|
+
|
|
+typedef enum {
|
|
+ NETC_SEQI_RTAG = 1,
|
|
+ NETC_SEQI_HSR_SEQ_TAG,
|
|
+ NETC_SEQI_PRP_SEQ_TRAILER,
|
|
+} netc_encapsulation_t;
|
|
+
|
|
+typedef enum {
|
|
+ NETC_SEQR_VECTOR = 0,
|
|
+ NETC_SEQR_MATCH,
|
|
+} netc_seqr_algorithm_t;
|
|
+
|
|
+struct netc_stream_seqgen {
|
|
+ netc_encapsulation_t enc;
|
|
+ uint8_t iport;
|
|
+};
|
|
+
|
|
+struct netc_stream_seqrec {
|
|
+ netc_encapsulation_t enc;
|
|
+ netc_seqr_algorithm_t alg;
|
|
+ uint16_t reset_timeout;
|
|
+ uint8_t his_len;
|
|
+ uint8_t rtag_pop_en;
|
|
+ uint8_t eport;
|
|
+};
|
|
+
|
|
+enum tc_frer_tag_action {
|
|
+ FRER_TAG_NULL,
|
|
+ FRER_TAG_PUSH,
|
|
+ FRER_TAG_POP,
|
|
+};
|
|
+
|
|
+struct netc_stream_qci {
|
|
+ uint32_t maxsdu;
|
|
+ int8_t priority_spec;
|
|
+ struct {
|
|
+ int32_t prio;
|
|
+ uint64_t basetime;
|
|
+ uint32_t cycletime;
|
|
+ uint32_t cycletimeext;
|
|
+ uint16_t num_entries;
|
|
+ struct action_gate_entry *entries;
|
|
+ } gate;
|
|
+ struct {
|
|
+ uint32_t burst;
|
|
+ uint64_t rate;
|
|
+ } police;
|
|
+};
|
|
+
|
|
+struct netc_stream_filter {
|
|
+ struct list_head list;
|
|
+ uint16_t stream_handle;
|
|
+ union {
|
|
+ struct netc_stream_seqgen seqgen;
|
|
+ struct netc_stream_seqrec seqrec;
|
|
+ struct netc_stream_qci qci;
|
|
+ };
|
|
+};
|
|
+
|
|
+/* command data for NETC_CMD_STREAMID_SET */
|
|
+struct netc_cmd_nullstreamid {
|
|
+ uint8_t mac_addr[ETH_ALEN];
|
|
+ uint16_t vid;
|
|
+ uint16_t handle;
|
|
+ uint8_t type;
|
|
+ uint8_t port_mask;
|
|
+};
|
|
+
|
|
+/* command data for NETC_CMD_FRER_SG_SET */
|
|
+struct netc_cmd_frer_sg {
|
|
+ uint16_t stream_handle;
|
|
+ uint8_t encap;
|
|
+ uint8_t iport;
|
|
+};
|
|
+
|
|
+/* command data for NETC_CMD_FRER_SR_SET */
|
|
+struct netc_cmd_frer_sr {
|
|
+ uint16_t stream_handle;
|
|
+ uint16_t reset_timeout;
|
|
+ uint8_t his_len;
|
|
+ uint8_t encap;
|
|
+ uint8_t alg;
|
|
+ uint8_t rtag_pop_en;
|
|
+ uint8_t eport;
|
|
+ uint8_t reserved[3];
|
|
+};
|
|
+
|
|
+struct netc_cmd_psfp_sg_p1 {
|
|
+ uint64_t base_time;
|
|
+ uint32_t cycle_time;
|
|
+ uint16_t gcl_len;
|
|
+ uint16_t index;
|
|
+};
|
|
+
|
|
+struct netc_cmd_psfp_sg_p2 {
|
|
+ uint32_t cycle_time_ext;
|
|
+ int32_t prio;
|
|
+ uint8_t reserved[8];
|
|
+};
|
|
+
|
|
+struct netc_cmd_psfp_sgl {
|
|
+ uint32_t interval;
|
|
+ int32_t maxoctets;
|
|
+ int32_t ipv;
|
|
+ uint8_t gate_state;
|
|
+ uint8_t reserved[3];
|
|
+};
|
|
+
|
|
+struct netc_cmd_psfp_fm {
|
|
+ uint64_t rate;
|
|
+ uint32_t burst;
|
|
+ uint16_t index;
|
|
+ uint8_t reserved[2];
|
|
+};
|
|
+
|
|
+struct netc_cmd_psfp_sf {
|
|
+ uint32_t maxsdu;
|
|
+ uint16_t stream_handle;
|
|
+ int8_t priority_spec;
|
|
+ uint8_t sg_enable;
|
|
+ uint8_t fm_enable;
|
|
+ uint8_t port;
|
|
+ uint8_t reserved[6];
|
|
+};
|
|
+
|
|
+struct netc_cmd_psfp_response {
|
|
+ uint64_t pkts;
|
|
+ uint64_t drops;
|
|
+};
|
|
+
|
|
+struct netc_cmd_priority_map {
|
|
+ uint8_t port;
|
|
+ uint8_t map[8];
|
|
+ uint8_t reserved[7];
|
|
+};
|
|
+
|
|
+struct netc_cmd_qbv_gcl {
|
|
+ uint32_t interval;
|
|
+ uint16_t gate_mask;
|
|
+ uint16_t operation;
|
|
+};
|
|
+
|
|
+struct netc_cmd_qbv_set_p1 {
|
|
+ uint64_t base_time;
|
|
+ uint32_t cycle_time;
|
|
+ uint16_t gcl_len;
|
|
+ uint8_t enabled;
|
|
+ uint8_t port;
|
|
+};
|
|
+
|
|
+struct netc_cmd_qbv_set_p2 {
|
|
+ uint32_t cycle_time_ext;
|
|
+ uint8_t reserved[12];
|
|
+};
|
|
+
|
|
+struct netc_cmd_set_get_mm {
|
|
+ uint32_t verify_time;
|
|
+ uint32_t add_frag_size;
|
|
+ uint8_t verify_enabled;
|
|
+ uint8_t verify_status;
|
|
+ uint8_t tx_enabled;
|
|
+ uint8_t pmac_enabled;
|
|
+ uint8_t tx_active;
|
|
+ uint8_t port;
|
|
+ uint8_t reserved[2];
|
|
+};
|
|
+
|
|
+struct netc_cmd_qbu_set {
|
|
+ uint8_t preemption_mask;
|
|
+ uint8_t port;
|
|
+ uint8_t reserved[2];
|
|
+};
|
|
+
|
|
+struct netc_cmd_port_ethtool_stats {
|
|
+ uint64_t values[NETC_ETHTOOL_STATS_NUM_MAX];
|
|
+};
|
|
+
|
|
+struct netc_mac_config {
|
|
+ uint8_t port;
|
|
+ uint16_t speed;
|
|
+ uint16_t vlanid;
|
|
+ bool link;
|
|
+ bool egress;
|
|
+ bool ingress;
|
|
+ bool duplex;
|
|
+ bool drptag;
|
|
+ bool drpuntag;
|
|
+ bool retag;
|
|
+};
|
|
+
|
|
+struct netc_fdb_entry {
|
|
+ uint8_t mac_addr[ETH_ALEN];
|
|
+ uint16_t vid;
|
|
+ uint32_t port_map; /* bit 0: switch port 0 etc. */
|
|
+ bool dynamic;
|
|
+};
|
|
+
|
|
+struct netc_vlan_entry {
|
|
+ uint16_t vid;
|
|
+ uint16_t port;
|
|
+ uint32_t port_map;
|
|
+ uint32_t tag_ports;
|
|
+ uint32_t entry_id;
|
|
+};
|
|
+
|
|
+struct netc_config {
|
|
+ uint16_t device_id;
|
|
+ uint16_t vendor_id;
|
|
+ uint8_t version_major;
|
|
+ uint8_t version_minor;
|
|
+ uint8_t version_revision;
|
|
+ uint8_t cpu_port_mode;
|
|
+ uint16_t tpid;
|
|
+ uint16_t tpid2;
|
|
+ struct netc_mac_config mac[NETC_MAX_NUM_PORTS];
|
|
+ int cpu_port;
|
|
+ int vlan_count;
|
|
+ int vlan_max_count;
|
|
+ struct netc_vlan_entry *vlan;
|
|
+};
|
|
+
|
|
+struct netc_private;
|
|
+
|
|
+int netc_get_devinfo(struct netc_private *priv, struct netc_config *config);
|
|
+
|
|
+int netc_port_phylink_mode_set(struct netc_private *priv,
|
|
+ struct netc_mac_config *mac);
|
|
+int netc_port_phylink_stats_get(struct netc_private *priv,
|
|
+ struct netc_mac_config *mac);
|
|
+int netc_port_pvid_set(struct netc_private *priv, int port, uint16_t pvid);
|
|
+int netc_port_link_set(struct netc_private *priv, int port, bool up);
|
|
+int netc_port_dropuntag_set(struct netc_private *priv, int port, bool drop);
|
|
+
|
|
+int netc_port_mtu_set(struct netc_private *priv, int port, int mtu);
|
|
+int netc_port_mtu_get(struct netc_private *priv, int port, int *mtu);
|
|
+
|
|
+int netc_port_pvid_set(struct netc_private *priv, int port, uint16_t pvid);
|
|
+
|
|
+int netc_port_dsa_add(struct netc_private *priv, int cpu_port,
|
|
+ int slave_port, const unsigned char *mac_addr);
|
|
+int netc_port_dsa_del(struct netc_private *priv, int slave_port);
|
|
+
|
|
+int netc_fdb_entry_add(struct netc_private *priv,
|
|
+ const unsigned char *mac_addr,
|
|
+ uint16_t vid, int port);
|
|
+int netc_fdb_entry_del(struct netc_private *priv,
|
|
+ const unsigned char *mac_addr,
|
|
+ uint16_t vid, int port);
|
|
+int netc_fdb_entry_get(struct netc_private *priv,
|
|
+ struct netc_fdb_entry *fdb,
|
|
+ uint32_t entry_id, uint32_t *next_id);
|
|
+
|
|
+int netc_vlan_entry_add(struct netc_private *priv,
|
|
+ uint16_t vid, int port, bool untagged);
|
|
+int netc_vlan_entry_del(struct netc_private *priv, uint16_t vid, int port);
|
|
+int netc_vlan_entry_get(struct netc_private *priv,
|
|
+ struct netc_vlan_entry *vlan,
|
|
+ uint32_t entry_id, uint32_t *next_id);
|
|
+
|
|
+int netc_config_setup(struct netc_config *config);
|
|
+void netc_config_free(struct netc_config *config);
|
|
+
|
|
+int netc_streamid_set(struct netc_private *priv, int port_mask, uint16_t handle,
|
|
+ const unsigned char *mac, uint16_t vid, tsn_cb_streamid_type type);
|
|
+int netc_streamid_del(struct netc_private *priv, uint16_t handle);
|
|
+
|
|
+int netc_frer_seqgen(struct netc_private *priv,
|
|
+ struct netc_stream_filter *filter);
|
|
+int netc_frer_seqrec(struct netc_private *priv,
|
|
+ struct netc_stream_filter *filter);
|
|
+int netc_frer_sg_del(struct netc_private *priv, uint16_t handle, uint32_t port);
|
|
+int netc_frer_sr_del(struct netc_private *priv, uint16_t handle, uint32_t port);
|
|
+
|
|
+int netc_qci_set(struct netc_private *priv,
|
|
+ struct netc_stream_filter *filter, int port);
|
|
+int netc_qci_del(struct netc_private *priv,
|
|
+ uint16_t handle, uint32_t port);
|
|
+int netc_qci_get(struct netc_private *priv, uint16_t handle, struct flow_stats *stats);
|
|
+int netc_qbv_set(struct netc_private *priv, int port, int enable,
|
|
+ struct tc_taprio_qopt_offload *taprio);
|
|
+int netc_port_priority_map(struct netc_private *priv, int port, uint8_t *map);
|
|
+
|
|
+int netc_port_set_preemptible_tcs(struct dsa_switch *ds, int port,
|
|
+ unsigned long preemptible_tcs);
|
|
+int netc_port_set_mm(struct dsa_switch *ds, int port,
|
|
+ struct ethtool_mm_cfg *cfg,
|
|
+ struct netlink_ext_ack *extack);
|
|
+int netc_port_get_mm(struct dsa_switch *ds, int port,
|
|
+ struct ethtool_mm_state *state);
|
|
+#endif /* _NETC_CONFIG_H */
|
|
diff --git a/drivers/net/dsa/netc/netc_devlink.c b/drivers/net/dsa/netc/netc_devlink.c
|
|
new file mode 100644
|
|
index 000000000000..963a6fd8775c
|
|
--- /dev/null
|
|
+++ b/drivers/net/dsa/netc/netc_devlink.c
|
|
@@ -0,0 +1,107 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#include "netc.h"
|
|
+
|
|
+static size_t netc_config_get_size(struct netc_private *priv)
|
|
+{
|
|
+ return sizeof(struct netc_config);
|
|
+}
|
|
+
|
|
+static int
|
|
+netc_region_config_snapshot(struct devlink *dl,
|
|
+ const struct devlink_region_ops *ops,
|
|
+ struct netlink_ext_ack *extack,
|
|
+ u8 **data)
|
|
+{
|
|
+ struct dsa_switch *ds = dsa_devlink_to_ds(dl);
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ size_t len;
|
|
+
|
|
+ len = netc_config_get_size(priv);
|
|
+ *data = kcalloc(len, sizeof(u8), GFP_KERNEL);
|
|
+ if (!*data)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ return netc_xfer_get_cmd(priv, NETC_CMD_SYS_INFO_GET, 0, *data, len);
|
|
+}
|
|
+
|
|
+static struct devlink_region_ops netc_region_config_ops = {
|
|
+ .name = "config",
|
|
+ .snapshot = netc_region_config_snapshot,
|
|
+ .destructor = kfree,
|
|
+};
|
|
+
|
|
+enum netc_region_id {
|
|
+ NETC_REGION_CONFIG = 0,
|
|
+};
|
|
+
|
|
+struct netc_region {
|
|
+ const struct devlink_region_ops *ops;
|
|
+ size_t (*get_size)(struct netc_private *priv);
|
|
+};
|
|
+
|
|
+static struct netc_region netc_regions[] = {
|
|
+ [NETC_REGION_CONFIG] = {
|
|
+ .ops = &netc_region_config_ops,
|
|
+ .get_size = netc_config_get_size,
|
|
+ },
|
|
+};
|
|
+
|
|
+int netc_devlink_info_get(struct dsa_switch *ds,
|
|
+ struct devlink_info_req *req,
|
|
+ struct netlink_ext_ack *extack)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ int rc;
|
|
+
|
|
+ rc = devlink_info_version_fixed_put(req,
|
|
+ DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
|
|
+ priv->info->name);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int netc_devlink_setup(struct dsa_switch *ds)
|
|
+{
|
|
+ int i, num_regions = ARRAY_SIZE(netc_regions);
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ const struct devlink_region_ops *ops;
|
|
+ struct devlink_region *region;
|
|
+ u64 size;
|
|
+
|
|
+ priv->regions = kcalloc(num_regions, sizeof(struct devlink_region *),
|
|
+ GFP_KERNEL);
|
|
+ if (!priv->regions)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ for (i = 0; i < num_regions; i++) {
|
|
+ size = netc_regions[i].get_size(priv);
|
|
+ ops = netc_regions[i].ops;
|
|
+
|
|
+ region = dsa_devlink_region_create(ds, ops, 1, size);
|
|
+ if (IS_ERR(region)) {
|
|
+ while (--i >= 0)
|
|
+ dsa_devlink_region_destroy(priv->regions[i]);
|
|
+
|
|
+ kfree(priv->regions);
|
|
+ return PTR_ERR(region);
|
|
+ }
|
|
+
|
|
+ priv->regions[i] = region;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void netc_devlink_teardown(struct dsa_switch *ds)
|
|
+{
|
|
+ int i, num_regions = ARRAY_SIZE(netc_regions);
|
|
+ struct netc_private *priv = ds->priv;
|
|
+
|
|
+ for (i = 0; i < num_regions; i++)
|
|
+ dsa_devlink_region_destroy(priv->regions[i]);
|
|
+
|
|
+ kfree(priv->regions);
|
|
+}
|
|
diff --git a/drivers/net/dsa/netc/netc_ethtool.c b/drivers/net/dsa/netc/netc_ethtool.c
|
|
new file mode 100644
|
|
index 000000000000..7e6ab46ffee6
|
|
--- /dev/null
|
|
+++ b/drivers/net/dsa/netc/netc_ethtool.c
|
|
@@ -0,0 +1,344 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#include "netc.h"
|
|
+
|
|
+enum netc_stat_index {
|
|
+ /* RX stats */
|
|
+ NETC_STAT_RX_BYTES,
|
|
+ NETC_STAT_RX_VALID_BYTES,
|
|
+ NETC_STAT_RX_PAUSE_FRAMES,
|
|
+ NETC_STAT_RX_VALID_FRAMES,
|
|
+ NETC_STAT_RX_VLAN_FRAMES,
|
|
+ NETC_STAT_RX_UC_FRAMES,
|
|
+ NETC_STAT_RX_MC_FRAMES,
|
|
+ NETC_STAT_RX_BC_FRAMES,
|
|
+ NETC_STAT_RX_FRAMES,
|
|
+ NETC_STAT_RX_MIN_FRAMES,
|
|
+ NETC_STAT_RX_64_FRAMES,
|
|
+ NETC_STAT_RX_65_127_FRAMES,
|
|
+ NETC_STAT_RX_128_255_FRAMES,
|
|
+ NETC_STAT_RX_256_511_FRAMES,
|
|
+ NETC_STAT_RX_512_1023_FRAMES,
|
|
+ NETC_STAT_RX_1024_1522_FRAMES,
|
|
+ NETC_STAT_RX_1523_MAX_FRAMES,
|
|
+ NETC_STAT_RX_CONTROL_FRAMES,
|
|
+
|
|
+ /* TX stats */
|
|
+ NETC_STAT_TX_BYTES,
|
|
+ NETC_STAT_TX_VALID_BYTES,
|
|
+ NETC_STAT_TX_PAUSE_FRAMES,
|
|
+ NETC_STAT_TX_VALID_FRAMES,
|
|
+ NETC_STAT_TX_VLAN_FRAMES,
|
|
+ NETC_STAT_TX_UC_FRAMES,
|
|
+ NETC_STAT_TX_MC_FRAMES,
|
|
+ NETC_STAT_TX_BC_FRAMES,
|
|
+ NETC_STAT_TX_FRAMES,
|
|
+ NETC_STAT_TX_MIN_FRAMES,
|
|
+ NETC_STAT_TX_64_FRAMES,
|
|
+ NETC_STAT_TX_65_127_FRAMES,
|
|
+ NETC_STAT_TX_128_255_FRAMES,
|
|
+ NETC_STAT_TX_256_511_FRAMES,
|
|
+ NETC_STAT_TX_512_1023_FRAMES,
|
|
+ NETC_STAT_TX_1024_1522_FRAMES,
|
|
+ NETC_STAT_TX_1523_MAX_FRAMES,
|
|
+ NETC_STAT_TX_CONTROL_FRAMES,
|
|
+
|
|
+ NETC_STAT_RX_VALID_REASSEMBLED_FRAMES,
|
|
+ NETC_STAT_RX_ADDITIONAL_MPACKETS,
|
|
+ NETC_STAT_RX_ERROR_FRAME_REASSEMBLY,
|
|
+ NETC_STAT_RX_ERROR_FRAME_SMD,
|
|
+ NETC_STAT_TX_ADDITIONAL_MPACKETS,
|
|
+ NETC_STAT_TX_HOLD_TRANSITIONS,
|
|
+
|
|
+ /* Error stats */
|
|
+ NETC_STAT_RX_ERROR,
|
|
+ NETC_STAT_RX_ERROR_UNDERSIZE,
|
|
+ NETC_STAT_RX_ERROR_OVERSIZE,
|
|
+ NETC_STAT_RX_ERROR_FCS,
|
|
+ NETC_STAT_RX_ERROR_FRAGMENT,
|
|
+ NETC_STAT_RX_ERROR_JABBER,
|
|
+ NETC_STAT_RX_ERROR_DISCARD,
|
|
+ NETC_STAT_RX_ERROR_NO_TRUNCATED,
|
|
+ NETC_STAT_TX_ERROR_FCS,
|
|
+ NETC_STAT_TX_ERROR_UNDERSIZE,
|
|
+
|
|
+ /* Discard stats */
|
|
+ NETC_STAT_RX_DISCARD_COUNT,
|
|
+ NETC_STAT_RX_DISCARD_REASON0,
|
|
+ NETC_STAT_RX_DISCARD_TABLE_ID,
|
|
+ NETC_STAT_RX_DISCARD_ENTRY_ID,
|
|
+ NETC_STAT_TX_DISCARD_COUNT,
|
|
+ NETC_STAT_TX_DISCARD_REASON0,
|
|
+ NETC_STAT_TX_DISCARD_TABLE_ID,
|
|
+ NETC_STAT_TX_DISCARD_ENTRY_ID,
|
|
+ NETC_STAT_BRIDGE_DISCARD_COUNT,
|
|
+ NETC_STAT_BRIDGE_DISCARD_REASON0,
|
|
+ NETC_STAT_BRIDGE_DISCARD_TABLE_ID,
|
|
+ NETC_STAT_BRIDGE_DISCARD_ENTRY_ID,
|
|
+
|
|
+ /* Q0 stats */
|
|
+ NETC_STAT_Q0_REJECTED_BYTES,
|
|
+ NETC_STAT_Q0_REJECTED_FRAMES,
|
|
+ NETC_STAT_Q0_DEQUEUE_BYTES,
|
|
+ NETC_STAT_Q0_DEQUEUE_FRAMES,
|
|
+ NETC_STAT_Q0_DROPPED_BYTES,
|
|
+ NETC_STAT_Q0_DROPPED_FRAMES,
|
|
+ NETC_STAT_Q0_FRAMES,
|
|
+
|
|
+ /* Q1 stats */
|
|
+ NETC_STAT_Q1_REJECTED_BYTES,
|
|
+ NETC_STAT_Q1_REJECTED_FRAMES,
|
|
+ NETC_STAT_Q1_DEQUEUE_BYTES,
|
|
+ NETC_STAT_Q1_DEQUEUE_FRAMES,
|
|
+ NETC_STAT_Q1_DROPPED_BYTES,
|
|
+ NETC_STAT_Q1_DROPPED_FRAMES,
|
|
+ NETC_STAT_Q1_FRAMES,
|
|
+
|
|
+ /* Q2 stats */
|
|
+ NETC_STAT_Q2_REJECTED_BYTES,
|
|
+ NETC_STAT_Q2_REJECTED_FRAMES,
|
|
+ NETC_STAT_Q2_DEQUEUE_BYTES,
|
|
+ NETC_STAT_Q2_DEQUEUE_FRAMES,
|
|
+ NETC_STAT_Q2_DROPPED_BYTES,
|
|
+ NETC_STAT_Q2_DROPPED_FRAMES,
|
|
+ NETC_STAT_Q2_FRAMES,
|
|
+
|
|
+ /* Q3 stats */
|
|
+ NETC_STAT_Q3_REJECTED_BYTES,
|
|
+ NETC_STAT_Q3_REJECTED_FRAMES,
|
|
+ NETC_STAT_Q3_DEQUEUE_BYTES,
|
|
+ NETC_STAT_Q3_DEQUEUE_FRAMES,
|
|
+ NETC_STAT_Q3_DROPPED_BYTES,
|
|
+ NETC_STAT_Q3_DROPPED_FRAMES,
|
|
+ NETC_STAT_Q3_FRAMES,
|
|
+
|
|
+ /* Q4 stats */
|
|
+ NETC_STAT_Q4_REJECTED_BYTES,
|
|
+ NETC_STAT_Q4_REJECTED_FRAMES,
|
|
+ NETC_STAT_Q4_DEQUEUE_BYTES,
|
|
+ NETC_STAT_Q4_DEQUEUE_FRAMES,
|
|
+ NETC_STAT_Q4_DROPPED_BYTES,
|
|
+ NETC_STAT_Q4_DROPPED_FRAMES,
|
|
+ NETC_STAT_Q4_FRAMES,
|
|
+
|
|
+ /* Q5 stats */
|
|
+ NETC_STAT_Q5_REJECTED_BYTES,
|
|
+ NETC_STAT_Q5_REJECTED_FRAMES,
|
|
+ NETC_STAT_Q5_DEQUEUE_BYTES,
|
|
+ NETC_STAT_Q5_DEQUEUE_FRAMES,
|
|
+ NETC_STAT_Q5_DROPPED_BYTES,
|
|
+ NETC_STAT_Q5_DROPPED_FRAMES,
|
|
+ NETC_STAT_Q5_FRAMES,
|
|
+
|
|
+ /* Q6 stats */
|
|
+ NETC_STAT_Q6_REJECTED_BYTES,
|
|
+ NETC_STAT_Q6_REJECTED_FRAMES,
|
|
+ NETC_STAT_Q6_DEQUEUE_BYTES,
|
|
+ NETC_STAT_Q6_DEQUEUE_FRAMES,
|
|
+ NETC_STAT_Q6_DROPPED_BYTES,
|
|
+ NETC_STAT_Q6_DROPPED_FRAMES,
|
|
+ NETC_STAT_Q6_FRAMES,
|
|
+
|
|
+ /* Q7 stats */
|
|
+ NETC_STAT_Q7_REJECTED_BYTES,
|
|
+ NETC_STAT_Q7_REJECTED_FRAMES,
|
|
+ NETC_STAT_Q7_DEQUEUE_BYTES,
|
|
+ NETC_STAT_Q7_DEQUEUE_FRAMES,
|
|
+ NETC_STAT_Q7_DROPPED_BYTES,
|
|
+ NETC_STAT_Q7_DROPPED_FRAMES,
|
|
+ NETC_STAT_Q7_FRAMES,
|
|
+ NETC_STAT_NUM,
|
|
+};
|
|
+
|
|
+char netc_stat_name[][ETH_GSTRING_LEN] = {
|
|
+ /* RX stats */
|
|
+ [NETC_STAT_RX_BYTES] = "in-bytes",
|
|
+ [NETC_STAT_RX_VALID_BYTES] = "in-valid-bytes",
|
|
+ [NETC_STAT_RX_PAUSE_FRAMES] = "in-pause-frames",
|
|
+ [NETC_STAT_RX_VALID_FRAMES] = "in-valid-frames",
|
|
+ [NETC_STAT_RX_VLAN_FRAMES] = "in-vlan-frames",
|
|
+ [NETC_STAT_RX_UC_FRAMES] = "in-uc-frames",
|
|
+ [NETC_STAT_RX_MC_FRAMES] = "in-mc-frames",
|
|
+ [NETC_STAT_RX_BC_FRAMES] = "in-bc-frames",
|
|
+ [NETC_STAT_RX_FRAMES] = "in-frames",
|
|
+ [NETC_STAT_RX_MIN_FRAMES] = "in-min-frames",
|
|
+ [NETC_STAT_RX_64_FRAMES] = "in-64-frames",
|
|
+ [NETC_STAT_RX_65_127_FRAMES] = "in-65-127-frames",
|
|
+ [NETC_STAT_RX_128_255_FRAMES] = "in-128-255-frames",
|
|
+ [NETC_STAT_RX_256_511_FRAMES] = "in-256-511-frames",
|
|
+ [NETC_STAT_RX_512_1023_FRAMES] = "in-512-1023-frames",
|
|
+ [NETC_STAT_RX_1024_1522_FRAMES] = "in-1024-1522-frames",
|
|
+ [NETC_STAT_RX_1523_MAX_FRAMES] = "in-1523-max-frames",
|
|
+ [NETC_STAT_RX_CONTROL_FRAMES] = "in-control-frames",
|
|
+
|
|
+ /* TX stats */
|
|
+ [NETC_STAT_TX_BYTES] = "out-bytes",
|
|
+ [NETC_STAT_TX_VALID_BYTES] = "out-valid-bytes",
|
|
+ [NETC_STAT_TX_PAUSE_FRAMES] = "out-pause-frames",
|
|
+ [NETC_STAT_TX_VALID_FRAMES] = "out-valid-frames",
|
|
+ [NETC_STAT_TX_VLAN_FRAMES] = "out-vlan-frames",
|
|
+ [NETC_STAT_TX_UC_FRAMES] = "out-uc-frames",
|
|
+ [NETC_STAT_TX_MC_FRAMES] = "out-mc-frames",
|
|
+ [NETC_STAT_TX_BC_FRAMES] = "out-bc-frames",
|
|
+ [NETC_STAT_TX_FRAMES] = "out-frames",
|
|
+ [NETC_STAT_TX_MIN_FRAMES] = "out-min-frames",
|
|
+ [NETC_STAT_TX_64_FRAMES] = "out-64-frames",
|
|
+ [NETC_STAT_TX_65_127_FRAMES] = "out-65-127-frames",
|
|
+ [NETC_STAT_TX_128_255_FRAMES] = "out-128-255-frames",
|
|
+ [NETC_STAT_TX_256_511_FRAMES] = "out-256-511-frames",
|
|
+ [NETC_STAT_TX_512_1023_FRAMES] = "out-512-1023-frames",
|
|
+ [NETC_STAT_TX_1024_1522_FRAMES] = "out-1024-1522-frames",
|
|
+ [NETC_STAT_TX_1523_MAX_FRAMES] = "out-1523-max-frames",
|
|
+ [NETC_STAT_TX_CONTROL_FRAMES] = "out-control-frames",
|
|
+
|
|
+ [NETC_STAT_RX_VALID_REASSEMBLED_FRAMES] = "in-valid-reassembled-frames",
|
|
+ [NETC_STAT_RX_ADDITIONAL_MPACKETS] = "in-additional-mPackets",
|
|
+ [NETC_STAT_RX_ERROR_FRAME_REASSEMBLY] = "in-error-frame-reassembly",
|
|
+ [NETC_STAT_RX_ERROR_FRAME_SMD] = "in-error-frame-smd",
|
|
+ [NETC_STAT_TX_ADDITIONAL_MPACKETS] = "out-additional-mPackets",
|
|
+ [NETC_STAT_TX_HOLD_TRANSITIONS] = "out-hold-transitions",
|
|
+
|
|
+ /* Error stats */
|
|
+ [NETC_STAT_RX_ERROR] = "in-error",
|
|
+ [NETC_STAT_RX_ERROR_UNDERSIZE] = "in-error-undersize",
|
|
+ [NETC_STAT_RX_ERROR_OVERSIZE] = "in-error-oversize",
|
|
+ [NETC_STAT_RX_ERROR_FCS] = "in-error-fcs",
|
|
+ [NETC_STAT_RX_ERROR_FRAGMENT] = "in-error-fragment",
|
|
+ [NETC_STAT_RX_ERROR_JABBER] = "in-error-jabber",
|
|
+ [NETC_STAT_RX_ERROR_DISCARD] = "in-error-discard",
|
|
+ [NETC_STAT_RX_ERROR_NO_TRUNCATED] = "in-error-dicard-no-truncated",
|
|
+ [NETC_STAT_TX_ERROR_FCS] = "out-error-fcs",
|
|
+ [NETC_STAT_TX_ERROR_UNDERSIZE] = "out-error-undersize",
|
|
+
|
|
+ /* Discard stats */
|
|
+ [NETC_STAT_RX_DISCARD_COUNT] = "in-discard-count",
|
|
+ [NETC_STAT_RX_DISCARD_REASON0] = "in-discard-reason0",
|
|
+ [NETC_STAT_RX_DISCARD_TABLE_ID] = "in-discard-table-id",
|
|
+ [NETC_STAT_RX_DISCARD_ENTRY_ID] = "in-discard-entry-id",
|
|
+ [NETC_STAT_TX_DISCARD_COUNT] = "out-discard-count",
|
|
+ [NETC_STAT_TX_DISCARD_REASON0] = "out-discard-reason0",
|
|
+ [NETC_STAT_TX_DISCARD_TABLE_ID] = "out-discard-table-id",
|
|
+ [NETC_STAT_TX_DISCARD_ENTRY_ID] = "out-discard-entry-id",
|
|
+ [NETC_STAT_BRIDGE_DISCARD_COUNT] = "bridge-discard-count",
|
|
+ [NETC_STAT_BRIDGE_DISCARD_REASON0] = "bridge-discard-reason0",
|
|
+ [NETC_STAT_BRIDGE_DISCARD_TABLE_ID] = "bridge-discard-table-id",
|
|
+ [NETC_STAT_BRIDGE_DISCARD_ENTRY_ID] = "bridge-discard-entry-id",
|
|
+
|
|
+ /* Q0 stats */
|
|
+ [NETC_STAT_Q0_REJECTED_BYTES] = "q0-rejected-bytes",
|
|
+ [NETC_STAT_Q0_REJECTED_FRAMES] = "q0-rejected-frames",
|
|
+ [NETC_STAT_Q0_DEQUEUE_BYTES] = "q0-dequeue-bytes",
|
|
+ [NETC_STAT_Q0_DEQUEUE_FRAMES] = "q0-dequeue-frames",
|
|
+ [NETC_STAT_Q0_DROPPED_BYTES] = "q0-dropped-bytes",
|
|
+ [NETC_STAT_Q0_DROPPED_FRAMES] = "q0-dropped-frames",
|
|
+ [NETC_STAT_Q0_FRAMES] = "q0-frames",
|
|
+
|
|
+ /* Q1 stats */
|
|
+ [NETC_STAT_Q1_REJECTED_BYTES] = "q1-rejected-bytes",
|
|
+ [NETC_STAT_Q1_REJECTED_FRAMES] = "q1-rejected-frames",
|
|
+ [NETC_STAT_Q1_DEQUEUE_BYTES] = "q1-dequeue-bytes",
|
|
+ [NETC_STAT_Q1_DEQUEUE_FRAMES] = "q1-dequeue-frames",
|
|
+ [NETC_STAT_Q1_DROPPED_BYTES] = "q1-dropped-bytes",
|
|
+ [NETC_STAT_Q1_DROPPED_FRAMES] = "q1-dropped-frames",
|
|
+ [NETC_STAT_Q1_FRAMES] = "q1-frames",
|
|
+
|
|
+ /* Q2 stats */
|
|
+ [NETC_STAT_Q2_REJECTED_BYTES] = "q2-rejected-bytes",
|
|
+ [NETC_STAT_Q2_REJECTED_FRAMES] = "q2-rejected-frames",
|
|
+ [NETC_STAT_Q2_DEQUEUE_BYTES] = "q2-dequeue-bytes",
|
|
+ [NETC_STAT_Q2_DEQUEUE_FRAMES] = "q2-dequeue-frames",
|
|
+ [NETC_STAT_Q2_DROPPED_BYTES] = "q2-dropped-bytes",
|
|
+ [NETC_STAT_Q2_DROPPED_FRAMES] = "q2-dropped-frames",
|
|
+ [NETC_STAT_Q2_FRAMES] = "q2-frames",
|
|
+
|
|
+ /* Q3 stats */
|
|
+ [NETC_STAT_Q3_REJECTED_BYTES] = "q3-rejected-bytes",
|
|
+ [NETC_STAT_Q3_REJECTED_FRAMES] = "q3-rejected-frames",
|
|
+ [NETC_STAT_Q3_DEQUEUE_BYTES] = "q3-dequeue-bytes",
|
|
+ [NETC_STAT_Q3_DEQUEUE_FRAMES] = "q3-dequeue-frames",
|
|
+ [NETC_STAT_Q3_DROPPED_BYTES] = "q3-dropped-bytes",
|
|
+ [NETC_STAT_Q3_DROPPED_FRAMES] = "q3-dropped-frames",
|
|
+ [NETC_STAT_Q3_FRAMES] = "q3-frames",
|
|
+
|
|
+ /* Q4 stats */
|
|
+ [NETC_STAT_Q4_REJECTED_BYTES] = "q4-rejected-bytes",
|
|
+ [NETC_STAT_Q4_REJECTED_FRAMES] = "q4-rejected-frames",
|
|
+ [NETC_STAT_Q4_DEQUEUE_BYTES] = "q4-dequeue-bytes",
|
|
+ [NETC_STAT_Q4_DEQUEUE_FRAMES] = "q4-dequeue-frames",
|
|
+ [NETC_STAT_Q4_DROPPED_BYTES] = "q4-dropped-bytes",
|
|
+ [NETC_STAT_Q4_DROPPED_FRAMES] = "q4-dropped-frames",
|
|
+ [NETC_STAT_Q4_FRAMES] = "q4-frames",
|
|
+
|
|
+ /* Q5 stats */
|
|
+ [NETC_STAT_Q5_REJECTED_BYTES] = "q5-rejected-bytes",
|
|
+ [NETC_STAT_Q5_REJECTED_FRAMES] = "q5-rejected-frames",
|
|
+ [NETC_STAT_Q5_DEQUEUE_BYTES] = "q5-dequeue-bytes",
|
|
+ [NETC_STAT_Q5_DEQUEUE_FRAMES] = "q5-dequeue-frames",
|
|
+ [NETC_STAT_Q5_DROPPED_BYTES] = "q5-dropped-bytes",
|
|
+ [NETC_STAT_Q5_DROPPED_FRAMES] = "q5-dropped-frames",
|
|
+ [NETC_STAT_Q5_FRAMES] = "q5-frames",
|
|
+
|
|
+ /* Q6 stats */
|
|
+ [NETC_STAT_Q6_REJECTED_BYTES] = "q6-rejected-bytes",
|
|
+ [NETC_STAT_Q6_REJECTED_FRAMES] = "q6-rejected-frames",
|
|
+ [NETC_STAT_Q6_DEQUEUE_BYTES] = "q6-dequeue-bytes",
|
|
+ [NETC_STAT_Q6_DEQUEUE_FRAMES] = "q6-dequeue-frames",
|
|
+ [NETC_STAT_Q6_DROPPED_BYTES] = "q6-dropped-bytes",
|
|
+ [NETC_STAT_Q6_DROPPED_FRAMES] = "q6-dropped-frames",
|
|
+ [NETC_STAT_Q6_FRAMES] = "q6-frames",
|
|
+
|
|
+ /* Q7 stats */
|
|
+ [NETC_STAT_Q7_REJECTED_BYTES] = "q7-rejected-bytes",
|
|
+ [NETC_STAT_Q7_REJECTED_FRAMES] = "q7-rejected-frames",
|
|
+ [NETC_STAT_Q7_DEQUEUE_BYTES] = "q7-dequeue-bytes",
|
|
+ [NETC_STAT_Q7_DEQUEUE_FRAMES] = "q7-dequeue-frames",
|
|
+ [NETC_STAT_Q7_DROPPED_BYTES] = "q7-dropped-bytes",
|
|
+ [NETC_STAT_Q7_DROPPED_FRAMES] = "q7-dropped-frames",
|
|
+ [NETC_STAT_Q7_FRAMES] = "q7-frames",
|
|
+};
|
|
+
|
|
+void netc_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct netc_cmd_port_ethtool_stats stats;
|
|
+ int rc;
|
|
+ enum netc_stat_index i;
|
|
+
|
|
+ rc = netc_xfer_get_cmd(priv, NETC_CMD_PORT_ETHTOOL_STATS_GET,
|
|
+ port, &stats, sizeof(stats));
|
|
+
|
|
+ if (rc) {
|
|
+ dev_err(ds->dev,
|
|
+ "Failed to get port %d stats\n", port);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < NETC_STAT_NUM; i++)
|
|
+ data[i] = stats.values[i];
|
|
+}
|
|
+
|
|
+void netc_get_strings(struct dsa_switch *ds, int port,
|
|
+ u32 stringset, u8 *data)
|
|
+{
|
|
+ enum netc_stat_index i;
|
|
+ char *p = data;
|
|
+
|
|
+ if (stringset != ETH_SS_STATS)
|
|
+ return;
|
|
+
|
|
+ for (i = 0; i < NETC_STAT_NUM; i++) {
|
|
+ strscpy(p, netc_stat_name[i], ETH_GSTRING_LEN);
|
|
+ p += ETH_GSTRING_LEN;
|
|
+ }
|
|
+}
|
|
+
|
|
+int netc_get_sset_count(struct dsa_switch *ds, int port, int sset)
|
|
+{
|
|
+ if (sset != ETH_SS_STATS)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ return NETC_STAT_NUM;
|
|
+}
|
|
diff --git a/drivers/net/dsa/netc/netc_main.c b/drivers/net/dsa/netc/netc_main.c
|
|
new file mode 100644
|
|
index 000000000000..5aa93b3b295c
|
|
--- /dev/null
|
|
+++ b/drivers/net/dsa/netc/netc_main.c
|
|
@@ -0,0 +1,1439 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
+
|
|
+#include <linux/delay.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/printk.h>
|
|
+#include <linux/spi/spi.h>
|
|
+#include <linux/errno.h>
|
|
+#include <linux/phylink.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_net.h>
|
|
+#include <linux/of_mdio.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/netdev_features.h>
|
|
+#include <linux/netdevice.h>
|
|
+#include <linux/if_bridge.h>
|
|
+#include <linux/if_ether.h>
|
|
+#include <linux/if_vlan.h>
|
|
+#include <linux/dsa/netc.h>
|
|
+#include "netc.h"
|
|
+
|
|
+uint8_t netc_default_priority_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
|
|
+
|
|
+int netc_is_vlan_configured(struct netc_private *priv, uint16_t vid)
|
|
+{
|
|
+ struct netc_vlan_entry *vlan;
|
|
+ int count, i;
|
|
+
|
|
+ vlan = priv->config.vlan;
|
|
+ count = priv->config.vlan_count;
|
|
+
|
|
+ for (i = 0; i < count; i++) {
|
|
+ if (vlan[i].vid == vid)
|
|
+ return i;
|
|
+ }
|
|
+
|
|
+ /* Return an invalid entry index if not found */
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static bool vid_is_netc_dsa_8021q(struct dsa_switch *ds, u16 vid)
|
|
+{
|
|
+ int port;
|
|
+ struct dsa_port *dp;
|
|
+ unsigned int bridge_num;
|
|
+ u16 standalone_vid, bridge_vid;
|
|
+
|
|
+ for (port = 0; port < ds->num_ports; port++) {
|
|
+ dp = dsa_to_port(ds, port);
|
|
+ standalone_vid = dsa_tag_8021q_standalone_vid(dp);
|
|
+
|
|
+ if (vid == standalone_vid)
|
|
+ return true;
|
|
+
|
|
+ if (dp->bridge) {
|
|
+ bridge_num = dsa_port_bridge_num_get(dp);
|
|
+ bridge_vid = dsa_tag_8021q_bridge_vid(bridge_num);
|
|
+
|
|
+ if (vid == bridge_vid)
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
+static int netc_drop_untagged(struct dsa_switch *ds, int port, bool drop)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct netc_mac_config *mac;
|
|
+
|
|
+ mac = &priv->config.mac[port];
|
|
+ if (mac->drpuntag == drop)
|
|
+ return 0;
|
|
+
|
|
+ mac->drpuntag = drop;
|
|
+
|
|
+ return netc_port_dropuntag_set(priv, port, drop);
|
|
+}
|
|
+
|
|
+static int netc_pvid_apply(struct netc_private *priv, int port, uint16_t pvid)
|
|
+{
|
|
+ struct netc_mac_config *mac;
|
|
+
|
|
+ mac = &priv->config.mac[port];
|
|
+ if (mac->vlanid == pvid)
|
|
+ return 0;
|
|
+
|
|
+ mac->vlanid = pvid;
|
|
+
|
|
+ return netc_port_pvid_set(priv, port, pvid);
|
|
+}
|
|
+
|
|
+static int netc_commit_pvid(struct dsa_switch *ds, int port)
|
|
+{
|
|
+ struct dsa_port *dp = dsa_to_port(ds, port);
|
|
+ struct net_device *br = dsa_port_bridge_dev_get(dp);
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ bool drop_untagged = false;
|
|
+ int rc;
|
|
+ uint16_t pvid;
|
|
+
|
|
+ if (br && br_vlan_enabled(br))
|
|
+ pvid = priv->bridge_pvid[port];
|
|
+ else
|
|
+ pvid = priv->tag_8021q_pvid[port];
|
|
+
|
|
+ rc = netc_pvid_apply(priv, port, pvid);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
+ /*
|
|
+ * Only force dropping of untagged packets when the port is under a
|
|
+ * VLAN-aware bridge. When the tag_8021q pvid is used, we are
|
|
+ * deliberately removing the RX VLAN from the port's VMEMB_PORT list,
|
|
+ * to prevent DSA tag spoofing from the link partner. Untagged packets
|
|
+ * are the only ones that should be received with tag_8021q, so
|
|
+ * definitely don't drop them.
|
|
+ */
|
|
+ if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
|
|
+ drop_untagged = true;
|
|
+
|
|
+ return netc_drop_untagged(ds, port, drop_untagged);
|
|
+}
|
|
+
|
|
+static int netc_fdb_add(struct dsa_switch *ds, int port,
|
|
+ const unsigned char *addr, uint16_t vid,
|
|
+ struct dsa_db db)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ int rc;
|
|
+
|
|
+ if (!vid) {
|
|
+ switch (db.type) {
|
|
+ case DSA_DB_PORT:
|
|
+ vid = dsa_tag_8021q_standalone_vid(db.dp);
|
|
+ break;
|
|
+ case DSA_DB_BRIDGE:
|
|
+ vid = dsa_tag_8021q_bridge_vid(db.bridge.num);
|
|
+ break;
|
|
+ default:
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Allow enough time between consecutive calls for adding FDB entry */
|
|
+ usleep_range(NETC_SPI_MSG_RESPONSE_TIME,
|
|
+ NETC_SPI_MSG_RESPONSE_TIME * 10);
|
|
+
|
|
+ mutex_lock(&priv->fdb_lock);
|
|
+ rc = netc_fdb_entry_add(priv, addr, vid, port);
|
|
+ mutex_unlock(&priv->fdb_lock);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int netc_fdb_del(struct dsa_switch *ds, int port,
|
|
+ const unsigned char *addr, uint16_t vid,
|
|
+ struct dsa_db db)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ int rc;
|
|
+
|
|
+ if (!vid) {
|
|
+ switch (db.type) {
|
|
+ case DSA_DB_PORT:
|
|
+ vid = dsa_tag_8021q_standalone_vid(db.dp);
|
|
+ break;
|
|
+ case DSA_DB_BRIDGE:
|
|
+ vid = dsa_tag_8021q_bridge_vid(db.bridge.num);
|
|
+ break;
|
|
+ default:
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ mutex_lock(&priv->fdb_lock);
|
|
+ rc = netc_fdb_entry_del(priv, addr, vid, port);
|
|
+ mutex_unlock(&priv->fdb_lock);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int netc_fdb_dump(struct dsa_switch *ds, int port,
|
|
+ dsa_fdb_dump_cb_t *cb, void *data)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct device *dev = ds->dev;
|
|
+ u32 entry_id = 0, next_id = 0;
|
|
+ int rc;
|
|
+
|
|
+ while (1) {
|
|
+ struct netc_fdb_entry fdb = {0};
|
|
+
|
|
+ rc = netc_fdb_entry_get(priv, &fdb, entry_id, &next_id);
|
|
+ /* No fdb entry at i, not an issue */
|
|
+ if (rc) {
|
|
+ dev_err(dev, "Failed to dump FDB: %d\n", rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ if (next_id == 0) /* This entry is empty */
|
|
+ return 0;
|
|
+
|
|
+ /*
|
|
+ * FDB dump callback is per port. This means we have to
|
|
+ * disregard a valid entry if it's not for this port, even if
|
|
+ * only to revisit it later. This is inefficient because the
|
|
+ * 1024-sized FDB table needs to be traversed 4 times through
|
|
+ * SPI during a 'bridge fdb show' command.
|
|
+ */
|
|
+ if (fdb.port_map & BIT(port)) {
|
|
+ /* Need to hide the dsa_8021q VLANs from the user. */
|
|
+ if (vid_is_netc_dsa_8021q(ds, fdb.vid))
|
|
+ fdb.vid = 0;
|
|
+
|
|
+ rc = cb(fdb.mac_addr, fdb.vid, fdb.dynamic, data);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ entry_id = next_id;
|
|
+
|
|
+ if (entry_id == 0 || entry_id == 0xffffffff)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int netc_mdb_add(struct dsa_switch *ds, int port,
|
|
+ const struct switchdev_obj_port_mdb *mdb,
|
|
+ struct dsa_db db)
|
|
+{
|
|
+ return netc_fdb_add(ds, port, mdb->addr, mdb->vid, db);
|
|
+}
|
|
+
|
|
+static int netc_mdb_del(struct dsa_switch *ds, int port,
|
|
+ const struct switchdev_obj_port_mdb *mdb,
|
|
+ struct dsa_db db)
|
|
+{
|
|
+ return netc_fdb_del(ds, port, mdb->addr, mdb->vid, db);
|
|
+}
|
|
+
|
|
+static int netc_parse_ports_node(struct netc_private *priv,
|
|
+ struct device_node *ports_node)
|
|
+{
|
|
+ struct device *dev = &priv->spidev->dev;
|
|
+ struct device_node *child;
|
|
+
|
|
+ for_each_available_child_of_node(ports_node, child) {
|
|
+ struct device_node *phy_node;
|
|
+ phy_interface_t phy_mode;
|
|
+ u32 index;
|
|
+ int err;
|
|
+
|
|
+ /* Get switch port number from DT */
|
|
+ if (of_property_read_u32(child, "reg", &index) < 0) {
|
|
+ dev_err(dev, "Port number not defined in device tree\n");
|
|
+ of_node_put(child);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ /* Get PHY mode from DT */
|
|
+ err = of_get_phy_mode(child, &phy_mode);
|
|
+ if (err) {
|
|
+ dev_err(dev, "Failed to read phy-mode or phy-interface-type %d\n",
|
|
+ index);
|
|
+ of_node_put(child);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ phy_node = of_parse_phandle(child, "phy-handle", 0);
|
|
+ if (!phy_node) {
|
|
+ if (!of_phy_is_fixed_link(child)) {
|
|
+ dev_err(dev, "phy-handle or fixed-link properties missing!\n");
|
|
+ of_node_put(child);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+ /* phy-handle is missing, but fixed-link isn't.
|
|
+ * So it's a fixed link. Default to PHY role.
|
|
+ */
|
|
+ priv->fixed_link[index] = true;
|
|
+ } else {
|
|
+ of_node_put(phy_node);
|
|
+ }
|
|
+
|
|
+ priv->phy_mode[index] = phy_mode;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int netc_parse_dt(struct netc_private *priv)
|
|
+{
|
|
+ struct device *dev = &priv->spidev->dev;
|
|
+ struct device_node *switch_node = dev->of_node;
|
|
+ struct device_node *ports_node;
|
|
+ int rc;
|
|
+
|
|
+ ports_node = of_get_child_by_name(switch_node, "ports");
|
|
+ if (!ports_node)
|
|
+ ports_node = of_get_child_by_name(switch_node, "ethernet-ports");
|
|
+ if (!ports_node) {
|
|
+ dev_err(dev, "Incorrect bindings: absent \"ports\" node\n");
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ rc = netc_parse_ports_node(priv, ports_node);
|
|
+ of_node_put(ports_node);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static void netc_mac_link_down(struct dsa_switch *ds, int port,
|
|
+ unsigned int mode,
|
|
+ phy_interface_t interface)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct netc_mac_config *mac;
|
|
+
|
|
+ mac = &priv->config.mac[port];
|
|
+
|
|
+ mac->egress = false;
|
|
+
|
|
+ netc_port_link_set(priv, port, false);
|
|
+}
|
|
+
|
|
+static void netc_mac_link_up(struct dsa_switch *ds, int port,
|
|
+ unsigned int mode,
|
|
+ phy_interface_t interface,
|
|
+ struct phy_device *phydev,
|
|
+ int speed, int duplex,
|
|
+ bool tx_pause, bool rx_pause)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct netc_mac_config *mac;
|
|
+
|
|
+ mac = &priv->config.mac[port];
|
|
+
|
|
+ mac->speed = speed;
|
|
+ mac->egress = true;
|
|
+
|
|
+ netc_port_phylink_mode_set(priv, mac);
|
|
+ netc_port_link_set(priv, port, true);
|
|
+}
|
|
+
|
|
+static void netc_phylink_get_caps(struct dsa_switch *ds, int port,
|
|
+ struct phylink_config *config)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ phy_interface_t phy_mode;
|
|
+
|
|
+ phy_mode = priv->phy_mode[port];
|
|
+ __set_bit(phy_mode, config->supported_interfaces);
|
|
+
|
|
+ /*
|
|
+ * The MAC does not support pause frames, and also doesn't
|
|
+ * support half-duplex traffic modes.
|
|
+ */
|
|
+ config->mac_capabilities = MAC_10FD | MAC_100FD;
|
|
+ config->mac_capabilities |= MAC_1000FD;
|
|
+}
|
|
+
|
|
+static int netc_bridge_member(struct dsa_switch *ds, int port,
|
|
+ struct dsa_bridge bridge, bool member)
|
|
+{
|
|
+ int rc;
|
|
+
|
|
+ rc = netc_commit_pvid(ds, port);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int netc_bridge_join(struct dsa_switch *ds, int port,
|
|
+ struct dsa_bridge bridge,
|
|
+ bool *tx_fwd_offload,
|
|
+ struct netlink_ext_ack *extack)
|
|
+{
|
|
+ int rc;
|
|
+
|
|
+ rc = netc_bridge_member(ds, port, bridge, true);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
+ rc = dsa_tag_8021q_bridge_join(ds, port, bridge);
|
|
+ if (rc) {
|
|
+ netc_bridge_member(ds, port, bridge, false);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ *tx_fwd_offload = true;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void netc_bridge_leave(struct dsa_switch *ds, int port,
|
|
+ struct dsa_bridge bridge)
|
|
+{
|
|
+ dsa_tag_8021q_bridge_leave(ds, port, bridge);
|
|
+ netc_bridge_member(ds, port, bridge, false);
|
|
+}
|
|
+
|
|
+static enum dsa_tag_protocol
|
|
+netc_get_tag_protocol(struct dsa_switch *ds, int port,
|
|
+ enum dsa_tag_protocol mp)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+
|
|
+ return priv->info->tag_proto;
|
|
+}
|
|
+
|
|
+int netc_vlan_filtering(struct dsa_switch *ds, int port, bool enabled,
|
|
+ struct netlink_ext_ack *extack)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct netc_config *config = &priv->config;
|
|
+ int rc;
|
|
+
|
|
+ if (enabled) {
|
|
+ /* Enable VLAN filtering. */
|
|
+ config->tpid = ETH_P_8021Q;
|
|
+ config->tpid2 = ETH_P_8021AD;
|
|
+ } else {
|
|
+ /* Disable VLAN filtering. */
|
|
+ config->tpid = ETH_P_8021Q;
|
|
+ config->tpid2 = ETH_P_NETC;
|
|
+ }
|
|
+
|
|
+ for (port = 0; port < ds->num_ports; port++) {
|
|
+ if (dsa_is_unused_port(ds, port))
|
|
+ continue;
|
|
+
|
|
+ rc = netc_commit_pvid(ds, port);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int netc_bridge_vlan_add(struct dsa_switch *ds, int port,
|
|
+ const struct switchdev_obj_port_vlan *vlan,
|
|
+ struct netlink_ext_ack *extack)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ uint16_t flags = vlan->flags;
|
|
+ bool untagged = false;
|
|
+ int rc;
|
|
+
|
|
+ /* Be sure to deny the configuration done by tag_8021q. */
|
|
+ if (vid_is_netc_dsa_8021q(ds, vlan->vid)) {
|
|
+ NL_SET_ERR_MSG_MOD(extack,
|
|
+ "VLAN ID 3072-3076 & 3088 reserved for dsa_8021q operation");
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ /* Always install bridge VLANs as egress-tagged on CPU and DSA ports */
|
|
+ if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
|
|
+ flags = 0;
|
|
+
|
|
+ if (flags & BRIDGE_VLAN_INFO_UNTAGGED)
|
|
+ untagged = true;
|
|
+
|
|
+ rc = netc_vlan_entry_add(priv, vlan->vid, port, untagged);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
+ if (vlan->flags & BRIDGE_VLAN_INFO_PVID)
|
|
+ priv->bridge_pvid[port] = vlan->vid;
|
|
+
|
|
+ /* Allow enough time between adding VLAN entry and setting PVID */
|
|
+ usleep_range(NETC_SPI_MSG_RESPONSE_TIME,
|
|
+ NETC_SPI_MSG_RESPONSE_TIME * 10);
|
|
+
|
|
+ return netc_commit_pvid(ds, port);
|
|
+}
|
|
+
|
|
+static int netc_bridge_vlan_del(struct dsa_switch *ds, int port,
|
|
+ const struct switchdev_obj_port_vlan *vlan)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ int rc;
|
|
+
|
|
+ rc = netc_vlan_entry_del(priv, vlan->vid, port);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
+ /*
|
|
+ * In case the pvid was deleted, make sure that untagged packets will
|
|
+ * be dropped.
|
|
+ */
|
|
+ return netc_commit_pvid(ds, port);
|
|
+}
|
|
+
|
|
+static int netc_8021q_vlan_add(struct dsa_switch *ds, int port,
|
|
+ uint16_t vid, uint16_t flags)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ int rc;
|
|
+
|
|
+ rc = netc_vlan_entry_add(priv, vid, port, false);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
+ if (flags & BRIDGE_VLAN_INFO_PVID)
|
|
+ priv->tag_8021q_pvid[port] = vid;
|
|
+
|
|
+ /* Allow enough time between adding VLAN entry and setting PVID */
|
|
+ usleep_range(NETC_SPI_MSG_RESPONSE_TIME,
|
|
+ NETC_SPI_MSG_RESPONSE_TIME * 10);
|
|
+
|
|
+ return netc_commit_pvid(ds, port);
|
|
+}
|
|
+
|
|
+static int netc_8021q_vlan_del(struct dsa_switch *ds, int port, uint16_t vid)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+
|
|
+ return netc_vlan_entry_del(priv, vid, port);
|
|
+}
|
|
+
|
|
+static int netc_prechangeupper(struct dsa_switch *ds, int port,
|
|
+ struct netdev_notifier_changeupper_info *info)
|
|
+{
|
|
+ struct netlink_ext_ack *extack = info->info.extack;
|
|
+ struct net_device *upper = info->upper_dev;
|
|
+ struct dsa_switch_tree *dst = ds->dst;
|
|
+ struct dsa_port *dp;
|
|
+
|
|
+ if (is_vlan_dev(upper)) {
|
|
+ NL_SET_ERR_MSG_MOD(extack, "8021q uppers are not supported");
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ if (netif_is_bridge_master(upper)) {
|
|
+ list_for_each_entry(dp, &dst->ports, list) {
|
|
+ struct net_device *br = dsa_port_bridge_dev_get(dp);
|
|
+
|
|
+ if (br && br != upper && br_vlan_enabled(br)) {
|
|
+ NL_SET_ERR_MSG_MOD(extack,
|
|
+ "Only one VLAN-aware bridge is supported");
|
|
+ return -EBUSY;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int netc_connect_tag_protocol(struct dsa_switch *ds,
|
|
+ enum dsa_tag_protocol proto)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct netc_tagger_data *tagger_data;
|
|
+
|
|
+ if (proto != priv->info->tag_proto)
|
|
+ return -EPROTONOSUPPORT;
|
|
+
|
|
+ tagger_data = netc_tagger_data(ds);
|
|
+ tagger_data->meta_tstamp_handler = netc_process_meta_tstamp;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int netc_stream_identify(struct flow_cls_offload *f, struct netc_stream *stream)
|
|
+{
|
|
+ struct flow_rule *rule = flow_cls_offload_flow_rule(f);
|
|
+ struct flow_dissector *dissector = rule->match.dissector;
|
|
+
|
|
+ if (dissector->used_keys &
|
|
+ ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
|
|
+ BIT(FLOW_DISSECTOR_KEY_BASIC) |
|
|
+ BIT(FLOW_DISSECTOR_KEY_VLAN) |
|
|
+ BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS)))
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
|
|
+ struct flow_match_eth_addrs match;
|
|
+
|
|
+ flow_rule_match_eth_addrs(rule, &match);
|
|
+ if (is_zero_ether_addr(match.mask->src) &&
|
|
+ !is_zero_ether_addr(match.mask->dst)) {
|
|
+ ether_addr_copy(stream->mac, match.key->dst);
|
|
+ stream->type = STREAMID_NULL;
|
|
+ } else if (!is_zero_ether_addr(match.mask->src) &&
|
|
+ is_zero_ether_addr(match.mask->dst)) {
|
|
+ ether_addr_copy(stream->mac, match.key->src);
|
|
+ stream->type = STREAMID_SMAC_VLAN;
|
|
+ } else
|
|
+ return -EOPNOTSUPP;
|
|
+ } else {
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+
|
|
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
|
|
+ struct flow_match_vlan match;
|
|
+
|
|
+ flow_rule_match_vlan(rule, &match);
|
|
+ if (match.mask->vlan_priority)
|
|
+ stream->prio = match.key->vlan_priority;
|
|
+ else
|
|
+ stream->prio = -1;
|
|
+
|
|
+ if (!match.mask->vlan_id)
|
|
+ return -EOPNOTSUPP;
|
|
+ stream->vid = match.key->vlan_id;
|
|
+ } else {
|
|
+ stream->vid = 0;
|
|
+ }
|
|
+
|
|
+ stream->id = f->cookie;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct netc_stream *
|
|
+netc_stream_table_lookup(struct list_head *stream_list,
|
|
+ struct netc_stream *stream)
|
|
+{
|
|
+ struct netc_stream *tmp;
|
|
+
|
|
+ list_for_each_entry(tmp, stream_list, list)
|
|
+ if (ether_addr_equal(tmp->mac, stream->mac) &&
|
|
+ tmp->vid == stream->vid && tmp->port_mask == stream->port_mask &&
|
|
+ tmp->type == stream->type)
|
|
+ return tmp;
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static int netc_stream_handle_alloc(struct netc_private *priv)
|
|
+{
|
|
+ int i;
|
|
+ for (i = 0; i < MAX_SSIDS; i++) {
|
|
+ if (priv->psfp.ssids[i] == 0) {
|
|
+ priv->psfp.ssids[i] = 1;
|
|
+ priv->psfp.num_ssids++;
|
|
+ return i;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return -EINVAL;
|
|
+}
|
|
+
|
|
+static int netc_stream_handle_del(struct netc_private *priv, u32 handle)
|
|
+{
|
|
+ if (handle < 0 || handle > MAX_SSIDS)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (priv->psfp.ssids[handle] == 1) {
|
|
+ priv->psfp.ssids[handle] = 0;
|
|
+ priv->psfp.num_ssids--;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int netc_stream_table_add(struct netc_private *priv, struct list_head *stream_list,
|
|
+ struct netc_stream *stream, struct netlink_ext_ack *extack)
|
|
+{
|
|
+ struct netc_stream *stream_entry;
|
|
+ int rc;
|
|
+
|
|
+ stream_entry = kmemdup(stream, sizeof(*stream_entry), GFP_KERNEL);
|
|
+ if (!stream_entry)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ if (stream->update) {
|
|
+ rc = netc_streamid_set(priv, stream_entry->port_mask, stream_entry->handle,
|
|
+ stream_entry->mac, stream_entry->vid, stream_entry->type);
|
|
+ if (rc) {
|
|
+ kfree(stream_entry);
|
|
+ return rc;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ list_add_tail(&stream_entry->list, stream_list);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct netc_stream *
|
|
+netc_stream_table_get(struct list_head *stream_list, unsigned long id)
|
|
+{
|
|
+ struct netc_stream *tmp;
|
|
+
|
|
+ list_for_each_entry(tmp, stream_list, list)
|
|
+ if (tmp->id == id)
|
|
+ return tmp;
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static int netc_cls_flower_add(struct dsa_switch *ds, int port,
|
|
+ struct flow_cls_offload *f, bool ingress)
|
|
+{
|
|
+ struct dsa_port *dp = dsa_to_port(ds, port);
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct netlink_ext_ack *extack = f->common.extack;
|
|
+ const struct flow_action_entry *a;
|
|
+ struct netc_stream stream = {.action = NETC_STREAM_NULL};
|
|
+ struct netc_stream *stream_entry;
|
|
+ struct netc_psfp_list *psfp;
|
|
+ struct netc_stream_filter filter = {0};
|
|
+ int cpu_port = dp->cpu_dp->index;
|
|
+ uint64_t rate;
|
|
+ int i, rc;
|
|
+ uint32_t handle;
|
|
+ bool set_stream = false;
|
|
+
|
|
+ psfp = &priv->psfp;
|
|
+
|
|
+ rc = netc_stream_identify(f, &stream);
|
|
+ if (rc) {
|
|
+ NL_SET_ERR_MSG_MOD(extack, "Only can match on VID and dest MAC");
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ mutex_lock(&psfp->lock);
|
|
+
|
|
+ flow_action_for_each(i, a, &f->rule->action) {
|
|
+ switch (a->id) {
|
|
+ case FLOW_ACTION_FRER:
|
|
+ if ((a->frer.recover && a->frer.tag_action == FRER_TAG_PUSH) ||
|
|
+ (!a->frer.recover && a->frer.tag_action != FRER_TAG_PUSH)) {
|
|
+ NL_SET_ERR_MSG_MOD(extack,
|
|
+ "Non-supported tag action");
|
|
+ rc = -EOPNOTSUPP;
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ if (a->frer.recover) {
|
|
+ stream.action = NETC_STREAM_FRER_SEQREC;
|
|
+ filter.seqrec.enc = a->frer.tag_type;
|
|
+ filter.seqrec.alg = a->frer.rcvy_alg;
|
|
+ filter.seqrec.his_len = a->frer.rcvy_history_len;
|
|
+ filter.seqrec.reset_timeout = a->frer.rcvy_reset_msec;
|
|
+ filter.seqrec.rtag_pop_en =
|
|
+ (a->frer.tag_action == FRER_TAG_POP) ? 1 : 0;
|
|
+ if (ingress) {
|
|
+ stream.port_mask = 0xF & ~BIT(cpu_port);
|
|
+ filter.seqrec.eport = cpu_port;
|
|
+ } else {
|
|
+ stream.port_mask = 0xF & ~BIT(port);
|
|
+ filter.seqrec.eport = port;
|
|
+ }
|
|
+ } else {
|
|
+ stream.action = NETC_STREAM_FRER_SEQGEN;
|
|
+ filter.seqgen.enc = a->frer.tag_type;
|
|
+ if (ingress) {
|
|
+ filter.seqgen.iport = port;
|
|
+ stream.port_mask = BIT(port);
|
|
+ } else {
|
|
+ filter.seqgen.iport = cpu_port;
|
|
+ stream.port_mask = BIT(cpu_port);
|
|
+ }
|
|
+ }
|
|
+ set_stream = true;
|
|
+ break;
|
|
+
|
|
+ case FLOW_ACTION_GATE:
|
|
+ stream.port_mask = BIT(port);
|
|
+ stream.action = NETC_STREAM_QCI;
|
|
+ filter.qci.gate.prio = a->gate.prio;
|
|
+ filter.qci.gate.basetime = a->gate.basetime;
|
|
+ filter.qci.gate.cycletime = a->gate.cycletime;
|
|
+ filter.qci.gate.cycletimeext = a->gate.cycletimeext;
|
|
+ filter.qci.gate.num_entries = a->gate.num_entries;
|
|
+ filter.qci.gate.entries = a->gate.entries;
|
|
+ set_stream = true;
|
|
+ break;
|
|
+
|
|
+ case FLOW_ACTION_POLICE:
|
|
+ stream.port_mask = BIT(port);
|
|
+ stream.action = NETC_STREAM_QCI;
|
|
+ if (a->police.mtu < 0) {
|
|
+ NL_SET_ERR_MSG_MOD(extack,
|
|
+ "invalided maxsdu size");
|
|
+ rc = -EINVAL;
|
|
+ goto err;
|
|
+ }
|
|
+ filter.qci.maxsdu = a->police.mtu;
|
|
+
|
|
+ rate = a->police.rate_bytes_ps;
|
|
+ if (rate) {
|
|
+ filter.qci.police.burst = a->police.burst;
|
|
+ filter.qci.police.rate = rate * 8;
|
|
+ }
|
|
+ set_stream = true;
|
|
+ break;
|
|
+
|
|
+ case FLOW_ACTION_MIRRED:
|
|
+ if (stream.type != STREAMID_NULL) {
|
|
+ NL_SET_ERR_MSG_MOD(extack,
|
|
+ "Only support destination MAC");
|
|
+ rc = -EOPNOTSUPP;
|
|
+ goto err;
|
|
+ }
|
|
+ dp = dsa_port_from_netdev(a->dev);
|
|
+ if (IS_ERR(dp)) {
|
|
+ rc = -EINVAL;
|
|
+ goto err;
|
|
+ }
|
|
+ if (netc_fdb_entry_add(priv, stream.mac, stream.vid, dp->index) < 0) {
|
|
+ rc = -EINVAL;
|
|
+ goto err;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ rc = -EOPNOTSUPP;
|
|
+ goto err;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!set_stream)
|
|
+ goto exit;
|
|
+
|
|
+ stream_entry = netc_stream_table_lookup(&psfp->stream_list, &stream);
|
|
+ if (stream_entry) {
|
|
+ stream.handle = stream_entry->handle;
|
|
+ stream.update = false;
|
|
+ } else {
|
|
+ handle = netc_stream_handle_alloc(priv);
|
|
+ stream.handle = handle;
|
|
+ stream.update = true;
|
|
+ }
|
|
+
|
|
+ rc = netc_stream_table_add(priv, &psfp->stream_list,
|
|
+ &stream, extack);
|
|
+ if (rc) {
|
|
+ NL_SET_ERR_MSG_MOD(extack, "Failed to add new stream table");
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ filter.stream_handle = stream.handle;
|
|
+
|
|
+ switch (stream.action) {
|
|
+ case NETC_STREAM_FRER_SEQGEN:
|
|
+ rc = netc_frer_seqgen(priv, &filter);
|
|
+ if (rc) {
|
|
+ goto err;
|
|
+ }
|
|
+ break;
|
|
+ case NETC_STREAM_FRER_SEQREC:
|
|
+ rc = netc_frer_seqrec(priv, &filter);
|
|
+ if (rc) {
|
|
+ goto err;
|
|
+ }
|
|
+ break;
|
|
+ case NETC_STREAM_QCI:
|
|
+ filter.qci.priority_spec = stream.prio;
|
|
+ rc = netc_qci_set(priv, &filter, port);
|
|
+ if (rc) {
|
|
+ goto err;
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ mutex_unlock(&psfp->lock);
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+
|
|
+exit:
|
|
+ mutex_unlock(&psfp->lock);
|
|
+
|
|
+ return 0;
|
|
+err:
|
|
+ mutex_unlock(&psfp->lock);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int netc_cls_flower_del(struct dsa_switch *ds, int port,
|
|
+ struct flow_cls_offload *cls, bool ingress)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct netc_stream *stream, *tmp;
|
|
+ struct netc_psfp_list *psfp;
|
|
+ u32 stream_handle;
|
|
+ int rc;
|
|
+
|
|
+ psfp = &priv->psfp;
|
|
+
|
|
+ mutex_lock(&psfp->lock);
|
|
+
|
|
+ stream = netc_stream_table_get(&psfp->stream_list, cls->cookie);
|
|
+ if (!stream) {
|
|
+ mutex_unlock(&psfp->lock);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ stream_handle = stream->handle;
|
|
+
|
|
+ switch (stream->action) {
|
|
+ case NETC_STREAM_FRER_SEQGEN:
|
|
+ rc = netc_frer_sg_del(priv, stream_handle, port);
|
|
+ if (rc)
|
|
+ goto err;
|
|
+ break;
|
|
+ case NETC_STREAM_FRER_SEQREC:
|
|
+ rc = netc_frer_sr_del(priv, stream_handle, port);
|
|
+ if (rc)
|
|
+ goto err;
|
|
+ break;
|
|
+ case NETC_STREAM_QCI:
|
|
+ rc = netc_qci_del(priv, stream_handle, port);
|
|
+ if (rc)
|
|
+ goto err;
|
|
+ break;
|
|
+ default:
|
|
+ mutex_unlock(&psfp->lock);
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+
|
|
+ list_del(&stream->list);
|
|
+
|
|
+ tmp = netc_stream_table_lookup(&psfp->stream_list, stream);
|
|
+ if (!tmp) {
|
|
+ rc = netc_streamid_del(priv, stream->handle);
|
|
+ if (rc)
|
|
+ goto err;
|
|
+ rc = netc_stream_handle_del(priv, stream->handle);
|
|
+ if (rc)
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ kfree(stream);
|
|
+ mutex_unlock(&psfp->lock);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err:
|
|
+ mutex_unlock(&psfp->lock);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int netc_cls_flower_stats(struct dsa_switch *ds, int port,
|
|
+ struct flow_cls_offload *cls, bool ingress)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct netc_psfp_list *psfp;
|
|
+ struct netc_stream *stream;
|
|
+ struct flow_stats stats;
|
|
+ int rc;
|
|
+
|
|
+ psfp = &priv->psfp;
|
|
+
|
|
+ mutex_lock(&psfp->lock);
|
|
+
|
|
+ stream = netc_stream_table_get(&psfp->stream_list, cls->cookie);
|
|
+ if (!stream) {
|
|
+ mutex_unlock(&psfp->lock);
|
|
+ return 0;
|
|
+ }
|
|
+ mutex_unlock(&psfp->lock);
|
|
+
|
|
+ rc = netc_qci_get(priv, stream->handle, &stats);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ flow_stats_update(&cls->stats, 0x0, stats.pkts, stats.drops, 0x0,
|
|
+ FLOW_ACTION_HW_STATS_IMMEDIATE);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int netc_port_mqprio_set(struct dsa_switch *ds, int port,
|
|
+ struct tc_mqprio_qopt_offload *mqprio)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct tc_mqprio_qopt *qopt = &mqprio->qopt;
|
|
+ struct dsa_port *dp;
|
|
+ uint8_t *map;
|
|
+ int rc;
|
|
+
|
|
+ dp = dsa_to_port(ds, port);
|
|
+
|
|
+ if (dp->bridge)
|
|
+ map = qopt->prio_tc_map;
|
|
+ else
|
|
+ map = netc_default_priority_map;
|
|
+
|
|
+ if (!qopt->num_tc)
|
|
+ map = netc_default_priority_map;
|
|
+
|
|
+ rc = netc_port_set_preemptible_tcs(ds, port, mqprio->preemptible_tcs);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
+ return netc_port_priority_map(priv, port, map);
|
|
+}
|
|
+
|
|
+static int netc_port_taprio_set(struct dsa_switch *ds, int port,
|
|
+ struct tc_taprio_qopt_offload *taprio)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ int enable = 1;
|
|
+ int rc;
|
|
+
|
|
+ if (taprio->cmd == TAPRIO_CMD_DESTROY) {
|
|
+ enable = 0;
|
|
+ } else if (taprio->cmd != TAPRIO_CMD_REPLACE) {
|
|
+ rc = -EOPNOTSUPP;
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ netc_port_mqprio_set(ds, port, &taprio->mqprio);
|
|
+
|
|
+ rc = netc_qbv_set(priv, port, enable, taprio);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int netc_qos_query_caps(struct tc_query_caps_base *base)
|
|
+{
|
|
+ switch (base->type) {
|
|
+ case TC_SETUP_QDISC_TAPRIO: {
|
|
+ struct tc_taprio_caps *caps = base->caps;
|
|
+
|
|
+ caps->supports_queue_max_sdu = true;
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+ default:
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static int netc_port_setup_tc(struct dsa_switch *ds, int port,
|
|
+ enum tc_setup_type type,
|
|
+ void *type_data)
|
|
+{
|
|
+ switch (type) {
|
|
+ case TC_QUERY_CAPS:
|
|
+ return netc_qos_query_caps(type_data);
|
|
+ case TC_SETUP_QDISC_TAPRIO:
|
|
+ return netc_port_taprio_set(ds, port, type_data);
|
|
+ case TC_SETUP_QDISC_CBS:
|
|
+ dev_info(ds->dev, "TC_SETUP_QDISC_CBS not support yet!\n");
|
|
+ return -EOPNOTSUPP;
|
|
+ case TC_SETUP_QDISC_MQPRIO:
|
|
+ return netc_port_mqprio_set(ds, port, type_data);
|
|
+ default:
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int netc_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ int maxlen = new_mtu + ETH_HLEN + ETH_FCS_LEN;
|
|
+
|
|
+ if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
|
|
+ maxlen += VLAN_HLEN;
|
|
+
|
|
+ return netc_port_mtu_set(priv, port, maxlen);
|
|
+}
|
|
+
|
|
+static int netc_get_max_mtu(struct dsa_switch *ds, int port)
|
|
+{
|
|
+ return 2000 - VLAN_ETH_HLEN - ETH_FCS_LEN;
|
|
+}
|
|
+
|
|
+static int netc_mac_init(struct netc_private *priv)
|
|
+{
|
|
+ struct netc_mac_config *mac;
|
|
+ struct dsa_switch *ds = priv->ds;
|
|
+ struct dsa_port *dp;
|
|
+
|
|
+ mac = priv->config.mac;
|
|
+
|
|
+ dsa_switch_for_each_port(dp, ds) {
|
|
+ mac[dp->index].port = dp->index;
|
|
+ mac[dp->index].speed = 1000;
|
|
+ mac[dp->index].vlanid = 1;
|
|
+ mac[dp->index].drpuntag = false;
|
|
+ mac[dp->index].retag = false;
|
|
+
|
|
+ if (dsa_port_is_dsa(dp))
|
|
+ dp->learning = true;
|
|
+
|
|
+ /* Disallow untagged packets from being received on the
|
|
+ * CPU and DSA ports.
|
|
+ */
|
|
+ if (dsa_port_is_cpu(dp) || dsa_port_is_dsa(dp))
|
|
+ mac[dp->index].drpuntag = true;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int netc_dsa_init(struct netc_private *priv)
|
|
+{
|
|
+ struct dsa_switch *ds = priv->ds;
|
|
+ struct dsa_port *dp, *cpu_dp = NULL;
|
|
+ const u8 *mac;
|
|
+ int port;
|
|
+
|
|
+ for (port = 0; port < ds->num_ports; port++) {
|
|
+ if (dsa_is_cpu_port(ds, port)) {
|
|
+ cpu_dp = dsa_to_port(ds, port);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!cpu_dp) {
|
|
+ dev_err(ds->dev, "Failed to find cpu port\n");
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ if (!is_zero_ether_addr(cpu_dp->mac))
|
|
+ mac = cpu_dp->mac;
|
|
+ else
|
|
+ mac = cpu_dp->master->dev_addr;
|
|
+
|
|
+ pr_info("NETC DSA: cpu port:%d master:%s\n",
|
|
+ cpu_dp->index, cpu_dp->master->name);
|
|
+
|
|
+ for (port = 0; port < ds->num_ports; port++) {
|
|
+ dp = dsa_to_port(ds, port);
|
|
+
|
|
+ if (dsa_port_is_unused(dp))
|
|
+ continue;
|
|
+ if (dsa_port_is_cpu(dp))
|
|
+ continue;
|
|
+
|
|
+ pr_info("NETC DSA: add switch port:%d\n", port);
|
|
+
|
|
+ netc_port_dsa_add(priv, cpu_dp->index, port, mac);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int netc_setup(struct dsa_switch *ds)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ int port;
|
|
+ int rc;
|
|
+
|
|
+ rc = netc_config_setup(&priv->config);
|
|
+ if (rc < 0) {
|
|
+ dev_err(ds->dev, "Failed to setup config: %d\n", rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ netc_mac_init(priv);
|
|
+ netc_dsa_init(priv);
|
|
+
|
|
+ for (port = 0; port < ds->num_ports; port++) {
|
|
+ priv->tag_8021q_pvid[port] = NETC_DEFAULT_VLAN;
|
|
+ priv->bridge_pvid[port] = NETC_DEFAULT_VLAN;
|
|
+ }
|
|
+
|
|
+ rc = netc_ptp_clock_register(ds);
|
|
+ if (rc < 0) {
|
|
+ dev_err(ds->dev, "Failed to register PTP clock: %d\n", rc);
|
|
+ goto out_config_free;
|
|
+ }
|
|
+
|
|
+ rc = netc_devlink_setup(ds);
|
|
+ if (rc < 0)
|
|
+ goto out_ptp_teardown;
|
|
+
|
|
+ rtnl_lock();
|
|
+ rc = dsa_tag_8021q_register(ds, htons(ETH_P_8021Q));
|
|
+ rtnl_unlock();
|
|
+ if (rc)
|
|
+ goto out_devlink_teardown;
|
|
+
|
|
+ /*
|
|
+ * On netc, VLAN filtering per se is always enabled in hardware.
|
|
+ * The only thing we can do to disable it is lie about what the 802.1Q
|
|
+ * EtherType is.
|
|
+ * So it will still try to apply VLAN filtering, but all ingress
|
|
+ * traffic (except frames received with EtherType of ETH_P_NETC)
|
|
+ * will be internally tagged with a distorted VLAN header where the
|
|
+ * TPID is ETH_P_NETC, and the VLAN ID is the port pvid.
|
|
+ */
|
|
+ ds->vlan_filtering_is_global = true;
|
|
+ ds->untag_bridge_pvid = true;
|
|
+ ds->fdb_isolation = true;
|
|
+ /* tag_8021q has 3 bits for the VBID, and the value 0 is reserved */
|
|
+ ds->max_num_bridges = 7;
|
|
+
|
|
+ /* Advertise the 8 egress queues */
|
|
+ ds->num_tx_queues = NETC_NUM_TC;
|
|
+
|
|
+ ds->mtu_enforcement_ingress = true;
|
|
+ ds->assisted_learning_on_cpu_port = true;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+out_devlink_teardown:
|
|
+ netc_devlink_teardown(ds);
|
|
+out_ptp_teardown:
|
|
+ netc_ptp_clock_unregister(ds);
|
|
+out_config_free:
|
|
+ netc_config_free(&priv->config);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static void netc_teardown(struct dsa_switch *ds)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+
|
|
+ rtnl_lock();
|
|
+ dsa_tag_8021q_unregister(ds);
|
|
+ rtnl_unlock();
|
|
+
|
|
+ netc_devlink_teardown(ds);
|
|
+ netc_ptp_clock_unregister(ds);
|
|
+ netc_config_free(&priv->config);
|
|
+}
|
|
+
|
|
+static const struct dsa_switch_ops netc_switch_ops = {
|
|
+ .get_tag_protocol = netc_get_tag_protocol,
|
|
+ .connect_tag_protocol = netc_connect_tag_protocol,
|
|
+ .setup = netc_setup,
|
|
+ .teardown = netc_teardown,
|
|
+ .port_change_mtu = netc_change_mtu,
|
|
+ .port_max_mtu = netc_get_max_mtu,
|
|
+ .phylink_get_caps = netc_phylink_get_caps,
|
|
+ .phylink_mac_link_up = netc_mac_link_up,
|
|
+ .phylink_mac_link_down = netc_mac_link_down,
|
|
+ .get_strings = netc_get_strings,
|
|
+ .get_ethtool_stats = netc_get_ethtool_stats,
|
|
+ .get_sset_count = netc_get_sset_count,
|
|
+ .port_fdb_dump = netc_fdb_dump,
|
|
+ .port_fdb_add = netc_fdb_add,
|
|
+ .port_fdb_del = netc_fdb_del,
|
|
+ .port_mdb_add = netc_mdb_add,
|
|
+ .port_mdb_del = netc_mdb_del,
|
|
+ .port_bridge_join = netc_bridge_join,
|
|
+ .port_bridge_leave = netc_bridge_leave,
|
|
+ .port_vlan_filtering = netc_vlan_filtering,
|
|
+ .port_vlan_add = netc_bridge_vlan_add,
|
|
+ .port_vlan_del = netc_bridge_vlan_del,
|
|
+ .port_hwtstamp_get = netc_hwtstamp_get,
|
|
+ .port_hwtstamp_set = netc_hwtstamp_set,
|
|
+ .port_rxtstamp = netc_port_rxtstamp,
|
|
+ .port_txtstamp = netc_port_txtstamp,
|
|
+ .get_ts_info = netc_get_ts_info,
|
|
+ .devlink_info_get = netc_devlink_info_get,
|
|
+ .tag_8021q_vlan_add = netc_8021q_vlan_add,
|
|
+ .tag_8021q_vlan_del = netc_8021q_vlan_del,
|
|
+ .port_prechangeupper = netc_prechangeupper,
|
|
+ .cls_flower_add = netc_cls_flower_add,
|
|
+ .cls_flower_del = netc_cls_flower_del,
|
|
+ .cls_flower_stats = netc_cls_flower_stats,
|
|
+ .port_setup_tc = netc_port_setup_tc,
|
|
+ .set_mm = netc_port_set_mm,
|
|
+ .get_mm = netc_port_get_mm,
|
|
+};
|
|
+
|
|
+static const struct of_device_id netc_dt_ids[];
|
|
+static int netc_check_device_id(struct netc_private *priv)
|
|
+{
|
|
+ struct device *dev = &priv->spidev->dev;
|
|
+ struct netc_config *config = &priv->config;
|
|
+ int rc;
|
|
+
|
|
+ rc = netc_get_devinfo(priv, config);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ if (config->device_id != priv->info->device_id) {
|
|
+ dev_err(dev, "Device tree specifies device ID 0x%x, but found 0x%x please fix it!\n",
|
|
+ priv->info->device_id, config->device_id);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int netc_probe(struct spi_device *spi)
|
|
+{
|
|
+ struct device *dev = &spi->dev;
|
|
+ struct netc_private *priv;
|
|
+ struct dsa_switch *ds;
|
|
+ size_t max_xfer, max_msg;
|
|
+ int rc;
|
|
+
|
|
+ if (!dev->of_node) {
|
|
+ dev_err(dev, "No DTS bindings for netc driver\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ priv = devm_kzalloc(dev, sizeof(struct netc_private), GFP_KERNEL);
|
|
+ if (!priv)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ /*
|
|
+ * Populate our driver private structure (priv) based on
|
|
+ * the device tree node that was probed (spi)
|
|
+ */
|
|
+ priv->spidev = spi;
|
|
+ spi_set_drvdata(spi, priv);
|
|
+
|
|
+ /* Configure the SPI bus */
|
|
+ spi->bits_per_word = NETC_SPI_WORD_BITS;
|
|
+ rc = spi_setup(spi);
|
|
+ if (rc < 0) {
|
|
+ dev_err(dev, "Could not init SPI\n");
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ max_xfer = spi_max_transfer_size(spi);
|
|
+ max_msg = spi_max_message_size(spi);
|
|
+
|
|
+ /*
|
|
+ * We need to send at least one 64-bit word of SPI payload per message
|
|
+ * in order to be able to make useful progress.
|
|
+ */
|
|
+ if (max_msg < NETC_SPI_MSG_HEADER_SIZE + 8) {
|
|
+ dev_err(dev, "SPI master cannot send large enough buffers, aborting\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ priv->max_xfer_len = NETC_SPI_MSG_MAXLEN;
|
|
+ if (priv->max_xfer_len > max_xfer)
|
|
+ priv->max_xfer_len = max_xfer;
|
|
+ if (priv->max_xfer_len > max_msg - NETC_SPI_MSG_HEADER_SIZE)
|
|
+ priv->max_xfer_len = max_msg - NETC_SPI_MSG_HEADER_SIZE;
|
|
+
|
|
+ priv->info = of_device_get_match_data(dev);
|
|
+
|
|
+ /* Detect hardware device */
|
|
+ rc = netc_check_device_id(priv);
|
|
+ if (rc < 0) {
|
|
+ dev_err(dev, "Device ID check failed: %d\n", rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ dev_info(dev, "Probed switch chip:%s ID:0x%x firmware:%d.%d.%d\n",
|
|
+ priv->info->name,
|
|
+ priv->config.device_id,
|
|
+ priv->config.version_major,
|
|
+ priv->config.version_minor,
|
|
+ priv->config.version_revision);
|
|
+
|
|
+ ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL);
|
|
+ if (!ds)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ ds->dev = dev;
|
|
+ ds->num_ports = priv->info->num_ports;
|
|
+ ds->ops = &netc_switch_ops;
|
|
+ ds->priv = priv;
|
|
+ priv->ds = ds;
|
|
+
|
|
+ mutex_init(&priv->mgmt_lock);
|
|
+ mutex_init(&priv->fdb_lock);
|
|
+ spin_lock_init(&priv->ts_id_lock);
|
|
+
|
|
+ rc = netc_parse_dt(priv);
|
|
+ if (rc < 0) {
|
|
+ dev_err(ds->dev, "Failed to parse DT: %d\n", rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ //for tc filter
|
|
+ INIT_LIST_HEAD(&priv->psfp.stream_list);
|
|
+ memset(priv->psfp.ssids, 0, sizeof(priv->psfp.ssids));
|
|
+ priv->psfp.num_ssids = 0;
|
|
+ mutex_init(&priv->psfp.lock);
|
|
+
|
|
+ return dsa_register_switch(priv->ds);
|
|
+}
|
|
+
|
|
+static void netc_remove(struct spi_device *spi)
|
|
+{
|
|
+ struct netc_private *priv = spi_get_drvdata(spi);
|
|
+
|
|
+ if (!priv)
|
|
+ return;
|
|
+
|
|
+ dsa_unregister_switch(priv->ds);
|
|
+}
|
|
+
|
|
+static void netc_shutdown(struct spi_device *spi)
|
|
+{
|
|
+ struct netc_private *priv = spi_get_drvdata(spi);
|
|
+
|
|
+ if (!priv)
|
|
+ return;
|
|
+
|
|
+ dsa_switch_shutdown(priv->ds);
|
|
+
|
|
+ spi_set_drvdata(spi, NULL);
|
|
+}
|
|
+
|
|
+const struct netc_info netc_info = {
|
|
+ .device_id = NETC_RT1180_DEVICE_ID,
|
|
+ .tag_proto = DSA_TAG_PROTO_NETC_VALUE,
|
|
+ .can_limit_mcast_flood = false,
|
|
+ .num_ports = NETC_NUM_PORTS,
|
|
+ .name = "netc",
|
|
+};
|
|
+
|
|
+static const struct of_device_id netc_dt_ids[] = {
|
|
+ { .compatible = "nxp,imxrt1180-netc", .data = &netc_info},
|
|
+ { /* sentinel */ },
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, netc_dt_ids);
|
|
+
|
|
+static const struct spi_device_id netc_spi_ids[] = {
|
|
+ { "imxrt1180-netc" },
|
|
+ { },
|
|
+};
|
|
+MODULE_DEVICE_TABLE(spi, netc_spi_ids);
|
|
+
|
|
+static struct spi_driver netc_driver = {
|
|
+ .driver = {
|
|
+ .name = "netc-spi",
|
|
+ .owner = THIS_MODULE,
|
|
+ .of_match_table = of_match_ptr(netc_dt_ids),
|
|
+ },
|
|
+ .id_table = netc_spi_ids,
|
|
+ .probe = netc_probe,
|
|
+ .remove = netc_remove,
|
|
+ .shutdown = netc_shutdown,
|
|
+};
|
|
+
|
|
+module_spi_driver(netc_driver);
|
|
+
|
|
+MODULE_AUTHOR("Minghuan Lian <Minghuan.Lian@nxp.com>");
|
|
+
|
|
+MODULE_DESCRIPTION("NETC DSA Driver");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/drivers/net/dsa/netc/netc_ptp.c b/drivers/net/dsa/netc/netc_ptp.c
|
|
new file mode 100644
|
|
index 000000000000..3e03641b7ae9
|
|
--- /dev/null
|
|
+++ b/drivers/net/dsa/netc/netc_ptp.c
|
|
@@ -0,0 +1,375 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2023-2024 NXP
|
|
+ */
|
|
+
|
|
+#include "netc.h"
|
|
+
|
|
+#define extts_to_data(t) \
|
|
+ container_of((t), struct netc_ptp_data, extts_timer)
|
|
+#define ptp_caps_to_data(d) \
|
|
+ container_of((d), struct netc_ptp_data, caps)
|
|
+#define ptp_data_to_netc(d) \
|
|
+ container_of((d), struct netc_private, ptp_data)
|
|
+
|
|
+int netc_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct hwtstamp_config config;
|
|
+
|
|
+ if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
|
|
+ return -EFAULT;
|
|
+
|
|
+ switch (config.tx_type) {
|
|
+ case HWTSTAMP_TX_OFF:
|
|
+ priv->hwts_tx_en &= ~BIT(port);
|
|
+ break;
|
|
+ case HWTSTAMP_TX_ON:
|
|
+ priv->hwts_tx_en |= BIT(port);
|
|
+ break;
|
|
+ default:
|
|
+ return -ERANGE;
|
|
+ }
|
|
+
|
|
+ switch (config.rx_filter) {
|
|
+ case HWTSTAMP_FILTER_NONE:
|
|
+ priv->hwts_rx_en &= ~BIT(port);
|
|
+ break;
|
|
+ default:
|
|
+ priv->hwts_rx_en |= BIT(port);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
|
|
+ return -EFAULT;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct hwtstamp_config config;
|
|
+
|
|
+ config.flags = 0;
|
|
+ if (priv->hwts_tx_en & BIT(port))
|
|
+ config.tx_type = HWTSTAMP_TX_ON;
|
|
+ else
|
|
+ config.tx_type = HWTSTAMP_TX_OFF;
|
|
+ if (priv->hwts_rx_en & BIT(port))
|
|
+ config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
|
|
+ else
|
|
+ config.rx_filter = HWTSTAMP_FILTER_NONE;
|
|
+
|
|
+ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
|
|
+ -EFAULT : 0;
|
|
+}
|
|
+
|
|
+int netc_get_ts_info(struct dsa_switch *ds, int port,
|
|
+ struct ethtool_ts_info *info)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct netc_ptp_data *ptp_data = &priv->ptp_data;
|
|
+
|
|
+ /* Called during cleanup */
|
|
+ if (!ptp_data->clock)
|
|
+ return -ENODEV;
|
|
+
|
|
+ info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
|
|
+ SOF_TIMESTAMPING_RX_HARDWARE |
|
|
+ SOF_TIMESTAMPING_RAW_HARDWARE;
|
|
+ info->tx_types = (1 << HWTSTAMP_TX_OFF) |
|
|
+ (1 << HWTSTAMP_TX_ON);
|
|
+ info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
|
|
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT);
|
|
+ info->phc_index = ptp_clock_index(ptp_data->clock);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Called from dsa_skb_defer_rx_timestamp */
|
|
+bool netc_port_rxtstamp(struct dsa_switch *ds, int port,
|
|
+ struct sk_buff *skb, unsigned int type)
|
|
+{
|
|
+ struct skb_shared_hwtstamps *shwt = skb_hwtstamps(skb);
|
|
+ u64 ts = NETC_SKB_CB(skb)->tstamp;
|
|
+
|
|
+ *shwt = (struct skb_shared_hwtstamps) {0};
|
|
+
|
|
+ shwt->hwtstamp = ns_to_ktime(ts);
|
|
+
|
|
+ /* Don't defer */
|
|
+ return false;
|
|
+}
|
|
+
|
|
+void netc_process_meta_tstamp(struct dsa_switch *ds, int port,
|
|
+ u32 ts_id, u64 tstamp)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct netc_ptp_data *ptp_data = &priv->ptp_data;
|
|
+ struct sk_buff *skb, *skb_tmp, *skb_match = NULL;
|
|
+ struct skb_shared_hwtstamps shwt = {0};
|
|
+
|
|
+ spin_lock(&ptp_data->skb_txtstamp_queue.lock);
|
|
+
|
|
+ skb_queue_walk_safe(&ptp_data->skb_txtstamp_queue, skb, skb_tmp) {
|
|
+ if (NETC_SKB_CB(skb)->ts_id != ts_id)
|
|
+ continue;
|
|
+
|
|
+ __skb_unlink(skb, &ptp_data->skb_txtstamp_queue);
|
|
+ skb_match = skb;
|
|
+
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ spin_unlock(&ptp_data->skb_txtstamp_queue.lock);
|
|
+
|
|
+ if (WARN_ON(!skb_match))
|
|
+ return;
|
|
+
|
|
+ shwt.hwtstamp = ns_to_ktime(tstamp);
|
|
+ skb_complete_tx_timestamp(skb_match, &shwt);
|
|
+}
|
|
+
|
|
+/* Called from dsa_skb_tx_timestamp. This callback is just to clone
|
|
+ * the skb and have it available in NETC_SKB_CB in the .port_deferred_xmit
|
|
+ * callback, where we will timestamp it synchronously.
|
|
+ */
|
|
+void netc_port_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct sk_buff *clone;
|
|
+ struct netc_ptp_data *ptp_data = &priv->ptp_data;
|
|
+ u32 ts_id;
|
|
+
|
|
+ if (!(priv->hwts_tx_en & BIT(port)))
|
|
+ return;
|
|
+
|
|
+ clone = skb_clone_sk(skb);
|
|
+ if (!clone)
|
|
+ return;
|
|
+
|
|
+ NETC_SKB_CB(skb)->clone = clone;
|
|
+
|
|
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
|
|
+
|
|
+ spin_lock(&priv->ts_id_lock);
|
|
+
|
|
+ ts_id = priv->ts_id;
|
|
+ /* Deal automatically with 8-bit wraparound */
|
|
+ priv->ts_id++;
|
|
+
|
|
+ NETC_SKB_CB(clone)->ts_id = ts_id;
|
|
+
|
|
+ spin_unlock(&priv->ts_id_lock);
|
|
+
|
|
+ skb_queue_tail(&ptp_data->skb_txtstamp_queue, clone);
|
|
+}
|
|
+
|
|
+static int netc_ptp_reset(struct dsa_switch *ds)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct netc_ptp_data *ptp_data = &priv->ptp_data;
|
|
+ int rc;
|
|
+ u64 data = 1;
|
|
+
|
|
+ dev_dbg(ds->dev, "Resetting PTP clock\n");
|
|
+
|
|
+ mutex_lock(&ptp_data->lock);
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_PTP_SYNC_SET,
|
|
+ &data, sizeof(data));
|
|
+
|
|
+ mutex_unlock(&ptp_data->lock);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int netc_ptp_gettimex(struct ptp_clock_info *ptp,
|
|
+ struct timespec64 *ts,
|
|
+ struct ptp_system_timestamp *ptp_sts)
|
|
+{
|
|
+ struct netc_ptp_data *ptp_data = ptp_caps_to_data(ptp);
|
|
+ struct netc_private *priv = ptp_data_to_netc(ptp_data);
|
|
+ u64 now = 0;
|
|
+ int rc;
|
|
+
|
|
+ mutex_lock(&ptp_data->lock);
|
|
+
|
|
+ rc = netc_xfer_read_u64(priv, NETC_CMD_TIMER_CUR_GET, &now, ptp_sts);
|
|
+
|
|
+ mutex_unlock(&ptp_data->lock);
|
|
+
|
|
+ *ts = ns_to_timespec64(now);
|
|
+
|
|
+ if (rc < 0)
|
|
+ dev_err(priv->ds->dev, "Failed to read PTP clock: %d\n", rc);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int netc_ptp_settime(struct ptp_clock_info *ptp,
|
|
+ const struct timespec64 *ts)
|
|
+{
|
|
+ struct netc_ptp_data *ptp_data = ptp_caps_to_data(ptp);
|
|
+ struct netc_private *priv = ptp_data_to_netc(ptp_data);
|
|
+ struct netc_ptp_ctl_param param;
|
|
+ int rc;
|
|
+
|
|
+ param.ns = timespec64_to_ns(ts);
|
|
+ param.clock_id = 0;
|
|
+
|
|
+ mutex_lock(&ptp_data->lock);
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_TIMER_CUR_SET,
|
|
+ ¶m, sizeof(param));
|
|
+
|
|
+ mutex_unlock(&ptp_data->lock);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int netc_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
|
|
+{
|
|
+ struct netc_ptp_data *ptp_data = ptp_caps_to_data(ptp);
|
|
+ struct netc_private *priv = ptp_data_to_netc(ptp_data);
|
|
+ struct netc_ptp_ctl_param param;
|
|
+ int rc;
|
|
+
|
|
+ param.ppb = scaled_ppm_to_ppb(scaled_ppm);;
|
|
+ param.clock_id = 0;
|
|
+
|
|
+ mutex_lock(&ptp_data->lock);
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_TIMER_ADJFINE_SET,
|
|
+ ¶m, sizeof(param));
|
|
+
|
|
+ mutex_unlock(&ptp_data->lock);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int netc_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
|
|
+{
|
|
+ struct netc_ptp_data *ptp_data = ptp_caps_to_data(ptp);
|
|
+ struct netc_private *priv = ptp_data_to_netc(ptp_data);
|
|
+ struct netc_ptp_ctl_param param;
|
|
+ int rc;
|
|
+
|
|
+ param.offset = delta;
|
|
+ param.clock_id = 0;
|
|
+
|
|
+ mutex_lock(&ptp_data->lock);
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_TIMER_ADJTIME_SET,
|
|
+ ¶m, sizeof(param));
|
|
+
|
|
+ mutex_unlock(&ptp_data->lock);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int netc_per_out_enable(struct netc_private *priv,
|
|
+ struct ptp_perout_request *perout,
|
|
+ bool on)
|
|
+{
|
|
+ struct netc_ptp_data *ptp_data = &priv->ptp_data;
|
|
+ struct netc_cmd_timer_pps param;
|
|
+ int rc;
|
|
+
|
|
+ /* We only support one channel */
|
|
+ if (perout->index != 0)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ /* Reject requests with unsupported flags */
|
|
+ if (perout->flags)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ mutex_lock(&ptp_data->lock);
|
|
+
|
|
+ if (on) {
|
|
+ struct timespec64 pin_duration_ts = {
|
|
+ .tv_sec = perout->period.sec,
|
|
+ .tv_nsec = perout->period.nsec,
|
|
+ };
|
|
+ struct timespec64 pin_start_ts = {
|
|
+ .tv_sec = perout->start.sec,
|
|
+ .tv_nsec = perout->start.nsec,
|
|
+ };
|
|
+ u64 pin_duration = timespec64_to_ns(&pin_duration_ts);
|
|
+ if (pin_duration > U32_MAX) {
|
|
+ rc = -ERANGE;
|
|
+ goto _out;
|
|
+ }
|
|
+ param.pin_duration32 = (u32) pin_duration;
|
|
+ param.pin_start = timespec64_to_ns(&pin_start_ts);
|
|
+
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_TIMER_PPS_START,
|
|
+ ¶m, sizeof(param));
|
|
+ } else
|
|
+ rc = netc_xfer_set_cmd(priv, NETC_CMD_TIMER_PPS_STOP,
|
|
+ NULL, 0);
|
|
+
|
|
+_out:
|
|
+ mutex_unlock(&ptp_data->lock);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int netc_ptp_enable(struct ptp_clock_info *ptp,
|
|
+ struct ptp_clock_request *req, int on)
|
|
+{
|
|
+ struct netc_ptp_data *ptp_data = ptp_caps_to_data(ptp);
|
|
+ struct netc_private *priv = ptp_data_to_netc(ptp_data);
|
|
+ int rc = -EOPNOTSUPP;
|
|
+
|
|
+ if (req->type == PTP_CLK_REQ_PEROUT)
|
|
+ rc = netc_per_out_enable(priv, &req->perout, on);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+struct ptp_clock_info netc_clock_caps = {
|
|
+ .owner = THIS_MODULE,
|
|
+ .name = "NETC PHC",
|
|
+ .max_adj = 1000000,
|
|
+ .n_alarm = 2,
|
|
+ .n_ext_ts = 2,
|
|
+ .n_per_out = 3,
|
|
+ .n_pins = 0,
|
|
+ .pps = 1,
|
|
+ .adjfine = netc_ptp_adjfine,
|
|
+ .adjtime = netc_ptp_adjtime,
|
|
+ .gettimex64 = netc_ptp_gettimex,
|
|
+ .settime64 = netc_ptp_settime,
|
|
+ .enable = netc_ptp_enable,
|
|
+};
|
|
+
|
|
+int netc_ptp_clock_register(struct dsa_switch *ds)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct netc_ptp_data *ptp_data = &priv->ptp_data;
|
|
+
|
|
+ skb_queue_head_init(&ptp_data->skb_txtstamp_queue);
|
|
+
|
|
+ ptp_data->caps = netc_clock_caps;
|
|
+ ptp_data->clock = ptp_clock_register(&ptp_data->caps, ds->dev);
|
|
+ if (IS_ERR_OR_NULL(ptp_data->clock))
|
|
+ return PTR_ERR(ptp_data->clock);
|
|
+
|
|
+ return netc_ptp_reset(ds);
|
|
+}
|
|
+
|
|
+void netc_ptp_clock_unregister(struct dsa_switch *ds)
|
|
+{
|
|
+ struct netc_private *priv = ds->priv;
|
|
+ struct netc_ptp_data *ptp_data = &priv->ptp_data;
|
|
+
|
|
+ if (IS_ERR_OR_NULL(ptp_data->clock))
|
|
+ return;
|
|
+
|
|
+ del_timer_sync(&ptp_data->extts_timer);
|
|
+ ptp_cancel_worker_sync(ptp_data->clock);
|
|
+ skb_queue_purge(&ptp_data->skb_txtstamp_queue);
|
|
+ ptp_clock_unregister(ptp_data->clock);
|
|
+ ptp_data->clock = NULL;
|
|
+}
|
|
diff --git a/drivers/net/dsa/netc/netc_ptp.h b/drivers/net/dsa/netc/netc_ptp.h
|
|
new file mode 100644
|
|
index 000000000000..efdb15e90223
|
|
--- /dev/null
|
|
+++ b/drivers/net/dsa/netc/netc_ptp.h
|
|
@@ -0,0 +1,77 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2024 NXP
|
|
+ */
|
|
+
|
|
+#ifndef _NETC_PTP_H
|
|
+#define _NETC_PTP_H
|
|
+
|
|
+#include <linux/timer.h>
|
|
+
|
|
+#if IS_ENABLED(CONFIG_NET_DSA_NETC_PTP)
|
|
+
|
|
+struct netc_ptp_data {
|
|
+ struct timer_list extts_timer;
|
|
+ /* Used on NETC where meta frames are generated only for
|
|
+ * 2-step TX timestamps
|
|
+ */
|
|
+ struct sk_buff_head skb_txtstamp_queue;
|
|
+ struct ptp_clock *clock;
|
|
+ struct ptp_clock_info caps;
|
|
+ /* Serializes all operations on the PTP hardware clock */
|
|
+ struct mutex lock;
|
|
+ bool extts_enabled;
|
|
+ u64 ptpsyncts;
|
|
+};
|
|
+
|
|
+int netc_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr);
|
|
+
|
|
+int netc_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr);
|
|
+
|
|
+void netc_process_meta_tstamp(struct dsa_switch *ds, int port,
|
|
+ u32 ts_id, u64 tstamp);
|
|
+
|
|
+int netc_get_ts_info(struct dsa_switch *ds, int port,
|
|
+ struct ethtool_ts_info *ts);
|
|
+
|
|
+bool netc_port_rxtstamp(struct dsa_switch *ds, int port,
|
|
+ struct sk_buff *skb, unsigned int type);
|
|
+
|
|
+void netc_port_txtstamp(struct dsa_switch *ds, int port,
|
|
+ struct sk_buff *skb);
|
|
+
|
|
+int netc_ptp_clock_register(struct dsa_switch *ds);
|
|
+
|
|
+void netc_ptp_clock_unregister(struct dsa_switch *ds);
|
|
+
|
|
+
|
|
+#else
|
|
+
|
|
+struct netc_ptp_data {
|
|
+ struct mutex lock;
|
|
+};
|
|
+
|
|
+static inline int netc_ptp_clock_register(struct dsa_switch *ds)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline void netc_ptp_clock_unregister(struct dsa_switch *ds)
|
|
+{
|
|
+}
|
|
+
|
|
+#define netc_get_ts_info NULL
|
|
+
|
|
+#define netc_port_rxtstamp NULL
|
|
+
|
|
+#define netc_port_txtstamp NULL
|
|
+
|
|
+#define netc_hwtstamp_get NULL
|
|
+
|
|
+#define netc_hwtstamp_set NULL
|
|
+
|
|
+#define netc_process_meta_tstamp NULL
|
|
+
|
|
+#endif /* IS_ENABLED(CONFIG_NET_DSA_NETC_PTP) */
|
|
+
|
|
+#endif /* _NETC_PTP_H */
|
|
diff --git a/drivers/net/dsa/netc/netc_spi.c b/drivers/net/dsa/netc/netc_spi.c
|
|
new file mode 100644
|
|
index 000000000000..41cfbc3686ad
|
|
--- /dev/null
|
|
+++ b/drivers/net/dsa/netc/netc_spi.c
|
|
@@ -0,0 +1,147 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#include <linux/spi/spi.h>
|
|
+#include "netc.h"
|
|
+
|
|
+int netc_xfer_cmd(const struct netc_private *priv,
|
|
+ enum netc_spi_rw_mode rw, enum netc_cmd cmd,
|
|
+ void *param, size_t param_len,
|
|
+ void *resp, size_t resp_len,
|
|
+ struct ptp_system_timestamp *ptp_sts)
|
|
+{
|
|
+ struct netc_cmd_hdr hdr = {0};
|
|
+ struct spi_device *spi = priv->spidev;
|
|
+ struct spi_transfer hdr_xfer, resp_xfer;
|
|
+ int rc;
|
|
+
|
|
+ if (!IS_ALIGNED(resp_len, NETC_SPI_MSG_WORD_BYTES)) {
|
|
+ dev_err(&spi->dev, "netc cmd %d data size should be a multiple of 4 : %ld",
|
|
+ cmd, resp_len);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (resp_len > priv->max_xfer_len) {
|
|
+ dev_err(&spi->dev, "netc cmd %d data size is too large\n",
|
|
+ cmd);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (param_len > NETC_SPI_MSG_PARAM_SIZE) {
|
|
+ dev_err(&spi->dev, "netc cmd %d param size is too large\n",
|
|
+ cmd);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ hdr.cmd = (rw << NETC_CMD_DIR_SHIFT) |
|
|
+ ((resp_len / NETC_SPI_MSG_WORD_BYTES) <<
|
|
+ NETC_CMD_LEN_SHIFT) |
|
|
+ cmd;
|
|
+ if (param)
|
|
+ memcpy(hdr.param, param, param_len);
|
|
+
|
|
+ hdr_xfer.tx_buf = &hdr;
|
|
+ hdr_xfer.len = NETC_SPI_MSG_HEADER_SIZE;
|
|
+ hdr_xfer.ptp_sts_word_pre = hdr_xfer.len - 1;
|
|
+ hdr_xfer.ptp_sts_word_post = hdr_xfer.len - 1;
|
|
+ hdr_xfer.ptp_sts = ptp_sts;
|
|
+
|
|
+ rc = spi_sync_transfer(spi, &hdr_xfer, 1);
|
|
+ if (rc < 0) {
|
|
+ dev_err(&spi->dev, "netc cmd %d SPI transfer failed: %d\n",
|
|
+ cmd, rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ usleep_range(NETC_SPI_MSG_RESPONSE_TIME,
|
|
+ NETC_SPI_MSG_RESPONSE_TIME * 10);
|
|
+
|
|
+ if (!resp)
|
|
+ return 0;
|
|
+
|
|
+ /* Populate the transfer's data buffer */
|
|
+ if (rw == SPI_READ)
|
|
+ resp_xfer.rx_buf = resp;
|
|
+ else
|
|
+ resp_xfer.tx_buf = resp;
|
|
+ resp_xfer.len = resp_len;
|
|
+
|
|
+ resp_xfer.ptp_sts_word_pre = resp_xfer.len - 1;
|
|
+ resp_xfer.ptp_sts_word_post = resp_xfer.len - 1;
|
|
+ resp_xfer.ptp_sts = ptp_sts;
|
|
+
|
|
+ rc = spi_sync_transfer(spi, &resp_xfer, 1);
|
|
+ if (rc < 0) {
|
|
+ dev_err(&spi->dev, "netc cmd %d SPI transfer failed: %d\n",
|
|
+ cmd, rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ usleep_range(NETC_SPI_MSG_RESPONSE_TIME,
|
|
+ NETC_SPI_MSG_RESPONSE_TIME * 10);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int netc_xfer_set_cmd(const struct netc_private *priv,
|
|
+ enum netc_cmd cmd,
|
|
+ void *param, size_t param_len)
|
|
+{
|
|
+ return netc_xfer_cmd(priv, SPI_WRITE, cmd,
|
|
+ param, param_len,
|
|
+ NULL, 0, NULL);
|
|
+}
|
|
+
|
|
+int netc_xfer_get_cmd(const struct netc_private *priv,
|
|
+ enum netc_cmd cmd, uint32_t id,
|
|
+ void *resp, size_t resp_len)
|
|
+{
|
|
+ struct netc_cmd_read_param param;
|
|
+
|
|
+ param.id = id;
|
|
+
|
|
+ return netc_xfer_cmd(priv, SPI_READ, cmd,
|
|
+ ¶m, sizeof(param),
|
|
+ resp, resp_len, NULL);
|
|
+}
|
|
+
|
|
+int netc_xfer_write_reg(const struct netc_private *priv,
|
|
+ uint32_t reg, uint32_t value)
|
|
+{
|
|
+ struct netc_cmd_reg_cmd reg_cmd;
|
|
+
|
|
+ reg_cmd.reg = reg;
|
|
+ reg_cmd.value = value;
|
|
+
|
|
+ return netc_xfer_set_cmd(priv, NETC_CMD_REG_SET,
|
|
+ ®_cmd, sizeof(reg_cmd));
|
|
+}
|
|
+
|
|
+int netc_xfer_read_reg(const struct netc_private *priv,
|
|
+ uint32_t reg, uint32_t *value)
|
|
+{
|
|
+ return netc_xfer_get_cmd(priv, NETC_CMD_REG_GET, reg,
|
|
+ value, sizeof(*value));
|
|
+}
|
|
+
|
|
+int netc_xfer_write_u64(const struct netc_private *priv,
|
|
+ enum netc_cmd cmd, uint64_t value,
|
|
+ struct ptp_system_timestamp *ptp_sts)
|
|
+{
|
|
+ return netc_xfer_cmd(priv, SPI_WRITE, cmd,
|
|
+ &value, sizeof(value),
|
|
+ NULL, 0,
|
|
+ ptp_sts);
|
|
+}
|
|
+
|
|
+int netc_xfer_read_u64(const struct netc_private *priv,
|
|
+ enum netc_cmd cmd, uint64_t *value,
|
|
+ struct ptp_system_timestamp *ptp_sts)
|
|
+{
|
|
+ return netc_xfer_cmd(priv, SPI_READ, cmd,
|
|
+ NULL, 0,
|
|
+ value, sizeof(*value),
|
|
+ ptp_sts);
|
|
+}
|
|
diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
|
|
index 3e5105267c57..18f6cddf2478 100644
|
|
--- a/drivers/net/dsa/ocelot/felix.c
|
|
+++ b/drivers/net/dsa/ocelot/felix.c
|
|
@@ -1027,17 +1027,50 @@ static int felix_vlan_add(struct dsa_switch *ds, int port,
|
|
if (err)
|
|
return err;
|
|
|
|
- return ocelot_vlan_add(ocelot, port, vlan->vid,
|
|
+ err = ocelot_vlan_add(ocelot, port, vlan->vid,
|
|
flags & BRIDGE_VLAN_INFO_PVID,
|
|
flags & BRIDGE_VLAN_INFO_UNTAGGED);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ if (vlan->proto == ETH_P_8021AD) {
|
|
+ if (!ocelot->qinq_enable) {
|
|
+ ocelot->qinq_enable = true;
|
|
+ kref_init(&ocelot->qinq_refcount);
|
|
+ } else {
|
|
+ kref_get(&ocelot->qinq_refcount);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void felix_vlan_qinq_release(struct kref *ref)
|
|
+{
|
|
+ struct ocelot *ocelot;
|
|
+
|
|
+ ocelot = container_of(ref, struct ocelot, qinq_refcount);
|
|
+ ocelot->qinq_enable = false;
|
|
}
|
|
|
|
static int felix_vlan_del(struct dsa_switch *ds, int port,
|
|
const struct switchdev_obj_port_vlan *vlan)
|
|
{
|
|
struct ocelot *ocelot = ds->priv;
|
|
+ int err;
|
|
+
|
|
+ err = ocelot_vlan_del(ocelot, port, vlan->vid);
|
|
+ if (err) {
|
|
+ dev_err(ds->dev, "Failed to remove VLAN %d from port %d: %d\n",
|
|
+ vlan->vid, port, err);
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ if (ocelot->qinq_enable && vlan->proto == ETH_P_8021AD)
|
|
+ kref_put(&ocelot->qinq_refcount,
|
|
+ felix_vlan_qinq_release);
|
|
|
|
- return ocelot_vlan_del(ocelot, port, vlan->vid);
|
|
+ return 0;
|
|
}
|
|
|
|
static const u32 felix_phy_match_table[PHY_INTERFACE_MODE_MAX] = {
|
|
@@ -1108,6 +1141,9 @@ static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port,
|
|
|
|
ocelot_phylink_mac_link_down(ocelot, port, link_an_mode, interface,
|
|
felix->info->quirks);
|
|
+
|
|
+ if (felix->info->port_preempt_reset)
|
|
+ felix->info->port_preempt_reset(ocelot, port, 0);
|
|
}
|
|
|
|
static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port,
|
|
@@ -1126,6 +1162,9 @@ static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port,
|
|
|
|
if (felix->info->port_sched_speed_set)
|
|
felix->info->port_sched_speed_set(ocelot, port, speed);
|
|
+
|
|
+ if (felix->info->port_preempt_reset)
|
|
+ felix->info->port_preempt_reset(ocelot, port, 1);
|
|
}
|
|
|
|
static int felix_port_enable(struct dsa_switch *ds, int port,
|
|
@@ -1249,6 +1288,44 @@ static int felix_get_ts_info(struct dsa_switch *ds, int port,
|
|
return ocelot_get_ts_info(ocelot, port, info);
|
|
}
|
|
|
|
+static int felix_reset_preempt(struct dsa_switch *ds, int port, bool enable)
|
|
+{
|
|
+ struct ocelot *ocelot = ds->priv;
|
|
+ struct felix *felix = ocelot_to_felix(ocelot);
|
|
+
|
|
+ if (felix->info->port_preempt_reset) {
|
|
+ felix->info->port_preempt_reset(ocelot, port, enable);
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return -EOPNOTSUPP;
|
|
+}
|
|
+
|
|
+static int felix_set_preempt(struct dsa_switch *ds, int port,
|
|
+ struct ethtool_fp *fpcmd)
|
|
+{
|
|
+ struct ocelot *ocelot = ds->priv;
|
|
+ struct felix *felix = ocelot_to_felix(ocelot);
|
|
+
|
|
+ if (felix->info->port_set_preempt)
|
|
+ return felix->info->port_set_preempt(ocelot, port, fpcmd);
|
|
+
|
|
+ return -EOPNOTSUPP;
|
|
+}
|
|
+
|
|
+static int felix_get_preempt(struct dsa_switch *ds, int port,
|
|
+ struct ethtool_fp *fpcmd)
|
|
+{
|
|
+ struct ocelot *ocelot = ds->priv;
|
|
+ struct felix *felix = ocelot_to_felix(ocelot);
|
|
+
|
|
+ if (felix->info->port_get_preempt)
|
|
+ return felix->info->port_get_preempt(ocelot, port, fpcmd);
|
|
+
|
|
+ return -EOPNOTSUPP;
|
|
+}
|
|
+
|
|
static struct regmap *felix_request_regmap_by_name(struct felix *felix,
|
|
const char *resource_name)
|
|
{
|
|
@@ -1476,6 +1553,97 @@ static int felix_connect_tag_protocol(struct dsa_switch *ds,
|
|
}
|
|
}
|
|
|
|
+static int felix_qinq_port_bitmap_get(struct dsa_switch *ds, u32 *bitmap)
|
|
+{
|
|
+ struct ocelot *ocelot = ds->priv;
|
|
+ struct ocelot_port *ocelot_port;
|
|
+ int port;
|
|
+
|
|
+ *bitmap = 0;
|
|
+ for (port = 0; port < ds->num_ports; port++) {
|
|
+ ocelot_port = ocelot->ports[port];
|
|
+ if (ocelot_port->qinq_mode)
|
|
+ *bitmap |= 0x01 << port;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int felix_qinq_port_bitmap_set(struct dsa_switch *ds, u32 bitmap)
|
|
+{
|
|
+ struct ocelot *ocelot = ds->priv;
|
|
+ struct ocelot_port *ocelot_port;
|
|
+ int port;
|
|
+
|
|
+ for (port = 0; port < ds->num_ports; port++) {
|
|
+ ocelot_port = ocelot->ports[port];
|
|
+ if (bitmap & (0x01 << port))
|
|
+ ocelot_port->qinq_mode = true;
|
|
+ else
|
|
+ ocelot_port->qinq_mode = false;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+enum felix_devlink_param_id {
|
|
+ FELIX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
|
|
+ FELIX_DEVLINK_PARAM_ID_QINQ_PORT_BITMAP,
|
|
+};
|
|
+
|
|
+static int felix_devlink_param_get(struct dsa_switch *ds, u32 id,
|
|
+ struct devlink_param_gset_ctx *ctx)
|
|
+{
|
|
+ int err;
|
|
+
|
|
+ switch (id) {
|
|
+ case FELIX_DEVLINK_PARAM_ID_QINQ_PORT_BITMAP:
|
|
+ err = felix_qinq_port_bitmap_get(ds, &ctx->val.vu32);
|
|
+ break;
|
|
+ default:
|
|
+ err = -EOPNOTSUPP;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static int felix_devlink_param_set(struct dsa_switch *ds, u32 id,
|
|
+ struct devlink_param_gset_ctx *ctx)
|
|
+{
|
|
+ int err;
|
|
+
|
|
+ switch (id) {
|
|
+ case FELIX_DEVLINK_PARAM_ID_QINQ_PORT_BITMAP:
|
|
+ err = felix_qinq_port_bitmap_set(ds, ctx->val.vu32);
|
|
+ break;
|
|
+ default:
|
|
+ err = -EOPNOTSUPP;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static const struct devlink_param felix_devlink_params[] = {
|
|
+ DSA_DEVLINK_PARAM_DRIVER(FELIX_DEVLINK_PARAM_ID_QINQ_PORT_BITMAP,
|
|
+ "qinq_port_bitmap",
|
|
+ DEVLINK_PARAM_TYPE_U32,
|
|
+ BIT(DEVLINK_PARAM_CMODE_RUNTIME)),
|
|
+};
|
|
+
|
|
+static int felix_setup_devlink_params(struct dsa_switch *ds)
|
|
+{
|
|
+ return dsa_devlink_params_register(ds, felix_devlink_params,
|
|
+ ARRAY_SIZE(felix_devlink_params));
|
|
+}
|
|
+
|
|
+static void felix_teardown_devlink_params(struct dsa_switch *ds)
|
|
+{
|
|
+ dsa_devlink_params_unregister(ds, felix_devlink_params,
|
|
+ ARRAY_SIZE(felix_devlink_params));
|
|
+}
|
|
+
|
|
static int felix_setup(struct dsa_switch *ds)
|
|
{
|
|
struct ocelot *ocelot = ds->priv;
|
|
@@ -1526,6 +1694,10 @@ static int felix_setup(struct dsa_switch *ds)
|
|
ds->fdb_isolation = true;
|
|
ds->max_num_bridges = ds->num_ports;
|
|
|
|
+ err = felix_setup_devlink_params(ds);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+
|
|
return 0;
|
|
|
|
out_deinit_ports:
|
|
@@ -1553,6 +1725,8 @@ static void felix_teardown(struct dsa_switch *ds)
|
|
felix->tag_proto_ops->teardown(ds);
|
|
rtnl_unlock();
|
|
|
|
+ felix_teardown_devlink_params(ds);
|
|
+
|
|
dsa_switch_for_each_available_port(dp, ds)
|
|
ocelot_deinit_port(ocelot, dp->index);
|
|
|
|
@@ -2036,6 +2210,9 @@ const struct dsa_switch_ops felix_switch_ops = {
|
|
.get_ethtool_stats = felix_get_ethtool_stats,
|
|
.get_sset_count = felix_get_sset_count,
|
|
.get_ts_info = felix_get_ts_info,
|
|
+ .reset_preempt = felix_reset_preempt,
|
|
+ .set_preempt = felix_set_preempt,
|
|
+ .get_preempt = felix_get_preempt,
|
|
.phylink_get_caps = felix_phylink_get_caps,
|
|
.phylink_mac_config = felix_phylink_mac_config,
|
|
.phylink_mac_select_pcs = felix_phylink_mac_select_pcs,
|
|
@@ -2091,6 +2268,8 @@ const struct dsa_switch_ops felix_switch_ops = {
|
|
.port_mrp_del_ring_role = felix_mrp_del_ring_role,
|
|
.tag_8021q_vlan_add = felix_tag_8021q_vlan_add,
|
|
.tag_8021q_vlan_del = felix_tag_8021q_vlan_del,
|
|
+ .devlink_param_get = felix_devlink_param_get,
|
|
+ .devlink_param_set = felix_devlink_param_set,
|
|
.port_get_default_prio = felix_port_get_default_prio,
|
|
.port_set_default_prio = felix_port_set_default_prio,
|
|
.port_get_dscp_prio = felix_port_get_dscp_prio,
|
|
diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h
|
|
index 558a60de64b2..ac21a5451232 100644
|
|
--- a/drivers/net/dsa/ocelot/felix.h
|
|
+++ b/drivers/net/dsa/ocelot/felix.h
|
|
@@ -65,6 +65,11 @@ struct felix_info {
|
|
const struct phylink_link_state *state);
|
|
int (*configure_serdes)(struct ocelot *ocelot, int port,
|
|
struct device_node *portnp);
|
|
+ int (*port_set_preempt)(struct ocelot *ocelot, int port,
|
|
+ struct ethtool_fp *fpcmd);
|
|
+ int (*port_get_preempt)(struct ocelot *ocelot, int port,
|
|
+ struct ethtool_fp *fpcmd);
|
|
+ void (*port_preempt_reset)(struct ocelot *ocelot, int port, bool enable);
|
|
};
|
|
|
|
/* Methods for initializing the hardware resources specific to a tagging
|
|
diff --git a/drivers/net/dsa/ocelot/felix_tsn.c b/drivers/net/dsa/ocelot/felix_tsn.c
|
|
index be3576445afc..0d0f647915ed 100644
|
|
--- a/drivers/net/dsa/ocelot/felix_tsn.c
|
|
+++ b/drivers/net/dsa/ocelot/felix_tsn.c
|
|
@@ -415,10 +415,12 @@ static int felix_cb_streamid_set(struct net_device *ndev, u32 index, bool enable
|
|
if (!stream)
|
|
return -EINVAL;
|
|
|
|
+ dst_idx = stream->dst_idx;
|
|
ocelot_mact_forget(ocelot, stream->mac, stream->vid);
|
|
+
|
|
felix_stream_table_del(index);
|
|
|
|
- felix_streamid_force_forward_clear(ocelot, stream->dst_idx);
|
|
+ felix_streamid_force_forward_clear(ocelot, dst_idx);
|
|
|
|
return 0;
|
|
}
|
|
@@ -1456,7 +1458,7 @@ static int felix_pcpmap_set(struct net_device *ndev,
|
|
ocelot = dp->ds->priv;
|
|
port = dp->index;
|
|
|
|
- index = (c->pcp & GENMASK(2, 0)) * ((c->dei & BIT(0)) + 1);
|
|
+ index = (c->dei & BIT(0)) * 8 + (c->pcp & GENMASK(2, 0));
|
|
|
|
ocelot_rmw_ix(ocelot,
|
|
(ANA_PORT_PCP_DEI_MAP_DP_PCP_DEI_VAL & (c->dpl << 3)) |
|
|
diff --git a/drivers/net/dsa/ocelot/felix_vsc9959.c b/drivers/net/dsa/ocelot/felix_vsc9959.c
|
|
index 79a06db6b458..10cf8db2c8f0 100644
|
|
--- a/drivers/net/dsa/ocelot/felix_vsc9959.c
|
|
+++ b/drivers/net/dsa/ocelot/felix_vsc9959.c
|
|
@@ -1556,15 +1556,15 @@ static void vsc9959_tas_clock_adjust(struct ocelot *ocelot)
|
|
if (!taprio)
|
|
continue;
|
|
|
|
+ /* Disable time-aware shaper */
|
|
+ ocelot_rmw_rix(ocelot, 0, QSYS_TAG_CONFIG_ENABLE,
|
|
+ QSYS_TAG_CONFIG, port);
|
|
+
|
|
ocelot_rmw(ocelot,
|
|
QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port),
|
|
QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M,
|
|
QSYS_TAS_PARAM_CFG_CTRL);
|
|
|
|
- /* Disable time-aware shaper */
|
|
- ocelot_rmw_rix(ocelot, 0, QSYS_TAG_CONFIG_ENABLE,
|
|
- QSYS_TAG_CONFIG, port);
|
|
-
|
|
vsc9959_new_base_time(ocelot, taprio->base_time,
|
|
taprio->cycle_time, &base_ts);
|
|
|
|
@@ -1577,6 +1577,9 @@ static void vsc9959_tas_clock_adjust(struct ocelot *ocelot)
|
|
QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB_M,
|
|
QSYS_PARAM_CFG_REG_3);
|
|
|
|
+ for (int i = 0; i < taprio->num_entries; i++)
|
|
+ vsc9959_tas_gcl_set(ocelot, i, &taprio->entries[i]);
|
|
+
|
|
ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
|
|
QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
|
|
QSYS_TAS_PARAM_CFG_CTRL);
|
|
@@ -2629,6 +2632,91 @@ static const struct ocelot_ops vsc9959_ops = {
|
|
.tas_guard_bands_update = vsc9959_tas_guard_bands_update,
|
|
};
|
|
|
|
+static void vsc9959_port_preempt_reset(struct ocelot *ocelot, int port, bool enable)
|
|
+{
|
|
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
|
|
+
|
|
+ ocelot_port_rmwl(ocelot_port, 0,
|
|
+ DEV_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA |
|
|
+ DEV_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA,
|
|
+ DEV_MM_ENABLE_CONFIG);
|
|
+
|
|
+ if (enable) {
|
|
+ if (ocelot_port->fp_enabled_admin) {
|
|
+ ocelot_port_rmwl(ocelot_port,
|
|
+ DEV_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA |
|
|
+ DEV_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA,
|
|
+ DEV_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA |
|
|
+ DEV_MM_CONFIG_ENABLE_CONFIG_MM_TX_ENA,
|
|
+ DEV_MM_ENABLE_CONFIG);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static int vsc9959_port_set_preempt(struct ocelot *ocelot, int port,
|
|
+ struct ethtool_fp *fpcmd)
|
|
+{
|
|
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
|
|
+ u8 preemptible_tcs = fpcmd->preemptible_queues_mask;
|
|
+ struct ethtool_mm_cfg cfg;
|
|
+ int ret;
|
|
+
|
|
+ if (!fpcmd->disabled &&
|
|
+ (fpcmd->min_frag_size < 60 || fpcmd->min_frag_size > 252))
|
|
+ return -EINVAL;
|
|
+
|
|
+ cfg.tx_min_frag_size = fpcmd->min_frag_size;
|
|
+
|
|
+ if (!fpcmd->disabled) {
|
|
+ ocelot_port->fp_enabled_admin = 1;
|
|
+ cfg.pmac_enabled = 1;
|
|
+ cfg.tx_enabled = 1;
|
|
+ } else {
|
|
+ ocelot_port->fp_enabled_admin = 0;
|
|
+ cfg.pmac_enabled = 0;
|
|
+ cfg.tx_enabled = 0;
|
|
+ }
|
|
+
|
|
+ cfg.verify_enabled = fpcmd->fp_enabled;
|
|
+ cfg.verify_time = 0xa;
|
|
+
|
|
+ ret = ocelot_port_set_mm(ocelot, port, &cfg, NULL);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ mutex_lock(&ocelot->fwd_domain_lock);
|
|
+ ret = ocelot_port_change_fp(ocelot, port, preemptible_tcs);
|
|
+ mutex_unlock(&ocelot->fwd_domain_lock);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int vsc9959_port_get_preempt(struct ocelot *ocelot, int port,
|
|
+ struct ethtool_fp *fpcmd)
|
|
+{
|
|
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
|
|
+ u8 fragsize;
|
|
+ u32 val;
|
|
+
|
|
+ fpcmd->fp_supported = 1;
|
|
+ fpcmd->supported_queues_mask = GENMASK(7, 0);
|
|
+
|
|
+ val = ocelot_port_readl(ocelot_port, DEV_MM_STATUS);
|
|
+ val &= DEV_MM_STAT_MM_STATUS_PRMPT_ACTIVE_STATUS;
|
|
+ fpcmd->fp_active = (val ? 1 : 0);
|
|
+
|
|
+ val = ocelot_port_readl(ocelot_port, DEV_MM_ENABLE_CONFIG);
|
|
+ val &= DEV_MM_CONFIG_ENABLE_CONFIG_MM_RX_ENA;
|
|
+ fpcmd->fp_status = val;
|
|
+
|
|
+ val = ocelot_read_rix(ocelot, QSYS_PREEMPTION_CFG, port);
|
|
+ fpcmd->preemptible_queues_mask = val & QSYS_PREEMPTION_CFG_P_QUEUES_M;
|
|
+ fragsize = QSYS_PREEMPTION_CFG_MM_ADD_FRAG_SIZE_X(val);
|
|
+ fpcmd->min_frag_size = (fragsize + 1) * 64 - 4;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static const struct felix_info felix_info_vsc9959 = {
|
|
.resources = vsc9959_resources,
|
|
.num_resources = ARRAY_SIZE(vsc9959_resources),
|
|
@@ -2652,6 +2740,9 @@ static const struct felix_info felix_info_vsc9959 = {
|
|
.port_modes = vsc9959_port_modes,
|
|
.port_setup_tc = vsc9959_port_setup_tc,
|
|
.port_sched_speed_set = vsc9959_sched_speed_set,
|
|
+ .port_set_preempt = vsc9959_port_set_preempt,
|
|
+ .port_get_preempt = vsc9959_port_get_preempt,
|
|
+ .port_preempt_reset = vsc9959_port_preempt_reset,
|
|
};
|
|
|
|
/* The INTB interrupt is shared between for PTP TX timestamp availability
|
|
diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h
|
|
index 8c66d3bf61f0..eabc5b90a552 100644
|
|
--- a/drivers/net/dsa/sja1105/sja1105.h
|
|
+++ b/drivers/net/dsa/sja1105/sja1105.h
|
|
@@ -10,6 +10,7 @@
|
|
#include <linux/dsa/sja1105.h>
|
|
#include <linux/dsa/8021q.h>
|
|
#include <net/dsa.h>
|
|
+#include <net/pkt_sched.h>
|
|
#include <linux/mutex.h>
|
|
#include "sja1105_static_config.h"
|
|
|
|
@@ -255,6 +256,7 @@ struct sja1105_private {
|
|
unsigned long bcast_egress_floods;
|
|
unsigned long hwts_tx_en;
|
|
unsigned long hwts_rx_en;
|
|
+ u32 hostprio;
|
|
const struct sja1105_info *info;
|
|
size_t max_xfer_len;
|
|
struct spi_device *spidev;
|
|
@@ -298,6 +300,7 @@ enum sja1105_reset_reason {
|
|
SJA1105_SCHEDULING,
|
|
SJA1105_BEST_EFFORT_POLICING,
|
|
SJA1105_VIRTUAL_LINKS,
|
|
+ SJA1105_VLAN_PCP_TO_TXQ_MAPPING,
|
|
};
|
|
|
|
int sja1105_static_config_reload(struct sja1105_private *priv,
|
|
@@ -305,6 +308,8 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
|
|
int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled,
|
|
struct netlink_ext_ack *extack);
|
|
void sja1105_frame_memory_partitioning(struct sja1105_private *priv);
|
|
+int sja1105_setup_tc_mqprio(struct dsa_switch *ds, int port,
|
|
+ struct tc_mqprio_qopt_offload *mqprio);
|
|
|
|
/* From sja1105_mdio.c */
|
|
int sja1105_mdiobus_register(struct dsa_switch *ds);
|
|
diff --git a/drivers/net/dsa/sja1105/sja1105_clocking.c b/drivers/net/dsa/sja1105/sja1105_clocking.c
|
|
index e3699f76f6d7..08a3e7b96254 100644
|
|
--- a/drivers/net/dsa/sja1105/sja1105_clocking.c
|
|
+++ b/drivers/net/dsa/sja1105/sja1105_clocking.c
|
|
@@ -153,14 +153,14 @@ static int sja1105_cgu_mii_tx_clk_config(struct sja1105_private *priv,
|
|
{
|
|
const struct sja1105_regs *regs = priv->info->regs;
|
|
struct sja1105_cgu_mii_ctrl mii_tx_clk;
|
|
- const int mac_clk_sources[] = {
|
|
+ static const int mac_clk_sources[] = {
|
|
CLKSRC_MII0_TX_CLK,
|
|
CLKSRC_MII1_TX_CLK,
|
|
CLKSRC_MII2_TX_CLK,
|
|
CLKSRC_MII3_TX_CLK,
|
|
CLKSRC_MII4_TX_CLK,
|
|
};
|
|
- const int phy_clk_sources[] = {
|
|
+ static const int phy_clk_sources[] = {
|
|
CLKSRC_IDIV0,
|
|
CLKSRC_IDIV1,
|
|
CLKSRC_IDIV2,
|
|
@@ -194,7 +194,7 @@ sja1105_cgu_mii_rx_clk_config(struct sja1105_private *priv, int port)
|
|
const struct sja1105_regs *regs = priv->info->regs;
|
|
struct sja1105_cgu_mii_ctrl mii_rx_clk;
|
|
u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
|
|
- const int clk_sources[] = {
|
|
+ static const int clk_sources[] = {
|
|
CLKSRC_MII0_RX_CLK,
|
|
CLKSRC_MII1_RX_CLK,
|
|
CLKSRC_MII2_RX_CLK,
|
|
@@ -221,7 +221,7 @@ sja1105_cgu_mii_ext_tx_clk_config(struct sja1105_private *priv, int port)
|
|
const struct sja1105_regs *regs = priv->info->regs;
|
|
struct sja1105_cgu_mii_ctrl mii_ext_tx_clk;
|
|
u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
|
|
- const int clk_sources[] = {
|
|
+ static const int clk_sources[] = {
|
|
CLKSRC_IDIV0,
|
|
CLKSRC_IDIV1,
|
|
CLKSRC_IDIV2,
|
|
@@ -248,7 +248,7 @@ sja1105_cgu_mii_ext_rx_clk_config(struct sja1105_private *priv, int port)
|
|
const struct sja1105_regs *regs = priv->info->regs;
|
|
struct sja1105_cgu_mii_ctrl mii_ext_rx_clk;
|
|
u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
|
|
- const int clk_sources[] = {
|
|
+ static const int clk_sources[] = {
|
|
CLKSRC_IDIV0,
|
|
CLKSRC_IDIV1,
|
|
CLKSRC_IDIV2,
|
|
@@ -349,8 +349,13 @@ static int sja1105_cgu_rgmii_tx_clk_config(struct sja1105_private *priv,
|
|
if (speed == priv->info->port_speed[SJA1105_SPEED_1000MBPS]) {
|
|
clksrc = CLKSRC_PLL0;
|
|
} else {
|
|
- int clk_sources[] = {CLKSRC_IDIV0, CLKSRC_IDIV1, CLKSRC_IDIV2,
|
|
- CLKSRC_IDIV3, CLKSRC_IDIV4};
|
|
+ static const int clk_sources[] = {
|
|
+ CLKSRC_IDIV0,
|
|
+ CLKSRC_IDIV1,
|
|
+ CLKSRC_IDIV2,
|
|
+ CLKSRC_IDIV3,
|
|
+ CLKSRC_IDIV4,
|
|
+ };
|
|
clksrc = clk_sources[port];
|
|
}
|
|
|
|
@@ -638,7 +643,7 @@ static int sja1105_cgu_rmii_ref_clk_config(struct sja1105_private *priv,
|
|
const struct sja1105_regs *regs = priv->info->regs;
|
|
struct sja1105_cgu_mii_ctrl ref_clk;
|
|
u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
|
|
- const int clk_sources[] = {
|
|
+ static const int clk_sources[] = {
|
|
CLKSRC_MII0_TX_CLK,
|
|
CLKSRC_MII1_TX_CLK,
|
|
CLKSRC_MII2_TX_CLK,
|
|
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
|
|
index 1a367e64bc3b..fd0a3fcdac59 100644
|
|
--- a/drivers/net/dsa/sja1105/sja1105_main.c
|
|
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
|
|
@@ -862,7 +862,7 @@ static int sja1105_init_general_params(struct sja1105_private *priv)
|
|
/* Priority queue for link-local management frames
|
|
* (both ingress to and egress from CPU - PTP, STP etc)
|
|
*/
|
|
- .hostprio = 7,
|
|
+ .hostprio = priv->hostprio,
|
|
.mac_fltres1 = SJA1105_LINKLOCAL_FILTER_A,
|
|
.mac_flt1 = SJA1105_LINKLOCAL_FILTER_A_MASK,
|
|
.incl_srcpt1 = true,
|
|
@@ -1255,6 +1255,15 @@ static int sja1105_parse_dt(struct sja1105_private *priv)
|
|
return -ENODEV;
|
|
}
|
|
|
|
+ if (of_property_read_u32(switch_node, "hostprio", &priv->hostprio) < 0) {
|
|
+ priv->hostprio = 7;
|
|
+ } else if (priv->hostprio >= SJA1105_NUM_TC) {
|
|
+ dev_err(dev, "Out of range hostprio, must be between 0 and %d\n", (SJA1105_NUM_TC - 1));
|
|
+ return -ERANGE;
|
|
+ }
|
|
+
|
|
+ dev_info(dev, "Configured hostprio: using queue %u\n", priv->hostprio);
|
|
+
|
|
rc = sja1105_parse_ports_node(priv, ports_node);
|
|
of_node_put(ports_node);
|
|
|
|
@@ -2229,8 +2238,8 @@ static int sja1105_setup_tc_cbs(struct dsa_switch *ds, int port,
|
|
* but deduce the port transmit rate from idleslope - sendslope.
|
|
*/
|
|
port_transmit_rate_kbps = offload->idleslope - offload->sendslope;
|
|
- cbs->idle_slope = div_s64(offload->idleslope * BYTES_PER_KBIT,
|
|
- port_transmit_rate_kbps);
|
|
+ cbs->idle_slope = DIV_ROUND_UP_ULL(offload->idleslope * BYTES_PER_KBIT,
|
|
+ port_transmit_rate_kbps);
|
|
cbs->send_slope = div_s64(abs(offload->sendslope * BYTES_PER_KBIT),
|
|
port_transmit_rate_kbps);
|
|
/* Convert the negative values from 64-bit 2's complement
|
|
@@ -2275,6 +2284,7 @@ static const char * const sja1105_reset_reasons[] = {
|
|
[SJA1105_SCHEDULING] = "Time-aware scheduling",
|
|
[SJA1105_BEST_EFFORT_POLICING] = "Best-effort policing",
|
|
[SJA1105_VIRTUAL_LINKS] = "Virtual links",
|
|
+ [SJA1105_VLAN_PCP_TO_TXQ_MAPPING] = "VLAN PCP to TX queue mapping",
|
|
};
|
|
|
|
/* For situations where we need to change a setting at runtime that is only
|
|
@@ -2424,6 +2434,56 @@ sja1105_get_tag_protocol(struct dsa_switch *ds, int port,
|
|
return priv->info->tag_proto;
|
|
}
|
|
|
|
+int sja1105_setup_tc_mqprio(struct dsa_switch *ds, int port,
|
|
+ struct tc_mqprio_qopt_offload *mqprio)
|
|
+{
|
|
+ struct sja1105_l2_forwarding_entry *l2fwd;
|
|
+ struct sja1105_private *priv = ds->priv;
|
|
+ struct sja1105_table *table;
|
|
+ int pcp, tc;
|
|
+
|
|
+ if (mqprio->qopt.num_tc > SJA1105_MAX_NUM_PCP) {
|
|
+ dev_err(ds->dev,
|
|
+ "Only a maximum of %u traffic classes are supported by hardware\n",
|
|
+ SJA1105_MAX_NUM_PCP);
|
|
+ return -ERANGE;
|
|
+ }
|
|
+
|
|
+ table = &priv->static_config.tables[BLK_IDX_L2_FORWARDING];
|
|
+
|
|
+ l2fwd = table->entries;
|
|
+
|
|
+ if (!mqprio->qopt.num_tc) {
|
|
+ /* Delete qdisc: reset to default 1:1 mapping. */
|
|
+ for (pcp = 0; pcp < SJA1105_MAX_NUM_PCP; pcp++)
|
|
+ l2fwd[ds->num_ports + pcp].vlan_pmap[port] = pcp;
|
|
+ } else {
|
|
+ /* We restrict a single TXQ per traffic class
|
|
+ * The SJA1105 doesn't offer round robin among TXQs of the same priority
|
|
+ */
|
|
+ for (tc = 0; tc < mqprio->qopt.num_tc; tc++) {
|
|
+ if (mqprio->qopt.count[tc] != 1) {
|
|
+ dev_err(ds->dev,
|
|
+ "Only a single TXQ per traffic class is supported\n");
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Use MQPRIO mapping to configure Egress PCP to HW queue mapping. */
|
|
+ for (pcp = 0; pcp < SJA1105_MAX_NUM_PCP; pcp++)
|
|
+ l2fwd[ds->num_ports + pcp].vlan_pmap[port] = mqprio->qopt.prio_tc_map[pcp];
|
|
+ }
|
|
+
|
|
+ /* Although, the Egress PCP to HW queue mapping (the latter 8 entries)
|
|
+ * should be configured dynamically (once max_dynp is properly set: e.g 7),
|
|
+ * that did not work in practice. The switch (SJA1105Q) kept using
|
|
+ * the old mapping until a switch reset appears and force the reload of
|
|
+ * the static configuration.
|
|
+ * So, force a switch reset on mapping offload from here.
|
|
+ */
|
|
+ return sja1105_static_config_reload(priv, SJA1105_VLAN_PCP_TO_TXQ_MAPPING);
|
|
+}
|
|
+
|
|
/* The TPID setting belongs to the General Parameters table,
|
|
* which can only be partially reconfigured at runtime (and not the TPID).
|
|
* So a switch reset is required.
|
|
@@ -2825,6 +2885,8 @@ static int sja1105_port_setup_tc(struct dsa_switch *ds, int port,
|
|
return sja1105_setup_tc_taprio(ds, port, type_data);
|
|
case TC_SETUP_QDISC_CBS:
|
|
return sja1105_setup_tc_cbs(ds, port, type_data);
|
|
+ case TC_SETUP_QDISC_MQPRIO:
|
|
+ return sja1105_setup_tc_mqprio(ds, port, type_data);
|
|
default:
|
|
return -EOPNOTSUPP;
|
|
}
|
|
diff --git a/drivers/net/dsa/sja1105/sja1105_tas.c b/drivers/net/dsa/sja1105/sja1105_tas.c
|
|
index d7818710bc02..71073c3a413b 100644
|
|
--- a/drivers/net/dsa/sja1105/sja1105_tas.c
|
|
+++ b/drivers/net/dsa/sja1105/sja1105_tas.c
|
|
@@ -528,6 +528,8 @@ int sja1105_setup_tc_taprio(struct dsa_switch *ds, int port,
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
+ sja1105_setup_tc_mqprio(ds, port, &admin->mqprio);
|
|
+
|
|
return sja1105_static_config_reload(priv, SJA1105_SCHEDULING);
|
|
} else if (admin->cmd != TAPRIO_CMD_REPLACE) {
|
|
return -EOPNOTSUPP;
|
|
@@ -578,6 +580,8 @@ int sja1105_setup_tc_taprio(struct dsa_switch *ds, int port,
|
|
if (rc < 0)
|
|
return rc;
|
|
|
|
+ sja1105_setup_tc_mqprio(ds, port, &admin->mqprio);
|
|
+
|
|
return sja1105_static_config_reload(priv, SJA1105_SCHEDULING);
|
|
}
|
|
|
|
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig
|
|
index 2a8bdf9d1d68..81c4c7d2ca1a 100644
|
|
--- a/drivers/net/ethernet/freescale/Kconfig
|
|
+++ b/drivers/net/ethernet/freescale/Kconfig
|
|
@@ -35,6 +35,18 @@ config FEC
|
|
Say Y here if you want to use the built-in 10/100 Fast ethernet
|
|
controller on some Motorola ColdFire and Freescale i.MX/S32 processors.
|
|
|
|
+config FEC_ECAT
|
|
+ tristate "FEC native dirver for FEC ethernet controller (of ColdFire and some i.MX CPUs)"
|
|
+ depends on (ARCH_MXC)
|
|
+ default ARCH_MXC if ARM
|
|
+ depends on PTP_1588_CLOCK_OPTIONAL
|
|
+ select CRC32
|
|
+ select PHYLIB
|
|
+ imply NET_SELFTESTS
|
|
+ help
|
|
+ Say Y here if you want to use the built-in 10/100 Fast ethercat
|
|
+ controller on some Motorola ColdFire and Freescale i.MX/S32 processors.
|
|
+
|
|
config FEC_UIO
|
|
tristate "FEC_UIO ethernet controller (i.MX 8M Mini CPU)"
|
|
default n
|
|
@@ -43,6 +55,14 @@ config FEC_UIO
|
|
Say Y here if you want to use the built-in 10/100 Fast ethernet
|
|
controller on Freescale i.MX 8M Mini processor.
|
|
|
|
+config AVB_SUPPORT
|
|
+ bool "AVB interface support"
|
|
+ depends on FEC && ARCH_MXC
|
|
+ help
|
|
+ Say Y here if you want to enable the AVB interface in the FEC
|
|
+ driver. For the actual AVB functionality an external module is
|
|
+ still required.
|
|
+
|
|
config FEC_MPC52xx
|
|
tristate "FEC MPC52xx driver"
|
|
depends on PPC_MPC52xx && PPC_BESTCOMM
|
|
diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile
|
|
index 13ae9401e4c2..bd3ee981ce54 100644
|
|
--- a/drivers/net/ethernet/freescale/Makefile
|
|
+++ b/drivers/net/ethernet/freescale/Makefile
|
|
@@ -7,6 +7,8 @@ obj-$(CONFIG_FEC) += fec.o
|
|
fec-objs :=fec_main.o fec_ptp.o
|
|
obj-$(CONFIG_FEC_UIO) += fec_uio.o
|
|
|
|
+obj-$(CONFIG_FEC_ECAT) += fec_ecat.o
|
|
+
|
|
obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
|
|
ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
|
|
obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o
|
|
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
|
|
index 20d6f2f66c4d..7c65a112b0d2 100644
|
|
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
|
|
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
|
|
@@ -3735,6 +3735,7 @@ static int enetc_bdr_init(struct enetc_ndev_priv *priv, int i, int v_tx_rings)
|
|
{
|
|
struct enetc_int_vector *v __free(kfree);
|
|
struct enetc_bdr *bdr;
|
|
+ char name[NAPINAMSIZ];
|
|
int j, err;
|
|
|
|
v = kzalloc(struct_size(v, tx_ring, v_tx_rings), GFP_KERNEL);
|
|
@@ -3768,7 +3769,10 @@ static int enetc_bdr_init(struct enetc_ndev_priv *priv, int i, int v_tx_rings)
|
|
v->rx_dim_en = true;
|
|
}
|
|
INIT_WORK(&v->rx_dim.work, enetc_rx_dim_work);
|
|
- netif_napi_add(priv->ndev, &v->napi, enetc_poll);
|
|
+
|
|
+ snprintf(name, NAPINAMSIZ, "rxtx-%d", i);
|
|
+ netif_napi_add_named(priv->ndev, &v->napi, enetc_poll,
|
|
+ NAPI_POLL_WEIGHT, name);
|
|
v->count_tx_rings = v_tx_rings;
|
|
|
|
for (j = 0; j < v_tx_rings; j++) {
|
|
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
|
|
index e6f29cca3fe0..824cffe4cfc4 100644
|
|
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
|
|
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
|
|
@@ -533,6 +533,8 @@ struct enetc_ndev_priv {
|
|
* and link state updates
|
|
*/
|
|
struct mutex mm_lock;
|
|
+
|
|
+ bool fp_enabled_admin;
|
|
};
|
|
|
|
#define ENETC_CBD(R, i) (&(((struct enetc_cbd *)((R).bd_base))[i]))
|
|
@@ -582,6 +584,8 @@ void enetc_refresh_vlan_ht_filter(struct enetc_si *si);
|
|
void enetc_set_ethtool_ops(struct net_device *ndev);
|
|
void enetc_mm_link_state_update(struct enetc_ndev_priv *priv, bool link);
|
|
void enetc_mm_commit_preemptible_tcs(struct enetc_ndev_priv *priv);
|
|
+int enetc_preempt_reset(struct net_device *ndev, bool enable);
|
|
+int enetc_pmac_reset(struct net_device *ndev, bool enable);
|
|
void enetc_eee_mode_set(struct net_device *dev, bool enable);
|
|
|
|
/* control buffer descriptor ring (CBDR) */
|
|
@@ -802,6 +806,7 @@ static inline int enetc_set_psfp(struct net_device *ndev, bool en)
|
|
|
|
void enetc_tsn_pf_init(struct net_device *netdev, struct pci_dev *pdev);
|
|
void enetc_tsn_pf_deinit(struct net_device *netdev);
|
|
+void enetc_ptp_clock_update(void);
|
|
|
|
#else
|
|
|
|
@@ -813,6 +818,9 @@ static inline void enetc_tsn_pf_deinit(struct net_device *netdev)
|
|
{
|
|
}
|
|
|
|
+static inline void enetc_ptp_clock_update(void)
|
|
+{
|
|
+}
|
|
#endif
|
|
|
|
#if IS_ENABLED(CONFIG_DEBUG_FS)
|
|
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
|
|
index 8e63dff9d4ec..97a675c6d9ef 100644
|
|
--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
|
|
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
|
|
@@ -8,6 +8,8 @@
|
|
#include <linux/module.h>
|
|
#include "enetc_pf.h"
|
|
|
|
+static void enetc_configure_port_pmac(struct enetc_hw *hw, bool enable);
|
|
+
|
|
static const u32 enetc_si_regs[] = {
|
|
ENETC_SIMR, ENETC_SIPMAR0, ENETC_SIPMAR1, ENETC_SICBDRMR,
|
|
ENETC_SICBDRSR, ENETC_SICBDRBAR0, ENETC_SICBDRBAR1, ENETC_SICBDRPIR,
|
|
@@ -1313,6 +1315,27 @@ static int enetc_set_rxfh(struct net_device *ndev, const u32 *indir,
|
|
return err;
|
|
}
|
|
|
|
+static int enetc_reset_preempt(struct net_device *ndev, bool enable)
|
|
+{
|
|
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
|
|
+ u32 temp;
|
|
+
|
|
+ temp = enetc_rd(&priv->si->hw, ENETC_PTGCR);
|
|
+ if (temp & ENETC_PTGCR_TGE)
|
|
+ enetc_wr(&priv->si->hw, ENETC_PTGCR,
|
|
+ temp & (~ENETC_PTGCR_TGPE));
|
|
+
|
|
+ if (enable) {
|
|
+ if (priv->fp_enabled_admin) {
|
|
+ enetc_configure_port_pmac(&priv->si->hw, 1);
|
|
+ }
|
|
+ } else {
|
|
+ enetc_configure_port_pmac(&priv->si->hw, 0);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static void enetc_get_channels(struct net_device *ndev,
|
|
struct ethtool_channels *ch)
|
|
{
|
|
@@ -1754,6 +1777,34 @@ static int enetc_get_mm(struct net_device *ndev, struct ethtool_mm_state *state)
|
|
return 0;
|
|
}
|
|
|
|
+static void enetc_configure_port_pmac(struct enetc_hw *hw, bool enable)
|
|
+{
|
|
+ u32 temp;
|
|
+
|
|
+ /* Set pMAC step lock */
|
|
+ temp = enetc_port_rd(hw, ENETC_PFPMR);
|
|
+ enetc_port_wr(hw, ENETC_PFPMR, temp | ENETC_PFPMR_PMACE);
|
|
+
|
|
+ temp = enetc_port_rd(hw, ENETC_MMCSR);
|
|
+ if (enable)
|
|
+ temp |= ENETC_MMCSR_ME;
|
|
+ else
|
|
+ temp &= (~ENETC_MMCSR_ME);
|
|
+ enetc_port_wr(hw, ENETC_MMCSR, temp);
|
|
+}
|
|
+
|
|
+int enetc_pmac_reset(struct net_device *ndev, bool enable)
|
|
+{
|
|
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
|
|
+ u32 temp;
|
|
+
|
|
+ temp = enetc_port_rd(&priv->si->hw, ENETC_PFPMR);
|
|
+ if (temp & ENETC_PFPMR_PMACE)
|
|
+ enetc_configure_port_pmac(&priv->si->hw, enable);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int enetc_mm_wait_tx_active(struct enetc_hw *hw, int verify_time)
|
|
{
|
|
int timeout = verify_time * USEC_PER_MSEC * ENETC_MM_VERIFY_RETRIES;
|
|
@@ -2051,6 +2102,105 @@ void enetc_mm_link_state_update(struct enetc_ndev_priv *priv, bool link)
|
|
}
|
|
EXPORT_SYMBOL_GPL(enetc_mm_link_state_update);
|
|
|
|
+static int enetc_set_preempt(struct net_device *ndev,
|
|
+ struct ethtool_fp *pt)
|
|
+{
|
|
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
|
|
+ u32 preempt, temp;
|
|
+ int rafs;
|
|
+ int i;
|
|
+
|
|
+ if (!pt)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (!pt->disabled && (pt->min_frag_size < 60 || pt->min_frag_size > 252))
|
|
+ return -EINVAL;
|
|
+
|
|
+ rafs = DIV_ROUND_UP((pt->min_frag_size + 4), 64) - 1;
|
|
+
|
|
+ preempt = pt->preemptible_queues_mask;
|
|
+
|
|
+ temp = enetc_rd(&priv->si->hw, ENETC_PTGCR);
|
|
+ if (temp & ENETC_PTGCR_TGE)
|
|
+ enetc_wr(&priv->si->hw, ENETC_PTGCR,
|
|
+ temp & (~ENETC_PTGCR_TGPE));
|
|
+
|
|
+ for (i = 0; i < 8; i++) {
|
|
+ /* 1 Enabled. Traffic is transmitted on the preemptive MAC. */
|
|
+ temp = enetc_port_rd(&priv->si->hw, ENETC_PTCFPR(i));
|
|
+
|
|
+ if ((preempt >> i) & 0x1)
|
|
+ enetc_port_wr(&priv->si->hw,
|
|
+ ENETC_PTCFPR(i),
|
|
+ temp | ENETC_PTCFPR_FPE);
|
|
+ else
|
|
+ enetc_port_wr(&priv->si->hw,
|
|
+ ENETC_PTCFPR(i),
|
|
+ temp & ~ENETC_PTCFPR_FPE);
|
|
+ }
|
|
+
|
|
+ temp = enetc_port_rd(&priv->si->hw, ENETC_MMCSR);
|
|
+ temp &= ~ENETC_MMCSR_RAFS_MASK;
|
|
+ temp |= ENETC_MMCSR_RAFS(rafs);
|
|
+ if (pt->fp_enabled)
|
|
+ temp &= ~ENETC_MMCSR_VDIS;
|
|
+ else
|
|
+ temp |= ENETC_MMCSR_VDIS;
|
|
+ enetc_port_wr(&priv->si->hw, ENETC_MMCSR, temp);
|
|
+
|
|
+ if (pt->disabled) {
|
|
+ enetc_configure_port_pmac(&priv->si->hw, 0);
|
|
+ priv->fp_enabled_admin = 0;
|
|
+ } else {
|
|
+ enetc_configure_port_pmac(&priv->si->hw, 1);
|
|
+ priv->fp_enabled_admin = 1;
|
|
+ }
|
|
+
|
|
+ if (pt->disabled) {
|
|
+ temp = enetc_port_rd(&priv->si->hw, ENETC_PFPMR);
|
|
+ enetc_port_wr(&priv->si->hw, ENETC_PFPMR,
|
|
+ temp & ~ENETC_PFPMR_PMACE);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int enetc_get_preempt(struct net_device *ndev,
|
|
+ struct ethtool_fp *pt)
|
|
+{
|
|
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
|
|
+ u32 temp;
|
|
+ int i;
|
|
+
|
|
+ if (!pt)
|
|
+ return -EINVAL;
|
|
+
|
|
+ temp = enetc_port_rd(&priv->si->hw, ENETC_MMCSR);
|
|
+ if (!(temp & ENETC_MMCSR_VDIS) && (ENETC_MMCSR_GET_VSTS(temp) == 3))
|
|
+ pt->fp_active = true;
|
|
+ else if ((temp & ENETC_MMCSR_VDIS) && (temp & ENETC_MMCSR_ME))
|
|
+ pt->fp_active = true;
|
|
+ else
|
|
+ pt->fp_active = false;
|
|
+
|
|
+ if (temp & ENETC_MMCSR_ME)
|
|
+ pt->fp_status = true;
|
|
+ else
|
|
+ pt->fp_status = false;
|
|
+
|
|
+ pt->preemptible_queues_mask = 0;
|
|
+ for (i = 0; i < 8; i++)
|
|
+ if (enetc_port_rd(&priv->si->hw, ENETC_PTCFPR(i)) & 0x80000000)
|
|
+ pt->preemptible_queues_mask |= 1 << i;
|
|
+
|
|
+ pt->fp_supported = !!(priv->si->hw_features & ENETC_SI_F_QBU);
|
|
+ pt->supported_queues_mask = 0xff;
|
|
+ temp = enetc_port_rd(&priv->si->hw, ENETC_MMCSR);
|
|
+ pt->min_frag_size = (ENETC_MMCSR_GET_RAFS(temp) + 1) * 64;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static const struct ethtool_ops enetc_pf_ethtool_ops = {
|
|
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
|
|
ETHTOOL_COALESCE_MAX_FRAMES |
|
|
@@ -2087,6 +2237,9 @@ static const struct ethtool_ops enetc_pf_ethtool_ops = {
|
|
.get_mm = enetc_get_mm,
|
|
.set_mm = enetc_set_mm,
|
|
.get_mm_stats = enetc_get_mm_stats,
|
|
+ .set_preempt = enetc_set_preempt,
|
|
+ .get_preempt = enetc_get_preempt,
|
|
+ .reset_preempt = enetc_reset_preempt,
|
|
};
|
|
|
|
static const struct ethtool_ops enetc_vf_ethtool_ops = {
|
|
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
|
|
index f9f37e7ee258..d528efd900c5 100644
|
|
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
|
|
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
|
|
@@ -634,6 +634,7 @@ static void enetc_pl_mac_link_down(struct phylink_config *config,
|
|
enetc_mm_link_state_update(priv, false);
|
|
|
|
enetc_mac_enable(si, false);
|
|
+ enetc_pmac_reset(pf->si->ndev, 0);
|
|
}
|
|
|
|
static const struct phylink_mac_ops enetc_mac_phylink_ops = {
|
|
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ptp.c b/drivers/net/ethernet/freescale/enetc/enetc_ptp.c
|
|
index 5243fc031058..9c671494cd95 100644
|
|
--- a/drivers/net/ethernet/freescale/enetc/enetc_ptp.c
|
|
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ptp.c
|
|
@@ -10,6 +10,19 @@
|
|
int enetc_phc_index = -1;
|
|
EXPORT_SYMBOL_GPL(enetc_phc_index);
|
|
|
|
+int ptp_enetc_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = ptp_qoriq_settime(ptp, ts);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ enetc_ptp_clock_update();
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
static struct ptp_clock_info enetc_ptp_caps = {
|
|
.owner = THIS_MODULE,
|
|
.name = "ENETC PTP clock",
|
|
@@ -22,7 +35,7 @@ static struct ptp_clock_info enetc_ptp_caps = {
|
|
.adjfine = ptp_qoriq_adjfine,
|
|
.adjtime = ptp_qoriq_adjtime,
|
|
.gettime64 = ptp_qoriq_gettime,
|
|
- .settime64 = ptp_qoriq_settime,
|
|
+ .settime64 = ptp_enetc_settime,
|
|
.enable = ptp_qoriq_enable,
|
|
};
|
|
|
|
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
|
|
index 582ddbff1c94..441bce3dfef8 100644
|
|
--- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c
|
|
+++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c
|
|
@@ -2403,10 +2403,9 @@ static int enetc_config_clsflower(struct enetc_ndev_priv *priv,
|
|
err = enetc_psfp_parse_clsflower(priv, cls_flower);
|
|
else
|
|
err = enetc4_psfp_parse_clsflower(priv, cls_flower);
|
|
- if (err) {
|
|
- NL_SET_ERR_MSG_MOD(extack, "Invalid PSFP inputs");
|
|
+
|
|
+ if (err)
|
|
return err;
|
|
- }
|
|
} else {
|
|
NL_SET_ERR_MSG_MOD(extack, "Unsupported actions");
|
|
return -EOPNOTSUPP;
|
|
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_tsn.c b/drivers/net/ethernet/freescale/enetc/enetc_tsn.c
|
|
index 2da3055b2703..e0e7fea5fc36 100644
|
|
--- a/drivers/net/ethernet/freescale/enetc/enetc_tsn.c
|
|
+++ b/drivers/net/ethernet/freescale/enetc/enetc_tsn.c
|
|
@@ -5,6 +5,13 @@
|
|
|
|
#include <net/tsn.h>
|
|
|
|
+struct netdev_list_entry {
|
|
+ struct list_head list;
|
|
+ struct net_device *dev;
|
|
+};
|
|
+
|
|
+static struct list_head netdev_list = {0};
|
|
+
|
|
static int alloc_cbdr(struct enetc_si *si, struct enetc_cbd **curr_cbd)
|
|
{
|
|
struct enetc_cbdr *ring = &si->cbd_ring;
|
|
@@ -86,8 +93,8 @@ static int enetc_qbv_get(struct net_device *ndev,
|
|
{
|
|
struct tsn_qbv_basic *admin_basic = &admin_conf->admin;
|
|
struct enetc_ndev_priv *priv = netdev_priv(ndev);
|
|
+ u16 data_size, admin_len, oper_len, maxlen;
|
|
struct enetc_hw *hw = &priv->si->hw;
|
|
- u16 data_size, admin_len, maxlen;
|
|
struct tgs_gcl_query *gcl_query;
|
|
struct tgs_gcl_resp *gcl_data;
|
|
struct enetc_cbd *cbdr;
|
|
@@ -120,6 +127,7 @@ static int enetc_qbv_get(struct net_device *ndev,
|
|
gce = (struct gce *)(gcl_data + 1);
|
|
|
|
gcl_query->acl_len = cpu_to_le16(maxlen);
|
|
+ gcl_query->ocl_len = cpu_to_le16(maxlen);
|
|
|
|
dma_size = cpu_to_le16(data_size);
|
|
cbdr->length = dma_size;
|
|
@@ -142,8 +150,12 @@ static int enetc_qbv_get(struct net_device *ndev,
|
|
|
|
/* since cbdr already passed to free, below could be get wrong */
|
|
admin_len = le16_to_cpu(gcl_query->admin_list_len);
|
|
+ oper_len = le16_to_cpu(gcl_query->oper_list_len);
|
|
|
|
- admin_basic->control_list_length = admin_len;
|
|
+ if (!admin_len)
|
|
+ admin_basic->control_list_length = oper_len;
|
|
+ else
|
|
+ admin_basic->control_list_length = admin_len;
|
|
|
|
temp = ((u64)le32_to_cpu(gcl_data->abth)) << 32;
|
|
admin_basic->base_time = le32_to_cpu(gcl_data->abtl) + temp;
|
|
@@ -151,7 +163,7 @@ static int enetc_qbv_get(struct net_device *ndev,
|
|
admin_basic->cycle_time = le32_to_cpu(gcl_data->act);
|
|
admin_basic->cycle_time_extension = le32_to_cpu(gcl_data->acte);
|
|
|
|
- admin_basic->control_list = kcalloc(admin_len,
|
|
+ admin_basic->control_list = kcalloc(admin_basic->control_list_length,
|
|
sizeof(*admin_basic->control_list),
|
|
GFP_KERNEL);
|
|
if (!admin_basic->control_list) {
|
|
@@ -160,10 +172,15 @@ static int enetc_qbv_get(struct net_device *ndev,
|
|
return -ENOMEM;
|
|
}
|
|
|
|
- for (i = 0; i < admin_len; i++) {
|
|
- struct gce *temp_gce = gce + i;
|
|
+ for (i = 0; i < admin_basic->control_list_length; i++) {
|
|
+ struct gce *temp_gce;
|
|
struct tsn_qbv_entry *temp_entry;
|
|
|
|
+ if (!admin_len)
|
|
+ temp_gce = gce + maxlen + i;
|
|
+ else
|
|
+ temp_gce = gce + i;
|
|
+
|
|
temp_entry = admin_basic->control_list + i;
|
|
|
|
temp_entry->gate_state = temp_gce->gate;
|
|
@@ -298,6 +315,120 @@ static int enetc_qbv_get_status(struct net_device *ndev,
|
|
return 0;
|
|
}
|
|
|
|
+static int enetc_qbv_gcl_reset(struct net_device *ndev,
|
|
+ struct tsn_qbv_conf *admin_conf)
|
|
+{
|
|
+ struct tsn_qbv_basic *admin_basic = &admin_conf->admin;
|
|
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
|
|
+ struct enetc_hw *hw = &priv->si->hw;
|
|
+ struct tgs_gcl_conf *gcl_config;
|
|
+ struct tgs_gcl_data *gcl_data;
|
|
+ struct enetc_cbd *cbdr;
|
|
+ struct gce *gce;
|
|
+ dma_addr_t dma;
|
|
+ u16 data_size;
|
|
+ int curr_cbd;
|
|
+ u16 gcl_len;
|
|
+ u32 temp;
|
|
+ int i;
|
|
+
|
|
+ gcl_len = admin_basic->control_list_length;
|
|
+ if (gcl_len > enetc_get_max_gcl_len(hw))
|
|
+ return -EINVAL;
|
|
+
|
|
+ temp = enetc_rd(hw, ENETC_PTGCR);
|
|
+ if (admin_conf->gate_enabled) {
|
|
+ enetc_wr(hw, ENETC_PTGCR, temp & ~ENETC_PTGCR_TGE);
|
|
+ usleep_range(10, 20);
|
|
+ enetc_wr(hw, ENETC_PTGCR, temp | ENETC_PTGCR_TGE);
|
|
+ } else if (!admin_conf->gate_enabled) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* Configure the (administrative) gate control list using the
|
|
+ * control BD descriptor.
|
|
+ */
|
|
+ curr_cbd = alloc_cbdr(priv->si, &cbdr);
|
|
+
|
|
+ gcl_config = &cbdr->gcl_conf;
|
|
+
|
|
+ data_size = struct_size(gcl_data, entry, gcl_len);
|
|
+
|
|
+ gcl_data = kzalloc(data_size, __GFP_DMA | GFP_KERNEL);
|
|
+ if (!gcl_data)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ gce = &gcl_data->entry[0];
|
|
+
|
|
+ gcl_config->atc = admin_basic->gate_states;
|
|
+ gcl_config->acl_len = cpu_to_le16(gcl_len);
|
|
+
|
|
+ gcl_data->btl = cpu_to_le32(lower_32_bits(admin_basic->base_time));
|
|
+ gcl_data->bth = cpu_to_le32(upper_32_bits(admin_basic->base_time));
|
|
+
|
|
+ gcl_data->ct = cpu_to_le32(admin_basic->cycle_time);
|
|
+ gcl_data->cte = cpu_to_le32(admin_basic->cycle_time_extension);
|
|
+
|
|
+ for (i = 0; i < gcl_len; i++) {
|
|
+ struct gce *temp_gce = gce + i;
|
|
+ struct tsn_qbv_entry *temp_entry;
|
|
+
|
|
+ temp_entry = admin_basic->control_list + i;
|
|
+
|
|
+ temp_gce->gate = temp_entry->gate_state;
|
|
+ temp_gce->period = cpu_to_le32(temp_entry->time_interval);
|
|
+ }
|
|
+
|
|
+ cbdr->length = cpu_to_le16(data_size);
|
|
+ cbdr->status_flags = 0;
|
|
+
|
|
+ dma = dma_map_single(&priv->si->pdev->dev, gcl_data,
|
|
+ data_size, DMA_TO_DEVICE);
|
|
+ if (dma_mapping_error(&priv->si->pdev->dev, dma)) {
|
|
+ netdev_err(priv->si->ndev, "DMA mapping failed!\n");
|
|
+ kfree(gcl_data);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ cbdr->addr[0] = cpu_to_le32(lower_32_bits(dma));
|
|
+ cbdr->addr[1] = cpu_to_le32(upper_32_bits(dma));
|
|
+ cbdr->cmd = 0;
|
|
+ cbdr->cls = BDCR_CMD_PORT_GCL;
|
|
+
|
|
+ /* Updated by ENETC on completion of the configuration
|
|
+ * command. A zero value indicates success.
|
|
+ */
|
|
+ cbdr->status_flags = 0;
|
|
+
|
|
+ xmit_cbdr(priv->si, curr_cbd);
|
|
+
|
|
+ memset(cbdr, 0, sizeof(struct enetc_cbd));
|
|
+ dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE);
|
|
+ kfree(gcl_data);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int enetc_est_reset(struct net_device *ndev)
|
|
+{
|
|
+ struct tsn_qbv_conf admin_conf = {0};
|
|
+ int ret;
|
|
+
|
|
+ ret = enetc_qbv_get(ndev, &admin_conf);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ return enetc_qbv_gcl_reset(ndev, &admin_conf);
|
|
+}
|
|
+
|
|
+void enetc_ptp_clock_update()
|
|
+{
|
|
+ struct netdev_list_entry *entry;
|
|
+
|
|
+ list_for_each_entry(entry, &netdev_list, list)
|
|
+ enetc_est_reset(entry->dev);
|
|
+}
|
|
+
|
|
/* CBD Class 7: Stream Identity Entry Set Descriptor - Long Format */
|
|
static int enetc_cb_streamid_set(struct net_device *ndev, u32 index,
|
|
bool en, struct tsn_cb_streamid *streamid)
|
|
@@ -1383,6 +1514,14 @@ static int enetc_qbu_set(struct net_device *ndev, u8 preemptible_tcs)
|
|
|
|
enetc_change_preemptible_tcs(priv, preemptible_tcs);
|
|
|
|
+ /* Set pMAC step lock */
|
|
+ val = enetc_port_rd(&priv->si->hw, ENETC_PFPMR);
|
|
+ enetc_port_wr(&priv->si->hw, ENETC_PFPMR,
|
|
+ val | ENETC_PFPMR_PMACE);
|
|
+
|
|
+ val = enetc_port_rd(&priv->si->hw, ENETC_MMCSR);
|
|
+ enetc_port_wr(&priv->si->hw, ENETC_MMCSR, val | ENETC_MMCSR_ME);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -1734,6 +1873,33 @@ static const struct tsn_ops enetc_tsn_ops_part = {
|
|
.qci_fmi_get = enetc_qci_fmi_get,
|
|
};
|
|
|
|
+static void enetc_tsn_netdev_list_add(struct net_device *ndev)
|
|
+{
|
|
+ struct netdev_list_entry *entry;
|
|
+
|
|
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
|
+ if (!entry)
|
|
+ return;
|
|
+
|
|
+ entry->dev = ndev;
|
|
+
|
|
+ if (!netdev_list.next)
|
|
+ INIT_LIST_HEAD(&netdev_list);
|
|
+
|
|
+ list_add_tail(&entry->list, &netdev_list);
|
|
+}
|
|
+
|
|
+static void enetc_tsn_netdev_list_del(struct net_device *ndev)
|
|
+{
|
|
+ struct netdev_list_entry *tmp, *n;
|
|
+
|
|
+ list_for_each_entry_safe(tmp, n, &netdev_list, list)
|
|
+ if (tmp->dev == ndev) {
|
|
+ list_del(&tmp->list);
|
|
+ kfree(tmp);
|
|
+ }
|
|
+}
|
|
+
|
|
void enetc_tsn_pf_init(struct net_device *netdev, struct pci_dev *pdev)
|
|
{
|
|
int port = pdev->devfn & 0x7;
|
|
@@ -1744,9 +1910,12 @@ void enetc_tsn_pf_init(struct net_device *netdev, struct pci_dev *pdev)
|
|
else
|
|
tsn_port_register(netdev, &enetc_tsn_ops_full,
|
|
(u16)pdev->bus->number);
|
|
+
|
|
+ enetc_tsn_netdev_list_add(netdev);
|
|
}
|
|
|
|
void enetc_tsn_pf_deinit(struct net_device *netdev)
|
|
{
|
|
tsn_port_unregister(netdev);
|
|
+ enetc_tsn_netdev_list_del(netdev);
|
|
}
|
|
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
|
|
index b4e819ff34f7..7faa09477396 100644
|
|
--- a/drivers/net/ethernet/freescale/fec.h
|
|
+++ b/drivers/net/ethernet/freescale/fec.h
|
|
@@ -23,6 +23,7 @@
|
|
#include <dt-bindings/firmware/imx/rsrc.h>
|
|
#include <linux/firmware/imx/sci.h>
|
|
#include <net/xdp.h>
|
|
+#include <linux/fec.h>
|
|
|
|
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
|
|
defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) || \
|
|
@@ -334,30 +335,30 @@ struct bufdesc_ex {
|
|
(IDLE_SLOPE_2 & IDLE_SLOPE_MASK))
|
|
#define RCMR_MATCHEN (0x1 << 16)
|
|
#define RCMR_CMP_CFG(v, n) (((v) & 0x7) << (n << 2))
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+#define SR_CLASS_A_PRIORITY 3
|
|
+#define SR_CLASS_B_PRIORITY 2
|
|
+#define RCMR_CMP_1 (RCMR_CMP_CFG(SR_CLASS_A_PRIORITY, 0) | \
|
|
+ RCMR_CMP_CFG(SR_CLASS_A_PRIORITY, 1) | \
|
|
+ RCMR_CMP_CFG(SR_CLASS_A_PRIORITY, 2) | \
|
|
+ RCMR_CMP_CFG(SR_CLASS_A_PRIORITY, 3))
|
|
+#define RCMR_CMP_2 (RCMR_CMP_CFG(SR_CLASS_B_PRIORITY, 0) | \
|
|
+ RCMR_CMP_CFG(SR_CLASS_B_PRIORITY, 1) | \
|
|
+ RCMR_CMP_CFG(SR_CLASS_B_PRIORITY, 2) | \
|
|
+ RCMR_CMP_CFG(SR_CLASS_B_PRIORITY, 3))
|
|
+#else
|
|
#define RCMR_CMP_1 (RCMR_CMP_CFG(0, 0) | RCMR_CMP_CFG(1, 1) | \
|
|
RCMR_CMP_CFG(2, 2) | RCMR_CMP_CFG(3, 3))
|
|
#define RCMR_CMP_2 (RCMR_CMP_CFG(4, 0) | RCMR_CMP_CFG(5, 1) | \
|
|
RCMR_CMP_CFG(6, 2) | RCMR_CMP_CFG(7, 3))
|
|
+#endif
|
|
#define RCMR_CMP(X) (((X) == 1) ? RCMR_CMP_1 : RCMR_CMP_2)
|
|
#define FEC_TX_BD_FTYPE(X) (((X) & 0xf) << 20)
|
|
|
|
-/* The number of Tx and Rx buffers. These are allocated from the page
|
|
- * pool. The code may assume these are power of two, so it it best
|
|
- * to keep them that size.
|
|
- * We don't need to allocate pages for the transmitter. We just use
|
|
- * the skbuffer directly.
|
|
- */
|
|
+#define FEC_RX_FLUSH(X) (1 << ((X) + 3))
|
|
|
|
-#define FEC_ENET_XDP_HEADROOM (XDP_PACKET_HEADROOM)
|
|
-#define FEC_ENET_RX_PAGES 256
|
|
-#define FEC_ENET_RX_FRSIZE (PAGE_SIZE - FEC_ENET_XDP_HEADROOM \
|
|
- - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
|
|
-#define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE)
|
|
-#define RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES)
|
|
-#define FEC_ENET_TX_FRSIZE 2048
|
|
-#define FEC_ENET_TX_FRPPG (PAGE_SIZE / FEC_ENET_TX_FRSIZE)
|
|
-#define TX_RING_SIZE 1024 /* Must be power of two */
|
|
-#define TX_RING_MOD_MASK 511 /* for this to work */
|
|
+#define FEC_TX_SCHEME_CB 0x0 /* Credit based */
|
|
+#define FEC_TX_SCHEME_RR 0x1 /* Round-robin */
|
|
|
|
#define BD_ENET_RX_INT 0x00800000
|
|
#define BD_ENET_RX_PTP ((ushort)0x0400)
|
|
@@ -402,9 +403,14 @@ struct bufdesc_ex {
|
|
#define FEC_ITR_EN (0x1 << 31)
|
|
#define FEC_ITR_ICFT(X) (((X) & 0xff) << 20)
|
|
#define FEC_ITR_ICTT(X) ((X) & 0xffff)
|
|
-#define FEC_ITR_ICFT_DEFAULT 200 /* Set 200 frame count threshold */
|
|
#define FEC_ITR_ICTT_DEFAULT 1000 /* Set 1000us timer threshold */
|
|
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+#define FEC_ITR_ICFT_DEFAULT 50 /* Keep it coherent with FEC_TX_RING_SIZE/FEC_RX_RING_SIZE */
|
|
+#else
|
|
+#define FEC_ITR_ICFT_DEFAULT 200 /* Set 200 frame count threshold */
|
|
+#endif
|
|
+
|
|
#define FEC_VLAN_TAG_LEN 0x04
|
|
#define FEC_ETHTYPE_LEN 0x02
|
|
|
|
@@ -559,20 +565,31 @@ struct fec_tx_buffer {
|
|
|
|
struct fec_enet_priv_tx_q {
|
|
struct bufdesc_prop bd;
|
|
- unsigned char *tx_bounce[TX_RING_SIZE];
|
|
- struct fec_tx_buffer tx_buf[TX_RING_SIZE];
|
|
+ struct bufdesc *dirty_tx;
|
|
+ struct fec_tx_buffer tx_buf[FEC_TX_RING_SIZE];
|
|
+
|
|
+ unsigned int tx_bounce_size;
|
|
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ unsigned int tx_index;
|
|
+ unsigned char *tx_bounce[FEC_TX_RING_SIZE + 32];
|
|
+#else
|
|
+ unsigned char *tx_bounce[FEC_TX_RING_SIZE];
|
|
+#endif
|
|
unsigned short tx_stop_threshold;
|
|
unsigned short tx_wake_threshold;
|
|
|
|
- struct bufdesc *dirty_tx;
|
|
char *tso_hdrs;
|
|
dma_addr_t tso_hdrs_dma;
|
|
+
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ unsigned long tx_idle_slope;
|
|
+#endif
|
|
};
|
|
|
|
struct fec_enet_priv_rx_q {
|
|
struct bufdesc_prop bd;
|
|
- struct fec_enet_priv_txrx_info rx_skb_info[RX_RING_SIZE];
|
|
+ struct fec_enet_priv_txrx_info rx_skb_info[FEC_RX_RING_SIZE];
|
|
|
|
/* page_pool */
|
|
struct page_pool *page_pool;
|
|
@@ -622,6 +639,12 @@ struct fec_enet_private {
|
|
unsigned int total_tx_ring_size;
|
|
unsigned int total_rx_ring_size;
|
|
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ const struct avb_ops *avb;
|
|
+ void *avb_data;
|
|
+ unsigned int avb_enabled;
|
|
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_advertising);
|
|
+#endif
|
|
struct platform_device *pdev;
|
|
|
|
int dev_id;
|
|
@@ -654,12 +677,19 @@ struct fec_enet_private {
|
|
|
|
struct ptp_clock *ptp_clock;
|
|
struct ptp_clock_info ptp_caps;
|
|
- spinlock_t tmreg_lock;
|
|
+ raw_spinlock_t tmreg_lock;
|
|
struct cyclecounter cc;
|
|
struct timecounter tc;
|
|
u32 cycle_speed;
|
|
int hwts_rx_en;
|
|
int hwts_tx_en;
|
|
+
|
|
+ /* Transmit and receive latency, depending on link speed, for
|
|
+ * packets timestamps in ns
|
|
+ */
|
|
+ u32 rx_tstamp_latency;
|
|
+ u32 tx_tstamp_latency;
|
|
+
|
|
struct delayed_work time_keep;
|
|
struct regulator *reg_mdio;
|
|
struct regulator *reg_phy;
|
|
@@ -696,9 +726,35 @@ struct fec_enet_private {
|
|
/* XDP BPF Program */
|
|
struct bpf_prog *xdp_prog;
|
|
|
|
+ /* Configured rx/tx timestamps delays for different link speeds
|
|
+ * to compensate for FEC-PHY latency in ns
|
|
+ */
|
|
+ u32 rx_delay_100;
|
|
+ u32 tx_delay_100;
|
|
+ u32 rx_delay_1000;
|
|
+ u32 tx_delay_1000;
|
|
+
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ int rec_channel;
|
|
+ int rec_enable;
|
|
+#endif
|
|
+
|
|
u64 ethtool_stats[];
|
|
};
|
|
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+#define FEC_MAX_RATE 400 /* Mbps */
|
|
+#define FEC_MAX_RATE_HAS_AVB 1000 /* Mbps */
|
|
+
|
|
+static inline int fec_max_rate(struct fec_enet_private *fep)
|
|
+{
|
|
+ int max_rate = (fep->quirks & FEC_QUIRK_HAS_AVB) ? FEC_MAX_RATE_HAS_AVB : FEC_MAX_RATE;
|
|
+ return min(max_rate, fep->speed);
|
|
+}
|
|
+
|
|
+#define IDLE_SLOPE_DIVISOR 512
|
|
+#endif
|
|
+
|
|
void fec_ptp_init(struct platform_device *pdev, int irq_idx);
|
|
void fec_ptp_stop(struct platform_device *pdev);
|
|
void fec_ptp_start_cyclecounter(struct net_device *ndev);
|
|
diff --git a/drivers/net/ethernet/freescale/fec_ecat.c b/drivers/net/ethernet/freescale/fec_ecat.c
|
|
new file mode 100644
|
|
index 000000000000..642cfe340930
|
|
--- /dev/null
|
|
+++ b/drivers/net/ethernet/freescale/fec_ecat.c
|
|
@@ -0,0 +1,3063 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#include <linux/module.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/string.h>
|
|
+#include <linux/pm_runtime.h>
|
|
+#include <linux/ptrace.h>
|
|
+#include <linux/errno.h>
|
|
+#include <linux/ioport.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/netdevice.h>
|
|
+#include <linux/etherdevice.h>
|
|
+#include <linux/skbuff.h>
|
|
+#include <linux/in.h>
|
|
+#include <linux/ip.h>
|
|
+#include <net/ip.h>
|
|
+#include <net/selftests.h>
|
|
+#include <net/tso.h>
|
|
+#include <linux/tcp.h>
|
|
+#include <linux/udp.h>
|
|
+#include <linux/icmp.h>
|
|
+#include <linux/spinlock.h>
|
|
+#include <linux/workqueue.h>
|
|
+#include <linux/bitops.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/irq.h>
|
|
+#include <linux/clk.h>
|
|
+#include <linux/crc32.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/mdio.h>
|
|
+#include <linux/phy.h>
|
|
+#include <linux/fec.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/of_device.h>
|
|
+#include <linux/of_gpio.h>
|
|
+#include <linux/of_mdio.h>
|
|
+#include <linux/of_net.h>
|
|
+#include <linux/regulator/consumer.h>
|
|
+#include <linux/if_vlan.h>
|
|
+#include <linux/pinctrl/consumer.h>
|
|
+#include <linux/pm_runtime.h>
|
|
+#include <linux/busfreq-imx.h>
|
|
+#include <linux/prefetch.h>
|
|
+#include <linux/mfd/syscon.h>
|
|
+#include <linux/regmap.h>
|
|
+#include <soc/imx/cpuidle.h>
|
|
+#include <linux/uaccess.h>
|
|
+#include <linux/bpf.h>
|
|
+
|
|
+#include <asm/cacheflush.h>
|
|
+
|
|
+#include "fec_ecat.h"
|
|
+
|
|
+
|
|
+#define DRIVER_NAME "fec_ecat"
|
|
+
|
|
+/* Pause frame feild and FIFO threshold */
|
|
+#define FEC_ENET_FCE (1 << 5)
|
|
+#define FEC_ENET_RSEM_V 0x84
|
|
+#define FEC_ENET_RSFL_V 16
|
|
+#define FEC_ENET_RAEM_V 0x8
|
|
+#define FEC_ENET_RAFL_V 0x8
|
|
+#define FEC_ENET_OPD_V 0xFFF0
|
|
+#define FEC_MDIO_PM_TIMEOUT 100 /* ms */
|
|
+
|
|
+struct fec_devinfo {
|
|
+ u32 quirks;
|
|
+};
|
|
+
|
|
+static const struct fec_devinfo fec_imx25_info = {
|
|
+ .quirks = FEC_QUIRK_USE_GASKET | FEC_QUIRK_MIB_CLEAR |
|
|
+ FEC_QUIRK_HAS_FRREG,
|
|
+};
|
|
+
|
|
+static const struct fec_devinfo fec_imx27_info = {
|
|
+ .quirks = FEC_QUIRK_MIB_CLEAR | FEC_QUIRK_HAS_FRREG,
|
|
+};
|
|
+
|
|
+static const struct fec_devinfo fec_imx28_info = {
|
|
+ .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME |
|
|
+ FEC_QUIRK_SINGLE_MDIO | FEC_QUIRK_HAS_RACC |
|
|
+ FEC_QUIRK_HAS_FRREG | FEC_QUIRK_CLEAR_SETUP_MII |
|
|
+ FEC_QUIRK_NO_HARD_RESET,
|
|
+};
|
|
+
|
|
+static const struct fec_devinfo fec_imx6q_info = {
|
|
+ .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
|
|
+ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
|
|
+ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 |
|
|
+ FEC_QUIRK_HAS_RACC | FEC_QUIRK_CLEAR_SETUP_MII |
|
|
+ FEC_QUIRK_HAS_PMQOS,
|
|
+};
|
|
+
|
|
+static const struct fec_devinfo fec_mvf600_info = {
|
|
+ .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_RACC,
|
|
+};
|
|
+
|
|
+static const struct fec_devinfo fec_imx6x_info = {
|
|
+ .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
|
|
+ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
|
|
+ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
|
|
+ FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE |
|
|
+ FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE |
|
|
+ FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES,
|
|
+};
|
|
+
|
|
+static const struct fec_devinfo fec_imx6ul_info = {
|
|
+ .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
|
|
+ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
|
|
+ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR007885 |
|
|
+ FEC_QUIRK_BUG_CAPTURE | FEC_QUIRK_HAS_RACC |
|
|
+ FEC_QUIRK_HAS_COALESCE | FEC_QUIRK_CLEAR_SETUP_MII,
|
|
+};
|
|
+
|
|
+static const struct fec_devinfo fec_imx8mq_info = {
|
|
+ .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
|
|
+ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
|
|
+ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
|
|
+ FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE |
|
|
+ FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE |
|
|
+ FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES |
|
|
+ FEC_QUIRK_HAS_EEE | FEC_QUIRK_WAKEUP_FROM_INT2,
|
|
+};
|
|
+
|
|
+static const struct fec_devinfo fec_imx8qm_info = {
|
|
+ .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
|
|
+ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
|
|
+ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
|
|
+ FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE |
|
|
+ FEC_QUIRK_HAS_RACC | FEC_QUIRK_HAS_COALESCE |
|
|
+ FEC_QUIRK_CLEAR_SETUP_MII | FEC_QUIRK_HAS_MULTI_QUEUES |
|
|
+ FEC_QUIRK_DELAYED_CLKS_SUPPORT,
|
|
+};
|
|
+
|
|
+static const struct fec_devinfo fec_s32v234_info = {
|
|
+ .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
|
|
+ FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
|
|
+ FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_AVB |
|
|
+ FEC_QUIRK_ERR007885 | FEC_QUIRK_BUG_CAPTURE,
|
|
+};
|
|
+
|
|
+static struct platform_device_id fec_devtype[] = {
|
|
+ {
|
|
+ /* keep it for coldfire */
|
|
+ .name = DRIVER_NAME,
|
|
+ .driver_data = 0,
|
|
+ }, {
|
|
+ .name = "imx25-fec",
|
|
+ .driver_data = (kernel_ulong_t)&fec_imx25_info,
|
|
+ }, {
|
|
+ .name = "imx27-fec",
|
|
+ .driver_data = (kernel_ulong_t)&fec_imx27_info,
|
|
+ }, {
|
|
+ .name = "imx28-fec",
|
|
+ .driver_data = (kernel_ulong_t)&fec_imx28_info,
|
|
+ }, {
|
|
+ .name = "imx6q-fec",
|
|
+ .driver_data = (kernel_ulong_t)&fec_imx6q_info,
|
|
+ }, {
|
|
+ .name = "mvf600-fec",
|
|
+ .driver_data = (kernel_ulong_t)&fec_mvf600_info,
|
|
+ }, {
|
|
+ .name = "imx6sx-fec",
|
|
+ .driver_data = (kernel_ulong_t)&fec_imx6x_info,
|
|
+ }, {
|
|
+ .name = "imx6ul-fec",
|
|
+ .driver_data = (kernel_ulong_t)&fec_imx6ul_info,
|
|
+ }, {
|
|
+ .name = "imx8mq-fec",
|
|
+ .driver_data = (kernel_ulong_t)&fec_imx8mq_info,
|
|
+ }, {
|
|
+ .name = "imx8qm-fec",
|
|
+ .driver_data = (kernel_ulong_t)&fec_imx8qm_info,
|
|
+ }, {
|
|
+ .name = "s32v234-fec",
|
|
+ .driver_data = (kernel_ulong_t)&fec_s32v234_info,
|
|
+ }, {
|
|
+ /* sentinel */
|
|
+ }
|
|
+};
|
|
+MODULE_DEVICE_TABLE(platform, fec_devtype);
|
|
+
|
|
+enum imx_fec_type {
|
|
+ IMX25_FEC = 1, /* runs on i.mx25/50/53 */
|
|
+ IMX27_FEC, /* runs on i.mx27/35/51 */
|
|
+ IMX28_FEC,
|
|
+ IMX6Q_FEC,
|
|
+ MVF600_FEC,
|
|
+ IMX6SX_FEC,
|
|
+ IMX6UL_FEC,
|
|
+ IMX8MQ_FEC,
|
|
+ IMX8QM_FEC,
|
|
+ S32V234_FEC,
|
|
+};
|
|
+
|
|
+static const struct of_device_id fec_dt_ids[] = {
|
|
+ { .compatible = "fsl,imx25-fec-ecat", .data = &fec_devtype[IMX25_FEC], },
|
|
+ { .compatible = "fsl,imx27-fec-ecat", .data = &fec_devtype[IMX27_FEC], },
|
|
+ { .compatible = "fsl,imx28-fec-ecat", .data = &fec_devtype[IMX28_FEC], },
|
|
+ { .compatible = "fsl,imx6q-fec-ecat", .data = &fec_devtype[IMX6Q_FEC], },
|
|
+ { .compatible = "fsl,mvf600-fec-ecat", .data = &fec_devtype[MVF600_FEC], },
|
|
+ { .compatible = "fsl,imx6sx-fec-ecat", .data = &fec_devtype[IMX6SX_FEC], },
|
|
+ { .compatible = "fsl,imx6ul-fec-ecat", .data = &fec_devtype[IMX6UL_FEC], },
|
|
+ { .compatible = "fsl,imx8mq-fec-ecat", .data = &fec_devtype[IMX8MQ_FEC], },
|
|
+ { .compatible = "fsl,imx8qm-fec-ecat", .data = &fec_devtype[IMX8QM_FEC], },
|
|
+ { .compatible = "fsl,s32v234-fec-ecat", .data = &fec_devtype[S32V234_FEC], },
|
|
+ { /* sentinel */ }
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, fec_dt_ids);
|
|
+
|
|
+static unsigned char macaddr[ETH_ALEN];
|
|
+module_param_array(macaddr, byte, NULL, 0);
|
|
+MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
|
|
+
|
|
+#if defined(CONFIG_M5272)
|
|
+/*
|
|
+ * Some hardware gets it MAC address out of local flash memory.
|
|
+ * if this is non-zero then assume it is the address to get MAC from.
|
|
+ */
|
|
+#if defined(CONFIG_NETtel)
|
|
+#define FEC_FLASHMAC 0xf0006006
|
|
+#elif defined(CONFIG_GILBARCONAP) || defined(CONFIG_SCALES)
|
|
+#define FEC_FLASHMAC 0xf0006000
|
|
+#elif defined(CONFIG_CANCam)
|
|
+#define FEC_FLASHMAC 0xf0020000
|
|
+#elif defined (CONFIG_M5272C3)
|
|
+#define FEC_FLASHMAC (0xffe04000 + 4)
|
|
+#elif defined(CONFIG_MOD5272)
|
|
+#define FEC_FLASHMAC 0xffc0406b
|
|
+#else
|
|
+#define FEC_FLASHMAC 0
|
|
+#endif
|
|
+#endif /* CONFIG_M5272 */
|
|
+
|
|
+/* The FEC stores dest/src/type/vlan, data, and checksum for receive packets.
|
|
+ *
|
|
+ * 2048 byte skbufs are allocated. However, alignment requirements
|
|
+ * varies between FEC variants. Worst case is 64, so round down by 64.
|
|
+ */
|
|
+#define PKT_MAXBUF_SIZE (round_down(2048 - 64, 64))
|
|
+#define PKT_MINBUF_SIZE 64
|
|
+
|
|
+/* FEC receive acceleration */
|
|
+#define FEC_RACC_IPDIS (1 << 1)
|
|
+#define FEC_RACC_PRODIS (1 << 2)
|
|
+#define FEC_RACC_SHIFT16 BIT(7)
|
|
+#define FEC_RACC_OPTIONS (FEC_RACC_IPDIS | FEC_RACC_PRODIS)
|
|
+
|
|
+/* MIB Control Register */
|
|
+#define FEC_MIB_CTRLSTAT_DISABLE BIT(31)
|
|
+
|
|
+/*
|
|
+ * The 5270/5271/5280/5282/532x RX control register also contains maximum frame
|
|
+ * size bits. Other FEC hardware does not, so we need to take that into
|
|
+ * account when setting it.
|
|
+ */
|
|
+#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
|
|
+ defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) || \
|
|
+ defined(CONFIG_ARM64)
|
|
+#define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16)
|
|
+#else
|
|
+#define OPT_FRAME_SIZE 0
|
|
+#endif
|
|
+
|
|
+/* FEC MII MMFR bits definition */
|
|
+#define FEC_MMFR_ST (1 << 30)
|
|
+#define FEC_MMFR_ST_C45 (0)
|
|
+#define FEC_MMFR_OP_READ (2 << 28)
|
|
+#define FEC_MMFR_OP_READ_C45 (3 << 28)
|
|
+#define FEC_MMFR_OP_WRITE (1 << 28)
|
|
+#define FEC_MMFR_OP_ADDR_WRITE (0)
|
|
+#define FEC_MMFR_PA(v) ((v & 0x1f) << 23)
|
|
+#define FEC_MMFR_RA(v) ((v & 0x1f) << 18)
|
|
+#define FEC_MMFR_TA (2 << 16)
|
|
+#define FEC_MMFR_DATA(v) (v & 0xffff)
|
|
+/* FEC ECR bits definition */
|
|
+#define FEC_ECR_MAGICEN (1 << 2)
|
|
+#define FEC_ECR_SLEEP (1 << 3)
|
|
+
|
|
+#define FEC_MII_TIMEOUT 30000 /* us */
|
|
+
|
|
+/* Transmitter timeout */
|
|
+#define TX_TIMEOUT (2 * HZ)
|
|
+
|
|
+#define FEC_PAUSE_FLAG_AUTONEG 0x1
|
|
+#define FEC_PAUSE_FLAG_ENABLE 0x2
|
|
+#define FEC_WOL_HAS_MAGIC_PACKET (0x1 << 0)
|
|
+#define FEC_WOL_FLAG_ENABLE (0x1 << 1)
|
|
+#define FEC_WOL_FLAG_SLEEP_ON (0x1 << 2)
|
|
+
|
|
+static void set_multicast_list(struct net_device *ndev);
|
|
+static int mii_cnt;
|
|
+
|
|
+static struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp,
|
|
+ struct bufdesc_prop *bd)
|
|
+{
|
|
+ return (bdp >= bd->last) ? bd->base
|
|
+ : (struct bufdesc *)(((void *)bdp) + bd->dsize);
|
|
+}
|
|
+
|
|
+static struct bufdesc *fec_enet_get_prevdesc(struct bufdesc *bdp,
|
|
+ struct bufdesc_prop *bd)
|
|
+{
|
|
+ return (bdp <= bd->base) ? bd->last
|
|
+ : (struct bufdesc *)(((void *)bdp) - bd->dsize);
|
|
+}
|
|
+
|
|
+static int fec_enet_get_bd_index(struct bufdesc *bdp,
|
|
+ struct bufdesc_prop *bd)
|
|
+{
|
|
+ return ((const char *)bdp - (const char *)bd->base) >> bd->dsize_log2;
|
|
+}
|
|
+
|
|
+static void swap_buffer(void *bufaddr, int len)
|
|
+{
|
|
+ int i;
|
|
+ unsigned int *buf = bufaddr;
|
|
+
|
|
+ for (i = 0; i < len; i += 4, buf++)
|
|
+ swab32s(buf);
|
|
+}
|
|
+
|
|
+static void swap_buffer2(void *dst_buf, void *src_buf, int len)
|
|
+{
|
|
+ int i;
|
|
+ unsigned int *src = src_buf;
|
|
+ unsigned int *dst = dst_buf;
|
|
+
|
|
+ for (i = 0; i < len; i += 4, src++, dst++)
|
|
+ *dst = swab32p(src);
|
|
+}
|
|
+
|
|
+static void fec_dump(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ struct bufdesc *bdp;
|
|
+ struct fec_enet_priv_tx_q *txq;
|
|
+ int index = 0;
|
|
+
|
|
+ netdev_info(ndev, "TX ring dump\n");
|
|
+ pr_info("Nr SC addr len SKB\n");
|
|
+
|
|
+ txq = fep->tx_queue;
|
|
+ bdp = txq->bd.base;
|
|
+
|
|
+ do {
|
|
+ pr_info("%3u %c%c 0x%04x 0x%08x %4u %p\n",
|
|
+ index,
|
|
+ bdp == txq->bd.cur ? 'S' : ' ',
|
|
+ bdp == txq->dirty_tx ? 'H' : ' ',
|
|
+ fec16_to_cpu(bdp->cbd_sc),
|
|
+ fec32_to_cpu(bdp->cbd_bufaddr),
|
|
+ fec16_to_cpu(bdp->cbd_datlen),
|
|
+ txq->tx_skbuff[index]);
|
|
+ bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
|
|
+ index++;
|
|
+ } while (bdp != txq->bd.base);
|
|
+}
|
|
+
|
|
+
|
|
+static int fec_ecat_txq_submit_buff(struct fec_enet_priv_tx_q *txq,
|
|
+ void __user *buff, size_t len, struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ struct bufdesc *bdp, *last_bdp;
|
|
+ void *bufaddr;
|
|
+ unsigned short status;
|
|
+ unsigned short buflen;
|
|
+ unsigned int index;
|
|
+ struct sk_buff *skb;
|
|
+
|
|
+ bdp = txq->bd.cur;
|
|
+ last_bdp = bdp;
|
|
+ status = fec16_to_cpu(bdp->cbd_sc);
|
|
+ status &= ~BD_ENET_TX_STATS;
|
|
+
|
|
+ index = fec_enet_get_bd_index(last_bdp, &txq->bd);
|
|
+ skb = txq->tx_skbuff[index];
|
|
+ bufaddr = skb->data;
|
|
+ buflen = len;
|
|
+ copy_from_user(skb->data, buff, len);
|
|
+ bdp->cbd_datlen = cpu_to_fec16(buflen);
|
|
+ /* Push the data cache so the CPM does not get stale memory data. */
|
|
+ dma_sync_single_for_device(&fep->pdev->dev,
|
|
+ fec32_to_cpu(bdp->cbd_bufaddr),
|
|
+ buflen,
|
|
+ DMA_TO_DEVICE);
|
|
+
|
|
+ status |= (BD_ENET_TX_INTR | BD_ENET_TX_LAST);
|
|
+
|
|
+ wmb();
|
|
+
|
|
+ /* Send it on its way. Tell FEC it's ready, interrupt when done,
|
|
+ * it's the last BD of the frame, and to put the CRC on the end.
|
|
+ */
|
|
+ status |= (BD_ENET_TX_READY | BD_ENET_TX_TC);
|
|
+ bdp->cbd_sc = cpu_to_fec16(status);
|
|
+
|
|
+ /* If this was the last BD in the ring, start at the beginning again. */
|
|
+ bdp = fec_enet_get_nextdesc(last_bdp, &txq->bd);
|
|
+
|
|
+ wmb();
|
|
+ txq->bd.cur = bdp;
|
|
+
|
|
+ /* Trigger transmission start */
|
|
+ if (!(fep->quirks & FEC_QUIRK_ERR007885) ||
|
|
+ !readl(txq->bd.reg_desc_active) ||
|
|
+ !readl(txq->bd.reg_desc_active) ||
|
|
+ !readl(txq->bd.reg_desc_active) ||
|
|
+ !readl(txq->bd.reg_desc_active))
|
|
+ writel(0, txq->bd.reg_desc_active);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void fec_ecat_tx_queue(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ struct bufdesc *bdp;
|
|
+ unsigned short status;
|
|
+ struct fec_enet_priv_tx_q *txq = fep->tx_queue;
|
|
+ int index = 0;
|
|
+
|
|
+ /* get next bdp of dirty_tx */
|
|
+ bdp = txq->dirty_tx;
|
|
+
|
|
+ /* get next bdp of dirty_tx */
|
|
+ bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
|
|
+
|
|
+ while (bdp != READ_ONCE(txq->bd.cur)) {
|
|
+ /* Order the load of bd.cur and cbd_sc */
|
|
+ rmb();
|
|
+ status = fec16_to_cpu(READ_ONCE(bdp->cbd_sc));
|
|
+ if (status & BD_ENET_TX_READY)
|
|
+ break;
|
|
+
|
|
+ /* Check for errors. */
|
|
+ if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
|
|
+ BD_ENET_TX_RL | BD_ENET_TX_UN |
|
|
+ BD_ENET_TX_CSL)) {
|
|
+ ndev->stats.tx_errors++;
|
|
+ } else {
|
|
+ ndev->stats.tx_packets++;
|
|
+ }
|
|
+
|
|
+ wmb();
|
|
+ txq->dirty_tx = bdp;
|
|
+
|
|
+ /* Update pointer to next buffer descriptor to be transmitted */
|
|
+ bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
|
|
+ }
|
|
+
|
|
+ /* ERR006358: Keep the transmitter going */
|
|
+ if (bdp != txq->bd.cur &&
|
|
+ readl(txq->bd.reg_desc_active) == 0)
|
|
+ writel(0, txq->bd.reg_desc_active);
|
|
+}
|
|
+
|
|
+static int fec_ecat_fast_xmit(struct net_device *ndev, void __user *buff, size_t len)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ int ret;
|
|
+
|
|
+ if (!mutex_trylock(&fep->fast_ndev_lock)) {
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ ret = fec_ecat_txq_submit_buff(fep->tx_queue, buff, len, ndev);
|
|
+ fec_ecat_tx_queue(ndev);
|
|
+
|
|
+ mutex_unlock(&fep->fast_ndev_lock);
|
|
+
|
|
+ return NETDEV_TX_OK;
|
|
+}
|
|
+
|
|
+/* Init RX n TX buffer descriptors
|
|
+ */
|
|
+static void fec_enet_bd_init(struct net_device *dev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(dev);
|
|
+ struct fec_enet_priv_tx_q *txq = fep->tx_queue;
|
|
+ struct fec_enet_priv_rx_q *rxq = fep->rx_queue;
|
|
+ struct bufdesc *bdp;
|
|
+ int i;
|
|
+ struct sk_buff *skb;
|
|
+
|
|
+ /* Initialize the receive buffer descriptors. */
|
|
+ bdp = rxq->bd.base;
|
|
+
|
|
+ for (i = 0; i < rxq->bd.ring_size; i++) {
|
|
+ /* Initialize the BD for every fragment in the page. */
|
|
+ if (bdp->cbd_bufaddr)
|
|
+ bdp->cbd_sc = cpu_to_fec16(BD_ENET_RX_EMPTY);
|
|
+ else
|
|
+ bdp->cbd_sc = cpu_to_fec16(0);
|
|
+ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd);
|
|
+ }
|
|
+
|
|
+ /* Set the last buffer to wrap */
|
|
+ bdp = fec_enet_get_prevdesc(bdp, &rxq->bd);
|
|
+ bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP);
|
|
+ rxq->bd.cur = rxq->bd.base;
|
|
+
|
|
+ /* ...and the same for transmit */
|
|
+ bdp = txq->bd.base;
|
|
+ txq->bd.cur = bdp;
|
|
+
|
|
+ for (i = 0; i < txq->bd.ring_size; i++) {
|
|
+ bdp->cbd_sc = cpu_to_fec16(0);
|
|
+ bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
|
|
+ }
|
|
+
|
|
+ /* Set the last buffer to wrap */
|
|
+ bdp = fec_enet_get_prevdesc(bdp, &txq->bd);
|
|
+ bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP);
|
|
+ txq->dirty_tx = bdp;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * This function is called to start or restart the FEC during a link
|
|
+ * change, transmit timeout, or to reconfigure the FEC. The network
|
|
+ * packet processing for this device must be stopped before this call.
|
|
+ */
|
|
+static void
|
|
+fec_restart(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ u32 temp_mac[2];
|
|
+ u32 rcntl = OPT_FRAME_SIZE | 0x04;
|
|
+ u32 ecntl = FEC_ENET_ETHEREN; /* ETHEREN */
|
|
+
|
|
+ /* Always use disable MAC instead of MAC reset to:
|
|
+ * - Keep the ENET counter running
|
|
+ * - Avoid dead system bus for SoCs using the ENET-AXI bus
|
|
+ * and not the AHB bus, like the i.MX6SX
|
|
+ */
|
|
+ writel(0, fep->hwp + FEC_ECNTRL);
|
|
+
|
|
+ /*
|
|
+ * enet-mac reset will reset mac address registers too,
|
|
+ * so need to reconfigure it.
|
|
+ */
|
|
+ memcpy(&temp_mac, ndev->dev_addr, ETH_ALEN);
|
|
+ writel((__force u32)cpu_to_be32(temp_mac[0]),
|
|
+ fep->hwp + FEC_ADDR_LOW);
|
|
+ writel((__force u32)cpu_to_be32(temp_mac[1]),
|
|
+ fep->hwp + FEC_ADDR_HIGH);
|
|
+
|
|
+ /* Clear any outstanding interrupt, except MDIO. */
|
|
+ writel((0xffffffff & ~FEC_ENET_MII), fep->hwp + FEC_IEVENT);
|
|
+
|
|
+ fec_enet_bd_init(ndev);
|
|
+
|
|
+ writel(fep->rx_queue->bd.dma, fep->hwp + FEC_R_DES_START(0));
|
|
+ writel(PKT_MAXBUF_SIZE, fep->hwp + FEC_R_BUFF_SIZE(0));
|
|
+
|
|
+ writel(fep->tx_queue->bd.dma, fep->hwp + FEC_X_DES_START(0));
|
|
+
|
|
+ if (fep->quirks & FEC_QUIRK_HAS_AVB)
|
|
+ writel(FEC_RX_FLUSH(0) | FEC_TX_SCHEME_CB,
|
|
+ fep->hwp + FEC_QOS_SCHEME);
|
|
+
|
|
+ /* Enable MII mode */
|
|
+ if (fep->full_duplex == DUPLEX_FULL) {
|
|
+ /* FD enable */
|
|
+ writel(0x04, fep->hwp + FEC_X_CNTRL);
|
|
+ } else {
|
|
+ /* No Rcv on Xmit */
|
|
+ rcntl |= 0x02;
|
|
+ writel(0x0, fep->hwp + FEC_X_CNTRL);
|
|
+ }
|
|
+
|
|
+ /* Set MII speed */
|
|
+ writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
|
|
+
|
|
+#if !defined(CONFIG_M5272)
|
|
+ if (fep->quirks & FEC_QUIRK_HAS_RACC) {
|
|
+ u32 val = readl(fep->hwp + FEC_RACC);
|
|
+
|
|
+ /* align IP header */
|
|
+ val |= FEC_RACC_SHIFT16;
|
|
+ if (fep->csum_flags & FLAG_RX_CSUM_ENABLED)
|
|
+ /* set RX checksum */
|
|
+ val |= FEC_RACC_OPTIONS;
|
|
+ else
|
|
+ val &= ~FEC_RACC_OPTIONS;
|
|
+ writel(val, fep->hwp + FEC_RACC);
|
|
+ writel(PKT_MAXBUF_SIZE, fep->hwp + FEC_FTRL);
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ /*
|
|
+ * The phy interface and speed need to get configured
|
|
+ * differently on enet-mac.
|
|
+ */
|
|
+ if (fep->quirks & FEC_QUIRK_ENET_MAC) {
|
|
+ /* Enable flow control and length check */
|
|
+ rcntl |= 0x40000000 | 0x00000020;
|
|
+
|
|
+ /* RGMII, RMII or MII */
|
|
+ if (fep->phy_interface == PHY_INTERFACE_MODE_RGMII ||
|
|
+ fep->phy_interface == PHY_INTERFACE_MODE_RGMII_ID ||
|
|
+ fep->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID ||
|
|
+ fep->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID)
|
|
+ rcntl |= (1 << 6);
|
|
+ else if (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
|
|
+ rcntl |= (1 << 8);
|
|
+ else
|
|
+ rcntl &= ~(1 << 8);
|
|
+
|
|
+ /* 1G, 100M or 10M */
|
|
+ if (ndev->phydev) {
|
|
+ if (ndev->phydev->speed == SPEED_1000)
|
|
+ ecntl |= (1 << 5);
|
|
+ else if (ndev->phydev->speed == SPEED_100)
|
|
+ rcntl &= ~(1 << 9);
|
|
+ else
|
|
+ rcntl |= (1 << 9);
|
|
+ }
|
|
+ } else {
|
|
+#ifdef FEC_MIIGSK_ENR
|
|
+ if (fep->quirks & FEC_QUIRK_USE_GASKET) {
|
|
+ u32 cfgr;
|
|
+ /* disable the gasket and wait */
|
|
+ writel(0, fep->hwp + FEC_MIIGSK_ENR);
|
|
+ while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4)
|
|
+ udelay(1);
|
|
+
|
|
+ /*
|
|
+ * configure the gasket:
|
|
+ * RMII, 50 MHz, no loopback, no echo
|
|
+ * MII, 25 MHz, no loopback, no echo
|
|
+ */
|
|
+ cfgr = (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
|
|
+ ? BM_MIIGSK_CFGR_RMII : BM_MIIGSK_CFGR_MII;
|
|
+ if (ndev->phydev && ndev->phydev->speed == SPEED_10)
|
|
+ cfgr |= BM_MIIGSK_CFGR_FRCONT_10M;
|
|
+ writel(cfgr, fep->hwp + FEC_MIIGSK_CFGR);
|
|
+
|
|
+ /* re-enable the gasket */
|
|
+ writel(2, fep->hwp + FEC_MIIGSK_ENR);
|
|
+ }
|
|
+#endif
|
|
+ }
|
|
+
|
|
+#if !defined(CONFIG_M5272)
|
|
+ /* enable pause frame*/
|
|
+ if ((fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) ||
|
|
+ ((fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) &&
|
|
+ ndev->phydev && ndev->phydev->pause)) {
|
|
+ rcntl |= FEC_ENET_FCE;
|
|
+
|
|
+ /* set FIFO threshold parameter to reduce overrun */
|
|
+ writel(FEC_ENET_RSEM_V, fep->hwp + FEC_R_FIFO_RSEM);
|
|
+ writel(FEC_ENET_RSFL_V, fep->hwp + FEC_R_FIFO_RSFL);
|
|
+ writel(FEC_ENET_RAEM_V, fep->hwp + FEC_R_FIFO_RAEM);
|
|
+ writel(FEC_ENET_RAFL_V, fep->hwp + FEC_R_FIFO_RAFL);
|
|
+
|
|
+ /* OPD */
|
|
+ writel(FEC_ENET_OPD_V, fep->hwp + FEC_OPD);
|
|
+ } else {
|
|
+ rcntl &= ~FEC_ENET_FCE;
|
|
+ }
|
|
+#endif /* !defined(CONFIG_M5272) */
|
|
+
|
|
+ writel(rcntl, fep->hwp + FEC_R_CNTRL);
|
|
+
|
|
+ /* Setup multicast filter. */
|
|
+ set_multicast_list(ndev);
|
|
+#ifndef CONFIG_M5272
|
|
+ writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
|
|
+ writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
|
|
+#endif
|
|
+
|
|
+ if (fep->quirks & FEC_QUIRK_ENET_MAC) {
|
|
+ /* enable ENET endian swap */
|
|
+ ecntl |= (1 << 8);
|
|
+ /* enable ENET store and forward mode */
|
|
+ writel(1 << 8, fep->hwp + FEC_X_WMRK);
|
|
+ }
|
|
+
|
|
+ if (fep->quirks & FEC_QUIRK_DELAYED_CLKS_SUPPORT &&
|
|
+ fep->rgmii_txc_dly)
|
|
+ ecntl |= FEC_ENET_TXC_DLY;
|
|
+ if (fep->quirks & FEC_QUIRK_DELAYED_CLKS_SUPPORT &&
|
|
+ fep->rgmii_rxc_dly)
|
|
+ ecntl |= FEC_ENET_RXC_DLY;
|
|
+
|
|
+#ifndef CONFIG_M5272
|
|
+ /* Enable the MIB statistic event counters */
|
|
+ writel(0 << 31, fep->hwp + FEC_MIB_CTRLSTAT);
|
|
+#endif
|
|
+
|
|
+ /* And last, enable the transmit and receive processing */
|
|
+ writel(ecntl, fep->hwp + FEC_ECNTRL);
|
|
+ writel(0, fep->rx_queue->bd.reg_desc_active);
|
|
+
|
|
+ writel(0, fep->hwp + FEC_IMASK);
|
|
+}
|
|
+
|
|
+static int fec_enet_ipc_handle_init(struct fec_enet_private *fep)
|
|
+{
|
|
+ if (!(of_machine_is_compatible("fsl,imx8qm") ||
|
|
+ of_machine_is_compatible("fsl,imx8qxp") ||
|
|
+ of_machine_is_compatible("fsl,imx8dxl")))
|
|
+ return 0;
|
|
+
|
|
+ return imx_scu_get_handle(&fep->ipc_handle);
|
|
+}
|
|
+
|
|
+static void fec_enet_ipg_stop_set(struct fec_enet_private *fep, bool enabled)
|
|
+{
|
|
+ struct device_node *np = fep->pdev->dev.of_node;
|
|
+ u32 rsrc_id, val;
|
|
+ int idx;
|
|
+
|
|
+ if (!np || !fep->ipc_handle)
|
|
+ return;
|
|
+
|
|
+ idx = of_alias_get_id(np, "ethernet");
|
|
+ if (idx < 0)
|
|
+ idx = 0;
|
|
+ rsrc_id = idx ? IMX_SC_R_ENET_1 : IMX_SC_R_ENET_0;
|
|
+
|
|
+ val = enabled ? 1 : 0;
|
|
+ imx_sc_misc_set_control(fep->ipc_handle, rsrc_id, IMX_SC_C_IPG_STOP, val);
|
|
+}
|
|
+
|
|
+static void fec_enet_stop_mode(struct fec_enet_private *fep, bool enabled)
|
|
+{
|
|
+ struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
|
|
+ struct fec_stop_mode_gpr *stop_gpr = &fep->stop_gpr;
|
|
+
|
|
+ if (stop_gpr->gpr) {
|
|
+ if (enabled)
|
|
+ regmap_update_bits(stop_gpr->gpr, stop_gpr->reg,
|
|
+ BIT(stop_gpr->bit),
|
|
+ BIT(stop_gpr->bit));
|
|
+ else
|
|
+ regmap_update_bits(stop_gpr->gpr, stop_gpr->reg,
|
|
+ BIT(stop_gpr->bit), 0);
|
|
+ } else if (pdata && pdata->sleep_mode_enable) {
|
|
+ pdata->sleep_mode_enable(enabled);
|
|
+ } else {
|
|
+ fec_enet_ipg_stop_set(fep, enabled);
|
|
+ }
|
|
+}
|
|
+
|
|
+static inline void fec_irqs_disable(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+
|
|
+ writel(0, fep->hwp + FEC_IMASK);
|
|
+}
|
|
+
|
|
+static void
|
|
+fec_stop(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8);
|
|
+
|
|
+ /* We cannot expect a graceful transmit stop without link !!! */
|
|
+ if (fep->link) {
|
|
+ writel(1, fep->hwp + FEC_X_CNTRL); /* Graceful transmit stop */
|
|
+ udelay(10);
|
|
+ if (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_GRA))
|
|
+ netdev_err(ndev, "Graceful transmit stop did not complete!\n");
|
|
+ }
|
|
+
|
|
+ writel(0, fep->hwp + FEC_ECNTRL);
|
|
+
|
|
+ writel(0, fep->hwp + FEC_IMASK);
|
|
+ writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+fec_timeout(struct net_device *ndev, unsigned int txqueue)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+
|
|
+ fec_dump(ndev);
|
|
+
|
|
+ ndev->stats.tx_errors++;
|
|
+
|
|
+ schedule_work(&fep->tx_timeout_work);
|
|
+}
|
|
+
|
|
+static void fec_enet_timeout_work(struct work_struct *work)
|
|
+{
|
|
+ struct fec_enet_private *fep =
|
|
+ container_of(work, struct fec_enet_private, tx_timeout_work);
|
|
+ struct net_device *ndev = fep->netdev;
|
|
+
|
|
+ if (netif_device_present(ndev) || netif_running(ndev)) {
|
|
+ mutex_lock(&fep->fast_ndev_lock);
|
|
+
|
|
+ fec_restart(ndev);
|
|
+ mutex_unlock(&fep->fast_ndev_lock);
|
|
+ }
|
|
+}
|
|
+
|
|
+// must be powers of 2
|
|
+#define MAX_TX_BUF (64)
|
|
+#define MAX_RX_BUF (64)
|
|
+
|
|
+static int fec_ecat_recv_from_queue(struct net_device *ndev, void __user *buff, size_t len, struct sockaddr __user *addr, int *addr_len)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ struct fec_enet_priv_rx_q *rxq = fep->rx_queue;
|
|
+ struct bufdesc *bdp;
|
|
+ unsigned short status;
|
|
+ struct sk_buff *skb = NULL;
|
|
+ ushort pkt_len;
|
|
+ __u8 *data;
|
|
+ int recv_len = 0;
|
|
+ int index = 0;
|
|
+ bool need_swap = fep->quirks & FEC_QUIRK_SWAP_FRAME;
|
|
+ int ret = 0;
|
|
+
|
|
+#ifdef CONFIG_M532x
|
|
+ flush_cache_all();
|
|
+#endif
|
|
+
|
|
+ /* First, grab all of the stats for the incoming packet.
|
|
+ * These get messed up if we get called due to a busy condition.
|
|
+ */
|
|
+ bdp = rxq->bd.cur;
|
|
+
|
|
+ while (!((status = fec16_to_cpu(bdp->cbd_sc)) & BD_ENET_RX_EMPTY)) {
|
|
+
|
|
+ writel(FEC_ENET_RXF_GET(0), fep->hwp + FEC_IEVENT);
|
|
+
|
|
+ /* Check for errors. */
|
|
+ status ^= BD_ENET_RX_LAST;
|
|
+ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
|
|
+ BD_ENET_RX_CR | BD_ENET_RX_OV | BD_ENET_RX_LAST |
|
|
+ BD_ENET_RX_CL)) {
|
|
+ ndev->stats.rx_errors++;
|
|
+ if (status & BD_ENET_RX_OV) {
|
|
+ /* FIFO overrun */
|
|
+ ndev->stats.rx_fifo_errors++;
|
|
+ goto rx_processing_done;
|
|
+ }
|
|
+ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH
|
|
+ | BD_ENET_RX_LAST)) {
|
|
+ /* Frame too long or too short. */
|
|
+ ndev->stats.rx_length_errors++;
|
|
+ if (status & BD_ENET_RX_LAST)
|
|
+ netdev_err(ndev, "rcv is not +last\n");
|
|
+ }
|
|
+ if (status & BD_ENET_RX_CR) /* CRC Error */
|
|
+ ndev->stats.rx_crc_errors++;
|
|
+ /* Report late collisions as a frame error. */
|
|
+ if (status & (BD_ENET_RX_NO | BD_ENET_RX_CL))
|
|
+ ndev->stats.rx_frame_errors++;
|
|
+ goto rx_processing_done;
|
|
+ }
|
|
+
|
|
+ /* Process the incoming frame. */
|
|
+ ndev->stats.rx_packets++;
|
|
+ pkt_len = fec16_to_cpu(bdp->cbd_datlen);
|
|
+ ndev->stats.rx_bytes += pkt_len;
|
|
+
|
|
+ index = fec_enet_get_bd_index(bdp, &rxq->bd);
|
|
+ skb = rxq->rx_skbuff[index];
|
|
+
|
|
+ prefetch(skb->data - NET_IP_ALIGN);
|
|
+ dma_sync_single_for_cpu(&fep->pdev->dev,
|
|
+ fec32_to_cpu(bdp->cbd_bufaddr),
|
|
+ FEC_ENET_RX_FRSIZE - fep->rx_align,
|
|
+ DMA_FROM_DEVICE);
|
|
+
|
|
+ pkt_len -= 6;
|
|
+ data = skb->data;
|
|
+#if !defined(CONFIG_M5272)
|
|
+ if (fep->quirks & FEC_QUIRK_HAS_RACC)
|
|
+ data += 2;
|
|
+#endif
|
|
+ if (data[12] ==0x88 && data[13] ==0xa4) {
|
|
+ len = len < pkt_len? len : pkt_len;
|
|
+ if (!need_swap) {
|
|
+ copy_to_user(buff, data, len);
|
|
+ }
|
|
+ else {
|
|
+ swap_buffer2(buff, data, len);
|
|
+ }
|
|
+ if (addr != NULL) {
|
|
+ struct sockaddr_ll *sll = (struct sockaddr_ll *)addr;
|
|
+ sll->sll_hatype = ndev->type;
|
|
+ sll->sll_ifindex = ndev->ifindex;
|
|
+ }
|
|
+ recv_len = len;
|
|
+ }
|
|
+ dma_sync_single_for_device(&fep->pdev->dev,
|
|
+ fec32_to_cpu(bdp->cbd_bufaddr),
|
|
+ FEC_ENET_RX_FRSIZE - fep->rx_align,
|
|
+ DMA_FROM_DEVICE);
|
|
+rx_processing_done:
|
|
+ /* Clear the status flags for this buffer */
|
|
+ status &= ~BD_ENET_RX_STATS;
|
|
+
|
|
+ /* Mark the buffer empty */
|
|
+ status |= BD_ENET_RX_EMPTY;
|
|
+
|
|
+ /* Make sure the updates to rest of the descriptor are
|
|
+ * performed before transferring ownership.
|
|
+ */
|
|
+ wmb();
|
|
+ bdp->cbd_sc = cpu_to_fec16(status);
|
|
+
|
|
+ /* Update BD pointer to next entry */
|
|
+ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd);
|
|
+
|
|
+ /* Doing this here will keep the FEC running while we process
|
|
+ * incoming frames. On a heavily loaded network, we should be
|
|
+ * able to keep up at the expense of system resources.
|
|
+ */
|
|
+ writel(0, rxq->bd.reg_desc_active);
|
|
+ if (recv_len) {
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ rxq->bd.cur = bdp;
|
|
+ return recv_len;
|
|
+}
|
|
+
|
|
+static int fec_ecat_fast_recv(struct net_device *ndev, void __user *buff, size_t len, struct sockaddr __user *addr, int *addr_len)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ int ret;
|
|
+
|
|
+ if (!mutex_trylock(&fep->fast_ndev_lock)) {
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ ret = fec_ecat_recv_from_queue(ndev, buff, len, addr, addr_len);
|
|
+
|
|
+ mutex_unlock(&fep->fast_ndev_lock);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/* ------------------------------------------------------------------------- */
|
|
+static int fec_get_mac(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ unsigned char *iap, tmpaddr[ETH_ALEN];
|
|
+ int ret;
|
|
+
|
|
+ /*
|
|
+ * try to get mac address in following order:
|
|
+ *
|
|
+ * 1) module parameter via kernel command line in form
|
|
+ * fec.macaddr=0x00,0x04,0x9f,0x01,0x30,0xe0
|
|
+ */
|
|
+ iap = macaddr;
|
|
+
|
|
+ /*
|
|
+ * 2) from device tree data
|
|
+ */
|
|
+ if (!is_valid_ether_addr(iap)) {
|
|
+ struct device_node *np = fep->pdev->dev.of_node;
|
|
+ if (np) {
|
|
+ ret = of_get_mac_address(np, tmpaddr);
|
|
+ if (!ret)
|
|
+ iap = tmpaddr;
|
|
+ else if (ret == -EPROBE_DEFER)
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * 3) from flash or fuse (via platform data)
|
|
+ */
|
|
+ if (!is_valid_ether_addr(iap)) {
|
|
+#ifdef CONFIG_M5272
|
|
+ if (FEC_FLASHMAC)
|
|
+ iap = (unsigned char *)FEC_FLASHMAC;
|
|
+#else
|
|
+ struct fec_platform_data *pdata = dev_get_platdata(&fep->pdev->dev);
|
|
+
|
|
+ if (pdata)
|
|
+ iap = (unsigned char *)&pdata->mac;
|
|
+#endif
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * 4) FEC mac registers set by bootloader
|
|
+ */
|
|
+ if (!is_valid_ether_addr(iap)) {
|
|
+ *((__be32 *) &tmpaddr[0]) =
|
|
+ cpu_to_be32(readl(fep->hwp + FEC_ADDR_LOW));
|
|
+ *((__be16 *) &tmpaddr[4]) =
|
|
+ cpu_to_be16(readl(fep->hwp + FEC_ADDR_HIGH) >> 16);
|
|
+ iap = &tmpaddr[0];
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * 5) random mac address
|
|
+ */
|
|
+ if (!is_valid_ether_addr(iap)) {
|
|
+ /* Report it and use a random ethernet address instead */
|
|
+ dev_err(&fep->pdev->dev, "Invalid MAC address: %pM\n", iap);
|
|
+ eth_hw_addr_random(ndev);
|
|
+ dev_info(&fep->pdev->dev, "Using random MAC address: %pM\n",
|
|
+ ndev->dev_addr);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* Adjust MAC if using macaddr */
|
|
+ eth_hw_addr_gen(ndev, iap, iap == macaddr ? fep->dev_id : 0);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* ------------------------------------------------------------------------- */
|
|
+
|
|
+/*
|
|
+ * Phy section
|
|
+ */
|
|
+static void fec_enet_adjust_link(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ struct phy_device *phy_dev = ndev->phydev;
|
|
+ int status_change = 0;
|
|
+
|
|
+ /*
|
|
+ * If the netdev is down, or is going down, we're not interested
|
|
+ * in link state events, so just mark our idea of the link as down
|
|
+ * and ignore the event.
|
|
+ */
|
|
+ if (!netif_running(ndev) || !netif_device_present(ndev)) {
|
|
+ fep->link = 0;
|
|
+ } else if (phy_dev->link) {
|
|
+ if (!fep->link) {
|
|
+ fep->link = phy_dev->link;
|
|
+ status_change = 1;
|
|
+ }
|
|
+
|
|
+ if (fep->full_duplex != phy_dev->duplex) {
|
|
+ fep->full_duplex = phy_dev->duplex;
|
|
+ status_change = 1;
|
|
+ }
|
|
+
|
|
+ if (phy_dev->speed != fep->speed) {
|
|
+ fep->speed = phy_dev->speed;
|
|
+ status_change = 1;
|
|
+ }
|
|
+
|
|
+ switch (fep->speed) {
|
|
+ case SPEED_100:
|
|
+ fep->rx_tstamp_latency = fep->rx_delay_100;
|
|
+ fep->tx_tstamp_latency = fep->tx_delay_100;
|
|
+ break;
|
|
+ case SPEED_1000:
|
|
+ fep->rx_tstamp_latency = fep->rx_delay_1000;
|
|
+ fep->tx_tstamp_latency = fep->tx_delay_1000;
|
|
+ break;
|
|
+ default:
|
|
+ fep->rx_tstamp_latency = 0;
|
|
+ fep->tx_tstamp_latency = 0;
|
|
+ }
|
|
+
|
|
+ /* if any of the above changed restart the FEC */
|
|
+ if (status_change) {
|
|
+ mutex_lock(&fep->fast_ndev_lock);
|
|
+ fec_restart(ndev);
|
|
+ mutex_unlock(&fep->fast_ndev_lock);
|
|
+ }
|
|
+ } else {
|
|
+ if (fep->link) {
|
|
+ mutex_lock(&fep->fast_ndev_lock);
|
|
+ fec_stop(ndev);
|
|
+ mutex_unlock(&fep->fast_ndev_lock);
|
|
+ fep->link = phy_dev->link;
|
|
+ status_change = 1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (status_change)
|
|
+ phy_print_status(phy_dev);
|
|
+}
|
|
+
|
|
+static int fec_enet_mdio_wait(struct fec_enet_private *fep)
|
|
+{
|
|
+ uint ievent;
|
|
+ int ret;
|
|
+
|
|
+ ret = readl_poll_timeout_atomic(fep->hwp + FEC_IEVENT, ievent,
|
|
+ ievent & FEC_ENET_MII, 2, 30000);
|
|
+
|
|
+ if (!ret)
|
|
+ writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int fec_enet_mdio_read_c22(struct mii_bus *bus, int mii_id, int regnum)
|
|
+{
|
|
+ struct fec_enet_private *fep = bus->priv;
|
|
+ struct device *dev = &fep->pdev->dev;
|
|
+ int ret = 0, frame_start, frame_addr, frame_op;
|
|
+
|
|
+ ret = pm_runtime_resume_and_get(dev);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ /* C22 read */
|
|
+ frame_op = FEC_MMFR_OP_READ;
|
|
+ frame_start = FEC_MMFR_ST;
|
|
+ frame_addr = regnum;
|
|
+
|
|
+ /* start a read op */
|
|
+ writel(frame_start | frame_op |
|
|
+ FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(frame_addr) |
|
|
+ FEC_MMFR_TA, fep->hwp + FEC_MII_DATA);
|
|
+
|
|
+ /* wait for end of transfer */
|
|
+ ret = fec_enet_mdio_wait(fep);
|
|
+ if (ret) {
|
|
+ netdev_err(fep->netdev, "MDIO read timeout\n");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ ret = FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA));
|
|
+
|
|
+out:
|
|
+ pm_runtime_mark_last_busy(dev);
|
|
+ pm_runtime_put_autosuspend(dev);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int fec_enet_mdio_read_c45(struct mii_bus *bus, int mii_id,
|
|
+ int devad, int regnum)
|
|
+{
|
|
+ struct fec_enet_private *fep = bus->priv;
|
|
+ struct device *dev = &fep->pdev->dev;
|
|
+ int ret = 0, frame_start, frame_op;
|
|
+
|
|
+ ret = pm_runtime_resume_and_get(dev);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ frame_start = FEC_MMFR_ST_C45;
|
|
+
|
|
+ /* write address */
|
|
+ writel(frame_start | FEC_MMFR_OP_ADDR_WRITE |
|
|
+ FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(devad) |
|
|
+ FEC_MMFR_TA | (regnum & 0xFFFF),
|
|
+ fep->hwp + FEC_MII_DATA);
|
|
+
|
|
+ /* wait for end of transfer */
|
|
+ ret = fec_enet_mdio_wait(fep);
|
|
+ if (ret) {
|
|
+ netdev_err(fep->netdev, "MDIO address write timeout\n");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ frame_op = FEC_MMFR_OP_READ_C45;
|
|
+
|
|
+ /* start a read op */
|
|
+ writel(frame_start | frame_op |
|
|
+ FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(devad) |
|
|
+ FEC_MMFR_TA, fep->hwp + FEC_MII_DATA);
|
|
+
|
|
+ /* wait for end of transfer */
|
|
+ ret = fec_enet_mdio_wait(fep);
|
|
+ if (ret) {
|
|
+ netdev_err(fep->netdev, "MDIO read timeout\n");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ ret = FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA));
|
|
+
|
|
+out:
|
|
+ pm_runtime_mark_last_busy(dev);
|
|
+ pm_runtime_put_autosuspend(dev);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int fec_enet_mdio_write_c22(struct mii_bus *bus, int mii_id, int regnum,
|
|
+ u16 value)
|
|
+{
|
|
+ struct fec_enet_private *fep = bus->priv;
|
|
+ struct device *dev = &fep->pdev->dev;
|
|
+ int ret, frame_start, frame_addr;
|
|
+
|
|
+ ret = pm_runtime_resume_and_get(dev);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ /* C22 write */
|
|
+ frame_start = FEC_MMFR_ST;
|
|
+ frame_addr = regnum;
|
|
+
|
|
+ /* start a write op */
|
|
+ writel(frame_start | FEC_MMFR_OP_WRITE |
|
|
+ FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(frame_addr) |
|
|
+ FEC_MMFR_TA | FEC_MMFR_DATA(value),
|
|
+ fep->hwp + FEC_MII_DATA);
|
|
+
|
|
+ /* wait for end of transfer */
|
|
+ ret = fec_enet_mdio_wait(fep);
|
|
+ if (ret)
|
|
+ netdev_err(fep->netdev, "MDIO write timeout\n");
|
|
+
|
|
+ pm_runtime_mark_last_busy(dev);
|
|
+ pm_runtime_put_autosuspend(dev);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int fec_enet_mdio_write_c45(struct mii_bus *bus, int mii_id,
|
|
+ int devad, int regnum, u16 value)
|
|
+{
|
|
+ struct fec_enet_private *fep = bus->priv;
|
|
+ struct device *dev = &fep->pdev->dev;
|
|
+ int ret, frame_start;
|
|
+
|
|
+ ret = pm_runtime_resume_and_get(dev);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ frame_start = FEC_MMFR_ST_C45;
|
|
+
|
|
+ /* write address */
|
|
+ writel(frame_start | FEC_MMFR_OP_ADDR_WRITE |
|
|
+ FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(devad) |
|
|
+ FEC_MMFR_TA | (regnum & 0xFFFF),
|
|
+ fep->hwp + FEC_MII_DATA);
|
|
+
|
|
+ /* wait for end of transfer */
|
|
+ ret = fec_enet_mdio_wait(fep);
|
|
+ if (ret) {
|
|
+ netdev_err(fep->netdev, "MDIO address write timeout\n");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ /* start a write op */
|
|
+ writel(frame_start | FEC_MMFR_OP_WRITE |
|
|
+ FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(devad) |
|
|
+ FEC_MMFR_TA | FEC_MMFR_DATA(value),
|
|
+ fep->hwp + FEC_MII_DATA);
|
|
+
|
|
+ /* wait for end of transfer */
|
|
+ ret = fec_enet_mdio_wait(fep);
|
|
+ if (ret)
|
|
+ netdev_err(fep->netdev, "MDIO write timeout\n");
|
|
+
|
|
+out:
|
|
+ pm_runtime_mark_last_busy(dev);
|
|
+ pm_runtime_put_autosuspend(dev);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void fec_enet_phy_reset_after_clk_enable(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ struct phy_device *phy_dev = ndev->phydev;
|
|
+
|
|
+ if (phy_dev) {
|
|
+ phy_reset_after_clk_enable(phy_dev);
|
|
+ } else if (fep->phy_node) {
|
|
+ /*
|
|
+ * If the PHY still is not bound to the MAC, but there is
|
|
+ * OF PHY node and a matching PHY device instance already,
|
|
+ * use the OF PHY node to obtain the PHY device instance,
|
|
+ * and then use that PHY device instance when triggering
|
|
+ * the PHY reset.
|
|
+ */
|
|
+ phy_dev = of_phy_find_device(fep->phy_node);
|
|
+ phy_reset_after_clk_enable(phy_dev);
|
|
+ put_device(&phy_dev->mdio.dev);
|
|
+ }
|
|
+}
|
|
+
|
|
+static int fec_enet_clk_enable(struct net_device *ndev, bool enable)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ int ret;
|
|
+
|
|
+ if (enable) {
|
|
+ ret = clk_prepare_enable(fep->clk_enet_out);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ if (fep->clk_ptp) {
|
|
+ mutex_lock(&fep->ptp_clk_mutex);
|
|
+ ret = clk_prepare_enable(fep->clk_ptp);
|
|
+ if (ret) {
|
|
+ mutex_unlock(&fep->ptp_clk_mutex);
|
|
+ goto failed_clk_ptp;
|
|
+ } else {
|
|
+ fep->ptp_clk_on = true;
|
|
+ }
|
|
+ mutex_unlock(&fep->ptp_clk_mutex);
|
|
+ }
|
|
+
|
|
+ ret = clk_prepare_enable(fep->clk_ref);
|
|
+ if (ret)
|
|
+ goto failed_clk_ref;
|
|
+
|
|
+ ret = clk_prepare_enable(fep->clk_2x_txclk);
|
|
+ if (ret)
|
|
+ goto failed_clk_2x_txclk;
|
|
+
|
|
+ fec_enet_phy_reset_after_clk_enable(ndev);
|
|
+ } else {
|
|
+ clk_disable_unprepare(fep->clk_enet_out);
|
|
+ if (fep->clk_ptp) {
|
|
+ mutex_lock(&fep->ptp_clk_mutex);
|
|
+ clk_disable_unprepare(fep->clk_ptp);
|
|
+ fep->ptp_clk_on = false;
|
|
+ mutex_unlock(&fep->ptp_clk_mutex);
|
|
+ }
|
|
+ clk_disable_unprepare(fep->clk_ref);
|
|
+ clk_disable_unprepare(fep->clk_2x_txclk);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+failed_clk_2x_txclk:
|
|
+ if (fep->clk_ref)
|
|
+ clk_disable_unprepare(fep->clk_ref);
|
|
+failed_clk_ref:
|
|
+ if (fep->clk_ptp) {
|
|
+ mutex_lock(&fep->ptp_clk_mutex);
|
|
+ clk_disable_unprepare(fep->clk_ptp);
|
|
+ fep->ptp_clk_on = false;
|
|
+ mutex_unlock(&fep->ptp_clk_mutex);
|
|
+ }
|
|
+failed_clk_ptp:
|
|
+ clk_disable_unprepare(fep->clk_enet_out);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int fec_enet_parse_rgmii_delay(struct fec_enet_private *fep,
|
|
+ struct device_node *np)
|
|
+{
|
|
+ u32 rgmii_tx_delay, rgmii_rx_delay;
|
|
+
|
|
+ /* For rgmii tx internal delay, valid values are 0ps and 2000ps */
|
|
+ if (!of_property_read_u32(np, "tx-internal-delay-ps", &rgmii_tx_delay)) {
|
|
+ if (rgmii_tx_delay != 0 && rgmii_tx_delay != 2000) {
|
|
+ dev_err(&fep->pdev->dev, "The only allowed RGMII TX delay values are: 0ps, 2000ps");
|
|
+ return -EINVAL;
|
|
+ } else if (rgmii_tx_delay == 2000) {
|
|
+ fep->rgmii_txc_dly = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* For rgmii rx internal delay, valid values are 0ps and 2000ps */
|
|
+ if (!of_property_read_u32(np, "rx-internal-delay-ps", &rgmii_rx_delay)) {
|
|
+ if (rgmii_rx_delay != 0 && rgmii_rx_delay != 2000) {
|
|
+ dev_err(&fep->pdev->dev, "The only allowed RGMII RX delay values are: 0ps, 2000ps");
|
|
+ return -EINVAL;
|
|
+ } else if (rgmii_rx_delay == 2000) {
|
|
+ fep->rgmii_rxc_dly = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int fec_restore_mii_bus(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ int ret;
|
|
+
|
|
+ ret = pm_runtime_get_sync(&fep->pdev->dev);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ writel(0xffc00000, fep->hwp + FEC_IEVENT);
|
|
+ writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
|
|
+ writel(FEC_ENET_MII, fep->hwp + FEC_IMASK);
|
|
+ writel(FEC_ENET_ETHEREN, fep->hwp + FEC_ECNTRL);
|
|
+
|
|
+ pm_runtime_mark_last_busy(&fep->pdev->dev);
|
|
+ pm_runtime_put_autosuspend(&fep->pdev->dev);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int fec_enet_mii_probe(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ struct phy_device *phy_dev = NULL;
|
|
+ char mdio_bus_id[MII_BUS_ID_SIZE];
|
|
+ char phy_name[MII_BUS_ID_SIZE + 3];
|
|
+ int phy_id;
|
|
+ int dev_id = fep->dev_id;
|
|
+
|
|
+ if (fep->phy_node) {
|
|
+ phy_dev = of_phy_connect(ndev, fep->phy_node,
|
|
+ &fec_enet_adjust_link, 0,
|
|
+ fep->phy_interface);
|
|
+ if (!phy_dev) {
|
|
+ netdev_err(ndev, "Unable to connect to phy\n");
|
|
+ return -ENODEV;
|
|
+ }
|
|
+ } else {
|
|
+ /* check for attached phy */
|
|
+ for (phy_id = 0; (phy_id < PHY_MAX_ADDR); phy_id++) {
|
|
+ if (!mdiobus_is_registered_device(fep->mii_bus, phy_id))
|
|
+ continue;
|
|
+ if (dev_id--)
|
|
+ continue;
|
|
+ strlcpy(mdio_bus_id, fep->mii_bus->id, MII_BUS_ID_SIZE);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (phy_id >= PHY_MAX_ADDR) {
|
|
+ netdev_info(ndev, "no PHY, assuming direct connection to switch\n");
|
|
+ strlcpy(mdio_bus_id, "fixed-0", MII_BUS_ID_SIZE);
|
|
+ phy_id = 0;
|
|
+ }
|
|
+
|
|
+ snprintf(phy_name, sizeof(phy_name),
|
|
+ PHY_ID_FMT, mdio_bus_id, phy_id);
|
|
+ phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link,
|
|
+ fep->phy_interface);
|
|
+ }
|
|
+
|
|
+ if (IS_ERR(phy_dev)) {
|
|
+ netdev_err(ndev, "could not attach to PHY\n");
|
|
+ return PTR_ERR(phy_dev);
|
|
+ }
|
|
+
|
|
+ /* mask with MAC supported features */
|
|
+ if (fep->quirks & FEC_QUIRK_HAS_GBIT) {
|
|
+ phy_set_max_speed(phy_dev, 1000);
|
|
+ phy_remove_link_mode(phy_dev,
|
|
+ ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
|
|
+#if !defined(CONFIG_M5272)
|
|
+ phy_support_sym_pause(phy_dev);
|
|
+#endif
|
|
+ }
|
|
+ else
|
|
+ phy_set_max_speed(phy_dev, 100);
|
|
+
|
|
+ fep->link = 0;
|
|
+ fep->full_duplex = 0;
|
|
+
|
|
+ phy_dev->mac_managed_pm = 1;
|
|
+
|
|
+ phy_attached_info(phy_dev);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int fec_enet_mii_init(struct platform_device *pdev)
|
|
+{
|
|
+ static struct mii_bus *fec0_mii_bus;
|
|
+ static bool *fec_mii_bus_share;
|
|
+ struct net_device *ndev = platform_get_drvdata(pdev);
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ bool suppress_preamble = false;
|
|
+ struct device_node *node;
|
|
+ int err = -ENXIO;
|
|
+ u32 mii_speed, holdtime;
|
|
+ u32 bus_freq;
|
|
+
|
|
+ /*
|
|
+ * The i.MX28 dual fec interfaces are not equal.
|
|
+ * Here are the differences:
|
|
+ *
|
|
+ * - fec0 supports MII & RMII modes while fec1 only supports RMII
|
|
+ * - fec0 acts as the 1588 time master while fec1 is slave
|
|
+ * - external phys can only be configured by fec0
|
|
+ *
|
|
+ * That is to say fec1 can not work independently. It only works
|
|
+ * when fec0 is working. The reason behind this design is that the
|
|
+ * second interface is added primarily for Switch mode.
|
|
+ *
|
|
+ * Because of the last point above, both phys are attached on fec0
|
|
+ * mdio interface in board design, and need to be configured by
|
|
+ * fec0 mii_bus.
|
|
+ */
|
|
+ if ((fep->quirks & FEC_QUIRK_SINGLE_MDIO) && fep->dev_id > 0) {
|
|
+ /* fec1 uses fec0 mii_bus */
|
|
+ if (mii_cnt && fec0_mii_bus) {
|
|
+ fep->mii_bus = fec0_mii_bus;
|
|
+ *fec_mii_bus_share = true;
|
|
+ mii_cnt++;
|
|
+ return 0;
|
|
+ }
|
|
+ return -ENOENT;
|
|
+ }
|
|
+
|
|
+ bus_freq = 2500000; /* 2.5MHz by default */
|
|
+ node = of_get_child_by_name(pdev->dev.of_node, "mdio");
|
|
+ if (node) {
|
|
+ of_property_read_u32(node, "clock-frequency", &bus_freq);
|
|
+ suppress_preamble = of_property_read_bool(node,
|
|
+ "suppress-preamble");
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Set MII speed (= clk_get_rate() / 2 * phy_speed)
|
|
+ *
|
|
+ * The formula for FEC MDC is 'ref_freq / (MII_SPEED x 2)' while
|
|
+ * for ENET-MAC is 'ref_freq / ((MII_SPEED + 1) x 2)'. The i.MX28
|
|
+ * Reference Manual has an error on this, and gets fixed on i.MX6Q
|
|
+ * document.
|
|
+ */
|
|
+ mii_speed = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), bus_freq * 2);
|
|
+ if (fep->quirks & FEC_QUIRK_ENET_MAC)
|
|
+ mii_speed--;
|
|
+ if (mii_speed > 63) {
|
|
+ dev_err(&pdev->dev,
|
|
+ "fec clock (%lu) too fast to get right mii speed\n",
|
|
+ clk_get_rate(fep->clk_ipg));
|
|
+ err = -EINVAL;
|
|
+ goto err_out;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * The i.MX28 and i.MX6 types have another filed in the MSCR (aka
|
|
+ * MII_SPEED) register that defines the MDIO output hold time. Earlier
|
|
+ * versions are RAZ there, so just ignore the difference and write the
|
|
+ * register always.
|
|
+ * The minimal hold time according to IEE802.3 (clause 22) is 10 ns.
|
|
+ * HOLDTIME + 1 is the number of clk cycles the fec is holding the
|
|
+ * output.
|
|
+ * The HOLDTIME bitfield takes values between 0 and 7 (inclusive).
|
|
+ * Given that ceil(clkrate / 5000000) <= 64, the calculation for
|
|
+ * holdtime cannot result in a value greater than 3.
|
|
+ */
|
|
+ holdtime = DIV_ROUND_UP(clk_get_rate(fep->clk_ipg), 100000000) - 1;
|
|
+
|
|
+ fep->phy_speed = mii_speed << 1 | holdtime << 8;
|
|
+
|
|
+ if (suppress_preamble)
|
|
+ fep->phy_speed |= BIT(7);
|
|
+
|
|
+ if (fep->quirks & FEC_QUIRK_CLEAR_SETUP_MII) {
|
|
+ /* Clear MMFR to avoid to generate MII event by writing MSCR.
|
|
+ * MII event generation condition:
|
|
+ * - writing MSCR:
|
|
+ * - mmfr[31:0]_not_zero & mscr[7:0]_is_zero &
|
|
+ * mscr_reg_data_in[7:0] != 0
|
|
+ * - writing MMFR:
|
|
+ * - mscr[7:0]_not_zero
|
|
+ */
|
|
+ writel(0, fep->hwp + FEC_MII_DATA);
|
|
+ }
|
|
+
|
|
+ writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
|
|
+
|
|
+ /* Clear any pending transaction complete indication */
|
|
+ writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
|
|
+
|
|
+ fep->mii_bus = mdiobus_alloc();
|
|
+ if (fep->mii_bus == NULL) {
|
|
+ err = -ENOMEM;
|
|
+ goto err_out;
|
|
+ }
|
|
+
|
|
+ fep->mii_bus->name = "fec_enet_mii_bus";
|
|
+ fep->mii_bus->read = fec_enet_mdio_read_c22;
|
|
+ fep->mii_bus->write = fec_enet_mdio_write_c22;
|
|
+ if (fep->quirks & FEC_QUIRK_HAS_MDIO_C45) {
|
|
+ fep->mii_bus->read_c45 = fec_enet_mdio_read_c45;
|
|
+ fep->mii_bus->write_c45 = fec_enet_mdio_write_c45;
|
|
+ }
|
|
+ snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
|
|
+ pdev->name, fep->dev_id + 1);
|
|
+ fep->mii_bus->priv = fep;
|
|
+ fep->mii_bus->parent = &pdev->dev;
|
|
+
|
|
+ err = of_mdiobus_register(fep->mii_bus, node);
|
|
+ if (err)
|
|
+ goto err_out_free_mdiobus;
|
|
+ of_node_put(node);
|
|
+
|
|
+ mii_cnt++;
|
|
+
|
|
+ /* save fec0 mii_bus */
|
|
+ if (fep->quirks & FEC_QUIRK_SINGLE_MDIO) {
|
|
+ fec0_mii_bus = fep->mii_bus;
|
|
+ fec_mii_bus_share = &fep->mii_bus_share;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err_out_free_mdiobus:
|
|
+ mdiobus_free(fep->mii_bus);
|
|
+err_out:
|
|
+ of_node_put(node);
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static void fec_enet_mii_remove(struct fec_enet_private *fep)
|
|
+{
|
|
+ if (--mii_cnt == 0) {
|
|
+ mdiobus_unregister(fep->mii_bus);
|
|
+ mdiobus_free(fep->mii_bus);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void fec_enet_get_drvinfo(struct net_device *ndev,
|
|
+ struct ethtool_drvinfo *info)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+
|
|
+ strlcpy(info->driver, fep->pdev->dev.driver->name,
|
|
+ sizeof(info->driver));
|
|
+ strlcpy(info->bus_info, dev_name(&ndev->dev), sizeof(info->bus_info));
|
|
+}
|
|
+
|
|
+static int fec_enet_get_regs_len(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ struct resource *r;
|
|
+ int s = 0;
|
|
+
|
|
+ r = platform_get_resource(fep->pdev, IORESOURCE_MEM, 0);
|
|
+ if (r)
|
|
+ s = resource_size(r);
|
|
+
|
|
+ return s;
|
|
+}
|
|
+
|
|
+/* List of registers that can be safety be read to dump them with ethtool */
|
|
+#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
|
|
+ defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) || \
|
|
+ defined(CONFIG_ARM64) || defined(CONFIG_COMPILE_TEST)
|
|
+static __u32 fec_enet_register_version = 2;
|
|
+static u32 fec_enet_register_offset[] = {
|
|
+ FEC_IEVENT, FEC_IMASK, FEC_R_DES_ACTIVE_0, FEC_X_DES_ACTIVE_0,
|
|
+ FEC_ECNTRL, FEC_MII_DATA, FEC_MII_SPEED, FEC_MIB_CTRLSTAT, FEC_R_CNTRL,
|
|
+ FEC_X_CNTRL, FEC_ADDR_LOW, FEC_ADDR_HIGH, FEC_OPD, FEC_TXIC0, FEC_TXIC1,
|
|
+ FEC_TXIC2, FEC_RXIC0, FEC_RXIC1, FEC_RXIC2, FEC_HASH_TABLE_HIGH,
|
|
+ FEC_HASH_TABLE_LOW, FEC_GRP_HASH_TABLE_HIGH, FEC_GRP_HASH_TABLE_LOW,
|
|
+ FEC_X_WMRK, FEC_R_BOUND, FEC_R_FSTART, FEC_R_DES_START_1,
|
|
+ FEC_X_DES_START_1, FEC_R_BUFF_SIZE_1, FEC_R_DES_START_2,
|
|
+ FEC_X_DES_START_2, FEC_R_BUFF_SIZE_2, FEC_R_DES_START_0,
|
|
+ FEC_X_DES_START_0, FEC_R_BUFF_SIZE_0, FEC_R_FIFO_RSFL, FEC_R_FIFO_RSEM,
|
|
+ FEC_R_FIFO_RAEM, FEC_R_FIFO_RAFL, FEC_RACC, FEC_RCMR_1, FEC_RCMR_2,
|
|
+ FEC_DMA_CFG_1, FEC_DMA_CFG_2, FEC_R_DES_ACTIVE_1, FEC_X_DES_ACTIVE_1,
|
|
+ FEC_R_DES_ACTIVE_2, FEC_X_DES_ACTIVE_2, FEC_QOS_SCHEME,
|
|
+ RMON_T_DROP, RMON_T_PACKETS, RMON_T_BC_PKT, RMON_T_MC_PKT,
|
|
+ RMON_T_CRC_ALIGN, RMON_T_UNDERSIZE, RMON_T_OVERSIZE, RMON_T_FRAG,
|
|
+ RMON_T_JAB, RMON_T_COL, RMON_T_P64, RMON_T_P65TO127, RMON_T_P128TO255,
|
|
+ RMON_T_P256TO511, RMON_T_P512TO1023, RMON_T_P1024TO2047,
|
|
+ RMON_T_P_GTE2048, RMON_T_OCTETS,
|
|
+ IEEE_T_DROP, IEEE_T_FRAME_OK, IEEE_T_1COL, IEEE_T_MCOL, IEEE_T_DEF,
|
|
+ IEEE_T_LCOL, IEEE_T_EXCOL, IEEE_T_MACERR, IEEE_T_CSERR, IEEE_T_SQE,
|
|
+ IEEE_T_FDXFC, IEEE_T_OCTETS_OK,
|
|
+ RMON_R_PACKETS, RMON_R_BC_PKT, RMON_R_MC_PKT, RMON_R_CRC_ALIGN,
|
|
+ RMON_R_UNDERSIZE, RMON_R_OVERSIZE, RMON_R_FRAG, RMON_R_JAB,
|
|
+ RMON_R_RESVD_O, RMON_R_P64, RMON_R_P65TO127, RMON_R_P128TO255,
|
|
+ RMON_R_P256TO511, RMON_R_P512TO1023, RMON_R_P1024TO2047,
|
|
+ RMON_R_P_GTE2048, RMON_R_OCTETS,
|
|
+ IEEE_R_DROP, IEEE_R_FRAME_OK, IEEE_R_CRC, IEEE_R_ALIGN, IEEE_R_MACERR,
|
|
+ IEEE_R_FDXFC, IEEE_R_OCTETS_OK
|
|
+};
|
|
+#else
|
|
+static __u32 fec_enet_register_version = 1;
|
|
+static u32 fec_enet_register_offset[] = {
|
|
+ FEC_ECNTRL, FEC_IEVENT, FEC_IMASK, FEC_IVEC, FEC_R_DES_ACTIVE_0,
|
|
+ FEC_R_DES_ACTIVE_1, FEC_R_DES_ACTIVE_2, FEC_X_DES_ACTIVE_0,
|
|
+ FEC_X_DES_ACTIVE_1, FEC_X_DES_ACTIVE_2, FEC_MII_DATA, FEC_MII_SPEED,
|
|
+ FEC_R_BOUND, FEC_R_FSTART, FEC_X_WMRK, FEC_X_FSTART, FEC_R_CNTRL,
|
|
+ FEC_MAX_FRM_LEN, FEC_X_CNTRL, FEC_ADDR_LOW, FEC_ADDR_HIGH,
|
|
+ FEC_GRP_HASH_TABLE_HIGH, FEC_GRP_HASH_TABLE_LOW, FEC_R_DES_START_0,
|
|
+ FEC_R_DES_START_1, FEC_R_DES_START_2, FEC_X_DES_START_0,
|
|
+ FEC_X_DES_START_1, FEC_X_DES_START_2, FEC_R_BUFF_SIZE_0,
|
|
+ FEC_R_BUFF_SIZE_1, FEC_R_BUFF_SIZE_2
|
|
+};
|
|
+#endif
|
|
+
|
|
+static void fec_enet_get_regs(struct net_device *ndev,
|
|
+ struct ethtool_regs *regs, void *regbuf)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ u32 __iomem *theregs = (u32 __iomem *)fep->hwp;
|
|
+ struct device *dev = &fep->pdev->dev;
|
|
+ u32 *buf = (u32 *)regbuf;
|
|
+ u32 i, off;
|
|
+ int ret;
|
|
+
|
|
+ ret = pm_runtime_resume_and_get(dev);
|
|
+ if (ret < 0)
|
|
+ return;
|
|
+
|
|
+ regs->version = fec_enet_register_version;
|
|
+
|
|
+ memset(buf, 0, regs->len);
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(fec_enet_register_offset); i++) {
|
|
+ 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]);
|
|
+ }
|
|
+
|
|
+ pm_runtime_mark_last_busy(dev);
|
|
+ pm_runtime_put_autosuspend(dev);
|
|
+}
|
|
+
|
|
+
|
|
+#if !defined(CONFIG_M5272)
|
|
+
|
|
+static void fec_enet_get_pauseparam(struct net_device *ndev,
|
|
+ struct ethtool_pauseparam *pause)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+
|
|
+ pause->autoneg = (fep->pause_flag & FEC_PAUSE_FLAG_AUTONEG) != 0;
|
|
+ pause->tx_pause = (fep->pause_flag & FEC_PAUSE_FLAG_ENABLE) != 0;
|
|
+ pause->rx_pause = pause->tx_pause;
|
|
+}
|
|
+
|
|
+static int fec_enet_set_pauseparam(struct net_device *ndev,
|
|
+ struct ethtool_pauseparam *pause)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+
|
|
+ if (!ndev->phydev)
|
|
+ return -ENODEV;
|
|
+
|
|
+ if (pause->tx_pause != pause->rx_pause) {
|
|
+ netdev_info(ndev,
|
|
+ "hardware only support enable/disable both tx and rx");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ fep->pause_flag = 0;
|
|
+
|
|
+ /* tx pause must be same as rx pause */
|
|
+ fep->pause_flag |= pause->rx_pause ? FEC_PAUSE_FLAG_ENABLE : 0;
|
|
+ fep->pause_flag |= pause->autoneg ? FEC_PAUSE_FLAG_AUTONEG : 0;
|
|
+
|
|
+ phy_set_sym_pause(ndev->phydev, pause->rx_pause, pause->tx_pause,
|
|
+ pause->autoneg);
|
|
+
|
|
+ if (pause->autoneg) {
|
|
+ if (netif_running(ndev))
|
|
+ fec_stop(ndev);
|
|
+ phy_start_aneg(ndev->phydev);
|
|
+ }
|
|
+ if (netif_running(ndev)) {
|
|
+ mutex_lock(&fep->fast_ndev_lock);
|
|
+
|
|
+ netif_tx_lock_bh(ndev);
|
|
+ //netif_tx_wake_all_queues(ndev);
|
|
+
|
|
+ mutex_unlock(&fep->fast_ndev_lock);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct fec_stat {
|
|
+ char name[ETH_GSTRING_LEN];
|
|
+ u16 offset;
|
|
+} fec_stats[] = {
|
|
+ /* RMON TX */
|
|
+ { "tx_dropped", RMON_T_DROP },
|
|
+ { "tx_packets", RMON_T_PACKETS },
|
|
+ { "tx_broadcast", RMON_T_BC_PKT },
|
|
+ { "tx_multicast", RMON_T_MC_PKT },
|
|
+ { "tx_crc_errors", RMON_T_CRC_ALIGN },
|
|
+ { "tx_undersize", RMON_T_UNDERSIZE },
|
|
+ { "tx_oversize", RMON_T_OVERSIZE },
|
|
+ { "tx_fragment", RMON_T_FRAG },
|
|
+ { "tx_jabber", RMON_T_JAB },
|
|
+ { "tx_collision", RMON_T_COL },
|
|
+ { "tx_64byte", RMON_T_P64 },
|
|
+ { "tx_65to127byte", RMON_T_P65TO127 },
|
|
+ { "tx_128to255byte", RMON_T_P128TO255 },
|
|
+ { "tx_256to511byte", RMON_T_P256TO511 },
|
|
+ { "tx_512to1023byte", RMON_T_P512TO1023 },
|
|
+ { "tx_1024to2047byte", RMON_T_P1024TO2047 },
|
|
+ { "tx_GTE2048byte", RMON_T_P_GTE2048 },
|
|
+ { "tx_octets", RMON_T_OCTETS },
|
|
+
|
|
+ /* IEEE TX */
|
|
+ { "IEEE_tx_drop", IEEE_T_DROP },
|
|
+ { "IEEE_tx_frame_ok", IEEE_T_FRAME_OK },
|
|
+ { "IEEE_tx_1col", IEEE_T_1COL },
|
|
+ { "IEEE_tx_mcol", IEEE_T_MCOL },
|
|
+ { "IEEE_tx_def", IEEE_T_DEF },
|
|
+ { "IEEE_tx_lcol", IEEE_T_LCOL },
|
|
+ { "IEEE_tx_excol", IEEE_T_EXCOL },
|
|
+ { "IEEE_tx_macerr", IEEE_T_MACERR },
|
|
+ { "IEEE_tx_cserr", IEEE_T_CSERR },
|
|
+ { "IEEE_tx_sqe", IEEE_T_SQE },
|
|
+ { "IEEE_tx_fdxfc", IEEE_T_FDXFC },
|
|
+ { "IEEE_tx_octets_ok", IEEE_T_OCTETS_OK },
|
|
+
|
|
+ /* RMON RX */
|
|
+ { "rx_packets", RMON_R_PACKETS },
|
|
+ { "rx_broadcast", RMON_R_BC_PKT },
|
|
+ { "rx_multicast", RMON_R_MC_PKT },
|
|
+ { "rx_crc_errors", RMON_R_CRC_ALIGN },
|
|
+ { "rx_undersize", RMON_R_UNDERSIZE },
|
|
+ { "rx_oversize", RMON_R_OVERSIZE },
|
|
+ { "rx_fragment", RMON_R_FRAG },
|
|
+ { "rx_jabber", RMON_R_JAB },
|
|
+ { "rx_64byte", RMON_R_P64 },
|
|
+ { "rx_65to127byte", RMON_R_P65TO127 },
|
|
+ { "rx_128to255byte", RMON_R_P128TO255 },
|
|
+ { "rx_256to511byte", RMON_R_P256TO511 },
|
|
+ { "rx_512to1023byte", RMON_R_P512TO1023 },
|
|
+ { "rx_1024to2047byte", RMON_R_P1024TO2047 },
|
|
+ { "rx_GTE2048byte", RMON_R_P_GTE2048 },
|
|
+ { "rx_octets", RMON_R_OCTETS },
|
|
+
|
|
+ /* IEEE RX */
|
|
+ { "IEEE_rx_drop", IEEE_R_DROP },
|
|
+ { "IEEE_rx_frame_ok", IEEE_R_FRAME_OK },
|
|
+ { "IEEE_rx_crc", IEEE_R_CRC },
|
|
+ { "IEEE_rx_align", IEEE_R_ALIGN },
|
|
+ { "IEEE_rx_macerr", IEEE_R_MACERR },
|
|
+ { "IEEE_rx_fdxfc", IEEE_R_FDXFC },
|
|
+ { "IEEE_rx_octets_ok", IEEE_R_OCTETS_OK },
|
|
+};
|
|
+
|
|
+#define FEC_STATS_SIZE (ARRAY_SIZE(fec_stats) * sizeof(u64))
|
|
+
|
|
+static void fec_enet_update_ethtool_stats(struct net_device *dev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(dev);
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(fec_stats); i++)
|
|
+ fep->ethtool_stats[i] = readl(fep->hwp + fec_stats[i].offset);
|
|
+}
|
|
+
|
|
+static void fec_enet_get_ethtool_stats(struct net_device *dev,
|
|
+ struct ethtool_stats *stats, u64 *data)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(dev);
|
|
+
|
|
+ if (netif_running(dev))
|
|
+ fec_enet_update_ethtool_stats(dev);
|
|
+
|
|
+ memcpy(data, fep->ethtool_stats, FEC_STATS_SIZE);
|
|
+}
|
|
+
|
|
+static void fec_enet_get_strings(struct net_device *netdev,
|
|
+ u32 stringset, u8 *data)
|
|
+{
|
|
+ int i;
|
|
+ switch (stringset) {
|
|
+ case ETH_SS_STATS:
|
|
+ for (i = 0; i < ARRAY_SIZE(fec_stats); i++)
|
|
+ memcpy(data + i * ETH_GSTRING_LEN,
|
|
+ fec_stats[i].name, ETH_GSTRING_LEN);
|
|
+ break;
|
|
+ case ETH_SS_TEST:
|
|
+ net_selftest_get_strings(data);
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int fec_enet_get_sset_count(struct net_device *dev, int sset)
|
|
+{
|
|
+ switch (sset) {
|
|
+ case ETH_SS_STATS:
|
|
+ return ARRAY_SIZE(fec_stats);
|
|
+ case ETH_SS_TEST:
|
|
+ return net_selftest_get_count();
|
|
+ default:
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void fec_enet_clear_ethtool_stats(struct net_device *dev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(dev);
|
|
+ int i;
|
|
+
|
|
+ /* Disable MIB statistics counters */
|
|
+ writel(FEC_MIB_CTRLSTAT_DISABLE, fep->hwp + FEC_MIB_CTRLSTAT);
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(fec_stats); i++)
|
|
+ writel(0, fep->hwp + fec_stats[i].offset);
|
|
+
|
|
+ /* Don't disable MIB statistics counters */
|
|
+ writel(0, fep->hwp + FEC_MIB_CTRLSTAT);
|
|
+}
|
|
+
|
|
+#else /* !defined(CONFIG_M5272) */
|
|
+#define FEC_STATS_SIZE 0
|
|
+static inline void fec_enet_update_ethtool_stats(struct net_device *dev)
|
|
+{
|
|
+}
|
|
+
|
|
+static inline void fec_enet_clear_ethtool_stats(struct net_device *dev)
|
|
+{
|
|
+}
|
|
+#endif /* !defined(CONFIG_M5272) */
|
|
+
|
|
+/* ITR clock source is enet system clock (clk_ahb).
|
|
+ * TCTT unit is cycle_ns * 64 cycle
|
|
+ * So, the ICTT value = X us / (cycle_ns * 64)
|
|
+ */
|
|
+static int fec_enet_us_to_itr_clock(struct net_device *ndev, int us)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+
|
|
+ return us * (fep->itr_clk_rate / 64000) / 1000;
|
|
+}
|
|
+
|
|
+
|
|
+/* LPI Sleep Ts count base on tx clk (clk_ref).
|
|
+ * The lpi sleep cnt value = X us / (cycle_ns).
|
|
+ */
|
|
+static int fec_enet_us_to_tx_cycle(struct net_device *ndev, int us)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+
|
|
+ return us * (fep->clk_ref_rate / 1000) / 1000;
|
|
+}
|
|
+
|
|
+static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ struct ethtool_eee *p = &fep->eee;
|
|
+ unsigned int sleep_cycle, wake_cycle;
|
|
+ int ret = 0;
|
|
+
|
|
+ if (enable) {
|
|
+ ret = phy_init_eee(ndev->phydev, 0);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ sleep_cycle = fec_enet_us_to_tx_cycle(ndev, p->tx_lpi_timer);
|
|
+ wake_cycle = sleep_cycle;
|
|
+ } else {
|
|
+ sleep_cycle = 0;
|
|
+ wake_cycle = 0;
|
|
+ }
|
|
+
|
|
+ p->tx_lpi_enabled = enable;
|
|
+ p->eee_enabled = enable;
|
|
+ p->eee_active = enable;
|
|
+
|
|
+ writel(sleep_cycle, fep->hwp + FEC_LPI_SLEEP);
|
|
+ writel(wake_cycle, fep->hwp + FEC_LPI_WAKE);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+fec_enet_get_eee(struct net_device *ndev, struct ethtool_eee *edata)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ struct ethtool_eee *p = &fep->eee;
|
|
+
|
|
+ if (!(fep->quirks & FEC_QUIRK_HAS_EEE))
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ if (!netif_running(ndev))
|
|
+ return -ENETDOWN;
|
|
+
|
|
+ edata->eee_enabled = p->eee_enabled;
|
|
+ edata->eee_active = p->eee_active;
|
|
+ edata->tx_lpi_timer = p->tx_lpi_timer;
|
|
+ edata->tx_lpi_enabled = p->tx_lpi_enabled;
|
|
+
|
|
+ return phy_ethtool_get_eee(ndev->phydev, edata);
|
|
+}
|
|
+
|
|
+static int
|
|
+fec_enet_set_eee(struct net_device *ndev, struct ethtool_eee *edata)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ struct ethtool_eee *p = &fep->eee;
|
|
+ int ret = 0;
|
|
+
|
|
+ if (!(fep->quirks & FEC_QUIRK_HAS_EEE))
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ if (!netif_running(ndev))
|
|
+ return -ENETDOWN;
|
|
+
|
|
+ p->tx_lpi_timer = edata->tx_lpi_timer;
|
|
+
|
|
+ if (!edata->eee_enabled || !edata->tx_lpi_enabled ||
|
|
+ !edata->tx_lpi_timer)
|
|
+ ret = fec_enet_eee_mode_set(ndev, false);
|
|
+ else
|
|
+ ret = fec_enet_eee_mode_set(ndev, true);
|
|
+
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ return phy_ethtool_set_eee(ndev->phydev, edata);
|
|
+}
|
|
+
|
|
+static const struct ethtool_ops fec_enet_ethtool_ops = {
|
|
+ .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
|
|
+ ETHTOOL_COALESCE_MAX_FRAMES,
|
|
+ .get_drvinfo = fec_enet_get_drvinfo,
|
|
+ .get_regs_len = fec_enet_get_regs_len,
|
|
+ .get_regs = fec_enet_get_regs,
|
|
+ .nway_reset = phy_ethtool_nway_reset,
|
|
+ .get_link = ethtool_op_get_link,
|
|
+#ifndef CONFIG_M5272
|
|
+ .get_strings = fec_enet_get_strings,
|
|
+ .get_ethtool_stats = fec_enet_get_ethtool_stats,
|
|
+ .get_sset_count = fec_enet_get_sset_count,
|
|
+#endif
|
|
+ .get_eee = fec_enet_get_eee,
|
|
+ .set_eee = fec_enet_set_eee,
|
|
+ .get_link_ksettings = phy_ethtool_get_link_ksettings,
|
|
+ .set_link_ksettings = phy_ethtool_set_link_ksettings,
|
|
+ .self_test = net_selftest,
|
|
+};
|
|
+
|
|
+static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ struct phy_device *phydev = ndev->phydev;
|
|
+
|
|
+ if (!netif_running(ndev))
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (!phydev)
|
|
+ return -ENODEV;
|
|
+
|
|
+ return phy_mii_ioctl(phydev, rq, cmd);
|
|
+}
|
|
+
|
|
+static void fec_enet_free_buffers(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ unsigned int i;
|
|
+ struct sk_buff *skb;
|
|
+ struct bufdesc *bdp;
|
|
+ struct fec_enet_priv_tx_q *txq = fep->tx_queue;
|
|
+ struct fec_enet_priv_rx_q *rxq = fep->rx_queue;
|
|
+ unsigned int q;
|
|
+
|
|
+ bdp = rxq->bd.base;
|
|
+ for (i = 0; i < rxq->bd.ring_size; i++) {
|
|
+ skb = rxq->rx_skbuff[i];
|
|
+ rxq->rx_skbuff[i] = NULL;
|
|
+ if (skb) {
|
|
+ dma_unmap_single(&fep->pdev->dev,
|
|
+ fec32_to_cpu(bdp->cbd_bufaddr),
|
|
+ FEC_ENET_RX_FRSIZE - fep->rx_align,
|
|
+ DMA_FROM_DEVICE);
|
|
+ dev_kfree_skb(skb);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < txq->bd.ring_size; i++) {
|
|
+ skb = txq->tx_skbuff[i];
|
|
+ txq->tx_skbuff[i] = NULL;
|
|
+ if (skb) {
|
|
+ dma_unmap_single(&fep->pdev->dev,
|
|
+ fec32_to_cpu(bdp->cbd_bufaddr),
|
|
+ FEC_ENET_RX_FRSIZE - fep->rx_align,
|
|
+ DMA_FROM_DEVICE);
|
|
+ dev_kfree_skb(skb);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static void fec_enet_free_queue(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+
|
|
+ if (fep->rx_queue)
|
|
+ kfree(fep->rx_queue);
|
|
+ if (fep->tx_queue)
|
|
+ kfree(fep->tx_queue);
|
|
+}
|
|
+
|
|
+static int fec_enet_alloc_queue(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ int ret = 0;
|
|
+
|
|
+ fep->tx_queue = kzalloc(sizeof(*fep->tx_queue), GFP_KERNEL);
|
|
+ if (!fep->tx_queue) {
|
|
+ ret = -ENOMEM;
|
|
+ goto alloc_failed;
|
|
+ }
|
|
+
|
|
+ fep->tx_queue->bd.ring_size = FEC_TX_RING_SIZE;
|
|
+ fep->total_tx_ring_size += fep->tx_queue->bd.ring_size;
|
|
+
|
|
+
|
|
+ fep->rx_queue = kzalloc(sizeof(*fep->rx_queue), GFP_KERNEL);
|
|
+ if (!fep->rx_queue) {
|
|
+ ret = -ENOMEM;
|
|
+ goto alloc_failed;
|
|
+ }
|
|
+
|
|
+ fep->rx_queue->bd.ring_size = FEC_RX_RING_SIZE;
|
|
+ fep->total_rx_ring_size += fep->rx_queue->bd.ring_size;
|
|
+ return ret;
|
|
+
|
|
+alloc_failed:
|
|
+ fec_enet_free_queue(ndev);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int fec_enet_alloc_buffers(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ unsigned int i;
|
|
+ struct sk_buff *skb;
|
|
+ struct bufdesc *bdp;
|
|
+ int off;
|
|
+ struct fec_enet_priv_rx_q *rxq;
|
|
+ struct fec_enet_priv_tx_q *txq;
|
|
+
|
|
+ rxq = fep->rx_queue;
|
|
+ txq = fep->tx_queue;
|
|
+ bdp = rxq->bd.base;
|
|
+ for (i = 0; i < rxq->bd.ring_size; i++) {
|
|
+ skb = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE);
|
|
+ if (!skb)
|
|
+ goto err_alloc;
|
|
+
|
|
+ if ((off = ((unsigned long)skb->data) & fep->rx_align) > 0)
|
|
+ skb_reserve(skb, fep->rx_align + 1 - off);
|
|
+
|
|
+ bdp->cbd_bufaddr = cpu_to_fec32(dma_map_single(&fep->pdev->dev, skb->data, FEC_ENET_RX_FRSIZE - fep->rx_align, DMA_FROM_DEVICE));
|
|
+ if (dma_mapping_error(&fep->pdev->dev, fec32_to_cpu(bdp->cbd_bufaddr))) {
|
|
+ dev_kfree_skb(skb);
|
|
+ goto err_alloc;
|
|
+ }
|
|
+
|
|
+ rxq->rx_skbuff[i] = skb;
|
|
+ bdp->cbd_sc = cpu_to_fec16(BD_ENET_RX_EMPTY);
|
|
+
|
|
+ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd);
|
|
+ }
|
|
+
|
|
+ /* Set the last buffer to wrap. */
|
|
+ bdp = fec_enet_get_prevdesc(bdp, &rxq->bd);
|
|
+ bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP);
|
|
+
|
|
+ bdp = txq->bd.base;
|
|
+ txq->bd.cur = bdp;
|
|
+
|
|
+ for (i = 0; i < txq->bd.ring_size; i++) {
|
|
+ bdp->cbd_sc = cpu_to_fec16(0);
|
|
+ skb = netdev_alloc_skb(ndev, FEC_ENET_TX_FRSIZE);
|
|
+ if (!skb)
|
|
+ goto err_alloc;
|
|
+
|
|
+ if ((off = ((unsigned long)skb->data) & fep->tx_align) > 0)
|
|
+ skb_reserve(skb, fep->tx_align + 1 - off);
|
|
+
|
|
+ bdp->cbd_bufaddr = cpu_to_fec32(dma_map_single(&fep->pdev->dev, skb->data, FEC_ENET_TX_FRSIZE - fep->tx_align, DMA_TO_DEVICE));
|
|
+ if (dma_mapping_error(&fep->pdev->dev, fec32_to_cpu(bdp->cbd_bufaddr))) {
|
|
+ goto err_alloc;
|
|
+ }
|
|
+ txq->tx_skbuff[i] = skb;
|
|
+ bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
|
|
+ }
|
|
+
|
|
+ /* Set the last buffer to wrap. */
|
|
+ bdp = fec_enet_get_prevdesc(bdp, &txq->bd);
|
|
+ bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP);
|
|
+ txq->dirty_tx = bdp;
|
|
+ return 0;
|
|
+
|
|
+ err_alloc:
|
|
+ fec_enet_free_buffers(ndev);
|
|
+ return -ENOMEM;
|
|
+}
|
|
+
|
|
+static int
|
|
+fec_enet_open(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ int ret;
|
|
+ bool reset_again;
|
|
+ int i;
|
|
+
|
|
+ ret = pm_runtime_resume_and_get(&fep->pdev->dev);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ pinctrl_pm_select_default_state(&fep->pdev->dev);
|
|
+
|
|
+ /* During the first fec_enet_open call the PHY isn't probed at this
|
|
+ * point. Therefore the phy_reset_after_clk_enable() call within
|
|
+ * fec_enet_clk_enable() fails. As we need this reset in order to be
|
|
+ * sure the PHY is working correctly we check if we need to reset again
|
|
+ * later when the PHY is probed
|
|
+ */
|
|
+ if (ndev->phydev && ndev->phydev->drv)
|
|
+ reset_again = false;
|
|
+ else
|
|
+ reset_again = true;
|
|
+
|
|
+ /* I should reset the ring buffers here, but I don't yet know
|
|
+ * a simple way to do that.
|
|
+ */
|
|
+
|
|
+ ret = fec_enet_alloc_buffers(ndev);
|
|
+ if (ret)
|
|
+ goto err_enet_alloc;
|
|
+
|
|
+ /* Init MAC prior to mii bus probe */
|
|
+ fec_restart(ndev);
|
|
+
|
|
+ /* Call phy_reset_after_clk_enable() again if it failed during
|
|
+ * phy_reset_after_clk_enable() before because the PHY wasn't probed.
|
|
+ */
|
|
+ if (reset_again)
|
|
+ fec_enet_phy_reset_after_clk_enable(ndev);
|
|
+
|
|
+ /* Probe and connect to PHY when open the interface */
|
|
+ ret = fec_enet_mii_probe(ndev);
|
|
+ if (ret)
|
|
+ goto err_enet_mii_probe;
|
|
+
|
|
+ if (fep->quirks & FEC_QUIRK_ERR006687)
|
|
+ imx6q_cpuidle_fec_irqs_used();
|
|
+ if (fep->quirks & FEC_QUIRK_HAS_PMQOS)
|
|
+ cpu_latency_qos_add_request(&fep->pm_qos_req, 0);
|
|
+
|
|
+ phy_start(ndev->phydev);
|
|
+ mutex_unlock(&fep->fast_ndev_lock);
|
|
+ return 0;
|
|
+
|
|
+err_enet_mii_probe:
|
|
+ fec_enet_free_buffers(ndev);
|
|
+err_enet_alloc:
|
|
+ pm_runtime_mark_last_busy(&fep->pdev->dev);
|
|
+ pm_runtime_put_autosuspend(&fep->pdev->dev);
|
|
+ if (!fep->mii_bus_share)
|
|
+ pinctrl_pm_select_sleep_state(&fep->pdev->dev);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+fec_enet_close(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+
|
|
+ phy_stop(ndev->phydev);
|
|
+
|
|
+ if (netif_device_present(ndev)) {
|
|
+ netif_tx_disable(ndev);
|
|
+ fec_stop(ndev);
|
|
+ }
|
|
+
|
|
+ phy_disconnect(ndev->phydev);
|
|
+ ndev->phydev = NULL;
|
|
+
|
|
+ if (fep->quirks & FEC_QUIRK_ERR006687)
|
|
+ imx6q_cpuidle_fec_irqs_unused();
|
|
+
|
|
+ fec_enet_update_ethtool_stats(ndev);
|
|
+
|
|
+ if (!fep->mii_bus_share)
|
|
+ pinctrl_pm_select_sleep_state(&fep->pdev->dev);
|
|
+ pm_runtime_mark_last_busy(&fep->pdev->dev);
|
|
+ pm_runtime_put_autosuspend(&fep->pdev->dev);
|
|
+
|
|
+ fec_enet_free_buffers(ndev);
|
|
+ mutex_lock(&fep->fast_ndev_lock);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Set or clear the multicast filter for this adaptor.
|
|
+ * Skeleton taken from sunlance driver.
|
|
+ * The CPM Ethernet implementation allows Multicast as well as individual
|
|
+ * MAC address filtering. Some of the drivers check to make sure it is
|
|
+ * a group multicast address, and discard those that are not. I guess I
|
|
+ * will do the same for now, but just remove the test if you want
|
|
+ * individual filtering as well (do the upper net layers want or support
|
|
+ * this kind of feature?).
|
|
+ */
|
|
+
|
|
+#define FEC_HASH_BITS 6 /* #bits in hash */
|
|
+
|
|
+static void set_multicast_list(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ struct netdev_hw_addr *ha;
|
|
+ unsigned int crc, tmp;
|
|
+ unsigned char hash;
|
|
+ unsigned int hash_high = 0, hash_low = 0;
|
|
+
|
|
+ if (ndev->flags & IFF_PROMISC) {
|
|
+ tmp = readl(fep->hwp + FEC_R_CNTRL);
|
|
+ tmp |= 0x8;
|
|
+ writel(tmp, fep->hwp + FEC_R_CNTRL);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ tmp = readl(fep->hwp + FEC_R_CNTRL);
|
|
+ tmp &= ~0x8;
|
|
+ writel(tmp, fep->hwp + FEC_R_CNTRL);
|
|
+
|
|
+ if (ndev->flags & IFF_ALLMULTI) {
|
|
+ /* Catch all multicast addresses, so set the
|
|
+ * filter to all 1's
|
|
+ */
|
|
+ writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
|
|
+ writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
|
|
+
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* Add the addresses in hash register */
|
|
+ netdev_for_each_mc_addr(ha, ndev) {
|
|
+ /* calculate crc32 value of mac address */
|
|
+ crc = ether_crc_le(ndev->addr_len, ha->addr);
|
|
+
|
|
+ /* only upper 6 bits (FEC_HASH_BITS) are used
|
|
+ * which point to specific bit in the hash registers
|
|
+ */
|
|
+ hash = (crc >> (32 - FEC_HASH_BITS)) & 0x3f;
|
|
+
|
|
+ if (hash > 31)
|
|
+ hash_high |= 1 << (hash - 32);
|
|
+ else
|
|
+ hash_low |= 1 << hash;
|
|
+ }
|
|
+
|
|
+ writel(hash_high, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
|
|
+ writel(hash_low, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
|
|
+}
|
|
+
|
|
+/* Set a MAC change in hardware. */
|
|
+static int
|
|
+fec_set_mac_address(struct net_device *ndev, void *p)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ struct sockaddr *addr = p;
|
|
+
|
|
+ if (addr) {
|
|
+ if (!is_valid_ether_addr(addr->sa_data))
|
|
+ return -EADDRNOTAVAIL;
|
|
+ memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
|
|
+ }
|
|
+
|
|
+ /* Add netif status check here to avoid system hang in below case:
|
|
+ * ifconfig ethx down; ifconfig ethx hw ether xx:xx:xx:xx:xx:xx;
|
|
+ * After ethx down, fec all clocks are gated off and then register
|
|
+ * access causes system hang.
|
|
+ */
|
|
+ if (!netif_running(ndev))
|
|
+ return 0;
|
|
+
|
|
+ writel(ndev->dev_addr[3] | (ndev->dev_addr[2] << 8) |
|
|
+ (ndev->dev_addr[1] << 16) | (ndev->dev_addr[0] << 24),
|
|
+ fep->hwp + FEC_ADDR_LOW);
|
|
+ writel((ndev->dev_addr[5] << 16) | (ndev->dev_addr[4] << 24),
|
|
+ fep->hwp + FEC_ADDR_HIGH);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline void fec_enet_set_netdev_features(struct net_device *netdev,
|
|
+ netdev_features_t features)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(netdev);
|
|
+ netdev_features_t changed = features ^ netdev->features;
|
|
+
|
|
+ netdev->features = features;
|
|
+
|
|
+ /* Receive checksum has been changed */
|
|
+ if (changed & NETIF_F_RXCSUM) {
|
|
+ if (features & NETIF_F_RXCSUM)
|
|
+ fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
|
|
+ else
|
|
+ fep->csum_flags &= ~FLAG_RX_CSUM_ENABLED;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int fec_set_features(struct net_device *netdev,
|
|
+ netdev_features_t features)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(netdev);
|
|
+ netdev_features_t changed = features ^ netdev->features;
|
|
+ mutex_lock(&fep->fast_ndev_lock);
|
|
+
|
|
+ if (netif_running(netdev) && changed & NETIF_F_RXCSUM) {
|
|
+ fec_stop(netdev);
|
|
+ fec_enet_set_netdev_features(netdev, features);
|
|
+ fec_restart(netdev);
|
|
+ } else {
|
|
+ fec_enet_set_netdev_features(netdev, features);
|
|
+ }
|
|
+
|
|
+ mutex_unlock(&fep->fast_ndev_lock);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static netdev_tx_t
|
|
+fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
|
+{
|
|
+
|
|
+ return NETDEV_TX_OK;
|
|
+}
|
|
+
|
|
+static u16 fec_enet_select_queue(struct net_device *ndev, struct sk_buff *skb,
|
|
+ struct net_device *sb_dev)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct net_device_ops fec_netdev_ops = {
|
|
+ .ndo_open = fec_enet_open,
|
|
+ .ndo_stop = fec_enet_close,
|
|
+ .ndo_start_xmit = fec_enet_start_xmit,
|
|
+ .ndo_select_queue = fec_enet_select_queue,
|
|
+ .ndo_fast_xmit = fec_ecat_fast_xmit,
|
|
+ .ndo_fast_recv = fec_ecat_fast_recv,
|
|
+ .ndo_set_rx_mode = set_multicast_list,
|
|
+ .ndo_validate_addr = eth_validate_addr,
|
|
+ .ndo_tx_timeout = fec_timeout,
|
|
+ .ndo_set_mac_address = fec_set_mac_address,
|
|
+ .ndo_eth_ioctl = fec_enet_ioctl,
|
|
+ .ndo_set_features = fec_set_features,
|
|
+};
|
|
+
|
|
+static int fec_enet_init(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ struct bufdesc *cbd_base;
|
|
+ dma_addr_t bd_dma;
|
|
+ int bd_size;
|
|
+ unsigned int i;
|
|
+ unsigned dsize = sizeof(struct bufdesc);
|
|
+ unsigned dsize_log2 = __fls(dsize);
|
|
+ int ret;
|
|
+ unsigned char *pm = NULL;
|
|
+
|
|
+ WARN_ON(dsize != (1 << dsize_log2));
|
|
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
|
|
+ fep->rx_align = 0xf;
|
|
+ fep->tx_align = 0xf;
|
|
+#else
|
|
+ fep->rx_align = 0x3;
|
|
+ fep->tx_align = 0x3;
|
|
+#endif
|
|
+
|
|
+ /* Check mask of the streaming and coherent API */
|
|
+ ret = dma_set_mask_and_coherent(&fep->pdev->dev, DMA_BIT_MASK(32));
|
|
+ if (ret < 0) {
|
|
+ dev_warn(&fep->pdev->dev, "No suitable DMA available\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = fec_enet_alloc_queue(ndev);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ bd_size = (fep->total_tx_ring_size + fep->total_rx_ring_size) * dsize;
|
|
+
|
|
+ /* Allocate memory for buffer descriptors. */
|
|
+ cbd_base = dmam_alloc_coherent(&fep->pdev->dev, bd_size, &bd_dma,
|
|
+ GFP_KERNEL);
|
|
+ if (!cbd_base) {
|
|
+ ret = -ENOMEM;
|
|
+ goto free_queue_mem;
|
|
+ }
|
|
+
|
|
+ /* Get the Ethernet address */
|
|
+ ret = fec_get_mac(ndev);
|
|
+ if (ret)
|
|
+ goto free_queue_mem;
|
|
+
|
|
+ /* make sure MAC we just acquired is programmed into the hw */
|
|
+ fec_set_mac_address(ndev, NULL);
|
|
+
|
|
+ /* Set receive and transmit descriptor base. */
|
|
+ struct fec_enet_priv_rx_q *rxq = fep->rx_queue;
|
|
+ unsigned size;
|
|
+
|
|
+ size = dsize * rxq->bd.ring_size;
|
|
+ rxq->bd.qid = i;
|
|
+ rxq->bd.base = cbd_base;
|
|
+ rxq->bd.cur = cbd_base;
|
|
+ rxq->bd.dma = bd_dma;
|
|
+ rxq->bd.dsize = dsize;
|
|
+ rxq->bd.dsize_log2 = dsize_log2;
|
|
+ rxq->bd.reg_desc_active = fep->hwp + FEC_R_DES_ACTIVE_0;
|
|
+ bd_dma += size;
|
|
+ cbd_base = (struct bufdesc *)(((void *)cbd_base) + size);
|
|
+ rxq->bd.last = (struct bufdesc *)(((void *)cbd_base) - dsize);
|
|
+
|
|
+ struct fec_enet_priv_tx_q *txq = fep->tx_queue;
|
|
+ size = dsize * txq->bd.ring_size;
|
|
+ txq->bd.qid = i;
|
|
+ txq->bd.base = cbd_base;
|
|
+ txq->bd.cur = cbd_base;
|
|
+ txq->bd.dma = bd_dma;
|
|
+ txq->bd.dsize = dsize;
|
|
+ txq->bd.dsize_log2 = dsize_log2;
|
|
+ txq->bd.reg_desc_active = fep->hwp + FEC_X_DES_ACTIVE_0;
|
|
+ bd_dma += size;
|
|
+ cbd_base = (struct bufdesc *)(((void *)cbd_base) + size);
|
|
+ txq->bd.last = (struct bufdesc *)(((void *)cbd_base) - dsize);
|
|
+
|
|
+ fep->netdev = ndev;
|
|
+
|
|
+ /* The FEC Ethernet specific entries in the device structure */
|
|
+ ndev->watchdog_timeo = TX_TIMEOUT;
|
|
+ ndev->netdev_ops = &fec_netdev_ops;
|
|
+ ndev->ethtool_ops = &fec_enet_ethtool_ops;
|
|
+
|
|
+ pm = ndev->dev_addr;
|
|
+ writel(0, fep->hwp + FEC_IMASK);
|
|
+
|
|
+ if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES) {
|
|
+ fep->tx_align = 0;
|
|
+ fep->rx_align = 0x3f;
|
|
+ }
|
|
+
|
|
+ ndev->hw_features = ndev->features;
|
|
+
|
|
+ fec_restart(ndev);
|
|
+
|
|
+ if (fep->quirks & FEC_QUIRK_MIB_CLEAR)
|
|
+ fec_enet_clear_ethtool_stats(ndev);
|
|
+ else
|
|
+ fec_enet_update_ethtool_stats(ndev);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+free_queue_mem:
|
|
+ fec_enet_free_queue(ndev);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_OF
|
|
+static int fec_reset_phy(struct platform_device *pdev)
|
|
+{
|
|
+ int err, phy_reset;
|
|
+ bool active_high = false;
|
|
+ int msec = 1, phy_post_delay = 0;
|
|
+ struct device_node *np = pdev->dev.of_node;
|
|
+
|
|
+ if (!np)
|
|
+ return 0;
|
|
+
|
|
+ err = of_property_read_u32(np, "phy-reset-duration", &msec);
|
|
+ /* A sane reset duration should not be longer than 1s */
|
|
+ if (!err && msec > 1000)
|
|
+ msec = 1;
|
|
+
|
|
+ phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0);
|
|
+ if (phy_reset == -EPROBE_DEFER)
|
|
+ return phy_reset;
|
|
+ else if (!gpio_is_valid(phy_reset))
|
|
+ return 0;
|
|
+
|
|
+ err = of_property_read_u32(np, "phy-reset-post-delay", &phy_post_delay);
|
|
+ /* valid reset duration should be less than 1s */
|
|
+ if (!err && phy_post_delay > 1000)
|
|
+ return -EINVAL;
|
|
+
|
|
+ active_high = of_property_read_bool(np, "phy-reset-active-high");
|
|
+
|
|
+ err = devm_gpio_request_one(&pdev->dev, phy_reset,
|
|
+ active_high ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
|
|
+ "phy-reset");
|
|
+ if (err) {
|
|
+ dev_err(&pdev->dev, "failed to get phy-reset-gpios: %d\n", err);
|
|
+ return err;
|
|
+ }
|
|
+
|
|
+ if (msec > 20)
|
|
+ msleep(msec);
|
|
+ else
|
|
+ usleep_range(msec * 1000, msec * 1000 + 1000);
|
|
+
|
|
+ gpio_set_value_cansleep(phy_reset, !active_high);
|
|
+
|
|
+ if (!phy_post_delay)
|
|
+ return 0;
|
|
+
|
|
+ if (phy_post_delay > 20)
|
|
+ msleep(phy_post_delay);
|
|
+ else
|
|
+ usleep_range(phy_post_delay * 1000,
|
|
+ phy_post_delay * 1000 + 1000);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+#else /* CONFIG_OF */
|
|
+static int fec_reset_phy(struct platform_device *pdev)
|
|
+{
|
|
+ /*
|
|
+ * In case of platform probe, the reset has been done
|
|
+ * by machine code.
|
|
+ */
|
|
+ return 0;
|
|
+}
|
|
+#endif /* CONFIG_OF */
|
|
+
|
|
+static int fec_enet_init_stop_mode(struct fec_enet_private *fep,
|
|
+ struct device_node *np)
|
|
+{
|
|
+ struct device_node *gpr_np;
|
|
+ u32 out_val[3];
|
|
+ int ret = 0;
|
|
+
|
|
+ gpr_np = of_parse_phandle(np, "fsl,stop-mode", 0);
|
|
+ if (!gpr_np)
|
|
+ return 0;
|
|
+
|
|
+ ret = of_property_read_u32_array(np, "fsl,stop-mode", out_val,
|
|
+ ARRAY_SIZE(out_val));
|
|
+ if (ret) {
|
|
+ dev_dbg(&fep->pdev->dev, "no stop mode property\n");
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ fep->stop_gpr.gpr = syscon_node_to_regmap(gpr_np);
|
|
+ if (IS_ERR(fep->stop_gpr.gpr)) {
|
|
+ dev_err(&fep->pdev->dev, "could not find gpr regmap\n");
|
|
+ ret = PTR_ERR(fep->stop_gpr.gpr);
|
|
+ fep->stop_gpr.gpr = NULL;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ fep->stop_gpr.reg = out_val[1];
|
|
+ fep->stop_gpr.bit = out_val[2];
|
|
+
|
|
+out:
|
|
+ of_node_put(gpr_np);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+fec_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct fec_enet_private *fep;
|
|
+ struct fec_platform_data *pdata;
|
|
+ phy_interface_t interface;
|
|
+ struct net_device *ndev;
|
|
+ int i, irq, ret = 0;
|
|
+ const struct of_device_id *of_id;
|
|
+ static int dev_id;
|
|
+ struct device_node *np = pdev->dev.of_node, *phy_node;
|
|
+ char irq_name[8];
|
|
+ struct fec_devinfo *dev_info;
|
|
+
|
|
+ /* Init network device */
|
|
+ ndev = alloc_etherdev_mqs(sizeof(struct fec_enet_private) +
|
|
+ FEC_STATS_SIZE, 1, 1);
|
|
+ if (!ndev)
|
|
+ return -ENOMEM;
|
|
+ ndev->fast_raw_device = 1;
|
|
+ SET_NETDEV_DEV(ndev, &pdev->dev);
|
|
+
|
|
+ /* setup board info structure */
|
|
+ fep = netdev_priv(ndev);
|
|
+
|
|
+ of_id = of_match_device(fec_dt_ids, &pdev->dev);
|
|
+ if (of_id)
|
|
+ pdev->id_entry = of_id->data;
|
|
+ dev_info = (struct fec_devinfo *)pdev->id_entry->driver_data;
|
|
+ if (dev_info)
|
|
+ fep->quirks = dev_info->quirks;
|
|
+
|
|
+ fep->netdev = ndev;
|
|
+ mutex_init(&fep->fast_ndev_lock);
|
|
+#if !defined(CONFIG_M5272)
|
|
+ /* default enable pause frame auto negotiation */
|
|
+ if (fep->quirks & FEC_QUIRK_HAS_GBIT)
|
|
+ fep->pause_flag |= FEC_PAUSE_FLAG_AUTONEG;
|
|
+#endif
|
|
+
|
|
+ /* Select default pin state */
|
|
+ pinctrl_pm_select_default_state(&pdev->dev);
|
|
+
|
|
+ fep->hwp = devm_platform_ioremap_resource(pdev, 0);
|
|
+ if (IS_ERR(fep->hwp)) {
|
|
+ ret = PTR_ERR(fep->hwp);
|
|
+ goto failed_ioremap;
|
|
+ }
|
|
+
|
|
+ fep->pdev = pdev;
|
|
+ fep->dev_id = dev_id++;
|
|
+
|
|
+ platform_set_drvdata(pdev, ndev);
|
|
+
|
|
+ if ((of_machine_is_compatible("fsl,imx6q") ||
|
|
+ of_machine_is_compatible("fsl,imx6dl")) &&
|
|
+ !of_property_read_bool(np, "fsl,err006687-workaround-present"))
|
|
+ fep->quirks |= FEC_QUIRK_ERR006687;
|
|
+
|
|
+ ret = fec_enet_ipc_handle_init(fep);
|
|
+ if (ret)
|
|
+ goto failed_ipc_init;
|
|
+
|
|
+ ret = fec_enet_init_stop_mode(fep, np);
|
|
+ if (ret)
|
|
+ goto failed_stop_mode;
|
|
+
|
|
+ phy_node = of_parse_phandle(np, "phy-handle", 0);
|
|
+ if (!phy_node && of_phy_is_fixed_link(np)) {
|
|
+ ret = of_phy_register_fixed_link(np);
|
|
+ if (ret < 0) {
|
|
+ dev_err(&pdev->dev,
|
|
+ "broken fixed-link specification\n");
|
|
+ goto failed_phy;
|
|
+ }
|
|
+ phy_node = of_node_get(np);
|
|
+ }
|
|
+ fep->phy_node = phy_node;
|
|
+
|
|
+ ret = of_get_phy_mode(pdev->dev.of_node, &interface);
|
|
+ if (ret) {
|
|
+ pdata = dev_get_platdata(&pdev->dev);
|
|
+ if (pdata)
|
|
+ fep->phy_interface = pdata->phy;
|
|
+ else
|
|
+ fep->phy_interface = PHY_INTERFACE_MODE_MII;
|
|
+ } else {
|
|
+ fep->phy_interface = interface;
|
|
+ }
|
|
+
|
|
+ ret = fec_enet_parse_rgmii_delay(fep, np);
|
|
+ if (ret)
|
|
+ goto failed_rgmii_delay;
|
|
+
|
|
+ request_bus_freq(BUS_FREQ_HIGH);
|
|
+
|
|
+ fep->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
|
|
+ if (IS_ERR(fep->clk_ipg)) {
|
|
+ ret = PTR_ERR(fep->clk_ipg);
|
|
+ goto failed_clk;
|
|
+ }
|
|
+
|
|
+ fep->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
|
|
+ if (IS_ERR(fep->clk_ahb)) {
|
|
+ ret = PTR_ERR(fep->clk_ahb);
|
|
+ goto failed_clk;
|
|
+ }
|
|
+
|
|
+ fep->itr_clk_rate = clk_get_rate(fep->clk_ahb);
|
|
+
|
|
+ /* enet_out is optional, depends on board */
|
|
+ fep->clk_enet_out = devm_clk_get(&pdev->dev, "enet_out");
|
|
+ if (IS_ERR(fep->clk_enet_out))
|
|
+ fep->clk_enet_out = NULL;
|
|
+
|
|
+ fep->ptp_clk_on = false;
|
|
+ mutex_init(&fep->ptp_clk_mutex);
|
|
+
|
|
+ /* clk_ref is optional, depends on board */
|
|
+ fep->clk_ref = devm_clk_get(&pdev->dev, "enet_clk_ref");
|
|
+ if (IS_ERR(fep->clk_ref))
|
|
+ fep->clk_ref = NULL;
|
|
+ fep->clk_ref_rate = clk_get_rate(fep->clk_ref);
|
|
+
|
|
+ /* clk_2x_txclk is optional, depends on board */
|
|
+ if (fep->rgmii_txc_dly || fep->rgmii_rxc_dly) {
|
|
+ fep->clk_2x_txclk = devm_clk_get(&pdev->dev, "enet_2x_txclk");
|
|
+ if (IS_ERR(fep->clk_2x_txclk))
|
|
+ fep->clk_2x_txclk = NULL;
|
|
+ }
|
|
+
|
|
+ ret = fec_enet_clk_enable(ndev, true);
|
|
+ if (ret)
|
|
+ goto failed_clk;
|
|
+
|
|
+ ret = clk_prepare_enable(fep->clk_ipg);
|
|
+ if (ret)
|
|
+ goto failed_clk_ipg;
|
|
+ ret = clk_prepare_enable(fep->clk_ahb);
|
|
+ if (ret)
|
|
+ goto failed_clk_ahb;
|
|
+
|
|
+ fep->reg_phy = devm_regulator_get_optional(&pdev->dev, "phy");
|
|
+ if (!IS_ERR(fep->reg_phy)) {
|
|
+ ret = regulator_enable(fep->reg_phy);
|
|
+ if (ret) {
|
|
+ dev_err(&pdev->dev,
|
|
+ "Failed to enable phy regulator: %d\n", ret);
|
|
+ goto failed_regulator;
|
|
+ }
|
|
+ } else {
|
|
+ if (PTR_ERR(fep->reg_phy) == -EPROBE_DEFER) {
|
|
+ ret = -EPROBE_DEFER;
|
|
+ goto failed_regulator;
|
|
+ }
|
|
+ fep->reg_phy = NULL;
|
|
+ }
|
|
+
|
|
+ if (of_property_read_u32(np, "fsl,rx-phy-delay-100-ns", &fep->rx_delay_100))
|
|
+ fep->rx_delay_100 = 600;
|
|
+
|
|
+ if (of_property_read_u32(np, "fsl,tx-phy-delay-100-ns", &fep->tx_delay_100))
|
|
+ fep->tx_delay_100 = 0;
|
|
+
|
|
+ if (of_property_read_u32(np, "fsl,rx-phy-delay-1000-ns", &fep->rx_delay_1000))
|
|
+ fep->rx_delay_1000 = 0;
|
|
+
|
|
+ if (of_property_read_u32(np, "fsl,tx-phy-delay-1000-ns", &fep->tx_delay_1000))
|
|
+ fep->tx_delay_1000 = 0;
|
|
+
|
|
+ pm_runtime_set_autosuspend_delay(&pdev->dev, FEC_MDIO_PM_TIMEOUT);
|
|
+ pm_runtime_use_autosuspend(&pdev->dev);
|
|
+ pm_runtime_get_noresume(&pdev->dev);
|
|
+ pm_runtime_set_active(&pdev->dev);
|
|
+ pm_runtime_enable(&pdev->dev);
|
|
+
|
|
+ ret = fec_reset_phy(pdev);
|
|
+ if (ret)
|
|
+ goto failed_reset;
|
|
+
|
|
+ //irq_cnt = fec_enet_get_irq_cnt(pdev);
|
|
+
|
|
+ ret = fec_enet_init(ndev);
|
|
+ if (ret)
|
|
+ goto failed_init;
|
|
+
|
|
+ /* board only enable one mii bus in default */
|
|
+ if (!of_get_property(np, "fsl,mii-exclusive", NULL))
|
|
+ fep->quirks |= FEC_QUIRK_SINGLE_MDIO;
|
|
+ ret = fec_enet_mii_init(pdev);
|
|
+ if (ret)
|
|
+ goto failed_mii_init;
|
|
+
|
|
+ /* Carrier starts down, phylib will bring it up */
|
|
+ netif_carrier_off(ndev);
|
|
+ pinctrl_pm_select_sleep_state(&pdev->dev);
|
|
+
|
|
+ ndev->max_mtu = PKT_MAXBUF_SIZE - ETH_HLEN - ETH_FCS_LEN;
|
|
+
|
|
+ ret = register_netdev(ndev);
|
|
+ if (ret)
|
|
+ goto failed_register;
|
|
+
|
|
+ device_init_wakeup(&ndev->dev, fep->wol_flag &
|
|
+ FEC_WOL_HAS_MAGIC_PACKET);
|
|
+
|
|
+
|
|
+ INIT_WORK(&fep->tx_timeout_work, fec_enet_timeout_work);
|
|
+
|
|
+ pm_runtime_mark_last_busy(&pdev->dev);
|
|
+ pm_runtime_put_autosuspend(&pdev->dev);
|
|
+ mutex_lock(&fep->fast_ndev_lock);
|
|
+ return 0;
|
|
+
|
|
+failed_register:
|
|
+ fec_enet_mii_remove(fep);
|
|
+failed_mii_init:
|
|
+failed_irq:
|
|
+failed_init:
|
|
+ //fec_ptp_stop(pdev);
|
|
+failed_reset:
|
|
+ pm_runtime_put_noidle(&pdev->dev);
|
|
+ pm_runtime_disable(&pdev->dev);
|
|
+ if (fep->reg_phy)
|
|
+ regulator_disable(fep->reg_phy);
|
|
+failed_regulator:
|
|
+ clk_disable_unprepare(fep->clk_ahb);
|
|
+failed_clk_ahb:
|
|
+ clk_disable_unprepare(fep->clk_ipg);
|
|
+failed_clk_ipg:
|
|
+ fec_enet_clk_enable(ndev, false);
|
|
+failed_clk:
|
|
+ release_bus_freq(BUS_FREQ_HIGH);
|
|
+failed_rgmii_delay:
|
|
+ if (of_phy_is_fixed_link(np))
|
|
+ of_phy_deregister_fixed_link(np);
|
|
+ of_node_put(phy_node);
|
|
+failed_stop_mode:
|
|
+failed_ipc_init:
|
|
+failed_phy:
|
|
+ dev_id--;
|
|
+failed_ioremap:
|
|
+ free_netdev(ndev);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int
|
|
+fec_drv_remove(struct platform_device *pdev)
|
|
+{
|
|
+ struct net_device *ndev = platform_get_drvdata(pdev);
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ struct device_node *np = pdev->dev.of_node;
|
|
+ int ret;
|
|
+
|
|
+ ret = pm_runtime_resume_and_get(&pdev->dev);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ cancel_work_sync(&fep->tx_timeout_work);
|
|
+ //fec_ptp_stop(pdev);
|
|
+ unregister_netdev(ndev);
|
|
+ fec_enet_mii_remove(fep);
|
|
+ if (fep->reg_phy)
|
|
+ regulator_disable(fep->reg_phy);
|
|
+
|
|
+ if (of_phy_is_fixed_link(np))
|
|
+ of_phy_deregister_fixed_link(np);
|
|
+ of_node_put(fep->phy_node);
|
|
+
|
|
+ clk_disable_unprepare(fep->clk_ahb);
|
|
+ clk_disable_unprepare(fep->clk_ipg);
|
|
+ pm_runtime_put_noidle(&pdev->dev);
|
|
+ pm_runtime_disable(&pdev->dev);
|
|
+
|
|
+ free_netdev(ndev);
|
|
+ mutex_unlock(&fep->fast_ndev_lock);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int __maybe_unused fec_suspend(struct device *dev)
|
|
+{
|
|
+ struct net_device *ndev = dev_get_drvdata(dev);
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+
|
|
+ if (netif_running(ndev)) {
|
|
+ int ret;
|
|
+
|
|
+ phy_stop(ndev->phydev);
|
|
+
|
|
+ netif_device_detach(ndev);
|
|
+ fec_stop(ndev);
|
|
+ fec_enet_clk_enable(ndev, false);
|
|
+
|
|
+ fep->rpm_active = !pm_runtime_status_suspended(dev);
|
|
+ if (fep->rpm_active) {
|
|
+ ret = pm_runtime_force_suspend(dev);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+ }
|
|
+ } else if (fep->mii_bus_share && !ndev->phydev) {
|
|
+ pinctrl_pm_select_sleep_state(&fep->pdev->dev);
|
|
+ }
|
|
+
|
|
+ if (fep->reg_phy && !(fep->wol_flag & FEC_WOL_FLAG_ENABLE))
|
|
+ regulator_disable(fep->reg_phy);
|
|
+
|
|
+ /* SOC supply clock to phy, when clock is disabled, phy link down
|
|
+ * SOC control phy regulator, when regulator is disabled, phy link down
|
|
+ */
|
|
+ if (fep->clk_enet_out || fep->reg_phy)
|
|
+ fep->link = 0;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int __maybe_unused fec_resume(struct device *dev)
|
|
+{
|
|
+ struct net_device *ndev = dev_get_drvdata(dev);
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ int ret = 0;
|
|
+ int val;
|
|
+
|
|
+ if (fep->reg_phy && !(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) {
|
|
+ ret = regulator_enable(fep->reg_phy);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ if (netif_running(ndev)) {
|
|
+ if (fep->rpm_active)
|
|
+ pm_runtime_force_resume(dev);
|
|
+
|
|
+ ret = fec_enet_clk_enable(ndev, true);
|
|
+ if (ret) {
|
|
+ rtnl_unlock();
|
|
+ goto failed_clk;
|
|
+ }
|
|
+ pinctrl_pm_select_default_state(&fep->pdev->dev);
|
|
+ fec_restart(ndev);
|
|
+ netif_device_attach(ndev);
|
|
+
|
|
+ //napi_enable(&fep->napi);
|
|
+
|
|
+ phy_init_hw(ndev->phydev);
|
|
+ phy_start(ndev->phydev);
|
|
+ } else if (fep->mii_bus_share && !ndev->phydev) {
|
|
+ pinctrl_pm_select_default_state(&fep->pdev->dev);
|
|
+ /* And then recovery mii bus */
|
|
+ ret = fec_restore_mii_bus(ndev);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+
|
|
+failed_clk:
|
|
+ if (fep->reg_phy)
|
|
+ regulator_disable(fep->reg_phy);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int __maybe_unused fec_runtime_suspend(struct device *dev)
|
|
+{
|
|
+ struct net_device *ndev = dev_get_drvdata(dev);
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+
|
|
+ clk_disable_unprepare(fep->clk_ahb);
|
|
+ clk_disable_unprepare(fep->clk_ipg);
|
|
+ release_bus_freq(BUS_FREQ_HIGH);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int __maybe_unused fec_runtime_resume(struct device *dev)
|
|
+{
|
|
+ struct net_device *ndev = dev_get_drvdata(dev);
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ int ret;
|
|
+
|
|
+ request_bus_freq(BUS_FREQ_HIGH);
|
|
+
|
|
+ ret = clk_prepare_enable(fep->clk_ahb);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ ret = clk_prepare_enable(fep->clk_ipg);
|
|
+ if (ret)
|
|
+ goto failed_clk_ipg;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+failed_clk_ipg:
|
|
+ clk_disable_unprepare(fep->clk_ahb);
|
|
+ release_bus_freq(BUS_FREQ_HIGH);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct dev_pm_ops fec_pm_ops = {
|
|
+ SET_SYSTEM_SLEEP_PM_OPS(fec_suspend, fec_resume)
|
|
+ SET_RUNTIME_PM_OPS(fec_runtime_suspend, fec_runtime_resume, NULL)
|
|
+};
|
|
+
|
|
+static struct platform_driver fec_ecat_driver = {
|
|
+ .driver = {
|
|
+ .name = DRIVER_NAME,
|
|
+ .pm = &fec_pm_ops,
|
|
+ .of_match_table = fec_dt_ids,
|
|
+ .suppress_bind_attrs = true,
|
|
+ },
|
|
+ .id_table = fec_devtype,
|
|
+ .probe = fec_probe,
|
|
+ .remove = fec_drv_remove,
|
|
+};
|
|
+
|
|
+module_platform_driver(fec_ecat_driver);
|
|
+
|
|
+MODULE_LICENSE("GPL");
|
|
diff --git a/drivers/net/ethernet/freescale/fec_ecat.h b/drivers/net/ethernet/freescale/fec_ecat.h
|
|
new file mode 100644
|
|
index 000000000000..e8235a0978a8
|
|
--- /dev/null
|
|
+++ b/drivers/net/ethernet/freescale/fec_ecat.h
|
|
@@ -0,0 +1,718 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+/****************************************************************************/
|
|
+#ifndef FEC_ECAT_H
|
|
+#define FEC_ECAT_H
|
|
+/****************************************************************************/
|
|
+
|
|
+#include <linux/clocksource.h>
|
|
+#include <linux/net_tstamp.h>
|
|
+#include <linux/pm_qos.h>
|
|
+#include <linux/ptp_clock_kernel.h>
|
|
+#include <linux/timecounter.h>
|
|
+#include <dt-bindings/firmware/imx/rsrc.h>
|
|
+#include <linux/firmware/imx/sci.h>
|
|
+#include <linux/fec.h>
|
|
+
|
|
+#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
|
|
+ defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) || \
|
|
+ defined(CONFIG_ARM64) || defined(CONFIG_COMPILE_TEST)
|
|
+/*
|
|
+ * Just figures, Motorola would have to change the offsets for
|
|
+ * registers in the same peripheral device on different models
|
|
+ * of the ColdFire!
|
|
+ */
|
|
+#define FEC_IEVENT 0x004 /* Interrupt event reg */
|
|
+#define FEC_IMASK 0x008 /* Interrupt mask reg */
|
|
+#define FEC_R_DES_ACTIVE_0 0x010 /* Receive descriptor reg */
|
|
+#define FEC_X_DES_ACTIVE_0 0x014 /* Transmit descriptor reg */
|
|
+#define FEC_ECNTRL 0x024 /* Ethernet control reg */
|
|
+#define FEC_MII_DATA 0x040 /* MII manage frame reg */
|
|
+#define FEC_MII_SPEED 0x044 /* MII speed control reg */
|
|
+#define FEC_MIB_CTRLSTAT 0x064 /* MIB control/status reg */
|
|
+#define FEC_R_CNTRL 0x084 /* Receive control reg */
|
|
+#define FEC_X_CNTRL 0x0c4 /* Transmit Control reg */
|
|
+#define FEC_ADDR_LOW 0x0e4 /* Low 32bits MAC address */
|
|
+#define FEC_ADDR_HIGH 0x0e8 /* High 16bits MAC address */
|
|
+#define FEC_OPD 0x0ec /* Opcode + Pause duration */
|
|
+#define FEC_TXIC0 0x0f0 /* Tx Interrupt Coalescing for ring 0 */
|
|
+#define FEC_TXIC1 0x0f4 /* Tx Interrupt Coalescing for ring 1 */
|
|
+#define FEC_TXIC2 0x0f8 /* Tx Interrupt Coalescing for ring 2 */
|
|
+#define FEC_RXIC0 0x100 /* Rx Interrupt Coalescing for ring 0 */
|
|
+#define FEC_RXIC1 0x104 /* Rx Interrupt Coalescing for ring 1 */
|
|
+#define FEC_RXIC2 0x108 /* Rx Interrupt Coalescing for ring 2 */
|
|
+#define FEC_HASH_TABLE_HIGH 0x118 /* High 32bits hash table */
|
|
+#define FEC_HASH_TABLE_LOW 0x11c /* Low 32bits hash table */
|
|
+#define FEC_GRP_HASH_TABLE_HIGH 0x120 /* High 32bits hash table */
|
|
+#define FEC_GRP_HASH_TABLE_LOW 0x124 /* Low 32bits hash table */
|
|
+#define FEC_X_WMRK 0x144 /* FIFO transmit water mark */
|
|
+#define FEC_R_BOUND 0x14c /* FIFO receive bound reg */
|
|
+#define FEC_R_FSTART 0x150 /* FIFO receive start reg */
|
|
+#define FEC_R_DES_START_1 0x160 /* Receive descriptor ring 1 */
|
|
+#define FEC_X_DES_START_1 0x164 /* Transmit descriptor ring 1 */
|
|
+#define FEC_R_BUFF_SIZE_1 0x168 /* Maximum receive buff ring1 size */
|
|
+#define FEC_R_DES_START_2 0x16c /* Receive descriptor ring 2 */
|
|
+#define FEC_X_DES_START_2 0x170 /* Transmit descriptor ring 2 */
|
|
+#define FEC_R_BUFF_SIZE_2 0x174 /* Maximum receive buff ring2 size */
|
|
+#define FEC_R_DES_START_0 0x180 /* Receive descriptor ring */
|
|
+#define FEC_X_DES_START_0 0x184 /* Transmit descriptor ring */
|
|
+#define FEC_R_BUFF_SIZE_0 0x188 /* Maximum receive buff size */
|
|
+#define FEC_R_FIFO_RSFL 0x190 /* Receive FIFO section full threshold */
|
|
+#define FEC_R_FIFO_RSEM 0x194 /* Receive FIFO section empty threshold */
|
|
+#define FEC_R_FIFO_RAEM 0x198 /* Receive FIFO almost empty threshold */
|
|
+#define FEC_R_FIFO_RAFL 0x19c /* Receive FIFO almost full threshold */
|
|
+#define FEC_FTRL 0x1b0 /* Frame truncation receive length*/
|
|
+#define FEC_RACC 0x1c4 /* Receive Accelerator function */
|
|
+#define FEC_RCMR_1 0x1c8 /* Receive classification match ring 1 */
|
|
+#define FEC_RCMR_2 0x1cc /* Receive classification match ring 2 */
|
|
+#define FEC_DMA_CFG_1 0x1d8 /* DMA class configuration for ring 1 */
|
|
+#define FEC_DMA_CFG_2 0x1dc /* DMA class Configuration for ring 2 */
|
|
+#define FEC_R_DES_ACTIVE_1 0x1e0 /* Rx descriptor active for ring 1 */
|
|
+#define FEC_X_DES_ACTIVE_1 0x1e4 /* Tx descriptor active for ring 1 */
|
|
+#define FEC_R_DES_ACTIVE_2 0x1e8 /* Rx descriptor active for ring 2 */
|
|
+#define FEC_X_DES_ACTIVE_2 0x1ec /* Tx descriptor active for ring 2 */
|
|
+#define FEC_QOS_SCHEME 0x1f0 /* Set multi queues Qos scheme */
|
|
+#define FEC_LPI_SLEEP 0x1f4 /* Set IEEE802.3az LPI Sleep Ts time */
|
|
+#define FEC_LPI_WAKE 0x1f8 /* Set IEEE802.3az LPI Wake Tw time */
|
|
+#define FEC_MIIGSK_CFGR 0x300 /* MIIGSK Configuration reg */
|
|
+#define FEC_MIIGSK_ENR 0x308 /* MIIGSK Enable reg */
|
|
+
|
|
+#define BM_MIIGSK_CFGR_MII 0x00
|
|
+#define BM_MIIGSK_CFGR_RMII 0x01
|
|
+#define BM_MIIGSK_CFGR_FRCONT_10M 0x40
|
|
+
|
|
+#define RMON_T_DROP 0x200 /* Count of frames not cntd correctly */
|
|
+#define RMON_T_PACKETS 0x204 /* RMON TX packet count */
|
|
+#define RMON_T_BC_PKT 0x208 /* RMON TX broadcast pkts */
|
|
+#define RMON_T_MC_PKT 0x20c /* RMON TX multicast pkts */
|
|
+#define RMON_T_CRC_ALIGN 0x210 /* RMON TX pkts with CRC align err */
|
|
+#define RMON_T_UNDERSIZE 0x214 /* RMON TX pkts < 64 bytes, good CRC */
|
|
+#define RMON_T_OVERSIZE 0x218 /* RMON TX pkts > MAX_FL bytes good CRC */
|
|
+#define RMON_T_FRAG 0x21c /* RMON TX pkts < 64 bytes, bad CRC */
|
|
+#define RMON_T_JAB 0x220 /* RMON TX pkts > MAX_FL bytes, bad CRC */
|
|
+#define RMON_T_COL 0x224 /* RMON TX collision count */
|
|
+#define RMON_T_P64 0x228 /* RMON TX 64 byte pkts */
|
|
+#define RMON_T_P65TO127 0x22c /* RMON TX 65 to 127 byte pkts */
|
|
+#define RMON_T_P128TO255 0x230 /* RMON TX 128 to 255 byte pkts */
|
|
+#define RMON_T_P256TO511 0x234 /* RMON TX 256 to 511 byte pkts */
|
|
+#define RMON_T_P512TO1023 0x238 /* RMON TX 512 to 1023 byte pkts */
|
|
+#define RMON_T_P1024TO2047 0x23c /* RMON TX 1024 to 2047 byte pkts */
|
|
+#define RMON_T_P_GTE2048 0x240 /* RMON TX pkts > 2048 bytes */
|
|
+#define RMON_T_OCTETS 0x244 /* RMON TX octets */
|
|
+#define IEEE_T_DROP 0x248 /* Count of frames not counted crtly */
|
|
+#define IEEE_T_FRAME_OK 0x24c /* Frames tx'd OK */
|
|
+#define IEEE_T_1COL 0x250 /* Frames tx'd with single collision */
|
|
+#define IEEE_T_MCOL 0x254 /* Frames tx'd with multiple collision */
|
|
+#define IEEE_T_DEF 0x258 /* Frames tx'd after deferral delay */
|
|
+#define IEEE_T_LCOL 0x25c /* Frames tx'd with late collision */
|
|
+#define IEEE_T_EXCOL 0x260 /* Frames tx'd with excesv collisions */
|
|
+#define IEEE_T_MACERR 0x264 /* Frames tx'd with TX FIFO underrun */
|
|
+#define IEEE_T_CSERR 0x268 /* Frames tx'd with carrier sense err */
|
|
+#define IEEE_T_SQE 0x26c /* Frames tx'd with SQE err */
|
|
+#define IEEE_T_FDXFC 0x270 /* Flow control pause frames tx'd */
|
|
+#define IEEE_T_OCTETS_OK 0x274 /* Octet count for frames tx'd w/o err */
|
|
+#define RMON_R_PACKETS 0x284 /* RMON RX packet count */
|
|
+#define RMON_R_BC_PKT 0x288 /* RMON RX broadcast pkts */
|
|
+#define RMON_R_MC_PKT 0x28c /* RMON RX multicast pkts */
|
|
+#define RMON_R_CRC_ALIGN 0x290 /* RMON RX pkts with CRC alignment err */
|
|
+#define RMON_R_UNDERSIZE 0x294 /* RMON RX pkts < 64 bytes, good CRC */
|
|
+#define RMON_R_OVERSIZE 0x298 /* RMON RX pkts > MAX_FL bytes good CRC */
|
|
+#define RMON_R_FRAG 0x29c /* RMON RX pkts < 64 bytes, bad CRC */
|
|
+#define RMON_R_JAB 0x2a0 /* RMON RX pkts > MAX_FL bytes, bad CRC */
|
|
+#define RMON_R_RESVD_O 0x2a4 /* Reserved */
|
|
+#define RMON_R_P64 0x2a8 /* RMON RX 64 byte pkts */
|
|
+#define RMON_R_P65TO127 0x2ac /* RMON RX 65 to 127 byte pkts */
|
|
+#define RMON_R_P128TO255 0x2b0 /* RMON RX 128 to 255 byte pkts */
|
|
+#define RMON_R_P256TO511 0x2b4 /* RMON RX 256 to 511 byte pkts */
|
|
+#define RMON_R_P512TO1023 0x2b8 /* RMON RX 512 to 1023 byte pkts */
|
|
+#define RMON_R_P1024TO2047 0x2bc /* RMON RX 1024 to 2047 byte pkts */
|
|
+#define RMON_R_P_GTE2048 0x2c0 /* RMON RX pkts > 2048 bytes */
|
|
+#define RMON_R_OCTETS 0x2c4 /* RMON RX octets */
|
|
+#define IEEE_R_DROP 0x2c8 /* Count frames not counted correctly */
|
|
+#define IEEE_R_FRAME_OK 0x2cc /* Frames rx'd OK */
|
|
+#define IEEE_R_CRC 0x2d0 /* Frames rx'd with CRC err */
|
|
+#define IEEE_R_ALIGN 0x2d4 /* Frames rx'd with alignment err */
|
|
+#define IEEE_R_MACERR 0x2d8 /* Receive FIFO overflow count */
|
|
+#define IEEE_R_FDXFC 0x2dc /* Flow control pause frames rx'd */
|
|
+#define IEEE_R_OCTETS_OK 0x2e0 /* Octet cnt for frames rx'd w/o err */
|
|
+
|
|
+#else
|
|
+
|
|
+#define FEC_ECNTRL 0x000 /* Ethernet control reg */
|
|
+#define FEC_IEVENT 0x004 /* Interrupt even reg */
|
|
+#define FEC_IMASK 0x008 /* Interrupt mask reg */
|
|
+#define FEC_IVEC 0x00c /* Interrupt vec status reg */
|
|
+#define FEC_R_DES_ACTIVE_0 0x010 /* Receive descriptor reg */
|
|
+#define FEC_R_DES_ACTIVE_1 FEC_R_DES_ACTIVE_0
|
|
+#define FEC_R_DES_ACTIVE_2 FEC_R_DES_ACTIVE_0
|
|
+#define FEC_X_DES_ACTIVE_0 0x014 /* Transmit descriptor reg */
|
|
+#define FEC_X_DES_ACTIVE_1 FEC_X_DES_ACTIVE_0
|
|
+#define FEC_X_DES_ACTIVE_2 FEC_X_DES_ACTIVE_0
|
|
+#define FEC_MII_DATA 0x040 /* MII manage frame reg */
|
|
+#define FEC_MII_SPEED 0x044 /* MII speed control reg */
|
|
+#define FEC_R_BOUND 0x08c /* FIFO receive bound reg */
|
|
+#define FEC_R_FSTART 0x090 /* FIFO receive start reg */
|
|
+#define FEC_X_WMRK 0x0a4 /* FIFO transmit water mark */
|
|
+#define FEC_X_FSTART 0x0ac /* FIFO transmit start reg */
|
|
+#define FEC_R_CNTRL 0x104 /* Receive control reg */
|
|
+#define FEC_MAX_FRM_LEN 0x108 /* Maximum frame length reg */
|
|
+#define FEC_X_CNTRL 0x144 /* Transmit Control reg */
|
|
+#define FEC_ADDR_LOW 0x3c0 /* Low 32bits MAC address */
|
|
+#define FEC_ADDR_HIGH 0x3c4 /* High 16bits MAC address */
|
|
+#define FEC_GRP_HASH_TABLE_HIGH 0x3c8 /* High 32bits hash table */
|
|
+#define FEC_GRP_HASH_TABLE_LOW 0x3cc /* Low 32bits hash table */
|
|
+#define FEC_R_DES_START_0 0x3d0 /* Receive descriptor ring */
|
|
+#define FEC_R_DES_START_1 FEC_R_DES_START_0
|
|
+#define FEC_R_DES_START_2 FEC_R_DES_START_0
|
|
+#define FEC_X_DES_START_0 0x3d4 /* Transmit descriptor ring */
|
|
+#define FEC_X_DES_START_1 FEC_X_DES_START_0
|
|
+#define FEC_X_DES_START_2 FEC_X_DES_START_0
|
|
+#define FEC_R_BUFF_SIZE_0 0x3d8 /* Maximum receive buff size */
|
|
+#define FEC_R_BUFF_SIZE_1 FEC_R_BUFF_SIZE_0
|
|
+#define FEC_R_BUFF_SIZE_2 FEC_R_BUFF_SIZE_0
|
|
+#define FEC_FIFO_RAM 0x400 /* FIFO RAM buffer */
|
|
+/* Not existed in real chip
|
|
+ * Just for pass build.
|
|
+ */
|
|
+#define FEC_RCMR_1 0xfff
|
|
+#define FEC_RCMR_2 0xfff
|
|
+#define FEC_DMA_CFG_1 0xfff
|
|
+#define FEC_DMA_CFG_2 0xfff
|
|
+#define FEC_TXIC0 0xfff
|
|
+#define FEC_TXIC1 0xfff
|
|
+#define FEC_TXIC2 0xfff
|
|
+#define FEC_RXIC0 0xfff
|
|
+#define FEC_RXIC1 0xfff
|
|
+#define FEC_RXIC2 0xfff
|
|
+#define FEC_LPI_SLEEP 0xfff
|
|
+#define FEC_LPI_WAKE 0xfff
|
|
+#endif /* CONFIG_M5272 */
|
|
+
|
|
+
|
|
+/*
|
|
+ * Define the buffer descriptor structure.
|
|
+ *
|
|
+ * Evidently, ARM SoCs have the FEC block generated in a
|
|
+ * little endian mode so adjust endianness accordingly.
|
|
+ */
|
|
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
|
|
+#define fec32_to_cpu le32_to_cpu
|
|
+#define fec16_to_cpu le16_to_cpu
|
|
+#define cpu_to_fec32 cpu_to_le32
|
|
+#define cpu_to_fec16 cpu_to_le16
|
|
+#define __fec32 __le32
|
|
+#define __fec16 __le16
|
|
+
|
|
+struct bufdesc {
|
|
+ __fec16 cbd_datlen; /* Data length */
|
|
+ __fec16 cbd_sc; /* Control and status info */
|
|
+ __fec32 cbd_bufaddr; /* Buffer address */
|
|
+};
|
|
+#else
|
|
+#define fec32_to_cpu be32_to_cpu
|
|
+#define fec16_to_cpu be16_to_cpu
|
|
+#define cpu_to_fec32 cpu_to_be32
|
|
+#define cpu_to_fec16 cpu_to_be16
|
|
+#define __fec32 __be32
|
|
+#define __fec16 __be16
|
|
+
|
|
+struct bufdesc {
|
|
+ __fec16 cbd_sc; /* Control and status info */
|
|
+ __fec16 cbd_datlen; /* Data length */
|
|
+ __fec32 cbd_bufaddr; /* Buffer address */
|
|
+};
|
|
+#endif
|
|
+
|
|
+struct bufdesc_ex {
|
|
+ struct bufdesc desc;
|
|
+ __fec32 cbd_esc;
|
|
+ __fec32 cbd_prot;
|
|
+ __fec32 cbd_bdu;
|
|
+ __fec32 ts;
|
|
+ __fec16 res0[4];
|
|
+};
|
|
+
|
|
+/*
|
|
+ * The following definitions courtesy of commproc.h, which where
|
|
+ * Copyright (c) 1997 Dan Malek (dmalek@jlc.net).
|
|
+ */
|
|
+#define BD_SC_EMPTY ((ushort)0x8000) /* Receive is empty */
|
|
+#define BD_SC_READY ((ushort)0x8000) /* Transmit is ready */
|
|
+#define BD_SC_WRAP ((ushort)0x2000) /* Last buffer descriptor */
|
|
+#define BD_SC_INTRPT ((ushort)0x1000) /* Interrupt on change */
|
|
+#define BD_SC_CM ((ushort)0x0200) /* Continuous mode */
|
|
+#define BD_SC_ID ((ushort)0x0100) /* Rec'd too many idles */
|
|
+#define BD_SC_P ((ushort)0x0100) /* xmt preamble */
|
|
+#define BD_SC_BR ((ushort)0x0020) /* Break received */
|
|
+#define BD_SC_FR ((ushort)0x0010) /* Framing error */
|
|
+#define BD_SC_PR ((ushort)0x0008) /* Parity error */
|
|
+#define BD_SC_OV ((ushort)0x0002) /* Overrun */
|
|
+#define BD_SC_CD ((ushort)0x0001) /* ?? */
|
|
+
|
|
+/* Buffer descriptor control/status used by Ethernet receive.
|
|
+ */
|
|
+#define BD_ENET_RX_EMPTY ((ushort)0x8000)
|
|
+#define BD_ENET_RX_WRAP ((ushort)0x2000)
|
|
+#define BD_ENET_RX_INTR ((ushort)0x1000)
|
|
+#define BD_ENET_RX_LAST ((ushort)0x0800)
|
|
+#define BD_ENET_RX_FIRST ((ushort)0x0400)
|
|
+#define BD_ENET_RX_MISS ((ushort)0x0100)
|
|
+#define BD_ENET_RX_LG ((ushort)0x0020)
|
|
+#define BD_ENET_RX_NO ((ushort)0x0010)
|
|
+#define BD_ENET_RX_SH ((ushort)0x0008)
|
|
+#define BD_ENET_RX_CR ((ushort)0x0004)
|
|
+#define BD_ENET_RX_OV ((ushort)0x0002)
|
|
+#define BD_ENET_RX_CL ((ushort)0x0001)
|
|
+#define BD_ENET_RX_STATS ((ushort)0x013f) /* All status bits */
|
|
+
|
|
+/* Enhanced buffer descriptor control/status used by Ethernet receive */
|
|
+#define BD_ENET_RX_VLAN 0x00000004
|
|
+
|
|
+/* Buffer descriptor control/status used by Ethernet transmit.
|
|
+ */
|
|
+#define BD_ENET_TX_READY ((ushort)0x8000)
|
|
+#define BD_ENET_TX_PAD ((ushort)0x4000)
|
|
+#define BD_ENET_TX_WRAP ((ushort)0x2000)
|
|
+#define BD_ENET_TX_INTR ((ushort)0x1000)
|
|
+#define BD_ENET_TX_LAST ((ushort)0x0800)
|
|
+#define BD_ENET_TX_TC ((ushort)0x0400)
|
|
+#define BD_ENET_TX_DEF ((ushort)0x0200)
|
|
+#define BD_ENET_TX_HB ((ushort)0x0100)
|
|
+#define BD_ENET_TX_LC ((ushort)0x0080)
|
|
+#define BD_ENET_TX_RL ((ushort)0x0040)
|
|
+#define BD_ENET_TX_RCMASK ((ushort)0x003c)
|
|
+#define BD_ENET_TX_UN ((ushort)0x0002)
|
|
+#define BD_ENET_TX_CSL ((ushort)0x0001)
|
|
+#define BD_ENET_TX_STATS ((ushort)0x0fff) /* All status bits */
|
|
+
|
|
+/* enhanced buffer descriptor control/status used by Ethernet transmit */
|
|
+#define BD_ENET_TX_INT 0x40000000
|
|
+#define BD_ENET_TX_TS 0x20000000
|
|
+#define BD_ENET_TX_PINS 0x10000000
|
|
+#define BD_ENET_TX_IINS 0x08000000
|
|
+
|
|
+
|
|
+/* This device has up to three irqs on some platforms */
|
|
+#define FEC_IRQ_NUM 3
|
|
+
|
|
+/* Maximum number of queues supported
|
|
+ * ENET with AVB IP can support up to 3 independent tx queues and rx queues.
|
|
+ * User can point the queue number that is less than or equal to 3.
|
|
+ */
|
|
+#define FEC_ENET_MAX_TX_QS 3
|
|
+#define FEC_ENET_MAX_RX_QS 3
|
|
+
|
|
+#define FEC_R_DES_START(X) (((X) == 1) ? FEC_R_DES_START_1 : \
|
|
+ (((X) == 2) ? \
|
|
+ FEC_R_DES_START_2 : FEC_R_DES_START_0))
|
|
+#define FEC_X_DES_START(X) (((X) == 1) ? FEC_X_DES_START_1 : \
|
|
+ (((X) == 2) ? \
|
|
+ FEC_X_DES_START_2 : FEC_X_DES_START_0))
|
|
+#define FEC_R_BUFF_SIZE(X) (((X) == 1) ? FEC_R_BUFF_SIZE_1 : \
|
|
+ (((X) == 2) ? \
|
|
+ FEC_R_BUFF_SIZE_2 : FEC_R_BUFF_SIZE_0))
|
|
+
|
|
+#define FEC_DMA_CFG(X) (((X) == 2) ? FEC_DMA_CFG_2 : FEC_DMA_CFG_1)
|
|
+
|
|
+#define DMA_CLASS_EN (1 << 16)
|
|
+#define FEC_RCMR(X) (((X) == 2) ? FEC_RCMR_2 : FEC_RCMR_1)
|
|
+#define IDLE_SLOPE_MASK 0xffff
|
|
+#define IDLE_SLOPE_1 0x200 /* BW fraction: 0.5 */
|
|
+#define IDLE_SLOPE_2 0x200 /* BW fraction: 0.5 */
|
|
+#define IDLE_SLOPE(X) (((X) == 1) ? \
|
|
+ (IDLE_SLOPE_1 & IDLE_SLOPE_MASK) : \
|
|
+ (IDLE_SLOPE_2 & IDLE_SLOPE_MASK))
|
|
+#define RCMR_MATCHEN (0x1 << 16)
|
|
+#define RCMR_CMP_CFG(v, n) (((v) & 0x7) << (n << 2))
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+#define SR_CLASS_A_PRIORITY 3
|
|
+#define SR_CLASS_B_PRIORITY 2
|
|
+#define RCMR_CMP_1 (RCMR_CMP_CFG(SR_CLASS_A_PRIORITY, 0) | \
|
|
+ RCMR_CMP_CFG(SR_CLASS_A_PRIORITY, 1) | \
|
|
+ RCMR_CMP_CFG(SR_CLASS_A_PRIORITY, 2) | \
|
|
+ RCMR_CMP_CFG(SR_CLASS_A_PRIORITY, 3))
|
|
+#define RCMR_CMP_2 (RCMR_CMP_CFG(SR_CLASS_B_PRIORITY, 0) | \
|
|
+ RCMR_CMP_CFG(SR_CLASS_B_PRIORITY, 1) | \
|
|
+ RCMR_CMP_CFG(SR_CLASS_B_PRIORITY, 2) | \
|
|
+ RCMR_CMP_CFG(SR_CLASS_B_PRIORITY, 3))
|
|
+#else
|
|
+#define RCMR_CMP_1 (RCMR_CMP_CFG(0, 0) | RCMR_CMP_CFG(1, 1) | \
|
|
+ RCMR_CMP_CFG(2, 2) | RCMR_CMP_CFG(3, 3))
|
|
+#define RCMR_CMP_2 (RCMR_CMP_CFG(4, 0) | RCMR_CMP_CFG(5, 1) | \
|
|
+ RCMR_CMP_CFG(6, 2) | RCMR_CMP_CFG(7, 3))
|
|
+#endif
|
|
+#define RCMR_CMP(X) (((X) == 1) ? RCMR_CMP_1 : RCMR_CMP_2)
|
|
+#define FEC_TX_BD_FTYPE(X) (((X) & 0xf) << 20)
|
|
+
|
|
+#define FEC_RX_FLUSH(X) (1 << ((X) + 3))
|
|
+
|
|
+#define FEC_TX_SCHEME_CB 0x0 /* Credit based */
|
|
+#define FEC_TX_SCHEME_RR 0x1 /* Round-robin */
|
|
+
|
|
+#define BD_ENET_RX_INT 0x00800000
|
|
+#define BD_ENET_RX_PTP ((ushort)0x0400)
|
|
+#define BD_ENET_RX_ICE 0x00000020
|
|
+#define BD_ENET_RX_PCR 0x00000010
|
|
+#define FLAG_RX_CSUM_ENABLED (BD_ENET_RX_ICE | BD_ENET_RX_PCR)
|
|
+#define FLAG_RX_CSUM_ERROR (BD_ENET_RX_ICE | BD_ENET_RX_PCR)
|
|
+
|
|
+/* Interrupt events/masks. */
|
|
+#define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */
|
|
+#define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */
|
|
+#define FEC_ENET_BABT ((uint)0x20000000) /* Babbling transmitter */
|
|
+#define FEC_ENET_GRA ((uint)0x10000000) /* Graceful stop complete */
|
|
+#define FEC_ENET_TXF_0 ((uint)0x08000000) /* Full frame transmitted */
|
|
+#define FEC_ENET_TXF_1 ((uint)0x00000008) /* Full frame transmitted */
|
|
+#define FEC_ENET_TXF_2 ((uint)0x00000080) /* Full frame transmitted */
|
|
+#define FEC_ENET_TXB ((uint)0x04000000) /* A buffer was transmitted */
|
|
+#define FEC_ENET_RXF_0 ((uint)0x02000000) /* Full frame received */
|
|
+#define FEC_ENET_RXF_1 ((uint)0x00000002) /* Full frame received */
|
|
+#define FEC_ENET_RXF_2 ((uint)0x00000020) /* Full frame received */
|
|
+#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */
|
|
+#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */
|
|
+#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */
|
|
+#define FEC_ENET_WAKEUP ((uint)0x00020000) /* Wakeup request */
|
|
+#define FEC_ENET_TXF (FEC_ENET_TXF_0 | FEC_ENET_TXF_1 | FEC_ENET_TXF_2)
|
|
+#define FEC_ENET_RXF (FEC_ENET_RXF_0 | FEC_ENET_RXF_1 | FEC_ENET_RXF_2)
|
|
+#define FEC_ENET_RXF_GET(X) (((X) == 0) ? FEC_ENET_RXF_0 : \
|
|
+ (((X) == 1) ? FEC_ENET_RXF_1 : \
|
|
+ FEC_ENET_RXF_2))
|
|
+#define FEC_ENET_TS_AVAIL ((uint)0x00010000)
|
|
+#define FEC_ENET_TS_TIMER ((uint)0x00008000)
|
|
+
|
|
+#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF)
|
|
+#define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF))
|
|
+
|
|
+#define FEC_ENET_ETHEREN ((uint)0x00000002)
|
|
+#define FEC_ENET_TXC_DLY ((uint)0x00010000)
|
|
+#define FEC_ENET_RXC_DLY ((uint)0x00020000)
|
|
+
|
|
+/* ENET interrupt coalescing macro define */
|
|
+#define FEC_ITR_CLK_SEL (0x1 << 30)
|
|
+#define FEC_ITR_EN (0x1 << 31)
|
|
+#define FEC_ITR_ICFT(X) (((X) & 0xff) << 20)
|
|
+#define FEC_ITR_ICTT(X) ((X) & 0xffff)
|
|
+#define FEC_ITR_ICFT_DEFAULT 200 /* Set 200 frame count threshold */
|
|
+#define FEC_ITR_ICTT_DEFAULT 1000 /* Set 1000us timer threshold */
|
|
+
|
|
+#define FEC_VLAN_TAG_LEN 0x04
|
|
+#define FEC_ETHTYPE_LEN 0x02
|
|
+
|
|
+/* Controller is ENET-MAC */
|
|
+#define FEC_QUIRK_ENET_MAC (1 << 0)
|
|
+/* Controller needs driver to swap frame */
|
|
+#define FEC_QUIRK_SWAP_FRAME (1 << 1)
|
|
+/* Controller uses gasket */
|
|
+#define FEC_QUIRK_USE_GASKET (1 << 2)
|
|
+/* Controller has GBIT support */
|
|
+#define FEC_QUIRK_HAS_GBIT (1 << 3)
|
|
+/* Controller has extend desc buffer */
|
|
+#define FEC_QUIRK_HAS_BUFDESC_EX (1 << 4)
|
|
+/* Controller has hardware checksum support */
|
|
+#define FEC_QUIRK_HAS_CSUM (1 << 5)
|
|
+/* Controller has hardware vlan support */
|
|
+#define FEC_QUIRK_HAS_VLAN (1 << 6)
|
|
+/* ENET IP errata ERR006358
|
|
+ *
|
|
+ * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously
|
|
+ * detected as not set during a prior frame transmission, then the
|
|
+ * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs
|
|
+ * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in
|
|
+ * frames not being transmitted until there is a 0-to-1 transition on
|
|
+ * ENET_TDAR[TDAR].
|
|
+ */
|
|
+#define FEC_QUIRK_ERR006358 (1 << 7)
|
|
+/* ENET IP hw AVB
|
|
+ *
|
|
+ * i.MX6SX ENET IP add Audio Video Bridging (AVB) feature support.
|
|
+ * - Two class indicators on receive with configurable priority
|
|
+ * - Two class indicators and line speed timer on transmit allowing
|
|
+ * implementation class credit based shapers externally
|
|
+ * - Additional DMA registers provisioned to allow managing up to 3
|
|
+ * independent rings
|
|
+ */
|
|
+#define FEC_QUIRK_HAS_AVB (1 << 8)
|
|
+/* There is a TDAR race condition for mutliQ when the software sets TDAR
|
|
+ * and the UDMA clears TDAR simultaneously or in a small window (2-4 cycles).
|
|
+ * This will cause the udma_tx and udma_tx_arbiter state machines to hang.
|
|
+ * The issue exist at i.MX6SX enet IP.
|
|
+ */
|
|
+#define FEC_QUIRK_ERR007885 (1 << 9)
|
|
+/* ENET Block Guide/ Chapter for the iMX6SX (PELE) address one issue:
|
|
+ * After set ENET_ATCR[Capture], there need some time cycles before the counter
|
|
+ * value is capture in the register clock domain.
|
|
+ * The wait-time-cycles is at least 6 clock cycles of the slower clock between
|
|
+ * the register clock and the 1588 clock. The 1588 ts_clk is fixed to 25Mhz,
|
|
+ * register clock is 66Mhz, so the wait-time-cycles must be greater than 240ns
|
|
+ * (40ns * 6).
|
|
+ */
|
|
+#define FEC_QUIRK_BUG_CAPTURE (1 << 10)
|
|
+/* Controller has only one MDIO bus */
|
|
+#define FEC_QUIRK_SINGLE_MDIO (1 << 11)
|
|
+/* Controller supports RACC register */
|
|
+#define FEC_QUIRK_HAS_RACC (1 << 12)
|
|
+/* Controller supports interrupt coalesc */
|
|
+#define FEC_QUIRK_HAS_COALESCE (1 << 13)
|
|
+/* Interrupt doesn't wake CPU from deep idle */
|
|
+#define FEC_QUIRK_ERR006687 (1 << 14)
|
|
+/* The MIB counters should be cleared and enabled during
|
|
+ * 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)
|
|
+
|
|
+/* Some FEC hardware blocks need the MMFR cleared at setup time to avoid
|
|
+ * the generation of an MII event. This must be avoided in the older
|
|
+ * FEC blocks where it will stop MII events being generated.
|
|
+ */
|
|
+#define FEC_QUIRK_CLEAR_SETUP_MII (1 << 17)
|
|
+
|
|
+/* Some link partners do not tolerate the momentary reset of the REF_CLK
|
|
+ * frequency when the RNCTL register is cleared by hardware reset.
|
|
+ */
|
|
+#define FEC_QUIRK_NO_HARD_RESET (1 << 18)
|
|
+
|
|
+/* i.MX6SX ENET IP supports multiple queues (3 queues), use this quirk to
|
|
+ * represents this ENET IP.
|
|
+ */
|
|
+#define FEC_QUIRK_HAS_MULTI_QUEUES (1 << 19)
|
|
+
|
|
+/* i.MX8MQ ENET IP version add new feature to support IEEE 802.3az EEE
|
|
+ * standard. For the transmission, MAC supply two user registers to set
|
|
+ * Sleep (TS) and Wake (TW) time.
|
|
+ */
|
|
+#define FEC_QUIRK_HAS_EEE (1 << 20)
|
|
+
|
|
+/* i.MX8QM ENET IP version add new feture to generate delayed TXC/RXC
|
|
+ * as an alternative option to make sure it works well with various PHYs.
|
|
+ * For the implementation of delayed clock, ENET takes synchronized 250MHz
|
|
+ * clocks to generate 2ns delay.
|
|
+ */
|
|
+#define FEC_QUIRK_DELAYED_CLKS_SUPPORT (1 << 21)
|
|
+
|
|
+
|
|
+/* i.MX8MQ SoC integration mix wakeup interrupt signal into "int2" interrupt line. */
|
|
+#define FEC_QUIRK_WAKEUP_FROM_INT2 (1 << 22)
|
|
+
|
|
+/* request pmqos during low power */
|
|
+#define FEC_QUIRK_HAS_PMQOS BIT(23)
|
|
+
|
|
+/* Not all FEC hardware block MDIOs support accesses in C45 mode.
|
|
+ * Older blocks in the ColdFire parts do not support it.
|
|
+ */
|
|
+#define FEC_QUIRK_HAS_MDIO_C45 BIT(24)
|
|
+
|
|
+struct bufdesc_prop {
|
|
+ int qid;
|
|
+ /* Address of Rx and Tx buffers */
|
|
+ struct bufdesc *base;
|
|
+ struct bufdesc *last;
|
|
+ struct bufdesc *cur;
|
|
+ void __iomem *reg_desc_active;
|
|
+ dma_addr_t dma;
|
|
+ unsigned short ring_size;
|
|
+ unsigned char dsize;
|
|
+ unsigned char dsize_log2;
|
|
+};
|
|
+
|
|
+struct fec_enet_priv_tx_q {
|
|
+ struct bufdesc_prop bd;
|
|
+ struct bufdesc *dirty_tx;
|
|
+ struct sk_buff *tx_skbuff[FEC_TX_RING_SIZE];
|
|
+
|
|
+ unsigned int tx_bounce_size;
|
|
+
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ unsigned int tx_index;
|
|
+ unsigned char *tx_bounce[FEC_TX_RING_SIZE + 32];
|
|
+#else
|
|
+ unsigned char *tx_bounce[FEC_TX_RING_SIZE];
|
|
+#endif
|
|
+ unsigned short tx_stop_threshold;
|
|
+ unsigned short tx_wake_threshold;
|
|
+
|
|
+ char *tso_hdrs;
|
|
+ dma_addr_t tso_hdrs_dma;
|
|
+
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ unsigned long tx_idle_slope;
|
|
+#endif
|
|
+};
|
|
+
|
|
+struct fec_enet_priv_rx_q {
|
|
+ struct bufdesc_prop bd;
|
|
+ struct sk_buff *rx_skbuff[FEC_RX_RING_SIZE];
|
|
+};
|
|
+
|
|
+struct fec_stop_mode_gpr {
|
|
+ struct regmap *gpr;
|
|
+ u8 reg;
|
|
+ u8 bit;
|
|
+};
|
|
+
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+#define AVB_DMA_MAPPING 1
|
|
+#endif
|
|
+
|
|
+/* The FEC buffer descriptors track the ring buffers. The rx_bd_base and
|
|
+ * tx_bd_base always point to the base of the buffer descriptors. The
|
|
+ * cur_rx and cur_tx point to the currently available buffer.
|
|
+ * The dirty_tx tracks the current buffer that is being sent by the
|
|
+ * controller. The cur_tx and dirty_tx are equal under both completely
|
|
+ * empty and completely full conditions. The empty/ready indicator in
|
|
+ * the buffer descriptor determines the actual condition.
|
|
+ */
|
|
+struct fec_enet_private {
|
|
+ /* Hardware registers of the FEC device */
|
|
+ void __iomem *hwp;
|
|
+
|
|
+ struct net_device *netdev;
|
|
+
|
|
+ struct clk *clk_ipg;
|
|
+ struct clk *clk_ahb;
|
|
+ struct clk *clk_ref;
|
|
+ struct clk *clk_enet_out;
|
|
+ struct clk *clk_ptp;
|
|
+ struct clk *clk_2x_txclk;
|
|
+
|
|
+ bool ptp_clk_on;
|
|
+ struct mutex ptp_clk_mutex;
|
|
+ unsigned int num_tx_queues;
|
|
+ unsigned int num_rx_queues;
|
|
+
|
|
+ /* The saved address of a sent-in-place packet/buffer, for skfree(). */
|
|
+ struct fec_enet_priv_tx_q *tx_queue;
|
|
+ struct fec_enet_priv_rx_q *rx_queue;
|
|
+
|
|
+ unsigned int total_tx_ring_size;
|
|
+ unsigned int total_rx_ring_size;
|
|
+
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ const struct avb_ops *avb;
|
|
+ void *avb_data;
|
|
+ unsigned int avb_enabled;
|
|
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_advertising);
|
|
+#endif
|
|
+ struct platform_device *pdev;
|
|
+
|
|
+ int dev_id;
|
|
+
|
|
+ /* Phylib and MDIO interface */
|
|
+ struct mii_bus *mii_bus;
|
|
+ uint phy_speed;
|
|
+ phy_interface_t phy_interface;
|
|
+ struct device_node *phy_node;
|
|
+ bool rgmii_txc_dly;
|
|
+ bool rgmii_rxc_dly;
|
|
+ bool mii_bus_share;
|
|
+ bool rpm_active;
|
|
+ int link;
|
|
+ int full_duplex;
|
|
+ int speed;
|
|
+ int irq[FEC_IRQ_NUM];
|
|
+ bool bufdesc_ex;
|
|
+ int pause_flag;
|
|
+ int wol_flag;
|
|
+ int wake_irq;
|
|
+ u32 quirks;
|
|
+
|
|
+ struct napi_struct napi;
|
|
+ int csum_flags;
|
|
+
|
|
+ struct work_struct tx_timeout_work;
|
|
+
|
|
+ struct ptp_clock *ptp_clock;
|
|
+ struct ptp_clock_info ptp_caps;
|
|
+ unsigned long last_overflow_check;
|
|
+ raw_spinlock_t tmreg_lock;
|
|
+ struct cyclecounter cc;
|
|
+ struct timecounter tc;
|
|
+ int rx_hwtstamp_filter;
|
|
+ u32 base_incval;
|
|
+ u32 cycle_speed;
|
|
+ int hwts_rx_en;
|
|
+ int hwts_tx_en;
|
|
+
|
|
+ /* Transmit and receive latency, depending on link speed, for
|
|
+ * packets timestamps in ns
|
|
+ */
|
|
+ u32 rx_tstamp_latency;
|
|
+ u32 tx_tstamp_latency;
|
|
+
|
|
+ struct delayed_work time_keep;
|
|
+ struct regulator *reg_phy;
|
|
+ struct fec_stop_mode_gpr stop_gpr;
|
|
+ struct pm_qos_request pm_qos_req;
|
|
+
|
|
+ unsigned int tx_align;
|
|
+ unsigned int rx_align;
|
|
+
|
|
+ /* hw interrupt coalesce */
|
|
+ unsigned int rx_pkts_itr;
|
|
+ unsigned int rx_time_itr;
|
|
+ unsigned int tx_pkts_itr;
|
|
+ unsigned int tx_time_itr;
|
|
+ unsigned int itr_clk_rate;
|
|
+
|
|
+ /* tx lpi eee mode */
|
|
+ struct ethtool_eee eee;
|
|
+ unsigned int clk_ref_rate;
|
|
+
|
|
+ u32 rx_copybreak;
|
|
+
|
|
+ /* ptp clock period in ns*/
|
|
+ unsigned int ptp_inc;
|
|
+
|
|
+ /* pps */
|
|
+ int pps_channel;
|
|
+ unsigned int reload_period;
|
|
+ int pps_enable;
|
|
+ unsigned int next_counter;
|
|
+
|
|
+ struct mutex fast_ndev_lock;
|
|
+ struct imx_sc_ipc *ipc_handle;
|
|
+
|
|
+ /* Configured rx/tx timestamps delays for different link speeds
|
|
+ * to compensate for FEC-PHY latency in ns
|
|
+ */
|
|
+ u32 rx_delay_100;
|
|
+ u32 tx_delay_100;
|
|
+ u32 rx_delay_1000;
|
|
+ u32 tx_delay_1000;
|
|
+
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ int rec_channel;
|
|
+ int rec_enable;
|
|
+#endif
|
|
+
|
|
+ u64 ethtool_stats[];
|
|
+};
|
|
+
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+#define FEC_MAX_RATE 400 /* Mbps */
|
|
+#define FEC_MAX_RATE_HAS_AVB 1000 /* Mbps */
|
|
+
|
|
+static inline int fec_max_rate(struct fec_enet_private *fep)
|
|
+{
|
|
+ int max_rate = (fep->quirks & FEC_QUIRK_HAS_AVB) ? FEC_MAX_RATE_HAS_AVB : FEC_MAX_RATE;
|
|
+ return min(max_rate, fep->speed);
|
|
+}
|
|
+
|
|
+#define IDLE_SLOPE_DIVISOR 512
|
|
+#endif
|
|
+
|
|
+void fec_ptp_init(struct platform_device *pdev, int irq_idx);
|
|
+void fec_ptp_stop(struct platform_device *pdev);
|
|
+void fec_ptp_start_cyclecounter(struct net_device *ndev);
|
|
+void fec_ptp_disable_hwts(struct net_device *ndev);
|
|
+int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr);
|
|
+int fec_ptp_get(struct net_device *ndev, struct ifreq *ifr);
|
|
+
|
|
+/****************************************************************************/
|
|
+#endif /* FEC_H */
|
|
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
|
|
index fb0497a4cd79..be3f9740a0b6 100644
|
|
--- a/drivers/net/ethernet/freescale/fec_main.c
|
|
+++ b/drivers/net/ethernet/freescale/fec_main.c
|
|
@@ -79,14 +79,22 @@
|
|
|
|
static void set_multicast_list(struct net_device *ndev);
|
|
static void fec_enet_itr_coal_set(struct net_device *ndev);
|
|
+#ifndef CONFIG_AVB_SUPPORT
|
|
static int fec_enet_xdp_tx_xmit(struct fec_enet_private *fep,
|
|
int cpu, struct xdp_buff *xdp,
|
|
u32 dma_sync_len);
|
|
+#endif
|
|
|
|
#define DRIVER_NAME "fec"
|
|
|
|
static const u16 fec_enet_vlan_pri_to_queue[8] = {0, 0, 1, 1, 1, 2, 2, 2};
|
|
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+/* Idle Slope values specific to AVB capable boards */
|
|
+static const unsigned short idle_slope_values[] = {1, 2, 4, 8, 16, 32, 64, 128,
|
|
+ 256, 384, 512, 640, 768, 896, 1024, 1152, 1280, 1408, 1536};
|
|
+#endif
|
|
+
|
|
/* Pause frame feild and FIFO threshold */
|
|
#define FEC_ENET_FCE (1 << 5)
|
|
#define FEC_ENET_RSEM_V 0x84
|
|
@@ -357,6 +365,24 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
|
|
|
|
static int mii_cnt;
|
|
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+static inline void read16(void *dst, void *src)
|
|
+{
|
|
+#ifdef CONFIG_ARM64
|
|
+ asm volatile ( "ldp x10, x11, [%1]\n\t"
|
|
+ "stp x10, x11, [%0]\n\t"
|
|
+ : : "r" (dst), "r" (src) : "x10", "x11", "memory");
|
|
+#elif CONFIG_ARM
|
|
+ asm volatile ( "ldmia %1, {r5-r8}\n\t"
|
|
+ "stmia %0, {r5-r8}\n\t"
|
|
+ : : "r" (dst), "r" (src) : "r5", "r6", "r7", "r8", "memory");
|
|
+#else
|
|
+ ((u64 *)dst)[0] = ((u64 *)src)[0];
|
|
+ ((u64 *)dst)[1] = ((u64 *)src)[1];
|
|
+#endif
|
|
+}
|
|
+#endif /*CONFIG_AVB_SUPPORT*/
|
|
+
|
|
static struct bufdesc *fec_enet_get_nextdesc(struct bufdesc *bdp,
|
|
struct bufdesc_prop *bd)
|
|
{
|
|
@@ -488,6 +514,253 @@ fec_enet_create_page_pool(struct fec_enet_private *fep,
|
|
return err;
|
|
}
|
|
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+/*
|
|
+ * Sends an AVB buffer on the network.
|
|
+ */
|
|
+int fec_enet_start_xmit_avb(void *data, struct avb_tx_desc *desc)
|
|
+{
|
|
+ struct fec_enet_private *fep = data;
|
|
+ struct bufdesc *bdp;
|
|
+ unsigned short status;
|
|
+ unsigned int index;
|
|
+ struct bufdesc_ex *ebdp;
|
|
+ unsigned long cbd_esc;
|
|
+ unsigned short queue_id = desc->queue_id;
|
|
+ struct fec_enet_priv_tx_q *txq = fep->tx_queue[queue_id];
|
|
+
|
|
+ /* ring buffer base address */
|
|
+ /* registers base address */
|
|
+ /* current descriptor pointer */
|
|
+ bdp = txq->bd.cur;
|
|
+
|
|
+ if (bdp == txq->dirty_tx)
|
|
+ return -2;
|
|
+
|
|
+ status = fec16_to_cpu(bdp->cbd_sc);
|
|
+
|
|
+ if (status & BD_ENET_TX_READY)
|
|
+ return -2;
|
|
+
|
|
+ /* Clear all of the status flags */
|
|
+ status &= ~BD_ENET_TX_STATS;
|
|
+
|
|
+ index = fec_enet_get_bd_index(bdp, &txq->bd);
|
|
+
|
|
+ /* Save desc pointer */
|
|
+ txq->tx_buf[index].buf_p = (void *)desc;
|
|
+
|
|
+ bdp->cbd_datlen = cpu_to_fec16(desc->common.len);
|
|
+ bdp->cbd_bufaddr = cpu_to_fec32(desc->dma_addr);
|
|
+
|
|
+ ebdp = (struct bufdesc_ex *)bdp;
|
|
+
|
|
+ ebdp->cbd_bdu = cpu_to_fec32(0);
|
|
+
|
|
+ if (desc->common.flags & AVB_TX_FLAG_HW_TS)
|
|
+ cbd_esc = BD_ENET_TX_TS | desc->esc;
|
|
+ else
|
|
+ cbd_esc = desc->esc;
|
|
+
|
|
+ if (desc->common.flags & AVB_TX_FLAG_HW_CSUM)
|
|
+ cbd_esc |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;
|
|
+
|
|
+ if (fep->quirks & FEC_QUIRK_HAS_AVB)
|
|
+ cbd_esc |= FEC_TX_BD_FTYPE(txq->bd.qid);
|
|
+
|
|
+ ebdp->cbd_esc = cpu_to_fec32(cbd_esc);
|
|
+
|
|
+ wmb();
|
|
+
|
|
+ bdp->cbd_sc = cpu_to_fec16(status | (BD_ENET_TX_READY | BD_ENET_TX_LAST | BD_ENET_TX_TC));
|
|
+
|
|
+ /* If this was the last BD in the ring, start at the beginning again. */
|
|
+ bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
|
|
+
|
|
+ txq->bd.cur = bdp;
|
|
+
|
|
+ /* Trigger transmission start */
|
|
+ if (!(fep->quirks & FEC_QUIRK_ERR006358))
|
|
+ if (!(fep->quirks & FEC_QUIRK_ERR007885) ||
|
|
+ !readl(txq->bd.reg_desc_active) ||
|
|
+ !readl(txq->bd.reg_desc_active) ||
|
|
+ !readl(txq->bd.reg_desc_active) ||
|
|
+ !readl(txq->bd.reg_desc_active))
|
|
+ writel(0, txq->bd.reg_desc_active);
|
|
+
|
|
+ if (bdp == txq->dirty_tx)
|
|
+ return -1;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(fec_enet_start_xmit_avb);
|
|
+
|
|
+void fec_enet_finish_xmit_avb(void *data, unsigned int queue_id)
|
|
+{
|
|
+ struct fec_enet_private *fep = data;
|
|
+
|
|
+ /* Trigger transmission start */
|
|
+ if (fep->quirks & FEC_QUIRK_ERR006358)
|
|
+ if (!(fep->quirks & FEC_QUIRK_ERR007885) ||
|
|
+ !readl(fep->tx_queue[queue_id]->bd.reg_desc_active) ||
|
|
+ !readl(fep->tx_queue[queue_id]->bd.reg_desc_active) ||
|
|
+ !readl(fep->tx_queue[queue_id]->bd.reg_desc_active) ||
|
|
+ !readl(fep->tx_queue[queue_id]->bd.reg_desc_active))
|
|
+ writel(0, fep->tx_queue[queue_id]->bd.reg_desc_active);
|
|
+}
|
|
+EXPORT_SYMBOL(fec_enet_finish_xmit_avb);
|
|
+
|
|
+/*
|
|
+ * When AVB is enabled, it is the transmit function for the regular
|
|
+ * network traffic. It does not support any SG/TSO skb.
|
|
+ * Frames are posted to the AVB module for further scheduling.
|
|
+ */
|
|
+static int fec_enet_start_xmit_best_effort(struct fec_enet_priv_tx_q *txq,
|
|
+ struct netdev_queue *nq, struct sk_buff *skb, struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ void *bufaddr;
|
|
+ struct avb_tx_desc *desc;
|
|
+ int rc;
|
|
+
|
|
+ if (fep->avb->tx_full(fep->avb_data)) {
|
|
+ netdev_err(ndev, "tx queue full!\n");
|
|
+ return NETDEV_TX_BUSY;
|
|
+ }
|
|
+
|
|
+ /* Protocol checksum off-load for TCP and UDP. */
|
|
+ if (fec_enet_clear_csum(skb, ndev)) {
|
|
+ dev_kfree_skb_any(skb);
|
|
+ ndev->stats.tx_dropped++;
|
|
+ return NETDEV_TX_OK;
|
|
+ }
|
|
+
|
|
+ if (skb_headroom(skb) < sizeof(struct avb_tx_desc)) {
|
|
+ if (pskb_expand_head(skb, sizeof(struct avb_tx_desc), 0, GFP_ATOMIC)) {
|
|
+ dev_kfree_skb_any(skb);
|
|
+ ndev->stats.tx_dropped++;
|
|
+ return NETDEV_TX_OK;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ bufaddr = skb->data;
|
|
+ desc = (struct avb_tx_desc *)(skb->data - sizeof(struct avb_tx_desc));
|
|
+
|
|
+ /* Set buffer length and buffer pointer */
|
|
+ desc->common.offset = sizeof(struct avb_tx_desc);
|
|
+ desc->common.len = skb->len;
|
|
+ desc->queue_id = txq->bd.qid;
|
|
+
|
|
+ if ((((unsigned long) bufaddr) & fep->tx_align) ||
|
|
+ (fep->quirks & FEC_QUIRK_SWAP_FRAME)) {
|
|
+ memcpy(txq->tx_bounce[txq->tx_index], skb->data, skb->len);
|
|
+ bufaddr = txq->tx_bounce[txq->tx_index];
|
|
+
|
|
+ txq->tx_index++;
|
|
+ if (txq->tx_index >= txq->tx_bounce_size)
|
|
+ txq->tx_index = 0;
|
|
+
|
|
+ if (fep->quirks & FEC_QUIRK_SWAP_FRAME)
|
|
+ swap_buffer(bufaddr, skb->len);
|
|
+ }
|
|
+
|
|
+ /* Save skb pointer */
|
|
+ desc->data = skb;
|
|
+ desc->common.flags = AVB_TX_FLAG_SKB;
|
|
+
|
|
+ /* Push the data cache so the CPM does not get stale memory data. */
|
|
+ desc->dma_addr = dma_map_single(&fep->pdev->dev, bufaddr, skb->len, DMA_TO_DEVICE);
|
|
+ if (dma_mapping_error(&fep->pdev->dev, desc->dma_addr)) {
|
|
+ dev_kfree_skb_any(skb);
|
|
+ if (net_ratelimit())
|
|
+ netdev_err(ndev, "Tx DMA memory map failed\n");
|
|
+ return NETDEV_TX_OK;
|
|
+ }
|
|
+
|
|
+ desc->esc = 0;
|
|
+
|
|
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP &&
|
|
+ fep->hwts_tx_en)) {
|
|
+ skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
|
|
+ desc->esc |= BD_ENET_TX_TS;
|
|
+ }
|
|
+
|
|
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
|
|
+ desc->esc |= BD_ENET_TX_PINS | BD_ENET_TX_IINS;
|
|
+
|
|
+ skb_tx_timestamp(skb);
|
|
+
|
|
+ if ((rc = fep->avb->tx(fep->avb_data, desc)) < 0) {
|
|
+ if (rc < -1) {
|
|
+ kfree_skb(skb);
|
|
+ ndev->stats.tx_dropped++;
|
|
+ }
|
|
+
|
|
+ netif_tx_stop_queue(nq);
|
|
+ return NETDEV_TX_OK;
|
|
+ }
|
|
+
|
|
+ return NETDEV_TX_OK;
|
|
+}
|
|
+
|
|
+int fec_enet_set_idle_slope(void *data, unsigned int queue_id,
|
|
+ u32 desired_rate)
|
|
+{
|
|
+ struct fec_enet_private *fep = data;
|
|
+ struct fec_enet_priv_tx_q *txq;
|
|
+ u64 idle_slope;
|
|
+ u32 line_rate;
|
|
+ int i;
|
|
+
|
|
+ if (!fep)
|
|
+ return -EINVAL;
|
|
+
|
|
+ /* Nothing to be done for non-AVB boards */
|
|
+ if (!(fep->quirks & FEC_QUIRK_HAS_AVB))
|
|
+ return 0;
|
|
+
|
|
+ if ((queue_id == 0) || (queue_id >= fep->num_tx_queues))
|
|
+ return -EINVAL;
|
|
+
|
|
+ if ((fep->speed != SPEED_100) && (fep->speed != SPEED_1000))
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ line_rate = fep->speed * 1000000ULL;
|
|
+ if (desired_rate > line_rate)
|
|
+ return -EINVAL;
|
|
+
|
|
+ txq = fep->tx_queue[queue_id];
|
|
+
|
|
+ /*
|
|
+ * Compute the desired Idle-Slope based on the desired rate and use
|
|
+ * the round up to the next integer.
|
|
+ */
|
|
+ idle_slope = (u64)desired_rate * IDLE_SLOPE_DIVISOR + line_rate - desired_rate - 1;
|
|
+ idle_slope = div_u64(idle_slope, line_rate - desired_rate);
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(idle_slope_values); i++)
|
|
+ if (idle_slope <= idle_slope_values[i])
|
|
+ break;
|
|
+
|
|
+ if (i >= ARRAY_SIZE(idle_slope_values))
|
|
+ return -EINVAL;
|
|
+ /*
|
|
+ * If the desired rate is higher than the last available bandwidth
|
|
+ * threshold then we should not configure the Credit-Based shaper
|
|
+ * at all.
|
|
+ */
|
|
+ if (idle_slope > idle_slope_values[i])
|
|
+ return -EINVAL;
|
|
+
|
|
+ txq->tx_idle_slope = idle_slope_values[i];
|
|
+ writel(DMA_CLASS_EN | txq->tx_idle_slope,
|
|
+ fep->hwp + FEC_DMA_CFG(queue_id));
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(fec_enet_set_idle_slope);
|
|
+#endif
|
|
+
|
|
static struct bufdesc *
|
|
fec_enet_txq_submit_frag_skb(struct fec_enet_priv_tx_q *txq,
|
|
struct sk_buff *skb,
|
|
@@ -697,7 +970,12 @@ static int fec_enet_txq_submit_skb(struct fec_enet_priv_tx_q *txq,
|
|
txq->bd.cur = bdp;
|
|
|
|
/* Trigger transmission start */
|
|
- writel(0, txq->bd.reg_desc_active);
|
|
+ if (!(fep->quirks & FEC_QUIRK_ERR007885) ||
|
|
+ !readl(txq->bd.reg_desc_active) ||
|
|
+ !readl(txq->bd.reg_desc_active) ||
|
|
+ !readl(txq->bd.reg_desc_active) ||
|
|
+ !readl(txq->bd.reg_desc_active))
|
|
+ writel(0, txq->bd.reg_desc_active);
|
|
|
|
return 0;
|
|
}
|
|
@@ -914,6 +1192,11 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
|
txq = fep->tx_queue[queue];
|
|
nq = netdev_get_tx_queue(ndev, queue);
|
|
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled)
|
|
+ return fec_enet_start_xmit_best_effort(txq, nq, skb, ndev);
|
|
+#endif
|
|
+
|
|
if (skb_is_gso(skb))
|
|
ret = fec_enet_txq_submit_tso(txq, skb, ndev);
|
|
else
|
|
@@ -938,6 +1221,9 @@ static void fec_enet_bd_init(struct net_device *dev)
|
|
struct bufdesc *bdp;
|
|
unsigned int i;
|
|
unsigned int q;
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ struct sk_buff *skb;
|
|
+#endif
|
|
|
|
for (q = 0; q < fep->num_rx_queues; q++) {
|
|
/* Initialize the receive buffer descriptors. */
|
|
@@ -961,6 +1247,23 @@ static void fec_enet_bd_init(struct net_device *dev)
|
|
rxq->bd.cur = rxq->bd.base;
|
|
}
|
|
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled) {
|
|
+ struct avb_tx_desc *desc;
|
|
+
|
|
+ while ((desc = fep->avb->tx_cleanup_dequeue(fep->avb_data)) != (void *) -1) {
|
|
+
|
|
+ skb = desc->data;
|
|
+
|
|
+ dma_unmap_single(&fep->pdev->dev, desc->bufaddr,
|
|
+ skb->len, DMA_TO_DEVICE);
|
|
+
|
|
+ /* Free the sk buffer associated with this last transmit */
|
|
+ dev_kfree_skb_any(skb);
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
for (q = 0; q < fep->num_tx_queues; q++) {
|
|
/* ...and the same for transmit */
|
|
txq = fep->tx_queue[q];
|
|
@@ -970,6 +1273,42 @@ static void fec_enet_bd_init(struct net_device *dev)
|
|
for (i = 0; i < txq->bd.ring_size; i++) {
|
|
/* Initialize the BD for every fragment in the page. */
|
|
bdp->cbd_sc = cpu_to_fec16(0);
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ /* AVB not compatible with XDP: all buffers are either avb descriptors or skbs. */
|
|
+ if (txq->tx_buf[i].buf_p) {
|
|
+ skb = NULL;
|
|
+ if (fep->avb_enabled) {
|
|
+ struct avb_tx_desc *desc = (struct avb_tx_desc *)txq->tx_buf[i].buf_p;
|
|
+
|
|
+ if (!(desc->common.flags & AVB_TX_FLAG_SKB)) {
|
|
+ fep->avb->free(fep->avb_data, &desc->common);
|
|
+ /* Avoid unmapping AVB buffers below */
|
|
+ bdp->cbd_bufaddr = cpu_to_fec32(0);
|
|
+ } else {
|
|
+ skb = desc->data;
|
|
+ }
|
|
+ } else
|
|
+ skb = txq->tx_buf[i].buf_p;
|
|
+
|
|
+ if (skb) {
|
|
+ dev_kfree_skb_any(skb);
|
|
+ }
|
|
+
|
|
+ txq->tx_buf[i].buf_p = NULL;
|
|
+ }
|
|
+
|
|
+ if (bdp->cbd_bufaddr &&
|
|
+ !IS_TSO_HEADER(txq, fec32_to_cpu(bdp->cbd_bufaddr)))
|
|
+ dma_unmap_single(&fep->pdev->dev,
|
|
+ fec32_to_cpu(bdp->cbd_bufaddr),
|
|
+ fec16_to_cpu(bdp->cbd_datlen),
|
|
+ DMA_TO_DEVICE);
|
|
+ if (txq->tx_buf[i].buf_p) {
|
|
+ dev_kfree_skb_any(txq->tx_buf[i].buf_p);
|
|
+ txq->tx_buf[i].buf_p = NULL;
|
|
+ }
|
|
+
|
|
+#else
|
|
if (txq->tx_buf[i].type == FEC_TXBUF_T_SKB) {
|
|
if (bdp->cbd_bufaddr &&
|
|
!IS_TSO_HEADER(txq, fec32_to_cpu(bdp->cbd_bufaddr)))
|
|
@@ -998,6 +1337,7 @@ static void fec_enet_bd_init(struct net_device *dev)
|
|
txq->tx_buf[i].buf_p = NULL;
|
|
/* restore default tx buffer type: FEC_TXBUF_T_SKB */
|
|
txq->tx_buf[i].type = FEC_TXBUF_T_SKB;
|
|
+#endif
|
|
bdp->cbd_bufaddr = cpu_to_fec32(0);
|
|
bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
|
|
}
|
|
@@ -1023,6 +1363,7 @@ static void fec_enet_enable_ring(struct net_device *ndev)
|
|
struct fec_enet_private *fep = netdev_priv(ndev);
|
|
struct fec_enet_priv_tx_q *txq;
|
|
struct fec_enet_priv_rx_q *rxq;
|
|
+ unsigned long idle_slope;
|
|
int i;
|
|
|
|
for (i = 0; i < fep->num_rx_queues; i++) {
|
|
@@ -1041,10 +1382,25 @@ static void fec_enet_enable_ring(struct net_device *ndev)
|
|
writel(txq->bd.dma, fep->hwp + FEC_X_DES_START(i));
|
|
|
|
/* enable DMA1/2 */
|
|
- if (i)
|
|
- writel(DMA_CLASS_EN | IDLE_SLOPE(i),
|
|
+ if (i) {
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ idle_slope = txq->tx_idle_slope;
|
|
+#else
|
|
+ idle_slope = IDLE_SLOPE(i);
|
|
+#endif
|
|
+
|
|
+ writel(DMA_CLASS_EN | idle_slope,
|
|
fep->hwp + FEC_DMA_CFG(i));
|
|
+ }
|
|
}
|
|
+
|
|
+ /*
|
|
+ * For AVB capable devices we should enable RX flushing for the
|
|
+ * best effort queue (ring 0) and also the TX credit based shaper.
|
|
+ */
|
|
+ if (fep->quirks & FEC_QUIRK_HAS_AVB)
|
|
+ writel(FEC_RX_FLUSH(0) | FEC_TX_SCHEME_CB,
|
|
+ fep->hwp + FEC_QOS_SCHEME);
|
|
}
|
|
|
|
/*
|
|
@@ -1064,13 +1420,7 @@ fec_restart(struct net_device *ndev)
|
|
* For i.MX6SX SOC, enet use AXI bus, we use disable MAC
|
|
* instead of reset MAC itself.
|
|
*/
|
|
- if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES ||
|
|
- ((fep->quirks & FEC_QUIRK_NO_HARD_RESET) && fep->link)) {
|
|
- writel(0, fep->hwp + FEC_ECNTRL);
|
|
- } else {
|
|
- writel(1, fep->hwp + FEC_ECNTRL);
|
|
- udelay(10);
|
|
- }
|
|
+ writel(0, fep->hwp + FEC_ECNTRL);
|
|
|
|
/*
|
|
* enet-mac reset will reset mac address registers too,
|
|
@@ -1227,9 +1577,6 @@ fec_restart(struct net_device *ndev)
|
|
writel(ecntl, fep->hwp + FEC_ECNTRL);
|
|
fec_enet_active_rxring(ndev);
|
|
|
|
- if (fep->bufdesc_ex)
|
|
- fec_ptp_start_cyclecounter(ndev);
|
|
-
|
|
/* Enable interrupts we wish to service */
|
|
if (fep->link)
|
|
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
|
|
@@ -1319,17 +1666,14 @@ fec_stop(struct net_device *ndev)
|
|
netdev_err(ndev, "Graceful transmit stop did not complete!\n");
|
|
}
|
|
|
|
- /* Whack a reset. We should wait for this.
|
|
- * For i.MX6SX SOC, enet use AXI bus, we use disable MAC
|
|
- * instead of reset MAC itself.
|
|
- */
|
|
if (!(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) {
|
|
- if (fep->quirks & FEC_QUIRK_HAS_MULTI_QUEUES) {
|
|
- writel(0, fep->hwp + FEC_ECNTRL);
|
|
- } else {
|
|
- writel(FEC_ECR_RESET, fep->hwp + FEC_ECNTRL);
|
|
- udelay(10);
|
|
- }
|
|
+ /* Always use disable MAC instead of MAC reset to:
|
|
+ * - Keep the ENET counter running
|
|
+ * - Avoid dead system bus for SoCs using the ENET-AXI bus
|
|
+ * and not the AHB bus, like the i.MX6SX
|
|
+ */
|
|
+ writel(0, fep->hwp + FEC_ECNTRL);
|
|
+
|
|
} else {
|
|
val = readl(fep->hwp + FEC_ECNTRL);
|
|
val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP);
|
|
@@ -1374,7 +1718,15 @@ static void fec_enet_timeout_work(struct work_struct *work)
|
|
if (netif_device_present(ndev) || netif_running(ndev)) {
|
|
napi_disable(&fep->napi);
|
|
netif_tx_lock_bh(ndev);
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled)
|
|
+ fep->avb->close(fep->avb_data);
|
|
+#endif
|
|
fec_restart(ndev);
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled)
|
|
+ fep->avb->open(fep->avb_data, fep, fec_max_rate(fep));
|
|
+#endif
|
|
netif_tx_wake_all_queues(ndev);
|
|
netif_tx_unlock_bh(ndev);
|
|
napi_enable(&fep->napi);
|
|
@@ -1389,14 +1741,194 @@ fec_enet_hwtstamp(struct fec_enet_private *fep, unsigned ts,
|
|
unsigned long flags;
|
|
u64 ns;
|
|
|
|
- spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
+ raw_spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
ns = timecounter_cyc2time(&fep->tc, ts);
|
|
- spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
|
|
memset(hwtstamps, 0, sizeof(*hwtstamps));
|
|
hwtstamps->hwtstamp = ns_to_ktime(ns);
|
|
}
|
|
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+static int
|
|
+fec_enet_tx_queue_avb(struct net_device *ndev, u16 queue_id)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ struct bufdesc *bdp;
|
|
+ struct bufdesc_ex local_ebdp;
|
|
+ struct avb_tx_desc *desc;
|
|
+ unsigned short status;
|
|
+ struct fec_enet_priv_tx_q *txq;
|
|
+ struct netdev_queue *nq;
|
|
+ int index = 0;
|
|
+ int rc = 0;
|
|
+ unsigned int total_tx_packets = 0;
|
|
+ unsigned int total_tx_bytes = 0;
|
|
+ u16 tx_tstamp_latency = fep->tx_tstamp_latency;
|
|
+
|
|
+ txq = fep->tx_queue[queue_id];
|
|
+ nq = netdev_get_tx_queue(ndev, queue_id);
|
|
+
|
|
+ bdp = txq->dirty_tx;
|
|
+
|
|
+ /* get next bdp of dirty_tx */
|
|
+ bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
|
|
+
|
|
+ while (bdp != READ_ONCE(txq->bd.cur)) {
|
|
+ /* Order the load of cur_tx and cbd_sc */
|
|
+ rmb();
|
|
+
|
|
+ /* Read the first 16 bytes of the descriptor at once to avoid
|
|
+ * multiple reads of non cacheable memory from RAM */
|
|
+ read16(&local_ebdp, bdp);
|
|
+
|
|
+ status = fec16_to_cpu(local_ebdp.desc.cbd_sc);
|
|
+ if (status & BD_ENET_TX_READY)
|
|
+ break;
|
|
+
|
|
+ index = fec_enet_get_bd_index(bdp, &txq->bd);
|
|
+ desc = (struct avb_tx_desc *)txq->tx_buf[index].buf_p;
|
|
+
|
|
+ if (!(desc->common.flags & AVB_TX_FLAG_SKB)) {
|
|
+ if ((desc->common.flags & AVB_TX_FLAG_HW_TS)) {
|
|
+ struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
|
|
+
|
|
+ desc->common.ts = ebdp->ts + tx_tstamp_latency;
|
|
+
|
|
+ /* upper layer will retrieve the timestamp and free the descriptor */
|
|
+ rc |= fep->avb->tx_ts(fep->avb_data, &desc->common);
|
|
+ }
|
|
+ else
|
|
+ fep->avb->free(fep->avb_data, &desc->common);
|
|
+
|
|
+ total_tx_packets++;
|
|
+ total_tx_bytes += desc->datlen;
|
|
+ } else {
|
|
+ /* Backup hardware descriptor fields in software descriptor */
|
|
+ desc->sc = status;
|
|
+ desc->datlen = fec16_to_cpu(local_ebdp.desc.cbd_datlen);
|
|
+ desc->bufaddr = fec32_to_cpu(local_ebdp.desc.cbd_bufaddr);
|
|
+ desc->common.ts = fec32_to_cpu(((struct bufdesc_ex *)bdp)->ts);
|
|
+
|
|
+ if (fep->avb->tx_cleanup(fep->avb_data, desc) < 0)
|
|
+ BUG();
|
|
+ }
|
|
+
|
|
+ txq->tx_buf[index].buf_p = NULL;
|
|
+ bdp->cbd_bufaddr = cpu_to_fec32(0);
|
|
+ txq->dirty_tx = bdp;
|
|
+
|
|
+ /* Update pointer to next buffer descriptor to be transmitted */
|
|
+ bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
|
|
+ }
|
|
+
|
|
+ /* schedule tx napi, based on level of tx cleanup queue or time passed */
|
|
+ if (fep->avb->tx_cleanup_ready(fep->avb_data) || netif_tx_queue_stopped(nq)) {
|
|
+ if (napi_schedule_prep(&fep->napi)) {
|
|
+ __napi_schedule(&fep->napi);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Update stats*/
|
|
+ ndev->stats.tx_packets += total_tx_packets;
|
|
+ ndev->stats.tx_bytes += total_tx_bytes;
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int
|
|
+fec_enet_tx_avb(void *data)
|
|
+{
|
|
+ struct fec_enet_private *fep = data;
|
|
+ u16 queue_id;
|
|
+ int rc = 0;
|
|
+
|
|
+ for (queue_id = 0; queue_id < fep->num_tx_queues; queue_id++)
|
|
+ rc |= fec_enet_tx_queue_avb(fep->netdev, queue_id);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+EXPORT_SYMBOL(fec_enet_tx_avb);
|
|
+
|
|
+static void
|
|
+fec_enet_tx_best_effort(struct net_device *ndev)
|
|
+{
|
|
+ struct fec_enet_private *fep;
|
|
+ unsigned short status;
|
|
+ struct avb_tx_desc *desc;
|
|
+ struct sk_buff *skb;
|
|
+ struct fec_enet_priv_tx_q *txq;
|
|
+ struct netdev_queue *nq;
|
|
+
|
|
+ fep = netdev_priv(ndev);
|
|
+
|
|
+ while ((desc = fep->avb->tx_cleanup_dequeue(fep->avb_data)) != (void *) -1) {
|
|
+
|
|
+ txq = fep->tx_queue[desc->queue_id];
|
|
+ nq = netdev_get_tx_queue(ndev, desc->queue_id);
|
|
+
|
|
+ status = desc->sc;
|
|
+
|
|
+ /* Check for errors. */
|
|
+ if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
|
|
+ BD_ENET_TX_RL | BD_ENET_TX_UN |
|
|
+ BD_ENET_TX_CSL)) {
|
|
+ ndev->stats.tx_errors++;
|
|
+ if (status & BD_ENET_TX_HB) /* No heartbeat */
|
|
+ ndev->stats.tx_heartbeat_errors++;
|
|
+ if (status & BD_ENET_TX_LC) /* Late collision */
|
|
+ ndev->stats.tx_window_errors++;
|
|
+ if (status & BD_ENET_TX_RL) /* Retrans limit */
|
|
+ ndev->stats.tx_aborted_errors++;
|
|
+ if (status & BD_ENET_TX_UN) /* Underrun */
|
|
+ ndev->stats.tx_fifo_errors++;
|
|
+ if (status & BD_ENET_TX_CSL) /* Carrier lost */
|
|
+ ndev->stats.tx_carrier_errors++;
|
|
+ } else {
|
|
+ ndev->stats.tx_packets++;
|
|
+ ndev->stats.tx_bytes += desc->datlen;
|
|
+ }
|
|
+
|
|
+ skb = desc->data;
|
|
+
|
|
+ if (!IS_TSO_HEADER(txq, desc->bufaddr))
|
|
+ dma_unmap_single(&fep->pdev->dev, desc->bufaddr,
|
|
+ desc->datlen, DMA_TO_DEVICE);
|
|
+
|
|
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) {
|
|
+ struct skb_shared_hwtstamps shhwtstamps;
|
|
+
|
|
+ desc->common.ts += fep->tx_tstamp_latency;
|
|
+ fec_enet_hwtstamp(fep, desc->common.ts,
|
|
+ &shhwtstamps);
|
|
+ skb_tstamp_tx(skb, &shhwtstamps);
|
|
+ }
|
|
+
|
|
+ /* Deferred means some collisions occurred during transmit,
|
|
+ * but we eventually sent the packet OK.
|
|
+ */
|
|
+ if (status & BD_ENET_TX_DEF)
|
|
+ ndev->stats.collisions++;
|
|
+
|
|
+ /* Free the sk buffer associated with this last transmit */
|
|
+ dev_kfree_skb_any(skb);
|
|
+
|
|
+ /* Make sure the update to bdp and tx_buf are performed
|
|
+ * before dirty_tx
|
|
+ */
|
|
+ wmb();
|
|
+
|
|
+ //FIXME add treshold
|
|
+ if (!fep->avb->tx_full(fep->avb_data)) {
|
|
+ if (netif_tx_queue_stopped(nq)) {
|
|
+ //` netdev_info(ndev, "wake queue\n");
|
|
+ netif_tx_wake_queue(nq);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+}
|
|
+#endif
|
|
+
|
|
static void
|
|
fec_enet_tx_queue(struct net_device *ndev, u16 queue_id, int budget)
|
|
{
|
|
@@ -1512,6 +2044,11 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id, int budget)
|
|
struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
|
|
|
|
fec_enet_hwtstamp(fep, fec32_to_cpu(ebdp->ts), &shhwtstamps);
|
|
+ /* Adjust for TX MAC-PHY latency
|
|
+ */
|
|
+ shhwtstamps.hwtstamp =
|
|
+ ktime_add_ns(shhwtstamps.hwtstamp, fep->tx_tstamp_latency);
|
|
+
|
|
skb_tstamp_tx(skb, &shhwtstamps);
|
|
}
|
|
|
|
@@ -1578,6 +2115,7 @@ static void fec_enet_update_cbd(struct fec_enet_priv_rx_q *rxq,
|
|
bdp->cbd_bufaddr = cpu_to_fec32(phys_addr);
|
|
}
|
|
|
|
+#ifndef CONFIG_AVB_SUPPORT
|
|
static u32
|
|
fec_enet_run_xdp(struct fec_enet_private *fep, struct bpf_prog *prog,
|
|
struct xdp_buff *xdp, struct fec_enet_priv_rx_q *rxq, int cpu)
|
|
@@ -1619,29 +2157,299 @@ fec_enet_run_xdp(struct fec_enet_private *fep, struct bpf_prog *prog,
|
|
goto xdp_err;
|
|
}
|
|
|
|
- ret = FEC_ENET_XDP_TX;
|
|
- break;
|
|
+ ret = FEC_ENET_XDP_TX;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ bpf_warn_invalid_xdp_action(fep->netdev, prog, act);
|
|
+ fallthrough;
|
|
+
|
|
+ case XDP_ABORTED:
|
|
+ fallthrough; /* handle aborts by dropping packet */
|
|
+
|
|
+ case XDP_DROP:
|
|
+ rxq->stats[RX_XDP_DROP]++;
|
|
+xdp_err:
|
|
+ ret = FEC_ENET_XDP_CONSUMED;
|
|
+ page = virt_to_head_page(xdp->data);
|
|
+ page_pool_put_page(rxq->page_pool, page, sync, true);
|
|
+ if (act != XDP_DROP)
|
|
+ trace_xdp_exception(fep->netdev, prog, act);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+#else /* CONFIG_AVB_SUPPORT */
|
|
+
|
|
+static int
|
|
+fec_enet_rx_best_effort(struct net_device *ndev, int budget)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ struct avb_rx_desc *desc;
|
|
+ struct sk_buff *skb;
|
|
+ ushort pkt_len;
|
|
+ __u8 *data;
|
|
+ bool vlan_packet_rcvd = false;
|
|
+ u16 vlan_tag;
|
|
+ int pkt_received = 0;
|
|
+
|
|
+ do {
|
|
+ desc = fep->avb->dequeue(fep->avb_data);
|
|
+ if (desc == (void *)-1)
|
|
+ break;
|
|
+
|
|
+ /* Process the incoming frame. */
|
|
+ pkt_len = desc->common.len;
|
|
+ data = (u8 *)desc + desc->common.offset;
|
|
+
|
|
+ skb = netdev_alloc_skb(ndev, pkt_len - 4);
|
|
+ if (unlikely(!skb)) {
|
|
+ ndev->stats.rx_dropped++;
|
|
+ goto rx_processing_done;
|
|
+ }
|
|
+ else {
|
|
+ /* Make some room minus FCS */
|
|
+ skb_put(skb, pkt_len - 4);
|
|
+
|
|
+ /* Copy AVB buffer to skb */
|
|
+ skb_copy_to_linear_data(skb, data, pkt_len - 4);
|
|
+ data = skb->data;
|
|
+
|
|
+ /* Get receive timestamp from the skb */
|
|
+ if (fep->hwts_rx_en) {
|
|
+ skb_reset_mac_header(skb);
|
|
+ fec_enet_hwtstamp(fep, desc->common.ts,
|
|
+ skb_hwtstamps(skb));
|
|
+ }
|
|
+
|
|
+ /* If this is a VLAN packet remove the VLAN Tag */
|
|
+ vlan_packet_rcvd = false;
|
|
+ if (desc->common.private & BD_ENET_RX_VLAN) {
|
|
+ /* Push and remove the vlan tag */
|
|
+ struct vlan_hdr *vlan_header =
|
|
+ (struct vlan_hdr *) (data + ETH_HLEN);
|
|
+ vlan_tag = ntohs(vlan_header->h_vlan_TCI);
|
|
+
|
|
+ vlan_packet_rcvd = true;
|
|
+
|
|
+ memmove(skb->data + VLAN_HLEN, data, ETH_ALEN * 2);
|
|
+
|
|
+ skb_pull(skb, VLAN_HLEN);
|
|
+ }
|
|
+
|
|
+ skb->protocol = eth_type_trans(skb, ndev);
|
|
+
|
|
+ if (fep->csum_flags & FLAG_RX_CSUM_ENABLED) {
|
|
+ if (!(desc->common.private & FLAG_RX_CSUM_ERROR)) {
|
|
+ /* don't check it */
|
|
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
+ } else {
|
|
+ skb_checksum_none_assert(skb);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Handle received VLAN packets */
|
|
+ if (vlan_packet_rcvd)
|
|
+ __vlan_hwaccel_put_tag(skb,
|
|
+ htons(ETH_P_8021Q),
|
|
+ vlan_tag);
|
|
+
|
|
+ napi_gro_receive(&fep->napi, skb);
|
|
+ }
|
|
+rx_processing_done:
|
|
+ fep->avb->free(fep->avb_data, &desc->common);
|
|
+
|
|
+ } while (++pkt_received < budget);
|
|
+
|
|
+ return pkt_received;
|
|
+}
|
|
+
|
|
+static unsigned int
|
|
+fec_enet_rx_queue_avb(struct net_device *ndev, u16 queue_id)
|
|
+{
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ struct fec_enet_priv_rx_q *rxq;
|
|
+ struct bufdesc *bdp;
|
|
+ unsigned short status;
|
|
+ ushort pkt_len;
|
|
+ __u8 *data, *new_data;
|
|
+ int index = 0;
|
|
+ struct bufdesc_ex *ebdp = NULL;
|
|
+ struct bufdesc_ex local_ebdp;
|
|
+ struct avb_rx_desc *desc;
|
|
+ unsigned int rc = 0;
|
|
+ unsigned int net_data_offset;
|
|
+ unsigned int count = 0;
|
|
+ unsigned int total_rx_packets = 0;
|
|
+ unsigned int total_rx_bytes = 0;
|
|
+ u16 rx_tstamp_latency = fep->rx_tstamp_latency;
|
|
+ bool need_swap = fep->quirks & FEC_QUIRK_SWAP_FRAME;
|
|
+ bool has_racc = fep->quirks & FEC_QUIRK_HAS_RACC;
|
|
+
|
|
+ rxq = fep->rx_queue[queue_id];
|
|
+
|
|
+ /* First, grab all of the stats for the incoming packet.
|
|
+ * These get messed up if we get called due to a busy condition.
|
|
+ */
|
|
+ bdp = rxq->bd.cur;
|
|
+
|
|
+ /* 20 packets per 125us > 64 bytes packets @ 100Mbps */
|
|
+ while (!((status = fec16_to_cpu(bdp->cbd_sc)) & BD_ENET_RX_EMPTY) && (count++ < 20)) {
|
|
+
|
|
+ writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT);
|
|
+
|
|
+ /* Read the first 16 bytes of the descriptor at once to avoid
|
|
+ * multiple reads of non cacheable memory from RAM */
|
|
+ read16(&local_ebdp, bdp);
|
|
+
|
|
+ /* Check for errors. */
|
|
+ status ^= BD_ENET_RX_LAST;
|
|
+ if (unlikely(status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
|
|
+ BD_ENET_RX_CR | BD_ENET_RX_OV | BD_ENET_RX_LAST |
|
|
+ BD_ENET_RX_CL))) {
|
|
+ ndev->stats.rx_errors++;
|
|
+ if (status & BD_ENET_RX_OV) {
|
|
+ /* FIFO overrun */
|
|
+ ndev->stats.rx_fifo_errors++;
|
|
+ goto rx_processing_done;
|
|
+ }
|
|
+ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH
|
|
+ | BD_ENET_RX_LAST)) {
|
|
+ /* Frame too long or too short. */
|
|
+ ndev->stats.rx_length_errors++;
|
|
+ if (status & BD_ENET_RX_LAST)
|
|
+ netdev_err(ndev, "rcv is not +last\n");
|
|
+ }
|
|
+ if (status & BD_ENET_RX_CR) /* CRC Error */
|
|
+ ndev->stats.rx_crc_errors++;
|
|
+ /* Report late collisions as a frame error. */
|
|
+ if (status & (BD_ENET_RX_NO | BD_ENET_RX_CL))
|
|
+ ndev->stats.rx_frame_errors++;
|
|
+ goto rx_processing_done;
|
|
+ }
|
|
+
|
|
+ new_data = fep->avb->alloc(fep->avb_data);
|
|
+ if (unlikely(!new_data)) {
|
|
+ ndev->stats.rx_dropped++;
|
|
+ goto rx_processing_done;
|
|
+ }
|
|
+
|
|
+ /* Process the incoming frame. */
|
|
+ total_rx_packets++;
|
|
+ pkt_len = fec16_to_cpu(local_ebdp.desc.cbd_datlen);
|
|
+ total_rx_bytes += pkt_len;
|
|
+ index = fec_enet_get_bd_index(bdp, &rxq->bd);
|
|
+ data = (__u8 *)rxq->rx_skb_info[index].skb;
|
|
+
|
|
+ /* FIXME, skip unmap of audio data */
|
|
+ dma_sync_single_for_cpu(&fep->pdev->dev, fec32_to_cpu(local_ebdp.desc.cbd_bufaddr),
|
|
+ L1_CACHE_ALIGN(pkt_len), DMA_FROM_DEVICE);
|
|
+
|
|
+ desc = (struct avb_rx_desc *)data;
|
|
+
|
|
+ net_data_offset = desc->common.offset;
|
|
+
|
|
+#if !defined(CONFIG_M5272)
|
|
+ if (has_racc)
|
|
+ net_data_offset -= 2;
|
|
+#endif
|
|
+ prefetch(data + net_data_offset);
|
|
+
|
|
+ if (need_swap)
|
|
+ swap_buffer(data, pkt_len);
|
|
+
|
|
+ desc->common.len = pkt_len;
|
|
+ desc->sc = fec16_to_cpu(local_ebdp.desc.cbd_sc);
|
|
+
|
|
+ /* Extract the enhanced buffer descriptor */
|
|
+ ebdp = (struct bufdesc_ex *)bdp;
|
|
+
|
|
+ desc->common.ts = ebdp->ts - rx_tstamp_latency;
|
|
+ desc->common.private = fec32_to_cpu(local_ebdp.cbd_esc);
|
|
+
|
|
+ rc |= fep->avb->rx(fep->avb_data, desc);
|
|
+
|
|
+ data = new_data;
|
|
+
|
|
+ desc = (struct avb_rx_desc *)data;
|
|
+
|
|
+ desc->common.len = 0;
|
|
+ desc->queue_id = queue_id;
|
|
+
|
|
+ bdp->cbd_bufaddr = cpu_to_fec32((dma_addr_t)(desc->dma_addr));
|
|
+
|
|
+#if !defined(CONFIG_M5272)
|
|
+ if (has_racc)
|
|
+ desc->common.offset += 2;
|
|
+#endif
|
|
+ rxq->rx_skb_info[index].skb = (void *)data;
|
|
+rx_processing_done:
|
|
+ /* Clear the status flags for this buffer */
|
|
+ status &= ~BD_ENET_RX_STATS;
|
|
+
|
|
+ /* Mark the buffer empty */
|
|
+ status |= BD_ENET_RX_EMPTY;
|
|
+ bdp->cbd_sc = cpu_to_fec16(status);
|
|
+
|
|
+ ebdp = (struct bufdesc_ex *)bdp;
|
|
+
|
|
+ ebdp->cbd_esc = cpu_to_fec32(0);
|
|
+ ebdp->cbd_prot = cpu_to_fec32(0);
|
|
+ ebdp->cbd_bdu = cpu_to_fec32(0);
|
|
+
|
|
+ /* Update BD pointer to next entry */
|
|
+
|
|
+ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd);
|
|
+ }
|
|
+
|
|
+ /* If the receive ring buffer can hold at least double the maximum
|
|
+ number of packets per polling period (18.2 packets @ 100Mbps), it's
|
|
+ ok to only re-enable receive after processing all current packets */
|
|
+
|
|
+ writel(0, rxq->bd.reg_desc_active);
|
|
+
|
|
+ rxq->bd.cur = bdp;
|
|
+
|
|
+ /*Update stats*/
|
|
+ ndev->stats.rx_packets += total_rx_packets;
|
|
+ ndev->stats.rx_bytes += total_rx_bytes;
|
|
+
|
|
+ return rc;
|
|
+}
|
|
|
|
- default:
|
|
- bpf_warn_invalid_xdp_action(fep->netdev, prog, act);
|
|
- fallthrough;
|
|
+static unsigned int
|
|
+fec_enet_rx_avb(struct net_device *ndev)
|
|
+{
|
|
+ u16 queue_id;
|
|
+ struct fec_enet_private *fep = netdev_priv(ndev);
|
|
+ unsigned int rc = 0;
|
|
|
|
- case XDP_ABORTED:
|
|
- fallthrough; /* handle aborts by dropping packet */
|
|
+ for (queue_id = 0; queue_id < fep->num_rx_queues; queue_id++)
|
|
+ rc |= fec_enet_rx_queue_avb(ndev, queue_id);
|
|
|
|
- case XDP_DROP:
|
|
- rxq->stats[RX_XDP_DROP]++;
|
|
-xdp_err:
|
|
- ret = FEC_ENET_XDP_CONSUMED;
|
|
- page = virt_to_head_page(xdp->data);
|
|
- page_pool_put_page(rxq->page_pool, page, sync, true);
|
|
- if (act != XDP_DROP)
|
|
- trace_xdp_exception(fep->netdev, prog, act);
|
|
- break;
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int fec_enet_rx_poll_avb(void *data)
|
|
+{
|
|
+ struct fec_enet_private *fep = data;
|
|
+ struct net_device *ndev = fep->netdev;
|
|
+ unsigned int rc;
|
|
+
|
|
+ rc = fec_enet_rx_avb(ndev);
|
|
+
|
|
+ if (rc & AVB_WAKE_NAPI) {
|
|
+ /* Best effort packets were posted, schedule napi if not scheduled yet. */
|
|
+ if (napi_schedule_prep(&fep->napi))
|
|
+ __napi_schedule(&fep->napi);
|
|
}
|
|
|
|
- return ret;
|
|
+ return rc;
|
|
}
|
|
+EXPORT_SYMBOL(fec_enet_rx_poll_avb);
|
|
+
|
|
+#endif /* CONFIG_AVB_SUPPORT */
|
|
|
|
/* During a receive, the bd_rx.cur points to the current incoming buffer.
|
|
* When we update through the ring, if the next incoming buffer has
|
|
@@ -1664,11 +2472,13 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
|
|
u16 vlan_tag;
|
|
int index = 0;
|
|
bool need_swap = fep->quirks & FEC_QUIRK_SWAP_FRAME;
|
|
+#ifndef CONFIG_AVB_SUPPORT
|
|
struct bpf_prog *xdp_prog = READ_ONCE(fep->xdp_prog);
|
|
u32 ret, xdp_result = FEC_ENET_XDP_PASS;
|
|
- u32 data_start = FEC_ENET_XDP_HEADROOM;
|
|
int cpu = smp_processor_id();
|
|
struct xdp_buff xdp;
|
|
+#endif
|
|
+ u32 data_start = FEC_ENET_XDP_HEADROOM;
|
|
struct page *page;
|
|
u32 sub_len = 4;
|
|
|
|
@@ -1691,7 +2501,9 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
|
|
* These get messed up if we get called due to a busy condition.
|
|
*/
|
|
bdp = rxq->bd.cur;
|
|
+#ifndef CONFIG_AVB_SUPPORT
|
|
xdp_init_buff(&xdp, PAGE_SIZE, &rxq->xdp_rxq);
|
|
+#endif
|
|
|
|
while (!((status = fec16_to_cpu(bdp->cbd_sc)) & BD_ENET_RX_EMPTY)) {
|
|
|
|
@@ -1741,6 +2553,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
|
|
prefetch(page_address(page));
|
|
fec_enet_update_cbd(rxq, bdp, index);
|
|
|
|
+#ifndef CONFIG_AVB_SUPPORT
|
|
if (xdp_prog) {
|
|
xdp_buff_clear_frags_flag(&xdp);
|
|
/* subtract 16bit shift and FCS */
|
|
@@ -1751,6 +2564,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
|
|
if (ret != FEC_ENET_XDP_PASS)
|
|
goto rx_processing_done;
|
|
}
|
|
+#endif
|
|
|
|
/* The packet length includes FCS, but we don't want to
|
|
* include that when passing upstream as it messes up
|
|
@@ -1799,10 +2613,16 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
|
|
skb->protocol = eth_type_trans(skb, ndev);
|
|
|
|
/* Get receive timestamp from the skb */
|
|
- if (fep->hwts_rx_en && fep->bufdesc_ex)
|
|
+ if (fep->hwts_rx_en && fep->bufdesc_ex) {
|
|
fec_enet_hwtstamp(fep, fec32_to_cpu(ebdp->ts),
|
|
skb_hwtstamps(skb));
|
|
|
|
+ /* Adjust for RX MAC-PHY latency
|
|
+ */
|
|
+ skb_hwtstamps(skb)->hwtstamp =
|
|
+ ktime_sub_ns(skb_hwtstamps(skb)->hwtstamp, fep->rx_tstamp_latency);
|
|
+ }
|
|
+
|
|
if (fep->bufdesc_ex &&
|
|
(fep->csum_flags & FLAG_RX_CSUM_ENABLED)) {
|
|
if (!(ebdp->cbd_esc & cpu_to_fec32(FLAG_RX_CSUM_ERROR))) {
|
|
@@ -1853,8 +2673,10 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
|
|
}
|
|
rxq->bd.cur = bdp;
|
|
|
|
+#ifndef CONFIG_AVB_SUPPORT
|
|
if (xdp_result & FEC_ENET_XDP_REDIR)
|
|
xdp_do_flush_map();
|
|
+#endif
|
|
|
|
return pkt_received;
|
|
}
|
|
@@ -1895,6 +2717,10 @@ fec_enet_interrupt(int irq, void *dev_id)
|
|
if (fec_enet_collect_events(fep) && fep->link) {
|
|
ret = IRQ_HANDLED;
|
|
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled)
|
|
+ dev_err(&fep->pdev->dev, "Rx/Tx IRQ with AVB enabled, should not happen\n");
|
|
+#endif
|
|
if (napi_schedule_prep(&fep->napi)) {
|
|
/* Disable interrupts */
|
|
writel(0, fep->hwp + FEC_IMASK);
|
|
@@ -1911,10 +2737,18 @@ static int fec_enet_rx_napi(struct napi_struct *napi, int budget)
|
|
struct fec_enet_private *fep = netdev_priv(ndev);
|
|
int done = 0;
|
|
|
|
- do {
|
|
- done += fec_enet_rx(ndev, budget - done);
|
|
- fec_enet_tx(ndev, budget);
|
|
- } while ((done < budget) && fec_enet_collect_events(fep));
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled) {
|
|
+ done = fec_enet_rx_best_effort(ndev, budget);
|
|
+ fec_enet_tx_best_effort(ndev);
|
|
+ } else
|
|
+#endif
|
|
+ {
|
|
+ do {
|
|
+ done += fec_enet_rx(ndev, budget - done);
|
|
+ fec_enet_tx(ndev, budget);
|
|
+ } while ((done < budget) && fec_enet_collect_events(fep));
|
|
+ }
|
|
|
|
if (done < budget) {
|
|
napi_complete_done(napi, done);
|
|
@@ -2031,12 +2865,34 @@ static void fec_enet_adjust_link(struct net_device *ndev)
|
|
status_change = 1;
|
|
}
|
|
|
|
+ switch (fep->speed) {
|
|
+ case SPEED_100:
|
|
+ fep->rx_tstamp_latency = fep->rx_delay_100;
|
|
+ fep->tx_tstamp_latency = fep->tx_delay_100;
|
|
+ break;
|
|
+ case SPEED_1000:
|
|
+ fep->rx_tstamp_latency = fep->rx_delay_1000;
|
|
+ fep->tx_tstamp_latency = fep->tx_delay_1000;
|
|
+ break;
|
|
+ default:
|
|
+ fep->rx_tstamp_latency = 0;
|
|
+ fep->tx_tstamp_latency = 0;
|
|
+ }
|
|
+
|
|
/* if any of the above changed restart the FEC */
|
|
if (status_change) {
|
|
netif_stop_queue(ndev);
|
|
napi_disable(&fep->napi);
|
|
netif_tx_lock_bh(ndev);
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled)
|
|
+ fep->avb->close(fep->avb_data);
|
|
+#endif
|
|
fec_restart(ndev);
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled)
|
|
+ fep->avb->open(fep->avb_data, fep, fec_max_rate(fep));
|
|
+#endif
|
|
netif_tx_wake_all_queues(ndev);
|
|
netif_tx_unlock_bh(ndev);
|
|
napi_enable(&fep->napi);
|
|
@@ -2046,7 +2902,15 @@ static void fec_enet_adjust_link(struct net_device *ndev)
|
|
netif_stop_queue(ndev);
|
|
napi_disable(&fep->napi);
|
|
netif_tx_lock_bh(ndev);
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled)
|
|
+ fep->avb->close(fep->avb_data);
|
|
+#endif
|
|
fec_stop(ndev);
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled)
|
|
+ fep->avb->open(fep->avb_data, fep, fec_max_rate(fep));
|
|
+#endif
|
|
netif_tx_unlock_bh(ndev);
|
|
napi_enable(&fep->napi);
|
|
fep->link = phy_dev->link;
|
|
@@ -2420,6 +3284,12 @@ static int fec_enet_mii_probe(struct net_device *ndev)
|
|
else
|
|
phy_set_max_speed(phy_dev, 100);
|
|
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ /* Restore advertising settings saved last interface close */
|
|
+ if (!linkmode_empty(fep->phy_advertising))
|
|
+ linkmode_copy(phy_dev->advertising, fep->phy_advertising);
|
|
+#endif
|
|
+
|
|
fep->link = 0;
|
|
fep->full_duplex = 0;
|
|
|
|
@@ -3291,24 +4161,93 @@ static void fec_enet_free_buffers(struct net_device *ndev)
|
|
unsigned int i;
|
|
struct fec_enet_priv_tx_q *txq;
|
|
struct fec_enet_priv_rx_q *rxq;
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ struct sk_buff *skb;
|
|
+#endif
|
|
unsigned int q;
|
|
|
|
for (q = 0; q < fep->num_rx_queues; q++) {
|
|
rxq = fep->rx_queue[q];
|
|
- for (i = 0; i < rxq->bd.ring_size; i++)
|
|
- page_pool_put_full_page(rxq->page_pool, rxq->rx_skb_info[i].page, false);
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled) {
|
|
+ struct bufdesc *bdp = rxq->bd.base;
|
|
+ for (i = 0; i < rxq->bd.ring_size; i++) {
|
|
+ if (bdp->cbd_bufaddr) {
|
|
+ struct avb_rx_desc *desc;
|
|
+
|
|
+ desc = (struct avb_rx_desc *)rxq->rx_skb_info[i].skb;
|
|
+ fep->avb->free(fep->avb_data, &desc->common);
|
|
+ bdp->cbd_bufaddr = cpu_to_fec32(0);
|
|
+ }
|
|
+
|
|
+ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd);
|
|
+ }
|
|
+ } else
|
|
+#endif
|
|
+ {
|
|
+ for (i = 0; i < rxq->bd.ring_size; i++)
|
|
+ page_pool_put_full_page(rxq->page_pool, rxq->rx_skb_info[i].page, false);
|
|
|
|
- for (i = 0; i < XDP_STATS_TOTAL; i++)
|
|
- rxq->stats[i] = 0;
|
|
+ for (i = 0; i < XDP_STATS_TOTAL; i++)
|
|
+ rxq->stats[i] = 0;
|
|
|
|
- if (xdp_rxq_info_is_reg(&rxq->xdp_rxq))
|
|
- xdp_rxq_info_unreg(&rxq->xdp_rxq);
|
|
- page_pool_destroy(rxq->page_pool);
|
|
- rxq->page_pool = NULL;
|
|
+ if (xdp_rxq_info_is_reg(&rxq->xdp_rxq))
|
|
+ xdp_rxq_info_unreg(&rxq->xdp_rxq);
|
|
+ page_pool_destroy(rxq->page_pool);
|
|
+ rxq->page_pool = NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled) {
|
|
+ struct avb_rx_desc *rx_desc;
|
|
+ struct avb_tx_desc *tx_desc;
|
|
+
|
|
+ while ((rx_desc = fep->avb->dequeue(fep->avb_data)) != (void *) -1)
|
|
+ fep->avb->free(fep->avb_data, &rx_desc->common);
|
|
+
|
|
+ while ((tx_desc = fep->avb->tx_cleanup_dequeue(fep->avb_data)) != (void *) -1) {
|
|
+
|
|
+ skb = tx_desc->data;
|
|
+
|
|
+ dma_unmap_single(&fep->pdev->dev, tx_desc->bufaddr,
|
|
+ skb->len, DMA_TO_DEVICE);
|
|
+
|
|
+ /* Free the sk buffer associated with this last transmit */
|
|
+ dev_kfree_skb_any(skb);
|
|
+ }
|
|
}
|
|
+#endif
|
|
|
|
for (q = 0; q < fep->num_tx_queues; q++) {
|
|
txq = fep->tx_queue[q];
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ for (i = 0; i < txq->bd.ring_size; i++) {
|
|
+ if (txq->tx_buf[i].buf_p) {
|
|
+ skb = NULL;
|
|
+ if (fep->avb_enabled) {
|
|
+ struct avb_tx_desc *desc = (struct avb_tx_desc *)txq->tx_buf[i].buf_p;
|
|
+
|
|
+ if (!(desc->common.flags & AVB_TX_FLAG_SKB))
|
|
+ fep->avb->free(fep->avb_data, &desc->common);
|
|
+ else
|
|
+ skb = desc->data;
|
|
+ } else {
|
|
+ skb = txq->tx_buf[i].buf_p;
|
|
+ }
|
|
+
|
|
+ if (skb)
|
|
+ dev_kfree_skb(skb);
|
|
+
|
|
+ txq->tx_buf[i].buf_p = NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < txq->tx_bounce_size; i++) {
|
|
+ kfree(txq->tx_bounce[i]);
|
|
+ txq->tx_bounce[i] = NULL;
|
|
+ }
|
|
+#else
|
|
for (i = 0; i < txq->bd.ring_size; i++) {
|
|
kfree(txq->tx_bounce[i]);
|
|
txq->tx_bounce[i] = NULL;
|
|
@@ -3331,6 +4270,7 @@ static void fec_enet_free_buffers(struct net_device *ndev)
|
|
txq->tx_buf[i].buf_p = NULL;
|
|
txq->tx_buf[i].type = FEC_TXBUF_T_SKB;
|
|
}
|
|
+#endif
|
|
}
|
|
}
|
|
|
|
@@ -3370,11 +4310,18 @@ static int fec_enet_alloc_queue(struct net_device *ndev)
|
|
}
|
|
|
|
fep->tx_queue[i] = txq;
|
|
- txq->bd.ring_size = TX_RING_SIZE;
|
|
+ txq->bd.ring_size = FEC_TX_RING_SIZE;
|
|
fep->total_tx_ring_size += fep->tx_queue[i]->bd.ring_size;
|
|
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ txq->tx_stop_threshold = FEC_TX_RING_SIZE * 3/4;
|
|
+
|
|
+ txq->tx_wake_threshold =
|
|
+ (txq->bd.ring_size - txq->tx_stop_threshold) / 2;
|
|
+#else
|
|
txq->tx_stop_threshold = FEC_MAX_SKB_DESCS;
|
|
txq->tx_wake_threshold = FEC_MAX_SKB_DESCS + 2 * MAX_SKB_FRAGS;
|
|
+#endif
|
|
|
|
txq->tso_hdrs = dma_alloc_coherent(&fep->pdev->dev,
|
|
txq->bd.ring_size * TSO_HEADER_SIZE,
|
|
@@ -3394,7 +4341,7 @@ static int fec_enet_alloc_queue(struct net_device *ndev)
|
|
goto alloc_failed;
|
|
}
|
|
|
|
- fep->rx_queue[i]->bd.ring_size = RX_RING_SIZE;
|
|
+ fep->rx_queue[i]->bd.ring_size = FEC_RX_RING_SIZE;
|
|
fep->total_rx_ring_size += fep->rx_queue[i]->bd.ring_size;
|
|
}
|
|
return ret;
|
|
@@ -3415,32 +4362,77 @@ fec_enet_alloc_rxq_buffers(struct net_device *ndev, unsigned int queue)
|
|
int i, err;
|
|
|
|
rxq = fep->rx_queue[queue];
|
|
+
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
bdp = rxq->bd.base;
|
|
|
|
- err = fec_enet_create_page_pool(fep, rxq, rxq->bd.ring_size);
|
|
- if (err < 0) {
|
|
- netdev_err(ndev, "%s failed queue %d (%d)\n", __func__, queue, err);
|
|
- return err;
|
|
+ for (i = 0; i < rxq->bd.ring_size; i++) {
|
|
+ bdp->cbd_bufaddr = cpu_to_fec32(0);
|
|
+ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd);
|
|
}
|
|
+#endif
|
|
|
|
- for (i = 0; i < rxq->bd.ring_size; i++) {
|
|
- page = page_pool_dev_alloc_pages(rxq->page_pool);
|
|
- if (!page)
|
|
- goto err_alloc;
|
|
+ bdp = rxq->bd.base;
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled) {
|
|
+ for (i = 0; i < rxq->bd.ring_size; i++) {
|
|
+ struct avb_rx_desc *desc;
|
|
+ void *buffer;
|
|
|
|
- phys_addr = page_pool_get_dma_addr(page) + FEC_ENET_XDP_HEADROOM;
|
|
- bdp->cbd_bufaddr = cpu_to_fec32(phys_addr);
|
|
+ buffer = fep->avb->alloc(fep->avb_data);
|
|
+ if (!buffer)
|
|
+ goto err_alloc;
|
|
|
|
- rxq->rx_skb_info[i].page = page;
|
|
- rxq->rx_skb_info[i].offset = FEC_ENET_XDP_HEADROOM;
|
|
- bdp->cbd_sc = cpu_to_fec16(BD_ENET_RX_EMPTY);
|
|
+ desc = buffer;
|
|
|
|
- if (fep->bufdesc_ex) {
|
|
- struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
|
|
- ebdp->cbd_esc = cpu_to_fec32(BD_ENET_RX_INT);
|
|
+ desc->common.len = 0;
|
|
+ desc->queue_id = queue;
|
|
+
|
|
+ rxq->rx_skb_info[i].skb = buffer;
|
|
+ bdp->cbd_bufaddr = cpu_to_fec32((dma_addr_t)(desc->dma_addr));
|
|
+
|
|
+#if !defined(CONFIG_M5272)
|
|
+ if (fep->quirks & FEC_QUIRK_HAS_RACC)
|
|
+ desc->common.offset += 2;
|
|
+#endif
|
|
+
|
|
+ bdp->cbd_sc = cpu_to_fec16(BD_ENET_RX_EMPTY);
|
|
+
|
|
+ if (fep->bufdesc_ex) {
|
|
+ struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
|
|
+ ebdp->cbd_esc = cpu_to_fec32(0);
|
|
+ }
|
|
+
|
|
+ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd);
|
|
+ }
|
|
+ } else
|
|
+#endif
|
|
+ {
|
|
+ err = fec_enet_create_page_pool(fep, rxq, rxq->bd.ring_size);
|
|
+ if (err < 0) {
|
|
+ netdev_err(ndev, "%s failed queue %d (%d)\n", __func__, queue, err);
|
|
+ return err;
|
|
}
|
|
|
|
- bdp = fec_enet_get_nextdesc(bdp, &rxq->bd);
|
|
+ for (i = 0; i < rxq->bd.ring_size; i++) {
|
|
+ page = page_pool_dev_alloc_pages(rxq->page_pool);
|
|
+ if (!page)
|
|
+ goto err_alloc;
|
|
+
|
|
+ phys_addr = page_pool_get_dma_addr(page) + FEC_ENET_XDP_HEADROOM;
|
|
+ bdp->cbd_bufaddr = cpu_to_fec32(phys_addr);
|
|
+
|
|
+ rxq->rx_skb_info[i].page = page;
|
|
+ rxq->rx_skb_info[i].offset = FEC_ENET_XDP_HEADROOM;
|
|
+ bdp->cbd_sc = cpu_to_fec16(BD_ENET_RX_EMPTY);
|
|
+
|
|
+ if (fep->bufdesc_ex) {
|
|
+ struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
|
|
+ ebdp->cbd_esc = cpu_to_fec32(BD_ENET_RX_INT);
|
|
+ }
|
|
+
|
|
+ bdp = fec_enet_get_nextdesc(bdp, &rxq->bd);
|
|
+ }
|
|
}
|
|
|
|
/* Set the last buffer to wrap. */
|
|
@@ -3463,17 +4455,28 @@ fec_enet_alloc_txq_buffers(struct net_device *ndev, unsigned int queue)
|
|
|
|
txq = fep->tx_queue[queue];
|
|
bdp = txq->bd.base;
|
|
- for (i = 0; i < txq->bd.ring_size; i++) {
|
|
+ for (i = 0; i < txq->tx_bounce_size; i++) {
|
|
txq->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL);
|
|
if (!txq->tx_bounce[i])
|
|
goto err_alloc;
|
|
+ }
|
|
|
|
+ bdp = txq->bd.base;
|
|
+ txq->bd.cur = bdp;
|
|
+
|
|
+ for (i = 0; i < txq->bd.ring_size; i++) {
|
|
bdp->cbd_sc = cpu_to_fec16(0);
|
|
bdp->cbd_bufaddr = cpu_to_fec32(0);
|
|
|
|
if (fep->bufdesc_ex) {
|
|
struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
|
|
- ebdp->cbd_esc = cpu_to_fec32(BD_ENET_TX_INT);
|
|
+
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled)
|
|
+ ebdp->cbd_esc = cpu_to_fec32(0);
|
|
+ else
|
|
+#endif
|
|
+ ebdp->cbd_esc = cpu_to_fec32(BD_ENET_TX_INT);
|
|
}
|
|
|
|
bdp = fec_enet_get_nextdesc(bdp, &txq->bd);
|
|
@@ -3482,6 +4485,7 @@ fec_enet_alloc_txq_buffers(struct net_device *ndev, unsigned int queue)
|
|
/* Set the last buffer to wrap. */
|
|
bdp = fec_enet_get_prevdesc(bdp, &txq->bd);
|
|
bdp->cbd_sc |= cpu_to_fec16(BD_SC_WRAP);
|
|
+ txq->dirty_tx = bdp;
|
|
|
|
return 0;
|
|
|
|
@@ -3511,15 +4515,31 @@ fec_enet_open(struct net_device *ndev)
|
|
struct fec_enet_private *fep = netdev_priv(ndev);
|
|
int ret;
|
|
bool reset_again;
|
|
+ int i;
|
|
+
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled) {
|
|
+ if (!try_module_get(fep->avb->owner)) {
|
|
+ ret = -EIO;
|
|
+ goto err_module_get;
|
|
+ }
|
|
+ for (i = 0; i < fep->num_tx_queues; i++)
|
|
+ fep->tx_queue[i]->tx_bounce_size = FEC_TX_RING_SIZE + 32;
|
|
+ } else
|
|
+#endif
|
|
+ for (i = 0; i < fep->num_tx_queues; i++)
|
|
+ fep->tx_queue[i]->tx_bounce_size = FEC_TX_RING_SIZE;
|
|
|
|
ret = pm_runtime_resume_and_get(&fep->pdev->dev);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
pinctrl_pm_select_default_state(&fep->pdev->dev);
|
|
+#ifndef CONFIG_AVB_SUPPORT
|
|
ret = fec_enet_clk_enable(ndev, true);
|
|
if (ret)
|
|
goto clk_enable;
|
|
+#endif
|
|
|
|
/* During the first fec_enet_open call the PHY isn't probed at this
|
|
* point. Therefore the phy_reset_after_clk_enable() call within
|
|
@@ -3562,6 +4582,12 @@ fec_enet_open(struct net_device *ndev)
|
|
|
|
napi_enable(&fep->napi);
|
|
phy_start(ndev->phydev);
|
|
+
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled)
|
|
+ fep->avb->open(fep->avb_data, fep, fec_max_rate(fep));
|
|
+#endif
|
|
+
|
|
netif_tx_start_all_queues(ndev);
|
|
|
|
device_set_wakeup_enable(&ndev->dev, fep->wol_flag &
|
|
@@ -3572,12 +4598,23 @@ fec_enet_open(struct net_device *ndev)
|
|
err_enet_mii_probe:
|
|
fec_enet_free_buffers(ndev);
|
|
err_enet_alloc:
|
|
+#ifndef CONFIG_AVB_SUPPORT
|
|
fec_enet_clk_enable(ndev, false);
|
|
clk_enable:
|
|
+#endif
|
|
pm_runtime_mark_last_busy(&fep->pdev->dev);
|
|
pm_runtime_put_autosuspend(&fep->pdev->dev);
|
|
if (!fep->mii_bus_share)
|
|
pinctrl_pm_select_sleep_state(&fep->pdev->dev);
|
|
+
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled)
|
|
+ module_put(fep->avb->owner);
|
|
+#endif
|
|
+
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+err_module_get:
|
|
+#endif
|
|
return ret;
|
|
}
|
|
|
|
@@ -3591,9 +4628,20 @@ fec_enet_close(struct net_device *ndev)
|
|
if (netif_device_present(ndev)) {
|
|
napi_disable(&fep->napi);
|
|
netif_tx_disable(ndev);
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled)
|
|
+ fep->avb->close(fep->avb_data);
|
|
+#endif
|
|
fec_stop(ndev);
|
|
}
|
|
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ /*
|
|
+ * Save advertising settings so there are not lost
|
|
+ * when opening the interface again.
|
|
+ */
|
|
+ linkmode_copy(fep->phy_advertising, ndev->phydev->advertising);
|
|
+#endif
|
|
phy_disconnect(ndev->phydev);
|
|
ndev->phydev = NULL;
|
|
|
|
@@ -3602,7 +4650,9 @@ fec_enet_close(struct net_device *ndev)
|
|
|
|
fec_enet_update_ethtool_stats(ndev);
|
|
|
|
+#ifndef CONFIG_AVB_SUPPORT
|
|
fec_enet_clk_enable(ndev, false);
|
|
+#endif
|
|
if (fep->quirks & FEC_QUIRK_HAS_PMQOS)
|
|
cpu_latency_qos_remove_request(&fep->pm_qos_req);
|
|
|
|
@@ -3613,6 +4663,11 @@ fec_enet_close(struct net_device *ndev)
|
|
|
|
fec_enet_free_buffers(ndev);
|
|
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled)
|
|
+ module_put(fep->avb->owner);
|
|
+#endif
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -3769,6 +4824,7 @@ static u16 fec_enet_select_queue(struct net_device *ndev, struct sk_buff *skb,
|
|
return fec_enet_vlan_pri_to_queue[vlan_tag >> 13];
|
|
}
|
|
|
|
+#ifndef CONFIG_AVB_SUPPORT
|
|
static int fec_enet_bpf(struct net_device *dev, struct netdev_bpf *bpf)
|
|
{
|
|
struct fec_enet_private *fep = netdev_priv(dev);
|
|
@@ -3970,6 +5026,7 @@ static int fec_enet_xdp_xmit(struct net_device *dev,
|
|
|
|
return sent_frames;
|
|
}
|
|
+#endif /* !CONFIG_AVB_SUPPORT */
|
|
|
|
static int fec_hwtstamp_get(struct net_device *ndev,
|
|
struct kernel_hwtstamp_config *config)
|
|
@@ -4013,8 +5070,11 @@ static const struct net_device_ops fec_netdev_ops = {
|
|
.ndo_set_mac_address = fec_set_mac_address,
|
|
.ndo_eth_ioctl = phy_do_ioctl_running,
|
|
.ndo_set_features = fec_set_features,
|
|
+#ifndef CONFIG_AVB_SUPPORT
|
|
+ /* AVB support not compatible with XDP */
|
|
.ndo_bpf = fec_enet_bpf,
|
|
.ndo_xdp_xmit = fec_enet_xdp_xmit,
|
|
+#endif
|
|
.ndo_hwtstamp_get = fec_hwtstamp_get,
|
|
.ndo_hwtstamp_set = fec_hwtstamp_set,
|
|
};
|
|
@@ -4027,6 +5087,196 @@ static const unsigned short offset_des_active_txq[] = {
|
|
FEC_X_DES_ACTIVE_0, FEC_X_DES_ACTIVE_1, FEC_X_DES_ACTIVE_2
|
|
};
|
|
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+
|
|
+static struct platform_driver fec_driver;
|
|
+
|
|
+/* Checks if the net_device is registered by the fec */
|
|
+static bool __is_fec_net_device(struct net_device *ndev)
|
|
+{
|
|
+ if (!ndev)
|
|
+ return false;
|
|
+
|
|
+ if (ndev->dev.parent->driver == &fec_driver.driver)
|
|
+ return true;
|
|
+ else
|
|
+ return false;
|
|
+}
|
|
+
|
|
+struct device *fec_enet_avb_get_device(const char *ifname)
|
|
+{
|
|
+ struct net_device *ndev;
|
|
+ struct fec_enet_private *fep;
|
|
+
|
|
+ ndev = dev_get_by_name(&init_net, ifname);
|
|
+ if (!ndev)
|
|
+ goto err_dev_get;
|
|
+
|
|
+ if (!__is_fec_net_device(ndev))
|
|
+ goto err_ndev;
|
|
+
|
|
+ fep = netdev_priv(ndev);
|
|
+
|
|
+ dev_put(ndev);
|
|
+
|
|
+ return &fep->pdev->dev;
|
|
+
|
|
+err_ndev:
|
|
+ dev_put(ndev);
|
|
+
|
|
+err_dev_get:
|
|
+ return NULL;
|
|
+}
|
|
+EXPORT_SYMBOL(fec_enet_avb_get_device);
|
|
+
|
|
+int fec_enet_avb_register(const char *ifname, const struct avb_ops *avb, void *data)
|
|
+{
|
|
+ struct net_device *ndev;
|
|
+ struct fec_enet_private *fep;
|
|
+ unsigned int up;
|
|
+ int ifindex;
|
|
+
|
|
+ ndev = dev_get_by_name(&init_net, ifname);
|
|
+ if (!ndev)
|
|
+ goto err_dev_get;
|
|
+
|
|
+ if (!__is_fec_net_device(ndev))
|
|
+ goto err_ndev;
|
|
+
|
|
+ fep = netdev_priv(ndev);
|
|
+
|
|
+ if (fep->avb)
|
|
+ goto err_avb;
|
|
+
|
|
+ rtnl_lock();
|
|
+ up = ndev->flags & IFF_UP;
|
|
+ if (up)
|
|
+ dev_close(ndev);
|
|
+
|
|
+ fep->avb = avb;
|
|
+ fep->avb_data = data;
|
|
+ fep->avb_enabled = 1;
|
|
+ ifindex = ndev->ifindex;
|
|
+
|
|
+ if (up) {
|
|
+ /* In case of error, device is closed but avb interface is registered */
|
|
+ dev_open(ndev, NULL);
|
|
+ }
|
|
+
|
|
+ rtnl_unlock();
|
|
+
|
|
+ dev_put(ndev);
|
|
+
|
|
+ return ifindex;
|
|
+
|
|
+err_avb:
|
|
+err_ndev:
|
|
+ dev_put(ndev);
|
|
+
|
|
+err_dev_get:
|
|
+ return -1;
|
|
+}
|
|
+EXPORT_SYMBOL(fec_enet_avb_register);
|
|
+
|
|
+int fec_enet_avb_unregister(int ifindex, const struct avb_ops *avb)
|
|
+{
|
|
+ struct net_device *ndev;
|
|
+ struct fec_enet_private *fep;
|
|
+ unsigned int up;
|
|
+
|
|
+ ndev = dev_get_by_index(&init_net, ifindex);
|
|
+ if (!ndev)
|
|
+ goto err_dev_get;
|
|
+
|
|
+ if (!__is_fec_net_device(ndev))
|
|
+ goto err_ndev;
|
|
+
|
|
+ fep = netdev_priv(ndev);
|
|
+ if (fep->avb != avb)
|
|
+ goto err_avb;
|
|
+
|
|
+ rtnl_lock();
|
|
+ up = ndev->flags & IFF_UP;
|
|
+ if (up)
|
|
+ dev_close(ndev);
|
|
+
|
|
+ fep->avb = NULL;
|
|
+ fep->avb_data = NULL;
|
|
+ fep->avb_enabled = 0;
|
|
+
|
|
+ if (up)
|
|
+ /* In case of error, device is closed but avb interface is unregistered */
|
|
+ dev_open(ndev, NULL);
|
|
+
|
|
+ rtnl_unlock();
|
|
+
|
|
+ dev_put(ndev);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err_avb:
|
|
+err_ndev:
|
|
+ dev_put(ndev);
|
|
+
|
|
+err_dev_get:
|
|
+ return -1;
|
|
+}
|
|
+EXPORT_SYMBOL(fec_enet_avb_unregister);
|
|
+
|
|
+int fec_enet_get_tx_queue_properties(int ifindex, struct tx_queue_properties *prop)
|
|
+{
|
|
+ struct net_device *ndev;
|
|
+ struct fec_enet_private *fep;
|
|
+
|
|
+ ndev = dev_get_by_index(&init_net, ifindex);
|
|
+ if (!ndev)
|
|
+ goto err_dev_get;
|
|
+
|
|
+ if (!__is_fec_net_device(ndev))
|
|
+ goto err_ndev;
|
|
+
|
|
+ fep = netdev_priv(ndev);
|
|
+
|
|
+ if (fep->num_tx_queues >= TX_QUEUE_PROP_MAX)
|
|
+ goto err_queues;
|
|
+
|
|
+ if (fep->quirks & FEC_QUIRK_HAS_AVB) {
|
|
+ prop->num_queues = fep->num_tx_queues;
|
|
+ prop->queue[0].priority = 0;
|
|
+ prop->queue[0].flags = TX_QUEUE_FLAGS_STRICT_PRIORITY;
|
|
+ prop->queue[1].priority = 2;
|
|
+ prop->queue[1].flags = TX_QUEUE_FLAGS_CREDIT_SHAPER;
|
|
+ prop->queue[2].priority = 1;
|
|
+ prop->queue[2].flags = TX_QUEUE_FLAGS_CREDIT_SHAPER;
|
|
+ } else {
|
|
+ /*
|
|
+ * For now, there is no MAC non-AVB capable
|
|
+ * with more than 1 queue.
|
|
+ */
|
|
+ if (fep->num_tx_queues == 1) {
|
|
+ prop->num_queues = fep->num_tx_queues;
|
|
+ prop->queue[0].priority = 0;
|
|
+ prop->queue[0].flags = TX_QUEUE_FLAGS_STRICT_PRIORITY;
|
|
+ } else {
|
|
+ netdev_err(ndev, "%s invalid/unknown TX queues configuration\n", __func__);
|
|
+ goto err_queues;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ dev_put(ndev);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err_queues:
|
|
+err_ndev:
|
|
+ dev_put(ndev);
|
|
+
|
|
+err_dev_get:
|
|
+ return -1;
|
|
+}
|
|
+EXPORT_SYMBOL(fec_enet_get_tx_queue_properties);
|
|
+#endif
|
|
+
|
|
/*
|
|
* XXX: We need to clean up on failure exits here.
|
|
*
|
|
@@ -4111,10 +5361,14 @@ static int fec_enet_init(struct net_device *ndev)
|
|
txq->bd.dsize_log2 = dsize_log2;
|
|
txq->bd.reg_desc_active = fep->hwp + offset_des_active_txq[i];
|
|
bd_dma += size;
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ txq->tx_idle_slope = IDLE_SLOPE(i);
|
|
+#endif
|
|
cbd_base = (struct bufdesc *)(((void *)cbd_base) + size);
|
|
txq->bd.last = (struct bufdesc *)(((void *)cbd_base) - dsize);
|
|
}
|
|
|
|
+ fep->netdev = ndev;
|
|
|
|
/* The FEC Ethernet specific entries in the device structure */
|
|
ndev->watchdog_timeo = TX_TIMEOUT;
|
|
@@ -4132,8 +5386,13 @@ static int fec_enet_init(struct net_device *ndev)
|
|
netif_set_tso_max_segs(ndev, FEC_MAX_TSO_SEGS);
|
|
|
|
/* enable hw accelerator */
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ /* AVB support not compatible with SG or TSO */
|
|
+ ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM);
|
|
+#else
|
|
ndev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM
|
|
| NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO);
|
|
+#endif
|
|
fep->csum_flags |= FLAG_RX_CSUM_ENABLED;
|
|
}
|
|
|
|
@@ -4144,9 +5403,11 @@ static int fec_enet_init(struct net_device *ndev)
|
|
|
|
ndev->hw_features = ndev->features;
|
|
|
|
+#ifndef CONFIG_AVB_SUPPORT
|
|
if (!(fep->quirks & FEC_QUIRK_SWAP_FRAME))
|
|
ndev->xdp_features = NETDEV_XDP_ACT_BASIC |
|
|
NETDEV_XDP_ACT_REDIRECT;
|
|
+#endif
|
|
|
|
fec_restart(ndev);
|
|
|
|
@@ -4469,6 +5730,13 @@ fec_probe(struct platform_device *pdev)
|
|
}
|
|
|
|
fep->bufdesc_ex = fep->quirks & FEC_QUIRK_HAS_BUFDESC_EX;
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (!fep->bufdesc_ex) {
|
|
+ dev_err(&pdev->dev,
|
|
+ "Error: AVB Support requires extended buffer descriptor\n");
|
|
+ goto failed_clk;
|
|
+ }
|
|
+#endif
|
|
fep->clk_ptp = devm_clk_get(&pdev->dev, "ptp");
|
|
if (IS_ERR(fep->clk_ptp)) {
|
|
fep->clk_ptp = NULL;
|
|
@@ -4518,12 +5786,32 @@ fec_probe(struct platform_device *pdev)
|
|
fep->reg_phy = NULL;
|
|
}
|
|
|
|
+ if (of_property_read_u32(np, "fsl,rx-phy-delay-100-ns", &fep->rx_delay_100))
|
|
+ fep->rx_delay_100 = 0;
|
|
+
|
|
+ if (of_property_read_u32(np, "fsl,tx-phy-delay-100-ns", &fep->tx_delay_100))
|
|
+ fep->tx_delay_100 = 0;
|
|
+
|
|
+ if (of_property_read_u32(np, "fsl,rx-phy-delay-1000-ns", &fep->rx_delay_1000))
|
|
+ fep->rx_delay_1000 = 0;
|
|
+
|
|
+ if (of_property_read_u32(np, "fsl,tx-phy-delay-1000-ns", &fep->tx_delay_1000))
|
|
+ fep->tx_delay_1000 = 0;
|
|
+
|
|
pm_runtime_set_autosuspend_delay(&pdev->dev, FEC_MDIO_PM_TIMEOUT);
|
|
pm_runtime_use_autosuspend(&pdev->dev);
|
|
pm_runtime_get_noresume(&pdev->dev);
|
|
pm_runtime_set_active(&pdev->dev);
|
|
pm_runtime_enable(&pdev->dev);
|
|
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ /*
|
|
+ * Prevent runtime pm with avb module to keep all clocks
|
|
+ * running even on link down.
|
|
+ */
|
|
+ pm_runtime_forbid(&pdev->dev);
|
|
+#endif
|
|
+
|
|
ret = fec_reset_phy(pdev);
|
|
if (ret)
|
|
goto failed_reset;
|
|
@@ -4566,7 +5854,9 @@ fec_probe(struct platform_device *pdev)
|
|
|
|
/* Carrier starts down, phylib will bring it up */
|
|
netif_carrier_off(ndev);
|
|
+#ifndef CONFIG_AVB_SUPPORT
|
|
fec_enet_clk_enable(ndev, false);
|
|
+#endif
|
|
pinctrl_pm_select_sleep_state(&pdev->dev);
|
|
|
|
ndev->max_mtu = PKT_MAXBUF_SIZE - ETH_HLEN - ETH_FCS_LEN;
|
|
@@ -4679,6 +5969,10 @@ static int __maybe_unused fec_suspend(struct device *dev)
|
|
netif_tx_lock_bh(ndev);
|
|
netif_device_detach(ndev);
|
|
netif_tx_unlock_bh(ndev);
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled)
|
|
+ fep->avb->close(fep->avb_data);
|
|
+#endif
|
|
fec_stop(ndev);
|
|
if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) {
|
|
fec_irqs_disable(ndev);
|
|
@@ -4777,6 +6071,10 @@ static int __maybe_unused fec_resume(struct device *dev)
|
|
napi_enable(&fep->napi);
|
|
phy_init_hw(ndev->phydev);
|
|
phy_start(ndev->phydev);
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->avb_enabled)
|
|
+ fep->avb->open(fep->avb_data, fep, fec_max_rate(fep));
|
|
+#endif
|
|
} else if (fep->mii_bus_share && !ndev->phydev) {
|
|
pinctrl_pm_select_default_state(&fep->pdev->dev);
|
|
if (fep->phy_reset_in_suspend)
|
|
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
|
|
index 92fc03f29ca1..88215a644d82 100644
|
|
--- a/drivers/net/ethernet/freescale/fec_ptp.c
|
|
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
|
|
@@ -104,16 +104,22 @@ static int fec_ptp_enable_pps(struct fec_enet_private *fep, uint enable)
|
|
struct timespec64 ts;
|
|
u64 ns;
|
|
|
|
- spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
+ raw_spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
|
|
if (fep->pps_enable == enable) {
|
|
- spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
return 0;
|
|
}
|
|
|
|
fep->pps_channel = DEFAULT_PPS_CHANNEL;
|
|
fep->reload_period = PPS_OUPUT_RELOAD_PERIOD;
|
|
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ if (fep->rec_enable && (fep->pps_channel == fep->rec_channel)) {
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+ return -EBUSY;
|
|
+ }
|
|
+#endif
|
|
if (enable) {
|
|
/* clear capture or output compare interrupt status if have.
|
|
*/
|
|
@@ -197,7 +203,7 @@ static int fec_ptp_enable_pps(struct fec_enet_private *fep, uint enable)
|
|
}
|
|
|
|
fep->pps_enable = enable;
|
|
- spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -208,7 +214,7 @@ static int fec_ptp_pps_perout(struct fec_enet_private *fep)
|
|
u64 curr_time;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
+ raw_spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
|
|
/* Update time counter */
|
|
timecounter_read(&fep->tc);
|
|
@@ -231,7 +237,7 @@ static int fec_ptp_pps_perout(struct fec_enet_private *fep)
|
|
*/
|
|
if (fep->perout_stime < curr_time + 100 * NSEC_PER_MSEC) {
|
|
dev_err(&fep->pdev->dev, "Current time is too close to the start time!\n");
|
|
- spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
return -1;
|
|
}
|
|
|
|
@@ -259,7 +265,7 @@ static int fec_ptp_pps_perout(struct fec_enet_private *fep)
|
|
*/
|
|
writel(fep->next_counter, fep->hwp + FEC_TCCR(fep->pps_channel));
|
|
fep->next_counter = (fep->next_counter + fep->reload_period) & fep->cc.mask;
|
|
- spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -274,6 +280,26 @@ static enum hrtimer_restart fec_ptp_pps_perout_handler(struct hrtimer *timer)
|
|
return HRTIMER_NORESTART;
|
|
}
|
|
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+/**
|
|
+ * fec_timecounter_set
|
|
+ * @start_tstamp: new time in ns
|
|
+ *
|
|
+ * update the FEC timecounter structure to a new time, and make sure
|
|
+ * the HW counter matches that value.
|
|
+ */
|
|
+static inline void fec_timecounter_set(struct fec_enet_private *fep,
|
|
+ u64 start_tstamp)
|
|
+{
|
|
+ u32 tempval;
|
|
+
|
|
+ tempval = start_tstamp & fep->cc.mask;
|
|
+ writel(tempval, fep->hwp + FEC_ATIME);
|
|
+ fep->tc.cycle_last = tempval;
|
|
+ fep->tc.nsec = start_tstamp;
|
|
+}
|
|
+#endif
|
|
+
|
|
/**
|
|
* fec_ptp_read - read raw cycle counter (to be used by time counter)
|
|
* @cc: the cyclecounter structure
|
|
@@ -288,14 +314,14 @@ static u64 fec_ptp_read(const struct cyclecounter *cc)
|
|
container_of(cc, struct fec_enet_private, cc);
|
|
u32 tempval;
|
|
|
|
- tempval = readl(fep->hwp + FEC_ATIME_CTRL);
|
|
+ tempval = readl_relaxed(fep->hwp + FEC_ATIME_CTRL);
|
|
tempval |= FEC_T_CTRL_CAPTURE;
|
|
writel(tempval, fep->hwp + FEC_ATIME_CTRL);
|
|
|
|
if (fep->quirks & FEC_QUIRK_BUG_CAPTURE)
|
|
udelay(1);
|
|
|
|
- return readl(fep->hwp + FEC_ATIME);
|
|
+ return readl_relaxed(fep->hwp + FEC_ATIME);
|
|
}
|
|
|
|
/**
|
|
@@ -315,29 +341,315 @@ void fec_ptp_start_cyclecounter(struct net_device *ndev)
|
|
inc = 1000000000 / fep->cycle_speed;
|
|
|
|
/* grab the ptp lock */
|
|
- spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
+ raw_spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
|
|
- /* 1ns counter */
|
|
- writel(inc << FEC_T_INC_OFFSET, fep->hwp + FEC_ATIME_INC);
|
|
+ /* 1ns counter, disable correction period */
|
|
+ writel_relaxed(0, fep->hwp + FEC_ATIME_CORR);
|
|
+ writel_relaxed(inc << FEC_T_INC_OFFSET, fep->hwp + FEC_ATIME_INC);
|
|
|
|
- /* use 31-bit timer counter */
|
|
- writel(FEC_COUNTER_PERIOD, fep->hwp + FEC_ATIME_EVT_PERIOD);
|
|
|
|
- writel(FEC_T_CTRL_ENABLE | FEC_T_CTRL_PERIOD_RST,
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ /* use 32-bits timer counter */
|
|
+ writel_relaxed(0, fep->hwp + FEC_ATIME_EVT_PERIOD);
|
|
+ writel_relaxed(FEC_T_CTRL_ENABLE, fep->hwp + FEC_ATIME_CTRL);
|
|
+#else
|
|
+ /* use 31-bit timer counter */
|
|
+ writel_relaxed(FEC_COUNTER_PERIOD, fep->hwp + FEC_ATIME_EVT_PERIOD);
|
|
+ writel_relaxed(FEC_T_CTRL_ENABLE | FEC_T_CTRL_PERIOD_RST,
|
|
fep->hwp + FEC_ATIME_CTRL);
|
|
+#endif
|
|
|
|
memset(&fep->cc, 0, sizeof(fep->cc));
|
|
fep->cc.read = fec_ptp_read;
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ fep->cc.mask = CLOCKSOURCE_MASK(32);
|
|
+#else
|
|
fep->cc.mask = CLOCKSOURCE_MASK(31);
|
|
+#endif
|
|
fep->cc.shift = 31;
|
|
fep->cc.mult = FEC_CC_MULT;
|
|
|
|
/* reset the ns time counter */
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ fep->tc.cc = &fep->cc;
|
|
+ fec_timecounter_set(fep, 0);
|
|
+#else
|
|
timecounter_init(&fep->tc, &fep->cc, 0);
|
|
+#endif
|
|
+
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+/**
|
|
+ * fec_ptp_adjfreq - adjust ptp cycle frequency
|
|
+ * @ptp: the ptp clock structure
|
|
+ * @scaled_ppm: scaled parts per million adjustment from base
|
|
+ *
|
|
+ * Adjust the frequency of the ptp cycle counter by the
|
|
+ * indicated amount from the base frequency.
|
|
+ *
|
|
+ * Scaled parts per million is ppm with a 16-bit binary fractional field.
|
|
+ *
|
|
+ * This version adjusts the HW counter. The HW implementation results in the following equation:
|
|
+ * fe * diff = ppb * (pc + 1)
|
|
+ * with:
|
|
+ * . fe : ENET ref clock frequency in Hz
|
|
+ * . diff = inc_corr - inc : difference between default increment and correction increment
|
|
+ * . ppb : parts per billion adjustment from base
|
|
+ * . pc : correction period (in number of fe clock cycles)
|
|
+ *
|
|
+ * Limitations:
|
|
+ * . only add or remove 1ns per correction period. This will limit jitter and improve short term
|
|
+ * accuracy (in particular for trigger events during clock recovery) but increase the max possible
|
|
+ * error, since the correction period will be the shortest possible and thus may not be optimal.
|
|
+ * In the case of an adjustment of about 100ppm (which should be the max if the ref clock
|
|
+ * is within the 802.1AS spec), the max error will be about 0.2ppm with a 50MHz ref clock, and
|
|
+ * 0.08ppm with a 125MHz ref clock.
|
|
+ * Long term accuracy will also be lower (20ns per 100ms @50MHz, 8ns per 100ms @125MHz), but this
|
|
+ * can be fixed by phase adjustments.
|
|
+ * . It seems not all period/correction values are valid. With a 1ns correction, all even
|
|
+ * period values return wrong timings (half the requested correction), but on the other hand odd
|
|
+ * values are not taken into account systematically by the hardware, so we choose the closest even
|
|
+ * value that matches the following equation:
|
|
+ * fe * diff = 2 * ppb * (pc + 1)
|
|
+ * . given we force abs(diff) = 1, limit max adjustment to prevent pc < 1.
|
|
+ *
|
|
+ */
|
|
+static int fec_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
|
|
+{
|
|
+ struct fec_enet_private *fep =
|
|
+ container_of(ptp, struct fec_enet_private, ptp_caps);
|
|
+ s32 ppb = scaled_ppm_to_ppb(scaled_ppm);
|
|
+ unsigned long flags;
|
|
+ u32 inc, cor, pc;
|
|
+
|
|
+ inc = fep->ptp_inc;
|
|
+ if (ppb == 0) {
|
|
+ cor = 0;
|
|
+ pc = 0;
|
|
+ } else {
|
|
+ if (ppb < 0) {
|
|
+ ppb = -ppb;
|
|
+ cor = inc - 1;
|
|
+ }
|
|
+ else
|
|
+ cor = inc + 1;
|
|
+
|
|
+ if (ppb > fep->ptp_caps.max_adj) {
|
|
+ dev_err(&fep->pdev->dev, "ppb value %d outside accepted range (max_adj = %d)", (cor > inc) ? ppb : -ppb, ptp->max_adj);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ pc = (((fep->cycle_speed / (2*ppb)) - 1) + 1) & ~ 0x1; // + 1) & ~ 0x1 returns the closest even value
|
|
+ }
|
|
|
|
- spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+ raw_spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
+
|
|
+ writel_relaxed((cor << FEC_T_INC_CORR_OFFSET) | (inc << FEC_T_INC_OFFSET), fep->hwp + FEC_ATIME_INC);
|
|
+ writel_relaxed(pc, fep->hwp + FEC_ATIME_CORR);
|
|
+
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
+/**
|
|
+ * fec_ptp_adjtime
|
|
+ * @ptp: the ptp clock structure
|
|
+ * @delta: offset to adjust the cycle counter by
|
|
+ *
|
|
+ * adjust the timer by updating the HW counter AND the timecounter structure
|
|
+ * as well. Since updating the HW register requires a read and a write, make
|
|
+ * a crude estimate of the read time and subtract it from the desired delta.
|
|
+ */
|
|
+static int fec_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
|
|
+{
|
|
+ struct fec_enet_private *fep =
|
|
+ container_of(ptp, struct fec_enet_private, ptp_caps);
|
|
+ unsigned long flags;
|
|
+ u64 now, then;
|
|
+ s64 real_delta;
|
|
+
|
|
+ raw_spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
+
|
|
+ now = timecounter_read(&fep->tc);
|
|
+ then = timecounter_read(&fep->tc);
|
|
+
|
|
+ real_delta = delta + (then - now);
|
|
+
|
|
+ now = timecounter_read(&fep->tc);
|
|
+ now += real_delta;
|
|
+
|
|
+ fec_timecounter_set(fep, now);
|
|
+
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * fec_ptp_settime
|
|
+ * @ptp: the ptp clock structure
|
|
+ * @ts: the timespec containing the new time for the cycle counter
|
|
+ *
|
|
+ * Update the timecounter to use a new base value instead of the kernel
|
|
+ * wall timer value, and update the HW counter as well.
|
|
+ */
|
|
+static int fec_ptp_settime(struct ptp_clock_info *ptp,
|
|
+ const struct timespec64 *ts)
|
|
+{
|
|
+ struct fec_enet_private *fep =
|
|
+ container_of(ptp, struct fec_enet_private, ptp_caps);
|
|
+ u64 ns;
|
|
+ unsigned long flags;
|
|
+
|
|
+ ns = ts->tv_sec * 1000000000ULL;
|
|
+ ns += ts->tv_nsec;
|
|
+
|
|
+ raw_spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
+ fec_timecounter_set(fep, ns);
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * fec_ptp_read
|
|
+ * @data: fec private context ptr
|
|
+ * @cnt: data pointer for counter value
|
|
+ *
|
|
+ * Returns status
|
|
+ */
|
|
+int fec_ptp_read_cnt(void *data, u32 *cnt)
|
|
+{
|
|
+ struct fec_enet_private *fep = data;
|
|
+ unsigned long flags;
|
|
+
|
|
+ /* Note : it might be possible to avoid taking the lock */
|
|
+ raw_spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
+
|
|
+ *cnt = (u32) fec_ptp_read(&fep->cc);
|
|
+
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(fec_ptp_read_cnt);
|
|
+
|
|
+/**
|
|
+ * fec_ptp_tc_start
|
|
+ * @data: fec private context ptr
|
|
+ * @id: TC register ID
|
|
+ * @ts_0: First timestamp
|
|
+ * @ts_1: Second timestamp
|
|
+ * @tcsr_val: TCSR register value
|
|
+ *
|
|
+ * Returns 0 on success, -1 if PTP counter is not
|
|
+ * enabled.
|
|
+ */
|
|
+int fec_ptp_tc_start(void *data, u8 id, u32 ts_0, u32 ts_1, u32 tcsr_val)
|
|
+{
|
|
+ struct fec_enet_private *fep = data;
|
|
+ unsigned long flags;
|
|
+ u32 ctrl_val;
|
|
+ int rc = 0;
|
|
+
|
|
+ if (id > MAX_TIMER_CHANNEL) {
|
|
+ rc = -1;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ raw_spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
+
|
|
+ /* Simple resource sharing handling with pps */
|
|
+ if (fep->pps_enable && (fep->pps_channel == id)) {
|
|
+ rc = -1;
|
|
+ goto exit_unlock;
|
|
+ }
|
|
+
|
|
+ ctrl_val = readl_relaxed(fep->hwp + FEC_ATIME_CTRL);
|
|
+ if (!(ctrl_val & FEC_T_CTRL_ENABLE)) {
|
|
+ rc = -1;
|
|
+ goto exit_unlock;
|
|
+ }
|
|
+
|
|
+ writel_relaxed(ts_0, fep->hwp + FEC_TCCR(id));
|
|
+ writel_relaxed(tcsr_val, fep->hwp + FEC_TCSR(id));
|
|
+ writel_relaxed(ts_1, fep->hwp + FEC_TCCR(id));
|
|
+
|
|
+ fep->rec_enable = 1;
|
|
+ fep->rec_channel = id;
|
|
+
|
|
+exit_unlock:
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+exit:
|
|
+ return rc;
|
|
+}
|
|
+EXPORT_SYMBOL(fec_ptp_tc_start);
|
|
+
|
|
+/**
|
|
+ * fec_ptp_tc_stop
|
|
+ * @data: fec private context ptr
|
|
+ * @id: TC register ID
|
|
+ *
|
|
+ * Returns none
|
|
+ */
|
|
+void fec_ptp_tc_stop(void *data, u8 id)
|
|
+{
|
|
+ struct fec_enet_private *fep = data;
|
|
+ unsigned long flags;
|
|
+
|
|
+ raw_spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
+
|
|
+ writel_relaxed(0, fep->hwp + FEC_TCCR(id));
|
|
+ writel_relaxed(FEC_T_TF_MASK, fep->hwp + FEC_TCSR(id));
|
|
+
|
|
+ fep->rec_enable = 0;
|
|
+
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+}
|
|
+EXPORT_SYMBOL(fec_ptp_tc_stop);
|
|
+
|
|
+/**
|
|
+ * fec_ptp_tc_reload
|
|
+ * @data: fec private context ptr
|
|
+ * @id: TC register ID
|
|
+ * @ts: New timestamp to load
|
|
+ *
|
|
+ * Returns 0 if success, -1 if compare has not occured
|
|
+ * or if PTP counter is not enabled.
|
|
+ */
|
|
+int fec_ptp_tc_reload(void *data, u8 id, u32 ts)
|
|
+{
|
|
+ struct fec_enet_private *fep = data;
|
|
+ unsigned long flags;
|
|
+ u32 tcsr_val;
|
|
+ u32 ctrl_val;
|
|
+ int rc = 0;
|
|
+
|
|
+ raw_spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
+
|
|
+ ctrl_val = readl_relaxed(fep->hwp + FEC_ATIME_CTRL);
|
|
+ if (!(ctrl_val & FEC_T_CTRL_ENABLE)) {
|
|
+ rc = -1;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ tcsr_val = readl_relaxed(fep->hwp + FEC_TCSR(id));
|
|
+ if (tcsr_val & FEC_T_TF_MASK) {
|
|
+ writel_relaxed(ts, fep->hwp + FEC_TCCR(id));
|
|
+ writel_relaxed(tcsr_val, fep->hwp + FEC_TCSR(id));
|
|
+ }
|
|
+ else
|
|
+ rc = -1;
|
|
+
|
|
+exit:
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+ return rc;
|
|
+}
|
|
+EXPORT_SYMBOL(fec_ptp_tc_reload);
|
|
+#else /* CONFIG_AVB_SUPPORT */
|
|
+
|
|
/**
|
|
* fec_ptp_adjfine - adjust ptp cycle frequency
|
|
* @ptp: the ptp clock structure
|
|
@@ -399,7 +711,7 @@ static int fec_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
|
|
else
|
|
corr_ns = fep->ptp_inc + corr_inc;
|
|
|
|
- spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
+ raw_spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
|
|
tmp = readl(fep->hwp + FEC_ATIME_INC) & FEC_T_INC_MASK;
|
|
tmp |= corr_ns << FEC_T_INC_CORR_OFFSET;
|
|
@@ -409,7 +721,7 @@ static int fec_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
|
|
/* dummy read to update the timer. */
|
|
timecounter_read(&fep->tc);
|
|
|
|
- spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -427,27 +739,30 @@ static int fec_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
|
|
container_of(ptp, struct fec_enet_private, ptp_caps);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
+ raw_spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
timecounter_adjtime(&fep->tc, delta);
|
|
- spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
- * fec_ptp_gettime
|
|
+ * fec_ptp_settime
|
|
* @ptp: the ptp clock structure
|
|
- * @ts: timespec structure to hold the current time value
|
|
+ * @ts: the timespec containing the new time for the cycle counter
|
|
*
|
|
- * read the timecounter and return the correct value on ns,
|
|
- * after converting it into a struct timespec.
|
|
+ * reset the timecounter to use a new base value instead of the kernel
|
|
+ * wall timer value.
|
|
*/
|
|
-static int fec_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
|
|
+static int fec_ptp_settime(struct ptp_clock_info *ptp,
|
|
+ const struct timespec64 *ts)
|
|
{
|
|
struct fec_enet_private *fep =
|
|
container_of(ptp, struct fec_enet_private, ptp_caps);
|
|
+
|
|
u64 ns;
|
|
unsigned long flags;
|
|
+ u32 counter;
|
|
|
|
mutex_lock(&fep->ptp_clk_mutex);
|
|
/* Check the ptp clock */
|
|
@@ -455,33 +770,37 @@ static int fec_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
|
|
mutex_unlock(&fep->ptp_clk_mutex);
|
|
return -EINVAL;
|
|
}
|
|
- spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
- ns = timecounter_read(&fep->tc);
|
|
- spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
- mutex_unlock(&fep->ptp_clk_mutex);
|
|
|
|
- *ts = ns_to_timespec64(ns);
|
|
+ ns = timespec64_to_ns(ts);
|
|
+ /* Get the timer value based on timestamp.
|
|
+ * Update the counter with the masked value.
|
|
+ */
|
|
+ counter = ns & fep->cc.mask;
|
|
|
|
+ raw_spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
+ writel(counter, fep->hwp + FEC_ATIME);
|
|
+ timecounter_init(&fep->tc, &fep->cc, ns);
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+ mutex_unlock(&fep->ptp_clk_mutex);
|
|
return 0;
|
|
}
|
|
+#endif /* CONFIG_AVB_SUPPORT */
|
|
|
|
/**
|
|
- * fec_ptp_settime
|
|
+ * fec_ptp_gettime
|
|
* @ptp: the ptp clock structure
|
|
- * @ts: the timespec containing the new time for the cycle counter
|
|
+ * @ts: timespec structure to hold the current time value
|
|
*
|
|
- * reset the timecounter to use a new base value instead of the kernel
|
|
- * wall timer value.
|
|
+ * read the timecounter and return the correct value on ns,
|
|
+ * after converting it into a struct timespec.
|
|
*/
|
|
-static int fec_ptp_settime(struct ptp_clock_info *ptp,
|
|
- const struct timespec64 *ts)
|
|
+static int fec_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
|
|
{
|
|
struct fec_enet_private *fep =
|
|
container_of(ptp, struct fec_enet_private, ptp_caps);
|
|
-
|
|
u64 ns;
|
|
+ u32 remainder;
|
|
unsigned long flags;
|
|
- u32 counter;
|
|
|
|
mutex_lock(&fep->ptp_clk_mutex);
|
|
/* Check the ptp clock */
|
|
@@ -489,18 +808,14 @@ static int fec_ptp_settime(struct ptp_clock_info *ptp,
|
|
mutex_unlock(&fep->ptp_clk_mutex);
|
|
return -EINVAL;
|
|
}
|
|
+ raw_spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
+ ns = timecounter_read(&fep->tc);
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+ mutex_unlock(&fep->ptp_clk_mutex);
|
|
|
|
- ns = timespec64_to_ns(ts);
|
|
- /* Get the timer value based on timestamp.
|
|
- * Update the counter with the masked value.
|
|
- */
|
|
- counter = ns & fep->cc.mask;
|
|
+ ts->tv_sec = div_u64_rem(ns, 1000000000ULL, &remainder);
|
|
+ ts->tv_nsec = remainder;
|
|
|
|
- spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
- writel(counter, fep->hwp + FEC_ATIME);
|
|
- timecounter_init(&fep->tc, &fep->cc, ns);
|
|
- spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
- mutex_unlock(&fep->ptp_clk_mutex);
|
|
return 0;
|
|
}
|
|
|
|
@@ -508,9 +823,9 @@ static int fec_ptp_pps_disable(struct fec_enet_private *fep, uint channel)
|
|
{
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
+ raw_spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
writel(0, fep->hwp + FEC_TCSR(channel));
|
|
- spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -574,10 +889,10 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp,
|
|
mutex_unlock(&fep->ptp_clk_mutex);
|
|
return -EOPNOTSUPP;
|
|
}
|
|
- spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
+ raw_spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
/* Read current timestamp */
|
|
curr_time = timecounter_read(&fep->tc);
|
|
- spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
mutex_unlock(&fep->ptp_clk_mutex);
|
|
|
|
/* Calculate time difference */
|
|
@@ -662,9 +977,9 @@ static void fec_time_keep(struct work_struct *work)
|
|
|
|
mutex_lock(&fep->ptp_clk_mutex);
|
|
if (fep->ptp_clk_on) {
|
|
- spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
+ raw_spin_lock_irqsave(&fep->tmreg_lock, flags);
|
|
timecounter_read(&fep->tc);
|
|
- spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
+ raw_spin_unlock_irqrestore(&fep->tmreg_lock, flags);
|
|
}
|
|
mutex_unlock(&fep->ptp_clk_mutex);
|
|
|
|
@@ -680,6 +995,9 @@ static irqreturn_t fec_pps_interrupt(int irq, void *dev_id)
|
|
u8 channel = fep->pps_channel;
|
|
struct ptp_clock_event event;
|
|
|
|
+ if (fep->pps_enable)
|
|
+ goto exit;
|
|
+
|
|
val = readl(fep->hwp + FEC_TCSR(channel));
|
|
if (val & FEC_T_TF_MASK) {
|
|
/* Write the next next compare(not the next according the spec)
|
|
@@ -699,6 +1017,7 @@ static irqreturn_t fec_pps_interrupt(int irq, void *dev_id)
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
+exit:
|
|
return IRQ_NONE;
|
|
}
|
|
|
|
@@ -722,7 +1041,18 @@ void fec_ptp_init(struct platform_device *pdev, int irq_idx)
|
|
fep->ptp_caps.owner = THIS_MODULE;
|
|
strscpy(fep->ptp_caps.name, "fec ptp", sizeof(fep->ptp_caps.name));
|
|
|
|
+ fep->cycle_speed = clk_get_rate(fep->clk_ptp);
|
|
+ if (!fep->cycle_speed) {
|
|
+ fep->cycle_speed = NSEC_PER_SEC;
|
|
+ dev_err(&fep->pdev->dev, "clk_ptp clock rate is zero\n");
|
|
+ }
|
|
+ fep->ptp_inc = NSEC_PER_SEC / fep->cycle_speed;
|
|
+
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+ fep->ptp_caps.max_adj = fep->cycle_speed / 2;
|
|
+#else
|
|
fep->ptp_caps.max_adj = 250000000;
|
|
+#endif
|
|
fep->ptp_caps.n_alarm = 0;
|
|
fep->ptp_caps.n_ext_ts = 0;
|
|
fep->ptp_caps.n_per_out = 1;
|
|
@@ -734,14 +1064,7 @@ void fec_ptp_init(struct platform_device *pdev, int irq_idx)
|
|
fep->ptp_caps.settime64 = fec_ptp_settime;
|
|
fep->ptp_caps.enable = fec_ptp_enable;
|
|
|
|
- fep->cycle_speed = clk_get_rate(fep->clk_ptp);
|
|
- if (!fep->cycle_speed) {
|
|
- fep->cycle_speed = NSEC_PER_SEC;
|
|
- dev_err(&fep->pdev->dev, "clk_ptp clock rate is zero\n");
|
|
- }
|
|
- fep->ptp_inc = NSEC_PER_SEC / fep->cycle_speed;
|
|
-
|
|
- spin_lock_init(&fep->tmreg_lock);
|
|
+ raw_spin_lock_init(&fep->tmreg_lock);
|
|
|
|
fec_ptp_start_cyclecounter(ndev);
|
|
|
|
diff --git a/drivers/net/ethernet/freescale/fec_uio.c b/drivers/net/ethernet/freescale/fec_uio.c
|
|
index 17049d99c3e7..3503c3142dec 100644
|
|
--- a/drivers/net/ethernet/freescale/fec_uio.c
|
|
+++ b/drivers/net/ethernet/freescale/fec_uio.c
|
|
@@ -1249,8 +1249,8 @@ static int fec_enet_uio_init(struct net_device *ndev)
|
|
return ret;
|
|
}
|
|
|
|
- tx_ring_size = RING_SIZE_TX;
|
|
- rx_ring_size = RING_SIZE_RX;
|
|
+ tx_ring_size = FEC_TX_RING_SIZE;
|
|
+ rx_ring_size = FEC_RX_RING_SIZE;
|
|
|
|
for (i = 0; i < FEC_MAX_Q; i++) {
|
|
total_tx_ring_size += tx_ring_size;
|
|
diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c
|
|
index 7a15b9245698..4d2fba3b2dd2 100644
|
|
--- a/drivers/net/ethernet/freescale/gianfar_ethtool.c
|
|
+++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c
|
|
@@ -11,6 +11,7 @@
|
|
* Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com>
|
|
*
|
|
* Copyright 2003-2006, 2008-2009, 2011 Freescale Semiconductor, Inc.
|
|
+ * Copyright 2017-2023 NXP
|
|
*/
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
@@ -168,6 +169,32 @@ static void gfar_gdrvinfo(struct net_device *dev,
|
|
strscpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
|
|
}
|
|
|
|
+static int gfar_get_eee(struct net_device *dev, struct ethtool_eee *et_eee)
|
|
+{
|
|
+ struct phy_device *phydev = dev->phydev;
|
|
+
|
|
+ if (!phydev)
|
|
+ return -ENODEV;
|
|
+
|
|
+ return phy_ethtool_get_eee(phydev, et_eee);
|
|
+}
|
|
+
|
|
+static int gfar_set_eee(struct net_device *dev, struct ethtool_eee *et_eee)
|
|
+{
|
|
+ struct phy_device *phydev = dev->phydev;
|
|
+
|
|
+ if (!phydev)
|
|
+ return -ENODEV;
|
|
+
|
|
+ if (et_eee->eee_enabled ||
|
|
+ et_eee->tx_lpi_enabled ||
|
|
+ et_eee->tx_lpi_timer) {
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+
|
|
+ return phy_ethtool_set_eee(phydev, et_eee);
|
|
+}
|
|
+
|
|
/* Return the length of the register structure */
|
|
static int gfar_reglen(struct net_device *dev)
|
|
{
|
|
@@ -1491,6 +1518,8 @@ static int gfar_get_ts_info(struct net_device *dev,
|
|
const struct ethtool_ops gfar_ethtool_ops = {
|
|
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
|
|
ETHTOOL_COALESCE_MAX_FRAMES,
|
|
+ .get_eee = gfar_get_eee,
|
|
+ .set_eee = gfar_set_eee,
|
|
.get_drvinfo = gfar_gdrvinfo,
|
|
.get_regs_len = gfar_reglen,
|
|
.get_regs = gfar_get_regs,
|
|
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig b/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig
|
|
index bb6693e2d702..9e219bbfd978 100644
|
|
--- a/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig
|
|
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/Kconfig
|
|
@@ -84,7 +84,7 @@ config FSL_DPAA_ETH_JUMBO_FRAME
|
|
config FSL_DPAA_TS
|
|
bool "Linux compliant timestamping"
|
|
depends on FSL_SDK_DPAA_ETH
|
|
- default n
|
|
+ default y
|
|
help
|
|
Enable Linux API compliant timestamping support.
|
|
|
|
@@ -96,6 +96,15 @@ config FSL_DPAA_1588
|
|
help
|
|
Enable IEEE1588 support code.
|
|
|
|
+config FSL_DPAA_ETHERCAT
|
|
+ bool "Enable DPAA Ethercat support"
|
|
+ depends on FSL_SDK_DPAA_ETH
|
|
+ default n
|
|
+ help
|
|
+ Enable DPAA Ethercat support code, if enabling this feature, will create a new
|
|
+ QMan Portal for Ethercat port, and isolate the last cpu core for Ethercat traffic.
|
|
+ Regular ethernet traffic will NOT be in the isolated core.
|
|
+
|
|
config FSL_DPAA_ETH_MAX_BUF_COUNT
|
|
int "Maximum number of buffers in the private bpool"
|
|
depends on FSL_SDK_DPAA_ETH
|
|
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/Makefile b/drivers/net/ethernet/freescale/sdk_dpaa/Makefile
|
|
index a0623b24fa1c..9f9980099aad 100644
|
|
--- a/drivers/net/ethernet/freescale/sdk_dpaa/Makefile
|
|
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/Makefile
|
|
@@ -11,6 +11,9 @@ ccflags-y += -I$(NET_DPA)
|
|
obj-$(CONFIG_FSL_SDK_DPAA_ETH) += fsl_mac.o fsl_dpa.o
|
|
|
|
fsl_dpa-objs += dpaa_ethtool.o dpaa_eth_sysfs.o dpaa_eth.o dpaa_eth_sg.o dpaa_eth_common.o
|
|
+ifeq ($(CONFIG_FSL_DPAA_ETHERCAT),y)
|
|
+fsl_dpa-objs += dpaa_ethercat.o
|
|
+endif
|
|
ifeq ($(CONFIG_FSL_DPAA_DBG_LOOP),y)
|
|
fsl_dpa-objs += dpaa_debugfs.o
|
|
endif
|
|
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
|
|
index a8f59cd1b4f6..857705fb85f3 100644
|
|
--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
|
|
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth.h
|
|
@@ -1,5 +1,5 @@
|
|
/* Copyright 2008-2012 Freescale Semiconductor Inc.
|
|
- * Copyright 2019 NXP
|
|
+ * Copyright 2019-2023 NXP
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
@@ -415,6 +415,12 @@ struct dpa_priv_s {
|
|
#ifdef CONFIG_FSL_DPAA_CEETM
|
|
bool ceetm_en; /* CEETM QoS enabled */
|
|
#endif
|
|
+
|
|
+#ifdef CONFIG_FSL_DPAA_ETHERCAT
|
|
+ uint16_t ethercat_channel; /* "fsl,qman-channel-id" */
|
|
+ struct qman_portal *p;
|
|
+ void *ecdev;
|
|
+#endif
|
|
};
|
|
|
|
struct fm_port_fqs {
|
|
@@ -461,6 +467,11 @@ int __hot skb_to_sg_fd(struct dpa_priv_s *priv,
|
|
int __cold __attribute__((nonnull))
|
|
_dpa_fq_free(struct device *dev, struct qman_fq *fq);
|
|
|
|
+#ifdef CONFIG_FSL_DPAA_ETHERCAT
|
|
+int dpa_unregister_ethercat(struct net_device *net_dev);
|
|
+int ec_dpaa_receive_data(void *pecdev, const void *data, size_t size);
|
|
+#endif
|
|
+
|
|
/* Turn on HW checksum computation for this outgoing frame.
|
|
* If the current protocol is not something we support in this regard
|
|
* (or if the stack has already computed the SW checksum), we do nothing.
|
|
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
|
|
index b31bd1b0461b..2967d09905e6 100644
|
|
--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
|
|
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_common.c
|
|
@@ -1,4 +1,5 @@
|
|
/* Copyright 2008-2013 Freescale Semiconductor, Inc.
|
|
+ * Copyright 2019-2023 NXP
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
@@ -471,7 +472,15 @@ int __cold dpa_remove(struct platform_device *of_dev)
|
|
dpaa_eth_sysfs_remove(dev);
|
|
|
|
dev_set_drvdata(dev, NULL);
|
|
+
|
|
+#ifdef CONFIG_FSL_DPAA_ETHERCAT
|
|
+ if (priv->ecdev)
|
|
+ dpa_unregister_ethercat(net_dev);
|
|
+ else
|
|
+ unregister_netdev(net_dev);
|
|
+#else
|
|
unregister_netdev(net_dev);
|
|
+#endif
|
|
|
|
err = dpa_fq_free(dev, &priv->dpa_fq_list);
|
|
|
|
@@ -985,6 +994,49 @@ void dpa_release_channel(void)
|
|
}
|
|
EXPORT_SYMBOL(dpa_release_channel);
|
|
|
|
+#ifdef CONFIG_FSL_DPAA_ETHERCAT
|
|
+static int ec_cpu_isolated[NR_CPUS];
|
|
+static int __init ethercat_cpus_setup(char *str)
|
|
+{
|
|
+ int last_idx = -1;
|
|
+ int dash_flag = 0;
|
|
+ int idx = 0;
|
|
+ int i = 0;
|
|
+ int j = 0;
|
|
+
|
|
+ if (!str)
|
|
+ return 0;
|
|
+
|
|
+ for (i = 0; i < strlen(str); i++) {
|
|
+ if (str[i] == ',') {
|
|
+ last_idx = -1;
|
|
+ dash_flag = 0;
|
|
+ continue;
|
|
+ } else if ((str[i] == '-') && (last_idx >= 0)) {
|
|
+ dash_flag = 1;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if ((str[i] >= '0') && (str[i] <= '9')) {
|
|
+ idx = str[i] - '0';
|
|
+ ec_cpu_isolated[idx] = 1;
|
|
+
|
|
+ if (dash_flag) {
|
|
+ for (j = last_idx; j < idx; j++)
|
|
+ ec_cpu_isolated[j] = 1;
|
|
+ last_idx = -1;
|
|
+ dash_flag = 0;
|
|
+ } else {
|
|
+ last_idx = idx;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+__setup("ethercat_cpus=", ethercat_cpus_setup);
|
|
+#endif
|
|
+
|
|
void dpaa_eth_add_channel(u16 channel)
|
|
{
|
|
const cpumask_t *cpus = qman_affine_cpus();
|
|
@@ -993,6 +1045,10 @@ void dpaa_eth_add_channel(u16 channel)
|
|
struct qman_portal *portal;
|
|
|
|
for_each_cpu(cpu, cpus) {
|
|
+#ifdef CONFIG_FSL_DPAA_ETHERCAT
|
|
+ if (ec_cpu_isolated[cpu])
|
|
+ continue;
|
|
+#endif
|
|
portal = (struct qman_portal *)qman_get_affine_portal(cpu);
|
|
qman_p_static_dequeue_add(portal, pool);
|
|
}
|
|
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
|
|
index 14015cf6a9a6..0834a5d8265f 100644
|
|
--- a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
|
|
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_eth_sg.c
|
|
@@ -1,5 +1,5 @@
|
|
/* Copyright 2012 Freescale Semiconductor Inc.
|
|
- * Copyright 2019 NXP
|
|
+ * Copyright 2019-2023 NXP
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
@@ -610,10 +610,31 @@ void __hot _dpa_rx(struct net_device *net_dev,
|
|
* which case we were in) having been removed from the pool.
|
|
*/
|
|
(*count_ptr)--;
|
|
+#ifndef CONFIG_FSL_DPAA_ETHERCAT
|
|
skb->protocol = eth_type_trans(skb, net_dev);
|
|
-
|
|
+#endif
|
|
skb_len = skb->len;
|
|
|
|
+#ifdef CONFIG_FSL_DPAA_ETHERCAT
|
|
+ if (priv->ecdev) {
|
|
+ u16 rawcpuid = 0;
|
|
+ u16 prot = 0;
|
|
+
|
|
+ rawcpuid = (u16)raw_smp_processor_id();
|
|
+ skb_record_rx_queue(skb, rawcpuid);
|
|
+
|
|
+ prot = ntohs(*(u16 *)(skb->data + 12));
|
|
+ if (prot == ETH_P_ETHERCAT)
|
|
+ ec_dpaa_receive_data(priv->ecdev, skb->data, skb->len);
|
|
+ else
|
|
+ pr_warn("invalid ethercat protocol 0x%x\n", prot);
|
|
+
|
|
+ dev_kfree_skb(skb);
|
|
+ goto ethercat_tag;
|
|
+ }
|
|
+ skb->protocol = eth_type_trans(skb, net_dev);
|
|
+#endif
|
|
+
|
|
#ifdef CONFIG_FSL_DPAA_DBG_LOOP
|
|
if (dpa_skb_loop(priv, skb)) {
|
|
percpu_stats->rx_packets++;
|
|
@@ -637,6 +658,9 @@ void __hot _dpa_rx(struct net_device *net_dev,
|
|
} else if (unlikely(netif_receive_skb(skb) == NET_RX_DROP))
|
|
return;
|
|
|
|
+#ifdef CONFIG_FSL_DPAA_ETHERCAT
|
|
+ethercat_tag:
|
|
+#endif
|
|
percpu_stats->rx_packets++;
|
|
percpu_stats->rx_bytes += skb_len;
|
|
|
|
diff --git a/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethercat.c b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethercat.c
|
|
new file mode 100644
|
|
index 000000000000..74a77460fecf
|
|
--- /dev/null
|
|
+++ b/drivers/net/ethernet/freescale/sdk_dpaa/dpaa_ethercat.c
|
|
@@ -0,0 +1,1216 @@
|
|
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
|
|
+/*
|
|
+ * Copyright 2021-2023 NXP
|
|
+ */
|
|
+
|
|
+#include <linux/init.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/of_mdio.h>
|
|
+#include <linux/of_net.h>
|
|
+#include <linux/kthread.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/if_arp.h> /* arp_hdr_len() */
|
|
+#include <linux/if_vlan.h> /* VLAN_HLEN */
|
|
+#include <linux/icmp.h> /* struct icmphdr */
|
|
+#include <linux/ip.h> /* struct iphdr */
|
|
+#include <linux/ipv6.h> /* struct ipv6hdr */
|
|
+#include <linux/udp.h> /* struct udphdr */
|
|
+#include <linux/tcp.h> /* struct tcphdr */
|
|
+#include <linux/net.h> /* net_ratelimit() */
|
|
+#include <linux/if_ether.h> /* ETH_P_IP and ETH_P_IPV6 */
|
|
+#include <linux/highmem.h>
|
|
+#include <linux/percpu.h>
|
|
+#include <linux/dma-mapping.h>
|
|
+#include <linux/fsl_bman.h>
|
|
+#ifdef CONFIG_SOC_BUS
|
|
+#include <linux/sys_soc.h> /* soc_device_match */
|
|
+#endif
|
|
+
|
|
+#include "fsl_fman.h"
|
|
+#include "fm_ext.h"
|
|
+#include "fm_port_ext.h"
|
|
+
|
|
+#include "mac.h"
|
|
+#include "dpaa_eth.h"
|
|
+#include "dpaa_eth_common.h"
|
|
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
|
|
+#include "dpaa_debugfs.h"
|
|
+#endif /* CONFIG_FSL_DPAA_DBG_LOOP */
|
|
+
|
|
+#define DPA_NAPI_WEIGHT 64
|
|
+
|
|
+/* Valid checksum indication */
|
|
+#define DPA_CSUM_VALID 0xFFFF
|
|
+
|
|
+#define DPA_DESCRIPTION "FSL/NXP DPAA Ethercat driver"
|
|
+
|
|
+MODULE_LICENSE("Dual BSD/GPL");
|
|
+
|
|
+MODULE_DESCRIPTION(DPA_DESCRIPTION);
|
|
+
|
|
+static u8 debug = -1;
|
|
+
|
|
+/* This has to work in tandem with the DPA_CS_THRESHOLD_xxx values. */
|
|
+static u16 tx_timeout = 1000;
|
|
+
|
|
+static const char rtx[][3] = {
|
|
+ [RX] = "RX",
|
|
+ [TX] = "TX"
|
|
+};
|
|
+
|
|
+/* BM */
|
|
+
|
|
+#define DPAA_ETH_MAX_PAD (L1_CACHE_BYTES * 8)
|
|
+
|
|
+static u32 dpa_priv_bpid;
|
|
+static u32 dpa_priv_cpuid;
|
|
+
|
|
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
|
|
+struct net_device *dpa_loop_netdevs[20];
|
|
+#endif
|
|
+
|
|
+#ifdef CONFIG_PM
|
|
+
|
|
+static int dpaa_suspend(struct device *dev)
|
|
+{
|
|
+ struct net_device *net_dev;
|
|
+ struct dpa_priv_s *priv;
|
|
+ struct mac_device *mac_dev;
|
|
+ int err = 0;
|
|
+
|
|
+ net_dev = dev_get_drvdata(dev);
|
|
+
|
|
+ if (net_dev->flags & IFF_UP) {
|
|
+ priv = netdev_priv(net_dev);
|
|
+ mac_dev = priv->mac_dev;
|
|
+
|
|
+ if (priv->wol & DPAA_WOL_MAGIC) {
|
|
+ err = priv->mac_dev->set_wol(mac_dev->port_dev[RX],
|
|
+ priv->mac_dev->get_mac_handle(mac_dev), true);
|
|
+ if (err) {
|
|
+ netdev_err(net_dev, "set_wol() = %d\n", err);
|
|
+ goto set_wol_failed;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ err = fm_port_suspend(mac_dev->port_dev[RX]);
|
|
+ if (err) {
|
|
+ netdev_err(net_dev, "fm_port_suspend(RX) = %d\n", err);
|
|
+ goto rx_port_suspend_failed;
|
|
+ }
|
|
+
|
|
+ err = fm_port_suspend(mac_dev->port_dev[TX]);
|
|
+ if (err) {
|
|
+ netdev_err(net_dev, "fm_port_suspend(TX) = %d\n", err);
|
|
+ goto tx_port_suspend_failed;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+tx_port_suspend_failed:
|
|
+ fm_port_resume(mac_dev->port_dev[RX]);
|
|
+rx_port_suspend_failed:
|
|
+ if (priv->wol & DPAA_WOL_MAGIC) {
|
|
+ priv->mac_dev->set_wol(mac_dev->port_dev[RX],
|
|
+ priv->mac_dev->get_mac_handle(mac_dev), false);
|
|
+ }
|
|
+set_wol_failed:
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static int dpaa_resume(struct device *dev)
|
|
+{
|
|
+ struct net_device *net_dev;
|
|
+ struct dpa_priv_s *priv;
|
|
+ struct mac_device *mac_dev;
|
|
+ int err = 0;
|
|
+
|
|
+ net_dev = dev_get_drvdata(dev);
|
|
+
|
|
+ if (net_dev->flags & IFF_UP) {
|
|
+ priv = netdev_priv(net_dev);
|
|
+ mac_dev = priv->mac_dev;
|
|
+
|
|
+ err = fm_mac_resume(mac_dev->get_mac_handle(mac_dev));
|
|
+ if (err) {
|
|
+ netdev_err(net_dev, "fm_mac_resume = %d\n", err);
|
|
+ goto resume_failed;
|
|
+ }
|
|
+
|
|
+ err = fm_port_resume(mac_dev->port_dev[TX]);
|
|
+ if (err) {
|
|
+ netdev_err(net_dev, "fm_port_resume(TX) = %d\n", err);
|
|
+ goto resume_failed;
|
|
+ }
|
|
+
|
|
+ err = fm_port_resume(mac_dev->port_dev[RX]);
|
|
+ if (err) {
|
|
+ netdev_err(net_dev, "fm_port_resume(RX) = %d\n", err);
|
|
+ goto resume_failed;
|
|
+ }
|
|
+
|
|
+ if (priv->wol & DPAA_WOL_MAGIC) {
|
|
+ err = priv->mac_dev->set_wol(mac_dev->port_dev[RX],
|
|
+ priv->mac_dev->get_mac_handle(mac_dev), false);
|
|
+ if (err) {
|
|
+ netdev_err(net_dev, "set_wol() = %d\n", err);
|
|
+ goto resume_failed;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+resume_failed:
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static const struct dev_pm_ops dpaa_pm_ops = {
|
|
+ .suspend = dpaa_suspend,
|
|
+ .resume = dpaa_resume,
|
|
+};
|
|
+
|
|
+#define DPAA_PM_OPS (&dpaa_pm_ops)
|
|
+
|
|
+#else /* CONFIG_PM */
|
|
+
|
|
+#define DPAA_PM_OPS NULL
|
|
+
|
|
+#endif /* CONFIG_PM */
|
|
+
|
|
+/* Checks whether the checksum field in Parse Results array is valid
|
|
+ * (equals 0xFFFF) and increments the .cse counter otherwise
|
|
+ */
|
|
+static inline void
|
|
+dpa_csum_validation(const struct dpa_priv_s *priv,
|
|
+ struct dpa_percpu_priv_s *percpu_priv,
|
|
+ const struct qm_fd *fd)
|
|
+{
|
|
+ dma_addr_t addr = qm_fd_addr(fd);
|
|
+ struct dpa_bp *dpa_bp = priv->dpa_bp;
|
|
+ void *frm = phys_to_virt(addr);
|
|
+ fm_prs_result_t *parse_result;
|
|
+
|
|
+ if (unlikely(!frm))
|
|
+ return;
|
|
+
|
|
+ dma_sync_single_for_cpu(dpa_bp->dev, addr, DPA_RX_PRIV_DATA_SIZE +
|
|
+ DPA_PARSE_RESULTS_SIZE, DMA_BIDIRECTIONAL);
|
|
+
|
|
+ parse_result = (fm_prs_result_t *)(frm + DPA_RX_PRIV_DATA_SIZE);
|
|
+
|
|
+ if (parse_result->cksum != DPA_CSUM_VALID)
|
|
+ percpu_priv->rx_errors.cse++;
|
|
+}
|
|
+
|
|
+static void _dpa_rx_error(struct net_device *net_dev,
|
|
+ const struct dpa_priv_s *priv,
|
|
+ struct dpa_percpu_priv_s *percpu_priv,
|
|
+ const struct qm_fd *fd,
|
|
+ u32 fqid)
|
|
+{
|
|
+ /* limit common, possibly innocuous Rx FIFO Overflow errors'
|
|
+ * interference with zero-loss convergence benchmark results.
|
|
+ */
|
|
+ if (likely(fd->status & FM_FD_STAT_ERR_PHYSICAL))
|
|
+ pr_warn_once("fsl-dpa: non-zero error counters in fman statistics (sysfs)\n");
|
|
+ else
|
|
+ if (netif_msg_hw(priv) && net_ratelimit())
|
|
+ netdev_dbg(net_dev, "Err FD status = 0x%08x\n",
|
|
+ fd->status & FM_FD_STAT_RX_ERRORS);
|
|
+#ifdef CONFIG_FSL_DPAA_HOOKS
|
|
+ if (dpaa_eth_hooks.rx_error &&
|
|
+ dpaa_eth_hooks.rx_error(net_dev, fd, fqid) == DPAA_ETH_STOLEN)
|
|
+ /* it's up to the hook to perform resource cleanup */
|
|
+ return;
|
|
+#endif
|
|
+ percpu_priv->stats.rx_errors++;
|
|
+
|
|
+ if (fd->status & FM_PORT_FRM_ERR_DMA)
|
|
+ percpu_priv->rx_errors.dme++;
|
|
+ if (fd->status & FM_PORT_FRM_ERR_PHYSICAL)
|
|
+ percpu_priv->rx_errors.fpe++;
|
|
+ if (fd->status & FM_PORT_FRM_ERR_SIZE)
|
|
+ percpu_priv->rx_errors.fse++;
|
|
+ if (fd->status & FM_PORT_FRM_ERR_PRS_HDR_ERR)
|
|
+ percpu_priv->rx_errors.phe++;
|
|
+ if (fd->status & FM_FD_STAT_L4CV)
|
|
+ dpa_csum_validation(priv, percpu_priv, fd);
|
|
+
|
|
+ dpa_fd_release(net_dev, fd);
|
|
+}
|
|
+
|
|
+static void _dpa_tx_error(struct net_device *net_dev,
|
|
+ const struct dpa_priv_s *priv,
|
|
+ struct dpa_percpu_priv_s *percpu_priv,
|
|
+ const struct qm_fd *fd,
|
|
+ u32 fqid)
|
|
+{
|
|
+ struct sk_buff *skb;
|
|
+
|
|
+ if (netif_msg_hw(priv) && net_ratelimit())
|
|
+ netdev_warn(net_dev, "FD status = 0x%08x\n",
|
|
+ fd->status & FM_FD_STAT_TX_ERRORS);
|
|
+#ifdef CONFIG_FSL_DPAA_HOOKS
|
|
+ if (dpaa_eth_hooks.tx_error &&
|
|
+ dpaa_eth_hooks.tx_error(net_dev, fd, fqid) == DPAA_ETH_STOLEN)
|
|
+ /* now the hook must ensure proper cleanup */
|
|
+ return;
|
|
+#endif
|
|
+ percpu_priv->stats.tx_errors++;
|
|
+
|
|
+ /* If we intended the buffers from this frame to go into the bpools
|
|
+ * when the FMan transmit was done, we need to put it in manually.
|
|
+ */
|
|
+ if (fd->bpid != 0xff) {
|
|
+ dpa_fd_release(net_dev, fd);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ skb = _dpa_cleanup_tx_fd(priv, fd);
|
|
+ if (!priv->ecdev)
|
|
+ dev_kfree_skb(skb);
|
|
+}
|
|
+
|
|
+static void __hot _dpa_tx_conf(struct net_device *net_dev,
|
|
+ const struct dpa_priv_s *priv,
|
|
+ struct dpa_percpu_priv_s *percpu_priv,
|
|
+ const struct qm_fd *fd,
|
|
+ u32 fqid)
|
|
+{
|
|
+ struct sk_buff *skb;
|
|
+
|
|
+ /* do we need the timestamp for the error frames? */
|
|
+
|
|
+ if (unlikely(fd->status & FM_FD_STAT_TX_ERRORS) != 0) {
|
|
+ if (netif_msg_hw(priv) && net_ratelimit())
|
|
+ netdev_warn(net_dev, "FD status = 0x%08x\n",
|
|
+ fd->status & FM_FD_STAT_TX_ERRORS);
|
|
+
|
|
+ percpu_priv->stats.tx_errors++;
|
|
+ }
|
|
+
|
|
+ /* hopefully we need not get the timestamp before the hook */
|
|
+#ifdef CONFIG_FSL_DPAA_HOOKS
|
|
+ if (dpaa_eth_hooks.tx_confirm &&
|
|
+ dpaa_eth_hooks.tx_confirm(net_dev, fd, fqid) == DPAA_ETH_STOLEN)
|
|
+ /* it's the hook that must now perform cleanup */
|
|
+ return;
|
|
+#endif
|
|
+ /* This might not perfectly reflect the reality, if the core dequeuing
|
|
+ * the Tx confirmation is different from the one that did the enqueue,
|
|
+ * but at least it'll show up in the total count.
|
|
+ */
|
|
+ percpu_priv->tx_confirm++;
|
|
+
|
|
+ skb = _dpa_cleanup_tx_fd(priv, fd);
|
|
+ if (!priv->ecdev)
|
|
+ dev_kfree_skb(skb);
|
|
+}
|
|
+
|
|
+static enum qman_cb_dqrr_result
|
|
+priv_rx_error_dqrr(struct qman_portal *portal,
|
|
+ struct qman_fq *fq,
|
|
+ const struct qm_dqrr_entry *dq)
|
|
+{
|
|
+ struct net_device *net_dev;
|
|
+ struct dpa_priv_s *priv;
|
|
+ struct dpa_percpu_priv_s *percpu_priv;
|
|
+ int *count_ptr;
|
|
+
|
|
+ net_dev = ((struct dpa_fq *)fq)->net_dev;
|
|
+ priv = netdev_priv(net_dev);
|
|
+
|
|
+ percpu_priv = raw_cpu_ptr(priv->percpu_priv);
|
|
+ count_ptr = raw_cpu_ptr(priv->percpu_count);
|
|
+
|
|
+ if (unlikely(dpaa_eth_refill_bpools(priv->dpa_bp, count_ptr)))
|
|
+ /* Unable to refill the buffer pool due to insufficient
|
|
+ * system memory. Just release the frame back into the pool,
|
|
+ * otherwise we'll soon end up with an empty buffer pool.
|
|
+ */
|
|
+ dpa_fd_release(net_dev, &dq->fd);
|
|
+ else
|
|
+ _dpa_rx_error(net_dev, priv, percpu_priv, &dq->fd, fq->fqid);
|
|
+
|
|
+ return qman_cb_dqrr_consume;
|
|
+}
|
|
+
|
|
+static enum qman_cb_dqrr_result __hot
|
|
+priv_rx_default_dqrr(struct qman_portal *portal,
|
|
+ struct qman_fq *fq,
|
|
+ const struct qm_dqrr_entry *dq)
|
|
+{
|
|
+ struct net_device *net_dev;
|
|
+ struct dpa_priv_s *priv;
|
|
+ struct dpa_percpu_priv_s *percpu_priv;
|
|
+ int *count_ptr;
|
|
+ struct dpa_bp *dpa_bp;
|
|
+
|
|
+ net_dev = ((struct dpa_fq *)fq)->net_dev;
|
|
+ priv = netdev_priv(net_dev);
|
|
+ dpa_bp = priv->dpa_bp;
|
|
+
|
|
+ /* IRQ handler, non-migratable; safe to use raw_cpu_ptr here */
|
|
+ percpu_priv = raw_cpu_ptr(priv->percpu_priv);
|
|
+ count_ptr = raw_cpu_ptr(priv->percpu_count);
|
|
+
|
|
+ /* Vale of plenty: make sure we didn't run out of buffers */
|
|
+
|
|
+ if (unlikely(dpaa_eth_refill_bpools(dpa_bp, count_ptr)))
|
|
+ /* Unable to refill the buffer pool due to insufficient
|
|
+ * system memory. Just release the frame back into the pool,
|
|
+ * otherwise we'll soon end up with an empty buffer pool.
|
|
+ */
|
|
+ dpa_fd_release(net_dev, &dq->fd);
|
|
+ else
|
|
+ _dpa_rx(net_dev, portal, priv, percpu_priv, &dq->fd, fq->fqid,
|
|
+ count_ptr);
|
|
+
|
|
+ return qman_cb_dqrr_consume;
|
|
+}
|
|
+
|
|
+static enum qman_cb_dqrr_result
|
|
+priv_tx_conf_error_dqrr(struct qman_portal *portal,
|
|
+ struct qman_fq *fq,
|
|
+ const struct qm_dqrr_entry *dq)
|
|
+{
|
|
+ struct net_device *net_dev;
|
|
+ struct dpa_priv_s *priv;
|
|
+ struct dpa_percpu_priv_s *percpu_priv;
|
|
+
|
|
+ net_dev = ((struct dpa_fq *)fq)->net_dev;
|
|
+ priv = netdev_priv(net_dev);
|
|
+
|
|
+ percpu_priv = raw_cpu_ptr(priv->percpu_priv);
|
|
+
|
|
+ _dpa_tx_error(net_dev, priv, percpu_priv, &dq->fd, fq->fqid);
|
|
+
|
|
+ return qman_cb_dqrr_consume;
|
|
+}
|
|
+
|
|
+static enum qman_cb_dqrr_result __hot
|
|
+priv_tx_conf_default_dqrr(struct qman_portal *portal,
|
|
+ struct qman_fq *fq,
|
|
+ const struct qm_dqrr_entry *dq)
|
|
+{
|
|
+ struct net_device *net_dev;
|
|
+ struct dpa_priv_s *priv;
|
|
+ struct dpa_percpu_priv_s *percpu_priv;
|
|
+
|
|
+ net_dev = ((struct dpa_fq *)fq)->net_dev;
|
|
+ priv = netdev_priv(net_dev);
|
|
+
|
|
+ /* Non-migratable context, safe to use raw_cpu_ptr */
|
|
+ percpu_priv = raw_cpu_ptr(priv->percpu_priv);
|
|
+
|
|
+ _dpa_tx_conf(net_dev, priv, percpu_priv, &dq->fd, fq->fqid);
|
|
+
|
|
+ return qman_cb_dqrr_consume;
|
|
+}
|
|
+
|
|
+static void priv_ern(struct qman_portal *portal,
|
|
+ struct qman_fq *fq,
|
|
+ const struct qm_mr_entry *msg)
|
|
+{
|
|
+ struct net_device *net_dev;
|
|
+ const struct dpa_priv_s *priv;
|
|
+ struct sk_buff *skb;
|
|
+ struct dpa_percpu_priv_s *percpu_priv;
|
|
+ struct qm_fd fd = msg->ern.fd;
|
|
+
|
|
+ net_dev = ((struct dpa_fq *)fq)->net_dev;
|
|
+ priv = netdev_priv(net_dev);
|
|
+ /* Non-migratable context, safe to use raw_cpu_ptr */
|
|
+ percpu_priv = raw_cpu_ptr(priv->percpu_priv);
|
|
+
|
|
+ percpu_priv->stats.tx_dropped++;
|
|
+ percpu_priv->stats.tx_fifo_errors++;
|
|
+ count_ern(percpu_priv, msg);
|
|
+
|
|
+ /* If we intended this buffer to go into the pool
|
|
+ * when the FM was done, we need to put it in
|
|
+ * manually.
|
|
+ */
|
|
+ if (msg->ern.fd.bpid != 0xff) {
|
|
+ dpa_fd_release(net_dev, &fd);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ skb = _dpa_cleanup_tx_fd(priv, &fd);
|
|
+ dev_kfree_skb_any(skb);
|
|
+}
|
|
+
|
|
+static const struct dpa_fq_cbs_t private_fq_cbs = {
|
|
+ .rx_defq = { .cb = { .dqrr = priv_rx_default_dqrr } },
|
|
+ .tx_defq = { .cb = { .dqrr = priv_tx_conf_default_dqrr } },
|
|
+ .rx_errq = { .cb = { .dqrr = priv_rx_error_dqrr } },
|
|
+ .tx_errq = { .cb = { .dqrr = priv_tx_conf_error_dqrr } },
|
|
+ .egress_ern = { .cb = { .ern = priv_ern } }
|
|
+};
|
|
+
|
|
+static int __cold dpa_eth_priv_start(struct net_device *net_dev)
|
|
+{
|
|
+ int err;
|
|
+ struct dpa_priv_s *priv;
|
|
+
|
|
+ priv = netdev_priv(net_dev);
|
|
+
|
|
+ err = dpa_start(net_dev);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static int __cold dpa_eth_priv_stop(struct net_device *net_dev)
|
|
+{
|
|
+ int _errno;
|
|
+ struct dpa_priv_s *priv;
|
|
+
|
|
+ _errno = dpa_stop(net_dev);
|
|
+ /* Allow NAPI to consume any frame still in the Rx/TxConfirm
|
|
+ * ingress queues. This is to avoid a race between the current
|
|
+ * context and ksoftirqd which could leave NAPI disabled while
|
|
+ * in fact there's still Rx traffic to be processed.
|
|
+ */
|
|
+ usleep_range(5000, 10000);
|
|
+
|
|
+ priv = netdev_priv(net_dev);
|
|
+
|
|
+ return _errno;
|
|
+}
|
|
+
|
|
+static const struct net_device_ops dpa_private_ops = {
|
|
+ .ndo_open = dpa_eth_priv_start,
|
|
+ .ndo_start_xmit = dpa_tx,
|
|
+ .ndo_stop = dpa_eth_priv_stop,
|
|
+ .ndo_tx_timeout = dpa_timeout,
|
|
+ .ndo_get_stats64 = dpa_get_stats64,
|
|
+ .ndo_set_mac_address = dpa_set_mac_address,
|
|
+ .ndo_validate_addr = eth_validate_addr,
|
|
+#ifdef CONFIG_FMAN_PFC
|
|
+ .ndo_select_queue = dpa_select_queue,
|
|
+#endif
|
|
+ .ndo_set_rx_mode = dpa_set_rx_mode,
|
|
+ .ndo_init = dpa_ndo_init,
|
|
+ .ndo_set_features = dpa_set_features,
|
|
+ .ndo_do_ioctl = dpa_ioctl,
|
|
+};
|
|
+
|
|
+typedef int (*ec_dpaa_receive_cb)(void *pecdev, const void *data, size_t size);
|
|
+typedef int (*ec_dpaa_link_cb)(void *pecdev, uint8_t link);
|
|
+typedef int (*ec_dpaa_close_cb)(void *pecdev);
|
|
+
|
|
+static ec_dpaa_receive_cb ec_dpaa_recv_func;
|
|
+static ec_dpaa_close_cb ec_dpaa_close_func;
|
|
+static ec_dpaa_link_cb ec_dpaa_link_func;
|
|
+
|
|
+int ec_dpaa_receive_data(void *pecdev, const void *data, size_t size)
|
|
+{
|
|
+ int ret = 0;
|
|
+
|
|
+ if (ec_dpaa_recv_func)
|
|
+ ret = ec_dpaa_recv_func(pecdev, data, size);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int ec_dpaa_set_func_cb(ec_dpaa_receive_cb recv, ec_dpaa_link_cb link, ec_dpaa_close_cb close)
|
|
+{
|
|
+ ec_dpaa_recv_func = recv;
|
|
+ ec_dpaa_link_func = link;
|
|
+ ec_dpaa_close_func = close;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(ec_dpaa_set_func_cb);
|
|
+
|
|
+struct module *ec_dpaa_get_module(void)
|
|
+{
|
|
+ struct module *m = THIS_MODULE;
|
|
+ return m;
|
|
+}
|
|
+EXPORT_SYMBOL(ec_dpaa_get_module);
|
|
+
|
|
+#define MAX_EC_DPAA_NETDEV_CNT (16)
|
|
+static int ec_dpaa_netdev_cnt;
|
|
+static struct net_device *ec_dpaa_netdev[MAX_EC_DPAA_NETDEV_CNT];
|
|
+
|
|
+struct net_device *ec_dpaa_get_netdev(int idx)
|
|
+{
|
|
+ if (idx >= MAX_EC_DPAA_NETDEV_CNT)
|
|
+ return NULL;
|
|
+
|
|
+ if (idx >= ec_dpaa_netdev_cnt)
|
|
+ return NULL;
|
|
+
|
|
+ return ec_dpaa_netdev[idx];
|
|
+}
|
|
+EXPORT_SYMBOL(ec_dpaa_get_netdev);
|
|
+
|
|
+int ec_dpaa_set_ecdev(int idx, void *ecdev)
|
|
+{
|
|
+ struct net_device *net_dev = NULL;
|
|
+ struct dpa_priv_s *priv = NULL;
|
|
+
|
|
+ net_dev = ec_dpaa_get_netdev(idx);
|
|
+ if (net_dev) {
|
|
+ priv = netdev_priv(net_dev);
|
|
+ priv->ecdev = ecdev;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(ec_dpaa_set_ecdev);
|
|
+
|
|
+void *ec_dpaa_get_ecdev(int idx)
|
|
+{
|
|
+ struct net_device *net_dev = NULL;
|
|
+ struct dpa_priv_s *priv = NULL;
|
|
+ void *ecdev = NULL;
|
|
+
|
|
+ net_dev = ec_dpaa_get_netdev(idx);
|
|
+ if (net_dev) {
|
|
+ priv = netdev_priv(net_dev);
|
|
+ ecdev = priv->ecdev;
|
|
+ }
|
|
+
|
|
+ return ecdev;
|
|
+}
|
|
+EXPORT_SYMBOL(ec_dpaa_get_ecdev);
|
|
+
|
|
+void ec_dpaa_poll(struct net_device *net_dev)
|
|
+{
|
|
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
|
|
+ u8 link = net_dev->phydev->state;
|
|
+
|
|
+ qman_p_poll_dqrr(priv->p, DPA_NAPI_WEIGHT);
|
|
+
|
|
+ if (ec_dpaa_link_func)
|
|
+ ec_dpaa_link_func(priv->ecdev, link);
|
|
+}
|
|
+EXPORT_SYMBOL(ec_dpaa_poll);
|
|
+
|
|
+int dpa_unregister_ethercat(struct net_device *net_dev)
|
|
+{
|
|
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
|
|
+
|
|
+ if (priv->ecdev) {
|
|
+ if (ec_dpaa_close_func)
|
|
+ ec_dpaa_close_func(priv->ecdev);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+EXPORT_SYMBOL(dpa_unregister_ethercat);
|
|
+
|
|
+static int dpa_ethercat_netdev_init(struct net_device *net_dev,
|
|
+ const u8 *mac_addr,
|
|
+ uint16_t tx_timeout)
|
|
+{
|
|
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
|
|
+
|
|
+ net_dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
|
|
+
|
|
+ net_dev->features |= net_dev->hw_features;
|
|
+ net_dev->vlan_features = net_dev->features;
|
|
+
|
|
+ memcpy(net_dev->perm_addr, mac_addr, net_dev->addr_len);
|
|
+ memcpy(net_dev->dev_addr, mac_addr, net_dev->addr_len);
|
|
+
|
|
+ net_dev->ethtool_ops = &dpa_ethtool_ops;
|
|
+
|
|
+ net_dev->needed_headroom = priv->tx_headroom;
|
|
+ net_dev->watchdog_timeo = msecs_to_jiffies(tx_timeout);
|
|
+
|
|
+ if (ec_dpaa_netdev_cnt < MAX_EC_DPAA_NETDEV_CNT)
|
|
+ ec_dpaa_netdev[ec_dpaa_netdev_cnt++] = net_dev;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int dpa_private_netdev_init(struct net_device *net_dev)
|
|
+{
|
|
+ int i;
|
|
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
|
|
+ struct dpa_percpu_priv_s *percpu_priv;
|
|
+ const u8 *mac_addr;
|
|
+
|
|
+ /* Although we access another CPU's private data here
|
|
+ * we do it at initialization so it is safe
|
|
+ */
|
|
+ for_each_possible_cpu(i) {
|
|
+ percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
|
|
+ percpu_priv->net_dev = net_dev;
|
|
+ }
|
|
+
|
|
+ net_dev->netdev_ops = &dpa_private_ops;
|
|
+ mac_addr = priv->mac_dev->addr;
|
|
+
|
|
+ net_dev->mem_start = priv->mac_dev->res->start;
|
|
+ net_dev->mem_end = priv->mac_dev->res->end;
|
|
+
|
|
+ /* Configure the maximum MTU according to the FMan's MAXFRM */
|
|
+ net_dev->min_mtu = ETH_MIN_MTU;
|
|
+ net_dev->max_mtu = dpa_get_max_mtu();
|
|
+
|
|
+ net_dev->hw_features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
|
|
+ NETIF_F_LLTX);
|
|
+
|
|
+ /* Advertise S/G and HIGHDMA support for private interfaces */
|
|
+ net_dev->hw_features |= NETIF_F_SG | NETIF_F_HIGHDMA;
|
|
+ /* Recent kernels enable GSO automatically, if
|
|
+ * we declare NETIF_F_SG. For conformity, we'll
|
|
+ * still declare GSO explicitly.
|
|
+ */
|
|
+ net_dev->features |= NETIF_F_GSO;
|
|
+
|
|
+ /* Advertise GRO support */
|
|
+ net_dev->features |= NETIF_F_GRO;
|
|
+
|
|
+ return dpa_ethercat_netdev_init(net_dev, mac_addr, tx_timeout);
|
|
+}
|
|
+
|
|
+static struct dpa_bp * __cold
|
|
+dpa_priv_bp_probe(struct device *dev)
|
|
+{
|
|
+ struct dpa_bp *dpa_bp;
|
|
+
|
|
+ dpa_bp = devm_kzalloc(dev, sizeof(*dpa_bp), GFP_KERNEL);
|
|
+ if (unlikely(!dpa_bp)) {
|
|
+ dev_err(dev, "devm_kzalloc() failed\n");
|
|
+ return ERR_PTR(-ENOMEM);
|
|
+ }
|
|
+
|
|
+ dpa_bp->target_count = CONFIG_FSL_DPAA_ETH_MAX_BUF_COUNT;
|
|
+
|
|
+ dpa_bp->free_buf_cb = _dpa_bp_free_pf;
|
|
+
|
|
+ return dpa_bp;
|
|
+}
|
|
+
|
|
+/* Place all ingress FQs (Rx Default, Rx Error, PCD FQs) in a dedicated CGR.
|
|
+ * We won't be sending congestion notifications to FMan; for now, we just use
|
|
+ * this CGR to generate enqueue rejections to FMan in order to drop the frames
|
|
+ * before they reach our ingress queues and eat up memory.
|
|
+ */
|
|
+static int dpaa_eth_priv_ingress_cgr_init(struct dpa_priv_s *priv)
|
|
+{
|
|
+ struct qm_mcc_initcgr initcgr;
|
|
+ u32 cs_th;
|
|
+ int err;
|
|
+
|
|
+ err = qman_alloc_cgrid(&priv->ingress_cgr.cgrid);
|
|
+ if (err < 0) {
|
|
+ pr_err("Error %d allocating CGR ID\n", err);
|
|
+ goto out_error;
|
|
+ }
|
|
+
|
|
+ /* Enable CS TD, but disable Congestion State Change Notifications. */
|
|
+ memset(&initcgr, 0, sizeof(initcgr));
|
|
+ initcgr.we_mask = QM_CGR_WE_CS_THRES;
|
|
+ initcgr.cgr.cscn_en = QM_CGR_EN;
|
|
+ cs_th = CONFIG_FSL_DPAA_INGRESS_CS_THRESHOLD;
|
|
+ qm_cgr_cs_thres_set64(&initcgr.cgr.cs_thres, cs_th, 1);
|
|
+
|
|
+ initcgr.we_mask |= QM_CGR_WE_CSTD_EN;
|
|
+ initcgr.cgr.cstd_en = QM_CGR_EN;
|
|
+
|
|
+ /* This is actually a hack, because this CGR will be associated with
|
|
+ * our affine SWP. However, we'll place our ingress FQs in it.
|
|
+ */
|
|
+ err = qman_create_cgr(&priv->ingress_cgr, QMAN_CGR_FLAG_USE_INIT,
|
|
+ &initcgr);
|
|
+ if (err < 0) {
|
|
+ pr_err("Error %d creating ingress CGR with ID %d\n", err,
|
|
+ priv->ingress_cgr.cgrid);
|
|
+ qman_release_cgrid(priv->ingress_cgr.cgrid);
|
|
+ goto out_error;
|
|
+ }
|
|
+ pr_debug("Created ingress CGR %d for netdev with hwaddr %pM\n",
|
|
+ priv->ingress_cgr.cgrid, priv->mac_dev->addr);
|
|
+
|
|
+ /* struct qman_cgr allows special cgrid values (i.e. outside the 0..255
|
|
+ * range), but we have no common initialization path between the
|
|
+ * different variants of the DPAA Eth driver, so we do it here rather
|
|
+ * than modifying every other variant than "private Eth".
|
|
+ */
|
|
+ priv->use_ingress_cgr = true;
|
|
+
|
|
+out_error:
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static void dpa_priv_bp_seed(struct net_device *net_dev)
|
|
+{
|
|
+ struct dpa_priv_s *priv = netdev_priv(net_dev);
|
|
+ struct dpa_bp *dpa_bp = priv->dpa_bp;
|
|
+ int i;
|
|
+
|
|
+ /* Give each CPU an allotment of buffers */
|
|
+ for_each_possible_cpu(i) {
|
|
+ /* Although we access another CPU's counters here
|
|
+ * we do it at boot time so it is safe
|
|
+ */
|
|
+ int *count_ptr = per_cpu_ptr(priv->percpu_count, i);
|
|
+
|
|
+ dpaa_eth_refill_bpools(dpa_bp, count_ptr);
|
|
+ }
|
|
+}
|
|
+
|
|
+static const struct of_device_id dpa_match[];
|
|
+
|
|
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
|
|
+static int dpa_new_loop_id(void)
|
|
+{
|
|
+ static int if_id;
|
|
+
|
|
+ return if_id++;
|
|
+}
|
|
+#endif
|
|
+
|
|
+extern int dpa_bp_create(struct net_device *net_dev, struct dpa_bp *dpa_bp,
|
|
+ size_t count);
|
|
+
|
|
+static inline void dpa_setup_ingress(const struct dpa_priv_s *priv,
|
|
+ struct dpa_fq *fq,
|
|
+ const struct qman_fq *template)
|
|
+{
|
|
+ fq->fq_base = *template;
|
|
+ fq->net_dev = priv->net_dev;
|
|
+
|
|
+ fq->flags = QMAN_FQ_FLAG_NO_ENQUEUE;
|
|
+ fq->channel = priv->channel;
|
|
+}
|
|
+
|
|
+static inline void dpa_setup_egress(const struct dpa_priv_s *priv,
|
|
+ struct dpa_fq *fq,
|
|
+ struct fm_port *port,
|
|
+ const struct qman_fq *template)
|
|
+{
|
|
+ fq->fq_base = *template;
|
|
+ fq->net_dev = priv->net_dev;
|
|
+
|
|
+ if (port) {
|
|
+ fq->flags = QMAN_FQ_FLAG_TO_DCPORTAL;
|
|
+ fq->channel = (u16)fm_get_tx_port_channel(port);
|
|
+ } else {
|
|
+ fq->flags = QMAN_FQ_FLAG_NO_MODIFY;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void dpa_fq_setup_ethercat(struct dpa_priv_s *priv, const struct dpa_fq_cbs_t *fq_cbs,
|
|
+ struct fm_port *tx_port)
|
|
+{
|
|
+ struct dpa_fq *fq;
|
|
+ u16 portals[NR_CPUS];
|
|
+ int cpu, portal_cnt = 0, num_portals = 0;
|
|
+ u32 pcd_fqid, pcd_fqid_hi_prio;
|
|
+ const cpumask_t *affine_cpus = qman_affine_cpus();
|
|
+ int egress_cnt = 0, conf_cnt = 0;
|
|
+
|
|
+ /* Prepare for PCD FQs init */
|
|
+ for_each_cpu(cpu, affine_cpus)
|
|
+ portals[num_portals++] = priv->ethercat_channel;
|
|
+
|
|
+ if (num_portals == 0)
|
|
+ dev_err(priv->net_dev->dev.parent,
|
|
+ "No Qman software (affine) channels found");
|
|
+
|
|
+ pcd_fqid = (priv->mac_dev) ?
|
|
+ DPAA_ETH_PCD_FQ_BASE(priv->mac_dev->res->start) : 0;
|
|
+ pcd_fqid_hi_prio = (priv->mac_dev) ?
|
|
+ DPAA_ETH_PCD_FQ_HI_PRIO_BASE(priv->mac_dev->res->start) : 0;
|
|
+
|
|
+ /* Initialize each FQ in the list */
|
|
+ list_for_each_entry(fq, &priv->dpa_fq_list, list) {
|
|
+ switch (fq->fq_type) {
|
|
+ case FQ_TYPE_RX_DEFAULT:
|
|
+ WARN_ON(!priv->mac_dev);
|
|
+ dpa_setup_ingress(priv, fq, &fq_cbs->rx_defq);
|
|
+ break;
|
|
+ case FQ_TYPE_RX_ERROR:
|
|
+ WARN_ON(!priv->mac_dev);
|
|
+ dpa_setup_ingress(priv, fq, &fq_cbs->rx_errq);
|
|
+ break;
|
|
+ case FQ_TYPE_RX_PCD:
|
|
+ /* For MACless we can't have dynamic Rx queues */
|
|
+ WARN_ON(!priv->mac_dev && !fq->fqid);
|
|
+ dpa_setup_ingress(priv, fq, &fq_cbs->rx_defq);
|
|
+ if (!fq->fqid)
|
|
+ fq->fqid = pcd_fqid++;
|
|
+ fq->channel = portals[portal_cnt];
|
|
+ portal_cnt = (portal_cnt + 1) % num_portals;
|
|
+ break;
|
|
+ case FQ_TYPE_RX_PCD_HI_PRIO:
|
|
+ /* For MACless we can't have dynamic Hi Pri Rx queues */
|
|
+ WARN_ON(!priv->mac_dev && !fq->fqid);
|
|
+ dpa_setup_ingress(priv, fq, &fq_cbs->rx_defq);
|
|
+ if (!fq->fqid)
|
|
+ fq->fqid = pcd_fqid_hi_prio++;
|
|
+ fq->channel = portals[portal_cnt];
|
|
+ portal_cnt = (portal_cnt + 1) % num_portals;
|
|
+ break;
|
|
+ case FQ_TYPE_TX:
|
|
+ dpa_setup_egress(priv, fq, tx_port,
|
|
+ &fq_cbs->egress_ern);
|
|
+ /* If we have more Tx queues than the number of cores,
|
|
+ * just ignore the extra ones.
|
|
+ */
|
|
+ if (egress_cnt < DPAA_ETH_TX_QUEUES)
|
|
+ priv->egress_fqs[egress_cnt++] = &fq->fq_base;
|
|
+ break;
|
|
+ case FQ_TYPE_TX_CONFIRM:
|
|
+ WARN_ON(!priv->mac_dev);
|
|
+ dpa_setup_ingress(priv, fq, &fq_cbs->tx_defq);
|
|
+ break;
|
|
+ case FQ_TYPE_TX_CONF_MQ:
|
|
+ WARN_ON(!priv->mac_dev);
|
|
+ dpa_setup_ingress(priv, fq, &fq_cbs->tx_defq);
|
|
+ priv->conf_fqs[conf_cnt++] = &fq->fq_base;
|
|
+ break;
|
|
+ case FQ_TYPE_TX_ERROR:
|
|
+ WARN_ON(!priv->mac_dev);
|
|
+ dpa_setup_ingress(priv, fq, &fq_cbs->tx_errq);
|
|
+ break;
|
|
+ default:
|
|
+ dev_warn(priv->net_dev->dev.parent,
|
|
+ "Unknown FQ type detected!\n");
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* The number of Tx queues may be smaller than the number of cores, if
|
|
+ * the Tx queue range is specified in the device tree instead of being
|
|
+ * dynamically allocated.
|
|
+ * Make sure all CPUs receive a corresponding Tx queue.
|
|
+ */
|
|
+ while (egress_cnt < DPAA_ETH_TX_QUEUES) {
|
|
+ list_for_each_entry(fq, &priv->dpa_fq_list, list) {
|
|
+ if (fq->fq_type != FQ_TYPE_TX)
|
|
+ continue;
|
|
+ priv->egress_fqs[egress_cnt++] = &fq->fq_base;
|
|
+ if (egress_cnt == DPAA_ETH_TX_QUEUES)
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static int dpaa_ethercat_probe(struct platform_device *_of_dev)
|
|
+{
|
|
+ int err = 0, i;
|
|
+ struct device *dev;
|
|
+ struct device_node *dpa_node;
|
|
+ struct dpa_bp *dpa_bp;
|
|
+ size_t count = 1;
|
|
+ struct net_device *net_dev = NULL;
|
|
+ struct dpa_priv_s *priv = NULL;
|
|
+ struct dpa_percpu_priv_s *percpu_priv;
|
|
+ struct fm_port_fqs port_fqs;
|
|
+ struct dpa_buffer_layout_s *buf_layout = NULL;
|
|
+ struct mac_device *mac_dev;
|
|
+ u32 last_cpu = 0;
|
|
+
|
|
+ dev = &_of_dev->dev;
|
|
+
|
|
+ dpa_node = dev->of_node;
|
|
+
|
|
+ if (!of_device_is_available(dpa_node))
|
|
+ return -ENODEV;
|
|
+
|
|
+ /* Get the buffer pools assigned to this interface;
|
|
+ * run only once the default pool probing code
|
|
+ */
|
|
+
|
|
+ err = of_property_read_u32(dpa_node, "fsl,bpid", &dpa_priv_bpid);
|
|
+ if (err) {
|
|
+ dev_err(dev, "Cannot find buffer pool ID in the device tree\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ last_cpu = qman_get_affine_last_cpu();
|
|
+ err = of_property_read_u32(dpa_node, "fsl,cpuid", &dpa_priv_cpuid);
|
|
+ if (err) {
|
|
+ dev_warn(dev, "Cannot find cpuid in the device tree, using the last core\n");
|
|
+ dpa_priv_cpuid = last_cpu;
|
|
+ } else if (dpa_priv_cpuid > last_cpu) {
|
|
+ dev_warn(dev, "Invalid cpuid in the device tree, using the last core\n");
|
|
+ dpa_priv_cpuid = last_cpu;
|
|
+ }
|
|
+
|
|
+ dpa_bp = (dpa_bpid2pool(dpa_priv_bpid)) ? :
|
|
+ dpa_priv_bp_probe(dev);
|
|
+ if (IS_ERR(dpa_bp))
|
|
+ return PTR_ERR(dpa_bp);
|
|
+ if (dpa_bp->bpid == 0)
|
|
+ dpa_bp->bpid = dpa_priv_bpid;
|
|
+
|
|
+ /* Allocate this early, so we can store relevant information in
|
|
+ * the private area (needed by 1588 code in dpa_mac_probe)
|
|
+ */
|
|
+ net_dev = alloc_etherdev_mq(sizeof(*priv), DPAA_ETH_TX_QUEUES);
|
|
+ if (!net_dev) {
|
|
+ dev_err(dev, "alloc_etherdev_mq() failed\n");
|
|
+ goto alloc_etherdev_mq_failed;
|
|
+ }
|
|
+
|
|
+ /* Do this here, so we can be verbose early */
|
|
+ SET_NETDEV_DEV(net_dev, dev);
|
|
+ dev_set_drvdata(dev, net_dev);
|
|
+
|
|
+ priv = netdev_priv(net_dev);
|
|
+ priv->net_dev = net_dev;
|
|
+ strcpy(priv->if_type, "private");
|
|
+
|
|
+ priv->msg_enable = netif_msg_init(debug, -1);
|
|
+
|
|
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
|
|
+ priv->loop_id = dpa_new_loop_id();
|
|
+ priv->loop_to = -1; /* disabled by default */
|
|
+ dpa_loop_netdevs[priv->loop_id] = net_dev;
|
|
+#endif
|
|
+
|
|
+ mac_dev = dpa_mac_probe(_of_dev);
|
|
+ if (IS_ERR(mac_dev) || !mac_dev) {
|
|
+ err = PTR_ERR(mac_dev);
|
|
+ goto mac_probe_failed;
|
|
+ }
|
|
+
|
|
+ /* We have physical ports, so we need to establish
|
|
+ * the buffer layout.
|
|
+ */
|
|
+ buf_layout = devm_kzalloc(dev, 2 * sizeof(*buf_layout),
|
|
+ GFP_KERNEL);
|
|
+ if (!buf_layout) {
|
|
+ dev_err(dev, "devm_kzalloc() failed\n");
|
|
+ goto alloc_failed;
|
|
+ }
|
|
+ dpa_set_buffers_layout(mac_dev, buf_layout);
|
|
+
|
|
+ /* For private ports, need to compute the size of the default
|
|
+ * buffer pool, based on FMan port buffer layout;also update
|
|
+ * the maximum buffer size for private ports if necessary
|
|
+ */
|
|
+ dpa_bp->size = dpa_bp_size(&buf_layout[RX]);
|
|
+
|
|
+#ifdef CONFIG_FSL_DPAA_ETH_JUMBO_FRAME
|
|
+ /* We only want to use jumbo frame optimization if we actually have
|
|
+ * L2 MAX FRM set for jumbo frames as well.
|
|
+ */
|
|
+ if (fm_get_max_frm() < 9600)
|
|
+ dev_warn(dev,
|
|
+ "Invalid configuration: if jumbo frames support is on, FSL_FM_MAX_FRAME_SIZE should be set to 9600\n");
|
|
+#endif
|
|
+
|
|
+ INIT_LIST_HEAD(&priv->dpa_fq_list);
|
|
+
|
|
+ memset(&port_fqs, 0, sizeof(port_fqs));
|
|
+
|
|
+ err = dpa_fq_probe_mac(dev, &priv->dpa_fq_list, &port_fqs, true, RX);
|
|
+ if (!err)
|
|
+ err = dpa_fq_probe_mac(dev, &priv->dpa_fq_list,
|
|
+ &port_fqs, true, TX);
|
|
+
|
|
+ if (err < 0)
|
|
+ goto fq_probe_failed;
|
|
+
|
|
+ /* bp init */
|
|
+
|
|
+ err = dpa_bp_create(net_dev, dpa_bp, count);
|
|
+
|
|
+ if (err < 0)
|
|
+ goto bp_create_failed;
|
|
+
|
|
+ priv->mac_dev = mac_dev;
|
|
+ priv->ethercat_channel = (u16)qman_affine_channel_ethercat(dpa_priv_cpuid);
|
|
+ priv->channel = priv->ethercat_channel;
|
|
+ priv->p = qman_get_affine_portal_ethercat(dpa_priv_cpuid);
|
|
+
|
|
+ dpa_fq_setup_ethercat(priv, &private_fq_cbs, priv->mac_dev->port_dev[TX]);
|
|
+
|
|
+ /* Create a congestion group for this netdev, with
|
|
+ * dynamically-allocated CGR ID.
|
|
+ * Must be executed after probing the MAC, but before
|
|
+ * assigning the egress FQs to the CGRs.
|
|
+ */
|
|
+ err = dpaa_eth_cgr_init(priv);
|
|
+ if (err < 0) {
|
|
+ dev_err(dev, "Error initializing CGR\n");
|
|
+ goto tx_cgr_init_failed;
|
|
+ }
|
|
+ err = dpaa_eth_priv_ingress_cgr_init(priv);
|
|
+ if (err < 0) {
|
|
+ dev_err(dev, "Error initializing ingress CGR\n");
|
|
+ goto rx_cgr_init_failed;
|
|
+ }
|
|
+
|
|
+ /* Add the FQs to the interface, and make them active */
|
|
+ err = dpa_fqs_init(dev, &priv->dpa_fq_list, false);
|
|
+ if (err < 0)
|
|
+ goto fq_alloc_failed;
|
|
+
|
|
+ priv->buf_layout = buf_layout;
|
|
+ priv->tx_headroom = dpa_get_headroom(&priv->buf_layout[TX]);
|
|
+ priv->rx_headroom = dpa_get_headroom(&priv->buf_layout[RX]);
|
|
+
|
|
+ /* All real interfaces need their ports initialized */
|
|
+ dpaa_eth_init_ports(mac_dev, dpa_bp, count, &port_fqs,
|
|
+ buf_layout, dev);
|
|
+
|
|
+#ifdef CONFIG_FMAN_PFC
|
|
+ for (i = 0; i < CONFIG_FMAN_PFC_COS_COUNT; i++) {
|
|
+ err = fm_port_set_pfc_priorities_mapping_to_qman_wq(mac_dev->port_dev[TX], i, i);
|
|
+ if (unlikely(err != 0)) {
|
|
+ dev_err(dev, "Error maping PFC %u to WQ %u\n", i, i);
|
|
+ goto pfc_mapping_failed;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ priv->percpu_priv = devm_alloc_percpu(dev, *priv->percpu_priv);
|
|
+
|
|
+ if (!priv->percpu_priv) {
|
|
+ dev_err(dev, "devm_alloc_percpu() failed\n");
|
|
+ err = -ENOMEM;
|
|
+ goto alloc_percpu_failed;
|
|
+ }
|
|
+
|
|
+ for_each_possible_cpu(i) {
|
|
+ percpu_priv = per_cpu_ptr(priv->percpu_priv, i);
|
|
+ memset(percpu_priv, 0, sizeof(*percpu_priv));
|
|
+ }
|
|
+
|
|
+ priv->percpu_count = devm_alloc_percpu(dev, *priv->percpu_count);
|
|
+ if (!priv->percpu_count) {
|
|
+ dev_err(dev, "devm_alloc_percpu() failed\n");
|
|
+ err = -ENOMEM;
|
|
+ goto alloc_percpu_failed;
|
|
+ }
|
|
+
|
|
+ for_each_possible_cpu(i) {
|
|
+ int *percpu_count = per_cpu_ptr(priv->percpu_count, i);
|
|
+ *percpu_count = 0;
|
|
+ }
|
|
+
|
|
+ err = dpa_private_netdev_init(net_dev);
|
|
+
|
|
+ dpa_priv_bp_seed(net_dev);
|
|
+
|
|
+ if (err < 0)
|
|
+ goto netdev_init_failed;
|
|
+
|
|
+ pr_info("Ethercat port:%02hx:%02hx:%02hx:%02hx:%02hx:%02hx bpid:%d cpu:%d\n",
|
|
+ mac_dev->addr[0], mac_dev->addr[1], mac_dev->addr[2],
|
|
+ mac_dev->addr[3], mac_dev->addr[4], mac_dev->addr[5],
|
|
+ dpa_priv_bpid, dpa_priv_cpuid);
|
|
+
|
|
+#ifdef CONFIG_PM
|
|
+ device_set_wakeup_capable(dev, true);
|
|
+#endif
|
|
+
|
|
+ pr_info("fsl_dpa: Probed interface %s\n", net_dev->name);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+netdev_init_failed:
|
|
+
|
|
+alloc_percpu_failed:
|
|
+#ifdef CONFIG_FMAN_PFC
|
|
+pfc_mapping_failed:
|
|
+#endif
|
|
+ dpa_fq_free(dev, &priv->dpa_fq_list);
|
|
+fq_alloc_failed:
|
|
+ qman_delete_cgr_safe(&priv->ingress_cgr);
|
|
+ qman_release_cgrid(priv->ingress_cgr.cgrid);
|
|
+rx_cgr_init_failed:
|
|
+ qman_delete_cgr_safe(&priv->cgr_data.cgr);
|
|
+ qman_release_cgrid(priv->cgr_data.cgr.cgrid);
|
|
+tx_cgr_init_failed:
|
|
+
|
|
+ dpa_bp_free(priv);
|
|
+bp_create_failed:
|
|
+fq_probe_failed:
|
|
+alloc_failed:
|
|
+mac_probe_failed:
|
|
+ dev_set_drvdata(dev, NULL);
|
|
+ free_netdev(net_dev);
|
|
+alloc_etherdev_mq_failed:
|
|
+ if (atomic_read(&dpa_bp->refs) == 0)
|
|
+ devm_kfree(dev, dpa_bp);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static const struct of_device_id dpa_match[] = {
|
|
+ {
|
|
+ .compatible = "fsl,dpa-ethercat"
|
|
+ },
|
|
+ {}
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, dpa_match);
|
|
+
|
|
+static struct platform_driver dpa_driver = {
|
|
+ .driver = {
|
|
+ .name = KBUILD_MODNAME "-ethercat",
|
|
+ .of_match_table = dpa_match,
|
|
+ .owner = THIS_MODULE,
|
|
+ .pm = DPAA_PM_OPS,
|
|
+ },
|
|
+ .probe = dpaa_ethercat_probe,
|
|
+ .remove = dpa_remove
|
|
+};
|
|
+
|
|
+static int __init __cold dpa_ethercat_load(void)
|
|
+{
|
|
+ int _errno;
|
|
+
|
|
+ pr_info(DPA_DESCRIPTION "\n");
|
|
+
|
|
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
|
|
+ dpa_debugfs_module_init();
|
|
+#endif /* CONFIG_FSL_DPAA_DBG_LOOP */
|
|
+
|
|
+ /* initialise dpaa_eth mirror values */
|
|
+ dpa_rx_extra_headroom = fm_get_rx_extra_headroom();
|
|
+ dpa_max_frm = fm_get_max_frm();
|
|
+ dpa_num_cpus = num_possible_cpus();
|
|
+
|
|
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
|
|
+ memset(dpa_loop_netdevs, 0, sizeof(dpa_loop_netdevs));
|
|
+#endif
|
|
+
|
|
+ _errno = platform_driver_register(&dpa_driver);
|
|
+ if (unlikely(_errno < 0)) {
|
|
+ pr_err(KBUILD_MODNAME
|
|
+ ": %s:%hu:%s(): platform_driver_register() = %d\n",
|
|
+ KBUILD_BASENAME ".c", __LINE__, __func__, _errno);
|
|
+ }
|
|
+
|
|
+ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
|
|
+ KBUILD_BASENAME ".c", __func__);
|
|
+
|
|
+ return _errno;
|
|
+}
|
|
+module_init(dpa_ethercat_load);
|
|
+
|
|
+static void __exit __cold dpa_ethercat_unload(void)
|
|
+{
|
|
+ pr_debug(KBUILD_MODNAME ": -> %s:%s()\n",
|
|
+ KBUILD_BASENAME ".c", __func__);
|
|
+
|
|
+ platform_driver_unregister(&dpa_driver);
|
|
+
|
|
+#ifdef CONFIG_FSL_DPAA_DBG_LOOP
|
|
+ dpa_debugfs_module_exit();
|
|
+#endif /* CONFIG_FSL_DPAA_DBG_LOOP */
|
|
+
|
|
+ /* Only one channel is used and needs to be relased after all
|
|
+ * interfaces are removed
|
|
+ */
|
|
+ dpa_release_channel();
|
|
+
|
|
+ pr_debug(KBUILD_MODNAME ": %s:%s() ->\n",
|
|
+ KBUILD_BASENAME ".c", __func__);
|
|
+}
|
|
+module_exit(dpa_ethercat_unload);
|
|
diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c
|
|
index 62733d7e139f..f26026b5a511 100644
|
|
--- a/drivers/net/ethernet/mscc/ocelot.c
|
|
+++ b/drivers/net/ethernet/mscc/ocelot.c
|
|
@@ -247,6 +247,12 @@ static void ocelot_vcap_enable(struct ocelot *ocelot, int port)
|
|
ocelot_write_gix(ocelot, ANA_PORT_VCAP_CFG_S1_ENA,
|
|
ANA_PORT_VCAP_CFG, port);
|
|
|
|
+ /* Use key S1_5TUPLE_IP4 in second lookup. */
|
|
+ ocelot_write_ix(ocelot,
|
|
+ ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP6_CFG(2) |
|
|
+ ANA_PORT_VCAP_S1_KEY_CFG_S1_KEY_IP4_CFG(2),
|
|
+ ANA_PORT_VCAP_S1_KEY_CFG, port, 1);
|
|
+
|
|
ocelot_rmw_gix(ocelot, REW_PORT_CFG_ES0_EN,
|
|
REW_PORT_CFG_ES0_EN,
|
|
REW_PORT_CFG, port);
|
|
@@ -380,6 +386,8 @@ static void ocelot_port_manage_port_tag(struct ocelot *ocelot, int port)
|
|
struct ocelot_port *ocelot_port = ocelot->ports[port];
|
|
enum ocelot_port_tag_config tag_cfg;
|
|
bool uses_native_vlan = false;
|
|
+ u32 port_tpid = 0;
|
|
+ u32 tag_tpid = 0;
|
|
|
|
if (ocelot_port->vlan_aware) {
|
|
uses_native_vlan = ocelot_port_uses_native_vlan(ocelot, port);
|
|
@@ -390,12 +398,17 @@ static void ocelot_port_manage_port_tag(struct ocelot *ocelot, int port)
|
|
tag_cfg = OCELOT_PORT_TAG_DISABLED;
|
|
else
|
|
tag_cfg = OCELOT_PORT_TAG_TRUNK;
|
|
+
|
|
+ if (ocelot->qinq_enable && ocelot_port->qinq_mode)
|
|
+ tag_tpid = REW_TAG_CFG_TAG_TPID_CFG(1);
|
|
+ else
|
|
+ tag_tpid = REW_TAG_CFG_TAG_TPID_CFG(0);
|
|
} else {
|
|
tag_cfg = OCELOT_PORT_TAG_DISABLED;
|
|
}
|
|
|
|
- ocelot_rmw_gix(ocelot, REW_TAG_CFG_TAG_CFG(tag_cfg),
|
|
- REW_TAG_CFG_TAG_CFG_M,
|
|
+ ocelot_rmw_gix(ocelot, REW_TAG_CFG_TAG_CFG(tag_cfg) | tag_tpid,
|
|
+ REW_TAG_CFG_TAG_CFG_M | REW_TAG_CFG_TAG_TPID_CFG_M,
|
|
REW_TAG_CFG, port);
|
|
|
|
if (uses_native_vlan) {
|
|
@@ -407,9 +420,16 @@ static void ocelot_port_manage_port_tag(struct ocelot *ocelot, int port)
|
|
*/
|
|
native_vlan = ocelot_port_find_native_vlan(ocelot, port);
|
|
|
|
+ if (ocelot->qinq_enable && ocelot_port->qinq_mode)
|
|
+ port_tpid = REW_PORT_VLAN_CFG_PORT_TPID(ETH_P_8021AD);
|
|
+ else
|
|
+ port_tpid = REW_PORT_VLAN_CFG_PORT_TPID(ETH_P_8021Q);
|
|
+
|
|
ocelot_rmw_gix(ocelot,
|
|
- REW_PORT_VLAN_CFG_PORT_VID(native_vlan->vid),
|
|
- REW_PORT_VLAN_CFG_PORT_VID_M,
|
|
+ REW_PORT_VLAN_CFG_PORT_VID(native_vlan->vid) |
|
|
+ port_tpid,
|
|
+ REW_PORT_VLAN_CFG_PORT_VID_M |
|
|
+ REW_PORT_VLAN_CFG_PORT_TPID_M,
|
|
REW_PORT_VLAN_CFG, port);
|
|
}
|
|
}
|
|
@@ -454,6 +474,10 @@ static void ocelot_port_set_pvid(struct ocelot *ocelot, int port,
|
|
struct ocelot_port *ocelot_port = ocelot->ports[port];
|
|
u16 pvid = ocelot_vlan_unaware_pvid(ocelot, ocelot_port->bridge);
|
|
u32 val = 0;
|
|
+ u32 tag_type = 0;
|
|
+
|
|
+ if (ocelot->qinq_enable && ocelot_port->qinq_mode)
|
|
+ tag_type = ANA_PORT_VLAN_CFG_VLAN_TAG_TYPE;
|
|
|
|
ocelot_port->pvid_vlan = pvid_vlan;
|
|
|
|
@@ -461,8 +485,8 @@ static void ocelot_port_set_pvid(struct ocelot *ocelot, int port,
|
|
pvid = pvid_vlan->vid;
|
|
|
|
ocelot_rmw_gix(ocelot,
|
|
- ANA_PORT_VLAN_CFG_VLAN_VID(pvid),
|
|
- ANA_PORT_VLAN_CFG_VLAN_VID_M,
|
|
+ ANA_PORT_VLAN_CFG_VLAN_VID(pvid) | tag_type,
|
|
+ ANA_PORT_VLAN_CFG_VLAN_VID_M | tag_type,
|
|
ANA_PORT_VLAN_CFG, port);
|
|
|
|
/* If there's no pvid, we should drop not only untagged traffic (which
|
|
@@ -620,6 +644,15 @@ int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port,
|
|
ANA_PORT_VLAN_CFG_VLAN_POP_CNT(1);
|
|
else
|
|
val = 0;
|
|
+
|
|
+ /* if switch is enabled for QinQ, the port for LAN should set
|
|
+ * VLAN_CFG.VLAN_POP_CNT=0 && VLAN_CFG.VLAN_AWARE_ENA=0.
|
|
+ * the port for MAN should set VLAN_CFG.VLAN_POP_CNT=1 &&
|
|
+ * VLAN_CFG.VLAN_AWARE_ENA=1. referring to 4.3.3 in VSC9959_1_00_TS.pdf
|
|
+ */
|
|
+ if (ocelot->qinq_enable && !ocelot_port->qinq_mode)
|
|
+ val = 0;
|
|
+
|
|
ocelot_rmw_gix(ocelot, val,
|
|
ANA_PORT_VLAN_CFG_VLAN_AWARE_ENA |
|
|
ANA_PORT_VLAN_CFG_VLAN_POP_CNT_M,
|
|
diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c
|
|
index 33b438c6aec5..0fdcefeed2ef 100644
|
|
--- a/drivers/net/ethernet/mscc/ocelot_flower.c
|
|
+++ b/drivers/net/ethernet/mscc/ocelot_flower.c
|
|
@@ -468,20 +468,27 @@ static int ocelot_flower_parse_action(struct ocelot *ocelot, int port,
|
|
switch (ntohs(a->vlan.proto)) {
|
|
case ETH_P_8021Q:
|
|
tpid = OCELOT_TAG_TPID_SEL_8021Q;
|
|
+ filter->action.tag_b_tpid_sel = tpid;
|
|
+ filter->action.push_inner_tag = OCELOT_ES0_TAG;
|
|
+ filter->action.tag_b_vid_sel = OCELOT_ES0_VID;
|
|
+ filter->action.tag_b_pcp_sel = OCELOT_ES0_PCP;
|
|
+ filter->action.vid_b_val = a->vlan.vid;
|
|
+ filter->action.pcp_b_val = a->vlan.prio;
|
|
break;
|
|
case ETH_P_8021AD:
|
|
tpid = OCELOT_TAG_TPID_SEL_8021AD;
|
|
+ filter->action.tag_a_tpid_sel = tpid;
|
|
+ filter->action.push_outer_tag = OCELOT_ES0_TAG;
|
|
+ filter->action.tag_a_vid_sel = OCELOT_ES0_VID;
|
|
+ filter->action.tag_a_pcp_sel = OCELOT_ES0_PCP;
|
|
+ filter->action.vid_a_val = a->vlan.vid;
|
|
+ filter->action.pcp_a_val = a->vlan.prio;
|
|
break;
|
|
default:
|
|
NL_SET_ERR_MSG_MOD(extack,
|
|
"Cannot push custom TPID");
|
|
return -EOPNOTSUPP;
|
|
}
|
|
- filter->action.tag_a_tpid_sel = tpid;
|
|
- filter->action.push_outer_tag = OCELOT_ES0_TAG;
|
|
- filter->action.tag_a_vid_sel = OCELOT_ES0_VID;
|
|
- filter->action.vid_a_val = a->vlan.vid;
|
|
- filter->action.pcp_a_val = a->vlan.prio;
|
|
filter->type = OCELOT_VCAP_FILTER_OFFLOAD;
|
|
break;
|
|
case FLOW_ACTION_GATE:
|
|
@@ -586,6 +593,7 @@ ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress,
|
|
BIT_ULL(FLOW_DISSECTOR_KEY_META) |
|
|
BIT_ULL(FLOW_DISSECTOR_KEY_PORTS) |
|
|
BIT_ULL(FLOW_DISSECTOR_KEY_VLAN) |
|
|
+ BIT_ULL(FLOW_DISSECTOR_KEY_CVLAN) |
|
|
BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
|
|
BIT_ULL(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
|
|
BIT_ULL(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
|
|
@@ -627,6 +635,18 @@ ocelot_flower_parse_key(struct ocelot *ocelot, int port, bool ingress,
|
|
match_protocol = false;
|
|
}
|
|
|
|
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CVLAN)) {
|
|
+ struct flow_match_vlan match;
|
|
+
|
|
+ flow_rule_match_cvlan(rule, &match);
|
|
+ filter->key_type = OCELOT_VCAP_KEY_ANY;
|
|
+ filter->cvlan.vid.value = match.key->vlan_id;
|
|
+ filter->cvlan.vid.mask = match.mask->vlan_id;
|
|
+ filter->cvlan.pcp.value[0] = match.key->vlan_priority;
|
|
+ filter->cvlan.pcp.mask[0] = match.mask->vlan_priority;
|
|
+ match_protocol = false;
|
|
+ }
|
|
+
|
|
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
|
|
struct flow_match_eth_addrs match;
|
|
|
|
diff --git a/drivers/net/ethernet/mscc/ocelot_ptp.c b/drivers/net/ethernet/mscc/ocelot_ptp.c
|
|
index cb32234a5bf1..e1ca9d1081e6 100644
|
|
--- a/drivers/net/ethernet/mscc/ocelot_ptp.c
|
|
+++ b/drivers/net/ethernet/mscc/ocelot_ptp.c
|
|
@@ -14,6 +14,8 @@
|
|
#include <soc/mscc/ocelot.h>
|
|
#include "ocelot.h"
|
|
|
|
+#define OCELOT_PTP_TX_TSTAMP_TIMEOUT (5 * HZ)
|
|
+
|
|
int ocelot_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts)
|
|
{
|
|
struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
|
|
@@ -325,6 +327,7 @@ static void
|
|
ocelot_populate_ipv4_ptp_event_trap_key(struct ocelot_vcap_filter *trap)
|
|
{
|
|
trap->key_type = OCELOT_VCAP_KEY_IPV4;
|
|
+ trap->key.ipv4.fragment = OCELOT_VCAP_BIT_0;
|
|
trap->key.ipv4.proto.value[0] = IPPROTO_UDP;
|
|
trap->key.ipv4.proto.mask[0] = 0xff;
|
|
trap->key.ipv4.dport.value = PTP_EV_PORT;
|
|
@@ -345,6 +348,7 @@ static void
|
|
ocelot_populate_ipv4_ptp_general_trap_key(struct ocelot_vcap_filter *trap)
|
|
{
|
|
trap->key_type = OCELOT_VCAP_KEY_IPV4;
|
|
+ trap->key.ipv4.fragment = OCELOT_VCAP_BIT_0;
|
|
trap->key.ipv4.proto.value[0] = IPPROTO_UDP;
|
|
trap->key.ipv4.proto.mask[0] = 0xff;
|
|
trap->key.ipv4.dport.value = PTP_GEN_PORT;
|
|
@@ -532,6 +536,7 @@ int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct ifreq *ifr)
|
|
switch (cfg.tx_type) {
|
|
case HWTSTAMP_TX_ON:
|
|
ocelot_port->ptp_cmd = IFH_REW_OP_TWO_STEP_PTP;
|
|
+ skb_queue_purge(&ocelot_port->tx_skbs);
|
|
break;
|
|
case HWTSTAMP_TX_ONESTEP_SYNC:
|
|
/* IFH_REW_OP_ONE_STEP_PTP updates the correctional field, we
|
|
@@ -607,34 +612,91 @@ int ocelot_get_ts_info(struct ocelot *ocelot, int port,
|
|
}
|
|
EXPORT_SYMBOL(ocelot_get_ts_info);
|
|
|
|
-static int ocelot_port_add_txtstamp_skb(struct ocelot *ocelot, int port,
|
|
- struct sk_buff *clone)
|
|
+static struct sk_buff *
|
|
+ocelot_port_remove_ptp_tx_skb(struct ocelot_port *ocelot_port, u8 ts_id)
|
|
{
|
|
- struct ocelot_port *ocelot_port = ocelot->ports[port];
|
|
+ struct sk_buff *skb, *skb_tmp, *skb_match = NULL;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&ocelot->ts_id_lock, flags);
|
|
+ spin_lock_irqsave(&ocelot_port->tx_skbs.lock, flags);
|
|
|
|
- if (ocelot_port->ptp_skbs_in_flight == OCELOT_MAX_PTP_ID ||
|
|
- ocelot->ptp_skbs_in_flight == OCELOT_PTP_FIFO_SIZE) {
|
|
- spin_unlock_irqrestore(&ocelot->ts_id_lock, flags);
|
|
- return -EBUSY;
|
|
+ skb_queue_walk_safe(&ocelot_port->tx_skbs, skb, skb_tmp) {
|
|
+ if (OCELOT_SKB_CB(skb)->ts_id != ts_id)
|
|
+ continue;
|
|
+ __skb_unlink(skb, &ocelot_port->tx_skbs);
|
|
+ skb_match = skb;
|
|
+ break;
|
|
}
|
|
|
|
- skb_shinfo(clone)->tx_flags |= SKBTX_IN_PROGRESS;
|
|
- /* Store timestamp ID in OCELOT_SKB_CB(clone)->ts_id */
|
|
- OCELOT_SKB_CB(clone)->ts_id = ocelot_port->ts_id;
|
|
+ spin_unlock_irqrestore(&ocelot_port->tx_skbs.lock, flags);
|
|
|
|
- ocelot_port->ts_id++;
|
|
- if (ocelot_port->ts_id == OCELOT_MAX_PTP_ID)
|
|
- ocelot_port->ts_id = 0;
|
|
+ return skb_match;
|
|
+}
|
|
|
|
- ocelot_port->ptp_skbs_in_flight++;
|
|
+static int ocelot_port_ts_id_get(struct ocelot *ocelot, int port, u8 *ts_id)
|
|
+{
|
|
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
|
|
+ unsigned long n;
|
|
+
|
|
+ /* To get a better chance of acquiring a timestamp ID, first flush the
|
|
+ * stale packets still waiting in the TX timestamping queue. They are
|
|
+ * probably lost.
|
|
+ */
|
|
+ for_each_set_bit(n, ocelot_port->ts_id_in_flight, OCELOT_MAX_PTP_ID) {
|
|
+ if (time_before(ocelot_port->ptp_tx_time[n] +
|
|
+ OCELOT_PTP_TX_TSTAMP_TIMEOUT, jiffies)) {
|
|
+ dev_warn_ratelimited(ocelot->dev,
|
|
+ "port %d invalidating stale timestamp ID %lu which seems lost\n",
|
|
+ port, n);
|
|
+ __clear_bit(n, ocelot_port->ts_id_in_flight);
|
|
+ ocelot->ptp_skbs_in_flight--;
|
|
+ ocelot_port_remove_ptp_tx_skb(ocelot_port, n);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (ocelot->ptp_skbs_in_flight == OCELOT_PTP_FIFO_SIZE)
|
|
+ return -EBUSY;
|
|
+
|
|
+ n = find_first_zero_bit(ocelot_port->ts_id_in_flight,
|
|
+ OCELOT_MAX_PTP_ID);
|
|
+ if (n == OCELOT_MAX_PTP_ID)
|
|
+ return -EBUSY;
|
|
+
|
|
+ /* Found an available timestamp ID, use it */
|
|
+ __set_bit(n, ocelot_port->ts_id_in_flight);
|
|
+ *ts_id = n;
|
|
+ ocelot_port->ptp_tx_time[n] = jiffies;
|
|
ocelot->ptp_skbs_in_flight++;
|
|
+ dev_dbg_ratelimited(ocelot->dev, "port %d timestamp id %lu\n", port, n);
|
|
|
|
- skb_queue_tail(&ocelot_port->tx_skbs, clone);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void ocelot_port_ts_id_put(struct ocelot *ocelot, int port, int ts_id)
|
|
+{
|
|
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
|
|
+
|
|
+ __clear_bit(ts_id, ocelot_port->ts_id_in_flight);
|
|
+ ocelot->ptp_skbs_in_flight--;
|
|
+}
|
|
|
|
+static int ocelot_port_add_txtstamp_skb(struct ocelot *ocelot, int port,
|
|
+ struct sk_buff *clone)
|
|
+{
|
|
+ struct ocelot_port *ocelot_port = ocelot->ports[port];
|
|
+ unsigned long flags;
|
|
+ int err;
|
|
+
|
|
+ /* Store timestamp ID in OCELOT_SKB_CB(clone)->ts_id */
|
|
+ spin_lock_irqsave(&ocelot->ts_id_lock, flags);
|
|
+ err = ocelot_port_ts_id_get(ocelot, port, &OCELOT_SKB_CB(clone)->ts_id);
|
|
spin_unlock_irqrestore(&ocelot->ts_id_lock, flags);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ skb_shinfo(clone)->tx_flags |= SKBTX_IN_PROGRESS;
|
|
+
|
|
+ skb_queue_tail(&ocelot_port->tx_skbs, clone);
|
|
|
|
return 0;
|
|
}
|
|
@@ -746,12 +808,11 @@ void ocelot_get_txtstamp(struct ocelot *ocelot)
|
|
int budget = OCELOT_PTP_QUEUE_SZ;
|
|
|
|
while (budget--) {
|
|
- struct sk_buff *skb, *skb_tmp, *skb_match = NULL;
|
|
struct skb_shared_hwtstamps shhwtstamps;
|
|
u32 val, id, seqid, txport;
|
|
+ struct sk_buff *skb_match;
|
|
struct ocelot_port *port;
|
|
struct timespec64 ts;
|
|
- unsigned long flags;
|
|
|
|
val = ocelot_read(ocelot, SYS_PTP_STATUS);
|
|
|
|
@@ -769,32 +830,24 @@ void ocelot_get_txtstamp(struct ocelot *ocelot)
|
|
port = ocelot->ports[txport];
|
|
|
|
spin_lock(&ocelot->ts_id_lock);
|
|
- port->ptp_skbs_in_flight--;
|
|
- ocelot->ptp_skbs_in_flight--;
|
|
+ ocelot_port_ts_id_put(ocelot, txport, id);
|
|
spin_unlock(&ocelot->ts_id_lock);
|
|
|
|
/* Retrieve its associated skb */
|
|
try_again:
|
|
- spin_lock_irqsave(&port->tx_skbs.lock, flags);
|
|
-
|
|
- skb_queue_walk_safe(&port->tx_skbs, skb, skb_tmp) {
|
|
- if (OCELOT_SKB_CB(skb)->ts_id != id)
|
|
- continue;
|
|
- __skb_unlink(skb, &port->tx_skbs);
|
|
- skb_match = skb;
|
|
- break;
|
|
- }
|
|
-
|
|
- spin_unlock_irqrestore(&port->tx_skbs.lock, flags);
|
|
-
|
|
- if (WARN_ON(!skb_match))
|
|
+ skb_match = ocelot_port_remove_ptp_tx_skb(port, id);
|
|
+ if (!skb_match) {
|
|
+ dev_warn_ratelimited(ocelot->dev,
|
|
+ "port %d received TX timestamp (seqid %d, ts id %u) for packet previously declared stale\n",
|
|
+ txport, seqid, id);
|
|
continue;
|
|
+ }
|
|
|
|
if (!ocelot_validate_ptp_skb(skb_match, seqid)) {
|
|
dev_err_ratelimited(ocelot->dev,
|
|
- "port %d received stale TX timestamp for seqid %d, discarding\n",
|
|
- txport, seqid);
|
|
- dev_kfree_skb_any(skb);
|
|
+ "port %d received stale TX timestamp (seqid %d, ts id %u), discarding\n",
|
|
+ txport, seqid, id);
|
|
+ dev_kfree_skb_any(skb_match);
|
|
goto try_again;
|
|
}
|
|
|
|
diff --git a/drivers/net/ethernet/mscc/ocelot_vcap.c b/drivers/net/ethernet/mscc/ocelot_vcap.c
|
|
index 73cdec5ca6a3..9947b634194a 100644
|
|
--- a/drivers/net/ethernet/mscc/ocelot_vcap.c
|
|
+++ b/drivers/net/ethernet/mscc/ocelot_vcap.c
|
|
@@ -666,10 +666,11 @@ static void is1_action_set(struct ocelot *ocelot, struct vcap_data *data,
|
|
vcap_action_set(vcap, data, VCAP_IS1_ACT_PAG_VAL, a->pag_val);
|
|
}
|
|
|
|
-static void is1_entry_set(struct ocelot *ocelot, int ix,
|
|
+static int is1_entry_set(struct ocelot *ocelot, int ix,
|
|
struct ocelot_vcap_filter *filter)
|
|
{
|
|
const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS1];
|
|
+ struct ocelot_vcap_key_vlan *ctag = &filter->cvlan;
|
|
struct ocelot_vcap_key_vlan *tag = &filter->vlan;
|
|
struct vcap_data data;
|
|
int row = ix / 2;
|
|
@@ -689,6 +690,11 @@ static void is1_entry_set(struct ocelot *ocelot, int ix,
|
|
if (filter->prio != 0)
|
|
data.tg |= data.tg_value;
|
|
|
|
+ if (filter->lookup == 1)
|
|
+ type = IS1_TYPE_S1_5TUPLE_IP4;
|
|
+ else
|
|
+ type = IS1_TYPE_S1_NORMAL;
|
|
+
|
|
vcap_key_set(vcap, &data, VCAP_IS1_HK_LOOKUP, filter->lookup, 0x3);
|
|
vcap_key_set(vcap, &data, VCAP_IS1_HK_IGR_PORT_MASK, 0,
|
|
~filter->ingress_port_mask);
|
|
@@ -699,12 +705,31 @@ static void is1_entry_set(struct ocelot *ocelot, int ix,
|
|
tag->vid.value, tag->vid.mask);
|
|
vcap_key_set(vcap, &data, VCAP_IS1_HK_PCP,
|
|
tag->pcp.value[0], tag->pcp.mask[0]);
|
|
- type = IS1_TYPE_S1_NORMAL;
|
|
+
|
|
+ if (ctag->vid.value != 0) {
|
|
+ if (type != IS1_TYPE_S1_5TUPLE_IP4)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TPID,
|
|
+ OCELOT_VCAP_BIT_1);
|
|
+ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_VLAN_DBL_TAGGED,
|
|
+ OCELOT_VCAP_BIT_1);
|
|
+ vcap_key_set(vcap, &data, VCAP_IS1_HK_IP4_INNER_VID,
|
|
+ ctag->vid.value, ctag->vid.mask);
|
|
+ vcap_key_set(vcap, &data, VCAP_IS1_HK_IP4_INNER_PCP,
|
|
+ ctag->pcp.value[0], ctag->pcp.mask[0]);
|
|
+ }
|
|
|
|
switch (filter->key_type) {
|
|
case OCELOT_VCAP_KEY_ETYPE: {
|
|
struct ocelot_vcap_key_etype *etype = &filter->key.etype;
|
|
|
|
+ if (type != IS1_TYPE_S1_NORMAL)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ if (etype->dmac.mask[0])
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_L2_SMAC,
|
|
etype->smac.value, etype->smac.mask);
|
|
vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_ETYPE,
|
|
@@ -716,48 +741,103 @@ static void is1_entry_set(struct ocelot *ocelot, int ix,
|
|
struct ocelot_vcap_udp_tcp *sport = &ipv4->sport;
|
|
struct ocelot_vcap_udp_tcp *dport = &ipv4->dport;
|
|
enum ocelot_vcap_bit tcp_udp = OCELOT_VCAP_BIT_0;
|
|
+ enum ocelot_vcap_bit fragment = ipv4->fragment;
|
|
+ enum ocelot_vcap_bit options = ipv4->options;
|
|
+ enum ocelot_vcap_bit tcp = OCELOT_VCAP_BIT_0;
|
|
struct ocelot_vcap_u8 proto = ipv4->proto;
|
|
struct ocelot_vcap_ipv4 sip = ipv4->sip;
|
|
+ struct ocelot_vcap_ipv4 dip = ipv4->dip;
|
|
+ struct ocelot_vcap_u32 port;
|
|
u32 val, msk;
|
|
|
|
- vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP_SNAP,
|
|
- OCELOT_VCAP_BIT_1);
|
|
- vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP4,
|
|
- OCELOT_VCAP_BIT_1);
|
|
- vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_ETYPE_LEN,
|
|
- OCELOT_VCAP_BIT_1);
|
|
- vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_L3_IP4_SIP,
|
|
- sip.value.addr, sip.mask.addr);
|
|
-
|
|
- val = proto.value[0];
|
|
- msk = proto.mask[0];
|
|
-
|
|
- if ((val == NEXTHDR_TCP || val == NEXTHDR_UDP) && msk == 0xff)
|
|
- tcp_udp = OCELOT_VCAP_BIT_1;
|
|
- vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TCP_UDP, tcp_udp);
|
|
-
|
|
- if (tcp_udp) {
|
|
- enum ocelot_vcap_bit tcp = OCELOT_VCAP_BIT_0;
|
|
-
|
|
- if (val == NEXTHDR_TCP)
|
|
- tcp = OCELOT_VCAP_BIT_1;
|
|
-
|
|
- vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TCP, tcp);
|
|
- vcap_key_l4_port_set(vcap, &data, VCAP_IS1_HK_L4_SPORT,
|
|
- sport);
|
|
- /* Overloaded field */
|
|
- vcap_key_l4_port_set(vcap, &data, VCAP_IS1_HK_ETYPE,
|
|
- dport);
|
|
- } else {
|
|
- /* IPv4 "other" frame */
|
|
- struct ocelot_vcap_u16 etype = {0};
|
|
-
|
|
- /* Overloaded field */
|
|
- etype.value[0] = proto.value[0];
|
|
- etype.mask[0] = proto.mask[0];
|
|
+ if (type == IS1_TYPE_S1_5TUPLE_IP4) {
|
|
+ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP4_IP4,
|
|
+ OCELOT_VCAP_BIT_1);
|
|
+ vcap_key_bit_set(vcap, &data,
|
|
+ VCAP_IS1_HK_IP4_L3_FRAGMENT,
|
|
+ fragment);
|
|
+ vcap_key_bit_set(vcap, &data,
|
|
+ VCAP_IS1_HK_IP4_L3_OPTIONS,
|
|
+ options);
|
|
+ vcap_key_bytes_set(vcap, &data,
|
|
+ VCAP_IS1_HK_IP4_L3_IP4_DIP,
|
|
+ dip.value.addr, dip.mask.addr);
|
|
+ vcap_key_bytes_set(vcap, &data,
|
|
+ VCAP_IS1_HK_IP4_L3_IP4_SIP,
|
|
+ sip.value.addr, sip.mask.addr);
|
|
+
|
|
+ val = proto.value[0];
|
|
+ msk = proto.mask[0];
|
|
+ if ((val == NEXTHDR_TCP || val == NEXTHDR_UDP) &&
|
|
+ msk == 0xff) {
|
|
+ tcp_udp = OCELOT_VCAP_BIT_1;
|
|
+ tcp = (val == NEXTHDR_TCP ?
|
|
+ OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0);
|
|
+
|
|
+ vcap_key_bit_set(vcap, &data,
|
|
+ VCAP_IS1_HK_IP4_TCP_UDP,
|
|
+ tcp_udp);
|
|
+ vcap_key_bit_set(vcap, &data,
|
|
+ VCAP_IS1_HK_IP4_TCP, tcp);
|
|
+
|
|
+ port.value[0] = sport->value & 0xFF;
|
|
+ port.value[1] = sport->value >> 8;
|
|
+ port.value[2] = dport->value & 0xFF;
|
|
+ port.value[3] = dport->value >> 8;
|
|
+ port.mask[0] = sport->mask & 0xFF;
|
|
+ port.mask[1] = sport->mask >> 8;
|
|
+ port.mask[2] = dport->mask & 0xFF;
|
|
+ port.mask[3] = dport->mask >> 8;
|
|
+ vcap_key_bytes_set(vcap, &data,
|
|
+ VCAP_IS1_HK_IP4_IP_PAYLOAD_S1_5TUPLE,
|
|
+ port.value, port.mask);
|
|
+ }
|
|
|
|
- vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_ETYPE,
|
|
- etype.value, etype.mask);
|
|
+ } else if (type == IS1_TYPE_S1_NORMAL) {
|
|
+ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP_SNAP,
|
|
+ OCELOT_VCAP_BIT_1);
|
|
+ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP4,
|
|
+ OCELOT_VCAP_BIT_1);
|
|
+ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_ETYPE_LEN,
|
|
+ OCELOT_VCAP_BIT_1);
|
|
+ vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_L3_IP4_SIP,
|
|
+ sip.value.addr, sip.mask.addr);
|
|
+
|
|
+ if (dip.mask.addr[0])
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ val = proto.value[0];
|
|
+ msk = proto.mask[0];
|
|
+
|
|
+ if ((val == NEXTHDR_TCP || val == NEXTHDR_UDP) &&
|
|
+ msk == 0xff) {
|
|
+ tcp_udp = OCELOT_VCAP_BIT_1;
|
|
+ tcp = (val == NEXTHDR_TCP ?
|
|
+ OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0);
|
|
+
|
|
+ vcap_key_bit_set(vcap, &data,
|
|
+ VCAP_IS1_HK_TCP_UDP, tcp_udp);
|
|
+ vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TCP,
|
|
+ tcp);
|
|
+ vcap_key_l4_port_set(vcap, &data,
|
|
+ VCAP_IS1_HK_L4_SPORT,
|
|
+ sport);
|
|
+ /* Overloaded field */
|
|
+ vcap_key_l4_port_set(vcap, &data,
|
|
+ VCAP_IS1_HK_ETYPE,
|
|
+ dport);
|
|
+ } else if (msk == 0xff) {
|
|
+ /* IPv4 "other" frame */
|
|
+ struct ocelot_vcap_u16 etype = {0};
|
|
+
|
|
+ /* Overloaded field */
|
|
+ etype.value[0] = proto.value[0];
|
|
+ etype.mask[0] = proto.mask[0];
|
|
+
|
|
+ vcap_key_bytes_set(vcap, &data,
|
|
+ VCAP_IS1_HK_ETYPE,
|
|
+ etype.value, etype.mask);
|
|
+ }
|
|
}
|
|
break;
|
|
}
|
|
@@ -775,6 +855,8 @@ static void is1_entry_set(struct ocelot *ocelot, int ix,
|
|
vcap_entry2cache(ocelot, vcap, &data);
|
|
vcap_action2cache(ocelot, vcap, &data);
|
|
vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_WRITE, VCAP_SEL_ALL);
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
static void es0_action_set(struct ocelot *ocelot, struct vcap_data *data,
|
|
@@ -872,15 +954,17 @@ static void vcap_entry_get(struct ocelot *ocelot, int ix,
|
|
filter->stats.pkts = cnt;
|
|
}
|
|
|
|
-static void vcap_entry_set(struct ocelot *ocelot, int ix,
|
|
- struct ocelot_vcap_filter *filter)
|
|
+static int vcap_entry_set(struct ocelot *ocelot, int ix,
|
|
+ struct ocelot_vcap_filter *filter)
|
|
{
|
|
if (filter->block_id == VCAP_IS1)
|
|
return is1_entry_set(ocelot, ix, filter);
|
|
if (filter->block_id == VCAP_IS2)
|
|
- return is2_entry_set(ocelot, ix, filter);
|
|
+ is2_entry_set(ocelot, ix, filter);
|
|
if (filter->block_id == VCAP_ES0)
|
|
- return es0_entry_set(ocelot, ix, filter);
|
|
+ es0_entry_set(ocelot, ix, filter);
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
struct vcap_policer_entry {
|
|
@@ -1214,8 +1298,7 @@ int ocelot_vcap_filter_add(struct ocelot *ocelot,
|
|
}
|
|
|
|
/* Now insert the new filter */
|
|
- vcap_entry_set(ocelot, index, filter);
|
|
- return 0;
|
|
+ return vcap_entry_set(ocelot, index, filter);
|
|
}
|
|
EXPORT_SYMBOL(ocelot_vcap_filter_add);
|
|
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
|
|
index a9837985a483..419912680e56 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
|
|
@@ -1244,6 +1244,7 @@ const struct stmmac_ops dwmac410_ops = {
|
|
.est_configure = dwmac5_est_configure,
|
|
.est_irq_status = dwmac5_est_irq_status,
|
|
.fpe_configure = dwmac5_fpe_configure,
|
|
+ .fpe_configure_get = dwmac5_fpe_configure_get,
|
|
.fpe_send_mpacket = dwmac5_fpe_send_mpacket,
|
|
.fpe_irq_status = dwmac5_fpe_irq_status,
|
|
.add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr,
|
|
@@ -1297,6 +1298,7 @@ const struct stmmac_ops dwmac510_ops = {
|
|
.est_configure = dwmac5_est_configure,
|
|
.est_irq_status = dwmac5_est_irq_status,
|
|
.fpe_configure = dwmac5_fpe_configure,
|
|
+ .fpe_configure_get = dwmac5_fpe_configure_get,
|
|
.fpe_send_mpacket = dwmac5_fpe_send_mpacket,
|
|
.fpe_irq_status = dwmac5_fpe_irq_status,
|
|
.add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr,
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
|
|
index 8fd167501fa0..74825f602482 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
|
|
@@ -712,10 +712,15 @@ void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev,
|
|
|
|
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
|
u32 num_txq, u32 num_rxq,
|
|
- bool enable)
|
|
+ bool enable, struct stmmac_fpe *fpe)
|
|
{
|
|
u32 value;
|
|
|
|
+ if (fpe) {
|
|
+ value = fpe->p_queues << MTL_FPECTRL_PEC_SHIFT | fpe->fragsize;
|
|
+ writel(value, ioaddr + MTL_FPE_CTRL_STS);
|
|
+ }
|
|
+
|
|
if (enable) {
|
|
cfg->fpe_csr = EFPE;
|
|
value = readl(ioaddr + GMAC_RXQ_CTRL1);
|
|
@@ -728,6 +733,18 @@ void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
|
writel(cfg->fpe_csr, ioaddr + MAC_FPE_CTRL_STS);
|
|
}
|
|
|
|
+void dwmac5_fpe_configure_get(void __iomem *ioaddr, struct stmmac_fpe *fpe)
|
|
+{
|
|
+ u32 value;
|
|
+
|
|
+ value = readl(ioaddr + MAC_FPE_CTRL_STS);
|
|
+ fpe->enable = value & EFPE;
|
|
+
|
|
+ value = readl(ioaddr + MTL_FPE_CTRL_STS);
|
|
+ fpe->p_queues = (value >> MTL_FPECTRL_PEC_SHIFT) & GENMASK(7, 0);
|
|
+ fpe->fragsize = value & GENMASK(1, 0);
|
|
+}
|
|
+
|
|
int dwmac5_fpe_irq_status(void __iomem *ioaddr, struct net_device *dev)
|
|
{
|
|
u32 value;
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
|
|
index 34e620790eb3..344aad5f3ee1 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
|
|
@@ -20,6 +20,9 @@
|
|
#define SVER BIT(1)
|
|
#define EFPE BIT(0)
|
|
|
|
+#define MTL_FPE_CTRL_STS 0x00000c90
|
|
+#define MTL_FPECTRL_PEC_SHIFT 8
|
|
+
|
|
#define MAC_PPS_CONTROL 0x00000b70
|
|
#define PPS_MAXIDX(x) ((((x) + 1) * 8) - 1)
|
|
#define PPS_MINIDX(x) ((x) * 8)
|
|
@@ -155,7 +158,8 @@ void dwmac5_est_irq_status(void __iomem *ioaddr, struct net_device *dev,
|
|
struct stmmac_extra_stats *x, u32 txqcnt);
|
|
void dwmac5_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
|
u32 num_txq, u32 num_rxq,
|
|
- bool enable);
|
|
+ bool enable, struct stmmac_fpe *fpe);
|
|
+void dwmac5_fpe_configure_get(void __iomem *ioaddr, struct stmmac_fpe *fpe);
|
|
void dwmac5_fpe_send_mpacket(void __iomem *ioaddr,
|
|
struct stmmac_fpe_cfg *cfg,
|
|
enum stmmac_mpacket_type type);
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
|
|
index 052566f5b7f3..4dd0de102ced 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
|
|
@@ -1558,7 +1558,8 @@ static int dwxgmac3_est_configure(void __iomem *ioaddr, struct stmmac_est *cfg,
|
|
|
|
static void dwxgmac3_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
|
u32 num_txq,
|
|
- u32 num_rxq, bool enable)
|
|
+ u32 num_rxq, bool enable,
|
|
+ struct stmmac_fpe *fpe)
|
|
{
|
|
u32 value;
|
|
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
|
|
index 47fb8e1646c2..610b90a31be2 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
|
|
@@ -296,6 +296,12 @@ struct stmmac_pps_cfg;
|
|
struct stmmac_rss;
|
|
struct stmmac_est;
|
|
|
|
+struct stmmac_fpe {
|
|
+ u8 enable;
|
|
+ u8 p_queues;
|
|
+ u8 fragsize;
|
|
+};
|
|
+
|
|
/* Helpers to program the MAC core */
|
|
struct stmmac_ops {
|
|
/* MAC core initialization */
|
|
@@ -414,7 +420,8 @@ struct stmmac_ops {
|
|
struct stmmac_extra_stats *x, u32 txqcnt);
|
|
void (*fpe_configure)(void __iomem *ioaddr, struct stmmac_fpe_cfg *cfg,
|
|
u32 num_txq, u32 num_rxq,
|
|
- bool enable);
|
|
+ bool enable, struct stmmac_fpe *fpe);
|
|
+ void (*fpe_configure_get)(void __iomem *ioaddr, struct stmmac_fpe *fpe);
|
|
void (*fpe_send_mpacket)(void __iomem *ioaddr,
|
|
struct stmmac_fpe_cfg *cfg,
|
|
enum stmmac_mpacket_type type);
|
|
@@ -521,6 +528,8 @@ struct stmmac_ops {
|
|
stmmac_do_void_callback(__priv, mac, est_irq_status, __args)
|
|
#define stmmac_fpe_configure(__priv, __args...) \
|
|
stmmac_do_void_callback(__priv, mac, fpe_configure, __args)
|
|
+#define stmmac_fpe_configure_get(__priv, __args...) \
|
|
+ stmmac_do_void_callback(__priv, mac, fpe_configure_get, __args)
|
|
#define stmmac_fpe_send_mpacket(__priv, __args...) \
|
|
stmmac_do_void_callback(__priv, mac, fpe_send_mpacket, __args)
|
|
#define stmmac_fpe_irq_status(__priv, __args...) \
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
|
|
index 04ac04d805fd..ecc164b5d9b9 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
|
|
@@ -335,6 +335,7 @@ struct stmmac_priv {
|
|
/* XDP BPF Program */
|
|
unsigned long *af_xdp_zc_qps;
|
|
struct bpf_prog *xdp_prog;
|
|
+ bool fp_enabled_admin;
|
|
};
|
|
|
|
enum stmmac_state {
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
|
|
index 521b1b5ffebb..892113ef5a06 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
|
|
@@ -19,6 +19,7 @@
|
|
#include "stmmac.h"
|
|
#include "dwmac_dma.h"
|
|
#include "dwxgmac2.h"
|
|
+#include "common.h"
|
|
|
|
#define REG_SPACE_SIZE 0x1060
|
|
#define GMAC4_REG_SPACE_SIZE 0x116C
|
|
@@ -1261,6 +1262,108 @@ static int stmmac_set_tunable(struct net_device *dev,
|
|
return ret;
|
|
}
|
|
|
|
+static int stmmac_reset_preempt(struct net_device *dev, bool enable)
|
|
+{
|
|
+ struct stmmac_priv *priv = netdev_priv(dev);
|
|
+ struct stmmac_fpe_cfg *fpe_cfg = priv->plat->fpe_cfg;
|
|
+ bool *hs_enable = &fpe_cfg->hs_enable;
|
|
+
|
|
+ if (enable) {
|
|
+ if (priv->fp_enabled_admin) {
|
|
+ priv->plat->fpe_cfg->enable = 1;
|
|
+ if (!*hs_enable)
|
|
+ stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
|
|
+ priv->plat->tx_queues_to_use,
|
|
+ priv->plat->rx_queues_to_use, true, NULL);
|
|
+ }
|
|
+ } else {
|
|
+ priv->plat->fpe_cfg->enable = 0;
|
|
+ stmmac_fpe_configure(priv, priv->ioaddr, fpe_cfg,
|
|
+ priv->plat->tx_queues_to_use,
|
|
+ priv->plat->rx_queues_to_use, false, NULL);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int stmmac_set_preempt(struct net_device *dev, struct ethtool_fp *fpcmd)
|
|
+{
|
|
+ struct stmmac_priv *priv = netdev_priv(dev);
|
|
+ struct stmmac_fpe fpe;
|
|
+
|
|
+ if (!priv->dma_cap.fpesel)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ if (!fpcmd->disabled &&
|
|
+ (fpcmd->min_frag_size < 60 || fpcmd->min_frag_size > 252))
|
|
+ return -EINVAL;
|
|
+
|
|
+ fpe.p_queues = fpcmd->preemptible_queues_mask;
|
|
+ fpe.fragsize = DIV_ROUND_UP((fpcmd->min_frag_size + 4), 64) - 1;
|
|
+
|
|
+ if (priv->plat->fpe_cfg->lo_fpe_state == FPE_STATE_ON)
|
|
+ fpe.enable = 1;
|
|
+ else
|
|
+ fpe.enable = fpcmd->fp_enabled ? 0 : 1;
|
|
+
|
|
+ /* To support preemption MAC should have more than 1 TX queue with at
|
|
+ * least 1 Queue designated as Express Queue. Queue 0 is always used as
|
|
+ * preemption queue when preemption MAC is enabled.
|
|
+ */
|
|
+ if (fpe.p_queues >= (GENMASK(priv->plat->tx_queues_to_use - 1, 0) - 1)) {
|
|
+ netdev_err(priv->dev,
|
|
+ "Preemptable queue mask 0x%x not supported.",
|
|
+ fpe.p_queues);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (fpcmd->disabled) {
|
|
+ fpe.enable = 0;
|
|
+ priv->plat->fpe_cfg->enable = 0;
|
|
+ priv->fp_enabled_admin = 0;
|
|
+ } else {
|
|
+ priv->plat->fpe_cfg->enable = 1;
|
|
+ priv->fp_enabled_admin = 1;
|
|
+ }
|
|
+ stmmac_fpe_configure(priv, priv->ioaddr, priv->plat->fpe_cfg,
|
|
+ priv->plat->tx_queues_to_use,
|
|
+ priv->plat->rx_queues_to_use, fpe.enable, &fpe);
|
|
+
|
|
+ stmmac_fpe_handshake(priv, fpcmd->fp_enabled);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int stmmac_get_preempt(struct net_device *dev, struct ethtool_fp *fpcmd)
|
|
+{
|
|
+ struct stmmac_priv *priv = netdev_priv(dev);
|
|
+ struct stmmac_fpe fpe;
|
|
+ int ret;
|
|
+
|
|
+ ret = stmmac_fpe_configure_get(priv, priv->ioaddr, &fpe);
|
|
+ if (ret) {
|
|
+ fpcmd->fp_supported = 0;
|
|
+ fpcmd->supported_queues_mask = 0;
|
|
+ fpcmd->preemptible_queues_mask = 0;
|
|
+ fpcmd->min_frag_size = 0;
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ fpcmd->fp_supported = 1;
|
|
+ fpcmd->fp_status = priv->plat->fpe_cfg->enable;
|
|
+ fpcmd->fp_active = fpe.enable;
|
|
+ fpcmd->supported_queues_mask = GENMASK(priv->plat->tx_queues_to_use - 1,
|
|
+ 0);
|
|
+ fpcmd->preemptible_queues_mask = fpe.p_queues;
|
|
+ /* Queue 0 is always preemption when preemption is active. */
|
|
+ if (fpcmd->fp_active)
|
|
+ fpcmd->preemptible_queues_mask |= 1;
|
|
+ fpcmd->min_frag_size = (fpe.fragsize + 1) * 64 - 4;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static const struct ethtool_ops stmmac_ethtool_ops = {
|
|
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
|
|
ETHTOOL_COALESCE_MAX_FRAMES,
|
|
@@ -1300,6 +1403,9 @@ static const struct ethtool_ops stmmac_ethtool_ops = {
|
|
.set_tunable = stmmac_set_tunable,
|
|
.get_link_ksettings = stmmac_ethtool_get_link_ksettings,
|
|
.set_link_ksettings = stmmac_ethtool_set_link_ksettings,
|
|
+ .set_preempt = stmmac_set_preempt,
|
|
+ .get_preempt = stmmac_get_preempt,
|
|
+ .reset_preempt = stmmac_reset_preempt,
|
|
};
|
|
|
|
void stmmac_set_ethtool_ops(struct net_device *netdev)
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
|
index e7dcf9b2d3a4..673761ba3507 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
|
|
@@ -969,6 +969,12 @@ static void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up)
|
|
} else {
|
|
*lo_state = FPE_STATE_OFF;
|
|
*lp_state = FPE_STATE_OFF;
|
|
+ priv->plat->fpe_cfg->enable = false;
|
|
+ stmmac_fpe_configure(priv, priv->ioaddr,
|
|
+ fpe_cfg,
|
|
+ priv->plat->tx_queues_to_use,
|
|
+ priv->plat->rx_queues_to_use,
|
|
+ false, NULL);
|
|
}
|
|
}
|
|
|
|
@@ -2455,12 +2461,14 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget)
|
|
/* We are sharing with slow path and stop XSK TX desc submission when
|
|
* available TX ring is less than threshold.
|
|
*/
|
|
- if (unlikely(stmmac_tx_avail(priv, queue) < STMMAC_TX_XSK_AVAIL) ||
|
|
- !netif_carrier_ok(priv->dev)) {
|
|
+ if (unlikely(stmmac_tx_avail(priv, queue) < STMMAC_TX_XSK_AVAIL)) {
|
|
work_done = false;
|
|
break;
|
|
}
|
|
|
|
+ if (!netif_carrier_ok(priv->dev))
|
|
+ break;
|
|
+
|
|
if (!xsk_tx_peek_desc(pool, &xdp_desc))
|
|
break;
|
|
|
|
@@ -6993,7 +7001,9 @@ static const struct net_device_ops stmmac_netdev_ops = {
|
|
.ndo_fix_features = stmmac_fix_features,
|
|
.ndo_set_features = stmmac_set_features,
|
|
.ndo_set_rx_mode = stmmac_set_rx_mode,
|
|
+#ifndef CONFIG_NET_SCH_MULTIQ
|
|
.ndo_tx_timeout = stmmac_tx_timeout,
|
|
+#endif
|
|
.ndo_eth_ioctl = stmmac_ioctl,
|
|
.ndo_get_stats64 = stmmac_get_stats64,
|
|
.ndo_setup_tc = stmmac_setup_tc,
|
|
@@ -7145,6 +7155,7 @@ static void stmmac_napi_add(struct net_device *dev)
|
|
{
|
|
struct stmmac_priv *priv = netdev_priv(dev);
|
|
u32 queue, maxq;
|
|
+ char name[NAPINAMSIZ];
|
|
|
|
maxq = max(priv->plat->rx_queues_to_use, priv->plat->tx_queues_to_use);
|
|
|
|
@@ -7156,16 +7167,22 @@ static void stmmac_napi_add(struct net_device *dev)
|
|
spin_lock_init(&ch->lock);
|
|
|
|
if (queue < priv->plat->rx_queues_to_use) {
|
|
- netif_napi_add(dev, &ch->rx_napi, stmmac_napi_poll_rx);
|
|
+ snprintf(name, NAPINAMSIZ, "rx-%d", queue);
|
|
+ netif_napi_add_named(dev, &ch->rx_napi, stmmac_napi_poll_rx,
|
|
+ NAPI_POLL_WEIGHT, name);
|
|
}
|
|
if (queue < priv->plat->tx_queues_to_use) {
|
|
- netif_napi_add_tx(dev, &ch->tx_napi,
|
|
- stmmac_napi_poll_tx);
|
|
+ snprintf(name, NAPINAMSIZ, "tx-%d", queue);
|
|
+ netif_napi_add_tx_named(dev, &ch->tx_napi,
|
|
+ stmmac_napi_poll_tx,
|
|
+ NAPI_POLL_WEIGHT, name);
|
|
}
|
|
if (queue < priv->plat->rx_queues_to_use &&
|
|
queue < priv->plat->tx_queues_to_use) {
|
|
- netif_napi_add(dev, &ch->rxtx_napi,
|
|
- stmmac_napi_poll_rxtx);
|
|
+ snprintf(name, NAPINAMSIZ, "zc-%d", queue);
|
|
+ netif_napi_add_named(dev, &ch->rxtx_napi,
|
|
+ stmmac_napi_poll_rxtx,
|
|
+ NAPI_POLL_WEIGHT, name);
|
|
}
|
|
}
|
|
}
|
|
@@ -7251,7 +7268,6 @@ static void stmmac_fpe_lp_task(struct work_struct *work)
|
|
enum stmmac_fpe_state *lo_state = &fpe_cfg->lo_fpe_state;
|
|
enum stmmac_fpe_state *lp_state = &fpe_cfg->lp_fpe_state;
|
|
bool *hs_enable = &fpe_cfg->hs_enable;
|
|
- bool *enable = &fpe_cfg->enable;
|
|
int retries = 20;
|
|
|
|
while (retries-- > 0) {
|
|
@@ -7265,7 +7281,7 @@ static void stmmac_fpe_lp_task(struct work_struct *work)
|
|
fpe_cfg,
|
|
priv->plat->tx_queues_to_use,
|
|
priv->plat->rx_queues_to_use,
|
|
- *enable);
|
|
+ true, NULL);
|
|
|
|
netdev_info(priv->dev, "configured FPE\n");
|
|
|
|
@@ -7773,7 +7789,7 @@ int stmmac_suspend(struct device *dev)
|
|
stmmac_fpe_configure(priv, priv->ioaddr,
|
|
priv->plat->fpe_cfg,
|
|
priv->plat->tx_queues_to_use,
|
|
- priv->plat->rx_queues_to_use, false);
|
|
+ priv->plat->rx_queues_to_use, false, NULL);
|
|
|
|
stmmac_fpe_handshake(priv, false);
|
|
stmmac_fpe_stop_wq(priv);
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
|
|
index 77245f856dd0..176edb91f40f 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
|
|
@@ -923,7 +923,7 @@ static int tc_setup_taprio(struct stmmac_priv *priv,
|
|
struct plat_stmmacenet_data *plat = priv->plat;
|
|
struct timespec64 time, current_time, qopt_time;
|
|
ktime_t current_time_ns;
|
|
- bool fpe = false;
|
|
+ struct stmmac_fpe fpe;
|
|
int i, ret = 0;
|
|
u64 ctr;
|
|
|
|
@@ -995,6 +995,8 @@ static int tc_setup_taprio(struct stmmac_priv *priv,
|
|
priv->plat->est->enable = qopt->cmd == TAPRIO_CMD_REPLACE;
|
|
mutex_unlock(&priv->plat->est->lock);
|
|
|
|
+ stmmac_fpe_configure_get(priv, priv->ioaddr, &fpe);
|
|
+
|
|
for (i = 0; i < size; i++) {
|
|
s64 delta_ns = qopt->entries[i].interval;
|
|
u32 gates = qopt->entries[i].gate_mask;
|
|
@@ -1006,16 +1008,18 @@ static int tc_setup_taprio(struct stmmac_priv *priv,
|
|
|
|
switch (qopt->entries[i].command) {
|
|
case TC_TAPRIO_CMD_SET_GATES:
|
|
- if (fpe)
|
|
+ if (fpe.enable)
|
|
return -EINVAL;
|
|
break;
|
|
case TC_TAPRIO_CMD_SET_AND_HOLD:
|
|
+ if (!fpe.enable)
|
|
+ return -EINVAL;
|
|
gates |= BIT(0);
|
|
- fpe = true;
|
|
break;
|
|
case TC_TAPRIO_CMD_SET_AND_RELEASE:
|
|
+ if (!fpe.enable)
|
|
+ return -EINVAL;
|
|
gates &= ~BIT(0);
|
|
- fpe = true;
|
|
break;
|
|
default:
|
|
return -EOPNOTSUPP;
|
|
@@ -1042,16 +1046,6 @@ static int tc_setup_taprio(struct stmmac_priv *priv,
|
|
priv->plat->est->ctr[0] = do_div(ctr, NSEC_PER_SEC);
|
|
priv->plat->est->ctr[1] = (u32)ctr;
|
|
|
|
- if (fpe && !priv->dma_cap.fpesel) {
|
|
- mutex_unlock(&priv->plat->est->lock);
|
|
- return -EOPNOTSUPP;
|
|
- }
|
|
-
|
|
- /* Actual FPE register configuration will be done after FPE handshake
|
|
- * is success.
|
|
- */
|
|
- priv->plat->fpe_cfg->enable = fpe;
|
|
-
|
|
ret = stmmac_est_configure(priv, priv->ioaddr, priv->plat->est,
|
|
priv->plat->clk_ptp_rate);
|
|
mutex_unlock(&priv->plat->est->lock);
|
|
@@ -1062,11 +1056,6 @@ static int tc_setup_taprio(struct stmmac_priv *priv,
|
|
|
|
netdev_info(priv->dev, "configured EST\n");
|
|
|
|
- if (fpe) {
|
|
- stmmac_fpe_handshake(priv, true);
|
|
- netdev_info(priv->dev, "start FPE handshake\n");
|
|
- }
|
|
-
|
|
return 0;
|
|
|
|
disable:
|
|
@@ -1078,17 +1067,6 @@ static int tc_setup_taprio(struct stmmac_priv *priv,
|
|
mutex_unlock(&priv->plat->est->lock);
|
|
}
|
|
|
|
- priv->plat->fpe_cfg->enable = false;
|
|
- stmmac_fpe_configure(priv, priv->ioaddr,
|
|
- priv->plat->fpe_cfg,
|
|
- priv->plat->tx_queues_to_use,
|
|
- priv->plat->rx_queues_to_use,
|
|
- false);
|
|
- netdev_info(priv->dev, "disabled FPE\n");
|
|
-
|
|
- stmmac_fpe_handshake(priv, false);
|
|
- netdev_info(priv->dev, "stop FPE handshake\n");
|
|
-
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
|
|
index 95a9c35e293c..6eff60426a08 100644
|
|
--- a/drivers/net/phy/phy.c
|
|
+++ b/drivers/net/phy/phy.c
|
|
@@ -36,7 +36,8 @@
|
|
#include <net/genetlink.h>
|
|
#include <net/sock.h>
|
|
|
|
-#define PHY_STATE_TIME HZ
|
|
+#define PHY_STATE_TIME HZ
|
|
+#define PHY_STATE_TIME_MS 100
|
|
|
|
#define PHY_STATE_STR(_state) \
|
|
case PHY_##_state: \
|
|
@@ -1544,7 +1545,7 @@ void phy_state_machine(struct work_struct *work)
|
|
*/
|
|
mutex_lock(&phydev->lock);
|
|
if (phy_polling_mode(phydev) && phy_is_started(phydev))
|
|
- phy_queue_state_machine(phydev, PHY_STATE_TIME);
|
|
+ phy_queue_state_machine(phydev, (PHY_STATE_TIME_MS * HZ) / 1000);
|
|
mutex_unlock(&phydev->lock);
|
|
}
|
|
|
|
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
|
|
index 288c6f1c6979..64d3846b93be 100644
|
|
--- a/drivers/nfc/Kconfig
|
|
+++ b/drivers/nfc/Kconfig
|
|
@@ -60,6 +60,7 @@ config NFC_VIRTUAL_NCI
|
|
|
|
If unsure, say N.
|
|
|
|
+source "drivers/nfc/pn5xx/Kconfig"
|
|
source "drivers/nfc/fdp/Kconfig"
|
|
source "drivers/nfc/pn544/Kconfig"
|
|
source "drivers/nfc/pn533/Kconfig"
|
|
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
|
|
index 7b1bfde1d971..62d495c57a15 100644
|
|
--- a/drivers/nfc/Makefile
|
|
+++ b/drivers/nfc/Makefile
|
|
@@ -3,6 +3,7 @@
|
|
# Makefile for nfc devices
|
|
#
|
|
|
|
+obj-$(CONFIG_NFC_NXP_PN5XX) += pn5xx/
|
|
obj-$(CONFIG_NFC_FDP) += fdp/
|
|
obj-$(CONFIG_NFC_PN544) += pn544/
|
|
obj-$(CONFIG_NFC_MICROREAD) += microread/
|
|
diff --git a/drivers/nfc/pn5xx/Kconfig b/drivers/nfc/pn5xx/Kconfig
|
|
new file mode 100644
|
|
index 000000000000..10db8c403866
|
|
--- /dev/null
|
|
+++ b/drivers/nfc/pn5xx/Kconfig
|
|
@@ -0,0 +1,12 @@
|
|
+config NFC_NXP_PN5XX
|
|
+ tristate "NXP PN5XX based driver"
|
|
+ depends on I2C
|
|
+ select CRC_CCITT
|
|
+ help
|
|
+ NXP PN5XX driver based on I2C.
|
|
+ This is a driver to provides I2C access to PN5xx and PN7120 NFC
|
|
+ Controller devices
|
|
+
|
|
+ To compile this driver as a module, choose m here. The module will
|
|
+ be called pn5xx_i2c.
|
|
+ Say N if unsure.
|
|
diff --git a/drivers/nfc/pn5xx/Makefile b/drivers/nfc/pn5xx/Makefile
|
|
new file mode 100644
|
|
index 000000000000..b31bbb51423a
|
|
--- /dev/null
|
|
+++ b/drivers/nfc/pn5xx/Makefile
|
|
@@ -0,0 +1,6 @@
|
|
+# SPDX-License-Identifier: GPL-2.0-only
|
|
+#
|
|
+# Makefile for PN5xx NFC driver
|
|
+#
|
|
+
|
|
+obj-$(CONFIG_NFC_NXP_PN5XX) += pn5xx_i2c.o
|
|
diff --git a/drivers/nfc/pn5xx/README.md b/drivers/nfc/pn5xx/README.md
|
|
new file mode 100644
|
|
index 000000000000..c0c8d5c73757
|
|
--- /dev/null
|
|
+++ b/drivers/nfc/pn5xx/README.md
|
|
@@ -0,0 +1,2 @@
|
|
+# nxp-pn5xx
|
|
+NXP's NFC Open Source Kernel mode driver
|
|
diff --git a/drivers/nfc/pn5xx/pn5xx_i2c.c b/drivers/nfc/pn5xx/pn5xx_i2c.c
|
|
new file mode 100644
|
|
index 000000000000..4b85b12aa7ff
|
|
--- /dev/null
|
|
+++ b/drivers/nfc/pn5xx/pn5xx_i2c.c
|
|
@@ -0,0 +1,669 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * Copyright (C) 2010 Trusted Logic S.A.
|
|
+ * Copyright 2015,2019-2023 NXP
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/list.h>
|
|
+#include <linux/i2c.h>
|
|
+#include <linux/irq.h>
|
|
+#include <linux/jiffies.h>
|
|
+#include <linux/uaccess.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/gpio.h>
|
|
+#include <linux/miscdevice.h>
|
|
+#include <linux/spinlock.h>
|
|
+#include "pn5xx_i2c.h"
|
|
+#include <linux/of_gpio.h>
|
|
+#include <linux/regulator/consumer.h>
|
|
+#include <linux/of.h>
|
|
+#include <linux/sched.h>
|
|
+
|
|
+#include <linux/kthread.h>
|
|
+
|
|
+#define MAX_BUFFER_SIZE 512
|
|
+
|
|
+#define MODE_OFF 0
|
|
+#define MODE_RUN 1
|
|
+#define MODE_FW 2
|
|
+
|
|
+/* pn7120, pn548, pn547 and pn544 are supported */
|
|
+#define CHIP "pn544"
|
|
+#define DRIVER_CARD "PN54x NFC"
|
|
+#define DRIVER_DESC "NFC driver for PN54x Family"
|
|
+
|
|
+#ifndef CONFIG_OF
|
|
+#define CONFIG_OF
|
|
+#endif
|
|
+
|
|
+struct pn54x_dev {
|
|
+ wait_queue_head_t read_wq;
|
|
+ struct mutex read_mutex;
|
|
+ struct i2c_client *client;
|
|
+ struct miscdevice pn54x_device;
|
|
+ int ven_gpio;
|
|
+ int firm_gpio;
|
|
+ int irq_gpio;
|
|
+ int clkreq_gpio;
|
|
+ struct regulator *pvdd_reg;
|
|
+ struct regulator *vbat_reg;
|
|
+ struct regulator *pmuvcc_reg;
|
|
+ struct regulator *sevdd_reg;
|
|
+ bool irq_enabled;
|
|
+ spinlock_t irq_enabled_lock;
|
|
+};
|
|
+
|
|
+static struct task_struct *test_task;
|
|
+/* Interrupt control and handler */
|
|
+static void pn54x_disable_irq(struct pn54x_dev *pn54x_dev)
|
|
+{
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&pn54x_dev->irq_enabled_lock, flags);
|
|
+ if (pn54x_dev->irq_enabled) {
|
|
+ disable_irq_nosync(pn54x_dev->client->irq);
|
|
+ pn54x_dev->irq_enabled = false;
|
|
+ }
|
|
+ spin_unlock_irqrestore(&pn54x_dev->irq_enabled_lock, flags);
|
|
+}
|
|
+
|
|
+static irqreturn_t pn54x_dev_irq_handler(int irq, void *dev_id)
|
|
+{
|
|
+ struct pn54x_dev *pn54x_dev = dev_id;
|
|
+
|
|
+ pn54x_disable_irq(pn54x_dev);
|
|
+
|
|
+ /* Wake up waiting readers */
|
|
+ wake_up(&pn54x_dev->read_wq);
|
|
+
|
|
+ return IRQ_HANDLED;
|
|
+}
|
|
+
|
|
+static struct pn54x_dev *gpn54x_dev = NULL;
|
|
+static int pn54x_dev_loop_handler(void *data)
|
|
+{
|
|
+ struct pn54x_dev *pn54x_dev = (struct pn54x_dev *)gpn54x_dev;
|
|
+
|
|
+ printk("In pn54x_dev_loop_handler...%x \n", data);
|
|
+ while (1) {
|
|
+ /* Wake up waiting readers */
|
|
+ wake_up(&pn54x_dev->read_wq);
|
|
+ msleep(200);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* private functions */
|
|
+static int pn544_enable(struct pn54x_dev *dev, int mode)
|
|
+{
|
|
+ int r;
|
|
+
|
|
+ /*
|
|
+ * turn on the regulators
|
|
+ * -- if the regulators were specified, they're required
|
|
+ */
|
|
+ if (dev->pvdd_reg != NULL) {
|
|
+ r = regulator_enable(dev->pvdd_reg);
|
|
+ if (r < 0) {
|
|
+ pr_err("%s: not able to enable pvdd\n", __func__);
|
|
+ return r;
|
|
+ }
|
|
+ }
|
|
+ if (dev->vbat_reg != NULL) {
|
|
+ r = regulator_enable(dev->vbat_reg);
|
|
+ if (r < 0) {
|
|
+ pr_err("%s: not able to enable vbat\n", __func__);
|
|
+ goto enable_exit0;
|
|
+ }
|
|
+ }
|
|
+ if (dev->pmuvcc_reg != NULL) {
|
|
+ r = regulator_enable(dev->pmuvcc_reg);
|
|
+ if (r < 0) {
|
|
+ pr_err("%s: not able to enable pmuvcc\n", __func__);
|
|
+ goto enable_exit1;
|
|
+ }
|
|
+ }
|
|
+ if (dev->sevdd_reg != NULL) {
|
|
+ r = regulator_enable(dev->sevdd_reg);
|
|
+ if (r < 0) {
|
|
+ pr_err("%s: not able to enable sevdd\n", __func__);
|
|
+ goto enable_exit2;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (MODE_RUN == mode) {
|
|
+ printk("%s power on\n", __func__);
|
|
+ if (gpio_is_valid(dev->firm_gpio))
|
|
+ gpio_set_value_cansleep(dev->firm_gpio, 0);
|
|
+ msleep(100);
|
|
+ } else if (MODE_FW == mode) {
|
|
+ /* power on with firmware download (requires hw reset) */
|
|
+ pr_info("%s power on with firmware\n", __func__);
|
|
+ msleep(20);
|
|
+ if (gpio_is_valid(dev->firm_gpio)) {
|
|
+ gpio_set_value(dev->firm_gpio, 1);
|
|
+ } else {
|
|
+ pr_err("%s Unused Firm GPIO %d\n", __func__, mode);
|
|
+ return GPIO_UNUSED;
|
|
+ }
|
|
+ msleep(20);
|
|
+ msleep(100);
|
|
+ msleep(20);
|
|
+ } else {
|
|
+ pr_err("%s bad arg %d\n", __func__, mode);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+enable_exit2:
|
|
+ if (dev->pmuvcc_reg)
|
|
+ regulator_disable(dev->pmuvcc_reg);
|
|
+enable_exit1:
|
|
+ if (dev->vbat_reg)
|
|
+ regulator_disable(dev->vbat_reg);
|
|
+enable_exit0:
|
|
+ if (dev->pvdd_reg)
|
|
+ regulator_disable(dev->pvdd_reg);
|
|
+
|
|
+ return r;
|
|
+}
|
|
+
|
|
+static void pn544_disable(struct pn54x_dev *dev)
|
|
+{
|
|
+ /* power off */
|
|
+ printk("%s power off\n", __func__);
|
|
+ if (gpio_is_valid(dev->firm_gpio))
|
|
+ gpio_set_value_cansleep(dev->firm_gpio, 0);
|
|
+ msleep(100);
|
|
+
|
|
+ if (dev->sevdd_reg)
|
|
+ regulator_disable(dev->sevdd_reg);
|
|
+ if (dev->pmuvcc_reg)
|
|
+ regulator_disable(dev->pmuvcc_reg);
|
|
+ if (dev->vbat_reg)
|
|
+ regulator_disable(dev->vbat_reg);
|
|
+ if (dev->pvdd_reg)
|
|
+ regulator_disable(dev->pvdd_reg);
|
|
+}
|
|
+
|
|
+/* driver functions */
|
|
+static ssize_t pn54x_dev_read(struct file *filp, char __user *buf,
|
|
+ size_t count, loff_t *offset)
|
|
+{
|
|
+ struct pn54x_dev *pn54x_dev = filp->private_data;
|
|
+ char tmp[MAX_BUFFER_SIZE];
|
|
+ int ret;
|
|
+
|
|
+ if (count > MAX_BUFFER_SIZE)
|
|
+ count = MAX_BUFFER_SIZE;
|
|
+
|
|
+ mutex_lock(&pn54x_dev->read_mutex);
|
|
+
|
|
+ /* Read data */
|
|
+ ret = i2c_master_recv(pn54x_dev->client, tmp, count);
|
|
+
|
|
+ mutex_unlock(&pn54x_dev->read_mutex);
|
|
+
|
|
+ /*
|
|
+ * pn54x seems to be slow in handling I2C read requests
|
|
+ * so add 1ms delay after recv operation
|
|
+ */
|
|
+ udelay(1000);
|
|
+
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ if (ret > count) {
|
|
+ pr_err("%s: received too many bytes from i2c (%d)\n",
|
|
+ __func__, ret);
|
|
+ return -EIO;
|
|
+ }
|
|
+ if (copy_to_user(buf, tmp, ret)) {
|
|
+ pr_err("%s : failed to copy to user space\n", __func__);
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ return ret;
|
|
+
|
|
+fail:
|
|
+ mutex_unlock(&pn54x_dev->read_mutex);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static ssize_t pn54x_dev_write(struct file *filp, const char __user *buf,
|
|
+ size_t count, loff_t *offset)
|
|
+{
|
|
+ struct pn54x_dev *pn54x_dev;
|
|
+ char tmp[MAX_BUFFER_SIZE];
|
|
+ int ret;
|
|
+
|
|
+ pn54x_dev = filp->private_data;
|
|
+
|
|
+ if (count > MAX_BUFFER_SIZE)
|
|
+ count = MAX_BUFFER_SIZE;
|
|
+
|
|
+ if (copy_from_user(tmp, buf, count)) {
|
|
+ pr_err("%s : failed to copy from user space\n", __func__);
|
|
+ return -EFAULT;
|
|
+ }
|
|
+
|
|
+ pr_debug("%s : writing %zu bytes.\n", __func__, count);
|
|
+ /* Write data */
|
|
+ ret = i2c_master_send(pn54x_dev->client, tmp, count);
|
|
+ if (ret != count) {
|
|
+ pr_err("%s : i2c_master_send returned %d\n", __func__, ret);
|
|
+ pr_err("I2C addr is 0x%02X, name is %s\n",
|
|
+ pn54x_dev->client->addr, pn54x_dev->client->name);
|
|
+ ret = -EIO;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * pn54x seems to be slow in handling I2C write requests
|
|
+ * so add 1ms delay after I2C send oparation
|
|
+ */
|
|
+ udelay(1000);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int pn54x_dev_open(struct inode *inode, struct file *filp)
|
|
+{
|
|
+ struct pn54x_dev *pn54x_dev = container_of(filp->private_data,
|
|
+ struct pn54x_dev,
|
|
+ pn54x_device);
|
|
+
|
|
+ filp->private_data = pn54x_dev;
|
|
+
|
|
+ pr_info("%s : %d,%d\n", __func__, imajor(inode), iminor(inode));
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int pn54x_dev_release(struct inode *inode, struct file *filp)
|
|
+{
|
|
+ pr_info("%s : closing %d,%d\n", __func__, imajor(inode), iminor(inode));
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static long pn54x_dev_ioctl(struct file *filp, unsigned int cmd,
|
|
+ unsigned long arg)
|
|
+{
|
|
+ struct pn54x_dev *pn54x_dev = filp->private_data;
|
|
+
|
|
+ pr_info("%s, cmd=%d, arg=%lu\n", __func__, cmd, arg);
|
|
+ switch (cmd) {
|
|
+ case PN544_SET_PWR:
|
|
+ if (arg == 2) {
|
|
+ /* power on w/FW */
|
|
+ if (pn544_enable(pn54x_dev, arg) == GPIO_UNUSED)
|
|
+ return GPIO_UNUSED;
|
|
+ } else if (arg == 1) {
|
|
+ /* power on */
|
|
+ pn544_enable(pn54x_dev, arg);
|
|
+ } else if (arg == 0) {
|
|
+ /* power off */
|
|
+ pn544_disable(pn54x_dev);
|
|
+ } else {
|
|
+ pr_err("%s bad SET_PWR arg %lu\n", __func__, arg);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ break;
|
|
+ case PN54X_CLK_REQ:
|
|
+ if (arg == 1) {
|
|
+ if (gpio_is_valid(pn54x_dev->clkreq_gpio)) {
|
|
+ gpio_set_value(pn54x_dev->clkreq_gpio, 1);
|
|
+ } else {
|
|
+ pr_err("%s Unused Clkreq GPIO %lu\n",
|
|
+ __func__, arg);
|
|
+ return GPIO_UNUSED;
|
|
+ }
|
|
+ } else if (arg == 0) {
|
|
+ if (gpio_is_valid(pn54x_dev->clkreq_gpio)) {
|
|
+ gpio_set_value(pn54x_dev->clkreq_gpio, 0);
|
|
+ } else {
|
|
+ pr_err("%s Unused Clkreq GPIO %lu\n",
|
|
+ __func__, arg);
|
|
+ return GPIO_UNUSED;
|
|
+ }
|
|
+ } else {
|
|
+ pr_err("%s bad CLK_REQ arg %lu\n", __func__, arg);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ pr_err("%s bad ioctl %u\n", __func__, cmd);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct file_operations pn54x_dev_fops = {
|
|
+ .owner = THIS_MODULE,
|
|
+ .llseek = no_llseek,
|
|
+ .read = pn54x_dev_read,
|
|
+ .write = pn54x_dev_write,
|
|
+ .open = pn54x_dev_open,
|
|
+ .release = pn54x_dev_release,
|
|
+ .unlocked_ioctl = pn54x_dev_ioctl,
|
|
+};
|
|
+
|
|
+/* Handlers for alternative sources of platform_data */
|
|
+#ifdef CONFIG_OF
|
|
+/* Translate OpenFirmware node properties into platform_data */
|
|
+static int pn54x_get_pdata(struct device *dev,
|
|
+ struct pn544_i2c_platform_data *pdata)
|
|
+{
|
|
+ struct device_node *node;
|
|
+ int val;
|
|
+
|
|
+ /* make sure there is actually a device tree node */
|
|
+ node = dev->of_node;
|
|
+ if (!node)
|
|
+ return -ENODEV;
|
|
+
|
|
+ memset(pdata, 0, sizeof(*pdata));
|
|
+
|
|
+ /*
|
|
+ * read the dev tree data
|
|
+ * firm pin - controls firmware download - OPTIONAL
|
|
+ */
|
|
+ val = of_get_named_gpio(node, "firmware-gpios", 0);
|
|
+ if (val >= 0) {
|
|
+ pdata->firm_gpio = val;
|
|
+ } else {
|
|
+ pdata->firm_gpio = GPIO_UNUSED;
|
|
+ dev_warn(dev, "FIRM GPIO <OPTIONAL> error getting from OF node\n");
|
|
+ }
|
|
+
|
|
+ /* clkreq pin - controls the clock to the PN547 - OPTIONAL */
|
|
+ val = of_get_named_gpio(node, "nxp,pn54x-clkreq", 0);
|
|
+ if (val >= 0) {
|
|
+ pdata->clkreq_gpio = val;
|
|
+ } else {
|
|
+ pdata->clkreq_gpio = GPIO_UNUSED;
|
|
+ dev_warn(dev,
|
|
+ "CLKREQ GPIO <OPTIONAL> error getting from OF node\n");
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * handle the regulator lines - these are optional
|
|
+ * PVdd - pad Vdd (544, 547)
|
|
+ * Vbat - Battery (544, 547)
|
|
+ * PMUVcc - UICC Power (544, 547)
|
|
+ * SEVdd - SE Power (544)
|
|
+ *
|
|
+ * Will attempt to load a matching Regulator Resource for each
|
|
+ * If no resource is provided, then the input will not be controlled
|
|
+ * Example: if only PVdd is provided, it is the only one that will be
|
|
+ * turned on/off.
|
|
+ */
|
|
+ pdata->pvdd_reg = regulator_get(dev, "nxp,pn54x-pvdd");
|
|
+ if (IS_ERR(pdata->pvdd_reg)) {
|
|
+ pr_err("%s: could not get nxp,pn54x-pvdd, rc=%ld\n",
|
|
+ __func__, PTR_ERR(pdata->pvdd_reg));
|
|
+ pdata->pvdd_reg = NULL;
|
|
+ }
|
|
+
|
|
+ pdata->vbat_reg = regulator_get(dev, "nxp,pn54x-vbat");
|
|
+ if (IS_ERR(pdata->vbat_reg)) {
|
|
+ pr_err("%s: could not get nxp,pn54x-vbat, rc=%ld\n",
|
|
+ __func__, PTR_ERR(pdata->vbat_reg));
|
|
+ pdata->vbat_reg = NULL;
|
|
+ }
|
|
+
|
|
+ pdata->pmuvcc_reg = regulator_get(dev, "nxp,pn54x-pmuvcc");
|
|
+ if (IS_ERR(pdata->pmuvcc_reg)) {
|
|
+ pr_err("%s: could not get nxp,pn54x-pmuvcc, rc=%ld\n",
|
|
+ __func__, PTR_ERR(pdata->pmuvcc_reg));
|
|
+ pdata->pmuvcc_reg = NULL;
|
|
+ }
|
|
+
|
|
+ pdata->sevdd_reg = regulator_get(dev, "nxp,pn54x-sevdd");
|
|
+ if (IS_ERR(pdata->sevdd_reg)) {
|
|
+ pr_err("%s: could not get nxp,pn54x-sevdd, rc=%ld\n",
|
|
+ __func__, PTR_ERR(pdata->sevdd_reg));
|
|
+ pdata->sevdd_reg = NULL;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+#else
|
|
+static int pn54x_get_pdata(struct device *dev,
|
|
+ struct pn544_i2c_platform_data *pdata)
|
|
+{
|
|
+ pdata = dev->platform_data;
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
+/* pn54x_probe */
|
|
+#ifdef KERNEL_3_4_AND_OLDER
|
|
+static int __devinit pn54x_probe(struct i2c_client *client)
|
|
+#else
|
|
+static int pn54x_probe(struct i2c_client *client)
|
|
+#endif
|
|
+{
|
|
+ int ret;
|
|
+ /* gpio values, from board file or DT */
|
|
+ struct pn544_i2c_platform_data *pdata;
|
|
+ struct pn544_i2c_platform_data tmp_pdata;
|
|
+ /* internal device specific data */
|
|
+ struct pn54x_dev *pn54x_dev;
|
|
+
|
|
+ pr_info("%s\n", __func__);
|
|
+
|
|
+ /*
|
|
+ * ---- retrieve the platform data ----
|
|
+ * If the dev.platform_data is NULL, then
|
|
+ * attempt to read from the device tree
|
|
+ */
|
|
+ if (!client->dev.platform_data) {
|
|
+ ret = pn54x_get_pdata(&(client->dev), &tmp_pdata);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ pdata = &tmp_pdata;
|
|
+ } else {
|
|
+ pdata = client->dev.platform_data;
|
|
+ }
|
|
+
|
|
+ if (pdata == NULL) {
|
|
+ pr_err("%s : nfc probe fail\n", __func__);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ /* validate the the adapter has basic I2C functionality */
|
|
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
|
+ pr_err("%s : need I2C_FUNC_I2C\n", __func__);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ if (gpio_is_valid(pdata->firm_gpio)) {
|
|
+ pr_info("%s: request firm_gpio %d\n",
|
|
+ __func__, pdata->firm_gpio);
|
|
+ ret = gpio_request(pdata->firm_gpio, "nfc_firm");
|
|
+ if (ret) {
|
|
+ pr_err("%s :not able to get GPIO firm_gpio\n",
|
|
+ __func__);
|
|
+ goto err_firm;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (gpio_is_valid(pdata->clkreq_gpio)) {
|
|
+ pr_info("%s: request clkreq_gpio %d\n",
|
|
+ __func__, pdata->clkreq_gpio);
|
|
+ ret = gpio_request(pdata->clkreq_gpio, "nfc_clkreq");
|
|
+ if (ret) {
|
|
+ pr_err("%s :not able to get GPIO clkreq_gpio\n",
|
|
+ __func__);
|
|
+ goto err_clkreq;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* allocate the pn54x driver information structure */
|
|
+ pn54x_dev = kzalloc(sizeof(*pn54x_dev), GFP_KERNEL);
|
|
+ if (pn54x_dev == NULL) {
|
|
+ dev_err(&client->dev,
|
|
+ "failed to allocate memory for module data\n");
|
|
+ ret = -ENOMEM;
|
|
+ goto err_exit;
|
|
+ }
|
|
+
|
|
+ /* store the platform data in the driver info struct */
|
|
+ pn54x_dev->firm_gpio = pdata->firm_gpio;
|
|
+ pn54x_dev->clkreq_gpio = pdata->clkreq_gpio;
|
|
+ pn54x_dev->pvdd_reg = pdata->pvdd_reg;
|
|
+ pn54x_dev->vbat_reg = pdata->vbat_reg;
|
|
+ pn54x_dev->pmuvcc_reg = pdata->pmuvcc_reg;
|
|
+ pn54x_dev->sevdd_reg = pdata->sevdd_reg;
|
|
+
|
|
+ pn54x_dev->client = client;
|
|
+
|
|
+ if (gpio_is_valid(pn54x_dev->firm_gpio)) {
|
|
+ ret = gpio_direction_output(pn54x_dev->firm_gpio, 0);
|
|
+ if (ret < 0) {
|
|
+ pr_err("%s : not able to set firm_gpio as output\n",
|
|
+ __func__);
|
|
+ goto err_exit;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (gpio_is_valid(pn54x_dev->clkreq_gpio)) {
|
|
+ ret = gpio_direction_output(pn54x_dev->clkreq_gpio, 0);
|
|
+ if (ret < 0) {
|
|
+ pr_err("%s : not able to set clkreq_gpio as output\n",
|
|
+ __func__);
|
|
+ goto err_exit;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* init mutex and queues */
|
|
+ init_waitqueue_head(&pn54x_dev->read_wq);
|
|
+ mutex_init(&pn54x_dev->read_mutex);
|
|
+ spin_lock_init(&pn54x_dev->irq_enabled_lock);
|
|
+
|
|
+ /* register as a misc device - character based with one entry point */
|
|
+ pn54x_dev->pn54x_device.minor = MISC_DYNAMIC_MINOR;
|
|
+ pn54x_dev->pn54x_device.name = CHIP;
|
|
+ pn54x_dev->pn54x_device.fops = &pn54x_dev_fops;
|
|
+ ret = misc_register(&pn54x_dev->pn54x_device);
|
|
+ if (ret) {
|
|
+ pr_err("%s : misc_register failed\n", __FILE__);
|
|
+ goto err_misc_register;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * request irq. the irq is set whenever the chip has data available
|
|
+ * for reading. it is cleared when all data has been read.
|
|
+ */
|
|
+ i2c_set_clientdata(client, pn54x_dev);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err_request_irq_failed:
|
|
+ misc_deregister(&pn54x_dev->pn54x_device);
|
|
+err_misc_register:
|
|
+err_exit:
|
|
+ if (gpio_is_valid(pdata->clkreq_gpio))
|
|
+ gpio_free(pdata->clkreq_gpio);
|
|
+err_clkreq:
|
|
+ if (gpio_is_valid(pdata->firm_gpio))
|
|
+ gpio_free(pdata->firm_gpio);
|
|
+err_firm:
|
|
+err_ven:
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+#ifdef KERNEL_3_4_AND_OLDER
|
|
+static int __devexit pn54x_remove(struct i2c_client *client)
|
|
+#else
|
|
+static void pn54x_remove(struct i2c_client *client)
|
|
+#endif
|
|
+{
|
|
+ struct pn54x_dev *pn54x_dev;
|
|
+
|
|
+ pr_info("%s\n", __func__);
|
|
+
|
|
+ pn54x_dev = i2c_get_clientdata(client);
|
|
+ free_irq(client->irq, pn54x_dev);
|
|
+ misc_deregister(&pn54x_dev->pn54x_device);
|
|
+ mutex_destroy(&pn54x_dev->read_mutex);
|
|
+ if (gpio_is_valid(pn54x_dev->firm_gpio))
|
|
+ gpio_free(pn54x_dev->firm_gpio);
|
|
+ if (gpio_is_valid(pn54x_dev->clkreq_gpio))
|
|
+ gpio_free(pn54x_dev->clkreq_gpio);
|
|
+ regulator_put(pn54x_dev->pvdd_reg);
|
|
+ regulator_put(pn54x_dev->vbat_reg);
|
|
+ regulator_put(pn54x_dev->pmuvcc_reg);
|
|
+ regulator_put(pn54x_dev->sevdd_reg);
|
|
+
|
|
+ kfree(pn54x_dev);
|
|
+
|
|
+#ifdef KERNEL_3_4_AND_OLDER
|
|
+ return 0;
|
|
+#else
|
|
+ return;
|
|
+#endif
|
|
+}
|
|
+
|
|
+#ifdef CONFIG_OF
|
|
+static struct of_device_id pn54x_dt_match[] = {
|
|
+ { .compatible = "nxp,pn547", },
|
|
+ { .compatible = "nxp,pn544", },
|
|
+ {},
|
|
+};
|
|
+MODULE_DEVICE_TABLE(of, pn54x_dt_match);
|
|
+#endif
|
|
+
|
|
+static const struct i2c_device_id pn54x_id[] = {
|
|
+ { "pn547", 0 },
|
|
+ { },
|
|
+};
|
|
+MODULE_DEVICE_TABLE(i2c, pn54x_id);
|
|
+
|
|
+static struct i2c_driver pn54x_driver = {
|
|
+ .id_table = pn54x_id,
|
|
+ .probe = pn54x_probe,
|
|
+#ifdef KERNEL_3_4_AND_OLDER
|
|
+ .remove = __devexit_p(pn54x_remove),
|
|
+#else
|
|
+ .remove = pn54x_remove,
|
|
+#endif
|
|
+ .driver = {
|
|
+ .owner = THIS_MODULE,
|
|
+ .name = "pn544",
|
|
+ .of_match_table = pn54x_dt_match,
|
|
+ },
|
|
+};
|
|
+
|
|
+/* module load/unload record keeping */
|
|
+static int __init pn54x_dev_init(void)
|
|
+{
|
|
+ pr_info("%s\n", __func__);
|
|
+ return i2c_add_driver(&pn54x_driver);
|
|
+}
|
|
+
|
|
+static void __exit pn54x_dev_exit(void)
|
|
+{
|
|
+ pr_info("%s\n", __func__);
|
|
+ i2c_del_driver(&pn54x_driver);
|
|
+}
|
|
+
|
|
+module_init(pn54x_dev_init);
|
|
+module_exit(pn54x_dev_exit);
|
|
+
|
|
+MODULE_AUTHOR("Sylvain Fonteneau");
|
|
+MODULE_DESCRIPTION(DRIVER_DESC);
|
|
+MODULE_LICENSE("GPL");
|
|
diff --git a/drivers/nfc/pn5xx/pn5xx_i2c.h b/drivers/nfc/pn5xx/pn5xx_i2c.h
|
|
new file mode 100644
|
|
index 000000000000..4b53655007e0
|
|
--- /dev/null
|
|
+++ b/drivers/nfc/pn5xx/pn5xx_i2c.h
|
|
@@ -0,0 +1,38 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * Copyright (C) 2010 Trusted Logic S.A.
|
|
+ * Copyright 2015,2019-2023 NXP
|
|
+ *
|
|
+ */
|
|
+
|
|
+#define PN544_MAGIC 0xE9
|
|
+
|
|
+/*
|
|
+ * PN544 power control via ioctl
|
|
+ * PN544_SET_PWR(0): power off
|
|
+ * PN544_SET_PWR(1): power on
|
|
+ * PN544_SET_PWR(2): reset and power on with firmware download enabled
|
|
+ */
|
|
+
|
|
+#define PWR_OFF 0
|
|
+#define PWR_ON 1
|
|
+#define PWR_FW 2
|
|
+
|
|
+#define CLK_OFF 0
|
|
+#define CLK_ON 1
|
|
+
|
|
+#define GPIO_UNUSED -1
|
|
+
|
|
+#define PN544_SET_PWR _IOW(PN544_MAGIC, 0x01, unsigned int)
|
|
+#define PN54X_CLK_REQ _IOW(PN544_MAGIC, 0x02, unsigned int)
|
|
+
|
|
+struct pn544_i2c_platform_data {
|
|
+ unsigned int irq_gpio;
|
|
+ unsigned int ven_gpio;
|
|
+ unsigned int firm_gpio;
|
|
+ unsigned int clkreq_gpio;
|
|
+ struct regulator *pvdd_reg;
|
|
+ struct regulator *vbat_reg;
|
|
+ struct regulator *pmuvcc_reg;
|
|
+ struct regulator *sevdd_reg;
|
|
+};
|
|
diff --git a/drivers/nfc/pn5xx/sample_devicetree.txt b/drivers/nfc/pn5xx/sample_devicetree.txt
|
|
new file mode 100644
|
|
index 000000000000..0e81959052fc
|
|
--- /dev/null
|
|
+++ b/drivers/nfc/pn5xx/sample_devicetree.txt
|
|
@@ -0,0 +1,17 @@
|
|
+Example:
|
|
+
|
|
+&i2c{
|
|
+
|
|
+ status = "okay";
|
|
+
|
|
+ pn547: pn547@29 {
|
|
+
|
|
+ compatible = "nxp,pn547";
|
|
+
|
|
+ reg = <0x29>;
|
|
+ clock-frequency = <400000>;
|
|
+
|
|
+ interrupt-gpios = <&gpio2 17 0>;
|
|
+ enable-gpios = <&gpio4 21 0>;
|
|
+ };
|
|
+};
|
|
diff --git a/drivers/pmdomain/imx/scu-pd.c b/drivers/pmdomain/imx/scu-pd.c
|
|
index 38f3cdd21042..97d1a537917a 100644
|
|
--- a/drivers/pmdomain/imx/scu-pd.c
|
|
+++ b/drivers/pmdomain/imx/scu-pd.c
|
|
@@ -171,6 +171,7 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
|
|
{ "esai1", IMX_SC_R_ESAI_1, 1, false, 0 },
|
|
{ "spdif0", IMX_SC_R_SPDIF_0, 1, false, 0 },
|
|
{ "spdif1", IMX_SC_R_SPDIF_1, 1, false, 0 },
|
|
+ { "gpt", IMX_SC_R_GPT_5, 4, true, 5 },
|
|
{ "sai", IMX_SC_R_SAI_0, 3, true, 0 },
|
|
{ "sai3", IMX_SC_R_SAI_3, 1, false, 0 },
|
|
{ "sai4", IMX_SC_R_SAI_4, 1, false, 0 },
|
|
diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c
|
|
index 91cc6ffa0095..f32e633a3f65 100644
|
|
--- a/drivers/ptp/ptp_chardev.c
|
|
+++ b/drivers/ptp/ptp_chardev.c
|
|
@@ -121,6 +121,7 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
|
|
struct ptp_clock_time *pct;
|
|
unsigned int i, pin_index;
|
|
struct ptp_pin_desc pd;
|
|
+ struct ptp_convert_timestamps convert_ts;
|
|
struct timespec64 ts;
|
|
int enable, err = 0;
|
|
|
|
@@ -422,6 +423,28 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
|
|
mutex_unlock(&ptp->pincfg_mux);
|
|
break;
|
|
|
|
+ case PTP_CONVERT_TIMESTAMPS:
|
|
+ if (copy_from_user(&convert_ts, (void __user *)arg, sizeof(convert_ts))) {
|
|
+ err = -EFAULT;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (convert_ts.n_ts > PTP_MAX_CONVERT_TS_NUM) {
|
|
+ err = -EINVAL;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (ptp->is_virtual_clock)
|
|
+ err = ptp_vclock_convert_timestamps(ptp, convert_ts.src_ts, convert_ts.n_ts,
|
|
+ convert_ts.dst_phc_index, convert_ts.dst_ts);
|
|
+ else
|
|
+ err = ptp_clock_convert_timestamps(ptp, convert_ts.src_ts, convert_ts.n_ts,
|
|
+ convert_ts.dst_phc_index, convert_ts.dst_ts);
|
|
+
|
|
+ if (!err && copy_to_user((void __user *)arg, &convert_ts, sizeof(convert_ts)))
|
|
+ err = -EFAULT;
|
|
+
|
|
+ break;
|
|
default:
|
|
err = -ENOTTY;
|
|
break;
|
|
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
|
|
index 9a50bfb56453..b857cfca55b7 100644
|
|
--- a/drivers/ptp/ptp_clock.c
|
|
+++ b/drivers/ptp/ptp_clock.c
|
|
@@ -201,6 +201,25 @@ static void ptp_aux_kworker(struct kthread_work *work)
|
|
kthread_queue_delayed_work(ptp->kworker, &ptp->aux_work, delay);
|
|
}
|
|
|
|
+/* Convert from physical to virtual time domains. */
|
|
+int ptp_clock_convert_timestamps(struct ptp_clock *ptp,
|
|
+ struct ptp_clock_time *src_ts, unsigned int n_ts, int dst_phc_index,
|
|
+ struct ptp_clock_time *dst_ts)
|
|
+{
|
|
+ int rc;
|
|
+
|
|
+ /* If the destination time domain is the same as the source, quick return. */
|
|
+ if (ptp->index == dst_phc_index) {
|
|
+ memcpy(dst_ts, src_ts, n_ts * sizeof(struct ptp_clock_time));
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ rc = ptp_vclock_convert_from_hw_timestamps(ptp, src_ts, n_ts,
|
|
+ dst_phc_index, dst_ts);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
/* public interface */
|
|
|
|
struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
|
|
diff --git a/drivers/ptp/ptp_private.h b/drivers/ptp/ptp_private.h
|
|
index b8d4f61f14be..03136915423f 100644
|
|
--- a/drivers/ptp/ptp_private.h
|
|
+++ b/drivers/ptp/ptp_private.h
|
|
@@ -141,6 +141,24 @@ extern const struct attribute_group *ptp_groups[];
|
|
int ptp_populate_pin_groups(struct ptp_clock *ptp);
|
|
void ptp_cleanup_pin_groups(struct ptp_clock *ptp);
|
|
|
|
+/*
|
|
+ * see ptp_vclock.c
|
|
+ */
|
|
+
|
|
struct ptp_vclock *ptp_vclock_register(struct ptp_clock *pclock);
|
|
void ptp_vclock_unregister(struct ptp_vclock *vclock);
|
|
+int ptp_vclock_convert_from_hw_timestamps(struct ptp_clock *ptp,
|
|
+ struct ptp_clock_time *src_ts, unsigned int n_ts, int dst_phc_index,
|
|
+ struct ptp_clock_time *dst_ts);
|
|
+int ptp_vclock_convert_timestamps(struct ptp_clock *ptp, struct ptp_clock_time *src_ts,
|
|
+ unsigned int n_ts, int dst_phc_index,
|
|
+ struct ptp_clock_time *dst_ts);
|
|
+
|
|
+/*
|
|
+ * see ptp_clock.c
|
|
+ */
|
|
+
|
|
+int ptp_clock_convert_timestamps(struct ptp_clock *ptp,
|
|
+ struct ptp_clock_time *src_ts, unsigned int n_ts, int dst_phc_index,
|
|
+ struct ptp_clock_time *dst_ts);
|
|
#endif
|
|
diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c
|
|
index aefc06ae5d09..dd762d776de8 100644
|
|
--- a/drivers/ptp/ptp_sysfs.c
|
|
+++ b/drivers/ptp/ptp_sysfs.c
|
|
@@ -220,14 +220,21 @@ static ssize_t n_vclocks_store(struct device *dev,
|
|
|
|
/* Need to create more vclocks */
|
|
if (num > ptp->n_vclocks) {
|
|
- for (i = 0; i < num - ptp->n_vclocks; i++) {
|
|
+ unsigned int nb_vclocks = num - ptp->n_vclocks;
|
|
+
|
|
+ for (i = 0; i < nb_vclocks; i++) {
|
|
vclock = ptp_vclock_register(ptp);
|
|
- if (!vclock)
|
|
+ if (!vclock) {
|
|
+ dev_err(dev, "failed to create more than %u (out of %u) virtual clocks for ptp%d\n",
|
|
+ i, nb_vclocks, ptp->index);
|
|
goto out;
|
|
+ }
|
|
|
|
- *(ptp->vclock_index + ptp->n_vclocks + i) =
|
|
+ *(ptp->vclock_index + ptp->n_vclocks) =
|
|
vclock->clock->index;
|
|
|
|
+ ptp->n_vclocks++;
|
|
+
|
|
dev_info(dev, "new virtual clock ptp%d\n",
|
|
vclock->clock->index);
|
|
}
|
|
@@ -241,6 +248,8 @@ static ssize_t n_vclocks_store(struct device *dev,
|
|
|
|
for (i = 1; i <= ptp->n_vclocks - num; i++)
|
|
*(ptp->vclock_index + ptp->n_vclocks - i) = -1;
|
|
+
|
|
+ ptp->n_vclocks = num;
|
|
}
|
|
|
|
/* Need to inform about changed physical clock behavior */
|
|
@@ -251,7 +260,6 @@ static ssize_t n_vclocks_store(struct device *dev,
|
|
dev_info(dev, "guarantee physical clock free running\n");
|
|
}
|
|
|
|
- ptp->n_vclocks = num;
|
|
mutex_unlock(&ptp->n_vclocks_mux);
|
|
|
|
return count;
|
|
diff --git a/drivers/ptp/ptp_vclock.c b/drivers/ptp/ptp_vclock.c
|
|
index dcf752c9e045..bb26d2535218 100644
|
|
--- a/drivers/ptp/ptp_vclock.c
|
|
+++ b/drivers/ptp/ptp_vclock.c
|
|
@@ -40,6 +40,24 @@ static void ptp_vclock_hash_del(struct ptp_vclock *vclock)
|
|
synchronize_rcu();
|
|
}
|
|
|
|
+/* This function and its return value (the vclock pointer) must be used
|
|
+ * inside the same RCU read critical section
|
|
+ */
|
|
+static struct ptp_vclock *ptp_vclock_lookup(int vclock_index)
|
|
+{
|
|
+ unsigned int hash = vclock_index % HASH_SIZE(vclock_hash);
|
|
+ struct ptp_vclock *vclock;
|
|
+
|
|
+ hlist_for_each_entry_rcu(vclock, &vclock_hash[hash], vclock_hash_node) {
|
|
+ if (vclock->clock->index != vclock_index)
|
|
+ continue;
|
|
+
|
|
+ return vclock;
|
|
+ }
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
static int ptp_vclock_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
|
|
{
|
|
struct ptp_vclock *vclock = info_to_vclock(ptp);
|
|
@@ -154,6 +172,182 @@ static long ptp_vclock_refresh(struct ptp_clock_info *ptp)
|
|
return PTP_VCLOCK_REFRESH_INTERVAL;
|
|
}
|
|
|
|
+/* Convert from virtual clock to physical time domain */
|
|
+static u64 ptp_vclock_to_hw_time(const struct timecounter *tc, u64 nsec)
|
|
+{
|
|
+ u64 ns_hw = tc->cycle_last;
|
|
+ u64 delta;
|
|
+
|
|
+ /* TODO implement a less costly conversion using a shift/mult rather
|
|
+ * than an integer division ?
|
|
+ */
|
|
+ if (nsec > tc->nsec) {
|
|
+ delta = nsec - tc->nsec;
|
|
+ delta <<= tc->cc->shift;
|
|
+ ns_hw += div_u64(delta, tc->cc->mult);
|
|
+ } else {
|
|
+ delta = tc->nsec - nsec;
|
|
+ delta <<= tc->cc->shift;
|
|
+ ns_hw -= div_u64(delta, tc->cc->mult);
|
|
+ }
|
|
+
|
|
+ return ns_hw;
|
|
+}
|
|
+
|
|
+static inline s64 ptp_clock_time_to_ns(const struct ptp_clock_time *ptp_time)
|
|
+{
|
|
+ struct timespec64 ts;
|
|
+
|
|
+ ts.tv_sec = ptp_time->sec;
|
|
+ ts.tv_nsec = ptp_time->nsec;
|
|
+
|
|
+ return timespec64_to_ns(&ts);
|
|
+}
|
|
+
|
|
+static inline struct ptp_clock_time ns_to_ptp_clock_time(s64 nsec)
|
|
+{
|
|
+ struct ptp_clock_time ptp_time = { 0 };
|
|
+ struct timespec64 ts;
|
|
+
|
|
+ ts = ns_to_timespec64(nsec);
|
|
+
|
|
+ ptp_time.sec = ts.tv_sec;
|
|
+ ptp_time.nsec = ts.tv_nsec;
|
|
+
|
|
+ return ptp_time;
|
|
+}
|
|
+
|
|
+/* This function converts from a virtual domain to a destination
|
|
+ * clock domain (either virtual or physical)
|
|
+ */
|
|
+int ptp_vclock_convert_timestamps(struct ptp_clock *ptp, struct ptp_clock_time *src_ts,
|
|
+ unsigned int n_ts, int dst_phc_index,
|
|
+ struct ptp_clock_time *dst_ts)
|
|
+{
|
|
+ unsigned int hash = dst_phc_index % HASH_SIZE(vclock_hash);
|
|
+ struct ptp_vclock *vclock = info_to_vclock(ptp->info);
|
|
+ struct ptp_vclock *vclock_dst;
|
|
+ int i, rc = 0;
|
|
+ u64 dst_ns;
|
|
+
|
|
+ /* The destination clock domain is the same as the source, early exit. */
|
|
+ if (dst_phc_index == vclock->clock->index) {
|
|
+ memcpy(dst_ts, src_ts, n_ts * sizeof(struct ptp_clock_time));
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ rcu_read_lock();
|
|
+
|
|
+ vclock_dst = ptp_vclock_lookup(dst_phc_index);
|
|
+
|
|
+ if (vclock_dst) {
|
|
+ /* Check that both virtual clocks share the same physical parent. */
|
|
+ if (vclock_dst->pclock != vclock->pclock) {
|
|
+ rc = -EINVAL;
|
|
+ goto out_unlock_rcu;
|
|
+ }
|
|
+
|
|
+ if (mutex_lock_interruptible(&vclock->lock)) {
|
|
+ rc = -ERESTARTSYS;
|
|
+ goto out_unlock_rcu;
|
|
+ }
|
|
+
|
|
+ if (mutex_lock_interruptible(&vclock_dst->lock)) {
|
|
+ mutex_unlock(&vclock->lock);
|
|
+ rc = -ERESTARTSYS;
|
|
+ goto out_unlock_rcu;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < n_ts; i++) {
|
|
+ /* Convert from source virtual to physical time domain. */
|
|
+ dst_ns = ptp_vclock_to_hw_time(&vclock->tc,
|
|
+ ptp_clock_time_to_ns(src_ts + i));
|
|
+ /* Convert from physical to destination virtual time domain. */
|
|
+ dst_ns = timecounter_cyc2time(&vclock_dst->tc, dst_ns);
|
|
+
|
|
+ *(dst_ts + i) = ns_to_ptp_clock_time(dst_ns);
|
|
+ }
|
|
+
|
|
+ mutex_unlock(&vclock_dst->lock);
|
|
+ mutex_unlock(&vclock->lock);
|
|
+ } else {
|
|
+ /* Check that the destination physical clock is the parent of the source
|
|
+ * virtual clock.
|
|
+ */
|
|
+ if (vclock->pclock->index != dst_phc_index) {
|
|
+ rc = -EINVAL;
|
|
+ goto out_unlock_rcu;
|
|
+ }
|
|
+
|
|
+ if (mutex_lock_interruptible(&vclock->lock)) {
|
|
+ rc = -EINTR;
|
|
+ goto out_unlock_rcu;
|
|
+ }
|
|
+
|
|
+ /* Convert from virtual to physical time domain . */
|
|
+ for (i = 0; i < n_ts; i++) {
|
|
+ dst_ns = ptp_vclock_to_hw_time(&vclock->tc,
|
|
+ ptp_clock_time_to_ns(src_ts + i));
|
|
+ *(dst_ts + i) = ns_to_ptp_clock_time(dst_ns);
|
|
+ }
|
|
+
|
|
+ mutex_unlock(&vclock->lock);
|
|
+
|
|
+ }
|
|
+
|
|
+out_unlock_rcu:
|
|
+ rcu_read_unlock();
|
|
+
|
|
+out:
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/* Convert from physical to virtual time domain. */
|
|
+int ptp_vclock_convert_from_hw_timestamps(struct ptp_clock *ptp, struct ptp_clock_time *src_ts,
|
|
+ unsigned int n_ts, int dst_vclock_index,
|
|
+ struct ptp_clock_time *dst_ts)
|
|
+{
|
|
+ unsigned int hash = dst_vclock_index % HASH_SIZE(vclock_hash);
|
|
+ struct ptp_vclock *vclock;
|
|
+ int i, rc = 0;
|
|
+ u64 dst_ns;
|
|
+
|
|
+ rcu_read_lock();
|
|
+
|
|
+ vclock = ptp_vclock_lookup(dst_vclock_index);
|
|
+
|
|
+ /* Check that dst_vclock_index point to a virtual clock. */
|
|
+ if (!vclock) {
|
|
+ rc = -EINVAL;
|
|
+ goto out_unlock_rcu;
|
|
+ }
|
|
+
|
|
+ /* Check that the source physical clock is the parent of the
|
|
+ * destination virtual clock.
|
|
+ */
|
|
+ if (vclock->pclock != ptp) {
|
|
+ rc = -EINVAL;
|
|
+ goto out_unlock_rcu;
|
|
+ }
|
|
+
|
|
+ if (mutex_lock_interruptible(&vclock->lock)) {
|
|
+ rc = -ERESTARTSYS;
|
|
+ goto out_unlock_rcu;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < n_ts; i++) {
|
|
+ dst_ns = timecounter_cyc2time(&vclock->tc, ptp_clock_time_to_ns(src_ts + i));
|
|
+ *(dst_ts + i) = ns_to_ptp_clock_time(dst_ns);
|
|
+ }
|
|
+
|
|
+ mutex_unlock(&vclock->lock);
|
|
+
|
|
+out_unlock_rcu:
|
|
+ rcu_read_unlock();
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
static const struct ptp_clock_info ptp_vclock_info = {
|
|
.owner = THIS_MODULE,
|
|
.name = "ptp virtual clock",
|
|
@@ -276,17 +470,15 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index)
|
|
|
|
rcu_read_lock();
|
|
|
|
- hlist_for_each_entry_rcu(vclock, &vclock_hash[hash], vclock_hash_node) {
|
|
- if (vclock->clock->index != vclock_index)
|
|
- continue;
|
|
-
|
|
+ vclock = ptp_vclock_lookup(vclock_index);
|
|
+ if (vclock) {
|
|
if (mutex_lock_interruptible(&vclock->lock))
|
|
- break;
|
|
+ goto out_unlock_rcu;
|
|
vclock_ns = timecounter_cyc2time(&vclock->tc, ns);
|
|
mutex_unlock(&vclock->lock);
|
|
- break;
|
|
}
|
|
|
|
+out_unlock_rcu:
|
|
rcu_read_unlock();
|
|
|
|
return ns_to_ktime(vclock_ns);
|
|
diff --git a/drivers/remoteproc/imx_rproc.c b/drivers/remoteproc/imx_rproc.c
|
|
index 5e15dd127bde..449ff92129cf 100644
|
|
--- a/drivers/remoteproc/imx_rproc.c
|
|
+++ b/drivers/remoteproc/imx_rproc.c
|
|
@@ -6,7 +6,9 @@
|
|
#include <dt-bindings/firmware/imx/rsrc.h>
|
|
#include <linux/arm-smccc.h>
|
|
#include <linux/clk.h>
|
|
+#include <linux/cpu.h>
|
|
#include <linux/delay.h>
|
|
+#include <linux/dma-map-ops.h>
|
|
#include <linux/err.h>
|
|
#include <linux/firmware.h>
|
|
#include <linux/firmware/imx/sci.h>
|
|
@@ -20,11 +22,16 @@
|
|
#include <linux/of_reserved_mem.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/pm_domain.h>
|
|
+#include <linux/psci.h>
|
|
#include <linux/reboot.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/remoteproc.h>
|
|
#include <linux/workqueue.h>
|
|
|
|
+#include <uapi/linux/psci.h>
|
|
+
|
|
+#include <asm/smp_plat.h>
|
|
+
|
|
#include "remoteproc_elf_helpers.h"
|
|
#include "remoteproc_internal.h"
|
|
|
|
@@ -73,6 +80,8 @@
|
|
#define IMX_SIP_RPROC_STARTED 0x01
|
|
#define IMX_SIP_RPROC_STOP 0x02
|
|
|
|
+#define IMX_SIP_CPU_OFF 0xC200000D
|
|
+
|
|
#define IMX_SC_IRQ_GROUP_REBOOTED 5
|
|
|
|
/**
|
|
@@ -125,6 +134,8 @@ struct imx_rproc {
|
|
struct device_link **pd_dev_link;
|
|
u32 startup_delay;
|
|
struct sys_off_data data;
|
|
+ cpumask_t cpus;
|
|
+ cpumask_t offlined_cpus;
|
|
};
|
|
|
|
static const struct imx_rproc_att imx_rproc_att_imx95_m7[] = {
|
|
@@ -157,6 +168,9 @@ static const struct imx_rproc_att imx_rproc_att_imx93[] = {
|
|
{ 0x80000000, 0x80000000, 0x10000000, 0 },
|
|
{ 0x90000000, 0x80000000, 0x10000000, 0 },
|
|
|
|
+ { 0xa0000000, 0xa0000000, 0x10000000, 0 },
|
|
+ { 0xb0000000, 0xa0000000, 0x10000000, 0 },
|
|
+
|
|
{ 0xC0000000, 0xC0000000, 0x10000000, 0 },
|
|
{ 0xD0000000, 0xC0000000, 0x10000000, 0 },
|
|
};
|
|
@@ -384,12 +398,102 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx93 = {
|
|
.method = IMX_RPROC_SMC,
|
|
};
|
|
|
|
+static const struct imx_rproc_dcfg imx_rproc_cfg_psci = {
|
|
+ .att = NULL,
|
|
+ .att_size = 0,
|
|
+ .method = IMX_RPROC_PSCI,
|
|
+};
|
|
+
|
|
static const struct imx_rproc_dcfg imx_rproc_cfg_imx95_m7 = {
|
|
.att = imx_rproc_att_imx95_m7,
|
|
.att_size = ARRAY_SIZE(imx_rproc_att_imx95_m7),
|
|
.method = IMX_RPROC_SMC,
|
|
};
|
|
|
|
+static int imx_rproc_psci_start(struct rproc *rproc)
|
|
+{
|
|
+ struct imx_rproc *priv = rproc->priv;
|
|
+ struct device *dev = priv->dev;
|
|
+ unsigned int cpu;
|
|
+ int ret;
|
|
+
|
|
+ if (cpumask_empty(&priv->cpus)) {
|
|
+ dev_err(dev, "No CPU Core assigned!\n");
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ for_each_cpu(cpu, &priv->cpus) {
|
|
+ if (cpu_online(cpu)) {
|
|
+ ret = remove_cpu(cpu);
|
|
+ if (ret)
|
|
+ goto err;
|
|
+ cpumask_set_cpu(cpu, &priv->offlined_cpus);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ cpu = cpumask_first(&priv->cpus);
|
|
+ ret = psci_ops.cpu_on(cpu_logical_map(cpu), rproc->bootaddr);
|
|
+ if (ret) {
|
|
+ dev_err(dev, "Boot failed on CPU Core %d\n", cpu);
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err:
|
|
+ for_each_cpu(cpu, &priv->cpus) {
|
|
+ if (!cpu_online(cpu) && add_cpu(cpu) == 0)
|
|
+ cpumask_clear_cpu(cpu, &priv->offlined_cpus);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int imx_rproc_psci_stop(struct rproc *rproc)
|
|
+{
|
|
+ struct imx_rproc *priv = rproc->priv;
|
|
+ struct device *dev = priv->dev;
|
|
+ struct arm_smccc_res res;
|
|
+ unsigned int cpu;
|
|
+ unsigned long start, end;
|
|
+ int err;
|
|
+
|
|
+ for_each_cpu(cpu, &priv->cpus) {
|
|
+ /* Check CPU status */
|
|
+ err = psci_ops.affinity_info(cpu_logical_map(cpu), 0);
|
|
+ if (err == PSCI_0_2_AFFINITY_LEVEL_OFF)
|
|
+ continue;
|
|
+
|
|
+ /* Bring CPU to be off */
|
|
+ arm_smccc_smc(IMX_SIP_CPU_OFF, cpu, 0,
|
|
+ 0, 0, 0, 0, 0, &res);
|
|
+ start = jiffies;
|
|
+ end = start + msecs_to_jiffies(100);
|
|
+ do {
|
|
+ err = psci_ops.affinity_info(cpu_logical_map(cpu), 0);
|
|
+ if (err == PSCI_0_2_AFFINITY_LEVEL_OFF) {
|
|
+ pr_info("CPU%d is killed (polled %d ms)\n", cpu,
|
|
+ jiffies_to_msecs(jiffies - start));
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ usleep_range(100, 1000);
|
|
+ } while (time_before(jiffies, end));
|
|
+ }
|
|
+
|
|
+ /* Return back freed CPU Core to Linux kernel */
|
|
+ for_each_cpu(cpu, &priv->cpus) {
|
|
+ if (cpumask_test_cpu(cpu, &priv->offlined_cpus)) {
|
|
+ if (add_cpu(cpu) != 0)
|
|
+ dev_err(dev, "Failed to bring CPU %d back to be online", cpu);
|
|
+ cpumask_clear_cpu(cpu, &priv->offlined_cpus);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
static int imx_rproc_start(struct rproc *rproc)
|
|
{
|
|
struct imx_rproc *priv = rproc->priv;
|
|
@@ -424,6 +528,9 @@ static int imx_rproc_start(struct rproc *rproc)
|
|
case IMX_RPROC_SCU_API:
|
|
ret = imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, true, priv->entry);
|
|
break;
|
|
+ case IMX_RPROC_PSCI:
|
|
+ ret = imx_rproc_psci_start(rproc);
|
|
+ break;
|
|
default:
|
|
return -EOPNOTSUPP;
|
|
}
|
|
@@ -470,6 +577,9 @@ static int imx_rproc_stop(struct rproc *rproc)
|
|
case IMX_RPROC_SCU_API:
|
|
ret = imx_sc_pm_cpu_start(priv->ipc_handle, priv->rsrc_id, false, priv->entry);
|
|
break;
|
|
+ case IMX_RPROC_PSCI:
|
|
+ ret = imx_rproc_psci_stop(rproc);
|
|
+ break;
|
|
default:
|
|
return -EOPNOTSUPP;
|
|
}
|
|
@@ -488,6 +598,12 @@ static int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da,
|
|
const struct imx_rproc_dcfg *dcfg = priv->dcfg;
|
|
int i;
|
|
|
|
+ /* No need to translate for Cortex-A Core */
|
|
+ if (dcfg->method == IMX_RPROC_PSCI) {
|
|
+ *sys = da;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
/* parse address translation table */
|
|
for (i = 0; i < dcfg->att_size; i++) {
|
|
const struct imx_rproc_att *att = &dcfg->att[i];
|
|
@@ -558,7 +674,13 @@ static int imx_rproc_mem_alloc(struct rproc *rproc,
|
|
void *va;
|
|
|
|
dev_dbg(dev, "map memory: %p+%zx\n", &mem->dma, mem->len);
|
|
- va = ioremap_wc(mem->dma, mem->len);
|
|
+ if (dev_is_dma_coherent(dev) &&
|
|
+ !strncmp(mem->name, "vdev0vring", strlen("vdev0vring"))) {
|
|
+ va = ioremap_cache(mem->dma, mem->len);
|
|
+ } else {
|
|
+ va = ioremap_wc(mem->dma, mem->len);
|
|
+ }
|
|
+
|
|
if (IS_ERR_OR_NULL(va)) {
|
|
dev_err(dev, "Unable to map memory region: %p+%zx\n",
|
|
&mem->dma, mem->len);
|
|
@@ -588,19 +710,15 @@ static int imx_rproc_prepare(struct rproc *rproc)
|
|
struct rproc_mem_entry *mem;
|
|
struct reserved_mem *rmem;
|
|
u32 da;
|
|
+ int index = 0;
|
|
|
|
/* Register associated reserved memory regions */
|
|
of_phandle_iterator_init(&it, np, "memory-region", NULL, 0);
|
|
while (of_phandle_iterator_next(&it) == 0) {
|
|
- /*
|
|
- * Ignore the first memory region which will be used vdev buffer.
|
|
- * No need to do extra handlings, rproc_add_virtio_dev will handle it.
|
|
- */
|
|
- if (!strcmp(it.node->name, "vdev0buffer"))
|
|
- continue;
|
|
-
|
|
- if (!strcmp(it.node->name, "rsc-table"))
|
|
+ if (!strcmp(it.node->name, "rsc-table")) {
|
|
+ index++;
|
|
continue;
|
|
+ }
|
|
|
|
rmem = of_reserved_mem_lookup(it.node);
|
|
if (!rmem) {
|
|
@@ -612,19 +730,28 @@ static int imx_rproc_prepare(struct rproc *rproc)
|
|
/* No need to translate pa to da, i.MX use same map */
|
|
da = rmem->base;
|
|
|
|
- /* Register memory region */
|
|
- mem = rproc_mem_entry_init(priv->dev, NULL, (dma_addr_t)rmem->base, rmem->size, da,
|
|
- imx_rproc_mem_alloc, imx_rproc_mem_release,
|
|
- it.node->name);
|
|
+ if (strcmp(it.node->name, "vdev0buffer")) {
|
|
+ /* Register memory region */
|
|
+ mem = rproc_mem_entry_init(priv->dev, NULL, (dma_addr_t)rmem->base,
|
|
+ rmem->size, da, imx_rproc_mem_alloc,
|
|
+ imx_rproc_mem_release, it.node->name);
|
|
|
|
- if (mem) {
|
|
- rproc_coredump_add_segment(rproc, da, rmem->size);
|
|
+ if (mem) {
|
|
+ rproc_coredump_add_segment(rproc, da, rmem->size);
|
|
+ }
|
|
} else {
|
|
+
|
|
+ /* Register reserved memory for vdev buffer alloc */
|
|
+ mem = rproc_of_resm_mem_entry_init(priv->dev, index, rmem->size,
|
|
+ rmem->base, it.node->name);
|
|
+ }
|
|
+
|
|
+ if (!mem) {
|
|
of_node_put(it.node);
|
|
return -ENOMEM;
|
|
}
|
|
-
|
|
rproc_add_carveout(rproc, mem);
|
|
+ index++;
|
|
}
|
|
|
|
return 0;
|
|
@@ -1046,6 +1173,25 @@ static int imx_rproc_detect_mode(struct imx_rproc *priv)
|
|
case IMX_RPROC_NONE:
|
|
priv->rproc->state = RPROC_DETACHED;
|
|
return 0;
|
|
+ case IMX_RPROC_PSCI:
|
|
+ unsigned int cpu;
|
|
+ int cpu_aff;
|
|
+
|
|
+ priv->rproc->state = RPROC_DETACHED;
|
|
+ for_each_cpu(cpu, &priv->cpus) {
|
|
+ cpu_aff = psci_ops.affinity_info(cpu_logical_map(cpu), 0);
|
|
+ if (cpu_aff == PSCI_0_2_AFFINITY_LEVEL_OFF) {
|
|
+ priv->rproc->state = RPROC_OFFLINE;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* in psci on state but not running Linux */
|
|
+ if (cpu_online(cpu)) {
|
|
+ priv->rproc->state = RPROC_OFFLINE;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
case IMX_RPROC_SMC:
|
|
arm_smccc_smc(IMX_SIP_RPROC, IMX_SIP_RPROC_STARTED, 0, 0, 0, 0, 0, 0, &res);
|
|
if (res.a0)
|
|
@@ -1210,10 +1356,12 @@ static int imx_rproc_probe(struct platform_device *pdev)
|
|
struct imx_rproc *priv;
|
|
struct rproc *rproc;
|
|
const struct imx_rproc_dcfg *dcfg;
|
|
+ unsigned int cpus;
|
|
+ unsigned long cpus_bits;
|
|
int ret;
|
|
|
|
- /* set some other name then imx */
|
|
- rproc = rproc_alloc(dev, "imx-rproc", &imx_rproc_ops,
|
|
+ /* set node name to be remote processor name */
|
|
+ rproc = rproc_alloc(dev, np->name, &imx_rproc_ops,
|
|
NULL, sizeof(*priv));
|
|
if (!rproc)
|
|
return -ENOMEM;
|
|
@@ -1249,6 +1397,17 @@ static int imx_rproc_probe(struct platform_device *pdev)
|
|
goto err_put_mbox;
|
|
}
|
|
|
|
+ /* Init priv->cpus before detect mode */
|
|
+ ret = of_property_read_u32(dev->of_node, "fsl,cpus-bits", &cpus);
|
|
+ if (ret) {
|
|
+ cpumask_clear(&priv->cpus);
|
|
+ } else {
|
|
+ cpus_bits = cpus;
|
|
+ bitmap_copy(cpumask_bits(&priv->cpus), &cpus_bits,
|
|
+ min((unsigned int)nr_cpumask_bits,
|
|
+ (unsigned int)sizeof(unsigned long)));
|
|
+ }
|
|
+
|
|
ret = imx_rproc_detect_mode(priv);
|
|
if (ret)
|
|
goto err_put_mbox;
|
|
@@ -1332,6 +1491,7 @@ static const struct of_device_id imx_rproc_of_match[] = {
|
|
{ .compatible = "fsl,imx8ulp-cm33", .data = &imx_rproc_cfg_imx8ulp },
|
|
{ .compatible = "fsl,imx93-cm33", .data = &imx_rproc_cfg_imx93 },
|
|
{ .compatible = "fsl,imx95-cm7", .data = &imx_rproc_cfg_imx95_m7 },
|
|
+ { .compatible = "fsl,imx-rproc-psci", .data = &imx_rproc_cfg_psci },
|
|
{},
|
|
};
|
|
MODULE_DEVICE_TABLE(of, imx_rproc_of_match);
|
|
diff --git a/drivers/remoteproc/imx_rproc.h b/drivers/remoteproc/imx_rproc.h
|
|
index 79a1b8956d14..052d43fe563a 100644
|
|
--- a/drivers/remoteproc/imx_rproc.h
|
|
+++ b/drivers/remoteproc/imx_rproc.h
|
|
@@ -24,6 +24,8 @@ enum imx_rproc_method {
|
|
IMX_RPROC_SMC,
|
|
/* Through System Control Unit API */
|
|
IMX_RPROC_SCU_API,
|
|
+ /* Through ARM64 PSCI */
|
|
+ IMX_RPROC_PSCI,
|
|
};
|
|
|
|
struct imx_rproc_dcfg {
|
|
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
|
|
index 695cce218e8c..3104f28d871d 100644
|
|
--- a/drivers/remoteproc/remoteproc_core.c
|
|
+++ b/drivers/remoteproc/remoteproc_core.c
|
|
@@ -38,6 +38,7 @@
|
|
#include <linux/virtio_ring.h>
|
|
#include <asm/byteorder.h>
|
|
#include <linux/platform_device.h>
|
|
+#include <linux/dma-map-ops.h>
|
|
|
|
#include "remoteproc_internal.h"
|
|
|
|
@@ -522,6 +523,9 @@ static int rproc_handle_vdev(struct rproc *rproc, void *ptr,
|
|
return PTR_ERR(pdev);
|
|
}
|
|
|
|
+ /* inherit parent's dma_coherent */
|
|
+ pdev->dev.dma_coherent = dev_is_dma_coherent(dev);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -1285,7 +1289,7 @@ static int rproc_start(struct rproc *rproc, const struct firmware *fw)
|
|
* that any subsequent changes will be applied to the loaded version.
|
|
*/
|
|
loaded_table = rproc_find_loaded_rsc_table(rproc, fw);
|
|
- if (loaded_table) {
|
|
+ if (loaded_table && rproc->cached_table) {
|
|
memcpy(loaded_table, rproc->cached_table, rproc->table_sz);
|
|
rproc->table_ptr = loaded_table;
|
|
}
|
|
@@ -2463,6 +2467,8 @@ struct rproc *rproc_alloc(struct device *dev, const char *name,
|
|
rproc->dev.type = &rproc_type;
|
|
rproc->dev.class = &rproc_class;
|
|
rproc->dev.driver_data = rproc;
|
|
+ /* inherit parent's dma_coherent */
|
|
+ rproc->dev.dma_coherent = dev_is_dma_coherent(dev);
|
|
idr_init(&rproc->notifyids);
|
|
|
|
rproc->name = kstrdup_const(name, GFP_KERNEL);
|
|
diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig
|
|
index afba55506632..968ddd1fac18 100644
|
|
--- a/drivers/rpmsg/Kconfig
|
|
+++ b/drivers/rpmsg/Kconfig
|
|
@@ -81,10 +81,17 @@ config RPMSG_VIRTIO
|
|
select RPMSG_NS
|
|
select VIRTIO
|
|
|
|
+config RPMSG_PERF
|
|
+ tristate "RPMSG performance test driver"
|
|
+ depends on RPMSG
|
|
+ default m
|
|
+ help
|
|
+ Say Y here to enable the RPMSG performance test driver.
|
|
+
|
|
config HAVE_IMX_RPMSG
|
|
bool "IMX RPMSG driver on the AMP SOCs"
|
|
default y
|
|
- depends on IMX_MBOX
|
|
+ depends on IMX_MBOX || GENERIC_SOFTWARE_MAILBOX
|
|
select RPMSG_VIRTIO
|
|
help
|
|
Say y here to enable support for the iMX Rpmsg Driver providing
|
|
@@ -118,4 +125,11 @@ config IMX_RPMSG_TTY
|
|
executed by the command "echo <string> > <accordingly node>", thus
|
|
remote M core would receive the string.
|
|
|
|
+config RPMSG_8M_BUF
|
|
+ bool "RPMSG 8M bytes buffer support"
|
|
+ default n
|
|
+ depends on HAVE_IMX_RPMSG
|
|
+ help
|
|
+ Say y here to enable support for 8M bytes Vring buffer for rpmsg.
|
|
+
|
|
endmenu
|
|
diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile
|
|
index 7c4ee52e92c4..f64fa4d0ada2 100644
|
|
--- a/drivers/rpmsg/Makefile
|
|
+++ b/drivers/rpmsg/Makefile
|
|
@@ -1,6 +1,7 @@
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
obj-$(CONFIG_RPMSG) += rpmsg_core.o
|
|
obj-$(CONFIG_RPMSG_CHAR) += rpmsg_char.o
|
|
+obj-$(CONFIG_RPMSG_PERF) += rpmsg_perf.o
|
|
obj-$(CONFIG_RPMSG_CTRL) += rpmsg_ctrl.o
|
|
obj-$(CONFIG_RPMSG_NS) += rpmsg_ns.o
|
|
obj-$(CONFIG_RPMSG_MTK_SCP) += mtk_rpmsg.o
|
|
diff --git a/drivers/rpmsg/imx_rpmsg.c b/drivers/rpmsg/imx_rpmsg.c
|
|
index 8d4ecd7360fd..b4277d5cfe37 100644
|
|
--- a/drivers/rpmsg/imx_rpmsg.c
|
|
+++ b/drivers/rpmsg/imx_rpmsg.c
|
|
@@ -1,6 +1,6 @@
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
- * Copyright 2019 NXP
|
|
+ * Copyright 2019,2023 NXP
|
|
*/
|
|
|
|
#include <linux/slab.h>
|
|
@@ -15,6 +15,7 @@
|
|
#include <linux/module.h>
|
|
#include <linux/notifier.h>
|
|
#include <linux/of_device.h>
|
|
+#include <linux/of_address.h>
|
|
#include <linux/of_reserved_mem.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/virtio_config.h>
|
|
@@ -163,8 +164,12 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
/* ioremap'ing normal memory, so we cast away sparse's complaints */
|
|
- rpvq->addr = (__force void *) ioremap(virdev->vring[index],
|
|
- RPMSG_RING_SIZE);
|
|
+ if (of_dma_is_coherent(dev->of_node))
|
|
+ rpvq->addr = (__force void *)ioremap_cache(virdev->vring[index],
|
|
+ RPMSG_RING_SIZE);
|
|
+ else
|
|
+ rpvq->addr = (__force void *)ioremap(virdev->vring[index],
|
|
+ RPMSG_RING_SIZE);
|
|
if (!rpvq->addr) {
|
|
err = -ENOMEM;
|
|
goto free_rpvq;
|
|
@@ -466,6 +471,13 @@ static int imx_rpmsg_rxdb_channel_init(struct imx_rpmsg_vproc *rpdev)
|
|
return ret;
|
|
}
|
|
|
|
+static int imx_rpmsg_rxdb_channel_deinit(struct imx_rpmsg_vproc *rpdev)
|
|
+{
|
|
+ mbox_free_channel(rpdev->rxdb_ch);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static void imx_rpmsg_rx_callback(struct mbox_client *c, void *msg)
|
|
{
|
|
int buf_space;
|
|
@@ -531,6 +543,14 @@ static int imx_rpmsg_xtr_channel_init(struct imx_rpmsg_vproc *rpdev)
|
|
return ret;
|
|
}
|
|
|
|
+static int imx_rpmsg_xtr_channel_deinit(struct imx_rpmsg_vproc *rpdev)
|
|
+{
|
|
+ mbox_free_channel(rpdev->tx_ch);
|
|
+ mbox_free_channel(rpdev->rx_ch);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static int imx_rpmsg_probe(struct platform_device *pdev)
|
|
{
|
|
int j, ret = 0;
|
|
@@ -653,6 +673,36 @@ static int imx_rpmsg_probe(struct platform_device *pdev)
|
|
return ret;
|
|
}
|
|
|
|
+static int imx_rpmsg_remove(struct platform_device *pdev)
|
|
+{
|
|
+ struct imx_rpmsg_vproc *rpdev = platform_get_drvdata(pdev);
|
|
+ struct device *dev = &pdev->dev;
|
|
+ int i;
|
|
+
|
|
+#ifdef CONFIG_IMX_SCU
|
|
+ if (rpdev->variant == IMX8QXP || rpdev->variant == IMX8QM) {
|
|
+ imx_scu_irq_unregister_notifier(&rpdev->proc_nb);
|
|
+ imx_scu_irq_group_enable(IMX_SC_IRQ_GROUP_REBOOTED,
|
|
+ BIT(rpdev->mub_partition), false);
|
|
+ }
|
|
+#endif
|
|
+ imx_rpmsg_rxdb_channel_deinit(rpdev);
|
|
+
|
|
+ for (i = 0; i < rpdev->vdev_nums; i++) {
|
|
+ unregister_virtio_device(&rpdev->ivdev[i]->vdev);
|
|
+ kfree(rpdev->ivdev[i]);
|
|
+ }
|
|
+
|
|
+ if (rpdev->flags & SPECIFIC_DMA_POOL)
|
|
+ of_reserved_mem_device_release(dev);
|
|
+
|
|
+ imx_rpmsg_xtr_channel_deinit(rpdev);
|
|
+
|
|
+ cancel_delayed_work_sync(&rpdev->rpmsg_work);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static struct platform_driver imx_rpmsg_driver = {
|
|
.driver = {
|
|
.owner = THIS_MODULE,
|
|
@@ -660,6 +710,7 @@ static struct platform_driver imx_rpmsg_driver = {
|
|
.of_match_table = imx_rpmsg_dt_ids,
|
|
},
|
|
.probe = imx_rpmsg_probe,
|
|
+ .remove = imx_rpmsg_remove,
|
|
};
|
|
|
|
static int __init imx_rpmsg_init(void)
|
|
diff --git a/drivers/rpmsg/imx_rpmsg_tty.c b/drivers/rpmsg/imx_rpmsg_tty.c
|
|
index aaf343fc1e54..431a33afc0ad 100644
|
|
--- a/drivers/rpmsg/imx_rpmsg_tty.c
|
|
+++ b/drivers/rpmsg/imx_rpmsg_tty.c
|
|
@@ -1,6 +1,6 @@
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
- * Copyright 2019 NXP
|
|
+ * Copyright 2019,2023 NXP
|
|
*/
|
|
|
|
#include <linux/slab.h>
|
|
@@ -13,8 +13,24 @@
|
|
#include <linux/tty_flip.h>
|
|
#include <linux/virtio.h>
|
|
|
|
+#ifdef CONFIG_RPMSG_8M_BUF
|
|
+struct rpmsg_hdr {
|
|
+ __rpmsg32 src;
|
|
+ __rpmsg32 dst;
|
|
+ __rpmsg32 reserved;
|
|
+ __rpmsg16 len;
|
|
+ __rpmsg16 flags;
|
|
+ u8 data[];
|
|
+} __packed;
|
|
+
|
|
+#define MAX_RPMSG_BUF_SIZE (512 * 2)
|
|
+/* this needs to be less then (RPMSG_BUF_SIZE - sizeof(struct rpmsg_hdr)) */
|
|
+#define RPMSG_MAX_SIZE (MAX_RPMSG_BUF_SIZE - sizeof(struct rpmsg_hdr))
|
|
+#else
|
|
/* this needs to be less then (RPMSG_BUF_SIZE - sizeof(struct rpmsg_hdr)) */
|
|
#define RPMSG_MAX_SIZE 256
|
|
+#endif
|
|
+
|
|
#define MSG "hello world!"
|
|
|
|
/*
|
|
diff --git a/drivers/rpmsg/rpmsg_perf.c b/drivers/rpmsg/rpmsg_perf.c
|
|
new file mode 100644
|
|
index 000000000000..f58b15b2ea8d
|
|
--- /dev/null
|
|
+++ b/drivers/rpmsg/rpmsg_perf.c
|
|
@@ -0,0 +1,545 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
+
|
|
+#include <linux/cdev.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/device.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/idr.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/ktime.h>
|
|
+#include <linux/kthread.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/rpmsg.h>
|
|
+#include <linux/slab.h>
|
|
+#include <uapi/linux/rpmsg.h>
|
|
+
|
|
+#include "rpmsg_internal.h"
|
|
+
|
|
+#define RPMSG_PERF_AS_SENDER_IOCTL _IO(0xb5, 0x5)
|
|
+#define RPMSG_PERF_AS_RECEIVER_IOCTL _IO(0xb5, 0x6)
|
|
+#define RPMSG_PERF_AS_RECEIVER_END_ACK_IOCTL _IO(0xb5, 0x7)
|
|
+#define RPMSG_PERF_GET_RUNNING_STA_IOCTL _IO(0xb5, 0x8)
|
|
+
|
|
+#define RPMSG_DEV_MAX (MINORMASK + 1)
|
|
+
|
|
+static dev_t rpmsg_major;
|
|
+
|
|
+static DEFINE_IDA(rpmsg_perf_minor_ida);
|
|
+
|
|
+#define dev_to_eptdev(dev) container_of(dev, struct rpmsg_eptdev, dev)
|
|
+#define cdev_to_eptdev(i_cdev) container_of(i_cdev, struct rpmsg_eptdev, cdev)
|
|
+
|
|
+struct packet_header {
|
|
+ uint32_t preamble;
|
|
+ bool no_copy;
|
|
+ uint32_t packet_size;
|
|
+ uint32_t packet_cnt;
|
|
+ uint32_t test_time; /* unit: second */
|
|
+};
|
|
+
|
|
+enum {
|
|
+ RPMSG_PERF_PREAMBLE_SENDER_START = 0xBECAACEA,
|
|
+ RPMSG_PERF_PREAMBLE_SENDER_END = 0xBECAACEB,
|
|
+ RPMSG_PERF_PREAMBLE_SENDER_END_ACK = 0xBECAACEC,
|
|
+ RPMSG_PERF_PREAMBLE_RECEIVER_START = 0xBECAACED,
|
|
+ RPMSG_PERF_PREAMBLE_RECEIVER_END = 0xBECAACEE,
|
|
+ RPMSG_PERF_PREAMBLE_RECEIVER_END_ACK = 0xBECAACEF,
|
|
+};
|
|
+
|
|
+enum dev_state {
|
|
+ RPMSG_DEV_IDLE,
|
|
+ RPMSG_DEV_SENDING,
|
|
+ RPMSG_DEV_RECEIVING,
|
|
+};
|
|
+
|
|
+struct test_statistic {
|
|
+ uint32_t recv_packet_cnt;
|
|
+ uint32_t send_packet_cnt;
|
|
+ uint32_t packet_size;
|
|
+ uint32_t test_time;
|
|
+};
|
|
+
|
|
+/**
|
|
+ * struct rpmsg_eptdev - endpoint device context
|
|
+ * @dev: endpoint device
|
|
+ * @cdev: cdev for the endpoint device
|
|
+ * @rpdev: underlaying rpmsg device
|
|
+ * @chinfo: info used to open the endpoint
|
|
+ * @ept_lock: synchronization of @ept modifications
|
|
+ * @ept: rpmsg endpoint reference, when open
|
|
+ * @default_ept: set to channel default endpoint if the default endpoint should be re-used
|
|
+ * on device open to prevent endpoint address update.
|
|
+ */
|
|
+struct rpmsg_eptdev {
|
|
+ struct device dev;
|
|
+ struct cdev cdev;
|
|
+
|
|
+ struct rpmsg_device *rpdev;
|
|
+ struct rpmsg_channel_info chinfo;
|
|
+
|
|
+ struct mutex ept_lock;
|
|
+ struct rpmsg_endpoint *ept;
|
|
+ struct rpmsg_endpoint *default_ept;
|
|
+
|
|
+ enum dev_state state;
|
|
+ struct test_statistic statistic;
|
|
+
|
|
+ struct packet_header param;
|
|
+};
|
|
+
|
|
+static int rpmsg_perf_ept_cb(struct rpmsg_device *rpdev, void *buf, int len,
|
|
+ void *priv, u32 addr)
|
|
+{
|
|
+ struct packet_header *hdr = (struct packet_header *)buf;
|
|
+ struct rpmsg_eptdev *eptdev = priv;
|
|
+ struct test_statistic *statistic = &eptdev->statistic;
|
|
+ uint32_t rate;
|
|
+
|
|
+ switch (hdr->preamble) {
|
|
+ case RPMSG_PERF_PREAMBLE_SENDER_END_ACK:
|
|
+ if (eptdev->state == RPMSG_DEV_SENDING) {
|
|
+ eptdev->state = RPMSG_DEV_IDLE;
|
|
+ rate = statistic->send_packet_cnt /
|
|
+ statistic->test_time / 1000;
|
|
+ pr_info("packet size: %u, sent packets: %u, time: %u s, rate: %u kpps\n",
|
|
+ statistic->packet_size,
|
|
+ statistic->send_packet_cnt,
|
|
+ statistic->test_time, rate);
|
|
+ statistic->packet_size = 0;
|
|
+ statistic->send_packet_cnt = 0;
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+ statistic->recv_packet_cnt++;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int rpmsg_perf_eptdev_open(struct inode *inode, struct file *filp)
|
|
+{
|
|
+ struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev);
|
|
+ struct rpmsg_endpoint *ept;
|
|
+ struct rpmsg_device *rpdev = eptdev->rpdev;
|
|
+ struct device *dev = &eptdev->dev;
|
|
+
|
|
+ mutex_lock(&eptdev->ept_lock);
|
|
+ if (eptdev->ept) {
|
|
+ mutex_unlock(&eptdev->ept_lock);
|
|
+ return -EBUSY;
|
|
+ }
|
|
+
|
|
+ get_device(dev);
|
|
+
|
|
+ /*
|
|
+ * If the default_ept is set, the rpmsg device default endpoint is used.
|
|
+ * Else a new endpoint is created on open that will be destroyed on release.
|
|
+ */
|
|
+ if (eptdev->default_ept)
|
|
+ ept = eptdev->default_ept;
|
|
+ else
|
|
+ ept = rpmsg_create_ept(rpdev, rpmsg_perf_ept_cb, eptdev, eptdev->chinfo);
|
|
+
|
|
+ if (!ept) {
|
|
+ dev_err(dev, "failed to open %s\n", eptdev->chinfo.name);
|
|
+ put_device(dev);
|
|
+ mutex_unlock(&eptdev->ept_lock);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ eptdev->ept = ept;
|
|
+ filp->private_data = eptdev;
|
|
+ mutex_unlock(&eptdev->ept_lock);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int rpmsg_perf_eptdev_release(struct inode *inode, struct file *filp)
|
|
+{
|
|
+ struct rpmsg_eptdev *eptdev = cdev_to_eptdev(inode->i_cdev);
|
|
+ struct device *dev = &eptdev->dev;
|
|
+
|
|
+ /* Close the endpoint, if it's not already destroyed by the parent */
|
|
+ mutex_lock(&eptdev->ept_lock);
|
|
+ if (eptdev->ept) {
|
|
+ if (!eptdev->default_ept)
|
|
+ rpmsg_destroy_ept(eptdev->ept);
|
|
+ eptdev->ept = NULL;
|
|
+ }
|
|
+ mutex_unlock(&eptdev->ept_lock);
|
|
+
|
|
+ put_device(dev);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int rpmsg_perf_sender_thread(void *p)
|
|
+{
|
|
+ struct rpmsg_eptdev *eptdev = (struct rpmsg_eptdev *)p;
|
|
+ struct packet_header hdr = eptdev->param;
|
|
+ unsigned long timeout;
|
|
+ uint8_t *data;
|
|
+ uint32_t packet_len;
|
|
+ int ret;
|
|
+
|
|
+ hdr.preamble = RPMSG_PERF_PREAMBLE_SENDER_START;
|
|
+ packet_len = hdr.packet_size;
|
|
+ eptdev->statistic.send_packet_cnt = 0;
|
|
+
|
|
+ ret = rpmsg_sendto(eptdev->ept, &hdr, sizeof(hdr), eptdev->chinfo.dst);
|
|
+ if (ret) {
|
|
+ pr_err("failed to send packet header\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ /* Prepare data packets */
|
|
+ data = kmalloc(packet_len, GFP_KERNEL);
|
|
+ if (data == NULL) {
|
|
+ pr_err("allocate data buffer failure\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ memset(data, 0, packet_len);
|
|
+
|
|
+ udelay(100);
|
|
+ timeout = jiffies + msecs_to_jiffies(hdr.test_time * 1000);
|
|
+
|
|
+ do {
|
|
+ do {
|
|
+ ret = rpmsg_trysendto(eptdev->ept, data, packet_len,
|
|
+ eptdev->chinfo.dst);
|
|
+ } while (ret != 0);
|
|
+ eptdev->statistic.send_packet_cnt++;
|
|
+ } while (time_before(jiffies, timeout));
|
|
+
|
|
+ memset(&hdr, 0, sizeof(hdr));
|
|
+ hdr.preamble = RPMSG_PERF_PREAMBLE_SENDER_END;
|
|
+
|
|
+ ret = rpmsg_sendto(eptdev->ept, &hdr, sizeof(hdr), eptdev->chinfo.dst);
|
|
+ if (ret) {
|
|
+ pr_err("failed to send RPMSG_PERF_PREAMBLE_SENDER_END packet\n");
|
|
+ }
|
|
+
|
|
+ kfree(data);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static long rpmsg_perf_eptdev_ioctl(struct file *fp, unsigned int cmd,
|
|
+ unsigned long arg)
|
|
+{
|
|
+ struct rpmsg_eptdev *eptdev = fp->private_data;
|
|
+ struct test_statistic *statistic = &eptdev->statistic;
|
|
+ struct task_struct *sender_thread_h;
|
|
+ struct packet_header hdr = {0};
|
|
+ uint32_t packet_cnt;
|
|
+ uint32_t rate;
|
|
+ uint32_t status;
|
|
+ long ret;
|
|
+
|
|
+ switch (cmd) {
|
|
+ case RPMSG_PERF_GET_RUNNING_STA_IOCTL:
|
|
+ status = eptdev->state;
|
|
+ if (copy_to_user((char __user *)arg, &status, sizeof(status))) {
|
|
+ pr_err("copy_to_user() failed\n");
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ break;
|
|
+ case RPMSG_PERF_AS_SENDER_IOCTL:
|
|
+ if (eptdev->state != RPMSG_DEV_IDLE)
|
|
+ return -EINVAL;
|
|
+
|
|
+ eptdev->state = RPMSG_DEV_SENDING;
|
|
+ ret = copy_from_user((void *)&hdr, (const void __user *)arg,
|
|
+ sizeof(struct packet_header));
|
|
+ if (ret) {
|
|
+ pr_err("copy_from_user() failed\n");
|
|
+ return -EFAULT;
|
|
+ }
|
|
+
|
|
+ eptdev->param.no_copy = hdr.no_copy;
|
|
+ eptdev->param.packet_size = hdr.packet_size;
|
|
+ eptdev->param.test_time = hdr.test_time;
|
|
+ statistic->packet_size = hdr.packet_size;
|
|
+ statistic->test_time = hdr.test_time;
|
|
+
|
|
+ sender_thread_h = kthread_run(rpmsg_perf_sender_thread,
|
|
+ eptdev, "rpmsg_sender");
|
|
+ if (IS_ERR(sender_thread_h)) {
|
|
+ pr_err("failed to create sender thread\n");
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ break;
|
|
+ case RPMSG_PERF_AS_RECEIVER_IOCTL:
|
|
+ if (eptdev->state != RPMSG_DEV_IDLE)
|
|
+ return -EINVAL;
|
|
+
|
|
+ eptdev->state = RPMSG_DEV_RECEIVING;
|
|
+ ret = copy_from_user((void *)&hdr, (const void __user *)arg,
|
|
+ sizeof(struct packet_header));
|
|
+ if (ret) {
|
|
+ pr_err("copy_from_user() failed\n");
|
|
+ return -EFAULT;
|
|
+ }
|
|
+ hdr.preamble = RPMSG_PERF_PREAMBLE_RECEIVER_START;
|
|
+ statistic->test_time = hdr.test_time;
|
|
+ statistic->packet_size = hdr.packet_size;
|
|
+ statistic->recv_packet_cnt = 0;
|
|
+
|
|
+ ret = rpmsg_sendto(eptdev->ept, &hdr, sizeof(hdr),
|
|
+ eptdev->chinfo.dst);
|
|
+ if (ret)
|
|
+ pr_err("failed to send RPMSG_PERF_PREAMBLE_RECEIVER_START packet\n");
|
|
+ break;
|
|
+ case RPMSG_PERF_AS_RECEIVER_END_ACK_IOCTL:
|
|
+ if (eptdev->state != RPMSG_DEV_RECEIVING)
|
|
+ return -EINVAL;
|
|
+
|
|
+ packet_cnt = statistic->recv_packet_cnt - 1;
|
|
+ rate = packet_cnt / statistic->test_time / 1000;
|
|
+ pr_info("packet size: %u, received packets: %u, time: %u s, rate: %u kpps\n",
|
|
+ statistic->packet_size, packet_cnt,
|
|
+ statistic->test_time, rate);
|
|
+
|
|
+ hdr.preamble = RPMSG_PERF_PREAMBLE_RECEIVER_END_ACK;
|
|
+ hdr.packet_cnt = packet_cnt;
|
|
+ ret = rpmsg_sendto(eptdev->ept, &hdr, sizeof(hdr),
|
|
+ eptdev->chinfo.dst);
|
|
+ if (ret) {
|
|
+ pr_err("failed to send RPMSG_PERF_PREAMBLE_RECEIVER_END_ACK packet\n");
|
|
+ return ret;
|
|
+ }
|
|
+ eptdev->state = RPMSG_DEV_IDLE;
|
|
+ statistic->test_time = 0;
|
|
+ break;
|
|
+ default:
|
|
+ ret = -EINVAL;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct file_operations rpmsg_perf_eptdev_fops = {
|
|
+ .owner = THIS_MODULE,
|
|
+ .open = rpmsg_perf_eptdev_open,
|
|
+ .release = rpmsg_perf_eptdev_release,
|
|
+ .unlocked_ioctl = rpmsg_perf_eptdev_ioctl,
|
|
+ .compat_ioctl = compat_ptr_ioctl,
|
|
+};
|
|
+
|
|
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
|
|
+ char *buf)
|
|
+{
|
|
+ struct rpmsg_eptdev *eptdev = dev_get_drvdata(dev);
|
|
+
|
|
+ return sprintf(buf, "%s\n", eptdev->chinfo.name);
|
|
+}
|
|
+static DEVICE_ATTR_RO(name);
|
|
+
|
|
+static ssize_t src_show(struct device *dev, struct device_attribute *attr,
|
|
+ char *buf)
|
|
+{
|
|
+ struct rpmsg_eptdev *eptdev = dev_get_drvdata(dev);
|
|
+
|
|
+ return sprintf(buf, "%d\n", eptdev->chinfo.src);
|
|
+}
|
|
+static DEVICE_ATTR_RO(src);
|
|
+
|
|
+static ssize_t dst_show(struct device *dev, struct device_attribute *attr,
|
|
+ char *buf)
|
|
+{
|
|
+ struct rpmsg_eptdev *eptdev = dev_get_drvdata(dev);
|
|
+
|
|
+ return sprintf(buf, "%d\n", eptdev->chinfo.dst);
|
|
+}
|
|
+static DEVICE_ATTR_RO(dst);
|
|
+
|
|
+static struct attribute *rpmsg_perf_eptdev_attrs[] = {
|
|
+ &dev_attr_name.attr,
|
|
+ &dev_attr_src.attr,
|
|
+ &dev_attr_dst.attr,
|
|
+ NULL
|
|
+};
|
|
+ATTRIBUTE_GROUPS(rpmsg_perf_eptdev);
|
|
+
|
|
+static void rpmsg_eptdev_release_device(struct device *dev)
|
|
+{
|
|
+ struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev);
|
|
+
|
|
+ ida_simple_remove(&rpmsg_perf_minor_ida, MINOR(eptdev->dev.devt));
|
|
+ kfree(eptdev);
|
|
+}
|
|
+
|
|
+static struct rpmsg_eptdev *rpmsg_perf_eptdev_alloc(struct rpmsg_device *rpdev,
|
|
+ struct device *parent)
|
|
+{
|
|
+ struct rpmsg_eptdev *eptdev;
|
|
+ struct device *dev;
|
|
+
|
|
+ eptdev = kzalloc(sizeof(*eptdev), GFP_KERNEL);
|
|
+ if (!eptdev)
|
|
+ return ERR_PTR(-ENOMEM);
|
|
+
|
|
+ eptdev->state = RPMSG_DEV_IDLE;
|
|
+
|
|
+ dev = &eptdev->dev;
|
|
+ eptdev->rpdev = rpdev;
|
|
+
|
|
+ mutex_init(&eptdev->ept_lock);
|
|
+
|
|
+ device_initialize(dev);
|
|
+ dev->class = rpmsg_class;
|
|
+ dev->parent = parent;
|
|
+ dev->groups = rpmsg_perf_eptdev_groups;
|
|
+ dev_set_drvdata(dev, eptdev);
|
|
+
|
|
+ cdev_init(&eptdev->cdev, &rpmsg_perf_eptdev_fops);
|
|
+ eptdev->cdev.owner = THIS_MODULE;
|
|
+
|
|
+ return eptdev;
|
|
+}
|
|
+
|
|
+static int rpmsg_perf_eptdev_add(struct rpmsg_eptdev *eptdev,
|
|
+ struct rpmsg_channel_info chinfo)
|
|
+{
|
|
+ struct device *dev = &eptdev->dev;
|
|
+ int dst = eptdev->rpdev->dst;
|
|
+ int ret;
|
|
+
|
|
+ eptdev->chinfo = chinfo;
|
|
+
|
|
+ ret = ida_simple_get(&rpmsg_perf_minor_ida, 0,
|
|
+ RPMSG_DEV_MAX, GFP_KERNEL);
|
|
+ if (ret < 0)
|
|
+ goto free_eptdev;
|
|
+ dev->devt = MKDEV(MAJOR(rpmsg_major), ret);
|
|
+
|
|
+ dev->id = dst;
|
|
+ dev_set_name(dev, "rpmsg-perf%d", dst);
|
|
+
|
|
+ ret = cdev_device_add(&eptdev->cdev, &eptdev->dev);
|
|
+ if (ret)
|
|
+ goto free_minor_ida;
|
|
+
|
|
+ /* We can now rely on the release function for cleanup */
|
|
+ dev->release = rpmsg_eptdev_release_device;
|
|
+
|
|
+ return ret;
|
|
+
|
|
+free_minor_ida:
|
|
+ ida_simple_remove(&rpmsg_perf_minor_ida, MINOR(dev->devt));
|
|
+free_eptdev:
|
|
+ put_device(dev);
|
|
+ kfree(eptdev);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int rpmsg_perf_probe(struct rpmsg_device *rpdev)
|
|
+{
|
|
+ struct rpmsg_channel_info chinfo;
|
|
+ struct rpmsg_eptdev *eptdev;
|
|
+ struct device *dev = &rpdev->dev;
|
|
+
|
|
+ memcpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE);
|
|
+ chinfo.src = rpdev->src;
|
|
+ chinfo.dst = rpdev->dst;
|
|
+
|
|
+ eptdev = rpmsg_perf_eptdev_alloc(rpdev, dev);
|
|
+ if (IS_ERR(eptdev))
|
|
+ return PTR_ERR(eptdev);
|
|
+
|
|
+ /* Set the default_ept to the rpmsg device endpoint */
|
|
+ eptdev->default_ept = rpdev->ept;
|
|
+
|
|
+ /*
|
|
+ * The rpmsg_perf_ept_cb uses *priv parameter to get its
|
|
+ * rpmsg_eptdev context. Stored it in default_ept *priv field.
|
|
+ */
|
|
+ eptdev->default_ept->priv = eptdev;
|
|
+
|
|
+ return rpmsg_perf_eptdev_add(eptdev, chinfo);
|
|
+}
|
|
+
|
|
+static int rpmsg_perf_eptdev_chrdev_destroy(struct device *dev, void *data)
|
|
+{
|
|
+ struct rpmsg_eptdev *eptdev = dev_to_eptdev(dev);
|
|
+
|
|
+ mutex_lock(&eptdev->ept_lock);
|
|
+ if (eptdev->ept) {
|
|
+ /* The default endpoint is released by the rpmsg core */
|
|
+ if (!eptdev->default_ept)
|
|
+ rpmsg_destroy_ept(eptdev->ept);
|
|
+ eptdev->ept = NULL;
|
|
+ }
|
|
+ mutex_unlock(&eptdev->ept_lock);
|
|
+
|
|
+ cdev_device_del(&eptdev->cdev, &eptdev->dev);
|
|
+ put_device(&eptdev->dev);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void rpmsg_perf_remove(struct rpmsg_device *rpdev)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = device_for_each_child(&rpdev->dev, NULL,
|
|
+ rpmsg_perf_eptdev_chrdev_destroy);
|
|
+ if (ret)
|
|
+ dev_warn(&rpdev->dev, "failed to destroy endpoints: %d\n", ret);
|
|
+}
|
|
+
|
|
+static struct rpmsg_device_id rpmsg_perf_id_table[] = {
|
|
+ { .name = "rpmsg-perf" },
|
|
+ { },
|
|
+};
|
|
+
|
|
+static struct rpmsg_driver rpmsg_perf_driver = {
|
|
+ .probe = rpmsg_perf_probe,
|
|
+ .remove = rpmsg_perf_remove,
|
|
+ .callback = rpmsg_perf_ept_cb,
|
|
+ .id_table = rpmsg_perf_id_table,
|
|
+ .drv.name = "rpmsg_perf",
|
|
+};
|
|
+
|
|
+static int rpmsg_perf_init(void)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = alloc_chrdev_region(&rpmsg_major, 0, RPMSG_DEV_MAX, "rpmsg_perf");
|
|
+ if (ret < 0) {
|
|
+ pr_err("failed to allocate char dev region\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = register_rpmsg_driver(&rpmsg_perf_driver);
|
|
+ if (ret < 0) {
|
|
+ pr_err("rpmsg: failed to register rpmsg raw driver\n");
|
|
+ goto free_region;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+free_region:
|
|
+ unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+postcore_initcall(rpmsg_perf_init);
|
|
+
|
|
+static void rpmsg_perf_exit(void)
|
|
+{
|
|
+ unregister_rpmsg_driver(&rpmsg_perf_driver);
|
|
+ unregister_chrdev_region(rpmsg_major, RPMSG_DEV_MAX);
|
|
+}
|
|
+module_exit(rpmsg_perf_exit);
|
|
+
|
|
+MODULE_ALIAS("rpmsg:rpmsg_perf");
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c
|
|
index f1af0f674615..40ee347fcc9b 100644
|
|
--- a/drivers/rpmsg/virtio_rpmsg_bus.c
|
|
+++ b/drivers/rpmsg/virtio_rpmsg_bus.c
|
|
@@ -127,8 +127,13 @@ struct virtio_rpmsg_channel {
|
|
* can change this without changing anything in the firmware of the remote
|
|
* processor.
|
|
*/
|
|
+#ifdef CONFIG_RPMSG_8M_BUF
|
|
+#define MAX_RPMSG_NUM_BUFS (1024 * 8)
|
|
+#define MAX_RPMSG_BUF_SIZE (512 * 2)
|
|
+#else
|
|
#define MAX_RPMSG_NUM_BUFS (512)
|
|
#define MAX_RPMSG_BUF_SIZE (512)
|
|
+#endif
|
|
|
|
/*
|
|
* Local addresses are dynamically allocated on-demand.
|
|
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
|
|
index 882d0c850c10..80a8b479c90f 100644
|
|
--- a/drivers/rtc/Kconfig
|
|
+++ b/drivers/rtc/Kconfig
|
|
@@ -1835,6 +1835,7 @@ config RTC_DRV_IMX_SM
|
|
config RTC_DRV_IMX_RPMSG
|
|
tristate "NXP RPMSG RTC support"
|
|
depends on OF
|
|
+ depends on RPMSG
|
|
help
|
|
If you say yes here you get support for the NXP RPMSG
|
|
RTC module.
|
|
diff --git a/drivers/staging/fsl_qbman/qman_driver.c b/drivers/staging/fsl_qbman/qman_driver.c
|
|
index a752faa4e85d..2f17d4a510e2 100644
|
|
--- a/drivers/staging/fsl_qbman/qman_driver.c
|
|
+++ b/drivers/staging/fsl_qbman/qman_driver.c
|
|
@@ -1,4 +1,5 @@
|
|
/* Copyright 2008-2012 Freescale Semiconductor, Inc.
|
|
+ * Copyright 2019-2023 NXP
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
@@ -723,6 +724,50 @@ static int qman_online_cpu(unsigned int cpu)
|
|
|
|
#endif /* CONFIG_HOTPLUG_CPU */
|
|
|
|
+#ifdef CONFIG_FSL_DPAA_ETHERCAT
|
|
+__init void qman_ethercat_portal_init(int cpu, bool need_cleanup)
|
|
+{
|
|
+ struct qm_portal_config *pcfg;
|
|
+ struct qman_portal *p;
|
|
+
|
|
+ pcfg = get_pcfg(&unused_pcfgs);
|
|
+ if (pcfg) {
|
|
+ pcfg->public_cfg.cpu = cpu;
|
|
+ pcfg->public_cfg.is_shared = 0;
|
|
+
|
|
+ pcfg->iommu_domain = NULL;
|
|
+ portal_set_cpu(pcfg, pcfg->public_cfg.cpu);
|
|
+ p = qman_create_affine_portal_ethercat(pcfg, NULL, cpu, need_cleanup);
|
|
+ if (p) {
|
|
+ pr_info("Qman portal %sinitialised, cpu %d\n",
|
|
+ pcfg->public_cfg.is_shared ? "(shared) " : "",
|
|
+ pcfg->public_cfg.cpu);
|
|
+ } else {
|
|
+ pr_crit("Qman portal failure on cpu %d\n",
|
|
+ pcfg->public_cfg.cpu);
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+}
|
|
+
|
|
+static u32 qman_affine_last_cpu;
|
|
+
|
|
+u32 qman_get_affine_last_cpu(void)
|
|
+{
|
|
+ return qman_affine_last_cpu;
|
|
+}
|
|
+
|
|
+__init void qman_ethercat_portal_init_on_cpu(bool need_cleanup)
|
|
+{
|
|
+ int cpu = 0;
|
|
+
|
|
+ for_each_online_cpu(cpu) {
|
|
+ qman_affine_last_cpu = cpu;
|
|
+ qman_ethercat_portal_init(cpu, need_cleanup);
|
|
+ }
|
|
+}
|
|
+#endif
|
|
+
|
|
__init int qman_init(void)
|
|
{
|
|
struct cpumask slave_cpus;
|
|
@@ -897,6 +942,10 @@ __init int qman_init(void)
|
|
qman_enable_irqs();
|
|
}
|
|
|
|
+#ifdef CONFIG_FSL_DPAA_ETHERCAT
|
|
+ qman_ethercat_portal_init_on_cpu(need_cleanup);
|
|
+#endif
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/drivers/staging/fsl_qbman/qman_high.c b/drivers/staging/fsl_qbman/qman_high.c
|
|
index d1cbfaa987fe..feb47294a02f 100644
|
|
--- a/drivers/staging/fsl_qbman/qman_high.c
|
|
+++ b/drivers/staging/fsl_qbman/qman_high.c
|
|
@@ -1,4 +1,5 @@
|
|
/* Copyright 2008-2012 Freescale Semiconductor, Inc.
|
|
+ * Copyright 2019-2023 NXP
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
@@ -802,6 +803,30 @@ struct qman_portal *qman_create_portal(
|
|
return NULL;
|
|
}
|
|
|
|
+#ifdef CONFIG_FSL_DPAA_ETHERCAT
|
|
+static struct qman_portal ethercat_portal[NR_CPUS];
|
|
+static u16 ethercat_channel[NR_CPUS];
|
|
+static DEFINE_SPINLOCK(ethercat_mask_lock);
|
|
+
|
|
+struct qman_portal *qman_create_affine_portal_ethercat
|
|
+ (const struct qm_portal_config *config,
|
|
+ const struct qman_cgrs *cgrs, int cpu,
|
|
+ bool need_cleanup)
|
|
+{
|
|
+ struct qman_portal *res;
|
|
+ struct qman_portal *portal = NULL;
|
|
+
|
|
+ portal = ðercat_portal[cpu];
|
|
+ res = qman_create_portal(portal, config, cgrs, need_cleanup);
|
|
+ if (res) {
|
|
+ spin_lock(ðercat_mask_lock);
|
|
+ ethercat_channel[cpu] = config->public_cfg.channel;
|
|
+ spin_unlock(ðercat_mask_lock);
|
|
+ }
|
|
+ return res;
|
|
+}
|
|
+#endif
|
|
+
|
|
struct qman_portal *qman_create_affine_portal(
|
|
const struct qm_portal_config *config,
|
|
const struct qman_cgrs *cgrs,
|
|
@@ -1468,6 +1493,20 @@ void *qman_get_affine_portal(int cpu)
|
|
}
|
|
EXPORT_SYMBOL(qman_get_affine_portal);
|
|
|
|
+#ifdef CONFIG_FSL_DPAA_ETHERCAT
|
|
+u16 qman_affine_channel_ethercat(int cpu)
|
|
+{
|
|
+ return ethercat_channel[cpu];
|
|
+}
|
|
+EXPORT_SYMBOL(qman_affine_channel_ethercat);
|
|
+
|
|
+void *qman_get_affine_portal_ethercat(int cpu)
|
|
+{
|
|
+ return ðercat_portal[cpu];
|
|
+}
|
|
+EXPORT_SYMBOL(qman_get_affine_portal_ethercat);
|
|
+#endif
|
|
+
|
|
int qman_p_poll_dqrr(struct qman_portal *p, unsigned int limit)
|
|
{
|
|
int ret;
|
|
diff --git a/drivers/staging/fsl_qbman/qman_private.h b/drivers/staging/fsl_qbman/qman_private.h
|
|
index 615d5a135702..9803d6990353 100644
|
|
--- a/drivers/staging/fsl_qbman/qman_private.h
|
|
+++ b/drivers/staging/fsl_qbman/qman_private.h
|
|
@@ -1,4 +1,5 @@
|
|
/* Copyright 2008-2012 Freescale Semiconductor, Inc.
|
|
+ * Copyright 2019-2023 NXP
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
@@ -233,6 +234,12 @@ struct qman_portal *qman_create_portal(
|
|
const struct qman_cgrs *cgrs,
|
|
bool need_cleanup);
|
|
|
|
+#ifdef CONFIG_FSL_DPAA_ETHERCAT
|
|
+struct qman_portal *qman_create_affine_portal_ethercat
|
|
+ (const struct qm_portal_config *config,
|
|
+ const struct qman_cgrs *cgrs, int cpu,
|
|
+ bool need_cleanup);
|
|
+#endif
|
|
struct qman_portal *qman_create_affine_portal(
|
|
const struct qm_portal_config *config,
|
|
const struct qman_cgrs *cgrs,
|
|
diff --git a/drivers/tty/rpmsg_tty.c b/drivers/tty/rpmsg_tty.c
|
|
index 60a2915f5cfe..7f3f0373c9cf 100644
|
|
--- a/drivers/tty/rpmsg_tty.c
|
|
+++ b/drivers/tty/rpmsg_tty.c
|
|
@@ -1,13 +1,14 @@
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) 2021 STMicroelectronics - All Rights Reserved
|
|
+ * Copyright 2023 NXP
|
|
*
|
|
* The rpmsg tty driver implements serial communication on the RPMsg bus to makes
|
|
* possible for user-space programs to send and receive rpmsg messages as a standard
|
|
* tty protocol.
|
|
*
|
|
- * The remote processor can instantiate a new tty by requesting a "rpmsg-tty" RPMsg service.
|
|
- * The "rpmsg-tty" service is directly used for data exchange. No flow control is implemented yet.
|
|
+ * The remote processor can instantiate a new tty by requesting a "srtm-uart-channel" or "rpmsg-tty" RPMsg service.
|
|
+ * The "srtm-uart-channel" or "rpmsg-tty" service is directly used for data exchange. No flow control is implemented yet.
|
|
*/
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
@@ -17,6 +18,43 @@
|
|
#include <linux/slab.h>
|
|
#include <linux/tty.h>
|
|
#include <linux/tty_flip.h>
|
|
+#include <linux/rpmsg/imx_srtm.h>
|
|
+#include <linux/of.h>
|
|
+
|
|
+/*
|
|
+ * The srtm (simplified real time message) protocol for uart:
|
|
+ *
|
|
+ * +---------------+-------------------------------+
|
|
+ * | Byte Offset | Content |
|
|
+ * +---------------+---+---+---+---+---+---+---+---+
|
|
+ * | 0 | Category |
|
|
+ * +---------------+---+---+---+---+---+---+---+---+
|
|
+ * | 1 ~ 2 | Version |
|
|
+ * +---------------+---+---+---+---+---+---+---+---+
|
|
+ * | 3 | Type |
|
|
+ * +---------------+---+---+---+---+---+---+---+---+
|
|
+ * | 4 | Command |
|
|
+ * +---------------+---+---+---+---+---+---+---+---+
|
|
+ * | 5 | Priority |
|
|
+ * +---------------+---+---+---+---+---+---+---+---+
|
|
+ * | 6 | Reserved1 |
|
|
+ * +---------------+---+---+---+---+---+---+---+---+
|
|
+ * | 7 | Reserved2 |
|
|
+ * +---------------+---+---+---+---+---+---+---+---+
|
|
+ * | 8 | Reserved3 |
|
|
+ * +---------------+---+---+---+---+---+---+---+---+
|
|
+ * | 9 | Reserved4 |
|
|
+ * +---------------+---+---+---+---+---+---+---+---+
|
|
+ * | 10 | UART BUS ID |
|
|
+ * +---------------+---+---+---+---+---+---+---+---+
|
|
+ * | 11 | reserved/ret code |
|
|
+ * +---------------+---+---+---+---+---+---+---+---+
|
|
+ * | 12 ~ 13 | Flags |
|
|
+ * +---------------+---+---+---+---+---+---+---+---+
|
|
+ * | 14 ~ 495 | Data |
|
|
+ * +---------------+---+---+---+---+---+---+---+---+
|
|
+ * UART BUS ID: real uart instance, such as: the soc has UART0(UART BUS ID = 0), UART1(UART BUS ID = 1), UART2(UART BUS ID = 2), ... , UARTx(UART BUS ID = x)
|
|
+ */
|
|
|
|
#define RPMSG_TTY_NAME "ttyRPMSG"
|
|
#define MAX_TTY_RPMSG 32
|
|
@@ -29,18 +67,72 @@ static struct tty_driver *rpmsg_tty_driver;
|
|
struct rpmsg_tty_port {
|
|
struct tty_port port; /* TTY port data */
|
|
int id; /* TTY rpmsg index */
|
|
+ int bus_id; /* used for srtm uart protocol, which real uart will be used, such as, uart0, uart1, uart2, uart3... */
|
|
+ int flags; /* used for srtm uart protocol */
|
|
+ u16 srtm_uart_msg_data_max_sz; /* used for srtm uart protocol */
|
|
+ bool use_srtm_uart_protocol; /* used for srtm uart protocol */
|
|
struct rpmsg_device *rpdev; /* rpmsg device */
|
|
};
|
|
|
|
+struct srtm_uart_msg_header {
|
|
+ struct imx_srtm_head common;
|
|
+ u8 bus_id; /* The bus_id is used when send data from acore to mcore; The bus_id is useless when acore received data that from mcore*/
|
|
+ union {
|
|
+ u8 reserved; /* used in request packet */
|
|
+ u8 retCode; /* used in response packet */
|
|
+ };
|
|
+ u16 flags;
|
|
+} __packed __aligned[1];
|
|
+
|
|
+struct srtm_uart_msg {
|
|
+ struct srtm_uart_msg_header header;
|
|
+ /* srtm uart Payload Start */
|
|
+ u8 data[1];
|
|
+} __packed __aligned(1);
|
|
+
|
|
+struct imx_srtm_uart_data_structure
|
|
+{
|
|
+ bool use_srtm_uart_protocol;
|
|
+};
|
|
+
|
|
+const static struct imx_srtm_uart_data_structure imx_srtm_uart_data = {
|
|
+ .use_srtm_uart_protocol = true,
|
|
+};
|
|
+
|
|
+const static struct imx_srtm_uart_data_structure rpmsg_tty_data = {
|
|
+ .use_srtm_uart_protocol = false,
|
|
+};
|
|
+
|
|
static int rpmsg_tty_cb(struct rpmsg_device *rpdev, void *data, int len, void *priv, u32 src)
|
|
{
|
|
struct rpmsg_tty_port *cport = dev_get_drvdata(&rpdev->dev);
|
|
+ struct srtm_uart_msg *msg = (struct srtm_uart_msg *)data;
|
|
int copied;
|
|
+ u8 *payload = data;
|
|
+ int payload_len = len;
|
|
|
|
- if (!len)
|
|
+ if (!payload_len)
|
|
return -EINVAL;
|
|
- copied = tty_insert_flip_string(&cport->port, data, len);
|
|
- if (copied != len)
|
|
+ if (cport->use_srtm_uart_protocol) {
|
|
+ if (payload_len < (sizeof(struct srtm_uart_msg)))
|
|
+ return -EINVAL;
|
|
+ payload_len -= (sizeof(struct srtm_uart_msg) - 1); /* 1: msg->data[0] */
|
|
+
|
|
+ if (msg->header.common.type != IMX_SRTM_TYPE_RESPONSE && msg->header.common.type != IMX_SRTM_TYPE_NOTIFY) {
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (payload_len > cport->srtm_uart_msg_data_max_sz) {
|
|
+ dev_err(&rpdev->dev,
|
|
+ "%s failed: data length greater than %d, len=%d\n",
|
|
+ __func__, cport->srtm_uart_msg_data_max_sz, payload_len);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ payload = &msg->data[0];
|
|
+ }
|
|
+
|
|
+ copied = tty_insert_flip_string(&cport->port, payload, payload_len);
|
|
+ if (copied != payload_len)
|
|
dev_err_ratelimited(&rpdev->dev, "Trunc buffer: available space is %d\n", copied);
|
|
tty_flip_buffer_push(&cport->port);
|
|
|
|
@@ -78,27 +170,53 @@ static ssize_t rpmsg_tty_write(struct tty_struct *tty, const u8 *buf,
|
|
{
|
|
struct rpmsg_tty_port *cport = tty->driver_data;
|
|
struct rpmsg_device *rpdev;
|
|
- int msg_max_size, msg_size;
|
|
+ int msg_max_size, msg_size = -1;
|
|
+ struct srtm_uart_msg *msg = NULL;
|
|
int ret;
|
|
+ void *data = NULL;
|
|
+ int data_len = 0;
|
|
|
|
rpdev = cport->rpdev;
|
|
|
|
- msg_max_size = rpmsg_get_mtu(rpdev->ept);
|
|
+ msg_max_size = cport->use_srtm_uart_protocol ? (cport->srtm_uart_msg_data_max_sz) : (rpmsg_get_mtu(rpdev->ept));
|
|
if (msg_max_size < 0)
|
|
return msg_max_size;
|
|
|
|
msg_size = min_t(unsigned int, len, msg_max_size);
|
|
|
|
+ if (cport->use_srtm_uart_protocol) {
|
|
+ data_len = msg_size + sizeof(struct srtm_uart_msg) - 1; /* srtm uart msg header + data len */
|
|
+ msg = kmalloc(data_len, GFP_KERNEL);
|
|
+ if (!msg)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ memset(msg, 0, data_len);
|
|
+ msg->header.common.cate = IMX_SRTM_CATEGORY_UART;
|
|
+ msg->header.common.major = IMX_SRTM_VER_UART;
|
|
+ msg->header.common.minor = IMX_SRTM_VER_UART >> 8;
|
|
+ msg->header.common.type = IMX_SRTM_TYPE_NOTIFY;
|
|
+ msg->header.common.cmd = IMX_SRTM_UART_COMMAND_SEND;
|
|
+ msg->header.common.reserved[0] = IMX_SRTM_UART_PRIORITY;
|
|
+ msg->header.bus_id = cport->bus_id & 0xFF;
|
|
+ msg->header.flags = cport->flags & 0xFFFF;
|
|
+ memcpy(&msg->data[0], buf, msg_size);
|
|
+ data = (void *)msg;
|
|
+ } else {
|
|
+ data = (void *)buf;
|
|
+ data_len = msg_size;
|
|
+ }
|
|
/*
|
|
* Use rpmsg_trysend instead of rpmsg_send to send the message so the caller is not
|
|
* hung until a rpmsg buffer is available. In such case rpmsg_trysend returns -ENOMEM.
|
|
*/
|
|
- ret = rpmsg_trysend(rpdev->ept, (void *)buf, msg_size);
|
|
+ ret = rpmsg_trysend(rpdev->ept, data, data_len);
|
|
if (ret) {
|
|
dev_dbg_ratelimited(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
|
|
- return ret;
|
|
+ msg_size = ret;
|
|
}
|
|
|
|
+ kfree(msg);
|
|
+
|
|
return msg_size;
|
|
}
|
|
|
|
@@ -106,8 +224,10 @@ static unsigned int rpmsg_tty_write_room(struct tty_struct *tty)
|
|
{
|
|
struct rpmsg_tty_port *cport = tty->driver_data;
|
|
int size;
|
|
+ struct rpmsg_device *rpdev;
|
|
|
|
- size = rpmsg_get_mtu(cport->rpdev->ept);
|
|
+ rpdev = cport->rpdev;
|
|
+ size = cport->use_srtm_uart_protocol ? (cport->srtm_uart_msg_data_max_sz) : (rpmsg_get_mtu(rpdev->ept));
|
|
if (size < 0)
|
|
return 0;
|
|
|
|
@@ -173,7 +293,12 @@ static int rpmsg_tty_probe(struct rpmsg_device *rpdev)
|
|
struct rpmsg_tty_port *cport;
|
|
struct device *dev = &rpdev->dev;
|
|
struct device *tty_dev;
|
|
+ struct device_node *np;
|
|
+ struct imx_srtm_uart_data_structure *srtm_uart_data = NULL;
|
|
+ struct srtm_uart_msg *msg = NULL;
|
|
int ret;
|
|
+ int data_len = 0;
|
|
+ char buf[64];
|
|
|
|
cport = rpmsg_tty_alloc_cport();
|
|
if (IS_ERR(cport))
|
|
@@ -182,6 +307,23 @@ static int rpmsg_tty_probe(struct rpmsg_device *rpdev)
|
|
tty_port_init(&cport->port);
|
|
cport->port.ops = &rpmsg_tty_port_ops;
|
|
|
|
+ cport->rpdev = rpdev;
|
|
+
|
|
+ srtm_uart_data = (struct imx_srtm_uart_data_structure *)rpdev->id.driver_data;
|
|
+ if (srtm_uart_data && srtm_uart_data->use_srtm_uart_protocol == true) {
|
|
+ cport->bus_id = 0xFF; /* mcore directly print the data that received from acore */
|
|
+ cport->use_srtm_uart_protocol = true;
|
|
+ snprintf(buf, sizeof(buf), "uart-rpbus-%d", cport->id);
|
|
+ np = of_find_node_by_name(NULL, buf);
|
|
+ if (np && of_device_is_compatible(np, "fsl,uart-rpbus") && of_device_is_available(np)) {
|
|
+ of_property_read_u32(np, "bus_id", &cport->bus_id); /* mcore will use the id as uart instance, then write data to the real uart instance */
|
|
+ of_property_read_u32(np, "flags", &cport->flags);
|
|
+ }
|
|
+ cport->srtm_uart_msg_data_max_sz = rpmsg_get_mtu(rpdev->ept) - (sizeof(struct srtm_uart_msg) - 1); /* 1: data[1] of struct srtm_uart_msg */
|
|
+ } else {
|
|
+ cport->use_srtm_uart_protocol = false;
|
|
+ }
|
|
+
|
|
tty_dev = tty_port_register_device(&cport->port, rpmsg_tty_driver,
|
|
cport->id, dev);
|
|
if (IS_ERR(tty_dev)) {
|
|
@@ -190,9 +332,28 @@ static int rpmsg_tty_probe(struct rpmsg_device *rpdev)
|
|
return ret;
|
|
}
|
|
|
|
- cport->rpdev = rpdev;
|
|
-
|
|
- dev_set_drvdata(dev, cport);
|
|
+ dev_set_drvdata(dev, (void *)cport);
|
|
+
|
|
+ /* Say hello to remote to acknowleage each other */
|
|
+ if (cport->use_srtm_uart_protocol) {
|
|
+ data_len = sizeof(struct srtm_uart_msg); /* srtm uart msg header */
|
|
+ msg = kmalloc(data_len, GFP_KERNEL);
|
|
+ if (!msg)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ memset(msg, 0, data_len);
|
|
+ msg->header.common.cate = IMX_SRTM_CATEGORY_UART;
|
|
+ msg->header.common.major = IMX_SRTM_VER_UART;
|
|
+ msg->header.common.minor = IMX_SRTM_VER_UART >> 8;
|
|
+ msg->header.common.type = IMX_SRTM_TYPE_NOTIFY;
|
|
+ msg->header.common.cmd = IMX_SRTM_UART_COMMAND_HELLO;
|
|
+ msg->header.common.reserved[0] = IMX_SRTM_UART_PRIORITY;
|
|
+ msg->header.bus_id = cport->bus_id & 0xFF;
|
|
+ msg->header.flags = cport->flags & 0xFFFF;
|
|
+
|
|
+ rpmsg_send(rpdev->ept, (void *)msg, data_len);
|
|
+ kfree(msg);
|
|
+ }
|
|
|
|
dev_dbg(dev, "New channel: 0x%x -> 0x%x: " RPMSG_TTY_NAME "%d\n",
|
|
rpdev->src, rpdev->dst, cport->id);
|
|
@@ -215,7 +376,8 @@ static void rpmsg_tty_remove(struct rpmsg_device *rpdev)
|
|
}
|
|
|
|
static struct rpmsg_device_id rpmsg_driver_tty_id_table[] = {
|
|
- { .name = "rpmsg-tty" },
|
|
+ { .name = "srtm-uart-channel", .driver_data = (kernel_ulong_t)&imx_srtm_uart_data, },
|
|
+ { .name = "rpmsg-tty", .driver_data = (kernel_ulong_t)&rpmsg_tty_data, },
|
|
{ },
|
|
};
|
|
MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_tty_id_table);
|
|
@@ -284,5 +446,6 @@ module_init(rpmsg_tty_init);
|
|
module_exit(rpmsg_tty_exit);
|
|
|
|
MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@foss.st.com>");
|
|
+MODULE_AUTHOR("Biwen Li <biwen.li@nxp.com>");
|
|
MODULE_DESCRIPTION("remote processor messaging tty driver");
|
|
MODULE_LICENSE("GPL v2");
|
|
diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c
|
|
index d756fcc884cb..4de0c975ebdc 100644
|
|
--- a/drivers/tty/serial/21285.c
|
|
+++ b/drivers/tty/serial/21285.c
|
|
@@ -185,14 +185,14 @@ static void serial21285_break_ctl(struct uart_port *port, int break_state)
|
|
unsigned long flags;
|
|
unsigned int h_lcr;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
h_lcr = *CSR_H_UBRLCR;
|
|
if (break_state)
|
|
h_lcr |= H_UBRLCR_BREAK;
|
|
else
|
|
h_lcr &= ~H_UBRLCR_BREAK;
|
|
*CSR_H_UBRLCR = h_lcr;
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static int serial21285_startup(struct uart_port *port)
|
|
@@ -272,7 +272,7 @@ serial21285_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
if (port->fifosize)
|
|
h_lcr |= H_UBRLCR_FIFO;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/*
|
|
* Update the per-port timeout.
|
|
@@ -309,7 +309,7 @@ serial21285_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
*CSR_H_UBRLCR = h_lcr;
|
|
*CSR_UARTCON = 1;
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *serial21285_type(struct uart_port *port)
|
|
diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c
|
|
index 4a9e71b2dbbc..021949f252f8 100644
|
|
--- a/drivers/tty/serial/8250/8250_aspeed_vuart.c
|
|
+++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c
|
|
@@ -288,9 +288,9 @@ static void aspeed_vuart_set_throttle(struct uart_port *port, bool throttle)
|
|
struct uart_8250_port *up = up_to_u8250p(port);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
__aspeed_vuart_set_throttle(up, throttle);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void aspeed_vuart_throttle(struct uart_port *port)
|
|
@@ -340,7 +340,7 @@ static int aspeed_vuart_handle_irq(struct uart_port *port)
|
|
if (iir & UART_IIR_NO_INT)
|
|
return 0;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
lsr = serial_port_in(port, UART_LSR);
|
|
|
|
diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c
|
|
index 9afd5979c9e0..db23b3a02aef 100644
|
|
--- a/drivers/tty/serial/8250/8250_bcm7271.c
|
|
+++ b/drivers/tty/serial/8250/8250_bcm7271.c
|
|
@@ -567,7 +567,7 @@ static irqreturn_t brcmuart_isr(int irq, void *dev_id)
|
|
if (interrupts == 0)
|
|
return IRQ_NONE;
|
|
|
|
- spin_lock_irqsave(&up->lock, flags);
|
|
+ uart_port_lock_irqsave(up, &flags);
|
|
|
|
/* Clear all interrupts */
|
|
udma_writel(priv, REGS_DMA_ISR, UDMA_INTR_CLEAR, interrupts);
|
|
@@ -581,7 +581,7 @@ static irqreturn_t brcmuart_isr(int irq, void *dev_id)
|
|
if ((rval | tval) == 0)
|
|
dev_warn(dev, "Spurious interrupt: 0x%x\n", interrupts);
|
|
|
|
- spin_unlock_irqrestore(&up->lock, flags);
|
|
+ uart_port_unlock_irqrestore(up, flags);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
@@ -608,10 +608,10 @@ static int brcmuart_startup(struct uart_port *port)
|
|
*
|
|
* Synchronize UART_IER access against the console.
|
|
*/
|
|
- spin_lock_irq(&port->lock);
|
|
+ uart_port_lock_irq(port);
|
|
up->ier &= ~UART_IER_RDI;
|
|
serial_port_out(port, UART_IER, up->ier);
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
|
|
priv->tx_running = false;
|
|
priv->dma.rx_dma = NULL;
|
|
@@ -629,7 +629,7 @@ static void brcmuart_shutdown(struct uart_port *port)
|
|
struct brcmuart_priv *priv = up->port.private_data;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
priv->shutdown = true;
|
|
if (priv->dma_enabled) {
|
|
stop_rx_dma(up);
|
|
@@ -645,7 +645,7 @@ static void brcmuart_shutdown(struct uart_port *port)
|
|
*/
|
|
up->dma = NULL;
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
serial8250_do_shutdown(port);
|
|
}
|
|
|
|
@@ -807,7 +807,7 @@ static int brcmuart_handle_irq(struct uart_port *p)
|
|
* interrupt but there is no data ready.
|
|
*/
|
|
if (((iir & UART_IIR_ID) == UART_IIR_RX_TIMEOUT) && !(priv->shutdown)) {
|
|
- spin_lock_irqsave(&p->lock, flags);
|
|
+ uart_port_lock_irqsave(p, &flags);
|
|
status = serial_port_in(p, UART_LSR);
|
|
if ((status & UART_LSR_DR) == 0) {
|
|
|
|
@@ -832,7 +832,7 @@ static int brcmuart_handle_irq(struct uart_port *p)
|
|
|
|
handled = 1;
|
|
}
|
|
- spin_unlock_irqrestore(&p->lock, flags);
|
|
+ uart_port_unlock_irqrestore(p, flags);
|
|
if (handled)
|
|
return 1;
|
|
}
|
|
@@ -850,7 +850,7 @@ static enum hrtimer_restart brcmuart_hrtimer_func(struct hrtimer *t)
|
|
if (priv->shutdown)
|
|
return HRTIMER_NORESTART;
|
|
|
|
- spin_lock_irqsave(&p->lock, flags);
|
|
+ uart_port_lock_irqsave(p, &flags);
|
|
status = serial_port_in(p, UART_LSR);
|
|
|
|
/*
|
|
@@ -874,7 +874,7 @@ static enum hrtimer_restart brcmuart_hrtimer_func(struct hrtimer *t)
|
|
status |= UART_MCR_RTS;
|
|
serial_port_out(p, UART_MCR, status);
|
|
}
|
|
- spin_unlock_irqrestore(&p->lock, flags);
|
|
+ uart_port_unlock_irqrestore(p, flags);
|
|
return HRTIMER_NORESTART;
|
|
}
|
|
|
|
@@ -1173,10 +1173,10 @@ static int __maybe_unused brcmuart_suspend(struct device *dev)
|
|
* This will prevent resume from enabling RTS before the
|
|
* baud rate has been restored.
|
|
*/
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
priv->saved_mctrl = port->mctrl;
|
|
port->mctrl &= ~TIOCM_RTS;
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
serial8250_suspend_port(priv->line);
|
|
clk_disable_unprepare(priv->baud_mux_clk);
|
|
@@ -1215,10 +1215,10 @@ static int __maybe_unused brcmuart_resume(struct device *dev)
|
|
|
|
if (priv->saved_mctrl & TIOCM_RTS) {
|
|
/* Restore RTS */
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
port->mctrl |= TIOCM_RTS;
|
|
port->ops->set_mctrl(port, port->mctrl);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
return 0;
|
|
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
|
|
index 3449f8790e46..30434718fad8 100644
|
|
--- a/drivers/tty/serial/8250/8250_core.c
|
|
+++ b/drivers/tty/serial/8250/8250_core.c
|
|
@@ -259,7 +259,7 @@ static void serial8250_backup_timeout(struct timer_list *t)
|
|
unsigned int iir, ier = 0, lsr;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
/*
|
|
* Must disable interrupts or else we risk racing with the interrupt
|
|
@@ -292,7 +292,7 @@ static void serial8250_backup_timeout(struct timer_list *t)
|
|
if (up->port.irq)
|
|
serial_out(up, UART_IER, ier);
|
|
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
/* Standard timer interval plus 0.2s to keep the port running */
|
|
mod_timer(&up->timer,
|
|
@@ -592,6 +592,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
|
|
|
|
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
|
|
|
+#ifdef CONFIG_SERIAL_8250_LEGACY_CONSOLE
|
|
static void univ8250_console_write(struct console *co, const char *s,
|
|
unsigned int count)
|
|
{
|
|
@@ -599,6 +600,37 @@ static void univ8250_console_write(struct console *co, const char *s,
|
|
|
|
serial8250_console_write(up, s, count);
|
|
}
|
|
+#else
|
|
+static bool univ8250_console_write_atomic(struct console *co,
|
|
+ struct nbcon_write_context *wctxt)
|
|
+{
|
|
+ struct uart_8250_port *up = &serial8250_ports[co->index];
|
|
+
|
|
+ return serial8250_console_write_atomic(up, wctxt);
|
|
+}
|
|
+
|
|
+static bool univ8250_console_write_thread(struct console *co,
|
|
+ struct nbcon_write_context *wctxt)
|
|
+{
|
|
+ struct uart_8250_port *up = &serial8250_ports[co->index];
|
|
+
|
|
+ return serial8250_console_write_thread(up, wctxt);
|
|
+}
|
|
+
|
|
+static void univ8250_console_driver_enter(struct console *con, unsigned long *flags)
|
|
+{
|
|
+ struct uart_port *up = &serial8250_ports[con->index].port;
|
|
+
|
|
+ __uart_port_lock_irqsave(up, flags);
|
|
+}
|
|
+
|
|
+static void univ8250_console_driver_exit(struct console *con, unsigned long flags)
|
|
+{
|
|
+ struct uart_port *up = &serial8250_ports[con->index].port;
|
|
+
|
|
+ __uart_port_unlock_irqrestore(up, flags);
|
|
+}
|
|
+#endif /* CONFIG_SERIAL_8250_LEGACY_CONSOLE */
|
|
|
|
static int univ8250_console_setup(struct console *co, char *options)
|
|
{
|
|
@@ -698,12 +730,20 @@ static int univ8250_console_match(struct console *co, char *name, int idx,
|
|
|
|
static struct console univ8250_console = {
|
|
.name = "ttyS",
|
|
+#ifdef CONFIG_SERIAL_8250_LEGACY_CONSOLE
|
|
.write = univ8250_console_write,
|
|
+ .flags = CON_PRINTBUFFER | CON_ANYTIME,
|
|
+#else
|
|
+ .write_atomic = univ8250_console_write_atomic,
|
|
+ .write_thread = univ8250_console_write_thread,
|
|
+ .driver_enter = univ8250_console_driver_enter,
|
|
+ .driver_exit = univ8250_console_driver_exit,
|
|
+ .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_NBCON,
|
|
+#endif
|
|
.device = uart_console_device,
|
|
.setup = univ8250_console_setup,
|
|
.exit = univ8250_console_exit,
|
|
.match = univ8250_console_match,
|
|
- .flags = CON_PRINTBUFFER | CON_ANYTIME,
|
|
.index = -1,
|
|
.data = &serial8250_reg,
|
|
};
|
|
@@ -992,11 +1032,11 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work)
|
|
struct uart_port *port = &up->port;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
up->ier |= UART_IER_RLSI | UART_IER_RDI;
|
|
up->port.read_status_mask |= UART_LSR_DR;
|
|
serial_out(up, UART_IER, up->ier);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/**
|
|
@@ -1194,9 +1234,9 @@ void serial8250_unregister_port(int line)
|
|
if (uart->em485) {
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&uart->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&uart->port, &flags);
|
|
serial8250_em485_destroy(uart);
|
|
- spin_unlock_irqrestore(&uart->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&uart->port, flags);
|
|
}
|
|
|
|
uart_remove_one_port(&serial8250_reg, &uart->port);
|
|
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
|
|
index 7fa66501792d..8b30ca8fdd3f 100644
|
|
--- a/drivers/tty/serial/8250/8250_dma.c
|
|
+++ b/drivers/tty/serial/8250/8250_dma.c
|
|
@@ -22,7 +22,7 @@ static void __dma_tx_complete(void *param)
|
|
dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
|
|
UART_XMIT_SIZE, DMA_TO_DEVICE);
|
|
|
|
- spin_lock_irqsave(&p->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&p->port, &flags);
|
|
|
|
dma->tx_running = 0;
|
|
|
|
@@ -35,7 +35,7 @@ static void __dma_tx_complete(void *param)
|
|
if (ret || !dma->tx_running)
|
|
serial8250_set_THRI(p);
|
|
|
|
- spin_unlock_irqrestore(&p->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&p->port, flags);
|
|
}
|
|
|
|
static void __dma_rx_complete(struct uart_8250_port *p)
|
|
@@ -70,7 +70,7 @@ static void dma_rx_complete(void *param)
|
|
struct uart_8250_dma *dma = p->dma;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&p->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&p->port, &flags);
|
|
if (dma->rx_running)
|
|
__dma_rx_complete(p);
|
|
|
|
@@ -80,7 +80,7 @@ static void dma_rx_complete(void *param)
|
|
*/
|
|
if (!dma->rx_running && (serial_lsr_in(p) & UART_LSR_DR))
|
|
p->dma->rx_dma(p);
|
|
- spin_unlock_irqrestore(&p->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&p->port, flags);
|
|
}
|
|
|
|
int serial8250_tx_dma(struct uart_8250_port *p)
|
|
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
|
|
index 8aed33be2ebf..5367bcc6256c 100644
|
|
--- a/drivers/tty/serial/8250/8250_dw.c
|
|
+++ b/drivers/tty/serial/8250/8250_dw.c
|
|
@@ -290,20 +290,20 @@ static int dw8250_handle_irq(struct uart_port *p)
|
|
* so we limit the workaround only to non-DMA mode.
|
|
*/
|
|
if (!up->dma && rx_timeout) {
|
|
- spin_lock_irqsave(&p->lock, flags);
|
|
+ uart_port_lock_irqsave(p, &flags);
|
|
status = serial_lsr_in(up);
|
|
|
|
if (!(status & (UART_LSR_DR | UART_LSR_BI)))
|
|
(void) p->serial_in(p, UART_RX);
|
|
|
|
- spin_unlock_irqrestore(&p->lock, flags);
|
|
+ uart_port_unlock_irqrestore(p, flags);
|
|
}
|
|
|
|
/* Manually stop the Rx DMA transfer when acting as flow controller */
|
|
if (quirks & DW_UART_QUIRK_IS_DMA_FC && up->dma && up->dma->rx_running && rx_timeout) {
|
|
- spin_lock_irqsave(&p->lock, flags);
|
|
+ uart_port_lock_irqsave(p, &flags);
|
|
status = serial_lsr_in(up);
|
|
- spin_unlock_irqrestore(&p->lock, flags);
|
|
+ uart_port_unlock_irqrestore(p, flags);
|
|
|
|
if (status & (UART_LSR_DR | UART_LSR_BI)) {
|
|
dw8250_writel_ext(p, RZN1_UART_RDMACR, 0);
|
|
diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
|
|
index 27430fdd9e76..17be6ad24a0f 100644
|
|
--- a/drivers/tty/serial/8250/8250_exar.c
|
|
+++ b/drivers/tty/serial/8250/8250_exar.c
|
|
@@ -243,9 +243,9 @@ static int xr17v35x_startup(struct uart_port *port)
|
|
*
|
|
* Synchronize UART_IER access against the console.
|
|
*/
|
|
- spin_lock_irq(&port->lock);
|
|
+ uart_port_lock_irq(port);
|
|
serial_port_out(port, UART_IER, 0);
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
|
|
return serial8250_do_startup(port);
|
|
}
|
|
diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c
|
|
index 6af4e1c1210a..f522eb5026c9 100644
|
|
--- a/drivers/tty/serial/8250/8250_fsl.c
|
|
+++ b/drivers/tty/serial/8250/8250_fsl.c
|
|
@@ -30,11 +30,11 @@ int fsl8250_handle_irq(struct uart_port *port)
|
|
unsigned int iir;
|
|
struct uart_8250_port *up = up_to_u8250p(port);
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
iir = port->serial_in(port, UART_IIR);
|
|
if (iir & UART_IIR_NO_INT) {
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
return 0;
|
|
}
|
|
|
|
@@ -54,7 +54,7 @@ int fsl8250_handle_irq(struct uart_port *port)
|
|
if (unlikely(up->lsr_saved_flags & UART_LSR_BI)) {
|
|
up->lsr_saved_flags &= ~UART_LSR_BI;
|
|
port->serial_in(port, UART_RX);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
return 1;
|
|
}
|
|
|
|
diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
|
|
index 28f9a2679a20..33699e86eb52 100644
|
|
--- a/drivers/tty/serial/8250/8250_mtk.c
|
|
+++ b/drivers/tty/serial/8250/8250_mtk.c
|
|
@@ -102,7 +102,7 @@ static void mtk8250_dma_rx_complete(void *param)
|
|
if (data->rx_status == DMA_RX_SHUTDOWN)
|
|
return;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
|
total = dma->rx_size - state.residue;
|
|
@@ -128,7 +128,7 @@ static void mtk8250_dma_rx_complete(void *param)
|
|
|
|
mtk8250_rx_dma(up);
|
|
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static void mtk8250_rx_dma(struct uart_8250_port *up)
|
|
@@ -372,7 +372,7 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
* Ok, we're now changing the port state. Do it with
|
|
* interrupts disabled.
|
|
*/
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/*
|
|
* Update the per-port timeout.
|
|
@@ -420,7 +420,7 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
if (uart_console(port))
|
|
up->port.cons->cflag = termios->c_cflag;
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
/* Don't rewrite B0 */
|
|
if (tty_termios_baud_rate(termios))
|
|
tty_termios_encode_baud_rate(termios, baud, baud);
|
|
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
|
|
index 8f472a2080ff..78fc1f17d5e2 100644
|
|
--- a/drivers/tty/serial/8250/8250_omap.c
|
|
+++ b/drivers/tty/serial/8250/8250_omap.c
|
|
@@ -405,7 +405,7 @@ static void omap_8250_set_termios(struct uart_port *port,
|
|
* interrupts disabled.
|
|
*/
|
|
pm_runtime_get_sync(port->dev);
|
|
- spin_lock_irq(&port->lock);
|
|
+ uart_port_lock_irq(port);
|
|
|
|
/*
|
|
* Update the per-port timeout.
|
|
@@ -508,7 +508,7 @@ static void omap_8250_set_termios(struct uart_port *port,
|
|
}
|
|
omap8250_restore_regs(up);
|
|
|
|
- spin_unlock_irq(&up->port.lock);
|
|
+ uart_port_unlock_irq(&up->port);
|
|
pm_runtime_mark_last_busy(port->dev);
|
|
pm_runtime_put_autosuspend(port->dev);
|
|
|
|
@@ -533,7 +533,7 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state,
|
|
pm_runtime_get_sync(port->dev);
|
|
|
|
/* Synchronize UART_IER access against the console. */
|
|
- spin_lock_irq(&port->lock);
|
|
+ uart_port_lock_irq(port);
|
|
|
|
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
|
|
efr = serial_in(up, UART_EFR);
|
|
@@ -545,7 +545,7 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state,
|
|
serial_out(up, UART_EFR, efr);
|
|
serial_out(up, UART_LCR, 0);
|
|
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
|
|
pm_runtime_mark_last_busy(port->dev);
|
|
pm_runtime_put_autosuspend(port->dev);
|
|
@@ -676,7 +676,7 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
|
|
unsigned long delay;
|
|
|
|
/* Synchronize UART_IER access against the console. */
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
up->ier = port->serial_in(port, UART_IER);
|
|
if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
|
|
port->ops->stop_rx(port);
|
|
@@ -686,7 +686,7 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
|
|
*/
|
|
cancel_delayed_work(&up->overrun_backoff);
|
|
}
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
delay = msecs_to_jiffies(up->overrun_backoff_time_ms);
|
|
schedule_delayed_work(&up->overrun_backoff, delay);
|
|
@@ -733,10 +733,10 @@ static int omap_8250_startup(struct uart_port *port)
|
|
}
|
|
|
|
/* Synchronize UART_IER access against the console. */
|
|
- spin_lock_irq(&port->lock);
|
|
+ uart_port_lock_irq(port);
|
|
up->ier = UART_IER_RLSI | UART_IER_RDI;
|
|
serial_out(up, UART_IER, up->ier);
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
|
|
#ifdef CONFIG_PM
|
|
up->capabilities |= UART_CAP_RPM;
|
|
@@ -749,9 +749,9 @@ static int omap_8250_startup(struct uart_port *port)
|
|
serial_out(up, UART_OMAP_WER, priv->wer);
|
|
|
|
if (up->dma && !(priv->habit & UART_HAS_EFR2)) {
|
|
- spin_lock_irq(&port->lock);
|
|
+ uart_port_lock_irq(port);
|
|
up->dma->rx_dma(up);
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
}
|
|
|
|
enable_irq(up->port.irq);
|
|
@@ -777,10 +777,10 @@ static void omap_8250_shutdown(struct uart_port *port)
|
|
serial_out(up, UART_OMAP_EFR2, 0x0);
|
|
|
|
/* Synchronize UART_IER access against the console. */
|
|
- spin_lock_irq(&port->lock);
|
|
+ uart_port_lock_irq(port);
|
|
up->ier = 0;
|
|
serial_out(up, UART_IER, 0);
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
disable_irq_nosync(up->port.irq);
|
|
dev_pm_clear_wake_irq(port->dev);
|
|
|
|
@@ -805,10 +805,10 @@ static void omap_8250_throttle(struct uart_port *port)
|
|
|
|
pm_runtime_get_sync(port->dev);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
port->ops->stop_rx(port);
|
|
priv->throttled = true;
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
pm_runtime_mark_last_busy(port->dev);
|
|
pm_runtime_put_autosuspend(port->dev);
|
|
@@ -823,14 +823,14 @@ static void omap_8250_unthrottle(struct uart_port *port)
|
|
pm_runtime_get_sync(port->dev);
|
|
|
|
/* Synchronize UART_IER access against the console. */
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
priv->throttled = false;
|
|
if (up->dma)
|
|
up->dma->rx_dma(up);
|
|
up->ier |= UART_IER_RLSI | UART_IER_RDI;
|
|
port->read_status_mask |= UART_LSR_DR;
|
|
serial_out(up, UART_IER, up->ier);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
pm_runtime_mark_last_busy(port->dev);
|
|
pm_runtime_put_autosuspend(port->dev);
|
|
@@ -974,7 +974,7 @@ static void __dma_rx_complete(void *param)
|
|
unsigned long flags;
|
|
|
|
/* Synchronize UART_IER access against the console. */
|
|
- spin_lock_irqsave(&p->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&p->port, &flags);
|
|
|
|
/*
|
|
* If the tx status is not DMA_COMPLETE, then this is a delayed
|
|
@@ -983,7 +983,7 @@ static void __dma_rx_complete(void *param)
|
|
*/
|
|
if (dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state) !=
|
|
DMA_COMPLETE) {
|
|
- spin_unlock_irqrestore(&p->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&p->port, flags);
|
|
return;
|
|
}
|
|
__dma_rx_do_complete(p);
|
|
@@ -994,7 +994,7 @@ static void __dma_rx_complete(void *param)
|
|
omap_8250_rx_dma(p);
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&p->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&p->port, flags);
|
|
}
|
|
|
|
static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
|
|
@@ -1099,7 +1099,7 @@ static void omap_8250_dma_tx_complete(void *param)
|
|
dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
|
|
UART_XMIT_SIZE, DMA_TO_DEVICE);
|
|
|
|
- spin_lock_irqsave(&p->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&p->port, &flags);
|
|
|
|
dma->tx_running = 0;
|
|
|
|
@@ -1128,7 +1128,7 @@ static void omap_8250_dma_tx_complete(void *param)
|
|
serial8250_set_THRI(p);
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&p->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&p->port, flags);
|
|
}
|
|
|
|
static int omap_8250_tx_dma(struct uart_8250_port *p)
|
|
@@ -1294,7 +1294,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
status = serial_port_in(port, UART_LSR);
|
|
|
|
@@ -1774,15 +1774,15 @@ static int omap8250_runtime_resume(struct device *dev)
|
|
up = serial8250_get_port(priv->line);
|
|
|
|
if (up && omap8250_lost_context(up)) {
|
|
- spin_lock_irq(&up->port.lock);
|
|
+ uart_port_lock_irq(&up->port);
|
|
omap8250_restore_regs(up);
|
|
- spin_unlock_irq(&up->port.lock);
|
|
+ uart_port_unlock_irq(&up->port);
|
|
}
|
|
|
|
if (up && up->dma && up->dma->rxchan && !(priv->habit & UART_HAS_EFR2)) {
|
|
- spin_lock_irq(&up->port.lock);
|
|
+ uart_port_lock_irq(&up->port);
|
|
omap_8250_rx_dma(up);
|
|
- spin_unlock_irq(&up->port.lock);
|
|
+ uart_port_unlock_irq(&up->port);
|
|
}
|
|
|
|
priv->latency = priv->calc_latency;
|
|
diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c
|
|
index a3b25779d921..53e238c8cc89 100644
|
|
--- a/drivers/tty/serial/8250/8250_pci1xxxx.c
|
|
+++ b/drivers/tty/serial/8250/8250_pci1xxxx.c
|
|
@@ -225,10 +225,10 @@ static bool pci1xxxx_port_suspend(int line)
|
|
if (port->suspended == 0 && port->dev) {
|
|
wakeup_mask = readb(up->port.membase + UART_WAKE_MASK_REG);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
port->mctrl &= ~TIOCM_OUT2;
|
|
port->ops->set_mctrl(port, port->mctrl);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
ret = (wakeup_mask & UART_WAKE_SRCS) != UART_WAKE_SRCS;
|
|
}
|
|
@@ -251,10 +251,10 @@ static void pci1xxxx_port_resume(int line)
|
|
writeb(UART_WAKE_SRCS, port->membase + UART_WAKE_REG);
|
|
|
|
if (port->suspended == 0) {
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
port->mctrl |= TIOCM_OUT2;
|
|
port->ops->set_mctrl(port, port->mctrl);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
mutex_unlock(&tport->mutex);
|
|
}
|
|
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
|
|
index a17803da83f8..2d4e775cd7cb 100644
|
|
--- a/drivers/tty/serial/8250/8250_port.c
|
|
+++ b/drivers/tty/serial/8250/8250_port.c
|
|
@@ -557,6 +557,11 @@ static int serial8250_em485_init(struct uart_8250_port *p)
|
|
if (!p->em485)
|
|
return -ENOMEM;
|
|
|
|
+#ifndef CONFIG_SERIAL_8250_LEGACY_CONSOLE
|
|
+ if (uart_console(&p->port))
|
|
+ dev_warn(p->port.dev, "no atomic printing for rs485 consoles\n");
|
|
+#endif
|
|
+
|
|
hrtimer_init(&p->em485->stop_tx_timer, CLOCK_MONOTONIC,
|
|
HRTIMER_MODE_REL);
|
|
hrtimer_init(&p->em485->start_tx_timer, CLOCK_MONOTONIC,
|
|
@@ -689,7 +694,7 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
|
|
|
|
if (p->capabilities & UART_CAP_SLEEP) {
|
|
/* Synchronize UART_IER access against the console. */
|
|
- spin_lock_irq(&p->port.lock);
|
|
+ uart_port_lock_irq(&p->port);
|
|
if (p->capabilities & UART_CAP_EFR) {
|
|
lcr = serial_in(p, UART_LCR);
|
|
efr = serial_in(p, UART_EFR);
|
|
@@ -703,13 +708,17 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
|
|
serial_out(p, UART_EFR, efr);
|
|
serial_out(p, UART_LCR, lcr);
|
|
}
|
|
- spin_unlock_irq(&p->port.lock);
|
|
+ uart_port_unlock_irq(&p->port);
|
|
}
|
|
|
|
serial8250_rpm_put(p);
|
|
}
|
|
|
|
-static void serial8250_clear_IER(struct uart_8250_port *up)
|
|
+/*
|
|
+ * Only to be used by write_atomic() and the legacy write(), which do not
|
|
+ * require port lock.
|
|
+ */
|
|
+static void __serial8250_clear_IER(struct uart_8250_port *up)
|
|
{
|
|
if (up->capabilities & UART_CAP_UUE)
|
|
serial_out(up, UART_IER, UART_IER_UUE);
|
|
@@ -717,6 +726,14 @@ static void serial8250_clear_IER(struct uart_8250_port *up)
|
|
serial_out(up, UART_IER, 0);
|
|
}
|
|
|
|
+static inline void serial8250_clear_IER(struct uart_8250_port *up)
|
|
+{
|
|
+ /* Port locked to synchronize UART_IER access against the console. */
|
|
+ lockdep_assert_held_once(&up->port.lock);
|
|
+
|
|
+ __serial8250_clear_IER(up);
|
|
+}
|
|
+
|
|
#ifdef CONFIG_SERIAL_8250_RSA
|
|
/*
|
|
* Attempts to turn on the RSA FIFO. Returns zero on failure.
|
|
@@ -746,9 +763,9 @@ static void enable_rsa(struct uart_8250_port *up)
|
|
{
|
|
if (up->port.type == PORT_RSA) {
|
|
if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) {
|
|
- spin_lock_irq(&up->port.lock);
|
|
+ uart_port_lock_irq(&up->port);
|
|
__enable_rsa(up);
|
|
- spin_unlock_irq(&up->port.lock);
|
|
+ uart_port_unlock_irq(&up->port);
|
|
}
|
|
if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
|
|
serial_out(up, UART_RSA_FRR, 0);
|
|
@@ -768,7 +785,7 @@ static void disable_rsa(struct uart_8250_port *up)
|
|
|
|
if (up->port.type == PORT_RSA &&
|
|
up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {
|
|
- spin_lock_irq(&up->port.lock);
|
|
+ uart_port_lock_irq(&up->port);
|
|
|
|
mode = serial_in(up, UART_RSA_MSR);
|
|
result = !(mode & UART_RSA_MSR_FIFO);
|
|
@@ -781,7 +798,7 @@ static void disable_rsa(struct uart_8250_port *up)
|
|
|
|
if (result)
|
|
up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16;
|
|
- spin_unlock_irq(&up->port.lock);
|
|
+ uart_port_unlock_irq(&up->port);
|
|
}
|
|
}
|
|
#endif /* CONFIG_SERIAL_8250_RSA */
|
|
@@ -1172,7 +1189,7 @@ static void autoconfig(struct uart_8250_port *up)
|
|
*
|
|
* Synchronize UART_IER access against the console.
|
|
*/
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
up->capabilities = 0;
|
|
up->bugs = 0;
|
|
@@ -1211,7 +1228,7 @@ static void autoconfig(struct uart_8250_port *up)
|
|
/*
|
|
* We failed; there's nothing here
|
|
*/
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
DEBUG_AUTOCONF("IER test failed (%02x, %02x) ",
|
|
scratch2, scratch3);
|
|
goto out;
|
|
@@ -1235,7 +1252,7 @@ static void autoconfig(struct uart_8250_port *up)
|
|
status1 = serial_in(up, UART_MSR) & UART_MSR_STATUS_BITS;
|
|
serial8250_out_MCR(up, save_mcr);
|
|
if (status1 != (UART_MSR_DCD | UART_MSR_CTS)) {
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
DEBUG_AUTOCONF("LOOP test failed (%02x) ",
|
|
status1);
|
|
goto out;
|
|
@@ -1304,7 +1321,7 @@ static void autoconfig(struct uart_8250_port *up)
|
|
serial8250_clear_IER(up);
|
|
|
|
out_unlock:
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
/*
|
|
* Check if the device is a Fintek F81216A
|
|
@@ -1341,9 +1358,9 @@ static void autoconfig_irq(struct uart_8250_port *up)
|
|
probe_irq_off(probe_irq_on());
|
|
save_mcr = serial8250_in_MCR(up);
|
|
/* Synchronize UART_IER access against the console. */
|
|
- spin_lock_irq(&port->lock);
|
|
+ uart_port_lock_irq(port);
|
|
save_ier = serial_in(up, UART_IER);
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
serial8250_out_MCR(up, UART_MCR_OUT1 | UART_MCR_OUT2);
|
|
|
|
irqs = probe_irq_on();
|
|
@@ -1356,9 +1373,9 @@ static void autoconfig_irq(struct uart_8250_port *up)
|
|
UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
|
|
}
|
|
/* Synchronize UART_IER access against the console. */
|
|
- spin_lock_irq(&port->lock);
|
|
+ uart_port_lock_irq(port);
|
|
serial_out(up, UART_IER, UART_IER_ALL_INTR);
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
serial_in(up, UART_LSR);
|
|
serial_in(up, UART_RX);
|
|
serial_in(up, UART_IIR);
|
|
@@ -1369,9 +1386,9 @@ static void autoconfig_irq(struct uart_8250_port *up)
|
|
|
|
serial8250_out_MCR(up, save_mcr);
|
|
/* Synchronize UART_IER access against the console. */
|
|
- spin_lock_irq(&port->lock);
|
|
+ uart_port_lock_irq(port);
|
|
serial_out(up, UART_IER, save_ier);
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
|
|
if (port->flags & UPF_FOURPORT)
|
|
outb_p(save_ICP, ICP);
|
|
@@ -1436,13 +1453,13 @@ static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t)
|
|
unsigned long flags;
|
|
|
|
serial8250_rpm_get(p);
|
|
- spin_lock_irqsave(&p->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&p->port, &flags);
|
|
if (em485->active_timer == &em485->stop_tx_timer) {
|
|
p->rs485_stop_tx(p);
|
|
em485->active_timer = NULL;
|
|
em485->tx_stopped = true;
|
|
}
|
|
- spin_unlock_irqrestore(&p->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&p->port, flags);
|
|
serial8250_rpm_put(p);
|
|
|
|
return HRTIMER_NORESTART;
|
|
@@ -1624,12 +1641,12 @@ static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t)
|
|
struct uart_8250_port *p = em485->port;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&p->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&p->port, &flags);
|
|
if (em485->active_timer == &em485->start_tx_timer) {
|
|
__start_tx(&p->port);
|
|
em485->active_timer = NULL;
|
|
}
|
|
- spin_unlock_irqrestore(&p->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&p->port, flags);
|
|
|
|
return HRTIMER_NORESTART;
|
|
}
|
|
@@ -1912,7 +1929,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
|
|
if (iir & UART_IIR_NO_INT)
|
|
return 0;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
status = serial_lsr_in(up);
|
|
|
|
@@ -1982,9 +1999,9 @@ static int serial8250_tx_threshold_handle_irq(struct uart_port *port)
|
|
if ((iir & UART_IIR_ID) == UART_IIR_THRI) {
|
|
struct uart_8250_port *up = up_to_u8250p(port);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
serial8250_tx_chars(up);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
iir = serial_port_in(port, UART_IIR);
|
|
@@ -1999,10 +2016,10 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
|
|
|
|
serial8250_rpm_get(up);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
if (!serial8250_tx_dma_running(up) && uart_lsr_tx_empty(serial_lsr_in(up)))
|
|
result = TIOCSER_TEMT;
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
serial8250_rpm_put(up);
|
|
|
|
@@ -2064,13 +2081,13 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
|
|
unsigned long flags;
|
|
|
|
serial8250_rpm_get(up);
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
if (break_state == -1)
|
|
up->lcr |= UART_LCR_SBC;
|
|
else
|
|
up->lcr &= ~UART_LCR_SBC;
|
|
serial_port_out(port, UART_LCR, up->lcr);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
serial8250_rpm_put(up);
|
|
}
|
|
|
|
@@ -2205,7 +2222,7 @@ int serial8250_do_startup(struct uart_port *port)
|
|
*
|
|
* Synchronize UART_IER access against the console.
|
|
*/
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
up->acr = 0;
|
|
serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B);
|
|
serial_port_out(port, UART_EFR, UART_EFR_ECB);
|
|
@@ -2215,7 +2232,7 @@ int serial8250_do_startup(struct uart_port *port)
|
|
serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B);
|
|
serial_port_out(port, UART_EFR, UART_EFR_ECB);
|
|
serial_port_out(port, UART_LCR, 0);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
if (port->type == PORT_DA830) {
|
|
@@ -2224,10 +2241,10 @@ int serial8250_do_startup(struct uart_port *port)
|
|
*
|
|
* Synchronize UART_IER access against the console.
|
|
*/
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
serial_port_out(port, UART_IER, 0);
|
|
serial_port_out(port, UART_DA830_PWREMU_MGMT, 0);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
mdelay(10);
|
|
|
|
/* Enable Tx, Rx and free run mode */
|
|
@@ -2341,7 +2358,7 @@ int serial8250_do_startup(struct uart_port *port)
|
|
*
|
|
* Synchronize UART_IER access against the console.
|
|
*/
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
wait_for_xmitr(up, UART_LSR_THRE);
|
|
serial_port_out_sync(port, UART_IER, UART_IER_THRI);
|
|
@@ -2353,7 +2370,7 @@ int serial8250_do_startup(struct uart_port *port)
|
|
iir = serial_port_in(port, UART_IIR);
|
|
serial_port_out(port, UART_IER, 0);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
if (port->irqflags & IRQF_SHARED)
|
|
enable_irq(port->irq);
|
|
@@ -2376,7 +2393,7 @@ int serial8250_do_startup(struct uart_port *port)
|
|
*/
|
|
serial_port_out(port, UART_LCR, UART_LCR_WLEN8);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
if (up->port.flags & UPF_FOURPORT) {
|
|
if (!up->port.irq)
|
|
up->port.mctrl |= TIOCM_OUT1;
|
|
@@ -2422,7 +2439,7 @@ int serial8250_do_startup(struct uart_port *port)
|
|
}
|
|
|
|
dont_test_tx_en:
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
/*
|
|
* Clear the interrupt registers again for luck, and clear the
|
|
@@ -2493,17 +2510,17 @@ void serial8250_do_shutdown(struct uart_port *port)
|
|
*
|
|
* Synchronize UART_IER access against the console.
|
|
*/
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
up->ier = 0;
|
|
serial_port_out(port, UART_IER, 0);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
synchronize_irq(port->irq);
|
|
|
|
if (up->dma)
|
|
serial8250_release_dma(up);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
if (port->flags & UPF_FOURPORT) {
|
|
/* reset interrupts on the AST Fourport board */
|
|
inb((port->iobase & 0xfe0) | 0x1f);
|
|
@@ -2512,7 +2529,7 @@ void serial8250_do_shutdown(struct uart_port *port)
|
|
port->mctrl &= ~TIOCM_OUT2;
|
|
|
|
serial8250_set_mctrl(port, port->mctrl);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
/*
|
|
* Disable break condition and FIFOs
|
|
@@ -2748,14 +2765,14 @@ void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk)
|
|
quot = serial8250_get_divisor(port, baud, &frac);
|
|
|
|
serial8250_rpm_get(up);
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
|
|
serial8250_set_divisor(port, baud, quot, frac);
|
|
serial_port_out(port, UART_LCR, up->lcr);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
serial8250_rpm_put(up);
|
|
|
|
out_unlock:
|
|
@@ -2792,7 +2809,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
* Synchronize UART_IER access against the console.
|
|
*/
|
|
serial8250_rpm_get(up);
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
up->lcr = cval; /* Save computed LCR */
|
|
|
|
@@ -2895,7 +2912,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
serial_port_out(port, UART_FCR, up->fcr); /* set fcr */
|
|
}
|
|
serial8250_set_mctrl(port, port->mctrl);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
serial8250_rpm_put(up);
|
|
|
|
/* Don't rewrite B0 */
|
|
@@ -2918,15 +2935,15 @@ void serial8250_do_set_ldisc(struct uart_port *port, struct ktermios *termios)
|
|
{
|
|
if (termios->c_line == N_PPS) {
|
|
port->flags |= UPF_HARDPPS_CD;
|
|
- spin_lock_irq(&port->lock);
|
|
+ uart_port_lock_irq(port);
|
|
serial8250_enable_ms(port);
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
} else {
|
|
port->flags &= ~UPF_HARDPPS_CD;
|
|
if (!UART_ENABLE_MS(port, termios->c_cflag)) {
|
|
- spin_lock_irq(&port->lock);
|
|
+ uart_port_lock_irq(port);
|
|
serial8250_disable_ms(port);
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
}
|
|
}
|
|
}
|
|
@@ -3322,6 +3339,11 @@ static void serial8250_console_putchar(struct uart_port *port, unsigned char ch)
|
|
|
|
wait_for_xmitr(up, UART_LSR_THRE);
|
|
serial_port_out(port, UART_TX, ch);
|
|
+
|
|
+ if (ch == '\n')
|
|
+ up->console_newline_needed = false;
|
|
+ else
|
|
+ up->console_newline_needed = true;
|
|
}
|
|
|
|
/*
|
|
@@ -3350,6 +3372,7 @@ static void serial8250_console_restore(struct uart_8250_port *up)
|
|
serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS);
|
|
}
|
|
|
|
+#ifdef CONFIG_SERIAL_8250_LEGACY_CONSOLE
|
|
/*
|
|
* Print a string to the serial port using the device FIFO
|
|
*
|
|
@@ -3400,15 +3423,15 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
|
|
touch_nmi_watchdog();
|
|
|
|
if (oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&port->lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(port, &flags);
|
|
else
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/*
|
|
* First save the IER then disable the interrupts
|
|
*/
|
|
ier = serial_port_in(port, UART_IER);
|
|
- serial8250_clear_IER(up);
|
|
+ __serial8250_clear_IER(up);
|
|
|
|
/* check scratch reg to see if port powered off during system sleep */
|
|
if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) {
|
|
@@ -3472,8 +3495,137 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
|
|
serial8250_modem_status(up);
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
+#else
|
|
+bool serial8250_console_write_thread(struct uart_8250_port *up,
|
|
+ struct nbcon_write_context *wctxt)
|
|
+{
|
|
+ struct uart_8250_em485 *em485 = up->em485;
|
|
+ struct uart_port *port = &up->port;
|
|
+ bool done = false;
|
|
+ unsigned int ier;
|
|
+
|
|
+ touch_nmi_watchdog();
|
|
+
|
|
+ if (!nbcon_enter_unsafe(wctxt))
|
|
+ return false;
|
|
+
|
|
+ /* First save IER then disable the interrupts. */
|
|
+ ier = serial_port_in(port, UART_IER);
|
|
+ serial8250_clear_IER(up);
|
|
+
|
|
+ /* Check scratch reg if port powered off during system sleep. */
|
|
+ if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) {
|
|
+ serial8250_console_restore(up);
|
|
+ up->canary = 0;
|
|
+ }
|
|
+
|
|
+ if (em485) {
|
|
+ if (em485->tx_stopped)
|
|
+ up->rs485_start_tx(up);
|
|
+ mdelay(port->rs485.delay_rts_before_send);
|
|
+ }
|
|
+
|
|
+ if (nbcon_exit_unsafe(wctxt)) {
|
|
+ int len = READ_ONCE(wctxt->len);
|
|
+ int i;
|
|
+
|
|
+ /*
|
|
+ * Write out the message. Toggle unsafe for each byte in order
|
|
+ * to give another (higher priority) context the opportunity
|
|
+ * for a friendly takeover. If such a takeover occurs, this
|
|
+ * context must reacquire ownership in order to perform final
|
|
+ * actions (such as re-enabling the interrupts).
|
|
+ *
|
|
+ * IMPORTANT: wctxt->outbuf and wctxt->len are no longer valid
|
|
+ * after a reacquire so writing the message must be
|
|
+ * aborted.
|
|
+ */
|
|
+ for (i = 0; i < len; i++) {
|
|
+ if (!nbcon_enter_unsafe(wctxt)) {
|
|
+ nbcon_reacquire(wctxt);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ uart_console_write(port, wctxt->outbuf + i, 1, serial8250_console_putchar);
|
|
+
|
|
+ if (!nbcon_exit_unsafe(wctxt)) {
|
|
+ nbcon_reacquire(wctxt);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ done = (i == len);
|
|
+ } else {
|
|
+ nbcon_reacquire(wctxt);
|
|
+ }
|
|
+
|
|
+ while (!nbcon_enter_unsafe(wctxt))
|
|
+ nbcon_reacquire(wctxt);
|
|
+
|
|
+ /* Finally, wait for transmitter to become empty and restore IER. */
|
|
+ wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
|
|
+ if (em485) {
|
|
+ mdelay(port->rs485.delay_rts_after_send);
|
|
+ if (em485->tx_stopped)
|
|
+ up->rs485_stop_tx(up);
|
|
+ }
|
|
+ serial_port_out(port, UART_IER, ier);
|
|
+
|
|
+ /*
|
|
+ * The receive handling will happen properly because the receive ready
|
|
+ * bit will still be set; it is not cleared on read. However, modem
|
|
+ * control will not, we must call it if we have saved something in the
|
|
+ * saved flags while processing with interrupts off.
|
|
+ */
|
|
+ if (up->msr_saved_flags)
|
|
+ serial8250_modem_status(up);
|
|
+
|
|
+ /* Success if no handover/takeover and message fully printed. */
|
|
+ return (nbcon_exit_unsafe(wctxt) && done);
|
|
+}
|
|
+
|
|
+bool serial8250_console_write_atomic(struct uart_8250_port *up,
|
|
+ struct nbcon_write_context *wctxt)
|
|
+{
|
|
+ struct uart_port *port = &up->port;
|
|
+ unsigned int ier;
|
|
+
|
|
+ /* Atomic console not supported for rs485 mode. */
|
|
+ if (up->em485)
|
|
+ return false;
|
|
+
|
|
+ touch_nmi_watchdog();
|
|
+
|
|
+ if (!nbcon_enter_unsafe(wctxt))
|
|
+ return false;
|
|
+
|
|
+ /*
|
|
+ * First save IER then disable the interrupts. The special variant to
|
|
+ * clear IER is used because atomic printing may occur without holding
|
|
+ * the port lock.
|
|
+ */
|
|
+ ier = serial_port_in(port, UART_IER);
|
|
+ __serial8250_clear_IER(up);
|
|
+
|
|
+ /* Check scratch reg if port powered off during system sleep. */
|
|
+ if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) {
|
|
+ serial8250_console_restore(up);
|
|
+ up->canary = 0;
|
|
+ }
|
|
+
|
|
+ if (up->console_newline_needed)
|
|
+ uart_console_write(port, "\n", 1, serial8250_console_putchar);
|
|
+ uart_console_write(port, wctxt->outbuf, wctxt->len, serial8250_console_putchar);
|
|
+
|
|
+ /* Finally, wait for transmitter to become empty and restore IER. */
|
|
+ wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
|
|
+ serial_port_out(port, UART_IER, ier);
|
|
+
|
|
+ /* Success if no handover/takeover. */
|
|
+ return nbcon_exit_unsafe(wctxt);
|
|
+}
|
|
+#endif /* CONFIG_SERIAL_8250_LEGACY_CONSOLE */
|
|
|
|
static unsigned int probe_baud(struct uart_port *port)
|
|
{
|
|
@@ -3492,6 +3644,7 @@ static unsigned int probe_baud(struct uart_port *port)
|
|
|
|
int serial8250_console_setup(struct uart_port *port, char *options, bool probe)
|
|
{
|
|
+ struct uart_8250_port *up = up_to_u8250p(port);
|
|
int baud = 9600;
|
|
int bits = 8;
|
|
int parity = 'n';
|
|
@@ -3501,6 +3654,8 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe)
|
|
if (!port->iobase && !port->membase)
|
|
return -ENODEV;
|
|
|
|
+ up->console_newline_needed = false;
|
|
+
|
|
if (options)
|
|
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
|
else if (probe)
|
|
diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c
|
|
index 5fab4c978891..7090b251dd4d 100644
|
|
--- a/drivers/tty/serial/altera_jtaguart.c
|
|
+++ b/drivers/tty/serial/altera_jtaguart.c
|
|
@@ -147,14 +147,14 @@ static irqreturn_t altera_jtaguart_interrupt(int irq, void *data)
|
|
isr = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) >>
|
|
ALTERA_JTAGUART_CONTROL_RI_OFF) & port->read_status_mask;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
if (isr & ALTERA_JTAGUART_CONTROL_RE_MSK)
|
|
altera_jtaguart_rx_chars(port);
|
|
if (isr & ALTERA_JTAGUART_CONTROL_WE_MSK)
|
|
altera_jtaguart_tx_chars(port);
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
return IRQ_RETVAL(isr);
|
|
}
|
|
@@ -180,14 +180,14 @@ static int altera_jtaguart_startup(struct uart_port *port)
|
|
return ret;
|
|
}
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Enable RX interrupts now */
|
|
port->read_status_mask = ALTERA_JTAGUART_CONTROL_RE_MSK;
|
|
writel(port->read_status_mask,
|
|
port->membase + ALTERA_JTAGUART_CONTROL_REG);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -196,14 +196,14 @@ static void altera_jtaguart_shutdown(struct uart_port *port)
|
|
{
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Disable all interrupts now */
|
|
port->read_status_mask = 0;
|
|
writel(port->read_status_mask,
|
|
port->membase + ALTERA_JTAGUART_CONTROL_REG);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
free_irq(port->irq, port);
|
|
}
|
|
@@ -264,33 +264,33 @@ static void altera_jtaguart_console_putc(struct uart_port *port, unsigned char c
|
|
unsigned long flags;
|
|
u32 status;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
while (!altera_jtaguart_tx_space(port, &status)) {
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
if ((status & ALTERA_JTAGUART_CONTROL_AC_MSK) == 0) {
|
|
return; /* no connection activity */
|
|
}
|
|
|
|
cpu_relax();
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
}
|
|
writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
#else
|
|
static void altera_jtaguart_console_putc(struct uart_port *port, unsigned char c)
|
|
{
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
while (!altera_jtaguart_tx_space(port, NULL)) {
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
cpu_relax();
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
}
|
|
writel(c, port->membase + ALTERA_JTAGUART_DATA_REG);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
#endif
|
|
|
|
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
|
|
index a9c41942190c..77835ac68df2 100644
|
|
--- a/drivers/tty/serial/altera_uart.c
|
|
+++ b/drivers/tty/serial/altera_uart.c
|
|
@@ -164,13 +164,13 @@ static void altera_uart_break_ctl(struct uart_port *port, int break_state)
|
|
struct altera_uart *pp = container_of(port, struct altera_uart, port);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
if (break_state == -1)
|
|
pp->imr |= ALTERA_UART_CONTROL_TRBK_MSK;
|
|
else
|
|
pp->imr &= ~ALTERA_UART_CONTROL_TRBK_MSK;
|
|
altera_uart_update_ctrl_reg(pp);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void altera_uart_set_termios(struct uart_port *port,
|
|
@@ -187,10 +187,10 @@ static void altera_uart_set_termios(struct uart_port *port,
|
|
tty_termios_copy_hw(termios, old);
|
|
tty_termios_encode_baud_rate(termios, baud, baud);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
/*
|
|
* FIXME: port->read_status_mask and port->ignore_status_mask
|
|
@@ -264,12 +264,12 @@ static irqreturn_t altera_uart_interrupt(int irq, void *data)
|
|
|
|
isr = altera_uart_readl(port, ALTERA_UART_STATUS_REG) & pp->imr;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
if (isr & ALTERA_UART_STATUS_RRDY_MSK)
|
|
altera_uart_rx_chars(port);
|
|
if (isr & ALTERA_UART_STATUS_TRDY_MSK)
|
|
altera_uart_tx_chars(port);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return IRQ_RETVAL(isr);
|
|
}
|
|
@@ -313,13 +313,13 @@ static int altera_uart_startup(struct uart_port *port)
|
|
}
|
|
}
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Enable RX interrupts now */
|
|
pp->imr = ALTERA_UART_CONTROL_RRDY_MSK;
|
|
altera_uart_update_ctrl_reg(pp);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -329,13 +329,13 @@ static void altera_uart_shutdown(struct uart_port *port)
|
|
struct altera_uart *pp = container_of(port, struct altera_uart, port);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Disable all interrupts now */
|
|
pp->imr = 0;
|
|
altera_uart_update_ctrl_reg(pp);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
if (port->irq)
|
|
free_irq(port->irq, port);
|
|
diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c
|
|
index b5a7404cbacb..eabbf8afc9b5 100644
|
|
--- a/drivers/tty/serial/amba-pl010.c
|
|
+++ b/drivers/tty/serial/amba-pl010.c
|
|
@@ -207,7 +207,7 @@ static irqreturn_t pl010_int(int irq, void *dev_id)
|
|
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
|
|
int handled = 0;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
status = readb(port->membase + UART010_IIR);
|
|
if (status) {
|
|
@@ -228,7 +228,7 @@ static irqreturn_t pl010_int(int irq, void *dev_id)
|
|
handled = 1;
|
|
}
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
return IRQ_RETVAL(handled);
|
|
}
|
|
@@ -270,14 +270,14 @@ static void pl010_break_ctl(struct uart_port *port, int break_state)
|
|
unsigned long flags;
|
|
unsigned int lcr_h;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
lcr_h = readb(port->membase + UART010_LCRH);
|
|
if (break_state == -1)
|
|
lcr_h |= UART01x_LCRH_BRK;
|
|
else
|
|
lcr_h &= ~UART01x_LCRH_BRK;
|
|
writel(lcr_h, port->membase + UART010_LCRH);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static int pl010_startup(struct uart_port *port)
|
|
@@ -385,7 +385,7 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
if (port->fifosize > 1)
|
|
lcr_h |= UART01x_LCRH_FEN;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/*
|
|
* Update the per-port timeout.
|
|
@@ -438,22 +438,22 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
writel(lcr_h, port->membase + UART010_LCRH);
|
|
writel(old_cr, port->membase + UART010_CR);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void pl010_set_ldisc(struct uart_port *port, struct ktermios *termios)
|
|
{
|
|
if (termios->c_line == N_PPS) {
|
|
port->flags |= UPF_HARDPPS_CD;
|
|
- spin_lock_irq(&port->lock);
|
|
+ uart_port_lock_irq(port);
|
|
pl010_enable_ms(port);
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
} else {
|
|
port->flags &= ~UPF_HARDPPS_CD;
|
|
if (!UART_ENABLE_MS(port, termios->c_cflag)) {
|
|
- spin_lock_irq(&port->lock);
|
|
+ uart_port_lock_irq(port);
|
|
pl010_disable_ms(port);
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
}
|
|
}
|
|
}
|
|
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
|
|
index 362bbcdece0d..9cd660edb165 100644
|
|
--- a/drivers/tty/serial/amba-pl011.c
|
|
+++ b/drivers/tty/serial/amba-pl011.c
|
|
@@ -347,9 +347,9 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)
|
|
flag = TTY_FRAME;
|
|
}
|
|
|
|
- spin_unlock(&uap->port.lock);
|
|
+ uart_port_unlock(&uap->port);
|
|
sysrq = uart_handle_sysrq_char(&uap->port, ch & 255);
|
|
- spin_lock(&uap->port.lock);
|
|
+ uart_port_lock(&uap->port);
|
|
|
|
if (!sysrq)
|
|
uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
|
|
@@ -544,7 +544,7 @@ static void pl011_dma_tx_callback(void *data)
|
|
unsigned long flags;
|
|
u16 dmacr;
|
|
|
|
- spin_lock_irqsave(&uap->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&uap->port, &flags);
|
|
if (uap->dmatx.queued)
|
|
dma_unmap_single(dmatx->chan->device->dev, dmatx->dma,
|
|
dmatx->len, DMA_TO_DEVICE);
|
|
@@ -565,7 +565,7 @@ static void pl011_dma_tx_callback(void *data)
|
|
if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) ||
|
|
uart_circ_empty(&uap->port.state->xmit)) {
|
|
uap->dmatx.queued = false;
|
|
- spin_unlock_irqrestore(&uap->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&uap->port, flags);
|
|
return;
|
|
}
|
|
|
|
@@ -576,7 +576,7 @@ static void pl011_dma_tx_callback(void *data)
|
|
*/
|
|
pl011_start_tx_pio(uap);
|
|
|
|
- spin_unlock_irqrestore(&uap->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&uap->port, flags);
|
|
}
|
|
|
|
/*
|
|
@@ -1004,7 +1004,7 @@ static void pl011_dma_rx_callback(void *data)
|
|
* routine to flush out the secondary DMA buffer while
|
|
* we immediately trigger the next DMA job.
|
|
*/
|
|
- spin_lock_irq(&uap->port.lock);
|
|
+ uart_port_lock_irq(&uap->port);
|
|
/*
|
|
* Rx data can be taken by the UART interrupts during
|
|
* the DMA irq handler. So we check the residue here.
|
|
@@ -1020,7 +1020,7 @@ static void pl011_dma_rx_callback(void *data)
|
|
ret = pl011_dma_rx_trigger_dma(uap);
|
|
|
|
pl011_dma_rx_chars(uap, pending, lastbuf, false);
|
|
- spin_unlock_irq(&uap->port.lock);
|
|
+ uart_port_unlock_irq(&uap->port);
|
|
/*
|
|
* Do this check after we picked the DMA chars so we don't
|
|
* get some IRQ immediately from RX.
|
|
@@ -1086,11 +1086,11 @@ static void pl011_dma_rx_poll(struct timer_list *t)
|
|
if (jiffies_to_msecs(jiffies - dmarx->last_jiffies)
|
|
> uap->dmarx.poll_timeout) {
|
|
|
|
- spin_lock_irqsave(&uap->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&uap->port, &flags);
|
|
pl011_dma_rx_stop(uap);
|
|
uap->im |= UART011_RXIM;
|
|
pl011_write(uap->im, uap, REG_IMSC);
|
|
- spin_unlock_irqrestore(&uap->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&uap->port, flags);
|
|
|
|
uap->dmarx.running = false;
|
|
dmaengine_terminate_all(rxchan);
|
|
@@ -1186,10 +1186,10 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
|
|
while (pl011_read(uap, REG_FR) & uap->vendor->fr_busy)
|
|
cpu_relax();
|
|
|
|
- spin_lock_irq(&uap->port.lock);
|
|
+ uart_port_lock_irq(&uap->port);
|
|
uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE);
|
|
pl011_write(uap->dmacr, uap, REG_DMACR);
|
|
- spin_unlock_irq(&uap->port.lock);
|
|
+ uart_port_unlock_irq(&uap->port);
|
|
|
|
if (uap->using_tx_dma) {
|
|
/* In theory, this should already be done by pl011_dma_flush_buffer */
|
|
@@ -1400,9 +1400,9 @@ static void pl011_throttle_rx(struct uart_port *port)
|
|
{
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
pl011_stop_rx(port);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void pl011_enable_ms(struct uart_port *port)
|
|
@@ -1420,7 +1420,7 @@ __acquires(&uap->port.lock)
|
|
{
|
|
pl011_fifo_to_tty(uap);
|
|
|
|
- spin_unlock(&uap->port.lock);
|
|
+ uart_port_unlock(&uap->port);
|
|
tty_flip_buffer_push(&uap->port.state->port);
|
|
/*
|
|
* If we were temporarily out of DMA mode for a while,
|
|
@@ -1445,7 +1445,7 @@ __acquires(&uap->port.lock)
|
|
#endif
|
|
}
|
|
}
|
|
- spin_lock(&uap->port.lock);
|
|
+ uart_port_lock(&uap->port);
|
|
}
|
|
|
|
static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
|
|
@@ -1551,7 +1551,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
|
|
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
|
|
int handled = 0;
|
|
|
|
- spin_lock_irqsave(&uap->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&uap->port, &flags);
|
|
status = pl011_read(uap, REG_RIS) & uap->im;
|
|
if (status) {
|
|
do {
|
|
@@ -1581,7 +1581,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
|
|
handled = 1;
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&uap->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&uap->port, flags);
|
|
|
|
return IRQ_RETVAL(handled);
|
|
}
|
|
@@ -1653,14 +1653,14 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
|
|
unsigned long flags;
|
|
unsigned int lcr_h;
|
|
|
|
- spin_lock_irqsave(&uap->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&uap->port, &flags);
|
|
lcr_h = pl011_read(uap, REG_LCRH_TX);
|
|
if (break_state == -1)
|
|
lcr_h |= UART01x_LCRH_BRK;
|
|
else
|
|
lcr_h &= ~UART01x_LCRH_BRK;
|
|
pl011_write(lcr_h, uap, REG_LCRH_TX);
|
|
- spin_unlock_irqrestore(&uap->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&uap->port, flags);
|
|
}
|
|
|
|
#ifdef CONFIG_CONSOLE_POLL
|
|
@@ -1799,7 +1799,7 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap)
|
|
unsigned long flags;
|
|
unsigned int i;
|
|
|
|
- spin_lock_irqsave(&uap->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&uap->port, &flags);
|
|
|
|
/* Clear out any spuriously appearing RX interrupts */
|
|
pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR);
|
|
@@ -1821,7 +1821,7 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap)
|
|
if (!pl011_dma_rx_running(uap))
|
|
uap->im |= UART011_RXIM;
|
|
pl011_write(uap->im, uap, REG_IMSC);
|
|
- spin_unlock_irqrestore(&uap->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&uap->port, flags);
|
|
}
|
|
|
|
static void pl011_unthrottle_rx(struct uart_port *port)
|
|
@@ -1829,7 +1829,7 @@ static void pl011_unthrottle_rx(struct uart_port *port)
|
|
struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&uap->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&uap->port, &flags);
|
|
|
|
uap->im = UART011_RTIM;
|
|
if (!pl011_dma_rx_running(uap))
|
|
@@ -1837,7 +1837,7 @@ static void pl011_unthrottle_rx(struct uart_port *port)
|
|
|
|
pl011_write(uap->im, uap, REG_IMSC);
|
|
|
|
- spin_unlock_irqrestore(&uap->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&uap->port, flags);
|
|
}
|
|
|
|
static int pl011_startup(struct uart_port *port)
|
|
@@ -1857,7 +1857,7 @@ static int pl011_startup(struct uart_port *port)
|
|
|
|
pl011_write(uap->vendor->ifls, uap, REG_IFLS);
|
|
|
|
- spin_lock_irq(&uap->port.lock);
|
|
+ uart_port_lock_irq(&uap->port);
|
|
|
|
cr = pl011_read(uap, REG_CR);
|
|
cr &= UART011_CR_RTS | UART011_CR_DTR;
|
|
@@ -1868,7 +1868,7 @@ static int pl011_startup(struct uart_port *port)
|
|
|
|
pl011_write(cr, uap, REG_CR);
|
|
|
|
- spin_unlock_irq(&uap->port.lock);
|
|
+ uart_port_unlock_irq(&uap->port);
|
|
|
|
/*
|
|
* initialise the old status of the modem signals
|
|
@@ -1929,12 +1929,12 @@ static void pl011_disable_uart(struct uart_amba_port *uap)
|
|
unsigned int cr;
|
|
|
|
uap->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
|
|
- spin_lock_irq(&uap->port.lock);
|
|
+ uart_port_lock_irq(&uap->port);
|
|
cr = pl011_read(uap, REG_CR);
|
|
cr &= UART011_CR_RTS | UART011_CR_DTR;
|
|
cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
|
|
pl011_write(cr, uap, REG_CR);
|
|
- spin_unlock_irq(&uap->port.lock);
|
|
+ uart_port_unlock_irq(&uap->port);
|
|
|
|
/*
|
|
* disable break condition and fifos
|
|
@@ -1946,14 +1946,14 @@ static void pl011_disable_uart(struct uart_amba_port *uap)
|
|
|
|
static void pl011_disable_interrupts(struct uart_amba_port *uap)
|
|
{
|
|
- spin_lock_irq(&uap->port.lock);
|
|
+ uart_port_lock_irq(&uap->port);
|
|
|
|
/* mask all interrupts and clear all pending ones */
|
|
uap->im = 0;
|
|
pl011_write(uap->im, uap, REG_IMSC);
|
|
pl011_write(0xffff, uap, REG_ICR);
|
|
|
|
- spin_unlock_irq(&uap->port.lock);
|
|
+ uart_port_unlock_irq(&uap->port);
|
|
}
|
|
|
|
static void pl011_shutdown(struct uart_port *port)
|
|
@@ -2098,7 +2098,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
|
|
bits = tty_get_frame_size(termios->c_cflag);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/*
|
|
* Update the per-port timeout.
|
|
@@ -2172,7 +2172,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
old_cr |= UART011_CR_RXE;
|
|
pl011_write(old_cr, uap, REG_CR);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void
|
|
@@ -2190,10 +2190,10 @@ sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
termios->c_cflag &= ~(CMSPAR | CRTSCTS);
|
|
termios->c_cflag |= CS8 | CLOCAL;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
uart_update_timeout(port, CS8, uap->fixed_baud);
|
|
pl011_setup_status_masks(port, termios);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *pl011_type(struct uart_port *port)
|
|
@@ -2328,13 +2328,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
|
|
|
|
clk_enable(uap->clk);
|
|
|
|
- local_irq_save(flags);
|
|
- if (uap->port.sysrq)
|
|
- locked = 0;
|
|
- else if (oops_in_progress)
|
|
- locked = spin_trylock(&uap->port.lock);
|
|
+ if (uap->port.sysrq || oops_in_progress)
|
|
+ locked = uart_port_trylock_irqsave(&uap->port, &flags);
|
|
else
|
|
- spin_lock(&uap->port.lock);
|
|
+ uart_port_lock_irqsave(&uap->port, &flags);
|
|
|
|
/*
|
|
* First save the CR then disable the interrupts
|
|
@@ -2360,8 +2357,7 @@ pl011_console_write(struct console *co, const char *s, unsigned int count)
|
|
pl011_write(old_cr, uap, REG_CR);
|
|
|
|
if (locked)
|
|
- spin_unlock(&uap->port.lock);
|
|
- local_irq_restore(flags);
|
|
+ uart_port_unlock_irqrestore(&uap->port, flags);
|
|
|
|
clk_disable(uap->clk);
|
|
}
|
|
diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c
|
|
index d3cb341f2c55..364599f256db 100644
|
|
--- a/drivers/tty/serial/apbuart.c
|
|
+++ b/drivers/tty/serial/apbuart.c
|
|
@@ -133,7 +133,7 @@ static irqreturn_t apbuart_int(int irq, void *dev_id)
|
|
struct uart_port *port = dev_id;
|
|
unsigned int status;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
status = UART_GET_STATUS(port);
|
|
if (status & UART_STATUS_DR)
|
|
@@ -141,7 +141,7 @@ static irqreturn_t apbuart_int(int irq, void *dev_id)
|
|
if (status & UART_STATUS_THE)
|
|
apbuart_tx_chars(port);
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -228,7 +228,7 @@ static void apbuart_set_termios(struct uart_port *port,
|
|
if (termios->c_cflag & CRTSCTS)
|
|
cr |= UART_CTRL_FL;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Update the per-port timeout. */
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
@@ -251,7 +251,7 @@ static void apbuart_set_termios(struct uart_port *port,
|
|
UART_PUT_SCAL(port, quot);
|
|
UART_PUT_CTRL(port, cr);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *apbuart_type(struct uart_port *port)
|
|
diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
|
|
index 924c1a89347c..ffd234673177 100644
|
|
--- a/drivers/tty/serial/ar933x_uart.c
|
|
+++ b/drivers/tty/serial/ar933x_uart.c
|
|
@@ -133,9 +133,9 @@ static unsigned int ar933x_uart_tx_empty(struct uart_port *port)
|
|
unsigned long flags;
|
|
unsigned int rdata;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
return (rdata & AR933X_UART_DATA_TX_CSR) ? 0 : TIOCSER_TEMT;
|
|
}
|
|
@@ -220,14 +220,14 @@ static void ar933x_uart_break_ctl(struct uart_port *port, int break_state)
|
|
container_of(port, struct ar933x_uart_port, port);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
if (break_state == -1)
|
|
ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
|
|
AR933X_UART_CS_TX_BREAK);
|
|
else
|
|
ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG,
|
|
AR933X_UART_CS_TX_BREAK);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
/*
|
|
@@ -318,7 +318,7 @@ static void ar933x_uart_set_termios(struct uart_port *port,
|
|
* Ok, we're now changing the port state. Do it with
|
|
* interrupts disabled.
|
|
*/
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
/* disable the UART */
|
|
ar933x_uart_rmw_clear(up, AR933X_UART_CS_REG,
|
|
@@ -352,7 +352,7 @@ static void ar933x_uart_set_termios(struct uart_port *port,
|
|
AR933X_UART_CS_IF_MODE_M << AR933X_UART_CS_IF_MODE_S,
|
|
AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S);
|
|
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
if (tty_termios_baud_rate(new))
|
|
tty_termios_encode_baud_rate(new, baud, baud);
|
|
@@ -450,7 +450,7 @@ static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id)
|
|
if ((status & AR933X_UART_CS_HOST_INT) == 0)
|
|
return IRQ_NONE;
|
|
|
|
- spin_lock(&up->port.lock);
|
|
+ uart_port_lock(&up->port);
|
|
|
|
status = ar933x_uart_read(up, AR933X_UART_INT_REG);
|
|
status &= ar933x_uart_read(up, AR933X_UART_INT_EN_REG);
|
|
@@ -468,7 +468,7 @@ static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id)
|
|
ar933x_uart_tx_chars(up);
|
|
}
|
|
|
|
- spin_unlock(&up->port.lock);
|
|
+ uart_port_unlock(&up->port);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -485,7 +485,7 @@ static int ar933x_uart_startup(struct uart_port *port)
|
|
if (ret)
|
|
return ret;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
/* Enable HOST interrupts */
|
|
ar933x_uart_rmw_set(up, AR933X_UART_CS_REG,
|
|
@@ -498,7 +498,7 @@ static int ar933x_uart_startup(struct uart_port *port)
|
|
/* Enable RX interrupts */
|
|
ar933x_uart_start_rx_interrupt(up);
|
|
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -632,9 +632,9 @@ static void ar933x_uart_console_write(struct console *co, const char *s,
|
|
if (up->port.sysrq)
|
|
locked = 0;
|
|
else if (oops_in_progress)
|
|
- locked = spin_trylock(&up->port.lock);
|
|
+ locked = uart_port_trylock(&up->port);
|
|
else
|
|
- spin_lock(&up->port.lock);
|
|
+ uart_port_lock(&up->port);
|
|
|
|
/*
|
|
* First save the IER then disable the interrupts
|
|
@@ -654,7 +654,7 @@ static void ar933x_uart_console_write(struct console *co, const char *s,
|
|
ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_ALLINTS);
|
|
|
|
if (locked)
|
|
- spin_unlock(&up->port.lock);
|
|
+ uart_port_unlock(&up->port);
|
|
|
|
local_irq_restore(flags);
|
|
}
|
|
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
|
|
index ad4ae19b6ce3..1aa5b2b49c26 100644
|
|
--- a/drivers/tty/serial/arc_uart.c
|
|
+++ b/drivers/tty/serial/arc_uart.c
|
|
@@ -279,9 +279,9 @@ static irqreturn_t arc_serial_isr(int irq, void *dev_id)
|
|
if (status & RXIENB) {
|
|
|
|
/* already in ISR, no need of xx_irqsave */
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
arc_serial_rx_chars(port, status);
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
}
|
|
|
|
if ((status & TXIENB) && (status & TXEMPTY)) {
|
|
@@ -291,12 +291,12 @@ static irqreturn_t arc_serial_isr(int irq, void *dev_id)
|
|
*/
|
|
UART_TX_IRQ_DISABLE(port);
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
if (!uart_tx_stopped(port))
|
|
arc_serial_tx_chars(port);
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
}
|
|
|
|
return IRQ_HANDLED;
|
|
@@ -366,7 +366,7 @@ arc_serial_set_termios(struct uart_port *port, struct ktermios *new,
|
|
uartl = hw_val & 0xFF;
|
|
uarth = (hw_val >> 8) & 0xFF;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
UART_ALL_IRQ_DISABLE(port);
|
|
|
|
@@ -391,7 +391,7 @@ arc_serial_set_termios(struct uart_port *port, struct ktermios *new,
|
|
|
|
uart_update_timeout(port, new->c_cflag, baud);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *arc_serial_type(struct uart_port *port)
|
|
@@ -521,9 +521,9 @@ static void arc_serial_console_write(struct console *co, const char *s,
|
|
struct uart_port *port = &arc_uart_ports[co->index].port;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
uart_console_write(port, s, count, arc_serial_console_putchar);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static struct console arc_console = {
|
|
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
|
|
index bcca5627afac..5a3f2fc476f9 100644
|
|
--- a/drivers/tty/serial/atmel_serial.c
|
|
+++ b/drivers/tty/serial/atmel_serial.c
|
|
@@ -861,7 +861,7 @@ static void atmel_complete_tx_dma(void *arg)
|
|
struct dma_chan *chan = atmel_port->chan_tx;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
if (chan)
|
|
dmaengine_terminate_all(chan);
|
|
@@ -893,7 +893,7 @@ static void atmel_complete_tx_dma(void *arg)
|
|
atmel_port->tx_done_mask);
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void atmel_release_tx_dma(struct uart_port *port)
|
|
@@ -1711,9 +1711,9 @@ static void atmel_tasklet_rx_func(struct tasklet_struct *t)
|
|
struct uart_port *port = &atmel_port->uart;
|
|
|
|
/* The interrupt handler does not take the lock */
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
atmel_port->schedule_rx(port);
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
}
|
|
|
|
static void atmel_tasklet_tx_func(struct tasklet_struct *t)
|
|
@@ -1723,9 +1723,9 @@ static void atmel_tasklet_tx_func(struct tasklet_struct *t)
|
|
struct uart_port *port = &atmel_port->uart;
|
|
|
|
/* The interrupt handler does not take the lock */
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
atmel_port->schedule_tx(port);
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
}
|
|
|
|
static void atmel_init_property(struct atmel_uart_port *atmel_port,
|
|
@@ -2175,7 +2175,7 @@ static void atmel_set_termios(struct uart_port *port,
|
|
} else
|
|
mode |= ATMEL_US_PAR_NONE;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
port->read_status_mask = ATMEL_US_OVRE;
|
|
if (termios->c_iflag & INPCK)
|
|
@@ -2377,22 +2377,22 @@ static void atmel_set_termios(struct uart_port *port,
|
|
else
|
|
atmel_disable_ms(port);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void atmel_set_ldisc(struct uart_port *port, struct ktermios *termios)
|
|
{
|
|
if (termios->c_line == N_PPS) {
|
|
port->flags |= UPF_HARDPPS_CD;
|
|
- spin_lock_irq(&port->lock);
|
|
+ uart_port_lock_irq(port);
|
|
atmel_enable_ms(port);
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
} else {
|
|
port->flags &= ~UPF_HARDPPS_CD;
|
|
if (!UART_ENABLE_MS(port, termios->c_cflag)) {
|
|
- spin_lock_irq(&port->lock);
|
|
+ uart_port_lock_irq(port);
|
|
atmel_disable_ms(port);
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
}
|
|
}
|
|
}
|
|
diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c
|
|
index 44c27e5cefbc..b104c36ce5c0 100644
|
|
--- a/drivers/tty/serial/bcm63xx_uart.c
|
|
+++ b/drivers/tty/serial/bcm63xx_uart.c
|
|
@@ -201,7 +201,7 @@ static void bcm_uart_break_ctl(struct uart_port *port, int ctl)
|
|
unsigned long flags;
|
|
unsigned int val;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
val = bcm_uart_readl(port, UART_CTL_REG);
|
|
if (ctl)
|
|
@@ -210,7 +210,7 @@ static void bcm_uart_break_ctl(struct uart_port *port, int ctl)
|
|
val &= ~UART_CTL_XMITBRK_MASK;
|
|
bcm_uart_writel(port, val, UART_CTL_REG);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/*
|
|
@@ -335,7 +335,7 @@ static irqreturn_t bcm_uart_interrupt(int irq, void *dev_id)
|
|
unsigned int irqstat;
|
|
|
|
port = dev_id;
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
irqstat = bcm_uart_readl(port, UART_IR_REG);
|
|
if (irqstat & UART_RX_INT_STAT)
|
|
@@ -356,7 +356,7 @@ static irqreturn_t bcm_uart_interrupt(int irq, void *dev_id)
|
|
estat & UART_EXTINP_DCD_MASK);
|
|
}
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
@@ -454,9 +454,9 @@ static void bcm_uart_shutdown(struct uart_port *port)
|
|
{
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
bcm_uart_writel(port, 0, UART_IR_REG);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
bcm_uart_disable(port);
|
|
bcm_uart_flush(port);
|
|
@@ -473,7 +473,7 @@ static void bcm_uart_set_termios(struct uart_port *port, struct ktermios *new,
|
|
unsigned long flags;
|
|
int tries;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Drain the hot tub fully before we power it off for the winter. */
|
|
for (tries = 3; !bcm_uart_tx_empty(port) && tries; tries--)
|
|
@@ -549,7 +549,7 @@ static void bcm_uart_set_termios(struct uart_port *port, struct ktermios *new,
|
|
|
|
uart_update_timeout(port, new->c_cflag, baud);
|
|
bcm_uart_enable(port);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/*
|
|
@@ -715,9 +715,9 @@ static void bcm_console_write(struct console *co, const char *s,
|
|
/* bcm_uart_interrupt() already took the lock */
|
|
locked = 0;
|
|
} else if (oops_in_progress) {
|
|
- locked = spin_trylock(&port->lock);
|
|
+ locked = uart_port_trylock(port);
|
|
} else {
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
locked = 1;
|
|
}
|
|
|
|
@@ -728,7 +728,7 @@ static void bcm_console_write(struct console *co, const char *s,
|
|
wait_for_xmitr(port);
|
|
|
|
if (locked)
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
local_irq_restore(flags);
|
|
}
|
|
|
|
diff --git a/drivers/tty/serial/cpm_uart.c b/drivers/tty/serial/cpm_uart.c
|
|
index 626423022d62..be4af6eda4c2 100644
|
|
--- a/drivers/tty/serial/cpm_uart.c
|
|
+++ b/drivers/tty/serial/cpm_uart.c
|
|
@@ -569,7 +569,7 @@ static void cpm_uart_set_termios(struct uart_port *port,
|
|
if ((termios->c_cflag & CREAD) == 0)
|
|
port->read_status_mask &= ~BD_SC_EMPTY;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
if (IS_SMC(pinfo)) {
|
|
unsigned int bits = tty_get_frame_size(termios->c_cflag);
|
|
@@ -609,7 +609,7 @@ static void cpm_uart_set_termios(struct uart_port *port,
|
|
clk_set_rate(pinfo->clk, baud);
|
|
else
|
|
cpm_setbrg(pinfo->brg - 1, baud);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *cpm_uart_type(struct uart_port *port)
|
|
@@ -1386,9 +1386,9 @@ static void cpm_uart_console_write(struct console *co, const char *s,
|
|
cpm_uart_early_write(pinfo, s, count, true);
|
|
local_irq_restore(flags);
|
|
} else {
|
|
- spin_lock_irqsave(&pinfo->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&pinfo->port, &flags);
|
|
cpm_uart_early_write(pinfo, s, count, true);
|
|
- spin_unlock_irqrestore(&pinfo->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&pinfo->port, flags);
|
|
}
|
|
}
|
|
|
|
diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c
|
|
index 128b5479e813..5004125f3045 100644
|
|
--- a/drivers/tty/serial/digicolor-usart.c
|
|
+++ b/drivers/tty/serial/digicolor-usart.c
|
|
@@ -133,7 +133,7 @@ static void digicolor_uart_rx(struct uart_port *port)
|
|
{
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
while (1) {
|
|
u8 status, ch, ch_flag;
|
|
@@ -172,7 +172,7 @@ static void digicolor_uart_rx(struct uart_port *port)
|
|
ch_flag);
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
tty_flip_buffer_push(&port->state->port);
|
|
}
|
|
@@ -185,7 +185,7 @@ static void digicolor_uart_tx(struct uart_port *port)
|
|
if (digicolor_uart_tx_full(port))
|
|
return;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
if (port->x_char) {
|
|
writeb_relaxed(port->x_char, port->membase + UA_EMI_REC);
|
|
@@ -211,7 +211,7 @@ static void digicolor_uart_tx(struct uart_port *port)
|
|
uart_write_wakeup(port);
|
|
|
|
out:
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static irqreturn_t digicolor_uart_int(int irq, void *dev_id)
|
|
@@ -333,7 +333,7 @@ static void digicolor_uart_set_termios(struct uart_port *port,
|
|
port->ignore_status_mask |= UA_STATUS_OVERRUN_ERR
|
|
| UA_STATUS_PARITY_ERR | UA_STATUS_FRAME_ERR;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
|
|
@@ -341,7 +341,7 @@ static void digicolor_uart_set_termios(struct uart_port *port,
|
|
writeb_relaxed(divisor & 0xff, port->membase + UA_HBAUD_LO);
|
|
writeb_relaxed(divisor >> 8, port->membase + UA_HBAUD_HI);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *digicolor_uart_type(struct uart_port *port)
|
|
@@ -398,14 +398,14 @@ static void digicolor_uart_console_write(struct console *co, const char *c,
|
|
int locked = 1;
|
|
|
|
if (oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&port->lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(port, &flags);
|
|
else
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
uart_console_write(port, c, n, digicolor_uart_console_putchar);
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
/* Wait for transmitter to become empty */
|
|
do {
|
|
diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c
|
|
index 667f52e83277..6df7af9edc1c 100644
|
|
--- a/drivers/tty/serial/dz.c
|
|
+++ b/drivers/tty/serial/dz.c
|
|
@@ -268,9 +268,9 @@ static inline void dz_transmit_chars(struct dz_mux *mux)
|
|
}
|
|
/* If nothing to do or stopped or hardware stopped. */
|
|
if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) {
|
|
- spin_lock(&dport->port.lock);
|
|
+ uart_port_lock(&dport->port);
|
|
dz_stop_tx(&dport->port);
|
|
- spin_unlock(&dport->port.lock);
|
|
+ uart_port_unlock(&dport->port);
|
|
return;
|
|
}
|
|
|
|
@@ -287,9 +287,9 @@ static inline void dz_transmit_chars(struct dz_mux *mux)
|
|
|
|
/* Are we are done. */
|
|
if (uart_circ_empty(xmit)) {
|
|
- spin_lock(&dport->port.lock);
|
|
+ uart_port_lock(&dport->port);
|
|
dz_stop_tx(&dport->port);
|
|
- spin_unlock(&dport->port.lock);
|
|
+ uart_port_unlock(&dport->port);
|
|
}
|
|
}
|
|
|
|
@@ -415,14 +415,14 @@ static int dz_startup(struct uart_port *uport)
|
|
return ret;
|
|
}
|
|
|
|
- spin_lock_irqsave(&dport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&dport->port, &flags);
|
|
|
|
/* Enable interrupts. */
|
|
tmp = dz_in(dport, DZ_CSR);
|
|
tmp |= DZ_RIE | DZ_TIE;
|
|
dz_out(dport, DZ_CSR, tmp);
|
|
|
|
- spin_unlock_irqrestore(&dport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&dport->port, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -443,9 +443,9 @@ static void dz_shutdown(struct uart_port *uport)
|
|
int irq_guard;
|
|
u16 tmp;
|
|
|
|
- spin_lock_irqsave(&dport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&dport->port, &flags);
|
|
dz_stop_tx(&dport->port);
|
|
- spin_unlock_irqrestore(&dport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&dport->port, flags);
|
|
|
|
irq_guard = atomic_add_return(-1, &mux->irq_guard);
|
|
if (!irq_guard) {
|
|
@@ -491,14 +491,14 @@ static void dz_break_ctl(struct uart_port *uport, int break_state)
|
|
unsigned long flags;
|
|
unsigned short tmp, mask = 1 << dport->port.line;
|
|
|
|
- spin_lock_irqsave(&uport->lock, flags);
|
|
+ uart_port_lock_irqsave(uport, &flags);
|
|
tmp = dz_in(dport, DZ_TCR);
|
|
if (break_state)
|
|
tmp |= mask;
|
|
else
|
|
tmp &= ~mask;
|
|
dz_out(dport, DZ_TCR, tmp);
|
|
- spin_unlock_irqrestore(&uport->lock, flags);
|
|
+ uart_port_unlock_irqrestore(uport, flags);
|
|
}
|
|
|
|
static int dz_encode_baud_rate(unsigned int baud)
|
|
@@ -608,7 +608,7 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
|
|
if (termios->c_cflag & CREAD)
|
|
cflag |= DZ_RXENAB;
|
|
|
|
- spin_lock_irqsave(&dport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&dport->port, &flags);
|
|
|
|
uart_update_timeout(uport, termios->c_cflag, baud);
|
|
|
|
@@ -631,7 +631,7 @@ static void dz_set_termios(struct uart_port *uport, struct ktermios *termios,
|
|
if (termios->c_iflag & IGNBRK)
|
|
dport->port.ignore_status_mask |= DZ_BREAK;
|
|
|
|
- spin_unlock_irqrestore(&dport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&dport->port, flags);
|
|
}
|
|
|
|
/*
|
|
@@ -645,12 +645,12 @@ static void dz_pm(struct uart_port *uport, unsigned int state,
|
|
struct dz_port *dport = to_dport(uport);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&dport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&dport->port, &flags);
|
|
if (state < 3)
|
|
dz_start_tx(&dport->port);
|
|
else
|
|
dz_stop_tx(&dport->port);
|
|
- spin_unlock_irqrestore(&dport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&dport->port, flags);
|
|
}
|
|
|
|
|
|
@@ -811,7 +811,7 @@ static void dz_console_putchar(struct uart_port *uport, unsigned char ch)
|
|
unsigned short csr, tcr, trdy, mask;
|
|
int loops = 10000;
|
|
|
|
- spin_lock_irqsave(&dport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&dport->port, &flags);
|
|
csr = dz_in(dport, DZ_CSR);
|
|
dz_out(dport, DZ_CSR, csr & ~DZ_TIE);
|
|
tcr = dz_in(dport, DZ_TCR);
|
|
@@ -819,7 +819,7 @@ static void dz_console_putchar(struct uart_port *uport, unsigned char ch)
|
|
mask = tcr;
|
|
dz_out(dport, DZ_TCR, mask);
|
|
iob();
|
|
- spin_unlock_irqrestore(&dport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&dport->port, flags);
|
|
|
|
do {
|
|
trdy = dz_in(dport, DZ_CSR);
|
|
diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
|
|
index 249cb380c3c6..7fa809a405e8 100644
|
|
--- a/drivers/tty/serial/fsl_linflexuart.c
|
|
+++ b/drivers/tty/serial/fsl_linflexuart.c
|
|
@@ -203,7 +203,7 @@ static irqreturn_t linflex_txint(int irq, void *dev_id)
|
|
struct circ_buf *xmit = &sport->state->xmit;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&sport->lock, flags);
|
|
+ uart_port_lock_irqsave(sport, &flags);
|
|
|
|
if (sport->x_char) {
|
|
linflex_put_char(sport, sport->x_char);
|
|
@@ -217,7 +217,7 @@ static irqreturn_t linflex_txint(int irq, void *dev_id)
|
|
|
|
linflex_transmit_buffer(sport);
|
|
out:
|
|
- spin_unlock_irqrestore(&sport->lock, flags);
|
|
+ uart_port_unlock_irqrestore(sport, flags);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
@@ -230,7 +230,7 @@ static irqreturn_t linflex_rxint(int irq, void *dev_id)
|
|
unsigned char rx;
|
|
bool brk;
|
|
|
|
- spin_lock_irqsave(&sport->lock, flags);
|
|
+ uart_port_lock_irqsave(sport, &flags);
|
|
|
|
status = readl(sport->membase + UARTSR);
|
|
while (status & LINFLEXD_UARTSR_RMB) {
|
|
@@ -266,7 +266,7 @@ static irqreturn_t linflex_rxint(int irq, void *dev_id)
|
|
}
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&sport->lock, flags);
|
|
+ uart_port_unlock_irqrestore(sport, flags);
|
|
|
|
tty_flip_buffer_push(port);
|
|
|
|
@@ -369,11 +369,11 @@ static int linflex_startup(struct uart_port *port)
|
|
int ret = 0;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
linflex_setup_watermark(port);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
ret = devm_request_irq(port->dev, port->irq, linflex_int, 0,
|
|
DRIVER_NAME, port);
|
|
@@ -386,14 +386,14 @@ static void linflex_shutdown(struct uart_port *port)
|
|
unsigned long ier;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* disable interrupts */
|
|
ier = readl(port->membase + LINIER);
|
|
ier &= ~(LINFLEXD_LINIER_DRIE | LINFLEXD_LINIER_DTIE);
|
|
writel(ier, port->membase + LINIER);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
devm_free_irq(port->dev, port->irq, port);
|
|
}
|
|
@@ -474,7 +474,7 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
cr &= ~LINFLEXD_UARTCR_PCE;
|
|
}
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
port->read_status_mask = 0;
|
|
|
|
@@ -507,7 +507,7 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
|
|
writel(cr1, port->membase + LINCR1);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *linflex_type(struct uart_port *port)
|
|
@@ -646,14 +646,14 @@ linflex_console_write(struct console *co, const char *s, unsigned int count)
|
|
if (sport->sysrq)
|
|
locked = 0;
|
|
else if (oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&sport->lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(sport, &flags);
|
|
else
|
|
- spin_lock_irqsave(&sport->lock, flags);
|
|
+ uart_port_lock_irqsave(sport, &flags);
|
|
|
|
linflex_string_write(sport, s, count);
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&sport->lock, flags);
|
|
+ uart_port_unlock_irqrestore(sport, flags);
|
|
}
|
|
|
|
/*
|
|
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
|
|
index 11f6fabce051..1f7478c72e66 100644
|
|
--- a/drivers/tty/serial/fsl_lpuart.c
|
|
+++ b/drivers/tty/serial/fsl_lpuart.c
|
|
@@ -547,9 +547,9 @@ static void lpuart_dma_tx_complete(void *arg)
|
|
struct dma_chan *chan = sport->dma_tx_chan;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
if (!sport->dma_tx_in_progress) {
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
return;
|
|
}
|
|
|
|
@@ -558,7 +558,7 @@ static void lpuart_dma_tx_complete(void *arg)
|
|
|
|
uart_xmit_advance(&sport->port, sport->dma_tx_bytes);
|
|
sport->dma_tx_in_progress = false;
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
|
|
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
|
uart_write_wakeup(&sport->port);
|
|
@@ -568,12 +568,12 @@ static void lpuart_dma_tx_complete(void *arg)
|
|
return;
|
|
}
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
|
|
if (!lpuart_stopped_or_empty(&sport->port))
|
|
lpuart_dma_tx(sport);
|
|
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
}
|
|
|
|
static dma_addr_t lpuart_dma_datareg_addr(struct lpuart_port *sport)
|
|
@@ -666,7 +666,7 @@ static int lpuart_poll_init(struct uart_port *port)
|
|
|
|
sport->port.fifosize = 0;
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
/* Disable Rx & Tx */
|
|
writeb(0, sport->port.membase + UARTCR2);
|
|
|
|
@@ -690,7 +690,7 @@ static int lpuart_poll_init(struct uart_port *port)
|
|
|
|
/* Enable Rx and Tx */
|
|
writeb(UARTCR2_RE | UARTCR2_TE, sport->port.membase + UARTCR2);
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -718,7 +718,7 @@ static int lpuart32_poll_init(struct uart_port *port)
|
|
|
|
sport->port.fifosize = 0;
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
|
|
/* Disable Rx & Tx */
|
|
lpuart32_write(&sport->port, 0, UARTCTRL);
|
|
@@ -739,7 +739,7 @@ static int lpuart32_poll_init(struct uart_port *port)
|
|
|
|
/* Enable Rx and Tx */
|
|
lpuart32_write(&sport->port, UARTCTRL_RE | UARTCTRL_TE, UARTCTRL);
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -902,9 +902,9 @@ static unsigned int lpuart32_tx_empty(struct uart_port *port)
|
|
|
|
static void lpuart_txint(struct lpuart_port *sport)
|
|
{
|
|
- spin_lock(&sport->port.lock);
|
|
+ uart_port_lock(&sport->port);
|
|
lpuart_transmit_buffer(sport);
|
|
- spin_unlock(&sport->port.lock);
|
|
+ uart_port_unlock(&sport->port);
|
|
}
|
|
|
|
static void lpuart_rxint(struct lpuart_port *sport)
|
|
@@ -913,7 +913,7 @@ static void lpuart_rxint(struct lpuart_port *sport)
|
|
struct tty_port *port = &sport->port.state->port;
|
|
unsigned char rx, sr;
|
|
|
|
- spin_lock(&sport->port.lock);
|
|
+ uart_port_lock(&sport->port);
|
|
|
|
while (!(readb(sport->port.membase + UARTSFIFO) & UARTSFIFO_RXEMPT)) {
|
|
flg = TTY_NORMAL;
|
|
@@ -979,9 +979,9 @@ static void lpuart_rxint(struct lpuart_port *sport)
|
|
|
|
static void lpuart32_txint(struct lpuart_port *sport)
|
|
{
|
|
- spin_lock(&sport->port.lock);
|
|
+ uart_port_lock(&sport->port);
|
|
lpuart32_transmit_buffer(sport);
|
|
- spin_unlock(&sport->port.lock);
|
|
+ uart_port_unlock(&sport->port);
|
|
}
|
|
|
|
static void lpuart32_rxint(struct lpuart_port *sport)
|
|
@@ -991,7 +991,7 @@ static void lpuart32_rxint(struct lpuart_port *sport)
|
|
unsigned long rx, sr;
|
|
bool is_break;
|
|
|
|
- spin_lock(&sport->port.lock);
|
|
+ uart_port_lock(&sport->port);
|
|
|
|
while (!(lpuart32_read(&sport->port, UARTFIFO) & UARTFIFO_RXEMPT)) {
|
|
flg = TTY_NORMAL;
|
|
@@ -1193,12 +1193,12 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
|
|
|
|
async_tx_ack(sport->dma_rx_desc);
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
|
|
dmastat = dmaengine_tx_status(chan, sport->dma_rx_cookie, &state);
|
|
if (dmastat == DMA_ERROR) {
|
|
dev_err(sport->port.dev, "Rx DMA transfer failed!\n");
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
return;
|
|
}
|
|
|
|
@@ -1267,7 +1267,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
|
|
dma_sync_sg_for_device(chan->device->dev, &sport->rx_sgl, 1,
|
|
DMA_FROM_DEVICE);
|
|
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
|
|
tty_flip_buffer_push(port);
|
|
if (!sport->dma_idle_int)
|
|
@@ -1358,9 +1358,9 @@ static void lpuart_timer_func(struct timer_list *t)
|
|
mod_timer(&sport->lpuart_timer,
|
|
jiffies + sport->dma_rx_timeout);
|
|
|
|
- if (spin_trylock_irqsave(&sport->port.lock, flags)) {
|
|
+ if (uart_port_trylock_irqsave(&sport->port, &flags)) {
|
|
sport->last_residue = state.residue;
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
}
|
|
}
|
|
|
|
@@ -1838,14 +1838,14 @@ static void lpuart_hw_setup(struct lpuart_port *sport)
|
|
{
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
|
|
lpuart_setup_watermark_enable(sport);
|
|
|
|
lpuart_rx_dma_startup(sport);
|
|
lpuart_tx_dma_startup(sport);
|
|
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
}
|
|
|
|
static int lpuart_startup(struct uart_port *port)
|
|
@@ -1895,7 +1895,7 @@ static void lpuart32_hw_setup(struct lpuart_port *sport)
|
|
{
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
|
|
lpuart32_hw_disable(sport);
|
|
|
|
@@ -1905,7 +1905,7 @@ static void lpuart32_hw_setup(struct lpuart_port *sport)
|
|
lpuart32_setup_watermark_enable(sport);
|
|
lpuart32_configure(sport);
|
|
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
}
|
|
|
|
static int lpuart32_startup(struct uart_port *port)
|
|
@@ -1977,7 +1977,7 @@ static void lpuart_shutdown(struct uart_port *port)
|
|
unsigned char temp;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* disable Rx/Tx and interrupts */
|
|
temp = readb(port->membase + UARTCR2);
|
|
@@ -1985,7 +1985,7 @@ static void lpuart_shutdown(struct uart_port *port)
|
|
UARTCR2_TIE | UARTCR2_TCIE | UARTCR2_RIE);
|
|
writeb(temp, port->membase + UARTCR2);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
lpuart_dma_shutdown(sport);
|
|
}
|
|
@@ -1997,7 +1997,7 @@ static void lpuart32_shutdown(struct uart_port *port)
|
|
unsigned long temp;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* clear status */
|
|
temp = lpuart32_read(&sport->port, UARTSTAT);
|
|
@@ -2014,7 +2014,7 @@ static void lpuart32_shutdown(struct uart_port *port)
|
|
UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE | UARTCTRL_SBK);
|
|
lpuart32_write(port, temp, UARTCTRL);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
lpuart_dma_shutdown(sport);
|
|
}
|
|
@@ -2114,7 +2114,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
if (old && sport->lpuart_dma_rx_use)
|
|
lpuart_dma_rx_free(&sport->port);
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
|
|
sport->port.read_status_mask = 0;
|
|
if (termios->c_iflag & INPCK)
|
|
@@ -2169,7 +2169,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
sport->lpuart_dma_rx_use = false;
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
}
|
|
|
|
static void __lpuart32_serial_setbrg(struct uart_port *port,
|
|
@@ -2358,7 +2358,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
if (old && sport->lpuart_dma_rx_use)
|
|
lpuart_dma_rx_free(&sport->port);
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
|
|
sport->port.read_status_mask = 0;
|
|
if (termios->c_iflag & INPCK)
|
|
@@ -2416,7 +2416,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
sport->lpuart_dma_rx_use = false;
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
}
|
|
|
|
static const char *lpuart_type(struct uart_port *port)
|
|
@@ -2534,9 +2534,9 @@ lpuart_console_write(struct console *co, const char *s, unsigned int count)
|
|
int locked = 1;
|
|
|
|
if (oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&sport->port.lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(&sport->port, &flags);
|
|
else
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
|
|
/* first save CR2 and then disable interrupts */
|
|
cr2 = old_cr2 = readb(sport->port.membase + UARTCR2);
|
|
@@ -2552,7 +2552,7 @@ lpuart_console_write(struct console *co, const char *s, unsigned int count)
|
|
writeb(old_cr2, sport->port.membase + UARTCR2);
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
}
|
|
|
|
static void
|
|
@@ -2564,9 +2564,9 @@ lpuart32_console_write(struct console *co, const char *s, unsigned int count)
|
|
int locked = 1;
|
|
|
|
if (oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&sport->port.lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(&sport->port, &flags);
|
|
else
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
|
|
/* first save CR2 and then disable interrupts */
|
|
cr = old_cr = lpuart32_read(&sport->port, UARTCTRL);
|
|
@@ -2582,7 +2582,7 @@ lpuart32_console_write(struct console *co, const char *s, unsigned int count)
|
|
lpuart32_write(&sport->port, old_cr, UARTCTRL);
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
}
|
|
|
|
/*
|
|
@@ -3158,7 +3158,7 @@ static int lpuart_suspend(struct device *dev)
|
|
uart_suspend_port(&lpuart_reg, &sport->port);
|
|
|
|
if (lpuart_uport_is_active(sport)) {
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
if (lpuart_is_32(sport)) {
|
|
/* disable Rx/Tx and interrupts */
|
|
temp = lpuart32_read(&sport->port, UARTCTRL);
|
|
@@ -3170,7 +3170,7 @@ static int lpuart_suspend(struct device *dev)
|
|
temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE);
|
|
writeb(temp, sport->port.membase + UARTCR2);
|
|
}
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
|
|
if (sport->lpuart_dma_rx_use) {
|
|
/*
|
|
@@ -3183,7 +3183,7 @@ static int lpuart_suspend(struct device *dev)
|
|
lpuart_dma_rx_free(&sport->port);
|
|
|
|
/* Disable Rx DMA to use UART port as wakeup source */
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
if (lpuart_is_32(sport)) {
|
|
temp = lpuart32_read(&sport->port, UARTBAUD);
|
|
lpuart32_write(&sport->port, temp & ~UARTBAUD_RDMAE,
|
|
@@ -3192,11 +3192,11 @@ static int lpuart_suspend(struct device *dev)
|
|
writeb(readb(sport->port.membase + UARTCR5) &
|
|
~UARTCR5_RDMAS, sport->port.membase + UARTCR5);
|
|
}
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
}
|
|
|
|
if (sport->lpuart_dma_tx_use) {
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
if (lpuart_is_32(sport)) {
|
|
temp = lpuart32_read(&sport->port, UARTBAUD);
|
|
temp &= ~UARTBAUD_TDMAE;
|
|
@@ -3206,7 +3206,7 @@ static int lpuart_suspend(struct device *dev)
|
|
temp &= ~UARTCR5_TDMAS;
|
|
writeb(temp, sport->port.membase + UARTCR5);
|
|
}
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
sport->dma_tx_in_progress = false;
|
|
dmaengine_terminate_sync(sport->dma_tx_chan);
|
|
}
|
|
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
|
|
index 819f957b6b84..a75eafbcbea3 100644
|
|
--- a/drivers/tty/serial/icom.c
|
|
+++ b/drivers/tty/serial/icom.c
|
|
@@ -929,7 +929,7 @@ static inline void check_modem_status(struct icom_port *icom_port)
|
|
char delta_status;
|
|
unsigned char status;
|
|
|
|
- spin_lock(&icom_port->uart_port.lock);
|
|
+ uart_port_lock(&icom_port->uart_port);
|
|
|
|
/*modem input register */
|
|
status = readb(&icom_port->dram->isr);
|
|
@@ -951,7 +951,7 @@ static inline void check_modem_status(struct icom_port *icom_port)
|
|
port.delta_msr_wait);
|
|
old_status = status;
|
|
}
|
|
- spin_unlock(&icom_port->uart_port.lock);
|
|
+ uart_port_unlock(&icom_port->uart_port);
|
|
}
|
|
|
|
static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port)
|
|
@@ -1093,7 +1093,7 @@ static void process_interrupt(u16 port_int_reg,
|
|
struct icom_port *icom_port)
|
|
{
|
|
|
|
- spin_lock(&icom_port->uart_port.lock);
|
|
+ uart_port_lock(&icom_port->uart_port);
|
|
trace(icom_port, "INTERRUPT", port_int_reg);
|
|
|
|
if (port_int_reg & (INT_XMIT_COMPLETED | INT_XMIT_DISABLED))
|
|
@@ -1102,7 +1102,7 @@ static void process_interrupt(u16 port_int_reg,
|
|
if (port_int_reg & INT_RCV_COMPLETED)
|
|
recv_interrupt(port_int_reg, icom_port);
|
|
|
|
- spin_unlock(&icom_port->uart_port.lock);
|
|
+ uart_port_unlock(&icom_port->uart_port);
|
|
}
|
|
|
|
static irqreturn_t icom_interrupt(int irq, void *dev_id)
|
|
@@ -1186,14 +1186,14 @@ static unsigned int icom_tx_empty(struct uart_port *port)
|
|
int ret;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
if (le16_to_cpu(icom_port->statStg->xmit[0].flags) &
|
|
SA_FLAGS_READY_TO_XMIT)
|
|
ret = TIOCSER_TEMT;
|
|
else
|
|
ret = 0;
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
return ret;
|
|
}
|
|
|
|
@@ -1276,7 +1276,7 @@ static void icom_send_xchar(struct uart_port *port, char ch)
|
|
|
|
/* wait .1 sec to send char */
|
|
for (index = 0; index < 10; index++) {
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
xdata = readb(&icom_port->dram->xchar);
|
|
if (xdata == 0x00) {
|
|
trace(icom_port, "QUICK_WRITE", 0);
|
|
@@ -1284,10 +1284,10 @@ static void icom_send_xchar(struct uart_port *port, char ch)
|
|
|
|
/* flush write operation */
|
|
xdata = readb(&icom_port->dram->xchar);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
break;
|
|
}
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
msleep(10);
|
|
}
|
|
}
|
|
@@ -1307,7 +1307,7 @@ static void icom_break(struct uart_port *port, int break_state)
|
|
unsigned char cmdReg;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
trace(icom_port, "BREAK", 0);
|
|
cmdReg = readb(&icom_port->dram->CmdReg);
|
|
if (break_state == -1) {
|
|
@@ -1315,7 +1315,7 @@ static void icom_break(struct uart_port *port, int break_state)
|
|
} else {
|
|
writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg);
|
|
}
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static int icom_open(struct uart_port *port)
|
|
@@ -1365,7 +1365,7 @@ static void icom_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
unsigned long offset;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
trace(icom_port, "CHANGE_SPEED", 0);
|
|
|
|
cflag = termios->c_cflag;
|
|
@@ -1516,7 +1516,7 @@ static void icom_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
trace(icom_port, "XR_ENAB", 0);
|
|
writeb(CMD_XMIT_RCV_ENABLE, &icom_port->dram->CmdReg);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *icom_type(struct uart_port *port)
|
|
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
|
|
index 70641b53e008..88a45ba65123 100644
|
|
--- a/drivers/tty/serial/imx.c
|
|
+++ b/drivers/tty/serial/imx.c
|
|
@@ -596,7 +596,7 @@ static void imx_uart_dma_tx_callback(void *data)
|
|
unsigned long flags;
|
|
u32 ucr1;
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
|
|
dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
|
|
|
|
@@ -621,7 +621,7 @@ static void imx_uart_dma_tx_callback(void *data)
|
|
imx_uart_writel(sport, ucr4, UCR4);
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
}
|
|
|
|
/* called with port.lock taken and irqs off */
|
|
@@ -795,11 +795,11 @@ static irqreturn_t imx_uart_rtsint(int irq, void *dev_id)
|
|
struct imx_port *sport = dev_id;
|
|
irqreturn_t ret;
|
|
|
|
- spin_lock(&sport->port.lock);
|
|
+ uart_port_lock(&sport->port);
|
|
|
|
ret = __imx_uart_rtsint(irq, dev_id);
|
|
|
|
- spin_unlock(&sport->port.lock);
|
|
+ uart_port_unlock(&sport->port);
|
|
|
|
return ret;
|
|
}
|
|
@@ -808,9 +808,9 @@ static irqreturn_t imx_uart_txint(int irq, void *dev_id)
|
|
{
|
|
struct imx_port *sport = dev_id;
|
|
|
|
- spin_lock(&sport->port.lock);
|
|
+ uart_port_lock(&sport->port);
|
|
imx_uart_transmit_buffer(sport);
|
|
- spin_unlock(&sport->port.lock);
|
|
+ uart_port_unlock(&sport->port);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
@@ -924,11 +924,11 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id)
|
|
struct imx_port *sport = dev_id;
|
|
irqreturn_t ret;
|
|
|
|
- spin_lock(&sport->port.lock);
|
|
+ uart_port_lock(&sport->port);
|
|
|
|
ret = __imx_uart_rxint(irq, dev_id);
|
|
|
|
- spin_unlock(&sport->port.lock);
|
|
+ uart_port_unlock(&sport->port);
|
|
|
|
return ret;
|
|
}
|
|
@@ -991,7 +991,7 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id)
|
|
unsigned int usr1, usr2, ucr1, ucr2, ucr3, ucr4;
|
|
irqreturn_t ret = IRQ_NONE;
|
|
|
|
- spin_lock(&sport->port.lock);
|
|
+ uart_port_lock(&sport->port);
|
|
|
|
usr1 = imx_uart_readl(sport, USR1);
|
|
usr2 = imx_uart_readl(sport, USR2);
|
|
@@ -1061,7 +1061,7 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id)
|
|
ret = IRQ_HANDLED;
|
|
}
|
|
|
|
- spin_unlock(&sport->port.lock);
|
|
+ uart_port_unlock(&sport->port);
|
|
|
|
return ret;
|
|
}
|
|
@@ -1144,7 +1144,7 @@ static void imx_uart_break_ctl(struct uart_port *port, int break_state)
|
|
unsigned long flags;
|
|
u32 ucr1;
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
|
|
ucr1 = imx_uart_readl(sport, UCR1) & ~UCR1_SNDBRK;
|
|
|
|
@@ -1153,7 +1153,7 @@ static void imx_uart_break_ctl(struct uart_port *port, int break_state)
|
|
|
|
imx_uart_writel(sport, ucr1, UCR1);
|
|
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
}
|
|
|
|
/*
|
|
@@ -1166,9 +1166,9 @@ static void imx_uart_timeout(struct timer_list *t)
|
|
unsigned long flags;
|
|
|
|
if (sport->port.state) {
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
imx_uart_mctrl_check(sport);
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
|
|
mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
|
|
}
|
|
@@ -1198,9 +1198,9 @@ static void imx_uart_dma_rx_callback(void *data)
|
|
status = dmaengine_tx_status(chan, sport->rx_cookie, &state);
|
|
|
|
if (status == DMA_ERROR) {
|
|
- spin_lock(&sport->port.lock);
|
|
+ uart_port_lock(&sport->port);
|
|
imx_uart_clear_rx_errors(sport);
|
|
- spin_unlock(&sport->port.lock);
|
|
+ uart_port_unlock(&sport->port);
|
|
return;
|
|
}
|
|
|
|
@@ -1229,9 +1229,9 @@ static void imx_uart_dma_rx_callback(void *data)
|
|
r_bytes = rx_ring->head - rx_ring->tail;
|
|
|
|
/* If we received something, check for 0xff flood */
|
|
- spin_lock(&sport->port.lock);
|
|
+ uart_port_lock(&sport->port);
|
|
imx_uart_check_flood(sport, imx_uart_readl(sport, USR2));
|
|
- spin_unlock(&sport->port.lock);
|
|
+ uart_port_unlock(&sport->port);
|
|
|
|
if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) {
|
|
|
|
@@ -1504,7 +1504,7 @@ static int imx_uart_startup(struct uart_port *port)
|
|
if (!uart_console(port) && imx_uart_dma_init(sport) == 0)
|
|
dma_is_inited = 1;
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
|
|
/* Reset fifo's and state machines */
|
|
imx_uart_soft_reset(sport);
|
|
@@ -1578,7 +1578,7 @@ static int imx_uart_startup(struct uart_port *port)
|
|
|
|
imx_uart_disable_loopback_rs485(sport);
|
|
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -1603,21 +1603,21 @@ static void imx_uart_shutdown(struct uart_port *port)
|
|
sport->dma_is_rxing = 0;
|
|
}
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
imx_uart_stop_tx(port);
|
|
imx_uart_stop_rx(port);
|
|
imx_uart_disable_dma(sport);
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
imx_uart_dma_exit(sport);
|
|
}
|
|
|
|
mctrl_gpio_disable_ms(sport->gpios);
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
ucr2 = imx_uart_readl(sport, UCR2);
|
|
ucr2 &= ~(UCR2_TXEN | UCR2_ATEN);
|
|
imx_uart_writel(sport, ucr2, UCR2);
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
|
|
/*
|
|
* Stop our timer.
|
|
@@ -1628,7 +1628,7 @@ static void imx_uart_shutdown(struct uart_port *port)
|
|
* Disable all interrupts, port and break condition.
|
|
*/
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
|
|
ucr1 = imx_uart_readl(sport, UCR1);
|
|
ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_RXDMAEN |
|
|
@@ -1650,7 +1650,7 @@ static void imx_uart_shutdown(struct uart_port *port)
|
|
ucr4 &= ~UCR4_TCEN;
|
|
imx_uart_writel(sport, ucr4, UCR4);
|
|
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
|
|
clk_disable_unprepare(sport->clk_per);
|
|
clk_disable_unprepare(sport->clk_ipg);
|
|
@@ -1713,7 +1713,7 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
|
|
quot = uart_get_divisor(port, baud);
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
|
|
/*
|
|
* Read current UCR2 and save it for future use, then clear all the bits
|
|
@@ -1841,7 +1841,7 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
|
|
imx_uart_enable_ms(&sport->port);
|
|
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
}
|
|
|
|
static const char *imx_uart_type(struct uart_port *port)
|
|
@@ -1903,7 +1903,7 @@ static int imx_uart_poll_init(struct uart_port *port)
|
|
|
|
imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
|
|
/*
|
|
* Be careful about the order of enabling bits here. First enable the
|
|
@@ -1931,7 +1931,7 @@ static int imx_uart_poll_init(struct uart_port *port)
|
|
imx_uart_writel(sport, ucr1 | UCR1_RRDYEN, UCR1);
|
|
imx_uart_writel(sport, ucr2 | UCR2_ATEN, UCR2);
|
|
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -2051,9 +2051,9 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count)
|
|
if (sport->port.sysrq)
|
|
locked = 0;
|
|
else if (oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&sport->port.lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(&sport->port, &flags);
|
|
else
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
|
|
/*
|
|
* First, save UCR1/2/3 and then disable interrupts
|
|
@@ -2081,7 +2081,7 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count)
|
|
imx_uart_ucrs_restore(sport, &old_ucr);
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
}
|
|
|
|
/*
|
|
@@ -2239,10 +2239,10 @@ static enum hrtimer_restart imx_trigger_start_tx(struct hrtimer *t)
|
|
struct imx_port *sport = container_of(t, struct imx_port, trigger_start_tx);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
if (sport->tx_state == WAIT_AFTER_RTS)
|
|
imx_uart_start_tx(&sport->port);
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
|
|
return HRTIMER_NORESTART;
|
|
}
|
|
@@ -2252,10 +2252,10 @@ static enum hrtimer_restart imx_trigger_stop_tx(struct hrtimer *t)
|
|
struct imx_port *sport = container_of(t, struct imx_port, trigger_stop_tx);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
if (sport->tx_state == WAIT_AFTER_SEND)
|
|
imx_uart_stop_tx(&sport->port);
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
|
|
return HRTIMER_NORESTART;
|
|
}
|
|
@@ -2583,9 +2583,9 @@ static void imx_uart_restore_context(struct imx_port *sport)
|
|
{
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
if (!sport->context_saved) {
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
return;
|
|
}
|
|
|
|
@@ -2600,7 +2600,7 @@ 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);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
}
|
|
|
|
static void imx_uart_save_context(struct imx_port *sport)
|
|
@@ -2608,7 +2608,7 @@ static void imx_uart_save_context(struct imx_port *sport)
|
|
unsigned long flags;
|
|
|
|
/* Save necessary regs */
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &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);
|
|
@@ -2620,7 +2620,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);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
}
|
|
|
|
static void imx_uart_enable_wakeup(struct imx_port *sport, bool on)
|
|
diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c
|
|
index 845ff706bc59..320b29cd4683 100644
|
|
--- a/drivers/tty/serial/ip22zilog.c
|
|
+++ b/drivers/tty/serial/ip22zilog.c
|
|
@@ -432,7 +432,7 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id)
|
|
unsigned char r3;
|
|
bool push = false;
|
|
|
|
- spin_lock(&up->port.lock);
|
|
+ uart_port_lock(&up->port);
|
|
r3 = read_zsreg(channel, R3);
|
|
|
|
/* Channel A */
|
|
@@ -448,7 +448,7 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id)
|
|
if (r3 & CHATxIP)
|
|
ip22zilog_transmit_chars(up, channel);
|
|
}
|
|
- spin_unlock(&up->port.lock);
|
|
+ uart_port_unlock(&up->port);
|
|
|
|
if (push)
|
|
tty_flip_buffer_push(&up->port.state->port);
|
|
@@ -458,7 +458,7 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id)
|
|
channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
|
|
push = false;
|
|
|
|
- spin_lock(&up->port.lock);
|
|
+ uart_port_lock(&up->port);
|
|
if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
|
|
writeb(RES_H_IUS, &channel->control);
|
|
ZSDELAY();
|
|
@@ -471,7 +471,7 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id)
|
|
if (r3 & CHBTxIP)
|
|
ip22zilog_transmit_chars(up, channel);
|
|
}
|
|
- spin_unlock(&up->port.lock);
|
|
+ uart_port_unlock(&up->port);
|
|
|
|
if (push)
|
|
tty_flip_buffer_push(&up->port.state->port);
|
|
@@ -504,11 +504,11 @@ static unsigned int ip22zilog_tx_empty(struct uart_port *port)
|
|
unsigned char status;
|
|
unsigned int ret;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
status = ip22zilog_read_channel_status(port);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
if (status & Tx_BUF_EMP)
|
|
ret = TIOCSER_TEMT;
|
|
@@ -664,7 +664,7 @@ static void ip22zilog_break_ctl(struct uart_port *port, int break_state)
|
|
else
|
|
clear_bits |= SND_BRK;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
new_reg = (up->curregs[R5] | set_bits) & ~clear_bits;
|
|
if (new_reg != up->curregs[R5]) {
|
|
@@ -674,7 +674,7 @@ static void ip22zilog_break_ctl(struct uart_port *port, int break_state)
|
|
write_zsreg(channel, R5, up->curregs[R5]);
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void __ip22zilog_reset(struct uart_ip22zilog_port *up)
|
|
@@ -735,9 +735,9 @@ static int ip22zilog_startup(struct uart_port *port)
|
|
if (ZS_IS_CONS(up))
|
|
return 0;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
__ip22zilog_startup(up);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
return 0;
|
|
}
|
|
|
|
@@ -775,7 +775,7 @@ static void ip22zilog_shutdown(struct uart_port *port)
|
|
if (ZS_IS_CONS(up))
|
|
return;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
channel = ZILOG_CHANNEL_FROM_PORT(port);
|
|
|
|
@@ -788,7 +788,7 @@ static void ip22zilog_shutdown(struct uart_port *port)
|
|
up->curregs[R5] &= ~SND_BRK;
|
|
ip22zilog_maybe_update_regs(up, channel);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/* Shared by TTY driver and serial console setup. The port lock is held
|
|
@@ -880,7 +880,7 @@ ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
|
|
baud = uart_get_baud_rate(port, termios, old, 1200, 76800);
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
|
|
|
|
@@ -894,7 +894,7 @@ ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
ip22zilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port));
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static const char *ip22zilog_type(struct uart_port *port)
|
|
@@ -1016,10 +1016,10 @@ ip22zilog_console_write(struct console *con, const char *s, unsigned int count)
|
|
struct uart_ip22zilog_port *up = &ip22zilog_port_table[con->index];
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
uart_console_write(&up->port, s, count, ip22zilog_put_char);
|
|
udelay(2);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static int __init ip22zilog_console_setup(struct console *con, char *options)
|
|
@@ -1034,13 +1034,13 @@ static int __init ip22zilog_console_setup(struct console *con, char *options)
|
|
|
|
printk(KERN_INFO "Console: ttyS%d (IP22-Zilog)\n", con->index);
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
up->curregs[R15] |= BRKIE;
|
|
|
|
__ip22zilog_startup(up);
|
|
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
if (options)
|
|
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
|
diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c
|
|
index 0c78f66276cd..2bd640428970 100644
|
|
--- a/drivers/tty/serial/jsm/jsm_neo.c
|
|
+++ b/drivers/tty/serial/jsm/jsm_neo.c
|
|
@@ -816,9 +816,9 @@ static void neo_parse_isr(struct jsm_board *brd, u32 port)
|
|
/* Parse any modem signal changes */
|
|
jsm_dbg(INTR, &ch->ch_bd->pci_dev,
|
|
"MOD_STAT: sending to parse_modem_sigs\n");
|
|
- spin_lock_irqsave(&ch->uart_port.lock, lock_flags);
|
|
+ uart_port_lock_irqsave(&ch->uart_port, &lock_flags);
|
|
neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr));
|
|
- spin_unlock_irqrestore(&ch->uart_port.lock, lock_flags);
|
|
+ uart_port_unlock_irqrestore(&ch->uart_port, lock_flags);
|
|
}
|
|
}
|
|
|
|
diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c
|
|
index 222afc270c88..ce0fef7e2c66 100644
|
|
--- a/drivers/tty/serial/jsm/jsm_tty.c
|
|
+++ b/drivers/tty/serial/jsm/jsm_tty.c
|
|
@@ -152,14 +152,14 @@ static void jsm_tty_send_xchar(struct uart_port *port, char ch)
|
|
container_of(port, struct jsm_channel, uart_port);
|
|
struct ktermios *termios;
|
|
|
|
- spin_lock_irqsave(&port->lock, lock_flags);
|
|
+ uart_port_lock_irqsave(port, &lock_flags);
|
|
termios = &port->state->port.tty->termios;
|
|
if (ch == termios->c_cc[VSTART])
|
|
channel->ch_bd->bd_ops->send_start_character(channel);
|
|
|
|
if (ch == termios->c_cc[VSTOP])
|
|
channel->ch_bd->bd_ops->send_stop_character(channel);
|
|
- spin_unlock_irqrestore(&port->lock, lock_flags);
|
|
+ uart_port_unlock_irqrestore(port, lock_flags);
|
|
}
|
|
|
|
static void jsm_tty_stop_rx(struct uart_port *port)
|
|
@@ -176,13 +176,13 @@ static void jsm_tty_break(struct uart_port *port, int break_state)
|
|
struct jsm_channel *channel =
|
|
container_of(port, struct jsm_channel, uart_port);
|
|
|
|
- spin_lock_irqsave(&port->lock, lock_flags);
|
|
+ uart_port_lock_irqsave(port, &lock_flags);
|
|
if (break_state == -1)
|
|
channel->ch_bd->bd_ops->send_break(channel);
|
|
else
|
|
channel->ch_bd->bd_ops->clear_break(channel);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, lock_flags);
|
|
+ uart_port_unlock_irqrestore(port, lock_flags);
|
|
}
|
|
|
|
static int jsm_tty_open(struct uart_port *port)
|
|
@@ -241,7 +241,7 @@ static int jsm_tty_open(struct uart_port *port)
|
|
channel->ch_cached_lsr = 0;
|
|
channel->ch_stops_sent = 0;
|
|
|
|
- spin_lock_irqsave(&port->lock, lock_flags);
|
|
+ uart_port_lock_irqsave(port, &lock_flags);
|
|
termios = &port->state->port.tty->termios;
|
|
channel->ch_c_cflag = termios->c_cflag;
|
|
channel->ch_c_iflag = termios->c_iflag;
|
|
@@ -261,7 +261,7 @@ static int jsm_tty_open(struct uart_port *port)
|
|
jsm_carrier(channel);
|
|
|
|
channel->ch_open_count++;
|
|
- spin_unlock_irqrestore(&port->lock, lock_flags);
|
|
+ uart_port_unlock_irqrestore(port, lock_flags);
|
|
|
|
jsm_dbg(OPEN, &channel->ch_bd->pci_dev, "finish\n");
|
|
return 0;
|
|
@@ -307,7 +307,7 @@ static void jsm_tty_set_termios(struct uart_port *port,
|
|
struct jsm_channel *channel =
|
|
container_of(port, struct jsm_channel, uart_port);
|
|
|
|
- spin_lock_irqsave(&port->lock, lock_flags);
|
|
+ uart_port_lock_irqsave(port, &lock_flags);
|
|
channel->ch_c_cflag = termios->c_cflag;
|
|
channel->ch_c_iflag = termios->c_iflag;
|
|
channel->ch_c_oflag = termios->c_oflag;
|
|
@@ -317,7 +317,7 @@ static void jsm_tty_set_termios(struct uart_port *port,
|
|
|
|
channel->ch_bd->bd_ops->param(channel);
|
|
jsm_carrier(channel);
|
|
- spin_unlock_irqrestore(&port->lock, lock_flags);
|
|
+ uart_port_unlock_irqrestore(port, lock_flags);
|
|
}
|
|
|
|
static const char *jsm_tty_type(struct uart_port *port)
|
|
diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c
|
|
index d881cdd2a58f..a25ab1efe38f 100644
|
|
--- a/drivers/tty/serial/liteuart.c
|
|
+++ b/drivers/tty/serial/liteuart.c
|
|
@@ -139,13 +139,13 @@ static irqreturn_t liteuart_interrupt(int irq, void *data)
|
|
* if polling, the context would be "in_serving_softirq", so use
|
|
* irq[save|restore] spin_lock variants to cover all possibilities
|
|
*/
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
isr = litex_read8(port->membase + OFF_EV_PENDING) & uart->irq_reg;
|
|
if (isr & EV_RX)
|
|
liteuart_rx_chars(port);
|
|
if (isr & EV_TX)
|
|
liteuart_tx_chars(port);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return IRQ_RETVAL(isr);
|
|
}
|
|
@@ -195,10 +195,10 @@ static int liteuart_startup(struct uart_port *port)
|
|
}
|
|
}
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
/* only enabling rx irqs during startup */
|
|
liteuart_update_irq_reg(port, true, EV_RX);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
if (!port->irq) {
|
|
timer_setup(&uart->timer, liteuart_timer, 0);
|
|
@@ -213,9 +213,9 @@ static void liteuart_shutdown(struct uart_port *port)
|
|
struct liteuart_port *uart = to_liteuart_port(port);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
liteuart_update_irq_reg(port, false, EV_RX | EV_TX);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
if (port->irq)
|
|
free_irq(port->irq, port);
|
|
@@ -229,13 +229,13 @@ static void liteuart_set_termios(struct uart_port *port, struct ktermios *new,
|
|
unsigned int baud;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* update baudrate */
|
|
baud = uart_get_baud_rate(port, new, old, 0, 460800);
|
|
uart_update_timeout(port, new->c_cflag, baud);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *liteuart_type(struct uart_port *port)
|
|
@@ -382,9 +382,9 @@ static void liteuart_console_write(struct console *co, const char *s,
|
|
uart = (struct liteuart_port *)xa_load(&liteuart_array, co->index);
|
|
port = &uart->port;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
uart_console_write(port, s, count, liteuart_putchar);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static int liteuart_console_setup(struct console *co, char *options)
|
|
diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c
|
|
index b38fe4728c26..5149a947b7fe 100644
|
|
--- a/drivers/tty/serial/lpc32xx_hs.c
|
|
+++ b/drivers/tty/serial/lpc32xx_hs.c
|
|
@@ -140,15 +140,15 @@ static void lpc32xx_hsuart_console_write(struct console *co, const char *s,
|
|
if (up->port.sysrq)
|
|
locked = 0;
|
|
else if (oops_in_progress)
|
|
- locked = spin_trylock(&up->port.lock);
|
|
+ locked = uart_port_trylock(&up->port);
|
|
else
|
|
- spin_lock(&up->port.lock);
|
|
+ uart_port_lock(&up->port);
|
|
|
|
uart_console_write(&up->port, s, count, lpc32xx_hsuart_console_putchar);
|
|
wait_for_xmit_empty(&up->port);
|
|
|
|
if (locked)
|
|
- spin_unlock(&up->port.lock);
|
|
+ uart_port_unlock(&up->port);
|
|
local_irq_restore(flags);
|
|
}
|
|
|
|
@@ -298,7 +298,7 @@ static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id)
|
|
struct tty_port *tport = &port->state->port;
|
|
u32 status;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
/* Read UART status and clear latched interrupts */
|
|
status = readl(LPC32XX_HSUART_IIR(port->membase));
|
|
@@ -333,7 +333,7 @@ static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id)
|
|
__serial_lpc32xx_tx(port);
|
|
}
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -404,14 +404,14 @@ static void serial_lpc32xx_break_ctl(struct uart_port *port,
|
|
unsigned long flags;
|
|
u32 tmp;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
|
|
if (break_state != 0)
|
|
tmp |= LPC32XX_HSU_BREAK;
|
|
else
|
|
tmp &= ~LPC32XX_HSU_BREAK;
|
|
writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/* port->lock is not held. */
|
|
@@ -421,7 +421,7 @@ static int serial_lpc32xx_startup(struct uart_port *port)
|
|
unsigned long flags;
|
|
u32 tmp;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
__serial_uart_flush(port);
|
|
|
|
@@ -441,7 +441,7 @@ static int serial_lpc32xx_startup(struct uart_port *port)
|
|
|
|
lpc32xx_loopback_set(port->mapbase, 0); /* get out of loopback mode */
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
retval = request_irq(port->irq, serial_lpc32xx_interrupt,
|
|
0, MODNAME, port);
|
|
@@ -458,7 +458,7 @@ static void serial_lpc32xx_shutdown(struct uart_port *port)
|
|
u32 tmp;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
|
|
LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B;
|
|
@@ -466,7 +466,7 @@ static void serial_lpc32xx_shutdown(struct uart_port *port)
|
|
|
|
lpc32xx_loopback_set(port->mapbase, 1); /* go to loopback mode */
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
free_irq(port->irq, port);
|
|
}
|
|
@@ -491,7 +491,7 @@ static void serial_lpc32xx_set_termios(struct uart_port *port,
|
|
|
|
quot = __serial_get_clock_div(port->uartclk, baud);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Ignore characters? */
|
|
tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
|
|
@@ -505,7 +505,7 @@ static void serial_lpc32xx_set_termios(struct uart_port *port,
|
|
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
/* Don't rewrite B0 */
|
|
if (tty_termios_baud_rate(termios))
|
|
diff --git a/drivers/tty/serial/ma35d1_serial.c b/drivers/tty/serial/ma35d1_serial.c
|
|
index 99225f1e02ac..faccd772c68c 100644
|
|
--- a/drivers/tty/serial/ma35d1_serial.c
|
|
+++ b/drivers/tty/serial/ma35d1_serial.c
|
|
@@ -269,16 +269,16 @@ static void receive_chars(struct uart_ma35d1_port *up)
|
|
if (uart_handle_sysrq_char(&up->port, ch))
|
|
continue;
|
|
|
|
- spin_lock(&up->port.lock);
|
|
+ uart_port_lock(&up->port);
|
|
uart_insert_char(&up->port, fsr, MA35_FSR_RX_OVER_IF, ch, flag);
|
|
- spin_unlock(&up->port.lock);
|
|
+ uart_port_unlock(&up->port);
|
|
|
|
fsr = serial_in(up, MA35_FSR_REG);
|
|
} while (!(fsr & MA35_FSR_RX_EMPTY) && (max_count-- > 0));
|
|
|
|
- spin_lock(&up->port.lock);
|
|
+ uart_port_lock(&up->port);
|
|
tty_flip_buffer_push(&up->port.state->port);
|
|
- spin_unlock(&up->port.lock);
|
|
+ uart_port_unlock(&up->port);
|
|
}
|
|
|
|
static irqreturn_t ma35d1serial_interrupt(int irq, void *dev_id)
|
|
@@ -364,14 +364,14 @@ static void ma35d1serial_break_ctl(struct uart_port *port, int break_state)
|
|
unsigned long flags;
|
|
u32 lcr;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
lcr = serial_in(up, MA35_LCR_REG);
|
|
if (break_state != 0)
|
|
lcr |= MA35_LCR_BREAK;
|
|
else
|
|
lcr &= ~MA35_LCR_BREAK;
|
|
serial_out(up, MA35_LCR_REG, lcr);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static int ma35d1serial_startup(struct uart_port *port)
|
|
@@ -441,7 +441,7 @@ static void ma35d1serial_set_termios(struct uart_port *port,
|
|
* Ok, we're now changing the port state. Do it with
|
|
* interrupts disabled.
|
|
*/
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
up->port.read_status_mask = MA35_FSR_RX_OVER_IF;
|
|
if (termios->c_iflag & INPCK)
|
|
@@ -475,7 +475,7 @@ static void ma35d1serial_set_termios(struct uart_port *port,
|
|
|
|
serial_out(up, MA35_LCR_REG, lcr);
|
|
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static const char *ma35d1serial_type(struct uart_port *port)
|
|
@@ -568,9 +568,9 @@ static void ma35d1serial_console_write(struct console *co, const char *s, u32 co
|
|
if (up->port.sysrq)
|
|
locked = 0;
|
|
else if (oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&up->port.lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(&up->port, &flags);
|
|
else
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
/*
|
|
* First save the IER then disable the interrupts
|
|
@@ -584,7 +584,7 @@ static void ma35d1serial_console_write(struct console *co, const char *s, u32 co
|
|
serial_out(up, MA35_IER_REG, ier);
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static int __init ma35d1serial_console_setup(struct console *co, char *options)
|
|
diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
|
|
index aea29b4e6567..ee40af20a08f 100644
|
|
--- a/drivers/tty/serial/mcf.c
|
|
+++ b/drivers/tty/serial/mcf.c
|
|
@@ -135,12 +135,12 @@ static void mcf_break_ctl(struct uart_port *port, int break_state)
|
|
{
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
if (break_state == -1)
|
|
writeb(MCFUART_UCR_CMDBREAKSTART, port->membase + MCFUART_UCR);
|
|
else
|
|
writeb(MCFUART_UCR_CMDBREAKSTOP, port->membase + MCFUART_UCR);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
@@ -150,7 +150,7 @@ static int mcf_startup(struct uart_port *port)
|
|
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Reset UART, get it into known state... */
|
|
writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
|
|
@@ -164,7 +164,7 @@ static int mcf_startup(struct uart_port *port)
|
|
pp->imr = MCFUART_UIR_RXREADY;
|
|
writeb(pp->imr, port->membase + MCFUART_UIMR);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -176,7 +176,7 @@ static void mcf_shutdown(struct uart_port *port)
|
|
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Disable all interrupts now */
|
|
pp->imr = 0;
|
|
@@ -186,7 +186,7 @@ static void mcf_shutdown(struct uart_port *port)
|
|
writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
|
|
writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
@@ -252,7 +252,7 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
mr2 |= MCFUART_MR2_TXCTS;
|
|
}
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
if (port->rs485.flags & SER_RS485_ENABLED) {
|
|
dev_dbg(port->dev, "Setting UART to RS485\n");
|
|
mr2 |= MCFUART_MR2_TXRTS;
|
|
@@ -273,7 +273,7 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
port->membase + MCFUART_UCSR);
|
|
writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
|
|
port->membase + MCFUART_UCR);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
@@ -350,7 +350,7 @@ static irqreturn_t mcf_interrupt(int irq, void *data)
|
|
|
|
isr = readb(port->membase + MCFUART_UISR) & pp->imr;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
if (isr & MCFUART_UIR_RXREADY) {
|
|
mcf_rx_chars(pp);
|
|
ret = IRQ_HANDLED;
|
|
@@ -359,7 +359,7 @@ static irqreturn_t mcf_interrupt(int irq, void *data)
|
|
mcf_tx_chars(pp);
|
|
ret = IRQ_HANDLED;
|
|
}
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
return ret;
|
|
}
|
|
diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c
|
|
index d2502aaa3e8c..8048fa542fc4 100644
|
|
--- a/drivers/tty/serial/men_z135_uart.c
|
|
+++ b/drivers/tty/serial/men_z135_uart.c
|
|
@@ -392,7 +392,7 @@ static irqreturn_t men_z135_intr(int irq, void *data)
|
|
if (!irq_id)
|
|
goto out;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
/* It's save to write to IIR[7:6] RXC[9:8] */
|
|
iowrite8(irq_id, port->membase + MEN_Z135_STAT_REG);
|
|
|
|
@@ -418,7 +418,7 @@ static irqreturn_t men_z135_intr(int irq, void *data)
|
|
handled = true;
|
|
}
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
out:
|
|
return IRQ_RETVAL(handled);
|
|
}
|
|
@@ -708,7 +708,7 @@ static void men_z135_set_termios(struct uart_port *port,
|
|
|
|
baud = uart_get_baud_rate(port, termios, old, 0, uart_freq / 16);
|
|
|
|
- spin_lock_irq(&port->lock);
|
|
+ uart_port_lock_irq(port);
|
|
if (tty_termios_baud_rate(termios))
|
|
tty_termios_encode_baud_rate(termios, baud, baud);
|
|
|
|
@@ -716,7 +716,7 @@ static void men_z135_set_termios(struct uart_port *port,
|
|
iowrite32(bd_reg, port->membase + MEN_Z135_BAUD_REG);
|
|
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
}
|
|
|
|
static const char *men_z135_type(struct uart_port *port)
|
|
diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
|
|
index 9388b9ddea3b..4c1d2089a0bb 100644
|
|
--- a/drivers/tty/serial/meson_uart.c
|
|
+++ b/drivers/tty/serial/meson_uart.c
|
|
@@ -129,14 +129,14 @@ static void meson_uart_shutdown(struct uart_port *port)
|
|
|
|
free_irq(port->irq, port);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
val = readl(port->membase + AML_UART_CONTROL);
|
|
val &= ~AML_UART_RX_EN;
|
|
val &= ~(AML_UART_RX_INT_EN | AML_UART_TX_INT_EN);
|
|
writel(val, port->membase + AML_UART_CONTROL);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void meson_uart_start_tx(struct uart_port *port)
|
|
@@ -238,7 +238,7 @@ static irqreturn_t meson_uart_interrupt(int irq, void *dev_id)
|
|
{
|
|
struct uart_port *port = (struct uart_port *)dev_id;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
if (!(readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY))
|
|
meson_receive_chars(port);
|
|
@@ -248,7 +248,7 @@ static irqreturn_t meson_uart_interrupt(int irq, void *dev_id)
|
|
meson_uart_start_tx(port);
|
|
}
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -284,7 +284,7 @@ static int meson_uart_startup(struct uart_port *port)
|
|
u32 val;
|
|
int ret = 0;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
val = readl(port->membase + AML_UART_CONTROL);
|
|
val |= AML_UART_CLEAR_ERR;
|
|
@@ -301,7 +301,7 @@ static int meson_uart_startup(struct uart_port *port)
|
|
val = (AML_UART_RECV_IRQ(1) | AML_UART_XMIT_IRQ(port->fifosize / 2));
|
|
writel(val, port->membase + AML_UART_MISC);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
ret = request_irq(port->irq, meson_uart_interrupt, 0,
|
|
port->name, port);
|
|
@@ -341,7 +341,7 @@ static void meson_uart_set_termios(struct uart_port *port,
|
|
unsigned long flags;
|
|
u32 val;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
cflags = termios->c_cflag;
|
|
iflags = termios->c_iflag;
|
|
@@ -405,7 +405,7 @@ static void meson_uart_set_termios(struct uart_port *port,
|
|
AML_UART_FRAME_ERR;
|
|
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static int meson_uart_verify_port(struct uart_port *port,
|
|
@@ -464,14 +464,14 @@ static int meson_uart_poll_get_char(struct uart_port *port)
|
|
u32 c;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
if (readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY)
|
|
c = NO_POLL_CHAR;
|
|
else
|
|
c = readl(port->membase + AML_UART_RFIFO);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return c;
|
|
}
|
|
@@ -482,7 +482,7 @@ static void meson_uart_poll_put_char(struct uart_port *port, unsigned char c)
|
|
u32 reg;
|
|
int ret;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Wait until FIFO is empty or timeout */
|
|
ret = readl_poll_timeout_atomic(port->membase + AML_UART_STATUS, reg,
|
|
@@ -506,7 +506,7 @@ static void meson_uart_poll_put_char(struct uart_port *port, unsigned char c)
|
|
dev_err(port->dev, "Timeout waiting for UART TX EMPTY\n");
|
|
|
|
out:
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
#endif /* CONFIG_CONSOLE_POLL */
|
|
@@ -563,9 +563,9 @@ static void meson_serial_port_write(struct uart_port *port, const char *s,
|
|
if (port->sysrq) {
|
|
locked = 0;
|
|
} else if (oops_in_progress) {
|
|
- locked = spin_trylock(&port->lock);
|
|
+ locked = uart_port_trylock(port);
|
|
} else {
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
locked = 1;
|
|
}
|
|
|
|
@@ -577,7 +577,7 @@ static void meson_serial_port_write(struct uart_port *port, const char *s,
|
|
writel(val, port->membase + AML_UART_CONTROL);
|
|
|
|
if (locked)
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
local_irq_restore(flags);
|
|
}
|
|
|
|
diff --git a/drivers/tty/serial/milbeaut_usio.c b/drivers/tty/serial/milbeaut_usio.c
|
|
index 70a910085e93..db3b81f2aa57 100644
|
|
--- a/drivers/tty/serial/milbeaut_usio.c
|
|
+++ b/drivers/tty/serial/milbeaut_usio.c
|
|
@@ -207,9 +207,9 @@ static irqreturn_t mlb_usio_rx_irq(int irq, void *dev_id)
|
|
{
|
|
struct uart_port *port = dev_id;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
mlb_usio_rx_chars(port);
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -218,10 +218,10 @@ static irqreturn_t mlb_usio_tx_irq(int irq, void *dev_id)
|
|
{
|
|
struct uart_port *port = dev_id;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
if (readb(port->membase + MLB_USIO_REG_SSR) & MLB_USIO_SSR_TBI)
|
|
mlb_usio_tx_chars(port);
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -267,7 +267,7 @@ static int mlb_usio_startup(struct uart_port *port)
|
|
escr = readb(port->membase + MLB_USIO_REG_ESCR);
|
|
if (of_property_read_bool(port->dev->of_node, "auto-flow-control"))
|
|
escr |= MLB_USIO_ESCR_FLWEN;
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
writeb(0, port->membase + MLB_USIO_REG_SCR);
|
|
writeb(escr, port->membase + MLB_USIO_REG_ESCR);
|
|
writeb(MLB_USIO_SCR_UPCL, port->membase + MLB_USIO_REG_SCR);
|
|
@@ -282,7 +282,7 @@ static int mlb_usio_startup(struct uart_port *port)
|
|
|
|
writeb(MLB_USIO_SCR_TXE | MLB_USIO_SCR_RIE | MLB_USIO_SCR_TBIE |
|
|
MLB_USIO_SCR_RXE, port->membase + MLB_USIO_REG_SCR);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -337,7 +337,7 @@ static void mlb_usio_set_termios(struct uart_port *port,
|
|
else
|
|
quot = 0;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
port->read_status_mask = MLB_USIO_SSR_ORE | MLB_USIO_SSR_RDRF |
|
|
MLB_USIO_SSR_TDRE;
|
|
@@ -367,7 +367,7 @@ static void mlb_usio_set_termios(struct uart_port *port,
|
|
writew(BIT(12), port->membase + MLB_USIO_REG_FBYTE);
|
|
writeb(MLB_USIO_SCR_RIE | MLB_USIO_SCR_RXE | MLB_USIO_SCR_TBIE |
|
|
MLB_USIO_SCR_TXE, port->membase + MLB_USIO_REG_SCR);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *mlb_usio_type(struct uart_port *port)
|
|
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
|
|
index 916507b8f31d..a252465e745f 100644
|
|
--- a/drivers/tty/serial/mpc52xx_uart.c
|
|
+++ b/drivers/tty/serial/mpc52xx_uart.c
|
|
@@ -1096,14 +1096,14 @@ static void
|
|
mpc52xx_uart_break_ctl(struct uart_port *port, int ctl)
|
|
{
|
|
unsigned long flags;
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
if (ctl == -1)
|
|
psc_ops->command(port, MPC52xx_PSC_START_BRK);
|
|
else
|
|
psc_ops->command(port, MPC52xx_PSC_STOP_BRK);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static int
|
|
@@ -1214,7 +1214,7 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
|
|
}
|
|
|
|
/* Get the lock */
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Do our best to flush TX & RX, so we don't lose anything */
|
|
/* But we don't wait indefinitely ! */
|
|
@@ -1250,7 +1250,7 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
|
|
psc_ops->command(port, MPC52xx_PSC_RX_ENABLE);
|
|
|
|
/* We're all set, release the lock */
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *
|
|
@@ -1477,11 +1477,11 @@ mpc52xx_uart_int(int irq, void *dev_id)
|
|
struct uart_port *port = dev_id;
|
|
irqreturn_t ret;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
ret = psc_ops->handle_irq(port);
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
return ret;
|
|
}
|
|
diff --git a/drivers/tty/serial/mps2-uart.c b/drivers/tty/serial/mps2-uart.c
|
|
index ea5a7911cb15..2a4c09f3a834 100644
|
|
--- a/drivers/tty/serial/mps2-uart.c
|
|
+++ b/drivers/tty/serial/mps2-uart.c
|
|
@@ -188,12 +188,12 @@ static irqreturn_t mps2_uart_rxirq(int irq, void *data)
|
|
if (unlikely(!(irqflag & UARTn_INT_RX)))
|
|
return IRQ_NONE;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
mps2_uart_write8(port, UARTn_INT_RX, UARTn_INT);
|
|
mps2_uart_rx_chars(port);
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -206,12 +206,12 @@ static irqreturn_t mps2_uart_txirq(int irq, void *data)
|
|
if (unlikely(!(irqflag & UARTn_INT_TX)))
|
|
return IRQ_NONE;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
mps2_uart_write8(port, UARTn_INT_TX, UARTn_INT);
|
|
mps2_uart_tx_chars(port);
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -222,7 +222,7 @@ static irqreturn_t mps2_uart_oerrirq(int irq, void *data)
|
|
struct uart_port *port = data;
|
|
u8 irqflag = mps2_uart_read8(port, UARTn_INT);
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
if (irqflag & UARTn_INT_RX_OVERRUN) {
|
|
struct tty_port *tport = &port->state->port;
|
|
@@ -244,7 +244,7 @@ static irqreturn_t mps2_uart_oerrirq(int irq, void *data)
|
|
handled = IRQ_HANDLED;
|
|
}
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
return handled;
|
|
}
|
|
@@ -356,12 +356,12 @@ mps2_uart_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
|
|
bauddiv = DIV_ROUND_CLOSEST(port->uartclk, baud);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
mps2_uart_write32(port, bauddiv, UARTn_BAUDDIV);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
if (tty_termios_baud_rate(termios))
|
|
tty_termios_encode_baud_rate(termios, baud, baud);
|
|
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
|
|
index 90953e679e38..597264b546fd 100644
|
|
--- a/drivers/tty/serial/msm_serial.c
|
|
+++ b/drivers/tty/serial/msm_serial.c
|
|
@@ -444,7 +444,7 @@ static void msm_complete_tx_dma(void *args)
|
|
unsigned int count;
|
|
u32 val;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Already stopped */
|
|
if (!dma->count)
|
|
@@ -476,7 +476,7 @@ static void msm_complete_tx_dma(void *args)
|
|
|
|
msm_handle_tx(port);
|
|
done:
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count)
|
|
@@ -549,7 +549,7 @@ static void msm_complete_rx_dma(void *args)
|
|
unsigned long flags;
|
|
u32 val;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Already stopped */
|
|
if (!dma->count)
|
|
@@ -587,16 +587,16 @@ static void msm_complete_rx_dma(void *args)
|
|
if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK))
|
|
flag = TTY_NORMAL;
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
sysrq = uart_handle_sysrq_char(port, dma->virt[i]);
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
if (!sysrq)
|
|
tty_insert_flip_char(tport, dma->virt[i], flag);
|
|
}
|
|
|
|
msm_start_rx_dma(msm_port);
|
|
done:
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
if (count)
|
|
tty_flip_buffer_push(tport);
|
|
@@ -762,9 +762,9 @@ static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr)
|
|
if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK))
|
|
flag = TTY_NORMAL;
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
sysrq = uart_handle_sysrq_char(port, buf[i]);
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
if (!sysrq)
|
|
tty_insert_flip_char(tport, buf[i], flag);
|
|
}
|
|
@@ -824,9 +824,9 @@ static void msm_handle_rx(struct uart_port *port)
|
|
else if (sr & MSM_UART_SR_PAR_FRAME_ERR)
|
|
flag = TTY_FRAME;
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
sysrq = uart_handle_sysrq_char(port, c);
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
if (!sysrq)
|
|
tty_insert_flip_char(tport, c, flag);
|
|
}
|
|
@@ -951,7 +951,7 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id)
|
|
unsigned int misr;
|
|
u32 val;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
misr = msm_read(port, MSM_UART_MISR);
|
|
msm_write(port, 0, MSM_UART_IMR); /* disable interrupt */
|
|
|
|
@@ -983,7 +983,7 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id)
|
|
msm_handle_delta_cts(port);
|
|
|
|
msm_write(port, msm_port->imr, MSM_UART_IMR); /* restore interrupt */
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -1128,13 +1128,13 @@ static int msm_set_baud_rate(struct uart_port *port, unsigned int baud,
|
|
unsigned long flags, rate;
|
|
|
|
flags = *saved_flags;
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
entry = msm_find_best_baud(port, baud, &rate);
|
|
clk_set_rate(msm_port->clk, rate);
|
|
baud = rate / 16 / entry->divisor;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
*saved_flags = flags;
|
|
port->uartclk = rate;
|
|
|
|
@@ -1266,7 +1266,7 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
unsigned long flags;
|
|
unsigned int baud, mr;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
if (dma->chan) /* Terminate if any */
|
|
msm_stop_dma(port, dma);
|
|
@@ -1338,7 +1338,7 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
/* Try to use DMA */
|
|
msm_start_rx_dma(msm_port);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *msm_type(struct uart_port *port)
|
|
@@ -1620,9 +1620,9 @@ static void __msm_console_write(struct uart_port *port, const char *s,
|
|
if (port->sysrq)
|
|
locked = 0;
|
|
else if (oops_in_progress)
|
|
- locked = spin_trylock(&port->lock);
|
|
+ locked = uart_port_trylock(port);
|
|
else
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
if (is_uartdm)
|
|
msm_reset_dm_count(port, count);
|
|
@@ -1661,7 +1661,7 @@ static void __msm_console_write(struct uart_port *port, const char *s,
|
|
}
|
|
|
|
if (locked)
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
local_irq_restore(flags);
|
|
}
|
|
diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
|
|
index ea924e9b913b..0255646bc175 100644
|
|
--- a/drivers/tty/serial/mvebu-uart.c
|
|
+++ b/drivers/tty/serial/mvebu-uart.c
|
|
@@ -187,9 +187,9 @@ static unsigned int mvebu_uart_tx_empty(struct uart_port *port)
|
|
unsigned long flags;
|
|
unsigned int st;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
st = readl(port->membase + UART_STAT);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return (st & STAT_TX_EMP) ? TIOCSER_TEMT : 0;
|
|
}
|
|
@@ -249,14 +249,14 @@ static void mvebu_uart_break_ctl(struct uart_port *port, int brk)
|
|
unsigned int ctl;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
ctl = readl(port->membase + UART_CTRL(port));
|
|
if (brk == -1)
|
|
ctl |= CTRL_SND_BRK_SEQ;
|
|
else
|
|
ctl &= ~CTRL_SND_BRK_SEQ;
|
|
writel(ctl, port->membase + UART_CTRL(port));
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status)
|
|
@@ -540,7 +540,7 @@ static void mvebu_uart_set_termios(struct uart_port *port,
|
|
unsigned long flags;
|
|
unsigned int baud, min_baud, max_baud;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
port->read_status_mask = STAT_RX_RDY(port) | STAT_OVR_ERR |
|
|
STAT_TX_RDY(port) | STAT_TX_FIFO_FUL;
|
|
@@ -589,7 +589,7 @@ static void mvebu_uart_set_termios(struct uart_port *port,
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *mvebu_uart_type(struct uart_port *port)
|
|
@@ -735,9 +735,9 @@ static void mvebu_uart_console_write(struct console *co, const char *s,
|
|
int locked = 1;
|
|
|
|
if (oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&port->lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(port, &flags);
|
|
else
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
ier = readl(port->membase + UART_CTRL(port)) & CTRL_BRK_INT;
|
|
intr = readl(port->membase + UART_INTR(port)) &
|
|
@@ -758,7 +758,7 @@ static void mvebu_uart_console_write(struct console *co, const char *s,
|
|
}
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static int mvebu_uart_console_setup(struct console *co, char *options)
|
|
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
|
|
index 135a838f517a..1097fca22307 100644
|
|
--- a/drivers/tty/serial/omap-serial.c
|
|
+++ b/drivers/tty/serial/omap-serial.c
|
|
@@ -390,10 +390,10 @@ static void serial_omap_throttle(struct uart_port *port)
|
|
struct uart_omap_port *up = to_uart_omap_port(port);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
|
|
serial_out(up, UART_IER, up->ier);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static void serial_omap_unthrottle(struct uart_port *port)
|
|
@@ -401,10 +401,10 @@ static void serial_omap_unthrottle(struct uart_port *port)
|
|
struct uart_omap_port *up = to_uart_omap_port(port);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
up->ier |= UART_IER_RLSI | UART_IER_RDI;
|
|
serial_out(up, UART_IER, up->ier);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static unsigned int check_modem_status(struct uart_omap_port *up)
|
|
@@ -527,7 +527,7 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id)
|
|
irqreturn_t ret = IRQ_NONE;
|
|
int max_count = 256;
|
|
|
|
- spin_lock(&up->port.lock);
|
|
+ uart_port_lock(&up->port);
|
|
|
|
do {
|
|
iir = serial_in(up, UART_IIR);
|
|
@@ -563,7 +563,7 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id)
|
|
}
|
|
} while (max_count--);
|
|
|
|
- spin_unlock(&up->port.lock);
|
|
+ uart_port_unlock(&up->port);
|
|
|
|
tty_flip_buffer_push(&up->port.state->port);
|
|
|
|
@@ -579,9 +579,9 @@ static unsigned int serial_omap_tx_empty(struct uart_port *port)
|
|
unsigned int ret = 0;
|
|
|
|
dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->port.line);
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
return ret;
|
|
}
|
|
@@ -647,13 +647,13 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state)
|
|
unsigned long flags;
|
|
|
|
dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->port.line);
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
if (break_state == -1)
|
|
up->lcr |= UART_LCR_SBC;
|
|
else
|
|
up->lcr &= ~UART_LCR_SBC;
|
|
serial_out(up, UART_LCR, up->lcr);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static int serial_omap_startup(struct uart_port *port)
|
|
@@ -701,13 +701,13 @@ static int serial_omap_startup(struct uart_port *port)
|
|
* Now, initialize the UART
|
|
*/
|
|
serial_out(up, UART_LCR, UART_LCR_WLEN8);
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
/*
|
|
* Most PC uarts need OUT2 raised to enable interrupts.
|
|
*/
|
|
up->port.mctrl |= TIOCM_OUT2;
|
|
serial_omap_set_mctrl(&up->port, up->port.mctrl);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
up->msr_saved_flags = 0;
|
|
/*
|
|
@@ -742,10 +742,10 @@ static void serial_omap_shutdown(struct uart_port *port)
|
|
up->ier = 0;
|
|
serial_out(up, UART_IER, 0);
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
up->port.mctrl &= ~TIOCM_OUT2;
|
|
serial_omap_set_mctrl(&up->port, up->port.mctrl);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
/*
|
|
* Disable break condition and FIFOs
|
|
@@ -815,7 +815,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
* Ok, we're now changing the port state. Do it with
|
|
* interrupts disabled.
|
|
*/
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
/*
|
|
* Update the per-port timeout.
|
|
@@ -1013,7 +1013,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
|
|
serial_omap_set_mctrl(&up->port, up->port.mctrl);
|
|
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->port.line);
|
|
}
|
|
|
|
@@ -1212,13 +1212,10 @@ serial_omap_console_write(struct console *co, const char *s,
|
|
unsigned int ier;
|
|
int locked = 1;
|
|
|
|
- local_irq_save(flags);
|
|
- if (up->port.sysrq)
|
|
- locked = 0;
|
|
- else if (oops_in_progress)
|
|
- locked = spin_trylock(&up->port.lock);
|
|
+ if (up->port.sysrq || oops_in_progress)
|
|
+ locked = uart_port_trylock_irqsave(&up->port, &flags);
|
|
else
|
|
- spin_lock(&up->port.lock);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
/*
|
|
* First save the IER then disable the interrupts
|
|
@@ -1245,8 +1242,7 @@ serial_omap_console_write(struct console *co, const char *s,
|
|
check_modem_status(up);
|
|
|
|
if (locked)
|
|
- spin_unlock(&up->port.lock);
|
|
- local_irq_restore(flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static int __init
|
|
diff --git a/drivers/tty/serial/owl-uart.c b/drivers/tty/serial/owl-uart.c
|
|
index e99970a9437f..919f5e5aa0f1 100644
|
|
--- a/drivers/tty/serial/owl-uart.c
|
|
+++ b/drivers/tty/serial/owl-uart.c
|
|
@@ -125,12 +125,12 @@ static unsigned int owl_uart_tx_empty(struct uart_port *port)
|
|
u32 val;
|
|
unsigned int ret;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
val = owl_uart_read(port, OWL_UART_STAT);
|
|
ret = (val & OWL_UART_STAT_TFES) ? TIOCSER_TEMT : 0;
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return ret;
|
|
}
|
|
@@ -232,7 +232,7 @@ static irqreturn_t owl_uart_irq(int irq, void *dev_id)
|
|
unsigned long flags;
|
|
u32 stat;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
stat = owl_uart_read(port, OWL_UART_STAT);
|
|
|
|
@@ -246,7 +246,7 @@ static irqreturn_t owl_uart_irq(int irq, void *dev_id)
|
|
stat |= OWL_UART_STAT_RIP | OWL_UART_STAT_TIP;
|
|
owl_uart_write(port, stat, OWL_UART_STAT);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -256,14 +256,14 @@ static void owl_uart_shutdown(struct uart_port *port)
|
|
u32 val;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
val = owl_uart_read(port, OWL_UART_CTL);
|
|
val &= ~(OWL_UART_CTL_TXIE | OWL_UART_CTL_RXIE
|
|
| OWL_UART_CTL_TXDE | OWL_UART_CTL_RXDE | OWL_UART_CTL_EN);
|
|
owl_uart_write(port, val, OWL_UART_CTL);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
free_irq(port->irq, port);
|
|
}
|
|
@@ -279,7 +279,7 @@ static int owl_uart_startup(struct uart_port *port)
|
|
if (ret)
|
|
return ret;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
val = owl_uart_read(port, OWL_UART_STAT);
|
|
val |= OWL_UART_STAT_RIP | OWL_UART_STAT_TIP
|
|
@@ -291,7 +291,7 @@ static int owl_uart_startup(struct uart_port *port)
|
|
val |= OWL_UART_CTL_EN;
|
|
owl_uart_write(port, val, OWL_UART_CTL);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -311,7 +311,7 @@ static void owl_uart_set_termios(struct uart_port *port,
|
|
u32 ctl;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
ctl = owl_uart_read(port, OWL_UART_CTL);
|
|
|
|
@@ -371,7 +371,7 @@ static void owl_uart_set_termios(struct uart_port *port,
|
|
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void owl_uart_release_port(struct uart_port *port)
|
|
@@ -515,9 +515,9 @@ static void owl_uart_port_write(struct uart_port *port, const char *s,
|
|
if (port->sysrq)
|
|
locked = 0;
|
|
else if (oops_in_progress)
|
|
- locked = spin_trylock(&port->lock);
|
|
+ locked = uart_port_trylock(port);
|
|
else {
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
locked = 1;
|
|
}
|
|
|
|
@@ -541,7 +541,7 @@ static void owl_uart_port_write(struct uart_port *port, const char *s,
|
|
owl_uart_write(port, old_ctl, OWL_UART_CTL);
|
|
|
|
if (locked)
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
local_irq_restore(flags);
|
|
}
|
|
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
|
|
index cc83b772b7ca..436cc6d52a11 100644
|
|
--- a/drivers/tty/serial/pch_uart.c
|
|
+++ b/drivers/tty/serial/pch_uart.c
|
|
@@ -1347,7 +1347,7 @@ static void pch_uart_set_termios(struct uart_port *port,
|
|
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
|
|
|
|
spin_lock_irqsave(&priv->lock, flags);
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
rtn = pch_uart_hal_set_line(priv, baud, parity, bits, stb);
|
|
@@ -1360,7 +1360,7 @@ static void pch_uart_set_termios(struct uart_port *port,
|
|
tty_termios_encode_baud_rate(termios, baud, baud);
|
|
|
|
out:
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
spin_unlock_irqrestore(&priv->lock, flags);
|
|
}
|
|
|
|
@@ -1581,10 +1581,10 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
|
|
port_locked = 0;
|
|
} else if (oops_in_progress) {
|
|
priv_locked = spin_trylock(&priv->lock);
|
|
- port_locked = spin_trylock(&priv->port.lock);
|
|
+ port_locked = uart_port_trylock(&priv->port);
|
|
} else {
|
|
spin_lock(&priv->lock);
|
|
- spin_lock(&priv->port.lock);
|
|
+ uart_port_lock(&priv->port);
|
|
}
|
|
|
|
/*
|
|
@@ -1604,7 +1604,7 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
|
|
iowrite8(ier, priv->membase + UART_IER);
|
|
|
|
if (port_locked)
|
|
- spin_unlock(&priv->port.lock);
|
|
+ uart_port_unlock(&priv->port);
|
|
if (priv_locked)
|
|
spin_unlock(&priv->lock);
|
|
local_irq_restore(flags);
|
|
diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c
|
|
index e308d5022b3f..3a95bf5d55d3 100644
|
|
--- a/drivers/tty/serial/pic32_uart.c
|
|
+++ b/drivers/tty/serial/pic32_uart.c
|
|
@@ -243,7 +243,7 @@ static void pic32_uart_break_ctl(struct uart_port *port, int ctl)
|
|
struct pic32_sport *sport = to_pic32_sport(port);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
if (ctl)
|
|
pic32_uart_writel(sport, PIC32_SET(PIC32_UART_STA),
|
|
@@ -252,7 +252,7 @@ static void pic32_uart_break_ctl(struct uart_port *port, int ctl)
|
|
pic32_uart_writel(sport, PIC32_CLR(PIC32_UART_STA),
|
|
PIC32_UART_STA_UTXBRK);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/* get port type in string format */
|
|
@@ -274,7 +274,7 @@ static void pic32_uart_do_rx(struct uart_port *port)
|
|
*/
|
|
max_count = PIC32_UART_RX_FIFO_DEPTH;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
tty = &port->state->port;
|
|
|
|
@@ -331,7 +331,7 @@ static void pic32_uart_do_rx(struct uart_port *port)
|
|
|
|
} while (--max_count);
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
tty_flip_buffer_push(tty);
|
|
}
|
|
@@ -410,9 +410,9 @@ static irqreturn_t pic32_uart_tx_interrupt(int irq, void *dev_id)
|
|
struct uart_port *port = dev_id;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
pic32_uart_do_tx(port);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -580,9 +580,9 @@ static void pic32_uart_shutdown(struct uart_port *port)
|
|
unsigned long flags;
|
|
|
|
/* disable uart */
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
pic32_uart_dsbl_and_mask(port);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
clk_disable_unprepare(sport->clk);
|
|
|
|
/* free all 3 interrupts for this UART */
|
|
@@ -604,7 +604,7 @@ static void pic32_uart_set_termios(struct uart_port *port,
|
|
unsigned int quot;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* disable uart and mask all interrupts while changing speed */
|
|
pic32_uart_dsbl_and_mask(port);
|
|
@@ -672,7 +672,7 @@ static void pic32_uart_set_termios(struct uart_port *port,
|
|
/* enable uart */
|
|
pic32_uart_en_and_unmask(port);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/* serial core request to claim uart iomem */
|
|
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
|
|
index 29bc80d39e8b..77691fbbf779 100644
|
|
--- a/drivers/tty/serial/pmac_zilog.c
|
|
+++ b/drivers/tty/serial/pmac_zilog.c
|
|
@@ -245,9 +245,9 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap)
|
|
#endif /* USE_CTRL_O_SYSRQ */
|
|
if (uap->port.sysrq) {
|
|
int swallow;
|
|
- spin_unlock(&uap->port.lock);
|
|
+ uart_port_unlock(&uap->port);
|
|
swallow = uart_handle_sysrq_char(&uap->port, ch);
|
|
- spin_lock(&uap->port.lock);
|
|
+ uart_port_lock(&uap->port);
|
|
if (swallow)
|
|
goto next_char;
|
|
}
|
|
@@ -421,7 +421,7 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id)
|
|
uap_a = pmz_get_port_A(uap);
|
|
uap_b = uap_a->mate;
|
|
|
|
- spin_lock(&uap_a->port.lock);
|
|
+ uart_port_lock(&uap_a->port);
|
|
r3 = read_zsreg(uap_a, R3);
|
|
|
|
/* Channel A */
|
|
@@ -442,14 +442,14 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id)
|
|
rc = IRQ_HANDLED;
|
|
}
|
|
skip_a:
|
|
- spin_unlock(&uap_a->port.lock);
|
|
+ uart_port_unlock(&uap_a->port);
|
|
if (push)
|
|
tty_flip_buffer_push(&uap->port.state->port);
|
|
|
|
if (!uap_b)
|
|
goto out;
|
|
|
|
- spin_lock(&uap_b->port.lock);
|
|
+ uart_port_lock(&uap_b->port);
|
|
push = false;
|
|
if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
|
|
if (!ZS_IS_OPEN(uap_b)) {
|
|
@@ -467,7 +467,7 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id)
|
|
rc = IRQ_HANDLED;
|
|
}
|
|
skip_b:
|
|
- spin_unlock(&uap_b->port.lock);
|
|
+ uart_port_unlock(&uap_b->port);
|
|
if (push)
|
|
tty_flip_buffer_push(&uap->port.state->port);
|
|
|
|
@@ -483,9 +483,9 @@ static inline u8 pmz_peek_status(struct uart_pmac_port *uap)
|
|
unsigned long flags;
|
|
u8 status;
|
|
|
|
- spin_lock_irqsave(&uap->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&uap->port, &flags);
|
|
status = read_zsreg(uap, R0);
|
|
- spin_unlock_irqrestore(&uap->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&uap->port, flags);
|
|
|
|
return status;
|
|
}
|
|
@@ -671,7 +671,7 @@ static void pmz_break_ctl(struct uart_port *port, int break_state)
|
|
else
|
|
clear_bits |= SND_BRK;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
new_reg = (uap->curregs[R5] | set_bits) & ~clear_bits;
|
|
if (new_reg != uap->curregs[R5]) {
|
|
@@ -679,7 +679,7 @@ static void pmz_break_ctl(struct uart_port *port, int break_state)
|
|
write_zsreg(uap, R5, uap->curregs[R5]);
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
#ifdef CONFIG_PPC_PMAC
|
|
@@ -851,18 +851,18 @@ static void pmz_irda_reset(struct uart_pmac_port *uap)
|
|
{
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&uap->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&uap->port, &flags);
|
|
uap->curregs[R5] |= DTR;
|
|
write_zsreg(uap, R5, uap->curregs[R5]);
|
|
zssync(uap);
|
|
- spin_unlock_irqrestore(&uap->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&uap->port, flags);
|
|
msleep(110);
|
|
|
|
- spin_lock_irqsave(&uap->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&uap->port, &flags);
|
|
uap->curregs[R5] &= ~DTR;
|
|
write_zsreg(uap, R5, uap->curregs[R5]);
|
|
zssync(uap);
|
|
- spin_unlock_irqrestore(&uap->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&uap->port, flags);
|
|
msleep(10);
|
|
}
|
|
|
|
@@ -882,9 +882,9 @@ static int pmz_startup(struct uart_port *port)
|
|
* initialize the chip
|
|
*/
|
|
if (!ZS_IS_CONS(uap)) {
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
pwr_delay = __pmz_startup(uap);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
sprintf(uap->irq_name, PMACZILOG_NAME"%d", uap->port.line);
|
|
if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED,
|
|
@@ -907,9 +907,9 @@ static int pmz_startup(struct uart_port *port)
|
|
pmz_irda_reset(uap);
|
|
|
|
/* Enable interrupt requests for the channel */
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
pmz_interrupt_control(uap, 1);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -919,7 +919,7 @@ static void pmz_shutdown(struct uart_port *port)
|
|
struct uart_pmac_port *uap = to_pmz(port);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Disable interrupt requests for the channel */
|
|
pmz_interrupt_control(uap, 0);
|
|
@@ -934,19 +934,19 @@ static void pmz_shutdown(struct uart_port *port)
|
|
pmz_maybe_update_regs(uap);
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
/* Release interrupt handler */
|
|
free_irq(uap->port.irq, uap);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
uap->flags &= ~PMACZILOG_FLAG_IS_OPEN;
|
|
|
|
if (!ZS_IS_CONS(uap))
|
|
pmz_set_scc_power(uap, 0); /* Shut the chip down */
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/* Shared by TTY driver and serial console setup. The port lock is held
|
|
@@ -1233,7 +1233,7 @@ static void pmz_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
struct uart_pmac_port *uap = to_pmz(port);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Disable IRQs on the port */
|
|
pmz_interrupt_control(uap, 0);
|
|
@@ -1245,7 +1245,7 @@ static void pmz_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
if (ZS_IS_OPEN(uap))
|
|
pmz_interrupt_control(uap, 1);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *pmz_type(struct uart_port *port)
|
|
@@ -1882,7 +1882,7 @@ static void pmz_console_write(struct console *con, const char *s, unsigned int c
|
|
struct uart_pmac_port *uap = &pmz_ports[con->index];
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&uap->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&uap->port, &flags);
|
|
|
|
/* Turn of interrupts and enable the transmitter. */
|
|
write_zsreg(uap, R1, uap->curregs[1] & ~TxINT_ENAB);
|
|
@@ -1894,7 +1894,7 @@ static void pmz_console_write(struct console *con, const char *s, unsigned int c
|
|
write_zsreg(uap, R1, uap->curregs[1]);
|
|
/* Don't disable the transmitter. */
|
|
|
|
- spin_unlock_irqrestore(&uap->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&uap->port, flags);
|
|
}
|
|
|
|
/*
|
|
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
|
|
index 73c60f5ea027..46e70e155aab 100644
|
|
--- a/drivers/tty/serial/pxa.c
|
|
+++ b/drivers/tty/serial/pxa.c
|
|
@@ -225,14 +225,14 @@ static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id)
|
|
iir = serial_in(up, UART_IIR);
|
|
if (iir & UART_IIR_NO_INT)
|
|
return IRQ_NONE;
|
|
- spin_lock(&up->port.lock);
|
|
+ uart_port_lock(&up->port);
|
|
lsr = serial_in(up, UART_LSR);
|
|
if (lsr & UART_LSR_DR)
|
|
receive_chars(up, &lsr);
|
|
check_modem_status(up);
|
|
if (lsr & UART_LSR_THRE)
|
|
transmit_chars(up);
|
|
- spin_unlock(&up->port.lock);
|
|
+ uart_port_unlock(&up->port);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
@@ -242,9 +242,9 @@ static unsigned int serial_pxa_tx_empty(struct uart_port *port)
|
|
unsigned long flags;
|
|
unsigned int ret;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
return ret;
|
|
}
|
|
@@ -295,13 +295,13 @@ static void serial_pxa_break_ctl(struct uart_port *port, int break_state)
|
|
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
if (break_state == -1)
|
|
up->lcr |= UART_LCR_SBC;
|
|
else
|
|
up->lcr &= ~UART_LCR_SBC;
|
|
serial_out(up, UART_LCR, up->lcr);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static int serial_pxa_startup(struct uart_port *port)
|
|
@@ -346,10 +346,10 @@ static int serial_pxa_startup(struct uart_port *port)
|
|
*/
|
|
serial_out(up, UART_LCR, UART_LCR_WLEN8);
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
up->port.mctrl |= TIOCM_OUT2;
|
|
serial_pxa_set_mctrl(&up->port, up->port.mctrl);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
/*
|
|
* Finally, enable interrupts. Note: Modem status interrupts
|
|
@@ -383,10 +383,10 @@ static void serial_pxa_shutdown(struct uart_port *port)
|
|
up->ier = 0;
|
|
serial_out(up, UART_IER, 0);
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
up->port.mctrl &= ~TIOCM_OUT2;
|
|
serial_pxa_set_mctrl(&up->port, up->port.mctrl);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
/*
|
|
* Disable break condition and FIFOs
|
|
@@ -434,7 +434,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
* Ok, we're now changing the port state. Do it with
|
|
* interrupts disabled.
|
|
*/
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
/*
|
|
* Ensure the port will be enabled.
|
|
@@ -504,7 +504,7 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
up->lcr = cval; /* Save LCR */
|
|
serial_pxa_set_mctrl(&up->port, up->port.mctrl);
|
|
serial_out(up, UART_FCR, fcr);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static void
|
|
@@ -608,9 +608,9 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
|
|
if (up->port.sysrq)
|
|
locked = 0;
|
|
else if (oops_in_progress)
|
|
- locked = spin_trylock(&up->port.lock);
|
|
+ locked = uart_port_trylock(&up->port);
|
|
else
|
|
- spin_lock(&up->port.lock);
|
|
+ uart_port_lock(&up->port);
|
|
|
|
/*
|
|
* First save the IER then disable the interrupts
|
|
@@ -628,7 +628,7 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
|
|
serial_out(up, UART_IER, ier);
|
|
|
|
if (locked)
|
|
- spin_unlock(&up->port.lock);
|
|
+ uart_port_unlock(&up->port);
|
|
local_irq_restore(flags);
|
|
clk_disable(up->clk);
|
|
|
|
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
|
|
index 2e1b1c827dfe..549909644011 100644
|
|
--- a/drivers/tty/serial/qcom_geni_serial.c
|
|
+++ b/drivers/tty/serial/qcom_geni_serial.c
|
|
@@ -482,9 +482,9 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
|
|
|
|
uport = &port->uport;
|
|
if (oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&uport->lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(uport, &flags);
|
|
else
|
|
- spin_lock_irqsave(&uport->lock, flags);
|
|
+ uart_port_lock_irqsave(uport, &flags);
|
|
|
|
geni_status = readl(uport->membase + SE_GENI_STATUS);
|
|
|
|
@@ -520,7 +520,7 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
|
|
qcom_geni_serial_setup_tx(uport, port->tx_remaining);
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&uport->lock, flags);
|
|
+ uart_port_unlock_irqrestore(uport, flags);
|
|
}
|
|
|
|
static void handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
|
|
@@ -972,7 +972,7 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
|
|
if (uport->suspended)
|
|
return IRQ_NONE;
|
|
|
|
- spin_lock(&uport->lock);
|
|
+ uart_port_lock(uport);
|
|
|
|
m_irq_status = readl(uport->membase + SE_GENI_M_IRQ_STATUS);
|
|
s_irq_status = readl(uport->membase + SE_GENI_S_IRQ_STATUS);
|
|
diff --git a/drivers/tty/serial/rda-uart.c b/drivers/tty/serial/rda-uart.c
|
|
index be5c842b5ba9..d824c8318f33 100644
|
|
--- a/drivers/tty/serial/rda-uart.c
|
|
+++ b/drivers/tty/serial/rda-uart.c
|
|
@@ -139,12 +139,12 @@ static unsigned int rda_uart_tx_empty(struct uart_port *port)
|
|
unsigned int ret;
|
|
u32 val;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
val = rda_uart_read(port, RDA_UART_STATUS);
|
|
ret = (val & RDA_UART_TX_FIFO_MASK) ? TIOCSER_TEMT : 0;
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return ret;
|
|
}
|
|
@@ -246,7 +246,7 @@ static void rda_uart_set_termios(struct uart_port *port,
|
|
unsigned int baud;
|
|
u32 irq_mask;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
baud = uart_get_baud_rate(port, termios, old, 9600, port->uartclk / 4);
|
|
rda_uart_change_baudrate(rda_port, baud);
|
|
@@ -325,7 +325,7 @@ static void rda_uart_set_termios(struct uart_port *port,
|
|
/* update the per-port timeout */
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void rda_uart_send_chars(struct uart_port *port)
|
|
@@ -408,7 +408,7 @@ static irqreturn_t rda_interrupt(int irq, void *dev_id)
|
|
unsigned long flags;
|
|
u32 val, irq_mask;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Clear IRQ cause */
|
|
val = rda_uart_read(port, RDA_UART_IRQ_CAUSE);
|
|
@@ -425,7 +425,7 @@ static irqreturn_t rda_interrupt(int irq, void *dev_id)
|
|
rda_uart_send_chars(port);
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -436,16 +436,16 @@ static int rda_uart_startup(struct uart_port *port)
|
|
int ret;
|
|
u32 val;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
rda_uart_write(port, 0, RDA_UART_IRQ_MASK);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
ret = request_irq(port->irq, rda_interrupt, IRQF_NO_SUSPEND,
|
|
"rda-uart", port);
|
|
if (ret)
|
|
return ret;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
val = rda_uart_read(port, RDA_UART_CTRL);
|
|
val |= RDA_UART_ENABLE;
|
|
@@ -456,7 +456,7 @@ static int rda_uart_startup(struct uart_port *port)
|
|
val |= (RDA_UART_RX_DATA_AVAILABLE | RDA_UART_RX_TIMEOUT);
|
|
rda_uart_write(port, val, RDA_UART_IRQ_MASK);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -466,7 +466,7 @@ static void rda_uart_shutdown(struct uart_port *port)
|
|
unsigned long flags;
|
|
u32 val;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
rda_uart_stop_tx(port);
|
|
rda_uart_stop_rx(port);
|
|
@@ -475,7 +475,7 @@ static void rda_uart_shutdown(struct uart_port *port)
|
|
val &= ~RDA_UART_ENABLE;
|
|
rda_uart_write(port, val, RDA_UART_CTRL);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *rda_uart_type(struct uart_port *port)
|
|
@@ -515,7 +515,7 @@ static void rda_uart_config_port(struct uart_port *port, int flags)
|
|
rda_uart_request_port(port);
|
|
}
|
|
|
|
- spin_lock_irqsave(&port->lock, irq_flags);
|
|
+ uart_port_lock_irqsave(port, &irq_flags);
|
|
|
|
/* Clear mask, so no surprise interrupts. */
|
|
rda_uart_write(port, 0, RDA_UART_IRQ_MASK);
|
|
@@ -523,7 +523,7 @@ static void rda_uart_config_port(struct uart_port *port, int flags)
|
|
/* Clear status register */
|
|
rda_uart_write(port, 0, RDA_UART_STATUS);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, irq_flags);
|
|
+ uart_port_unlock_irqrestore(port, irq_flags);
|
|
}
|
|
|
|
static void rda_uart_release_port(struct uart_port *port)
|
|
@@ -597,9 +597,9 @@ static void rda_uart_port_write(struct uart_port *port, const char *s,
|
|
if (port->sysrq) {
|
|
locked = 0;
|
|
} else if (oops_in_progress) {
|
|
- locked = spin_trylock(&port->lock);
|
|
+ locked = uart_port_trylock(port);
|
|
} else {
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
locked = 1;
|
|
}
|
|
|
|
@@ -615,7 +615,7 @@ static void rda_uart_port_write(struct uart_port *port, const char *s,
|
|
rda_uart_write(port, old_irq_mask, RDA_UART_IRQ_MASK);
|
|
|
|
if (locked)
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
local_irq_restore(flags);
|
|
}
|
|
diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c
|
|
index de220ac8ca54..d46a81cddfcd 100644
|
|
--- a/drivers/tty/serial/rp2.c
|
|
+++ b/drivers/tty/serial/rp2.c
|
|
@@ -276,9 +276,9 @@ static unsigned int rp2_uart_tx_empty(struct uart_port *port)
|
|
* But the TXEMPTY bit doesn't seem to work unless the TX IRQ is
|
|
* enabled.
|
|
*/
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
tx_fifo_bytes = readw(up->base + RP2_TX_FIFO_COUNT);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
return tx_fifo_bytes ? 0 : TIOCSER_TEMT;
|
|
}
|
|
@@ -323,10 +323,10 @@ static void rp2_uart_break_ctl(struct uart_port *port, int break_state)
|
|
{
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
rp2_rmw(port_to_up(port), RP2_TXRX_CTL, RP2_TXRX_CTL_BREAK_m,
|
|
break_state ? RP2_TXRX_CTL_BREAK_m : 0);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void rp2_uart_enable_ms(struct uart_port *port)
|
|
@@ -383,7 +383,7 @@ static void rp2_uart_set_termios(struct uart_port *port, struct ktermios *new,
|
|
if (tty_termios_baud_rate(new))
|
|
tty_termios_encode_baud_rate(new, baud, baud);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* ignore all characters if CREAD is not set */
|
|
port->ignore_status_mask = (new->c_cflag & CREAD) ? 0 : RP2_DUMMY_READ;
|
|
@@ -391,7 +391,7 @@ static void rp2_uart_set_termios(struct uart_port *port, struct ktermios *new,
|
|
__rp2_uart_set_termios(up, new->c_cflag, new->c_iflag, baud_div);
|
|
uart_update_timeout(port, new->c_cflag, baud);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void rp2_rx_chars(struct rp2_uart_port *up)
|
|
@@ -440,7 +440,7 @@ static void rp2_ch_interrupt(struct rp2_uart_port *up)
|
|
{
|
|
u32 status;
|
|
|
|
- spin_lock(&up->port.lock);
|
|
+ uart_port_lock(&up->port);
|
|
|
|
/*
|
|
* The IRQ status bits are clear-on-write. Other status bits in
|
|
@@ -456,7 +456,7 @@ static void rp2_ch_interrupt(struct rp2_uart_port *up)
|
|
if (status & RP2_CHAN_STAT_MS_CHANGED_MASK)
|
|
wake_up_interruptible(&up->port.state->port.delta_msr_wait);
|
|
|
|
- spin_unlock(&up->port.lock);
|
|
+ uart_port_unlock(&up->port);
|
|
}
|
|
|
|
static int rp2_asic_interrupt(struct rp2_card *card, unsigned int asic_id)
|
|
@@ -516,10 +516,10 @@ static void rp2_uart_shutdown(struct uart_port *port)
|
|
|
|
rp2_uart_break_ctl(port, 0);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
rp2_mask_ch_irq(up, up->idx, 0);
|
|
rp2_rmw(up, RP2_CHAN_STAT, 0, 0);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *rp2_uart_type(struct uart_port *port)
|
|
diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c
|
|
index ad011f1e2f4d..be7bcd75d9f4 100644
|
|
--- a/drivers/tty/serial/sa1100.c
|
|
+++ b/drivers/tty/serial/sa1100.c
|
|
@@ -115,9 +115,9 @@ static void sa1100_timeout(struct timer_list *t)
|
|
unsigned long flags;
|
|
|
|
if (sport->port.state) {
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
sa1100_mctrl_check(sport);
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
|
|
mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
|
|
}
|
|
@@ -247,7 +247,7 @@ static irqreturn_t sa1100_int(int irq, void *dev_id)
|
|
struct sa1100_port *sport = dev_id;
|
|
unsigned int status, pass_counter = 0;
|
|
|
|
- spin_lock(&sport->port.lock);
|
|
+ uart_port_lock(&sport->port);
|
|
status = UART_GET_UTSR0(sport);
|
|
status &= SM_TO_UTSR0(sport->port.read_status_mask) | ~UTSR0_TFS;
|
|
do {
|
|
@@ -276,7 +276,7 @@ static irqreturn_t sa1100_int(int irq, void *dev_id)
|
|
status &= SM_TO_UTSR0(sport->port.read_status_mask) |
|
|
~UTSR0_TFS;
|
|
} while (status & (UTSR0_TFS | UTSR0_RFS | UTSR0_RID));
|
|
- spin_unlock(&sport->port.lock);
|
|
+ uart_port_unlock(&sport->port);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -321,14 +321,14 @@ static void sa1100_break_ctl(struct uart_port *port, int break_state)
|
|
unsigned long flags;
|
|
unsigned int utcr3;
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
utcr3 = UART_GET_UTCR3(sport);
|
|
if (break_state == -1)
|
|
utcr3 |= UTCR3_BRK;
|
|
else
|
|
utcr3 &= ~UTCR3_BRK;
|
|
UART_PUT_UTCR3(sport, utcr3);
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
}
|
|
|
|
static int sa1100_startup(struct uart_port *port)
|
|
@@ -354,9 +354,9 @@ static int sa1100_startup(struct uart_port *port)
|
|
/*
|
|
* Enable modem status interrupts
|
|
*/
|
|
- spin_lock_irq(&sport->port.lock);
|
|
+ uart_port_lock_irq(&sport->port);
|
|
sa1100_enable_ms(&sport->port);
|
|
- spin_unlock_irq(&sport->port.lock);
|
|
+ uart_port_unlock_irq(&sport->port);
|
|
|
|
return 0;
|
|
}
|
|
@@ -423,7 +423,7 @@ sa1100_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
|
|
del_timer_sync(&sport->timer);
|
|
|
|
- spin_lock_irqsave(&sport->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&sport->port, &flags);
|
|
|
|
sport->port.read_status_mask &= UTSR0_TO_SM(UTSR0_TFS);
|
|
sport->port.read_status_mask |= UTSR1_TO_SM(UTSR1_ROR);
|
|
@@ -485,7 +485,7 @@ sa1100_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
|
|
sa1100_enable_ms(&sport->port);
|
|
|
|
- spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&sport->port, flags);
|
|
}
|
|
|
|
static const char *sa1100_type(struct uart_port *port)
|
|
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
|
|
index 5a4d88e13471..a82b65155f6e 100644
|
|
--- a/drivers/tty/serial/samsung_tty.c
|
|
+++ b/drivers/tty/serial/samsung_tty.c
|
|
@@ -248,7 +248,7 @@ static void s3c24xx_serial_rx_enable(struct uart_port *port)
|
|
unsigned int ucon, ufcon;
|
|
int count = 10000;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
while (--count && !s3c24xx_serial_txempty_nofifo(port))
|
|
udelay(100);
|
|
@@ -262,7 +262,7 @@ static void s3c24xx_serial_rx_enable(struct uart_port *port)
|
|
wr_regl(port, S3C2410_UCON, ucon);
|
|
|
|
ourport->rx_enabled = 1;
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void s3c24xx_serial_rx_disable(struct uart_port *port)
|
|
@@ -271,14 +271,14 @@ static void s3c24xx_serial_rx_disable(struct uart_port *port)
|
|
unsigned long flags;
|
|
unsigned int ucon;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
ucon = rd_regl(port, S3C2410_UCON);
|
|
ucon &= ~S3C2410_UCON_RXIRQMODE;
|
|
wr_regl(port, S3C2410_UCON, ucon);
|
|
|
|
ourport->rx_enabled = 0;
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void s3c24xx_serial_stop_tx(struct uart_port *port)
|
|
@@ -344,7 +344,7 @@ static void s3c24xx_serial_tx_dma_complete(void *args)
|
|
dma->tx_transfer_addr, dma->tx_size,
|
|
DMA_TO_DEVICE);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
uart_xmit_advance(port, count);
|
|
ourport->tx_in_progress = 0;
|
|
@@ -353,7 +353,7 @@ static void s3c24xx_serial_tx_dma_complete(void *args)
|
|
uart_write_wakeup(port);
|
|
|
|
s3c24xx_serial_start_next_tx(ourport);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
|
|
@@ -619,7 +619,7 @@ static void s3c24xx_serial_rx_dma_complete(void *args)
|
|
received = dma->rx_bytes_requested - state.residue;
|
|
async_tx_ack(dma->rx_desc);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
if (received)
|
|
s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
|
|
@@ -631,7 +631,7 @@ static void s3c24xx_serial_rx_dma_complete(void *args)
|
|
|
|
s3c64xx_start_rx_dma(ourport);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport)
|
|
@@ -722,7 +722,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id)
|
|
utrstat = rd_regl(port, S3C2410_UTRSTAT);
|
|
rd_regl(port, S3C2410_UFSTAT);
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
if (!(utrstat & S3C2410_UTRSTAT_TIMEOUT)) {
|
|
s3c64xx_start_rx_dma(ourport);
|
|
@@ -751,7 +751,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id)
|
|
wr_regl(port, S3C2410_UTRSTAT, S3C2410_UTRSTAT_TIMEOUT);
|
|
|
|
finish:
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -849,9 +849,9 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(void *dev_id)
|
|
struct s3c24xx_uart_port *ourport = dev_id;
|
|
struct uart_port *port = &ourport->port;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
s3c24xx_serial_rx_drain_fifo(ourport);
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -932,11 +932,11 @@ static irqreturn_t s3c24xx_serial_tx_irq(int irq, void *id)
|
|
struct s3c24xx_uart_port *ourport = id;
|
|
struct uart_port *port = &ourport->port;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
s3c24xx_serial_tx_chars(ourport);
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
@@ -1032,7 +1032,7 @@ static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
|
|
unsigned long flags;
|
|
unsigned int ucon;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
ucon = rd_regl(port, S3C2410_UCON);
|
|
|
|
@@ -1043,7 +1043,7 @@ static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
|
|
|
|
wr_regl(port, S3C2410_UCON, ucon);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
|
|
@@ -1302,7 +1302,7 @@ static int s3c64xx_serial_startup(struct uart_port *port)
|
|
ourport->rx_enabled = 1;
|
|
ourport->tx_enabled = 0;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
ufcon = rd_regl(port, S3C2410_UFCON);
|
|
ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8;
|
|
@@ -1312,7 +1312,7 @@ static int s3c64xx_serial_startup(struct uart_port *port)
|
|
|
|
enable_rx_pio(ourport);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
/* Enable Rx Interrupt */
|
|
s3c24xx_clear_bit(port, S3C64XX_UINTM_RXD, S3C64XX_UINTM);
|
|
@@ -1340,7 +1340,7 @@ static int apple_s5l_serial_startup(struct uart_port *port)
|
|
ourport->rx_enabled = 1;
|
|
ourport->tx_enabled = 0;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
ufcon = rd_regl(port, S3C2410_UFCON);
|
|
ufcon |= S3C2410_UFCON_RESETRX | S5PV210_UFCON_RXTRIG8;
|
|
@@ -1350,7 +1350,7 @@ static int apple_s5l_serial_startup(struct uart_port *port)
|
|
|
|
enable_rx_pio(ourport);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
/* Enable Rx Interrupt */
|
|
s3c24xx_set_bit(port, APPLE_S5L_UCON_RXTHRESH_ENA, S3C2410_UCON);
|
|
@@ -1625,7 +1625,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
|
|
ulcon |= S3C2410_LCON_PNONE;
|
|
}
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
dev_dbg(port->dev,
|
|
"setting ulcon to %08x, brddiv to %d, udivslot %08x\n",
|
|
@@ -1683,7 +1683,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
|
|
if ((termios->c_cflag & CREAD) == 0)
|
|
port->ignore_status_mask |= RXSTAT_DUMMY_READ;
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *s3c24xx_serial_type(struct uart_port *port)
|
|
@@ -2375,14 +2375,14 @@ s3c24xx_serial_console_write(struct console *co, const char *s,
|
|
if (cons_uart->sysrq)
|
|
locked = false;
|
|
else if (oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&cons_uart->lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(cons_uart, &flags);
|
|
else
|
|
- spin_lock_irqsave(&cons_uart->lock, flags);
|
|
+ uart_port_lock_irqsave(cons_uart, &flags);
|
|
|
|
uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar);
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&cons_uart->lock, flags);
|
|
+ uart_port_unlock_irqrestore(cons_uart, flags);
|
|
}
|
|
|
|
/* Shouldn't be __init, as it can be instantiated from other module */
|
|
diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c
|
|
index f3cd69346482..dbec29d9a6c3 100644
|
|
--- a/drivers/tty/serial/sb1250-duart.c
|
|
+++ b/drivers/tty/serial/sb1250-duart.c
|
|
@@ -610,7 +610,7 @@ static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios,
|
|
else
|
|
aux &= ~M_DUART_CTS_CHNG_ENA;
|
|
|
|
- spin_lock(&uport->lock);
|
|
+ uart_port_lock(uport);
|
|
|
|
if (sport->tx_stopped)
|
|
command |= M_DUART_TX_DIS;
|
|
@@ -632,7 +632,7 @@ static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios,
|
|
|
|
write_sbdchn(sport, R_DUART_CMD, command);
|
|
|
|
- spin_unlock(&uport->lock);
|
|
+ uart_port_unlock(uport);
|
|
}
|
|
|
|
|
|
@@ -839,22 +839,22 @@ static void sbd_console_write(struct console *co, const char *s,
|
|
unsigned int mask;
|
|
|
|
/* Disable transmit interrupts and enable the transmitter. */
|
|
- spin_lock_irqsave(&uport->lock, flags);
|
|
+ uart_port_lock_irqsave(uport, &flags);
|
|
mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2));
|
|
write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2),
|
|
mask & ~M_DUART_IMR_TX);
|
|
write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN);
|
|
- spin_unlock_irqrestore(&uport->lock, flags);
|
|
+ uart_port_unlock_irqrestore(uport, flags);
|
|
|
|
uart_console_write(&sport->port, s, count, sbd_console_putchar);
|
|
|
|
/* Restore transmit interrupts and the transmitter enable. */
|
|
- spin_lock_irqsave(&uport->lock, flags);
|
|
+ uart_port_lock_irqsave(uport, &flags);
|
|
sbd_line_drain(sport);
|
|
if (sport->tx_stopped)
|
|
write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS);
|
|
write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask);
|
|
- spin_unlock_irqrestore(&uport->lock, flags);
|
|
+ uart_port_unlock_irqrestore(uport, flags);
|
|
}
|
|
|
|
static int __init sbd_console_setup(struct console *co, char *options)
|
|
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
|
|
index 7a9924d9b294..be9ae5cdd1b8 100644
|
|
--- a/drivers/tty/serial/sc16is7xx.c
|
|
+++ b/drivers/tty/serial/sc16is7xx.c
|
|
@@ -817,6 +817,7 @@ static void sc16is7xx_tx_proc(struct kthread_work *ws)
|
|
{
|
|
struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port);
|
|
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
|
|
+ unsigned long flags;
|
|
|
|
if ((port->rs485.flags & SER_RS485_ENABLED) &&
|
|
(port->rs485.delay_rts_before_send > 0))
|
|
@@ -825,6 +826,10 @@ static void sc16is7xx_tx_proc(struct kthread_work *ws)
|
|
mutex_lock(&one->efr_lock);
|
|
sc16is7xx_handle_tx(port);
|
|
mutex_unlock(&one->efr_lock);
|
|
+
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
+ sc16is7xx_ier_set(port, SC16IS7XX_IER_THRI_BIT);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void sc16is7xx_reconf_rs485(struct uart_port *port)
|
|
diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
|
|
index d4ec943cb8e9..6d4006b41975 100644
|
|
--- a/drivers/tty/serial/serial-tegra.c
|
|
+++ b/drivers/tty/serial/serial-tegra.c
|
|
@@ -411,7 +411,7 @@ static int tegra_set_baudrate(struct tegra_uart_port *tup, unsigned int baud)
|
|
divisor = DIV_ROUND_CLOSEST(rate, baud * 16);
|
|
}
|
|
|
|
- spin_lock_irqsave(&tup->uport.lock, flags);
|
|
+ uart_port_lock_irqsave(&tup->uport, &flags);
|
|
lcr = tup->lcr_shadow;
|
|
lcr |= UART_LCR_DLAB;
|
|
tegra_uart_write(tup, lcr, UART_LCR);
|
|
@@ -424,7 +424,7 @@ static int tegra_set_baudrate(struct tegra_uart_port *tup, unsigned int baud)
|
|
|
|
/* Dummy read to ensure the write is posted */
|
|
tegra_uart_read(tup, UART_SCR);
|
|
- spin_unlock_irqrestore(&tup->uport.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&tup->uport, flags);
|
|
|
|
tup->current_baud = baud;
|
|
|
|
@@ -522,13 +522,13 @@ static void tegra_uart_tx_dma_complete(void *args)
|
|
dmaengine_tx_status(tup->tx_dma_chan, tup->tx_cookie, &state);
|
|
count = tup->tx_bytes_requested - state.residue;
|
|
async_tx_ack(tup->tx_dma_desc);
|
|
- spin_lock_irqsave(&tup->uport.lock, flags);
|
|
+ uart_port_lock_irqsave(&tup->uport, &flags);
|
|
uart_xmit_advance(&tup->uport, count);
|
|
tup->tx_in_progress = 0;
|
|
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
|
uart_write_wakeup(&tup->uport);
|
|
tegra_uart_start_next_tx(tup);
|
|
- spin_unlock_irqrestore(&tup->uport.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&tup->uport, flags);
|
|
}
|
|
|
|
static int tegra_uart_start_tx_dma(struct tegra_uart_port *tup,
|
|
@@ -598,13 +598,13 @@ static unsigned int tegra_uart_tx_empty(struct uart_port *u)
|
|
unsigned int ret = 0;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&u->lock, flags);
|
|
+ uart_port_lock_irqsave(u, &flags);
|
|
if (!tup->tx_in_progress) {
|
|
unsigned long lsr = tegra_uart_read(tup, UART_LSR);
|
|
if ((lsr & TX_EMPTY_STATUS) == TX_EMPTY_STATUS)
|
|
ret = TIOCSER_TEMT;
|
|
}
|
|
- spin_unlock_irqrestore(&u->lock, flags);
|
|
+ uart_port_unlock_irqrestore(u, flags);
|
|
return ret;
|
|
}
|
|
|
|
@@ -727,7 +727,7 @@ static void tegra_uart_rx_dma_complete(void *args)
|
|
struct dma_tx_state state;
|
|
enum dma_status status;
|
|
|
|
- spin_lock_irqsave(&u->lock, flags);
|
|
+ uart_port_lock_irqsave(u, &flags);
|
|
|
|
status = dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
|
|
|
|
@@ -749,7 +749,7 @@ static void tegra_uart_rx_dma_complete(void *args)
|
|
set_rts(tup, true);
|
|
|
|
done:
|
|
- spin_unlock_irqrestore(&u->lock, flags);
|
|
+ uart_port_unlock_irqrestore(u, flags);
|
|
}
|
|
|
|
static void tegra_uart_terminate_rx_dma(struct tegra_uart_port *tup)
|
|
@@ -836,7 +836,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data)
|
|
bool is_rx_int = false;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&u->lock, flags);
|
|
+ uart_port_lock_irqsave(u, &flags);
|
|
while (1) {
|
|
iir = tegra_uart_read(tup, UART_IIR);
|
|
if (iir & UART_IIR_NO_INT) {
|
|
@@ -852,7 +852,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data)
|
|
} else if (is_rx_start) {
|
|
tegra_uart_start_rx_dma(tup);
|
|
}
|
|
- spin_unlock_irqrestore(&u->lock, flags);
|
|
+ uart_port_unlock_irqrestore(u, flags);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
@@ -969,11 +969,11 @@ static void tegra_uart_hw_deinit(struct tegra_uart_port *tup)
|
|
}
|
|
}
|
|
|
|
- spin_lock_irqsave(&tup->uport.lock, flags);
|
|
+ uart_port_lock_irqsave(&tup->uport, &flags);
|
|
/* Reset the Rx and Tx FIFOs */
|
|
tegra_uart_fifo_reset(tup, UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR);
|
|
tup->current_baud = 0;
|
|
- spin_unlock_irqrestore(&tup->uport.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&tup->uport, flags);
|
|
|
|
tup->rx_in_progress = 0;
|
|
tup->tx_in_progress = 0;
|
|
@@ -1292,7 +1292,7 @@ static void tegra_uart_set_termios(struct uart_port *u,
|
|
int ret;
|
|
|
|
max_divider *= 16;
|
|
- spin_lock_irqsave(&u->lock, flags);
|
|
+ uart_port_lock_irqsave(u, &flags);
|
|
|
|
/* Changing configuration, it is safe to stop any rx now */
|
|
if (tup->rts_active)
|
|
@@ -1341,7 +1341,7 @@ static void tegra_uart_set_termios(struct uart_port *u,
|
|
baud = uart_get_baud_rate(u, termios, oldtermios,
|
|
parent_clk_rate/max_divider,
|
|
parent_clk_rate/16);
|
|
- spin_unlock_irqrestore(&u->lock, flags);
|
|
+ uart_port_unlock_irqrestore(u, flags);
|
|
ret = tegra_set_baudrate(tup, baud);
|
|
if (ret < 0) {
|
|
dev_err(tup->uport.dev, "Failed to set baud rate\n");
|
|
@@ -1349,7 +1349,7 @@ static void tegra_uart_set_termios(struct uart_port *u,
|
|
}
|
|
if (tty_termios_baud_rate(termios))
|
|
tty_termios_encode_baud_rate(termios, baud, baud);
|
|
- spin_lock_irqsave(&u->lock, flags);
|
|
+ uart_port_lock_irqsave(u, &flags);
|
|
|
|
/* Flow control */
|
|
if (termios->c_cflag & CRTSCTS) {
|
|
@@ -1382,7 +1382,7 @@ static void tegra_uart_set_termios(struct uart_port *u,
|
|
if (termios->c_iflag & IGNBRK)
|
|
tup->uport.ignore_status_mask |= UART_LSR_BI;
|
|
|
|
- spin_unlock_irqrestore(&u->lock, flags);
|
|
+ uart_port_unlock_irqrestore(u, flags);
|
|
}
|
|
|
|
static const char *tegra_uart_type(struct uart_port *u)
|
|
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
|
|
index ed8798fdf522..f0cd976e22e2 100644
|
|
--- a/drivers/tty/serial/serial_core.c
|
|
+++ b/drivers/tty/serial/serial_core.c
|
|
@@ -79,7 +79,7 @@ static inline void uart_port_deref(struct uart_port *uport)
|
|
({ \
|
|
struct uart_port *__uport = uart_port_ref(state); \
|
|
if (__uport) \
|
|
- spin_lock_irqsave(&__uport->lock, flags); \
|
|
+ uart_port_lock_irqsave(__uport, &flags); \
|
|
__uport; \
|
|
})
|
|
|
|
@@ -87,7 +87,7 @@ static inline void uart_port_deref(struct uart_port *uport)
|
|
({ \
|
|
struct uart_port *__uport = uport; \
|
|
if (__uport) { \
|
|
- spin_unlock_irqrestore(&__uport->lock, flags); \
|
|
+ uart_port_unlock_irqrestore(__uport, flags); \
|
|
uart_port_deref(__uport); \
|
|
} \
|
|
})
|
|
@@ -179,12 +179,12 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
|
|
unsigned long flags;
|
|
unsigned int old;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
old = port->mctrl;
|
|
port->mctrl = (old & ~clear) | set;
|
|
if (old != port->mctrl && !(port->rs485.flags & SER_RS485_ENABLED))
|
|
port->ops->set_mctrl(port, port->mctrl);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
#define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0)
|
|
@@ -219,7 +219,7 @@ static void uart_change_line_settings(struct tty_struct *tty, struct uart_state
|
|
/*
|
|
* Set modem status enables based on termios cflag
|
|
*/
|
|
- spin_lock_irq(&uport->lock);
|
|
+ uart_port_lock_irq(uport);
|
|
if (termios->c_cflag & CRTSCTS)
|
|
uport->status |= UPSTAT_CTS_ENABLE;
|
|
else
|
|
@@ -240,7 +240,7 @@ static void uart_change_line_settings(struct tty_struct *tty, struct uart_state
|
|
else
|
|
__uart_start(state);
|
|
}
|
|
- spin_unlock_irq(&uport->lock);
|
|
+ uart_port_unlock_irq(uport);
|
|
}
|
|
|
|
/*
|
|
@@ -715,11 +715,11 @@ static void uart_send_xchar(struct tty_struct *tty, char ch)
|
|
if (port->ops->send_xchar)
|
|
port->ops->send_xchar(port, ch);
|
|
else {
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
port->x_char = ch;
|
|
if (ch)
|
|
port->ops->start_tx(port);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
uart_port_deref(port);
|
|
}
|
|
@@ -1106,9 +1106,9 @@ static int uart_tiocmget(struct tty_struct *tty)
|
|
|
|
if (!tty_io_error(tty)) {
|
|
result = uport->mctrl;
|
|
- spin_lock_irq(&uport->lock);
|
|
+ uart_port_lock_irq(uport);
|
|
result |= uport->ops->get_mctrl(uport);
|
|
- spin_unlock_irq(&uport->lock);
|
|
+ uart_port_unlock_irq(uport);
|
|
}
|
|
out:
|
|
mutex_unlock(&port->mutex);
|
|
@@ -1244,16 +1244,16 @@ static int uart_wait_modem_status(struct uart_state *state, unsigned long arg)
|
|
uport = uart_port_ref(state);
|
|
if (!uport)
|
|
return -EIO;
|
|
- spin_lock_irq(&uport->lock);
|
|
+ uart_port_lock_irq(uport);
|
|
memcpy(&cprev, &uport->icount, sizeof(struct uart_icount));
|
|
uart_enable_ms(uport);
|
|
- spin_unlock_irq(&uport->lock);
|
|
+ uart_port_unlock_irq(uport);
|
|
|
|
add_wait_queue(&port->delta_msr_wait, &wait);
|
|
for (;;) {
|
|
- spin_lock_irq(&uport->lock);
|
|
+ uart_port_lock_irq(uport);
|
|
memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
|
|
- spin_unlock_irq(&uport->lock);
|
|
+ uart_port_unlock_irq(uport);
|
|
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
|
|
|
@@ -1298,9 +1298,9 @@ static int uart_get_icount(struct tty_struct *tty,
|
|
uport = uart_port_ref(state);
|
|
if (!uport)
|
|
return -EIO;
|
|
- spin_lock_irq(&uport->lock);
|
|
+ uart_port_lock_irq(uport);
|
|
memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
|
|
- spin_unlock_irq(&uport->lock);
|
|
+ uart_port_unlock_irq(uport);
|
|
uart_port_deref(uport);
|
|
|
|
icount->cts = cnow.cts;
|
|
@@ -1453,9 +1453,9 @@ static int uart_rs485_config(struct uart_port *port)
|
|
uart_set_rs485_termination(port, rs485);
|
|
uart_set_rs485_rx_during_tx(port, rs485);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
ret = port->rs485_config(port, NULL, rs485);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
if (ret) {
|
|
memset(rs485, 0, sizeof(*rs485));
|
|
/* unset GPIOs */
|
|
@@ -1472,9 +1472,9 @@ static int uart_get_rs485_config(struct uart_port *port,
|
|
unsigned long flags;
|
|
struct serial_rs485 aux;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
aux = port->rs485;
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
if (copy_to_user(rs485, &aux, sizeof(aux)))
|
|
return -EFAULT;
|
|
@@ -1502,7 +1502,7 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port,
|
|
uart_set_rs485_termination(port, &rs485);
|
|
uart_set_rs485_rx_during_tx(port, &rs485);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
ret = port->rs485_config(port, &tty->termios, &rs485);
|
|
if (!ret) {
|
|
port->rs485 = rs485;
|
|
@@ -1511,7 +1511,7 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port,
|
|
if (!(rs485.flags & SER_RS485_ENABLED))
|
|
port->ops->set_mctrl(port, port->mctrl);
|
|
}
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
if (ret) {
|
|
/* restore old GPIO settings */
|
|
gpiod_set_value_cansleep(port->rs485_term_gpio,
|
|
@@ -1536,9 +1536,9 @@ static int uart_get_iso7816_config(struct uart_port *port,
|
|
if (!port->iso7816_config)
|
|
return -ENOTTY;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
aux = port->iso7816;
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
if (copy_to_user(iso7816, &aux, sizeof(aux)))
|
|
return -EFAULT;
|
|
@@ -1567,9 +1567,9 @@ static int uart_set_iso7816_config(struct uart_port *port,
|
|
if (iso7816.reserved[i])
|
|
return -EINVAL;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
ret = port->iso7816_config(port, &iso7816);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
if (ret)
|
|
return ret;
|
|
|
|
@@ -1786,9 +1786,9 @@ static void uart_tty_port_shutdown(struct tty_port *port)
|
|
if (WARN(!uport, "detached port still initialized!\n"))
|
|
return;
|
|
|
|
- spin_lock_irq(&uport->lock);
|
|
+ uart_port_lock_irq(uport);
|
|
uport->ops->stop_rx(uport);
|
|
- spin_unlock_irq(&uport->lock);
|
|
+ uart_port_unlock_irq(uport);
|
|
|
|
serial_base_port_shutdown(uport);
|
|
uart_port_shutdown(port);
|
|
@@ -1803,11 +1803,11 @@ static void uart_tty_port_shutdown(struct tty_port *port)
|
|
/*
|
|
* Free the transmit buffer.
|
|
*/
|
|
- spin_lock_irq(&uport->lock);
|
|
+ uart_port_lock_irq(uport);
|
|
uart_circ_clear(&state->xmit);
|
|
buf = state->xmit.buf;
|
|
state->xmit.buf = NULL;
|
|
- spin_unlock_irq(&uport->lock);
|
|
+ uart_port_unlock_irq(uport);
|
|
|
|
free_page((unsigned long)buf);
|
|
|
|
@@ -1950,10 +1950,10 @@ static bool uart_carrier_raised(struct tty_port *port)
|
|
*/
|
|
if (WARN_ON(!uport))
|
|
return true;
|
|
- spin_lock_irq(&uport->lock);
|
|
+ uart_port_lock_irq(uport);
|
|
uart_enable_ms(uport);
|
|
mctrl = uport->ops->get_mctrl(uport);
|
|
- spin_unlock_irq(&uport->lock);
|
|
+ uart_port_unlock_irq(uport);
|
|
uart_port_deref(uport);
|
|
|
|
return mctrl & TIOCM_CAR;
|
|
@@ -2070,9 +2070,9 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
|
|
pm_state = state->pm_state;
|
|
if (pm_state != UART_PM_STATE_ON)
|
|
uart_change_pm(state, UART_PM_STATE_ON);
|
|
- spin_lock_irq(&uport->lock);
|
|
+ uart_port_lock_irq(uport);
|
|
status = uport->ops->get_mctrl(uport);
|
|
- spin_unlock_irq(&uport->lock);
|
|
+ uart_port_unlock_irq(uport);
|
|
if (pm_state != UART_PM_STATE_ON)
|
|
uart_change_pm(state, pm_state);
|
|
|
|
@@ -2411,9 +2411,9 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
|
|
*/
|
|
if (!console_suspend_enabled && uart_console(uport)) {
|
|
if (uport->ops->start_rx) {
|
|
- spin_lock_irq(&uport->lock);
|
|
+ uart_port_lock_irq(uport);
|
|
uport->ops->stop_rx(uport);
|
|
- spin_unlock_irq(&uport->lock);
|
|
+ uart_port_unlock_irq(uport);
|
|
}
|
|
goto unlock;
|
|
}
|
|
@@ -2428,7 +2428,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
|
|
tty_port_set_suspended(port, true);
|
|
tty_port_set_initialized(port, false);
|
|
|
|
- spin_lock_irq(&uport->lock);
|
|
+ uart_port_lock_irq(uport);
|
|
ops->stop_tx(uport);
|
|
if (!(uport->rs485.flags & SER_RS485_ENABLED))
|
|
ops->set_mctrl(uport, 0);
|
|
@@ -2436,7 +2436,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
|
|
mctrl = uport->mctrl;
|
|
uport->mctrl = 0;
|
|
ops->stop_rx(uport);
|
|
- spin_unlock_irq(&uport->lock);
|
|
+ uart_port_unlock_irq(uport);
|
|
|
|
/*
|
|
* Wait for the transmitter to empty.
|
|
@@ -2508,9 +2508,9 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
|
|
uart_change_pm(state, UART_PM_STATE_ON);
|
|
uport->ops->set_termios(uport, &termios, NULL);
|
|
if (!console_suspend_enabled && uport->ops->start_rx) {
|
|
- spin_lock_irq(&uport->lock);
|
|
+ uart_port_lock_irq(uport);
|
|
uport->ops->start_rx(uport);
|
|
- spin_unlock_irq(&uport->lock);
|
|
+ uart_port_unlock_irq(uport);
|
|
}
|
|
if (console_suspend_enabled)
|
|
console_start(uport->cons);
|
|
@@ -2521,10 +2521,10 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
|
|
int ret;
|
|
|
|
uart_change_pm(state, UART_PM_STATE_ON);
|
|
- spin_lock_irq(&uport->lock);
|
|
+ uart_port_lock_irq(uport);
|
|
if (!(uport->rs485.flags & SER_RS485_ENABLED))
|
|
ops->set_mctrl(uport, 0);
|
|
- spin_unlock_irq(&uport->lock);
|
|
+ uart_port_unlock_irq(uport);
|
|
if (console_suspend_enabled || !uart_console(uport)) {
|
|
/* Protected by port mutex for now */
|
|
struct tty_struct *tty = port->tty;
|
|
@@ -2534,11 +2534,11 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
|
|
if (tty)
|
|
uart_change_line_settings(tty, state, NULL);
|
|
uart_rs485_config(uport);
|
|
- spin_lock_irq(&uport->lock);
|
|
+ uart_port_lock_irq(uport);
|
|
if (!(uport->rs485.flags & SER_RS485_ENABLED))
|
|
ops->set_mctrl(uport, uport->mctrl);
|
|
ops->start_tx(uport);
|
|
- spin_unlock_irq(&uport->lock);
|
|
+ uart_port_unlock_irq(uport);
|
|
tty_port_set_initialized(port, true);
|
|
} else {
|
|
/*
|
|
@@ -2650,11 +2650,11 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
|
|
* keep the DTR setting that is set in uart_set_options()
|
|
* We probably don't need a spinlock around this, but
|
|
*/
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
port->mctrl &= TIOCM_DTR;
|
|
if (!(port->rs485.flags & SER_RS485_ENABLED))
|
|
port->ops->set_mctrl(port, port->mctrl);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
uart_rs485_config(port);
|
|
|
|
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
|
|
index 7d5aaa8d422b..e51ca593ab86 100644
|
|
--- a/drivers/tty/serial/serial_mctrl_gpio.c
|
|
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
|
|
@@ -184,7 +184,7 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
|
|
|
|
mctrl_gpio_get(gpios, &mctrl);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
mctrl_diff = mctrl ^ gpios->mctrl_prev;
|
|
gpios->mctrl_prev = mctrl;
|
|
@@ -205,7 +205,7 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
|
|
wake_up_interruptible(&port->state->port.delta_msr_wait);
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
diff --git a/drivers/tty/serial/serial_port.c b/drivers/tty/serial/serial_port.c
|
|
index 469ad26cde48..66fd117d8aea 100644
|
|
--- a/drivers/tty/serial/serial_port.c
|
|
+++ b/drivers/tty/serial/serial_port.c
|
|
@@ -38,14 +38,14 @@ static int serial_port_runtime_resume(struct device *dev)
|
|
goto out;
|
|
|
|
/* Flush any pending TX for the port */
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
if (!port_dev->tx_enabled)
|
|
goto unlock;
|
|
if (__serial_port_busy(port))
|
|
port->ops->start_tx(port);
|
|
|
|
unlock:
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
out:
|
|
pm_runtime_mark_last_busy(dev);
|
|
diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c
|
|
index be08fb6f749c..eaa980722455 100644
|
|
--- a/drivers/tty/serial/serial_txx9.c
|
|
+++ b/drivers/tty/serial/serial_txx9.c
|
|
@@ -335,13 +335,13 @@ static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id)
|
|
unsigned int status;
|
|
|
|
while (1) {
|
|
- spin_lock(&up->lock);
|
|
+ uart_port_lock(up);
|
|
status = sio_in(up, TXX9_SIDISR);
|
|
if (!(sio_in(up, TXX9_SIDICR) & TXX9_SIDICR_TIE))
|
|
status &= ~TXX9_SIDISR_TDIS;
|
|
if (!(status & (TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS |
|
|
TXX9_SIDISR_TOUT))) {
|
|
- spin_unlock(&up->lock);
|
|
+ uart_port_unlock(up);
|
|
break;
|
|
}
|
|
|
|
@@ -353,7 +353,7 @@ static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id)
|
|
sio_mask(up, TXX9_SIDISR,
|
|
TXX9_SIDISR_TDIS | TXX9_SIDISR_RDIS |
|
|
TXX9_SIDISR_TOUT);
|
|
- spin_unlock(&up->lock);
|
|
+ uart_port_unlock(up);
|
|
|
|
if (pass_counter++ > PASS_LIMIT)
|
|
break;
|
|
@@ -367,9 +367,9 @@ static unsigned int serial_txx9_tx_empty(struct uart_port *up)
|
|
unsigned long flags;
|
|
unsigned int ret;
|
|
|
|
- spin_lock_irqsave(&up->lock, flags);
|
|
+ uart_port_lock_irqsave(up, &flags);
|
|
ret = (sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS) ? TIOCSER_TEMT : 0;
|
|
- spin_unlock_irqrestore(&up->lock, flags);
|
|
+ uart_port_unlock_irqrestore(up, flags);
|
|
|
|
return ret;
|
|
}
|
|
@@ -399,12 +399,12 @@ static void serial_txx9_break_ctl(struct uart_port *up, int break_state)
|
|
{
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&up->lock, flags);
|
|
+ uart_port_lock_irqsave(up, &flags);
|
|
if (break_state == -1)
|
|
sio_set(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK);
|
|
else
|
|
sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_TBRK);
|
|
- spin_unlock_irqrestore(&up->lock, flags);
|
|
+ uart_port_unlock_irqrestore(up, flags);
|
|
}
|
|
|
|
#if defined(CONFIG_SERIAL_TXX9_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
|
|
@@ -517,9 +517,9 @@ static int serial_txx9_startup(struct uart_port *up)
|
|
/*
|
|
* Now, initialize the UART
|
|
*/
|
|
- spin_lock_irqsave(&up->lock, flags);
|
|
+ uart_port_lock_irqsave(up, &flags);
|
|
serial_txx9_set_mctrl(up, up->mctrl);
|
|
- spin_unlock_irqrestore(&up->lock, flags);
|
|
+ uart_port_unlock_irqrestore(up, flags);
|
|
|
|
/* Enable RX/TX */
|
|
sio_mask(up, TXX9_SIFLCR, TXX9_SIFLCR_RSDE | TXX9_SIFLCR_TSDE);
|
|
@@ -541,9 +541,9 @@ static void serial_txx9_shutdown(struct uart_port *up)
|
|
*/
|
|
sio_out(up, TXX9_SIDICR, 0); /* disable all intrs */
|
|
|
|
- spin_lock_irqsave(&up->lock, flags);
|
|
+ uart_port_lock_irqsave(up, &flags);
|
|
serial_txx9_set_mctrl(up, up->mctrl);
|
|
- spin_unlock_irqrestore(&up->lock, flags);
|
|
+ uart_port_unlock_irqrestore(up, flags);
|
|
|
|
/*
|
|
* Disable break condition
|
|
@@ -625,7 +625,7 @@ serial_txx9_set_termios(struct uart_port *up, struct ktermios *termios,
|
|
* Ok, we're now changing the port state. Do it with
|
|
* interrupts disabled.
|
|
*/
|
|
- spin_lock_irqsave(&up->lock, flags);
|
|
+ uart_port_lock_irqsave(up, &flags);
|
|
|
|
/*
|
|
* Update the per-port timeout.
|
|
@@ -676,7 +676,7 @@ serial_txx9_set_termios(struct uart_port *up, struct ktermios *termios,
|
|
sio_out(up, TXX9_SIFCR, fcr);
|
|
|
|
serial_txx9_set_mctrl(up, up->mctrl);
|
|
- spin_unlock_irqrestore(&up->lock, flags);
|
|
+ uart_port_unlock_irqrestore(up, flags);
|
|
}
|
|
|
|
static void
|
|
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
|
|
index f793624fd501..2559c97812fa 100644
|
|
--- a/drivers/tty/serial/sh-sci.c
|
|
+++ b/drivers/tty/serial/sh-sci.c
|
|
@@ -1205,7 +1205,7 @@ static void sci_dma_tx_complete(void *arg)
|
|
|
|
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
uart_xmit_advance(port, s->tx_dma_len);
|
|
|
|
@@ -1229,7 +1229,7 @@ static void sci_dma_tx_complete(void *arg)
|
|
}
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/* Locking: called with port lock held */
|
|
@@ -1325,7 +1325,7 @@ static void sci_dma_rx_complete(void *arg)
|
|
dev_dbg(port->dev, "%s(%d) active cookie %d\n", __func__, port->line,
|
|
s->active_rx);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
active = sci_dma_rx_find_active(s);
|
|
if (active >= 0)
|
|
@@ -1352,20 +1352,20 @@ static void sci_dma_rx_complete(void *arg)
|
|
|
|
dma_async_issue_pending(chan);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
dev_dbg(port->dev, "%s: cookie %d #%d, new active cookie %d\n",
|
|
__func__, s->cookie_rx[active], active, s->active_rx);
|
|
return;
|
|
|
|
fail:
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
|
|
/* Switch to PIO */
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
dmaengine_terminate_async(chan);
|
|
sci_dma_rx_chan_invalidate(s);
|
|
sci_dma_rx_reenable_irq(s);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void sci_dma_tx_release(struct sci_port *s)
|
|
@@ -1414,13 +1414,13 @@ static int sci_dma_rx_submit(struct sci_port *s, bool port_lock_held)
|
|
fail:
|
|
/* Switch to PIO */
|
|
if (!port_lock_held)
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
if (i)
|
|
dmaengine_terminate_async(chan);
|
|
sci_dma_rx_chan_invalidate(s);
|
|
sci_start_rx(port);
|
|
if (!port_lock_held)
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
return -EAGAIN;
|
|
}
|
|
|
|
@@ -1442,14 +1442,14 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
|
|
* transmit till the end, and then the rest. Take the port lock to get a
|
|
* consistent xmit buffer state.
|
|
*/
|
|
- spin_lock_irq(&port->lock);
|
|
+ uart_port_lock_irq(port);
|
|
head = xmit->head;
|
|
tail = xmit->tail;
|
|
buf = s->tx_dma_addr + tail;
|
|
s->tx_dma_len = CIRC_CNT_TO_END(head, tail, UART_XMIT_SIZE);
|
|
if (!s->tx_dma_len) {
|
|
/* Transmit buffer has been flushed */
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
return;
|
|
}
|
|
|
|
@@ -1457,7 +1457,7 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
|
|
DMA_MEM_TO_DEV,
|
|
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
|
if (!desc) {
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
dev_warn(port->dev, "Failed preparing Tx DMA descriptor\n");
|
|
goto switch_to_pio;
|
|
}
|
|
@@ -1469,12 +1469,12 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
|
|
desc->callback_param = s;
|
|
s->cookie_tx = dmaengine_submit(desc);
|
|
if (dma_submit_error(s->cookie_tx)) {
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
|
|
goto switch_to_pio;
|
|
}
|
|
|
|
- spin_unlock_irq(&port->lock);
|
|
+ uart_port_unlock_irq(port);
|
|
dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n",
|
|
__func__, xmit->buf, tail, head, s->cookie_tx);
|
|
|
|
@@ -1482,10 +1482,10 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
|
|
return;
|
|
|
|
switch_to_pio:
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
s->chan_tx = NULL;
|
|
sci_start_tx(port);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
return;
|
|
}
|
|
|
|
@@ -1502,17 +1502,17 @@ static enum hrtimer_restart sci_dma_rx_timer_fn(struct hrtimer *t)
|
|
|
|
dev_dbg(port->dev, "DMA Rx timed out\n");
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
active = sci_dma_rx_find_active(s);
|
|
if (active < 0) {
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
return HRTIMER_NORESTART;
|
|
}
|
|
|
|
status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state);
|
|
if (status == DMA_COMPLETE) {
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
dev_dbg(port->dev, "Cookie %d #%d has already completed\n",
|
|
s->active_rx, active);
|
|
|
|
@@ -1530,7 +1530,7 @@ static enum hrtimer_restart sci_dma_rx_timer_fn(struct hrtimer *t)
|
|
*/
|
|
status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state);
|
|
if (status == DMA_COMPLETE) {
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
dev_dbg(port->dev, "Transaction complete after DMA engine was stopped");
|
|
return HRTIMER_NORESTART;
|
|
}
|
|
@@ -1551,7 +1551,7 @@ static enum hrtimer_restart sci_dma_rx_timer_fn(struct hrtimer *t)
|
|
|
|
sci_dma_rx_reenable_irq(s);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return HRTIMER_NORESTART;
|
|
}
|
|
@@ -1775,9 +1775,9 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
|
|
struct uart_port *port = ptr;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
sci_transmit_chars(port);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -1791,11 +1791,11 @@ static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr)
|
|
if (port->type != PORT_SCI)
|
|
return sci_tx_interrupt(irq, ptr);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
ctrl = serial_port_in(port, SCSCR);
|
|
ctrl &= ~(SCSCR_TE | SCSCR_TEIE);
|
|
serial_port_out(port, SCSCR, ctrl);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -2192,7 +2192,7 @@ static void sci_break_ctl(struct uart_port *port, int break_state)
|
|
return;
|
|
}
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
scsptr = serial_port_in(port, SCSPTR);
|
|
scscr = serial_port_in(port, SCSCR);
|
|
|
|
@@ -2206,7 +2206,7 @@ static void sci_break_ctl(struct uart_port *port, int break_state)
|
|
|
|
serial_port_out(port, SCSPTR, scsptr);
|
|
serial_port_out(port, SCSCR, scscr);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static int sci_startup(struct uart_port *port)
|
|
@@ -2238,7 +2238,7 @@ static void sci_shutdown(struct uart_port *port)
|
|
s->autorts = false;
|
|
mctrl_gpio_disable_ms(to_sci_port(port)->gpios);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
sci_stop_rx(port);
|
|
sci_stop_tx(port);
|
|
/*
|
|
@@ -2248,7 +2248,7 @@ static void sci_shutdown(struct uart_port *port)
|
|
scr = serial_port_in(port, SCSCR);
|
|
serial_port_out(port, SCSCR, scr &
|
|
(SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot));
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
#ifdef CONFIG_SERIAL_SH_SCI_DMA
|
|
if (s->chan_rx_saved) {
|
|
@@ -2550,7 +2550,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
serial_port_out(port, SCCKS, sccks);
|
|
}
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
sci_reset(port);
|
|
|
|
@@ -2672,7 +2672,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
if ((termios->c_cflag & CREAD) != 0)
|
|
sci_start_rx(port);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
sci_port_disable(s);
|
|
|
|
@@ -3057,9 +3057,9 @@ static void serial_console_write(struct console *co, const char *s,
|
|
if (port->sysrq)
|
|
locked = 0;
|
|
else if (oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&port->lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(port, &flags);
|
|
else
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* first save SCSCR then disable interrupts, keep clock source */
|
|
ctrl = serial_port_in(port, SCSCR);
|
|
@@ -3079,7 +3079,7 @@ static void serial_console_write(struct console *co, const char *s,
|
|
serial_port_out(port, SCSCR, ctrl);
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static int serial_console_setup(struct console *co, char *options)
|
|
diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c
|
|
index d195c5de52e7..b296e57a9dee 100644
|
|
--- a/drivers/tty/serial/sifive.c
|
|
+++ b/drivers/tty/serial/sifive.c
|
|
@@ -521,11 +521,11 @@ static irqreturn_t sifive_serial_irq(int irq, void *dev_id)
|
|
struct sifive_serial_port *ssp = dev_id;
|
|
u32 ip;
|
|
|
|
- spin_lock(&ssp->port.lock);
|
|
+ uart_port_lock(&ssp->port);
|
|
|
|
ip = __ssp_readl(ssp, SIFIVE_SERIAL_IP_OFFS);
|
|
if (!ip) {
|
|
- spin_unlock(&ssp->port.lock);
|
|
+ uart_port_unlock(&ssp->port);
|
|
return IRQ_NONE;
|
|
}
|
|
|
|
@@ -534,7 +534,7 @@ static irqreturn_t sifive_serial_irq(int irq, void *dev_id)
|
|
if (ip & SIFIVE_SERIAL_IP_TXWM_MASK)
|
|
__ssp_transmit_chars(ssp);
|
|
|
|
- spin_unlock(&ssp->port.lock);
|
|
+ uart_port_unlock(&ssp->port);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -653,7 +653,7 @@ static void sifive_serial_set_termios(struct uart_port *port,
|
|
ssp->port.uartclk / 16);
|
|
__ssp_update_baud_rate(ssp, rate);
|
|
|
|
- spin_lock_irqsave(&ssp->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&ssp->port, &flags);
|
|
|
|
/* Update the per-port timeout */
|
|
uart_update_timeout(port, termios->c_cflag, rate);
|
|
@@ -670,7 +670,7 @@ static void sifive_serial_set_termios(struct uart_port *port,
|
|
if (v != old_v)
|
|
__ssp_writel(v, SIFIVE_SERIAL_RXCTRL_OFFS, ssp);
|
|
|
|
- spin_unlock_irqrestore(&ssp->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&ssp->port, flags);
|
|
}
|
|
|
|
static void sifive_serial_release_port(struct uart_port *port)
|
|
@@ -795,9 +795,9 @@ static void sifive_serial_console_write(struct console *co, const char *s,
|
|
if (ssp->port.sysrq)
|
|
locked = 0;
|
|
else if (oops_in_progress)
|
|
- locked = spin_trylock(&ssp->port.lock);
|
|
+ locked = uart_port_trylock(&ssp->port);
|
|
else
|
|
- spin_lock(&ssp->port.lock);
|
|
+ uart_port_lock(&ssp->port);
|
|
|
|
ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS);
|
|
__ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp);
|
|
@@ -807,7 +807,7 @@ static void sifive_serial_console_write(struct console *co, const char *s,
|
|
__ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp);
|
|
|
|
if (locked)
|
|
- spin_unlock(&ssp->port.lock);
|
|
+ uart_port_unlock(&ssp->port);
|
|
local_irq_restore(flags);
|
|
}
|
|
|
|
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
|
|
index f328fa57231f..f257525f9299 100644
|
|
--- a/drivers/tty/serial/sprd_serial.c
|
|
+++ b/drivers/tty/serial/sprd_serial.c
|
|
@@ -247,7 +247,7 @@ static void sprd_complete_tx_dma(void *data)
|
|
struct circ_buf *xmit = &port->state->xmit;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
dma_unmap_single(port->dev, sp->tx_dma.phys_addr,
|
|
sp->tx_dma.trans_len, DMA_TO_DEVICE);
|
|
|
|
@@ -260,7 +260,7 @@ static void sprd_complete_tx_dma(void *data)
|
|
sprd_tx_dma_config(port))
|
|
sp->tx_dma.trans_len = 0;
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static int sprd_uart_dma_submit(struct uart_port *port,
|
|
@@ -429,13 +429,13 @@ static void sprd_complete_rx_dma(void *data)
|
|
enum dma_status status;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
status = dmaengine_tx_status(sp->rx_dma.chn,
|
|
sp->rx_dma.cookie, &state);
|
|
if (status != DMA_COMPLETE) {
|
|
sprd_stop_rx(port);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
return;
|
|
}
|
|
|
|
@@ -449,7 +449,7 @@ static void sprd_complete_rx_dma(void *data)
|
|
if (sprd_start_dma_rx(port))
|
|
sprd_stop_rx(port);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static int sprd_start_dma_rx(struct uart_port *port)
|
|
@@ -638,12 +638,12 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id)
|
|
struct uart_port *port = dev_id;
|
|
unsigned int ims;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
ims = serial_in(port, SPRD_IMSR);
|
|
|
|
if (!ims) {
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
return IRQ_NONE;
|
|
}
|
|
|
|
@@ -660,7 +660,7 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id)
|
|
if (ims & SPRD_IMSR_TX_FIFO_EMPTY)
|
|
sprd_tx(port);
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -727,13 +727,13 @@ static int sprd_startup(struct uart_port *port)
|
|
serial_out(port, SPRD_CTL1, fc);
|
|
|
|
/* enable interrupt */
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
ien = serial_in(port, SPRD_IEN);
|
|
ien |= SPRD_IEN_BREAK_DETECT | SPRD_IEN_TIMEOUT;
|
|
if (!sp->rx_dma.enable)
|
|
ien |= SPRD_IEN_RX_FULL;
|
|
serial_out(port, SPRD_IEN, ien);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -793,7 +793,7 @@ static void sprd_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
lcr |= SPRD_LCR_EVEN_PAR;
|
|
}
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* update the per-port timeout */
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
@@ -837,7 +837,7 @@ static void sprd_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
fc |= RX_TOUT_THLD_DEF | RX_HFC_THLD_DEF;
|
|
serial_out(port, SPRD_CTL1, fc);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
/* Don't rewrite B0 */
|
|
if (tty_termios_baud_rate(termios))
|
|
@@ -974,9 +974,9 @@ static void sprd_console_write(struct console *co, const char *s,
|
|
if (port->sysrq)
|
|
locked = 0;
|
|
else if (oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&port->lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(port, &flags);
|
|
else
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
uart_console_write(port, s, count, sprd_console_putchar);
|
|
|
|
@@ -984,7 +984,7 @@ static void sprd_console_write(struct console *co, const char *s,
|
|
wait_for_xmitr(port);
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static int sprd_console_setup(struct console *co, char *options)
|
|
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
|
|
index 92b9f6894006..a821f5d76a26 100644
|
|
--- a/drivers/tty/serial/st-asc.c
|
|
+++ b/drivers/tty/serial/st-asc.c
|
|
@@ -319,7 +319,7 @@ static irqreturn_t asc_interrupt(int irq, void *ptr)
|
|
struct uart_port *port = ptr;
|
|
u32 status;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
status = asc_in(port, ASC_STA);
|
|
|
|
@@ -334,7 +334,7 @@ static irqreturn_t asc_interrupt(int irq, void *ptr)
|
|
asc_transmit_chars(port);
|
|
}
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -452,10 +452,10 @@ static void asc_pm(struct uart_port *port, unsigned int state,
|
|
* we can come to turning it off. Note this is not called with
|
|
* the port spinlock held.
|
|
*/
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
ctl = asc_in(port, ASC_CTL) & ~ASC_CTL_RUN;
|
|
asc_out(port, ASC_CTL, ctl);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
clk_disable_unprepare(ascport->clk);
|
|
break;
|
|
}
|
|
@@ -480,7 +480,7 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
|
|
cflag = termios->c_cflag;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* read control register */
|
|
ctrl_val = asc_in(port, ASC_CTL);
|
|
@@ -594,7 +594,7 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
/* write final value and enable port */
|
|
asc_out(port, ASC_CTL, (ctrl_val | ASC_CTL_RUN));
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *asc_type(struct uart_port *port)
|
|
@@ -849,9 +849,9 @@ static void asc_console_write(struct console *co, const char *s, unsigned count)
|
|
if (port->sysrq)
|
|
locked = 0; /* asc_interrupt has already claimed the lock */
|
|
else if (oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&port->lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(port, &flags);
|
|
else
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/*
|
|
* Disable interrupts so we don't get the IRQ line bouncing
|
|
@@ -869,7 +869,7 @@ static void asc_console_write(struct console *co, const char *s, unsigned count)
|
|
asc_out(port, ASC_INTEN, intenable);
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static int asc_console_setup(struct console *co, char *options)
|
|
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
|
|
index 9ef90bb30a47..b963f9ccb070 100644
|
|
--- a/drivers/tty/serial/stm32-usart.c
|
|
+++ b/drivers/tty/serial/stm32-usart.c
|
|
@@ -535,7 +535,7 @@ static void stm32_usart_rx_dma_complete(void *arg)
|
|
unsigned int size;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
size = stm32_usart_receive_chars(port, false);
|
|
uart_unlock_and_check_sysrq_irqrestore(port, flags);
|
|
if (size)
|
|
@@ -641,9 +641,9 @@ static void stm32_usart_tx_dma_complete(void *arg)
|
|
stm32_usart_tx_dma_terminate(stm32port);
|
|
|
|
/* Let's see if we have pending data to send */
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
stm32_usart_transmit_chars(port);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void stm32_usart_tx_interrupt_enable(struct uart_port *port)
|
|
@@ -892,7 +892,7 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
|
|
if (!stm32_port->throttled) {
|
|
if (((sr & USART_SR_RXNE) && !stm32_usart_rx_dma_started(stm32_port)) ||
|
|
((sr & USART_SR_ERR_MASK) && stm32_usart_rx_dma_started(stm32_port))) {
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
size = stm32_usart_receive_chars(port, false);
|
|
uart_unlock_and_check_sysrq(port);
|
|
if (size)
|
|
@@ -902,15 +902,15 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr)
|
|
}
|
|
|
|
if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) {
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
stm32_usart_transmit_chars(port);
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
ret = IRQ_HANDLED;
|
|
}
|
|
|
|
/* Receiver timeout irq for DMA RX */
|
|
if (stm32_usart_rx_dma_started(stm32_port) && !stm32_port->throttled) {
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
size = stm32_usart_receive_chars(port, false);
|
|
uart_unlock_and_check_sysrq(port);
|
|
if (size)
|
|
@@ -999,7 +999,7 @@ static void stm32_usart_throttle(struct uart_port *port)
|
|
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/*
|
|
* Pause DMA transfer, so the RX data gets queued into the FIFO.
|
|
@@ -1012,7 +1012,7 @@ static void stm32_usart_throttle(struct uart_port *port)
|
|
stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq);
|
|
|
|
stm32_port->throttled = true;
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/* Unthrottle the remote, the input buffer can now accept data. */
|
|
@@ -1022,7 +1022,7 @@ static void stm32_usart_unthrottle(struct uart_port *port)
|
|
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
stm32_usart_set_bits(port, ofs->cr1, stm32_port->cr1_irq);
|
|
if (stm32_port->cr3_irq)
|
|
stm32_usart_set_bits(port, ofs->cr3, stm32_port->cr3_irq);
|
|
@@ -1036,7 +1036,7 @@ static void stm32_usart_unthrottle(struct uart_port *port)
|
|
if (stm32_port->rx_ch)
|
|
stm32_usart_rx_dma_start_or_resume(port);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/* Receive stop */
|
|
@@ -1165,7 +1165,7 @@ static void stm32_usart_set_termios(struct uart_port *port,
|
|
|
|
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 8);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr,
|
|
isr,
|
|
@@ -1356,7 +1356,7 @@ static void stm32_usart_set_termios(struct uart_port *port,
|
|
writel_relaxed(cr1, port->membase + ofs->cr1);
|
|
|
|
stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
/* Handle modem control interrupts */
|
|
if (UART_ENABLE_MS(port, termios->c_cflag))
|
|
@@ -1406,9 +1406,9 @@ static void stm32_usart_pm(struct uart_port *port, unsigned int state,
|
|
pm_runtime_get_sync(port->dev);
|
|
break;
|
|
case UART_PM_STATE_OFF:
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
pm_runtime_put_sync(port->dev);
|
|
break;
|
|
}
|
|
@@ -1891,9 +1891,9 @@ static void stm32_usart_console_write(struct console *co, const char *s,
|
|
int locked = 1;
|
|
|
|
if (oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&port->lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(port, &flags);
|
|
else
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Save and disable interrupts, enable the transmitter */
|
|
old_cr1 = readl_relaxed(port->membase + ofs->cr1);
|
|
@@ -1907,7 +1907,7 @@ static void stm32_usart_console_write(struct console *co, const char *s,
|
|
writel_relaxed(old_cr1, port->membase + ofs->cr1);
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static int stm32_usart_console_setup(struct console *co, char *options)
|
|
@@ -2042,7 +2042,7 @@ static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port,
|
|
* low-power mode.
|
|
*/
|
|
if (stm32_port->rx_ch) {
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
/* Poll data from DMA RX buffer if any */
|
|
if (!stm32_usart_rx_dma_pause(stm32_port))
|
|
size += stm32_usart_receive_chars(port, true);
|
|
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c
|
|
index c671d674bce4..5bfc0040f17b 100644
|
|
--- a/drivers/tty/serial/sunhv.c
|
|
+++ b/drivers/tty/serial/sunhv.c
|
|
@@ -217,10 +217,10 @@ static irqreturn_t sunhv_interrupt(int irq, void *dev_id)
|
|
struct tty_port *tport;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
tport = receive_chars(port);
|
|
transmit_chars(port);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
if (tport)
|
|
tty_flip_buffer_push(tport);
|
|
@@ -271,7 +271,7 @@ static void sunhv_send_xchar(struct uart_port *port, char ch)
|
|
if (ch == __DISABLED_CHAR)
|
|
return;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
while (limit-- > 0) {
|
|
long status = sun4v_con_putchar(ch);
|
|
@@ -280,7 +280,7 @@ static void sunhv_send_xchar(struct uart_port *port, char ch)
|
|
udelay(1);
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/* port->lock held by caller. */
|
|
@@ -295,7 +295,7 @@ static void sunhv_break_ctl(struct uart_port *port, int break_state)
|
|
unsigned long flags;
|
|
int limit = 10000;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
while (limit-- > 0) {
|
|
long status = sun4v_con_putchar(CON_BREAK);
|
|
@@ -304,7 +304,7 @@ static void sunhv_break_ctl(struct uart_port *port, int break_state)
|
|
udelay(1);
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
}
|
|
|
|
@@ -328,7 +328,7 @@ static void sunhv_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
unsigned int iflag, cflag;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
iflag = termios->c_iflag;
|
|
cflag = termios->c_cflag;
|
|
@@ -343,7 +343,7 @@ static void sunhv_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
uart_update_timeout(port, cflag,
|
|
(port->uartclk / (16 * quot)));
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *sunhv_type(struct uart_port *port)
|
|
@@ -437,9 +437,9 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign
|
|
int locked = 1;
|
|
|
|
if (port->sysrq || oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&port->lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(port, &flags);
|
|
else
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
while (n > 0) {
|
|
unsigned long ra = __pa(con_write_page);
|
|
@@ -470,7 +470,7 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign
|
|
}
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static inline void sunhv_console_putchar(struct uart_port *port, char c)
|
|
@@ -492,9 +492,9 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig
|
|
int i, locked = 1;
|
|
|
|
if (port->sysrq || oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&port->lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(port, &flags);
|
|
else
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
for (i = 0; i < n; i++) {
|
|
if (*s == '\n')
|
|
@@ -503,7 +503,7 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig
|
|
}
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static struct console sunhv_console = {
|
|
diff --git a/drivers/tty/serial/sunplus-uart.c b/drivers/tty/serial/sunplus-uart.c
|
|
index 3aacd5eb414c..4251f4e1ba99 100644
|
|
--- a/drivers/tty/serial/sunplus-uart.c
|
|
+++ b/drivers/tty/serial/sunplus-uart.c
|
|
@@ -184,7 +184,7 @@ static void sunplus_break_ctl(struct uart_port *port, int ctl)
|
|
unsigned long flags;
|
|
unsigned int lcr;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
lcr = readl(port->membase + SUP_UART_LCR);
|
|
|
|
@@ -195,7 +195,7 @@ static void sunplus_break_ctl(struct uart_port *port, int ctl)
|
|
|
|
writel(lcr, port->membase + SUP_UART_LCR);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void transmit_chars(struct uart_port *port)
|
|
@@ -277,7 +277,7 @@ static irqreturn_t sunplus_uart_irq(int irq, void *args)
|
|
struct uart_port *port = args;
|
|
unsigned int isc;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
isc = readl(port->membase + SUP_UART_ISC);
|
|
|
|
@@ -287,7 +287,7 @@ static irqreturn_t sunplus_uart_irq(int irq, void *args)
|
|
if (isc & SUP_UART_ISC_TX)
|
|
transmit_chars(port);
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -302,14 +302,14 @@ static int sunplus_startup(struct uart_port *port)
|
|
if (ret)
|
|
return ret;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
/* isc define Bit[7:4] int setting, Bit[3:0] int status
|
|
* isc register will clean Bit[3:0] int status after read
|
|
* only do a write to Bit[7:4] int setting
|
|
*/
|
|
isc |= SUP_UART_ISC_RXM;
|
|
writel(isc, port->membase + SUP_UART_ISC);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -318,13 +318,13 @@ static void sunplus_shutdown(struct uart_port *port)
|
|
{
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
/* isc define Bit[7:4] int setting, Bit[3:0] int status
|
|
* isc register will clean Bit[3:0] int status after read
|
|
* only do a write to Bit[7:4] int setting
|
|
*/
|
|
writel(0, port->membase + SUP_UART_ISC); /* disable all interrupt */
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
free_irq(port->irq, port);
|
|
}
|
|
@@ -372,7 +372,7 @@ static void sunplus_set_termios(struct uart_port *port,
|
|
lcr |= UART_LCR_EPAR;
|
|
}
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
|
|
@@ -407,7 +407,7 @@ static void sunplus_set_termios(struct uart_port *port,
|
|
writel(div_l, port->membase + SUP_UART_DIV_L);
|
|
writel(lcr, port->membase + SUP_UART_LCR);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void sunplus_set_ldisc(struct uart_port *port, struct ktermios *termios)
|
|
@@ -517,15 +517,15 @@ static void sunplus_console_write(struct console *co,
|
|
if (sunplus_console_ports[co->index]->port.sysrq)
|
|
locked = 0;
|
|
else if (oops_in_progress)
|
|
- locked = spin_trylock(&sunplus_console_ports[co->index]->port.lock);
|
|
+ locked = uart_port_trylock(&sunplus_console_ports[co->index]->port);
|
|
else
|
|
- spin_lock(&sunplus_console_ports[co->index]->port.lock);
|
|
+ uart_port_lock(&sunplus_console_ports[co->index]->port);
|
|
|
|
uart_console_write(&sunplus_console_ports[co->index]->port, s, count,
|
|
sunplus_uart_console_putchar);
|
|
|
|
if (locked)
|
|
- spin_unlock(&sunplus_console_ports[co->index]->port.lock);
|
|
+ uart_port_unlock(&sunplus_console_ports[co->index]->port);
|
|
|
|
local_irq_restore(flags);
|
|
}
|
|
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c
|
|
index 40eeaf835bba..6aa51a6f8063 100644
|
|
--- a/drivers/tty/serial/sunsab.c
|
|
+++ b/drivers/tty/serial/sunsab.c
|
|
@@ -310,7 +310,7 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id)
|
|
unsigned long flags;
|
|
unsigned char gis;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
status.stat = 0;
|
|
gis = readb(&up->regs->r.gis) >> up->gis_shift;
|
|
@@ -331,7 +331,7 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id)
|
|
transmit_chars(up, &status);
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
if (port)
|
|
tty_flip_buffer_push(port);
|
|
@@ -473,12 +473,12 @@ static void sunsab_send_xchar(struct uart_port *port, char ch)
|
|
if (ch == __DISABLED_CHAR)
|
|
return;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
sunsab_tec_wait(up);
|
|
writeb(ch, &up->regs->w.tic);
|
|
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
/* port->lock held by caller. */
|
|
@@ -499,7 +499,7 @@ static void sunsab_break_ctl(struct uart_port *port, int break_state)
|
|
unsigned long flags;
|
|
unsigned char val;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
val = up->cached_dafo;
|
|
if (break_state)
|
|
@@ -512,7 +512,7 @@ static void sunsab_break_ctl(struct uart_port *port, int break_state)
|
|
if (test_bit(SAB82532_XPR, &up->irqflags))
|
|
sunsab_tx_idle(up);
|
|
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
/* port->lock is not held. */
|
|
@@ -527,7 +527,7 @@ static int sunsab_startup(struct uart_port *port)
|
|
if (err)
|
|
return err;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
/*
|
|
* Wait for any commands or immediate characters
|
|
@@ -582,7 +582,7 @@ static int sunsab_startup(struct uart_port *port)
|
|
set_bit(SAB82532_ALLS, &up->irqflags);
|
|
set_bit(SAB82532_XPR, &up->irqflags);
|
|
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -594,7 +594,7 @@ static void sunsab_shutdown(struct uart_port *port)
|
|
container_of(port, struct uart_sunsab_port, port);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
/* Disable Interrupts */
|
|
up->interrupt_mask0 = 0xff;
|
|
@@ -628,7 +628,7 @@ static void sunsab_shutdown(struct uart_port *port)
|
|
writeb(tmp, &up->regs->rw.ccr0);
|
|
#endif
|
|
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
free_irq(up->port.irq, up);
|
|
}
|
|
|
|
@@ -779,9 +779,9 @@ static void sunsab_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
|
|
unsigned int quot = uart_get_divisor(port, baud);
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
sunsab_convert_to_sab(up, termios->c_cflag, termios->c_iflag, baud, quot);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static const char *sunsab_type(struct uart_port *port)
|
|
@@ -857,15 +857,15 @@ static void sunsab_console_write(struct console *con, const char *s, unsigned n)
|
|
int locked = 1;
|
|
|
|
if (up->port.sysrq || oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&up->port.lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(&up->port, &flags);
|
|
else
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
uart_console_write(&up->port, s, n, sunsab_console_putchar);
|
|
sunsab_tec_wait(up);
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static int sunsab_console_setup(struct console *con, char *options)
|
|
@@ -914,7 +914,7 @@ static int sunsab_console_setup(struct console *con, char *options)
|
|
*/
|
|
sunsab_startup(&up->port);
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
/*
|
|
* Finally, enable interrupts
|
|
@@ -932,7 +932,7 @@ static int sunsab_console_setup(struct console *con, char *options)
|
|
sunsab_convert_to_sab(up, con->cflag, 0, baud, quot);
|
|
sunsab_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
|
|
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
return 0;
|
|
}
|
|
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
|
|
index 58a4342ad0f9..1e051cc2591c 100644
|
|
--- a/drivers/tty/serial/sunsu.c
|
|
+++ b/drivers/tty/serial/sunsu.c
|
|
@@ -212,9 +212,9 @@ static void enable_rsa(struct uart_sunsu_port *up)
|
|
{
|
|
if (up->port.type == PORT_RSA) {
|
|
if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) {
|
|
- spin_lock_irq(&up->port.lock);
|
|
+ uart_port_lock_irq(&up->port);
|
|
__enable_rsa(up);
|
|
- spin_unlock_irq(&up->port.lock);
|
|
+ uart_port_unlock_irq(&up->port);
|
|
}
|
|
if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
|
|
serial_outp(up, UART_RSA_FRR, 0);
|
|
@@ -234,7 +234,7 @@ static void disable_rsa(struct uart_sunsu_port *up)
|
|
|
|
if (up->port.type == PORT_RSA &&
|
|
up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {
|
|
- spin_lock_irq(&up->port.lock);
|
|
+ uart_port_lock_irq(&up->port);
|
|
|
|
mode = serial_inp(up, UART_RSA_MSR);
|
|
result = !(mode & UART_RSA_MSR_FIFO);
|
|
@@ -247,7 +247,7 @@ static void disable_rsa(struct uart_sunsu_port *up)
|
|
|
|
if (result)
|
|
up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16;
|
|
- spin_unlock_irq(&up->port.lock);
|
|
+ uart_port_unlock_irq(&up->port);
|
|
}
|
|
}
|
|
#endif /* CONFIG_SERIAL_8250_RSA */
|
|
@@ -311,10 +311,10 @@ static void sunsu_enable_ms(struct uart_port *port)
|
|
container_of(port, struct uart_sunsu_port, port);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
up->ier |= UART_IER_MSI;
|
|
serial_out(up, UART_IER, up->ier);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static void
|
|
@@ -456,7 +456,7 @@ static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id)
|
|
unsigned long flags;
|
|
unsigned char status;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
do {
|
|
status = serial_inp(up, UART_LSR);
|
|
@@ -470,7 +470,7 @@ static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id)
|
|
|
|
} while (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT));
|
|
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -545,9 +545,9 @@ static unsigned int sunsu_tx_empty(struct uart_port *port)
|
|
unsigned long flags;
|
|
unsigned int ret;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
return ret;
|
|
}
|
|
@@ -599,13 +599,13 @@ static void sunsu_break_ctl(struct uart_port *port, int break_state)
|
|
container_of(port, struct uart_sunsu_port, port);
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
if (break_state == -1)
|
|
up->lcr |= UART_LCR_SBC;
|
|
else
|
|
up->lcr &= ~UART_LCR_SBC;
|
|
serial_out(up, UART_LCR, up->lcr);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static int sunsu_startup(struct uart_port *port)
|
|
@@ -683,12 +683,12 @@ static int sunsu_startup(struct uart_port *port)
|
|
*/
|
|
serial_outp(up, UART_LCR, UART_LCR_WLEN8);
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
up->port.mctrl |= TIOCM_OUT2;
|
|
|
|
sunsu_set_mctrl(&up->port, up->port.mctrl);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
/*
|
|
* Finally, enable interrupts. Note: Modem status interrupts
|
|
@@ -731,7 +731,7 @@ static void sunsu_shutdown(struct uart_port *port)
|
|
up->ier = 0;
|
|
serial_outp(up, UART_IER, 0);
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
if (up->port.flags & UPF_FOURPORT) {
|
|
/* reset interrupts on the AST Fourport board */
|
|
inb((up->port.iobase & 0xfe0) | 0x1f);
|
|
@@ -740,7 +740,7 @@ static void sunsu_shutdown(struct uart_port *port)
|
|
up->port.mctrl &= ~TIOCM_OUT2;
|
|
|
|
sunsu_set_mctrl(&up->port, up->port.mctrl);
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
/*
|
|
* Disable break condition and FIFOs
|
|
@@ -826,7 +826,7 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag,
|
|
* Ok, we're now changing the port state. Do it with
|
|
* interrupts disabled.
|
|
*/
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
/*
|
|
* Update the per-port timeout.
|
|
@@ -891,7 +891,7 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag,
|
|
|
|
up->cflag = cflag;
|
|
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static void
|
|
@@ -1038,7 +1038,7 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
|
|
up->type_probed = PORT_UNKNOWN;
|
|
up->port.iotype = UPIO_MEM;
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
if (!(up->port.flags & UPF_BUGGY_UART)) {
|
|
/*
|
|
@@ -1173,7 +1173,7 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
|
|
serial_outp(up, UART_IER, 0);
|
|
|
|
out:
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static struct uart_driver sunsu_reg = {
|
|
@@ -1298,9 +1298,9 @@ static void sunsu_console_write(struct console *co, const char *s,
|
|
int locked = 1;
|
|
|
|
if (up->port.sysrq || oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&up->port.lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(&up->port, &flags);
|
|
else
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
/*
|
|
* First save the UER then disable the interrupts
|
|
@@ -1318,7 +1318,7 @@ static void sunsu_console_write(struct console *co, const char *s,
|
|
serial_out(up, UART_IER, ier);
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
/*
|
|
diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c
|
|
index c8c71c56264c..d3b5e864b727 100644
|
|
--- a/drivers/tty/serial/sunzilog.c
|
|
+++ b/drivers/tty/serial/sunzilog.c
|
|
@@ -531,7 +531,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id)
|
|
struct tty_port *port;
|
|
unsigned char r3;
|
|
|
|
- spin_lock(&up->port.lock);
|
|
+ uart_port_lock(&up->port);
|
|
r3 = read_zsreg(channel, R3);
|
|
|
|
/* Channel A */
|
|
@@ -548,7 +548,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id)
|
|
if (r3 & CHATxIP)
|
|
sunzilog_transmit_chars(up, channel);
|
|
}
|
|
- spin_unlock(&up->port.lock);
|
|
+ uart_port_unlock(&up->port);
|
|
|
|
if (port)
|
|
tty_flip_buffer_push(port);
|
|
@@ -557,7 +557,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id)
|
|
up = up->next;
|
|
channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
|
|
|
|
- spin_lock(&up->port.lock);
|
|
+ uart_port_lock(&up->port);
|
|
port = NULL;
|
|
if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
|
|
writeb(RES_H_IUS, &channel->control);
|
|
@@ -571,7 +571,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id)
|
|
if (r3 & CHBTxIP)
|
|
sunzilog_transmit_chars(up, channel);
|
|
}
|
|
- spin_unlock(&up->port.lock);
|
|
+ uart_port_unlock(&up->port);
|
|
|
|
if (port)
|
|
tty_flip_buffer_push(port);
|
|
@@ -604,11 +604,11 @@ static unsigned int sunzilog_tx_empty(struct uart_port *port)
|
|
unsigned char status;
|
|
unsigned int ret;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
status = sunzilog_read_channel_status(port);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
if (status & Tx_BUF_EMP)
|
|
ret = TIOCSER_TEMT;
|
|
@@ -764,7 +764,7 @@ static void sunzilog_break_ctl(struct uart_port *port, int break_state)
|
|
else
|
|
clear_bits |= SND_BRK;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
new_reg = (up->curregs[R5] | set_bits) & ~clear_bits;
|
|
if (new_reg != up->curregs[R5]) {
|
|
@@ -774,7 +774,7 @@ static void sunzilog_break_ctl(struct uart_port *port, int break_state)
|
|
write_zsreg(channel, R5, up->curregs[R5]);
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static void __sunzilog_startup(struct uart_sunzilog_port *up)
|
|
@@ -800,9 +800,9 @@ static int sunzilog_startup(struct uart_port *port)
|
|
if (ZS_IS_CONS(up))
|
|
return 0;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
__sunzilog_startup(up);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
return 0;
|
|
}
|
|
|
|
@@ -840,7 +840,7 @@ static void sunzilog_shutdown(struct uart_port *port)
|
|
if (ZS_IS_CONS(up))
|
|
return;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
channel = ZILOG_CHANNEL_FROM_PORT(port);
|
|
|
|
@@ -853,7 +853,7 @@ static void sunzilog_shutdown(struct uart_port *port)
|
|
up->curregs[R5] &= ~SND_BRK;
|
|
sunzilog_maybe_update_regs(up, channel);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/* Shared by TTY driver and serial console setup. The port lock is held
|
|
@@ -945,7 +945,7 @@ sunzilog_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
|
|
baud = uart_get_baud_rate(port, termios, old, 1200, 76800);
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
|
|
|
|
@@ -962,7 +962,7 @@ sunzilog_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static const char *sunzilog_type(struct uart_port *port)
|
|
@@ -1201,15 +1201,15 @@ sunzilog_console_write(struct console *con, const char *s, unsigned int count)
|
|
int locked = 1;
|
|
|
|
if (up->port.sysrq || oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&up->port.lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(&up->port, &flags);
|
|
else
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
uart_console_write(&up->port, s, count, sunzilog_putchar);
|
|
udelay(2);
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
}
|
|
|
|
static int __init sunzilog_console_setup(struct console *con, char *options)
|
|
@@ -1244,7 +1244,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options)
|
|
|
|
brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
|
|
up->curregs[R15] |= BRKIE;
|
|
sunzilog_convert_to_zs(up, con->cflag, 0, brg);
|
|
@@ -1252,7 +1252,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options)
|
|
sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
|
|
__sunzilog_startup(up);
|
|
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
return 0;
|
|
}
|
|
@@ -1333,7 +1333,7 @@ static void sunzilog_init_hw(struct uart_sunzilog_port *up)
|
|
|
|
channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
|
|
|
|
- spin_lock_irqsave(&up->port.lock, flags);
|
|
+ uart_port_lock_irqsave(&up->port, &flags);
|
|
if (ZS_IS_CHANNEL_A(up)) {
|
|
write_zsreg(channel, R9, FHWRES);
|
|
ZSDELAY_LONG();
|
|
@@ -1383,7 +1383,7 @@ static void sunzilog_init_hw(struct uart_sunzilog_port *up)
|
|
write_zsreg(channel, R9, up->curregs[R9]);
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&up->port.lock, flags);
|
|
+ uart_port_unlock_irqrestore(&up->port, flags);
|
|
|
|
#ifdef CONFIG_SERIO
|
|
if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
|
|
diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c
|
|
index 0859394a78cd..0cc6524f5e8b 100644
|
|
--- a/drivers/tty/serial/timbuart.c
|
|
+++ b/drivers/tty/serial/timbuart.c
|
|
@@ -174,7 +174,7 @@ static void timbuart_tasklet(struct tasklet_struct *t)
|
|
struct timbuart_port *uart = from_tasklet(uart, t, tasklet);
|
|
u32 isr, ier = 0;
|
|
|
|
- spin_lock(&uart->port.lock);
|
|
+ uart_port_lock(&uart->port);
|
|
|
|
isr = ioread32(uart->port.membase + TIMBUART_ISR);
|
|
dev_dbg(uart->port.dev, "%s ISR: %x\n", __func__, isr);
|
|
@@ -189,7 +189,7 @@ static void timbuart_tasklet(struct tasklet_struct *t)
|
|
|
|
iowrite32(ier, uart->port.membase + TIMBUART_IER);
|
|
|
|
- spin_unlock(&uart->port.lock);
|
|
+ uart_port_unlock(&uart->port);
|
|
dev_dbg(uart->port.dev, "%s leaving\n", __func__);
|
|
}
|
|
|
|
@@ -295,10 +295,10 @@ static void timbuart_set_termios(struct uart_port *port,
|
|
tty_termios_copy_hw(termios, old);
|
|
tty_termios_encode_baud_rate(termios, baud, baud);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
iowrite8((u8)bindex, port->membase + TIMBUART_BAUDRATE);
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *timbuart_type(struct uart_port *port)
|
|
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
|
|
index b225a78f6175..404c14acafa5 100644
|
|
--- a/drivers/tty/serial/uartlite.c
|
|
+++ b/drivers/tty/serial/uartlite.c
|
|
@@ -216,11 +216,11 @@ static irqreturn_t ulite_isr(int irq, void *dev_id)
|
|
unsigned long flags;
|
|
|
|
do {
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
stat = uart_in32(ULITE_STATUS, port);
|
|
busy = ulite_receive(port, stat);
|
|
busy |= ulite_transmit(port, stat);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
n++;
|
|
} while (busy);
|
|
|
|
@@ -238,9 +238,9 @@ static unsigned int ulite_tx_empty(struct uart_port *port)
|
|
unsigned long flags;
|
|
unsigned int ret;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
ret = uart_in32(ULITE_STATUS, port);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
|
|
}
|
|
@@ -323,7 +323,7 @@ static void ulite_set_termios(struct uart_port *port,
|
|
termios->c_cflag |= pdata->cflags & (PARENB | PARODD | CSIZE);
|
|
tty_termios_encode_baud_rate(termios, pdata->baud, pdata->baud);
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
port->read_status_mask = ULITE_STATUS_RXVALID | ULITE_STATUS_OVERRUN
|
|
| ULITE_STATUS_TXFULL;
|
|
@@ -346,7 +346,7 @@ static void ulite_set_termios(struct uart_port *port,
|
|
/* update timeout */
|
|
uart_update_timeout(port, termios->c_cflag, pdata->baud);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *ulite_type(struct uart_port *port)
|
|
@@ -495,9 +495,9 @@ static void ulite_console_write(struct console *co, const char *s,
|
|
int locked = 1;
|
|
|
|
if (oops_in_progress) {
|
|
- locked = spin_trylock_irqsave(&port->lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(port, &flags);
|
|
} else
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* save and disable interrupt */
|
|
ier = uart_in32(ULITE_STATUS, port) & ULITE_STATUS_IE;
|
|
@@ -512,7 +512,7 @@ static void ulite_console_write(struct console *co, const char *s,
|
|
uart_out32(ULITE_CONTROL_IE, ULITE_CONTROL, port);
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static int ulite_console_setup(struct console *co, char *options)
|
|
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
|
|
index b06661b80f41..ed7a6bb5596a 100644
|
|
--- a/drivers/tty/serial/ucc_uart.c
|
|
+++ b/drivers/tty/serial/ucc_uart.c
|
|
@@ -931,7 +931,7 @@ static void qe_uart_set_termios(struct uart_port *port,
|
|
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
|
|
|
|
/* Do we really need a spinlock here? */
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Update the per-port timeout. */
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
@@ -949,7 +949,7 @@ static void qe_uart_set_termios(struct uart_port *port,
|
|
qe_setbrg(qe_port->us_info.tx_clock, baud, 16);
|
|
}
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/*
|
|
diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c
|
|
index c5d5c2765119..78a1c1eea11b 100644
|
|
--- a/drivers/tty/serial/vt8500_serial.c
|
|
+++ b/drivers/tty/serial/vt8500_serial.c
|
|
@@ -227,7 +227,7 @@ static irqreturn_t vt8500_irq(int irq, void *dev_id)
|
|
struct uart_port *port = dev_id;
|
|
unsigned long isr;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
isr = vt8500_read(port, VT8500_URISR);
|
|
|
|
/* Acknowledge active status bits */
|
|
@@ -240,7 +240,7 @@ static irqreturn_t vt8500_irq(int irq, void *dev_id)
|
|
if (isr & TCTS)
|
|
handle_delta_cts(port);
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
@@ -342,7 +342,7 @@ static void vt8500_set_termios(struct uart_port *port,
|
|
unsigned int baud, lcr;
|
|
unsigned int loops = 1000;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* calculate and set baud rate */
|
|
baud = uart_get_baud_rate(port, termios, old, 900, 921600);
|
|
@@ -410,7 +410,7 @@ static void vt8500_set_termios(struct uart_port *port,
|
|
vt8500_write(&vt8500_port->uart, 0x881, VT8500_URFCR);
|
|
vt8500_write(&vt8500_port->uart, vt8500_port->ier, VT8500_URIER);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
static const char *vt8500_type(struct uart_port *port)
|
|
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
|
|
index 2e5e86a00a77..9c13dac1d4d1 100644
|
|
--- a/drivers/tty/serial/xilinx_uartps.c
|
|
+++ b/drivers/tty/serial/xilinx_uartps.c
|
|
@@ -346,7 +346,7 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
|
|
struct uart_port *port = (struct uart_port *)dev_id;
|
|
unsigned int isrstatus;
|
|
|
|
- spin_lock(&port->lock);
|
|
+ uart_port_lock(port);
|
|
|
|
/* Read the interrupt status register to determine which
|
|
* interrupt(s) is/are active and clear them.
|
|
@@ -369,7 +369,7 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
|
|
!(readl(port->membase + CDNS_UART_CR) & CDNS_UART_CR_RX_DIS))
|
|
cdns_uart_handle_rx(dev_id, isrstatus);
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
@@ -506,14 +506,14 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
|
|
return NOTIFY_BAD;
|
|
}
|
|
|
|
- spin_lock_irqsave(&cdns_uart->port->lock, flags);
|
|
+ uart_port_lock_irqsave(cdns_uart->port, &flags);
|
|
|
|
/* Disable the TX and RX to set baud rate */
|
|
ctrl_reg = readl(port->membase + CDNS_UART_CR);
|
|
ctrl_reg |= CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS;
|
|
writel(ctrl_reg, port->membase + CDNS_UART_CR);
|
|
|
|
- spin_unlock_irqrestore(&cdns_uart->port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(cdns_uart->port, flags);
|
|
|
|
return NOTIFY_OK;
|
|
}
|
|
@@ -523,7 +523,7 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
|
|
* frequency.
|
|
*/
|
|
|
|
- spin_lock_irqsave(&cdns_uart->port->lock, flags);
|
|
+ uart_port_lock_irqsave(cdns_uart->port, &flags);
|
|
|
|
locked = 1;
|
|
port->uartclk = ndata->new_rate;
|
|
@@ -533,7 +533,7 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
|
|
fallthrough;
|
|
case ABORT_RATE_CHANGE:
|
|
if (!locked)
|
|
- spin_lock_irqsave(&cdns_uart->port->lock, flags);
|
|
+ uart_port_lock_irqsave(cdns_uart->port, &flags);
|
|
|
|
/* Set TX/RX Reset */
|
|
ctrl_reg = readl(port->membase + CDNS_UART_CR);
|
|
@@ -555,7 +555,7 @@ static int cdns_uart_clk_notifier_cb(struct notifier_block *nb,
|
|
ctrl_reg |= CDNS_UART_CR_TX_EN | CDNS_UART_CR_RX_EN;
|
|
writel(ctrl_reg, port->membase + CDNS_UART_CR);
|
|
|
|
- spin_unlock_irqrestore(&cdns_uart->port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(cdns_uart->port, flags);
|
|
|
|
return NOTIFY_OK;
|
|
default:
|
|
@@ -652,7 +652,7 @@ static void cdns_uart_break_ctl(struct uart_port *port, int ctl)
|
|
unsigned int status;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
status = readl(port->membase + CDNS_UART_CR);
|
|
|
|
@@ -664,7 +664,7 @@ static void cdns_uart_break_ctl(struct uart_port *port, int ctl)
|
|
writel(CDNS_UART_CR_STOPBRK | status,
|
|
port->membase + CDNS_UART_CR);
|
|
}
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/**
|
|
@@ -683,7 +683,7 @@ static void cdns_uart_set_termios(struct uart_port *port,
|
|
unsigned long flags;
|
|
unsigned int ctrl_reg, mode_reg;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Disable the TX and RX to set baud rate */
|
|
ctrl_reg = readl(port->membase + CDNS_UART_CR);
|
|
@@ -794,7 +794,7 @@ static void cdns_uart_set_termios(struct uart_port *port,
|
|
cval &= ~CDNS_UART_MODEMCR_FCM;
|
|
writel(cval, port->membase + CDNS_UART_MODEMCR);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/**
|
|
@@ -813,7 +813,7 @@ static int cdns_uart_startup(struct uart_port *port)
|
|
|
|
is_brk_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Disable the TX and RX */
|
|
writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
|
|
@@ -861,7 +861,7 @@ static int cdns_uart_startup(struct uart_port *port)
|
|
writel(readl(port->membase + CDNS_UART_ISR),
|
|
port->membase + CDNS_UART_ISR);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
ret = request_irq(port->irq, cdns_uart_isr, 0, CDNS_UART_NAME, port);
|
|
if (ret) {
|
|
@@ -889,7 +889,7 @@ static void cdns_uart_shutdown(struct uart_port *port)
|
|
int status;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Disable interrupts */
|
|
status = readl(port->membase + CDNS_UART_IMR);
|
|
@@ -900,7 +900,7 @@ static void cdns_uart_shutdown(struct uart_port *port)
|
|
writel(CDNS_UART_CR_TX_DIS | CDNS_UART_CR_RX_DIS,
|
|
port->membase + CDNS_UART_CR);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
free_irq(port->irq, port);
|
|
}
|
|
@@ -1050,7 +1050,7 @@ static int cdns_uart_poll_get_char(struct uart_port *port)
|
|
int c;
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Check if FIFO is empty */
|
|
if (readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY)
|
|
@@ -1058,7 +1058,7 @@ static int cdns_uart_poll_get_char(struct uart_port *port)
|
|
else /* Read a character */
|
|
c = (unsigned char) readl(port->membase + CDNS_UART_FIFO);
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
return c;
|
|
}
|
|
@@ -1067,7 +1067,7 @@ static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c)
|
|
{
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Wait until FIFO is empty */
|
|
while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY))
|
|
@@ -1080,7 +1080,7 @@ static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c)
|
|
while (!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXEMPTY))
|
|
cpu_relax();
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
#endif
|
|
|
|
@@ -1232,9 +1232,9 @@ static void cdns_uart_console_write(struct console *co, const char *s,
|
|
if (port->sysrq)
|
|
locked = 0;
|
|
else if (oops_in_progress)
|
|
- locked = spin_trylock_irqsave(&port->lock, flags);
|
|
+ locked = uart_port_trylock_irqsave(port, &flags);
|
|
else
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* save and disable interrupt */
|
|
imr = readl(port->membase + CDNS_UART_IMR);
|
|
@@ -1257,7 +1257,7 @@ static void cdns_uart_console_write(struct console *co, const char *s,
|
|
writel(imr, port->membase + CDNS_UART_IER);
|
|
|
|
if (locked)
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/**
|
|
@@ -1325,7 +1325,7 @@ static int cdns_uart_suspend(struct device *device)
|
|
if (console_suspend_enabled && uart_console(port) && may_wake) {
|
|
unsigned long flags;
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
/* Empty the receive FIFO 1st before making changes */
|
|
while (!(readl(port->membase + CDNS_UART_SR) &
|
|
CDNS_UART_SR_RXEMPTY))
|
|
@@ -1334,7 +1334,7 @@ static int cdns_uart_suspend(struct device *device)
|
|
writel(1, port->membase + CDNS_UART_RXWM);
|
|
/* disable RX timeout interrups */
|
|
writel(CDNS_UART_IXR_TOUT, port->membase + CDNS_UART_IDR);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
/*
|
|
@@ -1372,7 +1372,7 @@ static int cdns_uart_resume(struct device *device)
|
|
return ret;
|
|
}
|
|
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
|
|
/* Set TX/RX Reset */
|
|
ctrl_reg = readl(port->membase + CDNS_UART_CR);
|
|
@@ -1392,14 +1392,14 @@ static int cdns_uart_resume(struct device *device)
|
|
|
|
clk_disable(cdns_uart->uartclk);
|
|
clk_disable(cdns_uart->pclk);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
} else {
|
|
- spin_lock_irqsave(&port->lock, flags);
|
|
+ uart_port_lock_irqsave(port, &flags);
|
|
/* restore original rx trigger level */
|
|
writel(rx_trigger_level, port->membase + CDNS_UART_RXWM);
|
|
/* enable RX timeout interrupt */
|
|
writel(CDNS_UART_IXR_TOUT, port->membase + CDNS_UART_IER);
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
|
|
return uart_resume_port(cdns_uart->cdns_uart_driver, port);
|
|
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
|
|
index 493fc4742895..afa52883c498 100644
|
|
--- a/drivers/tty/tty_io.c
|
|
+++ b/drivers/tty/tty_io.c
|
|
@@ -3543,8 +3543,15 @@ static ssize_t show_cons_active(struct device *dev,
|
|
for_each_console(c) {
|
|
if (!c->device)
|
|
continue;
|
|
- if (!c->write)
|
|
- continue;
|
|
+ if (c->flags & CON_NBCON) {
|
|
+ if (!c->write_atomic &&
|
|
+ !(c->write_thread && c->kthread)) {
|
|
+ continue;
|
|
+ }
|
|
+ } else {
|
|
+ if (!c->write)
|
|
+ continue;
|
|
+ }
|
|
if ((c->flags & CON_ENABLED) == 0)
|
|
continue;
|
|
cs[i++] = c;
|
|
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
|
|
index 106b47ab9f4f..d0b8375d10ec 100644
|
|
--- a/drivers/virtio/Kconfig
|
|
+++ b/drivers/virtio/Kconfig
|
|
@@ -145,6 +145,14 @@ config VIRTIO_INPUT
|
|
|
|
If unsure, say M.
|
|
|
|
+config VIRTIO_TRANS
|
|
+ tristate "VirtIO transfer test driver"
|
|
+ depends on VIRTIO
|
|
+ help
|
|
+ This driver is for VirtIO transfer performance test
|
|
+ between front-end and back-end driver.
|
|
+ If unsure, say N.
|
|
+
|
|
config VIRTIO_MMIO
|
|
tristate "Platform bus driver for memory mapped virtio devices"
|
|
depends on HAS_IOMEM && HAS_DMA
|
|
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
|
|
index 7960f6493913..bdf34908610c 100644
|
|
--- a/drivers/virtio/Makefile
|
|
+++ b/drivers/virtio/Makefile
|
|
@@ -13,3 +13,4 @@ obj-$(CONFIG_VIRTIO_INPUT) += virtio_input.o
|
|
obj-$(CONFIG_VIRTIO_VDPA) += virtio_vdpa.o
|
|
obj-$(CONFIG_VIRTIO_MEM) += virtio_mem.o
|
|
obj-$(CONFIG_VIRTIO_DMA_SHARED_BUFFER) += virtio_dma_buf.o
|
|
+obj-$(CONFIG_VIRTIO_TRANS) += virtio_trans.o
|
|
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
|
|
index 59892a31cf76..f6b983303e31 100644
|
|
--- a/drivers/virtio/virtio_mmio.c
|
|
+++ b/drivers/virtio/virtio_mmio.c
|
|
@@ -3,6 +3,7 @@
|
|
* Virtio memory mapped device driver
|
|
*
|
|
* Copyright 2011-2014, ARM Ltd.
|
|
+ * Copyright 2022-2023 NXP
|
|
*
|
|
* This module allows virtio devices to be used over a virtual, memory mapped
|
|
* platform device.
|
|
@@ -60,8 +61,10 @@
|
|
#include <linux/interrupt.h>
|
|
#include <linux/io.h>
|
|
#include <linux/list.h>
|
|
+#include <linux/mailbox_client.h>
|
|
#include <linux/module.h>
|
|
#include <linux/of.h>
|
|
+#include <linux/of_reserved_mem.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/pm.h>
|
|
#include <linux/slab.h>
|
|
@@ -70,7 +73,7 @@
|
|
#include <linux/virtio_config.h>
|
|
#include <uapi/linux/virtio_mmio.h>
|
|
#include <linux/virtio_ring.h>
|
|
-
|
|
+#include <linux/delay.h>
|
|
|
|
|
|
/* The alignment to use between consumer and producer parts of vring.
|
|
@@ -82,6 +85,13 @@
|
|
#define to_virtio_mmio_device(_plat_dev) \
|
|
container_of(_plat_dev, struct virtio_mmio_device, vdev)
|
|
|
|
+struct virtio_mmio_wr_op {
|
|
+ uint64_t phy_base;
|
|
+ uint32_t offset;
|
|
+ uint32_t value;
|
|
+ uint8_t len;
|
|
+};
|
|
+
|
|
struct virtio_mmio_device {
|
|
struct virtio_device vdev;
|
|
struct platform_device *pdev;
|
|
@@ -92,6 +102,16 @@ struct virtio_mmio_device {
|
|
/* a list of queues so we can dispatch IRQs */
|
|
spinlock_t lock;
|
|
struct list_head virtqueues;
|
|
+
|
|
+ /* Hypervisor_less virtio */
|
|
+ bool is_hypervisor_less;
|
|
+ phys_addr_t phys;
|
|
+ struct virtio_mmio_wr_op *wr_ops;
|
|
+ dma_addr_t wr_ops_phys;
|
|
+ struct mbox_client mbox_wr_cl;
|
|
+ struct mbox_client mbox_irq_cl;
|
|
+ struct mbox_chan *mmio_wr_ch;
|
|
+ struct mbox_chan *mmio_irq_ch;
|
|
};
|
|
|
|
struct virtio_mmio_vq_info {
|
|
@@ -102,6 +122,72 @@ struct virtio_mmio_vq_info {
|
|
struct list_head node;
|
|
};
|
|
|
|
+static void vmd_write(struct virtio_mmio_device *vm_dev, u32 val, u32 off, u8 len)
|
|
+{
|
|
+ void __iomem *addr = vm_dev->base + off;
|
|
+ struct virtio_mmio_wr_op *wr_ops = vm_dev->wr_ops;
|
|
+ int timeout;
|
|
+ int ret;
|
|
+
|
|
+ switch (len) {
|
|
+ case 1:
|
|
+ writeb(val, addr);
|
|
+ break;
|
|
+ case 2:
|
|
+ writew(val, addr);
|
|
+ break;
|
|
+ case 4:
|
|
+ writel(val, addr);
|
|
+ break;
|
|
+ default:
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (vm_dev->is_hypervisor_less) {
|
|
+
|
|
+ timeout = 1000000;
|
|
+ writel(0, vm_dev->base + VIRTIO_MMIO_WD_STATUS);
|
|
+
|
|
+ wr_ops->phy_base = (uint64_t)vm_dev->phys;
|
|
+ wr_ops->offset = off;
|
|
+ wr_ops->value = val;
|
|
+ wr_ops->len = len;
|
|
+
|
|
+ ret = mbox_send_message(vm_dev->mmio_wr_ch, &vm_dev->wr_ops_phys);
|
|
+ if (ret < 0)
|
|
+ dev_err(&vm_dev->vdev.dev, "mmio write error: base: %llx offset: %x, val: %x, len: %d\n",
|
|
+ wr_ops->phy_base, wr_ops->offset,
|
|
+ wr_ops->value, wr_ops->len);
|
|
+
|
|
+ /* Unnecessary to sync for virtqueue notification */
|
|
+ if (off == VIRTIO_MMIO_QUEUE_NOTIFY)
|
|
+ return;
|
|
+
|
|
+ /* poll backend write operation complete */
|
|
+ while (timeout-- && !readl(vm_dev->base + VIRTIO_MMIO_WD_STATUS))
|
|
+ udelay(1);
|
|
+
|
|
+ if (timeout < 0)
|
|
+ dev_err(&vm_dev->vdev.dev, "mmio write timeout: base: %llx offset: %x, val: %x, len: %d\n",
|
|
+ wr_ops->phy_base, wr_ops->offset,
|
|
+ wr_ops->value, wr_ops->len);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void vmd_writel(struct virtio_mmio_device *vm_dev, u32 val, u32 off)
|
|
+{
|
|
+ vmd_write(vm_dev, val, off, 4);
|
|
+}
|
|
+
|
|
+static void vmd_writew(struct virtio_mmio_device *vm_dev, u32 val, u32 off)
|
|
+{
|
|
+ vmd_write(vm_dev, val, off, 2);
|
|
+}
|
|
+
|
|
+static void vmd_writeb(struct virtio_mmio_device *vm_dev, u32 val, u32 off)
|
|
+{
|
|
+ vmd_write(vm_dev, val, off, 1);
|
|
+}
|
|
|
|
|
|
/* Configuration interface */
|
|
@@ -111,11 +197,11 @@ static u64 vm_get_features(struct virtio_device *vdev)
|
|
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
|
|
u64 features;
|
|
|
|
- writel(1, vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL);
|
|
+ vmd_writel(vm_dev, 1, VIRTIO_MMIO_DEVICE_FEATURES_SEL);
|
|
features = readl(vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES);
|
|
features <<= 32;
|
|
|
|
- writel(0, vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL);
|
|
+ vmd_writel(vm_dev, 0, VIRTIO_MMIO_DEVICE_FEATURES_SEL);
|
|
features |= readl(vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES);
|
|
|
|
return features;
|
|
@@ -135,13 +221,13 @@ static int vm_finalize_features(struct virtio_device *vdev)
|
|
return -EINVAL;
|
|
}
|
|
|
|
- writel(1, vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL);
|
|
- writel((u32)(vdev->features >> 32),
|
|
- vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES);
|
|
+ vmd_writel(vm_dev, 1, VIRTIO_MMIO_DRIVER_FEATURES_SEL);
|
|
+ vmd_writel(vm_dev, (u32)(vdev->features >> 32),
|
|
+ VIRTIO_MMIO_DRIVER_FEATURES);
|
|
|
|
- writel(0, vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL);
|
|
- writel((u32)vdev->features,
|
|
- vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES);
|
|
+ vmd_writel(vm_dev, 0, VIRTIO_MMIO_DRIVER_FEATURES_SEL);
|
|
+ vmd_writel(vm_dev, (u32)vdev->features,
|
|
+ VIRTIO_MMIO_DRIVER_FEATURES);
|
|
|
|
return 0;
|
|
}
|
|
@@ -192,39 +278,34 @@ static void vm_set(struct virtio_device *vdev, unsigned int offset,
|
|
const void *buf, unsigned int len)
|
|
{
|
|
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
|
|
- void __iomem *base = vm_dev->base + VIRTIO_MMIO_CONFIG;
|
|
+ u32 base = VIRTIO_MMIO_CONFIG;
|
|
u8 b;
|
|
__le16 w;
|
|
__le32 l;
|
|
|
|
if (vm_dev->version == 1) {
|
|
- const u8 *ptr = buf;
|
|
- int i;
|
|
-
|
|
- for (i = 0; i < len; i++)
|
|
- writeb(ptr[i], base + offset + i);
|
|
-
|
|
+ vmd_writel(vm_dev, *(u32 *)buf, base + offset);
|
|
return;
|
|
}
|
|
|
|
switch (len) {
|
|
case 1:
|
|
memcpy(&b, buf, sizeof b);
|
|
- writeb(b, base + offset);
|
|
+ vmd_writeb(vm_dev, b, base + offset);
|
|
break;
|
|
case 2:
|
|
memcpy(&w, buf, sizeof w);
|
|
- writew(le16_to_cpu(w), base + offset);
|
|
+ vmd_writew(vm_dev, le16_to_cpu(w), base + offset);
|
|
break;
|
|
case 4:
|
|
memcpy(&l, buf, sizeof l);
|
|
- writel(le32_to_cpu(l), base + offset);
|
|
+ vmd_writel(vm_dev, le32_to_cpu(l), base + offset);
|
|
break;
|
|
case 8:
|
|
memcpy(&l, buf, sizeof l);
|
|
- writel(le32_to_cpu(l), base + offset);
|
|
+ vmd_writel(vm_dev, le32_to_cpu(l), base + offset);
|
|
memcpy(&l, buf + sizeof l, sizeof l);
|
|
- writel(le32_to_cpu(l), base + offset + sizeof l);
|
|
+ vmd_writel(vm_dev, le32_to_cpu(l), base + offset + sizeof l);
|
|
break;
|
|
default:
|
|
BUG();
|
|
@@ -260,7 +341,7 @@ static void vm_set_status(struct virtio_device *vdev, u8 status)
|
|
* that the cache coherent memory writes have completed
|
|
* before writing to the MMIO region.
|
|
*/
|
|
- writel(status, vm_dev->base + VIRTIO_MMIO_STATUS);
|
|
+ vmd_writel(vm_dev, status, VIRTIO_MMIO_STATUS);
|
|
}
|
|
|
|
static void vm_reset(struct virtio_device *vdev)
|
|
@@ -268,7 +349,7 @@ static void vm_reset(struct virtio_device *vdev)
|
|
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
|
|
|
|
/* 0 status means a reset. */
|
|
- writel(0, vm_dev->base + VIRTIO_MMIO_STATUS);
|
|
+ vmd_writel(vm_dev, 0, VIRTIO_MMIO_STATUS);
|
|
}
|
|
|
|
|
|
@@ -282,7 +363,7 @@ static bool vm_notify(struct virtqueue *vq)
|
|
|
|
/* We write the queue's selector into the notification register to
|
|
* signal the other end */
|
|
- writel(vq->index, vm_dev->base + VIRTIO_MMIO_QUEUE_NOTIFY);
|
|
+ vmd_writel(vm_dev, vq->index, VIRTIO_MMIO_QUEUE_NOTIFY);
|
|
return true;
|
|
}
|
|
|
|
@@ -296,6 +377,36 @@ static bool vm_notify_with_data(struct virtqueue *vq)
|
|
return true;
|
|
}
|
|
|
|
+/* Notify all virtqueues on an interrupt. */
|
|
+static void virtio_mmio_irq_callback(struct mbox_client *c, void *msg)
|
|
+{
|
|
+ struct virtio_mmio_device *vm_dev = container_of(c,
|
|
+ struct virtio_mmio_device, mbox_irq_cl);
|
|
+ struct virtio_mmio_vq_info *info;
|
|
+ unsigned long status;
|
|
+ unsigned long flags;
|
|
+
|
|
+ /* Read and acknowledge interrupts */
|
|
+ status = readl(vm_dev->base + VIRTIO_MMIO_INTERRUPT_STATUS);
|
|
+
|
|
+ /*
|
|
+ * For Hypervisor-less virtio, write ACK without notification, since
|
|
+ * in mailbox RX channel callback function sometimes the timeout occur
|
|
+ * calling the vmd_writel().
|
|
+ */
|
|
+ writel(status, vm_dev->base + VIRTIO_MMIO_INTERRUPT_ACK);
|
|
+
|
|
+ if (unlikely(status & VIRTIO_MMIO_INT_CONFIG))
|
|
+ virtio_config_changed(&vm_dev->vdev);
|
|
+
|
|
+ if (likely(status & VIRTIO_MMIO_INT_VRING)) {
|
|
+ spin_lock_irqsave(&vm_dev->lock, flags);
|
|
+ list_for_each_entry(info, &vm_dev->virtqueues, node)
|
|
+ vring_interrupt(0, info->vq);
|
|
+ spin_unlock_irqrestore(&vm_dev->lock, flags);
|
|
+ }
|
|
+}
|
|
+
|
|
/* Notify all virtqueues on an interrupt. */
|
|
static irqreturn_t vm_interrupt(int irq, void *opaque)
|
|
{
|
|
@@ -307,7 +418,7 @@ static irqreturn_t vm_interrupt(int irq, void *opaque)
|
|
|
|
/* Read and acknowledge interrupts */
|
|
status = readl(vm_dev->base + VIRTIO_MMIO_INTERRUPT_STATUS);
|
|
- writel(status, vm_dev->base + VIRTIO_MMIO_INTERRUPT_ACK);
|
|
+ vmd_writel(vm_dev, status, VIRTIO_MMIO_INTERRUPT_ACK);
|
|
|
|
if (unlikely(status & VIRTIO_MMIO_INT_CONFIG)) {
|
|
virtio_config_changed(&vm_dev->vdev);
|
|
@@ -338,11 +449,11 @@ static void vm_del_vq(struct virtqueue *vq)
|
|
spin_unlock_irqrestore(&vm_dev->lock, flags);
|
|
|
|
/* Select and deactivate the queue */
|
|
- writel(index, vm_dev->base + VIRTIO_MMIO_QUEUE_SEL);
|
|
+ vmd_writel(vm_dev, index, VIRTIO_MMIO_QUEUE_SEL);
|
|
if (vm_dev->version == 1) {
|
|
- writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN);
|
|
+ vmd_writel(vm_dev, 0, VIRTIO_MMIO_QUEUE_PFN);
|
|
} else {
|
|
- writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_READY);
|
|
+ vmd_writel(vm_dev, 0, VIRTIO_MMIO_QUEUE_READY);
|
|
WARN_ON(readl(vm_dev->base + VIRTIO_MMIO_QUEUE_READY));
|
|
}
|
|
|
|
@@ -359,7 +470,10 @@ static void vm_del_vqs(struct virtio_device *vdev)
|
|
list_for_each_entry_safe(vq, n, &vdev->vqs, list)
|
|
vm_del_vq(vq);
|
|
|
|
- free_irq(platform_get_irq(vm_dev->pdev, 0), vm_dev);
|
|
+ if (vm_dev->is_hypervisor_less)
|
|
+ mbox_free_channel(vm_dev->mmio_irq_ch);
|
|
+ else
|
|
+ free_irq(platform_get_irq(vm_dev->pdev, 0), vm_dev);
|
|
}
|
|
|
|
static void vm_synchronize_cbs(struct virtio_device *vdev)
|
|
@@ -390,7 +504,7 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int in
|
|
return NULL;
|
|
|
|
/* Select the queue we're interested in */
|
|
- writel(index, vm_dev->base + VIRTIO_MMIO_QUEUE_SEL);
|
|
+ vmd_writel(vm_dev, index, VIRTIO_MMIO_QUEUE_SEL);
|
|
|
|
/* Queue shouldn't already be set up. */
|
|
if (readl(vm_dev->base + (vm_dev->version == 1 ?
|
|
@@ -423,7 +537,7 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int in
|
|
vq->num_max = num;
|
|
|
|
/* Activate the queue */
|
|
- writel(virtqueue_get_vring_size(vq), vm_dev->base + VIRTIO_MMIO_QUEUE_NUM);
|
|
+ vmd_writel(vm_dev, virtqueue_get_vring_size(vq), VIRTIO_MMIO_QUEUE_NUM);
|
|
if (vm_dev->version == 1) {
|
|
u64 q_pfn = virtqueue_get_desc_addr(vq) >> PAGE_SHIFT;
|
|
|
|
@@ -440,27 +554,27 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int in
|
|
goto error_bad_pfn;
|
|
}
|
|
|
|
- writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_QUEUE_ALIGN);
|
|
- writel(q_pfn, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN);
|
|
+ vmd_writel(vm_dev, PAGE_SIZE, VIRTIO_MMIO_QUEUE_ALIGN);
|
|
+ vmd_writel(vm_dev, q_pfn, VIRTIO_MMIO_QUEUE_PFN);
|
|
} else {
|
|
u64 addr;
|
|
|
|
addr = virtqueue_get_desc_addr(vq);
|
|
- writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_DESC_LOW);
|
|
- writel((u32)(addr >> 32),
|
|
- vm_dev->base + VIRTIO_MMIO_QUEUE_DESC_HIGH);
|
|
+ vmd_writel(vm_dev, (u32)addr, VIRTIO_MMIO_QUEUE_DESC_LOW);
|
|
+ vmd_writel(vm_dev, (u32)(addr >> 32),
|
|
+ VIRTIO_MMIO_QUEUE_DESC_HIGH);
|
|
|
|
addr = virtqueue_get_avail_addr(vq);
|
|
- writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_AVAIL_LOW);
|
|
- writel((u32)(addr >> 32),
|
|
- vm_dev->base + VIRTIO_MMIO_QUEUE_AVAIL_HIGH);
|
|
+ vmd_writel(vm_dev, (u32)addr, VIRTIO_MMIO_QUEUE_AVAIL_LOW);
|
|
+ vmd_writel(vm_dev, (u32)(addr >> 32),
|
|
+ VIRTIO_MMIO_QUEUE_AVAIL_HIGH);
|
|
|
|
addr = virtqueue_get_used_addr(vq);
|
|
- writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_USED_LOW);
|
|
- writel((u32)(addr >> 32),
|
|
- vm_dev->base + VIRTIO_MMIO_QUEUE_USED_HIGH);
|
|
+ vmd_writel(vm_dev, (u32)addr, VIRTIO_MMIO_QUEUE_USED_LOW);
|
|
+ vmd_writel(vm_dev, (u32)(addr >> 32),
|
|
+ VIRTIO_MMIO_QUEUE_USED_HIGH);
|
|
|
|
- writel(1, vm_dev->base + VIRTIO_MMIO_QUEUE_READY);
|
|
+ vmd_writel(vm_dev, 1, VIRTIO_MMIO_QUEUE_READY);
|
|
}
|
|
|
|
vq->priv = info;
|
|
@@ -476,9 +590,9 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int in
|
|
vring_del_virtqueue(vq);
|
|
error_new_virtqueue:
|
|
if (vm_dev->version == 1) {
|
|
- writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN);
|
|
+ vmd_writel(vm_dev, 0, VIRTIO_MMIO_QUEUE_PFN);
|
|
} else {
|
|
- writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_READY);
|
|
+ vmd_writel(vm_dev, 0, VIRTIO_MMIO_QUEUE_READY);
|
|
WARN_ON(readl(vm_dev->base + VIRTIO_MMIO_QUEUE_READY));
|
|
}
|
|
kfree(info);
|
|
@@ -487,6 +601,28 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned int in
|
|
return ERR_PTR(err);
|
|
}
|
|
|
|
+static int virtio_mmio_irq_channel_init(struct virtio_mmio_device *vm_dev)
|
|
+{
|
|
+ struct platform_device *pdev = vm_dev->pdev;
|
|
+ struct device *dev = &pdev->dev;
|
|
+ struct mbox_client *cl;
|
|
+ int ret = 0;
|
|
+
|
|
+ cl = &vm_dev->mbox_irq_cl;
|
|
+ cl->dev = dev;
|
|
+ cl->rx_callback = virtio_mmio_irq_callback;
|
|
+
|
|
+ vm_dev->mmio_irq_ch = mbox_request_channel_byname(cl, "mmioirq");
|
|
+ if (IS_ERR(vm_dev->mmio_irq_ch)) {
|
|
+ ret = PTR_ERR(vm_dev->mmio_irq_ch);
|
|
+ dev_err(cl->dev, "failed to request mbox irq chan, ret %d\n",
|
|
+ ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
static int vm_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
|
|
struct virtqueue *vqs[],
|
|
vq_callback_t *callbacks[],
|
|
@@ -495,16 +631,23 @@ static int vm_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
|
|
struct irq_affinity *desc)
|
|
{
|
|
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
|
|
- int irq = platform_get_irq(vm_dev->pdev, 0);
|
|
+ int irq;
|
|
int i, err, queue_idx = 0;
|
|
|
|
- if (irq < 0)
|
|
- return irq;
|
|
+ if (vm_dev->is_hypervisor_less) {
|
|
+ err = virtio_mmio_irq_channel_init(vm_dev);
|
|
+ if (err)
|
|
+ return err;
|
|
+ } else {
|
|
+ irq = platform_get_irq(vm_dev->pdev, 0);
|
|
+ if (irq < 0)
|
|
+ return irq;
|
|
|
|
- err = request_irq(irq, vm_interrupt, IRQF_SHARED,
|
|
+ err = request_irq(irq, vm_interrupt, IRQF_SHARED,
|
|
dev_name(&vdev->dev), vm_dev);
|
|
- if (err)
|
|
- return err;
|
|
+ if (err)
|
|
+ return err;
|
|
+ }
|
|
|
|
if (of_property_read_bool(vm_dev->pdev->dev.of_node, "wakeup-source"))
|
|
enable_irq_wake(irq);
|
|
@@ -540,7 +683,7 @@ static bool vm_get_shm_region(struct virtio_device *vdev,
|
|
u64 len, addr;
|
|
|
|
/* Select the region we're interested in */
|
|
- writel(id, vm_dev->base + VIRTIO_MMIO_SHM_SEL);
|
|
+ vmd_writel(vm_dev, id, VIRTIO_MMIO_SHM_SEL);
|
|
|
|
/* Read the region size */
|
|
len = (u64) readl(vm_dev->base + VIRTIO_MMIO_SHM_LEN_LOW);
|
|
@@ -611,6 +754,27 @@ static void virtio_mmio_release_dev(struct device *_d)
|
|
kfree(vm_dev);
|
|
}
|
|
|
|
+static int virtio_mmio_mbox_channel_init(struct virtio_mmio_device *vm_dev)
|
|
+{
|
|
+ struct platform_device *pdev = vm_dev->pdev;
|
|
+ struct device *dev = &pdev->dev;
|
|
+ struct mbox_client *cl;
|
|
+ int ret = 0;
|
|
+
|
|
+ cl = &vm_dev->mbox_wr_cl;
|
|
+ cl->dev = dev;
|
|
+
|
|
+ vm_dev->mmio_wr_ch = mbox_request_channel_byname(cl, "mmiowr");
|
|
+ if (IS_ERR(vm_dev->mmio_wr_ch)) {
|
|
+ ret = PTR_ERR(vm_dev->mmio_wr_ch);
|
|
+ dev_err(cl->dev, "failed to request mbox chan mmio, ret %d\n",
|
|
+ ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
/* Platform device */
|
|
|
|
static int virtio_mmio_probe(struct platform_device *pdev)
|
|
@@ -618,11 +782,19 @@ static int virtio_mmio_probe(struct platform_device *pdev)
|
|
struct virtio_mmio_device *vm_dev;
|
|
unsigned long magic;
|
|
int rc;
|
|
+ struct resource *res;
|
|
|
|
vm_dev = kzalloc(sizeof(*vm_dev), GFP_KERNEL);
|
|
if (!vm_dev)
|
|
return -ENOMEM;
|
|
|
|
+ if (of_property_read_bool(pdev->dev.of_node, "hypervisor_less")) {
|
|
+ vm_dev->is_hypervisor_less = true;
|
|
+ rc = of_reserved_mem_device_init(&pdev->dev);
|
|
+ if (rc)
|
|
+ dev_info(&pdev->dev, "Device specific DMA pool is not available\n");
|
|
+ }
|
|
+
|
|
vm_dev->vdev.dev.parent = &pdev->dev;
|
|
vm_dev->vdev.dev.release = virtio_mmio_release_dev;
|
|
vm_dev->vdev.config = &virtio_mmio_config_ops;
|
|
@@ -630,7 +802,7 @@ static int virtio_mmio_probe(struct platform_device *pdev)
|
|
INIT_LIST_HEAD(&vm_dev->virtqueues);
|
|
spin_lock_init(&vm_dev->lock);
|
|
|
|
- vm_dev->base = devm_platform_ioremap_resource(pdev, 0);
|
|
+ vm_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
|
if (IS_ERR(vm_dev->base)) {
|
|
rc = PTR_ERR(vm_dev->base);
|
|
goto free_vm_dev;
|
|
@@ -641,7 +813,7 @@ static int virtio_mmio_probe(struct platform_device *pdev)
|
|
if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) {
|
|
dev_warn(&pdev->dev, "Wrong magic value 0x%08lx!\n", magic);
|
|
rc = -ENODEV;
|
|
- goto free_vm_dev;
|
|
+ goto err;
|
|
}
|
|
|
|
/* Check device version */
|
|
@@ -650,7 +822,7 @@ static int virtio_mmio_probe(struct platform_device *pdev)
|
|
dev_err(&pdev->dev, "Version %ld not supported!\n",
|
|
vm_dev->version);
|
|
rc = -ENXIO;
|
|
- goto free_vm_dev;
|
|
+ goto err;
|
|
}
|
|
|
|
vm_dev->vdev.id.device = readl(vm_dev->base + VIRTIO_MMIO_DEVICE_ID);
|
|
@@ -660,12 +832,24 @@ static int virtio_mmio_probe(struct platform_device *pdev)
|
|
* with no function. End probing now with no error reported.
|
|
*/
|
|
rc = -ENODEV;
|
|
- goto free_vm_dev;
|
|
+ goto err;
|
|
}
|
|
vm_dev->vdev.id.vendor = readl(vm_dev->base + VIRTIO_MMIO_VENDOR_ID);
|
|
|
|
+ if (vm_dev->is_hypervisor_less) {
|
|
+ vm_dev->phys = res->start;
|
|
+
|
|
+ vm_dev->wr_ops = vm_dev->base + VIRTIO_MMIO_RW_OPS_MEM_OFFSET;
|
|
+ vm_dev->wr_ops_phys = res->start + VIRTIO_MMIO_RW_OPS_MEM_OFFSET;
|
|
+
|
|
+ /* Initialize mailbox mmio channel. */
|
|
+ rc = virtio_mmio_mbox_channel_init(vm_dev);
|
|
+ if (rc)
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
if (vm_dev->version == 1) {
|
|
- writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_GUEST_PAGE_SIZE);
|
|
+ vmd_writel(vm_dev, PAGE_SIZE, VIRTIO_MMIO_GUEST_PAGE_SIZE);
|
|
|
|
rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
|
|
/*
|
|
@@ -691,14 +875,22 @@ static int virtio_mmio_probe(struct platform_device *pdev)
|
|
|
|
return rc;
|
|
|
|
+err:
|
|
+ if (vm_dev->is_hypervisor_less)
|
|
+ of_reserved_mem_device_release(&pdev->dev);
|
|
free_vm_dev:
|
|
kfree(vm_dev);
|
|
+
|
|
return rc;
|
|
}
|
|
|
|
static int virtio_mmio_remove(struct platform_device *pdev)
|
|
{
|
|
struct virtio_mmio_device *vm_dev = platform_get_drvdata(pdev);
|
|
+
|
|
+ if (vm_dev->is_hypervisor_less)
|
|
+ mbox_free_channel(vm_dev->mmio_wr_ch);
|
|
+
|
|
unregister_virtio_device(&vm_dev->vdev);
|
|
|
|
return 0;
|
|
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
|
|
index 80669e05bf0e..99ecfae18d9c 100644
|
|
--- a/drivers/virtio/virtio_ring.c
|
|
+++ b/drivers/virtio/virtio_ring.c
|
|
@@ -599,8 +599,6 @@ static inline int virtqueue_add_split(struct virtqueue *_vq,
|
|
/* FIXME: for historical reasons, we force a notify here if
|
|
* there are outgoing parts to the buffer. Presumably the
|
|
* host should service the ring ASAP. */
|
|
- if (out_sgs)
|
|
- vq->notify(&vq->vq);
|
|
if (indirect)
|
|
kfree(desc);
|
|
END_USE(vq);
|
|
diff --git a/drivers/virtio/virtio_trans.c b/drivers/virtio/virtio_trans.c
|
|
new file mode 100644
|
|
index 000000000000..13c003e2ba45
|
|
--- /dev/null
|
|
+++ b/drivers/virtio/virtio_trans.c
|
|
@@ -0,0 +1,793 @@
|
|
+// SPDX-License-Identifier: GPL-2.0-or-later
|
|
+/*
|
|
+ * Copyright 2022-2023 NXP
|
|
+ */
|
|
+
|
|
+#include <linux/delay.h>
|
|
+#include <linux/device.h>
|
|
+#include <linux/dma-mapping.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/freezer.h>
|
|
+#include <linux/fs.h>
|
|
+#include <linux/pagemap.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/list.h>
|
|
+#include <linux/math64.h>
|
|
+#include <linux/poll.h>
|
|
+#include <linux/sched.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/spinlock.h>
|
|
+#include <linux/virtio.h>
|
|
+#include <linux/wait.h>
|
|
+#include <linux/workqueue.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/virtio_config.h>
|
|
+#include <uapi/linux/virtio_ids.h>
|
|
+#include <uapi/linux/virtio_trans.h>
|
|
+
|
|
+#define MAX_TEST_LEN 2048
|
|
+#define VT_TIMES 1000
|
|
+#define INDIRECT_NUM 1
|
|
+#define WAIT_TO_MS 2
|
|
+
|
|
+#define VT_TXRX_BIT (1 << 0)
|
|
+#define VT_B_COPY_BIT (1 << 1)
|
|
+#define VT_F_COPY_BIT (1 << 2)
|
|
+#define VT_B_MODE_BIT (1 << 3)
|
|
+#define VT_F_MODE_BIT (1 << 4)
|
|
+
|
|
+static u32 poll_delay = 10;
|
|
+
|
|
+struct virtio_trans {
|
|
+ /* The virtio device we're associated with */
|
|
+ struct virtio_device *vdev;
|
|
+ struct device *dev;
|
|
+ wait_queue_head_t waitqueue;
|
|
+ struct work_struct config_work;
|
|
+
|
|
+ struct virtqueue *tx_vq, *rx_vq;
|
|
+ void *tx_buf, *rx_buf;
|
|
+ spinlock_t txvq_lock;
|
|
+ spinlock_t rxvq_lock;
|
|
+ struct scatterlist *tx_sgl;
|
|
+ struct scatterlist *rx_sgl;
|
|
+ size_t tx_vring_size;
|
|
+ size_t rx_vring_size;
|
|
+
|
|
+ bool vt_running;
|
|
+ u32 regression;
|
|
+ size_t pkt_size;
|
|
+ bool tx;
|
|
+ bool do_copy;
|
|
+ bool poll_mode;
|
|
+ bool back_poll_mode;
|
|
+ void *data_buf;
|
|
+};
|
|
+
|
|
+static void tx_intr(struct virtqueue *vq)
|
|
+{
|
|
+ struct virtio_trans *vt = vq->vdev->priv;
|
|
+
|
|
+ if (vt->poll_mode)
|
|
+ return;
|
|
+
|
|
+ if (!vt->vt_running)
|
|
+ return;
|
|
+
|
|
+ if (!vt->tx)
|
|
+ return;
|
|
+
|
|
+ wake_up_interruptible(&vt->waitqueue);
|
|
+}
|
|
+
|
|
+static void virttrans_init_sg(struct scatterlist *sg, size_t sg_num, void *base, size_t len)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ sg_init_table(sg, sg_num);
|
|
+ if (likely(is_vmalloc_addr(base)))
|
|
+ for (i = 0; i < sg_num; i++)
|
|
+ sg_set_page(&sg[i], vmalloc_to_page(base + i * len), len,
|
|
+ offset_in_page(base));
|
|
+ else
|
|
+ for (i = 0; i < sg_num; i++)
|
|
+ sg_set_buf(&sg[i], base + i * len, len);
|
|
+}
|
|
+
|
|
+/* call this func with lock */
|
|
+static void virttrans_queue_txbuf(struct virtio_trans *vt,
|
|
+ struct scatterlist *sg,
|
|
+ void *buf, size_t pkt_size)
|
|
+{
|
|
+ if (vt->do_copy)
|
|
+ memcpy(buf, vt->data_buf, pkt_size);
|
|
+ virtqueue_add_outbuf(vt->tx_vq, sg, INDIRECT_NUM, buf, GFP_ATOMIC);
|
|
+}
|
|
+
|
|
+static void virttrans_reclaim_txvq(struct virtio_trans *vt)
|
|
+{
|
|
+ void *buf;
|
|
+ u32 len;
|
|
+
|
|
+ spin_lock(&vt->txvq_lock);
|
|
+ while ((buf = virtqueue_get_buf(vt->tx_vq, &len)) != NULL)
|
|
+ ;
|
|
+ spin_unlock(&vt->txvq_lock);
|
|
+
|
|
+}
|
|
+
|
|
+static void virttrans_fill_txvq(struct virtio_trans *vt, size_t pkt_size)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ spin_lock(&vt->txvq_lock);
|
|
+ for (i = 0; i < vt->tx_vring_size; i++) {
|
|
+ virttrans_init_sg(&vt->tx_sgl[i * INDIRECT_NUM], INDIRECT_NUM,
|
|
+ vt->tx_buf + i * MAX_TEST_LEN * INDIRECT_NUM,
|
|
+ pkt_size);
|
|
+ virttrans_queue_txbuf(vt, &vt->tx_sgl[i * INDIRECT_NUM],
|
|
+ vt->tx_buf + i * MAX_TEST_LEN *
|
|
+ INDIRECT_NUM, pkt_size);
|
|
+ }
|
|
+ spin_unlock(&vt->txvq_lock);
|
|
+}
|
|
+
|
|
+static void *vt_get_tx_buf(struct virtio_trans *vt)
|
|
+{
|
|
+ void *buf;
|
|
+ int len;
|
|
+
|
|
+ spin_lock(&vt->txvq_lock);
|
|
+ buf = virtqueue_get_buf(vt->tx_vq, &len);
|
|
+ spin_unlock(&vt->txvq_lock);
|
|
+
|
|
+ return buf;
|
|
+}
|
|
+static int tx_pkts(struct virtio_trans *vt, size_t pkt_size, u32 times)
|
|
+{
|
|
+
|
|
+ ktime_t start_time, stop_time;
|
|
+ u32 cnt = times;
|
|
+ u64 time_period;
|
|
+ u32 tx_count;
|
|
+ int err;
|
|
+ int i;
|
|
+ u64 idx = 0;
|
|
+ void *buf;
|
|
+
|
|
+ if (pkt_size > MAX_TEST_LEN) {
|
|
+ dev_err(vt->dev, "pkt_size must be less than 0x%x\n",
|
|
+ MAX_TEST_LEN);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ start_time = ktime_get();
|
|
+
|
|
+ while (vt->vt_running && cnt > 0) {
|
|
+ buf = vt_get_tx_buf(vt);
|
|
+ while (!buf) {
|
|
+ if (!vt->back_poll_mode)
|
|
+ virtqueue_kick(vt->tx_vq);
|
|
+
|
|
+ if (vt->poll_mode) {
|
|
+ udelay(poll_delay);
|
|
+ buf = vt_get_tx_buf(vt);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ err = wait_event_interruptible_timeout(vt->waitqueue,
|
|
+ (buf = vt_get_tx_buf(vt)),
|
|
+ msecs_to_jiffies(WAIT_TO_MS));
|
|
+ if (err == -ERESTARTSYS) {
|
|
+ dev_info(vt->dev, "%s: interrupt the waiting for tx buffer by signal\n",
|
|
+ __func__);
|
|
+ goto out;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ spin_lock(&vt->txvq_lock);
|
|
+ u64 tmp_idx = idx;
|
|
+ u32 tmp_rem;
|
|
+ div_u64_rem(tmp_idx, vt->tx_vring_size, &tmp_rem);
|
|
+ virttrans_queue_txbuf(vt, &vt->tx_sgl[tmp_rem],
|
|
+ buf, vt->pkt_size);
|
|
+ idx++;
|
|
+ spin_unlock(&vt->txvq_lock);
|
|
+
|
|
+ cnt -= INDIRECT_NUM;
|
|
+ }
|
|
+
|
|
+out:
|
|
+ i = 100;
|
|
+ while (i--) {
|
|
+ virtqueue_kick(vt->tx_vq);
|
|
+ virtio_cread_le(vt->vdev, struct virtio_trans_config,
|
|
+ tx_count, &tx_count);
|
|
+ if (tx_count >= times - cnt)
|
|
+ break;
|
|
+ mdelay(10);
|
|
+ }
|
|
+
|
|
+ if (i < 0)
|
|
+ dev_err(vt->dev, "Wait backend completion timeout\n");
|
|
+
|
|
+ stop_time = ktime_get();
|
|
+ time_period = ktime_us_delta(stop_time, start_time);
|
|
+
|
|
+ pr_info("tx_test: pkt_size (%zu B), pkt_cnt (%d), period (%llu us)\n",
|
|
+ pkt_size, times - cnt, time_period);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+/* call this func with lock */
|
|
+static void virttrans_queue_rxbuf(struct virtio_trans *vt,
|
|
+ struct scatterlist *sg,
|
|
+ void *buf, size_t pkt_size)
|
|
+{
|
|
+ if (vt->do_copy)
|
|
+ memcpy(vt->data_buf, buf, pkt_size);
|
|
+ virtqueue_add_inbuf(vt->rx_vq, sg, INDIRECT_NUM, buf, GFP_ATOMIC);
|
|
+}
|
|
+
|
|
+static void virttrans_reclaim_rxvq(struct virtio_trans *vt)
|
|
+{
|
|
+ void *buf;
|
|
+ u32 len;
|
|
+
|
|
+ spin_lock(&vt->rxvq_lock);
|
|
+ while ((buf = virtqueue_get_buf(vt->rx_vq, &len)) != NULL)
|
|
+ ;
|
|
+ spin_unlock(&vt->rxvq_lock);
|
|
+
|
|
+}
|
|
+
|
|
+static void virttrans_fill_rxvq(struct virtio_trans *vt, size_t pkt_size)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ spin_lock(&vt->rxvq_lock);
|
|
+ for (i = 0; i < vt->rx_vring_size; i++) {
|
|
+ virttrans_init_sg(&vt->rx_sgl[i * INDIRECT_NUM], INDIRECT_NUM,
|
|
+ vt->rx_buf + i * MAX_TEST_LEN * INDIRECT_NUM,
|
|
+ pkt_size);
|
|
+ virttrans_queue_rxbuf(vt, &vt->rx_sgl[i * INDIRECT_NUM],
|
|
+ vt->rx_buf + i * MAX_TEST_LEN *
|
|
+ INDIRECT_NUM, pkt_size);
|
|
+ }
|
|
+ spin_unlock(&vt->rxvq_lock);
|
|
+}
|
|
+
|
|
+static void rx_intr(struct virtqueue *vq)
|
|
+{
|
|
+ struct virtio_trans *vt = vq->vdev->priv;
|
|
+
|
|
+ if (vt->poll_mode)
|
|
+ return;
|
|
+
|
|
+ if (!vt->vt_running)
|
|
+ return;
|
|
+
|
|
+ if (vt->tx)
|
|
+ return;
|
|
+
|
|
+ wake_up_interruptible(&vt->waitqueue);
|
|
+}
|
|
+
|
|
+static void *vt_get_rx_buf(struct virtio_trans *vt)
|
|
+{
|
|
+ void *buf;
|
|
+ int len;
|
|
+
|
|
+ spin_lock(&vt->rxvq_lock);
|
|
+ buf = virtqueue_get_buf(vt->rx_vq, &len);
|
|
+ spin_unlock(&vt->rxvq_lock);
|
|
+
|
|
+ return buf;
|
|
+}
|
|
+
|
|
+static int rx_pkts(struct virtio_trans *vt, size_t pkt_size, u32 times)
|
|
+{
|
|
+
|
|
+ ktime_t start_time, stop_time;
|
|
+ u32 cnt = times;
|
|
+ u64 time_period;
|
|
+ int err;
|
|
+ void *buf;
|
|
+ u64 idx = 0;
|
|
+
|
|
+ if (pkt_size > MAX_TEST_LEN) {
|
|
+ dev_err(vt->dev, "pkt_size must be less than 0x%x\n",
|
|
+ MAX_TEST_LEN);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ start_time = ktime_get();
|
|
+ while (vt->vt_running && cnt > 0) {
|
|
+ buf = vt_get_rx_buf(vt);
|
|
+ while (!buf) {
|
|
+ if (!vt->back_poll_mode)
|
|
+ virtqueue_kick(vt->rx_vq);
|
|
+
|
|
+ if (vt->poll_mode) {
|
|
+ udelay(poll_delay);
|
|
+ buf = vt_get_rx_buf(vt);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ err = wait_event_interruptible_timeout(vt->waitqueue,
|
|
+ (buf = vt_get_rx_buf(vt)),
|
|
+ msecs_to_jiffies(WAIT_TO_MS));
|
|
+ if (err == -ERESTARTSYS) {
|
|
+ dev_info(vt->dev, "%s: interrupt the waiting for rx buffer by signal\n",
|
|
+ __func__);
|
|
+ goto out;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ spin_lock(&vt->rxvq_lock);
|
|
+ u64 tmp_idx = idx;
|
|
+ u32 tmp_rem;
|
|
+ div_u64_rem(tmp_idx, vt->rx_vring_size, &tmp_rem);
|
|
+ virttrans_queue_rxbuf(vt, &vt->rx_sgl[tmp_rem],
|
|
+ buf, vt->pkt_size);
|
|
+ idx++;
|
|
+ spin_unlock(&vt->rxvq_lock);
|
|
+
|
|
+ cnt -= INDIRECT_NUM;
|
|
+ }
|
|
+
|
|
+out:
|
|
+ stop_time = ktime_get();
|
|
+ time_period = ktime_us_delta(stop_time, start_time);
|
|
+
|
|
+ pr_info("rx_test: pkt_size (%zu B), pkt_cnt (%d), period (%llu us)\n",
|
|
+ pkt_size, times - cnt, time_period);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static ssize_t vt_control_show(struct device *dev,
|
|
+ struct device_attribute *attr,
|
|
+ char *buf)
|
|
+{
|
|
+ struct virtio_trans *vt = dev_get_drvdata(dev);
|
|
+ u32 control;
|
|
+
|
|
+ virtio_cread_le(vt->vdev, struct virtio_trans_config, control,
|
|
+ &control);
|
|
+
|
|
+ return sprintf(buf, "0: stop\n1: start\ncontrol = %u\n", control);
|
|
+}
|
|
+
|
|
+static ssize_t vt_control_store(struct device *dev,
|
|
+ struct device_attribute *attr,
|
|
+ const char *buf, size_t cnt)
|
|
+{
|
|
+ struct virtio_trans *vt = dev_get_drvdata(dev);
|
|
+ u32 control;
|
|
+ unsigned long val;
|
|
+
|
|
+ if (kstrtoul(buf, 0, &val) < 0 || (val > 1)) {
|
|
+ dev_err(vt->dev, "Invalid param\n");
|
|
+ pr_info("0: stop\n");
|
|
+ pr_info("1: start\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ virtio_cread_le(vt->vdev, struct virtio_trans_config, control,
|
|
+ &control);
|
|
+
|
|
+ if (!val) {
|
|
+ control &= ~VT_CTRL_START;
|
|
+ virtio_cwrite_le(vt->vdev, struct virtio_trans_config, control,
|
|
+ &control);
|
|
+ vt->vt_running = 0;
|
|
+ if (!vt->tx)
|
|
+ virttrans_reclaim_rxvq(vt);
|
|
+ else
|
|
+ virttrans_reclaim_txvq(vt);
|
|
+
|
|
+ vt->regression = 0;
|
|
+ return cnt;
|
|
+ }
|
|
+
|
|
+ if (vt->vt_running) {
|
|
+ dev_err(vt->dev, "Try again after this test completed\n");
|
|
+ return -EAGAIN;
|
|
+ }
|
|
+
|
|
+ vt->vt_running = 1;
|
|
+ control |= VT_CTRL_START;
|
|
+
|
|
+ if (!vt->tx) {
|
|
+ virttrans_fill_rxvq(vt, vt->pkt_size);
|
|
+ virtio_cwrite_le(vt->vdev, struct virtio_trans_config, control,
|
|
+ &control);
|
|
+ rx_pkts(vt, vt->pkt_size, vt->regression);
|
|
+ } else {
|
|
+ virttrans_fill_txvq(vt, vt->pkt_size);
|
|
+ virtio_cwrite_le(vt->vdev, struct virtio_trans_config, control,
|
|
+ &control);
|
|
+ tx_pkts(vt, vt->pkt_size, vt->regression);
|
|
+ }
|
|
+
|
|
+ control &= ~VT_CTRL_START;
|
|
+ virtio_cwrite_le(vt->vdev, struct virtio_trans_config, control,
|
|
+ &control);
|
|
+
|
|
+ vt->vt_running = 0;
|
|
+ vt->regression = 0;
|
|
+
|
|
+ return cnt;
|
|
+}
|
|
+
|
|
+static ssize_t vt_config_store(struct device *dev,
|
|
+ struct device_attribute *attr,
|
|
+ const char *buf, size_t cnt)
|
|
+{
|
|
+ struct virtio_trans *vt = dev_get_drvdata(dev);
|
|
+ u32 config;
|
|
+ unsigned long val;
|
|
+
|
|
+ if (vt->vt_running) {
|
|
+ dev_err(dev, "Try again after this test completed\n");
|
|
+ return -EAGAIN;
|
|
+ }
|
|
+
|
|
+ if (kstrtoul(buf, 0, &val) < 0 || (val & ~0x1f)) {
|
|
+ dev_err(dev, "Invalid param\n");
|
|
+ pr_info("bit[0]:\n");
|
|
+ pr_info("\t0: TX\n");
|
|
+ pr_info("\t1: RX\n");
|
|
+ pr_info("bit[1]:\n");
|
|
+ pr_info("\t0: Backend do NOT copy buffer\n");
|
|
+ pr_info("\t1: Backend do copy buffer\n");
|
|
+ pr_info("bit[2]:\n");
|
|
+ pr_info("\t0: Frontend do NOT copy buffer\n");
|
|
+ pr_info("\t1: Frontend do copy buffer\n");
|
|
+ pr_info("bit[3]:\n");
|
|
+ pr_info("\t0: Backend interrupt mode\n");
|
|
+ pr_info("\t1: Backend polling mode\n");
|
|
+ pr_info("bit[4]:\n");
|
|
+ pr_info("\t0: Frontend interrupt mode\n");
|
|
+ pr_info("\t1: Frontend polling mode\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (!vt->pkt_size)
|
|
+ vt->pkt_size = 64;
|
|
+
|
|
+ if (!vt->regression) {
|
|
+ virtio_cwrite_le(vt->vdev, struct virtio_trans_config,
|
|
+ regression, &vt->regression);
|
|
+ vt->regression = VT_TIMES;
|
|
+ }
|
|
+
|
|
+ virtio_cread_le(vt->vdev, struct virtio_trans_config, config, &config);
|
|
+
|
|
+ config &= ~(VT_CFG_TX | VT_CFG_RX | VT_CFG_COPY |
|
|
+ VT_CFG_B_POLL | VT_CFG_F_POLL);
|
|
+ vt->do_copy = false;
|
|
+ vt->back_poll_mode = false;
|
|
+ vt->poll_mode = false;
|
|
+
|
|
+ if (val & VT_TXRX_BIT) {
|
|
+ vt->tx = false;
|
|
+ config |= VT_CFG_RX;
|
|
+ } else {
|
|
+ vt->tx = true;
|
|
+ config |= VT_CFG_TX;
|
|
+ }
|
|
+
|
|
+ if (val & VT_B_COPY_BIT)
|
|
+ config |= VT_CFG_COPY;
|
|
+
|
|
+ if (val & VT_F_COPY_BIT)
|
|
+ vt->do_copy = true;
|
|
+
|
|
+ if (val & VT_B_MODE_BIT) {
|
|
+ vt->back_poll_mode = true;
|
|
+ config |= VT_CFG_B_POLL;
|
|
+ }
|
|
+
|
|
+ if (val & VT_F_MODE_BIT) {
|
|
+ vt->poll_mode = true;
|
|
+ config |= VT_CFG_F_POLL;
|
|
+ }
|
|
+
|
|
+ pr_info("*********************************************************\n");
|
|
+ pr_info("Front-end: %s mode\n", vt->poll_mode ? "poll" : "interrupt");
|
|
+ pr_info("Back-end: %s mode\n", vt->back_poll_mode ? "poll" : "interrupt");
|
|
+ pr_info("Front-end: do %scopy buffer\n", vt->do_copy ? "" : "NOT ");
|
|
+ pr_info("Back-end: do %scopy buffer\n", (config & VT_CFG_COPY) ? "" : "NOT");
|
|
+
|
|
+ pr_info("\tTest case: %s\n\tpkt_size: <%zu>\n\tregress times: <%d>\n\n",
|
|
+ vt->tx ? "TX" : "RX", vt->pkt_size, vt->regression);
|
|
+
|
|
+ virtio_cwrite_le(vt->vdev, struct virtio_trans_config, config, &config);
|
|
+
|
|
+ return cnt;
|
|
+}
|
|
+static ssize_t vt_config_show(struct device *dev,
|
|
+ struct device_attribute *attr,
|
|
+ char *buf)
|
|
+{
|
|
+ struct virtio_trans *vt = dev_get_drvdata(dev);
|
|
+ u32 config;
|
|
+
|
|
+ virtio_cread_le(vt->vdev, struct virtio_trans_config, config, &config);
|
|
+
|
|
+ return sprintf(buf, "0x%x\n", config);
|
|
+}
|
|
+
|
|
+static ssize_t vt_pkt_size_store(struct device *dev,
|
|
+ struct device_attribute *attr,
|
|
+ const char *buf, size_t cnt)
|
|
+{
|
|
+ struct virtio_trans *vt = dev_get_drvdata(dev);
|
|
+ u32 val;
|
|
+
|
|
+ if (vt->vt_running) {
|
|
+ dev_err(dev, "Try again after this test completed\n");
|
|
+ return -EAGAIN;
|
|
+ }
|
|
+
|
|
+ if (kstrtou32(buf, 0, &val) < 0 || (val > MAX_TEST_LEN)) {
|
|
+ dev_err(dev, "pkt_size must be less then 0x%x\n", MAX_TEST_LEN);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ vt->pkt_size = val;
|
|
+ virtio_cwrite_le(vt->vdev, struct virtio_trans_config, pkt_size, &val);
|
|
+
|
|
+ dev_dbg(dev, "Update pkt_size to %u\n", val);
|
|
+
|
|
+ return cnt;
|
|
+}
|
|
+static ssize_t vt_pkt_size_show(struct device *dev,
|
|
+ struct device_attribute *attr,
|
|
+ char *buf)
|
|
+{
|
|
+ struct virtio_trans *vt = dev_get_drvdata(dev);
|
|
+
|
|
+ return sprintf(buf, "%ld\n", vt->pkt_size);
|
|
+}
|
|
+
|
|
+static ssize_t vt_regression_store(struct device *dev,
|
|
+ struct device_attribute *attr,
|
|
+ const char *buf, size_t cnt)
|
|
+{
|
|
+ struct virtio_trans *vt = dev_get_drvdata(dev);
|
|
+ u32 val;
|
|
+
|
|
+ if (vt->vt_running) {
|
|
+ dev_err(dev, "Try again after this test completed\n");
|
|
+ return -EAGAIN;
|
|
+ }
|
|
+
|
|
+ if (kstrtou32(buf, 0, &val) < 0 || val <= 0) {
|
|
+ dev_err(dev, "Invalid regression\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ vt->regression = val;
|
|
+
|
|
+ virtio_cwrite_le(vt->vdev, struct virtio_trans_config, regression,
|
|
+ &val);
|
|
+ dev_dbg(dev, "Update regression to %u\n", val);
|
|
+
|
|
+ return cnt;
|
|
+}
|
|
+static ssize_t vt_regression_show(struct device *dev,
|
|
+ struct device_attribute *attr,
|
|
+ char *buf)
|
|
+{
|
|
+ struct virtio_trans *vt = dev_get_drvdata(dev);
|
|
+
|
|
+ return sprintf(buf, "%u\n", vt->regression);
|
|
+}
|
|
+
|
|
+static DEVICE_ATTR_RW(vt_control);
|
|
+static DEVICE_ATTR_RW(vt_config);
|
|
+static DEVICE_ATTR_RW(vt_pkt_size);
|
|
+static DEVICE_ATTR_RW(vt_regression);
|
|
+
|
|
+static struct attribute *sysfs_entries[] = {
|
|
+ &dev_attr_vt_config.attr,
|
|
+ &dev_attr_vt_control.attr,
|
|
+ &dev_attr_vt_pkt_size.attr,
|
|
+ &dev_attr_vt_regression.attr,
|
|
+ NULL
|
|
+};
|
|
+
|
|
+static const struct attribute_group vt_attribute_group = {
|
|
+ .name = NULL, /* put in device directory */
|
|
+ .attrs = sysfs_entries,
|
|
+};
|
|
+
|
|
+static void config_intr(struct virtio_device *vdev)
|
|
+{
|
|
+ struct virtio_trans *vt = vdev->priv;
|
|
+
|
|
+ schedule_work(&vt->config_work);
|
|
+}
|
|
+
|
|
+static void config_work_handler(struct work_struct *work)
|
|
+{
|
|
+ /* handle the config change */
|
|
+}
|
|
+
|
|
+static int virttrans_init_vqs(struct virtio_trans *vt)
|
|
+{
|
|
+ struct virtqueue *vqs[2];
|
|
+ vq_callback_t *cbs[] = { tx_intr, rx_intr};
|
|
+ static const char * const names[] = { "tx", "rx" };
|
|
+ int err;
|
|
+
|
|
+ err = virtio_find_vqs(vt->vdev, 2, vqs, cbs, names, NULL);
|
|
+ if (err) {
|
|
+ dev_err(vt->dev, "Failed to find vqs\n");
|
|
+ return err;
|
|
+ }
|
|
+ vt->tx_vq = vqs[0];
|
|
+ vt->rx_vq = vqs[1];
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int virttrans_probe(struct virtio_device *vdev)
|
|
+{
|
|
+ struct virtio_trans *vt;
|
|
+ int err;
|
|
+ dma_addr_t tx_buf_dma;
|
|
+
|
|
+ vt = kzalloc(sizeof(*vt), GFP_KERNEL);
|
|
+ if (!vt)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ vdev->priv = vt;
|
|
+ vt->vdev = vdev;
|
|
+ vt->dev = &vdev->dev;
|
|
+ vt->pkt_size = 64;
|
|
+ vt->regression = VT_TIMES;
|
|
+
|
|
+ dev_set_drvdata(vt->dev, vt);
|
|
+
|
|
+ err = virttrans_init_vqs(vt);
|
|
+ if (err) {
|
|
+ dev_err(vt->dev, "Failed to init virtqueues\n");
|
|
+ goto err_init_vq;
|
|
+ }
|
|
+
|
|
+ vt->tx_vring_size = virtqueue_get_vring_size(vt->tx_vq);
|
|
+ vt->rx_vring_size = virtqueue_get_vring_size(vt->rx_vq);
|
|
+
|
|
+ vt->data_buf = kzalloc(MAX_TEST_LEN, GFP_KERNEL);
|
|
+ if (!vt->data_buf) {
|
|
+ err = -ENOMEM;
|
|
+ dev_err(vt->dev, "Failed to alloc data buffer\n");
|
|
+ goto alloc_data_buf;
|
|
+ }
|
|
+
|
|
+ memset(vt->data_buf, 0xa5, MAX_TEST_LEN);
|
|
+
|
|
+ vt->tx_sgl = kzalloc(INDIRECT_NUM * (vt->rx_vring_size +
|
|
+ vt->tx_vring_size) * sizeof(struct scatterlist),
|
|
+ GFP_KERNEL);
|
|
+
|
|
+ if (!vt->tx_sgl) {
|
|
+ err = -ENOMEM;
|
|
+ dev_err(vt->dev, "Failed to alloc SG descriptors\n");
|
|
+ goto alloc_sgl;
|
|
+ }
|
|
+
|
|
+ vt->rx_sgl = vt->tx_sgl + INDIRECT_NUM * vt->tx_vring_size;
|
|
+
|
|
+ vt->tx_buf = dma_alloc_coherent(vdev->dev.parent, MAX_TEST_LEN *
|
|
+ INDIRECT_NUM * (vt->rx_vring_size +
|
|
+ vt->tx_vring_size), &tx_buf_dma,
|
|
+ GFP_KERNEL);
|
|
+ if (!vt->tx_buf) {
|
|
+ err = -ENOMEM;
|
|
+ dev_err(vt->dev, "Failed to alloc Vring buffers\n");
|
|
+ goto alloc_buf;
|
|
+ }
|
|
+
|
|
+ vt->rx_buf = vt->tx_buf +
|
|
+ MAX_TEST_LEN * INDIRECT_NUM * vt->tx_vring_size;
|
|
+
|
|
+ spin_lock_init(&vt->txvq_lock);
|
|
+ spin_lock_init(&vt->rxvq_lock);
|
|
+ init_waitqueue_head(&vt->waitqueue);
|
|
+ INIT_WORK(&vt->config_work, &config_work_handler);
|
|
+
|
|
+ err = sysfs_create_group(&vt->dev->kobj, &vt_attribute_group);
|
|
+ if (err) {
|
|
+ dev_err(vt->dev, "Failed to create sysfs device attributes\n");
|
|
+ goto sysfs;
|
|
+ } else {
|
|
+ /*
|
|
+ * Generate a udev event so that appropriate
|
|
+ * symlinks can be created based on udev
|
|
+ * rules.
|
|
+ */
|
|
+ kobject_uevent(&vt->dev->kobj, KOBJ_CHANGE);
|
|
+ }
|
|
+
|
|
+ virtio_device_ready(vt->vdev);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+sysfs:
|
|
+ dma_free_coherent(vdev->dev.parent, MAX_TEST_LEN * INDIRECT_NUM *
|
|
+ (vt->rx_vring_size + vt->tx_vring_size),
|
|
+ vt->tx_buf, tx_buf_dma);
|
|
+alloc_buf:
|
|
+ kfree(vt->tx_sgl);
|
|
+alloc_sgl:
|
|
+ kfree(vt->data_buf);
|
|
+alloc_data_buf:
|
|
+ /* TODO: vtrans_deinit_vq(); */
|
|
+err_init_vq:
|
|
+ kfree(vt);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static void virttrans_remove(struct virtio_device *vdev)
|
|
+{
|
|
+ struct virtio_trans *vt = vdev->priv;
|
|
+ void *buf;
|
|
+
|
|
+ virtio_break_device(vdev);
|
|
+ flush_work(&vt->config_work);
|
|
+ vdev->config->reset(vdev);
|
|
+ cancel_work_sync(&vt->config_work);
|
|
+
|
|
+ sysfs_remove_group(&vt->dev->kobj, &vt_attribute_group);
|
|
+
|
|
+ while ((buf = virtqueue_detach_unused_buf(vt->tx_vq)) != NULL)
|
|
+ kfree(buf);
|
|
+ vdev->config->del_vqs(vdev);
|
|
+
|
|
+ kfree(vt);
|
|
+}
|
|
+
|
|
+static const struct virtio_device_id id_table[] = {
|
|
+ { VIRTIO_ID_TRANS, VIRTIO_DEV_ANY_ID },
|
|
+ { 0 },
|
|
+};
|
|
+
|
|
+static const unsigned int features[] = {
|
|
+ /* none */
|
|
+};
|
|
+
|
|
+
|
|
+static struct virtio_driver virtio_transfer = {
|
|
+ .feature_table = features,
|
|
+ .feature_table_size = ARRAY_SIZE(features),
|
|
+ .driver.name = KBUILD_MODNAME,
|
|
+ .driver.owner = THIS_MODULE,
|
|
+ .id_table = id_table,
|
|
+ .probe = virttrans_probe,
|
|
+ .remove = virttrans_remove,
|
|
+ .config_changed = config_intr,
|
|
+};
|
|
+
|
|
+static int __init virtio_transfer_init(void)
|
|
+{
|
|
+ int err;
|
|
+
|
|
+ err = register_virtio_driver(&virtio_transfer);
|
|
+ if (err < 0) {
|
|
+ pr_err("Failed to register virtio driver\n");
|
|
+ return err;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void __exit virtio_transfer_exit(void)
|
|
+{
|
|
+ unregister_virtio_driver(&virtio_transfer);
|
|
+}
|
|
+
|
|
+module_init(virtio_transfer_init);
|
|
+module_exit(virtio_transfer_exit);
|
|
+
|
|
+MODULE_DEVICE_TABLE(virtio, id_table);
|
|
+MODULE_DESCRIPTION("VirtIO transfer test driver");
|
|
+MODULE_LICENSE("GPL");
|
|
diff --git a/fs/proc/consoles.c b/fs/proc/consoles.c
|
|
index e0758fe7936d..2703676549f5 100644
|
|
--- a/fs/proc/consoles.c
|
|
+++ b/fs/proc/consoles.c
|
|
@@ -21,12 +21,14 @@ static int show_console_dev(struct seq_file *m, void *v)
|
|
{ CON_ENABLED, 'E' },
|
|
{ CON_CONSDEV, 'C' },
|
|
{ CON_BOOT, 'B' },
|
|
+ { CON_NBCON, 'N' },
|
|
{ CON_PRINTBUFFER, 'p' },
|
|
{ CON_BRL, 'b' },
|
|
{ CON_ANYTIME, 'a' },
|
|
};
|
|
char flags[ARRAY_SIZE(con_flags) + 1];
|
|
struct console *con = v;
|
|
+ char con_write = '-';
|
|
unsigned int a;
|
|
dev_t dev = 0;
|
|
|
|
@@ -57,9 +59,15 @@ static int show_console_dev(struct seq_file *m, void *v)
|
|
seq_setwidth(m, 21 - 1);
|
|
seq_printf(m, "%s%d", con->name, con->index);
|
|
seq_pad(m, ' ');
|
|
- seq_printf(m, "%c%c%c (%s)", con->read ? 'R' : '-',
|
|
- con->write ? 'W' : '-', con->unblank ? 'U' : '-',
|
|
- flags);
|
|
+ if (con->flags & CON_NBCON) {
|
|
+ if (con->write_atomic || con->write_thread)
|
|
+ con_write = 'W';
|
|
+ } else {
|
|
+ if (con->write)
|
|
+ con_write = 'W';
|
|
+ }
|
|
+ seq_printf(m, "%c%c%c (%s)", con->read ? 'R' : '-', con_write,
|
|
+ con->unblank ? 'U' : '-', flags);
|
|
if (dev)
|
|
seq_printf(m, " %4d:%d", MAJOR(dev), MINOR(dev));
|
|
|
|
diff --git a/include/dt-bindings/clock/imx8-clock.h b/include/dt-bindings/clock/imx8-clock.h
|
|
index 940b408fb5ca..ef9bc8c8a80f 100644
|
|
--- a/include/dt-bindings/clock/imx8-clock.h
|
|
+++ b/include/dt-bindings/clock/imx8-clock.h
|
|
@@ -37,4 +37,14 @@
|
|
|
|
#define IMX_ADMA_ACM_CLK_END 25
|
|
|
|
+/* ACM GPT Event Mux Control Register Offset */
|
|
+#define IMX_ADMA_ACM_GPT0_CAPIN1_SEL 0x80004
|
|
+#define IMX_ADMA_ACM_GPT0_CAPIN2_SEL 0x80008
|
|
+#define IMX_ADMA_ACM_GPT1_CAPIN1_SEL 0x90004
|
|
+#define IMX_ADMA_ACM_GPT1_CAPIN2_SEL 0x90008
|
|
+
|
|
+/* ACM GPT Event Mux Select Control */
|
|
+#define IMX_ADMA_ACM_GPT_EVENT_INPUT_ETH0 3
|
|
+#define IMX_ADMA_ACM_GPT_EVENT_INPUT_ETH1 4
|
|
+
|
|
#endif /* __DT_BINDINGS_CLOCK_IMX_H */
|
|
diff --git a/include/dt-bindings/rpmsg/imx_srtm.h b/include/dt-bindings/rpmsg/imx_srtm.h
|
|
new file mode 100644
|
|
index 000000000000..644ab9ceb407
|
|
--- /dev/null
|
|
+++ b/include/dt-bindings/rpmsg/imx_srtm.h
|
|
@@ -0,0 +1,20 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef _DT_BINDINGS_RPMSG_IMX_SRTM_H
|
|
+#define _DT_BINDINGS_RPMSG_IMX_SRTM_H
|
|
+
|
|
+/* Bit 0 as RPMSG Over UART flag */
|
|
+#define IMX_SRTM_RPMSG_OVER_UART_FLAG (1 << 0)
|
|
+#define IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG (1 << 1)
|
|
+/* [15:11]: port number, such as /dev/ttySRTM3, 3 is the port number */
|
|
+#define IMX_SRTM_UART_PORT_NUM_SHIFT (11U)
|
|
+#define IMX_SRTM_UART_PORT_NUM_MASK (0x1F << 11U)
|
|
+/* [10]: 0b1, specify port number; 0b0, not specify port number */
|
|
+#define IMX_SRTM_UART_SPECIFY_PORT_NUM_SHIFT (10U)
|
|
+#define IMX_SRTM_UART_SPECIFY_PORT_NUM_MASK (1 << IMX_SRTM_UART_SPECIFY_PORT_NUM_SHIFT)
|
|
+
|
|
+#endif
|
|
diff --git a/include/linux/bottom_half.h b/include/linux/bottom_half.h
|
|
index fc53e0ad56d9..448bbef47456 100644
|
|
--- a/include/linux/bottom_half.h
|
|
+++ b/include/linux/bottom_half.h
|
|
@@ -35,8 +35,10 @@ static inline void local_bh_enable(void)
|
|
|
|
#ifdef CONFIG_PREEMPT_RT
|
|
extern bool local_bh_blocked(void);
|
|
+extern void softirq_preempt(void);
|
|
#else
|
|
static inline bool local_bh_blocked(void) { return false; }
|
|
+static inline void softirq_preempt(void) { }
|
|
#endif
|
|
|
|
#endif /* _LINUX_BH_H */
|
|
diff --git a/include/linux/clk/imx-pll.h b/include/linux/clk/imx-pll.h
|
|
new file mode 100644
|
|
index 000000000000..9759ca15a6cc
|
|
--- /dev/null
|
|
+++ b/include/linux/clk/imx-pll.h
|
|
@@ -0,0 +1,26 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2018 NXP
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef __LINUX_CLK_IMX_PLL_H__
|
|
+#define __LINUX_CLK_IMX_PLL_H__
|
|
+
|
|
+enum clk_imx_pll_error {
|
|
+ IMX_CLK_PLL_SUCCESS = 0,
|
|
+ IMX_CLK_PLL_INVALID_PARAM,
|
|
+ IMX_CLK_PLL_PREC_ERR,
|
|
+ IMX_CLK_PLL_LOCK_ERR,
|
|
+};
|
|
+
|
|
+struct clk_imx_pll;
|
|
+
|
|
+struct clk_imx_pll *clk_imx_pll_get_by_name(const char *name);
|
|
+int clk_imx_pll_adjust(struct clk_imx_pll *pll, int *ppb);
|
|
+unsigned long clk_imx_pll_get_rate(struct clk_imx_pll *pll,
|
|
+ unsigned long parent_rate);
|
|
+int clk_imx_pll_set_rate(struct clk_imx_pll *pll, unsigned long rate,
|
|
+ unsigned long parent_rate);
|
|
+
|
|
+#endif /*__LINUX_CLK_IMX_PLL_H__*/
|
|
diff --git a/include/linux/console.h b/include/linux/console.h
|
|
index 7de11c763eb3..1eb9580e9b18 100644
|
|
--- a/include/linux/console.h
|
|
+++ b/include/linux/console.h
|
|
@@ -16,7 +16,9 @@
|
|
|
|
#include <linux/atomic.h>
|
|
#include <linux/bits.h>
|
|
+#include <linux/irq_work.h>
|
|
#include <linux/rculist.h>
|
|
+#include <linux/rcuwait.h>
|
|
#include <linux/types.h>
|
|
|
|
struct vc_data;
|
|
@@ -156,6 +158,8 @@ static inline int con_debug_leave(void)
|
|
* /dev/kmesg which requires a larger output buffer.
|
|
* @CON_SUSPENDED: Indicates if a console is suspended. If true, the
|
|
* printing callbacks must not be called.
|
|
+ * @CON_NBCON: Console can operate outside of the legacy style console_lock
|
|
+ * constraints.
|
|
*/
|
|
enum cons_flags {
|
|
CON_PRINTBUFFER = BIT(0),
|
|
@@ -166,6 +170,111 @@ enum cons_flags {
|
|
CON_BRL = BIT(5),
|
|
CON_EXTENDED = BIT(6),
|
|
CON_SUSPENDED = BIT(7),
|
|
+ CON_NBCON = BIT(8),
|
|
+};
|
|
+
|
|
+/**
|
|
+ * struct nbcon_state - console state for nbcon consoles
|
|
+ * @atom: Compound of the state fields for atomic operations
|
|
+ *
|
|
+ * @req_prio: The priority of a handover request
|
|
+ * @prio: The priority of the current owner
|
|
+ * @unsafe: Console is busy in a non takeover region
|
|
+ * @unsafe_takeover: A hostile takeover in an unsafe state happened in the
|
|
+ * past. The console cannot be safe until re-initialized.
|
|
+ * @cpu: The CPU on which the owner runs
|
|
+ *
|
|
+ * To be used for reading and preparing of the value stored in the nbcon
|
|
+ * state variable @console::nbcon_state.
|
|
+ *
|
|
+ * The @prio and @req_prio fields are particularly important to allow
|
|
+ * spin-waiting to timeout and give up without the risk of a waiter being
|
|
+ * assigned the lock after giving up.
|
|
+ */
|
|
+struct nbcon_state {
|
|
+ union {
|
|
+ unsigned int atom;
|
|
+ struct {
|
|
+ unsigned int prio : 2;
|
|
+ unsigned int req_prio : 2;
|
|
+ unsigned int unsafe : 1;
|
|
+ unsigned int unsafe_takeover : 1;
|
|
+ unsigned int cpu : 24;
|
|
+ };
|
|
+ };
|
|
+};
|
|
+
|
|
+/*
|
|
+ * The nbcon_state struct is used to easily create and interpret values that
|
|
+ * are stored in the @console::nbcon_state variable. Ensure this struct stays
|
|
+ * within the size boundaries of the atomic variable's underlying type in
|
|
+ * order to avoid any accidental truncation.
|
|
+ */
|
|
+static_assert(sizeof(struct nbcon_state) <= sizeof(int));
|
|
+
|
|
+/**
|
|
+ * nbcon_prio - console owner priority for nbcon consoles
|
|
+ * @NBCON_PRIO_NONE: Unused
|
|
+ * @NBCON_PRIO_NORMAL: Normal (non-emergency) usage
|
|
+ * @NBCON_PRIO_EMERGENCY: Emergency output (WARN/OOPS...)
|
|
+ * @NBCON_PRIO_PANIC: Panic output
|
|
+ * @NBCON_PRIO_MAX: The number of priority levels
|
|
+ *
|
|
+ * A higher priority context can takeover the console when it is
|
|
+ * in the safe state. The final attempt to flush consoles in panic()
|
|
+ * can be allowed to do so even in an unsafe state (Hope and pray).
|
|
+ */
|
|
+enum nbcon_prio {
|
|
+ NBCON_PRIO_NONE = 0,
|
|
+ NBCON_PRIO_NORMAL,
|
|
+ NBCON_PRIO_EMERGENCY,
|
|
+ NBCON_PRIO_PANIC,
|
|
+ NBCON_PRIO_MAX,
|
|
+};
|
|
+
|
|
+struct console;
|
|
+struct printk_buffers;
|
|
+
|
|
+/**
|
|
+ * struct nbcon_context - Context for console acquire/release
|
|
+ * @console: The associated console
|
|
+ * @spinwait_max_us: Limit for spin-wait acquire
|
|
+ * @prio: Priority of the context
|
|
+ * @allow_unsafe_takeover: Allow performing takeover even if unsafe. Can
|
|
+ * be used only with NBCON_PRIO_PANIC @prio. It
|
|
+ * might cause a system freeze when the console
|
|
+ * is used later.
|
|
+ * @backlog: Ringbuffer has pending records
|
|
+ * @pbufs: Pointer to the text buffer for this context
|
|
+ * @seq: The sequence number to print for this context
|
|
+ */
|
|
+struct nbcon_context {
|
|
+ /* members set by caller */
|
|
+ struct console *console;
|
|
+ unsigned int spinwait_max_us;
|
|
+ enum nbcon_prio prio;
|
|
+ unsigned int allow_unsafe_takeover : 1;
|
|
+
|
|
+ /* members set by emit */
|
|
+ unsigned int backlog : 1;
|
|
+
|
|
+ /* members set by acquire */
|
|
+ struct printk_buffers *pbufs;
|
|
+ u64 seq;
|
|
+};
|
|
+
|
|
+/**
|
|
+ * struct nbcon_write_context - Context handed to the nbcon write callbacks
|
|
+ * @ctxt: The core console context
|
|
+ * @outbuf: Pointer to the text buffer for output
|
|
+ * @len: Length to write
|
|
+ * @unsafe_takeover: If a hostile takeover in an unsafe state has occurred
|
|
+ */
|
|
+struct nbcon_write_context {
|
|
+ struct nbcon_context __private ctxt;
|
|
+ char *outbuf;
|
|
+ unsigned int len;
|
|
+ bool unsafe_takeover;
|
|
};
|
|
|
|
/**
|
|
@@ -187,6 +296,17 @@ enum cons_flags {
|
|
* @dropped: Number of unreported dropped ringbuffer records
|
|
* @data: Driver private data
|
|
* @node: hlist node for the console list
|
|
+ *
|
|
+ * @write_atomic: Write callback for atomic context
|
|
+ * @write_thread: Write callback for non-atomic context
|
|
+ * @driver_enter: Callback to begin synchronization with driver code
|
|
+ * @driver_exit: Callback to finish synchronization with driver code
|
|
+ * @nbcon_state: State for nbcon consoles
|
|
+ * @nbcon_seq: Sequence number of the next record for nbcon to print
|
|
+ * @pbufs: Pointer to nbcon private buffer
|
|
+ * @kthread: Printer kthread for this console
|
|
+ * @rcuwait: RCU-safe wait object for @kthread waking
|
|
+ * @irq_work: Defer @kthread waking to IRQ work context
|
|
*/
|
|
struct console {
|
|
char name[16];
|
|
@@ -206,6 +326,20 @@ struct console {
|
|
unsigned long dropped;
|
|
void *data;
|
|
struct hlist_node node;
|
|
+
|
|
+ /* nbcon console specific members */
|
|
+ bool (*write_atomic)(struct console *con,
|
|
+ struct nbcon_write_context *wctxt);
|
|
+ bool (*write_thread)(struct console *con,
|
|
+ struct nbcon_write_context *wctxt);
|
|
+ void (*driver_enter)(struct console *con, unsigned long *flags);
|
|
+ void (*driver_exit)(struct console *con, unsigned long flags);
|
|
+ atomic_t __private nbcon_state;
|
|
+ atomic_long_t __private nbcon_seq;
|
|
+ struct printk_buffers *pbufs;
|
|
+ struct task_struct *kthread;
|
|
+ struct rcuwait rcuwait;
|
|
+ struct irq_work irq_work;
|
|
};
|
|
|
|
#ifdef CONFIG_LOCKDEP
|
|
@@ -332,6 +466,22 @@ static inline bool console_is_registered(const struct console *con)
|
|
lockdep_assert_console_list_lock_held(); \
|
|
hlist_for_each_entry(con, &console_list, node)
|
|
|
|
+#ifdef CONFIG_PRINTK
|
|
+extern void nbcon_cpu_emergency_enter(void);
|
|
+extern void nbcon_cpu_emergency_exit(void);
|
|
+extern bool nbcon_can_proceed(struct nbcon_write_context *wctxt);
|
|
+extern bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt);
|
|
+extern bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt);
|
|
+extern void nbcon_reacquire(struct nbcon_write_context *wctxt);
|
|
+#else
|
|
+static inline void nbcon_cpu_emergency_enter(void) { }
|
|
+static inline void nbcon_cpu_emergency_exit(void) { }
|
|
+static inline bool nbcon_can_proceed(struct nbcon_write_context *wctxt) { return false; }
|
|
+static inline bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt) { return false; }
|
|
+static inline bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt) { return false; }
|
|
+static inline void nbcon_reacquire(struct nbcon_write_context *wctxt) { }
|
|
+#endif
|
|
+
|
|
extern int console_set_on_cmdline;
|
|
extern struct console *early_console;
|
|
|
|
diff --git a/include/linux/dsa/netc.h b/include/linux/dsa/netc.h
|
|
new file mode 100644
|
|
index 000000000000..adafcf70ebf1
|
|
--- /dev/null
|
|
+++ b/include/linux/dsa/netc.h
|
|
@@ -0,0 +1,69 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#ifndef _NET_DSA_NETC_H
|
|
+#define _NET_DSA_NETC_H
|
|
+
|
|
+#include <linux/kthread.h>
|
|
+#include <linux/skbuff.h>
|
|
+#include <linux/dsa/8021q.h>
|
|
+#include <net/dsa.h>
|
|
+
|
|
+#define ETH_P_NETC 0x88A8
|
|
+#define ETH_P_NETC_META 0xDADC
|
|
+#define ETH_P_NETC_8021Q ETH_P_8021Q
|
|
+
|
|
+#define NETC_DEFAULT_VLAN 1
|
|
+
|
|
+#define IFH_TAG_TYPE_C 0
|
|
+#define IFH_TAG_TYPE_S 1
|
|
+
|
|
+/* IEEE 802.3 Annex 57A: Slow Protocols PDUs (01:80:C2:xx:xx:xx) */
|
|
+#define NETC_LINKLOCAL_FILTER_A 0x0180C2000000ull
|
|
+#define NETC_LINKLOCAL_FILTER_A_MASK 0xFFFFFF000000ull
|
|
+/* IEEE 1588 Annex F: Transport of PTP over Ethernet (01:1B:19:xx:xx:xx) */
|
|
+#define NETC_LINKLOCAL_FILTER_B 0x011B19000000ull
|
|
+#define NETC_LINKLOCAL_FILTER_B_MASK 0xFFFFFF000000ull
|
|
+
|
|
+/* Source and Destination MAC of follow-up meta frames.
|
|
+ * Whereas the choice of SMAC only affects the unique identification of the
|
|
+ * switch as sender of meta frames, the DMAC must be an address that is present
|
|
+ * in the DSA master port's multicast MAC filter.
|
|
+ * 01-80-C2-00-00-0E is a good choice for this, as all profiles of IEEE 1588
|
|
+ * over L2 use this address for some purpose already.
|
|
+ */
|
|
+#define NETC_META_SMAC 0x222222222222ull
|
|
+#define NETC_META_DMAC 0x0180C200000Eull
|
|
+
|
|
+struct netc_deferred_xmit_work {
|
|
+ struct dsa_port *dp;
|
|
+ struct sk_buff *skb;
|
|
+ struct kthread_work work;
|
|
+};
|
|
+
|
|
+struct netc_skb_cb {
|
|
+ struct sk_buff *clone;
|
|
+ u64 tstamp;
|
|
+ u32 ts_id;
|
|
+};
|
|
+
|
|
+#define NETC_SKB_CB(skb) \
|
|
+ ((struct netc_skb_cb *)((skb)->cb))
|
|
+
|
|
+struct netc_tagger_data {
|
|
+ void (*meta_tstamp_handler)(struct dsa_switch *ds, int port,
|
|
+ u32 ts_id, u64 tstamp);
|
|
+ void (*meta_cmd_handler)(struct dsa_switch *ds, int port,
|
|
+ void *buf, size_t len);
|
|
+};
|
|
+
|
|
+static inline struct netc_tagger_data *
|
|
+netc_tagger_data(struct dsa_switch *ds)
|
|
+{
|
|
+ WARN_ON_ONCE(ds->dst->tag_ops->proto != DSA_TAG_PROTO_NETC);
|
|
+ return ds->tagger_data;
|
|
+}
|
|
+
|
|
+#endif /* _NET_DSA_NETC_H */
|
|
diff --git a/include/linux/dsa/sja1105.h b/include/linux/dsa/sja1105.h
|
|
index c177322f793d..31779f9bc92b 100644
|
|
--- a/include/linux/dsa/sja1105.h
|
|
+++ b/include/linux/dsa/sja1105.h
|
|
@@ -35,6 +35,8 @@
|
|
#define SJA1105_META_SMAC 0x222222222222ull
|
|
#define SJA1105_META_DMAC 0x0180C200000Eull
|
|
|
|
+#define SJA1105_MAX_NUM_PCP 8
|
|
+
|
|
enum sja1110_meta_tstamp {
|
|
SJA1110_META_TSTAMP_TX = 0,
|
|
SJA1110_META_TSTAMP_RX = 1,
|
|
diff --git a/include/linux/entry-common.h b/include/linux/entry-common.h
|
|
index d95ab85f96ba..8b3ab0cc1334 100644
|
|
--- a/include/linux/entry-common.h
|
|
+++ b/include/linux/entry-common.h
|
|
@@ -60,7 +60,7 @@
|
|
#define EXIT_TO_USER_MODE_WORK \
|
|
(_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_UPROBE | \
|
|
_TIF_NEED_RESCHED | _TIF_PATCH_PENDING | _TIF_NOTIFY_SIGNAL | \
|
|
- ARCH_EXIT_TO_USER_MODE_WORK)
|
|
+ _TIF_NEED_RESCHED_LAZY | ARCH_EXIT_TO_USER_MODE_WORK)
|
|
|
|
/**
|
|
* arch_enter_from_user_mode - Architecture specific sanity check for user mode regs
|
|
diff --git a/include/linux/entry-kvm.h b/include/linux/entry-kvm.h
|
|
index 6813171afccb..674a622c91be 100644
|
|
--- a/include/linux/entry-kvm.h
|
|
+++ b/include/linux/entry-kvm.h
|
|
@@ -18,7 +18,7 @@
|
|
|
|
#define XFER_TO_GUEST_MODE_WORK \
|
|
(_TIF_NEED_RESCHED | _TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL | \
|
|
- _TIF_NOTIFY_RESUME | ARCH_XFER_TO_GUEST_MODE_WORK)
|
|
+ _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED_LAZY | ARCH_XFER_TO_GUEST_MODE_WORK)
|
|
|
|
struct kvm_vcpu;
|
|
|
|
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
|
|
index 8d497be66da8..8543e5ffea39 100644
|
|
--- a/include/linux/ethtool.h
|
|
+++ b/include/linux/ethtool.h
|
|
@@ -752,6 +752,8 @@ struct ethtool_mm_stats {
|
|
* @get_ethtool_phy_stats: Return extended statistics about the PHY device.
|
|
* This is only useful if the device maintains PHY statistics and
|
|
* cannot use the standard PHY library helpers.
|
|
+ * @get_preempt: Get the network device Frame Preemption parameters.
|
|
+ * @set_preempt: Set the network device Frame Preemption parameters.
|
|
* @get_phy_tunable: Read the value of a PHY tunable.
|
|
* @set_phy_tunable: Set the value of a PHY tunable.
|
|
* @get_module_eeprom_by_page: Get a region of plug-in module EEPROM data from
|
|
@@ -884,6 +886,11 @@ struct ethtool_ops {
|
|
struct ethtool_fecparam *);
|
|
int (*set_fecparam)(struct net_device *,
|
|
struct ethtool_fecparam *);
|
|
+ int (*get_preempt)(struct net_device *,
|
|
+ struct ethtool_fp *);
|
|
+ int (*set_preempt)(struct net_device *,
|
|
+ struct ethtool_fp *);
|
|
+ int (*reset_preempt)(struct net_device *, bool enable);
|
|
void (*get_ethtool_phy_stats)(struct net_device *,
|
|
struct ethtool_stats *, u64 *);
|
|
int (*get_phy_tunable)(struct net_device *,
|
|
diff --git a/include/linux/fec.h b/include/linux/fec.h
|
|
index 9aaf53f07269..11f1d8bd6290 100644
|
|
--- a/include/linux/fec.h
|
|
+++ b/include/linux/fec.h
|
|
@@ -19,4 +19,124 @@ struct fec_platform_data {
|
|
void (*sleep_mode_enable)(int enabled);
|
|
};
|
|
|
|
+/* The number of Tx and Rx buffers. These are allocated from the page
|
|
+ * pool. The code may assume these are power of two, so it it best
|
|
+ * to keep them that size.
|
|
+ * We don't need to allocate pages for the transmitter. We just use
|
|
+ * the skbuffer directly.
|
|
+ */
|
|
+
|
|
+#define FEC_ENET_XDP_HEADROOM (XDP_PACKET_HEADROOM)
|
|
+#define FEC_ENET_RX_PAGES 256
|
|
+#define FEC_ENET_RX_FRSIZE (PAGE_SIZE - FEC_ENET_XDP_HEADROOM \
|
|
+ - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
|
|
+#define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE)
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+#define FEC_RX_RING_SIZE 256
|
|
+#define FEC_ENET_AVB_RX_FRSIZE 1522
|
|
+#else
|
|
+#define FEC_RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES)
|
|
+#endif
|
|
+#define FEC_ENET_TX_FRSIZE 2048
|
|
+#define FEC_ENET_TX_FRPPG (PAGE_SIZE / FEC_ENET_TX_FRSIZE)
|
|
+
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+#define FEC_TX_RING_SIZE 256 /* Must be power of two */
|
|
+#else
|
|
+#define FEC_TX_RING_SIZE 1024 /* Must be power of two */
|
|
+#endif
|
|
+
|
|
+#ifdef CONFIG_AVB_SUPPORT
|
|
+struct avb_desc {
|
|
+ u16 offset;
|
|
+ u16 len;
|
|
+ u32 ts;
|
|
+ u32 flags:28;
|
|
+ u32 pool_type:4;
|
|
+ u32 private; /* Will be used for saving userspace private value on TX and esc hw descriptor value on RX */
|
|
+};
|
|
+
|
|
+struct avb_tx_desc {
|
|
+ struct avb_desc common;
|
|
+
|
|
+ unsigned long dma_addr;
|
|
+ void *data;
|
|
+ u32 esc;
|
|
+ unsigned short queue_id;
|
|
+ unsigned short sc;
|
|
+ unsigned long bufaddr;
|
|
+ unsigned short datlen;
|
|
+};
|
|
+
|
|
+struct avb_rx_desc {
|
|
+ struct avb_desc common;
|
|
+
|
|
+ /* end of common rx fields */
|
|
+ unsigned long dma_addr;
|
|
+ unsigned short sc; /* Control and status info */
|
|
+ unsigned short queue_id;
|
|
+};
|
|
+
|
|
+#define AVB_WAKE_THREAD (1 << 0)
|
|
+#define AVB_WAKE_NAPI (1 << 1)
|
|
+
|
|
+#define AVB_TX_FLAG_SKB (1 << 0)
|
|
+#define AVB_TX_FLAG_HW_TS (1 << 1)
|
|
+#define AVB_TX_FLAG_HW_CSUM (1 << 2)
|
|
+#define AVB_TX_FLAG_TS (1 << 3)
|
|
+
|
|
+struct avb_ops {
|
|
+ void (*open)(void *, void *, int);
|
|
+ void (*close)(void *);
|
|
+
|
|
+ void * (*alloc)(void *);
|
|
+ void (*free)(void *, struct avb_desc *);
|
|
+
|
|
+ int (*rx)(void *, struct avb_rx_desc *);
|
|
+ void * (*dequeue)(void *);
|
|
+
|
|
+ int (*tx)(void *, struct avb_tx_desc *);
|
|
+ int (*tx_full)(void *);
|
|
+
|
|
+ int (*tx_cleanup)(void *, struct avb_tx_desc *);
|
|
+ int (*tx_cleanup_ready)(void *);
|
|
+ void * (*tx_cleanup_dequeue)(void *);
|
|
+
|
|
+ int (*tx_ts)(void *, struct avb_desc *);
|
|
+
|
|
+ struct module *owner;
|
|
+};
|
|
+
|
|
+#define TX_QUEUE_FLAGS_STRICT_PRIORITY BIT(0)
|
|
+#define TX_QUEUE_FLAGS_CREDIT_SHAPER BIT(1)
|
|
+
|
|
+#define TX_QUEUE_PROP_MAX 8
|
|
+
|
|
+struct tx_queue_property {
|
|
+ unsigned int priority;
|
|
+ unsigned int flags;
|
|
+};
|
|
+
|
|
+struct tx_queue_properties {
|
|
+ int num_queues;
|
|
+ struct tx_queue_property queue[TX_QUEUE_PROP_MAX];
|
|
+};
|
|
+
|
|
+int fec_enet_get_tx_queue_properties(int ifindex, struct tx_queue_properties *prop);
|
|
+int fec_enet_set_idle_slope(void *data, unsigned int queue_id, u32 idle_slope);
|
|
+int fec_enet_avb_register(const char *ifname, const struct avb_ops *avb, void *data);
|
|
+struct device *fec_enet_avb_get_device(const char *ifname);
|
|
+int fec_enet_avb_unregister(int ifindex, const struct avb_ops *avb);
|
|
+int fec_enet_rx_poll_avb(void *data);
|
|
+int fec_enet_start_xmit_avb(void *data, struct avb_tx_desc *desc);
|
|
+void fec_enet_finish_xmit_avb(void *data, unsigned int queue_id);
|
|
+int fec_enet_tx_avb(void *data);
|
|
+
|
|
+int fec_ptp_read_cnt(void *data, u32 *cnt);
|
|
+int fec_ptp_tc_start(void *data, u8 id, u32 ts_0, u32 ts_1, u32 tcsr_val);
|
|
+void fec_ptp_tc_stop(void *data, u8 id);
|
|
+int fec_ptp_tc_reload(void *data, u8 id, u32 ts);
|
|
+
|
|
+#endif
|
|
+
|
|
#endif
|
|
diff --git a/include/linux/fsl_qman.h b/include/linux/fsl_qman.h
|
|
index fd6b8a255969..ee2afdfa6f8c 100644
|
|
--- a/include/linux/fsl_qman.h
|
|
+++ b/include/linux/fsl_qman.h
|
|
@@ -1,4 +1,5 @@
|
|
/* Copyright 2008-2012 Freescale Semiconductor, Inc.
|
|
+ * Copyright 2019-2023 NXP
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
@@ -2125,6 +2126,9 @@ const cpumask_t *qman_affine_cpus(void);
|
|
* member of the mask returned from qman_affine_cpus().
|
|
*/
|
|
u16 qman_affine_channel(int cpu);
|
|
+#ifdef CONFIG_FSL_DPAA_ETHERCAT
|
|
+u16 qman_affine_channel_ethercat(int cpu);
|
|
+#endif
|
|
|
|
/**
|
|
* qman_get_affine_portal - return the portal pointer affine to cpu
|
|
@@ -2132,6 +2136,10 @@ u16 qman_affine_channel(int cpu);
|
|
*
|
|
*/
|
|
void *qman_get_affine_portal(int cpu);
|
|
+#ifdef CONFIG_FSL_DPAA_ETHERCAT
|
|
+void *qman_get_affine_portal_ethercat(int cpu);
|
|
+u32 qman_get_affine_last_cpu(void);
|
|
+#endif
|
|
|
|
/**
|
|
* qman_poll_dqrr - process DQRR (fast-path) entries
|
|
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
|
|
index 4a1dc88ddbff..a5091ac97fc6 100644
|
|
--- a/include/linux/interrupt.h
|
|
+++ b/include/linux/interrupt.h
|
|
@@ -609,6 +609,35 @@ extern void __raise_softirq_irqoff(unsigned int nr);
|
|
extern void raise_softirq_irqoff(unsigned int nr);
|
|
extern void raise_softirq(unsigned int nr);
|
|
|
|
+#ifdef CONFIG_PREEMPT_RT
|
|
+DECLARE_PER_CPU(struct task_struct *, timersd);
|
|
+DECLARE_PER_CPU(unsigned long, pending_timer_softirq);
|
|
+
|
|
+extern void raise_timer_softirq(void);
|
|
+extern void raise_hrtimer_softirq(void);
|
|
+
|
|
+static inline unsigned int local_pending_timers(void)
|
|
+{
|
|
+ return __this_cpu_read(pending_timer_softirq);
|
|
+}
|
|
+
|
|
+#else
|
|
+static inline void raise_timer_softirq(void)
|
|
+{
|
|
+ raise_softirq(TIMER_SOFTIRQ);
|
|
+}
|
|
+
|
|
+static inline void raise_hrtimer_softirq(void)
|
|
+{
|
|
+ raise_softirq_irqoff(HRTIMER_SOFTIRQ);
|
|
+}
|
|
+
|
|
+static inline unsigned int local_pending_timers(void)
|
|
+{
|
|
+ return local_softirq_pending();
|
|
+}
|
|
+#endif
|
|
+
|
|
DECLARE_PER_CPU(struct task_struct *, ksoftirqd);
|
|
|
|
static inline struct task_struct *this_cpu_ksoftirqd(void)
|
|
diff --git a/include/linux/ipi_baremetal.h b/include/linux/ipi_baremetal.h
|
|
new file mode 100644
|
|
index 000000000000..5f124be40dcc
|
|
--- /dev/null
|
|
+++ b/include/linux/ipi_baremetal.h
|
|
@@ -0,0 +1,27 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * include/linux/ipi_baremetal.h
|
|
+ *
|
|
+ * Copyright 2018-2023 NXP
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifndef __LINUX_IPI_BAREMETAL_H
|
|
+#define __LINUX_IPI_BAREMETAL_H
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+
|
|
+#if defined(CONFIG_LS1021A_BAREMETAL) || \
|
|
+ defined(CONFIG_LS1028A_BAREMETAL) || \
|
|
+ defined(CONFIG_IMX93_BAREMETAL)
|
|
+#define CONFIG_MAX_CPUS 2
|
|
+#elif defined(CONFIG_IMX8M_BAREMETAL)
|
|
+#define CONFIG_MAX_CPUS 4
|
|
+#elif defined(CONFIG_LX2160A_BAREMETAL)
|
|
+#define CONFIG_MAX_CPUS 16
|
|
+#else
|
|
+#define CONFIG_MAX_CPUS 4
|
|
+#endif
|
|
+
|
|
+int ipi_baremetal_handle(u32 irqnr, u32 irqsrc);
|
|
+#endif /* !__LINUX_IPI_BAREMETAL_H */
|
|
diff --git a/include/linux/net.h b/include/linux/net.h
|
|
index c9b4a63791a4..57bcc0e9bf65 100644
|
|
--- a/include/linux/net.h
|
|
+++ b/include/linux/net.h
|
|
@@ -126,6 +126,8 @@ struct socket {
|
|
const struct proto_ops *ops; /* Might change with IPV6_ADDRFORM or MPTCP. */
|
|
|
|
struct socket_wq wq;
|
|
+
|
|
+ struct net_device *ndev;
|
|
};
|
|
|
|
/*
|
|
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
|
|
index b8e60a20416b..2b45c8fdafb9 100644
|
|
--- a/include/linux/netdevice.h
|
|
+++ b/include/linux/netdevice.h
|
|
@@ -346,6 +346,8 @@ struct gro_list {
|
|
*/
|
|
#define GRO_HASH_BUCKETS 8
|
|
|
|
+
|
|
+#define NAPINAMSIZ 8
|
|
/*
|
|
* Structure for NAPI scheduling similar to tasklet but with weighting
|
|
*/
|
|
@@ -380,6 +382,7 @@ struct napi_struct {
|
|
/* control-path-only fields follow */
|
|
struct list_head dev_list;
|
|
struct hlist_node napi_hash_node;
|
|
+ char name[NAPINAMSIZ];
|
|
};
|
|
|
|
enum {
|
|
@@ -1414,6 +1417,9 @@ struct net_device_ops {
|
|
int (*ndo_stop)(struct net_device *dev);
|
|
netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb,
|
|
struct net_device *dev);
|
|
+ struct sk_buff* (*ndo_start_recv)(struct net_device *dev, int *err);
|
|
+ int (*ndo_fast_recv)(struct net_device *ndev, void __user *buff, size_t len, struct sockaddr __user *addr, int __user *addr_len);
|
|
+ int (*ndo_fast_xmit)(struct net_device *ndev, void __user *buff, size_t len);
|
|
netdev_features_t (*ndo_features_check)(struct sk_buff *skb,
|
|
struct net_device *dev,
|
|
netdev_features_t features);
|
|
@@ -2076,6 +2082,8 @@ struct net_device {
|
|
unsigned long mem_start;
|
|
unsigned long base_addr;
|
|
|
|
+ unsigned int fast_raw_device;
|
|
+
|
|
/*
|
|
* Some hardware also needs these fields (state,dev_list,
|
|
* napi_list,unreg_list,close_list) but they are not
|
|
@@ -2599,6 +2607,21 @@ void dev_net_set(struct net_device *dev, struct net *net)
|
|
write_pnet(&dev->nd_net, net);
|
|
}
|
|
|
|
+/**
|
|
+ * netif_napi_add_named - initialize a NAPI context
|
|
+ * @dev: network device
|
|
+ * @napi: NAPI context
|
|
+ * @poll: polling function
|
|
+ * @weight: default weight
|
|
+ * @name: napi instance name
|
|
+ *
|
|
+ * netif_napi_add_named() must be used to initialize a NAPI context prior to calling
|
|
+ * *any* of the other NAPI-related functions.
|
|
+ */
|
|
+void netif_napi_add_named(struct net_device *dev, struct napi_struct *napi,
|
|
+ int (*poll)(struct napi_struct *, int), int weight,
|
|
+ const char *name);
|
|
+
|
|
/**
|
|
* netdev_priv - access network device private data
|
|
* @dev: network device
|
|
@@ -2672,6 +2695,27 @@ static inline void netif_napi_add_tx(struct net_device *dev,
|
|
netif_napi_add_tx_weight(dev, napi, poll, NAPI_POLL_WEIGHT);
|
|
}
|
|
|
|
+/**
|
|
+ * netif_napi_add_tx_named - initialize a NAPI context
|
|
+ * @dev: network device
|
|
+ * @napi: NAPI context
|
|
+ * @poll: polling function
|
|
+ * @weight: default weight
|
|
+ * @name: napi instance name
|
|
+ *
|
|
+ * This variant of netif_napi_add_named() should be used from drivers using NAPI
|
|
+ * to exclusively poll a TX queue.
|
|
+ * This will avoid we add it into napi_hash[], thus polluting this hash table.
|
|
+ */
|
|
+static inline void netif_napi_add_tx_named(struct net_device *dev,
|
|
+ struct napi_struct *napi,
|
|
+ int (*poll)(struct napi_struct *, int),
|
|
+ int weight, const char *name)
|
|
+{
|
|
+ set_bit(NAPI_STATE_NO_BUSY_POLL, &napi->state);
|
|
+ netif_napi_add_named(dev, napi, poll, weight, name);
|
|
+}
|
|
+
|
|
/**
|
|
* __netif_napi_del - remove a NAPI context
|
|
* @napi: NAPI context
|
|
@@ -3258,7 +3302,11 @@ struct softnet_data {
|
|
int defer_count;
|
|
int defer_ipi_scheduled;
|
|
struct sk_buff *defer_list;
|
|
+#ifndef CONFIG_PREEMPT_RT
|
|
call_single_data_t defer_csd;
|
|
+#else
|
|
+ struct work_struct defer_work;
|
|
+#endif
|
|
};
|
|
|
|
static inline void input_queue_head_incr(struct softnet_data *sd)
|
|
diff --git a/include/linux/printk.h b/include/linux/printk.h
|
|
index e4878bb58f66..ebebc32e78de 100644
|
|
--- a/include/linux/printk.h
|
|
+++ b/include/linux/printk.h
|
|
@@ -9,6 +9,8 @@
|
|
#include <linux/ratelimit_types.h>
|
|
#include <linux/once_lite.h>
|
|
|
|
+struct uart_port;
|
|
+
|
|
extern const char linux_banner[];
|
|
extern const char linux_proc_banner[];
|
|
|
|
@@ -159,13 +161,16 @@ __printf(1, 2) __cold int _printk_deferred(const char *fmt, ...);
|
|
|
|
extern void __printk_safe_enter(void);
|
|
extern void __printk_safe_exit(void);
|
|
+extern void __printk_deferred_enter(void);
|
|
+extern void __printk_deferred_exit(void);
|
|
+
|
|
/*
|
|
* The printk_deferred_enter/exit macros are available only as a hack for
|
|
* some code paths that need to defer all printk console printing. Interrupts
|
|
* must be disabled for the deferred duration.
|
|
*/
|
|
-#define printk_deferred_enter __printk_safe_enter
|
|
-#define printk_deferred_exit __printk_safe_exit
|
|
+#define printk_deferred_enter() __printk_deferred_enter()
|
|
+#define printk_deferred_exit() __printk_deferred_exit()
|
|
|
|
/*
|
|
* Please don't use printk_ratelimit(), because it shares ratelimiting state
|
|
@@ -192,6 +197,10 @@ void show_regs_print_info(const char *log_lvl);
|
|
extern asmlinkage void dump_stack_lvl(const char *log_lvl) __cold;
|
|
extern asmlinkage void dump_stack(void) __cold;
|
|
void printk_trigger_flush(void);
|
|
+void printk_legacy_allow_panic_sync(void);
|
|
+extern void nbcon_acquire(struct uart_port *up);
|
|
+extern void nbcon_release(struct uart_port *up);
|
|
+void nbcon_atomic_flush_unsafe(void);
|
|
#else
|
|
static inline __printf(1, 0)
|
|
int vprintk(const char *s, va_list args)
|
|
@@ -271,6 +280,23 @@ static inline void dump_stack(void)
|
|
static inline void printk_trigger_flush(void)
|
|
{
|
|
}
|
|
+
|
|
+static inline void printk_legacy_allow_panic_sync(void)
|
|
+{
|
|
+}
|
|
+
|
|
+static inline void nbcon_acquire(struct uart_port *up)
|
|
+{
|
|
+}
|
|
+
|
|
+static inline void nbcon_release(struct uart_port *up)
|
|
+{
|
|
+}
|
|
+
|
|
+static inline void nbcon_atomic_flush_unsafe(void)
|
|
+{
|
|
+}
|
|
+
|
|
#endif
|
|
|
|
#ifdef CONFIG_SMP
|
|
diff --git a/include/linux/rpmsg/imx_srtm.h b/include/linux/rpmsg/imx_srtm.h
|
|
new file mode 100644
|
|
index 000000000000..7c0c53916cce
|
|
--- /dev/null
|
|
+++ b/include/linux/rpmsg/imx_srtm.h
|
|
@@ -0,0 +1,65 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * Copyright 2022-2023 NXP
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
+ * published by the Free Software Foundation.
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * @file linux/rpmsg/imx_srtm.h
|
|
+ *
|
|
+ * @brief Global header file for iMX SRTM (Simplified Real Time Message Application Protocol, base on rpmsg)
|
|
+ *
|
|
+ * @ingroup SRTM
|
|
+ */
|
|
+#ifndef __LINUX_RPMSG_IMX_SRTM_H__
|
|
+#define __LINUX_RPMSG_IMX_SRTM_H__
|
|
+
|
|
+/* Category define */
|
|
+#define IMX_SRTM_CATEGORY_LIFECYCLE (0x1)
|
|
+#define IMX_SRTM_CATEGORY_PMIC (0x2)
|
|
+#define IMX_SRTM_CATEGORY_AUDIO (0x3)
|
|
+#define IMX_SRTM_CATEGORY_KEY (0x4)
|
|
+#define IMX_SRTM_CATEGORY_GPIO (0x5)
|
|
+#define IMX_SRTM_CATEGORY_RTC (0x6)
|
|
+#define IMX_SRTM_CATEGORY_SENSOR (0x7)
|
|
+#define IMX_SRTM_CATEGORY_AUTO (0x8)
|
|
+#define IMX_SRTM_CATEGORY_I2C (0x9)
|
|
+#define IMX_SRTM_CATEGORY_PWM (0xA)
|
|
+#define IMX_SRTM_CATEGORY_UART (0xB)
|
|
+
|
|
+/* srtm version */
|
|
+#define IMX_SRTM_VER_UART (0x0001)
|
|
+
|
|
+/* type */
|
|
+#define IMX_SRTM_TYPE_REQUEST (0)
|
|
+#define IMX_SRTM_TYPE_RESPONSE (1)
|
|
+#define IMX_SRTM_TYPE_NOTIFY (2)
|
|
+
|
|
+/* command */
|
|
+#define IMX_SRTM_UART_COMMAND_SEND (1)
|
|
+#define IMX_SRTM_UART_COMMAND_HELLO (2)
|
|
+
|
|
+/* priority */
|
|
+#define IMX_SRTM_UART_PRIORITY (0x01)
|
|
+
|
|
+/* flags */
|
|
+#define IMX_SRTM_RPMSG_OVER_UART_FLAG (1 << 0)
|
|
+#define IMX_SRTM_UART_SUPPORT_MULTI_UART_MSG_FLAG (1 << 1)
|
|
+#define IMX_SRTM_UART_PORT_NUM_SHIFT (11U)
|
|
+#define IMX_SRTM_UART_PORT_NUM_MASK (0x1F << 11U)
|
|
+#define IMX_SRTM_UART_SPECIFY_PORT_NUM_SHIFT (10U)
|
|
+#define IMX_SRTM_UART_SPECIFY_PORT_NUM_MASK (1 << IMX_SRTM_UART_SPECIFY_PORT_NUM_SHIFT)
|
|
+
|
|
+struct imx_srtm_head {
|
|
+ u8 cate;
|
|
+ u8 major;
|
|
+ u8 minor;
|
|
+ u8 type;
|
|
+ u8 cmd;
|
|
+ u8 reserved[5];
|
|
+} __packed;
|
|
+
|
|
+#endif /* __LINUX_RPMSG_IMX_SRTM_H__ */
|
|
diff --git a/include/linux/sched.h b/include/linux/sched.h
|
|
index 77f01ac385f7..c02fd12b49dc 100644
|
|
--- a/include/linux/sched.h
|
|
+++ b/include/linux/sched.h
|
|
@@ -911,6 +911,9 @@ struct task_struct {
|
|
* ->sched_remote_wakeup gets used, so it can be in this word.
|
|
*/
|
|
unsigned sched_remote_wakeup:1;
|
|
+#ifdef CONFIG_RT_MUTEXES
|
|
+ unsigned sched_rt_mutex:1;
|
|
+#endif
|
|
|
|
/* Bit to tell LSMs we're in execve(): */
|
|
unsigned in_execve:1;
|
|
@@ -1902,6 +1905,7 @@ static inline int dl_task_check_affinity(struct task_struct *p, const struct cpu
|
|
}
|
|
#endif
|
|
|
|
+extern bool task_is_pi_boosted(const struct task_struct *p);
|
|
extern int yield_to(struct task_struct *p, bool preempt);
|
|
extern void set_user_nice(struct task_struct *p, long nice);
|
|
extern int task_prio(const struct task_struct *p);
|
|
@@ -2046,17 +2050,17 @@ static inline void update_tsk_thread_flag(struct task_struct *tsk, int flag,
|
|
update_ti_thread_flag(task_thread_info(tsk), flag, value);
|
|
}
|
|
|
|
-static inline int test_and_set_tsk_thread_flag(struct task_struct *tsk, int flag)
|
|
+static inline bool test_and_set_tsk_thread_flag(struct task_struct *tsk, int flag)
|
|
{
|
|
return test_and_set_ti_thread_flag(task_thread_info(tsk), flag);
|
|
}
|
|
|
|
-static inline int test_and_clear_tsk_thread_flag(struct task_struct *tsk, int flag)
|
|
+static inline bool test_and_clear_tsk_thread_flag(struct task_struct *tsk, int flag)
|
|
{
|
|
return test_and_clear_ti_thread_flag(task_thread_info(tsk), flag);
|
|
}
|
|
|
|
-static inline int test_tsk_thread_flag(struct task_struct *tsk, int flag)
|
|
+static inline bool test_tsk_thread_flag(struct task_struct *tsk, int flag)
|
|
{
|
|
return test_ti_thread_flag(task_thread_info(tsk), flag);
|
|
}
|
|
@@ -2069,9 +2073,11 @@ static inline void set_tsk_need_resched(struct task_struct *tsk)
|
|
static inline void clear_tsk_need_resched(struct task_struct *tsk)
|
|
{
|
|
clear_tsk_thread_flag(tsk,TIF_NEED_RESCHED);
|
|
+ if (IS_ENABLED(CONFIG_PREEMPT_BUILD_AUTO))
|
|
+ clear_tsk_thread_flag(tsk, TIF_NEED_RESCHED_LAZY);
|
|
}
|
|
|
|
-static inline int test_tsk_need_resched(struct task_struct *tsk)
|
|
+static inline bool test_tsk_need_resched(struct task_struct *tsk)
|
|
{
|
|
return unlikely(test_tsk_thread_flag(tsk,TIF_NEED_RESCHED));
|
|
}
|
|
@@ -2252,7 +2258,7 @@ static inline int rwlock_needbreak(rwlock_t *lock)
|
|
|
|
static __always_inline bool need_resched(void)
|
|
{
|
|
- return unlikely(tif_need_resched());
|
|
+ return unlikely(tif_need_resched_lazy() || tif_need_resched());
|
|
}
|
|
|
|
/*
|
|
diff --git a/include/linux/sched/idle.h b/include/linux/sched/idle.h
|
|
index 478084f9105e..719416fe8ddc 100644
|
|
--- a/include/linux/sched/idle.h
|
|
+++ b/include/linux/sched/idle.h
|
|
@@ -63,7 +63,7 @@ static __always_inline bool __must_check current_set_polling_and_test(void)
|
|
*/
|
|
smp_mb__after_atomic();
|
|
|
|
- return unlikely(tif_need_resched());
|
|
+ return unlikely(need_resched());
|
|
}
|
|
|
|
static __always_inline bool __must_check current_clr_polling_and_test(void)
|
|
@@ -76,7 +76,7 @@ static __always_inline bool __must_check current_clr_polling_and_test(void)
|
|
*/
|
|
smp_mb__after_atomic();
|
|
|
|
- return unlikely(tif_need_resched());
|
|
+ return unlikely(need_resched());
|
|
}
|
|
|
|
#else
|
|
@@ -85,11 +85,11 @@ static inline void __current_clr_polling(void) { }
|
|
|
|
static inline bool __must_check current_set_polling_and_test(void)
|
|
{
|
|
- return unlikely(tif_need_resched());
|
|
+ return unlikely(need_resched());
|
|
}
|
|
static inline bool __must_check current_clr_polling_and_test(void)
|
|
{
|
|
- return unlikely(tif_need_resched());
|
|
+ return unlikely(need_resched());
|
|
}
|
|
#endif
|
|
|
|
diff --git a/include/linux/sched/rt.h b/include/linux/sched/rt.h
|
|
index 994c25640e15..b2b9e6eb9683 100644
|
|
--- a/include/linux/sched/rt.h
|
|
+++ b/include/linux/sched/rt.h
|
|
@@ -30,6 +30,10 @@ static inline bool task_is_realtime(struct task_struct *tsk)
|
|
}
|
|
|
|
#ifdef CONFIG_RT_MUTEXES
|
|
+extern void rt_mutex_pre_schedule(void);
|
|
+extern void rt_mutex_schedule(void);
|
|
+extern void rt_mutex_post_schedule(void);
|
|
+
|
|
/*
|
|
* Must hold either p->pi_lock or task_rq(p)->lock.
|
|
*/
|
|
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
|
|
index be65de65fe61..ec46e3b49ee9 100644
|
|
--- a/include/linux/serial_8250.h
|
|
+++ b/include/linux/serial_8250.h
|
|
@@ -153,6 +153,8 @@ struct uart_8250_port {
|
|
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
|
|
unsigned char msr_saved_flags;
|
|
|
|
+ bool console_newline_needed;
|
|
+
|
|
struct uart_8250_dma *dma;
|
|
const struct uart_8250_ops *ops;
|
|
|
|
@@ -204,6 +206,10 @@ void serial8250_init_port(struct uart_8250_port *up);
|
|
void serial8250_set_defaults(struct uart_8250_port *up);
|
|
void serial8250_console_write(struct uart_8250_port *up, const char *s,
|
|
unsigned int count);
|
|
+bool serial8250_console_write_atomic(struct uart_8250_port *up,
|
|
+ struct nbcon_write_context *wctxt);
|
|
+bool serial8250_console_write_thread(struct uart_8250_port *up,
|
|
+ struct nbcon_write_context *wctxt);
|
|
int serial8250_console_setup(struct uart_port *port, char *options, bool probe);
|
|
int serial8250_console_exit(struct uart_port *port);
|
|
|
|
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
|
|
index 052df85dfd59..6de3d7aab17d 100644
|
|
--- a/include/linux/serial_core.h
|
|
+++ b/include/linux/serial_core.h
|
|
@@ -489,6 +489,7 @@ struct uart_port {
|
|
struct uart_icount icount; /* statistics */
|
|
|
|
struct console *cons; /* struct console, if any */
|
|
+ bool nbcon_locked_port; /* True, if the port is locked by nbcon */
|
|
/* flags must be updated while holding port mutex */
|
|
upf_t flags;
|
|
|
|
@@ -596,6 +597,7 @@ struct uart_port {
|
|
static inline void uart_port_lock(struct uart_port *up)
|
|
{
|
|
spin_lock(&up->lock);
|
|
+ nbcon_acquire(up);
|
|
}
|
|
|
|
/**
|
|
@@ -605,6 +607,7 @@ static inline void uart_port_lock(struct uart_port *up)
|
|
static inline void uart_port_lock_irq(struct uart_port *up)
|
|
{
|
|
spin_lock_irq(&up->lock);
|
|
+ nbcon_acquire(up);
|
|
}
|
|
|
|
/**
|
|
@@ -615,6 +618,7 @@ static inline void uart_port_lock_irq(struct uart_port *up)
|
|
static inline void uart_port_lock_irqsave(struct uart_port *up, unsigned long *flags)
|
|
{
|
|
spin_lock_irqsave(&up->lock, *flags);
|
|
+ nbcon_acquire(up);
|
|
}
|
|
|
|
/**
|
|
@@ -625,7 +629,11 @@ static inline void uart_port_lock_irqsave(struct uart_port *up, unsigned long *f
|
|
*/
|
|
static inline bool uart_port_trylock(struct uart_port *up)
|
|
{
|
|
- return spin_trylock(&up->lock);
|
|
+ if (!spin_trylock(&up->lock))
|
|
+ return false;
|
|
+
|
|
+ nbcon_acquire(up);
|
|
+ return true;
|
|
}
|
|
|
|
/**
|
|
@@ -637,7 +645,11 @@ static inline bool uart_port_trylock(struct uart_port *up)
|
|
*/
|
|
static inline bool uart_port_trylock_irqsave(struct uart_port *up, unsigned long *flags)
|
|
{
|
|
- return spin_trylock_irqsave(&up->lock, *flags);
|
|
+ if (!spin_trylock_irqsave(&up->lock, *flags))
|
|
+ return false;
|
|
+
|
|
+ nbcon_acquire(up);
|
|
+ return true;
|
|
}
|
|
|
|
/**
|
|
@@ -646,6 +658,7 @@ static inline bool uart_port_trylock_irqsave(struct uart_port *up, unsigned long
|
|
*/
|
|
static inline void uart_port_unlock(struct uart_port *up)
|
|
{
|
|
+ nbcon_release(up);
|
|
spin_unlock(&up->lock);
|
|
}
|
|
|
|
@@ -655,6 +668,7 @@ static inline void uart_port_unlock(struct uart_port *up)
|
|
*/
|
|
static inline void uart_port_unlock_irq(struct uart_port *up)
|
|
{
|
|
+ nbcon_release(up);
|
|
spin_unlock_irq(&up->lock);
|
|
}
|
|
|
|
@@ -664,6 +678,19 @@ static inline void uart_port_unlock_irq(struct uart_port *up)
|
|
* @flags: The saved interrupt flags for restore
|
|
*/
|
|
static inline void uart_port_unlock_irqrestore(struct uart_port *up, unsigned long flags)
|
|
+{
|
|
+ nbcon_release(up);
|
|
+ spin_unlock_irqrestore(&up->lock, flags);
|
|
+}
|
|
+
|
|
+/* Only for use in the console->driver_enter() callback. */
|
|
+static inline void __uart_port_lock_irqsave(struct uart_port *up, unsigned long *flags)
|
|
+{
|
|
+ spin_lock_irqsave(&up->lock, *flags);
|
|
+}
|
|
+
|
|
+/* Only for use in the console->driver_exit() callback. */
|
|
+static inline void __uart_port_unlock_irqrestore(struct uart_port *up, unsigned long flags)
|
|
{
|
|
spin_unlock_irqrestore(&up->lock, flags);
|
|
}
|
|
@@ -1078,14 +1105,14 @@ static inline void uart_unlock_and_check_sysrq(struct uart_port *port)
|
|
u8 sysrq_ch;
|
|
|
|
if (!port->has_sysrq) {
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
return;
|
|
}
|
|
|
|
sysrq_ch = port->sysrq_ch;
|
|
port->sysrq_ch = 0;
|
|
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
|
|
if (sysrq_ch)
|
|
handle_sysrq(sysrq_ch);
|
|
@@ -1097,14 +1124,14 @@ static inline void uart_unlock_and_check_sysrq_irqrestore(struct uart_port *port
|
|
u8 sysrq_ch;
|
|
|
|
if (!port->has_sysrq) {
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
return;
|
|
}
|
|
|
|
sysrq_ch = port->sysrq_ch;
|
|
port->sysrq_ch = 0;
|
|
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
|
|
if (sysrq_ch)
|
|
handle_sysrq(sysrq_ch);
|
|
@@ -1120,12 +1147,12 @@ static inline int uart_prepare_sysrq_char(struct uart_port *port, u8 ch)
|
|
}
|
|
static inline void uart_unlock_and_check_sysrq(struct uart_port *port)
|
|
{
|
|
- spin_unlock(&port->lock);
|
|
+ uart_port_unlock(port);
|
|
}
|
|
static inline void uart_unlock_and_check_sysrq_irqrestore(struct uart_port *port,
|
|
unsigned long flags)
|
|
{
|
|
- spin_unlock_irqrestore(&port->lock, flags);
|
|
+ uart_port_unlock_irqrestore(port, flags);
|
|
}
|
|
#endif /* CONFIG_MAGIC_SYSRQ_SERIAL */
|
|
|
|
diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h
|
|
index 9ea0b28068f4..5ded1450ac1a 100644
|
|
--- a/include/linux/thread_info.h
|
|
+++ b/include/linux/thread_info.h
|
|
@@ -59,6 +59,16 @@ enum syscall_work_bit {
|
|
|
|
#include <asm/thread_info.h>
|
|
|
|
+#ifdef CONFIG_PREEMPT_BUILD_AUTO
|
|
+# define TIF_NEED_RESCHED_LAZY TIF_ARCH_RESCHED_LAZY
|
|
+# define _TIF_NEED_RESCHED_LAZY _TIF_ARCH_RESCHED_LAZY
|
|
+# define TIF_NEED_RESCHED_LAZY_OFFSET (TIF_NEED_RESCHED_LAZY - TIF_NEED_RESCHED)
|
|
+#else
|
|
+# define TIF_NEED_RESCHED_LAZY TIF_NEED_RESCHED
|
|
+# define _TIF_NEED_RESCHED_LAZY _TIF_NEED_RESCHED
|
|
+# define TIF_NEED_RESCHED_LAZY_OFFSET 0
|
|
+#endif
|
|
+
|
|
#ifdef __KERNEL__
|
|
|
|
#ifndef arch_set_restart_data
|
|
@@ -185,6 +195,13 @@ static __always_inline bool tif_need_resched(void)
|
|
(unsigned long *)(¤t_thread_info()->flags));
|
|
}
|
|
|
|
+static __always_inline bool tif_need_resched_lazy(void)
|
|
+{
|
|
+ return IS_ENABLED(CONFIG_PREEMPT_BUILD_AUTO) &&
|
|
+ arch_test_bit(TIF_NEED_RESCHED_LAZY,
|
|
+ (unsigned long *)(¤t_thread_info()->flags));
|
|
+}
|
|
+
|
|
#else
|
|
|
|
static __always_inline bool tif_need_resched(void)
|
|
@@ -193,6 +210,13 @@ static __always_inline bool tif_need_resched(void)
|
|
(unsigned long *)(¤t_thread_info()->flags));
|
|
}
|
|
|
|
+static __always_inline bool tif_need_resched_lazy(void)
|
|
+{
|
|
+ return IS_ENABLED(CONFIG_PREEMPT_BUILD_AUTO) &&
|
|
+ test_bit(TIF_NEED_RESCHED_LAZY,
|
|
+ (unsigned long *)(¤t_thread_info()->flags));
|
|
+}
|
|
+
|
|
#endif /* _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H */
|
|
|
|
#ifndef CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES
|
|
diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
|
|
index cb8bd759e800..ce1fefc37cb5 100644
|
|
--- a/include/linux/trace_events.h
|
|
+++ b/include/linux/trace_events.h
|
|
@@ -178,8 +178,8 @@ unsigned int tracing_gen_ctx_irq_test(unsigned int irqs_status);
|
|
|
|
enum trace_flag_type {
|
|
TRACE_FLAG_IRQS_OFF = 0x01,
|
|
- TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
|
|
- TRACE_FLAG_NEED_RESCHED = 0x04,
|
|
+ TRACE_FLAG_NEED_RESCHED = 0x02,
|
|
+ TRACE_FLAG_NEED_RESCHED_LAZY = 0x04,
|
|
TRACE_FLAG_HARDIRQ = 0x08,
|
|
TRACE_FLAG_SOFTIRQ = 0x10,
|
|
TRACE_FLAG_PREEMPT_RESCHED = 0x20,
|
|
@@ -205,11 +205,11 @@ static inline unsigned int tracing_gen_ctx(void)
|
|
|
|
static inline unsigned int tracing_gen_ctx_flags(unsigned long irqflags)
|
|
{
|
|
- return tracing_gen_ctx_irq_test(TRACE_FLAG_IRQS_NOSUPPORT);
|
|
+ return tracing_gen_ctx_irq_test(0);
|
|
}
|
|
static inline unsigned int tracing_gen_ctx(void)
|
|
{
|
|
- return tracing_gen_ctx_irq_test(TRACE_FLAG_IRQS_NOSUPPORT);
|
|
+ return tracing_gen_ctx_irq_test(0);
|
|
}
|
|
#endif
|
|
|
|
diff --git a/include/net/dsa.h b/include/net/dsa.h
|
|
index 0b9c6aa27047..d6c3e3457401 100644
|
|
--- a/include/net/dsa.h
|
|
+++ b/include/net/dsa.h
|
|
@@ -56,6 +56,7 @@ struct phylink_link_state;
|
|
#define DSA_TAG_PROTO_RTL8_4T_VALUE 25
|
|
#define DSA_TAG_PROTO_RZN1_A5PSW_VALUE 26
|
|
#define DSA_TAG_PROTO_LAN937X_VALUE 27
|
|
+#define DSA_TAG_PROTO_NETC_VALUE 28
|
|
|
|
enum dsa_tag_protocol {
|
|
DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE,
|
|
@@ -86,6 +87,7 @@ enum dsa_tag_protocol {
|
|
DSA_TAG_PROTO_RTL8_4T = DSA_TAG_PROTO_RTL8_4T_VALUE,
|
|
DSA_TAG_PROTO_RZN1_A5PSW = DSA_TAG_PROTO_RZN1_A5PSW_VALUE,
|
|
DSA_TAG_PROTO_LAN937X = DSA_TAG_PROTO_LAN937X_VALUE,
|
|
+ DSA_TAG_PROTO_NETC = DSA_TAG_PROTO_NETC_VALUE,
|
|
};
|
|
|
|
struct dsa_switch;
|
|
@@ -956,6 +958,22 @@ struct dsa_switch_ops {
|
|
int (*port_del_dscp_prio)(struct dsa_switch *ds, int port, u8 dscp,
|
|
u8 prio);
|
|
|
|
+ /*
|
|
+ * ethtool --set-frame-preemption
|
|
+ */
|
|
+ int (*set_preempt)(struct dsa_switch *ds, int port,
|
|
+ struct ethtool_fp *fpcmd);
|
|
+
|
|
+ /*
|
|
+ * ethtool --show-frame-preemption
|
|
+ */
|
|
+ int (*get_preempt)(struct dsa_switch *ds, int port,
|
|
+ struct ethtool_fp *fpcmd);
|
|
+
|
|
+ /*
|
|
+ * ethtool --reset-frame-preemption
|
|
+ */
|
|
+ int (*reset_preempt)(struct dsa_switch *ds, int port, bool enable);
|
|
/*
|
|
* Suspend and resume
|
|
*/
|
|
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
|
|
index 9efa9a59e81f..e8c472ce2bfb 100644
|
|
--- a/include/net/flow_offload.h
|
|
+++ b/include/net/flow_offload.h
|
|
@@ -184,6 +184,7 @@ enum flow_action_id {
|
|
FLOW_ACTION_VLAN_PUSH_ETH,
|
|
FLOW_ACTION_VLAN_POP_ETH,
|
|
FLOW_ACTION_CONTINUE,
|
|
+ FLOW_ACTION_FRER,
|
|
NUM_FLOW_ACTIONS,
|
|
};
|
|
|
|
@@ -327,6 +328,14 @@ struct flow_action_entry {
|
|
struct { /* FLOW_ACTION_PPPOE_PUSH */
|
|
u16 sid;
|
|
} pppoe;
|
|
+ struct {
|
|
+ u8 tag_type;
|
|
+ u8 tag_action;
|
|
+ u8 recover;
|
|
+ u8 rcvy_alg;
|
|
+ u8 rcvy_history_len;
|
|
+ u16 rcvy_reset_msec;
|
|
+ } frer;
|
|
};
|
|
struct flow_action_cookie *user_cookie; /* user defined action cookie */
|
|
};
|
|
diff --git a/include/net/switchdev.h b/include/net/switchdev.h
|
|
index 8346b0d29542..990b1a430b81 100644
|
|
--- a/include/net/switchdev.h
|
|
+++ b/include/net/switchdev.h
|
|
@@ -97,6 +97,7 @@ struct switchdev_obj_port_vlan {
|
|
struct switchdev_obj obj;
|
|
u16 flags;
|
|
u16 vid;
|
|
+ u16 proto;
|
|
/* If set, the notifier signifies a change of one of the following
|
|
* flags for a VLAN that already exists:
|
|
* - BRIDGE_VLAN_INFO_PVID
|
|
diff --git a/include/net/tc_act/tc_frer.h b/include/net/tc_act/tc_frer.h
|
|
new file mode 100644
|
|
index 000000000000..b2ad2b2a3fe1
|
|
--- /dev/null
|
|
+++ b/include/net/tc_act/tc_frer.h
|
|
@@ -0,0 +1,52 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
+/* Copyright 2021 NXP */
|
|
+
|
|
+#ifndef __NET_TC_FRER_H
|
|
+#define __NET_TC_FRER_H
|
|
+
|
|
+#include <net/act_api.h>
|
|
+#include <linux/tc_act/tc_frer.h>
|
|
+
|
|
+struct tcf_frer;
|
|
+
|
|
+struct tcf_frer_proto_ops {
|
|
+ int (*encode)(struct sk_buff *skb, struct tcf_frer *frer_act);
|
|
+ int (*decode)(struct sk_buff *skb);
|
|
+ void (*tag_pop)(struct sk_buff *skb, struct tcf_frer *frer_act);
|
|
+};
|
|
+
|
|
+struct tcf_frer {
|
|
+ struct tc_action common;
|
|
+ u8 tag_type;
|
|
+ u8 tag_action;
|
|
+ u8 recover;
|
|
+ u8 rcvy_alg;
|
|
+ u8 rcvy_history_len;
|
|
+ u64 rcvy_reset_msec;
|
|
+ u32 gen_seq_num;
|
|
+ u32 rcvy_seq_num;
|
|
+ u64 seq_space;
|
|
+ u32 seq_history;
|
|
+ bool take_any;
|
|
+ bool rcvy_take_noseq;
|
|
+ u32 cps_seq_rcvy_lost_pkts;
|
|
+ u32 cps_seq_rcvy_tagless_pkts;
|
|
+ u32 cps_seq_rcvy_out_of_order_pkts;
|
|
+ u32 cps_seq_rcvy_rogue_pkts;
|
|
+ u32 cps_seq_rcvy_resets;
|
|
+ struct hrtimer hrtimer;
|
|
+ const struct tcf_frer_proto_ops *proto_ops;
|
|
+};
|
|
+
|
|
+#define to_frer(a) ((struct tcf_frer *)a)
|
|
+
|
|
+static inline bool is_tcf_frer(const struct tc_action *a)
|
|
+{
|
|
+#ifdef CONFIG_NET_CLS_ACT
|
|
+ if (a->ops && a->ops->id == TCA_ID_FRER)
|
|
+ return true;
|
|
+#endif
|
|
+ return false;
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
|
|
index 4d41baa6e0e1..87613b5746f5 100644
|
|
--- a/include/soc/mscc/ocelot.h
|
|
+++ b/include/soc/mscc/ocelot.h
|
|
@@ -11,6 +11,9 @@
|
|
#include <linux/regmap.h>
|
|
#include <net/dsa.h>
|
|
|
|
+#define OCELOT_MAX_PTP_ID 63
|
|
+#define OCELOT_PTP_FIFO_SIZE 128
|
|
+
|
|
struct phy;
|
|
struct tc_mqprio_qopt_offload;
|
|
|
|
@@ -788,7 +791,6 @@ struct ocelot_port {
|
|
phy_interface_t phy_mode;
|
|
struct phy *serdes;
|
|
|
|
- unsigned int ptp_skbs_in_flight;
|
|
struct sk_buff_head tx_skbs;
|
|
|
|
unsigned int trap_proto;
|
|
@@ -796,12 +798,12 @@ struct ocelot_port {
|
|
u16 mrp_ring_id;
|
|
|
|
u8 ptp_cmd;
|
|
- u8 ts_id;
|
|
|
|
u8 index;
|
|
|
|
u8 stp_state;
|
|
bool vlan_aware;
|
|
+ bool qinq_mode;
|
|
bool is_dsa_8021q_cpu;
|
|
bool learn_ena;
|
|
|
|
@@ -812,8 +814,11 @@ struct ocelot_port {
|
|
bool force_forward;
|
|
u8 cut_thru;
|
|
u8 cut_thru_selected_by_user;
|
|
+ bool fp_enabled_admin;
|
|
|
|
int speed;
|
|
+ DECLARE_BITMAP(ts_id_in_flight, OCELOT_MAX_PTP_ID);
|
|
+ unsigned long ptp_tx_time[OCELOT_MAX_PTP_ID];
|
|
};
|
|
|
|
struct ocelot {
|
|
@@ -902,6 +907,9 @@ struct ocelot {
|
|
|
|
struct ocelot_mm_state *mm;
|
|
|
|
+ bool qinq_enable;
|
|
+ struct kref qinq_refcount;
|
|
+
|
|
struct ocelot_fdma *fdma;
|
|
};
|
|
|
|
diff --git a/include/soc/mscc/ocelot_ptp.h b/include/soc/mscc/ocelot_ptp.h
|
|
index f085884b1fa2..ded497d72bdb 100644
|
|
--- a/include/soc/mscc/ocelot_ptp.h
|
|
+++ b/include/soc/mscc/ocelot_ptp.h
|
|
@@ -13,9 +13,6 @@
|
|
#include <linux/ptp_clock_kernel.h>
|
|
#include <soc/mscc/ocelot.h>
|
|
|
|
-#define OCELOT_MAX_PTP_ID 63
|
|
-#define OCELOT_PTP_FIFO_SIZE 128
|
|
-
|
|
#define PTP_PIN_CFG_RSZ 0x20
|
|
#define PTP_PIN_TOD_SEC_MSB_RSZ PTP_PIN_CFG_RSZ
|
|
#define PTP_PIN_TOD_SEC_LSB_RSZ PTP_PIN_CFG_RSZ
|
|
diff --git a/include/soc/mscc/ocelot_vcap.h b/include/soc/mscc/ocelot_vcap.h
|
|
index c601a4598b0d..f8cde2408890 100644
|
|
--- a/include/soc/mscc/ocelot_vcap.h
|
|
+++ b/include/soc/mscc/ocelot_vcap.h
|
|
@@ -704,6 +704,7 @@ struct ocelot_vcap_filter {
|
|
enum ocelot_vcap_bit dmac_mc;
|
|
enum ocelot_vcap_bit dmac_bc;
|
|
struct ocelot_vcap_key_vlan vlan;
|
|
+ struct ocelot_vcap_key_vlan cvlan;
|
|
|
|
enum ocelot_vcap_key_type key_type;
|
|
union {
|
|
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
|
|
index 421eb57fb6e9..b7a7aa00f499 100644
|
|
--- a/include/uapi/linux/ethtool.h
|
|
+++ b/include/uapi/linux/ethtool.h
|
|
@@ -379,6 +379,32 @@ struct ethtool_eee {
|
|
__u32 reserved[2];
|
|
};
|
|
|
|
+/**
|
|
+ * struct ethtool_fp - Frame Preemption information
|
|
+ * @cmd: ETHTOOL_{G,S}FP
|
|
+ * @disabled: Disable hardware preemption supports.
|
|
+ * @fp_supported: If frame preemption is supported.
|
|
+ * @fp_enabled: If frame preemption should be advertised to the link partner
|
|
+ * as enabled.
|
|
+ * @supported_queues_mask: Bitmask indicating which queues support being
|
|
+ * configured as preemptible (bit 0 -> queue 0, bit N -> queue N).
|
|
+ * @preemptible_queues_mask: Bitmask indicating which queues are
|
|
+ * configured as preemptible (bit 0 -> queue 0, bit N -> queue N).
|
|
+ * @min_frag_size: Minimum size for all non-final fragment size.
|
|
+ */
|
|
+struct ethtool_fp {
|
|
+ __u32 cmd;
|
|
+ __u8 disabled;
|
|
+ __u8 fp_supported;
|
|
+ __u8 fp_enabled;
|
|
+ __u8 fp_status;
|
|
+ __u8 fp_active;
|
|
+ __u32 supported_queues_mask;
|
|
+ __u32 preemptible_queues_mask;
|
|
+ __u32 min_frag_size;
|
|
+ __u32 reserved[2];
|
|
+};
|
|
+
|
|
/**
|
|
* struct ethtool_modinfo - plugin module eeprom information
|
|
* @cmd: %ETHTOOL_GMODULEINFO
|
|
@@ -1671,6 +1697,10 @@ enum ethtool_fec_config_bits {
|
|
#define ETHTOOL_GFECPARAM 0x00000050 /* Get FEC settings */
|
|
#define ETHTOOL_SFECPARAM 0x00000051 /* Set FEC settings */
|
|
|
|
+#define ETHTOOL_GFP 0x00000052 /* Get Frame Preemption settings */
|
|
+#define ETHTOOL_SFP 0x00000053 /* Set Frame Preemption settings */
|
|
+#define ETHTOOL_RFP 0x00000054 /* Reset Frame Preemption settings */
|
|
+
|
|
/* compatibility with older code */
|
|
#define SPARC_ETH_GSET ETHTOOL_GSET
|
|
#define SPARC_ETH_SSET ETHTOOL_SSET
|
|
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
|
|
index 73e2c10dc2cc..45010bfc11ca 100644
|
|
--- a/include/uapi/linux/ethtool_netlink.h
|
|
+++ b/include/uapi/linux/ethtool_netlink.h
|
|
@@ -41,6 +41,8 @@ enum {
|
|
ETHTOOL_MSG_TSINFO_GET,
|
|
ETHTOOL_MSG_CABLE_TEST_ACT,
|
|
ETHTOOL_MSG_CABLE_TEST_TDR_ACT,
|
|
+ ETHTOOL_MSG_PREEMPT_GET,
|
|
+ ETHTOOL_MSG_PREEMPT_SET,
|
|
ETHTOOL_MSG_TUNNEL_INFO_GET,
|
|
ETHTOOL_MSG_FEC_GET,
|
|
ETHTOOL_MSG_FEC_SET,
|
|
@@ -94,6 +96,8 @@ enum {
|
|
ETHTOOL_MSG_TSINFO_GET_REPLY,
|
|
ETHTOOL_MSG_CABLE_TEST_NTF,
|
|
ETHTOOL_MSG_CABLE_TEST_TDR_NTF,
|
|
+ ETHTOOL_MSG_PREEMPT_GET_REPLY,
|
|
+ ETHTOOL_MSG_PREEMPT_NTF,
|
|
ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY,
|
|
ETHTOOL_MSG_FEC_GET_REPLY,
|
|
ETHTOOL_MSG_FEC_NTF,
|
|
@@ -975,6 +979,23 @@ enum {
|
|
ETHTOOL_A_MM_MAX = (__ETHTOOL_A_MM_CNT - 1)
|
|
};
|
|
|
|
+/* FRAME PREEMPTION */
|
|
+enum {
|
|
+ ETHTOOL_A_PREEMPT_UNSPEC,
|
|
+ ETHTOOL_A_PREEMPT_HEADER, /* nest - _A_HEADER_* */
|
|
+ ETHTOOL_A_PREEMPT_DISABLED, /* bool */
|
|
+ ETHTOOL_A_PREEMPT_SUPPORTED, /* u8 */
|
|
+ ETHTOOL_A_PREEMPT_STATUS, /* u8 */
|
|
+ ETHTOOL_A_PREEMPT_ACTIVE, /* u8 */
|
|
+ ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE, /* u32 */
|
|
+ ETHTOOL_A_PREEMPT_QUEUES_SUPPORTED, /* u32 */
|
|
+ ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE, /* u32 */
|
|
+
|
|
+ /* add new constants above here */
|
|
+ __ETHTOOL_A_PREEMPT_CNT,
|
|
+ ETHTOOL_A_PREEMPT_MAX = (__ETHTOOL_A_PREEMPT_CNT - 1)
|
|
+};
|
|
+
|
|
/* generic netlink info */
|
|
#define ETHTOOL_GENL_NAME "ethtool"
|
|
#define ETHTOOL_GENL_VERSION 1
|
|
diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h
|
|
index 69e0457eb200..9bdcecde2be8 100644
|
|
--- a/include/uapi/linux/if_ether.h
|
|
+++ b/include/uapi/linux/if_ether.h
|
|
@@ -119,6 +119,7 @@
|
|
#define ETH_P_DSA_A5PSW 0xE001 /* A5PSW Tag Value [ NOT AN OFFICIALLY REGISTERED ID ] */
|
|
#define ETH_P_IFE 0xED3E /* ForCES inter-FE LFB type */
|
|
#define ETH_P_AF_IUCV 0xFBFB /* IBM af_iucv [ NOT AN OFFICIALLY REGISTERED ID ] */
|
|
+#define ETH_P_RTAG 0xF1C1 /* Redundancy Tag(IEEE 802.1CB) */
|
|
|
|
#define ETH_P_802_3_MIN 0x0600 /* If the value in the ethernet type is more than this value
|
|
* then the frame is Ethernet II. Else it is 802.3 */
|
|
diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h
|
|
index c7082cc60d21..930eb82f3e20 100644
|
|
--- a/include/uapi/linux/pkt_cls.h
|
|
+++ b/include/uapi/linux/pkt_cls.h
|
|
@@ -139,6 +139,7 @@ enum tca_id {
|
|
TCA_ID_MPLS,
|
|
TCA_ID_CT,
|
|
TCA_ID_GATE,
|
|
+ TCA_ID_FRER,
|
|
/* other actions go here */
|
|
__TCA_ID_MAX = 255
|
|
};
|
|
diff --git a/include/uapi/linux/ptp_clock.h b/include/uapi/linux/ptp_clock.h
|
|
index 05cc35fc94ac..e9f63daa4d06 100644
|
|
--- a/include/uapi/linux/ptp_clock.h
|
|
+++ b/include/uapi/linux/ptp_clock.h
|
|
@@ -199,6 +199,17 @@ struct ptp_pin_desc {
|
|
unsigned int rsv[5];
|
|
};
|
|
|
|
+#define PTP_MAX_CONVERT_TS_NUM 16 /* Maximum allowed number of timestamps to convert. */
|
|
+
|
|
+struct ptp_convert_timestamps {
|
|
+ /* src timestamp to convert in the ptp device clock domain. */
|
|
+ struct ptp_clock_time src_ts[PTP_MAX_CONVERT_TS_NUM];
|
|
+ /* converted timestamp in the destination ptp device clock domain. */
|
|
+ struct ptp_clock_time dst_ts[PTP_MAX_CONVERT_TS_NUM];
|
|
+ unsigned int dst_phc_index; /* destination ptp clock domain. */
|
|
+ unsigned int n_ts; /* Number of timestamps in src_ts array. */
|
|
+};
|
|
+
|
|
#define PTP_CLK_MAGIC '='
|
|
|
|
#define PTP_CLOCK_GETCAPS _IOR(PTP_CLK_MAGIC, 1, struct ptp_clock_caps)
|
|
@@ -224,6 +235,7 @@ struct ptp_pin_desc {
|
|
_IOWR(PTP_CLK_MAGIC, 17, struct ptp_sys_offset_precise)
|
|
#define PTP_SYS_OFFSET_EXTENDED2 \
|
|
_IOWR(PTP_CLK_MAGIC, 18, struct ptp_sys_offset_extended)
|
|
+#define PTP_CONVERT_TIMESTAMPS _IOW(PTP_CLK_MAGIC, 21, struct ptp_convert_timestamps)
|
|
|
|
struct ptp_extts_event {
|
|
struct ptp_clock_time t; /* Time event occured. */
|
|
diff --git a/include/uapi/linux/tc_act/tc_frer.h b/include/uapi/linux/tc_act/tc_frer.h
|
|
new file mode 100644
|
|
index 000000000000..fe2420337633
|
|
--- /dev/null
|
|
+++ b/include/uapi/linux/tc_act/tc_frer.h
|
|
@@ -0,0 +1,50 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
|
|
+/* Copyright 2021 NXP */
|
|
+
|
|
+#ifndef __LINUX_TC_FRER_H
|
|
+#define __LINUX_TC_FRER_H
|
|
+
|
|
+#include <linux/pkt_cls.h>
|
|
+
|
|
+struct tc_frer {
|
|
+ tc_gen;
|
|
+};
|
|
+
|
|
+enum {
|
|
+ TCA_FRER_UNSPEC,
|
|
+ TCA_FRER_TM,
|
|
+ TCA_FRER_PARMS,
|
|
+ TCA_FRER_PAD,
|
|
+ TCA_FRER_TAG_TYPE,
|
|
+ TCA_FRER_TAG_ACTION,
|
|
+ TCA_FRER_RECOVER,
|
|
+ TCA_FRER_RECOVER_ALG,
|
|
+ TCA_FRER_RECOVER_HISTORY_LEN,
|
|
+ TCA_FRER_RECOVER_RESET_TM,
|
|
+ TCA_FRER_RECOVER_TAGLESS_PKTS,
|
|
+ TCA_FRER_RECOVER_OUT_OF_ORDER_PKTS,
|
|
+ TCA_FRER_RECOVER_ROGUE_PKTS,
|
|
+ TCA_FRER_RECOVER_LOST_PKTS,
|
|
+ TCA_FRER_RECOVER_RESETS,
|
|
+ __TCA_FRER_MAX,
|
|
+};
|
|
+#define TCA_FRER_MAX (__TCA_FRER_MAX - 1)
|
|
+
|
|
+enum tc_frer_tag_action {
|
|
+ TCA_FRER_TAG_NULL,
|
|
+ TCA_FRER_TAG_PUSH,
|
|
+ TCA_FRER_TAG_POP,
|
|
+};
|
|
+
|
|
+enum tc_frer_tag_type {
|
|
+ TCA_FRER_TAG_RTAG = 1,
|
|
+ TCA_FRER_TAG_HSR,
|
|
+ TCA_FRER_TAG_PRP,
|
|
+};
|
|
+
|
|
+enum tc_frer_rcvy_alg {
|
|
+ TCA_FRER_RCVY_VECTOR_ALG,
|
|
+ TCA_FRER_RCVY_MATCH_ALG,
|
|
+};
|
|
+
|
|
+#endif
|
|
diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h
|
|
index 7aa2eb766205..67f7fe400730 100644
|
|
--- a/include/uapi/linux/virtio_ids.h
|
|
+++ b/include/uapi/linux/virtio_ids.h
|
|
@@ -68,6 +68,7 @@
|
|
#define VIRTIO_ID_AUDIO_POLICY 39 /* virtio audio policy */
|
|
#define VIRTIO_ID_BT 40 /* virtio bluetooth */
|
|
#define VIRTIO_ID_GPIO 41 /* virtio gpio */
|
|
+#define VIRTIO_ID_TRANS 42 /* virtio transfer test */
|
|
|
|
/*
|
|
* Virtio Transitional IDs
|
|
diff --git a/include/uapi/linux/virtio_mmio.h b/include/uapi/linux/virtio_mmio.h
|
|
index 0650f91bea6c..ee672e1b4a6e 100644
|
|
--- a/include/uapi/linux/virtio_mmio.h
|
|
+++ b/include/uapi/linux/virtio_mmio.h
|
|
@@ -110,6 +110,9 @@
|
|
/* Device status register - Read Write */
|
|
#define VIRTIO_MMIO_STATUS 0x070
|
|
|
|
+/* Hypervisor-less virtio: Device write operation done status register */
|
|
+#define VIRTIO_MMIO_WD_STATUS 0x074
|
|
+
|
|
/* Selected queue's Descriptor Table address, 64 bits in two halves */
|
|
#define VIRTIO_MMIO_QUEUE_DESC_LOW 0x080
|
|
#define VIRTIO_MMIO_QUEUE_DESC_HIGH 0x084
|
|
@@ -140,7 +143,9 @@
|
|
* the per-driver configuration space - Read Write */
|
|
#define VIRTIO_MMIO_CONFIG 0x100
|
|
|
|
-
|
|
+/* Hypervisor-less virtio: write operation space shared with remote */
|
|
+#define VIRTIO_MMIO_RW_OPS_MEM_OFFSET 0x400
|
|
+#define VIRTIO_MMIO_RW_OPS_MEM_SIZE 64
|
|
|
|
/*
|
|
* Interrupt flags (re: interrupt status & acknowledge registers)
|
|
diff --git a/include/uapi/linux/virtio_trans.h b/include/uapi/linux/virtio_trans.h
|
|
new file mode 100644
|
|
index 000000000000..24a10efb370e
|
|
--- /dev/null
|
|
+++ b/include/uapi/linux/virtio_trans.h
|
|
@@ -0,0 +1,60 @@
|
|
+/* SPDX-License-Identifier: BSD-3-Clause */
|
|
+/*
|
|
+ * Copyright 2022 NXP
|
|
+ */
|
|
+
|
|
+#ifndef _LINUX_VIRTIO_TRANS_H
|
|
+#define _LINUX_VIRTIO_TRANS_H
|
|
+
|
|
+#include <linux/types.h>
|
|
+
|
|
+/*
|
|
+ * status:
|
|
+ * bit0: TX ready
|
|
+ * bit1: RX ready
|
|
+ * config:
|
|
+ * bit0: TX
|
|
+ * bit1: RX
|
|
+ * bit2: 0: Backend do NOT copy buffer
|
|
+ * 1: Backend do copy buffer
|
|
+ * bit3: 0: Backend interrupt mode
|
|
+ * 1: Backend polling mode
|
|
+ * bit4: 0: Frontend interrupt mode
|
|
+ * 1: Frontend polling mode
|
|
+ * control:
|
|
+ * bit0: start transfer
|
|
+ * bit1: reset
|
|
+ * pkt_size: packet size in Byte
|
|
+ * tx_count: Completed count for TX packet, update by Backend
|
|
+ * rx_count: Completed count for RX packet, update by Backend
|
|
+ * regression: Packets to test, set by Frontend
|
|
+ */
|
|
+
|
|
+#define VT_STATUS 0x0
|
|
+#define VT_CONFIG 0x4
|
|
+#define VT_CONTROL 0x8
|
|
+#define VT_PKT_SIZE 0xc
|
|
+#define VT_TX_COUNT 0x10
|
|
+#define VT_RX_COUNT 0x14
|
|
+#define VT_REGRESSION 0x18
|
|
+
|
|
+#define VT_CFG_TX BIT(0)
|
|
+#define VT_CFG_RX BIT(1)
|
|
+#define VT_CFG_COPY BIT(2)
|
|
+#define VT_CFG_B_POLL BIT(3)
|
|
+#define VT_CFG_F_POLL BIT(4)
|
|
+
|
|
+#define VT_CTRL_START BIT(0)
|
|
+#define VT_CTRL_RESET BIT(1)
|
|
+
|
|
+struct virtio_trans_config {
|
|
+ __le32 status;
|
|
+ __le32 config;
|
|
+ __le32 control;
|
|
+ __le32 pkt_size;
|
|
+ __le32 tx_count;
|
|
+ __le32 rx_count;
|
|
+ __le32 regression;
|
|
+};
|
|
+
|
|
+#endif /* _LINUX_VIRTIO_TRANS_H */
|
|
diff --git a/kernel/Kconfig.preempt b/kernel/Kconfig.preempt
|
|
index c2f1fd95a821..0f3d4c2a41cb 100644
|
|
--- a/kernel/Kconfig.preempt
|
|
+++ b/kernel/Kconfig.preempt
|
|
@@ -11,6 +11,13 @@ config PREEMPT_BUILD
|
|
select PREEMPTION
|
|
select UNINLINE_SPIN_UNLOCK if !ARCH_INLINE_SPIN_UNLOCK
|
|
|
|
+config PREEMPT_BUILD_AUTO
|
|
+ bool
|
|
+ select PREEMPT_BUILD
|
|
+
|
|
+config HAVE_PREEMPT_AUTO
|
|
+ bool
|
|
+
|
|
choice
|
|
prompt "Preemption Model"
|
|
default PREEMPT_NONE
|
|
@@ -67,9 +74,17 @@ config PREEMPT
|
|
embedded system with latency requirements in the milliseconds
|
|
range.
|
|
|
|
+config PREEMPT_AUTO
|
|
+ bool "Automagic preemption mode with runtime tweaking support"
|
|
+ depends on HAVE_PREEMPT_AUTO
|
|
+ select PREEMPT_BUILD_AUTO
|
|
+ help
|
|
+ Add some sensible blurb here
|
|
+
|
|
config PREEMPT_RT
|
|
bool "Fully Preemptible Kernel (Real-Time)"
|
|
depends on EXPERT && ARCH_SUPPORTS_RT
|
|
+ select PREEMPT_BUILD_AUTO if HAVE_PREEMPT_AUTO
|
|
select PREEMPTION
|
|
help
|
|
This option turns the kernel into a real-time kernel by replacing
|
|
@@ -95,7 +110,7 @@ config PREEMPTION
|
|
|
|
config PREEMPT_DYNAMIC
|
|
bool "Preemption behaviour defined on boot"
|
|
- depends on HAVE_PREEMPT_DYNAMIC && !PREEMPT_RT
|
|
+ depends on HAVE_PREEMPT_DYNAMIC && !PREEMPT_RT && !PREEMPT_AUTO
|
|
select JUMP_LABEL if HAVE_PREEMPT_DYNAMIC_KEY
|
|
select PREEMPT_BUILD
|
|
default y if HAVE_PREEMPT_DYNAMIC_CALL
|
|
diff --git a/kernel/dma/coherent.c b/kernel/dma/coherent.c
|
|
index ff5683a57f77..3c659063b73a 100644
|
|
--- a/kernel/dma/coherent.c
|
|
+++ b/kernel/dma/coherent.c
|
|
@@ -36,7 +36,8 @@ static inline dma_addr_t dma_get_device_base(struct device *dev,
|
|
}
|
|
|
|
static struct dma_coherent_mem *dma_init_coherent_memory(phys_addr_t phys_addr,
|
|
- dma_addr_t device_addr, size_t size, bool use_dma_pfn_offset)
|
|
+ dma_addr_t device_addr, size_t size, bool use_dma_pfn_offset,
|
|
+ bool cacheable)
|
|
{
|
|
struct dma_coherent_mem *dma_mem;
|
|
int pages = size >> PAGE_SHIFT;
|
|
@@ -45,7 +46,8 @@ static struct dma_coherent_mem *dma_init_coherent_memory(phys_addr_t phys_addr,
|
|
if (!size)
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
- mem_base = memremap(phys_addr, size, MEMREMAP_WC);
|
|
+ mem_base = memremap(phys_addr, size, cacheable ? MEMREMAP_WB :
|
|
+ MEMREMAP_WC);
|
|
if (!mem_base)
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
@@ -119,8 +121,10 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr,
|
|
{
|
|
struct dma_coherent_mem *mem;
|
|
int ret;
|
|
+ bool cacheable = dev_is_dma_coherent(dev);
|
|
|
|
- mem = dma_init_coherent_memory(phys_addr, device_addr, size, false);
|
|
+ mem = dma_init_coherent_memory(phys_addr, device_addr, size, false,
|
|
+ cacheable);
|
|
if (IS_ERR(mem))
|
|
return PTR_ERR(mem);
|
|
|
|
@@ -312,7 +316,7 @@ int dma_init_global_coherent(phys_addr_t phys_addr, size_t size)
|
|
{
|
|
struct dma_coherent_mem *mem;
|
|
|
|
- mem = dma_init_coherent_memory(phys_addr, phys_addr, size, true);
|
|
+ mem = dma_init_coherent_memory(phys_addr, phys_addr, size, true, false);
|
|
if (IS_ERR(mem))
|
|
return PTR_ERR(mem);
|
|
dma_coherent_default_memory = mem;
|
|
@@ -337,9 +341,10 @@ static int rmem_dma_device_init(struct reserved_mem *rmem, struct device *dev)
|
|
{
|
|
if (!rmem->priv) {
|
|
struct dma_coherent_mem *mem;
|
|
+ bool cacheable = dev_is_dma_coherent(dev);
|
|
|
|
mem = dma_init_coherent_memory(rmem->base, rmem->base,
|
|
- rmem->size, true);
|
|
+ rmem->size, true, cacheable);
|
|
if (IS_ERR(mem))
|
|
return PTR_ERR(mem);
|
|
rmem->priv = mem;
|
|
diff --git a/kernel/entry/common.c b/kernel/entry/common.c
|
|
index ccf2b1e1b40b..f70d2a164de1 100644
|
|
--- a/kernel/entry/common.c
|
|
+++ b/kernel/entry/common.c
|
|
@@ -161,7 +161,7 @@ static unsigned long exit_to_user_mode_loop(struct pt_regs *regs,
|
|
|
|
local_irq_enable_exit_to_user(ti_work);
|
|
|
|
- if (ti_work & _TIF_NEED_RESCHED)
|
|
+ if (ti_work & (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY))
|
|
schedule();
|
|
|
|
if (ti_work & _TIF_UPROBE)
|
|
@@ -392,7 +392,7 @@ void raw_irqentry_exit_cond_resched(void)
|
|
rcu_irq_exit_check_preempt();
|
|
if (IS_ENABLED(CONFIG_DEBUG_ENTRY))
|
|
WARN_ON_ONCE(!on_thread_stack());
|
|
- if (need_resched())
|
|
+ if (test_tsk_need_resched(current))
|
|
preempt_schedule_irq();
|
|
}
|
|
}
|
|
diff --git a/kernel/entry/kvm.c b/kernel/entry/kvm.c
|
|
index 2e0f75bcb7fd..d952fa5ee880 100644
|
|
--- a/kernel/entry/kvm.c
|
|
+++ b/kernel/entry/kvm.c
|
|
@@ -13,7 +13,7 @@ static int xfer_to_guest_mode_work(struct kvm_vcpu *vcpu, unsigned long ti_work)
|
|
return -EINTR;
|
|
}
|
|
|
|
- if (ti_work & _TIF_NEED_RESCHED)
|
|
+ if (ti_work & (_TIF_NEED_RESCHED | TIF_NEED_RESCHED_LAZY))
|
|
schedule();
|
|
|
|
if (ti_work & _TIF_NOTIFY_RESUME)
|
|
diff --git a/kernel/futex/pi.c b/kernel/futex/pi.c
|
|
index ce2889f12375..d636a1bbd7d0 100644
|
|
--- a/kernel/futex/pi.c
|
|
+++ b/kernel/futex/pi.c
|
|
@@ -1,6 +1,7 @@
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include <linux/slab.h>
|
|
+#include <linux/sched/rt.h>
|
|
#include <linux/sched/task.h>
|
|
|
|
#include "futex.h"
|
|
@@ -610,29 +611,16 @@ int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb,
|
|
/*
|
|
* Caller must hold a reference on @pi_state.
|
|
*/
|
|
-static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_pi_state *pi_state)
|
|
+static int wake_futex_pi(u32 __user *uaddr, u32 uval,
|
|
+ struct futex_pi_state *pi_state,
|
|
+ struct rt_mutex_waiter *top_waiter)
|
|
{
|
|
- struct rt_mutex_waiter *top_waiter;
|
|
struct task_struct *new_owner;
|
|
bool postunlock = false;
|
|
DEFINE_RT_WAKE_Q(wqh);
|
|
u32 curval, newval;
|
|
int ret = 0;
|
|
|
|
- top_waiter = rt_mutex_top_waiter(&pi_state->pi_mutex);
|
|
- if (WARN_ON_ONCE(!top_waiter)) {
|
|
- /*
|
|
- * As per the comment in futex_unlock_pi() this should not happen.
|
|
- *
|
|
- * When this happens, give up our locks and try again, giving
|
|
- * the futex_lock_pi() instance time to complete, either by
|
|
- * waiting on the rtmutex or removing itself from the futex
|
|
- * queue.
|
|
- */
|
|
- ret = -EAGAIN;
|
|
- goto out_unlock;
|
|
- }
|
|
-
|
|
new_owner = top_waiter->task;
|
|
|
|
/*
|
|
@@ -1002,6 +990,12 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl
|
|
goto no_block;
|
|
}
|
|
|
|
+ /*
|
|
+ * Must be done before we enqueue the waiter, here is unfortunately
|
|
+ * under the hb lock, but that *should* work because it does nothing.
|
|
+ */
|
|
+ rt_mutex_pre_schedule();
|
|
+
|
|
rt_mutex_init_waiter(&rt_waiter);
|
|
|
|
/*
|
|
@@ -1039,19 +1033,37 @@ int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int tryl
|
|
ret = rt_mutex_wait_proxy_lock(&q.pi_state->pi_mutex, to, &rt_waiter);
|
|
|
|
cleanup:
|
|
- spin_lock(q.lock_ptr);
|
|
/*
|
|
* If we failed to acquire the lock (deadlock/signal/timeout), we must
|
|
- * first acquire the hb->lock before removing the lock from the
|
|
- * rt_mutex waitqueue, such that we can keep the hb and rt_mutex wait
|
|
- * lists consistent.
|
|
+ * must unwind the above, however we canont lock hb->lock because
|
|
+ * rt_mutex already has a waiter enqueued and hb->lock can itself try
|
|
+ * and enqueue an rt_waiter through rtlock.
|
|
+ *
|
|
+ * Doing the cleanup without holding hb->lock can cause inconsistent
|
|
+ * state between hb and pi_state, but only in the direction of not
|
|
+ * seeing a waiter that is leaving.
|
|
+ *
|
|
+ * See futex_unlock_pi(), it deals with this inconsistency.
|
|
+ *
|
|
+ * There be dragons here, since we must deal with the inconsistency on
|
|
+ * the way out (here), it is impossible to detect/warn about the race
|
|
+ * the other way around (missing an incoming waiter).
|
|
*
|
|
- * In particular; it is important that futex_unlock_pi() can not
|
|
- * observe this inconsistency.
|
|
+ * What could possibly go wrong...
|
|
*/
|
|
if (ret && !rt_mutex_cleanup_proxy_lock(&q.pi_state->pi_mutex, &rt_waiter))
|
|
ret = 0;
|
|
|
|
+ /*
|
|
+ * Now that the rt_waiter has been dequeued, it is safe to use
|
|
+ * spinlock/rtlock (which might enqueue its own rt_waiter) and fix up
|
|
+ * the
|
|
+ */
|
|
+ spin_lock(q.lock_ptr);
|
|
+ /*
|
|
+ * Waiter is unqueued.
|
|
+ */
|
|
+ rt_mutex_post_schedule();
|
|
no_block:
|
|
/*
|
|
* Fixup the pi_state owner and possibly acquire the lock if we
|
|
@@ -1132,6 +1144,7 @@ int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)
|
|
top_waiter = futex_top_waiter(hb, &key);
|
|
if (top_waiter) {
|
|
struct futex_pi_state *pi_state = top_waiter->pi_state;
|
|
+ struct rt_mutex_waiter *rt_waiter;
|
|
|
|
ret = -EINVAL;
|
|
if (!pi_state)
|
|
@@ -1144,22 +1157,39 @@ int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)
|
|
if (pi_state->owner != current)
|
|
goto out_unlock;
|
|
|
|
- get_pi_state(pi_state);
|
|
/*
|
|
* By taking wait_lock while still holding hb->lock, we ensure
|
|
- * there is no point where we hold neither; and therefore
|
|
- * wake_futex_p() must observe a state consistent with what we
|
|
- * observed.
|
|
+ * there is no point where we hold neither; and thereby
|
|
+ * wake_futex_pi() must observe any new waiters.
|
|
+ *
|
|
+ * Since the cleanup: case in futex_lock_pi() removes the
|
|
+ * rt_waiter without holding hb->lock, it is possible for
|
|
+ * wake_futex_pi() to not find a waiter while the above does,
|
|
+ * in this case the waiter is on the way out and it can be
|
|
+ * ignored.
|
|
*
|
|
* In particular; this forces __rt_mutex_start_proxy() to
|
|
* complete such that we're guaranteed to observe the
|
|
- * rt_waiter. Also see the WARN in wake_futex_pi().
|
|
+ * rt_waiter.
|
|
*/
|
|
raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock);
|
|
+
|
|
+ /*
|
|
+ * Futex vs rt_mutex waiter state -- if there are no rt_mutex
|
|
+ * waiters even though futex thinks there are, then the waiter
|
|
+ * is leaving and the uncontended path is safe to take.
|
|
+ */
|
|
+ rt_waiter = rt_mutex_top_waiter(&pi_state->pi_mutex);
|
|
+ if (!rt_waiter) {
|
|
+ raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
|
|
+ goto do_uncontended;
|
|
+ }
|
|
+
|
|
+ get_pi_state(pi_state);
|
|
spin_unlock(&hb->lock);
|
|
|
|
/* drops pi_state->pi_mutex.wait_lock */
|
|
- ret = wake_futex_pi(uaddr, uval, pi_state);
|
|
+ ret = wake_futex_pi(uaddr, uval, pi_state, rt_waiter);
|
|
|
|
put_pi_state(pi_state);
|
|
|
|
@@ -1187,6 +1217,7 @@ int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)
|
|
return ret;
|
|
}
|
|
|
|
+do_uncontended:
|
|
/*
|
|
* We have no kernel internal state, i.e. no waiters in the
|
|
* kernel. Waiters which are about to queue themselves are stuck
|
|
diff --git a/kernel/futex/requeue.c b/kernel/futex/requeue.c
|
|
index cba8b1a6a4cc..4c73e0b81acc 100644
|
|
--- a/kernel/futex/requeue.c
|
|
+++ b/kernel/futex/requeue.c
|
|
@@ -850,11 +850,13 @@ int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
|
|
pi_mutex = &q.pi_state->pi_mutex;
|
|
ret = rt_mutex_wait_proxy_lock(pi_mutex, to, &rt_waiter);
|
|
|
|
- /* Current is not longer pi_blocked_on */
|
|
- spin_lock(q.lock_ptr);
|
|
+ /*
|
|
+ * See futex_unlock_pi()'s cleanup: comment.
|
|
+ */
|
|
if (ret && !rt_mutex_cleanup_proxy_lock(pi_mutex, &rt_waiter))
|
|
ret = 0;
|
|
|
|
+ spin_lock(q.lock_ptr);
|
|
debug_rt_mutex_free_waiter(&rt_waiter);
|
|
/*
|
|
* Fixup the pi_state owner and possibly acquire the lock if we
|
|
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c
|
|
index 1d4bc493b2f4..486c68c11bbe 100644
|
|
--- a/kernel/ksysfs.c
|
|
+++ b/kernel/ksysfs.c
|
|
@@ -179,6 +179,15 @@ KERNEL_ATTR_RO(crash_elfcorehdr_size);
|
|
|
|
#endif /* CONFIG_CRASH_CORE */
|
|
|
|
+#if defined(CONFIG_PREEMPT_RT)
|
|
+static ssize_t realtime_show(struct kobject *kobj,
|
|
+ struct kobj_attribute *attr, char *buf)
|
|
+{
|
|
+ return sprintf(buf, "%d\n", 1);
|
|
+}
|
|
+KERNEL_ATTR_RO(realtime);
|
|
+#endif
|
|
+
|
|
/* whether file capabilities are enabled */
|
|
static ssize_t fscaps_show(struct kobject *kobj,
|
|
struct kobj_attribute *attr, char *buf)
|
|
@@ -274,6 +283,9 @@ static struct attribute * kernel_attrs[] = {
|
|
#ifndef CONFIG_TINY_RCU
|
|
&rcu_expedited_attr.attr,
|
|
&rcu_normal_attr.attr,
|
|
+#endif
|
|
+#ifdef CONFIG_PREEMPT_RT
|
|
+ &realtime_attr.attr,
|
|
#endif
|
|
NULL
|
|
};
|
|
diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
|
|
index 151bd3de5936..5c21ba41e308 100644
|
|
--- a/kernel/locking/lockdep.c
|
|
+++ b/kernel/locking/lockdep.c
|
|
@@ -56,6 +56,7 @@
|
|
#include <linux/kprobes.h>
|
|
#include <linux/lockdep.h>
|
|
#include <linux/context_tracking.h>
|
|
+#include <linux/console.h>
|
|
|
|
#include <asm/sections.h>
|
|
|
|
@@ -3971,6 +3972,8 @@ print_usage_bug(struct task_struct *curr, struct held_lock *this,
|
|
if (!debug_locks_off() || debug_locks_silent)
|
|
return;
|
|
|
|
+ nbcon_cpu_emergency_enter();
|
|
+
|
|
pr_warn("\n");
|
|
pr_warn("================================\n");
|
|
pr_warn("WARNING: inconsistent lock state\n");
|
|
@@ -3999,6 +4002,8 @@ print_usage_bug(struct task_struct *curr, struct held_lock *this,
|
|
|
|
pr_warn("\nstack backtrace:\n");
|
|
dump_stack();
|
|
+
|
|
+ nbcon_cpu_emergency_exit();
|
|
}
|
|
|
|
/*
|
|
diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
|
|
index bf3a28ee7d8f..99129c89120a 100644
|
|
--- a/kernel/locking/rtmutex.c
|
|
+++ b/kernel/locking/rtmutex.c
|
|
@@ -218,6 +218,11 @@ static __always_inline bool rt_mutex_cmpxchg_acquire(struct rt_mutex_base *lock,
|
|
return try_cmpxchg_acquire(&lock->owner, &old, new);
|
|
}
|
|
|
|
+static __always_inline bool rt_mutex_try_acquire(struct rt_mutex_base *lock)
|
|
+{
|
|
+ return rt_mutex_cmpxchg_acquire(lock, NULL, current);
|
|
+}
|
|
+
|
|
static __always_inline bool rt_mutex_cmpxchg_release(struct rt_mutex_base *lock,
|
|
struct task_struct *old,
|
|
struct task_struct *new)
|
|
@@ -297,6 +302,20 @@ static __always_inline bool rt_mutex_cmpxchg_acquire(struct rt_mutex_base *lock,
|
|
|
|
}
|
|
|
|
+static int __sched rt_mutex_slowtrylock(struct rt_mutex_base *lock);
|
|
+
|
|
+static __always_inline bool rt_mutex_try_acquire(struct rt_mutex_base *lock)
|
|
+{
|
|
+ /*
|
|
+ * With debug enabled rt_mutex_cmpxchg trylock() will always fail.
|
|
+ *
|
|
+ * Avoid unconditionally taking the slow path by using
|
|
+ * rt_mutex_slow_trylock() which is covered by the debug code and can
|
|
+ * acquire a non-contended rtmutex.
|
|
+ */
|
|
+ return rt_mutex_slowtrylock(lock);
|
|
+}
|
|
+
|
|
static __always_inline bool rt_mutex_cmpxchg_release(struct rt_mutex_base *lock,
|
|
struct task_struct *old,
|
|
struct task_struct *new)
|
|
@@ -1613,7 +1632,7 @@ static int __sched rt_mutex_slowlock_block(struct rt_mutex_base *lock,
|
|
raw_spin_unlock_irq(&lock->wait_lock);
|
|
|
|
if (!owner || !rtmutex_spin_on_owner(lock, waiter, owner))
|
|
- schedule();
|
|
+ rt_mutex_schedule();
|
|
|
|
raw_spin_lock_irq(&lock->wait_lock);
|
|
set_current_state(state);
|
|
@@ -1643,7 +1662,7 @@ static void __sched rt_mutex_handle_deadlock(int res, int detect_deadlock,
|
|
|
|
while (1) {
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
|
- schedule();
|
|
+ rt_mutex_schedule();
|
|
}
|
|
}
|
|
|
|
@@ -1738,6 +1757,15 @@ static int __sched rt_mutex_slowlock(struct rt_mutex_base *lock,
|
|
unsigned long flags;
|
|
int ret;
|
|
|
|
+ /*
|
|
+ * Do all pre-schedule work here, before we queue a waiter and invoke
|
|
+ * PI -- any such work that trips on rtlock (PREEMPT_RT spinlock) would
|
|
+ * otherwise recurse back into task_blocks_on_rt_mutex() through
|
|
+ * rtlock_slowlock() and will then enqueue a second waiter for this
|
|
+ * same task and things get really confusing real fast.
|
|
+ */
|
|
+ rt_mutex_pre_schedule();
|
|
+
|
|
/*
|
|
* Technically we could use raw_spin_[un]lock_irq() here, but this can
|
|
* be called in early boot if the cmpxchg() fast path is disabled
|
|
@@ -1749,6 +1777,7 @@ static int __sched rt_mutex_slowlock(struct rt_mutex_base *lock,
|
|
raw_spin_lock_irqsave(&lock->wait_lock, flags);
|
|
ret = __rt_mutex_slowlock_locked(lock, ww_ctx, state);
|
|
raw_spin_unlock_irqrestore(&lock->wait_lock, flags);
|
|
+ rt_mutex_post_schedule();
|
|
|
|
return ret;
|
|
}
|
|
@@ -1756,7 +1785,9 @@ static int __sched rt_mutex_slowlock(struct rt_mutex_base *lock,
|
|
static __always_inline int __rt_mutex_lock(struct rt_mutex_base *lock,
|
|
unsigned int state)
|
|
{
|
|
- if (likely(rt_mutex_cmpxchg_acquire(lock, NULL, current)))
|
|
+ lockdep_assert(!current->pi_blocked_on);
|
|
+
|
|
+ if (likely(rt_mutex_try_acquire(lock)))
|
|
return 0;
|
|
|
|
return rt_mutex_slowlock(lock, NULL, state);
|
|
diff --git a/kernel/locking/rwbase_rt.c b/kernel/locking/rwbase_rt.c
|
|
index 25ec0239477c..2eafd73a76eb 100644
|
|
--- a/kernel/locking/rwbase_rt.c
|
|
+++ b/kernel/locking/rwbase_rt.c
|
|
@@ -71,8 +71,20 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb,
|
|
struct rt_mutex_base *rtm = &rwb->rtmutex;
|
|
int ret;
|
|
|
|
+ rwbase_pre_schedule();
|
|
raw_spin_lock_irq(&rtm->wait_lock);
|
|
|
|
+ /*
|
|
+ * Allow readers, as long as the writer has not completely
|
|
+ * acquired the semaphore for write.
|
|
+ */
|
|
+ if (atomic_read(&rwb->readers) != WRITER_BIAS) {
|
|
+ atomic_inc(&rwb->readers);
|
|
+ raw_spin_unlock_irq(&rtm->wait_lock);
|
|
+ rwbase_post_schedule();
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
/*
|
|
* Call into the slow lock path with the rtmutex->wait_lock
|
|
* held, so this can't result in the following race:
|
|
@@ -125,12 +137,15 @@ static int __sched __rwbase_read_lock(struct rwbase_rt *rwb,
|
|
rwbase_rtmutex_unlock(rtm);
|
|
|
|
trace_contention_end(rwb, ret);
|
|
+ rwbase_post_schedule();
|
|
return ret;
|
|
}
|
|
|
|
static __always_inline int rwbase_read_lock(struct rwbase_rt *rwb,
|
|
unsigned int state)
|
|
{
|
|
+ lockdep_assert(!current->pi_blocked_on);
|
|
+
|
|
if (rwbase_read_trylock(rwb))
|
|
return 0;
|
|
|
|
@@ -237,6 +252,8 @@ static int __sched rwbase_write_lock(struct rwbase_rt *rwb,
|
|
/* Force readers into slow path */
|
|
atomic_sub(READER_BIAS, &rwb->readers);
|
|
|
|
+ rwbase_pre_schedule();
|
|
+
|
|
raw_spin_lock_irqsave(&rtm->wait_lock, flags);
|
|
if (__rwbase_write_trylock(rwb))
|
|
goto out_unlock;
|
|
@@ -248,6 +265,7 @@ static int __sched rwbase_write_lock(struct rwbase_rt *rwb,
|
|
if (rwbase_signal_pending_state(state, current)) {
|
|
rwbase_restore_current_state();
|
|
__rwbase_write_unlock(rwb, 0, flags);
|
|
+ rwbase_post_schedule();
|
|
trace_contention_end(rwb, -EINTR);
|
|
return -EINTR;
|
|
}
|
|
@@ -266,6 +284,7 @@ static int __sched rwbase_write_lock(struct rwbase_rt *rwb,
|
|
|
|
out_unlock:
|
|
raw_spin_unlock_irqrestore(&rtm->wait_lock, flags);
|
|
+ rwbase_post_schedule();
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c
|
|
index 11ed7ce6579e..62eac9fd809a 100644
|
|
--- a/kernel/locking/rwsem.c
|
|
+++ b/kernel/locking/rwsem.c
|
|
@@ -1427,8 +1427,14 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
|
|
#define rwbase_signal_pending_state(state, current) \
|
|
signal_pending_state(state, current)
|
|
|
|
+#define rwbase_pre_schedule() \
|
|
+ rt_mutex_pre_schedule()
|
|
+
|
|
#define rwbase_schedule() \
|
|
- schedule()
|
|
+ rt_mutex_schedule()
|
|
+
|
|
+#define rwbase_post_schedule() \
|
|
+ rt_mutex_post_schedule()
|
|
|
|
#include "rwbase_rt.c"
|
|
|
|
diff --git a/kernel/locking/spinlock_rt.c b/kernel/locking/spinlock_rt.c
|
|
index 48a19ed8486d..38e292454fcc 100644
|
|
--- a/kernel/locking/spinlock_rt.c
|
|
+++ b/kernel/locking/spinlock_rt.c
|
|
@@ -37,6 +37,8 @@
|
|
|
|
static __always_inline void rtlock_lock(struct rt_mutex_base *rtm)
|
|
{
|
|
+ lockdep_assert(!current->pi_blocked_on);
|
|
+
|
|
if (unlikely(!rt_mutex_cmpxchg_acquire(rtm, NULL, current)))
|
|
rtlock_slowlock(rtm);
|
|
}
|
|
@@ -184,9 +186,13 @@ static __always_inline int rwbase_rtmutex_trylock(struct rt_mutex_base *rtm)
|
|
|
|
#define rwbase_signal_pending_state(state, current) (0)
|
|
|
|
+#define rwbase_pre_schedule()
|
|
+
|
|
#define rwbase_schedule() \
|
|
schedule_rtlock()
|
|
|
|
+#define rwbase_post_schedule()
|
|
+
|
|
#include "rwbase_rt.c"
|
|
/*
|
|
* The common functions which get wrapped into the rwlock API.
|
|
diff --git a/kernel/locking/ww_rt_mutex.c b/kernel/locking/ww_rt_mutex.c
|
|
index d1473c624105..c7196de838ed 100644
|
|
--- a/kernel/locking/ww_rt_mutex.c
|
|
+++ b/kernel/locking/ww_rt_mutex.c
|
|
@@ -62,7 +62,7 @@ __ww_rt_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ww_ctx,
|
|
}
|
|
mutex_acquire_nest(&rtm->dep_map, 0, 0, nest_lock, ip);
|
|
|
|
- if (likely(rt_mutex_cmpxchg_acquire(&rtm->rtmutex, NULL, current))) {
|
|
+ if (likely(rt_mutex_try_acquire(&rtm->rtmutex))) {
|
|
if (ww_ctx)
|
|
ww_mutex_set_context_fastpath(lock, ww_ctx);
|
|
return 0;
|
|
diff --git a/kernel/panic.c b/kernel/panic.c
|
|
index ef9f9a4e928d..9215df21d8c2 100644
|
|
--- a/kernel/panic.c
|
|
+++ b/kernel/panic.c
|
|
@@ -366,6 +366,8 @@ void panic(const char *fmt, ...)
|
|
*/
|
|
atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
|
|
|
|
+ printk_legacy_allow_panic_sync();
|
|
+
|
|
panic_print_sys_info(false);
|
|
|
|
kmsg_dump(KMSG_DUMP_PANIC);
|
|
@@ -449,6 +451,7 @@ void panic(const char *fmt, ...)
|
|
* Explicitly flush the kernel log buffer one last time.
|
|
*/
|
|
console_flush_on_panic(CONSOLE_FLUSH_PENDING);
|
|
+ nbcon_atomic_flush_unsafe();
|
|
|
|
local_irq_enable();
|
|
for (i = 0; ; i += PANIC_TIMER_STEP) {
|
|
@@ -627,6 +630,7 @@ bool oops_may_print(void)
|
|
*/
|
|
void oops_enter(void)
|
|
{
|
|
+ nbcon_cpu_emergency_enter();
|
|
tracing_off();
|
|
/* can't trust the integrity of the kernel anymore: */
|
|
debug_locks_off();
|
|
@@ -649,6 +653,7 @@ void oops_exit(void)
|
|
{
|
|
do_oops_enter_exit();
|
|
print_oops_end_marker();
|
|
+ nbcon_cpu_emergency_exit();
|
|
kmsg_dump(KMSG_DUMP_OOPS);
|
|
}
|
|
|
|
@@ -660,6 +665,8 @@ struct warn_args {
|
|
void __warn(const char *file, int line, void *caller, unsigned taint,
|
|
struct pt_regs *regs, struct warn_args *args)
|
|
{
|
|
+ nbcon_cpu_emergency_enter();
|
|
+
|
|
disable_trace_on_warning();
|
|
|
|
if (file)
|
|
@@ -690,6 +697,8 @@ void __warn(const char *file, int line, void *caller, unsigned taint,
|
|
|
|
/* Just a warning, don't kill lockdep. */
|
|
add_taint(taint, LOCKDEP_STILL_OK);
|
|
+
|
|
+ nbcon_cpu_emergency_exit();
|
|
}
|
|
|
|
#ifdef CONFIG_BUG
|
|
diff --git a/kernel/printk/Makefile b/kernel/printk/Makefile
|
|
index f5b388e810b9..39a2b61c7232 100644
|
|
--- a/kernel/printk/Makefile
|
|
+++ b/kernel/printk/Makefile
|
|
@@ -1,6 +1,6 @@
|
|
# SPDX-License-Identifier: GPL-2.0-only
|
|
obj-y = printk.o
|
|
-obj-$(CONFIG_PRINTK) += printk_safe.o
|
|
+obj-$(CONFIG_PRINTK) += printk_safe.o nbcon.o
|
|
obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille.o
|
|
obj-$(CONFIG_PRINTK_INDEX) += index.o
|
|
|
|
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
|
|
index 7d4979d5c3ce..7db6992c54f3 100644
|
|
--- a/kernel/printk/internal.h
|
|
+++ b/kernel/printk/internal.h
|
|
@@ -3,6 +3,8 @@
|
|
* internal.h - printk internal definitions
|
|
*/
|
|
#include <linux/percpu.h>
|
|
+#include <linux/console.h>
|
|
+#include "printk_ringbuffer.h"
|
|
|
|
#if defined(CONFIG_PRINTK) && defined(CONFIG_SYSCTL)
|
|
void __init printk_sysctl_init(void);
|
|
@@ -12,6 +14,12 @@ int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write,
|
|
#define printk_sysctl_init() do { } while (0)
|
|
#endif
|
|
|
|
+#define con_printk(lvl, con, fmt, ...) \
|
|
+ printk(lvl pr_fmt("%s%sconsole [%s%d] " fmt), \
|
|
+ (con->flags & CON_NBCON) ? "" : "legacy ", \
|
|
+ (con->flags & CON_BOOT) ? "boot" : "", \
|
|
+ con->name, con->index, ##__VA_ARGS__)
|
|
+
|
|
#ifdef CONFIG_PRINTK
|
|
|
|
#ifdef CONFIG_PRINTK_CALLER
|
|
@@ -35,6 +43,19 @@ enum printk_info_flags {
|
|
LOG_CONT = 8, /* text is a fragment of a continuation line */
|
|
};
|
|
|
|
+extern struct printk_ringbuffer *prb;
|
|
+extern bool printk_threads_enabled;
|
|
+extern bool have_legacy_console;
|
|
+extern bool have_boot_console;
|
|
+
|
|
+/*
|
|
+ * Specifies if the console lock/unlock dance is needed for console
|
|
+ * printing. If @have_boot_console is true, the nbcon consoles will
|
|
+ * be printed serially along with the legacy consoles because nbcon
|
|
+ * consoles cannot print simultaneously with boot consoles.
|
|
+ */
|
|
+#define printing_via_unlock (have_legacy_console || have_boot_console)
|
|
+
|
|
__printf(4, 0)
|
|
int vprintk_store(int facility, int level,
|
|
const struct dev_printk_info *dev_info,
|
|
@@ -61,12 +82,90 @@ void defer_console_output(void);
|
|
|
|
u16 printk_parse_prefix(const char *text, int *level,
|
|
enum printk_info_flags *flags);
|
|
+void console_lock_spinning_enable(void);
|
|
+int console_lock_spinning_disable_and_check(int cookie);
|
|
+
|
|
+u64 nbcon_seq_read(struct console *con);
|
|
+void nbcon_seq_force(struct console *con, u64 seq);
|
|
+bool nbcon_alloc(struct console *con);
|
|
+void nbcon_init(struct console *con);
|
|
+void nbcon_free(struct console *con);
|
|
+enum nbcon_prio nbcon_get_default_prio(void);
|
|
+void nbcon_atomic_flush_all(void);
|
|
+bool nbcon_atomic_emit_next_record(struct console *con, bool *handover, int cookie);
|
|
+void nbcon_kthread_create(struct console *con);
|
|
+void nbcon_wake_threads(void);
|
|
+void nbcon_legacy_kthread_create(void);
|
|
+
|
|
+/*
|
|
+ * Check if the given console is currently capable and allowed to print
|
|
+ * records. Note that this function does not consider the current context,
|
|
+ * which can also play a role in deciding if @con can be used to print
|
|
+ * records.
|
|
+ */
|
|
+static inline bool console_is_usable(struct console *con, short flags, bool use_atomic)
|
|
+{
|
|
+ if (!(flags & CON_ENABLED))
|
|
+ return false;
|
|
+
|
|
+ if ((flags & CON_SUSPENDED))
|
|
+ return false;
|
|
+
|
|
+ if (flags & CON_NBCON) {
|
|
+ if (use_atomic) {
|
|
+ if (!con->write_atomic)
|
|
+ return false;
|
|
+ } else {
|
|
+ if (!con->write_thread || !con->kthread)
|
|
+ return false;
|
|
+ }
|
|
+ } else {
|
|
+ if (!con->write)
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Console drivers may assume that per-cpu resources have been
|
|
+ * allocated. So unless they're explicitly marked as being able to
|
|
+ * cope (CON_ANYTIME) don't call them until this CPU is officially up.
|
|
+ */
|
|
+ if (!cpu_online(raw_smp_processor_id()) && !(flags & CON_ANYTIME))
|
|
+ return false;
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_kthread_wake - Wake up a printk thread
|
|
+ * @con: Console to operate on
|
|
+ */
|
|
+static inline void nbcon_kthread_wake(struct console *con)
|
|
+{
|
|
+ /*
|
|
+ * Guarantee any new records can be seen by tasks preparing to wait
|
|
+ * before this context checks if the rcuwait is empty.
|
|
+ *
|
|
+ * The full memory barrier in rcuwait_wake_up() pairs with the full
|
|
+ * memory barrier within set_current_state() of
|
|
+ * ___rcuwait_wait_event(), which is called after prepare_to_rcuwait()
|
|
+ * adds the waiter but before it has checked the wait condition.
|
|
+ *
|
|
+ * This pairs with nbcon_kthread_func:A.
|
|
+ */
|
|
+ rcuwait_wake_up(&con->rcuwait); /* LMM(nbcon_kthread_wake:A) */
|
|
+}
|
|
+
|
|
#else
|
|
|
|
#define PRINTK_PREFIX_MAX 0
|
|
#define PRINTK_MESSAGE_MAX 0
|
|
#define PRINTKRB_RECORD_MAX 0
|
|
|
|
+static inline void nbcon_kthread_wake(struct console *con) { }
|
|
+static inline void nbcon_kthread_create(struct console *con) { }
|
|
+#define printk_threads_enabled (false)
|
|
+#define printing_via_unlock (false)
|
|
+
|
|
/*
|
|
* In !PRINTK builds we still export console_sem
|
|
* semaphore and some of console functions (console_unlock()/etc.), so
|
|
@@ -76,8 +175,23 @@ u16 printk_parse_prefix(const char *text, int *level,
|
|
#define printk_safe_exit_irqrestore(flags) local_irq_restore(flags)
|
|
|
|
static inline bool printk_percpu_data_ready(void) { return false; }
|
|
+static inline u64 nbcon_seq_read(struct console *con) { return 0; }
|
|
+static inline void nbcon_seq_force(struct console *con, u64 seq) { }
|
|
+static inline bool nbcon_alloc(struct console *con) { return false; }
|
|
+static inline void nbcon_init(struct console *con) { }
|
|
+static inline void nbcon_free(struct console *con) { }
|
|
+static inline enum nbcon_prio nbcon_get_default_prio(void) { return NBCON_PRIO_NONE; }
|
|
+static inline void nbcon_atomic_flush_all(void) { }
|
|
+static inline bool nbcon_atomic_emit_next_record(struct console *con, bool *handover,
|
|
+ int cookie) { return false; }
|
|
+
|
|
+static inline bool console_is_usable(struct console *con, short flags,
|
|
+ bool use_atomic) { return false; }
|
|
+
|
|
#endif /* CONFIG_PRINTK */
|
|
|
|
+extern struct printk_buffers printk_shared_pbufs;
|
|
+
|
|
/**
|
|
* struct printk_buffers - Buffers to read/format/output printk messages.
|
|
* @outbuf: After formatting, contains text to output.
|
|
@@ -105,3 +219,10 @@ struct printk_message {
|
|
};
|
|
|
|
bool other_cpu_in_panic(void);
|
|
+bool this_cpu_in_panic(void);
|
|
+bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
|
|
+ bool is_extended, bool may_supress);
|
|
+
|
|
+#ifdef CONFIG_PRINTK
|
|
+void console_prepend_dropped(struct printk_message *pmsg, unsigned long dropped);
|
|
+#endif
|
|
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
|
|
new file mode 100644
|
|
index 000000000000..b941039ee7d2
|
|
--- /dev/null
|
|
+++ b/kernel/printk/nbcon.c
|
|
@@ -0,0 +1,1665 @@
|
|
+// SPDX-License-Identifier: GPL-2.0-only
|
|
+// Copyright (C) 2022 Linutronix GmbH, John Ogness
|
|
+// Copyright (C) 2022 Intel, Thomas Gleixner
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/console.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/kthread.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/serial_core.h>
|
|
+#include <linux/syscore_ops.h>
|
|
+#include "printk_ringbuffer.h"
|
|
+#include "internal.h"
|
|
+/*
|
|
+ * Printk console printing implementation for consoles which does not depend
|
|
+ * on the legacy style console_lock mechanism.
|
|
+ *
|
|
+ * The state of the console is maintained in the "nbcon_state" atomic
|
|
+ * variable.
|
|
+ *
|
|
+ * The console is locked when:
|
|
+ *
|
|
+ * - The 'prio' field contains the priority of the context that owns the
|
|
+ * console. Only higher priority contexts are allowed to take over the
|
|
+ * lock. A value of 0 (NBCON_PRIO_NONE) means the console is not locked.
|
|
+ *
|
|
+ * - The 'cpu' field denotes on which CPU the console is locked. It is used
|
|
+ * to prevent busy waiting on the same CPU. Also it informs the lock owner
|
|
+ * that it has lost the lock in a more complex scenario when the lock was
|
|
+ * taken over by a higher priority context, released, and taken on another
|
|
+ * CPU with the same priority as the interrupted owner.
|
|
+ *
|
|
+ * The acquire mechanism uses a few more fields:
|
|
+ *
|
|
+ * - The 'req_prio' field is used by the handover approach to make the
|
|
+ * current owner aware that there is a context with a higher priority
|
|
+ * waiting for the friendly handover.
|
|
+ *
|
|
+ * - The 'unsafe' field allows to take over the console in a safe way in the
|
|
+ * middle of emitting a message. The field is set only when accessing some
|
|
+ * shared resources or when the console device is manipulated. It can be
|
|
+ * cleared, for example, after emitting one character when the console
|
|
+ * device is in a consistent state.
|
|
+ *
|
|
+ * - The 'unsafe_takeover' field is set when a hostile takeover took the
|
|
+ * console in an unsafe state. The console will stay in the unsafe state
|
|
+ * until re-initialized.
|
|
+ *
|
|
+ * The acquire mechanism uses three approaches:
|
|
+ *
|
|
+ * 1) Direct acquire when the console is not owned or is owned by a lower
|
|
+ * priority context and is in a safe state.
|
|
+ *
|
|
+ * 2) Friendly handover mechanism uses a request/grant handshake. It is used
|
|
+ * when the current owner has lower priority and the console is in an
|
|
+ * unsafe state.
|
|
+ *
|
|
+ * The requesting context:
|
|
+ *
|
|
+ * a) Sets its priority into the 'req_prio' field.
|
|
+ *
|
|
+ * b) Waits (with a timeout) for the owning context to unlock the
|
|
+ * console.
|
|
+ *
|
|
+ * c) Takes the lock and clears the 'req_prio' field.
|
|
+ *
|
|
+ * The owning context:
|
|
+ *
|
|
+ * a) Observes the 'req_prio' field set on exit from the unsafe
|
|
+ * console state.
|
|
+ *
|
|
+ * b) Gives up console ownership by clearing the 'prio' field.
|
|
+ *
|
|
+ * 3) Unsafe hostile takeover allows to take over the lock even when the
|
|
+ * console is an unsafe state. It is used only in panic() by the final
|
|
+ * attempt to flush consoles in a try and hope mode.
|
|
+ *
|
|
+ * Note that separate record buffers are used in panic(). As a result,
|
|
+ * the messages can be read and formatted without any risk even after
|
|
+ * using the hostile takeover in unsafe state.
|
|
+ *
|
|
+ * The release function simply clears the 'prio' field.
|
|
+ *
|
|
+ * All operations on @console::nbcon_state are atomic cmpxchg based to
|
|
+ * handle concurrency.
|
|
+ *
|
|
+ * The acquire/release functions implement only minimal policies:
|
|
+ *
|
|
+ * - Preference for higher priority contexts.
|
|
+ * - Protection of the panic CPU.
|
|
+ *
|
|
+ * All other policy decisions must be made at the call sites:
|
|
+ *
|
|
+ * - What is marked as an unsafe section.
|
|
+ * - Whether to spin-wait if there is already an owner and the console is
|
|
+ * in an unsafe state.
|
|
+ * - Whether to attempt an unsafe hostile takeover.
|
|
+ *
|
|
+ * The design allows to implement the well known:
|
|
+ *
|
|
+ * acquire()
|
|
+ * output_one_printk_record()
|
|
+ * release()
|
|
+ *
|
|
+ * The output of one printk record might be interrupted with a higher priority
|
|
+ * context. The new owner is supposed to reprint the entire interrupted record
|
|
+ * from scratch.
|
|
+ */
|
|
+
|
|
+/**
|
|
+ * nbcon_state_set - Helper function to set the console state
|
|
+ * @con: Console to update
|
|
+ * @new: The new state to write
|
|
+ *
|
|
+ * Only to be used when the console is not yet or no longer visible in the
|
|
+ * system. Otherwise use nbcon_state_try_cmpxchg().
|
|
+ */
|
|
+static inline void nbcon_state_set(struct console *con, struct nbcon_state *new)
|
|
+{
|
|
+ atomic_set(&ACCESS_PRIVATE(con, nbcon_state), new->atom);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_state_read - Helper function to read the console state
|
|
+ * @con: Console to read
|
|
+ * @state: The state to store the result
|
|
+ */
|
|
+static inline void nbcon_state_read(struct console *con, struct nbcon_state *state)
|
|
+{
|
|
+ state->atom = atomic_read(&ACCESS_PRIVATE(con, nbcon_state));
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_state_try_cmpxchg() - Helper function for atomic_try_cmpxchg() on console state
|
|
+ * @con: Console to update
|
|
+ * @cur: Old/expected state
|
|
+ * @new: New state
|
|
+ *
|
|
+ * Return: True on success. False on fail and @cur is updated.
|
|
+ */
|
|
+static inline bool nbcon_state_try_cmpxchg(struct console *con, struct nbcon_state *cur,
|
|
+ struct nbcon_state *new)
|
|
+{
|
|
+ return atomic_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_state), &cur->atom, new->atom);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_seq_read - Read the current console sequence
|
|
+ * @con: Console to read the sequence of
|
|
+ *
|
|
+ * Return: Sequence number of the next record to print on @con.
|
|
+ */
|
|
+u64 nbcon_seq_read(struct console *con)
|
|
+{
|
|
+ unsigned long nbcon_seq = atomic_long_read(&ACCESS_PRIVATE(con, nbcon_seq));
|
|
+
|
|
+ return __ulseq_to_u64seq(prb, nbcon_seq);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_seq_force - Force console sequence to a specific value
|
|
+ * @con: Console to work on
|
|
+ * @seq: Sequence number value to set
|
|
+ *
|
|
+ * Only to be used during init (before registration) or in extreme situations
|
|
+ * (such as panic with CONSOLE_REPLAY_ALL).
|
|
+ */
|
|
+void nbcon_seq_force(struct console *con, u64 seq)
|
|
+{
|
|
+ /*
|
|
+ * If the specified record no longer exists, the oldest available record
|
|
+ * is chosen. This is especially important on 32bit systems because only
|
|
+ * the lower 32 bits of the sequence number are stored. The upper 32 bits
|
|
+ * are derived from the sequence numbers available in the ringbuffer.
|
|
+ */
|
|
+ u64 valid_seq = max_t(u64, seq, prb_first_valid_seq(prb));
|
|
+
|
|
+ atomic_long_set(&ACCESS_PRIVATE(con, nbcon_seq), __u64seq_to_ulseq(valid_seq));
|
|
+
|
|
+ /* Clear con->seq since nbcon consoles use con->nbcon_seq instead. */
|
|
+ con->seq = 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_seq_try_update - Try to update the console sequence number
|
|
+ * @ctxt: Pointer to an acquire context that contains
|
|
+ * all information about the acquire mode
|
|
+ * @new_seq: The new sequence number to set
|
|
+ *
|
|
+ * @ctxt->seq is updated to the new value of @con::nbcon_seq (expanded to
|
|
+ * the 64bit value). This could be a different value than @new_seq if
|
|
+ * nbcon_seq_force() was used or the current context no longer owns the
|
|
+ * console. In the later case, it will stop printing anyway.
|
|
+ */
|
|
+static void nbcon_seq_try_update(struct nbcon_context *ctxt, u64 new_seq)
|
|
+{
|
|
+ unsigned long nbcon_seq = __u64seq_to_ulseq(ctxt->seq);
|
|
+ struct console *con = ctxt->console;
|
|
+
|
|
+ if (atomic_long_try_cmpxchg(&ACCESS_PRIVATE(con, nbcon_seq), &nbcon_seq,
|
|
+ __u64seq_to_ulseq(new_seq))) {
|
|
+ ctxt->seq = new_seq;
|
|
+ } else {
|
|
+ ctxt->seq = nbcon_seq_read(con);
|
|
+ }
|
|
+}
|
|
+
|
|
+bool printk_threads_enabled __ro_after_init;
|
|
+
|
|
+/**
|
|
+ * nbcon_context_try_acquire_direct - Try to acquire directly
|
|
+ * @ctxt: The context of the caller
|
|
+ * @cur: The current console state
|
|
+ *
|
|
+ * Acquire the console when it is released. Also acquire the console when
|
|
+ * the current owner has a lower priority and the console is in a safe state.
|
|
+ *
|
|
+ * Return: 0 on success. Otherwise, an error code on failure. Also @cur
|
|
+ * is updated to the latest state when failed to modify it.
|
|
+ *
|
|
+ * Errors:
|
|
+ *
|
|
+ * -EPERM: A panic is in progress and this is not the panic CPU.
|
|
+ * Or the current owner or waiter has the same or higher
|
|
+ * priority. No acquire method can be successful in
|
|
+ * this case.
|
|
+ *
|
|
+ * -EBUSY: The current owner has a lower priority but the console
|
|
+ * in an unsafe state. The caller should try using
|
|
+ * the handover acquire method.
|
|
+ */
|
|
+static int nbcon_context_try_acquire_direct(struct nbcon_context *ctxt,
|
|
+ struct nbcon_state *cur)
|
|
+{
|
|
+ unsigned int cpu = smp_processor_id();
|
|
+ struct console *con = ctxt->console;
|
|
+ struct nbcon_state new;
|
|
+
|
|
+ do {
|
|
+ if (other_cpu_in_panic())
|
|
+ return -EPERM;
|
|
+
|
|
+ if (ctxt->prio <= cur->prio || ctxt->prio <= cur->req_prio)
|
|
+ return -EPERM;
|
|
+
|
|
+ if (cur->unsafe)
|
|
+ return -EBUSY;
|
|
+
|
|
+ /*
|
|
+ * The console should never be safe for a direct acquire
|
|
+ * if an unsafe hostile takeover has ever happened.
|
|
+ */
|
|
+ WARN_ON_ONCE(cur->unsafe_takeover);
|
|
+
|
|
+ new.atom = cur->atom;
|
|
+ new.prio = ctxt->prio;
|
|
+ new.req_prio = NBCON_PRIO_NONE;
|
|
+ new.unsafe = cur->unsafe_takeover;
|
|
+ new.cpu = cpu;
|
|
+
|
|
+ } while (!nbcon_state_try_cmpxchg(con, cur, &new));
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static bool nbcon_waiter_matches(struct nbcon_state *cur, int expected_prio)
|
|
+{
|
|
+ /*
|
|
+ * The request context is well defined by the @req_prio because:
|
|
+ *
|
|
+ * - Only a context with a higher priority can take over the request.
|
|
+ * - There are only three priorities.
|
|
+ * - Only one CPU is allowed to request PANIC priority.
|
|
+ * - Lower priorities are ignored during panic() until reboot.
|
|
+ *
|
|
+ * As a result, the following scenario is *not* possible:
|
|
+ *
|
|
+ * 1. Another context with a higher priority directly takes ownership.
|
|
+ * 2. The higher priority context releases the ownership.
|
|
+ * 3. A lower priority context takes the ownership.
|
|
+ * 4. Another context with the same priority as this context
|
|
+ * creates a request and starts waiting.
|
|
+ */
|
|
+
|
|
+ return (cur->req_prio == expected_prio);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_context_try_acquire_requested - Try to acquire after having
|
|
+ * requested a handover
|
|
+ * @ctxt: The context of the caller
|
|
+ * @cur: The current console state
|
|
+ *
|
|
+ * This is a helper function for nbcon_context_try_acquire_handover().
|
|
+ * It is called when the console is in an unsafe state. The current
|
|
+ * owner will release the console on exit from the unsafe region.
|
|
+ *
|
|
+ * Return: 0 on success and @cur is updated to the new console state.
|
|
+ * Otherwise an error code on failure.
|
|
+ *
|
|
+ * Errors:
|
|
+ *
|
|
+ * -EPERM: A panic is in progress and this is not the panic CPU
|
|
+ * or this context is no longer the waiter.
|
|
+ *
|
|
+ * -EBUSY: The console is still locked. The caller should
|
|
+ * continue waiting.
|
|
+ *
|
|
+ * Note: The caller must still remove the request when an error has occurred
|
|
+ * except when this context is no longer the waiter.
|
|
+ */
|
|
+static int nbcon_context_try_acquire_requested(struct nbcon_context *ctxt,
|
|
+ struct nbcon_state *cur)
|
|
+{
|
|
+ unsigned int cpu = smp_processor_id();
|
|
+ struct console *con = ctxt->console;
|
|
+ struct nbcon_state new;
|
|
+
|
|
+ /* Note that the caller must still remove the request! */
|
|
+ if (other_cpu_in_panic())
|
|
+ return -EPERM;
|
|
+
|
|
+ /*
|
|
+ * Note that the waiter will also change if there was an unsafe
|
|
+ * hostile takeover.
|
|
+ */
|
|
+ if (!nbcon_waiter_matches(cur, ctxt->prio))
|
|
+ return -EPERM;
|
|
+
|
|
+ /* If still locked, caller should continue waiting. */
|
|
+ if (cur->prio != NBCON_PRIO_NONE)
|
|
+ return -EBUSY;
|
|
+
|
|
+ /*
|
|
+ * The previous owner should have never released ownership
|
|
+ * in an unsafe region.
|
|
+ */
|
|
+ WARN_ON_ONCE(cur->unsafe);
|
|
+
|
|
+ new.atom = cur->atom;
|
|
+ new.prio = ctxt->prio;
|
|
+ new.req_prio = NBCON_PRIO_NONE;
|
|
+ new.unsafe = cur->unsafe_takeover;
|
|
+ new.cpu = cpu;
|
|
+
|
|
+ if (!nbcon_state_try_cmpxchg(con, cur, &new)) {
|
|
+ /*
|
|
+ * The acquire could fail only when it has been taken
|
|
+ * over by a higher priority context.
|
|
+ */
|
|
+ WARN_ON_ONCE(nbcon_waiter_matches(cur, ctxt->prio));
|
|
+ return -EPERM;
|
|
+ }
|
|
+
|
|
+ /* Handover success. This context now owns the console. */
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_context_try_acquire_handover - Try to acquire via handover
|
|
+ * @ctxt: The context of the caller
|
|
+ * @cur: The current console state
|
|
+ *
|
|
+ * The function must be called only when the context has higher priority
|
|
+ * than the current owner and the console is in an unsafe state.
|
|
+ * It is the case when nbcon_context_try_acquire_direct() returns -EBUSY.
|
|
+ *
|
|
+ * The function sets "req_prio" field to make the current owner aware of
|
|
+ * the request. Then it waits until the current owner releases the console,
|
|
+ * or an even higher context takes over the request, or timeout expires.
|
|
+ *
|
|
+ * The current owner checks the "req_prio" field on exit from the unsafe
|
|
+ * region and releases the console. It does not touch the "req_prio" field
|
|
+ * so that the console stays reserved for the waiter.
|
|
+ *
|
|
+ * Return: 0 on success. Otherwise, an error code on failure. Also @cur
|
|
+ * is updated to the latest state when failed to modify it.
|
|
+ *
|
|
+ * Errors:
|
|
+ *
|
|
+ * -EPERM: A panic is in progress and this is not the panic CPU.
|
|
+ * Or a higher priority context has taken over the
|
|
+ * console or the handover request.
|
|
+ *
|
|
+ * -EBUSY: The current owner is on the same CPU so that the hand
|
|
+ * shake could not work. Or the current owner is not
|
|
+ * willing to wait (zero timeout). Or the console does
|
|
+ * not enter the safe state before timeout passed. The
|
|
+ * caller might still use the unsafe hostile takeover
|
|
+ * when allowed.
|
|
+ *
|
|
+ * -EAGAIN: @cur has changed when creating the handover request.
|
|
+ * The caller should retry with direct acquire.
|
|
+ */
|
|
+static int nbcon_context_try_acquire_handover(struct nbcon_context *ctxt,
|
|
+ struct nbcon_state *cur)
|
|
+{
|
|
+ unsigned int cpu = smp_processor_id();
|
|
+ struct console *con = ctxt->console;
|
|
+ struct nbcon_state new;
|
|
+ int timeout;
|
|
+ int request_err = -EBUSY;
|
|
+
|
|
+ /*
|
|
+ * Check that the handover is called when the direct acquire failed
|
|
+ * with -EBUSY.
|
|
+ */
|
|
+ WARN_ON_ONCE(ctxt->prio <= cur->prio || ctxt->prio <= cur->req_prio);
|
|
+ WARN_ON_ONCE(!cur->unsafe);
|
|
+
|
|
+ /* Handover is not possible on the same CPU. */
|
|
+ if (cur->cpu == cpu)
|
|
+ return -EBUSY;
|
|
+
|
|
+ /*
|
|
+ * Console stays unsafe after an unsafe takeover until re-initialized.
|
|
+ * Waiting is not going to help in this case.
|
|
+ */
|
|
+ if (cur->unsafe_takeover)
|
|
+ return -EBUSY;
|
|
+
|
|
+ /* Is the caller willing to wait? */
|
|
+ if (ctxt->spinwait_max_us == 0)
|
|
+ return -EBUSY;
|
|
+
|
|
+ /*
|
|
+ * Setup a request for the handover. The caller should try to acquire
|
|
+ * the console directly when the current state has been modified.
|
|
+ */
|
|
+ new.atom = cur->atom;
|
|
+ new.req_prio = ctxt->prio;
|
|
+ if (!nbcon_state_try_cmpxchg(con, cur, &new))
|
|
+ return -EAGAIN;
|
|
+
|
|
+ cur->atom = new.atom;
|
|
+
|
|
+ /* Wait until there is no owner and then acquire the console. */
|
|
+ for (timeout = ctxt->spinwait_max_us; timeout >= 0; timeout--) {
|
|
+ /* On successful acquire, this request is cleared. */
|
|
+ request_err = nbcon_context_try_acquire_requested(ctxt, cur);
|
|
+ if (!request_err)
|
|
+ return 0;
|
|
+
|
|
+ /*
|
|
+ * If the acquire should be aborted, it must be ensured
|
|
+ * that the request is removed before returning to caller.
|
|
+ */
|
|
+ if (request_err == -EPERM)
|
|
+ break;
|
|
+
|
|
+ udelay(1);
|
|
+
|
|
+ /* Re-read the state because some time has passed. */
|
|
+ nbcon_state_read(con, cur);
|
|
+ }
|
|
+
|
|
+ /* Timed out or aborted. Carefully remove handover request. */
|
|
+ do {
|
|
+ /*
|
|
+ * No need to remove request if there is a new waiter. This
|
|
+ * can only happen if a higher priority context has taken over
|
|
+ * the console or the handover request.
|
|
+ */
|
|
+ if (!nbcon_waiter_matches(cur, ctxt->prio))
|
|
+ return -EPERM;
|
|
+
|
|
+ /* Unset request for handover. */
|
|
+ new.atom = cur->atom;
|
|
+ new.req_prio = NBCON_PRIO_NONE;
|
|
+ if (nbcon_state_try_cmpxchg(con, cur, &new)) {
|
|
+ /*
|
|
+ * Request successfully unset. Report failure of
|
|
+ * acquiring via handover.
|
|
+ */
|
|
+ cur->atom = new.atom;
|
|
+ return request_err;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Unable to remove request. Try to acquire in case
|
|
+ * the owner has released the lock.
|
|
+ */
|
|
+ } while (nbcon_context_try_acquire_requested(ctxt, cur));
|
|
+
|
|
+ /* Lucky timing. The acquire succeeded while removing the request. */
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_context_try_acquire_hostile - Acquire via unsafe hostile takeover
|
|
+ * @ctxt: The context of the caller
|
|
+ * @cur: The current console state
|
|
+ *
|
|
+ * Acquire the console even in the unsafe state.
|
|
+ *
|
|
+ * It can be permitted by setting the 'allow_unsafe_takeover' field only
|
|
+ * by the final attempt to flush messages in panic().
|
|
+ *
|
|
+ * Return: 0 on success. -EPERM when not allowed by the context.
|
|
+ */
|
|
+static int nbcon_context_try_acquire_hostile(struct nbcon_context *ctxt,
|
|
+ struct nbcon_state *cur)
|
|
+{
|
|
+ unsigned int cpu = smp_processor_id();
|
|
+ struct console *con = ctxt->console;
|
|
+ struct nbcon_state new;
|
|
+
|
|
+ if (!ctxt->allow_unsafe_takeover)
|
|
+ return -EPERM;
|
|
+
|
|
+ /* Ensure caller is allowed to perform unsafe hostile takeovers. */
|
|
+ if (WARN_ON_ONCE(ctxt->prio != NBCON_PRIO_PANIC))
|
|
+ return -EPERM;
|
|
+
|
|
+ /*
|
|
+ * Check that try_acquire_direct() and try_acquire_handover() returned
|
|
+ * -EBUSY in the right situation.
|
|
+ */
|
|
+ WARN_ON_ONCE(ctxt->prio <= cur->prio || ctxt->prio <= cur->req_prio);
|
|
+ WARN_ON_ONCE(cur->unsafe != true);
|
|
+
|
|
+ do {
|
|
+ new.atom = cur->atom;
|
|
+ new.cpu = cpu;
|
|
+ new.prio = ctxt->prio;
|
|
+ new.unsafe |= cur->unsafe_takeover;
|
|
+ new.unsafe_takeover |= cur->unsafe;
|
|
+
|
|
+ } while (!nbcon_state_try_cmpxchg(con, cur, &new));
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct printk_buffers panic_nbcon_pbufs;
|
|
+
|
|
+/**
|
|
+ * nbcon_context_try_acquire - Try to acquire nbcon console
|
|
+ * @ctxt: The context of the caller
|
|
+ *
|
|
+ * Context: Any context which could not be migrated to another CPU.
|
|
+ * Return: True if the console was acquired. False otherwise.
|
|
+ *
|
|
+ * If the caller allowed an unsafe hostile takeover, on success the
|
|
+ * caller should check the current console state to see if it is
|
|
+ * in an unsafe state. Otherwise, on success the caller may assume
|
|
+ * the console is not in an unsafe state.
|
|
+ */
|
|
+static bool nbcon_context_try_acquire(struct nbcon_context *ctxt)
|
|
+{
|
|
+ unsigned int cpu = smp_processor_id();
|
|
+ struct console *con = ctxt->console;
|
|
+ struct nbcon_state cur;
|
|
+ int err;
|
|
+
|
|
+ nbcon_state_read(con, &cur);
|
|
+try_again:
|
|
+ err = nbcon_context_try_acquire_direct(ctxt, &cur);
|
|
+ if (err != -EBUSY)
|
|
+ goto out;
|
|
+
|
|
+ err = nbcon_context_try_acquire_handover(ctxt, &cur);
|
|
+ if (err == -EAGAIN)
|
|
+ goto try_again;
|
|
+ if (err != -EBUSY)
|
|
+ goto out;
|
|
+
|
|
+ err = nbcon_context_try_acquire_hostile(ctxt, &cur);
|
|
+out:
|
|
+ if (err)
|
|
+ return false;
|
|
+
|
|
+ /* Acquire succeeded. */
|
|
+
|
|
+ /* Assign the appropriate buffer for this context. */
|
|
+ if (atomic_read(&panic_cpu) == cpu)
|
|
+ ctxt->pbufs = &panic_nbcon_pbufs;
|
|
+ else
|
|
+ ctxt->pbufs = con->pbufs;
|
|
+
|
|
+ /* Set the record sequence for this context to print. */
|
|
+ ctxt->seq = nbcon_seq_read(ctxt->console);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+static bool nbcon_owner_matches(struct nbcon_state *cur, int expected_cpu,
|
|
+ int expected_prio)
|
|
+{
|
|
+ /*
|
|
+ * Since consoles can only be acquired by higher priorities,
|
|
+ * owning contexts are uniquely identified by @prio. However,
|
|
+ * since contexts can unexpectedly lose ownership, it is
|
|
+ * possible that later another owner appears with the same
|
|
+ * priority. For this reason @cpu is also needed.
|
|
+ */
|
|
+
|
|
+ if (cur->prio != expected_prio)
|
|
+ return false;
|
|
+
|
|
+ if (cur->cpu != expected_cpu)
|
|
+ return false;
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_context_release - Release the console
|
|
+ * @ctxt: The nbcon context from nbcon_context_try_acquire()
|
|
+ */
|
|
+static void nbcon_context_release(struct nbcon_context *ctxt)
|
|
+{
|
|
+ unsigned int cpu = smp_processor_id();
|
|
+ struct console *con = ctxt->console;
|
|
+ struct nbcon_state cur;
|
|
+ struct nbcon_state new;
|
|
+
|
|
+ nbcon_state_read(con, &cur);
|
|
+
|
|
+ do {
|
|
+ if (!nbcon_owner_matches(&cur, cpu, ctxt->prio))
|
|
+ break;
|
|
+
|
|
+ new.atom = cur.atom;
|
|
+ new.prio = NBCON_PRIO_NONE;
|
|
+
|
|
+ /*
|
|
+ * If @unsafe_takeover is set, it is kept set so that
|
|
+ * the state remains permanently unsafe.
|
|
+ */
|
|
+ new.unsafe |= cur.unsafe_takeover;
|
|
+
|
|
+ } while (!nbcon_state_try_cmpxchg(con, &cur, &new));
|
|
+
|
|
+ ctxt->pbufs = NULL;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_context_can_proceed - Check whether ownership can proceed
|
|
+ * @ctxt: The nbcon context from nbcon_context_try_acquire()
|
|
+ * @cur: The current console state
|
|
+ *
|
|
+ * Return: True if this context still owns the console. False if
|
|
+ * ownership was handed over or taken.
|
|
+ *
|
|
+ * Must be invoked when entering the unsafe state to make sure that it still
|
|
+ * owns the lock. Also must be invoked when exiting the unsafe context
|
|
+ * to eventually free the lock for a higher priority context which asked
|
|
+ * for the friendly handover.
|
|
+ *
|
|
+ * It can be called inside an unsafe section when the console is just
|
|
+ * temporary in safe state instead of exiting and entering the unsafe
|
|
+ * state.
|
|
+ *
|
|
+ * Also it can be called in the safe context before doing an expensive
|
|
+ * safe operation. It does not make sense to do the operation when
|
|
+ * a higher priority context took the lock.
|
|
+ *
|
|
+ * When this function returns false then the calling context no longer owns
|
|
+ * the console and is no longer allowed to go forward. In this case it must
|
|
+ * back out immediately and carefully. The buffer content is also no longer
|
|
+ * trusted since it no longer belongs to the calling context.
|
|
+ */
|
|
+static bool nbcon_context_can_proceed(struct nbcon_context *ctxt, struct nbcon_state *cur)
|
|
+{
|
|
+ unsigned int cpu = smp_processor_id();
|
|
+
|
|
+ /* Make sure this context still owns the console. */
|
|
+ if (!nbcon_owner_matches(cur, cpu, ctxt->prio))
|
|
+ return false;
|
|
+
|
|
+ /* The console owner can proceed if there is no waiter. */
|
|
+ if (cur->req_prio == NBCON_PRIO_NONE)
|
|
+ return true;
|
|
+
|
|
+ /*
|
|
+ * A console owner within an unsafe region is always allowed to
|
|
+ * proceed, even if there are waiters. It can perform a handover
|
|
+ * when exiting the unsafe region. Otherwise the waiter will
|
|
+ * need to perform an unsafe hostile takeover.
|
|
+ */
|
|
+ if (cur->unsafe)
|
|
+ return true;
|
|
+
|
|
+ /* Waiters always have higher priorities than owners. */
|
|
+ WARN_ON_ONCE(cur->req_prio <= cur->prio);
|
|
+
|
|
+ /*
|
|
+ * Having a safe point for take over and eventually a few
|
|
+ * duplicated characters or a full line is way better than a
|
|
+ * hostile takeover. Post processing can take care of the garbage.
|
|
+ * Release and hand over.
|
|
+ */
|
|
+ nbcon_context_release(ctxt);
|
|
+
|
|
+ /*
|
|
+ * It is not clear whether the waiter really took over ownership. The
|
|
+ * outermost callsite must make the final decision whether console
|
|
+ * ownership is needed for it to proceed. If yes, it must reacquire
|
|
+ * ownership (possibly hostile) before carefully proceeding.
|
|
+ *
|
|
+ * The calling context no longer owns the console so go back all the
|
|
+ * way instead of trying to implement reacquire heuristics in tons of
|
|
+ * places.
|
|
+ */
|
|
+ return false;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_can_proceed - Check whether ownership can proceed
|
|
+ * @wctxt: The write context that was handed to the write function
|
|
+ *
|
|
+ * Return: True if this context still owns the console. False if
|
|
+ * ownership was handed over or taken.
|
|
+ *
|
|
+ * It is used in nbcon_enter_unsafe() to make sure that it still owns the
|
|
+ * lock. Also it is used in nbcon_exit_unsafe() to eventually free the lock
|
|
+ * for a higher priority context which asked for the friendly handover.
|
|
+ *
|
|
+ * It can be called inside an unsafe section when the console is just
|
|
+ * temporary in safe state instead of exiting and entering the unsafe state.
|
|
+ *
|
|
+ * Also it can be called in the safe context before doing an expensive safe
|
|
+ * operation. It does not make sense to do the operation when a higher
|
|
+ * priority context took the lock.
|
|
+ *
|
|
+ * When this function returns false then the calling context no longer owns
|
|
+ * the console and is no longer allowed to go forward. In this case it must
|
|
+ * back out immediately and carefully. The buffer content is also no longer
|
|
+ * trusted since it no longer belongs to the calling context.
|
|
+ */
|
|
+bool nbcon_can_proceed(struct nbcon_write_context *wctxt)
|
|
+{
|
|
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
|
|
+ struct console *con = ctxt->console;
|
|
+ struct nbcon_state cur;
|
|
+
|
|
+ nbcon_state_read(con, &cur);
|
|
+
|
|
+ return nbcon_context_can_proceed(ctxt, &cur);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(nbcon_can_proceed);
|
|
+
|
|
+#define nbcon_context_enter_unsafe(c) __nbcon_context_update_unsafe(c, true)
|
|
+#define nbcon_context_exit_unsafe(c) __nbcon_context_update_unsafe(c, false)
|
|
+
|
|
+/**
|
|
+ * __nbcon_context_update_unsafe - Update the unsafe bit in @con->nbcon_state
|
|
+ * @ctxt: The nbcon context from nbcon_context_try_acquire()
|
|
+ * @unsafe: The new value for the unsafe bit
|
|
+ *
|
|
+ * Return: True if the unsafe state was updated and this context still
|
|
+ * owns the console. Otherwise false if ownership was handed
|
|
+ * over or taken.
|
|
+ *
|
|
+ * This function allows console owners to modify the unsafe status of the
|
|
+ * console.
|
|
+ *
|
|
+ * When this function returns false then the calling context no longer owns
|
|
+ * the console and is no longer allowed to go forward. In this case it must
|
|
+ * back out immediately and carefully. The buffer content is also no longer
|
|
+ * trusted since it no longer belongs to the calling context.
|
|
+ *
|
|
+ * Internal helper to avoid duplicated code.
|
|
+ */
|
|
+static bool __nbcon_context_update_unsafe(struct nbcon_context *ctxt, bool unsafe)
|
|
+{
|
|
+ struct console *con = ctxt->console;
|
|
+ struct nbcon_state cur;
|
|
+ struct nbcon_state new;
|
|
+
|
|
+ nbcon_state_read(con, &cur);
|
|
+
|
|
+ do {
|
|
+ /*
|
|
+ * The unsafe bit must not be cleared if an
|
|
+ * unsafe hostile takeover has occurred.
|
|
+ */
|
|
+ if (!unsafe && cur.unsafe_takeover)
|
|
+ goto out;
|
|
+
|
|
+ if (!nbcon_context_can_proceed(ctxt, &cur))
|
|
+ return false;
|
|
+
|
|
+ new.atom = cur.atom;
|
|
+ new.unsafe = unsafe;
|
|
+ } while (!nbcon_state_try_cmpxchg(con, &cur, &new));
|
|
+
|
|
+ cur.atom = new.atom;
|
|
+out:
|
|
+ return nbcon_context_can_proceed(ctxt, &cur);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_enter_unsafe - Enter an unsafe region in the driver
|
|
+ * @wctxt: The write context that was handed to the write function
|
|
+ *
|
|
+ * Return: True if this context still owns the console. False if
|
|
+ * ownership was handed over or taken.
|
|
+ *
|
|
+ * When this function returns false then the calling context no longer owns
|
|
+ * the console and is no longer allowed to go forward. In this case it must
|
|
+ * back out immediately and carefully. The buffer content is also no longer
|
|
+ * trusted since it no longer belongs to the calling context.
|
|
+ */
|
|
+bool nbcon_enter_unsafe(struct nbcon_write_context *wctxt)
|
|
+{
|
|
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
|
|
+
|
|
+ return nbcon_context_enter_unsafe(ctxt);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(nbcon_enter_unsafe);
|
|
+
|
|
+/**
|
|
+ * nbcon_exit_unsafe - Exit an unsafe region in the driver
|
|
+ * @wctxt: The write context that was handed to the write function
|
|
+ *
|
|
+ * Return: True if this context still owns the console. False if
|
|
+ * ownership was handed over or taken.
|
|
+ *
|
|
+ * When this function returns false then the calling context no longer owns
|
|
+ * the console and is no longer allowed to go forward. In this case it must
|
|
+ * back out immediately and carefully. The buffer content is also no longer
|
|
+ * trusted since it no longer belongs to the calling context.
|
|
+ */
|
|
+bool nbcon_exit_unsafe(struct nbcon_write_context *wctxt)
|
|
+{
|
|
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
|
|
+
|
|
+ return nbcon_context_exit_unsafe(ctxt);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(nbcon_exit_unsafe);
|
|
+
|
|
+/**
|
|
+ * nbcon_reacquire - Reacquire a console after losing ownership
|
|
+ * @wctxt: The write context that was handed to the write function
|
|
+ *
|
|
+ * Since ownership can be lost at any time due to handover or takeover, a
|
|
+ * printing context _should_ be prepared to back out immediately and
|
|
+ * carefully. However, there are many scenarios where the context _must_
|
|
+ * reacquire ownership in order to finalize or revert hardware changes.
|
|
+ *
|
|
+ * This function allows a context to reacquire ownership using the same
|
|
+ * priority as its previous ownership.
|
|
+ *
|
|
+ * Note that for printing contexts, after a successful reacquire the
|
|
+ * context will have no output buffer because that has been lost. This
|
|
+ * function cannot be used to resume printing.
|
|
+ */
|
|
+void nbcon_reacquire(struct nbcon_write_context *wctxt)
|
|
+{
|
|
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
|
|
+ struct console *con = ctxt->console;
|
|
+ struct nbcon_state cur;
|
|
+
|
|
+ while (!nbcon_context_try_acquire(ctxt))
|
|
+ cpu_relax();
|
|
+
|
|
+ wctxt->outbuf = NULL;
|
|
+ wctxt->len = 0;
|
|
+ nbcon_state_read(con, &cur);
|
|
+ wctxt->unsafe_takeover = cur.unsafe_takeover;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(nbcon_reacquire);
|
|
+
|
|
+/**
|
|
+ * nbcon_emit_next_record - Emit a record in the acquired context
|
|
+ * @wctxt: The write context that will be handed to the write function
|
|
+ * @use_atomic: True if the write_atomic callback is to be used
|
|
+ *
|
|
+ * Return: True if this context still owns the console. False if
|
|
+ * ownership was handed over or taken.
|
|
+ *
|
|
+ * When this function returns false then the calling context no longer owns
|
|
+ * the console and is no longer allowed to go forward. In this case it must
|
|
+ * back out immediately and carefully. The buffer content is also no longer
|
|
+ * trusted since it no longer belongs to the calling context. If the caller
|
|
+ * wants to do more it must reacquire the console first.
|
|
+ *
|
|
+ * When true is returned, @wctxt->ctxt.backlog indicates whether there are
|
|
+ * still records pending in the ringbuffer,
|
|
+ */
|
|
+static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt, bool use_atomic)
|
|
+{
|
|
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
|
|
+ struct console *con = ctxt->console;
|
|
+ bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED;
|
|
+ struct printk_message pmsg = {
|
|
+ .pbufs = ctxt->pbufs,
|
|
+ };
|
|
+ unsigned long con_dropped;
|
|
+ struct nbcon_state cur;
|
|
+ unsigned long dropped;
|
|
+ bool done = false;
|
|
+
|
|
+ /*
|
|
+ * The printk buffers are filled within an unsafe section. This
|
|
+ * prevents NBCON_PRIO_NORMAL and NBCON_PRIO_EMERGENCY from
|
|
+ * clobbering each other.
|
|
+ */
|
|
+
|
|
+ if (!nbcon_context_enter_unsafe(ctxt))
|
|
+ return false;
|
|
+
|
|
+ ctxt->backlog = printk_get_next_message(&pmsg, ctxt->seq, is_extended, true);
|
|
+ if (!ctxt->backlog)
|
|
+ return nbcon_context_exit_unsafe(ctxt);
|
|
+
|
|
+ /*
|
|
+ * @con->dropped is not protected in case of an unsafe hostile
|
|
+ * takeover. In that situation the update can be racy so
|
|
+ * annotate it accordingly.
|
|
+ */
|
|
+ con_dropped = data_race(READ_ONCE(con->dropped));
|
|
+
|
|
+ dropped = con_dropped + pmsg.dropped;
|
|
+ if (dropped && !is_extended)
|
|
+ console_prepend_dropped(&pmsg, dropped);
|
|
+
|
|
+ if (!nbcon_context_exit_unsafe(ctxt))
|
|
+ return false;
|
|
+
|
|
+ /* For skipped records just update seq/dropped in @con. */
|
|
+ if (pmsg.outbuf_len == 0)
|
|
+ goto update_con;
|
|
+
|
|
+ /* Initialize the write context for driver callbacks. */
|
|
+ wctxt->outbuf = &pmsg.pbufs->outbuf[0];
|
|
+ wctxt->len = pmsg.outbuf_len;
|
|
+ nbcon_state_read(con, &cur);
|
|
+ wctxt->unsafe_takeover = cur.unsafe_takeover;
|
|
+
|
|
+ if (use_atomic &&
|
|
+ con->write_atomic) {
|
|
+ done = con->write_atomic(con, wctxt);
|
|
+
|
|
+ } else if (!use_atomic &&
|
|
+ con->write_thread &&
|
|
+ con->kthread) {
|
|
+ WARN_ON_ONCE(con->kthread != current);
|
|
+ done = con->write_thread(con, wctxt);
|
|
+ }
|
|
+
|
|
+ if (!done) {
|
|
+ /*
|
|
+ * The emit was aborted, probably due to a loss of ownership.
|
|
+ * Ensure ownership was lost or released before reporting the
|
|
+ * loss.
|
|
+ */
|
|
+ nbcon_context_release(ctxt);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Since any dropped message was successfully output, reset the
|
|
+ * dropped count for the console.
|
|
+ */
|
|
+ dropped = 0;
|
|
+update_con:
|
|
+ /*
|
|
+ * The dropped count and the sequence number are updated within an
|
|
+ * unsafe section. This limits update races to the panic context and
|
|
+ * allows the panic context to win.
|
|
+ */
|
|
+
|
|
+ if (!nbcon_context_enter_unsafe(ctxt))
|
|
+ return false;
|
|
+
|
|
+ if (dropped != con_dropped) {
|
|
+ /* Counterpart to the READ_ONCE() above. */
|
|
+ WRITE_ONCE(con->dropped, dropped);
|
|
+ }
|
|
+
|
|
+ nbcon_seq_try_update(ctxt, pmsg.seq + 1);
|
|
+
|
|
+ return nbcon_context_exit_unsafe(ctxt);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_kthread_should_wakeup - Check whether a printer thread should wakeup
|
|
+ * @con: Console to operate on
|
|
+ * @ctxt: The acquire context that contains the state
|
|
+ * at console_acquire()
|
|
+ *
|
|
+ * Return: True if the thread should shutdown or if the console is
|
|
+ * allowed to print and a record is available. False otherwise.
|
|
+ *
|
|
+ * After the thread wakes up, it must first check if it should shutdown before
|
|
+ * attempting any printing.
|
|
+ */
|
|
+static bool nbcon_kthread_should_wakeup(struct console *con, struct nbcon_context *ctxt)
|
|
+{
|
|
+ bool is_usable;
|
|
+ short flags;
|
|
+ int cookie;
|
|
+
|
|
+ if (kthread_should_stop())
|
|
+ return true;
|
|
+
|
|
+ cookie = console_srcu_read_lock();
|
|
+ flags = console_srcu_read_flags(con);
|
|
+ is_usable = console_is_usable(con, flags, false);
|
|
+ console_srcu_read_unlock(cookie);
|
|
+
|
|
+ if (!is_usable)
|
|
+ return false;
|
|
+
|
|
+ /* Bring the sequence in @ctxt up to date */
|
|
+ ctxt->seq = nbcon_seq_read(con);
|
|
+
|
|
+ return prb_read_valid(prb, ctxt->seq, NULL);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_kthread_func - The printer thread function
|
|
+ * @__console: Console to operate on
|
|
+ */
|
|
+static int nbcon_kthread_func(void *__console)
|
|
+{
|
|
+ struct console *con = __console;
|
|
+ struct nbcon_write_context wctxt = {
|
|
+ .ctxt.console = con,
|
|
+ .ctxt.prio = NBCON_PRIO_NORMAL,
|
|
+ };
|
|
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt);
|
|
+ unsigned long flags;
|
|
+ short con_flags;
|
|
+ bool backlog;
|
|
+ int cookie;
|
|
+ int ret;
|
|
+
|
|
+wait_for_event:
|
|
+ /*
|
|
+ * Guarantee this task is visible on the rcuwait before
|
|
+ * checking the wake condition.
|
|
+ *
|
|
+ * The full memory barrier within set_current_state() of
|
|
+ * ___rcuwait_wait_event() pairs with the full memory
|
|
+ * barrier within rcuwait_has_sleeper().
|
|
+ *
|
|
+ * This pairs with rcuwait_has_sleeper:A and nbcon_kthread_wake:A.
|
|
+ */
|
|
+ ret = rcuwait_wait_event(&con->rcuwait,
|
|
+ nbcon_kthread_should_wakeup(con, ctxt),
|
|
+ TASK_INTERRUPTIBLE); /* LMM(nbcon_kthread_func:A) */
|
|
+
|
|
+ if (kthread_should_stop())
|
|
+ return 0;
|
|
+
|
|
+ /* Wait was interrupted by a spurious signal, go back to sleep. */
|
|
+ if (ret)
|
|
+ goto wait_for_event;
|
|
+
|
|
+ do {
|
|
+ backlog = false;
|
|
+
|
|
+ cookie = console_srcu_read_lock();
|
|
+
|
|
+ con_flags = console_srcu_read_flags(con);
|
|
+
|
|
+ if (console_is_usable(con, con_flags, false)) {
|
|
+ con->driver_enter(con, &flags);
|
|
+
|
|
+ /*
|
|
+ * Ensure this stays on the CPU to make handover and
|
|
+ * takeover possible.
|
|
+ */
|
|
+ cant_migrate();
|
|
+
|
|
+ if (nbcon_context_try_acquire(ctxt)) {
|
|
+ /*
|
|
+ * If the emit fails, this context is no
|
|
+ * longer the owner.
|
|
+ */
|
|
+ if (nbcon_emit_next_record(&wctxt, false)) {
|
|
+ nbcon_context_release(ctxt);
|
|
+ backlog = ctxt->backlog;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ con->driver_exit(con, flags);
|
|
+ }
|
|
+
|
|
+ console_srcu_read_unlock(cookie);
|
|
+ cond_resched();
|
|
+
|
|
+ } while (backlog);
|
|
+
|
|
+ goto wait_for_event;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_irq_work - irq work to wake printk thread
|
|
+ * @irq_work: The irq work to operate on
|
|
+ */
|
|
+static void nbcon_irq_work(struct irq_work *irq_work)
|
|
+{
|
|
+ struct console *con = container_of(irq_work, struct console, irq_work);
|
|
+
|
|
+ nbcon_kthread_wake(con);
|
|
+}
|
|
+
|
|
+static inline bool rcuwait_has_sleeper(struct rcuwait *w)
|
|
+{
|
|
+ bool has_sleeper;
|
|
+
|
|
+ rcu_read_lock();
|
|
+ /*
|
|
+ * Guarantee any new records can be seen by tasks preparing to wait
|
|
+ * before this context checks if the rcuwait is empty.
|
|
+ *
|
|
+ * This full memory barrier pairs with the full memory barrier within
|
|
+ * set_current_state() of ___rcuwait_wait_event(), which is called
|
|
+ * after prepare_to_rcuwait() adds the waiter but before it has
|
|
+ * checked the wait condition.
|
|
+ *
|
|
+ * This pairs with nbcon_kthread_func:A.
|
|
+ */
|
|
+ smp_mb(); /* LMM(rcuwait_has_sleeper:A) */
|
|
+ has_sleeper = !!rcu_dereference(w->task);
|
|
+ rcu_read_unlock();
|
|
+
|
|
+ return has_sleeper;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_wake_threads - Wake up printing threads using irq_work
|
|
+ */
|
|
+void nbcon_wake_threads(void)
|
|
+{
|
|
+ struct console *con;
|
|
+ int cookie;
|
|
+
|
|
+ cookie = console_srcu_read_lock();
|
|
+ for_each_console_srcu(con) {
|
|
+ /*
|
|
+ * Only schedule irq_work if the printing thread is
|
|
+ * actively waiting. If not waiting, the thread will
|
|
+ * notice by itself that it has work to do.
|
|
+ */
|
|
+ if (con->kthread && rcuwait_has_sleeper(&con->rcuwait))
|
|
+ irq_work_queue(&con->irq_work);
|
|
+ }
|
|
+ console_srcu_read_unlock(cookie);
|
|
+}
|
|
+
|
|
+/* Track the nbcon emergency nesting per CPU. */
|
|
+static DEFINE_PER_CPU(unsigned int, nbcon_pcpu_emergency_nesting);
|
|
+static unsigned int early_nbcon_pcpu_emergency_nesting __initdata;
|
|
+
|
|
+/**
|
|
+ * nbcon_get_cpu_emergency_nesting - Get the per CPU emergency nesting pointer
|
|
+ *
|
|
+ * Return: Either a pointer to the per CPU emergency nesting counter of
|
|
+ * the current CPU or to the init data during early boot.
|
|
+ */
|
|
+static __ref unsigned int *nbcon_get_cpu_emergency_nesting(void)
|
|
+{
|
|
+ /*
|
|
+ * The value of __printk_percpu_data_ready gets set in normal
|
|
+ * context and before SMP initialization. As a result it could
|
|
+ * never change while inside an nbcon emergency section.
|
|
+ */
|
|
+ if (!printk_percpu_data_ready())
|
|
+ return &early_nbcon_pcpu_emergency_nesting;
|
|
+
|
|
+ return this_cpu_ptr(&nbcon_pcpu_emergency_nesting);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_atomic_emit_one - Print one record for an nbcon console using the
|
|
+ * write_atomic() callback
|
|
+ * @wctxt: An initialized write context struct to use
|
|
+ * for this context
|
|
+ *
|
|
+ * Return: False if the given console could not print a record or there
|
|
+ * are no more records to print, otherwise true.
|
|
+ *
|
|
+ * This is an internal helper to handle the locking of the console before
|
|
+ * calling nbcon_emit_next_record().
|
|
+ */
|
|
+static bool nbcon_atomic_emit_one(struct nbcon_write_context *wctxt)
|
|
+{
|
|
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
|
|
+
|
|
+ if (!nbcon_context_try_acquire(ctxt))
|
|
+ return false;
|
|
+
|
|
+ /*
|
|
+ * nbcon_emit_next_record() returns false when the console was
|
|
+ * handed over or taken over. In both cases the context is no
|
|
+ * longer valid.
|
|
+ */
|
|
+ if (!nbcon_emit_next_record(wctxt, true))
|
|
+ return false;
|
|
+
|
|
+ nbcon_context_release(ctxt);
|
|
+
|
|
+ return ctxt->backlog;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_get_default_prio - The appropriate nbcon priority to use for nbcon
|
|
+ * printing on the current CPU
|
|
+ *
|
|
+ * Context: Any context which could not be migrated to another CPU.
|
|
+ * Return: The nbcon_prio to use for acquiring an nbcon console in this
|
|
+ * context for printing.
|
|
+ */
|
|
+enum nbcon_prio nbcon_get_default_prio(void)
|
|
+{
|
|
+ unsigned int *cpu_emergency_nesting;
|
|
+
|
|
+ if (this_cpu_in_panic())
|
|
+ return NBCON_PRIO_PANIC;
|
|
+
|
|
+ cpu_emergency_nesting = nbcon_get_cpu_emergency_nesting();
|
|
+ if (*cpu_emergency_nesting)
|
|
+ return NBCON_PRIO_EMERGENCY;
|
|
+
|
|
+ return NBCON_PRIO_NORMAL;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_atomic_emit_next_record - Print one record for an nbcon console
|
|
+ * using the write_atomic() callback
|
|
+ * @con: The console to print on
|
|
+ * @handover: Will be set to true if a printk waiter has taken over the
|
|
+ * console_lock, in which case the caller is no longer holding
|
|
+ * both the console_lock and the SRCU read lock. Otherwise it
|
|
+ * is set to false.
|
|
+ * @cookie: The cookie from the SRCU read lock.
|
|
+ *
|
|
+ * Context: Any context which could not be migrated to another CPU.
|
|
+ * Return: True if a record could be printed, otherwise false.
|
|
+ *
|
|
+ * This function is meant to be called by console_flush_all() to print records
|
|
+ * on nbcon consoles using the write_atomic() callback. Essentially it is the
|
|
+ * nbcon version of console_emit_next_record().
|
|
+ */
|
|
+bool nbcon_atomic_emit_next_record(struct console *con, bool *handover, int cookie)
|
|
+{
|
|
+ struct nbcon_write_context wctxt = { };
|
|
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt);
|
|
+ unsigned long driver_flags;
|
|
+ bool progress = false;
|
|
+ unsigned long flags;
|
|
+
|
|
+ *handover = false;
|
|
+
|
|
+ /* Use the same locking order as console_emit_next_record(). */
|
|
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) {
|
|
+ printk_safe_enter_irqsave(flags);
|
|
+ console_lock_spinning_enable();
|
|
+ stop_critical_timings();
|
|
+ }
|
|
+
|
|
+ con->driver_enter(con, &driver_flags);
|
|
+ cant_migrate();
|
|
+
|
|
+ ctxt->console = con;
|
|
+ ctxt->prio = nbcon_get_default_prio();
|
|
+
|
|
+ progress = nbcon_atomic_emit_one(&wctxt);
|
|
+
|
|
+ con->driver_exit(con, driver_flags);
|
|
+
|
|
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT)) {
|
|
+ start_critical_timings();
|
|
+ *handover = console_lock_spinning_disable_and_check(cookie);
|
|
+ printk_safe_exit_irqrestore(flags);
|
|
+ }
|
|
+
|
|
+ return progress;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * __nbcon_atomic_flush_all - Flush all nbcon consoles using their
|
|
+ * write_atomic() callback
|
|
+ * @stop_seq: Flush up until this record
|
|
+ * @allow_unsafe_takeover: True, to allow unsafe hostile takeovers
|
|
+ */
|
|
+static void __nbcon_atomic_flush_all(u64 stop_seq, bool allow_unsafe_takeover)
|
|
+{
|
|
+ struct nbcon_write_context wctxt = { };
|
|
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(&wctxt, ctxt);
|
|
+ struct console *con;
|
|
+ bool any_progress;
|
|
+ int cookie;
|
|
+
|
|
+ do {
|
|
+ any_progress = false;
|
|
+
|
|
+ cookie = console_srcu_read_lock();
|
|
+ for_each_console_srcu(con) {
|
|
+ short flags = console_srcu_read_flags(con);
|
|
+ unsigned long irq_flags;
|
|
+
|
|
+ if (!(flags & CON_NBCON))
|
|
+ continue;
|
|
+
|
|
+ if (!console_is_usable(con, flags, true))
|
|
+ continue;
|
|
+
|
|
+ if (nbcon_seq_read(con) >= stop_seq)
|
|
+ continue;
|
|
+
|
|
+ memset(ctxt, 0, sizeof(*ctxt));
|
|
+ ctxt->console = con;
|
|
+ ctxt->spinwait_max_us = 2000;
|
|
+ ctxt->allow_unsafe_takeover = allow_unsafe_takeover;
|
|
+
|
|
+ /*
|
|
+ * Atomic flushing does not use console driver
|
|
+ * synchronization (i.e. it does not hold the port
|
|
+ * lock for uart consoles). Therefore IRQs must be
|
|
+ * disabled to avoid being interrupted and then
|
|
+ * calling into a driver that will deadlock trying
|
|
+ * acquire console ownership.
|
|
+ *
|
|
+ * This also disables migration in order to get the
|
|
+ * current CPU priority.
|
|
+ */
|
|
+ local_irq_save(irq_flags);
|
|
+
|
|
+ ctxt->prio = nbcon_get_default_prio();
|
|
+
|
|
+ any_progress |= nbcon_atomic_emit_one(&wctxt);
|
|
+
|
|
+ local_irq_restore(irq_flags);
|
|
+ }
|
|
+ console_srcu_read_unlock(cookie);
|
|
+ } while (any_progress);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_atomic_flush_all - Flush all nbcon consoles using their
|
|
+ * write_atomic() callback
|
|
+ *
|
|
+ * Flush the backlog up through the currently newest record. Any new
|
|
+ * records added while flushing will not be flushed. This is to avoid
|
|
+ * one CPU printing unbounded because other CPUs continue to add records.
|
|
+ */
|
|
+void nbcon_atomic_flush_all(void)
|
|
+{
|
|
+ __nbcon_atomic_flush_all(prb_next_reserve_seq(prb), false);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_atomic_flush_unsafe - Flush all nbcon consoles using their
|
|
+ * write_atomic() callback and allowing unsafe hostile takeovers
|
|
+ *
|
|
+ * Flush the backlog up through the currently newest record. Unsafe hostile
|
|
+ * takeovers will be performed, if necessary.
|
|
+ */
|
|
+void nbcon_atomic_flush_unsafe(void)
|
|
+{
|
|
+ __nbcon_atomic_flush_all(prb_next_reserve_seq(prb), true);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_cpu_emergency_enter - Enter an emergency section where printk()
|
|
+ * messages for that CPU are only stored
|
|
+ *
|
|
+ * Upon exiting the emergency section, all stored messages are flushed.
|
|
+ *
|
|
+ * Context: Any context. Disables preemption.
|
|
+ *
|
|
+ * When within an emergency section, no printing occurs on that CPU. This
|
|
+ * is to allow all emergency messages to be dumped into the ringbuffer before
|
|
+ * flushing the ringbuffer. The actual printing occurs when exiting the
|
|
+ * outermost emergency section.
|
|
+ */
|
|
+void nbcon_cpu_emergency_enter(void)
|
|
+{
|
|
+ unsigned int *cpu_emergency_nesting;
|
|
+
|
|
+ preempt_disable();
|
|
+
|
|
+ cpu_emergency_nesting = nbcon_get_cpu_emergency_nesting();
|
|
+ (*cpu_emergency_nesting)++;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_cpu_emergency_exit - Exit an emergency section and flush the
|
|
+ * stored messages
|
|
+ *
|
|
+ * Flushing only occurs when exiting all nesting for the CPU.
|
|
+ *
|
|
+ * Context: Any context. Enables preemption.
|
|
+ */
|
|
+void nbcon_cpu_emergency_exit(void)
|
|
+{
|
|
+ unsigned int *cpu_emergency_nesting;
|
|
+ bool do_trigger_flush = false;
|
|
+
|
|
+ cpu_emergency_nesting = nbcon_get_cpu_emergency_nesting();
|
|
+
|
|
+ WARN_ON_ONCE(*cpu_emergency_nesting == 0);
|
|
+
|
|
+ if (*cpu_emergency_nesting == 1)
|
|
+ do_trigger_flush = true;
|
|
+
|
|
+ /* Undo the nesting count of nbcon_cpu_emergency_enter(). */
|
|
+ (*cpu_emergency_nesting)--;
|
|
+
|
|
+ preempt_enable();
|
|
+
|
|
+ if (do_trigger_flush)
|
|
+ printk_trigger_flush();
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_kthread_stop - Stop a printer thread
|
|
+ * @con: Console to operate on
|
|
+ */
|
|
+static void nbcon_kthread_stop(struct console *con)
|
|
+{
|
|
+ lockdep_assert_console_list_lock_held();
|
|
+
|
|
+ if (!con->kthread)
|
|
+ return;
|
|
+
|
|
+ kthread_stop(con->kthread);
|
|
+ con->kthread = NULL;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_kthread_create - Create a printer thread
|
|
+ * @con: Console to operate on
|
|
+ *
|
|
+ * If it fails, let the console proceed. The atomic part might
|
|
+ * be usable and useful.
|
|
+ */
|
|
+void nbcon_kthread_create(struct console *con)
|
|
+{
|
|
+ struct task_struct *kt;
|
|
+
|
|
+ lockdep_assert_console_list_lock_held();
|
|
+
|
|
+ if (!(con->flags & CON_NBCON) || !con->write_thread)
|
|
+ return;
|
|
+
|
|
+ if (!printk_threads_enabled || con->kthread)
|
|
+ return;
|
|
+
|
|
+ /*
|
|
+ * Printer threads cannot be started as long as any boot console is
|
|
+ * registered because there is no way to synchronize the hardware
|
|
+ * registers between boot console code and regular console code.
|
|
+ */
|
|
+ if (have_boot_console)
|
|
+ return;
|
|
+
|
|
+ kt = kthread_run(nbcon_kthread_func, con, "pr/%s%d", con->name, con->index);
|
|
+ if (IS_ERR(kt)) {
|
|
+ con_printk(KERN_ERR, con, "failed to start printing thread\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ con->kthread = kt;
|
|
+
|
|
+ /*
|
|
+ * It is important that console printing threads are scheduled
|
|
+ * shortly after a printk call and with generous runtime budgets.
|
|
+ */
|
|
+ sched_set_normal(con->kthread, -20);
|
|
+}
|
|
+
|
|
+static int __init printk_setup_threads(void)
|
|
+{
|
|
+ struct console *con;
|
|
+
|
|
+ console_list_lock();
|
|
+ printk_threads_enabled = true;
|
|
+ for_each_console(con)
|
|
+ nbcon_kthread_create(con);
|
|
+ if (IS_ENABLED(CONFIG_PREEMPT_RT) && printing_via_unlock)
|
|
+ nbcon_legacy_kthread_create();
|
|
+ console_list_unlock();
|
|
+ return 0;
|
|
+}
|
|
+early_initcall(printk_setup_threads);
|
|
+
|
|
+/**
|
|
+ * nbcon_alloc - Allocate buffers needed by the nbcon console
|
|
+ * @con: Console to allocate buffers for
|
|
+ *
|
|
+ * Return: True on success. False otherwise and the console cannot
|
|
+ * be used.
|
|
+ *
|
|
+ * This is not part of nbcon_init() because buffer allocation must
|
|
+ * be performed earlier in the console registration process.
|
|
+ */
|
|
+bool nbcon_alloc(struct console *con)
|
|
+{
|
|
+ if (con->flags & CON_BOOT) {
|
|
+ /*
|
|
+ * Boot console printing is synchronized with legacy console
|
|
+ * printing, so boot consoles can share the same global printk
|
|
+ * buffers.
|
|
+ */
|
|
+ con->pbufs = &printk_shared_pbufs;
|
|
+ } else {
|
|
+ con->pbufs = kmalloc(sizeof(*con->pbufs), GFP_KERNEL);
|
|
+ if (!con->pbufs) {
|
|
+ con_printk(KERN_ERR, con, "failed to allocate printing buffer\n");
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_init - Initialize the nbcon console specific data
|
|
+ * @con: Console to initialize
|
|
+ *
|
|
+ * nbcon_alloc() *must* be called and succeed before this function
|
|
+ * is called.
|
|
+ *
|
|
+ * This function expects that the legacy @con->seq has been set.
|
|
+ */
|
|
+void nbcon_init(struct console *con)
|
|
+{
|
|
+ struct nbcon_state state = { };
|
|
+
|
|
+ /* nbcon_alloc() must have been called and successful! */
|
|
+ BUG_ON(!con->pbufs);
|
|
+
|
|
+ rcuwait_init(&con->rcuwait);
|
|
+ init_irq_work(&con->irq_work, nbcon_irq_work);
|
|
+ nbcon_seq_force(con, con->seq);
|
|
+ nbcon_state_set(con, &state);
|
|
+ nbcon_kthread_create(con);
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_free - Free and cleanup the nbcon console specific data
|
|
+ * @con: Console to free/cleanup nbcon data
|
|
+ */
|
|
+void nbcon_free(struct console *con)
|
|
+{
|
|
+ struct nbcon_state state = { };
|
|
+
|
|
+ nbcon_kthread_stop(con);
|
|
+ nbcon_state_set(con, &state);
|
|
+
|
|
+ /* Boot consoles share global printk buffers. */
|
|
+ if (!(con->flags & CON_BOOT))
|
|
+ kfree(con->pbufs);
|
|
+
|
|
+ con->pbufs = NULL;
|
|
+}
|
|
+
|
|
+static inline bool uart_is_nbcon(struct uart_port *up)
|
|
+{
|
|
+ int cookie;
|
|
+ bool ret;
|
|
+
|
|
+ if (!uart_console(up))
|
|
+ return false;
|
|
+
|
|
+ cookie = console_srcu_read_lock();
|
|
+ ret = (console_srcu_read_flags(up->cons) & CON_NBCON);
|
|
+ console_srcu_read_unlock(cookie);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * nbcon_acquire - The second half of the port locking wrapper
|
|
+ * @up: The uart port whose @lock was locked
|
|
+ *
|
|
+ * The uart_port_lock() wrappers will first lock the spin_lock @up->lock.
|
|
+ * Then this function is called to implement nbcon-specific processing.
|
|
+ *
|
|
+ * If @up is an nbcon console, this console will be acquired and marked as
|
|
+ * unsafe. Otherwise this function does nothing.
|
|
+ *
|
|
+ * nbcon consoles acquired via the port lock wrapper always use priority
|
|
+ * NBCON_PRIO_NORMAL.
|
|
+ */
|
|
+void nbcon_acquire(struct uart_port *up)
|
|
+{
|
|
+ struct console *con = up->cons;
|
|
+ struct nbcon_context ctxt;
|
|
+
|
|
+ if (!uart_is_nbcon(up))
|
|
+ return;
|
|
+
|
|
+ WARN_ON_ONCE(up->nbcon_locked_port);
|
|
+
|
|
+ do {
|
|
+ do {
|
|
+ memset(&ctxt, 0, sizeof(ctxt));
|
|
+ ctxt.console = con;
|
|
+ ctxt.prio = NBCON_PRIO_NORMAL;
|
|
+ } while (!nbcon_context_try_acquire(&ctxt));
|
|
+
|
|
+ } while (!nbcon_context_enter_unsafe(&ctxt));
|
|
+
|
|
+ up->nbcon_locked_port = true;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(nbcon_acquire);
|
|
+
|
|
+/**
|
|
+ * nbcon_release - The first half of the port unlocking wrapper
|
|
+ * @up: The uart port whose @lock is about to be unlocked
|
|
+ *
|
|
+ * The uart_port_unlock() wrappers will first call this function to implement
|
|
+ * nbcon-specific processing. Then afterwards the uart_port_unlock() wrappers
|
|
+ * will unlock the spin_lock @up->lock.
|
|
+ *
|
|
+ * If @up is an nbcon console, the console will be marked as safe and
|
|
+ * released. Otherwise this function does nothing.
|
|
+ *
|
|
+ * nbcon consoles acquired via the port lock wrapper always use priority
|
|
+ * NBCON_PRIO_NORMAL.
|
|
+ */
|
|
+void nbcon_release(struct uart_port *up)
|
|
+{
|
|
+ struct console *con = up->cons;
|
|
+ struct nbcon_context ctxt = {
|
|
+ .console = con,
|
|
+ .prio = NBCON_PRIO_NORMAL,
|
|
+ };
|
|
+
|
|
+ if (!up->nbcon_locked_port)
|
|
+ return;
|
|
+
|
|
+ if (nbcon_context_exit_unsafe(&ctxt))
|
|
+ nbcon_context_release(&ctxt);
|
|
+
|
|
+ up->nbcon_locked_port = false;
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(nbcon_release);
|
|
+
|
|
+/**
|
|
+ * printk_kthread_shutdown - shutdown all threaded printers
|
|
+ *
|
|
+ * On system shutdown all threaded printers are stopped. This allows printk
|
|
+ * to transition back to atomic printing, thus providing a robust mechanism
|
|
+ * for the final shutdown/reboot messages to be output.
|
|
+ */
|
|
+static void printk_kthread_shutdown(void)
|
|
+{
|
|
+ struct console *con;
|
|
+
|
|
+ console_list_lock();
|
|
+ for_each_console(con) {
|
|
+ if (con->flags & CON_NBCON)
|
|
+ nbcon_kthread_stop(con);
|
|
+ }
|
|
+ console_list_unlock();
|
|
+}
|
|
+
|
|
+static struct syscore_ops printk_syscore_ops = {
|
|
+ .shutdown = printk_kthread_shutdown,
|
|
+};
|
|
+
|
|
+static int __init printk_init_ops(void)
|
|
+{
|
|
+ register_syscore_ops(&printk_syscore_ops);
|
|
+ return 0;
|
|
+}
|
|
+device_initcall(printk_init_ops);
|
|
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
|
|
index 0fca282c0a25..249576a8c351 100644
|
|
--- a/kernel/printk/printk.c
|
|
+++ b/kernel/printk/printk.c
|
|
@@ -102,12 +102,6 @@ DEFINE_STATIC_SRCU(console_srcu);
|
|
*/
|
|
int __read_mostly suppress_printk;
|
|
|
|
-/*
|
|
- * During panic, heavy printk by other CPUs can delay the
|
|
- * panic and risk deadlock on console resources.
|
|
- */
|
|
-static int __read_mostly suppress_panic_printk;
|
|
-
|
|
#ifdef CONFIG_LOCKDEP
|
|
static struct lockdep_map console_lock_dep_map = {
|
|
.name = "console_lock"
|
|
@@ -288,6 +282,7 @@ EXPORT_SYMBOL(console_list_unlock);
|
|
* Return: A cookie to pass to console_srcu_read_unlock().
|
|
*/
|
|
int console_srcu_read_lock(void)
|
|
+ __acquires(&console_srcu)
|
|
{
|
|
return srcu_read_lock_nmisafe(&console_srcu);
|
|
}
|
|
@@ -301,6 +296,7 @@ EXPORT_SYMBOL(console_srcu_read_lock);
|
|
* Counterpart to console_srcu_read_lock()
|
|
*/
|
|
void console_srcu_read_unlock(int cookie)
|
|
+ __releases(&console_srcu)
|
|
{
|
|
srcu_read_unlock_nmisafe(&console_srcu, cookie);
|
|
}
|
|
@@ -353,6 +349,29 @@ static bool panic_in_progress(void)
|
|
return unlikely(atomic_read(&panic_cpu) != PANIC_CPU_INVALID);
|
|
}
|
|
|
|
+/* Return true if a panic is in progress on the current CPU. */
|
|
+bool this_cpu_in_panic(void)
|
|
+{
|
|
+ /*
|
|
+ * We can use raw_smp_processor_id() here because it is impossible for
|
|
+ * the task to be migrated to the panic_cpu, or away from it. If
|
|
+ * panic_cpu has already been set, and we're not currently executing on
|
|
+ * that CPU, then we never will be.
|
|
+ */
|
|
+ return unlikely(atomic_read(&panic_cpu) == raw_smp_processor_id());
|
|
+}
|
|
+
|
|
+/*
|
|
+ * Return true if a panic is in progress on a remote CPU.
|
|
+ *
|
|
+ * On true, the local CPU should immediately release any printing resources
|
|
+ * that may be needed by the panic CPU.
|
|
+ */
|
|
+bool other_cpu_in_panic(void)
|
|
+{
|
|
+ return (panic_in_progress() && !this_cpu_in_panic());
|
|
+}
|
|
+
|
|
/*
|
|
* This is used for debugging the mess that is the VT code by
|
|
* keeping track if we have the console semaphore held. It's
|
|
@@ -444,8 +463,33 @@ static int console_msg_format = MSG_FORMAT_DEFAULT;
|
|
/* syslog_lock protects syslog_* variables and write access to clear_seq. */
|
|
static DEFINE_MUTEX(syslog_lock);
|
|
|
|
+/*
|
|
+ * Specifies if a legacy console is registered. If legacy consoles are
|
|
+ * present, it is necessary to perform the console_lock/console_unlock dance
|
|
+ * whenever console flushing should occur.
|
|
+ */
|
|
+bool have_legacy_console;
|
|
+
|
|
+/*
|
|
+ * Specifies if an nbcon console is registered. If nbcon consoles are present,
|
|
+ * synchronous printing of legacy consoles will not occur during panic until
|
|
+ * the backtrace has been stored to the ringbuffer.
|
|
+ */
|
|
+bool have_nbcon_console;
|
|
+
|
|
+/*
|
|
+ * Specifies if a boot console is registered. If boot consoles are present,
|
|
+ * nbcon consoles cannot print simultaneously and must be synchronized by
|
|
+ * the console lock. This is because boot consoles and nbcon consoles may
|
|
+ * have mapped the same hardware.
|
|
+ */
|
|
+bool have_boot_console;
|
|
+
|
|
#ifdef CONFIG_PRINTK
|
|
DECLARE_WAIT_QUEUE_HEAD(log_wait);
|
|
+
|
|
+static DECLARE_WAIT_QUEUE_HEAD(legacy_wait);
|
|
+
|
|
/* All 3 protected by @syslog_lock. */
|
|
/* the next printk record to read by syslog(READ) or /proc/kmsg */
|
|
static u64 syslog_seq;
|
|
@@ -494,7 +538,7 @@ _DEFINE_PRINTKRB(printk_rb_static, CONFIG_LOG_BUF_SHIFT - PRB_AVGBITS,
|
|
|
|
static struct printk_ringbuffer printk_rb_dynamic;
|
|
|
|
-static struct printk_ringbuffer *prb = &printk_rb_static;
|
|
+struct printk_ringbuffer *prb = &printk_rb_static;
|
|
|
|
/*
|
|
* We cannot access per-CPU data (e.g. per-CPU flush irq_work) before
|
|
@@ -698,9 +742,6 @@ static ssize_t msg_print_ext_body(char *buf, size_t size,
|
|
return len;
|
|
}
|
|
|
|
-static bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
|
|
- bool is_extended, bool may_supress);
|
|
-
|
|
/* /dev/kmsg - userspace message inject/listen interface */
|
|
struct devkmsg_user {
|
|
atomic64_t seq;
|
|
@@ -1848,7 +1889,7 @@ static bool console_waiter;
|
|
* there may be a waiter spinning (like a spinlock). Also it must be
|
|
* ready to hand over the lock at the end of the section.
|
|
*/
|
|
-static void console_lock_spinning_enable(void)
|
|
+void console_lock_spinning_enable(void)
|
|
{
|
|
/*
|
|
* Do not use spinning in panic(). The panic CPU wants to keep the lock.
|
|
@@ -1887,7 +1928,7 @@ static void console_lock_spinning_enable(void)
|
|
*
|
|
* Return: 1 if the lock rights were passed, 0 otherwise.
|
|
*/
|
|
-static int console_lock_spinning_disable_and_check(int cookie)
|
|
+int console_lock_spinning_disable_and_check(int cookie)
|
|
{
|
|
int waiter;
|
|
|
|
@@ -2298,54 +2339,123 @@ int vprintk_store(int facility, int level,
|
|
return ret;
|
|
}
|
|
|
|
+static bool legacy_allow_panic_sync;
|
|
+
|
|
+/*
|
|
+ * This acts as a one-way switch to allow legacy consoles to print from
|
|
+ * the printk() caller context on a panic CPU.
|
|
+ */
|
|
+void printk_legacy_allow_panic_sync(void)
|
|
+{
|
|
+ legacy_allow_panic_sync = true;
|
|
+}
|
|
+
|
|
asmlinkage int vprintk_emit(int facility, int level,
|
|
const struct dev_printk_info *dev_info,
|
|
const char *fmt, va_list args)
|
|
{
|
|
+ bool do_trylock_unlock = printing_via_unlock &&
|
|
+ !IS_ENABLED(CONFIG_PREEMPT_RT);
|
|
int printed_len;
|
|
- bool in_sched = false;
|
|
|
|
/* Suppress unimportant messages after panic happens */
|
|
if (unlikely(suppress_printk))
|
|
return 0;
|
|
|
|
- if (unlikely(suppress_panic_printk) && other_cpu_in_panic())
|
|
+ /*
|
|
+ * The messages on the panic CPU are the most important. If
|
|
+ * non-panic CPUs are generating any messages, they will be
|
|
+ * silently dropped.
|
|
+ */
|
|
+ if (other_cpu_in_panic())
|
|
return 0;
|
|
|
|
if (level == LOGLEVEL_SCHED) {
|
|
level = LOGLEVEL_DEFAULT;
|
|
- in_sched = true;
|
|
+ /* If called from the scheduler, we can not call up(). */
|
|
+ do_trylock_unlock = false;
|
|
}
|
|
|
|
printk_delay(level);
|
|
|
|
printed_len = vprintk_store(facility, level, dev_info, fmt, args);
|
|
|
|
- /* If called from the scheduler, we can not call up(). */
|
|
- if (!in_sched) {
|
|
+ if (!have_boot_console && have_nbcon_console) {
|
|
+ bool is_panic_context = this_cpu_in_panic();
|
|
+
|
|
+ /*
|
|
+ * In panic, the legacy consoles are not allowed to print from
|
|
+ * the printk calling context unless explicitly allowed. This
|
|
+ * gives the safe nbcon consoles a chance to print out all the
|
|
+ * panic messages first. This restriction only applies if
|
|
+ * there are nbcon consoles registered.
|
|
+ */
|
|
+ if (is_panic_context)
|
|
+ do_trylock_unlock &= legacy_allow_panic_sync;
|
|
+
|
|
+ /*
|
|
+ * There are situations where nbcon atomic printing should
|
|
+ * happen in the printk() caller context:
|
|
+ *
|
|
+ * - When this CPU is in panic.
|
|
+ *
|
|
+ * - When booting, before the printing threads have been
|
|
+ * started.
|
|
+ *
|
|
+ * - During shutdown, since the printing threads may not get
|
|
+ * a chance to print the final messages.
|
|
+ *
|
|
+ * Note that if boot consoles are registered, the
|
|
+ * console_lock/console_unlock dance must be relied upon
|
|
+ * instead because nbcon consoles cannot print simultaneously
|
|
+ * with boot consoles.
|
|
+ */
|
|
+ if (is_panic_context ||
|
|
+ !printk_threads_enabled ||
|
|
+ (system_state > SYSTEM_RUNNING)) {
|
|
+ nbcon_atomic_flush_all();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ nbcon_wake_threads();
|
|
+
|
|
+ if (do_trylock_unlock) {
|
|
/*
|
|
* The caller may be holding system-critical or
|
|
* timing-sensitive locks. Disable preemption during
|
|
* printing of all remaining records to all consoles so that
|
|
* this context can return as soon as possible. Hopefully
|
|
* another printk() caller will take over the printing.
|
|
+ *
|
|
+ * Also, nbcon_get_default_prio() requires migration disabled.
|
|
*/
|
|
preempt_disable();
|
|
+
|
|
/*
|
|
- * Try to acquire and then immediately release the console
|
|
- * semaphore. The release will print out buffers. With the
|
|
- * spinning variant, this context tries to take over the
|
|
- * printing from another printing context.
|
|
+ * Do not emit for EMERGENCY priority. The console will be
|
|
+ * explicitly flushed when exiting the emergency section.
|
|
*/
|
|
- if (console_trylock_spinning())
|
|
- console_unlock();
|
|
+ if (nbcon_get_default_prio() == NBCON_PRIO_EMERGENCY) {
|
|
+ do_trylock_unlock = false;
|
|
+ } else {
|
|
+ /*
|
|
+ * Try to acquire and then immediately release the
|
|
+ * console semaphore. The release will print out
|
|
+ * buffers. With the spinning variant, this context
|
|
+ * tries to take over the printing from another
|
|
+ * printing context.
|
|
+ */
|
|
+ if (console_trylock_spinning())
|
|
+ console_unlock();
|
|
+ }
|
|
+
|
|
preempt_enable();
|
|
}
|
|
|
|
- if (in_sched)
|
|
- defer_console_output();
|
|
- else
|
|
+ if (do_trylock_unlock)
|
|
wake_up_klogd();
|
|
+ else
|
|
+ defer_console_output();
|
|
|
|
return printed_len;
|
|
}
|
|
@@ -2373,6 +2483,14 @@ EXPORT_SYMBOL(_printk);
|
|
static bool pr_flush(int timeout_ms, bool reset_on_progress);
|
|
static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progress);
|
|
|
|
+static struct task_struct *nbcon_legacy_kthread;
|
|
+
|
|
+static inline void wake_up_legacy_kthread(void)
|
|
+{
|
|
+ if (nbcon_legacy_kthread)
|
|
+ wake_up_interruptible(&legacy_wait);
|
|
+}
|
|
+
|
|
#else /* CONFIG_PRINTK */
|
|
|
|
#define printk_time false
|
|
@@ -2383,25 +2501,11 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
|
|
|
|
static u64 syslog_seq;
|
|
|
|
-static size_t record_print_text(const struct printk_record *r,
|
|
- bool syslog, bool time)
|
|
-{
|
|
- return 0;
|
|
-}
|
|
-static ssize_t info_print_ext_header(char *buf, size_t size,
|
|
- struct printk_info *info)
|
|
-{
|
|
- return 0;
|
|
-}
|
|
-static ssize_t msg_print_ext_body(char *buf, size_t size,
|
|
- char *text, size_t text_len,
|
|
- struct dev_printk_info *dev_info) { return 0; }
|
|
-static void console_lock_spinning_enable(void) { }
|
|
-static int console_lock_spinning_disable_and_check(int cookie) { return 0; }
|
|
-static bool suppress_message_printing(int level) { return false; }
|
|
static bool pr_flush(int timeout_ms, bool reset_on_progress) { return true; }
|
|
static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progress) { return true; }
|
|
|
|
+static inline void nbcon_legacy_kthread_create(void) { }
|
|
+static inline void wake_up_legacy_kthread(void) { }
|
|
#endif /* CONFIG_PRINTK */
|
|
|
|
#ifdef CONFIG_EARLY_PRINTK
|
|
@@ -2609,6 +2713,8 @@ void suspend_console(void)
|
|
void resume_console(void)
|
|
{
|
|
struct console *con;
|
|
+ short flags;
|
|
+ int cookie;
|
|
|
|
if (!console_suspend_enabled)
|
|
return;
|
|
@@ -2625,6 +2731,20 @@ void resume_console(void)
|
|
*/
|
|
synchronize_srcu(&console_srcu);
|
|
|
|
+ /*
|
|
+ * Since this runs in task context, wake the threaded printers
|
|
+ * directly rather than scheduling irq_work to do it.
|
|
+ */
|
|
+ cookie = console_srcu_read_lock();
|
|
+ for_each_console_srcu(con) {
|
|
+ flags = console_srcu_read_flags(con);
|
|
+ if (flags & CON_NBCON)
|
|
+ nbcon_kthread_wake(con);
|
|
+ }
|
|
+ console_srcu_read_unlock(cookie);
|
|
+
|
|
+ wake_up_legacy_kthread();
|
|
+
|
|
pr_flush(1000, true);
|
|
}
|
|
|
|
@@ -2639,7 +2759,8 @@ void resume_console(void)
|
|
*/
|
|
static int console_cpu_notify(unsigned int cpu)
|
|
{
|
|
- if (!cpuhp_tasks_frozen) {
|
|
+ if (!cpuhp_tasks_frozen && printing_via_unlock &&
|
|
+ !IS_ENABLED(CONFIG_PREEMPT_RT)) {
|
|
/* If trylock fails, someone else is doing the printing */
|
|
if (console_trylock())
|
|
console_unlock();
|
|
@@ -2647,26 +2768,6 @@ static int console_cpu_notify(unsigned int cpu)
|
|
return 0;
|
|
}
|
|
|
|
-/*
|
|
- * Return true if a panic is in progress on a remote CPU.
|
|
- *
|
|
- * On true, the local CPU should immediately release any printing resources
|
|
- * that may be needed by the panic CPU.
|
|
- */
|
|
-bool other_cpu_in_panic(void)
|
|
-{
|
|
- if (!panic_in_progress())
|
|
- return false;
|
|
-
|
|
- /*
|
|
- * We can use raw_smp_processor_id() here because it is impossible for
|
|
- * the task to be migrated to the panic_cpu, or away from it. If
|
|
- * panic_cpu has already been set, and we're not currently executing on
|
|
- * that CPU, then we never will be.
|
|
- */
|
|
- return atomic_read(&panic_cpu) != raw_smp_processor_id();
|
|
-}
|
|
-
|
|
/**
|
|
* console_lock - block the console subsystem from printing
|
|
*
|
|
@@ -2716,42 +2817,16 @@ int is_console_locked(void)
|
|
}
|
|
EXPORT_SYMBOL(is_console_locked);
|
|
|
|
-/*
|
|
- * Check if the given console is currently capable and allowed to print
|
|
- * records.
|
|
- *
|
|
- * Requires the console_srcu_read_lock.
|
|
- */
|
|
-static inline bool console_is_usable(struct console *con)
|
|
-{
|
|
- short flags = console_srcu_read_flags(con);
|
|
-
|
|
- if (!(flags & CON_ENABLED))
|
|
- return false;
|
|
-
|
|
- if ((flags & CON_SUSPENDED))
|
|
- return false;
|
|
-
|
|
- if (!con->write)
|
|
- return false;
|
|
-
|
|
- /*
|
|
- * Console drivers may assume that per-cpu resources have been
|
|
- * allocated. So unless they're explicitly marked as being able to
|
|
- * cope (CON_ANYTIME) don't call them until this CPU is officially up.
|
|
- */
|
|
- if (!cpu_online(raw_smp_processor_id()) && !(flags & CON_ANYTIME))
|
|
- return false;
|
|
-
|
|
- return true;
|
|
-}
|
|
-
|
|
static void __console_unlock(void)
|
|
{
|
|
console_locked = 0;
|
|
up_console_sem();
|
|
}
|
|
|
|
+static DEFINE_WAIT_OVERRIDE_MAP(printk_legacy_map, LD_WAIT_SLEEP);
|
|
+
|
|
+#ifdef CONFIG_PRINTK
|
|
+
|
|
/*
|
|
* Prepend the message in @pmsg->pbufs->outbuf with a "dropped message". This
|
|
* is achieved by shifting the existing message over and inserting the dropped
|
|
@@ -2766,8 +2841,7 @@ static void __console_unlock(void)
|
|
*
|
|
* If @pmsg->pbufs->outbuf is modified, @pmsg->outbuf_len is updated.
|
|
*/
|
|
-#ifdef CONFIG_PRINTK
|
|
-static void console_prepend_dropped(struct printk_message *pmsg, unsigned long dropped)
|
|
+void console_prepend_dropped(struct printk_message *pmsg, unsigned long dropped)
|
|
{
|
|
struct printk_buffers *pbufs = pmsg->pbufs;
|
|
const size_t scratchbuf_sz = sizeof(pbufs->scratchbuf);
|
|
@@ -2798,9 +2872,6 @@ static void console_prepend_dropped(struct printk_message *pmsg, unsigned long d
|
|
memcpy(outbuf, scratchbuf, len);
|
|
pmsg->outbuf_len += len;
|
|
}
|
|
-#else
|
|
-#define console_prepend_dropped(pmsg, dropped)
|
|
-#endif /* CONFIG_PRINTK */
|
|
|
|
/*
|
|
* Read and format the specified record (or a later record if the specified
|
|
@@ -2821,11 +2892,9 @@ static void console_prepend_dropped(struct printk_message *pmsg, unsigned long d
|
|
* of @pmsg are valid. (See the documentation of struct printk_message
|
|
* for information about the @pmsg fields.)
|
|
*/
|
|
-static bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
|
|
- bool is_extended, bool may_suppress)
|
|
+bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
|
|
+ bool is_extended, bool may_suppress)
|
|
{
|
|
- static int panic_console_dropped;
|
|
-
|
|
struct printk_buffers *pbufs = pmsg->pbufs;
|
|
const size_t scratchbuf_sz = sizeof(pbufs->scratchbuf);
|
|
const size_t outbuf_sz = sizeof(pbufs->outbuf);
|
|
@@ -2853,17 +2922,6 @@ static bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
|
|
pmsg->seq = r.info->seq;
|
|
pmsg->dropped = r.info->seq - seq;
|
|
|
|
- /*
|
|
- * Check for dropped messages in panic here so that printk
|
|
- * suppression can occur as early as possible if necessary.
|
|
- */
|
|
- if (pmsg->dropped &&
|
|
- panic_in_progress() &&
|
|
- panic_console_dropped++ > 10) {
|
|
- suppress_panic_printk = 1;
|
|
- pr_warn_once("Too many dropped messages. Suppress messages on non-panic CPUs to prevent livelock.\n");
|
|
- }
|
|
-
|
|
/* Skip record that has level above the console loglevel. */
|
|
if (may_suppress && suppress_message_printing(r.info->level))
|
|
goto out;
|
|
@@ -2880,6 +2938,13 @@ static bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
|
|
return true;
|
|
}
|
|
|
|
+/*
|
|
+ * Used as the printk buffers for non-panic, serialized console printing.
|
|
+ * This is for legacy (!CON_NBCON) as well as all boot (CON_BOOT) consoles.
|
|
+ * Its usage requires the console_lock held.
|
|
+ */
|
|
+struct printk_buffers printk_shared_pbufs;
|
|
+
|
|
/*
|
|
* Print one record for the given console. The record printed is whatever
|
|
* record is the next available record for the given console.
|
|
@@ -2897,12 +2962,10 @@ static bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
|
|
*/
|
|
static bool console_emit_next_record(struct console *con, bool *handover, int cookie)
|
|
{
|
|
- static struct printk_buffers pbufs;
|
|
-
|
|
bool is_extended = console_srcu_read_flags(con) & CON_EXTENDED;
|
|
- char *outbuf = &pbufs.outbuf[0];
|
|
+ char *outbuf = &printk_shared_pbufs.outbuf[0];
|
|
struct printk_message pmsg = {
|
|
- .pbufs = &pbufs,
|
|
+ .pbufs = &printk_shared_pbufs,
|
|
};
|
|
unsigned long flags;
|
|
|
|
@@ -2924,35 +2987,59 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
|
|
con->dropped = 0;
|
|
}
|
|
|
|
- /*
|
|
- * While actively printing out messages, if another printk()
|
|
- * were to occur on another CPU, it may wait for this one to
|
|
- * finish. This task can not be preempted if there is a
|
|
- * waiter waiting to take over.
|
|
- *
|
|
- * Interrupts are disabled because the hand over to a waiter
|
|
- * must not be interrupted until the hand over is completed
|
|
- * (@console_waiter is cleared).
|
|
- */
|
|
- printk_safe_enter_irqsave(flags);
|
|
- console_lock_spinning_enable();
|
|
+ /* Write everything out to the hardware. */
|
|
|
|
- /* Do not trace print latency. */
|
|
- stop_critical_timings();
|
|
+ if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
|
|
+ /*
|
|
+ * On PREEMPT_RT this function is either in a thread or
|
|
+ * panic context. So there is no need for concern about
|
|
+ * printk reentrance, handovers, or lockdep complaints.
|
|
+ */
|
|
|
|
- /* Write everything out to the hardware. */
|
|
- con->write(con, outbuf, pmsg.outbuf_len);
|
|
+ con->write(con, outbuf, pmsg.outbuf_len);
|
|
+ con->seq = pmsg.seq + 1;
|
|
+ } else {
|
|
+ /*
|
|
+ * While actively printing out messages, if another printk()
|
|
+ * were to occur on another CPU, it may wait for this one to
|
|
+ * finish. This task can not be preempted if there is a
|
|
+ * waiter waiting to take over.
|
|
+ *
|
|
+ * Interrupts are disabled because the hand over to a waiter
|
|
+ * must not be interrupted until the hand over is completed
|
|
+ * (@console_waiter is cleared).
|
|
+ */
|
|
+ printk_safe_enter_irqsave(flags);
|
|
+ console_lock_spinning_enable();
|
|
|
|
- start_critical_timings();
|
|
+ /* Do not trace print latency. */
|
|
+ stop_critical_timings();
|
|
|
|
- con->seq = pmsg.seq + 1;
|
|
+ lock_map_acquire_try(&printk_legacy_map);
|
|
+ con->write(con, outbuf, pmsg.outbuf_len);
|
|
+ lock_map_release(&printk_legacy_map);
|
|
|
|
- *handover = console_lock_spinning_disable_and_check(cookie);
|
|
- printk_safe_exit_irqrestore(flags);
|
|
+ start_critical_timings();
|
|
+
|
|
+ con->seq = pmsg.seq + 1;
|
|
+
|
|
+ *handover = console_lock_spinning_disable_and_check(cookie);
|
|
+ printk_safe_exit_irqrestore(flags);
|
|
+ }
|
|
skip:
|
|
return true;
|
|
}
|
|
|
|
+#else
|
|
+
|
|
+static bool console_emit_next_record(struct console *con, bool *handover, int cookie)
|
|
+{
|
|
+ *handover = false;
|
|
+ return false;
|
|
+}
|
|
+
|
|
+#endif /* CONFIG_PRINTK */
|
|
+
|
|
/*
|
|
* Print out all remaining records to all consoles.
|
|
*
|
|
@@ -2991,13 +3078,33 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
|
|
|
|
cookie = console_srcu_read_lock();
|
|
for_each_console_srcu(con) {
|
|
+ short flags = console_srcu_read_flags(con);
|
|
+ u64 printk_seq;
|
|
bool progress;
|
|
|
|
- if (!console_is_usable(con))
|
|
+ /*
|
|
+ * console_flush_all() is only for legacy consoles,
|
|
+ * unless the nbcon console has no kthread printer.
|
|
+ */
|
|
+ if ((flags & CON_NBCON) && con->kthread)
|
|
+ continue;
|
|
+
|
|
+ if (!console_is_usable(con, flags, true))
|
|
continue;
|
|
any_usable = true;
|
|
|
|
- progress = console_emit_next_record(con, handover, cookie);
|
|
+ if (flags & CON_NBCON) {
|
|
+
|
|
+ lock_map_acquire_try(&printk_legacy_map);
|
|
+ progress = nbcon_atomic_emit_next_record(con, handover, cookie);
|
|
+ lock_map_release(&printk_legacy_map);
|
|
+
|
|
+ printk_seq = nbcon_seq_read(con);
|
|
+ } else {
|
|
+ progress = console_emit_next_record(con, handover, cookie);
|
|
+
|
|
+ printk_seq = con->seq;
|
|
+ }
|
|
|
|
/*
|
|
* If a handover has occurred, the SRCU read lock
|
|
@@ -3007,8 +3114,8 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
|
|
return false;
|
|
|
|
/* Track the next of the highest seq flushed. */
|
|
- if (con->seq > *next_seq)
|
|
- *next_seq = con->seq;
|
|
+ if (printk_seq > *next_seq)
|
|
+ *next_seq = printk_seq;
|
|
|
|
if (!progress)
|
|
continue;
|
|
@@ -3031,19 +3138,7 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove
|
|
return false;
|
|
}
|
|
|
|
-/**
|
|
- * console_unlock - unblock the console subsystem from printing
|
|
- *
|
|
- * Releases the console_lock which the caller holds to block printing of
|
|
- * the console subsystem.
|
|
- *
|
|
- * While the console_lock was held, console output may have been buffered
|
|
- * by printk(). If this is the case, console_unlock(); emits
|
|
- * the output prior to releasing the lock.
|
|
- *
|
|
- * console_unlock(); may be called from any context.
|
|
- */
|
|
-void console_unlock(void)
|
|
+static void console_flush_and_unlock(void)
|
|
{
|
|
bool do_cond_resched;
|
|
bool handover;
|
|
@@ -3087,6 +3182,32 @@ void console_unlock(void)
|
|
*/
|
|
} while (prb_read_valid(prb, next_seq, NULL) && console_trylock());
|
|
}
|
|
+
|
|
+/**
|
|
+ * console_unlock - unblock the console subsystem from printing
|
|
+ *
|
|
+ * Releases the console_lock which the caller holds to block printing of
|
|
+ * the console subsystem.
|
|
+ *
|
|
+ * While the console_lock was held, console output may have been buffered
|
|
+ * by printk(). If this is the case, console_unlock(); emits
|
|
+ * the output prior to releasing the lock.
|
|
+ *
|
|
+ * console_unlock(); may be called from any context.
|
|
+ */
|
|
+void console_unlock(void)
|
|
+{
|
|
+ /*
|
|
+ * PREEMPT_RT relies on kthread and atomic consoles for printing.
|
|
+ * It never attempts to print from console_unlock().
|
|
+ */
|
|
+ if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
|
|
+ __console_unlock();
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ console_flush_and_unlock();
|
|
+}
|
|
EXPORT_SYMBOL(console_unlock);
|
|
|
|
/**
|
|
@@ -3197,6 +3318,7 @@ void console_flush_on_panic(enum con_flush_mode mode)
|
|
|
|
if (mode == CONSOLE_REPLAY_ALL) {
|
|
struct console *c;
|
|
+ short flags;
|
|
int cookie;
|
|
u64 seq;
|
|
|
|
@@ -3204,16 +3326,25 @@ void console_flush_on_panic(enum con_flush_mode mode)
|
|
|
|
cookie = console_srcu_read_lock();
|
|
for_each_console_srcu(c) {
|
|
- /*
|
|
- * This is an unsynchronized assignment, but the
|
|
- * kernel is in "hope and pray" mode anyway.
|
|
- */
|
|
- c->seq = seq;
|
|
+ flags = console_srcu_read_flags(c);
|
|
+
|
|
+ if (flags & CON_NBCON) {
|
|
+ nbcon_seq_force(c, seq);
|
|
+ } else {
|
|
+ /*
|
|
+ * This is an unsynchronized assignment. On
|
|
+ * panic legacy consoles are only best effort.
|
|
+ */
|
|
+ c->seq = seq;
|
|
+ }
|
|
}
|
|
console_srcu_read_unlock(cookie);
|
|
}
|
|
|
|
- console_flush_all(false, &next_seq, &handover);
|
|
+ nbcon_atomic_flush_all();
|
|
+
|
|
+ if (printing_via_unlock)
|
|
+ console_flush_all(false, &next_seq, &handover);
|
|
}
|
|
|
|
/*
|
|
@@ -3270,13 +3401,122 @@ EXPORT_SYMBOL(console_stop);
|
|
|
|
void console_start(struct console *console)
|
|
{
|
|
+ short flags;
|
|
+
|
|
console_list_lock();
|
|
console_srcu_write_flags(console, console->flags | CON_ENABLED);
|
|
+ flags = console->flags;
|
|
console_list_unlock();
|
|
+
|
|
+ /*
|
|
+ * Ensure that all SRCU list walks have completed. The related
|
|
+ * printing context must be able to see it is enabled so that
|
|
+ * it is guaranteed to wake up and resume printing.
|
|
+ */
|
|
+ synchronize_srcu(&console_srcu);
|
|
+
|
|
+ if (flags & CON_NBCON)
|
|
+ nbcon_kthread_wake(console);
|
|
+ else
|
|
+ wake_up_legacy_kthread();
|
|
+
|
|
__pr_flush(console, 1000, true);
|
|
}
|
|
EXPORT_SYMBOL(console_start);
|
|
|
|
+#ifdef CONFIG_PRINTK
|
|
+static bool printer_should_wake(void)
|
|
+{
|
|
+ bool available = false;
|
|
+ struct console *con;
|
|
+ int cookie;
|
|
+
|
|
+ if (kthread_should_stop())
|
|
+ return true;
|
|
+
|
|
+ cookie = console_srcu_read_lock();
|
|
+ for_each_console_srcu(con) {
|
|
+ short flags = console_srcu_read_flags(con);
|
|
+ u64 printk_seq;
|
|
+
|
|
+ /*
|
|
+ * The legacy printer thread is only for legacy consoles,
|
|
+ * unless the nbcon console has no kthread printer.
|
|
+ */
|
|
+ if ((flags & CON_NBCON) && con->kthread)
|
|
+ continue;
|
|
+
|
|
+ if (!console_is_usable(con, flags, true))
|
|
+ continue;
|
|
+
|
|
+ if (flags & CON_NBCON) {
|
|
+ printk_seq = nbcon_seq_read(con);
|
|
+ } else {
|
|
+ /*
|
|
+ * It is safe to read @seq because only this
|
|
+ * thread context updates @seq.
|
|
+ */
|
|
+ printk_seq = con->seq;
|
|
+ }
|
|
+
|
|
+ if (prb_read_valid(prb, printk_seq, NULL)) {
|
|
+ available = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ console_srcu_read_unlock(cookie);
|
|
+
|
|
+ return available;
|
|
+}
|
|
+
|
|
+static int nbcon_legacy_kthread_func(void *unused)
|
|
+{
|
|
+ int error;
|
|
+
|
|
+ for (;;) {
|
|
+ error = wait_event_interruptible(legacy_wait, printer_should_wake());
|
|
+
|
|
+ if (kthread_should_stop())
|
|
+ break;
|
|
+
|
|
+ if (error)
|
|
+ continue;
|
|
+
|
|
+ console_lock();
|
|
+ console_flush_and_unlock();
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void nbcon_legacy_kthread_create(void)
|
|
+{
|
|
+ struct task_struct *kt;
|
|
+
|
|
+ lockdep_assert_held(&console_mutex);
|
|
+
|
|
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT))
|
|
+ return;
|
|
+
|
|
+ if (!printk_threads_enabled || nbcon_legacy_kthread)
|
|
+ return;
|
|
+
|
|
+ kt = kthread_run(nbcon_legacy_kthread_func, NULL, "pr/legacy");
|
|
+ if (IS_ERR(kt)) {
|
|
+ pr_err("unable to start legacy printing thread\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ nbcon_legacy_kthread = kt;
|
|
+
|
|
+ /*
|
|
+ * It is important that console printing threads are scheduled
|
|
+ * shortly after a printk call and with generous runtime budgets.
|
|
+ */
|
|
+ sched_set_normal(nbcon_legacy_kthread, -20);
|
|
+}
|
|
+#endif /* CONFIG_PRINTK */
|
|
+
|
|
static int __read_mostly keep_bootcon;
|
|
|
|
static int __init keep_bootcon_setup(char *str)
|
|
@@ -3375,11 +3615,6 @@ static void try_enable_default_console(struct console *newcon)
|
|
newcon->flags |= CON_CONSDEV;
|
|
}
|
|
|
|
-#define con_printk(lvl, con, fmt, ...) \
|
|
- printk(lvl pr_fmt("%sconsole [%s%d] " fmt), \
|
|
- (con->flags & CON_BOOT) ? "boot" : "", \
|
|
- con->name, con->index, ##__VA_ARGS__)
|
|
-
|
|
static void console_init_seq(struct console *newcon, bool bootcon_registered)
|
|
{
|
|
struct console *con;
|
|
@@ -3428,11 +3663,20 @@ static void console_init_seq(struct console *newcon, bool bootcon_registered)
|
|
|
|
newcon->seq = prb_next_seq(prb);
|
|
for_each_console(con) {
|
|
- if ((con->flags & CON_BOOT) &&
|
|
- (con->flags & CON_ENABLED) &&
|
|
- con->seq < newcon->seq) {
|
|
- newcon->seq = con->seq;
|
|
+ u64 seq;
|
|
+
|
|
+ if (!((con->flags & CON_BOOT) &&
|
|
+ (con->flags & CON_ENABLED))) {
|
|
+ continue;
|
|
}
|
|
+
|
|
+ if (con->flags & CON_NBCON)
|
|
+ seq = nbcon_seq_read(con);
|
|
+ else
|
|
+ seq = con->seq;
|
|
+
|
|
+ if (seq < newcon->seq)
|
|
+ newcon->seq = seq;
|
|
}
|
|
}
|
|
|
|
@@ -3493,6 +3737,15 @@ void register_console(struct console *newcon)
|
|
goto unlock;
|
|
}
|
|
|
|
+ if (newcon->flags & CON_NBCON) {
|
|
+ /*
|
|
+ * Ensure the nbcon console buffers can be allocated
|
|
+ * before modifying any global data.
|
|
+ */
|
|
+ if (!nbcon_alloc(newcon))
|
|
+ goto unlock;
|
|
+ }
|
|
+
|
|
/*
|
|
* See if we want to enable this console driver by default.
|
|
*
|
|
@@ -3520,8 +3773,11 @@ void register_console(struct console *newcon)
|
|
err = try_enable_preferred_console(newcon, false);
|
|
|
|
/* printk() messages are not printed to the Braille console. */
|
|
- if (err || newcon->flags & CON_BRL)
|
|
+ if (err || newcon->flags & CON_BRL) {
|
|
+ if (newcon->flags & CON_NBCON)
|
|
+ nbcon_free(newcon);
|
|
goto unlock;
|
|
+ }
|
|
|
|
/*
|
|
* If we have a bootconsole, and are switching to a real console,
|
|
@@ -3537,6 +3793,17 @@ void register_console(struct console *newcon)
|
|
newcon->dropped = 0;
|
|
console_init_seq(newcon, bootcon_registered);
|
|
|
|
+ if (newcon->flags & CON_NBCON) {
|
|
+ have_nbcon_console = true;
|
|
+ nbcon_init(newcon);
|
|
+ } else {
|
|
+ have_legacy_console = true;
|
|
+ nbcon_legacy_kthread_create();
|
|
+ }
|
|
+
|
|
+ if (newcon->flags & CON_BOOT)
|
|
+ have_boot_console = true;
|
|
+
|
|
/*
|
|
* Put this console in the list - keep the
|
|
* preferred driver at the head of the list.
|
|
@@ -3589,6 +3856,11 @@ EXPORT_SYMBOL(register_console);
|
|
/* Must be called under console_list_lock(). */
|
|
static int unregister_console_locked(struct console *console)
|
|
{
|
|
+ bool is_boot_con = (console->flags & CON_BOOT);
|
|
+ bool found_legacy_con = false;
|
|
+ bool found_nbcon_con = false;
|
|
+ bool found_boot_con = false;
|
|
+ struct console *c;
|
|
int res;
|
|
|
|
lockdep_assert_console_list_lock_held();
|
|
@@ -3628,11 +3900,50 @@ static int unregister_console_locked(struct console *console)
|
|
*/
|
|
synchronize_srcu(&console_srcu);
|
|
|
|
+ if (console->flags & CON_NBCON)
|
|
+ nbcon_free(console);
|
|
+
|
|
console_sysfs_notify();
|
|
|
|
if (console->exit)
|
|
res = console->exit(console);
|
|
|
|
+ /*
|
|
+ * With this console gone, the global flags tracking registered
|
|
+ * console types may have changed. Update them.
|
|
+ */
|
|
+ for_each_console(c) {
|
|
+ if (c->flags & CON_BOOT)
|
|
+ found_boot_con = true;
|
|
+
|
|
+ if (c->flags & CON_NBCON)
|
|
+ found_nbcon_con = true;
|
|
+ else
|
|
+ found_legacy_con = true;
|
|
+ }
|
|
+ if (!found_boot_con)
|
|
+ have_boot_console = false;
|
|
+ if (!found_legacy_con)
|
|
+ have_legacy_console = false;
|
|
+ if (!found_nbcon_con)
|
|
+ have_nbcon_console = false;
|
|
+
|
|
+ /*
|
|
+ * When the last boot console unregisters, start up the
|
|
+ * printing threads.
|
|
+ */
|
|
+ if (is_boot_con && !have_boot_console) {
|
|
+ for_each_console(c)
|
|
+ nbcon_kthread_create(c);
|
|
+ }
|
|
+
|
|
+#ifdef CONFIG_PRINTK
|
|
+ if (!printing_via_unlock && nbcon_legacy_kthread) {
|
|
+ kthread_stop(nbcon_legacy_kthread);
|
|
+ nbcon_legacy_kthread = NULL;
|
|
+ }
|
|
+#endif
|
|
+
|
|
return res;
|
|
}
|
|
|
|
@@ -3777,69 +4088,94 @@ late_initcall(printk_late_init);
|
|
/* If @con is specified, only wait for that console. Otherwise wait for all. */
|
|
static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progress)
|
|
{
|
|
- int remaining = timeout_ms;
|
|
+ unsigned long timeout_jiffies = msecs_to_jiffies(timeout_ms);
|
|
+ unsigned long remaining_jiffies = timeout_jiffies;
|
|
struct console *c;
|
|
u64 last_diff = 0;
|
|
u64 printk_seq;
|
|
+ short flags;
|
|
+ bool locked;
|
|
int cookie;
|
|
u64 diff;
|
|
u64 seq;
|
|
|
|
might_sleep();
|
|
|
|
- seq = prb_next_seq(prb);
|
|
+ seq = prb_next_reserve_seq(prb);
|
|
|
|
- /* Flush the consoles so that records up to @seq are printed. */
|
|
- console_lock();
|
|
- console_unlock();
|
|
+ /*
|
|
+ * Flush the consoles so that records up to @seq are printed.
|
|
+ * Otherwise this function will just wait for the threaded printers
|
|
+ * to print up to @seq.
|
|
+ */
|
|
+ if (printing_via_unlock && !IS_ENABLED(CONFIG_PREEMPT_RT)) {
|
|
+ console_lock();
|
|
+ console_unlock();
|
|
+ }
|
|
|
|
for (;;) {
|
|
+ unsigned long begin_jiffies;
|
|
+ unsigned long slept_jiffies;
|
|
+
|
|
+ locked = false;
|
|
diff = 0;
|
|
|
|
- /*
|
|
- * Hold the console_lock to guarantee safe access to
|
|
- * console->seq. Releasing console_lock flushes more
|
|
- * records in case @seq is still not printed on all
|
|
- * usable consoles.
|
|
- */
|
|
- console_lock();
|
|
+ if (printing_via_unlock) {
|
|
+ /*
|
|
+ * Hold the console_lock to guarantee safe access to
|
|
+ * console->seq. Releasing console_lock flushes more
|
|
+ * records in case @seq is still not printed on all
|
|
+ * usable consoles.
|
|
+ */
|
|
+ console_lock();
|
|
+ locked = true;
|
|
+ }
|
|
|
|
cookie = console_srcu_read_lock();
|
|
for_each_console_srcu(c) {
|
|
if (con && con != c)
|
|
continue;
|
|
+
|
|
+ flags = console_srcu_read_flags(c);
|
|
+
|
|
/*
|
|
* If consoles are not usable, it cannot be expected
|
|
* that they make forward progress, so only increment
|
|
* @diff for usable consoles.
|
|
*/
|
|
- if (!console_is_usable(c))
|
|
+ if (!console_is_usable(c, flags, true) &&
|
|
+ !console_is_usable(c, flags, false)) {
|
|
continue;
|
|
- printk_seq = c->seq;
|
|
+ }
|
|
+
|
|
+ if (flags & CON_NBCON) {
|
|
+ printk_seq = nbcon_seq_read(c);
|
|
+ } else {
|
|
+ WARN_ON_ONCE(!locked);
|
|
+ printk_seq = c->seq;
|
|
+ }
|
|
+
|
|
if (printk_seq < seq)
|
|
diff += seq - printk_seq;
|
|
}
|
|
console_srcu_read_unlock(cookie);
|
|
|
|
if (diff != last_diff && reset_on_progress)
|
|
- remaining = timeout_ms;
|
|
+ remaining_jiffies = timeout_jiffies;
|
|
|
|
- console_unlock();
|
|
+ if (locked)
|
|
+ console_unlock();
|
|
|
|
/* Note: @diff is 0 if there are no usable consoles. */
|
|
- if (diff == 0 || remaining == 0)
|
|
+ if (diff == 0 || remaining_jiffies == 0)
|
|
break;
|
|
|
|
- if (remaining < 0) {
|
|
- /* no timeout limit */
|
|
- msleep(100);
|
|
- } else if (remaining < 100) {
|
|
- msleep(remaining);
|
|
- remaining = 0;
|
|
- } else {
|
|
- msleep(100);
|
|
- remaining -= 100;
|
|
- }
|
|
+ /* msleep(1) might sleep much longer. Check time by jiffies. */
|
|
+ begin_jiffies = jiffies;
|
|
+ msleep(1);
|
|
+ slept_jiffies = jiffies - begin_jiffies;
|
|
+
|
|
+ remaining_jiffies -= min(slept_jiffies, remaining_jiffies);
|
|
|
|
last_diff = diff;
|
|
}
|
|
@@ -3880,9 +4216,16 @@ static void wake_up_klogd_work_func(struct irq_work *irq_work)
|
|
int pending = this_cpu_xchg(printk_pending, 0);
|
|
|
|
if (pending & PRINTK_PENDING_OUTPUT) {
|
|
- /* If trylock fails, someone else is doing the printing */
|
|
- if (console_trylock())
|
|
- console_unlock();
|
|
+ if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
|
|
+ wake_up_interruptible(&legacy_wait);
|
|
+ } else {
|
|
+ /*
|
|
+ * If trylock fails, some other context
|
|
+ * will do the printing.
|
|
+ */
|
|
+ if (console_trylock())
|
|
+ console_unlock();
|
|
+ }
|
|
}
|
|
|
|
if (pending & PRINTK_PENDING_WAKEUP)
|
|
@@ -3950,11 +4293,16 @@ void defer_console_output(void)
|
|
* New messages may have been added directly to the ringbuffer
|
|
* using vprintk_store(), so wake any waiters as well.
|
|
*/
|
|
- __wake_up_klogd(PRINTK_PENDING_WAKEUP | PRINTK_PENDING_OUTPUT);
|
|
+ int val = PRINTK_PENDING_WAKEUP;
|
|
+
|
|
+ if (printing_via_unlock)
|
|
+ val |= PRINTK_PENDING_OUTPUT;
|
|
+ __wake_up_klogd(val);
|
|
}
|
|
|
|
void printk_trigger_flush(void)
|
|
{
|
|
+ nbcon_wake_threads();
|
|
defer_console_output();
|
|
}
|
|
|
|
diff --git a/kernel/printk/printk_ringbuffer.c b/kernel/printk/printk_ringbuffer.c
|
|
index fde338606ce8..e7b808b829a0 100644
|
|
--- a/kernel/printk/printk_ringbuffer.c
|
|
+++ b/kernel/printk/printk_ringbuffer.c
|
|
@@ -6,6 +6,7 @@
|
|
#include <linux/errno.h>
|
|
#include <linux/bug.h>
|
|
#include "printk_ringbuffer.h"
|
|
+#include "internal.h"
|
|
|
|
/**
|
|
* DOC: printk_ringbuffer overview
|
|
@@ -303,6 +304,9 @@
|
|
*
|
|
* desc_push_tail:B / desc_reserve:D
|
|
* set descriptor reusable (state), then push descriptor tail (id)
|
|
+ *
|
|
+ * desc_update_last_finalized:A / desc_last_finalized_seq:A
|
|
+ * store finalized record, then set new highest finalized sequence number
|
|
*/
|
|
|
|
#define DATA_SIZE(data_ring) _DATA_SIZE((data_ring)->size_bits)
|
|
@@ -1030,9 +1034,13 @@ static char *data_alloc(struct printk_ringbuffer *rb, unsigned int size,
|
|
unsigned long next_lpos;
|
|
|
|
if (size == 0) {
|
|
- /* Specify a data-less block. */
|
|
- blk_lpos->begin = NO_LPOS;
|
|
- blk_lpos->next = NO_LPOS;
|
|
+ /*
|
|
+ * Data blocks are not created for empty lines. Instead, the
|
|
+ * reader will recognize these special lpos values and handle
|
|
+ * it appropriately.
|
|
+ */
|
|
+ blk_lpos->begin = EMPTY_LINE_LPOS;
|
|
+ blk_lpos->next = EMPTY_LINE_LPOS;
|
|
return NULL;
|
|
}
|
|
|
|
@@ -1210,10 +1218,18 @@ static const char *get_data(struct prb_data_ring *data_ring,
|
|
|
|
/* Data-less data block description. */
|
|
if (BLK_DATALESS(blk_lpos)) {
|
|
- if (blk_lpos->begin == NO_LPOS && blk_lpos->next == NO_LPOS) {
|
|
+ /*
|
|
+ * Records that are just empty lines are also valid, even
|
|
+ * though they do not have a data block. For such records
|
|
+ * explicitly return empty string data to signify success.
|
|
+ */
|
|
+ if (blk_lpos->begin == EMPTY_LINE_LPOS &&
|
|
+ blk_lpos->next == EMPTY_LINE_LPOS) {
|
|
*data_size = 0;
|
|
return "";
|
|
}
|
|
+
|
|
+ /* Data lost, invalid, or otherwise unavailable. */
|
|
return NULL;
|
|
}
|
|
|
|
@@ -1441,20 +1457,118 @@ bool prb_reserve_in_last(struct prb_reserved_entry *e, struct printk_ringbuffer
|
|
return false;
|
|
}
|
|
|
|
+/*
|
|
+ * @last_finalized_seq value guarantees that all records up to and including
|
|
+ * this sequence number are finalized and can be read. The only exception are
|
|
+ * too old records which have already been overwritten.
|
|
+ *
|
|
+ * It is also guaranteed that @last_finalized_seq only increases.
|
|
+ *
|
|
+ * Be aware that finalized records following non-finalized records are not
|
|
+ * reported because they are not yet available to the reader. For example,
|
|
+ * a new record stored via printk() will not be available to a printer if
|
|
+ * it follows a record that has not been finalized yet. However, once that
|
|
+ * non-finalized record becomes finalized, @last_finalized_seq will be
|
|
+ * appropriately updated and the full set of finalized records will be
|
|
+ * available to the printer. And since each printk() caller will either
|
|
+ * directly print or trigger deferred printing of all available unprinted
|
|
+ * records, all printk() messages will get printed.
|
|
+ */
|
|
+static u64 desc_last_finalized_seq(struct printk_ringbuffer *rb)
|
|
+{
|
|
+ struct prb_desc_ring *desc_ring = &rb->desc_ring;
|
|
+ unsigned long ulseq;
|
|
+
|
|
+ /*
|
|
+ * Guarantee the sequence number is loaded before loading the
|
|
+ * associated record in order to guarantee that the record can be
|
|
+ * seen by this CPU. This pairs with desc_update_last_finalized:A.
|
|
+ */
|
|
+ ulseq = atomic_long_read_acquire(&desc_ring->last_finalized_seq
|
|
+ ); /* LMM(desc_last_finalized_seq:A) */
|
|
+
|
|
+ return __ulseq_to_u64seq(rb, ulseq);
|
|
+}
|
|
+
|
|
+static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq,
|
|
+ struct printk_record *r, unsigned int *line_count);
|
|
+
|
|
+/*
|
|
+ * Check if there are records directly following @last_finalized_seq that are
|
|
+ * finalized. If so, update @last_finalized_seq to the latest of these
|
|
+ * records. It is not allowed to skip over records that are not yet finalized.
|
|
+ */
|
|
+static void desc_update_last_finalized(struct printk_ringbuffer *rb)
|
|
+{
|
|
+ struct prb_desc_ring *desc_ring = &rb->desc_ring;
|
|
+ u64 old_seq = desc_last_finalized_seq(rb);
|
|
+ unsigned long oldval;
|
|
+ unsigned long newval;
|
|
+ u64 finalized_seq;
|
|
+ u64 try_seq;
|
|
+
|
|
+try_again:
|
|
+ finalized_seq = old_seq;
|
|
+ try_seq = finalized_seq + 1;
|
|
+
|
|
+ /* Try to find later finalized records. */
|
|
+ while (_prb_read_valid(rb, &try_seq, NULL, NULL)) {
|
|
+ finalized_seq = try_seq;
|
|
+ try_seq++;
|
|
+ }
|
|
+
|
|
+ /* No update needed if no later finalized record was found. */
|
|
+ if (finalized_seq == old_seq)
|
|
+ return;
|
|
+
|
|
+ oldval = __u64seq_to_ulseq(old_seq);
|
|
+ newval = __u64seq_to_ulseq(finalized_seq);
|
|
+
|
|
+ /*
|
|
+ * Set the sequence number of a later finalized record that has been
|
|
+ * seen.
|
|
+ *
|
|
+ * Guarantee the record data is visible to other CPUs before storing
|
|
+ * its sequence number. This pairs with desc_last_finalized_seq:A.
|
|
+ *
|
|
+ * Memory barrier involvement:
|
|
+ *
|
|
+ * If desc_last_finalized_seq:A reads from
|
|
+ * desc_update_last_finalized:A, then desc_read:A reads from
|
|
+ * _prb_commit:B.
|
|
+ *
|
|
+ * Relies on:
|
|
+ *
|
|
+ * RELEASE from _prb_commit:B to desc_update_last_finalized:A
|
|
+ * matching
|
|
+ * ACQUIRE from desc_last_finalized_seq:A to desc_read:A
|
|
+ *
|
|
+ * Note: _prb_commit:B and desc_update_last_finalized:A can be
|
|
+ * different CPUs. However, the desc_update_last_finalized:A
|
|
+ * CPU (which performs the release) must have previously seen
|
|
+ * _prb_commit:B.
|
|
+ */
|
|
+ if (!atomic_long_try_cmpxchg_release(&desc_ring->last_finalized_seq,
|
|
+ &oldval, newval)) { /* LMM(desc_update_last_finalized:A) */
|
|
+ old_seq = __ulseq_to_u64seq(rb, oldval);
|
|
+ goto try_again;
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
* Attempt to finalize a specified descriptor. If this fails, the descriptor
|
|
* is either already final or it will finalize itself when the writer commits.
|
|
*/
|
|
-static void desc_make_final(struct prb_desc_ring *desc_ring, unsigned long id)
|
|
+static void desc_make_final(struct printk_ringbuffer *rb, unsigned long id)
|
|
{
|
|
+ struct prb_desc_ring *desc_ring = &rb->desc_ring;
|
|
unsigned long prev_state_val = DESC_SV(id, desc_committed);
|
|
struct prb_desc *d = to_desc(desc_ring, id);
|
|
|
|
- atomic_long_cmpxchg_relaxed(&d->state_var, prev_state_val,
|
|
- DESC_SV(id, desc_finalized)); /* LMM(desc_make_final:A) */
|
|
-
|
|
- /* Best effort to remember the last finalized @id. */
|
|
- atomic_long_set(&desc_ring->last_finalized_id, id);
|
|
+ if (atomic_long_try_cmpxchg_relaxed(&d->state_var, &prev_state_val,
|
|
+ DESC_SV(id, desc_finalized))) { /* LMM(desc_make_final:A) */
|
|
+ desc_update_last_finalized(rb);
|
|
+ }
|
|
}
|
|
|
|
/**
|
|
@@ -1550,7 +1664,7 @@ bool prb_reserve(struct prb_reserved_entry *e, struct printk_ringbuffer *rb,
|
|
* readers. (For seq==0 there is no previous descriptor.)
|
|
*/
|
|
if (info->seq > 0)
|
|
- desc_make_final(desc_ring, DESC_ID(id - 1));
|
|
+ desc_make_final(rb, DESC_ID(id - 1));
|
|
|
|
r->text_buf = data_alloc(rb, r->text_buf_size, &d->text_blk_lpos, id);
|
|
/* If text data allocation fails, a data-less record is committed. */
|
|
@@ -1643,7 +1757,7 @@ void prb_commit(struct prb_reserved_entry *e)
|
|
*/
|
|
head_id = atomic_long_read(&desc_ring->head_id); /* LMM(prb_commit:A) */
|
|
if (head_id != e->id)
|
|
- desc_make_final(desc_ring, e->id);
|
|
+ desc_make_final(e->rb, e->id);
|
|
}
|
|
|
|
/**
|
|
@@ -1663,12 +1777,9 @@ void prb_commit(struct prb_reserved_entry *e)
|
|
*/
|
|
void prb_final_commit(struct prb_reserved_entry *e)
|
|
{
|
|
- struct prb_desc_ring *desc_ring = &e->rb->desc_ring;
|
|
-
|
|
_prb_commit(e, desc_finalized);
|
|
|
|
- /* Best effort to remember the last finalized @id. */
|
|
- atomic_long_set(&desc_ring->last_finalized_id, e->id);
|
|
+ desc_update_last_finalized(e->rb);
|
|
}
|
|
|
|
/*
|
|
@@ -1746,6 +1857,8 @@ static bool copy_data(struct prb_data_ring *data_ring,
|
|
* descriptor. However, it also verifies that the record is finalized and has
|
|
* the sequence number @seq. On success, 0 is returned.
|
|
*
|
|
+ * For the panic CPU, committed descriptors are also considered finalized.
|
|
+ *
|
|
* Error return values:
|
|
* -EINVAL: A finalized record with sequence number @seq does not exist.
|
|
* -ENOENT: A finalized record with sequence number @seq exists, but its data
|
|
@@ -1764,16 +1877,25 @@ static int desc_read_finalized_seq(struct prb_desc_ring *desc_ring,
|
|
|
|
/*
|
|
* An unexpected @id (desc_miss) or @seq mismatch means the record
|
|
- * does not exist. A descriptor in the reserved or committed state
|
|
- * means the record does not yet exist for the reader.
|
|
+ * does not exist. A descriptor in the reserved state means the
|
|
+ * record does not yet exist for the reader.
|
|
*/
|
|
if (d_state == desc_miss ||
|
|
d_state == desc_reserved ||
|
|
- d_state == desc_committed ||
|
|
s != seq) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
+ /*
|
|
+ * A descriptor in the committed state means the record does not yet
|
|
+ * exist for the reader. However, for the panic CPU, committed
|
|
+ * records are also handled as finalized records since they contain
|
|
+ * message data in a consistent state and may contain additional
|
|
+ * hints as to the cause of the panic.
|
|
+ */
|
|
+ if (d_state == desc_committed && !this_cpu_in_panic())
|
|
+ return -EINVAL;
|
|
+
|
|
/*
|
|
* A descriptor in the reusable state may no longer have its data
|
|
* available; report it as existing but with lost data. Or the record
|
|
@@ -1832,7 +1954,7 @@ static int prb_read(struct printk_ringbuffer *rb, u64 seq,
|
|
}
|
|
|
|
/* Get the sequence number of the tail descriptor. */
|
|
-static u64 prb_first_seq(struct printk_ringbuffer *rb)
|
|
+u64 prb_first_seq(struct printk_ringbuffer *rb)
|
|
{
|
|
struct prb_desc_ring *desc_ring = &rb->desc_ring;
|
|
enum desc_state d_state;
|
|
@@ -1875,12 +1997,131 @@ static u64 prb_first_seq(struct printk_ringbuffer *rb)
|
|
return seq;
|
|
}
|
|
|
|
+/**
|
|
+ * prb_next_reserve_seq() - Get the sequence number after the most recently
|
|
+ * reserved record.
|
|
+ *
|
|
+ * @rb: The ringbuffer to get the sequence number from.
|
|
+ *
|
|
+ * This is the public function available to readers to see what sequence
|
|
+ * number will be assigned to the next reserved record.
|
|
+ *
|
|
+ * Note that depending on the situation, this value can be equal to or
|
|
+ * higher than the sequence number returned by prb_next_seq().
|
|
+ *
|
|
+ * Context: Any context.
|
|
+ * Return: The sequence number that will be assigned to the next record
|
|
+ * reserved.
|
|
+ */
|
|
+u64 prb_next_reserve_seq(struct printk_ringbuffer *rb)
|
|
+{
|
|
+ struct prb_desc_ring *desc_ring = &rb->desc_ring;
|
|
+ unsigned long last_finalized_id;
|
|
+ atomic_long_t *state_var;
|
|
+ u64 last_finalized_seq;
|
|
+ unsigned long head_id;
|
|
+ struct prb_desc desc;
|
|
+ unsigned long diff;
|
|
+ struct prb_desc *d;
|
|
+ int err;
|
|
+
|
|
+ /*
|
|
+ * It may not be possible to read a sequence number for @head_id.
|
|
+ * So the ID of @last_finailzed_seq is used to calculate what the
|
|
+ * sequence number of @head_id will be.
|
|
+ */
|
|
+
|
|
+try_again:
|
|
+ last_finalized_seq = desc_last_finalized_seq(rb);
|
|
+
|
|
+ /*
|
|
+ * @head_id is loaded after @last_finalized_seq to ensure that it is
|
|
+ * at or beyond @last_finalized_seq.
|
|
+ *
|
|
+ * Memory barrier involvement:
|
|
+ *
|
|
+ * If desc_last_finalized_seq:A reads from
|
|
+ * desc_update_last_finalized:A, then
|
|
+ * prb_next_reserve_seq:A reads from desc_reserve:D.
|
|
+ *
|
|
+ * Relies on:
|
|
+ *
|
|
+ * RELEASE from desc_reserve:D to desc_update_last_finalized:A
|
|
+ * matching
|
|
+ * ACQUIRE from desc_last_finalized_seq:A to prb_next_reserve_seq:A
|
|
+ *
|
|
+ * Note: desc_reserve:D and desc_update_last_finalized:A can be
|
|
+ * different CPUs. However, the desc_update_last_finalized:A CPU
|
|
+ * (which performs the release) must have previously seen
|
|
+ * desc_read:C, which implies desc_reserve:D can be seen.
|
|
+ */
|
|
+ head_id = atomic_long_read(&desc_ring->head_id); /* LMM(prb_next_reserve_seq:A) */
|
|
+
|
|
+ d = to_desc(desc_ring, last_finalized_seq);
|
|
+ state_var = &d->state_var;
|
|
+
|
|
+ /* Extract the ID, used to specify the descriptor to read. */
|
|
+ last_finalized_id = DESC_ID(atomic_long_read(state_var));
|
|
+
|
|
+ /* Ensure @last_finalized_id is correct. */
|
|
+ err = desc_read_finalized_seq(desc_ring, last_finalized_id, last_finalized_seq, &desc);
|
|
+
|
|
+ if (err == -EINVAL) {
|
|
+ if (last_finalized_seq == 0) {
|
|
+ /*
|
|
+ * @last_finalized_seq still contains its initial
|
|
+ * value. Probably no record has been finalized yet.
|
|
+ * This means the ringbuffer is not yet full and the
|
|
+ * @head_id value can be used directly (subtracting
|
|
+ * off the id value corresponding to seq=0).
|
|
+ */
|
|
+
|
|
+ /*
|
|
+ * Because of hack#2 of the bootstrapping phase, the
|
|
+ * @head_id initial value must be handled separately.
|
|
+ */
|
|
+ if (head_id == DESC0_ID(desc_ring->count_bits))
|
|
+ return 0;
|
|
+
|
|
+ /*
|
|
+ * The @head_id is initialized such that the first
|
|
+ * increment will yield the first record (seq=0).
|
|
+ * Therefore use the initial value +1 as the base to
|
|
+ * subtract from @head_id.
|
|
+ */
|
|
+ last_finalized_id = DESC0_ID(desc_ring->count_bits) + 1;
|
|
+ } else {
|
|
+ /* Record must have been overwritten. Try again. */
|
|
+ goto try_again;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * @diff is the number of records beyond the last record available
|
|
+ * to readers.
|
|
+ */
|
|
+ diff = head_id - last_finalized_id;
|
|
+
|
|
+ /*
|
|
+ * @head_id points to the most recently reserved record, but this
|
|
+ * function returns the sequence number that will be assigned to the
|
|
+ * next (not yet reserved) record. Thus +1 is needed.
|
|
+ */
|
|
+ return (last_finalized_seq + diff + 1);
|
|
+}
|
|
+
|
|
/*
|
|
- * Non-blocking read of a record. Updates @seq to the last finalized record
|
|
- * (which may have no data available).
|
|
+ * Non-blocking read of a record.
|
|
*
|
|
- * See the description of prb_read_valid() and prb_read_valid_info()
|
|
- * for details.
|
|
+ * On success @seq is updated to the record that was read and (if provided)
|
|
+ * @r and @line_count will contain the read/calculated data.
|
|
+ *
|
|
+ * On failure @seq is updated to a record that is not yet available to the
|
|
+ * reader, but it will be the next record available to the reader.
|
|
+ *
|
|
+ * Note: When the current CPU is in panic, this function will skip over any
|
|
+ * non-existent/non-finalized records in order to allow the panic CPU
|
|
+ * to print any and all records that have been finalized.
|
|
*/
|
|
static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq,
|
|
struct printk_record *r, unsigned int *line_count)
|
|
@@ -1899,12 +2140,32 @@ static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq,
|
|
*seq = tail_seq;
|
|
|
|
} else if (err == -ENOENT) {
|
|
- /* Record exists, but no data available. Skip. */
|
|
+ /* Record exists, but the data was lost. Skip. */
|
|
(*seq)++;
|
|
|
|
} else {
|
|
- /* Non-existent/non-finalized record. Must stop. */
|
|
- return false;
|
|
+ /*
|
|
+ * Non-existent/non-finalized record. Must stop.
|
|
+ *
|
|
+ * For panic situations it cannot be expected that
|
|
+ * non-finalized records will become finalized. But
|
|
+ * there may be other finalized records beyond that
|
|
+ * need to be printed for a panic situation. If this
|
|
+ * is the panic CPU, skip this
|
|
+ * non-existent/non-finalized record unless it is
|
|
+ * at or beyond the head, in which case it is not
|
|
+ * possible to continue.
|
|
+ *
|
|
+ * Note that new messages printed on panic CPU are
|
|
+ * finalized when we are here. The only exception
|
|
+ * might be the last message without trailing newline.
|
|
+ * But it would have the sequence number returned
|
|
+ * by "prb_next_reserve_seq() - 1".
|
|
+ */
|
|
+ if (this_cpu_in_panic() && ((*seq + 1) < prb_next_reserve_seq(rb)))
|
|
+ (*seq)++;
|
|
+ else
|
|
+ return false;
|
|
}
|
|
}
|
|
|
|
@@ -1932,7 +2193,7 @@ static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq,
|
|
* On success, the reader must check r->info.seq to see which record was
|
|
* actually read. This allows the reader to detect dropped records.
|
|
*
|
|
- * Failure means @seq refers to a not yet written record.
|
|
+ * Failure means @seq refers to a record not yet available to the reader.
|
|
*/
|
|
bool prb_read_valid(struct printk_ringbuffer *rb, u64 seq,
|
|
struct printk_record *r)
|
|
@@ -1962,7 +2223,7 @@ bool prb_read_valid(struct printk_ringbuffer *rb, u64 seq,
|
|
* On success, the reader must check info->seq to see which record meta data
|
|
* was actually read. This allows the reader to detect dropped records.
|
|
*
|
|
- * Failure means @seq refers to a not yet written record.
|
|
+ * Failure means @seq refers to a record not yet available to the reader.
|
|
*/
|
|
bool prb_read_valid_info(struct printk_ringbuffer *rb, u64 seq,
|
|
struct printk_info *info, unsigned int *line_count)
|
|
@@ -2008,7 +2269,9 @@ u64 prb_first_valid_seq(struct printk_ringbuffer *rb)
|
|
* newest sequence number available to readers will be.
|
|
*
|
|
* This provides readers a sequence number to jump to if all currently
|
|
- * available records should be skipped.
|
|
+ * available records should be skipped. It is guaranteed that all records
|
|
+ * previous to the returned value have been finalized and are (or were)
|
|
+ * available to the reader.
|
|
*
|
|
* Context: Any context.
|
|
* Return: The sequence number of the next newest (not yet available) record
|
|
@@ -2016,34 +2279,19 @@ u64 prb_first_valid_seq(struct printk_ringbuffer *rb)
|
|
*/
|
|
u64 prb_next_seq(struct printk_ringbuffer *rb)
|
|
{
|
|
- struct prb_desc_ring *desc_ring = &rb->desc_ring;
|
|
- enum desc_state d_state;
|
|
- unsigned long id;
|
|
u64 seq;
|
|
|
|
- /* Check if the cached @id still points to a valid @seq. */
|
|
- id = atomic_long_read(&desc_ring->last_finalized_id);
|
|
- d_state = desc_read(desc_ring, id, NULL, &seq, NULL);
|
|
+ seq = desc_last_finalized_seq(rb);
|
|
|
|
- if (d_state == desc_finalized || d_state == desc_reusable) {
|
|
- /*
|
|
- * Begin searching after the last finalized record.
|
|
- *
|
|
- * On 0, the search must begin at 0 because of hack#2
|
|
- * of the bootstrapping phase it is not known if a
|
|
- * record at index 0 exists.
|
|
- */
|
|
- if (seq != 0)
|
|
- seq++;
|
|
- } else {
|
|
- /*
|
|
- * The information about the last finalized sequence number
|
|
- * has gone. It should happen only when there is a flood of
|
|
- * new messages and the ringbuffer is rapidly recycled.
|
|
- * Give up and start from the beginning.
|
|
- */
|
|
- seq = 0;
|
|
- }
|
|
+ /*
|
|
+ * Begin searching after the last finalized record.
|
|
+ *
|
|
+ * On 0, the search must begin at 0 because of hack#2
|
|
+ * of the bootstrapping phase it is not known if a
|
|
+ * record at index 0 exists.
|
|
+ */
|
|
+ if (seq != 0)
|
|
+ seq++;
|
|
|
|
/*
|
|
* The information about the last finalized @seq might be inaccurate.
|
|
@@ -2085,7 +2333,7 @@ void prb_init(struct printk_ringbuffer *rb,
|
|
rb->desc_ring.infos = infos;
|
|
atomic_long_set(&rb->desc_ring.head_id, DESC0_ID(descbits));
|
|
atomic_long_set(&rb->desc_ring.tail_id, DESC0_ID(descbits));
|
|
- atomic_long_set(&rb->desc_ring.last_finalized_id, DESC0_ID(descbits));
|
|
+ atomic_long_set(&rb->desc_ring.last_finalized_seq, 0);
|
|
|
|
rb->text_data_ring.size_bits = textbits;
|
|
rb->text_data_ring.data = text_buf;
|
|
diff --git a/kernel/printk/printk_ringbuffer.h b/kernel/printk/printk_ringbuffer.h
|
|
index 18cd25e489b8..52626d0f1fa3 100644
|
|
--- a/kernel/printk/printk_ringbuffer.h
|
|
+++ b/kernel/printk/printk_ringbuffer.h
|
|
@@ -75,7 +75,7 @@ struct prb_desc_ring {
|
|
struct printk_info *infos;
|
|
atomic_long_t head_id;
|
|
atomic_long_t tail_id;
|
|
- atomic_long_t last_finalized_id;
|
|
+ atomic_long_t last_finalized_seq;
|
|
};
|
|
|
|
/*
|
|
@@ -127,8 +127,22 @@ enum desc_state {
|
|
#define DESC_SV(id, state) (((unsigned long)state << DESC_FLAGS_SHIFT) | id)
|
|
#define DESC_ID_MASK (~DESC_FLAGS_MASK)
|
|
#define DESC_ID(sv) ((sv) & DESC_ID_MASK)
|
|
+
|
|
+/*
|
|
+ * Special data block logical position values (for fields of
|
|
+ * @prb_desc.text_blk_lpos).
|
|
+ *
|
|
+ * - Bit0 is used to identify if the record has no data block. (Implemented in
|
|
+ * the LPOS_DATALESS() macro.)
|
|
+ *
|
|
+ * - Bit1 specifies the reason for not having a data block.
|
|
+ *
|
|
+ * These special values could never be real lpos values because of the
|
|
+ * meta data and alignment padding of data blocks. (See to_blk_size() for
|
|
+ * details.)
|
|
+ */
|
|
#define FAILED_LPOS 0x1
|
|
-#define NO_LPOS 0x3
|
|
+#define EMPTY_LINE_LPOS 0x3
|
|
|
|
#define FAILED_BLK_LPOS \
|
|
{ \
|
|
@@ -259,7 +273,7 @@ static struct printk_ringbuffer name = { \
|
|
.infos = &_##name##_infos[0], \
|
|
.head_id = ATOMIC_INIT(DESC0_ID(descbits)), \
|
|
.tail_id = ATOMIC_INIT(DESC0_ID(descbits)), \
|
|
- .last_finalized_id = ATOMIC_INIT(DESC0_ID(descbits)), \
|
|
+ .last_finalized_seq = ATOMIC_INIT(0), \
|
|
}, \
|
|
.text_data_ring = { \
|
|
.size_bits = (avgtextbits) + (descbits), \
|
|
@@ -378,7 +392,41 @@ bool prb_read_valid(struct printk_ringbuffer *rb, u64 seq,
|
|
bool prb_read_valid_info(struct printk_ringbuffer *rb, u64 seq,
|
|
struct printk_info *info, unsigned int *line_count);
|
|
|
|
+u64 prb_first_seq(struct printk_ringbuffer *rb);
|
|
u64 prb_first_valid_seq(struct printk_ringbuffer *rb);
|
|
u64 prb_next_seq(struct printk_ringbuffer *rb);
|
|
+u64 prb_next_reserve_seq(struct printk_ringbuffer *rb);
|
|
+
|
|
+#ifdef CONFIG_64BIT
|
|
+
|
|
+#define __u64seq_to_ulseq(u64seq) (u64seq)
|
|
+#define __ulseq_to_u64seq(rb, ulseq) (ulseq)
|
|
+
|
|
+#else /* CONFIG_64BIT */
|
|
+
|
|
+#define __u64seq_to_ulseq(u64seq) ((u32)u64seq)
|
|
+
|
|
+static inline u64 __ulseq_to_u64seq(struct printk_ringbuffer *rb, u32 ulseq)
|
|
+{
|
|
+ u64 rb_first_seq = prb_first_seq(rb);
|
|
+ u64 seq;
|
|
+
|
|
+ /*
|
|
+ * The provided sequence is only the lower 32 bits of the ringbuffer
|
|
+ * sequence. It needs to be expanded to 64bit. Get the first sequence
|
|
+ * number from the ringbuffer and fold it.
|
|
+ *
|
|
+ * Having a 32bit representation in the console is sufficient.
|
|
+ * If a console ever gets more than 2^31 records behind
|
|
+ * the ringbuffer then this is the least of the problems.
|
|
+ *
|
|
+ * Also the access to the ring buffer is always safe.
|
|
+ */
|
|
+ seq = rb_first_seq - (s32)((u32)rb_first_seq - ulseq);
|
|
+
|
|
+ return seq;
|
|
+}
|
|
+
|
|
+#endif /* CONFIG_64BIT */
|
|
|
|
#endif /* _KERNEL_PRINTK_RINGBUFFER_H */
|
|
diff --git a/kernel/printk/printk_safe.c b/kernel/printk/printk_safe.c
|
|
index 6d10927a07d8..8d9408d653de 100644
|
|
--- a/kernel/printk/printk_safe.c
|
|
+++ b/kernel/printk/printk_safe.c
|
|
@@ -26,6 +26,18 @@ void __printk_safe_exit(void)
|
|
this_cpu_dec(printk_context);
|
|
}
|
|
|
|
+void __printk_deferred_enter(void)
|
|
+{
|
|
+ cant_migrate();
|
|
+ this_cpu_inc(printk_context);
|
|
+}
|
|
+
|
|
+void __printk_deferred_exit(void)
|
|
+{
|
|
+ cant_migrate();
|
|
+ this_cpu_dec(printk_context);
|
|
+}
|
|
+
|
|
asmlinkage int vprintk(const char *fmt, va_list args)
|
|
{
|
|
#ifdef CONFIG_KGDB_KDB
|
|
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
|
|
index 46612fb15fc6..f893f4cfdd38 100644
|
|
--- a/kernel/rcu/rcutorture.c
|
|
+++ b/kernel/rcu/rcutorture.c
|
|
@@ -2409,6 +2409,12 @@ static int rcutorture_booster_init(unsigned int cpu)
|
|
WARN_ON_ONCE(!t);
|
|
sp.sched_priority = 2;
|
|
sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
|
|
+#ifdef CONFIG_PREEMPT_RT
|
|
+ t = per_cpu(timersd, cpu);
|
|
+ WARN_ON_ONCE(!t);
|
|
+ sp.sched_priority = 2;
|
|
+ sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
|
|
+#endif
|
|
}
|
|
|
|
/* Don't allow time recalculation while creating a new task. */
|
|
diff --git a/kernel/rcu/tree_stall.h b/kernel/rcu/tree_stall.h
|
|
index 11a1fac3a589..6f085a159fca 100644
|
|
--- a/kernel/rcu/tree_stall.h
|
|
+++ b/kernel/rcu/tree_stall.h
|
|
@@ -8,6 +8,7 @@
|
|
*/
|
|
|
|
#include <linux/kvm_para.h>
|
|
+#include <linux/console.h>
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
@@ -604,6 +605,8 @@ static void print_other_cpu_stall(unsigned long gp_seq, unsigned long gps)
|
|
if (rcu_stall_is_suppressed())
|
|
return;
|
|
|
|
+ nbcon_cpu_emergency_enter();
|
|
+
|
|
/*
|
|
* OK, time to rat on our buddy...
|
|
* See Documentation/RCU/stallwarn.rst for info on how to debug
|
|
@@ -658,6 +661,8 @@ static void print_other_cpu_stall(unsigned long gp_seq, unsigned long gps)
|
|
panic_on_rcu_stall();
|
|
|
|
rcu_force_quiescent_state(); /* Kick them all. */
|
|
+
|
|
+ nbcon_cpu_emergency_exit();
|
|
}
|
|
|
|
static void print_cpu_stall(unsigned long gps)
|
|
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
|
|
index 9b406d988654..5e65826dd984 100644
|
|
--- a/kernel/sched/core.c
|
|
+++ b/kernel/sched/core.c
|
|
@@ -897,14 +897,15 @@ static inline void hrtick_rq_init(struct rq *rq)
|
|
|
|
#if defined(CONFIG_SMP) && defined(TIF_POLLING_NRFLAG)
|
|
/*
|
|
- * Atomically set TIF_NEED_RESCHED and test for TIF_POLLING_NRFLAG,
|
|
+ * Atomically set TIF_NEED_RESCHED[_LAZY] and test for TIF_POLLING_NRFLAG,
|
|
* this avoids any races wrt polling state changes and thereby avoids
|
|
* spurious IPIs.
|
|
*/
|
|
-static inline bool set_nr_and_not_polling(struct task_struct *p)
|
|
+static inline bool set_nr_and_not_polling(struct task_struct *p, int tif_bit)
|
|
{
|
|
struct thread_info *ti = task_thread_info(p);
|
|
- return !(fetch_or(&ti->flags, _TIF_NEED_RESCHED) & _TIF_POLLING_NRFLAG);
|
|
+
|
|
+ return !(fetch_or(&ti->flags, 1 << tif_bit) & _TIF_POLLING_NRFLAG);
|
|
}
|
|
|
|
/*
|
|
@@ -921,7 +922,7 @@ static bool set_nr_if_polling(struct task_struct *p)
|
|
for (;;) {
|
|
if (!(val & _TIF_POLLING_NRFLAG))
|
|
return false;
|
|
- if (val & _TIF_NEED_RESCHED)
|
|
+ if (val & (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY))
|
|
return true;
|
|
if (try_cmpxchg(&ti->flags, &val, val | _TIF_NEED_RESCHED))
|
|
break;
|
|
@@ -930,9 +931,9 @@ static bool set_nr_if_polling(struct task_struct *p)
|
|
}
|
|
|
|
#else
|
|
-static inline bool set_nr_and_not_polling(struct task_struct *p)
|
|
+static inline bool set_nr_and_not_polling(struct task_struct *p, int tif_bit)
|
|
{
|
|
- set_tsk_need_resched(p);
|
|
+ set_tsk_thread_flag(p, tif_bit);
|
|
return true;
|
|
}
|
|
|
|
@@ -1037,28 +1038,47 @@ void wake_up_q(struct wake_q_head *head)
|
|
* might also involve a cross-CPU call to trigger the scheduler on
|
|
* the target CPU.
|
|
*/
|
|
-void resched_curr(struct rq *rq)
|
|
+static void __resched_curr(struct rq *rq, int lazy)
|
|
{
|
|
+ int cpu, tif_bit = TIF_NEED_RESCHED + lazy;
|
|
struct task_struct *curr = rq->curr;
|
|
- int cpu;
|
|
|
|
lockdep_assert_rq_held(rq);
|
|
|
|
- if (test_tsk_need_resched(curr))
|
|
+ if (unlikely(test_tsk_thread_flag(curr, tif_bit)))
|
|
return;
|
|
|
|
cpu = cpu_of(rq);
|
|
|
|
if (cpu == smp_processor_id()) {
|
|
- set_tsk_need_resched(curr);
|
|
- set_preempt_need_resched();
|
|
+ set_tsk_thread_flag(curr, tif_bit);
|
|
+ if (!lazy)
|
|
+ set_preempt_need_resched();
|
|
return;
|
|
}
|
|
|
|
- if (set_nr_and_not_polling(curr))
|
|
- smp_send_reschedule(cpu);
|
|
- else
|
|
+ if (set_nr_and_not_polling(curr, tif_bit)) {
|
|
+ if (!lazy)
|
|
+ smp_send_reschedule(cpu);
|
|
+ } else {
|
|
trace_sched_wake_idle_without_ipi(cpu);
|
|
+ }
|
|
+}
|
|
+
|
|
+void resched_curr(struct rq *rq)
|
|
+{
|
|
+ __resched_curr(rq, 0);
|
|
+}
|
|
+
|
|
+void resched_curr_lazy(struct rq *rq)
|
|
+{
|
|
+ int lazy = IS_ENABLED(CONFIG_PREEMPT_BUILD_AUTO) && !sched_feat(FORCE_NEED_RESCHED) ?
|
|
+ TIF_NEED_RESCHED_LAZY_OFFSET : 0;
|
|
+
|
|
+ if (lazy && unlikely(test_tsk_thread_flag(rq->curr, TIF_NEED_RESCHED)))
|
|
+ return;
|
|
+
|
|
+ __resched_curr(rq, lazy);
|
|
}
|
|
|
|
void resched_cpu(int cpu)
|
|
@@ -1131,7 +1151,7 @@ static void wake_up_idle_cpu(int cpu)
|
|
if (cpu == smp_processor_id())
|
|
return;
|
|
|
|
- if (set_nr_and_not_polling(rq->idle))
|
|
+ if (set_nr_and_not_polling(rq->idle, TIF_NEED_RESCHED))
|
|
smp_send_reschedule(cpu);
|
|
else
|
|
trace_sched_wake_idle_without_ipi(cpu);
|
|
@@ -6722,10 +6742,14 @@ void __noreturn do_task_dead(void)
|
|
|
|
static inline void sched_submit_work(struct task_struct *tsk)
|
|
{
|
|
+ static DEFINE_WAIT_OVERRIDE_MAP(sched_map, LD_WAIT_CONFIG);
|
|
unsigned int task_flags;
|
|
|
|
- if (task_is_running(tsk))
|
|
- return;
|
|
+ /*
|
|
+ * Establish LD_WAIT_CONFIG context to ensure none of the code called
|
|
+ * will use a blocking primitive -- which would lead to recursion.
|
|
+ */
|
|
+ lock_map_acquire_try(&sched_map);
|
|
|
|
task_flags = tsk->flags;
|
|
/*
|
|
@@ -6751,6 +6775,8 @@ static inline void sched_submit_work(struct task_struct *tsk)
|
|
* make sure to submit it to avoid deadlocks.
|
|
*/
|
|
blk_flush_plug(tsk->plug, true);
|
|
+
|
|
+ lock_map_release(&sched_map);
|
|
}
|
|
|
|
static void sched_update_worker(struct task_struct *tsk)
|
|
@@ -6763,16 +6789,26 @@ static void sched_update_worker(struct task_struct *tsk)
|
|
}
|
|
}
|
|
|
|
-asmlinkage __visible void __sched schedule(void)
|
|
+static __always_inline void __schedule_loop(unsigned int sched_mode)
|
|
{
|
|
- struct task_struct *tsk = current;
|
|
-
|
|
- sched_submit_work(tsk);
|
|
do {
|
|
preempt_disable();
|
|
- __schedule(SM_NONE);
|
|
+ __schedule(sched_mode);
|
|
sched_preempt_enable_no_resched();
|
|
} while (need_resched());
|
|
+}
|
|
+
|
|
+asmlinkage __visible void __sched schedule(void)
|
|
+{
|
|
+ struct task_struct *tsk = current;
|
|
+
|
|
+#ifdef CONFIG_RT_MUTEXES
|
|
+ lockdep_assert(!tsk->sched_rt_mutex);
|
|
+#endif
|
|
+
|
|
+ if (!task_is_running(tsk))
|
|
+ sched_submit_work(tsk);
|
|
+ __schedule_loop(SM_NONE);
|
|
sched_update_worker(tsk);
|
|
}
|
|
EXPORT_SYMBOL(schedule);
|
|
@@ -6836,11 +6872,7 @@ void __sched schedule_preempt_disabled(void)
|
|
#ifdef CONFIG_PREEMPT_RT
|
|
void __sched notrace schedule_rtlock(void)
|
|
{
|
|
- do {
|
|
- preempt_disable();
|
|
- __schedule(SM_RTLOCK_WAIT);
|
|
- sched_preempt_enable_no_resched();
|
|
- } while (need_resched());
|
|
+ __schedule_loop(SM_RTLOCK_WAIT);
|
|
}
|
|
NOKPROBE_SYMBOL(schedule_rtlock);
|
|
#endif
|
|
@@ -7036,6 +7068,32 @@ static void __setscheduler_prio(struct task_struct *p, int prio)
|
|
|
|
#ifdef CONFIG_RT_MUTEXES
|
|
|
|
+/*
|
|
+ * Would be more useful with typeof()/auto_type but they don't mix with
|
|
+ * bit-fields. Since it's a local thing, use int. Keep the generic sounding
|
|
+ * name such that if someone were to implement this function we get to compare
|
|
+ * notes.
|
|
+ */
|
|
+#define fetch_and_set(x, v) ({ int _x = (x); (x) = (v); _x; })
|
|
+
|
|
+void rt_mutex_pre_schedule(void)
|
|
+{
|
|
+ lockdep_assert(!fetch_and_set(current->sched_rt_mutex, 1));
|
|
+ sched_submit_work(current);
|
|
+}
|
|
+
|
|
+void rt_mutex_schedule(void)
|
|
+{
|
|
+ lockdep_assert(current->sched_rt_mutex);
|
|
+ __schedule_loop(SM_NONE);
|
|
+}
|
|
+
|
|
+void rt_mutex_post_schedule(void)
|
|
+{
|
|
+ sched_update_worker(current);
|
|
+ lockdep_assert(fetch_and_set(current->sched_rt_mutex, 0));
|
|
+}
|
|
+
|
|
static inline int __rt_effective_prio(struct task_struct *pi_task, int prio)
|
|
{
|
|
if (pi_task)
|
|
@@ -8886,6 +8944,21 @@ static inline void preempt_dynamic_init(void) { }
|
|
|
|
#endif /* #ifdef CONFIG_PREEMPT_DYNAMIC */
|
|
|
|
+/*
|
|
+ * task_is_pi_boosted - Check if task has been PI boosted.
|
|
+ * @p: Task to check.
|
|
+ *
|
|
+ * Return true if task is subject to priority inheritance.
|
|
+ */
|
|
+bool task_is_pi_boosted(const struct task_struct *p)
|
|
+{
|
|
+ int prio = p->prio;
|
|
+
|
|
+ if (!rt_prio(prio))
|
|
+ return false;
|
|
+ return prio != p->normal_prio;
|
|
+}
|
|
+
|
|
/**
|
|
* yield - yield the current processor to other threads.
|
|
*
|
|
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
|
|
index 4c3d0d9f3db6..63e19b89c8c3 100644
|
|
--- a/kernel/sched/debug.c
|
|
+++ b/kernel/sched/debug.c
|
|
@@ -333,6 +333,23 @@ static const struct file_operations sched_debug_fops = {
|
|
.release = seq_release,
|
|
};
|
|
|
|
+static ssize_t sched_hog_write(struct file *filp, const char __user *ubuf,
|
|
+ size_t cnt, loff_t *ppos)
|
|
+{
|
|
+ unsigned long end = jiffies + 60 * HZ;
|
|
+
|
|
+ for (; time_before(jiffies, end) && !signal_pending(current);)
|
|
+ cpu_relax();
|
|
+
|
|
+ return cnt;
|
|
+}
|
|
+
|
|
+static const struct file_operations sched_hog_fops = {
|
|
+ .write = sched_hog_write,
|
|
+ .open = simple_open,
|
|
+ .llseek = default_llseek,
|
|
+};
|
|
+
|
|
static struct dentry *debugfs_sched;
|
|
|
|
static __init int sched_init_debug(void)
|
|
@@ -374,6 +391,8 @@ static __init int sched_init_debug(void)
|
|
|
|
debugfs_create_file("debug", 0444, debugfs_sched, NULL, &sched_debug_fops);
|
|
|
|
+ debugfs_create_file("hog", 0200, debugfs_sched, NULL, &sched_hog_fops);
|
|
+
|
|
return 0;
|
|
}
|
|
late_initcall(sched_init_debug);
|
|
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
|
|
index b2e1009e5706..e7e5569fd505 100644
|
|
--- a/kernel/sched/fair.c
|
|
+++ b/kernel/sched/fair.c
|
|
@@ -1022,8 +1022,10 @@ static void clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se);
|
|
* XXX: strictly: vd_i += N*r_i/w_i such that: vd_i > ve_i
|
|
* this is probably good enough.
|
|
*/
|
|
-static void update_deadline(struct cfs_rq *cfs_rq, struct sched_entity *se)
|
|
+static void update_deadline(struct cfs_rq *cfs_rq, struct sched_entity *se, bool tick)
|
|
{
|
|
+ struct rq *rq = rq_of(cfs_rq);
|
|
+
|
|
if ((s64)(se->vruntime - se->deadline) < 0)
|
|
return;
|
|
|
|
@@ -1042,10 +1044,19 @@ static void update_deadline(struct cfs_rq *cfs_rq, struct sched_entity *se)
|
|
/*
|
|
* The task has consumed its request, reschedule.
|
|
*/
|
|
- if (cfs_rq->nr_running > 1) {
|
|
- resched_curr(rq_of(cfs_rq));
|
|
- clear_buddies(cfs_rq, se);
|
|
+ if (cfs_rq->nr_running < 2)
|
|
+ return;
|
|
+
|
|
+ if (!IS_ENABLED(CONFIG_PREEMPT_BUILD_AUTO) || sched_feat(FORCE_NEED_RESCHED)) {
|
|
+ resched_curr(rq);
|
|
+ } else {
|
|
+ /* Did the task ignore the lazy reschedule request? */
|
|
+ if (tick && test_tsk_thread_flag(rq->curr, TIF_NEED_RESCHED_LAZY))
|
|
+ resched_curr(rq);
|
|
+ else
|
|
+ resched_curr_lazy(rq);
|
|
}
|
|
+ clear_buddies(cfs_rq, se);
|
|
}
|
|
|
|
#include "pelt.h"
|
|
@@ -1153,7 +1164,7 @@ static void update_tg_load_avg(struct cfs_rq *cfs_rq)
|
|
/*
|
|
* Update the current task's runtime statistics.
|
|
*/
|
|
-static void update_curr(struct cfs_rq *cfs_rq)
|
|
+static void __update_curr(struct cfs_rq *cfs_rq, bool tick)
|
|
{
|
|
struct sched_entity *curr = cfs_rq->curr;
|
|
u64 now = rq_clock_task(rq_of(cfs_rq));
|
|
@@ -1180,7 +1191,7 @@ static void update_curr(struct cfs_rq *cfs_rq)
|
|
schedstat_add(cfs_rq->exec_clock, delta_exec);
|
|
|
|
curr->vruntime += calc_delta_fair(delta_exec, curr);
|
|
- update_deadline(cfs_rq, curr);
|
|
+ update_deadline(cfs_rq, curr, tick);
|
|
update_min_vruntime(cfs_rq);
|
|
|
|
if (entity_is_task(curr)) {
|
|
@@ -1194,6 +1205,11 @@ static void update_curr(struct cfs_rq *cfs_rq)
|
|
account_cfs_rq_runtime(cfs_rq, delta_exec);
|
|
}
|
|
|
|
+static inline void update_curr(struct cfs_rq *cfs_rq)
|
|
+{
|
|
+ __update_curr(cfs_rq, false);
|
|
+}
|
|
+
|
|
static void update_curr_fair(struct rq *rq)
|
|
{
|
|
update_curr(cfs_rq_of(&rq->curr->se));
|
|
@@ -5403,7 +5419,7 @@ entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued)
|
|
/*
|
|
* Update run-time statistics of the 'current'.
|
|
*/
|
|
- update_curr(cfs_rq);
|
|
+ __update_curr(cfs_rq, true);
|
|
|
|
/*
|
|
* Ensure that runnable average is periodically updated.
|
|
@@ -5417,7 +5433,7 @@ entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued)
|
|
* validating it and just reschedule.
|
|
*/
|
|
if (queued) {
|
|
- resched_curr(rq_of(cfs_rq));
|
|
+ resched_curr_lazy(rq_of(cfs_rq));
|
|
return;
|
|
}
|
|
/*
|
|
@@ -5563,7 +5579,7 @@ static void __account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec)
|
|
* hierarchy can be throttled
|
|
*/
|
|
if (!assign_cfs_rq_runtime(cfs_rq) && likely(cfs_rq->curr))
|
|
- resched_curr(rq_of(cfs_rq));
|
|
+ resched_curr_lazy(rq_of(cfs_rq));
|
|
}
|
|
|
|
static __always_inline
|
|
@@ -5823,7 +5839,7 @@ void unthrottle_cfs_rq(struct cfs_rq *cfs_rq)
|
|
|
|
/* Determine whether we need to wake up potentially idle CPU: */
|
|
if (rq->curr == rq->idle && rq->cfs.nr_running)
|
|
- resched_curr(rq);
|
|
+ resched_curr_lazy(rq);
|
|
}
|
|
|
|
#ifdef CONFIG_SMP
|
|
@@ -6528,7 +6544,7 @@ static void hrtick_start_fair(struct rq *rq, struct task_struct *p)
|
|
|
|
if (delta < 0) {
|
|
if (task_current(rq, p))
|
|
- resched_curr(rq);
|
|
+ resched_curr_lazy(rq);
|
|
return;
|
|
}
|
|
hrtick_start(rq, delta);
|
|
@@ -8206,7 +8222,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_
|
|
* prevents us from potentially nominating it as a false LAST_BUDDY
|
|
* below.
|
|
*/
|
|
- if (test_tsk_need_resched(curr))
|
|
+ if (need_resched())
|
|
return;
|
|
|
|
/* Idle tasks are by definition preempted by non-idle tasks. */
|
|
@@ -8248,7 +8264,7 @@ static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_
|
|
return;
|
|
|
|
preempt:
|
|
- resched_curr(rq);
|
|
+ resched_curr_lazy(rq);
|
|
}
|
|
|
|
#ifdef CONFIG_SMP
|
|
@@ -12394,7 +12410,7 @@ static inline void task_tick_core(struct rq *rq, struct task_struct *curr)
|
|
*/
|
|
if (rq->core->core_forceidle_count && rq->cfs.nr_running == 1 &&
|
|
__entity_slice_used(&curr->se, MIN_NR_TASKS_DURING_FORCEIDLE))
|
|
- resched_curr(rq);
|
|
+ resched_curr_lazy(rq);
|
|
}
|
|
|
|
/*
|
|
@@ -12559,7 +12575,7 @@ prio_changed_fair(struct rq *rq, struct task_struct *p, int oldprio)
|
|
*/
|
|
if (task_current(rq, p)) {
|
|
if (p->prio > oldprio)
|
|
- resched_curr(rq);
|
|
+ resched_curr_lazy(rq);
|
|
} else
|
|
check_preempt_curr(rq, p, 0);
|
|
}
|
|
diff --git a/kernel/sched/features.h b/kernel/sched/features.h
|
|
index f770168230ae..dd8b35f67fed 100644
|
|
--- a/kernel/sched/features.h
|
|
+++ b/kernel/sched/features.h
|
|
@@ -89,3 +89,5 @@ SCHED_FEAT(UTIL_EST_FASTUP, true)
|
|
SCHED_FEAT(LATENCY_WARN, false)
|
|
|
|
SCHED_FEAT(HZ_BW, true)
|
|
+
|
|
+SCHED_FEAT(FORCE_NEED_RESCHED, false)
|
|
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
|
|
index 5007b25c5bc6..95e1b3df1400 100644
|
|
--- a/kernel/sched/idle.c
|
|
+++ b/kernel/sched/idle.c
|
|
@@ -57,8 +57,7 @@ static noinline int __cpuidle cpu_idle_poll(void)
|
|
ct_cpuidle_enter();
|
|
|
|
raw_local_irq_enable();
|
|
- while (!tif_need_resched() &&
|
|
- (cpu_idle_force_poll || tick_check_broadcast_expired()))
|
|
+ while (!need_resched() && (cpu_idle_force_poll || tick_check_broadcast_expired()))
|
|
cpu_relax();
|
|
raw_local_irq_disable();
|
|
|
|
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
|
|
index 4ac36eb4cdee..acd1510e8d47 100644
|
|
--- a/kernel/sched/rt.c
|
|
+++ b/kernel/sched/rt.c
|
|
@@ -2253,8 +2253,11 @@ static int rto_next_cpu(struct root_domain *rd)
|
|
|
|
rd->rto_cpu = cpu;
|
|
|
|
- if (cpu < nr_cpu_ids)
|
|
+ if (cpu < nr_cpu_ids) {
|
|
+ if (!has_pushable_tasks(cpu_rq(cpu)))
|
|
+ continue;
|
|
return cpu;
|
|
+ }
|
|
|
|
rd->rto_cpu = -1;
|
|
|
|
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
|
|
index 8cbbbea7fdbb..00cdf0db8732 100644
|
|
--- a/kernel/sched/sched.h
|
|
+++ b/kernel/sched/sched.h
|
|
@@ -2438,6 +2438,7 @@ extern void init_sched_fair_class(void);
|
|
extern void reweight_task(struct task_struct *p, const struct load_weight *lw);
|
|
|
|
extern void resched_curr(struct rq *rq);
|
|
+extern void resched_curr_lazy(struct rq *rq);
|
|
extern void resched_cpu(int cpu);
|
|
|
|
extern struct rt_bandwidth def_rt_bandwidth;
|
|
diff --git a/kernel/signal.c b/kernel/signal.c
|
|
index 21903f524ef8..9f240d9cb240 100644
|
|
--- a/kernel/signal.c
|
|
+++ b/kernel/signal.c
|
|
@@ -2329,15 +2329,35 @@ static int ptrace_stop(int exit_code, int why, unsigned long message,
|
|
do_notify_parent_cldstop(current, false, why);
|
|
|
|
/*
|
|
- * Don't want to allow preemption here, because
|
|
- * sys_ptrace() needs this task to be inactive.
|
|
+ * The previous do_notify_parent_cldstop() invocation woke ptracer.
|
|
+ * One a PREEMPTION kernel this can result in preemption requirement
|
|
+ * which will be fulfilled after read_unlock() and the ptracer will be
|
|
+ * put on the CPU.
|
|
+ * The ptracer is in wait_task_inactive(, __TASK_TRACED) waiting for
|
|
+ * this task wait in schedule(). If this task gets preempted then it
|
|
+ * remains enqueued on the runqueue. The ptracer will observe this and
|
|
+ * then sleep for a delay of one HZ tick. In the meantime this task
|
|
+ * gets scheduled, enters schedule() and will wait for the ptracer.
|
|
*
|
|
- * XXX: implement read_unlock_no_resched().
|
|
+ * This preemption point is not bad from correctness point of view but
|
|
+ * extends the runtime by one HZ tick time due to the ptracer's sleep.
|
|
+ * The preempt-disable section ensures that there will be no preemption
|
|
+ * between unlock and schedule() and so improving the performance since
|
|
+ * the ptracer has no reason to sleep.
|
|
+ *
|
|
+ * On PREEMPT_RT locking tasklist_lock does not disable preemption.
|
|
+ * Therefore the task can be preempted (after
|
|
+ * do_notify_parent_cldstop()) before unlocking tasklist_lock so there
|
|
+ * is no benefit in doing this. The optimisation is harmful on
|
|
+ * PEEMPT_RT because the spinlock_t (in cgroup_enter_frozen()) must not
|
|
+ * be acquired with disabled preemption.
|
|
*/
|
|
- preempt_disable();
|
|
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT))
|
|
+ preempt_disable();
|
|
read_unlock(&tasklist_lock);
|
|
cgroup_enter_frozen();
|
|
- preempt_enable_no_resched();
|
|
+ if (!IS_ENABLED(CONFIG_PREEMPT_RT))
|
|
+ preempt_enable_no_resched();
|
|
schedule();
|
|
cgroup_leave_frozen(true);
|
|
|
|
diff --git a/kernel/softirq.c b/kernel/softirq.c
|
|
index bd9716d7bb63..2fde8af88e48 100644
|
|
--- a/kernel/softirq.c
|
|
+++ b/kernel/softirq.c
|
|
@@ -247,6 +247,19 @@ void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
|
|
}
|
|
EXPORT_SYMBOL(__local_bh_enable_ip);
|
|
|
|
+void softirq_preempt(void)
|
|
+{
|
|
+ if (WARN_ON_ONCE(!preemptible()))
|
|
+ return;
|
|
+
|
|
+ if (WARN_ON_ONCE(__this_cpu_read(softirq_ctrl.cnt) != SOFTIRQ_OFFSET))
|
|
+ return;
|
|
+
|
|
+ __local_bh_enable(SOFTIRQ_OFFSET, true);
|
|
+ /* preemption point */
|
|
+ __local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
|
|
+}
|
|
+
|
|
/*
|
|
* Invoked from ksoftirqd_run() outside of the interrupt disabled section
|
|
* to acquire the per CPU local lock for reentrancy protection.
|
|
@@ -623,6 +636,24 @@ static inline void tick_irq_exit(void)
|
|
#endif
|
|
}
|
|
|
|
+#ifdef CONFIG_PREEMPT_RT
|
|
+DEFINE_PER_CPU(struct task_struct *, timersd);
|
|
+DEFINE_PER_CPU(unsigned long, pending_timer_softirq);
|
|
+
|
|
+static void wake_timersd(void)
|
|
+{
|
|
+ struct task_struct *tsk = __this_cpu_read(timersd);
|
|
+
|
|
+ if (tsk)
|
|
+ wake_up_process(tsk);
|
|
+}
|
|
+
|
|
+#else
|
|
+
|
|
+static inline void wake_timersd(void) { }
|
|
+
|
|
+#endif
|
|
+
|
|
static inline void __irq_exit_rcu(void)
|
|
{
|
|
#ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED
|
|
@@ -635,6 +666,10 @@ static inline void __irq_exit_rcu(void)
|
|
if (!in_interrupt() && local_softirq_pending())
|
|
invoke_softirq();
|
|
|
|
+ if (IS_ENABLED(CONFIG_PREEMPT_RT) && local_pending_timers() &&
|
|
+ !(in_nmi() | in_hardirq()))
|
|
+ wake_timersd();
|
|
+
|
|
tick_irq_exit();
|
|
}
|
|
|
|
@@ -967,12 +1002,70 @@ static struct smp_hotplug_thread softirq_threads = {
|
|
.thread_comm = "ksoftirqd/%u",
|
|
};
|
|
|
|
+#ifdef CONFIG_PREEMPT_RT
|
|
+static void timersd_setup(unsigned int cpu)
|
|
+{
|
|
+ sched_set_fifo_low(current);
|
|
+}
|
|
+
|
|
+static int timersd_should_run(unsigned int cpu)
|
|
+{
|
|
+ return local_pending_timers();
|
|
+}
|
|
+
|
|
+static void run_timersd(unsigned int cpu)
|
|
+{
|
|
+ unsigned int timer_si;
|
|
+
|
|
+ ksoftirqd_run_begin();
|
|
+
|
|
+ timer_si = local_pending_timers();
|
|
+ __this_cpu_write(pending_timer_softirq, 0);
|
|
+ or_softirq_pending(timer_si);
|
|
+
|
|
+ __do_softirq();
|
|
+
|
|
+ ksoftirqd_run_end();
|
|
+}
|
|
+
|
|
+static void raise_ktimers_thread(unsigned int nr)
|
|
+{
|
|
+ trace_softirq_raise(nr);
|
|
+ __this_cpu_or(pending_timer_softirq, 1 << nr);
|
|
+}
|
|
+
|
|
+void raise_hrtimer_softirq(void)
|
|
+{
|
|
+ raise_ktimers_thread(HRTIMER_SOFTIRQ);
|
|
+}
|
|
+
|
|
+void raise_timer_softirq(void)
|
|
+{
|
|
+ unsigned long flags;
|
|
+
|
|
+ local_irq_save(flags);
|
|
+ raise_ktimers_thread(TIMER_SOFTIRQ);
|
|
+ wake_timersd();
|
|
+ local_irq_restore(flags);
|
|
+}
|
|
+
|
|
+static struct smp_hotplug_thread timer_threads = {
|
|
+ .store = &timersd,
|
|
+ .setup = timersd_setup,
|
|
+ .thread_should_run = timersd_should_run,
|
|
+ .thread_fn = run_timersd,
|
|
+ .thread_comm = "ktimers/%u",
|
|
+};
|
|
+#endif
|
|
+
|
|
static __init int spawn_ksoftirqd(void)
|
|
{
|
|
cpuhp_setup_state_nocalls(CPUHP_SOFTIRQ_DEAD, "softirq:dead", NULL,
|
|
takeover_tasklets);
|
|
BUG_ON(smpboot_register_percpu_thread(&softirq_threads));
|
|
-
|
|
+#ifdef CONFIG_PREEMPT_RT
|
|
+ BUG_ON(smpboot_register_percpu_thread(&timer_threads));
|
|
+#endif
|
|
return 0;
|
|
}
|
|
early_initcall(spawn_ksoftirqd);
|
|
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
|
|
index 57e5cb36f1bc..c4ae45701fab 100644
|
|
--- a/kernel/time/hrtimer.c
|
|
+++ b/kernel/time/hrtimer.c
|
|
@@ -1812,7 +1812,7 @@ void hrtimer_interrupt(struct clock_event_device *dev)
|
|
if (!ktime_before(now, cpu_base->softirq_expires_next)) {
|
|
cpu_base->softirq_expires_next = KTIME_MAX;
|
|
cpu_base->softirq_activated = 1;
|
|
- raise_softirq_irqoff(HRTIMER_SOFTIRQ);
|
|
+ raise_hrtimer_softirq();
|
|
}
|
|
|
|
__hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_HARD);
|
|
@@ -1925,7 +1925,7 @@ void hrtimer_run_queues(void)
|
|
if (!ktime_before(now, cpu_base->softirq_expires_next)) {
|
|
cpu_base->softirq_expires_next = KTIME_MAX;
|
|
cpu_base->softirq_activated = 1;
|
|
- raise_softirq_irqoff(HRTIMER_SOFTIRQ);
|
|
+ raise_hrtimer_softirq();
|
|
}
|
|
|
|
__hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_HARD);
|
|
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
|
|
index 55cbc49f70d1..1a0ed106b192 100644
|
|
--- a/kernel/time/tick-sched.c
|
|
+++ b/kernel/time/tick-sched.c
|
|
@@ -795,7 +795,7 @@ static void tick_nohz_restart(struct tick_sched *ts, ktime_t now)
|
|
|
|
static inline bool local_timer_softirq_pending(void)
|
|
{
|
|
- return local_softirq_pending() & BIT(TIMER_SOFTIRQ);
|
|
+ return local_pending_timers() & BIT(TIMER_SOFTIRQ);
|
|
}
|
|
|
|
static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
|
|
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
|
|
index 63a8ce7177dd..b3fbe97d1e34 100644
|
|
--- a/kernel/time/timer.c
|
|
+++ b/kernel/time/timer.c
|
|
@@ -1470,9 +1470,16 @@ static inline void timer_base_unlock_expiry(struct timer_base *base)
|
|
*/
|
|
static void timer_sync_wait_running(struct timer_base *base)
|
|
{
|
|
- if (atomic_read(&base->timer_waiters)) {
|
|
+ bool need_preempt;
|
|
+
|
|
+ need_preempt = task_is_pi_boosted(current);
|
|
+ if (need_preempt || atomic_read(&base->timer_waiters)) {
|
|
raw_spin_unlock_irq(&base->lock);
|
|
spin_unlock(&base->expiry_lock);
|
|
+
|
|
+ if (need_preempt)
|
|
+ softirq_preempt();
|
|
+
|
|
spin_lock(&base->expiry_lock);
|
|
raw_spin_lock_irq(&base->lock);
|
|
}
|
|
@@ -2054,7 +2061,7 @@ static void run_local_timers(void)
|
|
if (time_before(jiffies, base->next_expiry))
|
|
return;
|
|
}
|
|
- raise_softirq(TIMER_SOFTIRQ);
|
|
+ raise_timer_softirq();
|
|
}
|
|
|
|
/*
|
|
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
|
|
index be878005e344..fe755b1c2fe6 100644
|
|
--- a/kernel/trace/trace.c
|
|
+++ b/kernel/trace/trace.c
|
|
@@ -2708,6 +2708,8 @@ unsigned int tracing_gen_ctx_irq_test(unsigned int irqs_status)
|
|
|
|
if (tif_need_resched())
|
|
trace_flags |= TRACE_FLAG_NEED_RESCHED;
|
|
+ if (tif_need_resched_lazy())
|
|
+ trace_flags |= TRACE_FLAG_NEED_RESCHED_LAZY;
|
|
if (test_preempt_need_resched())
|
|
trace_flags |= TRACE_FLAG_PREEMPT_RESCHED;
|
|
return (trace_flags << 16) | (min_t(unsigned int, pc & 0xff, 0xf)) |
|
|
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
|
|
index 3b7d3e9eb6ea..5a4fefbc0856 100644
|
|
--- a/kernel/trace/trace_output.c
|
|
+++ b/kernel/trace/trace_output.c
|
|
@@ -460,17 +460,29 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry)
|
|
(entry->flags & TRACE_FLAG_IRQS_OFF && bh_off) ? 'D' :
|
|
(entry->flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
|
|
bh_off ? 'b' :
|
|
- (entry->flags & TRACE_FLAG_IRQS_NOSUPPORT) ? 'X' :
|
|
+ !IS_ENABLED(CONFIG_TRACE_IRQFLAGS_SUPPORT) ? 'X' :
|
|
'.';
|
|
|
|
- switch (entry->flags & (TRACE_FLAG_NEED_RESCHED |
|
|
+ switch (entry->flags & (TRACE_FLAG_NEED_RESCHED | TRACE_FLAG_NEED_RESCHED_LAZY |
|
|
TRACE_FLAG_PREEMPT_RESCHED)) {
|
|
+ case TRACE_FLAG_NEED_RESCHED | TRACE_FLAG_NEED_RESCHED_LAZY | TRACE_FLAG_PREEMPT_RESCHED:
|
|
+ need_resched = 'B';
|
|
+ break;
|
|
case TRACE_FLAG_NEED_RESCHED | TRACE_FLAG_PREEMPT_RESCHED:
|
|
need_resched = 'N';
|
|
break;
|
|
+ case TRACE_FLAG_NEED_RESCHED_LAZY | TRACE_FLAG_PREEMPT_RESCHED:
|
|
+ need_resched = 'L';
|
|
+ break;
|
|
+ case TRACE_FLAG_NEED_RESCHED | TRACE_FLAG_NEED_RESCHED_LAZY:
|
|
+ need_resched = 'b';
|
|
+ break;
|
|
case TRACE_FLAG_NEED_RESCHED:
|
|
need_resched = 'n';
|
|
break;
|
|
+ case TRACE_FLAG_NEED_RESCHED_LAZY:
|
|
+ need_resched = 'l';
|
|
+ break;
|
|
case TRACE_FLAG_PREEMPT_RESCHED:
|
|
need_resched = 'p';
|
|
break;
|
|
diff --git a/localversion-rt b/localversion-rt
|
|
new file mode 100644
|
|
index 000000000000..366440d74b77
|
|
--- /dev/null
|
|
+++ b/localversion-rt
|
|
@@ -0,0 +1 @@
|
|
+-rt35
|
|
diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c
|
|
index 7b41ee8740cb..294cb699bff2 100644
|
|
--- a/net/bridge/br_switchdev.c
|
|
+++ b/net/bridge/br_switchdev.c
|
|
@@ -173,6 +173,26 @@ br_switchdev_fdb_notify(struct net_bridge *br,
|
|
}
|
|
}
|
|
|
|
+static u16 br_switchdev_get_bridge_vlan_proto(const struct net_device *dev)
|
|
+{
|
|
+ const struct net_device *br = NULL;
|
|
+ u16 vlan_proto = ETH_P_8021Q;
|
|
+ struct net_bridge_port *p;
|
|
+
|
|
+ if (netif_is_bridge_master(dev)) {
|
|
+ br = dev;
|
|
+ } else {
|
|
+ p = br_port_get_rtnl_rcu(dev);
|
|
+ if (p)
|
|
+ br = p->br->dev;
|
|
+ }
|
|
+
|
|
+ if (br)
|
|
+ br_vlan_get_proto(br, &vlan_proto);
|
|
+
|
|
+ return vlan_proto;
|
|
+}
|
|
+
|
|
int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags,
|
|
bool changed, struct netlink_ext_ack *extack)
|
|
{
|
|
@@ -184,6 +204,8 @@ int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags,
|
|
.changed = changed,
|
|
};
|
|
|
|
+ v.proto = br_switchdev_get_bridge_vlan_proto(dev);
|
|
+
|
|
return switchdev_port_obj_add(dev, &v.obj, extack);
|
|
}
|
|
|
|
@@ -195,6 +217,8 @@ int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid)
|
|
.vid = vid,
|
|
};
|
|
|
|
+ v.proto = br_switchdev_get_bridge_vlan_proto(dev);
|
|
+
|
|
return switchdev_port_obj_del(dev, &v.obj);
|
|
}
|
|
|
|
diff --git a/net/core/dev.c b/net/core/dev.c
|
|
index 5a5bd339f11e..c57b4918b2b4 100644
|
|
--- a/net/core/dev.c
|
|
+++ b/net/core/dev.c
|
|
@@ -1428,8 +1428,8 @@ static int napi_kthread_create(struct napi_struct *n)
|
|
* TASK_INTERRUPTIBLE mode to avoid the blocked task
|
|
* warning and work with loadavg.
|
|
*/
|
|
- n->thread = kthread_run(napi_threaded_poll, n, "napi/%s-%d",
|
|
- n->dev->name, n->napi_id);
|
|
+ n->thread = kthread_run(napi_threaded_poll, n, "napi/%s-%s",
|
|
+ n->dev->name, n->name);
|
|
if (IS_ERR(n->thread)) {
|
|
err = PTR_ERR(n->thread);
|
|
pr_err("kthread_run failed with err %d\n", err);
|
|
@@ -4705,15 +4705,6 @@ static void rps_trigger_softirq(void *data)
|
|
|
|
#endif /* CONFIG_RPS */
|
|
|
|
-/* Called from hardirq (IPI) context */
|
|
-static void trigger_rx_softirq(void *data)
|
|
-{
|
|
- struct softnet_data *sd = data;
|
|
-
|
|
- __raise_softirq_irqoff(NET_RX_SOFTIRQ);
|
|
- smp_store_release(&sd->defer_ipi_scheduled, 0);
|
|
-}
|
|
-
|
|
/*
|
|
* After we queued a packet into sd->input_pkt_queue,
|
|
* we need to make sure this queue is serviced soon.
|
|
@@ -6426,8 +6417,9 @@ int dev_set_threaded(struct net_device *dev, bool threaded)
|
|
}
|
|
EXPORT_SYMBOL(dev_set_threaded);
|
|
|
|
-void netif_napi_add_weight(struct net_device *dev, struct napi_struct *napi,
|
|
- int (*poll)(struct napi_struct *, int), int weight)
|
|
+void netif_napi_add_named(struct net_device *dev, struct napi_struct *napi,
|
|
+ int (*poll)(struct napi_struct *, int), int weight,
|
|
+ const char *name)
|
|
{
|
|
if (WARN_ON(test_and_set_bit(NAPI_STATE_LISTED, &napi->state)))
|
|
return;
|
|
@@ -6455,6 +6447,12 @@ void netif_napi_add_weight(struct net_device *dev, struct napi_struct *napi,
|
|
list_add_rcu(&napi->dev_list, &dev->napi_list);
|
|
napi_hash_add(napi);
|
|
napi_get_frags_check(napi);
|
|
+
|
|
+ if (name)
|
|
+ strncpy(napi->name, name, NAPINAMSIZ);
|
|
+ else
|
|
+ snprintf(napi->name, NAPINAMSIZ, "%d", napi->napi_id);
|
|
+
|
|
/* Create kthread for this napi if dev->threaded is set.
|
|
* Clear dev->threaded if kthread creation failed so that
|
|
* threaded mode will not be enabled in napi_enable().
|
|
@@ -6462,6 +6460,13 @@ void netif_napi_add_weight(struct net_device *dev, struct napi_struct *napi,
|
|
if (dev->threaded && napi_kthread_create(napi))
|
|
dev->threaded = 0;
|
|
}
|
|
+EXPORT_SYMBOL(netif_napi_add_named);
|
|
+
|
|
+void netif_napi_add_weight(struct net_device *dev, struct napi_struct *napi,
|
|
+ int (*poll)(struct napi_struct *, int), int weight)
|
|
+{
|
|
+ netif_napi_add_named(dev, napi, poll, weight, NULL);
|
|
+}
|
|
EXPORT_SYMBOL(netif_napi_add_weight);
|
|
|
|
void napi_disable(struct napi_struct *n)
|
|
@@ -6682,6 +6687,32 @@ static void skb_defer_free_flush(struct softnet_data *sd)
|
|
}
|
|
}
|
|
|
|
+#ifndef CONFIG_PREEMPT_RT
|
|
+
|
|
+/* Called from hardirq (IPI) context */
|
|
+static void trigger_rx_softirq(void *data)
|
|
+{
|
|
+ struct softnet_data *sd = data;
|
|
+
|
|
+ __raise_softirq_irqoff(NET_RX_SOFTIRQ);
|
|
+ smp_store_release(&sd->defer_ipi_scheduled, 0);
|
|
+}
|
|
+
|
|
+#else
|
|
+
|
|
+static void trigger_rx_softirq(struct work_struct *defer_work)
|
|
+{
|
|
+ struct softnet_data *sd;
|
|
+
|
|
+ sd = container_of(defer_work, struct softnet_data, defer_work);
|
|
+ smp_store_release(&sd->defer_ipi_scheduled, 0);
|
|
+ local_bh_disable();
|
|
+ skb_defer_free_flush(sd);
|
|
+ local_bh_enable();
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
static int napi_threaded_poll(void *data)
|
|
{
|
|
struct napi_struct *napi = data;
|
|
@@ -10792,6 +10823,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
|
|
dev_mc_init(dev);
|
|
dev_uc_init(dev);
|
|
|
|
+ dev->fast_raw_device = 0;
|
|
dev_net_set(dev, &init_net);
|
|
|
|
dev->gso_max_size = GSO_LEGACY_MAX_SIZE;
|
|
@@ -11619,7 +11651,11 @@ static int __init net_dev_init(void)
|
|
INIT_CSD(&sd->csd, rps_trigger_softirq, sd);
|
|
sd->cpu = i;
|
|
#endif
|
|
+#ifndef CONFIG_PREEMPT_RT
|
|
INIT_CSD(&sd->defer_csd, trigger_rx_softirq, sd);
|
|
+#else
|
|
+ INIT_WORK(&sd->defer_work, trigger_rx_softirq);
|
|
+#endif
|
|
spin_lock_init(&sd->defer_lock);
|
|
|
|
init_gro_hash(&sd->backlog);
|
|
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
|
|
index cf3c7a0062b8..c82011571e07 100644
|
|
--- a/net/core/skbuff.c
|
|
+++ b/net/core/skbuff.c
|
|
@@ -6889,8 +6889,13 @@ nodefer: __kfree_skb(skb);
|
|
/* Make sure to trigger NET_RX_SOFTIRQ on the remote CPU
|
|
* if we are unlucky enough (this seems very unlikely).
|
|
*/
|
|
- if (unlikely(kick) && !cmpxchg(&sd->defer_ipi_scheduled, 0, 1))
|
|
+ if (unlikely(kick) && !cmpxchg(&sd->defer_ipi_scheduled, 0, 1)) {
|
|
+#ifndef CONFIG_PREEMPT_RT
|
|
smp_call_function_single_async(cpu, &sd->defer_csd);
|
|
+#else
|
|
+ schedule_work_on(cpu, &sd->defer_work);
|
|
+#endif
|
|
+ }
|
|
}
|
|
|
|
static void skb_splice_csum_page(struct sk_buff *skb, struct page *page,
|
|
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
|
|
index 8e698bea99a3..93bd38d95236 100644
|
|
--- a/net/dsa/Kconfig
|
|
+++ b/net/dsa/Kconfig
|
|
@@ -172,4 +172,10 @@ config NET_DSA_TAG_XRS700X
|
|
Say Y or M if you want to enable support for tagging frames for
|
|
Arrow SpeedChips XRS700x switches that use a single byte tag trailer.
|
|
|
|
+config NET_DSA_TAG_NETC
|
|
+ tristate "Tag driver for NETC family of switches, using VLAN"
|
|
+ help
|
|
+ Say Y or M if you want to enable support for tagging frames with a
|
|
+ NXP NETC switch family. The custom 802.1Q VLAN header is available.
|
|
+
|
|
endif
|
|
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
|
|
index 12e305824a96..b9d63a7c3a77 100644
|
|
--- a/net/dsa/Makefile
|
|
+++ b/net/dsa/Makefile
|
|
@@ -38,6 +38,7 @@ obj-$(CONFIG_NET_DSA_TAG_RZN1_A5PSW) += tag_rzn1_a5psw.o
|
|
obj-$(CONFIG_NET_DSA_TAG_SJA1105) += tag_sja1105.o
|
|
obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
|
|
obj-$(CONFIG_NET_DSA_TAG_XRS700X) += tag_xrs700x.o
|
|
+obj-$(CONFIG_NET_DSA_TAG_NETC) += tag_netc.o
|
|
|
|
# for tracing framework to find trace.h
|
|
CFLAGS_trace.o := -I$(src)
|
|
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
|
|
index 48db91b33390..75024f6fd3ef 100644
|
|
--- a/net/dsa/slave.c
|
|
+++ b/net/dsa/slave.c
|
|
@@ -1753,6 +1753,41 @@ static int dsa_slave_get_ts_info(struct net_device *dev,
|
|
return ds->ops->get_ts_info(ds, p->dp->index, ts);
|
|
}
|
|
|
|
+static int dsa_slave_reset_preempt(struct net_device *dev, bool enable)
|
|
+{
|
|
+ struct dsa_slave_priv *p = netdev_priv(dev);
|
|
+ struct dsa_switch *ds = p->dp->ds;
|
|
+
|
|
+ if (!ds->ops->reset_preempt)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ return ds->ops->reset_preempt(ds, p->dp->index, enable);
|
|
+}
|
|
+
|
|
+static int dsa_slave_set_preempt(struct net_device *dev,
|
|
+ struct ethtool_fp *fpcmd)
|
|
+{
|
|
+ struct dsa_slave_priv *p = netdev_priv(dev);
|
|
+ struct dsa_switch *ds = p->dp->ds;
|
|
+
|
|
+ if (!ds->ops->set_preempt)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ return ds->ops->set_preempt(ds, p->dp->index, fpcmd);
|
|
+}
|
|
+
|
|
+static int dsa_slave_get_preempt(struct net_device *dev,
|
|
+ struct ethtool_fp *fpcmd)
|
|
+{
|
|
+ struct dsa_slave_priv *p = netdev_priv(dev);
|
|
+ struct dsa_switch *ds = p->dp->ds;
|
|
+
|
|
+ if (!ds->ops->get_preempt)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ return ds->ops->get_preempt(ds, p->dp->index, fpcmd);
|
|
+}
|
|
+
|
|
static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto,
|
|
u16 vid)
|
|
{
|
|
@@ -1762,6 +1797,7 @@ static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto,
|
|
.vid = vid,
|
|
/* This API only allows programming tagged, non-PVID VIDs */
|
|
.flags = 0,
|
|
+ .proto = ntohs(proto),
|
|
};
|
|
struct netlink_ext_ack extack = {0};
|
|
struct dsa_switch *ds = dp->ds;
|
|
@@ -1778,6 +1814,7 @@ static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto,
|
|
}
|
|
|
|
/* And CPU port... */
|
|
+ vlan.proto = ETH_P_8021Q;
|
|
ret = dsa_port_host_vlan_add(dp, &vlan, &extack);
|
|
if (ret) {
|
|
if (extack._msg)
|
|
@@ -1836,6 +1873,7 @@ static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto,
|
|
.vid = vid,
|
|
/* This API only allows programming tagged, non-PVID VIDs */
|
|
.flags = 0,
|
|
+ .proto = ntohs(proto),
|
|
};
|
|
struct dsa_switch *ds = dp->ds;
|
|
struct netdev_hw_addr *ha;
|
|
@@ -2387,6 +2425,9 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {
|
|
.get_mm = dsa_slave_get_mm,
|
|
.set_mm = dsa_slave_set_mm,
|
|
.get_mm_stats = dsa_slave_get_mm_stats,
|
|
+ .set_preempt = dsa_slave_set_preempt,
|
|
+ .get_preempt = dsa_slave_get_preempt,
|
|
+ .reset_preempt = dsa_slave_reset_preempt,
|
|
};
|
|
|
|
static const struct dcbnl_rtnl_ops __maybe_unused dsa_slave_dcbnl_ops = {
|
|
@@ -2999,7 +3040,9 @@ dsa_slave_check_8021q_upper(struct net_device *dev,
|
|
struct net_device *br = dsa_port_bridge_dev_get(dp);
|
|
struct bridge_vlan_info br_info;
|
|
struct netlink_ext_ack *extack;
|
|
+ bool update_proto = false;
|
|
int err = NOTIFY_DONE;
|
|
+ u16 br_proto, proto;
|
|
u16 vid;
|
|
|
|
if (!br || !br_vlan_enabled(br))
|
|
@@ -3007,13 +3050,17 @@ dsa_slave_check_8021q_upper(struct net_device *dev,
|
|
|
|
extack = netdev_notifier_info_to_extack(&info->info);
|
|
vid = vlan_dev_vlan_id(info->upper_dev);
|
|
+ proto = vlan_dev_vlan_proto(info->upper_dev);
|
|
+ err = br_vlan_get_proto(br, &br_proto);
|
|
+ if (err == 0 && br_proto != proto)
|
|
+ update_proto = true;
|
|
|
|
/* br_vlan_get_info() returns -EINVAL or -ENOENT if the
|
|
* device, respectively the VID is not found, returning
|
|
* 0 means success, which is a failure for us here.
|
|
*/
|
|
err = br_vlan_get_info(br, vid, &br_info);
|
|
- if (err == 0) {
|
|
+ if (err == 0 && !update_proto) {
|
|
NL_SET_ERR_MSG_MOD(extack,
|
|
"This VLAN is already configured by the bridge");
|
|
return notifier_from_errno(-EBUSY);
|
|
diff --git a/net/dsa/tag_netc.c b/net/dsa/tag_netc.c
|
|
new file mode 100644
|
|
index 000000000000..b32ae484af9c
|
|
--- /dev/null
|
|
+++ b/net/dsa/tag_netc.c
|
|
@@ -0,0 +1,489 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright 2023 NXP
|
|
+ */
|
|
+
|
|
+#include <linux/if_vlan.h>
|
|
+#include <linux/dsa/netc.h>
|
|
+#include <linux/packing.h>
|
|
+#include "tag.h"
|
|
+#include "tag_8021q.h"
|
|
+
|
|
+#define NETC_8021Q_NAME "netc-8021q"
|
|
+
|
|
+/*
|
|
+ * NETC HEADRER after Source MAC
|
|
+ *
|
|
+ * | 2B | 2B | 0 / 4B / 8B / 12B / 16B |
|
|
+ * +------------ +-------------+---------------------------+
|
|
+ * | 0xDADC | HEADRER | DATA |
|
|
+ * +------------ +------------ +---------------------------+
|
|
+ */
|
|
+
|
|
+#define NETC_HEADER_LEN 4
|
|
+#define NETC_HEADER_DATA_TS_ID_LEN 4
|
|
+#define NETC_HEADER_DATA_TIMESTAP_LEN 8
|
|
+#define NETC_HEADER_DATA_CMD_LEN 16
|
|
+
|
|
+#define NETC_HEADER_HOST_TO_SWITCH BIT(15)
|
|
+
|
|
+/* Binary structure of the NETC Header ETH_P_NETC_META:
|
|
+ *
|
|
+ * | 15 | 14 | 13 | 12 | 11 | 10 - 9 | 7 - 4 | 3 - 0 |
|
|
+ * +-----------+------+-----------+-------+-------+--------+-----------+---------+
|
|
+ * | TO HOST 0 | META | HOST Only | RX TS | TX TS | | Switch ID | Port ID |
|
|
+ * +-----------+------+-----------+-------+-------+--------+-----------+---------+
|
|
+ */
|
|
+#define NETC_RX_HEADER_IS_METADATA BIT(14)
|
|
+#define NETC_RX_HEADER_HOST_ONLY BIT(13)
|
|
+#define NETC_RX_HEADER_RX_TIMESTAP BIT(12)
|
|
+#define NETC_RX_HEADER_TX_TIMESTAP BIT(11)
|
|
+
|
|
+#define NETC_HEADER_PORT_MASK 0x0F
|
|
+#define NETC_HEADER_PORT_OFFSET 0
|
|
+#define NETC_HEADER_SWITCH_MASK 0xF0
|
|
+#define NETC_HEADER_SWITCH_OFFSET 4
|
|
+#define NETC_RX_HEADER_PORT_ID(x) ((x) & NETC_HEADER_PORT_MASK)
|
|
+#define NETC_RX_HEADER_SWITCH_ID(x) (((x) & NETC_HEADER_SWITCH_MASK) >> NETC_HEADER_SWITCH_OFFSET)
|
|
+
|
|
+/*
|
|
+ * RX RX_Timestamp:
|
|
+ *
|
|
+ * | 64 - 0 |
|
|
+ * +------------ +
|
|
+ * | TimeStamp |
|
|
+ * +------------ +
|
|
+ */
|
|
+#define NETC_HEADER_TIMESTAMP_LEN 8
|
|
+
|
|
+/*
|
|
+ * RX TX_Timestamp:
|
|
+ *
|
|
+ * | 64 - 0 | 32 - 0 |
|
|
+ * +------------ +------------ +
|
|
+ * | TimeStamp | TS_ID |
|
|
+ * +------------ +------------ +
|
|
+ */
|
|
+#define NETC_RX_HEADER_TS_ID_LEN 4
|
|
+
|
|
+/* TX header */
|
|
+
|
|
+/*
|
|
+ * Binary structure of the NETC Header ETH_P_NETC_META:
|
|
+ *
|
|
+ * | 15 | 14 | 13 | 12 | 11 | 10 - 9 | 7 - 4 | 3 - 0 |
|
|
+ * +-----------+------+--------+-------+---------+--------+-----------+---------+
|
|
+ * | To SW 1 | META | | | TAKE TS | | SWITCH ID | PORT ID |
|
|
+ * +-----------+------+--------+-------+------ -+--------+-----------+---------+
|
|
+ */
|
|
+
|
|
+#define NETC_TX_HEADER_IS_METADATA BIT(14)
|
|
+#define NETC_TX_HEADER_TAKE_TS BIT(11)
|
|
+
|
|
+#define NETC_TX_HEADER_TSTAMP_ID(x) (x)
|
|
+#define NETC_TX_HEADER_SWITCHID(x) (((x) << NETC_HEADER_SWITCH_OFFSET) & NETC_HEADER_SWITCH_MASK)
|
|
+#define NETC_TX_HEADER_DESTPORTID(x) ((x) & NETC_HEADER_PORT_MASK)
|
|
+
|
|
+/*
|
|
+ * TX Take TS:
|
|
+ *
|
|
+ * | 32 - 0 |
|
|
+ * +------------ +
|
|
+ * | TS_ID |
|
|
+ * +------------ +
|
|
+ */
|
|
+#define NETC_TX_HEADER_TS_ID_LEN 4
|
|
+
|
|
+void print_skb_data(struct sk_buff *skb)
|
|
+{
|
|
+ u8 *buf = skb->data - ETH_HLEN;
|
|
+ int len = skb->len;
|
|
+ int i = 0;
|
|
+
|
|
+ if (!skb) {
|
|
+ printk("Bad skb parameter");
|
|
+ return;
|
|
+ }
|
|
+ printk("Packet length = 0x%x", len);
|
|
+
|
|
+ for (i = 0; i < len; i += 8) {
|
|
+ printk("0x%04x: %02x %02x %02x %02x %02x %02x %02x %02x\n", i,
|
|
+ buf[i + 0], buf[i + 1], buf[i + 2], buf[i + 3],
|
|
+ buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7]);
|
|
+ }
|
|
+ printk("\n");
|
|
+}
|
|
+
|
|
+/* Similar to is_link_local_ether_addr(hdr->h_dest) but also covers PTP */
|
|
+static inline bool netc_is_link_local(const struct sk_buff *skb)
|
|
+{
|
|
+ const struct ethhdr *hdr = eth_hdr(skb);
|
|
+ u64 dmac = ether_addr_to_u64(hdr->h_dest);
|
|
+
|
|
+ if (ntohs(hdr->h_proto) == ETH_P_NETC)
|
|
+ return false;
|
|
+
|
|
+ if ((dmac & NETC_LINKLOCAL_FILTER_A_MASK) ==
|
|
+ NETC_LINKLOCAL_FILTER_A)
|
|
+ return true;
|
|
+
|
|
+ if ((dmac & NETC_LINKLOCAL_FILTER_B_MASK) ==
|
|
+ NETC_LINKLOCAL_FILTER_B)
|
|
+ return true;
|
|
+
|
|
+ return false;
|
|
+}
|
|
+
|
|
+/* Send VLAN tags with a TPID that blends in with whatever VLAN protocol a
|
|
+ * bridge spanning ports of this switch might have.
|
|
+ */
|
|
+static u16 netc_xmit_tpid(struct dsa_port *dp)
|
|
+{
|
|
+ struct dsa_switch *ds = dp->ds;
|
|
+ struct dsa_port *other_dp;
|
|
+ u16 proto;
|
|
+
|
|
+ if (!dsa_port_is_vlan_filtering(dp))
|
|
+ return ETH_P_NETC_8021Q;
|
|
+
|
|
+ /* Port is VLAN-aware, so there is a bridge somewhere (a single one,
|
|
+ * we're sure about that). It may not be on this port though, so we
|
|
+ * need to find it.
|
|
+ */
|
|
+ dsa_switch_for_each_port(other_dp, ds) {
|
|
+ struct net_device *br = dsa_port_bridge_dev_get(other_dp);
|
|
+
|
|
+ if (!br)
|
|
+ continue;
|
|
+
|
|
+ /* Error is returned only if CONFIG_BRIDGE_VLAN_FILTERING,
|
|
+ * which seems pointless to handle, as our port cannot become
|
|
+ * VLAN-aware in that case.
|
|
+ */
|
|
+ br_vlan_get_proto(br, &proto);
|
|
+
|
|
+ return proto;
|
|
+ }
|
|
+
|
|
+ WARN_ONCE(1, "Port is VLAN-aware but cannot find associated bridge!\n");
|
|
+
|
|
+ return ETH_P_NETC_8021Q;
|
|
+}
|
|
+
|
|
+static struct sk_buff *netc_imprecise_xmit(struct sk_buff *skb,
|
|
+ struct net_device *netdev)
|
|
+{
|
|
+ struct dsa_port *dp = dsa_slave_to_port(netdev);
|
|
+ unsigned int bridge_num = dsa_port_bridge_num_get(dp);
|
|
+ struct net_device *br = dsa_port_bridge_dev_get(dp);
|
|
+ u16 tx_vid;
|
|
+
|
|
+ /* If the port is under a VLAN-aware bridge, just slide the
|
|
+ * VLAN-tagged packet into the FDB and hope for the best.
|
|
+ * This works because we support a single VLAN-aware bridge
|
|
+ * across the entire dst, and its VLANs cannot be shared with
|
|
+ * any standalone port.
|
|
+ */
|
|
+ if (br_vlan_enabled(br))
|
|
+ return skb;
|
|
+
|
|
+ /* If the port is under a VLAN-unaware bridge, use an imprecise
|
|
+ * TX VLAN that targets the bridge's entire broadcast domain,
|
|
+ * instead of just the specific port.
|
|
+ */
|
|
+ tx_vid = dsa_tag_8021q_bridge_vid(bridge_num);
|
|
+
|
|
+ if (unlikely(skb_vlan_tag_present(skb))) {
|
|
+ skb = __vlan_hwaccel_push_inside(skb);
|
|
+ if (!skb) {
|
|
+ WARN_ONCE(1, "Failed to push VLAN tag to payload!\n");
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return dsa_8021q_xmit(skb, netdev, netc_xmit_tpid(dp), tx_vid);
|
|
+}
|
|
+
|
|
+static struct sk_buff *netc_meta_xmit(struct sk_buff *skb,
|
|
+ struct net_device *netdev)
|
|
+{
|
|
+ struct sk_buff *clone = NETC_SKB_CB(skb)->clone;
|
|
+ struct dsa_port *dp = dsa_slave_to_port(netdev);
|
|
+ int len = NETC_HEADER_LEN;
|
|
+ __be16 *tx_header;
|
|
+ __be32 *p_ts_id;
|
|
+
|
|
+ if (clone)
|
|
+ len = len + NETC_TX_HEADER_TS_ID_LEN;
|
|
+
|
|
+ skb_push(skb, len);
|
|
+
|
|
+ dsa_alloc_etype_header(skb, len);
|
|
+
|
|
+ tx_header = dsa_etype_header_pos_tx(skb);
|
|
+
|
|
+ tx_header[0] = htons(ETH_P_NETC_META);
|
|
+ tx_header[1] = htons(NETC_HEADER_HOST_TO_SWITCH |
|
|
+ NETC_TX_HEADER_SWITCHID(dp->ds->index) |
|
|
+ NETC_TX_HEADER_DESTPORTID(dp->index));
|
|
+ if(clone) {
|
|
+ tx_header[1] |= htons(NETC_TX_HEADER_TAKE_TS);
|
|
+ p_ts_id = dsa_etype_header_pos_tx(skb) + NETC_HEADER_LEN;
|
|
+ p_ts_id[0] = cpu_to_be32(NETC_SKB_CB(clone)->ts_id);
|
|
+ }
|
|
+
|
|
+ return skb;
|
|
+}
|
|
+
|
|
+static struct sk_buff *netc_8021q_xmit(struct sk_buff *skb,
|
|
+ struct net_device *netdev)
|
|
+{
|
|
+ struct dsa_port *dp = dsa_slave_to_port(netdev);
|
|
+ u16 queue_mapping = skb_get_queue_mapping(skb);
|
|
+ u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
|
|
+ u16 tx_vid = dsa_tag_8021q_standalone_vid(dp);
|
|
+
|
|
+ return dsa_8021q_xmit(skb, netdev, netc_xmit_tpid(dp),
|
|
+ ((pcp << VLAN_PRIO_SHIFT) | tx_vid));
|
|
+}
|
|
+
|
|
+static struct sk_buff *netc_xmit(struct sk_buff *skb,
|
|
+ struct net_device *netdev)
|
|
+{
|
|
+ if (skb->offload_fwd_mark)
|
|
+ return netc_imprecise_xmit(skb, netdev);
|
|
+
|
|
+ if (unlikely(netc_is_link_local(skb)))
|
|
+ return netc_meta_xmit(skb, netdev);
|
|
+
|
|
+ return netc_8021q_xmit(skb, netdev);
|
|
+}
|
|
+
|
|
+static bool netc_skb_has_tag_8021q(const struct sk_buff *skb)
|
|
+{
|
|
+ u16 tpid = ntohs(eth_hdr(skb)->h_proto);
|
|
+
|
|
+ return tpid == ETH_P_NETC || tpid == ETH_P_8021Q ||
|
|
+ skb_vlan_tag_present(skb);
|
|
+}
|
|
+
|
|
+static bool netc_skb_has_inband_control_extension(const struct sk_buff *skb)
|
|
+{
|
|
+ return ntohs(eth_hdr(skb)->h_proto) == ETH_P_NETC_META;
|
|
+}
|
|
+
|
|
+static struct sk_buff *netc_rcv_meta_cmd(struct sk_buff *skb, u16 rx_header)
|
|
+{
|
|
+ u8 *buf = dsa_etype_header_pos_rx(skb) + NETC_HEADER_LEN;
|
|
+ int switch_id = NETC_RX_HEADER_SWITCH_ID(rx_header);
|
|
+ int source_port = NETC_RX_HEADER_PORT_ID(rx_header);
|
|
+ struct netc_tagger_data *tagger_data;
|
|
+ struct net_device *master = skb->dev;
|
|
+ struct dsa_port *cpu_dp;
|
|
+ struct dsa_switch *ds;
|
|
+
|
|
+ cpu_dp = master->dsa_ptr;
|
|
+ ds = dsa_switch_find(cpu_dp->dst->index, switch_id);
|
|
+ if (!ds) {
|
|
+ net_err_ratelimited("%s: cannot find switch id %d\n",
|
|
+ master->name, switch_id);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ tagger_data = netc_tagger_data(ds);
|
|
+ if (!tagger_data->meta_cmd_handler)
|
|
+ return NULL;
|
|
+
|
|
+ if (skb_is_nonlinear(skb))
|
|
+ if(skb_linearize(skb))
|
|
+ return NULL;
|
|
+
|
|
+ tagger_data->meta_cmd_handler(ds, source_port, buf,
|
|
+ skb->len - NETC_HEADER_LEN - 2 * ETH_ALEN);
|
|
+
|
|
+ /* Discard the meta frame */
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static struct sk_buff *netc_rcv_tx_timestap(struct sk_buff *skb, u16 rx_header)
|
|
+{
|
|
+ u8 *buf = dsa_etype_header_pos_rx(skb) + NETC_HEADER_LEN;
|
|
+ int switch_id = NETC_RX_HEADER_SWITCH_ID(rx_header);
|
|
+ int source_port = NETC_RX_HEADER_PORT_ID(rx_header);
|
|
+ struct netc_tagger_data *tagger_data;
|
|
+ struct net_device *master = skb->dev;
|
|
+ struct dsa_port *cpu_dp;
|
|
+ struct dsa_switch *ds;
|
|
+ u32 ts_id;
|
|
+ u64 tstamp;
|
|
+
|
|
+ cpu_dp = master->dsa_ptr;
|
|
+
|
|
+ ds = dsa_switch_find(cpu_dp->dst->index, switch_id);
|
|
+ if (!ds) {
|
|
+ net_err_ratelimited("%s: cannot find switch id %d\n",
|
|
+ master->name, switch_id);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ tagger_data = netc_tagger_data(ds);
|
|
+ if (!tagger_data->meta_tstamp_handler)
|
|
+ return NULL;
|
|
+
|
|
+
|
|
+ tstamp = be64_to_cpu(*(__be64 *)buf);
|
|
+ ts_id = be32_to_cpu(*(__be32 *)(buf + NETC_HEADER_TIMESTAMP_LEN));
|
|
+
|
|
+ tagger_data->meta_tstamp_handler(ds, source_port, ts_id, tstamp);
|
|
+
|
|
+ /* Discard the meta frame, we've consumed the timestamps it contained */
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static struct sk_buff *netc_rcv_inband_control_extension(struct sk_buff *skb,
|
|
+ int *source_port,
|
|
+ int *switch_id,
|
|
+ bool *host_only)
|
|
+{
|
|
+ u16 rx_header;
|
|
+ int len = 0;
|
|
+
|
|
+ if (unlikely(!pskb_may_pull(skb,
|
|
+ NETC_HEADER_LEN +
|
|
+ NETC_HEADER_TIMESTAMP_LEN +
|
|
+ NETC_RX_HEADER_TS_ID_LEN)))
|
|
+ return NULL;
|
|
+
|
|
+ rx_header = ntohs(*(__be16 *)skb->data);
|
|
+
|
|
+ if (rx_header & NETC_RX_HEADER_HOST_ONLY)
|
|
+ *host_only = true;
|
|
+
|
|
+ if (rx_header & NETC_RX_HEADER_IS_METADATA)
|
|
+ return netc_rcv_meta_cmd(skb, rx_header);
|
|
+
|
|
+ if (rx_header & NETC_RX_HEADER_TX_TIMESTAP)
|
|
+ return netc_rcv_tx_timestap(skb, rx_header);
|
|
+
|
|
+ /* RX Timestamp frame */
|
|
+ if (rx_header & NETC_RX_HEADER_RX_TIMESTAP) {
|
|
+ u64 *tstamp = &NETC_SKB_CB(skb)->tstamp;
|
|
+ u8 *buf = dsa_etype_header_pos_rx(skb) + NETC_HEADER_LEN;
|
|
+
|
|
+ *tstamp = be64_to_cpu(*(__be64 *)buf);
|
|
+
|
|
+ len += NETC_HEADER_TIMESTAMP_LEN;
|
|
+ }
|
|
+
|
|
+ *source_port = NETC_RX_HEADER_PORT_ID(rx_header);
|
|
+ *switch_id = NETC_RX_HEADER_SWITCH_ID(rx_header);
|
|
+
|
|
+ len += NETC_HEADER_LEN;
|
|
+
|
|
+ /* Advance skb->data past the DSA header */
|
|
+ skb_pull_rcsum(skb, len);
|
|
+
|
|
+ dsa_strip_etype_header(skb, len);
|
|
+
|
|
+ /* With skb->data in its final place, update the MAC header
|
|
+ * so that eth_hdr() continues to works properly.
|
|
+ */
|
|
+ skb_set_mac_header(skb, -ETH_HLEN);
|
|
+
|
|
+ return skb;
|
|
+}
|
|
+
|
|
+/* If the VLAN in the packet is a tag_8021q one, set @source_port and
|
|
+ * @switch_id and strip the header. Otherwise set @vid and keep it in the
|
|
+ * packet.
|
|
+ */
|
|
+static void netc_vlan_rcv(struct sk_buff *skb, int *source_port,
|
|
+ int *switch_id, int *vbid, u16 *vid)
|
|
+{
|
|
+ struct vlan_ethhdr *hdr = vlan_eth_hdr(skb);
|
|
+ u16 vlan_tci;
|
|
+
|
|
+ if (skb_vlan_tag_present(skb))
|
|
+ vlan_tci = skb_vlan_tag_get(skb);
|
|
+ else
|
|
+ vlan_tci = ntohs(hdr->h_vlan_TCI);
|
|
+
|
|
+ if (vid_is_dsa_8021q(vlan_tci & VLAN_VID_MASK))
|
|
+ return dsa_8021q_rcv(skb, source_port, switch_id, vbid);
|
|
+
|
|
+ /* Try our best with imprecise RX */
|
|
+ *vid = vlan_tci & VLAN_VID_MASK;
|
|
+}
|
|
+
|
|
+static struct sk_buff *netc_rcv(struct sk_buff *skb,
|
|
+ struct net_device *netdev)
|
|
+{
|
|
+ int src_port = -1, switch_id = -1, vbid = -1;
|
|
+ bool host_only = false;
|
|
+ u16 vid = 0;
|
|
+
|
|
+ if (netc_skb_has_inband_control_extension(skb)) {
|
|
+ skb = netc_rcv_inband_control_extension(skb, &src_port,
|
|
+ &switch_id,
|
|
+ &host_only);
|
|
+ if (!skb)
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ /* Packets with in-band control extensions might still have RX VLANs */
|
|
+ if (likely(netc_skb_has_tag_8021q(skb)))
|
|
+ netc_vlan_rcv(skb, &src_port, &switch_id, &vbid, &vid);
|
|
+
|
|
+ if (vbid >= 1)
|
|
+ skb->dev = dsa_tag_8021q_find_port_by_vbid(netdev, vbid);
|
|
+ else if (src_port == -1 || switch_id == -1)
|
|
+ skb->dev = dsa_find_designated_bridge_port_by_vid(netdev, vid);
|
|
+ else
|
|
+ skb->dev = dsa_master_find_slave(netdev, switch_id, src_port);
|
|
+ if (!skb->dev) {
|
|
+ /* netdev_warn(netdev, "Couldn't decode source port\n"); */
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (!host_only)
|
|
+ dsa_default_offload_fwd_mark(skb);
|
|
+
|
|
+ return skb;
|
|
+}
|
|
+
|
|
+static void netc_disconnect(struct dsa_switch *ds)
|
|
+{
|
|
+ struct netc_tagger_data *tagger_data = ds->tagger_data;
|
|
+
|
|
+ kfree(tagger_data);
|
|
+ ds->tagger_data = NULL;
|
|
+}
|
|
+
|
|
+static int netc_connect(struct dsa_switch *ds)
|
|
+{
|
|
+ struct netc_tagger_data *data;
|
|
+
|
|
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
|
|
+ if (!data)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ ds->tagger_data = data;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct dsa_device_ops netc_netdev_ops = {
|
|
+ .name = NETC_8021Q_NAME,
|
|
+ .proto = DSA_TAG_PROTO_NETC,
|
|
+ .xmit = netc_xmit,
|
|
+ .rcv = netc_rcv,
|
|
+ .connect = netc_connect,
|
|
+ .disconnect = netc_disconnect,
|
|
+ .needed_headroom = VLAN_HLEN,
|
|
+ .promisc_on_master = true,
|
|
+};
|
|
+
|
|
+MODULE_LICENSE("GPL v2");
|
|
+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_NETC, NETC_8021Q_NAME);
|
|
+
|
|
+module_dsa_tag_driver(netc_netdev_ops);
|
|
diff --git a/net/dsa/tag_sja1105.c b/net/dsa/tag_sja1105.c
|
|
index ade3eeb2f3e6..1f70d9859862 100644
|
|
--- a/net/dsa/tag_sja1105.c
|
|
+++ b/net/dsa/tag_sja1105.c
|
|
@@ -267,9 +267,8 @@ static struct sk_buff *sja1105_xmit(struct sk_buff *skb,
|
|
struct net_device *netdev)
|
|
{
|
|
struct dsa_port *dp = dsa_slave_to_port(netdev);
|
|
- u16 queue_mapping = skb_get_queue_mapping(skb);
|
|
- u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
|
|
u16 tx_vid = dsa_tag_8021q_standalone_vid(dp);
|
|
+ u8 pcp = skb->priority;
|
|
|
|
if (skb->offload_fwd_mark)
|
|
return sja1105_imprecise_xmit(skb, netdev);
|
|
diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile
|
|
index 504f954a1b28..348993bf8eab 100644
|
|
--- a/net/ethtool/Makefile
|
|
+++ b/net/ethtool/Makefile
|
|
@@ -8,4 +8,4 @@ ethtool_nl-y := netlink.o bitset.o strset.o linkinfo.o linkmodes.o rss.o \
|
|
linkstate.o debug.o wol.o features.o privflags.o rings.o \
|
|
channels.o coalesce.o pause.o eee.o tsinfo.o cabletest.o \
|
|
tunnels.o fec.o eeprom.o stats.o phc_vclocks.o mm.o \
|
|
- module.o pse-pd.o plca.o mm.o
|
|
+ module.o pse-pd.o plca.o mm.o preempt.o
|
|
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
|
|
index 4486cbe2faf0..07b9b939e294 100644
|
|
--- a/net/ethtool/ioctl.c
|
|
+++ b/net/ethtool/ioctl.c
|
|
@@ -2765,6 +2765,49 @@ static int ethtool_set_fecparam(struct net_device *dev, void __user *useraddr)
|
|
return dev->ethtool_ops->set_fecparam(dev, &fecparam);
|
|
}
|
|
|
|
+static int ethtool_get_preempt(struct net_device *dev, void __user *useraddr)
|
|
+{
|
|
+ struct ethtool_fp fpparam = { .cmd = ETHTOOL_GFP };
|
|
+ int rc;
|
|
+
|
|
+ if (!dev->ethtool_ops->get_preempt)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ rc = dev->ethtool_ops->get_preempt(dev, &fpparam);
|
|
+ if (rc)
|
|
+ return rc;
|
|
+
|
|
+ if (copy_to_user(useraddr, &fpparam, sizeof(fpparam)))
|
|
+ return -EFAULT;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int ethtool_set_preempt(struct net_device *dev, void __user *useraddr)
|
|
+{
|
|
+ struct ethtool_fp fpparam;
|
|
+
|
|
+ if (!dev->ethtool_ops->set_preempt)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ if (copy_from_user(&fpparam, useraddr, sizeof(fpparam)))
|
|
+ return -EFAULT;
|
|
+
|
|
+ return dev->ethtool_ops->set_preempt(dev, &fpparam);
|
|
+}
|
|
+
|
|
+static int ethtool_reset_preempt(struct net_device *dev, void __user *useraddr)
|
|
+{
|
|
+ struct ethtool_fp fpparam;
|
|
+
|
|
+ if (!dev->ethtool_ops->reset_preempt)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ if (copy_from_user(&fpparam, useraddr, sizeof(fpparam)))
|
|
+ return -EFAULT;
|
|
+
|
|
+ return dev->ethtool_ops->reset_preempt(dev, fpparam.fp_enabled);
|
|
+}
|
|
+
|
|
/* The main entry point in this file. Called from net/core/dev_ioctl.c */
|
|
|
|
static int
|
|
@@ -2824,6 +2867,9 @@ __dev_ethtool(struct net *net, struct ifreq *ifr, void __user *useraddr,
|
|
case ETHTOOL_PHY_GTUNABLE:
|
|
case ETHTOOL_GLINKSETTINGS:
|
|
case ETHTOOL_GFECPARAM:
|
|
+ case ETHTOOL_GFP:
|
|
+ case ETHTOOL_SFP:
|
|
+ case ETHTOOL_RFP:
|
|
break;
|
|
default:
|
|
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
|
|
@@ -3051,6 +3097,15 @@ __dev_ethtool(struct net *net, struct ifreq *ifr, void __user *useraddr,
|
|
case ETHTOOL_SFECPARAM:
|
|
rc = ethtool_set_fecparam(dev, useraddr);
|
|
break;
|
|
+ case ETHTOOL_GFP:
|
|
+ rc = ethtool_get_preempt(dev, useraddr);
|
|
+ break;
|
|
+ case ETHTOOL_SFP:
|
|
+ rc = ethtool_set_preempt(dev, useraddr);
|
|
+ break;
|
|
+ case ETHTOOL_RFP:
|
|
+ rc = ethtool_reset_preempt(dev, useraddr);
|
|
+ break;
|
|
default:
|
|
rc = -EOPNOTSUPP;
|
|
}
|
|
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
|
|
index fe3553f60bf3..4734689e173f 100644
|
|
--- a/net/ethtool/netlink.c
|
|
+++ b/net/ethtool/netlink.c
|
|
@@ -306,6 +306,7 @@ ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] = {
|
|
[ETHTOOL_MSG_PLCA_GET_STATUS] = ðnl_plca_status_request_ops,
|
|
[ETHTOOL_MSG_MM_GET] = ðnl_mm_request_ops,
|
|
[ETHTOOL_MSG_MM_SET] = ðnl_mm_request_ops,
|
|
+ [ETHTOOL_MSG_PREEMPT_GET] = ðnl_preempt_request_ops,
|
|
};
|
|
|
|
static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb)
|
|
@@ -639,6 +640,7 @@ ethnl_default_notify_ops[ETHTOOL_MSG_KERNEL_MAX + 1] = {
|
|
[ETHTOOL_MSG_MODULE_NTF] = ðnl_module_request_ops,
|
|
[ETHTOOL_MSG_PLCA_NTF] = ðnl_plca_cfg_request_ops,
|
|
[ETHTOOL_MSG_MM_NTF] = ðnl_mm_request_ops,
|
|
+ [ETHTOOL_MSG_PREEMPT_NTF] = ðnl_preempt_request_ops,
|
|
};
|
|
|
|
/* default notification handler */
|
|
@@ -737,6 +739,7 @@ static const ethnl_notify_handler_t ethnl_notify_handlers[] = {
|
|
[ETHTOOL_MSG_MODULE_NTF] = ethnl_default_notify,
|
|
[ETHTOOL_MSG_PLCA_NTF] = ethnl_default_notify,
|
|
[ETHTOOL_MSG_MM_NTF] = ethnl_default_notify,
|
|
+ [ETHTOOL_MSG_PREEMPT_NTF] = ethnl_default_notify,
|
|
};
|
|
|
|
void ethtool_notify(struct net_device *dev, unsigned int cmd, const void *data)
|
|
@@ -1129,6 +1132,20 @@ static const struct genl_ops ethtool_genl_ops[] = {
|
|
.policy = ethnl_mm_set_policy,
|
|
.maxattr = ARRAY_SIZE(ethnl_mm_set_policy) - 1,
|
|
},
|
|
+ {
|
|
+ .cmd = ETHTOOL_MSG_PREEMPT_GET,
|
|
+ .doit = ethnl_default_doit,
|
|
+ .start = ethnl_default_start,
|
|
+ .dumpit = ethnl_default_dumpit,
|
|
+ .done = ethnl_default_done,
|
|
+ .policy = preempt_get_policy,
|
|
+ .maxattr = ETHTOOL_A_PREEMPT_MAX,
|
|
+ },
|
|
+ {
|
|
+ .cmd = ETHTOOL_MSG_PREEMPT_SET,
|
|
+ .flags = GENL_UNS_ADMIN_PERM,
|
|
+ .doit = ethnl_set_preempt,
|
|
+ },
|
|
};
|
|
|
|
static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
|
|
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
|
|
index 9a333a8d04c1..ee2dddc44224 100644
|
|
--- a/net/ethtool/netlink.h
|
|
+++ b/net/ethtool/netlink.h
|
|
@@ -395,6 +395,7 @@ extern const struct ethnl_request_ops ethnl_rss_request_ops;
|
|
extern const struct ethnl_request_ops ethnl_plca_cfg_request_ops;
|
|
extern const struct ethnl_request_ops ethnl_plca_status_request_ops;
|
|
extern const struct ethnl_request_ops ethnl_mm_request_ops;
|
|
+extern const struct ethnl_request_ops ethnl_preempt_request_ops;
|
|
|
|
extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1];
|
|
extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1];
|
|
@@ -441,6 +442,7 @@ extern const struct nla_policy ethnl_plca_set_cfg_policy[ETHTOOL_A_PLCA_MAX + 1]
|
|
extern const struct nla_policy ethnl_plca_get_status_policy[ETHTOOL_A_PLCA_HEADER + 1];
|
|
extern const struct nla_policy ethnl_mm_get_policy[ETHTOOL_A_MM_HEADER + 1];
|
|
extern const struct nla_policy ethnl_mm_set_policy[ETHTOOL_A_MM_MAX + 1];
|
|
+extern const struct nla_policy preempt_get_policy[ETHTOOL_A_PREEMPT_MAX + 1];
|
|
|
|
int ethnl_set_features(struct sk_buff *skb, struct genl_info *info);
|
|
int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info);
|
|
@@ -448,6 +450,7 @@ int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info);
|
|
int ethnl_tunnel_info_doit(struct sk_buff *skb, struct genl_info *info);
|
|
int ethnl_tunnel_info_start(struct netlink_callback *cb);
|
|
int ethnl_tunnel_info_dumpit(struct sk_buff *skb, struct netlink_callback *cb);
|
|
+int ethnl_set_preempt(struct sk_buff *skb, struct genl_info *info);
|
|
|
|
extern const char stats_std_names[__ETHTOOL_STATS_CNT][ETH_GSTRING_LEN];
|
|
extern const char stats_eth_phy_names[__ETHTOOL_A_STATS_ETH_PHY_CNT][ETH_GSTRING_LEN];
|
|
diff --git a/net/ethtool/preempt.c b/net/ethtool/preempt.c
|
|
new file mode 100644
|
|
index 000000000000..06f47fc75c58
|
|
--- /dev/null
|
|
+++ b/net/ethtool/preempt.c
|
|
@@ -0,0 +1,191 @@
|
|
+// SPDX-License-Identifier: GPL-2.0-only
|
|
+
|
|
+#include "netlink.h"
|
|
+#include "common.h"
|
|
+
|
|
+struct preempt_req_info {
|
|
+ struct ethnl_req_info base;
|
|
+};
|
|
+
|
|
+struct preempt_reply_data {
|
|
+ struct ethnl_reply_data base;
|
|
+ struct ethtool_fp fp;
|
|
+};
|
|
+
|
|
+#define PREEMPT_REPDATA(__reply_base) \
|
|
+ container_of(__reply_base, struct preempt_reply_data, base)
|
|
+
|
|
+const struct nla_policy preempt_get_policy[ETHTOOL_A_PREEMPT_MAX + 1] = {
|
|
+ [ETHTOOL_A_PREEMPT_UNSPEC] = { .type = NLA_REJECT },
|
|
+ [ETHTOOL_A_PREEMPT_HEADER] = { .type = NLA_NESTED },
|
|
+ [ETHTOOL_A_PREEMPT_SUPPORTED] = { .type = NLA_REJECT },
|
|
+ [ETHTOOL_A_PREEMPT_STATUS] = { .type = NLA_REJECT },
|
|
+ [ETHTOOL_A_PREEMPT_ACTIVE] = { .type = NLA_REJECT },
|
|
+ [ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE] = { .type = NLA_REJECT },
|
|
+ [ETHTOOL_A_PREEMPT_QUEUES_SUPPORTED] = { .type = NLA_REJECT },
|
|
+ [ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE] = { .type = NLA_REJECT },
|
|
+};
|
|
+
|
|
+static int preempt_prepare_data(const struct ethnl_req_info *req_base,
|
|
+ struct ethnl_reply_data *reply_base,
|
|
+ const struct genl_info *info)
|
|
+{
|
|
+ struct preempt_reply_data *data = PREEMPT_REPDATA(reply_base);
|
|
+ struct net_device *dev = reply_base->dev;
|
|
+ int ret;
|
|
+
|
|
+ if (!dev->ethtool_ops->get_preempt)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ ret = ethnl_ops_begin(dev);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ ret = dev->ethtool_ops->get_preempt(dev, &data->fp);
|
|
+ ethnl_ops_complete(dev);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int preempt_reply_size(const struct ethnl_req_info *req_base,
|
|
+ const struct ethnl_reply_data *reply_base)
|
|
+{
|
|
+ int len = 0;
|
|
+
|
|
+ len += nla_total_size(sizeof(u8)); /* _PREEMPT_SUPPORTED */
|
|
+ len += nla_total_size(sizeof(u8)); /* _PREEMPT_STATUS */
|
|
+ len += nla_total_size(sizeof(u8)); /* _PREEMPT_ACTIVE */
|
|
+ len += nla_total_size(sizeof(u32)); /* _PREEMPT_QUEUES_SUPPORTED */
|
|
+ len += nla_total_size(sizeof(u32)); /* _PREEMPT_QUEUES_PREEMPTIBLE */
|
|
+ len += nla_total_size(sizeof(u32)); /* _PREEMPT_MIN_FRAG_SIZE */
|
|
+
|
|
+ return len;
|
|
+}
|
|
+
|
|
+static int preempt_fill_reply(struct sk_buff *skb,
|
|
+ const struct ethnl_req_info *req_base,
|
|
+ const struct ethnl_reply_data *reply_base)
|
|
+{
|
|
+ const struct preempt_reply_data *data = PREEMPT_REPDATA(reply_base);
|
|
+ const struct ethtool_fp *preempt = &data->fp;
|
|
+
|
|
+ if (nla_put_u32(skb, ETHTOOL_A_PREEMPT_QUEUES_SUPPORTED,
|
|
+ preempt->supported_queues_mask))
|
|
+ return -EMSGSIZE;
|
|
+
|
|
+ if (nla_put_u32(skb, ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE,
|
|
+ preempt->preemptible_queues_mask))
|
|
+ return -EMSGSIZE;
|
|
+
|
|
+ if (nla_put_u8(skb, ETHTOOL_A_PREEMPT_STATUS, preempt->fp_status))
|
|
+ return -EMSGSIZE;
|
|
+
|
|
+ if (nla_put_u8(skb, ETHTOOL_A_PREEMPT_ACTIVE, preempt->fp_active))
|
|
+ return -EMSGSIZE;
|
|
+
|
|
+ if (nla_put_u8(skb, ETHTOOL_A_PREEMPT_SUPPORTED,
|
|
+ preempt->fp_supported))
|
|
+ return -EMSGSIZE;
|
|
+
|
|
+ if (nla_put_u32(skb, ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE,
|
|
+ preempt->min_frag_size))
|
|
+ return -EMSGSIZE;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+const struct ethnl_request_ops ethnl_preempt_request_ops = {
|
|
+ .request_cmd = ETHTOOL_MSG_PREEMPT_GET,
|
|
+ .reply_cmd = ETHTOOL_MSG_PREEMPT_GET_REPLY,
|
|
+ .hdr_attr = ETHTOOL_A_PREEMPT_HEADER,
|
|
+ .req_info_size = sizeof(struct preempt_req_info),
|
|
+ .reply_data_size = sizeof(struct preempt_reply_data),
|
|
+
|
|
+ .prepare_data = preempt_prepare_data,
|
|
+ .reply_size = preempt_reply_size,
|
|
+ .fill_reply = preempt_fill_reply,
|
|
+};
|
|
+
|
|
+static const struct nla_policy
|
|
+preempt_set_policy[ETHTOOL_A_PREEMPT_MAX + 1] = {
|
|
+ [ETHTOOL_A_PREEMPT_UNSPEC] = { .type = NLA_REJECT },
|
|
+ [ETHTOOL_A_PREEMPT_HEADER] = { .type = NLA_NESTED },
|
|
+ [ETHTOOL_A_PREEMPT_DISABLED] = { .type = NLA_FLAG },
|
|
+ [ETHTOOL_A_PREEMPT_SUPPORTED] = { .type = NLA_REJECT },
|
|
+ [ETHTOOL_A_PREEMPT_STATUS] = { .type = NLA_REJECT },
|
|
+ [ETHTOOL_A_PREEMPT_ACTIVE] = { .type = NLA_U8 },
|
|
+ [ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE] = { .type = NLA_U32 },
|
|
+ [ETHTOOL_A_PREEMPT_QUEUES_SUPPORTED] = { .type = NLA_REJECT },
|
|
+ [ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE] = { .type = NLA_U32 },
|
|
+};
|
|
+
|
|
+int ethnl_set_preempt(struct sk_buff *skb, struct genl_info *info)
|
|
+{
|
|
+ struct nlattr *tb[ARRAY_SIZE(preempt_set_policy)];
|
|
+ struct ethtool_fp preempt = {};
|
|
+ struct ethnl_req_info req_info = {};
|
|
+ struct net_device *dev;
|
|
+ bool mod = false;
|
|
+ int ret;
|
|
+
|
|
+ ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb,
|
|
+ ETHTOOL_A_PREEMPT_MAX, preempt_set_policy,
|
|
+ info->extack);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ ret = ethnl_parse_header_dev_get(&req_info,
|
|
+ tb[ETHTOOL_A_PREEMPT_HEADER],
|
|
+ genl_info_net(info), info->extack,
|
|
+ true);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+ dev = req_info.dev;
|
|
+ ret = -EOPNOTSUPP;
|
|
+ if (!dev->ethtool_ops->get_preempt ||
|
|
+ !dev->ethtool_ops->set_preempt)
|
|
+ goto out_dev;
|
|
+
|
|
+ rtnl_lock();
|
|
+ ret = ethnl_ops_begin(dev);
|
|
+ if (ret < 0)
|
|
+ goto out_rtnl;
|
|
+
|
|
+ if (nla_get_flag(tb[ETHTOOL_A_PREEMPT_DISABLED])) {
|
|
+ preempt.disabled = 1;
|
|
+ mod = true;
|
|
+ }
|
|
+ if (tb[ETHTOOL_A_PREEMPT_ACTIVE]) {
|
|
+ ethnl_update_u8(&preempt.fp_enabled,
|
|
+ tb[ETHTOOL_A_PREEMPT_ACTIVE], &mod);
|
|
+ mod = true;
|
|
+ }
|
|
+ if (tb[ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE])
|
|
+ ethnl_update_u32(&preempt.min_frag_size,
|
|
+ tb[ETHTOOL_A_PREEMPT_MIN_FRAG_SIZE], &mod);
|
|
+ else
|
|
+ preempt.min_frag_size = 60;
|
|
+ if (tb[ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE]) {
|
|
+ ethnl_update_u32(&preempt.preemptible_queues_mask,
|
|
+ tb[ETHTOOL_A_PREEMPT_QUEUES_PREEMPTIBLE], &mod);
|
|
+ mod = true;
|
|
+ }
|
|
+
|
|
+ ret = 0;
|
|
+ if (!mod)
|
|
+ goto out_ops;
|
|
+
|
|
+ ret = dev->ethtool_ops->set_preempt(dev, &preempt);
|
|
+ if (ret < 0)
|
|
+ GENL_SET_ERR_MSG(info, "frame preemption settings update failed");
|
|
+ else
|
|
+ ethtool_notify(dev, ETHTOOL_MSG_PREEMPT_NTF, NULL);
|
|
+
|
|
+out_ops:
|
|
+ ethnl_ops_complete(dev);
|
|
+out_rtnl:
|
|
+ rtnl_unlock();
|
|
+out_dev:
|
|
+ dev_put(dev);
|
|
+ return ret;
|
|
+}
|
|
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
|
|
index 3e5703537e4e..9a4bae08b82e 100644
|
|
--- a/net/packet/af_packet.c
|
|
+++ b/net/packet/af_packet.c
|
|
@@ -3261,9 +3261,10 @@ static int packet_release(struct socket *sock)
|
|
* Attach a packet hook.
|
|
*/
|
|
|
|
-static int packet_do_bind(struct sock *sk, const char *name, int ifindex,
|
|
+static int packet_do_bind(struct socket *sock, const char *name, int ifindex,
|
|
__be16 proto)
|
|
{
|
|
+ struct sock *sk = sock->sk;
|
|
struct packet_sock *po = pkt_sk(sk);
|
|
struct net_device *dev = NULL;
|
|
bool unlisted = false;
|
|
@@ -3329,6 +3330,7 @@ static int packet_do_bind(struct sock *sk, const char *name, int ifindex,
|
|
po->prot_hook.dev = dev;
|
|
WRITE_ONCE(po->ifindex, dev ? dev->ifindex : 0);
|
|
packet_cached_dev_assign(po, dev);
|
|
+ sock->ndev = dev;
|
|
}
|
|
dev_put(dev);
|
|
}
|
|
@@ -3358,7 +3360,6 @@ static int packet_do_bind(struct sock *sk, const char *name, int ifindex,
|
|
static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr,
|
|
int addr_len)
|
|
{
|
|
- struct sock *sk = sock->sk;
|
|
char name[sizeof(uaddr->sa_data_min) + 1];
|
|
|
|
/*
|
|
@@ -3373,13 +3374,13 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr,
|
|
memcpy(name, uaddr->sa_data, sizeof(uaddr->sa_data_min));
|
|
name[sizeof(uaddr->sa_data_min)] = 0;
|
|
|
|
- return packet_do_bind(sk, name, 0, 0);
|
|
+
|
|
+ return packet_do_bind(sock, name, 0, 0);
|
|
}
|
|
|
|
static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
|
|
{
|
|
struct sockaddr_ll *sll = (struct sockaddr_ll *)uaddr;
|
|
- struct sock *sk = sock->sk;
|
|
|
|
/*
|
|
* Check legality
|
|
@@ -3390,7 +3391,7 @@ static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len
|
|
if (sll->sll_family != AF_PACKET)
|
|
return -EINVAL;
|
|
|
|
- return packet_do_bind(sk, NULL, sll->sll_ifindex, sll->sll_protocol);
|
|
+ return packet_do_bind(sock, NULL, sll->sll_ifindex, sll->sll_protocol);
|
|
}
|
|
|
|
static struct proto packet_proto = {
|
|
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
|
|
index 470c70deffe2..1f64c0ee84d1 100644
|
|
--- a/net/sched/Kconfig
|
|
+++ b/net/sched/Kconfig
|
|
@@ -925,6 +925,19 @@ config NET_ACT_GATE
|
|
To compile this code as a module, choose M here: the
|
|
module will be called act_gate.
|
|
|
|
+config NET_ACT_FRER
|
|
+ tristate "Frame frer tc action"
|
|
+ depends on NET_CLS_ACT
|
|
+ help
|
|
+ Say Y here to support frame replication and elimination for
|
|
+ reliability, which is defined by IEEE 802.1CB.
|
|
+ This action allow to add a frer tag. It also allow to remove
|
|
+ the frer tag and drop repeat frames.
|
|
+
|
|
+ If unsure, say N.
|
|
+ To compile this code as a module, choose M here: the
|
|
+ module will be called act_frer.
|
|
+
|
|
config NET_IFE_SKBMARK
|
|
tristate "Support to encoding decoding skb mark on IFE action"
|
|
depends on NET_ACT_IFE
|
|
diff --git a/net/sched/Makefile b/net/sched/Makefile
|
|
index b5fd49641d91..6ff9bc76febc 100644
|
|
--- a/net/sched/Makefile
|
|
+++ b/net/sched/Makefile
|
|
@@ -32,6 +32,7 @@ obj-$(CONFIG_NET_IFE_SKBTCINDEX) += act_meta_skbtcindex.o
|
|
obj-$(CONFIG_NET_ACT_TUNNEL_KEY)+= act_tunnel_key.o
|
|
obj-$(CONFIG_NET_ACT_CT) += act_ct.o
|
|
obj-$(CONFIG_NET_ACT_GATE) += act_gate.o
|
|
+obj-$(CONFIG_NET_ACT_FRER) += act_frer.o
|
|
obj-$(CONFIG_NET_SCH_FIFO) += sch_fifo.o
|
|
obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o
|
|
obj-$(CONFIG_NET_SCH_HFSC) += sch_hfsc.o
|
|
diff --git a/net/sched/act_frer.c b/net/sched/act_frer.c
|
|
new file mode 100644
|
|
index 000000000000..af455ef08813
|
|
--- /dev/null
|
|
+++ b/net/sched/act_frer.c
|
|
@@ -0,0 +1,731 @@
|
|
+// SPDX-License-Identifier: GPL-2.0-or-later
|
|
+/* Copyright 2021 NXP */
|
|
+
|
|
+#include <linux/module.h>
|
|
+#include <linux/types.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/string.h>
|
|
+#include <linux/errno.h>
|
|
+#include <linux/skbuff.h>
|
|
+#include <linux/rtnetlink.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/slab.h>
|
|
+#include <net/act_api.h>
|
|
+#include <net/netlink.h>
|
|
+#include <net/pkt_cls.h>
|
|
+#include <net/tc_act/tc_frer.h>
|
|
+
|
|
+#define FRER_SEQ_SPACE 16
|
|
+#define FRER_RCVY_RESET_MSEC 100
|
|
+#define FRER_RCVY_INVALID_SEQ 0x100
|
|
+#define FRER_RCVY_PASSED 0
|
|
+#define FRER_RCVY_DISCARDED -1
|
|
+
|
|
+static unsigned int frer_net_id;
|
|
+static struct tc_action_ops act_frer_ops;
|
|
+
|
|
+struct r_tag {
|
|
+ __be16 reserved;
|
|
+ __be16 sequence_nr;
|
|
+ __be16 encap_proto;
|
|
+} __packed;
|
|
+
|
|
+struct rtag_ethhdr {
|
|
+ struct ethhdr ethhdr;
|
|
+ struct r_tag h_rtag;
|
|
+} __packed;
|
|
+
|
|
+struct rtag_vlan_ethhdr {
|
|
+ struct vlan_ethhdr vlanhdr;
|
|
+ struct r_tag h_rtag;
|
|
+} __packed;
|
|
+
|
|
+static const struct nla_policy frer_policy[TCA_FRER_MAX + 1] = {
|
|
+ [TCA_FRER_PARMS] =
|
|
+ NLA_POLICY_EXACT_LEN(sizeof(struct tc_frer)),
|
|
+ [TCA_FRER_TAG_TYPE] = { .type = NLA_U8 },
|
|
+ [TCA_FRER_TAG_ACTION] = { .type = NLA_U8 },
|
|
+ [TCA_FRER_RECOVER] = { .type = NLA_U8 },
|
|
+ [TCA_FRER_RECOVER_ALG] = { .type = NLA_U8 },
|
|
+ [TCA_FRER_RECOVER_HISTORY_LEN] = { .type = NLA_U8 },
|
|
+ [TCA_FRER_RECOVER_RESET_TM] = { .type = NLA_U64 },
|
|
+};
|
|
+
|
|
+static void frer_seq_recovery_reset(struct tcf_frer *frer_act);
|
|
+
|
|
+static enum hrtimer_restart frer_hrtimer_func(struct hrtimer *timer)
|
|
+{
|
|
+ struct tcf_frer *frer_act = container_of(timer, struct tcf_frer,
|
|
+ hrtimer);
|
|
+ ktime_t remaining_tm;
|
|
+
|
|
+ frer_seq_recovery_reset(frer_act);
|
|
+
|
|
+ remaining_tm = (ktime_t)(frer_act->rcvy_reset_msec * 1000000);
|
|
+
|
|
+ hrtimer_forward(timer, timer->base->get_time(), remaining_tm);
|
|
+
|
|
+ return HRTIMER_RESTART;
|
|
+}
|
|
+
|
|
+static int frer_rtag_decode(struct sk_buff *skb)
|
|
+{
|
|
+ struct rtag_vlan_ethhdr *rtag_vlan_hdr;
|
|
+ struct rtag_ethhdr *rtag_hdr;
|
|
+ struct vlan_ethhdr *vlanhdr;
|
|
+ struct ethhdr *ethhdr;
|
|
+ struct r_tag *rtag;
|
|
+ bool is_vlan;
|
|
+ u16 sequence;
|
|
+ u16 proto;
|
|
+
|
|
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
|
|
+ proto = ethhdr->h_proto;
|
|
+ is_vlan = false;
|
|
+
|
|
+ if (proto == htons(ETH_P_8021Q)) {
|
|
+ vlanhdr = (struct vlan_ethhdr *)ethhdr;
|
|
+ proto = vlanhdr->h_vlan_encapsulated_proto;
|
|
+ is_vlan = true;
|
|
+ }
|
|
+
|
|
+ if (proto != htons(ETH_P_RTAG))
|
|
+ return FRER_RCVY_INVALID_SEQ;
|
|
+
|
|
+ if (is_vlan) {
|
|
+ rtag_vlan_hdr = (struct rtag_vlan_ethhdr *)ethhdr;
|
|
+ rtag = &rtag_vlan_hdr->h_rtag;
|
|
+ } else {
|
|
+ rtag_hdr = (struct rtag_ethhdr *)ethhdr;
|
|
+ rtag = &rtag_hdr->h_rtag;
|
|
+ }
|
|
+
|
|
+ sequence = ntohs(rtag->sequence_nr);
|
|
+
|
|
+ return sequence;
|
|
+}
|
|
+
|
|
+static int frer_seq_generation_alg(struct tcf_frer *frer_act)
|
|
+{
|
|
+ u32 gen_seq_max = frer_act->seq_space - 1;
|
|
+ u32 gen_seq_num = frer_act->gen_seq_num;
|
|
+ int sequence_number;
|
|
+
|
|
+ sequence_number = gen_seq_num;
|
|
+
|
|
+ if (gen_seq_num >= gen_seq_max)
|
|
+ gen_seq_num = 0;
|
|
+ else
|
|
+ gen_seq_num++;
|
|
+
|
|
+ frer_act->gen_seq_num = gen_seq_num;
|
|
+
|
|
+ return sequence_number;
|
|
+}
|
|
+
|
|
+static int frer_rtag_encode(struct sk_buff *skb, struct tcf_frer *frer_act)
|
|
+{
|
|
+ struct vlan_ethhdr *vlanhdr;
|
|
+ struct ethhdr *ethhdr;
|
|
+ struct r_tag *rtag;
|
|
+ int rtag_len, head_len;
|
|
+ unsigned char *dst, *src, *p;
|
|
+ __be16 *proto, proto_val;
|
|
+
|
|
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
|
|
+ if (ethhdr->h_proto == htons(ETH_P_8021Q)) {
|
|
+ vlanhdr = (struct vlan_ethhdr *)ethhdr;
|
|
+ p = (unsigned char *)(vlanhdr + 1);
|
|
+ proto = &vlanhdr->h_vlan_encapsulated_proto;
|
|
+ } else {
|
|
+ p = (unsigned char *)(ethhdr + 1);
|
|
+ proto = ðhdr->h_proto;
|
|
+ }
|
|
+
|
|
+ proto_val = *proto;
|
|
+ *proto = htons(ETH_P_RTAG);
|
|
+
|
|
+ src = skb_mac_header(skb);
|
|
+ head_len = p - src;
|
|
+
|
|
+ rtag_len = sizeof(struct r_tag);
|
|
+ if (skb_cow_head(skb, rtag_len) < 0)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ skb_push(skb, rtag_len);
|
|
+ skb_reset_network_header(skb);
|
|
+ skb->mac_header -= rtag_len;
|
|
+
|
|
+ dst = skb_mac_header(skb);
|
|
+ memmove(dst, src, head_len);
|
|
+
|
|
+ rtag = (struct r_tag *)(dst + head_len);
|
|
+ rtag->encap_proto = proto_val;
|
|
+ rtag->sequence_nr = htons(frer_act->gen_seq_num);
|
|
+ rtag->reserved = 0;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void frer_rtag_pop(struct sk_buff *skb, struct tcf_frer *frer_act)
|
|
+{
|
|
+ struct vlan_ethhdr *vlanhdr;
|
|
+ struct ethhdr *ethhdr;
|
|
+ struct r_tag *rtag;
|
|
+ int rtag_len, head_len;
|
|
+ unsigned char *dst, *src, *p;
|
|
+ __be16 *proto;
|
|
+
|
|
+ ethhdr = (struct ethhdr *)skb_mac_header(skb);
|
|
+
|
|
+ if (ethhdr->h_proto == htons(ETH_P_8021Q)) {
|
|
+ vlanhdr = (struct vlan_ethhdr *)ethhdr;
|
|
+ p = (unsigned char *)(vlanhdr + 1);
|
|
+ proto = &vlanhdr->h_vlan_encapsulated_proto;
|
|
+ } else {
|
|
+ p = (unsigned char *)(ethhdr + 1);
|
|
+ proto = ðhdr->h_proto;
|
|
+ }
|
|
+
|
|
+ if (*proto != htons(ETH_P_RTAG))
|
|
+ return;
|
|
+
|
|
+ rtag = (struct r_tag *)p;
|
|
+ rtag_len = sizeof(struct r_tag);
|
|
+ *proto = rtag->encap_proto;
|
|
+
|
|
+ src = skb_mac_header(skb);
|
|
+ head_len = p - src;
|
|
+
|
|
+ skb->data = skb_mac_header(skb);
|
|
+ skb_pull(skb, rtag_len);
|
|
+
|
|
+ skb_reset_mac_header(skb);
|
|
+
|
|
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
|
|
+ skb->csum_start += rtag_len;
|
|
+
|
|
+ dst = skb_mac_header(skb);
|
|
+ memmove(dst, src, head_len);
|
|
+}
|
|
+
|
|
+static const struct tcf_frer_proto_ops rtag_ops = {
|
|
+ .encode = frer_rtag_encode,
|
|
+ .decode = frer_rtag_decode,
|
|
+ .tag_pop = frer_rtag_pop,
|
|
+};
|
|
+
|
|
+static int tcf_frer_init(struct net *net, struct nlattr *nla,
|
|
+ struct nlattr *est, struct tc_action **a,
|
|
+ struct tcf_proto *tp, u32 flags,
|
|
+ struct netlink_ext_ack *extack)
|
|
+{
|
|
+ struct tc_action_net *tn = net_generic(net, frer_net_id);
|
|
+ bool bind = flags & TCA_ACT_FLAGS_BIND;
|
|
+ struct nlattr *tb[TCA_FRER_MAX + 1];
|
|
+ struct tcf_chain *goto_ch = NULL;
|
|
+ struct tcf_frer *frer_act;
|
|
+ struct tc_frer *parm;
|
|
+ bool exists = false;
|
|
+ int ret = 0, err, index;
|
|
+ ktime_t remaining_tm;
|
|
+
|
|
+ if (!nla) {
|
|
+ NL_SET_ERR_MSG_MOD(extack, "FRER requires attributes to be passed");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ err = nla_parse_nested_deprecated(tb, TCA_FRER_MAX, nla, frer_policy, extack);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+
|
|
+ if (!tb[TCA_FRER_PARMS]) {
|
|
+ NL_SET_ERR_MSG_MOD(extack, "Missing required FRER parameters");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ parm = nla_data(tb[TCA_FRER_PARMS]);
|
|
+ index = parm->index;
|
|
+
|
|
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+ exists = err;
|
|
+
|
|
+ if (exists && bind)
|
|
+ return 0;
|
|
+
|
|
+ if (!exists) {
|
|
+ ret = tcf_idr_create_from_flags(tn, index, est, a,
|
|
+ &act_frer_ops, bind, flags);
|
|
+
|
|
+ if (ret) {
|
|
+ tcf_idr_cleanup(tn, index);
|
|
+ return ret;
|
|
+ }
|
|
+ ret = ACT_P_CREATED;
|
|
+ } else if (!(flags & TCA_ACT_FLAGS_REPLACE)) {
|
|
+ tcf_idr_release(*a, bind);
|
|
+ return -EEXIST;
|
|
+ }
|
|
+
|
|
+ err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
|
|
+ if (err < 0)
|
|
+ goto release_idr;
|
|
+
|
|
+ frer_act = to_frer(*a);
|
|
+
|
|
+ spin_lock_bh(&frer_act->tcf_lock);
|
|
+ goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
|
|
+
|
|
+ frer_act->tag_type = nla_get_u8(tb[TCA_FRER_TAG_TYPE]);
|
|
+ frer_act->tag_action = nla_get_u8(tb[TCA_FRER_TAG_ACTION]);
|
|
+ frer_act->recover = nla_get_u8(tb[TCA_FRER_RECOVER]);
|
|
+ frer_act->rcvy_alg = nla_get_u8(tb[TCA_FRER_RECOVER_ALG]);
|
|
+ frer_act->rcvy_history_len = nla_get_u8(tb[TCA_FRER_RECOVER_HISTORY_LEN]);
|
|
+ frer_act->rcvy_reset_msec = nla_get_u64(tb[TCA_FRER_RECOVER_RESET_TM]);
|
|
+
|
|
+ frer_act->gen_seq_num = 0;
|
|
+ frer_act->seq_space = 1 << FRER_SEQ_SPACE;
|
|
+ frer_act->rcvy_seq_num = 0;
|
|
+ frer_act->seq_history = 0xFFFFFFFF;
|
|
+ frer_act->rcvy_take_noseq = true;
|
|
+
|
|
+ switch (frer_act->tag_type) {
|
|
+ case TCA_FRER_TAG_RTAG:
|
|
+ frer_act->proto_ops = &rtag_ops;
|
|
+ break;
|
|
+ case TCA_FRER_TAG_HSR:
|
|
+ case TCA_FRER_TAG_PRP:
|
|
+ default:
|
|
+ spin_unlock_bh(&frer_act->tcf_lock);
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+
|
|
+ if (frer_act->recover && frer_act->rcvy_reset_msec) {
|
|
+ hrtimer_init(&frer_act->hrtimer, CLOCK_TAI,
|
|
+ HRTIMER_MODE_REL_SOFT);
|
|
+ frer_act->hrtimer.function = frer_hrtimer_func;
|
|
+
|
|
+ remaining_tm = (ktime_t)(frer_act->rcvy_reset_msec * 1000000);
|
|
+ hrtimer_start(&frer_act->hrtimer, remaining_tm,
|
|
+ HRTIMER_MODE_REL_SOFT);
|
|
+ }
|
|
+
|
|
+ spin_unlock_bh(&frer_act->tcf_lock);
|
|
+
|
|
+ if (goto_ch)
|
|
+ tcf_chain_put_by_act(goto_ch);
|
|
+
|
|
+ return ret;
|
|
+
|
|
+release_idr:
|
|
+ tcf_idr_release(*a, bind);
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static void frer_seq_recovery_reset(struct tcf_frer *frer_act)
|
|
+{
|
|
+ spin_lock(&frer_act->tcf_lock);
|
|
+ if (frer_act->rcvy_alg == TCA_FRER_RCVY_VECTOR_ALG) {
|
|
+ frer_act->rcvy_seq_num = frer_act->seq_space - 1;
|
|
+ frer_act->seq_history = 0;
|
|
+ }
|
|
+ frer_act->cps_seq_rcvy_resets++;
|
|
+ frer_act->take_any = true;
|
|
+ spin_unlock(&frer_act->tcf_lock);
|
|
+}
|
|
+
|
|
+static void frer_shift_seq_history(int value, struct tcf_frer *frer_act)
|
|
+{
|
|
+ int history_len = frer_act->rcvy_history_len;
|
|
+
|
|
+ if ((frer_act->seq_history & BIT(history_len - 1)) == 0)
|
|
+ frer_act->cps_seq_rcvy_lost_pkts++;
|
|
+
|
|
+ frer_act->seq_history <<= 1;
|
|
+
|
|
+ if (value)
|
|
+ frer_act->seq_history |= BIT(0);
|
|
+}
|
|
+
|
|
+static int frer_vector_rcvy_alg(struct tcf_frer *frer_act, int sequence,
|
|
+ bool individual)
|
|
+{
|
|
+ struct hrtimer *timer = &frer_act->hrtimer;
|
|
+ bool reset_timer = false;
|
|
+ ktime_t remaining_tm;
|
|
+ int delta, ret;
|
|
+
|
|
+ if (sequence == FRER_RCVY_INVALID_SEQ) {
|
|
+ frer_act->cps_seq_rcvy_tagless_pkts++;
|
|
+ if (frer_act->rcvy_take_noseq) {
|
|
+ reset_timer = true;
|
|
+ ret = FRER_RCVY_PASSED;
|
|
+ goto out;
|
|
+ } else {
|
|
+ return FRER_RCVY_DISCARDED;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ delta = (sequence - frer_act->rcvy_seq_num) & (frer_act->seq_space - 1);
|
|
+ /* -(RecovSeqSpace/2) <= delta <= ((RecovSeqSpace/2)-1) */
|
|
+ if (delta & (frer_act->seq_space / 2))
|
|
+ delta -= frer_act->seq_space;
|
|
+
|
|
+ if (frer_act->take_any) {
|
|
+ frer_act->take_any = false;
|
|
+ frer_act->seq_history |= BIT(0);
|
|
+ frer_act->rcvy_seq_num = sequence;
|
|
+
|
|
+ reset_timer = true;
|
|
+ ret = FRER_RCVY_PASSED;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (delta >= frer_act->rcvy_history_len ||
|
|
+ delta <= -frer_act->rcvy_history_len) {
|
|
+ /* Packet is out-of-range. */
|
|
+ frer_act->cps_seq_rcvy_rogue_pkts++;
|
|
+
|
|
+ if (individual)
|
|
+ reset_timer = true;
|
|
+
|
|
+ ret = FRER_RCVY_DISCARDED;
|
|
+ goto out;
|
|
+ } else if (delta <= 0) {
|
|
+ /* Packet is old and in SequenceHistory. */
|
|
+ if (frer_act->seq_history & BIT(-delta)) {
|
|
+ if (individual)
|
|
+ reset_timer = true;
|
|
+
|
|
+ /* Packet has been seen. */
|
|
+ ret = FRER_RCVY_DISCARDED;
|
|
+ goto out;
|
|
+ } else {
|
|
+ /* Packet has not been seen. */
|
|
+ frer_act->seq_history |= BIT(-delta);
|
|
+ frer_act->cps_seq_rcvy_out_of_order_pkts++;
|
|
+
|
|
+ reset_timer = true;
|
|
+ ret = FRER_RCVY_PASSED;
|
|
+ goto out;
|
|
+ }
|
|
+ } else {
|
|
+ /* Packet is not too far ahead of the one we want. */
|
|
+ if (delta != 1)
|
|
+ frer_act->cps_seq_rcvy_out_of_order_pkts++;
|
|
+
|
|
+ while (--delta)
|
|
+ frer_shift_seq_history(0, frer_act);
|
|
+ frer_shift_seq_history(1, frer_act);
|
|
+ frer_act->rcvy_seq_num = sequence;
|
|
+
|
|
+ reset_timer = true;
|
|
+ ret = FRER_RCVY_PASSED;
|
|
+ goto out;
|
|
+ }
|
|
+out:
|
|
+ if (reset_timer && frer_act->rcvy_reset_msec) {
|
|
+ remaining_tm =
|
|
+ (ktime_t)(frer_act->rcvy_reset_msec * 1000000);
|
|
+ hrtimer_start(timer, remaining_tm, HRTIMER_MODE_REL_SOFT);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int frer_match_rcvy_alg(struct tcf_frer *frer_act, int sequence,
|
|
+ bool individual)
|
|
+{
|
|
+ struct hrtimer *timer = &frer_act->hrtimer;
|
|
+ bool reset_timer = false;
|
|
+ ktime_t remaining_tm;
|
|
+ int delta, ret;
|
|
+
|
|
+ if (sequence == FRER_RCVY_INVALID_SEQ) {
|
|
+ frer_act->cps_seq_rcvy_tagless_pkts++;
|
|
+
|
|
+ return FRER_RCVY_PASSED;
|
|
+ }
|
|
+
|
|
+ if (frer_act->take_any) {
|
|
+ frer_act->take_any = false;
|
|
+ frer_act->rcvy_seq_num = sequence;
|
|
+
|
|
+ reset_timer = true;
|
|
+ ret = FRER_RCVY_PASSED;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ delta = sequence - frer_act->rcvy_seq_num;
|
|
+ if (delta) {
|
|
+ /* Packet has not been seen, accept it. */
|
|
+ if (delta != 1)
|
|
+ frer_act->cps_seq_rcvy_out_of_order_pkts++;
|
|
+
|
|
+ frer_act->rcvy_seq_num = sequence;
|
|
+
|
|
+ reset_timer = true;
|
|
+ ret = FRER_RCVY_PASSED;
|
|
+ goto out;
|
|
+ } else {
|
|
+ if (individual)
|
|
+ reset_timer = true;
|
|
+
|
|
+ /* Packet has been seen. Do not forward. */
|
|
+ ret = FRER_RCVY_DISCARDED;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+out:
|
|
+ if (reset_timer && frer_act->rcvy_reset_msec) {
|
|
+ remaining_tm = (ktime_t)(frer_act->rcvy_reset_msec * 1000000);
|
|
+ hrtimer_start(timer, remaining_tm, HRTIMER_MODE_REL_SOFT);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int tcf_frer_act(struct sk_buff *skb, const struct tc_action *a,
|
|
+ struct tcf_result *res)
|
|
+{
|
|
+ struct tcf_frer *frer_act = to_frer(a);
|
|
+ bool ingress, individual;
|
|
+ int ret, retval;
|
|
+ int sequence;
|
|
+
|
|
+ tcf_lastuse_update(&frer_act->tcf_tm);
|
|
+ tcf_action_update_bstats(&frer_act->common, skb);
|
|
+
|
|
+ retval = READ_ONCE(frer_act->tcf_action);
|
|
+
|
|
+ sequence = frer_act->proto_ops->decode(skb);
|
|
+
|
|
+ ingress = skb_at_tc_ingress(skb);
|
|
+ individual = ingress;
|
|
+
|
|
+ if (frer_act->recover) {
|
|
+ spin_lock(&frer_act->tcf_lock);
|
|
+
|
|
+ if (frer_act->rcvy_alg == TCA_FRER_RCVY_VECTOR_ALG)
|
|
+ ret = frer_vector_rcvy_alg(frer_act, sequence,
|
|
+ individual);
|
|
+ else
|
|
+ ret = frer_match_rcvy_alg(frer_act, sequence,
|
|
+ individual);
|
|
+ if (ret) {
|
|
+ frer_act->tcf_qstats.drops++;
|
|
+ retval = TC_ACT_SHOT;
|
|
+ }
|
|
+
|
|
+ if (frer_act->tag_action == TCA_FRER_TAG_POP)
|
|
+ frer_act->proto_ops->tag_pop(skb, frer_act);
|
|
+
|
|
+ spin_unlock(&frer_act->tcf_lock);
|
|
+
|
|
+ return retval;
|
|
+ }
|
|
+
|
|
+ if (frer_act->tag_action == TCA_FRER_TAG_PUSH &&
|
|
+ sequence == FRER_RCVY_INVALID_SEQ) {
|
|
+ spin_lock(&frer_act->tcf_lock);
|
|
+
|
|
+ frer_seq_generation_alg(frer_act);
|
|
+
|
|
+ frer_act->proto_ops->encode(skb, frer_act);
|
|
+
|
|
+ spin_unlock(&frer_act->tcf_lock);
|
|
+ }
|
|
+
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+static int tcf_frer_dump(struct sk_buff *skb, struct tc_action *a,
|
|
+ int bind, int ref)
|
|
+{
|
|
+ unsigned char *b = skb_tail_pointer(skb);
|
|
+ struct tcf_frer *frer_act = to_frer(a);
|
|
+ struct tc_frer opt = {
|
|
+ .index = frer_act->tcf_index,
|
|
+ .refcnt = refcount_read(&frer_act->tcf_refcnt) - ref,
|
|
+ .bindcnt = atomic_read(&frer_act->tcf_bindcnt) - bind,
|
|
+ };
|
|
+ struct tcf_t t;
|
|
+
|
|
+ spin_lock_bh(&frer_act->tcf_lock);
|
|
+ opt.action = frer_act->tcf_action;
|
|
+
|
|
+ if (nla_put(skb, TCA_FRER_PARMS, sizeof(opt), &opt))
|
|
+ goto nla_put_failure;
|
|
+
|
|
+ if (nla_put_u8(skb, TCA_FRER_TAG_TYPE, frer_act->tag_type))
|
|
+ goto nla_put_failure;
|
|
+
|
|
+ if (nla_put_u8(skb, TCA_FRER_TAG_ACTION, frer_act->tag_action))
|
|
+ goto nla_put_failure;
|
|
+
|
|
+ if (nla_put_u8(skb, TCA_FRER_RECOVER, frer_act->recover))
|
|
+ goto nla_put_failure;
|
|
+
|
|
+ if (nla_put_u8(skb, TCA_FRER_RECOVER_ALG, frer_act->rcvy_alg))
|
|
+ goto nla_put_failure;
|
|
+
|
|
+ if (nla_put_u8(skb, TCA_FRER_RECOVER_HISTORY_LEN,
|
|
+ frer_act->rcvy_history_len))
|
|
+ goto nla_put_failure;
|
|
+
|
|
+ if (nla_put_u64_64bit(skb, TCA_FRER_RECOVER_RESET_TM,
|
|
+ frer_act->rcvy_reset_msec, TCA_FRER_PAD))
|
|
+ goto nla_put_failure;
|
|
+
|
|
+ if (nla_put_u32(skb, TCA_FRER_RECOVER_TAGLESS_PKTS,
|
|
+ frer_act->cps_seq_rcvy_tagless_pkts))
|
|
+ goto nla_put_failure;
|
|
+
|
|
+ if (nla_put_u32(skb, TCA_FRER_RECOVER_OUT_OF_ORDER_PKTS,
|
|
+ frer_act->cps_seq_rcvy_out_of_order_pkts))
|
|
+ goto nla_put_failure;
|
|
+
|
|
+ if (nla_put_u32(skb, TCA_FRER_RECOVER_ROGUE_PKTS,
|
|
+ frer_act->cps_seq_rcvy_rogue_pkts))
|
|
+ goto nla_put_failure;
|
|
+
|
|
+ if (nla_put_u32(skb, TCA_FRER_RECOVER_LOST_PKTS,
|
|
+ frer_act->cps_seq_rcvy_lost_pkts))
|
|
+ goto nla_put_failure;
|
|
+
|
|
+ if (nla_put_u32(skb, TCA_FRER_RECOVER_RESETS,
|
|
+ frer_act->cps_seq_rcvy_resets))
|
|
+ goto nla_put_failure;
|
|
+
|
|
+ tcf_tm_dump(&t, &frer_act->tcf_tm);
|
|
+ if (nla_put_64bit(skb, TCA_FRER_TM, sizeof(t),
|
|
+ &t, TCA_FRER_PAD))
|
|
+ goto nla_put_failure;
|
|
+ spin_unlock_bh(&frer_act->tcf_lock);
|
|
+
|
|
+ return skb->len;
|
|
+
|
|
+nla_put_failure:
|
|
+ spin_unlock_bh(&frer_act->tcf_lock);
|
|
+ nlmsg_trim(skb, b);
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static int tcf_frer_walker(struct net *net, struct sk_buff *skb,
|
|
+ struct netlink_callback *cb, int type,
|
|
+ const struct tc_action_ops *ops,
|
|
+ struct netlink_ext_ack *extack)
|
|
+{
|
|
+ struct tc_action_net *tn = net_generic(net, frer_net_id);
|
|
+
|
|
+ return tcf_generic_walker(tn, skb, cb, type, ops, extack);
|
|
+}
|
|
+
|
|
+static int tcf_frer_search(struct net *net, struct tc_action **a, u32 index)
|
|
+{
|
|
+ struct tc_action_net *tn = net_generic(net, frer_net_id);
|
|
+
|
|
+ return tcf_idr_search(tn, a, index);
|
|
+}
|
|
+
|
|
+static void tcf_frer_stats_update(struct tc_action *a, u64 bytes, u64 packets,
|
|
+ u64 drops, u64 lastuse, bool hw)
|
|
+{
|
|
+ struct tcf_frer *frer_act = to_frer(a);
|
|
+ struct tcf_t *tm = &frer_act->tcf_tm;
|
|
+
|
|
+ tcf_action_update_stats(a, bytes, packets, drops, hw);
|
|
+ tm->lastuse = max_t(u64, tm->lastuse, lastuse);
|
|
+}
|
|
+
|
|
+static void tcf_frer_cleanup(struct tc_action *a)
|
|
+{
|
|
+ struct tcf_frer *frer_act = to_frer(a);
|
|
+
|
|
+ if (frer_act->rcvy_reset_msec)
|
|
+ hrtimer_cancel(&frer_act->hrtimer);
|
|
+}
|
|
+
|
|
+static size_t tcf_frer_get_fill_size(const struct tc_action *act)
|
|
+{
|
|
+ return nla_total_size(sizeof(struct tc_frer));
|
|
+}
|
|
+
|
|
+static int tcf_frer_offload_act_setup(struct tc_action *act, void *entry_data,
|
|
+ u32 *index_inc, bool bind,
|
|
+ struct netlink_ext_ack *extack)
|
|
+{
|
|
+ if (bind) {
|
|
+ struct flow_action_entry *entry = entry_data;
|
|
+
|
|
+ entry->id = FLOW_ACTION_FRER;
|
|
+ entry->frer.tag_type = to_frer(act)->tag_type;
|
|
+ entry->frer.tag_action = to_frer(act)->tag_action;
|
|
+ entry->frer.recover = to_frer(act)->recover;
|
|
+ entry->frer.rcvy_alg = to_frer(act)->rcvy_alg;
|
|
+ entry->frer.rcvy_history_len =
|
|
+ to_frer(act)->rcvy_history_len;
|
|
+ entry->frer.rcvy_reset_msec =
|
|
+ to_frer(act)->rcvy_reset_msec;
|
|
+
|
|
+ *index_inc = 1;
|
|
+ } else {
|
|
+ struct flow_offload_action *fl_action = entry_data;
|
|
+
|
|
+ fl_action->id = FLOW_ACTION_FRER;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct tc_action_ops act_frer_ops = {
|
|
+ .kind = "frer",
|
|
+ .id = TCA_ID_FRER,
|
|
+ .owner = THIS_MODULE,
|
|
+ .act = tcf_frer_act,
|
|
+ .init = tcf_frer_init,
|
|
+ .cleanup = tcf_frer_cleanup,
|
|
+ .dump = tcf_frer_dump,
|
|
+ .walk = tcf_frer_walker,
|
|
+ .stats_update = tcf_frer_stats_update,
|
|
+ .get_fill_size = tcf_frer_get_fill_size,
|
|
+ .offload_act_setup = tcf_frer_offload_act_setup,
|
|
+ .lookup = tcf_frer_search,
|
|
+ .size = sizeof(struct tcf_frer),
|
|
+};
|
|
+
|
|
+static __net_init int frer_init_net(struct net *net)
|
|
+{
|
|
+ struct tc_action_net *tn = net_generic(net, frer_net_id);
|
|
+
|
|
+ return tc_action_net_init(net, tn, &act_frer_ops);
|
|
+}
|
|
+
|
|
+static void __net_exit frer_exit_net(struct list_head *net_list)
|
|
+{
|
|
+ tc_action_net_exit(net_list, frer_net_id);
|
|
+};
|
|
+
|
|
+static struct pernet_operations frer_net_ops = {
|
|
+ .init = frer_init_net,
|
|
+ .exit_batch = frer_exit_net,
|
|
+ .id = &frer_net_id,
|
|
+ .size = sizeof(struct tc_action_net),
|
|
+};
|
|
+
|
|
+static int __init frer_init_module(void)
|
|
+{
|
|
+ return tcf_register_action(&act_frer_ops, &frer_net_ops);
|
|
+}
|
|
+
|
|
+static void __exit frer_cleanup_module(void)
|
|
+{
|
|
+ tcf_unregister_action(&act_frer_ops, &frer_net_ops);
|
|
+}
|
|
+
|
|
+module_init(frer_init_module);
|
|
+module_exit(frer_cleanup_module);
|
|
+MODULE_LICENSE("GPL v2");
|
|
diff --git a/net/sched/sch_cbs.c b/net/sched/sch_cbs.c
|
|
index cac870eb7897..36a6a79697e2 100644
|
|
--- a/net/sched/sch_cbs.c
|
|
+++ b/net/sched/sch_cbs.c
|
|
@@ -379,6 +379,11 @@ static int cbs_change(struct Qdisc *sch, struct nlattr *opt,
|
|
|
|
qopt = nla_data(tb[TCA_CBS_PARMS]);
|
|
|
|
+ if (qopt->idleslope < 0 || qopt->sendslope > 0 || qopt->hicredit < 0 || qopt->locredit > 0) {
|
|
+ NL_SET_ERR_MSG(extack, "Invalid CBS parameters");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
if (!qopt->offload) {
|
|
cbs_set_port_rate(dev, q);
|
|
cbs_disable_offload(dev, q);
|
|
diff --git a/net/socket.c b/net/socket.c
|
|
index 9db33cd4a71b..69e7d4bc021a 100644
|
|
--- a/net/socket.c
|
|
+++ b/net/socket.c
|
|
@@ -110,6 +110,10 @@
|
|
#include <linux/ptp_clock_kernel.h>
|
|
#include <trace/events/sock.h>
|
|
|
|
+static int fast_raw_socket_fd = -1;
|
|
+static struct net_device *fast_raw_socket_dev;
|
|
+static struct socket *fast_raw_socket_sock = NULL;
|
|
+
|
|
#ifdef CONFIG_NET_RX_BUSY_POLL
|
|
unsigned int sysctl_net_busy_read __read_mostly;
|
|
unsigned int sysctl_net_busy_poll __read_mostly;
|
|
@@ -671,6 +675,10 @@ static void __sock_release(struct socket *sock, struct inode *inode)
|
|
iput(SOCK_INODE(sock));
|
|
return;
|
|
}
|
|
+ if (fast_raw_socket_sock != NULL && fast_raw_socket_sock == sock) {
|
|
+ fast_raw_socket_sock = NULL;
|
|
+ fast_raw_socket_fd = -1;
|
|
+ }
|
|
sock->file = NULL;
|
|
}
|
|
|
|
@@ -1853,6 +1861,15 @@ int __sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen)
|
|
&address, addrlen);
|
|
}
|
|
fput_light(sock->file, fput_needed);
|
|
+ if (fast_raw_socket_fd < 0) {
|
|
+ if (sock->type == SOCK_RAW && sock->sk->sk_family == PF_PACKET) {
|
|
+ if (sock->ndev != NULL && sock->ndev->fast_raw_device == 1) {
|
|
+ fast_raw_socket_fd = fd;
|
|
+ fast_raw_socket_dev = sock->ndev;
|
|
+ fast_raw_socket_sock = sock;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
}
|
|
return err;
|
|
}
|
|
@@ -2169,6 +2186,10 @@ int __sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags,
|
|
struct msghdr msg;
|
|
struct iovec iov;
|
|
int fput_needed;
|
|
+ if (fd == fast_raw_socket_fd) {
|
|
+ err = fast_raw_socket_dev->netdev_ops->ndo_fast_xmit(fast_raw_socket_dev, buff, len);
|
|
+ return err;
|
|
+ }
|
|
|
|
err = import_single_range(ITER_SOURCE, buff, len, &iov, &msg.msg_iter);
|
|
if (unlikely(err))
|
|
@@ -2190,6 +2211,7 @@ int __sys_sendto(int fd, void __user *buff, size_t len, unsigned int flags,
|
|
msg.msg_namelen = addr_len;
|
|
}
|
|
flags &= ~MSG_INTERNAL_SENDMSG_FLAGS;
|
|
+
|
|
if (sock->file->f_flags & O_NONBLOCK)
|
|
flags |= MSG_DONTWAIT;
|
|
msg.msg_flags = flags;
|
|
@@ -2235,6 +2257,11 @@ int __sys_recvfrom(int fd, void __user *ubuf, size_t size, unsigned int flags,
|
|
struct iovec iov;
|
|
int err, err2;
|
|
int fput_needed;
|
|
+ int i;
|
|
+ if (fd == fast_raw_socket_fd) {
|
|
+ err = fast_raw_socket_dev->netdev_ops->ndo_fast_recv(fast_raw_socket_dev, ubuf, size, addr, addr_len);
|
|
+ return err;
|
|
+ }
|
|
|
|
err = import_single_range(ITER_DEST, ubuf, size, &iov, &msg.msg_iter);
|
|
if (unlikely(err))
|
|
diff --git a/net/tsn/genl_tsn.c b/net/tsn/genl_tsn.c
|
|
index 13a2d8089609..b8a6c2db906c 100644
|
|
--- a/net/tsn/genl_tsn.c
|
|
+++ b/net/tsn/genl_tsn.c
|
|
@@ -1136,12 +1136,11 @@ static int cmd_qci_sfi_get(struct genl_info *info)
|
|
return valid;
|
|
}
|
|
|
|
- valid = tsnops->qci_sfi_counters_get(netdev, sfi_handle,
|
|
- &sficount);
|
|
- if (valid < 0) {
|
|
+ ret = tsnops->qci_sfi_counters_get(netdev, sfi_handle, &sficount);
|
|
+ if (ret < 0) {
|
|
tsn_simple_reply(info, TSN_CMD_REPLY,
|
|
- netdev->name, valid);
|
|
- return valid;
|
|
+ netdev->name, ret);
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
@@ -2121,6 +2120,9 @@ static int cmd_qbv_set(struct genl_info *info)
|
|
if (qbv[TSN_QBV_ATTR_CONFIGCHANGE])
|
|
qbvconfig.config_change = 1;
|
|
|
|
+ if (qbv[TSN_QBV_ATTR_MAXSDU])
|
|
+ qbvconfig.maxsdu = nla_get_u32(qbv[TSN_QBV_ATTR_MAXSDU]);
|
|
+
|
|
if (!qbv[TSN_QBV_ATTR_ADMINENTRY]) {
|
|
tsn_simple_reply(info, TSN_CMD_REPLY, netdev->name, -EINVAL);
|
|
return -1;
|
|
diff --git a/tools/virtio/vt_test.sh b/tools/virtio/vt_test.sh
|
|
new file mode 100755
|
|
index 000000000000..4d9479404bd0
|
|
--- /dev/null
|
|
+++ b/tools/virtio/vt_test.sh
|
|
@@ -0,0 +1,79 @@
|
|
+#! /bin/bash
|
|
+# SPDX-License-Identifier: GPL-2.0
|
|
+# Copyright 2022-2024 NXP
|
|
+
|
|
+set -eo pipefail
|
|
+
|
|
+usage()
|
|
+{
|
|
+ echo "USAGE: $0 [-h] [-s pkt_size] [-r regression] [-t type] [-b backend copy] [-f frontend copy]"
|
|
+ echo -e "-s: Packet size: max 2048 Bytes, default: 64 Bytes"
|
|
+ echo -e "-r: Regression times: default: 1000"
|
|
+ echo -e "-t: Test type: 0: TX (frontend to backend); 1: RX (backend to frontend)"
|
|
+ echo -e "-b: Backend copy buffer option: 0: not copy; 1: copy"
|
|
+ echo -e "-f: Frontend copy buffer option: 0: not copy; 1: copy"
|
|
+ echo -e "-h: This USAGE info"
|
|
+ exit 1
|
|
+}
|
|
+
|
|
+setvar()
|
|
+{
|
|
+ local varname=$1
|
|
+ shift
|
|
+ if [ -z "${varname}" ]; then
|
|
+ usage
|
|
+ else
|
|
+ eval "$varname=\"$@\""
|
|
+ fi
|
|
+}
|
|
+
|
|
+find_virtio_trans ()
|
|
+{
|
|
+ VIRTIO_TRANS=`find /sys/bus/platform/devices/ -name *.virtio_trans`
|
|
+ if [ -z "${VIRTIO_TRANS}" ] || [ ! -d ${VIRTIO_TRANS} ]; then
|
|
+ echo "${VIRTIO_TRANS}"
|
|
+ exit 2;
|
|
+ fi
|
|
+}
|
|
+
|
|
+while getopts 'hs:t:r:b:f:' c
|
|
+do
|
|
+ case $c in
|
|
+ h) usage ;;
|
|
+ s) setvar PKT_SIZE $OPTARG ;;
|
|
+ t) setvar TYPE $OPTARG ;;
|
|
+ r) setvar REGRESS $OPTARG ;;
|
|
+ b) setvar BACK_COPY $OPTARG ;;
|
|
+ f) setvar FRONT_COPY $OPTARG ;;
|
|
+ esac
|
|
+
|
|
+done
|
|
+
|
|
+if [ -z "${TYPE}" ]; then
|
|
+ TYPE=0;
|
|
+fi
|
|
+
|
|
+if [ -z "${PKT_SIZE}" ]; then
|
|
+ PKT_SIZE=64;
|
|
+fi
|
|
+
|
|
+if [ -z "${REGRESS}" ]; then
|
|
+ REGRESS=1000;
|
|
+fi
|
|
+
|
|
+if [ -z "${BACK_COPY}" ]; then
|
|
+ BACK_COPY=0;
|
|
+fi
|
|
+
|
|
+if [ -z "${FRONT_COPY}" ]; then
|
|
+ FRONT_COPY=0;
|
|
+fi
|
|
+
|
|
+CONFIG=$(( $(( TYPE << 0 )) | $(( BACK_COPY << 1 )) | $(( FRONT_COPY << 2 )) ))
|
|
+
|
|
+find_virtio_trans
|
|
+
|
|
+echo ${REGRESS} > ${VIRTIO_TRANS}/virtio0/vt_regression&&
|
|
+echo ${PKT_SIZE} > ${VIRTIO_TRANS}/virtio0/vt_pkt_size&&
|
|
+echo ${CONFIG} > ${VIRTIO_TRANS}/virtio0/vt_config&&
|
|
+echo 1 > ${VIRTIO_TRANS}/virtio0/vt_control;
|