summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap1
-rw-r--r--Documentation/accounting/delay-accounting.rst56
-rw-r--r--Documentation/admin-guide/kdump/kdump.rst21
-rw-r--r--Documentation/admin-guide/kernel-parameters.txt48
-rw-r--r--Documentation/admin-guide/sysctl/kernel.rst20
-rw-r--r--Documentation/devicetree/bindings/i3c/renesas,i3c.yaml179
-rw-r--r--Documentation/devicetree/bindings/pinctrl/amlogic,pinctrl-a4.yaml9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/eswin,eic7700-pinctrl.yaml156
-rw-r--r--Documentation/devicetree/bindings/pinctrl/mediatek,mt8189-pinctrl.yaml213
-rw-r--r--Documentation/devicetree/bindings/pinctrl/nxp,lpc1850-scu.txt71
-rw-r--r--Documentation/devicetree/bindings/pinctrl/nxp,lpc1850-scu.yaml79
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,milos-tlmm.yaml133
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml4
-rw-r--r--Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml2
-rw-r--r--Documentation/devicetree/bindings/pinctrl/st,stm32-hdp.yaml187
-rw-r--r--Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml25
-rw-r--r--Documentation/devicetree/bindings/rtc/amlogic,a4-rtc.yaml11
-rw-r--r--Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.yaml7
-rw-r--r--Documentation/devicetree/bindings/rtc/nxp,lpc3220-rtc.yaml49
-rw-r--r--Documentation/devicetree/bindings/rtc/nxp,pcf85063.yaml33
-rw-r--r--Documentation/devicetree/bindings/rtc/sophgo,cv1800b-rtc.yaml (renamed from Documentation/devicetree/bindings/soc/sophgo/sophgo,cv1800b-rtc.yaml)2
-rw-r--r--Documentation/devicetree/bindings/rtc/trivial-rtc.yaml2
-rw-r--r--MAINTAINERS40
-rw-r--r--Makefile6
-rw-r--r--arch/alpha/kernel/core_marvel.c11
-rw-r--r--arch/arm/kernel/setup.c2
-rw-r--r--arch/arm64/Kconfig.platforms1
-rw-r--r--arch/arm64/include/asm/asm-bug.h33
-rw-r--r--arch/arm64/mm/init.c2
-rw-r--r--arch/loongarch/kernel/setup.c2
-rw-r--r--arch/mips/kernel/setup.c2
-rw-r--r--arch/powerpc/include/asm/ppc-opcode.h1
-rw-r--r--arch/powerpc/kernel/eeh.c1
-rw-r--r--arch/powerpc/kernel/eeh_driver.c48
-rw-r--r--arch/powerpc/kernel/eeh_pe.c10
-rw-r--r--arch/powerpc/kernel/fadump.c2
-rw-r--r--arch/powerpc/kernel/pci-hotplug.c3
-rw-r--r--arch/powerpc/kexec/core.c2
-rw-r--r--arch/powerpc/mm/nohash/kaslr_booke.c2
-rw-r--r--arch/powerpc/net/bpf_jit_comp64.c82
-rw-r--r--arch/riscv/Kconfig1
-rw-r--r--arch/riscv/include/asm/bug.h35
-rw-r--r--arch/riscv/kernel/kexec_elf.c1
-rw-r--r--arch/riscv/kernel/setup.c5
-rw-r--r--arch/riscv/mm/init.c2
-rw-r--r--arch/s390/kernel/setup.c2
-rw-r--r--arch/sh/kernel/machine_kexec.c2
-rw-r--r--arch/x86/include/asm/bug.h56
-rw-r--r--arch/x86/kernel/crash.c26
-rw-r--r--arch/x86/kernel/setup.c5
-rw-r--r--arch/x86/kvm/i8254.c4
-rw-r--r--crypto/async_tx/async_pq.c2
-rw-r--r--crypto/async_tx/async_raid6_recov.c4
-rw-r--r--drivers/cpufreq/rcpufreq_dt.rs5
-rw-r--r--drivers/cxl/core/mce.h2
-rw-r--r--drivers/gpu/drm/drm_panic_qr.rs4
-rw-r--r--drivers/gpu/drm/i915/gt/uc/intel_guc_log.c3
-rw-r--r--drivers/gpu/drm/nova/nova.rs2
-rw-r--r--drivers/gpu/drm/xe/xe_vm_types.h2
-rw-r--r--drivers/gpu/nova-core/driver.rs2
-rw-r--r--drivers/gpu/nova-core/firmware.rs5
-rw-r--r--drivers/gpu/nova-core/nova_core.rs2
-rw-r--r--drivers/gpu/nova-core/regs.rs2
-rw-r--r--drivers/gpu/nova-core/regs/macros.rs2
-rw-r--r--drivers/gpu/nova-core/util.rs4
-rw-r--r--drivers/i3c/device.c11
-rw-r--r--drivers/i3c/internals.h38
-rw-r--r--drivers/i3c/master.c38
-rw-r--r--drivers/i3c/master/Kconfig10
-rw-r--r--drivers/i3c/master/Makefile1
-rw-r--r--drivers/i3c/master/dw-i3c-master.c47
-rw-r--r--drivers/i3c/master/i3c-master-cdns.c90
-rw-r--r--drivers/i3c/master/mipi-i3c-hci/core.c2
-rw-r--r--drivers/i3c/master/renesas-i3c.c1404
-rw-r--r--drivers/i3c/master/svc-i3c-master.c32
-rw-r--r--drivers/net/ethernet/marvell/mvneta.c2
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_trace.c3
-rw-r--r--drivers/net/wwan/t7xx/t7xx_port_trace.c2
-rw-r--r--drivers/pci/hotplug/pnv_php.c248
-rw-r--r--drivers/pinctrl/Kconfig21
-rw-r--r--drivers/pinctrl/Makefile3
-rw-r--r--drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c2
-rw-r--r--drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c2
-rw-r--r--drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c14
-rw-r--r--drivers/pinctrl/aspeed/pinctrl-aspeed.c2
-rw-r--r--drivers/pinctrl/aspeed/pinctrl-aspeed.h2
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm4908.c2
-rw-r--r--drivers/pinctrl/bcm/pinctrl-cygnus-mux.c8
-rw-r--r--drivers/pinctrl/bcm/pinctrl-ns.c2
-rw-r--r--drivers/pinctrl/bcm/pinctrl-ns2-mux.c8
-rw-r--r--drivers/pinctrl/bcm/pinctrl-nsp-mux.c8
-rw-r--r--drivers/pinctrl/berlin/berlin.c10
-rw-r--r--drivers/pinctrl/cirrus/pinctrl-cs42l43.c23
-rw-r--r--drivers/pinctrl/cirrus/pinctrl-lochnagar.c25
-rw-r--r--drivers/pinctrl/cirrus/pinctrl-madera-core.c14
-rw-r--r--drivers/pinctrl/core.c13
-rw-r--r--drivers/pinctrl/core.h2
-rw-r--r--drivers/pinctrl/intel/pinctrl-baytrail.c8
-rw-r--r--drivers/pinctrl/intel/pinctrl-cherryview.c6
-rw-r--r--drivers/pinctrl/intel/pinctrl-intel.c20
-rw-r--r--drivers/pinctrl/intel/pinctrl-lynxpoint.c6
-rw-r--r--drivers/pinctrl/mediatek/Kconfig12
-rw-r--r--drivers/pinctrl/mediatek/Makefile1
-rw-r--r--drivers/pinctrl/mediatek/mtk-eint.c4
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-airoha.c10
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-moore.c5
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8189.c1700
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-mt8189.h2452
-rw-r--r--drivers/pinctrl/meson/pinctrl-amlogic-a4.c118
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson-g12a.c22
-rw-r--r--drivers/pinctrl/nuvoton/pinctrl-ma35.c6
-rw-r--r--drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c2
-rw-r--r--drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c2
-rw-r--r--drivers/pinctrl/nuvoton/pinctrl-wpcm450.c2
-rw-r--r--drivers/pinctrl/pinctrl-amd.c8
-rw-r--r--drivers/pinctrl/pinctrl-amdisp.c6
-rw-r--r--drivers/pinctrl/pinctrl-apple-gpio.c6
-rw-r--r--drivers/pinctrl/pinctrl-artpec6.c2
-rw-r--r--drivers/pinctrl/pinctrl-as3722.c23
-rw-r--r--drivers/pinctrl/pinctrl-at91-pio4.c6
-rw-r--r--drivers/pinctrl/pinctrl-aw9523.c26
-rw-r--r--drivers/pinctrl/pinctrl-bm1880.c2
-rw-r--r--drivers/pinctrl/pinctrl-da9062.c14
-rw-r--r--drivers/pinctrl/pinctrl-digicolor.c8
-rw-r--r--drivers/pinctrl/pinctrl-eic7700.c704
-rw-r--r--drivers/pinctrl/pinctrl-equilibrium.c9
-rw-r--r--drivers/pinctrl/pinctrl-falcon.c2
-rw-r--r--drivers/pinctrl/pinctrl-ingenic.c5
-rw-r--r--drivers/pinctrl/pinctrl-k210.c2
-rw-r--r--drivers/pinctrl/pinctrl-k230.c13
-rw-r--r--drivers/pinctrl/pinctrl-keembay.c19
-rw-r--r--drivers/pinctrl/pinctrl-lpc18xx.c2
-rw-r--r--drivers/pinctrl/pinctrl-max77620.c9
-rw-r--r--drivers/pinctrl/pinctrl-mcp23s08.c20
-rw-r--r--drivers/pinctrl/pinctrl-mlxbf3.c2
-rw-r--r--drivers/pinctrl/pinctrl-palmas.c4
-rw-r--r--drivers/pinctrl/pinctrl-pic32.c8
-rw-r--r--drivers/pinctrl/pinctrl-pistachio.c8
-rw-r--r--drivers/pinctrl/pinctrl-st.c6
-rw-r--r--drivers/pinctrl/pinctrl-tb10x.c2
-rw-r--r--drivers/pinctrl/pinctrl-xway.c18
-rw-r--r--drivers/pinctrl/pinctrl-zynq.c2
-rw-r--r--drivers/pinctrl/pinmux.c45
-rw-r--r--drivers/pinctrl/pinmux.h10
-rw-r--r--drivers/pinctrl/qcom/Kconfig.msm8
-rw-r--r--drivers/pinctrl/qcom/Makefile1
-rw-r--r--drivers/pinctrl/qcom/pinctrl-milos.c1339
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-gpio.c2
-rw-r--r--drivers/pinctrl/qcom/tlmm-test.c47
-rw-r--r--drivers/pinctrl/renesas/Kconfig249
-rw-r--r--drivers/pinctrl/renesas/gpio.c6
-rw-r--r--drivers/pinctrl/renesas/pinctrl-rza1.c7
-rw-r--r--drivers/pinctrl/renesas/pinctrl-rza2.c7
-rw-r--r--drivers/pinctrl/renesas/pinctrl-rzg2l.c53
-rw-r--r--drivers/pinctrl/renesas/pinctrl-rzn1.c4
-rw-r--r--drivers/pinctrl/renesas/pinctrl-rzv2m.c8
-rw-r--r--drivers/pinctrl/samsung/pinctrl-exynos-arm64.c6
-rw-r--r--drivers/pinctrl/samsung/pinctrl-exynos.c103
-rw-r--r--drivers/pinctrl/samsung/pinctrl-samsung.h4
-rw-r--r--drivers/pinctrl/spear/pinctrl-plgpio.c11
-rw-r--r--drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c10
-rw-r--r--drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c7
-rw-r--r--drivers/pinctrl/stm32/Kconfig20
-rw-r--r--drivers/pinctrl/stm32/Makefile1
-rw-r--r--drivers/pinctrl/stm32/pinctrl-stm32-hdp.c720
-rw-r--r--drivers/pinctrl/stm32/pinctrl-stm32.c144
-rw-r--r--drivers/pinctrl/stm32/pinctrl-stm32.h22
-rw-r--r--drivers/pinctrl/stm32/pinctrl-stm32mp257.c15
-rw-r--r--drivers/pinctrl/sunplus/sppctl.c6
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c2
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sunxi.c21
-rw-r--r--drivers/pinctrl/vt8500/pinctrl-wmt.c17
-rw-r--r--drivers/rtc/Kconfig21
-rw-r--r--drivers/rtc/Makefile2
-rw-r--r--drivers/rtc/lib.c40
-rw-r--r--drivers/rtc/rtc-ds1307.c30
-rw-r--r--drivers/rtc/rtc-ds1685.c4
-rw-r--r--drivers/rtc/rtc-hym8563.c15
-rw-r--r--drivers/rtc/rtc-m41t80.c25
-rw-r--r--drivers/rtc/rtc-max31335.c12
-rw-r--r--drivers/rtc/rtc-nct3018y.c15
-rw-r--r--drivers/rtc/rtc-pcf85063.c267
-rw-r--r--drivers/rtc/rtc-pcf8563.c15
-rw-r--r--drivers/rtc/rtc-rv3028.c15
-rw-r--r--drivers/rtc/rtc-rv3032.c21
-rw-r--r--drivers/rtc/rtc-s3c.c8
-rw-r--r--drivers/rtc/rtc-sh.c8
-rw-r--r--drivers/rtc/rtc-stm32.c2
-rw-r--r--drivers/rtc/sysfs.c64
-rw-r--r--drivers/rtc/test_rtc_lib.c (renamed from drivers/rtc/lib_test.c)0
-rw-r--r--drivers/video/fbdev/Kconfig2
-rw-r--r--drivers/video/fbdev/core/Kconfig2
-rw-r--r--drivers/video/fbdev/core/fbcon.c77
-rw-r--r--drivers/video/fbdev/core/fbmem.c3
-rw-r--r--drivers/video/fbdev/core/svgalib.c95
-rw-r--r--drivers/video/fbdev/imxfb.c9
-rw-r--r--drivers/video/fbdev/kyro/fbdev.c24
-rw-r--r--drivers/video/fbdev/nvidia/nv_local.h2
-rw-r--r--drivers/video/fbdev/simplefb.c17
-rw-r--r--fs/fat/fatent.c2
-rw-r--r--fs/fat/misc.c6
-rw-r--r--fs/ocfs2/aops.c1
-rw-r--r--fs/ocfs2/dir.c8
-rw-r--r--fs/ocfs2/dlm/dlmrecovery.c2
-rw-r--r--fs/ocfs2/inode.c70
-rw-r--r--fs/ocfs2/move_extents.c19
-rw-r--r--fs/ocfs2/namei.c11
-rw-r--r--fs/ocfs2/stack_user.c15
-rw-r--r--fs/proc/vmcore.c29
-rw-r--r--fs/squashfs/block.c47
-rw-r--r--fs/squashfs/file.c7
-rw-r--r--include/dt-bindings/pinctrl/stm32-pinfunc.h1
-rw-r--r--include/linux/crash_reserve.h15
-rw-r--r--include/linux/gcd.h3
-rw-r--r--include/linux/hung_task.h18
-rw-r--r--include/linux/i3c/device.h4
-rw-r--r--include/linux/i3c/master.h13
-rw-r--r--include/linux/jhash.h8
-rw-r--r--include/linux/kexec.h10
-rw-r--r--include/linux/module.h29
-rw-r--r--include/linux/moduleparam.h15
-rw-r--r--include/linux/pinctrl/pinctrl.h8
-rw-r--r--include/linux/raid/pq.h12
-rw-r--r--include/linux/relay.h24
-rw-r--r--include/linux/ring_buffer.h3
-rw-r--r--include/linux/rtc/ds1685.h2
-rw-r--r--include/linux/rwsem.h12
-rw-r--r--include/linux/soc/samsung/exynos-regs-pmu.h1
-rw-r--r--include/linux/sys_info.h28
-rw-r--r--include/linux/xxhash.h26
-rw-r--r--include/uapi/linux/kexec.h1
-rw-r--r--include/xen/xenbus.h2
-rw-r--r--init/Kconfig4
-rw-r--r--init/main.c6
-rw-r--r--kernel/crash_core.c15
-rw-r--r--kernel/crash_reserve.c68
-rw-r--r--kernel/events/uprobes.c4
-rw-r--r--kernel/exit.c7
-rw-r--r--kernel/fork.c95
-rw-r--r--kernel/hung_task.c29
-rw-r--r--kernel/kcov.c2
-rw-r--r--kernel/kexec.c2
-rw-r--r--kernel/kexec_core.c100
-rw-r--r--kernel/kexec_file.c51
-rw-r--r--kernel/kexec_internal.h2
-rw-r--r--kernel/kthread.c11
-rw-r--r--kernel/locking/rwsem.c31
-rw-r--r--kernel/module/internal.h7
-rw-r--r--kernel/module/main.c12
-rw-r--r--kernel/panic.c71
-rw-r--r--kernel/relay.c69
-rw-r--r--kernel/trace/blktrace.c22
-rw-r--r--kernel/trace/ring_buffer.c16
-rw-r--r--kernel/trace/trace.c289
-rw-r--r--kernel/trace/trace_events_synth.c6
-rw-r--r--kernel/trace/trace_output.c8
-rw-r--r--kernel/ucount.c16
-rw-r--r--lib/Kconfig.debug20
-rw-r--r--lib/Makefile3
-rw-r--r--lib/kunit/test.c8
-rw-r--r--lib/math/div64.c13
-rw-r--r--lib/math/gcd.c27
-rw-r--r--lib/raid6/algos.c3
-rw-r--r--lib/raid6/recov.c6
-rw-r--r--lib/raid6/recov_avx2.c6
-rw-r--r--lib/raid6/recov_avx512.c6
-rw-r--r--lib/raid6/recov_loongarch_simd.c12
-rw-r--r--lib/raid6/recov_neon.c6
-rw-r--r--lib/raid6/recov_rvv.c6
-rw-r--r--lib/raid6/recov_s390xc.c6
-rw-r--r--lib/raid6/recov_ssse3.c6
-rw-r--r--lib/stackdepot.c67
-rw-r--r--lib/sys_info.c122
-rw-r--r--lib/test_kho.c305
-rw-r--r--lib/xxhash.c107
-rw-r--r--rust/Makefile8
-rw-r--r--rust/bindings/lib.rs3
-rw-r--r--rust/helpers/bug.c5
-rw-r--r--rust/helpers/helpers.c5
-rw-r--r--rust/helpers/time.c35
-rw-r--r--rust/kernel/.gitignore2
-rw-r--r--rust/kernel/alloc/allocator_test.rs2
-rw-r--r--rust/kernel/alloc/kbox.rs98
-rw-r--r--rust/kernel/alloc/kvec.rs59
-rw-r--r--rust/kernel/bits.rs203
-rw-r--r--rust/kernel/block/mq.rs2
-rw-r--r--rust/kernel/block/mq/operations.rs2
-rw-r--r--rust/kernel/block/mq/request.rs11
-rw-r--r--rust/kernel/bug.rs126
-rw-r--r--rust/kernel/clk.rs6
-rw-r--r--rust/kernel/configfs.rs30
-rw-r--r--rust/kernel/cpufreq.rs10
-rw-r--r--rust/kernel/cpumask.rs4
-rw-r--r--rust/kernel/device.rs4
-rw-r--r--rust/kernel/device_id.rs4
-rw-r--r--rust/kernel/devres.rs10
-rw-r--r--rust/kernel/dma.rs10
-rw-r--r--rust/kernel/drm/device.rs10
-rw-r--r--rust/kernel/drm/gem/mod.rs4
-rw-r--r--rust/kernel/error.rs10
-rw-r--r--rust/kernel/firmware.rs9
-rw-r--r--rust/kernel/fmt.rs7
-rw-r--r--rust/kernel/fs/file.rs2
-rw-r--r--rust/kernel/generated_arch_reachable_asm.rs.S7
-rw-r--r--rust/kernel/generated_arch_warn_asm.rs.S7
-rw-r--r--rust/kernel/init.rs34
-rw-r--r--rust/kernel/io.rs20
-rw-r--r--rust/kernel/kunit.rs13
-rw-r--r--rust/kernel/lib.rs10
-rw-r--r--rust/kernel/list.rs63
-rw-r--r--rust/kernel/list/impl_list_item_mod.rs239
-rw-r--r--rust/kernel/miscdevice.rs12
-rw-r--r--rust/kernel/mm/virt.rs52
-rw-r--r--rust/kernel/net/phy.rs4
-rw-r--r--rust/kernel/of.rs6
-rw-r--r--rust/kernel/opp.rs20
-rw-r--r--rust/kernel/pci.rs13
-rw-r--r--rust/kernel/platform.rs2
-rw-r--r--rust/kernel/prelude.rs4
-rw-r--r--rust/kernel/print.rs12
-rw-r--r--rust/kernel/rbtree.rs29
-rw-r--r--rust/kernel/revocable.rs4
-rw-r--r--rust/kernel/seq_file.rs2
-rw-r--r--rust/kernel/str.rs111
-rw-r--r--rust/kernel/sync.rs10
-rw-r--r--rust/kernel/sync/arc.rs102
-rw-r--r--rust/kernel/sync/aref.rs154
-rw-r--r--rust/kernel/time.rs233
-rw-r--r--rust/kernel/time/delay.rs49
-rw-r--r--rust/kernel/time/hrtimer.rs304
-rw-r--r--rust/kernel/time/hrtimer/arc.rs8
-rw-r--r--rust/kernel/time/hrtimer/pin.rs10
-rw-r--r--rust/kernel/time/hrtimer/pin_mut.rs10
-rw-r--r--rust/kernel/time/hrtimer/tbox.rs8
-rw-r--r--rust/kernel/types.rs229
-rw-r--r--rust/kernel/uaccess.rs167
-rw-r--r--rust/kernel/workqueue.rs342
-rw-r--r--rust/kernel/xarray.rs9
-rw-r--r--rust/macros/module.rs6
-rw-r--r--rust/pin-init/README.md2
-rw-r--r--rust/pin-init/examples/big_struct_in_place.rs28
-rw-r--r--rust/pin-init/examples/linked_list.rs10
-rw-r--r--rust/pin-init/examples/mutex.rs97
-rw-r--r--rust/pin-init/examples/pthread_mutex.rs4
-rw-r--r--rust/pin-init/examples/static_init.rs75
-rw-r--r--rust/pin-init/src/__internal.rs1
-rw-r--r--rust/pin-init/src/lib.rs120
-rw-r--r--rust/pin-init/src/macros.rs16
-rw-r--r--rust/uapi/lib.rs3
-rw-r--r--samples/Kconfig9
-rw-r--r--samples/hung_task/hung_task_tests.c81
-rw-r--r--samples/rust/rust_configfs.rs2
-rw-r--r--samples/rust/rust_driver_auxiliary.rs2
-rw-r--r--samples/rust/rust_misc_device.rs2
-rw-r--r--samples/rust/rust_print_main.rs2
-rw-r--r--scripts/Makefile.build5
-rwxr-xr-xscripts/checkpatch.pl33
-rw-r--r--scripts/coccinelle/misc/secs_to_jiffies.cocci49
-rw-r--r--scripts/gdb/linux/constants.py.in12
-rw-r--r--scripts/rustdoc_test_gen.rs33
-rw-r--r--scripts/spelling.txt1
-rw-r--r--tools/accounting/Makefile2
-rw-r--r--tools/accounting/delaytop.c862
-rw-r--r--tools/accounting/getdelays.c167
-rw-r--r--tools/testing/selftests/bpf/progs/bpf_misc.h3
-rw-r--r--tools/testing/selftests/kho/arm64.conf9
-rw-r--r--tools/testing/selftests/kho/init.c100
-rwxr-xr-xtools/testing/selftests/kho/vmtest.sh183
-rw-r--r--tools/testing/selftests/kho/x86.conf7
-rw-r--r--tools/testing/selftests/ptrace/.gitignore1
-rw-r--r--tools/testing/selftests/thermal/intel/workload_hint/workload_hint_test.c16
371 files changed, 16989 insertions, 2887 deletions
diff --git a/.mailmap b/.mailmap
index 729eb5db4e05..d9fa1b555116 100644
--- a/.mailmap
+++ b/.mailmap
@@ -673,6 +673,7 @@ Muchun Song <muchun.song@linux.dev> <smuchun@gmail.com>
Ross Zwisler <zwisler@kernel.org> <ross.zwisler@linux.intel.com>
Rudolf Marek <R.Marek@sh.cvut.cz>
Rui Saraiva <rmps@joel.ist.utl.pt>
+Sachin Mokashi <sachin.mokashi@intel.com> <sachinx.mokashi@intel.com>
Sachin P Sant <ssant@in.ibm.com>
Sai Prakash Ranjan <quic_saipraka@quicinc.com> <saiprakash.ranjan@codeaurora.org>
Sakari Ailus <sakari.ailus@linux.intel.com> <sakari.ailus@iki.fi>
diff --git a/Documentation/accounting/delay-accounting.rst b/Documentation/accounting/delay-accounting.rst
index 210c194d4a7b..8ccc5af5ea1e 100644
--- a/Documentation/accounting/delay-accounting.rst
+++ b/Documentation/accounting/delay-accounting.rst
@@ -131,3 +131,59 @@ Get IO accounting for pid 1, it works only with -p::
linuxrc: read=65536, write=0, cancelled_write=0
The above command can be used with -v to get more debug information.
+
+After the system starts, use `delaytop` to get the system-wide delay information,
+which includes system-wide PSI information and Top-N high-latency tasks.
+
+`delaytop` supports sorting by CPU latency in descending order by default,
+displays the top 20 high-latency tasks by default, and refreshes the latency
+data every 2 seconds by default.
+
+Get PSI information and Top-N tasks delay, since system boot::
+
+ bash# ./delaytop
+ System Pressure Information: (avg10/avg60/avg300/total)
+ CPU some: 0.0%/ 0.0%/ 0.0%/ 345(ms)
+ CPU full: 0.0%/ 0.0%/ 0.0%/ 0(ms)
+ Memory full: 0.0%/ 0.0%/ 0.0%/ 0(ms)
+ Memory some: 0.0%/ 0.0%/ 0.0%/ 0(ms)
+ IO full: 0.0%/ 0.0%/ 0.0%/ 65(ms)
+ IO some: 0.0%/ 0.0%/ 0.0%/ 79(ms)
+ IRQ full: 0.0%/ 0.0%/ 0.0%/ 0(ms)
+ Top 20 processes (sorted by CPU delay):
+ PID TGID COMMAND CPU(ms) IO(ms) SWAP(ms) RCL(ms) THR(ms) CMP(ms) WP(ms) IRQ(ms)
+ ----------------------------------------------------------------------------------------------
+ 161 161 zombie_memcg_re 1.40 0.00 0.00 0.00 0.00 0.00 0.00 0.00
+ 130 130 blkcg_punt_bio 1.37 0.00 0.00 0.00 0.00 0.00 0.00 0.00
+ 444 444 scsi_tmf_0 0.73 0.00 0.00 0.00 0.00 0.00 0.00 0.00
+ 1280 1280 rsyslogd 0.53 0.04 0.00 0.00 0.00 0.00 0.00 0.00
+ 12 12 ksoftirqd/0 0.47 0.00 0.00 0.00 0.00 0.00 0.00 0.00
+ 1277 1277 nbd-server 0.44 0.00 0.00 0.00 0.00 0.00 0.00 0.00
+ 308 308 kworker/2:2-sys 0.41 0.00 0.00 0.00 0.00 0.00 0.00 0.00
+ 55 55 netns 0.36 0.00 0.00 0.00 0.00 0.00 0.00 0.00
+ 1187 1187 acpid 0.31 0.03 0.00 0.00 0.00 0.00 0.00 0.00
+ 6184 6184 kworker/1:2-sys 0.24 0.00 0.00 0.00 0.00 0.00 0.00 0.00
+ 186 186 kaluad 0.24 0.00 0.00 0.00 0.00 0.00 0.00 0.00
+ 18 18 ksoftirqd/1 0.24 0.00 0.00 0.00 0.00 0.00 0.00 0.00
+ 185 185 kmpath_rdacd 0.23 0.00 0.00 0.00 0.00 0.00 0.00 0.00
+ 190 190 kstrp 0.23 0.00 0.00 0.00 0.00 0.00 0.00 0.00
+ 2759 2759 agetty 0.20 0.03 0.00 0.00 0.00 0.00 0.00 0.00
+ 1190 1190 kworker/0:3-sys 0.19 0.00 0.00 0.00 0.00 0.00 0.00 0.00
+ 1272 1272 sshd 0.15 0.04 0.00 0.00 0.00 0.00 0.00 0.00
+ 1156 1156 license 0.15 0.11 0.00 0.00 0.00 0.00 0.00 0.00
+ 134 134 md 0.13 0.00 0.00 0.00 0.00 0.00 0.00 0.00
+ 6142 6142 kworker/3:2-xfs 0.13 0.00 0.00 0.00 0.00 0.00 0.00 0.00
+
+Dynamic interactive interface of delaytop::
+
+ # ./delaytop -p pid
+ Print delayacct stats
+
+ # ./delaytop -P num
+ Display the top N tasks
+
+ # ./delaytop -n num
+ Set delaytop refresh frequency (num times)
+
+ # ./delaytop -d secs
+ Specify refresh interval as secs
diff --git a/Documentation/admin-guide/kdump/kdump.rst b/Documentation/admin-guide/kdump/kdump.rst
index 20fabdf6567e..9c6cd52f69cf 100644
--- a/Documentation/admin-guide/kdump/kdump.rst
+++ b/Documentation/admin-guide/kdump/kdump.rst
@@ -311,6 +311,27 @@ crashkernel syntax
crashkernel=0,low
+4) crashkernel=size,cma
+
+ Reserve additional crash kernel memory from CMA. This reservation is
+ usable by the first system's userspace memory and kernel movable
+ allocations (memory balloon, zswap). Pages allocated from this memory
+ range will not be included in the vmcore so this should not be used if
+ dumping of userspace memory is intended and it has to be expected that
+ some movable kernel pages may be missing from the dump.
+
+ A standard crashkernel reservation, as described above, is still needed
+ to hold the crash kernel and initrd.
+
+ This option increases the risk of a kdump failure: DMA transfers
+ configured by the first kernel may end up corrupting the second
+ kernel's memory.
+
+ This reservation method is intended for systems that can't afford to
+ sacrifice enough memory for standard crashkernel reservation and where
+ less reliable and possibly incomplete kdump is preferable to no kdump at
+ all.
+
Boot into System Kernel
-----------------------
1) Update the boot loader (such as grub, yaboot, or lilo) configuration
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 8981ae1c9355..c1a5cd991f2e 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -994,6 +994,28 @@
0: to disable low allocation.
It will be ignored when crashkernel=X,high is not used
or memory reserved is below 4G.
+ crashkernel=size[KMG],cma
+ [KNL, X86] Reserve additional crash kernel memory from
+ CMA. This reservation is usable by the first system's
+ userspace memory and kernel movable allocations (memory
+ balloon, zswap). Pages allocated from this memory range
+ will not be included in the vmcore so this should not
+ be used if dumping of userspace memory is intended and
+ it has to be expected that some movable kernel pages
+ may be missing from the dump.
+
+ A standard crashkernel reservation, as described above,
+ is still needed to hold the crash kernel and initrd.
+
+ This option increases the risk of a kdump failure: DMA
+ transfers configured by the first kernel may end up
+ corrupting the second kernel's memory.
+
+ This reservation method is intended for systems that
+ can't afford to sacrifice enough memory for standard
+ crashkernel reservation and where less reliable and
+ possibly incomplete kdump is preferable to no kdump at
+ all.
cryptomgr.notests
[KNL] Disable crypto self-tests
@@ -4557,7 +4579,7 @@
bit 2: print timer info
bit 3: print locks info if CONFIG_LOCKDEP is on
bit 4: print ftrace buffer
- bit 5: print all printk messages in buffer
+ bit 5: replay all messages on consoles at the end of panic
bit 6: print all CPUs backtrace (if available in the arch)
bit 7: print only tasks in uninterruptible (blocked) state
*Be aware* that this option may print a _lot_ of lines,
@@ -4565,6 +4587,25 @@
Use this option carefully, maybe worth to setup a
bigger log buffer with "log_buf_len" along with this.
+ panic_sys_info= A comma separated list of extra information to be dumped
+ on panic.
+ Format: val[,val...]
+ Where @val can be any of the following:
+
+ tasks: print all tasks info
+ mem: print system memory info
+ timers: print timers info
+ locks: print locks info if CONFIG_LOCKDEP is on
+ ftrace: print ftrace buffer
+ all_bt: print all CPUs backtrace (if available in the arch)
+ blocked_tasks: print only tasks in uninterruptible (blocked) state
+
+ This is a human readable alternative to the 'panic_print' option.
+
+ panic_console_replay
+ When panic happens, replay all kernel messages on
+ consoles at the end of panic.
+
parkbd.port= [HW] Parallel port number the keyboard adapter is
connected to, default is 0.
Format: <parport#>
@@ -7032,6 +7073,11 @@
consumed by the stack hash table. By default this is set
to false.
+ stack_depot_max_pools= [KNL,EARLY]
+ Specify the maximum number of pools to use for storing
+ stack traces. Pools are allocated on-demand up to this
+ limit. Default value is 8191 pools.
+
stacktrace [FTRACE]
Enabled the stack tracer on boot up.
diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst
index 3c8faad03d01..8b49eab937d0 100644
--- a/Documentation/admin-guide/sysctl/kernel.rst
+++ b/Documentation/admin-guide/sysctl/kernel.rst
@@ -890,7 +890,7 @@ bit 1 print system memory info
bit 2 print timer info
bit 3 print locks info if ``CONFIG_LOCKDEP`` is on
bit 4 print ftrace buffer
-bit 5 print all printk messages in buffer
+bit 5 replay all messages on consoles at the end of panic
bit 6 print all CPUs backtrace (if available in the arch)
bit 7 print only tasks in uninterruptible (blocked) state
===== ============================================
@@ -900,6 +900,24 @@ So for example to print tasks and memory info on panic, user can::
echo 3 > /proc/sys/kernel/panic_print
+panic_sys_info
+==============
+
+A comma separated list of extra information to be dumped on panic,
+for example, "tasks,mem,timers,...". It is a human readable alternative
+to 'panic_print'. Possible values are:
+
+============= ===================================================
+tasks print all tasks info
+mem print system memory info
+timer print timers info
+lock print locks info if CONFIG_LOCKDEP is on
+ftrace print ftrace buffer
+all_bt print all CPUs backtrace (if available in the arch)
+blocked_tasks print only tasks in uninterruptible (blocked) state
+============= ===================================================
+
+
panic_on_rcu_stall
==================
diff --git a/Documentation/devicetree/bindings/i3c/renesas,i3c.yaml b/Documentation/devicetree/bindings/i3c/renesas,i3c.yaml
new file mode 100644
index 000000000000..fe2e9633c46f
--- /dev/null
+++ b/Documentation/devicetree/bindings/i3c/renesas,i3c.yaml
@@ -0,0 +1,179 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/i3c/renesas,i3c.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Renesas RZ/G3S and RZ/G3E I3C Bus Interface
+
+maintainers:
+ - Wolfram Sang <wsa+renesas@sang-engineering.com>
+ - Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - renesas,r9a08g045-i3c # RZ/G3S
+ - renesas,r9a09g047-i3c # RZ/G3E
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ items:
+ - description: Non-recoverable internal error interrupt
+ - description: Normal transfer error interrupt
+ - description: Normal transfer abort interrupt
+ - description: Normal response status buffer full interrupt
+ - description: Normal command buffer empty interrupt
+ - description: Normal IBI status buffer full interrupt
+ - description: Normal Rx data buffer full interrupt
+ - description: Normal Tx data buffer empty interrupt
+ - description: Normal receive status buffer full interrupt
+ - description: START condition detection interrupt
+ - description: STOP condition detection interrupt
+ - description: Transmit end interrupt
+ - description: NACK detection interrupt
+ - description: Arbitration lost interrupt
+ - description: Timeout detection interrupt
+ - description: Wake-up condition detection interrupt
+ - description: HDR Exit Pattern detection interrupt
+ minItems: 16
+
+ interrupt-names:
+ items:
+ - const: ierr
+ - const: terr
+ - const: abort
+ - const: resp
+ - const: cmd
+ - const: ibi
+ - const: rx
+ - const: tx
+ - const: rcv
+ - const: st
+ - const: sp
+ - const: tend
+ - const: nack
+ - const: al
+ - const: tmo
+ - const: wu
+ - const: exit
+ minItems: 16
+
+ clocks:
+ items:
+ - description: APB bus clock
+ - description: transfer clock
+ - description: SFRs clock
+ minItems: 2
+
+ clock-names:
+ items:
+ - const: pclk
+ - const: tclk
+ - const: pclkrw
+ minItems: 2
+
+ power-domains:
+ maxItems: 1
+
+ resets:
+ items:
+ - description: Reset signal
+ - description: APB interface reset signal/SCAN reset signal
+
+ reset-names:
+ items:
+ - const: presetn
+ - const: tresetn
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - interrupt-names
+ - clock-names
+ - clocks
+ - power-domains
+ - resets
+ - reset-names
+
+allOf:
+ - $ref: i3c.yaml#
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: renesas,r9a08g045-i3c
+ then:
+ properties:
+ clocks:
+ maxItems: 2
+ clock-names:
+ maxItems: 2
+ interrupts:
+ minItems: 17
+ interrupt-names:
+ minItems: 17
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: renesas,r9a09g047-i3c
+ then:
+ properties:
+ clocks:
+ minItems: 3
+ clock-names:
+ minItems: 3
+ interrupts:
+ maxItems: 16
+ interrupt-names:
+ maxItems: 16
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/r9a08g045-cpg.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ i3c@1005b000 {
+ compatible = "renesas,r9a08g045-i3c";
+ reg = <0x1005b000 0x1000>;
+ clocks = <&cpg CPG_MOD R9A08G045_I3C_PCLK>,
+ <&cpg CPG_MOD R9A08G045_I3C_TCLK>;
+ clock-names = "pclk", "tclk";
+ interrupts = <GIC_SPI 289 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 290 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 293 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 294 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 295 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 296 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 297 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 298 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 299 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 304 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 305 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 307 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 308 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 309 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 310 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 311 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "ierr", "terr", "abort", "resp",
+ "cmd", "ibi", "rx", "tx", "rcv",
+ "st", "sp", "tend", "nack",
+ "al", "tmo", "wu", "exit";
+ resets = <&cpg R9A08G045_I3C_PRESETN>,
+ <&cpg R9A08G045_I3C_TRESETN>;
+ reset-names = "presetn", "tresetn";
+ power-domains = <&cpg>;
+ #address-cells = <3>;
+ #size-cells = <0>;
+ };
+...
diff --git a/Documentation/devicetree/bindings/pinctrl/amlogic,pinctrl-a4.yaml b/Documentation/devicetree/bindings/pinctrl/amlogic,pinctrl-a4.yaml
index a6ef4797e5c5..6ba66c2033b4 100644
--- a/Documentation/devicetree/bindings/pinctrl/amlogic,pinctrl-a4.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/amlogic,pinctrl-a4.yaml
@@ -15,11 +15,18 @@ allOf:
properties:
compatible:
oneOf:
- - const: amlogic,pinctrl-a4
+ - enum:
+ - amlogic,pinctrl-a4
+ - amlogic,pinctrl-s6
+ - amlogic,pinctrl-s7
- items:
- enum:
- amlogic,pinctrl-a5
- const: amlogic,pinctrl-a4
+ - items:
+ - enum:
+ - amlogic,pinctrl-s7d
+ - const: amlogic,pinctrl-s7
"#address-cells":
const: 2
diff --git a/Documentation/devicetree/bindings/pinctrl/eswin,eic7700-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/eswin,eic7700-pinctrl.yaml
new file mode 100644
index 000000000000..d46e7ee6372d
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/eswin,eic7700-pinctrl.yaml
@@ -0,0 +1,156 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/eswin,eic7700-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Eswin Eic7700 Pinctrl
+
+maintainers:
+ - Yulin Lu <luyulin@eswincomputing.com>
+
+allOf:
+ - $ref: pinctrl.yaml#
+
+description: |
+ eic7700 pin configuration nodes act as a container for an arbitrary number of
+ subnodes. Each of these subnodes represents some desired configuration for one or
+ more pins. This configuration can include the mux function to select on those pin(s),
+ and various pin configuration parameters, such as input-enable, pull-up, etc.
+
+properties:
+ compatible:
+ const: eswin,eic7700-pinctrl
+
+ reg:
+ maxItems: 1
+
+ vrgmii-supply:
+ description:
+ Regulator supply for the RGMII interface IO power domain.
+ This property should reference a regulator that provides either 1.8V or 3.3V,
+ depending on the board-level voltage configuration required by the RGMII interface.
+
+patternProperties:
+ '-grp$':
+ type: object
+ additionalProperties: false
+
+ patternProperties:
+ '-pins$':
+ type: object
+
+ properties:
+ pins:
+ description:
+ For eic7700, specifies the name(s) of one or more pins to be configured by
+ this node.
+ items:
+ enum: [ chip_mode, mode_set0, mode_set1, mode_set2, mode_set3, xin,
+ rst_out_n, key_reset_n, gpio0, por_sel, jtag0_tck, jtag0_tms,
+ jtag0_tdi, jtag0_tdo, gpio5, spi2_cs0_n, jtag1_tck, jtag1_tms,
+ jtag1_tdi, jtag1_tdo, gpio11, spi2_cs1_n, pcie_clkreq_n,
+ pcie_wake_n, pcie_perst_n, hdmi_scl, hdmi_sda, hdmi_cec,
+ jtag2_trst, rgmii0_clk_125, rgmii0_txen, rgmii0_txclk,
+ rgmii0_txd0, rgmii0_txd1, rgmii0_txd2, rgmii0_txd3, i2s0_bclk,
+ i2s0_wclk, i2s0_sdi, i2s0_sdo, i2s_mclk, rgmii0_rxclk,
+ rgmii0_rxdv, rgmii0_rxd0, rgmii0_rxd1, rgmii0_rxd2, rgmii0_rxd3,
+ i2s2_bclk, i2s2_wclk, i2s2_sdi, i2s2_sdo, gpio27, gpio28, gpio29,
+ rgmii0_mdc, rgmii0_mdio, rgmii0_intb, rgmii1_clk_125, rgmii1_txen,
+ rgmii1_txclk, rgmii1_txd0, rgmii1_txd1, rgmii1_txd2, rgmii1_txd3,
+ i2s1_bclk, i2s1_wclk, i2s1_sdi, i2s1_sdo, gpio34, rgmii1_rxclk,
+ rgmii1_rxdv, rgmii1_rxd0, rgmii1_rxd1, rgmii1_rxd2, rgmii1_rxd3,
+ spi1_cs0_n, spi1_clk, spi1_d0, spi1_d1, spi1_d2, spi1_d3, spi1_cs1_n,
+ rgmii1_mdc, rgmii1_mdio, rgmii1_intb, usb0_pwren, usb1_pwren,
+ i2c0_scl, i2c0_sda, i2c1_scl, i2c1_sda, i2c2_scl, i2c2_sda,
+ i2c3_scl, i2c3_sda, i2c4_scl, i2c4_sda, i2c5_scl, i2c5_sda,
+ uart0_tx, uart0_rx, uart1_tx, uart1_rx, uart1_cts, uart1_rts,
+ uart2_tx, uart2_rx, jtag2_tck, jtag2_tms, jtag2_tdi, jtag2_tdo,
+ fan_pwm, fan_tach, mipi_csi0_xvs, mipi_csi0_xhs, mipi_csi0_mclk,
+ mipi_csi1_xvs, mipi_csi1_xhs, mipi_csi1_mclk, mipi_csi2_xvs,
+ mipi_csi2_xhs, mipi_csi2_mclk, mipi_csi3_xvs, mipi_csi3_xhs,
+ mipi_csi3_mclk, mipi_csi4_xvs, mipi_csi4_xhs, mipi_csi4_mclk,
+ mipi_csi5_xvs, mipi_csi5_xhs, mipi_csi5_mclk, spi3_cs_n, spi3_clk,
+ spi3_di, spi3_do, gpio92, gpio93, s_mode, gpio95, spi0_cs_n,
+ spi0_clk, spi0_d0, spi0_d1, spi0_d2, spi0_d3, i2c10_scl,
+ i2c10_sda, i2c11_scl, i2c11_sda, gpio106, boot_sel0, boot_sel1,
+ boot_sel2, boot_sel3, gpio111, lpddr_ref_clk ]
+
+ function:
+ description:
+ Specify the alternative function to be configured for the
+ given pins.
+ enum: [ disabled, boot_sel, chip_mode, emmc, fan_tach,
+ gpio, hdmi, i2c, i2s, jtag, ddr_ref_clk_sel,
+ lpddr_ref_clk, mipi_csi, osc, pcie, pwm,
+ rgmii, reset, sata, sdio, spi, s_mode, uart, usb ]
+
+ input-schmitt-enable: true
+
+ input-schmitt-disable: true
+
+ bias-disable: true
+
+ bias-pull-down: true
+
+ bias-pull-up: true
+
+ input-enable: true
+
+ input-disable: true
+
+ drive-strength-microamp: true
+
+ required:
+ - pins
+
+ additionalProperties: false
+
+ allOf:
+ - $ref: pincfg-node.yaml#
+ - $ref: pinmux-node.yaml#
+
+ - if:
+ properties:
+ pins:
+ anyOf:
+ - pattern: '^rgmii'
+ - const: lpddr_ref_clk
+ then:
+ properties:
+ drive-strength-microamp:
+ enum: [3000, 6000, 9000, 12000, 15000, 18000, 21000, 24000]
+ else:
+ properties:
+ drive-strength-microamp:
+ enum: [6000, 9000, 12000, 15000, 18000, 21000, 24000, 27000]
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ pinctrl@51600080 {
+ compatible = "eswin,eic7700-pinctrl";
+ reg = <0x51600080 0x1fff80>;
+ vrgmii-supply = <&vcc_1v8>;
+
+ dev-active-grp {
+ /* group node defining 1 standard pin */
+ gpio10-pins {
+ pins = "jtag1_tdo";
+ function = "gpio";
+ input-enable;
+ bias-pull-up;
+ };
+
+ /* group node defining 2 I2C pins */
+ i2c6-pins {
+ pins = "uart1_cts", "uart1_rts";
+ function = "i2c";
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/mediatek,mt8189-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/mediatek,mt8189-pinctrl.yaml
new file mode 100644
index 000000000000..32e4653da5db
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/mediatek,mt8189-pinctrl.yaml
@@ -0,0 +1,213 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/mediatek,mt8189-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek MT8189 Pin Controller
+
+maintainers:
+ - Lei Xue <lei.xue@mediatek.com>
+ - Cathy Xu <ot_cathy.xu@mediatek.com>
+
+description:
+ The MediaTek's MT8189 Pin controller is used to control SoC pins.
+
+properties:
+ compatible:
+ const: mediatek,mt8189-pinctrl
+
+ reg:
+ items:
+ - description: gpio base
+ - description: lm group IO
+ - description: rb0 group IO
+ - description: rb1 group IO
+ - description: bm0 group IO
+ - description: bm1 group IO
+ - description: bm2 group IO
+ - description: lt0 group IO
+ - description: lt1 group IO
+ - description: rt group IO
+ - description: eint0 group IO
+ - description: eint1 group IO
+ - description: eint2 group IO
+ - description: eint3 group IO
+ - description: eint4 group IO
+
+ reg-names:
+ items:
+ - const: base
+ - const: lm
+ - const: rb0
+ - const: rb1
+ - const: bm0
+ - const: bm1
+ - const: bm2
+ - const: lt0
+ - const: lt1
+ - const: rt
+ - const: eint0
+ - const: eint1
+ - const: eint2
+ - const: eint3
+ - const: eint4
+
+ interrupts:
+ maxItems: 1
+
+ interrupt-controller: true
+
+ '#interrupt-cells':
+ const: 2
+
+ gpio-controller: true
+
+ '#gpio-cells':
+ const: 2
+
+ gpio-ranges:
+ maxItems: 1
+
+ gpio-line-names: true
+
+# PIN CONFIGURATION NODES
+patternProperties:
+ '-pins$':
+ type: object
+ additionalProperties: false
+
+ patternProperties:
+ '^pins':
+ type: object
+ $ref: /schemas/pinctrl/pincfg-node.yaml
+ additionalProperties: false
+ description:
+ A pinctrl node should contain at least one subnode representing the
+ pinctrl groups available on the machine. Each subnode will list the
+ pins it needs, and how they should be configured, with regard to muxer
+ configuration, pullups, drive strength, input enable/disable and input
+ schmitt.
+
+ properties:
+ pinmux:
+ description:
+ Integer array, represents gpio pin number and mux setting.
+ Supported pin number and mux varies for different SoCs, and are
+ defined as macros in arch/arm64/boot/dts/mediatek/mt8189-pinfunc.h
+ directly, for this SoC.
+
+ drive-strength:
+ enum: [2, 4, 6, 8, 10, 12, 14, 16]
+
+ bias-pull-down:
+ oneOf:
+ - type: boolean
+ - enum: [100, 101, 102, 103]
+ description: mt8189 pull down PUPD/R0/R1 type define value.
+ - enum: [75000, 5000]
+ description: mt8189 pull down RSEL type si unit value(ohm).
+ description: |
+ For pull down type is normal, it doesn't need add R1R0 define
+ and resistance value.
+
+ For pull down type is PUPD/R0/R1 type, it can add R1R0 define to
+ set different resistance. It can support "MTK_PUPD_SET_R1R0_00" &
+ "MTK_PUPD_SET_R1R0_01" & "MTK_PUPD_SET_R1R0_10" &
+ "MTK_PUPD_SET_R1R0_11" define in mt8189.
+
+ For pull down type is PD/RSEL, it can add resistance value(ohm)
+ to set different resistance by identifying property
+ "mediatek,rsel-resistance-in-si-unit".
+
+ bias-pull-up:
+ oneOf:
+ - type: boolean
+ - enum: [100, 101, 102, 103]
+ description: mt8189 pull up PUPD/R0/R1 type define value.
+ - enum: [1000, 1500, 2000, 3000, 4000, 5000, 75000]
+ description: mt8189 pull up RSEL type si unit value(ohm).
+ description: |
+ For pull up type is normal, it don't need add R1R0 define
+ and resistance value.
+
+ For pull up type is PUPD/R0/R1 type, it can add R1R0 define to
+ set different resistance. It can support "MTK_PUPD_SET_R1R0_00" &
+ "MTK_PUPD_SET_R1R0_01" & "MTK_PUPD_SET_R1R0_10" &
+ "MTK_PUPD_SET_R1R0_11" define in mt8189.
+
+ For pull up type is PU/RSEL, it can add resistance value(ohm)
+ to set different resistance by identifying property
+ "mediatek,rsel-resistance-in-si-unit".
+
+ bias-disable: true
+
+ output-high: true
+
+ output-low: true
+
+ input-enable: true
+
+ input-disable: true
+
+ input-schmitt-enable: true
+
+ input-schmitt-disable: true
+
+ required:
+ - pinmux
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - interrupt-controller
+ - '#interrupt-cells'
+ - gpio-controller
+ - '#gpio-cells'
+ - gpio-ranges
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/pinctrl/mt65xx.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #define PINMUX_GPIO51__FUNC_SCL0 (MTK_PIN_NO(51) | 2)
+ #define PINMUX_GPIO52__FUNC_SDA0 (MTK_PIN_NO(52) | 2)
+
+ pio: pinctrl@10005000 {
+ compatible = "mediatek,mt8189-pinctrl";
+ reg = <0x10005000 0x1000>,
+ <0x11b50000 0x1000>,
+ <0x11c50000 0x1000>,
+ <0x11c60000 0x1000>,
+ <0x11d20000 0x1000>,
+ <0x11d30000 0x1000>,
+ <0x11d40000 0x1000>,
+ <0x11e20000 0x1000>,
+ <0x11e30000 0x1000>,
+ <0x11f20000 0x1000>,
+ <0x11ce0000 0x1000>,
+ <0x11de0000 0x1000>,
+ <0x11e60000 0x1000>,
+ <0x1c01e000 0x1000>,
+ <0x11f00000 0x1000>;
+ reg-names = "base", "lm", "rb0", "rb1", "bm0" , "bm1",
+ "bm2", "lt0", "lt1", "rt", "eint0", "eint1",
+ "eint2", "eint3", "eint4";
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pio 0 0 182>;
+ interrupt-controller;
+ interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH 0>;
+ #interrupt-cells = <2>;
+
+ i2c0-pins {
+ pins {
+ pinmux = <PINMUX_GPIO51__FUNC_SCL0>,
+ <PINMUX_GPIO52__FUNC_SDA0>;
+ bias-disable;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/nxp,lpc1850-scu.txt b/Documentation/devicetree/bindings/pinctrl/nxp,lpc1850-scu.txt
deleted file mode 100644
index bd8b0c69fa44..000000000000
--- a/Documentation/devicetree/bindings/pinctrl/nxp,lpc1850-scu.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-NXP LPC18xx/43xx SCU pin controller Device Tree Bindings
---------------------------------------------------------
-
-Required properties:
-- compatible : Should be "nxp,lpc1850-scu"
-- reg : Address and length of the register set for the device
-- clocks : Clock specifier (see clock bindings for details)
-
-The lpc1850-scu driver uses the generic pin multiplexing and generic pin
-configuration documented in pinctrl-bindings.txt.
-
-The following generic nodes are supported:
- - function
- - pins
- - bias-disable
- - bias-pull-up
- - bias-pull-down
- - drive-strength
- - input-enable
- - input-disable
- - input-schmitt-enable
- - input-schmitt-disable
- - slew-rate
-
-NXP specific properties:
- - nxp,gpio-pin-interrupt : Assign pin to gpio pin interrupt controller
- irq number 0 to 7. See example below.
-
-Not all pins support all properties so either refer to the NXP 1850/4350
-user manual or the pin table in the pinctrl-lpc18xx driver for supported
-pin properties.
-
-Example:
-pinctrl: pinctrl@40086000 {
- compatible = "nxp,lpc1850-scu";
- reg = <0x40086000 0x1000>;
- clocks = <&ccu1 CLK_CPU_SCU>;
-
- i2c0_pins: i2c0-pins {
- i2c0_pins_cfg {
- pins = "i2c0_scl", "i2c0_sda";
- function = "i2c0";
- input-enable;
- };
- };
-
- uart0_pins: uart0-pins {
- uart0_rx_cfg {
- pins = "pf_11";
- function = "uart0";
- bias-disable;
- input-enable;
- };
-
- uart0_tx_cfg {
- pins = "pf_10";
- function = "uart0";
- bias-disable;
- };
- };
-
- gpio_joystick_pins: gpio-joystick-pins {
- gpio_joystick_1_cfg {
- pins = "p9_0";
- function = "gpio";
- nxp,gpio-pin-interrupt = <0>;
- input-enable;
- bias-disable;
- };
- };
-};
diff --git a/Documentation/devicetree/bindings/pinctrl/nxp,lpc1850-scu.yaml b/Documentation/devicetree/bindings/pinctrl/nxp,lpc1850-scu.yaml
new file mode 100644
index 000000000000..11f41359b5c8
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/nxp,lpc1850-scu.yaml
@@ -0,0 +1,79 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/nxp,lpc1850-scu.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP LPC18xx/43xx SCU pin controller
+
+description:
+ Not all pins support all pin generic node properties so either refer to
+ the NXP 1850/4350 user manual or the pin table in the pinctrl-lpc18xx
+ driver for supported pin properties.
+
+maintainers:
+ - Frank Li <Frank.Li@nxp.com>
+
+properties:
+ compatible:
+ const: nxp,lpc1850-scu
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+patternProperties:
+ '-pins$':
+ type: object
+ additionalProperties: false
+
+ patternProperties:
+ '_cfg$':
+ type: object
+
+ allOf:
+ - $ref: pincfg-node.yaml#
+ - $ref: pinmux-node.yaml#
+
+ unevaluatedProperties: false
+
+ properties:
+ nxp,gpio-pin-interrupt:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 7
+ description:
+ Assign pin to gpio pin interrupt controller
+ irq number 0 to 7. See example below.
+
+required:
+ - compatible
+ - reg
+ - clocks
+
+allOf:
+ - $ref: pinctrl.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/lpc18xx-ccu.h>
+
+ pinctrl@40086000 {
+ compatible = "nxp,lpc1850-scu";
+ reg = <0x40086000 0x1000>;
+ clocks = <&ccu1 CLK_CPU_SCU>;
+
+ gpio-joystick-pins {
+ gpio-joystick-1_cfg {
+ pins = "p9_0";
+ function = "gpio";
+ nxp,gpio-pin-interrupt = <0>;
+ input-enable;
+ bias-disable;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,milos-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,milos-tlmm.yaml
new file mode 100644
index 000000000000..0091204df20a
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,milos-tlmm.yaml
@@ -0,0 +1,133 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/qcom,milos-tlmm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Technologies, Inc. Milos TLMM block
+
+maintainers:
+ - Luca Weiss <luca.weiss@fairphone.com>
+
+description:
+ Top Level Mode Multiplexer pin controller in Qualcomm Milos SoC.
+
+allOf:
+ - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml#
+
+properties:
+ compatible:
+ const: qcom,milos-tlmm
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ gpio-reserved-ranges:
+ minItems: 1
+ maxItems: 84
+
+ gpio-line-names:
+ maxItems: 167
+
+patternProperties:
+ "-state$":
+ oneOf:
+ - $ref: "#/$defs/qcom-milos-tlmm-state"
+ - patternProperties:
+ "-pins$":
+ $ref: "#/$defs/qcom-milos-tlmm-state"
+ additionalProperties: false
+
+$defs:
+ qcom-milos-tlmm-state:
+ type: object
+ description:
+ Pinctrl node's client devices use subnodes for desired pin configuration.
+ Client device subnodes use below standard properties.
+ $ref: qcom,tlmm-common.yaml#/$defs/qcom-tlmm-state
+ unevaluatedProperties: false
+
+ properties:
+ pins:
+ description:
+ List of gpio pins affected by the properties specified in this
+ subnode.
+ items:
+ oneOf:
+ - pattern: "^gpio([0-9]|[1-9][0-9]|1[0-5][0-9]|16[0-7])$"
+ - enum: [ ufs_reset, sdc2_clk, sdc2_cmd, sdc2_data ]
+ minItems: 1
+ maxItems: 36
+
+ function:
+ description:
+ Specify the alternative function to be configured for the specified
+ pins.
+ enum: [ gpio, aoss_cti, atest_char, atest_usb, audio_ext_mclk0,
+ audio_ext_mclk1, audio_ref_clk, cam_mclk, cci_async_in0,
+ cci_i2c_scl, cci_i2c_sda, cci_timer, coex_uart1_rx,
+ coex_uart1_tx, dbg_out_clk, ddr_bist_complete, ddr_bist_fail,
+ ddr_bist_start, ddr_bist_stop, ddr_pxi0, ddr_pxi1, dp0_hot,
+ egpio, gcc_gp1, gcc_gp2, gcc_gp3, host2wlan_sol, i2s0_data0,
+ i2s0_data1, i2s0_sck, i2s0_ws, ibi_i3c, jitter_bist, mdp_vsync,
+ mdp_vsync0_out, mdp_vsync1_out, mdp_vsync2_out, mdp_vsync3_out,
+ mdp_vsync_e, nav_gpio0, nav_gpio1, nav_gpio2, pcie0_clk_req_n,
+ pcie1_clk_req_n, phase_flag, pll_bist_sync, pll_clk_aux,
+ prng_rosc0, prng_rosc1, prng_rosc2, prng_rosc3, qdss_cti,
+ qdss_gpio, qlink0_enable, qlink0_request, qlink0_wmss,
+ qlink1_enable, qlink1_request, qlink1_wmss, qspi0, qup0_se0,
+ qup0_se1, qup0_se2, qup0_se3, qup0_se4, qup0_se5, qup0_se6,
+ qup1_se0, qup1_se1, qup1_se2, qup1_se3, qup1_se4, qup1_se5,
+ qup1_se6, resout_gpio_n, sd_write_protect, sdc1_clk, sdc1_cmd,
+ sdc1_data, sdc1_rclk, sdc2_clk, sdc2_cmd, sdc2_data,
+ sdc2_fb_clk, tb_trig_sdc1, tb_trig_sdc2, tgu_ch0_trigout,
+ tgu_ch1_trigout, tmess_prng0, tmess_prng1, tmess_prng2,
+ tmess_prng3, tsense_pwm1, tsense_pwm2, uim0_clk, uim0_data,
+ uim0_present, uim0_reset, uim1_clk_mira, uim1_clk_mirb,
+ uim1_data_mira, uim1_data_mirb, uim1_present_mira,
+ uim1_present_mirb, uim1_reset_mira, uim1_reset_mirb, usb0_hs,
+ usb0_phy_ps, vfr_0, vfr_1, vsense_trigger_mirnat, wcn_sw,
+ wcn_sw_ctrl ]
+
+ required:
+ - pins
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ tlmm: pinctrl@f100000 {
+ compatible = "qcom,milos-tlmm";
+ reg = <0x0f100000 0x300000>;
+
+ interrupts = <GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ gpio-ranges = <&tlmm 0 0 168>;
+
+ gpio-wo-state {
+ pins = "gpio1";
+ function = "gpio";
+ };
+
+ qup-uart5-default-state {
+ pins = "gpio25", "gpio26";
+ function = "qup0_se5";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml
index 055cea5452eb..5e6dfcc3fe9b 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.yaml
@@ -27,6 +27,7 @@ properties:
- qcom,pm6450-gpio
- qcom,pm7250b-gpio
- qcom,pm7325-gpio
+ - qcom,pm7550-gpio
- qcom,pm7550ba-gpio
- qcom,pm8005-gpio
- qcom,pm8018-gpio
@@ -64,6 +65,7 @@ properties:
- qcom,pmi8994-gpio
- qcom,pmi8998-gpio
- qcom,pmih0108-gpio
+ - qcom,pmiv0104-gpio
- qcom,pmk8350-gpio
- qcom,pmk8550-gpio
- qcom,pmm8155au-gpio
@@ -228,6 +230,7 @@ allOf:
- qcom,pmc8180-gpio
- qcom,pmc8380-gpio
- qcom,pmi8994-gpio
+ - qcom,pmiv0104-gpio
- qcom,pmm8155au-gpio
then:
properties:
@@ -261,6 +264,7 @@ allOf:
- qcom,pm660l-gpio
- qcom,pm6150l-gpio
- qcom,pm7250b-gpio
+ - qcom,pm7550-gpio
- qcom,pm8038-gpio
- qcom,pm8150b-gpio
- qcom,pm8150l-gpio
diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
index 960758dc417f..125af766b992 100644
--- a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.yaml
@@ -135,7 +135,7 @@ additionalProperties:
description:
Pin bank index.
- minimum: 0
- maximum: 13
+ maximum: 14
description:
Mux 0 means GPIO and mux 1 to N means
the specific device function.
diff --git a/Documentation/devicetree/bindings/pinctrl/st,stm32-hdp.yaml b/Documentation/devicetree/bindings/pinctrl/st,stm32-hdp.yaml
new file mode 100644
index 000000000000..845b6b7b7552
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/st,stm32-hdp.yaml
@@ -0,0 +1,187 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) STMicroelectronics 2025.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/st,stm32-hdp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STM32 Hardware Debug Port Mux/Config
+
+maintainers:
+ - Clément LE GOFFIC <legoffic.clement@gmail.com>
+
+description:
+ STMicroelectronics's STM32 MPUs integrate a Hardware Debug Port (HDP).
+ It allows to output internal signals on SoC's GPIO.
+
+properties:
+ compatible:
+ enum:
+ - st,stm32mp131-hdp
+ - st,stm32mp151-hdp
+ - st,stm32mp251-hdp
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+patternProperties:
+ "^hdp[0-7]-pins$":
+ type: object
+ $ref: pinmux-node.yaml#
+ additionalProperties: false
+
+ properties:
+ pins:
+ pattern: '^HDP[0-7]$'
+
+ function: true
+
+ required:
+ - function
+ - pins
+
+allOf:
+ - $ref: pinctrl.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: st,stm32mp131-hdp
+ then:
+ patternProperties:
+ "^hdp[0-7]-pins$":
+ properties:
+ function:
+ enum: [ pwr_pwrwake_sys, pwr_stop_forbidden, pwr_stdby_wakeup, pwr_encomp_vddcore,
+ bsec_out_sec_niden, aiec_sys_wakeup, none, ddrctrl_lp_req,
+ pwr_ddr_ret_enable_n, dts_clk_ptat, sram3ctrl_tamp_erase_act, gpoval0,
+ pwr_sel_vth_vddcpu, pwr_mpu_ram_lowspeed, ca7_naxierrirq, pwr_okin_mr,
+ bsec_out_sec_dbgen, aiec_c1_wakeup, rcc_pwrds_mpu, ddrctrl_dfi_ctrlupd_req,
+ ddrctrl_cactive_ddrc_asr, sram3ctrl_hw_erase_act, nic400_s0_bready, gpoval1,
+ pwr_pwrwake_mpu, pwr_mpu_clock_disable_ack, ca7_ndbgreset_i,
+ bsec_in_rstcore_n, bsec_out_sec_bsc_dis, ddrctrl_dfi_init_complete,
+ ddrctrl_perf_op_is_refresh, ddrctrl_gskp_dfi_lp_req, sram3ctrl_sw_erase_act,
+ nic400_s0_bvalid, gpoval2, pwr_sel_vth_vddcore, pwr_mpu_clock_disable_req,
+ ca7_npmuirq0, ca7_nfiqout0, bsec_out_sec_dftlock, bsec_out_sec_jtag_dis,
+ rcc_pwrds_sys, sram3ctrl_tamp_erase_req, ddrctrl_stat_ddrc_reg_selfref_type0,
+ dts_valobus1_0, dts_valobus2_0, tamp_potential_tamp_erfcfg, nic400_s0_wready,
+ nic400_s0_rready, gpoval3, pwr_stop2_active, ca7_nl2reset_i,
+ ca7_npreset_varm_i, bsec_out_sec_dften, bsec_out_sec_dbgswenable,
+ eth1_out_pmt_intr_o, eth2_out_pmt_intr_o, ddrctrl_stat_ddrc_reg_selfref_type1,
+ ddrctrl_cactive_0, dts_valobus1_1, dts_valobus2_1, tamp_nreset_sram_ercfg,
+ nic400_s0_wlast, nic400_s0_rlast, gpoval4, ca7_standbywfil2,
+ pwr_vth_vddcore_ack, ca7_ncorereset_i, ca7_nirqout0, bsec_in_pwrok,
+ bsec_out_sec_deviceen, eth1_out_lpi_intr_o, eth2_out_lpi_intr_o,
+ ddrctrl_cactive_ddrc, ddrctrl_wr_credit_cnt, dts_valobus1_2, dts_valobus2_2,
+ pka_pka_itamp_out, nic400_s0_wvalid, nic400_s0_rvalid, gpoval5,
+ ca7_standbywfe0, pwr_vth_vddcpu_ack, ca7_evento, bsec_in_tamper_det,
+ bsec_out_sec_spniden, eth1_out_mac_speed_o1, eth2_out_mac_speed_o1,
+ ddrctrl_csysack_ddrc, ddrctrl_lpr_credit_cnt, dts_valobus1_3, dts_valobus2_3,
+ saes_tamper_out, nic400_s0_awready, nic400_s0_arready, gpoval6,
+ ca7_standbywfi0, pwr_rcc_vcpu_rdy, ca7_eventi, ca7_dbgack0, bsec_out_fuse_ok,
+ bsec_out_sec_spiden, eth1_out_mac_speed_o0, eth2_out_mac_speed_o0,
+ ddrctrl_csysreq_ddrc, ddrctrl_hpr_credit_cnt, dts_valobus1_4, dts_valobus2_4,
+ rng_tamper_out, nic400_s0_awavalid, nic400_s0_aravalid, gpoval7 ]
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: st,stm32mp151-hdp
+ then:
+ patternProperties:
+ "^hdp[0-7]-pins$":
+ properties:
+ function:
+ enum: [ pwr_pwrwake_sys, cm4_sleepdeep, pwr_stdby_wkup, pwr_encomp_vddcore,
+ bsec_out_sec_niden, none, rcc_cm4_sleepdeep, gpu_dbg7, ddrctrl_lp_req,
+ pwr_ddr_ret_enable_n, dts_clk_ptat, gpoval0, pwr_pwrwake_mcu, cm4_halted,
+ ca7_naxierrirq, pwr_okin_mr, bsec_out_sec_dbgen, exti_sys_wakeup,
+ rcc_pwrds_mpu, gpu_dbg6, ddrctrl_dfi_ctrlupd_req, ddrctrl_cactive_ddrc_asr,
+ gpoval1, pwr_pwrwake_mpu, cm4_rxev, ca7_npmuirq1, ca7_nfiqout1,
+ bsec_in_rstcore_n, exti_c2_wakeup, rcc_pwrds_mcu, gpu_dbg5,
+ ddrctrl_dfi_init_complete, ddrctrl_perf_op_is_refresh,
+ ddrctrl_gskp_dfi_lp_req, gpoval2, pwr_sel_vth_vddcore, cm4_txev, ca7_npmuirq0,
+ ca7_nfiqout0, bsec_out_sec_dftlock, exti_c1_wakeup, rcc_pwrds_sys, gpu_dbg4,
+ ddrctrl_stat_ddrc_reg_selfref_type0, ddrctrl_cactive_1, dts_valobus1_0,
+ dts_valobus2_0, gpoval3, pwr_mpu_pdds_not_cstbydis, cm4_sleeping, ca7_nreset1,
+ ca7_nirqout1, bsec_out_sec_dften, bsec_out_sec_dbgswenable,
+ eth_out_pmt_intr_o, gpu_dbg3, ddrctrl_stat_ddrc_reg_selfref_type1,
+ ddrctrl_cactive_0, dts_valobus1_1, dts_valobus2_1, gpoval4, ca7_standbywfil2,
+ pwr_vth_vddcore_ack, ca7_nreset0, ca7_nirqout0, bsec_in_pwrok,
+ bsec_out_sec_deviceen, eth_out_lpi_intr_o, gpu_dbg2, ddrctrl_cactive_ddrc,
+ ddrctrl_wr_credit_cnt, dts_valobus1_2, dts_valobus2_2, gpoval5,
+ ca7_standbywfi1, ca7_standbywfe1, ca7_evento, ca7_dbgack1,
+ bsec_out_sec_spniden, eth_out_mac_speed_o1, gpu_dbg1, ddrctrl_csysack_ddrc,
+ ddrctrl_lpr_credit_cnt, dts_valobus1_3, dts_valobus2_3, gpoval6,
+ ca7_standbywfi0, ca7_standbywfe0, ca7_dbgack0, bsec_out_fuse_ok,
+ bsec_out_sec_spiden, eth_out_mac_speed_o0, gpu_dbg0, ddrctrl_csysreq_ddrc,
+ ddrctrl_hpr_credit_cnt, dts_valobus1_4, dts_valobus2_4, gpoval7 ]
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: st,stm32mp251-hdp
+ then:
+ patternProperties:
+ "^hdp[0-7]-pins$":
+ properties:
+ function:
+ enum: [ pwr_pwrwake_sys, cpu2_sleep_deep, bsec_out_tst_sdr_unlock_or_disable_scan,
+ bsec_out_nidenm, bsec_out_nidena, cpu2_state_0, rcc_pwrds_sys, gpu_dbg7,
+ ddrss_csysreq_ddrc, ddrss_dfi_phyupd_req, cpu3_sleep_deep,
+ d2_gbl_per_clk_bus_req, pcie_usb_cxpl_debug_info_ei_0,
+ pcie_usb_cxpl_debug_info_ei_8, d3_state_0, gpoval0, pwr_pwrwake_cpu2,
+ cpu2_halted, cpu2_state_1, bsec_out_dbgenm, bsec_out_dbgena, exti1_sys_wakeup,
+ rcc_pwrds_cpu2, gpu_dbg6, ddrss_csysack_ddrc, ddrss_dfi_phymstr_req,
+ cpu3_halted, d2_gbl_per_dma_req, pcie_usb_cxpl_debug_info_ei_1,
+ pcie_usb_cxpl_debug_info_ei_9, d3_state_1, gpoval1, pwr_pwrwake_cpu1,
+ cpu2_rxev, cpu1_npumirq1, cpu1_nfiqout1, bsec_out_shdbgen, exti1_cpu2_wakeup,
+ rcc_pwrds_cpu1, gpu_dbg5, ddrss_cactive_ddrc, ddrss_dfi_lp_req, cpu3_rxev,
+ hpdma1_clk_bus_req, pcie_usb_cxpl_debug_info_ei_2,
+ pcie_usb_cxpl_debug_info_ei_10, d3_state_2, gpoval2, pwr_sel_vth_vddcpu,
+ cpu2_txev, cpu1_npumirq0, cpu1_nfiqout0, bsec_out_ddbgen, exti1_cpu1_wakeup,
+ cpu3_state_0, gpu_dbg4, ddrss_mcdcg_en, ddrss_dfi_freq_0, cpu3_txev,
+ hpdma2_clk_bus_req, pcie_usb_cxpl_debug_info_ei_3,
+ pcie_usb_cxpl_debug_info_ei_11, d1_state_0, gpoval3, pwr_sel_vth_vddcore,
+ cpu2_sleeping, cpu1_evento, cpu1_nirqout1, bsec_out_spnidena, exti2_d3_wakeup,
+ eth1_out_pmt_intr_o, gpu_dbg3, ddrss_dphycg_en, ddrss_obsp0, cpu3_sleeping,
+ hpdma3_clk_bus_req, pcie_usb_cxpl_debug_info_ei_4,
+ pcie_usb_cxpl_debug_info_ei_12, d1_state_1, gpoval4, cpu1_standby_wfil2,
+ none, cpu1_nirqout0, bsec_out_spidena, exti2_cpu3_wakeup, eth1_out_lpi_intr_o,
+ gpu_dbg2, ddrctrl_dfi_init_start, ddrss_obsp1, cpu3_state_1,
+ d3_gbl_per_clk_bus_req, pcie_usb_cxpl_debug_info_ei_5,
+ pcie_usb_cxpl_debug_info_ei_13, d1_state_2, gpoval5, cpu1_standby_wfi1,
+ cpu1_standby_wfe1, cpu1_halted1, cpu1_naxierrirq, bsec_out_spnidenm,
+ exti2_cpu2_wakeup, eth2_out_pmt_intr_o, gpu_dbg1, ddrss_dfi_init_complete,
+ ddrss_obsp2, d2_state_0, d3_gbl_per_dma_req, pcie_usb_cxpl_debug_info_ei_6,
+ pcie_usb_cxpl_debug_info_ei_14, cpu1_state_0, gpoval6, cpu1_standby_wfi0,
+ cpu1_standby_wfe0, cpu1_halted0, bsec_out_spidenm, exti2_cpu1__wakeup,
+ eth2_out_lpi_intr_o, gpu_dbg0, ddrss_dfi_ctrlupd_req, ddrss_obsp3, d2_state_1,
+ lpdma1_clk_bus_req, pcie_usb_cxpl_debug_info_ei_7,
+ pcie_usb_cxpl_debug_info_ei_15, cpu1_state_1, gpoval7 ]
+
+required:
+ - compatible
+ - reg
+ - clocks
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/stm32mp1-clks.h>
+
+ pinctrl@54090000 {
+ compatible = "st,stm32mp151-hdp";
+ reg = <0x54090000 0x400>;
+ clocks = <&rcc HDP>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdp2_gpo>;
+ hdp2_gpo: hdp2-pins {
+ function = "gpoval2";
+ pins = "HDP2";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml
index a28d77748095..961161c2ab62 100644
--- a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml
@@ -32,13 +32,16 @@ properties:
'#address-cells':
const: 1
+
'#size-cells':
const: 1
ranges: true
+
pins-are-numbered:
$ref: /schemas/types.yaml#/definitions/flag
deprecated: true
+
hwlocks: true
interrupts:
@@ -67,22 +70,29 @@ patternProperties:
additionalProperties: false
properties:
gpio-controller: true
+
'#gpio-cells':
const: 2
+
interrupt-controller: true
'#interrupt-cells':
const: 2
reg:
maxItems: 1
+
clocks:
maxItems: 1
+
resets:
maxItems: 1
+
gpio-line-names: true
+
gpio-ranges:
minItems: 1
maxItems: 16
+
ngpios:
description:
Number of available gpios in a bank.
@@ -160,9 +170,13 @@ patternProperties:
* ...
* 16 : Alternate Function 15
* 17 : Analog
+ * 18 : Reserved
To simplify the usage, macro is available to generate "pinmux" field.
This macro is available here:
- include/dt-bindings/pinctrl/stm32-pinfunc.h
+ Setting the pinmux's function to the Reserved (RSVD) value is used to inform
+ the driver that it shall not apply the mux setting. This can be used to
+ reserve some pins, for example to a co-processor not running Linux.
Some examples of using macro:
/* GPIO A9 set as alternate function 2 */
... {
@@ -176,21 +190,32 @@ patternProperties:
... {
pinmux = <STM32_PINMUX('A', 9, ANALOG)>;
};
+ /* GPIO A9 reserved for co-processor */
+ ... {
+ pinmux = <STM32_PINMUX('A', 9, RSVD)>;
+ };
bias-disable:
type: boolean
+
bias-pull-down:
type: boolean
+
bias-pull-up:
type: boolean
+
drive-push-pull:
type: boolean
+
drive-open-drain:
type: boolean
+
output-low:
type: boolean
+
output-high:
type: boolean
+
slew-rate:
description: |
0: Low speed
diff --git a/Documentation/devicetree/bindings/rtc/amlogic,a4-rtc.yaml b/Documentation/devicetree/bindings/rtc/amlogic,a4-rtc.yaml
index 5d3ac737abcb..e61f22eca85b 100644
--- a/Documentation/devicetree/bindings/rtc/amlogic,a4-rtc.yaml
+++ b/Documentation/devicetree/bindings/rtc/amlogic,a4-rtc.yaml
@@ -16,9 +16,14 @@ allOf:
properties:
compatible:
- enum:
- - amlogic,a4-rtc
- - amlogic,a5-rtc
+ oneOf:
+ - enum:
+ - amlogic,a4-rtc
+ - amlogic,a5-rtc
+ - items:
+ - enum:
+ - amlogic,c3-rtc
+ - const: amlogic,a5-rtc
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.yaml b/Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.yaml
index e88b847a1cc5..e896ba59302a 100644
--- a/Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.yaml
+++ b/Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.yaml
@@ -18,7 +18,12 @@ allOf:
properties:
compatible:
- const: nxp,lpc1788-rtc
+ oneOf:
+ - items:
+ - enum:
+ - nxp,lpc1850-rtc
+ - const: nxp,lpc1788-rtc
+ - const: nxp,lpc1788-rtc
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/rtc/nxp,lpc3220-rtc.yaml b/Documentation/devicetree/bindings/rtc/nxp,lpc3220-rtc.yaml
new file mode 100644
index 000000000000..53353de4cb37
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/nxp,lpc3220-rtc.yaml
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/nxp,lpc3220-rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP LPC32xx SoC Real-time Clock
+
+maintainers:
+ - Frank Li <Frank.Li@nxp.com>
+
+properties:
+ compatible:
+ enum:
+ - nxp,lpc3220-rtc
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ start-year: true
+
+required:
+ - compatible
+ - reg
+
+allOf:
+ - $ref: rtc.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/clock/lpc32xx-clock.h>
+
+ rtc@40024000 {
+ compatible = "nxp,lpc3220-rtc";
+ reg = <0x40024000 0x1000>;
+ interrupt-parent = <&sic1>;
+ interrupts = <20 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk LPC32XX_CLK_RTC>;
+ };
+
diff --git a/Documentation/devicetree/bindings/rtc/nxp,pcf85063.yaml b/Documentation/devicetree/bindings/rtc/nxp,pcf85063.yaml
index 2f892f8640d1..1e6277e524c2 100644
--- a/Documentation/devicetree/bindings/rtc/nxp,pcf85063.yaml
+++ b/Documentation/devicetree/bindings/rtc/nxp,pcf85063.yaml
@@ -12,6 +12,7 @@ maintainers:
properties:
compatible:
enum:
+ - microcrystal,rv8063
- microcrystal,rv8263
- nxp,pcf85063
- nxp,pcf85063a
@@ -44,13 +45,19 @@ properties:
wakeup-source: true
+ spi-cs-high: true
+
+ spi-3wire: true
+
allOf:
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
- $ref: rtc.yaml#
- if:
properties:
compatible:
contains:
enum:
+ - microcrystal,rv8063
- microcrystal,rv8263
then:
properties:
@@ -65,12 +72,23 @@ allOf:
properties:
quartz-load-femtofarads:
const: 7000
+ - if:
+ properties:
+ compatible:
+ not:
+ contains:
+ enum:
+ - microcrystal,rv8063
+ then:
+ properties:
+ spi-cs-high: false
+ spi-3wire: false
required:
- compatible
- reg
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
@@ -90,3 +108,16 @@ examples:
};
};
};
+
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rtc@0 {
+ compatible = "microcrystal,rv8063";
+ reg = <0>;
+ spi-cs-high;
+ spi-3wire;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/soc/sophgo/sophgo,cv1800b-rtc.yaml b/Documentation/devicetree/bindings/rtc/sophgo,cv1800b-rtc.yaml
index 5cf186c396c9..c695d2ff9fcc 100644
--- a/Documentation/devicetree/bindings/soc/sophgo/sophgo,cv1800b-rtc.yaml
+++ b/Documentation/devicetree/bindings/rtc/sophgo,cv1800b-rtc.yaml
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
-$id: http://devicetree.org/schemas/sophgo/sophgo,cv1800b-rtc.yaml#
+$id: http://devicetree.org/schemas/rtc/sophgo,cv1800b-rtc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Real Time Clock of the Sophgo CV1800 SoC
diff --git a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml
index 7330a7200831..5e0c7cd25cc6 100644
--- a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml
+++ b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml
@@ -63,8 +63,6 @@ properties:
- microcrystal,rv3029
# Real Time Clock
- microcrystal,rv8523
- # NXP LPC32xx SoC Real-time Clock
- - nxp,lpc3220-rtc
# I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
- ricoh,r2025sd
# I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
diff --git a/MAINTAINERS b/MAINTAINERS
index d780a6fcd163..1b57dd4fcf01 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6713,7 +6713,7 @@ S: Supported
F: drivers/input/keyboard/dlink-dir685-touchkeys.c
DALLAS/MAXIM DS1685-FAMILY REAL TIME CLOCK
-M: Joshua Kinard <kumba@gentoo.org>
+M: Joshua Kinard <linux@kumba.dev>
S: Maintained
F: drivers/rtc/rtc-ds1685.c
F: include/linux/rtc/ds1685.h
@@ -11612,6 +11612,13 @@ S: Maintained
F: Documentation/devicetree/bindings/i3c/cdns,i3c-master.yaml
F: drivers/i3c/master/i3c-master-cdns.c
+I3C DRIVER FOR RENESAS
+M: Wolfram Sang <wsa+renesas@sang-engineering.com>
+M: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
+S: Supported
+F: Documentation/devicetree/bindings/i3c/renesas,i3c.yaml
+F: drivers/i3c/master/renesas-i3c.c
+
I3C DRIVER FOR SYNOPSYS DESIGNWARE
S: Orphan
F: Documentation/devicetree/bindings/i3c/snps,dw-i3c-master.yaml
@@ -11622,6 +11629,7 @@ M: Alexandre Belloni <alexandre.belloni@bootlin.com>
R: Frank Li <Frank.Li@nxp.com>
L: linux-i3c@lists.infradead.org (moderated for non-subscribers)
S: Maintained
+Q: https://patchwork.kernel.org/project/linux-i3c/list/
C: irc://chat.freenode.net/linux-i3c
T: git git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux.git
F: Documentation/ABI/testing/sysfs-bus-i3c
@@ -13536,6 +13544,7 @@ F: Documentation/admin-guide/mm/kho.rst
F: Documentation/core-api/kho/*
F: include/linux/kexec_handover.h
F: kernel/kexec_handover.c
+F: tools/testing/selftests/kho/
KEYS-ENCRYPTED
M: Mimi Zohar <zohar@linux.ibm.com>
@@ -19733,6 +19742,16 @@ S: Maintained
F: include/linux/delayacct.h
F: kernel/delayacct.c
+TASK DELAY MONITORING TOOLS
+M: Andrew Morton <akpm@linux-foundation.org>
+M: Wang Yaxin <wang.yaxin@zte.com.cn>
+M: Fan Yu <fan.yu9@zte.com.cn>
+L: linux-kernel@vger.kernel.org
+S: Maintained
+F: Documentation/accounting/delay-accounting.rst
+F: tools/accounting/delaytop.c
+F: tools/accounting/getdelays.c
+
PERFORMANCE EVENTS SUBSYSTEM
M: Peter Zijlstra <peterz@infradead.org>
M: Ingo Molnar <mingo@redhat.com>
@@ -22032,6 +22051,10 @@ K: \b(?i:rust)\b
RUST [ALLOC]
M: Danilo Krummrich <dakr@kernel.org>
+R: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
+R: Vlastimil Babka <vbabka@suse.cz>
+R: Liam R. Howlett <Liam.Howlett@oracle.com>
+R: Uladzislau Rezki <urezki@gmail.com>
L: rust-for-linux@vger.kernel.org
S: Maintained
T: git https://github.com/Rust-for-Linux/linux.git alloc-next
@@ -23370,6 +23393,7 @@ F: drivers/md/md*
F: drivers/md/raid*
F: include/linux/raid/
F: include/uapi/linux/raid/
+F: lib/raid6/
SOLIDRUN CLEARFOG SUPPORT
M: Russell King <linux@armlinux.org.uk>
@@ -23814,6 +23838,12 @@ F: drivers/bus/stm32_etzpc.c
F: drivers/bus/stm32_firewall.c
F: drivers/bus/stm32_rifsc.c
+ST STM32 HDP PINCTRL DRIVER
+M: Clément Le Goffic <legoffic.clement@gmail.com>
+S: Maintained
+F: Documentation/devicetree/bindings/pinctrl/st,stm32-hdp.yaml
+F: drivers/pinctrl/stm32/pinctrl-stm32-hdp.c
+
ST STM32 I2C/SMBUS DRIVER
M: Pierre-Yves MORDRET <pierre-yves.mordret@foss.st.com>
M: Alain Volmat <alain.volmat@foss.st.com>
@@ -23827,6 +23857,14 @@ S: Maintained
F: Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml
F: drivers/memory/stm32_omm.c
+ST STM32 PINCTRL DRIVER
+M: Antonio Borneo <antonio.borneo@foss.st.com>
+S: Maintained
+F: Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml
+F: drivers/pinctrl/stm32/
+F: include/dt-bindings/pinctrl/stm32-pinfunc.h
+X: drivers/pinctrl/stm32/pinctrl-stm32-hdp.c
+
ST STM32 SPI DRIVER
M: Alain Volmat <alain.volmat@foss.st.com>
L: linux-spi@vger.kernel.org
diff --git a/Makefile b/Makefile
index 076de54b3311..98ab3435fc8d 100644
--- a/Makefile
+++ b/Makefile
@@ -479,11 +479,17 @@ export rust_common_flags := --edition=2021 \
-Wrust_2018_idioms \
-Wunreachable_pub \
-Wclippy::all \
+ -Wclippy::as_ptr_cast_mut \
+ -Wclippy::as_underscore \
+ -Wclippy::cast_lossless \
-Wclippy::ignored_unit_patterns \
-Wclippy::mut_mut \
-Wclippy::needless_bitwise_bool \
-Aclippy::needless_lifetimes \
-Wclippy::no_mangle_with_rust_abi \
+ -Wclippy::ptr_as_ptr \
+ -Wclippy::ptr_cast_constness \
+ -Wclippy::ref_as_ptr \
-Wclippy::undocumented_unsafe_blocks \
-Wclippy::unnecessary_safety_comment \
-Wclippy::unnecessary_safety_doc \
diff --git a/arch/alpha/kernel/core_marvel.c b/arch/alpha/kernel/core_marvel.c
index b1bfbd11980d..d38f4d6759e4 100644
--- a/arch/alpha/kernel/core_marvel.c
+++ b/arch/alpha/kernel/core_marvel.c
@@ -17,6 +17,7 @@
#include <linux/vmalloc.h>
#include <linux/mc146818rtc.h>
#include <linux/rtc.h>
+#include <linux/string.h>
#include <linux/module.h>
#include <linux/memblock.h>
@@ -79,10 +80,12 @@ mk_resource_name(int pe, int port, char *str)
{
char tmp[80];
char *name;
-
- sprintf(tmp, "PCI %s PE %d PORT %d", str, pe, port);
- name = memblock_alloc_or_panic(strlen(tmp) + 1, SMP_CACHE_BYTES);
- strcpy(name, tmp);
+ size_t sz;
+
+ sz = scnprintf(tmp, sizeof(tmp), "PCI %s PE %d PORT %d", str, pe, port);
+ sz += 1; /* NUL terminator */
+ name = memblock_alloc_or_panic(sz, SMP_CACHE_BYTES);
+ strscpy(name, tmp, sz);
return name;
}
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index a41c93988d2c..0bfd66c7ada0 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -1004,7 +1004,7 @@ static void __init reserve_crashkernel(void)
total_mem = get_total_mem();
ret = parse_crashkernel(boot_command_line, total_mem,
&crash_size, &crash_base,
- NULL, NULL);
+ NULL, NULL, NULL);
/* invalid value specified or crashkernel=0 */
if (ret || !crash_size)
return;
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 90d6b028fbbb..a88f5ad9328c 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -333,7 +333,6 @@ config ARCH_STM32
bool "STMicroelectronics STM32 SoC Family"
select GPIOLIB
select PINCTRL
- select PINCTRL_STM32MP257
select ARM_SMC_MBOX
select ARM_SCMI_PROTOCOL
select REGULATOR
diff --git a/arch/arm64/include/asm/asm-bug.h b/arch/arm64/include/asm/asm-bug.h
index 6e73809f6492..a5f13801b784 100644
--- a/arch/arm64/include/asm/asm-bug.h
+++ b/arch/arm64/include/asm/asm-bug.h
@@ -21,16 +21,21 @@
#endif
#ifdef CONFIG_GENERIC_BUG
-
-#define __BUG_ENTRY(flags) \
+#define __BUG_ENTRY_START \
.pushsection __bug_table,"aw"; \
.align 2; \
14470: .long 14471f - .; \
-_BUGVERBOSE_LOCATION(__FILE__, __LINE__) \
- .short flags; \
+
+#define __BUG_ENTRY_END \
.align 2; \
.popsection; \
14471:
+
+#define __BUG_ENTRY(flags) \
+ __BUG_ENTRY_START \
+_BUGVERBOSE_LOCATION(__FILE__, __LINE__) \
+ .short flags; \
+ __BUG_ENTRY_END
#else
#define __BUG_ENTRY(flags)
#endif
@@ -41,4 +46,24 @@ _BUGVERBOSE_LOCATION(__FILE__, __LINE__) \
#define ASM_BUG() ASM_BUG_FLAGS(0)
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+#define __BUG_LOCATION_STRING(file, line) \
+ ".long " file "- .;" \
+ ".short " line ";"
+#else
+#define __BUG_LOCATION_STRING(file, line)
+#endif
+
+#define __BUG_ENTRY_STRING(file, line, flags) \
+ __stringify(__BUG_ENTRY_START) \
+ __BUG_LOCATION_STRING(file, line) \
+ ".short " flags ";" \
+ __stringify(__BUG_ENTRY_END)
+
+#define ARCH_WARN_ASM(file, line, flags, size) \
+ __BUG_ENTRY_STRING(file, line, flags) \
+ __stringify(brk BUG_BRK_IMM)
+
+#define ARCH_WARN_REACHABLE
+
#endif /* __ASM_ASM_BUG_H */
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 0c8c35dd645e..ea84a61ed508 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -106,7 +106,7 @@ static void __init arch_reserve_crashkernel(void)
ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
&crash_size, &crash_base,
- &low_size, &high);
+ &low_size, NULL, &high);
if (ret)
return;
diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
index b99fbb388fe0..22b27cd447a1 100644
--- a/arch/loongarch/kernel/setup.c
+++ b/arch/loongarch/kernel/setup.c
@@ -265,7 +265,7 @@ static void __init arch_reserve_crashkernel(void)
return;
ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
- &crash_size, &crash_base, &low_size, &high);
+ &crash_size, &crash_base, &low_size, NULL, &high);
if (ret)
return;
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index fbfe0771317e..11b9b6b63e19 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -458,7 +458,7 @@ static void __init mips_parse_crashkernel(void)
total_mem = memblock_phys_mem_size();
ret = parse_crashkernel(boot_command_line, total_mem,
&crash_size, &crash_base,
- NULL, NULL);
+ NULL, NULL, NULL);
if (ret != 0 || crash_size <= 0)
return;
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index 4312bcb913a4..8053b24afc39 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -425,6 +425,7 @@
#define PPC_RAW_SC() (0x44000002)
#define PPC_RAW_SYNC() (0x7c0004ac)
#define PPC_RAW_ISYNC() (0x4c00012c)
+#define PPC_RAW_LWSYNC() (0x7c2004ac)
/*
* Define what the VSX XX1 form instructions will look like, then add
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index 13578f4db254..bb836f02101c 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -1139,6 +1139,7 @@ int eeh_unfreeze_pe(struct eeh_pe *pe)
return ret;
}
+EXPORT_SYMBOL_GPL(eeh_unfreeze_pe);
static struct pci_device_id eeh_reset_ids[] = {
diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
index 10ce6b3bd3b7..48ad0116f359 100644
--- a/arch/powerpc/kernel/eeh_driver.c
+++ b/arch/powerpc/kernel/eeh_driver.c
@@ -257,13 +257,12 @@ static void eeh_pe_report_edev(struct eeh_dev *edev, eeh_report_fn fn,
struct pci_driver *driver;
enum pci_ers_result new_result;
- pci_lock_rescan_remove();
pdev = edev->pdev;
if (pdev)
get_device(&pdev->dev);
- pci_unlock_rescan_remove();
if (!pdev) {
eeh_edev_info(edev, "no device");
+ *result = PCI_ERS_RESULT_DISCONNECT;
return;
}
device_lock(&pdev->dev);
@@ -304,8 +303,9 @@ static void eeh_pe_report(const char *name, struct eeh_pe *root,
struct eeh_dev *edev, *tmp;
pr_info("EEH: Beginning: '%s'\n", name);
- eeh_for_each_pe(root, pe) eeh_pe_for_each_dev(pe, edev, tmp)
- eeh_pe_report_edev(edev, fn, result);
+ eeh_for_each_pe(root, pe)
+ eeh_pe_for_each_dev(pe, edev, tmp)
+ eeh_pe_report_edev(edev, fn, result);
if (result)
pr_info("EEH: Finished:'%s' with aggregate recovery state:'%s'\n",
name, pci_ers_result_name(*result));
@@ -383,6 +383,8 @@ static void eeh_dev_restore_state(struct eeh_dev *edev, void *userdata)
if (!edev)
return;
+ pci_lock_rescan_remove();
+
/*
* The content in the config space isn't saved because
* the blocked config space on some adapters. We have
@@ -393,14 +395,19 @@ static void eeh_dev_restore_state(struct eeh_dev *edev, void *userdata)
if (list_is_last(&edev->entry, &edev->pe->edevs))
eeh_pe_restore_bars(edev->pe);
+ pci_unlock_rescan_remove();
return;
}
pdev = eeh_dev_to_pci_dev(edev);
- if (!pdev)
+ if (!pdev) {
+ pci_unlock_rescan_remove();
return;
+ }
pci_restore_state(pdev);
+
+ pci_unlock_rescan_remove();
}
/**
@@ -647,9 +654,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
if (any_passed || driver_eeh_aware || (pe->type & EEH_PE_VF)) {
eeh_pe_dev_traverse(pe, eeh_rmv_device, rmv_data);
} else {
- pci_lock_rescan_remove();
pci_hp_remove_devices(bus);
- pci_unlock_rescan_remove();
}
/*
@@ -665,8 +670,6 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
if (rc)
return rc;
- pci_lock_rescan_remove();
-
/* Restore PE */
eeh_ops->configure_bridge(pe);
eeh_pe_restore_bars(pe);
@@ -674,7 +677,6 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
/* Clear frozen state */
rc = eeh_clear_pe_frozen_state(pe, false);
if (rc) {
- pci_unlock_rescan_remove();
return rc;
}
@@ -709,7 +711,6 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus,
pe->tstamp = tstamp;
pe->freeze_count = cnt;
- pci_unlock_rescan_remove();
return 0;
}
@@ -843,10 +844,13 @@ void eeh_handle_normal_event(struct eeh_pe *pe)
{LIST_HEAD_INIT(rmv_data.removed_vf_list), 0};
int devices = 0;
+ pci_lock_rescan_remove();
+
bus = eeh_pe_bus_get(pe);
if (!bus) {
pr_err("%s: Cannot find PCI bus for PHB#%x-PE#%x\n",
__func__, pe->phb->global_number, pe->addr);
+ pci_unlock_rescan_remove();
return;
}
@@ -1094,10 +1098,15 @@ recover_failed:
eeh_pe_state_clear(pe, EEH_PE_PRI_BUS, true);
eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED);
- pci_lock_rescan_remove();
- pci_hp_remove_devices(bus);
- pci_unlock_rescan_remove();
+ bus = eeh_pe_bus_get(pe);
+ if (bus)
+ pci_hp_remove_devices(bus);
+ else
+ pr_err("%s: PCI bus for PHB#%x-PE#%x disappeared\n",
+ __func__, pe->phb->global_number, pe->addr);
+
/* The passed PE should no longer be used */
+ pci_unlock_rescan_remove();
return;
}
@@ -1114,6 +1123,8 @@ out:
eeh_clear_slot_attention(edev->pdev);
eeh_pe_state_clear(pe, EEH_PE_RECOVERING, true);
+
+ pci_unlock_rescan_remove();
}
/**
@@ -1132,6 +1143,7 @@ void eeh_handle_special_event(void)
unsigned long flags;
int rc;
+ pci_lock_rescan_remove();
do {
rc = eeh_ops->next_error(&pe);
@@ -1171,10 +1183,12 @@ void eeh_handle_special_event(void)
break;
case EEH_NEXT_ERR_NONE:
+ pci_unlock_rescan_remove();
return;
default:
pr_warn("%s: Invalid value %d from next_error()\n",
__func__, rc);
+ pci_unlock_rescan_remove();
return;
}
@@ -1186,7 +1200,9 @@ void eeh_handle_special_event(void)
if (rc == EEH_NEXT_ERR_FROZEN_PE ||
rc == EEH_NEXT_ERR_FENCED_PHB) {
eeh_pe_state_mark(pe, EEH_PE_RECOVERING);
+ pci_unlock_rescan_remove();
eeh_handle_normal_event(pe);
+ pci_lock_rescan_remove();
} else {
eeh_for_each_pe(pe, tmp_pe)
eeh_pe_for_each_dev(tmp_pe, edev, tmp_edev)
@@ -1199,7 +1215,6 @@ void eeh_handle_special_event(void)
eeh_report_failure, NULL);
eeh_set_channel_state(pe, pci_channel_io_perm_failure);
- pci_lock_rescan_remove();
list_for_each_entry(hose, &hose_list, list_node) {
phb_pe = eeh_phb_pe_get(hose);
if (!phb_pe ||
@@ -1218,7 +1233,6 @@ void eeh_handle_special_event(void)
}
pci_hp_remove_devices(bus);
}
- pci_unlock_rescan_remove();
}
/*
@@ -1228,4 +1242,6 @@ void eeh_handle_special_event(void)
if (rc == EEH_NEXT_ERR_DEAD_IOC)
break;
} while (rc != EEH_NEXT_ERR_NONE);
+
+ pci_unlock_rescan_remove();
}
diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c
index d283d281d28e..e740101fadf3 100644
--- a/arch/powerpc/kernel/eeh_pe.c
+++ b/arch/powerpc/kernel/eeh_pe.c
@@ -671,10 +671,12 @@ static void eeh_bridge_check_link(struct eeh_dev *edev)
eeh_ops->write_config(edev, cap + PCI_EXP_LNKCTL, 2, val);
/* Check link */
- if (!edev->pdev->link_active_reporting) {
- eeh_edev_dbg(edev, "No link reporting capability\n");
- msleep(1000);
- return;
+ if (edev->pdev) {
+ if (!edev->pdev->link_active_reporting) {
+ eeh_edev_dbg(edev, "No link reporting capability\n");
+ msleep(1000);
+ return;
+ }
}
/* Wait the link is up until timeout (5s) */
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
index 8a050f30e6d9..5782e743fd27 100644
--- a/arch/powerpc/kernel/fadump.c
+++ b/arch/powerpc/kernel/fadump.c
@@ -333,7 +333,7 @@ static __init u64 fadump_calculate_reserve_size(void)
* memory at a predefined offset.
*/
ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
- &size, &base, NULL, NULL);
+ &size, &base, NULL, NULL, NULL);
if (ret == 0 && size > 0) {
unsigned long max_size;
diff --git a/arch/powerpc/kernel/pci-hotplug.c b/arch/powerpc/kernel/pci-hotplug.c
index 9ea74973d78d..6f444d0822d8 100644
--- a/arch/powerpc/kernel/pci-hotplug.c
+++ b/arch/powerpc/kernel/pci-hotplug.c
@@ -141,6 +141,9 @@ void pci_hp_add_devices(struct pci_bus *bus)
struct pci_controller *phb;
struct device_node *dn = pci_bus_to_OF_node(bus);
+ if (!dn)
+ return;
+
phb = pci_bus_to_host(bus);
mode = PCI_PROBE_NORMAL;
diff --git a/arch/powerpc/kexec/core.c b/arch/powerpc/kexec/core.c
index 00e9c267b912..d1a2d755381c 100644
--- a/arch/powerpc/kexec/core.c
+++ b/arch/powerpc/kexec/core.c
@@ -110,7 +110,7 @@ void __init arch_reserve_crashkernel(void)
/* use common parsing */
ret = parse_crashkernel(boot_command_line, total_mem_sz, &crash_size,
- &crash_base, NULL, NULL);
+ &crash_base, NULL, NULL, NULL);
if (ret)
return;
diff --git a/arch/powerpc/mm/nohash/kaslr_booke.c b/arch/powerpc/mm/nohash/kaslr_booke.c
index 5c8d1bb98b3e..5e4897daaaea 100644
--- a/arch/powerpc/mm/nohash/kaslr_booke.c
+++ b/arch/powerpc/mm/nohash/kaslr_booke.c
@@ -178,7 +178,7 @@ static void __init get_crash_kernel(void *fdt, unsigned long size)
int ret;
ret = parse_crashkernel(boot_command_line, size, &crash_size,
- &crash_base, NULL, NULL);
+ &crash_base, NULL, NULL, NULL);
if (ret != 0 || crash_size == 0)
return;
if (crash_base == 0)
diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c
index a25a6ffe7d7c..025524378443 100644
--- a/arch/powerpc/net/bpf_jit_comp64.c
+++ b/arch/powerpc/net/bpf_jit_comp64.c
@@ -409,6 +409,71 @@ asm (
" blr ;"
);
+static int emit_atomic_ld_st(const struct bpf_insn insn, struct codegen_context *ctx, u32 *image)
+{
+ u32 code = insn.code;
+ u32 dst_reg = bpf_to_ppc(insn.dst_reg);
+ u32 src_reg = bpf_to_ppc(insn.src_reg);
+ u32 size = BPF_SIZE(code);
+ u32 tmp1_reg = bpf_to_ppc(TMP_REG_1);
+ u32 tmp2_reg = bpf_to_ppc(TMP_REG_2);
+ s16 off = insn.off;
+ s32 imm = insn.imm;
+
+ switch (imm) {
+ case BPF_LOAD_ACQ:
+ switch (size) {
+ case BPF_B:
+ EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off));
+ break;
+ case BPF_H:
+ EMIT(PPC_RAW_LHZ(dst_reg, src_reg, off));
+ break;
+ case BPF_W:
+ EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off));
+ break;
+ case BPF_DW:
+ if (off % 4) {
+ EMIT(PPC_RAW_LI(tmp1_reg, off));
+ EMIT(PPC_RAW_LDX(dst_reg, src_reg, tmp1_reg));
+ } else {
+ EMIT(PPC_RAW_LD(dst_reg, src_reg, off));
+ }
+ break;
+ }
+ EMIT(PPC_RAW_LWSYNC());
+ break;
+ case BPF_STORE_REL:
+ EMIT(PPC_RAW_LWSYNC());
+ switch (size) {
+ case BPF_B:
+ EMIT(PPC_RAW_STB(src_reg, dst_reg, off));
+ break;
+ case BPF_H:
+ EMIT(PPC_RAW_STH(src_reg, dst_reg, off));
+ break;
+ case BPF_W:
+ EMIT(PPC_RAW_STW(src_reg, dst_reg, off));
+ break;
+ case BPF_DW:
+ if (off % 4) {
+ EMIT(PPC_RAW_LI(tmp2_reg, off));
+ EMIT(PPC_RAW_STDX(src_reg, dst_reg, tmp2_reg));
+ } else {
+ EMIT(PPC_RAW_STD(src_reg, dst_reg, off));
+ }
+ break;
+ }
+ break;
+ default:
+ pr_err_ratelimited("unexpected atomic load/store op code %02x\n",
+ imm);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/* Assemble the body code between the prologue & epilogue */
int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, u32 *fimage, struct codegen_context *ctx,
u32 *addrs, int pass, bool extra_pass)
@@ -898,8 +963,25 @@ emit_clear:
/*
* BPF_STX ATOMIC (atomic ops)
*/
+ case BPF_STX | BPF_ATOMIC | BPF_B:
+ case BPF_STX | BPF_ATOMIC | BPF_H:
case BPF_STX | BPF_ATOMIC | BPF_W:
case BPF_STX | BPF_ATOMIC | BPF_DW:
+ if (bpf_atomic_is_load_store(&insn[i])) {
+ ret = emit_atomic_ld_st(insn[i], ctx, image);
+ if (ret)
+ return ret;
+
+ if (size != BPF_DW && insn_is_zext(&insn[i + 1]))
+ addrs[++i] = ctx->idx * 4;
+ break;
+ } else if (size == BPF_B || size == BPF_H) {
+ pr_err_ratelimited(
+ "eBPF filter atomic op code %02x (@%d) unsupported\n",
+ code, i);
+ return -EOPNOTSUPP;
+ }
+
save_reg = tmp2_reg;
ret_reg = src_reg;
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index e5668d9de58b..a4b233a0659e 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -93,6 +93,7 @@ config RISCV
select CLINT_TIMER if RISCV_M_MODE
select CLONE_BACKWARDS
select COMMON_CLK
+ select CPU_NO_EFFICIENT_FFS if !RISCV_ISA_ZBB
select CPU_PM if CPU_IDLE || HIBERNATION || SUSPEND
select DYNAMIC_FTRACE if FUNCTION_TRACER
select EDAC_SUPPORT
diff --git a/arch/riscv/include/asm/bug.h b/arch/riscv/include/asm/bug.h
index 1aaea81fb141..4c03e20ad11f 100644
--- a/arch/riscv/include/asm/bug.h
+++ b/arch/riscv/include/asm/bug.h
@@ -31,40 +31,45 @@ typedef u32 bug_insn_t;
#ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
#define __BUG_ENTRY_ADDR RISCV_INT " 1b - ."
-#define __BUG_ENTRY_FILE RISCV_INT " %0 - ."
+#define __BUG_ENTRY_FILE(file) RISCV_INT " " file " - ."
#else
#define __BUG_ENTRY_ADDR RISCV_PTR " 1b"
-#define __BUG_ENTRY_FILE RISCV_PTR " %0"
+#define __BUG_ENTRY_FILE(file) RISCV_PTR " " file
#endif
#ifdef CONFIG_DEBUG_BUGVERBOSE
-#define __BUG_ENTRY \
+#define __BUG_ENTRY(file, line, flags) \
__BUG_ENTRY_ADDR "\n\t" \
- __BUG_ENTRY_FILE "\n\t" \
- RISCV_SHORT " %1\n\t" \
- RISCV_SHORT " %2"
+ __BUG_ENTRY_FILE(file) "\n\t" \
+ RISCV_SHORT " " line "\n\t" \
+ RISCV_SHORT " " flags
#else
-#define __BUG_ENTRY \
- __BUG_ENTRY_ADDR "\n\t" \
- RISCV_SHORT " %2"
+#define __BUG_ENTRY(file, line, flags) \
+ __BUG_ENTRY_ADDR "\n\t" \
+ RISCV_SHORT " " flags
#endif
#ifdef CONFIG_GENERIC_BUG
-#define __BUG_FLAGS(flags) \
-do { \
- __asm__ __volatile__ ( \
+
+#define ARCH_WARN_ASM(file, line, flags, size) \
"1:\n\t" \
"ebreak\n" \
".pushsection __bug_table,\"aw\"\n\t" \
"2:\n\t" \
- __BUG_ENTRY "\n\t" \
- ".org 2b + %3\n\t" \
+ __BUG_ENTRY(file, line, flags) "\n\t" \
+ ".org 2b + " size "\n\t" \
".popsection" \
+
+#define __BUG_FLAGS(flags) \
+do { \
+ __asm__ __volatile__ ( \
+ ARCH_WARN_ASM("%0", "%1", "%2", "%3") \
: \
: "i" (__FILE__), "i" (__LINE__), \
"i" (flags), \
"i" (sizeof(struct bug_entry))); \
} while (0)
+
#else /* CONFIG_GENERIC_BUG */
#define __BUG_FLAGS(flags) do { \
__asm__ __volatile__ ("ebreak\n"); \
@@ -78,6 +83,8 @@ do { \
#define __WARN_FLAGS(flags) __BUG_FLAGS(BUGFLAG_WARNING|(flags))
+#define ARCH_WARN_REACHABLE
+
#define HAVE_ARCH_BUG
#include <asm-generic/bug.h>
diff --git a/arch/riscv/kernel/kexec_elf.c b/arch/riscv/kernel/kexec_elf.c
index f4755d49b89e..56444c7bd34e 100644
--- a/arch/riscv/kernel/kexec_elf.c
+++ b/arch/riscv/kernel/kexec_elf.c
@@ -95,6 +95,7 @@ static int elf_find_pbase(struct kimage *image, unsigned long kernel_len,
kbuf.buf_align = PMD_SIZE;
kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
kbuf.memsz = ALIGN(kernel_len, PAGE_SIZE);
+ kbuf.cma = NULL;
kbuf.top_down = false;
ret = arch_kexec_locate_mem_hole(&kbuf);
if (!ret) {
diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
index 14888e5ea19a..f90cce7a3ace 100644
--- a/arch/riscv/kernel/setup.c
+++ b/arch/riscv/kernel/setup.c
@@ -21,6 +21,8 @@
#include <linux/efi.h>
#include <linux/crash_dump.h>
#include <linux/panic_notifier.h>
+#include <linux/jump_label.h>
+#include <linux/gcd.h>
#include <asm/acpi.h>
#include <asm/alternative.h>
@@ -362,6 +364,9 @@ void __init setup_arch(char **cmdline_p)
riscv_user_isa_enable();
riscv_spinlock_init();
+
+ if (!IS_ENABLED(CONFIG_RISCV_ISA_ZBB) || !riscv_isa_extension_available(NULL, ZBB))
+ static_branch_disable(&efficient_ffs_key);
}
bool arch_cpu_is_hotpluggable(int cpu)
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 8d0374d7ce8e..15683ae13fa5 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -1408,7 +1408,7 @@ static void __init arch_reserve_crashkernel(void)
ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
&crash_size, &crash_base,
- &low_size, &high);
+ &low_size, NULL, &high);
if (ret)
return;
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index f244c5560e7f..b99aeb0db2ee 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -605,7 +605,7 @@ static void __init reserve_crashkernel(void)
int rc;
rc = parse_crashkernel(boot_command_line, ident_map_size,
- &crash_size, &crash_base, NULL, NULL);
+ &crash_size, &crash_base, NULL, NULL, NULL);
crash_base = ALIGN(crash_base, KEXEC_CRASH_MEM_ALIGN);
crash_size = ALIGN(crash_size, KEXEC_CRASH_MEM_ALIGN);
diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c
index 8321b31d2e19..37073ca1e0ad 100644
--- a/arch/sh/kernel/machine_kexec.c
+++ b/arch/sh/kernel/machine_kexec.c
@@ -146,7 +146,7 @@ void __init reserve_crashkernel(void)
return;
ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
- &crash_size, &crash_base, NULL, NULL);
+ &crash_size, &crash_base, NULL, NULL, NULL);
if (ret == 0 && crash_size > 0) {
crashk_res.start = crash_base;
crashk_res.end = crash_base + crash_size - 1;
diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h
index f0e9acf72547..20fcb8507ad1 100644
--- a/arch/x86/include/asm/bug.h
+++ b/arch/x86/include/asm/bug.h
@@ -32,45 +32,42 @@
#ifdef CONFIG_GENERIC_BUG
#ifdef CONFIG_X86_32
-# define __BUG_REL(val) ".long " __stringify(val)
+# define __BUG_REL(val) ".long " val
#else
-# define __BUG_REL(val) ".long " __stringify(val) " - ."
+# define __BUG_REL(val) ".long " val " - ."
#endif
#ifdef CONFIG_DEBUG_BUGVERBOSE
+#define __BUG_ENTRY(file, line, flags) \
+ "2:\t" __BUG_REL("1b") "\t# bug_entry::bug_addr\n" \
+ "\t" __BUG_REL(file) "\t# bug_entry::file\n" \
+ "\t.word " line "\t# bug_entry::line\n" \
+ "\t.word " flags "\t# bug_entry::flags\n"
+#else
+#define __BUG_ENTRY(file, line, flags) \
+ "2:\t" __BUG_REL("1b") "\t# bug_entry::bug_addr\n" \
+ "\t.word " flags "\t# bug_entry::flags\n"
+#endif
+
+#define _BUG_FLAGS_ASM(ins, file, line, flags, size, extra) \
+ "1:\t" ins "\n" \
+ ".pushsection __bug_table,\"aw\"\n" \
+ __BUG_ENTRY(file, line, flags) \
+ "\t.org 2b + " size "\n" \
+ ".popsection\n" \
+ extra
#define _BUG_FLAGS(ins, flags, extra) \
do { \
- asm_inline volatile("1:\t" ins "\n" \
- ".pushsection __bug_table,\"aw\"\n" \
- "2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n" \
- "\t" __BUG_REL(%c0) "\t# bug_entry::file\n" \
- "\t.word %c1" "\t# bug_entry::line\n" \
- "\t.word %c2" "\t# bug_entry::flags\n" \
- "\t.org 2b+%c3\n" \
- ".popsection\n" \
- extra \
+ asm_inline volatile(_BUG_FLAGS_ASM(ins, "%c0", \
+ "%c1", "%c2", "%c3", extra) \
: : "i" (__FILE__), "i" (__LINE__), \
"i" (flags), \
"i" (sizeof(struct bug_entry))); \
} while (0)
-#else /* !CONFIG_DEBUG_BUGVERBOSE */
-
-#define _BUG_FLAGS(ins, flags, extra) \
-do { \
- asm_inline volatile("1:\t" ins "\n" \
- ".pushsection __bug_table,\"aw\"\n" \
- "2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n" \
- "\t.word %c0" "\t# bug_entry::flags\n" \
- "\t.org 2b+%c1\n" \
- ".popsection\n" \
- extra \
- : : "i" (flags), \
- "i" (sizeof(struct bug_entry))); \
-} while (0)
-
-#endif /* CONFIG_DEBUG_BUGVERBOSE */
+#define ARCH_WARN_ASM(file, line, flags, size) \
+ _BUG_FLAGS_ASM(ASM_UD2, file, line, flags, size, "")
#else
@@ -92,11 +89,14 @@ do { \
* were to trigger, we'd rather wreck the machine in an attempt to get the
* message out than not know about it.
*/
+
+#define ARCH_WARN_REACHABLE ANNOTATE_REACHABLE(1b)
+
#define __WARN_FLAGS(flags) \
do { \
__auto_type __flags = BUGFLAG_WARNING|(flags); \
instrumentation_begin(); \
- _BUG_FLAGS(ASM_UD2, __flags, ANNOTATE_REACHABLE(1b)); \
+ _BUG_FLAGS(ASM_UD2, __flags, ARCH_WARN_REACHABLE); \
instrumentation_end(); \
} while (0)
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index bcb534688dfe..c6b12bed173d 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -163,10 +163,10 @@ static struct crash_mem *fill_up_crash_elf_data(void)
return NULL;
/*
- * Exclusion of crash region and/or crashk_low_res may cause
- * another range split. So add extra two slots here.
+ * Exclusion of crash region, crashk_low_res and/or crashk_cma_ranges
+ * may cause range splits. So add extra slots here.
*/
- nr_ranges += 2;
+ nr_ranges += 2 + crashk_cma_cnt;
cmem = vzalloc(struct_size(cmem, ranges, nr_ranges));
if (!cmem)
return NULL;
@@ -184,6 +184,7 @@ static struct crash_mem *fill_up_crash_elf_data(void)
static int elf_header_exclude_ranges(struct crash_mem *cmem)
{
int ret = 0;
+ int i;
/* Exclude the low 1M because it is always reserved */
ret = crash_exclude_mem_range(cmem, 0, SZ_1M - 1);
@@ -198,8 +199,17 @@ static int elf_header_exclude_ranges(struct crash_mem *cmem)
if (crashk_low_res.end)
ret = crash_exclude_mem_range(cmem, crashk_low_res.start,
crashk_low_res.end);
+ if (ret)
+ return ret;
- return ret;
+ for (i = 0; i < crashk_cma_cnt; ++i) {
+ ret = crash_exclude_mem_range(cmem, crashk_cma_ranges[i].start,
+ crashk_cma_ranges[i].end);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
@@ -374,6 +384,14 @@ int crash_setup_memmap_entries(struct kimage *image, struct boot_params *params)
add_e820_entry(params, &ei);
}
+ for (i = 0; i < crashk_cma_cnt; ++i) {
+ ei.addr = crashk_cma_ranges[i].start;
+ ei.size = crashk_cma_ranges[i].end -
+ crashk_cma_ranges[i].start + 1;
+ ei.type = E820_TYPE_RAM;
+ add_e820_entry(params, &ei);
+ }
+
out:
vfree(cmem);
return ret;
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 0792f31961ac..1b2edd07a3e1 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -603,7 +603,7 @@ static void __init memblock_x86_reserve_range_setup_data(void)
static void __init arch_reserve_crashkernel(void)
{
- unsigned long long crash_base, crash_size, low_size = 0;
+ unsigned long long crash_base, crash_size, low_size = 0, cma_size = 0;
bool high = false;
int ret;
@@ -612,7 +612,7 @@ static void __init arch_reserve_crashkernel(void)
ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
&crash_size, &crash_base,
- &low_size, &high);
+ &low_size, &cma_size, &high);
if (ret)
return;
@@ -622,6 +622,7 @@ static void __init arch_reserve_crashkernel(void)
}
reserve_crashkernel_generic(crash_size, crash_base, low_size, high);
+ reserve_crashkernel_cma(cma_size);
}
static struct resource standard_io_resources[] = {
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index d1b79b418c05..850972deac8e 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -641,7 +641,7 @@ static void kvm_pit_reset(struct kvm_pit *pit)
kvm_pit_reset_reinject(pit);
}
-static void pit_mask_notifer(struct kvm_irq_mask_notifier *kimn, bool mask)
+static void pit_mask_notifier(struct kvm_irq_mask_notifier *kimn, bool mask)
{
struct kvm_pit *pit = container_of(kimn, struct kvm_pit, mask_notifier);
@@ -763,7 +763,7 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
pit_state->irq_ack_notifier.gsi = 0;
pit_state->irq_ack_notifier.irq_acked = kvm_pit_ack_irq;
- pit->mask_notifier.func = pit_mask_notifer;
+ pit->mask_notifier.func = pit_mask_notifier;
kvm_pit_reset(pit);
diff --git a/crypto/async_tx/async_pq.c b/crypto/async_tx/async_pq.c
index 5e2b2680d7db..9e4bb7fbde25 100644
--- a/crypto/async_tx/async_pq.c
+++ b/crypto/async_tx/async_pq.c
@@ -119,7 +119,7 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int *offsets, int disks,
for (i = 0; i < disks; i++) {
if (blocks[i] == NULL) {
BUG_ON(i > disks - 3); /* P or Q can't be zero */
- srcs[i] = (void*)raid6_empty_zero_page;
+ srcs[i] = raid6_get_zero_page();
} else {
srcs[i] = page_address(blocks[i]) + offsets[i];
diff --git a/crypto/async_tx/async_raid6_recov.c b/crypto/async_tx/async_raid6_recov.c
index 354b8cd5537f..539ea5b378dc 100644
--- a/crypto/async_tx/async_raid6_recov.c
+++ b/crypto/async_tx/async_raid6_recov.c
@@ -414,7 +414,7 @@ async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
async_tx_quiesce(&submit->depend_tx);
for (i = 0; i < disks; i++)
if (blocks[i] == NULL)
- ptrs[i] = (void *) raid6_empty_zero_page;
+ ptrs[i] = raid6_get_zero_page();
else
ptrs[i] = page_address(blocks[i]) + offs[i];
@@ -497,7 +497,7 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila,
async_tx_quiesce(&submit->depend_tx);
for (i = 0; i < disks; i++)
if (blocks[i] == NULL)
- ptrs[i] = (void*)raid6_empty_zero_page;
+ ptrs[i] = raid6_get_zero_page();
else
ptrs[i] = page_address(blocks[i]) + offs[i];
diff --git a/drivers/cpufreq/rcpufreq_dt.rs b/drivers/cpufreq/rcpufreq_dt.rs
index 9ad85fe6fd05..7e1fbf9a091f 100644
--- a/drivers/cpufreq/rcpufreq_dt.rs
+++ b/drivers/cpufreq/rcpufreq_dt.rs
@@ -9,7 +9,6 @@ use kernel::{
cpumask::CpumaskVar,
device::{Core, Device},
error::code::*,
- fmt,
macros::vtable,
module_platform_driver, of, opp, platform,
prelude::*,
@@ -19,7 +18,7 @@ use kernel::{
/// Finds exact supply name from the OF node.
fn find_supply_name_exact(dev: &Device, name: &str) -> Option<CString> {
- let prop_name = CString::try_from_fmt(fmt!("{}-supply", name)).ok()?;
+ let prop_name = CString::try_from_fmt(fmt!("{name}-supply")).ok()?;
dev.fwnode()?
.property_present(&prop_name)
.then(|| CString::try_from_fmt(fmt!("{name}")).ok())
@@ -221,7 +220,7 @@ impl platform::Driver for CPUFreqDTDriver {
module_platform_driver! {
type: CPUFreqDTDriver,
name: "cpufreq-dt",
- author: "Viresh Kumar <viresh.kumar@linaro.org>",
+ authors: ["Viresh Kumar <viresh.kumar@linaro.org>"],
description: "Generic CPUFreq DT driver",
license: "GPL v2",
}
diff --git a/drivers/cxl/core/mce.h b/drivers/cxl/core/mce.h
index ace73424eeb6..ca272e8db6c7 100644
--- a/drivers/cxl/core/mce.h
+++ b/drivers/cxl/core/mce.h
@@ -7,7 +7,7 @@
#ifdef CONFIG_CXL_MCE
int devm_cxl_register_mce_notifier(struct device *dev,
- struct notifier_block *mce_notifer);
+ struct notifier_block *mce_notifier);
#else
static inline int
devm_cxl_register_mce_notifier(struct device *dev,
diff --git a/drivers/gpu/drm/drm_panic_qr.rs b/drivers/gpu/drm/drm_panic_qr.rs
index 18492daae4b3..09a9b452e8b7 100644
--- a/drivers/gpu/drm/drm_panic_qr.rs
+++ b/drivers/gpu/drm/drm_panic_qr.rs
@@ -404,7 +404,7 @@ impl DecFifo {
let mut out = 0;
let mut exp = 1;
for i in 0..poplen {
- out += self.decimals[self.len + i] as u16 * exp;
+ out += u16::from(self.decimals[self.len + i]) * exp;
exp *= 10;
}
Some((out, NUM_CHARS_BITS[poplen]))
@@ -425,7 +425,7 @@ impl Iterator for SegmentIterator<'_> {
match self.segment {
Segment::Binary(data) => {
if self.offset < data.len() {
- let byte = data[self.offset] as u16;
+ let byte = u16::from(data[self.offset]);
self.offset += 1;
Some((byte, 8))
} else {
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
index e8a04e476c57..09a64f224c49 100644
--- a/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
+++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_log.c
@@ -220,8 +220,7 @@ static int guc_action_control_log(struct intel_guc *guc, bool enable,
*/
static int subbuf_start_callback(struct rchan_buf *buf,
void *subbuf,
- void *prev_subbuf,
- size_t prev_padding)
+ void *prev_subbuf)
{
/*
* Use no-overwrite mode by default, where relay will stop accepting
diff --git a/drivers/gpu/drm/nova/nova.rs b/drivers/gpu/drm/nova/nova.rs
index 902876aa14d1..64fd670e99e1 100644
--- a/drivers/gpu/drm/nova/nova.rs
+++ b/drivers/gpu/drm/nova/nova.rs
@@ -12,7 +12,7 @@ use crate::driver::NovaDriver;
kernel::module_auxiliary_driver! {
type: NovaDriver,
name: "Nova",
- author: "Danilo Krummrich",
+ authors: ["Danilo Krummrich"],
description: "Nova GPU driver",
license: "GPL v2",
}
diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h
index bed6088e1bb3..8a07feef503b 100644
--- a/drivers/gpu/drm/xe/xe_vm_types.h
+++ b/drivers/gpu/drm/xe/xe_vm_types.h
@@ -266,7 +266,7 @@ struct xe_vm {
* up for revalidation. Protected from access with the
* @invalidated_lock. Removing items from the list
* additionally requires @lock in write mode, and adding
- * items to the list requires either the @userptr.notifer_lock in
+ * items to the list requires either the @userptr.notifier_lock in
* write mode, OR @lock in write mode.
*/
struct list_head invalidated;
diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs
index 5749bad9c285..274989ea1fb4 100644
--- a/drivers/gpu/nova-core/driver.rs
+++ b/drivers/gpu/nova-core/driver.rs
@@ -19,7 +19,7 @@ kernel::pci_device_table!(
MODULE_PCI_TABLE,
<NovaCore as pci::Driver>::IdInfo,
[(
- pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_NVIDIA, bindings::PCI_ANY_ID as _),
+ pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_NVIDIA, bindings::PCI_ANY_ID as u32),
()
)]
);
diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs
index 0fdece652587..2931912ddba0 100644
--- a/drivers/gpu/nova-core/firmware.rs
+++ b/drivers/gpu/nova-core/firmware.rs
@@ -30,11 +30,12 @@ pub(crate) struct Firmware {
impl Firmware {
pub(crate) fn new(dev: &device::Device, chipset: Chipset, ver: &str) -> Result<Firmware> {
- let mut chip_name = CString::try_from_fmt(fmt!("{}", chipset))?;
+ let mut chip_name = CString::try_from_fmt(fmt!("{chipset}"))?;
chip_name.make_ascii_lowercase();
+ let chip_name = &*chip_name;
let request = |name_| {
- CString::try_from_fmt(fmt!("nvidia/{}/gsp/{}-{}.bin", &*chip_name, name_, ver))
+ CString::try_from_fmt(fmt!("nvidia/{chip_name}/gsp/{name_}-{ver}.bin"))
.and_then(|path| firmware::Firmware::request(&path, dev))
};
diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs
index de14f2e92636..cb2bbb30cba1 100644
--- a/drivers/gpu/nova-core/nova_core.rs
+++ b/drivers/gpu/nova-core/nova_core.rs
@@ -18,7 +18,7 @@ pub(crate) const MODULE_NAME: &kernel::str::CStr = <LocalModule as kernel::Modul
kernel::module_pci_driver! {
type: driver::NovaCore,
name: "NovaCore",
- author: "Danilo Krummrich",
+ authors: ["Danilo Krummrich"],
description: "Nova Core GPU driver",
license: "GPL v2",
firmware: [],
diff --git a/drivers/gpu/nova-core/regs.rs b/drivers/gpu/nova-core/regs.rs
index 5ccfb61f850a..d49fddf6a3c6 100644
--- a/drivers/gpu/nova-core/regs.rs
+++ b/drivers/gpu/nova-core/regs.rs
@@ -36,7 +36,7 @@ impl NV_PMC_BOOT_0 {
pub(crate) fn chipset(self) -> Result<Chipset> {
self.architecture()
.map(|arch| {
- ((arch as u32) << Self::IMPLEMENTATION.len()) | self.implementation() as u32
+ ((arch as u32) << Self::IMPLEMENTATION.len()) | u32::from(self.implementation())
})
.and_then(Chipset::try_from)
}
diff --git a/drivers/gpu/nova-core/regs/macros.rs b/drivers/gpu/nova-core/regs/macros.rs
index cdf668073480..a3e6de1779d4 100644
--- a/drivers/gpu/nova-core/regs/macros.rs
+++ b/drivers/gpu/nova-core/regs/macros.rs
@@ -307,7 +307,7 @@ macro_rules! register {
pub(crate) fn [<set_ $field>](mut self, value: $to_type) -> Self {
const MASK: u32 = $name::[<$field:upper _MASK>];
const SHIFT: u32 = $name::[<$field:upper _SHIFT>];
- let value = ((value as u32) << SHIFT) & MASK;
+ let value = (u32::from(value) << SHIFT) & MASK;
self.0 = (self.0 & !MASK) | value;
self
diff --git a/drivers/gpu/nova-core/util.rs b/drivers/gpu/nova-core/util.rs
index 64fb13760764..76cedf3710d7 100644
--- a/drivers/gpu/nova-core/util.rs
+++ b/drivers/gpu/nova-core/util.rs
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
use kernel::prelude::*;
-use kernel::time::{Delta, Instant};
+use kernel::time::{Delta, Instant, Monotonic};
pub(crate) const fn to_lowercase_bytes<const N: usize>(s: &str) -> [u8; N] {
let src = s.as_bytes();
@@ -33,7 +33,7 @@ pub(crate) const fn const_bytes_to_str(bytes: &[u8]) -> &str {
/// TODO[DLAY]: replace with `read_poll_timeout` once it is available.
/// (https://lore.kernel.org/lkml/20250220070611.214262-8-fujita.tomonori@gmail.com/)
pub(crate) fn wait_on<R, F: Fn() -> Option<R>>(timeout: Delta, cond: F) -> Result<R> {
- let start_time = Instant::now();
+ let start_time = Instant::<Monotonic>::now();
loop {
if let Some(ret) = cond() {
diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c
index e80e48756914..2396545763ff 100644
--- a/drivers/i3c/device.c
+++ b/drivers/i3c/device.c
@@ -26,11 +26,12 @@
*
* This function can sleep and thus cannot be called in atomic context.
*
- * Return: 0 in case of success, a negative error core otherwise.
- * -EAGAIN: controller lost address arbitration. Target
- * (IBI, HJ or controller role request) win the bus. Client
- * driver needs to resend the 'xfers' some time later.
- * See I3C spec ver 1.1.1 09-Jun-2021. Section: 5.1.2.2.3.
+ * Return:
+ * * 0 in case of success, a negative error core otherwise.
+ * * -EAGAIN: controller lost address arbitration. Target (IBI, HJ or
+ * controller role request) win the bus. Client driver needs to resend the
+ * 'xfers' some time later. See I3C spec ver 1.1.1 09-Jun-2021. Section:
+ * 5.1.2.2.3.
*/
int i3c_device_do_priv_xfers(struct i3c_device *dev,
struct i3c_priv_xfer *xfers,
diff --git a/drivers/i3c/internals.h b/drivers/i3c/internals.h
index 433f6088b7ce..0d857cc68cc5 100644
--- a/drivers/i3c/internals.h
+++ b/drivers/i3c/internals.h
@@ -9,6 +9,7 @@
#define I3C_INTERNALS_H
#include <linux/i3c/master.h>
+#include <linux/io.h>
void i3c_bus_normaluse_lock(struct i3c_bus *bus);
void i3c_bus_normaluse_unlock(struct i3c_bus *bus);
@@ -22,4 +23,41 @@ int i3c_dev_enable_ibi_locked(struct i3c_dev_desc *dev);
int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev,
const struct i3c_ibi_setup *req);
void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev);
+
+/**
+ * i3c_writel_fifo - Write data buffer to 32bit FIFO
+ * @addr: FIFO Address to write to
+ * @buf: Pointer to the data bytes to write
+ * @nbytes: Number of bytes to write
+ */
+static inline void i3c_writel_fifo(void __iomem *addr, const void *buf,
+ int nbytes)
+{
+ writesl(addr, buf, nbytes / 4);
+ if (nbytes & 3) {
+ u32 tmp = 0;
+
+ memcpy(&tmp, buf + (nbytes & ~3), nbytes & 3);
+ writel(tmp, addr);
+ }
+}
+
+/**
+ * i3c_readl_fifo - Read data buffer from 32bit FIFO
+ * @addr: FIFO Address to read from
+ * @buf: Pointer to the buffer to store read bytes
+ * @nbytes: Number of bytes to read
+ */
+static inline void i3c_readl_fifo(const void __iomem *addr, void *buf,
+ int nbytes)
+{
+ readsl(addr, buf, nbytes / 4);
+ if (nbytes & 3) {
+ u32 tmp;
+
+ tmp = readl(addr);
+ memcpy(buf + (nbytes & ~3), &tmp, nbytes & 3);
+ }
+}
+
#endif /* I3C_INTERNAL_H */
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index fd81871609d9..2ef898a8fd80 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -141,7 +141,7 @@ static ssize_t bcr_show(struct device *dev,
i3c_bus_normaluse_lock(bus);
desc = dev_to_i3cdesc(dev);
- ret = sprintf(buf, "%x\n", desc->info.bcr);
+ ret = sprintf(buf, "0x%02x\n", desc->info.bcr);
i3c_bus_normaluse_unlock(bus);
return ret;
@@ -158,7 +158,7 @@ static ssize_t dcr_show(struct device *dev,
i3c_bus_normaluse_lock(bus);
desc = dev_to_i3cdesc(dev);
- ret = sprintf(buf, "%x\n", desc->info.dcr);
+ ret = sprintf(buf, "0x%02x\n", desc->info.dcr);
i3c_bus_normaluse_unlock(bus);
return ret;
@@ -727,12 +727,12 @@ static int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode,
switch (i3cbus->mode) {
case I3C_BUS_MODE_PURE:
if (!i3cbus->scl_rate.i3c)
- i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE;
+ i3cbus->scl_rate.i3c = I3C_BUS_I3C_SCL_TYP_RATE;
break;
case I3C_BUS_MODE_MIXED_FAST:
case I3C_BUS_MODE_MIXED_LIMITED:
if (!i3cbus->scl_rate.i3c)
- i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE;
+ i3cbus->scl_rate.i3c = I3C_BUS_I3C_SCL_TYP_RATE;
if (!i3cbus->scl_rate.i2c)
i3cbus->scl_rate.i2c = max_i2c_scl_rate;
break;
@@ -754,8 +754,8 @@ static int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode,
* I3C/I2C frequency may have been overridden, check that user-provided
* values are not exceeding max possible frequency.
*/
- if (i3cbus->scl_rate.i3c > I3C_BUS_MAX_I3C_SCL_RATE ||
- i3cbus->scl_rate.i2c > I3C_BUS_I2C_FM_PLUS_SCL_RATE)
+ if (i3cbus->scl_rate.i3c > I3C_BUS_I3C_SCL_MAX_RATE ||
+ i3cbus->scl_rate.i2c > I3C_BUS_I2C_FM_PLUS_SCL_MAX_RATE)
return -EINVAL;
return 0;
@@ -837,14 +837,14 @@ static int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master,
return -EINVAL;
if (!master->ops->send_ccc_cmd)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
if ((cmd->id & I3C_CCC_DIRECT) && (!cmd->dests || !cmd->ndests))
return -EINVAL;
if (master->ops->supports_ccc_cmd &&
!master->ops->supports_ccc_cmd(master, cmd))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
ret = master->ops->send_ccc_cmd(master, cmd);
if (ret) {
@@ -1439,7 +1439,7 @@ static int i3c_master_retrieve_dev_info(struct i3c_dev_desc *dev)
if (dev->info.bcr & I3C_BCR_HDR_CAP) {
ret = i3c_master_gethdrcap_locked(master, &dev->info);
- if (ret)
+ if (ret && ret != -EOPNOTSUPP)
return ret;
}
@@ -2210,7 +2210,7 @@ of_i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master,
*/
if (boardinfo->base.flags & I2C_CLIENT_TEN) {
dev_err(dev, "I2C device with 10 bit address not supported.");
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
}
/* LVR is encoded in reg[2]. */
@@ -2340,13 +2340,13 @@ static int i3c_master_i2c_adapter_xfer(struct i2c_adapter *adap,
return -EINVAL;
if (!master->ops->i2c_xfers)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
/* Doing transfers to different devices is not supported. */
addr = xfers[0].addr;
for (i = 1; i < nxfers; i++) {
if (addr != xfers[i].addr)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
}
i3c_bus_normaluse_lock(&master->bus);
@@ -2467,6 +2467,8 @@ static int i3c_i2c_notifier_call(struct notifier_block *nb, unsigned long action
case BUS_NOTIFY_DEL_DEVICE:
ret = i3c_master_i2c_detach(adap, client);
break;
+ default:
+ ret = -EINVAL;
}
i3c_bus_maintenance_unlock(&master->bus);
@@ -2766,7 +2768,7 @@ static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
* controller)
* @ops: the master controller operations
* @secondary: true if you are registering a secondary master. Will return
- * -ENOTSUPP if set to true since secondary masters are not yet
+ * -EOPNOTSUPP if set to true since secondary masters are not yet
* supported
*
* This function takes care of everything for you:
@@ -2785,7 +2787,7 @@ int i3c_master_register(struct i3c_master_controller *master,
const struct i3c_master_controller_ops *ops,
bool secondary)
{
- unsigned long i2c_scl_rate = I3C_BUS_I2C_FM_PLUS_SCL_RATE;
+ unsigned long i2c_scl_rate = I3C_BUS_I2C_FM_PLUS_SCL_MAX_RATE;
struct i3c_bus *i3cbus = i3c_master_get_bus(master);
enum i3c_bus_mode mode = I3C_BUS_MODE_PURE;
struct i2c_dev_boardinfo *i2cbi;
@@ -2793,7 +2795,7 @@ int i3c_master_register(struct i3c_master_controller *master,
/* We do not support secondary masters yet. */
if (secondary)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
ret = i3c_master_check_ops(ops);
if (ret)
@@ -2844,7 +2846,7 @@ int i3c_master_register(struct i3c_master_controller *master,
}
if (i2cbi->lvr & I3C_LVR_I2C_FM_MODE)
- i2c_scl_rate = I3C_BUS_I2C_FM_SCL_RATE;
+ i2c_scl_rate = I3C_BUS_I2C_FM_SCL_MAX_RATE;
}
ret = i3c_bus_set_mode(i3cbus, mode, i2c_scl_rate);
@@ -2954,7 +2956,7 @@ int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
return -EINVAL;
if (!master->ops->priv_xfers)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
return master->ops->priv_xfers(dev, xfers, nxfers);
}
@@ -3004,7 +3006,7 @@ int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev,
int ret;
if (!master->ops->request_ibi)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
if (dev->ibi)
return -EBUSY;
diff --git a/drivers/i3c/master/Kconfig b/drivers/i3c/master/Kconfig
index 7b30db3253af..13df2944f2ec 100644
--- a/drivers/i3c/master/Kconfig
+++ b/drivers/i3c/master/Kconfig
@@ -64,3 +64,13 @@ config MIPI_I3C_HCI_PCI
This driver can also be built as a module. If so, the module will be
called mipi-i3c-hci-pci.
+
+config RENESAS_I3C
+ tristate "Renesas I3C controller driver"
+ depends on HAS_IOMEM
+ depends on ARCH_RENESAS || COMPILE_TEST
+ help
+ Support the Renesas I3C controller as found in some RZ variants.
+
+ This driver can also be built as a module. If so, the module will be
+ called renesas-i3c.
diff --git a/drivers/i3c/master/Makefile b/drivers/i3c/master/Makefile
index 3e97960160bc..aac74f3e3851 100644
--- a/drivers/i3c/master/Makefile
+++ b/drivers/i3c/master/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_DW_I3C_MASTER) += dw-i3c-master.o
obj-$(CONFIG_AST2600_I3C_MASTER) += ast2600-i3c-master.o
obj-$(CONFIG_SVC_I3C_MASTER) += svc-i3c-master.o
obj-$(CONFIG_MIPI_I3C_HCI) += mipi-i3c-hci/
+obj-$(CONFIG_RENESAS_I3C) += renesas-i3c.o
diff --git a/drivers/i3c/master/dw-i3c-master.c b/drivers/i3c/master/dw-i3c-master.c
index 611c22b72c15..974122b2d20e 100644
--- a/drivers/i3c/master/dw-i3c-master.c
+++ b/drivers/i3c/master/dw-i3c-master.c
@@ -23,6 +23,7 @@
#include <linux/reset.h>
#include <linux/slab.h>
+#include "../internals.h"
#include "dw-i3c-master.h"
#define DEVICE_CTRL 0x0
@@ -336,37 +337,19 @@ static int dw_i3c_master_get_free_pos(struct dw_i3c_master *master)
static void dw_i3c_master_wr_tx_fifo(struct dw_i3c_master *master,
const u8 *bytes, int nbytes)
{
- writesl(master->regs + RX_TX_DATA_PORT, bytes, nbytes / 4);
- if (nbytes & 3) {
- u32 tmp = 0;
-
- memcpy(&tmp, bytes + (nbytes & ~3), nbytes & 3);
- writesl(master->regs + RX_TX_DATA_PORT, &tmp, 1);
- }
-}
-
-static void dw_i3c_master_read_fifo(struct dw_i3c_master *master,
- int reg, u8 *bytes, int nbytes)
-{
- readsl(master->regs + reg, bytes, nbytes / 4);
- if (nbytes & 3) {
- u32 tmp;
-
- readsl(master->regs + reg, &tmp, 1);
- memcpy(bytes + (nbytes & ~3), &tmp, nbytes & 3);
- }
+ i3c_writel_fifo(master->regs + RX_TX_DATA_PORT, bytes, nbytes);
}
static void dw_i3c_master_read_rx_fifo(struct dw_i3c_master *master,
u8 *bytes, int nbytes)
{
- return dw_i3c_master_read_fifo(master, RX_TX_DATA_PORT, bytes, nbytes);
+ i3c_readl_fifo(master->regs + RX_TX_DATA_PORT, bytes, nbytes);
}
static void dw_i3c_master_read_ibi_fifo(struct dw_i3c_master *master,
u8 *bytes, int nbytes)
{
- return dw_i3c_master_read_fifo(master, IBI_QUEUE_STATUS, bytes, nbytes);
+ i3c_readl_fifo(master->regs + IBI_QUEUE_STATUS, bytes, nbytes);
}
static struct dw_i3c_xfer *
@@ -622,14 +605,14 @@ static int dw_i2c_clk_cfg(struct dw_i3c_master *master)
core_period = DIV_ROUND_UP(1000000000, core_rate);
lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FMP_TLOW_MIN_NS, core_period);
- hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_PLUS_SCL_RATE) - lcnt;
+ hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_PLUS_SCL_MAX_RATE) - lcnt;
scl_timing = SCL_I2C_FMP_TIMING_HCNT(hcnt) |
SCL_I2C_FMP_TIMING_LCNT(lcnt);
writel(scl_timing, master->regs + SCL_I2C_FMP_TIMING);
master->i2c_fmp_timing = scl_timing;
lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FM_TLOW_MIN_NS, core_period);
- hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_SCL_RATE) - lcnt;
+ hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_SCL_MAX_RATE) - lcnt;
scl_timing = SCL_I2C_FM_TIMING_HCNT(hcnt) |
SCL_I2C_FM_TIMING_LCNT(lcnt);
writel(scl_timing, master->regs + SCL_I2C_FM_TIMING);
@@ -699,7 +682,6 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
dw_i3c_master_enable(master);
rpm_out:
- pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
}
@@ -829,7 +811,6 @@ static int dw_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
else
ret = dw_i3c_ccc_set(master, ccc);
- pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
}
@@ -912,7 +893,6 @@ static int dw_i3c_master_daa(struct i3c_master_controller *m)
dw_i3c_master_free_xfer(xfer);
rpm_out:
- pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
}
@@ -932,7 +912,7 @@ static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
return 0;
if (i3c_nxfers > master->caps.cmdfifodepth)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
for (i = 0; i < i3c_nxfers; i++) {
if (i3c_xfers[i].rnw)
@@ -943,7 +923,7 @@ static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
if (ntxwords > master->caps.datafifodepth ||
nrxwords > master->caps.datafifodepth)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
xfer = dw_i3c_master_alloc_xfer(master, i3c_nxfers);
if (!xfer)
@@ -998,7 +978,6 @@ static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
ret = xfer->ret;
dw_i3c_master_free_xfer(xfer);
- pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
}
@@ -1093,7 +1072,7 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
return 0;
if (i2c_nxfers > master->caps.cmdfifodepth)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
for (i = 0; i < i2c_nxfers; i++) {
if (i2c_xfers[i].flags & I2C_M_RD)
@@ -1104,7 +1083,7 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
if (ntxwords > master->caps.datafifodepth ||
nrxwords > master->caps.datafifodepth)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
xfer = dw_i3c_master_alloc_xfer(master, i2c_nxfers);
if (!xfer)
@@ -1142,13 +1121,12 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
}
dw_i3c_master_enqueue_xfer(master, xfer);
- if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT))
+ if (!wait_for_completion_timeout(&xfer->comp, m->i2c.timeout))
dw_i3c_master_dequeue_xfer(master, xfer);
ret = xfer->ret;
dw_i3c_master_free_xfer(xfer);
- pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
}
@@ -1316,7 +1294,6 @@ static int dw_i3c_master_disable_hotjoin(struct i3c_master_controller *m)
writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_HOT_JOIN_NACK,
master->regs + DEVICE_CTRL);
- pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return 0;
}
@@ -1342,7 +1319,6 @@ static int dw_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
if (rc) {
dw_i3c_master_set_sir_enabled(master, dev, data->index, false);
- pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
}
@@ -1362,7 +1338,6 @@ static int dw_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
dw_i3c_master_set_sir_enabled(master, dev, data->index, false);
- pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return 0;
}
diff --git a/drivers/i3c/master/i3c-master-cdns.c b/drivers/i3c/master/i3c-master-cdns.c
index fd3752cea654..97b151564d3d 100644
--- a/drivers/i3c/master/i3c-master-cdns.c
+++ b/drivers/i3c/master/i3c-master-cdns.c
@@ -23,6 +23,8 @@
#include <linux/spinlock.h>
#include <linux/workqueue.h>
+#include "../internals.h"
+
#define DEV_ID 0x0
#define DEV_ID_I3C_MASTER 0x5034
@@ -412,7 +414,6 @@ struct cdns_i3c_master {
} xferqueue;
void __iomem *regs;
struct clk *sysclk;
- struct clk *pclk;
struct cdns_i3c_master_caps caps;
unsigned long i3c_scl_lim;
const struct cdns_i3c_data *devdata;
@@ -427,25 +428,13 @@ to_cdns_i3c_master(struct i3c_master_controller *master)
static void cdns_i3c_master_wr_to_tx_fifo(struct cdns_i3c_master *master,
const u8 *bytes, int nbytes)
{
- writesl(master->regs + TX_FIFO, bytes, nbytes / 4);
- if (nbytes & 3) {
- u32 tmp = 0;
-
- memcpy(&tmp, bytes + (nbytes & ~3), nbytes & 3);
- writesl(master->regs + TX_FIFO, &tmp, 1);
- }
+ i3c_writel_fifo(master->regs + TX_FIFO, bytes, nbytes);
}
static void cdns_i3c_master_rd_from_rx_fifo(struct cdns_i3c_master *master,
u8 *bytes, int nbytes)
{
- readsl(master->regs + RX_FIFO, bytes, nbytes / 4);
- if (nbytes & 3) {
- u32 tmp;
-
- readsl(master->regs + RX_FIFO, &tmp, 1);
- memcpy(bytes + (nbytes & ~3), &tmp, nbytes & 3);
- }
+ i3c_readl_fifo(master->regs + RX_FIFO, bytes, nbytes);
}
static bool cdns_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m,
@@ -742,7 +731,7 @@ static int cdns_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
for (i = 0; i < nxfers; i++) {
if (xfers[i].len > CMD0_FIFO_PL_LEN_MAX)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
}
if (!nxfers)
@@ -750,7 +739,7 @@ static int cdns_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
if (nxfers > master->caps.cmdfifodepth ||
nxfers > master->caps.cmdrfifodepth)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
/*
* First make sure that all transactions (block of transfers separated
@@ -765,7 +754,7 @@ static int cdns_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
if (rxslots > master->caps.rxfifodepth ||
txslots > master->caps.txfifodepth)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
cdns_xfer = cdns_i3c_master_alloc_xfer(master, nxfers);
if (!cdns_xfer)
@@ -822,11 +811,11 @@ static int cdns_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
int i, ret = 0;
if (nxfers > master->caps.cmdfifodepth)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
for (i = 0; i < nxfers; i++) {
if (xfers[i].len > CMD0_FIFO_PL_LEN_MAX)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
if (xfers[i].flags & I2C_M_RD)
nrxwords += DIV_ROUND_UP(xfers[i].len, 4);
@@ -836,7 +825,7 @@ static int cdns_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
if (ntxwords > master->caps.txfifodepth ||
nrxwords > master->caps.rxfifodepth)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
xfer = cdns_i3c_master_alloc_xfer(master, nxfers);
if (!xfer)
@@ -863,7 +852,7 @@ static int cdns_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
}
cdns_i3c_master_queue_xfer(master, xfer);
- if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
+ if (!wait_for_completion_timeout(&xfer->comp, m->i2c.timeout))
cdns_i3c_master_unqueue_xfer(master, xfer);
ret = xfer->ret;
@@ -1330,12 +1319,7 @@ static void cdns_i3c_master_handle_ibi(struct cdns_i3c_master *master,
buf = slot->data;
nbytes = IBIR_XFER_BYTES(ibir);
- readsl(master->regs + IBI_DATA_FIFO, buf, nbytes / 4);
- if (nbytes % 3) {
- u32 tmp = __raw_readl(master->regs + IBI_DATA_FIFO);
-
- memcpy(buf + (nbytes & ~3), &tmp, nbytes & 3);
- }
+ i3c_readl_fifo(master->regs + IBI_DATA_FIFO, buf, nbytes);
slot->len = min_t(unsigned int, IBIR_XFER_BYTES(ibir),
dev->ibi->max_payload_len);
@@ -1566,6 +1550,7 @@ MODULE_DEVICE_TABLE(of, cdns_i3c_master_of_ids);
static int cdns_i3c_master_probe(struct platform_device *pdev)
{
struct cdns_i3c_master *master;
+ struct clk *pclk;
int ret, irq;
u32 val;
@@ -1581,11 +1566,11 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
if (IS_ERR(master->regs))
return PTR_ERR(master->regs);
- master->pclk = devm_clk_get(&pdev->dev, "pclk");
- if (IS_ERR(master->pclk))
- return PTR_ERR(master->pclk);
+ pclk = devm_clk_get_enabled(&pdev->dev, "pclk");
+ if (IS_ERR(pclk))
+ return PTR_ERR(pclk);
- master->sysclk = devm_clk_get(&pdev->dev, "sysclk");
+ master->sysclk = devm_clk_get_enabled(&pdev->dev, "sysclk");
if (IS_ERR(master->sysclk))
return PTR_ERR(master->sysclk);
@@ -1593,18 +1578,8 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- ret = clk_prepare_enable(master->pclk);
- if (ret)
- return ret;
-
- ret = clk_prepare_enable(master->sysclk);
- if (ret)
- goto err_disable_pclk;
-
- if (readl(master->regs + DEV_ID) != DEV_ID_I3C_MASTER) {
- ret = -EINVAL;
- goto err_disable_sysclk;
- }
+ if (readl(master->regs + DEV_ID) != DEV_ID_I3C_MASTER)
+ return -EINVAL;
spin_lock_init(&master->xferqueue.lock);
INIT_LIST_HEAD(&master->xferqueue.list);
@@ -1615,7 +1590,7 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, irq, cdns_i3c_master_interrupt, 0,
dev_name(&pdev->dev), master);
if (ret)
- goto err_disable_sysclk;
+ return ret;
platform_set_drvdata(pdev, master);
@@ -1637,29 +1612,15 @@ static int cdns_i3c_master_probe(struct platform_device *pdev)
master->ibi.slots = devm_kcalloc(&pdev->dev, master->ibi.num_slots,
sizeof(*master->ibi.slots),
GFP_KERNEL);
- if (!master->ibi.slots) {
- ret = -ENOMEM;
- goto err_disable_sysclk;
- }
+ if (!master->ibi.slots)
+ return -ENOMEM;
writel(IBIR_THR(1), master->regs + CMD_IBI_THR_CTRL);
writel(MST_INT_IBIR_THR, master->regs + MST_IER);
writel(DEVS_CTRL_DEV_CLR_ALL, master->regs + DEVS_CTRL);
- ret = i3c_master_register(&master->base, &pdev->dev,
- &cdns_i3c_master_ops, false);
- if (ret)
- goto err_disable_sysclk;
-
- return 0;
-
-err_disable_sysclk:
- clk_disable_unprepare(master->sysclk);
-
-err_disable_pclk:
- clk_disable_unprepare(master->pclk);
-
- return ret;
+ return i3c_master_register(&master->base, &pdev->dev,
+ &cdns_i3c_master_ops, false);
}
static void cdns_i3c_master_remove(struct platform_device *pdev)
@@ -1668,9 +1629,6 @@ static void cdns_i3c_master_remove(struct platform_device *pdev)
cancel_work_sync(&master->hj_work);
i3c_master_unregister(&master->base);
-
- clk_disable_unprepare(master->sysclk);
- clk_disable_unprepare(master->pclk);
}
static struct platform_driver cdns_i3c_master = {
diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
index bc4538694540..60f1175f1f37 100644
--- a/drivers/i3c/master/mipi-i3c-hci/core.c
+++ b/drivers/i3c/master/mipi-i3c-hci/core.c
@@ -395,7 +395,7 @@ static int i3c_hci_i2c_xfers(struct i2c_dev_desc *dev,
ret = hci->io->queue_xfer(hci, xfer, nxfers);
if (ret)
goto out;
- if (!wait_for_completion_timeout(&done, HZ) &&
+ if (!wait_for_completion_timeout(&done, m->i2c.timeout) &&
hci->io->dequeue_xfer(hci, xfer, nxfers)) {
ret = -ETIME;
goto out;
diff --git a/drivers/i3c/master/renesas-i3c.c b/drivers/i3c/master/renesas-i3c.c
new file mode 100644
index 000000000000..174d3dc5d276
--- /dev/null
+++ b/drivers/i3c/master/renesas-i3c.c
@@ -0,0 +1,1404 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas I3C Controller driver
+ * Copyright (C) 2023-25 Renesas Electronics Corp.
+ *
+ * TODO: IBI support, HotJoin support, Target support
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/i3c/master.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/iopoll.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include "../internals.h"
+
+#define PRTS 0x00
+#define PRTS_PRTMD BIT(0)
+
+#define BCTL 0x14
+#define BCTL_INCBA BIT(0)
+#define BCTL_HJACKCTL BIT(8)
+#define BCTL_ABT BIT(29)
+#define BCTL_BUSE BIT(31)
+
+#define MSDVAD 0x18
+#define MSDVAD_MDYAD(x) FIELD_PREP(GENMASK(21, 16), x)
+#define MSDVAD_MDYADV BIT(31)
+
+#define RSTCTL 0x20
+#define RSTCTL_RI3CRST BIT(0)
+#define RSTCTL_INTLRST BIT(16)
+
+#define INST 0x30
+
+#define IBINCTL 0x58
+#define IBINCTL_NRHJCTL BIT(0)
+#define IBINCTL_NRMRCTL BIT(1)
+#define IBINCTL_NRSIRCTL BIT(3)
+
+#define SVCTL 0x64
+
+#define REFCKCTL 0x70
+#define REFCKCTL_IREFCKS(x) FIELD_PREP(GENMASK(2, 0), x)
+
+#define STDBR 0x74
+#define STDBR_SBRLO(cond, x) FIELD_PREP(GENMASK(7, 0), (x) >> (cond))
+#define STDBR_SBRHO(cond, x) FIELD_PREP(GENMASK(15, 8), (x) >> (cond))
+#define STDBR_SBRLP(x) FIELD_PREP(GENMASK(21, 16), x)
+#define STDBR_SBRHP(x) FIELD_PREP(GENMASK(29, 24), x)
+#define STDBR_DSBRPO BIT(31)
+
+#define EXTBR 0x78
+#define EXTBR_EBRLO(x) FIELD_PREP(GENMASK(7, 0), x)
+#define EXTBR_EBRHO(x) FIELD_PREP(GENMASK(15, 8), x)
+#define EXTBR_EBRLP(x) FIELD_PREP(GENMASK(21, 16), x)
+#define EXTBR_EBRHP(x) FIELD_PREP(GENMASK(29, 24), x)
+
+#define BFRECDT 0x7c
+#define BFRECDT_FRECYC(x) FIELD_PREP(GENMASK(8, 0), x)
+
+#define BAVLCDT 0x80
+#define BAVLCDT_AVLCYC(x) FIELD_PREP(GENMASK(8, 0), x)
+
+#define BIDLCDT 0x84
+#define BIDLCDT_IDLCYC(x) FIELD_PREP(GENMASK(17, 0), x)
+
+#define ACKCTL 0xa0
+#define ACKCTL_ACKT BIT(1)
+#define ACKCTL_ACKTWP BIT(2)
+
+#define SCSTRCTL 0xa4
+#define SCSTRCTL_ACKTWE BIT(0)
+#define SCSTRCTL_RWE BIT(1)
+
+#define SCSTLCTL 0xb0
+
+#define CNDCTL 0x140
+#define CNDCTL_STCND BIT(0)
+#define CNDCTL_SRCND BIT(1)
+#define CNDCTL_SPCND BIT(2)
+
+#define NCMDQP 0x150 /* Normal Command Queue */
+#define NCMDQP_CMD_ATTR(x) FIELD_PREP(GENMASK(2, 0), x)
+#define NCMDQP_IMMED_XFER 0x01
+#define NCMDQP_ADDR_ASSGN 0x02
+#define NCMDQP_TID(x) FIELD_PREP(GENMASK(6, 3), x)
+#define NCMDQP_CMD(x) FIELD_PREP(GENMASK(14, 7), x)
+#define NCMDQP_CP BIT(15)
+#define NCMDQP_DEV_INDEX(x) FIELD_PREP(GENMASK(20, 16), x)
+#define NCMDQP_BYTE_CNT(x) FIELD_PREP(GENMASK(25, 23), x)
+#define NCMDQP_DEV_COUNT(x) FIELD_PREP(GENMASK(29, 26), x)
+#define NCMDQP_MODE(x) FIELD_PREP(GENMASK(28, 26), x)
+#define NCMDQP_RNW(x) FIELD_PREP(GENMASK(29, 29), x)
+#define NCMDQP_ROC BIT(30)
+#define NCMDQP_TOC BIT(31)
+#define NCMDQP_DATA_LENGTH(x) FIELD_PREP(GENMASK(31, 16), x)
+
+#define NRSPQP 0x154 /* Normal Respone Queue */
+#define NRSPQP_NO_ERROR 0
+#define NRSPQP_ERROR_CRC 1
+#define NRSPQP_ERROR_PARITY 2
+#define NRSPQP_ERROR_FRAME 3
+#define NRSPQP_ERROR_IBA_NACK 4
+#define NRSPQP_ERROR_ADDRESS_NACK 5
+#define NRSPQP_ERROR_OVER_UNDER_FLOW 6
+#define NRSPQP_ERROR_TRANSF_ABORT 8
+#define NRSPQP_ERROR_I2C_W_NACK_ERR 9
+#define NRSPQP_ERROR_UNSUPPORTED 10
+#define NRSPQP_DATA_LEN(x) FIELD_GET(GENMASK(15, 0), x)
+#define NRSPQP_ERR_STATUS(x) FIELD_GET(GENMASK(31, 28), x)
+
+#define NTDTBP0 0x158 /* Normal Transfer Data Buffer */
+#define NTDTBP0_DEPTH 16
+
+#define NQTHCTL 0x190
+#define NQTHCTL_CMDQTH(x) FIELD_PREP(GENMASK(1, 0), x)
+#define NQTHCTL_IBIDSSZ(x) FIELD_PREP(GENMASK(23, 16), x)
+
+#define NTBTHCTL0 0x194
+
+#define NRQTHCTL 0x1c0
+
+#define BST 0x1d0
+#define BST_STCNDDF BIT(0)
+#define BST_SPCNDDF BIT(1)
+#define BST_NACKDF BIT(4)
+#define BST_TENDF BIT(8)
+
+#define BSTE 0x1d4
+#define BSTE_STCNDDE BIT(0)
+#define BSTE_SPCNDDE BIT(1)
+#define BSTE_NACKDE BIT(4)
+#define BSTE_TENDE BIT(8)
+#define BSTE_ALE BIT(16)
+#define BSTE_TODE BIT(20)
+#define BSTE_WUCNDDE BIT(24)
+#define BSTE_ALL_FLAG (BSTE_STCNDDE | BSTE_SPCNDDE |\
+ BSTE_NACKDE | BSTE_TENDE |\
+ BSTE_ALE | BSTE_TODE | BSTE_WUCNDDE)
+
+#define BIE 0x1d8
+#define BIE_STCNDDIE BIT(0)
+#define BIE_SPCNDDIE BIT(1)
+#define BIE_NACKDIE BIT(4)
+#define BIE_TENDIE BIT(8)
+
+#define NTST 0x1e0
+#define NTST_TDBEF0 BIT(0)
+#define NTST_RDBFF0 BIT(1)
+#define NTST_CMDQEF BIT(3)
+#define NTST_RSPQFF BIT(4)
+#define NTST_TABTF BIT(5)
+#define NTST_TEF BIT(9)
+
+#define NTSTE 0x1e4
+#define NTSTE_TDBEE0 BIT(0)
+#define NTSTE_RDBFE0 BIT(1)
+#define NTSTE_IBIQEFE BIT(2)
+#define NTSTE_CMDQEE BIT(3)
+#define NTSTE_RSPQFE BIT(4)
+#define NTSTE_TABTE BIT(5)
+#define NTSTE_TEE BIT(9)
+#define NTSTE_RSQFE BIT(20)
+#define NTSTE_ALL_FLAG (NTSTE_TDBEE0 | NTSTE_RDBFE0 |\
+ NTSTE_IBIQEFE | NTSTE_CMDQEE |\
+ NTSTE_RSPQFE | NTSTE_TABTE |\
+ NTSTE_TEE | NTSTE_RSQFE)
+
+#define NTIE 0x1e8
+#define NTIE_TDBEIE0 BIT(0)
+#define NTIE_RDBFIE0 BIT(1)
+#define NTIE_IBIQEFIE BIT(2)
+#define NTIE_RSPQFIE BIT(4)
+#define NTIE_RSQFIE BIT(20)
+
+#define BCST 0x210
+#define BCST_BFREF BIT(0)
+
+#define DATBAS(x) (0x224 + 0x8 * (x))
+#define DATBAS_DVSTAD(x) FIELD_PREP(GENMASK(6, 0), x)
+#define DATBAS_DVDYAD(x) FIELD_PREP(GENMASK(23, 16), x)
+
+#define NDBSTLV0 0x398
+#define NDBSTLV0_RDBLV(x) FIELD_GET(GENMASK(15, 8), x)
+
+#define RENESAS_I3C_MAX_DEVS 8
+#define I2C_INIT_MSG -1
+
+enum i3c_internal_state {
+ I3C_INTERNAL_STATE_DISABLED,
+ I3C_INTERNAL_STATE_CONTROLLER_IDLE,
+ I3C_INTERNAL_STATE_CONTROLLER_ENTDAA,
+ I3C_INTERNAL_STATE_CONTROLLER_SETDASA,
+ I3C_INTERNAL_STATE_CONTROLLER_WRITE,
+ I3C_INTERNAL_STATE_CONTROLLER_READ,
+ I3C_INTERNAL_STATE_CONTROLLER_COMMAND_WRITE,
+ I3C_INTERNAL_STATE_CONTROLLER_COMMAND_READ,
+};
+
+enum renesas_i3c_event {
+ I3C_COMMAND_ADDRESS_ASSIGNMENT,
+ I3C_WRITE,
+ I3C_READ,
+ I3C_COMMAND_WRITE,
+ I3C_COMMAND_READ,
+};
+
+struct renesas_i3c_cmd {
+ u32 cmd0;
+ u32 len;
+ const void *tx_buf;
+ u32 tx_count;
+ void *rx_buf;
+ u32 rx_count;
+ u32 err;
+ u8 rnw;
+ /* i2c xfer */
+ int i2c_bytes_left;
+ int i2c_is_last;
+ u8 *i2c_buf;
+ const struct i2c_msg *msg;
+};
+
+struct renesas_i3c_xfer {
+ struct list_head node;
+ struct completion comp;
+ int ret;
+ bool is_i2c_xfer;
+ unsigned int ncmds;
+ struct renesas_i3c_cmd cmds[] __counted_by(ncmds);
+};
+
+struct renesas_i3c_xferqueue {
+ struct list_head list;
+ struct renesas_i3c_xfer *cur;
+ /* Lock for accessing the xfer queue */
+ spinlock_t lock;
+};
+
+struct renesas_i3c {
+ struct i3c_master_controller base;
+ enum i3c_internal_state internal_state;
+ u16 maxdevs;
+ u32 free_pos;
+ u32 i2c_STDBR;
+ u32 i3c_STDBR;
+ u8 addrs[RENESAS_I3C_MAX_DEVS];
+ struct renesas_i3c_xferqueue xferqueue;
+ void __iomem *regs;
+ struct clk *tclk;
+};
+
+struct renesas_i3c_i2c_dev_data {
+ u8 index;
+};
+
+struct renesas_i3c_irq_desc {
+ const char *name;
+ irq_handler_t isr;
+ const char *desc;
+};
+
+struct renesas_i3c_config {
+ unsigned int has_pclkrw:1;
+};
+
+static inline void renesas_i3c_reg_update(void __iomem *reg, u32 mask, u32 val)
+{
+ u32 data = readl(reg);
+
+ data &= ~mask;
+ data |= (val & mask);
+ writel(data, reg);
+}
+
+static inline u32 renesas_readl(void __iomem *base, u32 reg)
+{
+ return readl(base + reg);
+}
+
+static inline void renesas_writel(void __iomem *base, u32 reg, u32 val)
+{
+ writel(val, base + reg);
+}
+
+static void renesas_set_bit(void __iomem *base, u32 reg, u32 val)
+{
+ renesas_i3c_reg_update(base + reg, val, val);
+}
+
+static void renesas_clear_bit(void __iomem *base, u32 reg, u32 val)
+{
+ renesas_i3c_reg_update(base + reg, val, 0);
+}
+
+static inline struct renesas_i3c *to_renesas_i3c(struct i3c_master_controller *m)
+{
+ return container_of(m, struct renesas_i3c, base);
+}
+
+static inline u32 datbas_dvdyad_with_parity(u8 addr)
+{
+ return DATBAS_DVDYAD(addr | (parity8(addr) ? 0 : BIT(7)));
+}
+
+static int renesas_i3c_get_free_pos(struct renesas_i3c *i3c)
+{
+ if (!(i3c->free_pos & GENMASK(i3c->maxdevs - 1, 0)))
+ return -ENOSPC;
+
+ return ffs(i3c->free_pos) - 1;
+}
+
+static int renesas_i3c_get_addr_pos(struct renesas_i3c *i3c, u8 addr)
+{
+ int pos;
+
+ for (pos = 0; pos < i3c->maxdevs; pos++) {
+ if (addr == i3c->addrs[pos])
+ return pos;
+ }
+
+ return -EINVAL;
+}
+
+static struct renesas_i3c_xfer *renesas_i3c_alloc_xfer(struct renesas_i3c *i3c,
+ unsigned int ncmds)
+{
+ struct renesas_i3c_xfer *xfer;
+
+ xfer = kzalloc(struct_size(xfer, cmds, ncmds), GFP_KERNEL);
+ if (!xfer)
+ return NULL;
+
+ INIT_LIST_HEAD(&xfer->node);
+ xfer->ncmds = ncmds;
+ xfer->ret = -ETIMEDOUT;
+
+ return xfer;
+}
+
+static void renesas_i3c_start_xfer_locked(struct renesas_i3c *i3c)
+{
+ struct renesas_i3c_xfer *xfer = i3c->xferqueue.cur;
+ struct renesas_i3c_cmd *cmd;
+ u32 cmd1;
+
+ if (!xfer)
+ return;
+
+ cmd = xfer->cmds;
+
+ switch (i3c->internal_state) {
+ case I3C_INTERNAL_STATE_CONTROLLER_ENTDAA:
+ case I3C_INTERNAL_STATE_CONTROLLER_SETDASA:
+ renesas_set_bit(i3c->regs, NTIE, NTIE_RSPQFIE);
+ renesas_writel(i3c->regs, NCMDQP, cmd->cmd0);
+ renesas_writel(i3c->regs, NCMDQP, 0);
+ break;
+ case I3C_INTERNAL_STATE_CONTROLLER_WRITE:
+ case I3C_INTERNAL_STATE_CONTROLLER_COMMAND_WRITE:
+ renesas_set_bit(i3c->regs, NTIE, NTIE_RSPQFIE);
+ if (cmd->len <= 4) {
+ cmd->cmd0 |= NCMDQP_CMD_ATTR(NCMDQP_IMMED_XFER);
+ cmd->cmd0 |= NCMDQP_BYTE_CNT(cmd->len);
+ cmd->tx_count = cmd->len;
+ cmd1 = cmd->len == 0 ? 0 : *(u32 *)cmd->tx_buf;
+ } else {
+ cmd1 = NCMDQP_DATA_LENGTH(cmd->len);
+ }
+ renesas_writel(i3c->regs, NCMDQP, cmd->cmd0);
+ renesas_writel(i3c->regs, NCMDQP, cmd1);
+ break;
+ case I3C_INTERNAL_STATE_CONTROLLER_READ:
+ case I3C_INTERNAL_STATE_CONTROLLER_COMMAND_READ:
+ renesas_set_bit(i3c->regs, NTIE, NTIE_RDBFIE0);
+ cmd1 = NCMDQP_DATA_LENGTH(cmd->len);
+ renesas_writel(i3c->regs, NCMDQP, cmd->cmd0);
+ renesas_writel(i3c->regs, NCMDQP, cmd1);
+ break;
+ default:
+ break;
+ }
+
+ /* Clear the command queue empty flag */
+ renesas_clear_bit(i3c->regs, NTST, NTST_CMDQEF);
+}
+
+static void renesas_i3c_dequeue_xfer_locked(struct renesas_i3c *i3c,
+ struct renesas_i3c_xfer *xfer)
+{
+ if (i3c->xferqueue.cur == xfer)
+ i3c->xferqueue.cur = NULL;
+ else
+ list_del_init(&xfer->node);
+}
+
+static void renesas_i3c_dequeue_xfer(struct renesas_i3c *i3c, struct renesas_i3c_xfer *xfer)
+{
+ scoped_guard(spinlock_irqsave, &i3c->xferqueue.lock)
+ renesas_i3c_dequeue_xfer_locked(i3c, xfer);
+}
+
+static void renesas_i3c_enqueue_xfer(struct renesas_i3c *i3c, struct renesas_i3c_xfer *xfer)
+{
+ reinit_completion(&xfer->comp);
+ scoped_guard(spinlock_irqsave, &i3c->xferqueue.lock) {
+ if (i3c->xferqueue.cur) {
+ list_add_tail(&xfer->node, &i3c->xferqueue.list);
+ } else {
+ i3c->xferqueue.cur = xfer;
+ if (!xfer->is_i2c_xfer)
+ renesas_i3c_start_xfer_locked(i3c);
+ }
+ }
+}
+
+static void renesas_i3c_wait_xfer(struct renesas_i3c *i3c, struct renesas_i3c_xfer *xfer)
+{
+ unsigned long time_left;
+
+ renesas_i3c_enqueue_xfer(i3c, xfer);
+
+ time_left = wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000));
+ if (!time_left)
+ renesas_i3c_dequeue_xfer(i3c, xfer);
+}
+
+static void renesas_i3c_set_prts(struct renesas_i3c *i3c, u32 val)
+{
+ /* Required sequence according to tnrza0140ae */
+ renesas_set_bit(i3c->regs, RSTCTL, RSTCTL_INTLRST);
+ renesas_writel(i3c->regs, PRTS, val);
+ renesas_clear_bit(i3c->regs, RSTCTL, RSTCTL_INTLRST);
+}
+
+static void renesas_i3c_bus_enable(struct i3c_master_controller *m, bool i3c_mode)
+{
+ struct renesas_i3c *i3c = to_renesas_i3c(m);
+
+ /* Setup either I3C or I2C protocol */
+ if (i3c_mode) {
+ renesas_i3c_set_prts(i3c, 0);
+ /* Revisit: INCBA handling, especially after I2C transfers */
+ renesas_set_bit(i3c->regs, BCTL, BCTL_HJACKCTL | BCTL_INCBA);
+ renesas_set_bit(i3c->regs, MSDVAD, MSDVAD_MDYADV);
+ renesas_writel(i3c->regs, STDBR, i3c->i3c_STDBR);
+ } else {
+ renesas_i3c_set_prts(i3c, PRTS_PRTMD);
+ renesas_writel(i3c->regs, STDBR, i3c->i2c_STDBR);
+ }
+
+ /* Enable I3C bus */
+ renesas_set_bit(i3c->regs, BCTL, BCTL_BUSE);
+}
+
+static int renesas_i3c_reset(struct renesas_i3c *i3c)
+{
+ u32 val;
+
+ renesas_writel(i3c->regs, BCTL, 0);
+ renesas_set_bit(i3c->regs, RSTCTL, RSTCTL_RI3CRST);
+
+ return read_poll_timeout(renesas_readl, val, !(val & RSTCTL_RI3CRST),
+ 0, 1000, false, i3c->regs, RSTCTL);
+}
+
+static int renesas_i3c_bus_init(struct i3c_master_controller *m)
+{
+ struct renesas_i3c *i3c = to_renesas_i3c(m);
+ struct i3c_bus *bus = i3c_master_get_bus(m);
+ struct i3c_device_info info = {};
+ struct i2c_timings t;
+ unsigned long rate;
+ u32 double_SBR, val;
+ int cks, pp_high_ticks, pp_low_ticks, i3c_total_ticks;
+ int od_high_ticks, od_low_ticks, i2c_total_ticks;
+ int ret;
+
+ rate = clk_get_rate(i3c->tclk);
+ if (!rate)
+ return -EINVAL;
+
+ ret = renesas_i3c_reset(i3c);
+ if (ret)
+ return ret;
+
+ i2c_total_ticks = DIV_ROUND_UP(rate, bus->scl_rate.i2c);
+ i3c_total_ticks = DIV_ROUND_UP(rate, bus->scl_rate.i3c);
+
+ i2c_parse_fw_timings(&m->dev, &t, true);
+
+ for (cks = 0; cks < 7; cks++) {
+ /* SCL low-period calculation in Open-drain mode */
+ od_low_ticks = ((i2c_total_ticks * 6) / 10);
+
+ /* SCL clock calculation in Push-Pull mode */
+ if (bus->mode == I3C_BUS_MODE_PURE)
+ pp_high_ticks = ((i3c_total_ticks * 5) / 10);
+ else
+ pp_high_ticks = DIV_ROUND_UP(I3C_BUS_THIGH_MIXED_MAX_NS,
+ NSEC_PER_SEC / rate);
+ pp_low_ticks = i3c_total_ticks - pp_high_ticks;
+
+ if ((od_low_ticks / 2) <= 0xFF && pp_low_ticks < 0x3F)
+ break;
+
+ i2c_total_ticks /= 2;
+ i3c_total_ticks /= 2;
+ rate /= 2;
+ }
+
+ /* SCL clock period calculation in Open-drain mode */
+ if ((od_low_ticks / 2) > 0xFF || pp_low_ticks > 0x3F) {
+ dev_err(&m->dev, "invalid speed (i2c-scl = %lu Hz, i3c-scl = %lu Hz). Too slow.\n",
+ (unsigned long)bus->scl_rate.i2c, (unsigned long)bus->scl_rate.i3c);
+ return -EINVAL;
+ }
+
+ /* SCL high-period calculation in Open-drain mode */
+ od_high_ticks = i2c_total_ticks - od_low_ticks;
+
+ /* Standard Bit Rate setting */
+ double_SBR = od_low_ticks > 0xFF ? 1 : 0;
+ i3c->i3c_STDBR = (double_SBR ? STDBR_DSBRPO : 0) |
+ STDBR_SBRLO(double_SBR, od_low_ticks) |
+ STDBR_SBRHO(double_SBR, od_high_ticks) |
+ STDBR_SBRLP(pp_low_ticks) |
+ STDBR_SBRHP(pp_high_ticks);
+
+ od_low_ticks -= t.scl_fall_ns / (NSEC_PER_SEC / rate) + 1;
+ od_high_ticks -= t.scl_rise_ns / (NSEC_PER_SEC / rate) + 1;
+ i3c->i2c_STDBR = (double_SBR ? STDBR_DSBRPO : 0) |
+ STDBR_SBRLO(double_SBR, od_low_ticks) |
+ STDBR_SBRHO(double_SBR, od_high_ticks) |
+ STDBR_SBRLP(pp_low_ticks) |
+ STDBR_SBRHP(pp_high_ticks);
+ renesas_writel(i3c->regs, STDBR, i3c->i3c_STDBR);
+
+ /* Extended Bit Rate setting */
+ renesas_writel(i3c->regs, EXTBR, EXTBR_EBRLO(od_low_ticks) |
+ EXTBR_EBRHO(od_high_ticks) |
+ EXTBR_EBRLP(pp_low_ticks) |
+ EXTBR_EBRHP(pp_high_ticks));
+
+ renesas_writel(i3c->regs, REFCKCTL, REFCKCTL_IREFCKS(cks));
+
+ /* Disable Slave Mode */
+ renesas_writel(i3c->regs, SVCTL, 0);
+
+ /* Initialize Queue/Buffer threshold */
+ renesas_writel(i3c->regs, NQTHCTL, NQTHCTL_IBIDSSZ(6) |
+ NQTHCTL_CMDQTH(1));
+
+ /* The only supported configuration is two entries*/
+ renesas_writel(i3c->regs, NTBTHCTL0, 0);
+ /* Interrupt when there is one entry in the queue */
+ renesas_writel(i3c->regs, NRQTHCTL, 0);
+
+ /* Enable all Bus/Transfer Status Flags */
+ renesas_writel(i3c->regs, BSTE, BSTE_ALL_FLAG);
+ renesas_writel(i3c->regs, NTSTE, NTSTE_ALL_FLAG);
+
+ /* Interrupt enable settings */
+ renesas_writel(i3c->regs, BIE, BIE_NACKDIE | BIE_TENDIE);
+ renesas_writel(i3c->regs, NTIE, 0);
+
+ /* Clear Status register */
+ renesas_writel(i3c->regs, NTST, 0);
+ renesas_writel(i3c->regs, INST, 0);
+ renesas_writel(i3c->regs, BST, 0);
+
+ /* Hot-Join Acknowlege setting. */
+ renesas_set_bit(i3c->regs, BCTL, BCTL_HJACKCTL);
+
+ renesas_writel(i3c->regs, IBINCTL, IBINCTL_NRHJCTL | IBINCTL_NRMRCTL |
+ IBINCTL_NRSIRCTL);
+
+ renesas_writel(i3c->regs, SCSTLCTL, 0);
+ renesas_set_bit(i3c->regs, SCSTRCTL, SCSTRCTL_ACKTWE);
+
+ /* Bus condition timing */
+ val = DIV_ROUND_UP(I3C_BUS_TBUF_MIXED_FM_MIN_NS, NSEC_PER_SEC / rate);
+ renesas_writel(i3c->regs, BFRECDT, BFRECDT_FRECYC(val));
+
+ val = DIV_ROUND_UP(I3C_BUS_TAVAL_MIN_NS, NSEC_PER_SEC / rate);
+ renesas_writel(i3c->regs, BAVLCDT, BAVLCDT_AVLCYC(val));
+
+ val = DIV_ROUND_UP(I3C_BUS_TIDLE_MIN_NS, NSEC_PER_SEC / rate);
+ renesas_writel(i3c->regs, BIDLCDT, BIDLCDT_IDLCYC(val));
+
+ ret = i3c_master_get_free_addr(m, 0);
+ if (ret < 0)
+ return ret;
+
+ renesas_writel(i3c->regs, MSDVAD, MSDVAD_MDYAD(ret) | MSDVAD_MDYADV);
+
+ memset(&info, 0, sizeof(info));
+ info.dyn_addr = ret;
+ return i3c_master_set_info(&i3c->base, &info);
+}
+
+static void renesas_i3c_bus_cleanup(struct i3c_master_controller *m)
+{
+ struct renesas_i3c *i3c = to_renesas_i3c(m);
+
+ renesas_i3c_reset(i3c);
+}
+
+static int renesas_i3c_daa(struct i3c_master_controller *m)
+{
+ struct renesas_i3c *i3c = to_renesas_i3c(m);
+ struct renesas_i3c_cmd *cmd;
+ u32 olddevs, newdevs;
+ u8 last_addr = 0, pos;
+ int ret;
+
+ struct renesas_i3c_xfer *xfer __free(kfree) = renesas_i3c_alloc_xfer(i3c, 1);
+ if (!xfer)
+ return -ENOMEM;
+
+ /* Enable I3C bus. */
+ renesas_i3c_bus_enable(m, true);
+
+ olddevs = ~(i3c->free_pos);
+ i3c->internal_state = I3C_INTERNAL_STATE_CONTROLLER_ENTDAA;
+
+ /* Setting DATBASn registers for target devices. */
+ for (pos = 0; pos < i3c->maxdevs; pos++) {
+ if (olddevs & BIT(pos))
+ continue;
+
+ ret = i3c_master_get_free_addr(m, last_addr + 1);
+ if (ret < 0)
+ return -ENOSPC;
+
+ i3c->addrs[pos] = ret;
+ last_addr = ret;
+
+ renesas_writel(i3c->regs, DATBAS(pos), datbas_dvdyad_with_parity(ret));
+ }
+
+ init_completion(&xfer->comp);
+ cmd = xfer->cmds;
+ cmd->rx_count = 0;
+
+ ret = renesas_i3c_get_free_pos(i3c);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Setup the command descriptor to start the ENTDAA command
+ * and starting at the selected device index.
+ */
+ cmd->cmd0 = NCMDQP_CMD_ATTR(NCMDQP_ADDR_ASSGN) | NCMDQP_ROC |
+ NCMDQP_TID(I3C_COMMAND_ADDRESS_ASSIGNMENT) |
+ NCMDQP_CMD(I3C_CCC_ENTDAA) | NCMDQP_DEV_INDEX(ret) |
+ NCMDQP_DEV_COUNT(i3c->maxdevs - ret) | NCMDQP_TOC;
+
+ renesas_i3c_wait_xfer(i3c, xfer);
+
+ newdevs = GENMASK(i3c->maxdevs - cmd->rx_count - 1, 0);
+ newdevs &= ~olddevs;
+
+ for (pos = 0; pos < i3c->maxdevs; pos++) {
+ if (newdevs & BIT(pos))
+ i3c_master_add_i3c_dev_locked(m, i3c->addrs[pos]);
+ }
+
+ return ret < 0 ? ret : 0;
+}
+
+static bool renesas_i3c_supports_ccc_cmd(struct i3c_master_controller *m,
+ const struct i3c_ccc_cmd *cmd)
+{
+ if (cmd->ndests > 1)
+ return false;
+
+ switch (cmd->id) {
+ case I3C_CCC_ENEC(true):
+ case I3C_CCC_ENEC(false):
+ case I3C_CCC_DISEC(true):
+ case I3C_CCC_DISEC(false):
+ case I3C_CCC_ENTAS(0, true):
+ case I3C_CCC_ENTAS(1, true):
+ case I3C_CCC_ENTAS(2, true):
+ case I3C_CCC_ENTAS(3, true):
+ case I3C_CCC_ENTAS(0, false):
+ case I3C_CCC_ENTAS(1, false):
+ case I3C_CCC_ENTAS(2, false):
+ case I3C_CCC_ENTAS(3, false):
+ case I3C_CCC_RSTDAA(true):
+ case I3C_CCC_RSTDAA(false):
+ case I3C_CCC_ENTDAA:
+ case I3C_CCC_DEFSLVS:
+ case I3C_CCC_SETMWL(true):
+ case I3C_CCC_SETMWL(false):
+ case I3C_CCC_SETMRL(true):
+ case I3C_CCC_SETMRL(false):
+ case I3C_CCC_ENTTM:
+ case I3C_CCC_SETDASA:
+ case I3C_CCC_SETNEWDA:
+ case I3C_CCC_GETMWL:
+ case I3C_CCC_GETMRL:
+ case I3C_CCC_GETPID:
+ case I3C_CCC_GETBCR:
+ case I3C_CCC_GETDCR:
+ case I3C_CCC_GETSTATUS:
+ case I3C_CCC_GETACCMST:
+ case I3C_CCC_GETMXDS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int renesas_i3c_send_ccc_cmd(struct i3c_master_controller *m,
+ struct i3c_ccc_cmd *ccc)
+{
+ struct renesas_i3c *i3c = to_renesas_i3c(m);
+ struct renesas_i3c_xfer *xfer;
+ struct renesas_i3c_cmd *cmd;
+ int ret, pos = 0;
+
+ if (ccc->id & I3C_CCC_DIRECT) {
+ pos = renesas_i3c_get_addr_pos(i3c, ccc->dests[0].addr);
+ if (pos < 0)
+ return pos;
+ }
+
+ xfer = renesas_i3c_alloc_xfer(i3c, 1);
+ if (!xfer)
+ return -ENOMEM;
+
+ renesas_i3c_bus_enable(m, true);
+
+ init_completion(&xfer->comp);
+ cmd = xfer->cmds;
+ cmd->rnw = ccc->rnw;
+ cmd->cmd0 = 0;
+
+ /* Calculate the command descriptor. */
+ switch (ccc->id) {
+ case I3C_CCC_SETDASA:
+ renesas_writel(i3c->regs, DATBAS(pos),
+ DATBAS_DVSTAD(ccc->dests[0].addr) |
+ DATBAS_DVDYAD(*(u8 *)ccc->dests[0].payload.data >> 1));
+ cmd->cmd0 = NCMDQP_CMD_ATTR(NCMDQP_ADDR_ASSGN) | NCMDQP_ROC |
+ NCMDQP_TID(I3C_COMMAND_ADDRESS_ASSIGNMENT) |
+ NCMDQP_CMD(I3C_CCC_SETDASA) | NCMDQP_DEV_INDEX(pos) |
+ NCMDQP_DEV_COUNT(0) | NCMDQP_TOC;
+ i3c->internal_state = I3C_INTERNAL_STATE_CONTROLLER_SETDASA;
+ break;
+ default:
+ /* Calculate the command descriptor. */
+ cmd->cmd0 = NCMDQP_TID(I3C_COMMAND_WRITE) | NCMDQP_MODE(0) |
+ NCMDQP_RNW(ccc->rnw) | NCMDQP_CMD(ccc->id) |
+ NCMDQP_ROC | NCMDQP_TOC | NCMDQP_CP |
+ NCMDQP_DEV_INDEX(pos);
+
+ if (ccc->rnw) {
+ cmd->rx_buf = ccc->dests[0].payload.data;
+ cmd->len = ccc->dests[0].payload.len;
+ cmd->rx_count = 0;
+ i3c->internal_state = I3C_INTERNAL_STATE_CONTROLLER_COMMAND_READ;
+ } else {
+ cmd->tx_buf = ccc->dests[0].payload.data;
+ cmd->len = ccc->dests[0].payload.len;
+ cmd->tx_count = 0;
+ i3c->internal_state = I3C_INTERNAL_STATE_CONTROLLER_COMMAND_WRITE;
+ }
+ }
+
+ renesas_i3c_wait_xfer(i3c, xfer);
+
+ ret = xfer->ret;
+ if (ret)
+ ccc->err = I3C_ERROR_M2;
+
+ kfree(xfer);
+
+ return ret;
+}
+
+static int renesas_i3c_priv_xfers(struct i3c_dev_desc *dev, struct i3c_priv_xfer *i3c_xfers,
+ int i3c_nxfers)
+{
+ struct i3c_master_controller *m = i3c_dev_get_master(dev);
+ struct renesas_i3c *i3c = to_renesas_i3c(m);
+ struct renesas_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+ struct renesas_i3c_xfer *xfer;
+ int i;
+
+ /* Enable I3C bus. */
+ renesas_i3c_bus_enable(m, true);
+
+ xfer = renesas_i3c_alloc_xfer(i3c, 1);
+ if (!xfer)
+ return -ENOMEM;
+
+ init_completion(&xfer->comp);
+
+ for (i = 0; i < i3c_nxfers; i++) {
+ struct renesas_i3c_cmd *cmd = xfer->cmds;
+
+ /* Calculate the Transfer Command Descriptor */
+ cmd->rnw = i3c_xfers[i].rnw;
+ cmd->cmd0 = NCMDQP_DEV_INDEX(data->index) | NCMDQP_MODE(0) |
+ NCMDQP_RNW(cmd->rnw) | NCMDQP_ROC | NCMDQP_TOC;
+
+ if (i3c_xfers[i].rnw) {
+ cmd->rx_count = 0;
+ cmd->cmd0 |= NCMDQP_TID(I3C_READ);
+ cmd->rx_buf = i3c_xfers[i].data.in;
+ cmd->len = i3c_xfers[i].len;
+ i3c->internal_state = I3C_INTERNAL_STATE_CONTROLLER_READ;
+ } else {
+ cmd->tx_count = 0;
+ cmd->cmd0 |= NCMDQP_TID(I3C_WRITE);
+ cmd->tx_buf = i3c_xfers[i].data.out;
+ cmd->len = i3c_xfers[i].len;
+ i3c->internal_state = I3C_INTERNAL_STATE_CONTROLLER_WRITE;
+ }
+
+ if (!i3c_xfers[i].rnw && i3c_xfers[i].len > 4) {
+ i3c_writel_fifo(i3c->regs + NTDTBP0, cmd->tx_buf, cmd->len);
+ if (cmd->len > NTDTBP0_DEPTH * sizeof(u32))
+ renesas_set_bit(i3c->regs, NTIE, NTIE_TDBEIE0);
+ }
+
+ renesas_i3c_wait_xfer(i3c, xfer);
+ }
+
+ return 0;
+}
+
+static int renesas_i3c_attach_i3c_dev(struct i3c_dev_desc *dev)
+{
+ struct i3c_master_controller *m = i3c_dev_get_master(dev);
+ struct renesas_i3c *i3c = to_renesas_i3c(m);
+ struct renesas_i3c_i2c_dev_data *data;
+ int pos;
+
+ pos = renesas_i3c_get_free_pos(i3c);
+ if (pos < 0)
+ return pos;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->index = pos;
+ i3c->addrs[pos] = dev->info.dyn_addr ? : dev->info.static_addr;
+ i3c->free_pos &= ~BIT(pos);
+
+ renesas_writel(i3c->regs, DATBAS(pos), DATBAS_DVSTAD(dev->info.static_addr) |
+ datbas_dvdyad_with_parity(i3c->addrs[pos]));
+ i3c_dev_set_master_data(dev, data);
+
+ return 0;
+}
+
+static int renesas_i3c_reattach_i3c_dev(struct i3c_dev_desc *dev,
+ u8 old_dyn_addr)
+{
+ struct i3c_master_controller *m = i3c_dev_get_master(dev);
+ struct renesas_i3c *i3c = to_renesas_i3c(m);
+ struct renesas_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+
+ i3c->addrs[data->index] = dev->info.dyn_addr ? dev->info.dyn_addr :
+ dev->info.static_addr;
+
+ return 0;
+}
+
+static void renesas_i3c_detach_i3c_dev(struct i3c_dev_desc *dev)
+{
+ struct renesas_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
+ struct i3c_master_controller *m = i3c_dev_get_master(dev);
+ struct renesas_i3c *i3c = to_renesas_i3c(m);
+
+ i3c_dev_set_master_data(dev, NULL);
+ i3c->addrs[data->index] = 0;
+ i3c->free_pos |= BIT(data->index);
+ kfree(data);
+}
+
+static int renesas_i3c_i2c_xfers(struct i2c_dev_desc *dev,
+ struct i2c_msg *i2c_xfers,
+ int i2c_nxfers)
+{
+ struct i3c_master_controller *m = i2c_dev_get_master(dev);
+ struct renesas_i3c *i3c = to_renesas_i3c(m);
+ struct renesas_i3c_cmd *cmd;
+ u8 start_bit = CNDCTL_STCND;
+ int i;
+
+ struct renesas_i3c_xfer *xfer __free(kfree) = renesas_i3c_alloc_xfer(i3c, 1);
+ if (!xfer)
+ return -ENOMEM;
+
+ if (!i2c_nxfers)
+ return 0;
+
+ renesas_i3c_bus_enable(m, false);
+
+ init_completion(&xfer->comp);
+ xfer->is_i2c_xfer = true;
+ cmd = xfer->cmds;
+
+ if (!(renesas_readl(i3c->regs, BCST) & BCST_BFREF)) {
+ cmd->err = -EBUSY;
+ return cmd->err;
+ }
+
+ renesas_writel(i3c->regs, BST, 0);
+
+ renesas_i3c_enqueue_xfer(i3c, xfer);
+
+ for (i = 0; i < i2c_nxfers; i++) {
+ cmd->i2c_bytes_left = I2C_INIT_MSG;
+ cmd->i2c_buf = i2c_xfers[i].buf;
+ cmd->msg = &i2c_xfers[i];
+ cmd->i2c_is_last = (i == i2c_nxfers - 1);
+
+ renesas_set_bit(i3c->regs, BIE, BIE_NACKDIE);
+ renesas_set_bit(i3c->regs, NTIE, NTIE_TDBEIE0);
+ renesas_set_bit(i3c->regs, BIE, BIE_STCNDDIE);
+
+ /* Issue Start condition */
+ renesas_set_bit(i3c->regs, CNDCTL, start_bit);
+
+ renesas_set_bit(i3c->regs, NTSTE, NTSTE_TDBEE0);
+
+ wait_for_completion_timeout(&xfer->comp, m->i2c.timeout);
+
+ if (cmd->err)
+ break;
+
+ start_bit = CNDCTL_SRCND;
+ }
+
+ renesas_i3c_dequeue_xfer(i3c, xfer);
+ return cmd->err;
+}
+
+static int renesas_i3c_attach_i2c_dev(struct i2c_dev_desc *dev)
+{
+ struct i3c_master_controller *m = i2c_dev_get_master(dev);
+ struct renesas_i3c *i3c = to_renesas_i3c(m);
+ struct renesas_i3c_i2c_dev_data *data;
+ int pos;
+
+ pos = renesas_i3c_get_free_pos(i3c);
+ if (pos < 0)
+ return pos;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->index = pos;
+ i3c->addrs[pos] = dev->addr;
+ i3c->free_pos &= ~BIT(pos);
+ i2c_dev_set_master_data(dev, data);
+
+ return 0;
+}
+
+static void renesas_i3c_detach_i2c_dev(struct i2c_dev_desc *dev)
+{
+ struct renesas_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev);
+ struct i3c_master_controller *m = i2c_dev_get_master(dev);
+ struct renesas_i3c *i3c = to_renesas_i3c(m);
+
+ i2c_dev_set_master_data(dev, NULL);
+ i3c->addrs[data->index] = 0;
+ i3c->free_pos |= BIT(data->index);
+ kfree(data);
+}
+
+static irqreturn_t renesas_i3c_tx_isr(int irq, void *data)
+{
+ struct renesas_i3c *i3c = data;
+ struct renesas_i3c_xfer *xfer;
+ struct renesas_i3c_cmd *cmd;
+ u8 val;
+
+ scoped_guard(spinlock, &i3c->xferqueue.lock) {
+ xfer = i3c->xferqueue.cur;
+ cmd = xfer->cmds;
+
+ if (xfer->is_i2c_xfer) {
+ if (!cmd->i2c_bytes_left)
+ return IRQ_NONE;
+
+ if (cmd->i2c_bytes_left != I2C_INIT_MSG) {
+ val = *cmd->i2c_buf;
+ cmd->i2c_buf++;
+ cmd->i2c_bytes_left--;
+ renesas_writel(i3c->regs, NTDTBP0, val);
+ }
+
+ if (cmd->i2c_bytes_left == 0) {
+ renesas_clear_bit(i3c->regs, NTIE, NTIE_TDBEIE0);
+ renesas_set_bit(i3c->regs, BIE, BIE_TENDIE);
+ }
+
+ /* Clear the Transmit Buffer Empty status flag. */
+ renesas_clear_bit(i3c->regs, NTST, NTST_TDBEF0);
+ } else {
+ i3c_writel_fifo(i3c->regs + NTDTBP0, cmd->tx_buf, cmd->len);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t renesas_i3c_resp_isr(int irq, void *data)
+{
+ struct renesas_i3c *i3c = data;
+ struct renesas_i3c_xfer *xfer;
+ struct renesas_i3c_cmd *cmd;
+ u32 resp_descriptor = renesas_readl(i3c->regs, NRSPQP);
+ u32 bytes_remaining = 0;
+ u32 ntst, data_len;
+ int ret = 0;
+
+ scoped_guard(spinlock, &i3c->xferqueue.lock) {
+ xfer = i3c->xferqueue.cur;
+ cmd = xfer->cmds;
+
+ /* Clear the Respone Queue Full status flag*/
+ renesas_clear_bit(i3c->regs, NTST, NTST_RSPQFF);
+
+ data_len = NRSPQP_DATA_LEN(resp_descriptor);
+
+ switch (i3c->internal_state) {
+ case I3C_INTERNAL_STATE_CONTROLLER_ENTDAA:
+ cmd->rx_count = data_len;
+ break;
+ case I3C_INTERNAL_STATE_CONTROLLER_WRITE:
+ case I3C_INTERNAL_STATE_CONTROLLER_COMMAND_WRITE:
+ /* Disable the transmit IRQ if it hasn't been disabled already. */
+ renesas_clear_bit(i3c->regs, NTIE, NTIE_TDBEIE0);
+ break;
+ case I3C_INTERNAL_STATE_CONTROLLER_READ:
+ case I3C_INTERNAL_STATE_CONTROLLER_COMMAND_READ:
+ if (NDBSTLV0_RDBLV(renesas_readl(i3c->regs, NDBSTLV0)) && !cmd->err)
+ bytes_remaining = data_len - cmd->rx_count;
+
+ i3c_readl_fifo(i3c->regs + NTDTBP0, cmd->rx_buf, bytes_remaining);
+ renesas_clear_bit(i3c->regs, NTIE, NTIE_RDBFIE0);
+ break;
+ default:
+ break;
+ }
+
+ switch (NRSPQP_ERR_STATUS(resp_descriptor)) {
+ case NRSPQP_NO_ERROR:
+ break;
+ case NRSPQP_ERROR_PARITY:
+ case NRSPQP_ERROR_IBA_NACK:
+ case NRSPQP_ERROR_TRANSF_ABORT:
+ case NRSPQP_ERROR_CRC:
+ case NRSPQP_ERROR_FRAME:
+ ret = -EIO;
+ break;
+ case NRSPQP_ERROR_OVER_UNDER_FLOW:
+ ret = -ENOSPC;
+ break;
+ case NRSPQP_ERROR_UNSUPPORTED:
+ ret = -EOPNOTSUPP;
+ break;
+ case NRSPQP_ERROR_I2C_W_NACK_ERR:
+ case NRSPQP_ERROR_ADDRESS_NACK:
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ /*
+ * If the transfer was aborted, then the abort flag must be cleared
+ * before notifying the application that a transfer has completed.
+ */
+ ntst = renesas_readl(i3c->regs, NTST);
+ if (ntst & NTST_TABTF)
+ renesas_clear_bit(i3c->regs, BCTL, BCTL_ABT);
+
+ /* Clear error status flags. */
+ renesas_clear_bit(i3c->regs, NTST, NTST_TEF | NTST_TABTF);
+
+ xfer->ret = ret;
+ complete(&xfer->comp);
+
+ xfer = list_first_entry_or_null(&i3c->xferqueue.list,
+ struct renesas_i3c_xfer, node);
+ if (xfer)
+ list_del_init(&xfer->node);
+
+ i3c->xferqueue.cur = xfer;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t renesas_i3c_tend_isr(int irq, void *data)
+{
+ struct renesas_i3c *i3c = data;
+ struct renesas_i3c_xfer *xfer;
+ struct renesas_i3c_cmd *cmd;
+
+ scoped_guard(spinlock, &i3c->xferqueue.lock) {
+ xfer = i3c->xferqueue.cur;
+ cmd = xfer->cmds;
+
+ if (xfer->is_i2c_xfer) {
+ if (renesas_readl(i3c->regs, BST) & BST_NACKDF) {
+ /* We got a NACKIE */
+ renesas_readl(i3c->regs, NTDTBP0); /* dummy read */
+ renesas_clear_bit(i3c->regs, BST, BST_NACKDF);
+ cmd->err = -ENXIO;
+ } else if (cmd->i2c_bytes_left) {
+ renesas_set_bit(i3c->regs, NTIE, NTIE_TDBEIE0);
+ return IRQ_NONE;
+ }
+
+ if (cmd->i2c_is_last || cmd->err) {
+ renesas_clear_bit(i3c->regs, BIE, BIE_TENDIE);
+ renesas_set_bit(i3c->regs, BIE, BIE_SPCNDDIE);
+ renesas_set_bit(i3c->regs, CNDCTL, CNDCTL_SPCND);
+ } else {
+ /* Transfer is complete, but do not send STOP */
+ renesas_clear_bit(i3c->regs, NTSTE, NTSTE_TDBEE0);
+ renesas_clear_bit(i3c->regs, BIE, BIE_TENDIE);
+ xfer->ret = 0;
+ complete(&xfer->comp);
+ }
+ }
+
+ /* Clear the Transmit Buffer Empty status flag. */
+ renesas_clear_bit(i3c->regs, BST, BST_TENDF);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t renesas_i3c_rx_isr(int irq, void *data)
+{
+ struct renesas_i3c *i3c = data;
+ struct renesas_i3c_xfer *xfer;
+ struct renesas_i3c_cmd *cmd;
+ int read_bytes;
+
+ /* If resp_isr already read the data and updated 'xfer', we can just leave */
+ if (!(renesas_readl(i3c->regs, NTIE) & NTIE_RDBFIE0))
+ return IRQ_NONE;
+
+ scoped_guard(spinlock, &i3c->xferqueue.lock) {
+ xfer = i3c->xferqueue.cur;
+ cmd = xfer->cmds;
+
+ if (xfer->is_i2c_xfer) {
+ if (!cmd->i2c_bytes_left)
+ return IRQ_NONE;
+
+ if (cmd->i2c_bytes_left == I2C_INIT_MSG) {
+ cmd->i2c_bytes_left = cmd->msg->len;
+ renesas_set_bit(i3c->regs, SCSTRCTL, SCSTRCTL_RWE);
+ renesas_readl(i3c->regs, NTDTBP0); /* dummy read */
+ if (cmd->i2c_bytes_left == 1)
+ renesas_writel(i3c->regs, ACKCTL, ACKCTL_ACKT | ACKCTL_ACKTWP);
+ return IRQ_HANDLED;
+ }
+
+ if (cmd->i2c_bytes_left == 1) {
+ /* STOP must come before we set ACKCTL! */
+ if (cmd->i2c_is_last) {
+ renesas_set_bit(i3c->regs, BIE, BIE_SPCNDDIE);
+ renesas_clear_bit(i3c->regs, BST, BST_SPCNDDF);
+ renesas_set_bit(i3c->regs, CNDCTL, CNDCTL_SPCND);
+ }
+ renesas_writel(i3c->regs, ACKCTL, ACKCTL_ACKT | ACKCTL_ACKTWP);
+ } else {
+ renesas_writel(i3c->regs, ACKCTL, ACKCTL_ACKTWP);
+ }
+
+ /* Reading acks the RIE interrupt */
+ *cmd->i2c_buf = renesas_readl(i3c->regs, NTDTBP0);
+ cmd->i2c_buf++;
+ cmd->i2c_bytes_left--;
+ } else {
+ read_bytes = NDBSTLV0_RDBLV(renesas_readl(i3c->regs, NDBSTLV0)) * sizeof(u32);
+ i3c_readl_fifo(i3c->regs + NTDTBP0, cmd->rx_buf, read_bytes);
+ cmd->rx_count = read_bytes;
+ }
+
+ /* Clear the Read Buffer Full status flag. */
+ renesas_clear_bit(i3c->regs, NTST, NTST_RDBFF0);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t renesas_i3c_stop_isr(int irq, void *data)
+{
+ struct renesas_i3c *i3c = data;
+ struct renesas_i3c_xfer *xfer;
+
+ scoped_guard(spinlock, &i3c->xferqueue.lock) {
+ xfer = i3c->xferqueue.cur;
+
+ /* read back registers to confirm writes have fully propagated */
+ renesas_writel(i3c->regs, BST, 0);
+ renesas_readl(i3c->regs, BST);
+ renesas_writel(i3c->regs, BIE, 0);
+ renesas_clear_bit(i3c->regs, NTST, NTST_TDBEF0 | NTST_RDBFF0);
+ renesas_clear_bit(i3c->regs, SCSTRCTL, SCSTRCTL_RWE);
+
+ xfer->ret = 0;
+ complete(&xfer->comp);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t renesas_i3c_start_isr(int irq, void *data)
+{
+ struct renesas_i3c *i3c = data;
+ struct renesas_i3c_xfer *xfer;
+ struct renesas_i3c_cmd *cmd;
+ u8 val;
+
+ scoped_guard(spinlock, &i3c->xferqueue.lock) {
+ xfer = i3c->xferqueue.cur;
+ cmd = xfer->cmds;
+
+ if (xfer->is_i2c_xfer) {
+ if (!cmd->i2c_bytes_left)
+ return IRQ_NONE;
+
+ if (cmd->i2c_bytes_left == I2C_INIT_MSG) {
+ if (cmd->msg->flags & I2C_M_RD) {
+ /* On read, switch over to receive interrupt */
+ renesas_clear_bit(i3c->regs, NTIE, NTIE_TDBEIE0);
+ renesas_set_bit(i3c->regs, NTIE, NTIE_RDBFIE0);
+ } else {
+ /* On write, initialize length */
+ cmd->i2c_bytes_left = cmd->msg->len;
+ }
+
+ val = i2c_8bit_addr_from_msg(cmd->msg);
+ renesas_writel(i3c->regs, NTDTBP0, val);
+ }
+ }
+
+ renesas_clear_bit(i3c->regs, BIE, BIE_STCNDDIE);
+ renesas_clear_bit(i3c->regs, BST, BST_STCNDDF);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static const struct i3c_master_controller_ops renesas_i3c_ops = {
+ .bus_init = renesas_i3c_bus_init,
+ .bus_cleanup = renesas_i3c_bus_cleanup,
+ .attach_i3c_dev = renesas_i3c_attach_i3c_dev,
+ .reattach_i3c_dev = renesas_i3c_reattach_i3c_dev,
+ .detach_i3c_dev = renesas_i3c_detach_i3c_dev,
+ .do_daa = renesas_i3c_daa,
+ .supports_ccc_cmd = renesas_i3c_supports_ccc_cmd,
+ .send_ccc_cmd = renesas_i3c_send_ccc_cmd,
+ .priv_xfers = renesas_i3c_priv_xfers,
+ .attach_i2c_dev = renesas_i3c_attach_i2c_dev,
+ .detach_i2c_dev = renesas_i3c_detach_i2c_dev,
+ .i2c_xfers = renesas_i3c_i2c_xfers,
+};
+
+static const struct renesas_i3c_irq_desc renesas_i3c_irqs[] = {
+ { .name = "resp", .isr = renesas_i3c_resp_isr, .desc = "i3c-resp" },
+ { .name = "rx", .isr = renesas_i3c_rx_isr, .desc = "i3c-rx" },
+ { .name = "tx", .isr = renesas_i3c_tx_isr, .desc = "i3c-tx" },
+ { .name = "st", .isr = renesas_i3c_start_isr, .desc = "i3c-start" },
+ { .name = "sp", .isr = renesas_i3c_stop_isr, .desc = "i3c-stop" },
+ { .name = "tend", .isr = renesas_i3c_tend_isr, .desc = "i3c-tend" },
+ { .name = "nack", .isr = renesas_i3c_tend_isr, .desc = "i3c-nack" },
+};
+
+static int renesas_i3c_probe(struct platform_device *pdev)
+{
+ struct renesas_i3c *i3c;
+ struct reset_control *reset;
+ struct clk *clk;
+ const struct renesas_i3c_config *config = of_device_get_match_data(&pdev->dev);
+ int ret, i;
+
+ if (!config)
+ return -ENODATA;
+
+ i3c = devm_kzalloc(&pdev->dev, sizeof(*i3c), GFP_KERNEL);
+ if (!i3c)
+ return -ENOMEM;
+
+ i3c->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(i3c->regs))
+ return PTR_ERR(i3c->regs);
+
+ clk = devm_clk_get_enabled(&pdev->dev, "pclk");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ if (config->has_pclkrw) {
+ clk = devm_clk_get_enabled(&pdev->dev, "pclkrw");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ }
+
+ i3c->tclk = devm_clk_get_enabled(&pdev->dev, "tclk");
+ if (IS_ERR(i3c->tclk))
+ return PTR_ERR(i3c->tclk);
+
+ reset = devm_reset_control_get_optional_exclusive_deasserted(&pdev->dev, "tresetn");
+ if (IS_ERR(reset))
+ return dev_err_probe(&pdev->dev, PTR_ERR(reset),
+ "Error: missing tresetn ctrl\n");
+
+ reset = devm_reset_control_get_optional_exclusive_deasserted(&pdev->dev, "presetn");
+ if (IS_ERR(reset))
+ return dev_err_probe(&pdev->dev, PTR_ERR(reset),
+ "Error: missing presetn ctrl\n");
+
+ spin_lock_init(&i3c->xferqueue.lock);
+ INIT_LIST_HEAD(&i3c->xferqueue.list);
+
+ ret = renesas_i3c_reset(i3c);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(renesas_i3c_irqs); i++) {
+ ret = platform_get_irq_byname(pdev, renesas_i3c_irqs[i].name);
+ if (ret < 0)
+ return ret;
+
+ ret = devm_request_irq(&pdev->dev, ret, renesas_i3c_irqs[i].isr,
+ 0, renesas_i3c_irqs[i].desc, i3c);
+ if (ret)
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, i3c);
+
+ i3c->maxdevs = RENESAS_I3C_MAX_DEVS;
+ i3c->free_pos = GENMASK(i3c->maxdevs - 1, 0);
+
+ return i3c_master_register(&i3c->base, &pdev->dev, &renesas_i3c_ops, false);
+}
+
+static void renesas_i3c_remove(struct platform_device *pdev)
+{
+ struct renesas_i3c *i3c = platform_get_drvdata(pdev);
+
+ i3c_master_unregister(&i3c->base);
+}
+
+static const struct renesas_i3c_config empty_i3c_config = {
+};
+
+static const struct renesas_i3c_config r9a09g047_i3c_config = {
+ .has_pclkrw = 1,
+};
+
+static const struct of_device_id renesas_i3c_of_ids[] = {
+ { .compatible = "renesas,r9a08g045-i3c", .data = &empty_i3c_config },
+ { .compatible = "renesas,r9a09g047-i3c", .data = &r9a09g047_i3c_config },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, renesas_i3c_of_ids);
+
+static struct platform_driver renesas_i3c = {
+ .probe = renesas_i3c_probe,
+ .remove = renesas_i3c_remove,
+ .driver = {
+ .name = "renesas-i3c",
+ .of_match_table = renesas_i3c_of_ids,
+ },
+};
+module_platform_driver(renesas_i3c);
+
+MODULE_AUTHOR("Wolfram Sang <wsa+renesas@sang-engineering.com>");
+MODULE_AUTHOR("Renesas BSP teams");
+MODULE_DESCRIPTION("Renesas I3C controller driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i3c/master/svc-i3c-master.c b/drivers/i3c/master/svc-i3c-master.c
index 7e1a7cb94b43..701ae165b25b 100644
--- a/drivers/i3c/master/svc-i3c-master.c
+++ b/drivers/i3c/master/svc-i3c-master.c
@@ -104,6 +104,7 @@
#define SVC_I3C_MDATACTRL_TXTRIG_FIFO_NOT_FULL GENMASK(5, 4)
#define SVC_I3C_MDATACTRL_RXTRIG_FIFO_NOT_EMPTY 0
#define SVC_I3C_MDATACTRL_RXCOUNT(x) FIELD_GET(GENMASK(28, 24), (x))
+#define SVC_I3C_MDATACTRL_TXCOUNT(x) FIELD_GET(GENMASK(20, 16), (x))
#define SVC_I3C_MDATACTRL_TXFULL BIT(30)
#define SVC_I3C_MDATACTRL_RXEMPTY BIT(31)
@@ -664,7 +665,6 @@ static int svc_i3c_master_set_speed(struct i3c_master_controller *m,
}
rpm_out:
- pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
@@ -779,7 +779,6 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
goto rpm_out;
rpm_out:
- pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
@@ -801,7 +800,6 @@ static void svc_i3c_master_bus_cleanup(struct i3c_master_controller *m)
/* Disable master */
writel(0, master->regs + SVC_I3C_MCONFIG);
- pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
}
@@ -1207,7 +1205,6 @@ static int svc_i3c_master_do_daa(struct i3c_master_controller *m)
dev_err(master->dev, "Cannot handle such a list of devices");
rpm_out:
- pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
@@ -1304,14 +1301,19 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
* FIFO start filling as soon as possible after EmitStartAddr.
*/
if (svc_has_quirk(master, SVC_I3C_QUIRK_FIFO_EMPTY) && !rnw && xfer_len) {
- u32 end = xfer_len > SVC_I3C_FIFO_SIZE ? 0 : SVC_I3C_MWDATAB_END;
- u32 len = min_t(u32, xfer_len, SVC_I3C_FIFO_SIZE);
-
- writesb(master->regs + SVC_I3C_MWDATAB1, out, len - 1);
- /* Mark END bit if this is the last byte */
- writel(out[len - 1] | end, master->regs + SVC_I3C_MWDATAB);
- xfer_len -= len;
- out += len;
+ u32 space, end, len;
+
+ reg = readl(master->regs + SVC_I3C_MDATACTRL);
+ space = SVC_I3C_FIFO_SIZE - SVC_I3C_MDATACTRL_TXCOUNT(reg);
+ if (space) {
+ end = xfer_len > space ? 0 : SVC_I3C_MWDATAB_END;
+ len = min_t(u32, xfer_len, space);
+ writesb(master->regs + SVC_I3C_MWDATAB1, out, len - 1);
+ /* Mark END bit if this is the last byte */
+ writel(out[len - 1] | end, master->regs + SVC_I3C_MWDATAB);
+ xfer_len -= len;
+ out += len;
+ }
}
ret = readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg,
@@ -1511,7 +1513,6 @@ static void svc_i3c_master_enqueue_xfer(struct svc_i3c_master *master,
}
spin_unlock_irqrestore(&master->xferqueue.lock, flags);
- pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
}
@@ -1708,7 +1709,7 @@ static int svc_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
mutex_lock(&master->lock);
svc_i3c_master_enqueue_xfer(master, xfer);
- if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000)))
+ if (!wait_for_completion_timeout(&xfer->comp, m->i2c.timeout))
svc_i3c_master_dequeue_xfer(master, xfer);
mutex_unlock(&master->lock);
@@ -1801,7 +1802,6 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
ret = i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
- pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
@@ -1834,7 +1834,6 @@ static int svc_i3c_master_disable_hotjoin(struct i3c_master_controller *m)
if (!master->enabled_events)
svc_i3c_master_disable_interrupts(master);
- pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return 0;
@@ -1954,7 +1953,6 @@ static int svc_i3c_master_probe(struct platform_device *pdev)
if (ret)
goto rpm_disable;
- pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
return 0;
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index feab392ab2ee..476e73e502fe 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -4610,7 +4610,7 @@ static int mvneta_stop(struct net_device *dev)
/* Inform that we are stopping so we don't want to setup the
* driver for new CPUs in the notifiers. The code of the
* notifier for CPU online is protected by the same spinlock,
- * so when we get the lock, the notifer work is done.
+ * so when we get the lock, the notifier work is done.
*/
spin_lock(&pp->lock);
pp->is_stopped = true;
diff --git a/drivers/net/wwan/iosm/iosm_ipc_trace.c b/drivers/net/wwan/iosm/iosm_ipc_trace.c
index eeecfa3d10c5..9656254c1c6c 100644
--- a/drivers/net/wwan/iosm/iosm_ipc_trace.c
+++ b/drivers/net/wwan/iosm/iosm_ipc_trace.c
@@ -51,8 +51,7 @@ static int ipc_trace_remove_buf_file_handler(struct dentry *dentry)
}
static int ipc_trace_subbuf_start_handler(struct rchan_buf *buf, void *subbuf,
- void *prev_subbuf,
- size_t prev_padding)
+ void *prev_subbuf)
{
if (relay_buf_full(buf)) {
pr_err_ratelimited("Relay_buf full dropping traces");
diff --git a/drivers/net/wwan/t7xx/t7xx_port_trace.c b/drivers/net/wwan/t7xx/t7xx_port_trace.c
index 4ed8b4e29bf1..f16d3b01302c 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_trace.c
+++ b/drivers/net/wwan/t7xx/t7xx_port_trace.c
@@ -33,7 +33,7 @@ static int t7xx_trace_remove_buf_file_handler(struct dentry *dentry)
}
static int t7xx_trace_subbuf_start_handler(struct rchan_buf *buf, void *subbuf,
- void *prev_subbuf, size_t prev_padding)
+ void *prev_subbuf)
{
if (relay_buf_full(buf)) {
pr_err_ratelimited("Relay_buf full dropping traces");
diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c
index 573a41869c15..c5345bff9a55 100644
--- a/drivers/pci/hotplug/pnv_php.c
+++ b/drivers/pci/hotplug/pnv_php.c
@@ -3,12 +3,15 @@
* PCI Hotplug Driver for PowerPC PowerNV platform.
*
* Copyright Gavin Shan, IBM Corporation 2016.
+ * Copyright (C) 2025 Raptor Engineering, LLC
+ * Copyright (C) 2025 Raptor Computing Systems, LLC
*/
#include <linux/bitfield.h>
#include <linux/libfdt.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/delay.h>
#include <linux/pci_hotplug.h>
#include <linux/of_fdt.h>
@@ -36,8 +39,10 @@ static void pnv_php_register(struct device_node *dn);
static void pnv_php_unregister_one(struct device_node *dn);
static void pnv_php_unregister(struct device_node *dn);
+static void pnv_php_enable_irq(struct pnv_php_slot *php_slot);
+
static void pnv_php_disable_irq(struct pnv_php_slot *php_slot,
- bool disable_device)
+ bool disable_device, bool disable_msi)
{
struct pci_dev *pdev = php_slot->pdev;
u16 ctrl;
@@ -53,19 +58,15 @@ static void pnv_php_disable_irq(struct pnv_php_slot *php_slot,
php_slot->irq = 0;
}
- if (php_slot->wq) {
- destroy_workqueue(php_slot->wq);
- php_slot->wq = NULL;
- }
-
- if (disable_device) {
+ if (disable_device || disable_msi) {
if (pdev->msix_enabled)
pci_disable_msix(pdev);
else if (pdev->msi_enabled)
pci_disable_msi(pdev);
+ }
+ if (disable_device)
pci_disable_device(pdev);
- }
}
static void pnv_php_free_slot(struct kref *kref)
@@ -74,7 +75,8 @@ static void pnv_php_free_slot(struct kref *kref)
struct pnv_php_slot, kref);
WARN_ON(!list_empty(&php_slot->children));
- pnv_php_disable_irq(php_slot, false);
+ pnv_php_disable_irq(php_slot, false, false);
+ destroy_workqueue(php_slot->wq);
kfree(php_slot->name);
kfree(php_slot);
}
@@ -391,6 +393,20 @@ static int pnv_php_get_power_state(struct hotplug_slot *slot, u8 *state)
return 0;
}
+static int pcie_check_link_active(struct pci_dev *pdev)
+{
+ u16 lnk_status;
+ int ret;
+
+ ret = pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
+ if (ret == PCIBIOS_DEVICE_NOT_FOUND || PCI_POSSIBLE_ERROR(lnk_status))
+ return -ENODEV;
+
+ ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA);
+
+ return ret;
+}
+
static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
{
struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
@@ -403,6 +419,19 @@ static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
*/
ret = pnv_pci_get_presence_state(php_slot->id, &presence);
if (ret >= 0) {
+ if (pci_pcie_type(php_slot->pdev) == PCI_EXP_TYPE_DOWNSTREAM &&
+ presence == OPAL_PCI_SLOT_EMPTY) {
+ /*
+ * Similar to pciehp_hpc, check whether the Link Active
+ * bit is set to account for broken downstream bridges
+ * that don't properly assert Presence Detect State, as
+ * was observed on the Microsemi Switchtec PM8533 PFX
+ * [11f8:8533].
+ */
+ if (pcie_check_link_active(php_slot->pdev) > 0)
+ presence = OPAL_PCI_SLOT_PRESENT;
+ }
+
*state = presence;
ret = 0;
} else {
@@ -412,10 +441,23 @@ static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
return ret;
}
+static int pnv_php_get_raw_indicator_status(struct hotplug_slot *slot, u8 *state)
+{
+ struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
+ struct pci_dev *bridge = php_slot->pdev;
+ u16 status;
+
+ pcie_capability_read_word(bridge, PCI_EXP_SLTCTL, &status);
+ *state = (status & (PCI_EXP_SLTCTL_AIC | PCI_EXP_SLTCTL_PIC)) >> 6;
+ return 0;
+}
+
+
static int pnv_php_get_attention_state(struct hotplug_slot *slot, u8 *state)
{
struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
+ pnv_php_get_raw_indicator_status(slot, &php_slot->attention_state);
*state = php_slot->attention_state;
return 0;
}
@@ -433,7 +475,7 @@ static int pnv_php_set_attention_state(struct hotplug_slot *slot, u8 state)
mask = PCI_EXP_SLTCTL_AIC;
if (state)
- new = PCI_EXP_SLTCTL_ATTN_IND_ON;
+ new = FIELD_PREP(PCI_EXP_SLTCTL_AIC, state);
else
new = PCI_EXP_SLTCTL_ATTN_IND_OFF;
@@ -442,6 +484,61 @@ static int pnv_php_set_attention_state(struct hotplug_slot *slot, u8 state)
return 0;
}
+static int pnv_php_activate_slot(struct pnv_php_slot *php_slot,
+ struct hotplug_slot *slot)
+{
+ int ret, i;
+
+ /*
+ * Issue initial slot activation command to firmware
+ *
+ * Firmware will power slot on, attempt to train the link, and
+ * discover any downstream devices. If this process fails, firmware
+ * will return an error code and an invalid device tree. Failure
+ * can be caused for multiple reasons, including a faulty
+ * downstream device, poor connection to the downstream device, or
+ * a previously latched PHB fence. On failure, issue fundamental
+ * reset up to three times before aborting.
+ */
+ ret = pnv_php_set_slot_power_state(slot, OPAL_PCI_SLOT_POWER_ON);
+ if (ret) {
+ SLOT_WARN(
+ php_slot,
+ "PCI slot activation failed with error code %d, possible frozen PHB",
+ ret);
+ SLOT_WARN(
+ php_slot,
+ "Attempting complete PHB reset before retrying slot activation\n");
+ for (i = 0; i < 3; i++) {
+ /*
+ * Slot activation failed, PHB may be fenced from a
+ * prior device failure.
+ *
+ * Use the OPAL fundamental reset call to both try a
+ * device reset and clear any potentially active PHB
+ * fence / freeze.
+ */
+ SLOT_WARN(php_slot, "Try %d...\n", i + 1);
+ pci_set_pcie_reset_state(php_slot->pdev,
+ pcie_warm_reset);
+ msleep(250);
+ pci_set_pcie_reset_state(php_slot->pdev,
+ pcie_deassert_reset);
+
+ ret = pnv_php_set_slot_power_state(
+ slot, OPAL_PCI_SLOT_POWER_ON);
+ if (!ret)
+ break;
+ }
+
+ if (i >= 3)
+ SLOT_WARN(php_slot,
+ "Failed to bring slot online, aborting!\n");
+ }
+
+ return ret;
+}
+
static int pnv_php_enable(struct pnv_php_slot *php_slot, bool rescan)
{
struct hotplug_slot *slot = &php_slot->slot;
@@ -504,7 +601,7 @@ static int pnv_php_enable(struct pnv_php_slot *php_slot, bool rescan)
goto scan;
/* Power is off, turn it on and then scan the slot */
- ret = pnv_php_set_slot_power_state(slot, OPAL_PCI_SLOT_POWER_ON);
+ ret = pnv_php_activate_slot(php_slot, slot);
if (ret)
return ret;
@@ -561,8 +658,58 @@ static int pnv_php_reset_slot(struct hotplug_slot *slot, bool probe)
static int pnv_php_enable_slot(struct hotplug_slot *slot)
{
struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
+ u32 prop32;
+ int ret;
+
+ ret = pnv_php_enable(php_slot, true);
+ if (ret)
+ return ret;
+
+ /* (Re-)enable interrupt if the slot supports surprise hotplug */
+ ret = of_property_read_u32(php_slot->dn, "ibm,slot-surprise-pluggable",
+ &prop32);
+ if (!ret && prop32)
+ pnv_php_enable_irq(php_slot);
+
+ return 0;
+}
+
+/*
+ * Disable any hotplug interrupts for all slots on the provided bus, as well as
+ * all downstream slots in preparation for a hot unplug.
+ */
+static int pnv_php_disable_all_irqs(struct pci_bus *bus)
+{
+ struct pci_bus *child_bus;
+ struct pci_slot *slot;
+
+ /* First go down child buses */
+ list_for_each_entry(child_bus, &bus->children, node)
+ pnv_php_disable_all_irqs(child_bus);
+
+ /* Disable IRQs for all pnv_php slots on this bus */
+ list_for_each_entry(slot, &bus->slots, list) {
+ struct pnv_php_slot *php_slot = to_pnv_php_slot(slot->hotplug);
- return pnv_php_enable(php_slot, true);
+ pnv_php_disable_irq(php_slot, false, true);
+ }
+
+ return 0;
+}
+
+/*
+ * Disable any hotplug interrupts for all downstream slots on the provided
+ * bus in preparation for a hot unplug.
+ */
+static int pnv_php_disable_all_downstream_irqs(struct pci_bus *bus)
+{
+ struct pci_bus *child_bus;
+
+ /* Go down child buses, recursively deactivating their IRQs */
+ list_for_each_entry(child_bus, &bus->children, node)
+ pnv_php_disable_all_irqs(child_bus);
+
+ return 0;
}
static int pnv_php_disable_slot(struct hotplug_slot *slot)
@@ -579,6 +726,13 @@ static int pnv_php_disable_slot(struct hotplug_slot *slot)
php_slot->state != PNV_PHP_STATE_REGISTERED)
return 0;
+ /*
+ * Free all IRQ resources from all child slots before remove.
+ * Note that we do not disable the root slot IRQ here as that
+ * would also deactivate the slot hot (re)plug interrupt!
+ */
+ pnv_php_disable_all_downstream_irqs(php_slot->bus);
+
/* Remove all devices behind the slot */
pci_lock_rescan_remove();
pci_hp_remove_devices(php_slot->bus);
@@ -647,6 +801,15 @@ static struct pnv_php_slot *pnv_php_alloc_slot(struct device_node *dn)
return NULL;
}
+ /* Allocate workqueue for this slot's interrupt handling */
+ php_slot->wq = alloc_workqueue("pciehp-%s", 0, 0, php_slot->name);
+ if (!php_slot->wq) {
+ SLOT_WARN(php_slot, "Cannot alloc workqueue\n");
+ kfree(php_slot->name);
+ kfree(php_slot);
+ return NULL;
+ }
+
if (dn->child && PCI_DN(dn->child))
php_slot->slot_no = PCI_SLOT(PCI_DN(dn->child)->devfn);
else
@@ -745,16 +908,63 @@ static int pnv_php_enable_msix(struct pnv_php_slot *php_slot)
return entry.vector;
}
+static void
+pnv_php_detect_clear_suprise_removal_freeze(struct pnv_php_slot *php_slot)
+{
+ struct pci_dev *pdev = php_slot->pdev;
+ struct eeh_dev *edev;
+ struct eeh_pe *pe;
+ int i, rc;
+
+ /*
+ * When a device is surprise removed from a downstream bridge slot,
+ * the upstream bridge port can still end up frozen due to related EEH
+ * events, which will in turn block the MSI interrupts for slot hotplug
+ * detection.
+ *
+ * Detect and thaw any frozen upstream PE after slot deactivation.
+ */
+ edev = pci_dev_to_eeh_dev(pdev);
+ pe = edev ? edev->pe : NULL;
+ rc = eeh_pe_get_state(pe);
+ if ((rc == -ENODEV) || (rc == -ENOENT)) {
+ SLOT_WARN(
+ php_slot,
+ "Upstream bridge PE state unknown, hotplug detect may fail\n");
+ } else {
+ if (pe->state & EEH_PE_ISOLATED) {
+ SLOT_WARN(
+ php_slot,
+ "Upstream bridge PE %02x frozen, thawing...\n",
+ pe->addr);
+ for (i = 0; i < 3; i++)
+ if (!eeh_unfreeze_pe(pe))
+ break;
+ if (i >= 3)
+ SLOT_WARN(
+ php_slot,
+ "Unable to thaw PE %02x, hotplug detect will fail!\n",
+ pe->addr);
+ else
+ SLOT_WARN(php_slot,
+ "PE %02x thawed successfully\n",
+ pe->addr);
+ }
+ }
+}
+
static void pnv_php_event_handler(struct work_struct *work)
{
struct pnv_php_event *event =
container_of(work, struct pnv_php_event, work);
struct pnv_php_slot *php_slot = event->php_slot;
- if (event->added)
+ if (event->added) {
pnv_php_enable_slot(&php_slot->slot);
- else
+ } else {
pnv_php_disable_slot(&php_slot->slot);
+ pnv_php_detect_clear_suprise_removal_freeze(php_slot);
+ }
kfree(event);
}
@@ -843,14 +1053,6 @@ static void pnv_php_init_irq(struct pnv_php_slot *php_slot, int irq)
u16 sts, ctrl;
int ret;
- /* Allocate workqueue */
- php_slot->wq = alloc_workqueue("pciehp-%s", 0, 0, php_slot->name);
- if (!php_slot->wq) {
- SLOT_WARN(php_slot, "Cannot alloc workqueue\n");
- pnv_php_disable_irq(php_slot, true);
- return;
- }
-
/* Check PDC (Presence Detection Change) is broken or not */
ret = of_property_read_u32(php_slot->dn, "ibm,slot-broken-pdc",
&broken_pdc);
@@ -869,7 +1071,7 @@ static void pnv_php_init_irq(struct pnv_php_slot *php_slot, int irq)
ret = request_irq(irq, pnv_php_interrupt, IRQF_SHARED,
php_slot->name, php_slot);
if (ret) {
- pnv_php_disable_irq(php_slot, true);
+ pnv_php_disable_irq(php_slot, true, true);
SLOT_WARN(php_slot, "Error %d enabling IRQ %d\n", ret, irq);
return;
}
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index eb1b37af81fb..ddd11668457c 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -206,6 +206,17 @@ config PINCTRL_DIGICOLOR
select PINMUX
select GENERIC_PINCONF
+config PINCTRL_EIC7700
+ tristate "EIC7700 PINCTRL driver"
+ depends on ARCH_ESWIN || COMPILE_TEST
+ select PINMUX
+ select GENERIC_PINCONF
+ help
+ This driver support for the pin controller in ESWIN's EIC7700 SoC,
+ which supports pin multiplexing, pin configuration,and rgmii voltage
+ control.
+ Say Y here to enable the eic7700 pinctrl driver
+
config PINCTRL_EP93XX
bool
depends on ARCH_EP93XX || COMPILE_TEST
@@ -269,7 +280,8 @@ config PINCTRL_INGENIC
config PINCTRL_K210
bool "Pinctrl driver for the Canaan Kendryte K210 SoC"
- depends on RISCV && SOC_CANAAN_K210 && OF
+ depends on RISCV && SOC_CANAAN_K210 || COMPILE_TEST
+ depends on OF
select GENERIC_PINMUX_FUNCTIONS
select GENERIC_PINCONF
select GPIOLIB
@@ -554,8 +566,8 @@ config PINCTRL_SX150X
- 16 bits: sx1509q, sx1506q
config PINCTRL_TB10X
- bool
- depends on OF && ARC_PLAT_TB10X
+ bool "Pinctrl for TB10X" if COMPILE_TEST
+ depends on OF && ARC_PLAT_TB10X || COMPILE_TEST
select GPIOLIB
config PINCTRL_TPS6594
@@ -590,7 +602,8 @@ config PINCTRL_TH1520
config PINCTRL_ZYNQ
bool "Pinctrl driver for Xilinx Zynq"
- depends on ARCH_ZYNQ
+ depends on ARCH_ZYNQ || COMPILE_TEST
+ depends on OF
select PINMUX
select GENERIC_PINCONF
help
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 65dac8e38798..909ab89a56d2 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_PINCTRL_CY8C95X0) += pinctrl-cy8c95x0.o
obj-$(CONFIG_PINCTRL_DA850_PUPD) += pinctrl-da850-pupd.o
obj-$(CONFIG_PINCTRL_DA9062) += pinctrl-da9062.o
obj-$(CONFIG_PINCTRL_DIGICOLOR) += pinctrl-digicolor.o
+obj-$(CONFIG_PINCTRL_EIC7700) += pinctrl-eic7700.o
obj-$(CONFIG_PINCTRL_EQUILIBRIUM) += pinctrl-equilibrium.o
obj-$(CONFIG_PINCTRL_EP93XX) += pinctrl-ep93xx.o
obj-$(CONFIG_PINCTRL_EYEQ5) += pinctrl-eyeq5.o
@@ -83,7 +84,7 @@ obj-y += sophgo/
obj-y += spacemit/
obj-$(CONFIG_PINCTRL_SPEAR) += spear/
obj-y += sprd/
-obj-$(CONFIG_SOC_STARFIVE) += starfive/
+obj-y += starfive/
obj-$(CONFIG_PINCTRL_STM32) += stm32/
obj-y += sunplus/
obj-$(CONFIG_PINCTRL_SUNXI) += sunxi/
diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c
index 774f8d05142f..cb295856dda1 100644
--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c
+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c
@@ -2653,7 +2653,7 @@ static const struct pinconf_ops aspeed_g4_conf_ops = {
.pin_config_group_set = aspeed_pin_config_group_set,
};
-static struct pinctrl_desc aspeed_g4_pinctrl_desc = {
+static const struct pinctrl_desc aspeed_g4_pinctrl_desc = {
.name = "aspeed-g4-pinctrl",
.pins = aspeed_g4_pins,
.npins = ARRAY_SIZE(aspeed_g4_pins),
diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
index 5bb8fd0d1e41..792089628362 100644
--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
@@ -2845,7 +2845,7 @@ static const struct pinconf_ops aspeed_g5_conf_ops = {
.pin_config_group_set = aspeed_pin_config_group_set,
};
-static struct pinctrl_desc aspeed_g5_pinctrl_desc = {
+static const struct pinctrl_desc aspeed_g5_pinctrl_desc = {
.name = "aspeed-g5-pinctrl",
.pins = aspeed_g5_pins,
.npins = ARRAY_SIZE(aspeed_g5_pins),
diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c
index 5a7cd0a88687..b0c7e4f6df9c 100644
--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c
+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c
@@ -17,6 +17,7 @@
#include "../pinctrl-utils.h"
#include "pinctrl-aspeed.h"
+#define SCU040 0x040 /* Reset Control Set 1 */
#define SCU400 0x400 /* Multi-function Pin Control #1 */
#define SCU404 0x404 /* Multi-function Pin Control #2 */
#define SCU40C 0x40C /* Multi-function Pin Control #3 */
@@ -52,7 +53,7 @@
#define SCU6D0 0x6D0 /* Multi-function Pin Control #29 */
#define SCUC20 0xC20 /* PCIE configuration Setting Control */
-#define ASPEED_G6_NR_PINS 256
+#define ASPEED_G6_NR_PINS 258
#define M24 0
SIG_EXPR_LIST_DECL_SESG(M24, MDC3, MDIO3, SIG_DESC_SET(SCU410, 0));
@@ -1636,6 +1637,12 @@ FUNC_DECL_1(USB11BHID, USBB);
FUNC_DECL_1(USB2BD, USBB);
FUNC_DECL_1(USB2BH, USBB);
+#define D7 257
+SIG_EXPR_LIST_DECL_SESG(D7, RCRST, PCIERC1, SIG_DESC_SET(SCU040, 19),
+ SIG_DESC_SET(SCU500, 24));
+PIN_DECL_(D7, SIG_EXPR_LIST_PTR(D7, RCRST));
+FUNC_GROUP_DECL(PCIERC1, D7);
+
/* Pins, groups and functions are sort(1):ed alphabetically for sanity */
static struct pinctrl_pin_desc aspeed_g6_pins[ASPEED_G6_NR_PINS] = {
@@ -1806,6 +1813,7 @@ static struct pinctrl_pin_desc aspeed_g6_pins[ASPEED_G6_NR_PINS] = {
ASPEED_PINCTRL_PIN(D4),
ASPEED_PINCTRL_PIN(D5),
ASPEED_PINCTRL_PIN(D6),
+ ASPEED_PINCTRL_PIN(D7),
ASPEED_PINCTRL_PIN(E1),
ASPEED_PINCTRL_PIN(E11),
ASPEED_PINCTRL_PIN(E12),
@@ -2073,6 +2081,7 @@ static const struct aspeed_pin_group aspeed_g6_groups[] = {
ASPEED_PINCTRL_GROUP(SALT9G1),
ASPEED_PINCTRL_GROUP(SD1),
ASPEED_PINCTRL_GROUP(SD2),
+ ASPEED_PINCTRL_GROUP(PCIERC1),
ASPEED_PINCTRL_GROUP(EMMCG1),
ASPEED_PINCTRL_GROUP(EMMCG4),
ASPEED_PINCTRL_GROUP(EMMCG8),
@@ -2314,6 +2323,7 @@ static const struct aspeed_pin_function aspeed_g6_functions[] = {
ASPEED_PINCTRL_FUNC(SPI2),
ASPEED_PINCTRL_FUNC(SPI2CS1),
ASPEED_PINCTRL_FUNC(SPI2CS2),
+ ASPEED_PINCTRL_FUNC(PCIERC1),
ASPEED_PINCTRL_FUNC(TACH0),
ASPEED_PINCTRL_FUNC(TACH1),
ASPEED_PINCTRL_FUNC(TACH10),
@@ -2763,7 +2773,7 @@ static const struct pinconf_ops aspeed_g6_conf_ops = {
.pin_config_group_set = aspeed_pin_config_group_set,
};
-static struct pinctrl_desc aspeed_g6_pinctrl_desc = {
+static const struct pinctrl_desc aspeed_g6_pinctrl_desc = {
.name = "aspeed-g6-pinctrl",
.pins = aspeed_g6_pins,
.npins = ARRAY_SIZE(aspeed_g6_pins),
diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.c b/drivers/pinctrl/aspeed/pinctrl-aspeed.c
index 9c6ee46ac7a0..7e0ebf11af16 100644
--- a/drivers/pinctrl/aspeed/pinctrl-aspeed.c
+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.c
@@ -441,7 +441,7 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev,
}
int aspeed_pinctrl_probe(struct platform_device *pdev,
- struct pinctrl_desc *pdesc,
+ const struct pinctrl_desc *pdesc,
struct aspeed_pinctrl_data *pdata)
{
struct device *parent;
diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.h b/drivers/pinctrl/aspeed/pinctrl-aspeed.h
index 4dcde3bc29c8..28f3bde25081 100644
--- a/drivers/pinctrl/aspeed/pinctrl-aspeed.h
+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.h
@@ -102,7 +102,7 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned int offset);
int aspeed_pinctrl_probe(struct platform_device *pdev,
- struct pinctrl_desc *pdesc,
+ const struct pinctrl_desc *pdesc,
struct aspeed_pinctrl_data *pdata);
int aspeed_pin_config_get(struct pinctrl_dev *pctldev, unsigned int offset,
unsigned long *config);
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm4908.c b/drivers/pinctrl/bcm/pinctrl-bcm4908.c
index f190e0997f1f..12f7a253ea4d 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm4908.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm4908.c
@@ -456,7 +456,7 @@ static const struct pinmux_ops bcm4908_pinctrl_pmxops = {
* Controller code
*/
-static struct pinctrl_desc bcm4908_pinctrl_desc = {
+static const struct pinctrl_desc bcm4908_pinctrl_desc = {
.name = "bcm4908-pinctrl",
.pctlops = &bcm4908_pinctrl_ops,
.pmxops = &bcm4908_pinctrl_pmxops,
diff --git a/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c b/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c
index bf9597800954..e9aa99f85e05 100644
--- a/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c
+++ b/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c
@@ -903,6 +903,7 @@ static struct pinctrl_desc cygnus_pinctrl_desc = {
.name = "cygnus-pinmux",
.pctlops = &cygnus_pinctrl_ops,
.pmxops = &cygnus_pinmux_ops,
+ .npins = ARRAY_SIZE(cygnus_pins),
};
static int cygnus_mux_log_init(struct cygnus_pinctrl *pinctrl)
@@ -935,7 +936,6 @@ static int cygnus_pinmux_probe(struct platform_device *pdev)
struct cygnus_pinctrl *pinctrl;
int i, ret;
struct pinctrl_pin_desc *pins;
- unsigned num_pins = ARRAY_SIZE(cygnus_pins);
pinctrl = devm_kzalloc(&pdev->dev, sizeof(*pinctrl), GFP_KERNEL);
if (!pinctrl)
@@ -963,11 +963,12 @@ static int cygnus_pinmux_probe(struct platform_device *pdev)
return ret;
}
- pins = devm_kcalloc(&pdev->dev, num_pins, sizeof(*pins), GFP_KERNEL);
+ pins = devm_kcalloc(&pdev->dev, ARRAY_SIZE(cygnus_pins), sizeof(*pins),
+ GFP_KERNEL);
if (!pins)
return -ENOMEM;
- for (i = 0; i < num_pins; i++) {
+ for (i = 0; i < ARRAY_SIZE(cygnus_pins); i++) {
pins[i].number = cygnus_pins[i].pin;
pins[i].name = cygnus_pins[i].name;
pins[i].drv_data = &cygnus_pins[i].gpio_mux;
@@ -978,7 +979,6 @@ static int cygnus_pinmux_probe(struct platform_device *pdev)
pinctrl->functions = cygnus_pin_functions;
pinctrl->num_functions = ARRAY_SIZE(cygnus_pin_functions);
cygnus_pinctrl_desc.pins = pins;
- cygnus_pinctrl_desc.npins = num_pins;
pinctrl->pctl = devm_pinctrl_register(&pdev->dev, &cygnus_pinctrl_desc,
pinctrl);
diff --git a/drivers/pinctrl/bcm/pinctrl-ns.c b/drivers/pinctrl/bcm/pinctrl-ns.c
index 6bb2b461950b..03bd01b4a945 100644
--- a/drivers/pinctrl/bcm/pinctrl-ns.c
+++ b/drivers/pinctrl/bcm/pinctrl-ns.c
@@ -192,7 +192,7 @@ static const struct pinmux_ops ns_pinctrl_pmxops = {
* Controller code
*/
-static struct pinctrl_desc ns_pinctrl_desc = {
+static const struct pinctrl_desc ns_pinctrl_desc = {
.name = "pinctrl-ns",
.pctlops = &ns_pinctrl_ops,
.pmxops = &ns_pinctrl_pmxops,
diff --git a/drivers/pinctrl/bcm/pinctrl-ns2-mux.c b/drivers/pinctrl/bcm/pinctrl-ns2-mux.c
index 04f4fca854cc..23ab3ab064b6 100644
--- a/drivers/pinctrl/bcm/pinctrl-ns2-mux.c
+++ b/drivers/pinctrl/bcm/pinctrl-ns2-mux.c
@@ -971,6 +971,7 @@ static struct pinctrl_desc ns2_pinctrl_desc = {
.pctlops = &ns2_pinctrl_ops,
.pmxops = &ns2_pinmux_ops,
.confops = &ns2_pinconf_ops,
+ .npins = ARRAY_SIZE(ns2_pins),
};
static int ns2_mux_log_init(struct ns2_pinctrl *pinctrl)
@@ -1026,7 +1027,6 @@ static int ns2_pinmux_probe(struct platform_device *pdev)
struct resource *res;
int i, ret;
struct pinctrl_pin_desc *pins;
- unsigned int num_pins = ARRAY_SIZE(ns2_pins);
pinctrl = devm_kzalloc(&pdev->dev, sizeof(*pinctrl), GFP_KERNEL);
if (!pinctrl)
@@ -1060,11 +1060,12 @@ static int ns2_pinmux_probe(struct platform_device *pdev)
return ret;
}
- pins = devm_kcalloc(&pdev->dev, num_pins, sizeof(*pins), GFP_KERNEL);
+ pins = devm_kcalloc(&pdev->dev, ARRAY_SIZE(ns2_pins), sizeof(*pins),
+ GFP_KERNEL);
if (!pins)
return -ENOMEM;
- for (i = 0; i < num_pins; i++) {
+ for (i = 0; i < ARRAY_SIZE(ns2_pins); i++) {
pins[i].number = ns2_pins[i].pin;
pins[i].name = ns2_pins[i].name;
pins[i].drv_data = &ns2_pins[i];
@@ -1075,7 +1076,6 @@ static int ns2_pinmux_probe(struct platform_device *pdev)
pinctrl->functions = ns2_pin_functions;
pinctrl->num_functions = ARRAY_SIZE(ns2_pin_functions);
ns2_pinctrl_desc.pins = pins;
- ns2_pinctrl_desc.npins = num_pins;
pinctrl->pctl = pinctrl_register(&ns2_pinctrl_desc, &pdev->dev,
pinctrl);
diff --git a/drivers/pinctrl/bcm/pinctrl-nsp-mux.c b/drivers/pinctrl/bcm/pinctrl-nsp-mux.c
index eb6298507c1d..9b716c0d2b94 100644
--- a/drivers/pinctrl/bcm/pinctrl-nsp-mux.c
+++ b/drivers/pinctrl/bcm/pinctrl-nsp-mux.c
@@ -525,6 +525,7 @@ static struct pinctrl_desc nsp_pinctrl_desc = {
.name = "nsp-pinmux",
.pctlops = &nsp_pinctrl_ops,
.pmxops = &nsp_pinmux_ops,
+ .npins = ARRAY_SIZE(nsp_pins),
};
static int nsp_mux_log_init(struct nsp_pinctrl *pinctrl)
@@ -556,7 +557,6 @@ static int nsp_pinmux_probe(struct platform_device *pdev)
struct resource *res;
int i, ret;
struct pinctrl_pin_desc *pins;
- unsigned int num_pins = ARRAY_SIZE(nsp_pins);
pinctrl = devm_kzalloc(&pdev->dev, sizeof(*pinctrl), GFP_KERNEL);
if (!pinctrl)
@@ -589,11 +589,12 @@ static int nsp_pinmux_probe(struct platform_device *pdev)
return ret;
}
- pins = devm_kcalloc(&pdev->dev, num_pins, sizeof(*pins), GFP_KERNEL);
+ pins = devm_kcalloc(&pdev->dev, ARRAY_SIZE(nsp_pins), sizeof(*pins),
+ GFP_KERNEL);
if (!pins)
return -ENOMEM;
- for (i = 0; i < num_pins; i++) {
+ for (i = 0; i < ARRAY_SIZE(nsp_pins); i++) {
pins[i].number = nsp_pins[i].pin;
pins[i].name = nsp_pins[i].name;
pins[i].drv_data = &nsp_pins[i].gpio_select;
@@ -604,7 +605,6 @@ static int nsp_pinmux_probe(struct platform_device *pdev)
pinctrl->functions = nsp_pin_functions;
pinctrl->num_functions = ARRAY_SIZE(nsp_pin_functions);
nsp_pinctrl_desc.pins = pins;
- nsp_pinctrl_desc.npins = num_pins;
pinctrl->pctl = devm_pinctrl_register(&pdev->dev, &nsp_pinctrl_desc,
pinctrl);
diff --git a/drivers/pinctrl/berlin/berlin.c b/drivers/pinctrl/berlin/berlin.c
index c372a2a24be4..8afcfa4e5694 100644
--- a/drivers/pinctrl/berlin/berlin.c
+++ b/drivers/pinctrl/berlin/berlin.c
@@ -204,6 +204,7 @@ static int berlin_pinctrl_build_state(struct platform_device *pdev)
const struct berlin_desc_group *desc_group;
const struct berlin_desc_function *desc_function;
int i, max_functions = 0;
+ struct pinfunction *new_functions;
pctrl->nfunctions = 0;
@@ -229,12 +230,15 @@ static int berlin_pinctrl_build_state(struct platform_device *pdev)
}
}
- pctrl->functions = krealloc(pctrl->functions,
+ new_functions = krealloc(pctrl->functions,
pctrl->nfunctions * sizeof(*pctrl->functions),
GFP_KERNEL);
- if (!pctrl->functions)
+ if (!new_functions) {
+ kfree(pctrl->functions);
return -ENOMEM;
+ }
+ pctrl->functions = new_functions;
/* map functions to theirs groups */
for (i = 0; i < pctrl->desc->ngroups; i++) {
desc_group = pctrl->desc->groups + i;
@@ -283,7 +287,7 @@ static int berlin_pinctrl_build_state(struct platform_device *pdev)
return 0;
}
-static struct pinctrl_desc berlin_pctrl_desc = {
+static const struct pinctrl_desc berlin_pctrl_desc = {
.name = "berlin-pinctrl",
.pctlops = &berlin_pinctrl_ops,
.pmxops = &berlin_pinmux_ops,
diff --git a/drivers/pinctrl/cirrus/pinctrl-cs42l43.c b/drivers/pinctrl/cirrus/pinctrl-cs42l43.c
index 628b60ccc2b0..4e47710eb3d5 100644
--- a/drivers/pinctrl/cirrus/pinctrl-cs42l43.c
+++ b/drivers/pinctrl/cirrus/pinctrl-cs42l43.c
@@ -448,7 +448,7 @@ static const struct pinconf_ops cs42l43_pin_conf_ops = {
.pin_config_group_set = cs42l43_pin_config_group_set,
};
-static struct pinctrl_desc cs42l43_pin_desc = {
+static const struct pinctrl_desc cs42l43_pin_desc = {
.name = "cs42l43-pinctrl",
.owner = THIS_MODULE,
@@ -483,7 +483,8 @@ static int cs42l43_gpio_get(struct gpio_chip *chip, unsigned int offset)
return ret;
}
-static void cs42l43_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+static int cs42l43_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct cs42l43_pin *priv = gpiochip_get_data(chip);
unsigned int shift = offset + CS42L43_GPIO1_LVL_SHIFT;
@@ -493,23 +494,27 @@ static void cs42l43_gpio_set(struct gpio_chip *chip, unsigned int offset, int va
offset + 1, str_high_low(value));
ret = pm_runtime_resume_and_get(priv->dev);
- if (ret) {
- dev_err(priv->dev, "Failed to resume for set: %d\n", ret);
- return;
- }
+ if (ret)
+ return ret;
ret = regmap_update_bits(priv->regmap, CS42L43_GPIO_CTRL1,
BIT(shift), value << shift);
if (ret)
- dev_err(priv->dev, "Failed to set gpio%d: %d\n", offset + 1, ret);
+ return ret;
pm_runtime_put(priv->dev);
+
+ return 0;
}
static int cs42l43_gpio_direction_out(struct gpio_chip *chip,
unsigned int offset, int value)
{
- cs42l43_gpio_set(chip, offset, value);
+ int ret;
+
+ ret = cs42l43_gpio_set(chip, offset, value);
+ if (ret)
+ return ret;
return pinctrl_gpio_direction_output(chip, offset);
}
@@ -550,7 +555,7 @@ static int cs42l43_pin_probe(struct platform_device *pdev)
priv->gpio_chip.direction_output = cs42l43_gpio_direction_out;
priv->gpio_chip.add_pin_ranges = cs42l43_gpio_add_pin_ranges;
priv->gpio_chip.get = cs42l43_gpio_get;
- priv->gpio_chip.set = cs42l43_gpio_set;
+ priv->gpio_chip.set_rv = cs42l43_gpio_set;
priv->gpio_chip.label = dev_name(priv->dev);
priv->gpio_chip.parent = priv->dev;
priv->gpio_chip.can_sleep = true;
diff --git a/drivers/pinctrl/cirrus/pinctrl-lochnagar.c b/drivers/pinctrl/cirrus/pinctrl-lochnagar.c
index 0f32866a4aef..dcc0a2f3c7dd 100644
--- a/drivers/pinctrl/cirrus/pinctrl-lochnagar.c
+++ b/drivers/pinctrl/cirrus/pinctrl-lochnagar.c
@@ -1058,13 +1058,12 @@ static const struct pinctrl_desc lochnagar_pin_desc = {
.confops = &lochnagar_pin_conf_ops,
};
-static void lochnagar_gpio_set(struct gpio_chip *chip,
- unsigned int offset, int value)
+static int lochnagar_gpio_set(struct gpio_chip *chip,
+ unsigned int offset, int value)
{
struct lochnagar_pin_priv *priv = gpiochip_get_data(chip);
struct lochnagar *lochnagar = priv->lochnagar;
const struct lochnagar_pin *pin = priv->pins[offset].drv_data;
- int ret;
value = !!value;
@@ -1075,29 +1074,31 @@ static void lochnagar_gpio_set(struct gpio_chip *chip,
case LN_PTYPE_MUX:
value |= LN2_OP_GPIO;
- ret = lochnagar_pin_set_mux(priv, pin, value);
+ return lochnagar_pin_set_mux(priv, pin, value);
break;
case LN_PTYPE_GPIO:
if (pin->invert)
value = !value;
- ret = regmap_update_bits(lochnagar->regmap, pin->reg,
- BIT(pin->shift), value << pin->shift);
+ return regmap_update_bits(lochnagar->regmap, pin->reg,
+ BIT(pin->shift),
+ value << pin->shift);
break;
default:
- ret = -EINVAL;
break;
}
- if (ret < 0)
- dev_err(chip->parent, "Failed to set %s value: %d\n",
- pin->name, ret);
+ return -EINVAL;
}
static int lochnagar_gpio_direction_out(struct gpio_chip *chip,
unsigned int offset, int value)
{
- lochnagar_gpio_set(chip, offset, value);
+ int ret;
+
+ ret = lochnagar_gpio_set(chip, offset, value);
+ if (ret)
+ return ret;
return pinctrl_gpio_direction_output(chip, offset);
}
@@ -1160,7 +1161,7 @@ static int lochnagar_pin_probe(struct platform_device *pdev)
priv->gpio_chip.request = gpiochip_generic_request;
priv->gpio_chip.free = gpiochip_generic_free;
priv->gpio_chip.direction_output = lochnagar_gpio_direction_out;
- priv->gpio_chip.set = lochnagar_gpio_set;
+ priv->gpio_chip.set_rv = lochnagar_gpio_set;
priv->gpio_chip.can_sleep = true;
priv->gpio_chip.parent = dev;
priv->gpio_chip.base = -1;
diff --git a/drivers/pinctrl/cirrus/pinctrl-madera-core.c b/drivers/pinctrl/cirrus/pinctrl-madera-core.c
index 73ec5b9beb49..d19ef13224cc 100644
--- a/drivers/pinctrl/cirrus/pinctrl-madera-core.c
+++ b/drivers/pinctrl/cirrus/pinctrl-madera-core.c
@@ -1061,8 +1061,9 @@ static int madera_pin_probe(struct platform_device *pdev)
/* if the configuration is provided through pdata, apply it */
if (pdata->gpio_configs) {
- ret = pinctrl_register_mappings(pdata->gpio_configs,
- pdata->n_gpio_configs);
+ ret = devm_pinctrl_register_mappings(priv->dev,
+ pdata->gpio_configs,
+ pdata->n_gpio_configs);
if (ret)
return dev_err_probe(priv->dev, ret,
"Failed to register pdata mappings\n");
@@ -1081,17 +1082,8 @@ static int madera_pin_probe(struct platform_device *pdev)
return 0;
}
-static void madera_pin_remove(struct platform_device *pdev)
-{
- struct madera_pin_private *priv = platform_get_drvdata(pdev);
-
- if (priv->madera->pdata.gpio_configs)
- pinctrl_unregister_mappings(priv->madera->pdata.gpio_configs);
-}
-
static struct platform_driver madera_pin_driver = {
.probe = madera_pin_probe,
- .remove = madera_pin_remove,
.driver = {
.name = "madera-pinctrl",
},
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index 9046292d1360..73b78d6eac67 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -2062,7 +2062,7 @@ static int pinctrl_check_ops(struct pinctrl_dev *pctldev)
* @driver_data: private pin controller data for this pin controller
*/
static struct pinctrl_dev *
-pinctrl_init_controller(struct pinctrl_desc *pctldesc, struct device *dev,
+pinctrl_init_controller(const struct pinctrl_desc *pctldesc, struct device *dev,
void *driver_data)
{
struct pinctrl_dev *pctldev;
@@ -2132,7 +2132,8 @@ out_err:
return ERR_PTR(ret);
}
-static void pinctrl_uninit_controller(struct pinctrl_dev *pctldev, struct pinctrl_desc *pctldesc)
+static void pinctrl_uninit_controller(struct pinctrl_dev *pctldev,
+ const struct pinctrl_desc *pctldesc)
{
pinctrl_free_pindescs(pctldev, pctldesc->pins,
pctldesc->npins);
@@ -2209,7 +2210,7 @@ EXPORT_SYMBOL_GPL(pinctrl_enable);
* struct pinctrl_dev handle. To avoid issues later on, please use the
* new pinctrl_register_and_init() below instead.
*/
-struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
+struct pinctrl_dev *pinctrl_register(const struct pinctrl_desc *pctldesc,
struct device *dev, void *driver_data)
{
struct pinctrl_dev *pctldev;
@@ -2239,7 +2240,7 @@ EXPORT_SYMBOL_GPL(pinctrl_register);
* Note that pinctrl_enable() still needs to be manually called after
* this once the driver is ready.
*/
-int pinctrl_register_and_init(struct pinctrl_desc *pctldesc,
+int pinctrl_register_and_init(const struct pinctrl_desc *pctldesc,
struct device *dev, void *driver_data,
struct pinctrl_dev **pctldev)
{
@@ -2330,7 +2331,7 @@ static int devm_pinctrl_dev_match(struct device *dev, void *res, void *data)
* The pinctrl device will be automatically released when the device is unbound.
*/
struct pinctrl_dev *devm_pinctrl_register(struct device *dev,
- struct pinctrl_desc *pctldesc,
+ const struct pinctrl_desc *pctldesc,
void *driver_data)
{
struct pinctrl_dev **ptr, *pctldev;
@@ -2364,7 +2365,7 @@ EXPORT_SYMBOL_GPL(devm_pinctrl_register);
* The pinctrl device will be automatically released when the device is unbound.
*/
int devm_pinctrl_register_and_init(struct device *dev,
- struct pinctrl_desc *pctldesc,
+ const struct pinctrl_desc *pctldesc,
void *driver_data,
struct pinctrl_dev **pctldev)
{
diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
index d6c24978e708..fc513a9cdd4f 100644
--- a/drivers/pinctrl/core.h
+++ b/drivers/pinctrl/core.h
@@ -51,7 +51,7 @@ struct pinctrl_state;
*/
struct pinctrl_dev {
struct list_head node;
- struct pinctrl_desc *desc;
+ const struct pinctrl_desc *desc;
struct radix_tree_root pin_desc_tree;
#ifdef CONFIG_GENERIC_PINCTRL_GROUPS
struct radix_tree_root pin_group_tree;
diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c
index 969137c4cb06..6eb649f1ffd6 100644
--- a/drivers/pinctrl/intel/pinctrl-baytrail.c
+++ b/drivers/pinctrl/intel/pinctrl-baytrail.c
@@ -1045,7 +1045,7 @@ static int byt_gpio_get(struct gpio_chip *chip, unsigned int offset)
return !!(val & BYT_LEVEL);
}
-static void byt_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+static int byt_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct intel_pinctrl *vg = gpiochip_get_data(chip);
void __iomem *reg;
@@ -1053,7 +1053,7 @@ static void byt_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
reg = byt_gpio_reg(vg, offset, BYT_VAL_REG);
if (!reg)
- return;
+ return -EINVAL;
guard(raw_spinlock_irqsave)(&byt_lock);
@@ -1062,6 +1062,8 @@ static void byt_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
writel(old_val | BYT_LEVEL, reg);
else
writel(old_val & ~BYT_LEVEL, reg);
+
+ return 0;
}
static int byt_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
@@ -1229,7 +1231,7 @@ static const struct gpio_chip byt_gpio_chip = {
.direction_input = byt_gpio_direction_input,
.direction_output = byt_gpio_direction_output,
.get = byt_gpio_get,
- .set = byt_gpio_set,
+ .set_rv = byt_gpio_set,
.set_config = gpiochip_generic_config,
.dbg_show = byt_gpio_dbg_show,
};
diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c
index 69b18ce0f685..769e8c4102a5 100644
--- a/drivers/pinctrl/intel/pinctrl-cherryview.c
+++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -1112,7 +1112,7 @@ static int chv_gpio_get(struct gpio_chip *chip, unsigned int offset)
return !!(ctrl0 & CHV_PADCTRL0_GPIORXSTATE);
}
-static void chv_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+static int chv_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
u32 ctrl0;
@@ -1127,6 +1127,8 @@ static void chv_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
ctrl0 &= ~CHV_PADCTRL0_GPIOTXSTATE;
chv_writel(pctrl, offset, CHV_PADCTRL0, ctrl0);
+
+ return 0;
}
static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
@@ -1166,7 +1168,7 @@ static const struct gpio_chip chv_gpio_chip = {
.direction_input = chv_gpio_direction_input,
.direction_output = chv_gpio_direction_output,
.get = chv_gpio_get,
- .set = chv_gpio_set,
+ .set_rv = chv_gpio_set,
};
static void chv_gpio_irq_ack(struct irq_data *d)
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index d889c7c878e2..f2ff71e5ea6f 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -9,6 +9,7 @@
#include <linux/acpi.h>
#include <linux/cleanup.h>
+#include <linux/export.h>
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/log2.h>
@@ -1033,8 +1034,8 @@ static int intel_gpio_get(struct gpio_chip *chip, unsigned int offset)
return !!(padcfg0 & PADCFG0_GPIORXSTATE);
}
-static void intel_gpio_set(struct gpio_chip *chip, unsigned int offset,
- int value)
+static int intel_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
void __iomem *reg;
@@ -1043,11 +1044,11 @@ static void intel_gpio_set(struct gpio_chip *chip, unsigned int offset,
pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL);
if (pin < 0)
- return;
+ return -EINVAL;
reg = intel_get_padcfg(pctrl, pin, PADCFG0);
if (!reg)
- return;
+ return -EINVAL;
guard(raw_spinlock_irqsave)(&pctrl->lock);
@@ -1057,6 +1058,8 @@ static void intel_gpio_set(struct gpio_chip *chip, unsigned int offset,
else
padcfg0 &= ~PADCFG0_GPIOTXSTATE;
writel(padcfg0, reg);
+
+ return 0;
}
static int intel_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
@@ -1094,7 +1097,12 @@ static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned int offse
static int intel_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
int value)
{
- intel_gpio_set(chip, offset, value);
+ int ret;
+
+ ret = intel_gpio_set(chip, offset, value);
+ if (ret)
+ return ret;
+
return pinctrl_gpio_direction_output(chip, offset);
}
@@ -1106,7 +1114,7 @@ static const struct gpio_chip intel_gpio_chip = {
.direction_input = intel_gpio_direction_input,
.direction_output = intel_gpio_direction_output,
.get = intel_gpio_get,
- .set = intel_gpio_set,
+ .set_rv = intel_gpio_set,
.set_config = gpiochip_generic_config,
};
diff --git a/drivers/pinctrl/intel/pinctrl-lynxpoint.c b/drivers/pinctrl/intel/pinctrl-lynxpoint.c
index ac5459a4c63e..5d4a5dd493d1 100644
--- a/drivers/pinctrl/intel/pinctrl-lynxpoint.c
+++ b/drivers/pinctrl/intel/pinctrl-lynxpoint.c
@@ -503,7 +503,7 @@ static int lp_gpio_get(struct gpio_chip *chip, unsigned int offset)
return !!(ioread32(reg) & IN_LVL_BIT);
}
-static void lp_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+static int lp_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct intel_pinctrl *lg = gpiochip_get_data(chip);
void __iomem *reg = lp_gpio_reg(chip, offset, LP_CONFIG1);
@@ -514,6 +514,8 @@ static void lp_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
iowrite32(ioread32(reg) | OUT_LVL_BIT, reg);
else
iowrite32(ioread32(reg) & ~OUT_LVL_BIT, reg);
+
+ return 0;
}
static int lp_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
@@ -775,7 +777,7 @@ static int lp_gpio_probe(struct platform_device *pdev)
gc->direction_input = lp_gpio_direction_input;
gc->direction_output = lp_gpio_direction_output;
gc->get = lp_gpio_get;
- gc->set = lp_gpio_set;
+ gc->set_rv = lp_gpio_set;
gc->set_config = gpiochip_generic_config;
gc->get_direction = lp_gpio_get_direction;
gc->base = -1;
diff --git a/drivers/pinctrl/mediatek/Kconfig b/drivers/pinctrl/mediatek/Kconfig
index 2d15af6be276..5b191e12a8aa 100644
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -259,6 +259,18 @@ config PINCTRL_MT8188
In MTK platform, we support virtual gpio and use it to
map specific eint which doesn't have real gpio pin.
+config PINCTRL_MT8189
+ bool "MediaTek MT8189 pin control"
+ depends on OF
+ depends on ARM64 || COMPILE_TEST
+ default ARM64 && ARCH_MEDIATEK
+ select PINCTRL_MTK_PARIS
+ help
+ Say yes here to support pin controller and gpio driver
+ on MediaTek MT8189 SoC.
+ In MTK platform, we support virtual gpio and use it to
+ map specific eint which doesn't have real gpio pin.
+
config PINCTRL_MT8192
bool "MediaTek MT8192 pin control"
depends on OF
diff --git a/drivers/pinctrl/mediatek/Makefile b/drivers/pinctrl/mediatek/Makefile
index 7518980fba59..5d4646939ba3 100644
--- a/drivers/pinctrl/mediatek/Makefile
+++ b/drivers/pinctrl/mediatek/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o
obj-$(CONFIG_PINCTRL_MT8183) += pinctrl-mt8183.o
obj-$(CONFIG_PINCTRL_MT8186) += pinctrl-mt8186.o
obj-$(CONFIG_PINCTRL_MT8188) += pinctrl-mt8188.o
+obj-$(CONFIG_PINCTRL_MT8189) += pinctrl-mt8189.o
obj-$(CONFIG_PINCTRL_MT8192) += pinctrl-mt8192.o
obj-$(CONFIG_PINCTRL_MT8195) += pinctrl-mt8195.o
obj-$(CONFIG_PINCTRL_MT8196) += pinctrl-mt8196.o
diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
index d906a5e4101f..9f175c73613f 100644
--- a/drivers/pinctrl/mediatek/mtk-eint.c
+++ b/drivers/pinctrl/mediatek/mtk-eint.c
@@ -561,8 +561,8 @@ int mtk_eint_do_init(struct mtk_eint *eint, struct mtk_eint_pin *eint_pin)
goto err_eint;
}
- eint->domain = irq_domain_create_linear(of_fwnode_handle(eint->dev->of_node),
- eint->hw->ap_num, &irq_domain_simple_ops, NULL);
+ eint->domain = irq_domain_create_linear(dev_fwnode(eint->dev), eint->hw->ap_num,
+ &irq_domain_simple_ops, NULL);
if (!eint->domain)
goto err_eint;
diff --git a/drivers/pinctrl/mediatek/pinctrl-airoha.c b/drivers/pinctrl/mediatek/pinctrl-airoha.c
index b97b28ebb37a..1737b88530c3 100644
--- a/drivers/pinctrl/mediatek/pinctrl-airoha.c
+++ b/drivers/pinctrl/mediatek/pinctrl-airoha.c
@@ -2852,7 +2852,7 @@ static const struct pinctrl_ops airoha_pctlops = {
.dt_free_map = pinconf_generic_dt_free_map,
};
-static struct pinctrl_desc airoha_pinctrl_desc = {
+static const struct pinctrl_desc airoha_pinctrl_desc = {
.name = KBUILD_MODNAME,
.owner = THIS_MODULE,
.pctlops = &airoha_pctlops,
@@ -2907,11 +2907,9 @@ static int airoha_pinctrl_probe(struct platform_device *pdev)
const struct airoha_pinctrl_func *func;
func = &airoha_pinctrl_funcs[i];
- err = pinmux_generic_add_function(pinctrl->ctrl,
- func->desc.func.name,
- func->desc.func.groups,
- func->desc.func.ngroups,
- (void *)func);
+ err = pinmux_generic_add_pinfunction(pinctrl->ctrl,
+ &func->desc.func,
+ (void *)func);
if (err < 0) {
dev_err(dev, "Failed to register function %s\n",
func->desc.func.name);
diff --git a/drivers/pinctrl/mediatek/pinctrl-moore.c b/drivers/pinctrl/mediatek/pinctrl-moore.c
index 827d0f191031..ba0d6f880c6e 100644
--- a/drivers/pinctrl/mediatek/pinctrl-moore.c
+++ b/drivers/pinctrl/mediatek/pinctrl-moore.c
@@ -625,9 +625,8 @@ static int mtk_build_functions(struct mtk_pinctrl *hw)
const struct function_desc *function = hw->soc->funcs + i;
const struct pinfunction *func = &function->func;
- err = pinmux_generic_add_function(hw->pctrl, func->name,
- func->groups, func->ngroups,
- function->data);
+ err = pinmux_generic_add_pinfunction(hw->pctrl, func,
+ function->data);
if (err < 0) {
dev_err(hw->dev, "Failed to register function %s\n",
func->name);
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8189.c b/drivers/pinctrl/mediatek/pinctrl-mt8189.c
new file mode 100644
index 000000000000..7028aff55ae5
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8189.c
@@ -0,0 +1,1700 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 MediaTek Inc.
+ * Author: Lei Xue <lei.xue@mediatek.com>
+ * Cathy Xu <ot_cathy.xu@mediatek.com>
+ */
+
+#include "pinctrl-mtk-mt8189.h"
+#include "pinctrl-paris.h"
+
+#define PIN_FIELD_BASE(s_pin, e_pin, i_base, s_addr, x_addrs, s_bit, x_bits) \
+ PIN_FIELD_CALC(s_pin, e_pin, i_base, s_addr, x_addrs, s_bit, x_bits, \
+ 32, 0)
+
+#define PINS_FIELD_BASE(s_pin, e_pin, i_base, s_addr, x_addrs, s_bit, x_bits) \
+ PIN_FIELD_CALC(s_pin, e_pin, i_base, s_addr, x_addrs, s_bit, x_bits, \
+ 32, 1)
+
+static const struct mtk_pin_field_calc mt8189_pin_mode_range[] = {
+ PIN_FIELD(0, 182, 0x0300, 0x10, 0, 4),
+};
+
+static const struct mtk_pin_field_calc mt8189_pin_dir_range[] = {
+ PIN_FIELD(0, 182, 0x0000, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt8189_pin_di_range[] = {
+ PIN_FIELD(0, 182, 0x0200, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt8189_pin_do_range[] = {
+ PIN_FIELD(0, 182, 0x0100, 0x10, 0, 1),
+};
+
+static const struct mtk_pin_field_calc mt8189_pin_smt_range[] = {
+ PIN_FIELD_BASE(0, 0, 7, 0x00e0, 0x10, 5, 1),
+ PIN_FIELD_BASE(1, 1, 8, 0x00c0, 0x10, 3, 1),
+ PIN_FIELD_BASE(2, 2, 8, 0x00c0, 0x10, 4, 1),
+ PIN_FIELD_BASE(3, 3, 8, 0x00c0, 0x10, 5, 1),
+ PIN_FIELD_BASE(4, 4, 8, 0x00c0, 0x10, 6, 1),
+ PIN_FIELD_BASE(5, 5, 8, 0x00c0, 0x10, 7, 1),
+ PIN_FIELD_BASE(6, 6, 7, 0x00e0, 0x10, 6, 1),
+ PIN_FIELD_BASE(7, 7, 7, 0x00e0, 0x10, 7, 1),
+ PIN_FIELD_BASE(8, 8, 7, 0x00e0, 0x10, 8, 1),
+ PIN_FIELD_BASE(9, 9, 7, 0x00e0, 0x10, 9, 1),
+ PIN_FIELD_BASE(10, 10, 7, 0x00e0, 0x10, 10, 1),
+ PIN_FIELD_BASE(11, 11, 7, 0x00e0, 0x10, 11, 1),
+ PIN_FIELD_BASE(12, 12, 2, 0x00e0, 0x10, 5, 1),
+ PIN_FIELD_BASE(13, 13, 2, 0x00e0, 0x10, 6, 1),
+ PIN_FIELD_BASE(14, 14, 3, 0x00f0, 0x10, 0, 1),
+ PIN_FIELD_BASE(15, 15, 3, 0x00f0, 0x10, 1, 1),
+ PIN_FIELD_BASE(16, 16, 2, 0x00e0, 0x10, 7, 1),
+ PIN_FIELD_BASE(17, 17, 2, 0x00e0, 0x10, 8, 1),
+ PIN_FIELD_BASE(18, 18, 7, 0x00e0, 0x10, 0, 1),
+ PIN_FIELD_BASE(19, 19, 7, 0x00e0, 0x10, 2, 1),
+ PIN_FIELD_BASE(20, 20, 7, 0x00e0, 0x10, 1, 1),
+ PIN_FIELD_BASE(21, 21, 7, 0x00e0, 0x10, 3, 1),
+ PIN_FIELD_BASE(22, 22, 9, 0x00f0, 0x10, 0, 1),
+ PIN_FIELD_BASE(23, 23, 9, 0x00f0, 0x10, 1, 1),
+ PIN_FIELD_BASE(24, 24, 9, 0x00f0, 0x10, 2, 1),
+ PIN_FIELD_BASE(25, 25, 4, 0x00c0, 0x10, 2, 1),
+ PIN_FIELD_BASE(26, 26, 4, 0x00c0, 0x10, 1, 1),
+ PIN_FIELD_BASE(27, 27, 2, 0x00e0, 0x10, 1, 1),
+ PIN_FIELD_BASE(28, 28, 2, 0x00e0, 0x10, 2, 1),
+ PIN_FIELD_BASE(29, 29, 4, 0x00c0, 0x10, 0, 1),
+ PIN_FIELD_BASE(30, 30, 2, 0x00e0, 0x10, 0, 1),
+ PIN_FIELD_BASE(31, 31, 3, 0x00f0, 0x10, 19, 1),
+ PIN_FIELD_BASE(32, 32, 1, 0x00c0, 0x10, 30, 1),
+ PIN_FIELD_BASE(33, 33, 3, 0x00f0, 0x10, 21, 1),
+ PIN_FIELD_BASE(34, 34, 3, 0x00f0, 0x10, 20, 1),
+ PIN_FIELD_BASE(35, 35, 3, 0x00f0, 0x10, 23, 1),
+ PIN_FIELD_BASE(36, 36, 3, 0x00f0, 0x10, 22, 1),
+ PIN_FIELD_BASE(37, 37, 3, 0x00f0, 0x10, 25, 1),
+ PIN_FIELD_BASE(38, 38, 3, 0x00f0, 0x10, 24, 1),
+ PIN_FIELD_BASE(39, 39, 3, 0x00f0, 0x10, 5, 1),
+ PIN_FIELD_BASE(40, 40, 3, 0x00f0, 0x10, 2, 1),
+ PIN_FIELD_BASE(41, 41, 3, 0x00f0, 0x10, 3, 1),
+ PIN_FIELD_BASE(42, 42, 3, 0x00f0, 0x10, 4, 1),
+ PIN_FIELD_BASE(43, 43, 3, 0x00f0, 0x10, 6, 1),
+ PIN_FIELD_BASE(44, 44, 7, 0x00e0, 0x10, 20, 1),
+ PIN_FIELD_BASE(45, 45, 7, 0x00e0, 0x10, 21, 1),
+ PIN_FIELD_BASE(46, 46, 7, 0x00e0, 0x10, 22, 1),
+ PIN_FIELD_BASE(47, 47, 7, 0x00e0, 0x10, 23, 1),
+ PIN_FIELD_BASE(48, 48, 4, 0x00c0, 0x10, 5, 1),
+ PIN_FIELD_BASE(49, 49, 4, 0x00c0, 0x10, 4, 1),
+ PIN_FIELD_BASE(50, 50, 4, 0x00c0, 0x10, 3, 1),
+ PIN_FIELD_BASE(51, 51, 8, 0x00c0, 0x10, 8, 1),
+ PIN_FIELD_BASE(52, 52, 8, 0x00c0, 0x10, 10, 1),
+ PIN_FIELD_BASE(53, 53, 8, 0x00c0, 0x10, 9, 1),
+ PIN_FIELD_BASE(54, 54, 8, 0x00c0, 0x10, 11, 1),
+ PIN_FIELD_BASE(55, 55, 4, 0x00c0, 0x10, 6, 1),
+ PIN_FIELD_BASE(56, 56, 4, 0x00c0, 0x10, 7, 1),
+ PIN_FIELD_BASE(57, 57, 2, 0x00e0, 0x10, 13, 1),
+ PIN_FIELD_BASE(58, 58, 2, 0x00e0, 0x10, 17, 1),
+ PIN_FIELD_BASE(59, 59, 2, 0x00e0, 0x10, 14, 1),
+ PIN_FIELD_BASE(60, 60, 2, 0x00e0, 0x10, 18, 1),
+ PIN_FIELD_BASE(61, 61, 2, 0x00e0, 0x10, 15, 1),
+ PIN_FIELD_BASE(62, 62, 2, 0x00e0, 0x10, 19, 1),
+ PIN_FIELD_BASE(63, 63, 2, 0x00e0, 0x10, 16, 1),
+ PIN_FIELD_BASE(64, 64, 2, 0x00e0, 0x10, 20, 1),
+ PIN_FIELD_BASE(65, 65, 9, 0x00f0, 0x10, 10, 1),
+ PIN_FIELD_BASE(66, 66, 9, 0x00f0, 0x10, 12, 1),
+ PIN_FIELD_BASE(67, 67, 9, 0x00f0, 0x10, 11, 1),
+ PIN_FIELD_BASE(68, 68, 9, 0x00f0, 0x10, 13, 1),
+ PIN_FIELD_BASE(69, 69, 2, 0x00e0, 0x10, 22, 1),
+ PIN_FIELD_BASE(70, 70, 2, 0x00e0, 0x10, 21, 1),
+ PIN_FIELD_BASE(71, 71, 2, 0x00e0, 0x10, 24, 1),
+ PIN_FIELD_BASE(72, 72, 2, 0x00e0, 0x10, 23, 1),
+ PIN_FIELD_BASE(73, 73, 2, 0x00e0, 0x10, 26, 1),
+ PIN_FIELD_BASE(74, 74, 2, 0x00e0, 0x10, 25, 1),
+ PIN_FIELD_BASE(75, 75, 3, 0x00f0, 0x10, 13, 1),
+ PIN_FIELD_BASE(76, 76, 2, 0x00e0, 0x10, 27, 1),
+ PIN_FIELD_BASE(77, 77, 8, 0x00c0, 0x10, 13, 1),
+ PIN_FIELD_BASE(78, 78, 8, 0x00c0, 0x10, 12, 1),
+ PIN_FIELD_BASE(79, 79, 8, 0x00c0, 0x10, 15, 1),
+ PIN_FIELD_BASE(80, 80, 8, 0x00c0, 0x10, 14, 1),
+ PIN_FIELD_BASE(81, 81, 2, 0x00e0, 0x10, 29, 1),
+ PIN_FIELD_BASE(82, 82, 2, 0x00e0, 0x10, 28, 1),
+ PIN_FIELD_BASE(83, 83, 2, 0x00e0, 0x10, 30, 1),
+ PIN_FIELD_BASE(84, 84, 7, 0x00e0, 0x10, 24, 1),
+ PIN_FIELD_BASE(85, 85, 7, 0x00e0, 0x10, 25, 1),
+ PIN_FIELD_BASE(86, 86, 7, 0x00e0, 0x10, 26, 1),
+ PIN_FIELD_BASE(87, 87, 7, 0x00e0, 0x10, 27, 1),
+ PIN_FIELD_BASE(88, 88, 5, 0x0120, 0x10, 20, 1),
+ PIN_FIELD_BASE(89, 89, 5, 0x0120, 0x10, 19, 1),
+ PIN_FIELD_BASE(90, 90, 5, 0x0120, 0x10, 22, 1),
+ PIN_FIELD_BASE(91, 91, 5, 0x0120, 0x10, 21, 1),
+ PIN_FIELD_BASE(92, 92, 5, 0x0120, 0x10, 16, 1),
+ PIN_FIELD_BASE(93, 93, 5, 0x0120, 0x10, 17, 1),
+ PIN_FIELD_BASE(94, 94, 5, 0x0120, 0x10, 23, 1),
+ PIN_FIELD_BASE(95, 95, 5, 0x0120, 0x10, 15, 1),
+ PIN_FIELD_BASE(96, 96, 5, 0x0120, 0x10, 18, 1),
+ PIN_FIELD_BASE(97, 97, 5, 0x0120, 0x10, 0, 1),
+ PIN_FIELD_BASE(98, 98, 5, 0x0120, 0x10, 5, 1),
+ PIN_FIELD_BASE(99, 99, 5, 0x0120, 0x10, 3, 1),
+ PIN_FIELD_BASE(100, 100, 5, 0x0120, 0x10, 4, 1),
+ PIN_FIELD_BASE(101, 101, 5, 0x0120, 0x10, 1, 1),
+ PIN_FIELD_BASE(102, 102, 5, 0x0120, 0x10, 2, 1),
+ PIN_FIELD_BASE(103, 103, 7, 0x00e0, 0x10, 15, 1),
+ PIN_FIELD_BASE(104, 104, 7, 0x00e0, 0x10, 12, 1),
+ PIN_FIELD_BASE(105, 105, 7, 0x00e0, 0x10, 14, 1),
+ PIN_FIELD_BASE(106, 106, 7, 0x00e0, 0x10, 13, 1),
+ PIN_FIELD_BASE(107, 107, 7, 0x00e0, 0x10, 19, 1),
+ PIN_FIELD_BASE(108, 108, 7, 0x00e0, 0x10, 16, 1),
+ PIN_FIELD_BASE(109, 109, 7, 0x00e0, 0x10, 18, 1),
+ PIN_FIELD_BASE(110, 110, 7, 0x00e0, 0x10, 17, 1),
+ PIN_FIELD_BASE(111, 111, 7, 0x00e0, 0x10, 4, 1),
+ PIN_FIELD_BASE(112, 112, 8, 0x00c0, 0x10, 0, 1),
+ PIN_FIELD_BASE(113, 113, 8, 0x00c0, 0x10, 1, 1),
+ PIN_FIELD_BASE(114, 114, 8, 0x00c0, 0x10, 2, 1),
+ PIN_FIELD_BASE(115, 115, 2, 0x00e0, 0x10, 9, 1),
+ PIN_FIELD_BASE(116, 116, 2, 0x00e0, 0x10, 12, 1),
+ PIN_FIELD_BASE(117, 117, 2, 0x00e0, 0x10, 10, 1),
+ PIN_FIELD_BASE(118, 118, 2, 0x00e0, 0x10, 11, 1),
+ PIN_FIELD_BASE(119, 119, 1, 0x00c0, 0x10, 26, 1),
+ PIN_FIELD_BASE(120, 120, 1, 0x00c0, 0x10, 25, 1),
+ PIN_FIELD_BASE(121, 121, 1, 0x00c0, 0x10, 24, 1),
+ PIN_FIELD_BASE(122, 122, 1, 0x00c0, 0x10, 23, 1),
+ PIN_FIELD_BASE(123, 123, 1, 0x00c0, 0x10, 19, 1),
+ PIN_FIELD_BASE(124, 124, 1, 0x00c0, 0x10, 18, 1),
+ PIN_FIELD_BASE(125, 125, 1, 0x00c0, 0x10, 17, 1),
+ PIN_FIELD_BASE(126, 126, 1, 0x00c0, 0x10, 16, 1),
+ PIN_FIELD_BASE(127, 127, 1, 0x00c0, 0x10, 22, 1),
+ PIN_FIELD_BASE(128, 128, 1, 0x00c0, 0x10, 15, 1),
+ PIN_FIELD_BASE(129, 129, 1, 0x00c0, 0x10, 20, 1),
+ PIN_FIELD_BASE(130, 130, 1, 0x00c0, 0x10, 27, 1),
+ PIN_FIELD_BASE(131, 131, 1, 0x00c0, 0x10, 13, 1),
+ PIN_FIELD_BASE(132, 132, 1, 0x00c0, 0x10, 14, 1),
+ PIN_FIELD_BASE(133, 133, 1, 0x00c0, 0x10, 28, 1),
+ PIN_FIELD_BASE(134, 134, 1, 0x00c0, 0x10, 21, 1),
+ PIN_FIELD_BASE(135, 135, 1, 0x00c0, 0x10, 11, 1),
+ PIN_FIELD_BASE(136, 136, 1, 0x00c0, 0x10, 12, 1),
+ PIN_FIELD_BASE(137, 137, 2, 0x00e0, 0x10, 3, 1),
+ PIN_FIELD_BASE(138, 138, 2, 0x00e0, 0x10, 4, 1),
+ PIN_FIELD_BASE(139, 139, 1, 0x00c0, 0x10, 3, 1),
+ PIN_FIELD_BASE(140, 140, 1, 0x00c0, 0x10, 4, 1),
+ PIN_FIELD_BASE(141, 141, 1, 0x00c0, 0x10, 0, 1),
+ PIN_FIELD_BASE(142, 142, 1, 0x00c0, 0x10, 1, 1),
+ PIN_FIELD_BASE(143, 143, 1, 0x00c0, 0x10, 2, 1),
+ PIN_FIELD_BASE(144, 144, 1, 0x00c0, 0x10, 5, 1),
+ PIN_FIELD_BASE(145, 145, 1, 0x00c0, 0x10, 6, 1),
+ PIN_FIELD_BASE(146, 146, 1, 0x00c0, 0x10, 7, 1),
+ PIN_FIELD_BASE(147, 147, 1, 0x00c0, 0x10, 8, 1),
+ PIN_FIELD_BASE(148, 148, 1, 0x00c0, 0x10, 9, 1),
+ PIN_FIELD_BASE(149, 149, 1, 0x00c0, 0x10, 10, 1),
+ PIN_FIELD_BASE(150, 150, 3, 0x00f0, 0x10, 14, 1),
+ PIN_FIELD_BASE(151, 151, 1, 0x00c0, 0x10, 29, 1),
+ PIN_FIELD_BASE(152, 152, 3, 0x00f0, 0x10, 15, 1),
+ PIN_FIELD_BASE(153, 153, 3, 0x00f0, 0x10, 16, 1),
+ PIN_FIELD_BASE(154, 154, 3, 0x00f0, 0x10, 17, 1),
+ PIN_FIELD_BASE(155, 155, 3, 0x00f0, 0x10, 18, 1),
+ PIN_FIELD_BASE(156, 156, 5, 0x0120, 0x10, 12, 1),
+ PIN_FIELD_BASE(157, 157, 5, 0x0120, 0x10, 11, 1),
+ PIN_FIELD_BASE(158, 158, 5, 0x0120, 0x10, 10, 1),
+ PIN_FIELD_BASE(159, 159, 6, 0x0090, 0x10, 2, 1),
+ PIN_FIELD_BASE(160, 160, 5, 0x0120, 0x10, 14, 1),
+ PIN_FIELD_BASE(161, 161, 5, 0x0120, 0x10, 7, 1),
+ PIN_FIELD_BASE(162, 162, 5, 0x0120, 0x10, 6, 1),
+ PIN_FIELD_BASE(163, 163, 6, 0x0090, 0x10, 1, 1),
+ PIN_FIELD_BASE(164, 164, 5, 0x0120, 0x10, 9, 1),
+ PIN_FIELD_BASE(165, 165, 5, 0x0120, 0x10, 8, 1),
+ PIN_FIELD_BASE(166, 166, 6, 0x0090, 0x10, 0, 1),
+ PIN_FIELD_BASE(167, 167, 5, 0x0120, 0x10, 13, 1),
+ PIN_FIELD_BASE(168, 168, 3, 0x00f0, 0x10, 8, 1),
+ PIN_FIELD_BASE(169, 169, 3, 0x00f0, 0x10, 7, 1),
+ PIN_FIELD_BASE(170, 170, 3, 0x00f0, 0x10, 9, 1),
+ PIN_FIELD_BASE(171, 171, 3, 0x00f0, 0x10, 10, 1),
+ PIN_FIELD_BASE(172, 172, 3, 0x00f0, 0x10, 11, 1),
+ PIN_FIELD_BASE(173, 173, 3, 0x00f0, 0x10, 12, 1),
+ PIN_FIELD_BASE(174, 174, 9, 0x00f0, 0x10, 5, 1),
+ PIN_FIELD_BASE(175, 175, 9, 0x00f0, 0x10, 4, 1),
+ PIN_FIELD_BASE(176, 176, 9, 0x00f0, 0x10, 6, 1),
+ PIN_FIELD_BASE(177, 177, 9, 0x00f0, 0x10, 7, 1),
+ PIN_FIELD_BASE(178, 178, 9, 0x00f0, 0x10, 8, 1),
+ PIN_FIELD_BASE(179, 179, 9, 0x00f0, 0x10, 9, 1),
+ PIN_FIELD_BASE(180, 180, 5, 0x0120, 0x10, 24, 1),
+ PIN_FIELD_BASE(181, 181, 5, 0x0120, 0x10, 25, 1),
+ PIN_FIELD_BASE(182, 182, 9, 0x00f0, 0x10, 3, 1),
+};
+
+static const struct mtk_pin_field_calc mt8189_pin_ies_range[] = {
+ PIN_FIELD_BASE(0, 0, 7, 0x0050, 0x10, 5, 1),
+ PIN_FIELD_BASE(1, 1, 8, 0x0050, 0x10, 3, 1),
+ PIN_FIELD_BASE(2, 2, 8, 0x0050, 0x10, 4, 1),
+ PIN_FIELD_BASE(3, 3, 8, 0x0050, 0x10, 5, 1),
+ PIN_FIELD_BASE(4, 4, 8, 0x0050, 0x10, 6, 1),
+ PIN_FIELD_BASE(5, 5, 8, 0x0050, 0x10, 7, 1),
+ PIN_FIELD_BASE(6, 6, 7, 0x0050, 0x10, 6, 1),
+ PIN_FIELD_BASE(7, 7, 7, 0x0050, 0x10, 7, 1),
+ PIN_FIELD_BASE(8, 8, 7, 0x0050, 0x10, 8, 1),
+ PIN_FIELD_BASE(9, 9, 7, 0x0050, 0x10, 9, 1),
+ PIN_FIELD_BASE(10, 10, 7, 0x0050, 0x10, 10, 1),
+ PIN_FIELD_BASE(11, 11, 7, 0x0050, 0x10, 11, 1),
+ PIN_FIELD_BASE(12, 12, 2, 0x0070, 0x10, 5, 1),
+ PIN_FIELD_BASE(13, 13, 2, 0x0070, 0x10, 6, 1),
+ PIN_FIELD_BASE(14, 14, 3, 0x0050, 0x10, 0, 1),
+ PIN_FIELD_BASE(15, 15, 3, 0x0050, 0x10, 1, 1),
+ PIN_FIELD_BASE(16, 16, 2, 0x0070, 0x10, 7, 1),
+ PIN_FIELD_BASE(17, 17, 2, 0x0070, 0x10, 8, 1),
+ PIN_FIELD_BASE(18, 18, 7, 0x0050, 0x10, 0, 1),
+ PIN_FIELD_BASE(19, 19, 7, 0x0050, 0x10, 2, 1),
+ PIN_FIELD_BASE(20, 20, 7, 0x0050, 0x10, 1, 1),
+ PIN_FIELD_BASE(21, 21, 7, 0x0050, 0x10, 3, 1),
+ PIN_FIELD_BASE(22, 22, 9, 0x0040, 0x10, 0, 1),
+ PIN_FIELD_BASE(23, 23, 9, 0x0040, 0x10, 1, 1),
+ PIN_FIELD_BASE(24, 24, 9, 0x0040, 0x10, 2, 1),
+ PIN_FIELD_BASE(25, 25, 4, 0x0050, 0x10, 2, 1),
+ PIN_FIELD_BASE(26, 26, 4, 0x0050, 0x10, 1, 1),
+ PIN_FIELD_BASE(27, 27, 2, 0x0070, 0x10, 1, 1),
+ PIN_FIELD_BASE(28, 28, 2, 0x0070, 0x10, 2, 1),
+ PIN_FIELD_BASE(29, 29, 4, 0x0050, 0x10, 0, 1),
+ PIN_FIELD_BASE(30, 30, 2, 0x0070, 0x10, 0, 1),
+ PIN_FIELD_BASE(31, 31, 3, 0x0050, 0x10, 19, 1),
+ PIN_FIELD_BASE(32, 32, 1, 0x0050, 0x10, 30, 1),
+ PIN_FIELD_BASE(33, 33, 3, 0x0050, 0x10, 21, 1),
+ PIN_FIELD_BASE(34, 34, 3, 0x0050, 0x10, 20, 1),
+ PIN_FIELD_BASE(35, 35, 3, 0x0050, 0x10, 23, 1),
+ PIN_FIELD_BASE(36, 36, 3, 0x0050, 0x10, 22, 1),
+ PIN_FIELD_BASE(37, 37, 3, 0x0050, 0x10, 25, 1),
+ PIN_FIELD_BASE(38, 38, 3, 0x0050, 0x10, 24, 1),
+ PIN_FIELD_BASE(39, 39, 3, 0x0050, 0x10, 5, 1),
+ PIN_FIELD_BASE(40, 40, 3, 0x0050, 0x10, 2, 1),
+ PIN_FIELD_BASE(41, 41, 3, 0x0050, 0x10, 3, 1),
+ PIN_FIELD_BASE(42, 42, 3, 0x0050, 0x10, 4, 1),
+ PIN_FIELD_BASE(43, 43, 3, 0x0050, 0x10, 6, 1),
+ PIN_FIELD_BASE(44, 44, 7, 0x0050, 0x10, 20, 1),
+ PIN_FIELD_BASE(45, 45, 7, 0x0050, 0x10, 21, 1),
+ PIN_FIELD_BASE(46, 46, 7, 0x0050, 0x10, 22, 1),
+ PIN_FIELD_BASE(47, 47, 7, 0x0050, 0x10, 23, 1),
+ PIN_FIELD_BASE(48, 48, 4, 0x0050, 0x10, 5, 1),
+ PIN_FIELD_BASE(49, 49, 4, 0x0050, 0x10, 4, 1),
+ PIN_FIELD_BASE(50, 50, 4, 0x0050, 0x10, 3, 1),
+ PIN_FIELD_BASE(51, 51, 8, 0x0050, 0x10, 8, 1),
+ PIN_FIELD_BASE(52, 52, 8, 0x0050, 0x10, 10, 1),
+ PIN_FIELD_BASE(53, 53, 8, 0x0050, 0x10, 9, 1),
+ PIN_FIELD_BASE(54, 54, 8, 0x0050, 0x10, 11, 1),
+ PIN_FIELD_BASE(55, 55, 4, 0x0050, 0x10, 6, 1),
+ PIN_FIELD_BASE(56, 56, 4, 0x0050, 0x10, 7, 1),
+ PIN_FIELD_BASE(57, 57, 2, 0x0070, 0x10, 13, 1),
+ PIN_FIELD_BASE(58, 58, 2, 0x0070, 0x10, 17, 1),
+ PIN_FIELD_BASE(59, 59, 2, 0x0070, 0x10, 14, 1),
+ PIN_FIELD_BASE(60, 60, 2, 0x0070, 0x10, 18, 1),
+ PIN_FIELD_BASE(61, 61, 2, 0x0070, 0x10, 15, 1),
+ PIN_FIELD_BASE(62, 62, 2, 0x0070, 0x10, 19, 1),
+ PIN_FIELD_BASE(63, 63, 2, 0x0070, 0x10, 16, 1),
+ PIN_FIELD_BASE(64, 64, 2, 0x0070, 0x10, 20, 1),
+ PIN_FIELD_BASE(65, 65, 9, 0x0040, 0x10, 10, 1),
+ PIN_FIELD_BASE(66, 66, 9, 0x0040, 0x10, 12, 1),
+ PIN_FIELD_BASE(67, 67, 9, 0x0040, 0x10, 11, 1),
+ PIN_FIELD_BASE(68, 68, 9, 0x0040, 0x10, 13, 1),
+ PIN_FIELD_BASE(69, 69, 2, 0x0070, 0x10, 22, 1),
+ PIN_FIELD_BASE(70, 70, 2, 0x0070, 0x10, 21, 1),
+ PIN_FIELD_BASE(71, 71, 2, 0x0070, 0x10, 24, 1),
+ PIN_FIELD_BASE(72, 72, 2, 0x0070, 0x10, 23, 1),
+ PIN_FIELD_BASE(73, 73, 2, 0x0070, 0x10, 26, 1),
+ PIN_FIELD_BASE(74, 74, 2, 0x0070, 0x10, 25, 1),
+ PIN_FIELD_BASE(75, 75, 3, 0x0050, 0x10, 13, 1),
+ PIN_FIELD_BASE(76, 76, 2, 0x0070, 0x10, 27, 1),
+ PIN_FIELD_BASE(77, 77, 8, 0x0050, 0x10, 13, 1),
+ PIN_FIELD_BASE(78, 78, 8, 0x0050, 0x10, 12, 1),
+ PIN_FIELD_BASE(79, 79, 8, 0x0050, 0x10, 15, 1),
+ PIN_FIELD_BASE(80, 80, 8, 0x0050, 0x10, 14, 1),
+ PIN_FIELD_BASE(81, 81, 2, 0x0070, 0x10, 29, 1),
+ PIN_FIELD_BASE(82, 82, 2, 0x0070, 0x10, 28, 1),
+ PIN_FIELD_BASE(83, 83, 2, 0x0070, 0x10, 30, 1),
+ PIN_FIELD_BASE(84, 84, 7, 0x0050, 0x10, 24, 1),
+ PIN_FIELD_BASE(85, 85, 7, 0x0050, 0x10, 25, 1),
+ PIN_FIELD_BASE(86, 86, 7, 0x0050, 0x10, 26, 1),
+ PIN_FIELD_BASE(87, 87, 7, 0x0050, 0x10, 27, 1),
+ PIN_FIELD_BASE(88, 88, 5, 0x0060, 0x10, 20, 1),
+ PIN_FIELD_BASE(89, 89, 5, 0x0060, 0x10, 19, 1),
+ PIN_FIELD_BASE(90, 90, 5, 0x0060, 0x10, 22, 1),
+ PIN_FIELD_BASE(91, 91, 5, 0x0060, 0x10, 21, 1),
+ PIN_FIELD_BASE(92, 92, 5, 0x0060, 0x10, 16, 1),
+ PIN_FIELD_BASE(93, 93, 5, 0x0060, 0x10, 17, 1),
+ PIN_FIELD_BASE(94, 94, 5, 0x0060, 0x10, 23, 1),
+ PIN_FIELD_BASE(95, 95, 5, 0x0060, 0x10, 15, 1),
+ PIN_FIELD_BASE(96, 96, 5, 0x0060, 0x10, 18, 1),
+ PIN_FIELD_BASE(97, 97, 5, 0x0060, 0x10, 0, 1),
+ PIN_FIELD_BASE(98, 98, 5, 0x0060, 0x10, 5, 1),
+ PIN_FIELD_BASE(99, 99, 5, 0x0060, 0x10, 3, 1),
+ PIN_FIELD_BASE(100, 100, 5, 0x0060, 0x10, 4, 1),
+ PIN_FIELD_BASE(101, 101, 5, 0x0060, 0x10, 1, 1),
+ PIN_FIELD_BASE(102, 102, 5, 0x0060, 0x10, 2, 1),
+ PIN_FIELD_BASE(103, 103, 7, 0x0050, 0x10, 15, 1),
+ PIN_FIELD_BASE(104, 104, 7, 0x0050, 0x10, 12, 1),
+ PIN_FIELD_BASE(105, 105, 7, 0x0050, 0x10, 14, 1),
+ PIN_FIELD_BASE(106, 106, 7, 0x0050, 0x10, 13, 1),
+ PIN_FIELD_BASE(107, 107, 7, 0x0050, 0x10, 19, 1),
+ PIN_FIELD_BASE(108, 108, 7, 0x0050, 0x10, 16, 1),
+ PIN_FIELD_BASE(109, 109, 7, 0x0050, 0x10, 18, 1),
+ PIN_FIELD_BASE(110, 110, 7, 0x0050, 0x10, 17, 1),
+ PIN_FIELD_BASE(111, 111, 7, 0x0050, 0x10, 4, 1),
+ PIN_FIELD_BASE(112, 112, 8, 0x0050, 0x10, 0, 1),
+ PIN_FIELD_BASE(113, 113, 8, 0x0050, 0x10, 1, 1),
+ PIN_FIELD_BASE(114, 114, 8, 0x0050, 0x10, 2, 1),
+ PIN_FIELD_BASE(115, 115, 2, 0x0070, 0x10, 9, 1),
+ PIN_FIELD_BASE(116, 116, 2, 0x0070, 0x10, 12, 1),
+ PIN_FIELD_BASE(117, 117, 2, 0x0070, 0x10, 10, 1),
+ PIN_FIELD_BASE(118, 118, 2, 0x0070, 0x10, 11, 1),
+ PIN_FIELD_BASE(119, 119, 1, 0x0050, 0x10, 26, 1),
+ PIN_FIELD_BASE(120, 120, 1, 0x0050, 0x10, 25, 1),
+ PIN_FIELD_BASE(121, 121, 1, 0x0050, 0x10, 24, 1),
+ PIN_FIELD_BASE(122, 122, 1, 0x0050, 0x10, 23, 1),
+ PIN_FIELD_BASE(123, 123, 1, 0x0050, 0x10, 19, 1),
+ PIN_FIELD_BASE(124, 124, 1, 0x0050, 0x10, 18, 1),
+ PIN_FIELD_BASE(125, 125, 1, 0x0050, 0x10, 17, 1),
+ PIN_FIELD_BASE(126, 126, 1, 0x0050, 0x10, 16, 1),
+ PIN_FIELD_BASE(127, 127, 1, 0x0050, 0x10, 22, 1),
+ PIN_FIELD_BASE(128, 128, 1, 0x0050, 0x10, 15, 1),
+ PIN_FIELD_BASE(129, 129, 1, 0x0050, 0x10, 20, 1),
+ PIN_FIELD_BASE(130, 130, 1, 0x0050, 0x10, 27, 1),
+ PIN_FIELD_BASE(131, 131, 1, 0x0050, 0x10, 13, 1),
+ PIN_FIELD_BASE(132, 132, 1, 0x0050, 0x10, 14, 1),
+ PIN_FIELD_BASE(133, 133, 1, 0x0050, 0x10, 28, 1),
+ PIN_FIELD_BASE(134, 134, 1, 0x0050, 0x10, 21, 1),
+ PIN_FIELD_BASE(135, 135, 1, 0x0050, 0x10, 11, 1),
+ PIN_FIELD_BASE(136, 136, 1, 0x0050, 0x10, 12, 1),
+ PIN_FIELD_BASE(137, 137, 2, 0x0070, 0x10, 3, 1),
+ PIN_FIELD_BASE(138, 138, 2, 0x0070, 0x10, 4, 1),
+ PIN_FIELD_BASE(139, 139, 1, 0x0050, 0x10, 3, 1),
+ PIN_FIELD_BASE(140, 140, 1, 0x0050, 0x10, 4, 1),
+ PIN_FIELD_BASE(141, 141, 1, 0x0050, 0x10, 0, 1),
+ PIN_FIELD_BASE(142, 142, 1, 0x0050, 0x10, 1, 1),
+ PIN_FIELD_BASE(143, 143, 1, 0x0050, 0x10, 2, 1),
+ PIN_FIELD_BASE(144, 144, 1, 0x0050, 0x10, 5, 1),
+ PIN_FIELD_BASE(145, 145, 1, 0x0050, 0x10, 6, 1),
+ PIN_FIELD_BASE(146, 146, 1, 0x0050, 0x10, 7, 1),
+ PIN_FIELD_BASE(147, 147, 1, 0x0050, 0x10, 8, 1),
+ PIN_FIELD_BASE(148, 148, 1, 0x0050, 0x10, 9, 1),
+ PIN_FIELD_BASE(149, 149, 1, 0x0050, 0x10, 10, 1),
+ PIN_FIELD_BASE(150, 150, 3, 0x0050, 0x10, 14, 1),
+ PIN_FIELD_BASE(151, 151, 1, 0x0050, 0x10, 29, 1),
+ PIN_FIELD_BASE(152, 152, 3, 0x0050, 0x10, 15, 1),
+ PIN_FIELD_BASE(153, 153, 3, 0x0050, 0x10, 16, 1),
+ PIN_FIELD_BASE(154, 154, 3, 0x0050, 0x10, 17, 1),
+ PIN_FIELD_BASE(155, 155, 3, 0x0050, 0x10, 18, 1),
+ PIN_FIELD_BASE(156, 156, 5, 0x0060, 0x10, 12, 1),
+ PIN_FIELD_BASE(157, 157, 5, 0x0060, 0x10, 11, 1),
+ PIN_FIELD_BASE(158, 158, 5, 0x0060, 0x10, 10, 1),
+ PIN_FIELD_BASE(159, 159, 6, 0x0020, 0x10, 2, 1),
+ PIN_FIELD_BASE(160, 160, 5, 0x0060, 0x10, 14, 1),
+ PIN_FIELD_BASE(161, 161, 5, 0x0060, 0x10, 7, 1),
+ PIN_FIELD_BASE(162, 162, 5, 0x0060, 0x10, 6, 1),
+ PIN_FIELD_BASE(163, 163, 6, 0x0020, 0x10, 1, 1),
+ PIN_FIELD_BASE(164, 164, 5, 0x0060, 0x10, 9, 1),
+ PIN_FIELD_BASE(165, 165, 5, 0x0060, 0x10, 8, 1),
+ PIN_FIELD_BASE(166, 166, 6, 0x0020, 0x10, 0, 1),
+ PIN_FIELD_BASE(167, 167, 5, 0x0060, 0x10, 13, 1),
+ PIN_FIELD_BASE(168, 168, 3, 0x0050, 0x10, 8, 1),
+ PIN_FIELD_BASE(169, 169, 3, 0x0050, 0x10, 7, 1),
+ PIN_FIELD_BASE(170, 170, 3, 0x0050, 0x10, 9, 1),
+ PIN_FIELD_BASE(171, 171, 3, 0x0050, 0x10, 10, 1),
+ PIN_FIELD_BASE(172, 172, 3, 0x0050, 0x10, 11, 1),
+ PIN_FIELD_BASE(173, 173, 3, 0x0050, 0x10, 12, 1),
+ PIN_FIELD_BASE(174, 174, 9, 0x0040, 0x10, 5, 1),
+ PIN_FIELD_BASE(175, 175, 9, 0x0040, 0x10, 4, 1),
+ PIN_FIELD_BASE(176, 176, 9, 0x0040, 0x10, 6, 1),
+ PIN_FIELD_BASE(177, 177, 9, 0x0040, 0x10, 7, 1),
+ PIN_FIELD_BASE(178, 178, 9, 0x0040, 0x10, 8, 1),
+ PIN_FIELD_BASE(179, 179, 9, 0x0040, 0x10, 9, 1),
+ PIN_FIELD_BASE(180, 180, 5, 0x0060, 0x10, 24, 1),
+ PIN_FIELD_BASE(181, 181, 5, 0x0060, 0x10, 25, 1),
+ PIN_FIELD_BASE(182, 182, 9, 0x0040, 0x10, 3, 1),
+};
+
+static const struct mtk_pin_field_calc mt8189_pin_tdsel_range[] = {
+ PIN_FIELD_BASE(0, 0, 7, 0x00f0, 0x10, 0, 4),
+ PIN_FIELD_BASE(1, 1, 8, 0x00d0, 0x10, 0, 4),
+ PIN_FIELD_BASE(2, 2, 8, 0x00d0, 0x10, 4, 4),
+ PIN_FIELD_BASE(3, 3, 8, 0x00d0, 0x10, 8, 4),
+ PIN_FIELD_BASE(4, 4, 8, 0x00d0, 0x10, 12, 4),
+ PIN_FIELD_BASE(5, 5, 8, 0x00d0, 0x10, 16, 4),
+ PIN_FIELD_BASE(6, 6, 7, 0x00f0, 0x10, 4, 4),
+ PIN_FIELD_BASE(7, 7, 7, 0x00f0, 0x10, 8, 4),
+ PIN_FIELD_BASE(8, 8, 7, 0x00f0, 0x10, 12, 4),
+ PIN_FIELD_BASE(9, 9, 7, 0x00f0, 0x10, 16, 4),
+ PIN_FIELD_BASE(10, 10, 7, 0x00f0, 0x10, 20, 4),
+ PIN_FIELD_BASE(11, 11, 7, 0x00f0, 0x10, 24, 4),
+ PIN_FIELD_BASE(12, 12, 2, 0x00f0, 0x10, 12, 4),
+ PIN_FIELD_BASE(13, 13, 2, 0x00f0, 0x10, 16, 4),
+ PIN_FIELD_BASE(14, 14, 3, 0x0110, 0x10, 0, 4),
+ PIN_FIELD_BASE(15, 15, 3, 0x0110, 0x10, 4, 4),
+ PIN_FIELD_BASE(16, 16, 2, 0x00f0, 0x10, 20, 4),
+ PIN_FIELD_BASE(17, 17, 2, 0x00f0, 0x10, 28, 4),
+ PIN_FIELD_BASE(18, 18, 7, 0x0100, 0x10, 28, 4),
+ PIN_FIELD_BASE(19, 19, 7, 0x0110, 0x10, 0, 4),
+ PIN_FIELD_BASE(20, 20, 7, 0x0110, 0x10, 0, 4),
+ PIN_FIELD_BASE(21, 21, 7, 0x0110, 0x10, 0, 4),
+ PIN_FIELD_BASE(22, 22, 9, 0x0110, 0x10, 0, 4),
+ PIN_FIELD_BASE(23, 23, 9, 0x0110, 0x10, 4, 4),
+ PIN_FIELD_BASE(24, 24, 9, 0x0110, 0x10, 8, 4),
+ PIN_FIELD_BASE(25, 25, 4, 0x00d0, 0x10, 12, 4),
+ PIN_FIELD_BASE(26, 26, 4, 0x00d0, 0x10, 8, 4),
+ PIN_FIELD_BASE(27, 27, 2, 0x00f0, 0x10, 4, 4),
+ PIN_FIELD_BASE(28, 28, 2, 0x00f0, 0x10, 8, 4),
+ PIN_FIELD_BASE(29, 29, 4, 0x00d0, 0x10, 8, 4),
+ PIN_FIELD_BASE(30, 30, 2, 0x00f0, 0x10, 0, 4),
+ PIN_FIELD_BASE(31, 31, 3, 0x0120, 0x10, 8, 4),
+ PIN_FIELD_BASE(32, 32, 1, 0x00f0, 0x10, 16, 4),
+ PIN_FIELD_BASE(33, 33, 3, 0x0120, 0x10, 16, 4),
+ PIN_FIELD_BASE(34, 34, 3, 0x0120, 0x10, 4, 4),
+ PIN_FIELD_BASE(35, 35, 3, 0x0120, 0x10, 0, 4),
+ PIN_FIELD_BASE(36, 36, 3, 0x0120, 0x10, 8, 4),
+ PIN_FIELD_BASE(37, 37, 3, 0x0120, 0x10, 4, 4),
+ PIN_FIELD_BASE(38, 38, 3, 0x0120, 0x10, 4, 4),
+ PIN_FIELD_BASE(39, 39, 3, 0x0120, 0x10, 8, 4),
+ PIN_FIELD_BASE(40, 40, 3, 0x0120, 0x10, 8, 4),
+ PIN_FIELD_BASE(41, 41, 3, 0x0120, 0x10, 8, 4),
+ PIN_FIELD_BASE(42, 42, 3, 0x0120, 0x10, 8, 4),
+ PIN_FIELD_BASE(43, 43, 3, 0x0120, 0x10, 8, 4),
+ PIN_FIELD_BASE(44, 44, 7, 0x0110, 0x10, 0, 4),
+ PIN_FIELD_BASE(45, 45, 7, 0x0110, 0x10, 0, 4),
+ PIN_FIELD_BASE(46, 46, 7, 0x0110, 0x10, 0, 4),
+ PIN_FIELD_BASE(47, 47, 7, 0x0110, 0x10, 0, 4),
+ PIN_FIELD_BASE(48, 48, 4, 0x00d0, 0x10, 8, 4),
+ PIN_FIELD_BASE(49, 49, 4, 0x00d0, 0x10, 4, 4),
+ PIN_FIELD_BASE(50, 50, 4, 0x00d0, 0x10, 0, 4),
+ PIN_FIELD_BASE(51, 51, 8, 0x00d0, 0x10, 20, 4),
+ PIN_FIELD_BASE(52, 52, 8, 0x00d0, 0x10, 20, 4),
+ PIN_FIELD_BASE(53, 53, 8, 0x00d0, 0x10, 20, 4),
+ PIN_FIELD_BASE(54, 54, 8, 0x00d0, 0x10, 20, 4),
+ PIN_FIELD_BASE(55, 55, 4, 0x00d0, 0x10, 12, 4),
+ PIN_FIELD_BASE(56, 56, 4, 0x00d0, 0x10, 12, 4),
+ PIN_FIELD_BASE(57, 57, 2, 0x00f0, 0x10, 28, 4),
+ PIN_FIELD_BASE(58, 58, 2, 0x00f0, 0x10, 28, 4),
+ PIN_FIELD_BASE(59, 59, 2, 0x00f0, 0x10, 28, 4),
+ PIN_FIELD_BASE(60, 60, 2, 0x00f0, 0x10, 28, 4),
+ PIN_FIELD_BASE(61, 61, 2, 0x00f0, 0x10, 28, 4),
+ PIN_FIELD_BASE(62, 62, 2, 0x00f0, 0x10, 28, 4),
+ PIN_FIELD_BASE(63, 63, 2, 0x00f0, 0x10, 28, 4),
+ PIN_FIELD_BASE(64, 64, 2, 0x00f0, 0x10, 28, 4),
+ PIN_FIELD_BASE(65, 65, 9, 0x0120, 0x10, 4, 4),
+ PIN_FIELD_BASE(66, 66, 9, 0x0120, 0x10, 4, 4),
+ PIN_FIELD_BASE(67, 67, 9, 0x0120, 0x10, 4, 4),
+ PIN_FIELD_BASE(68, 68, 9, 0x0120, 0x10, 4, 4),
+ PIN_FIELD_BASE(69, 69, 2, 0x0100, 0x10, 4, 4),
+ PIN_FIELD_BASE(70, 70, 2, 0x0100, 0x10, 0, 4),
+ PIN_FIELD_BASE(71, 71, 2, 0x0100, 0x10, 12, 4),
+ PIN_FIELD_BASE(72, 72, 2, 0x0100, 0x10, 8, 4),
+ PIN_FIELD_BASE(73, 73, 2, 0x0100, 0x10, 20, 4),
+ PIN_FIELD_BASE(74, 74, 2, 0x0100, 0x10, 16, 4),
+ PIN_FIELD_BASE(75, 75, 3, 0x0120, 0x10, 12, 4),
+ PIN_FIELD_BASE(76, 76, 2, 0x0100, 0x10, 24, 4),
+ PIN_FIELD_BASE(77, 77, 8, 0x00d0, 0x10, 28, 4),
+ PIN_FIELD_BASE(78, 78, 8, 0x00d0, 0x10, 24, 4),
+ PIN_FIELD_BASE(79, 79, 8, 0x00e0, 0x10, 4, 4),
+ PIN_FIELD_BASE(80, 80, 8, 0x00e0, 0x10, 0, 4),
+ PIN_FIELD_BASE(81, 81, 2, 0x00f0, 0x10, 28, 4),
+ PIN_FIELD_BASE(82, 82, 2, 0x00f0, 0x10, 28, 4),
+ PIN_FIELD_BASE(83, 83, 2, 0x00f0, 0x10, 28, 4),
+ PIN_FIELD_BASE(84, 84, 7, 0x0110, 0x10, 0, 4),
+ PIN_FIELD_BASE(85, 85, 7, 0x0110, 0x10, 0, 4),
+ PIN_FIELD_BASE(86, 86, 7, 0x0110, 0x10, 0, 4),
+ PIN_FIELD_BASE(87, 87, 7, 0x0110, 0x10, 0, 4),
+ PIN_FIELD_BASE(88, 88, 5, 0x0140, 0x10, 4, 4),
+ PIN_FIELD_BASE(89, 89, 5, 0x0140, 0x10, 4, 4),
+ PIN_FIELD_BASE(90, 90, 5, 0x0140, 0x10, 4, 4),
+ PIN_FIELD_BASE(91, 91, 5, 0x0140, 0x10, 4, 4),
+ PIN_FIELD_BASE(92, 92, 5, 0x0140, 0x10, 8, 4),
+ PIN_FIELD_BASE(93, 93, 5, 0x0140, 0x10, 8, 4),
+ PIN_FIELD_BASE(94, 94, 5, 0x0140, 0x10, 8, 4),
+ PIN_FIELD_BASE(95, 95, 5, 0x0140, 0x10, 8, 4),
+ PIN_FIELD_BASE(96, 96, 5, 0x0140, 0x10, 12, 4),
+ PIN_FIELD_BASE(97, 97, 5, 0x0140, 0x10, 8, 4),
+ PIN_FIELD_BASE(98, 98, 5, 0x0140, 0x10, 8, 4),
+ PIN_FIELD_BASE(99, 99, 5, 0x0140, 0x10, 8, 4),
+ PIN_FIELD_BASE(100, 100, 5, 0x0140, 0x10, 8, 4),
+ PIN_FIELD_BASE(101, 101, 5, 0x0140, 0x10, 8, 4),
+ PIN_FIELD_BASE(102, 102, 5, 0x0140, 0x10, 8, 4),
+ PIN_FIELD_BASE(103, 103, 7, 0x0100, 0x10, 8, 4),
+ PIN_FIELD_BASE(104, 104, 7, 0x00f0, 0x10, 28, 4),
+ PIN_FIELD_BASE(105, 105, 7, 0x0100, 0x10, 4, 4),
+ PIN_FIELD_BASE(106, 106, 7, 0x0100, 0x10, 0, 4),
+ PIN_FIELD_BASE(107, 107, 7, 0x0100, 0x10, 24, 4),
+ PIN_FIELD_BASE(108, 108, 7, 0x0100, 0x10, 12, 4),
+ PIN_FIELD_BASE(109, 109, 7, 0x0100, 0x10, 20, 4),
+ PIN_FIELD_BASE(110, 110, 7, 0x0100, 0x10, 16, 4),
+ PIN_FIELD_BASE(111, 111, 7, 0x0110, 0x10, 0, 4),
+ PIN_FIELD_BASE(112, 112, 8, 0x00d0, 0x10, 20, 4),
+ PIN_FIELD_BASE(113, 113, 8, 0x00d0, 0x10, 20, 4),
+ PIN_FIELD_BASE(114, 114, 8, 0x00d0, 0x10, 20, 4),
+ PIN_FIELD_BASE(115, 115, 2, 0x00f0, 0x10, 24, 4),
+ PIN_FIELD_BASE(116, 116, 2, 0x00f0, 0x10, 28, 4),
+ PIN_FIELD_BASE(117, 117, 2, 0x00f0, 0x10, 28, 4),
+ PIN_FIELD_BASE(118, 118, 2, 0x00f0, 0x10, 28, 4),
+ PIN_FIELD_BASE(119, 119, 1, 0x00e0, 0x10, 24, 4),
+ PIN_FIELD_BASE(120, 120, 1, 0x00e0, 0x10, 20, 4),
+ PIN_FIELD_BASE(121, 121, 1, 0x00e0, 0x10, 16, 4),
+ PIN_FIELD_BASE(122, 122, 1, 0x00e0, 0x10, 12, 4),
+ PIN_FIELD_BASE(123, 123, 1, 0x00d0, 0x10, 28, 4),
+ PIN_FIELD_BASE(124, 124, 1, 0x00d0, 0x10, 24, 4),
+ PIN_FIELD_BASE(125, 125, 1, 0x00d0, 0x10, 20, 4),
+ PIN_FIELD_BASE(126, 126, 1, 0x00d0, 0x10, 16, 4),
+ PIN_FIELD_BASE(127, 127, 1, 0x00e0, 0x10, 8, 4),
+ PIN_FIELD_BASE(128, 128, 1, 0x00d0, 0x10, 12, 4),
+ PIN_FIELD_BASE(129, 129, 1, 0x00e0, 0x10, 0, 4),
+ PIN_FIELD_BASE(130, 130, 1, 0x00e0, 0x10, 28, 4),
+ PIN_FIELD_BASE(131, 131, 1, 0x00d0, 0x10, 4, 4),
+ PIN_FIELD_BASE(132, 132, 1, 0x00d0, 0x10, 8, 4),
+ PIN_FIELD_BASE(133, 133, 1, 0x00f0, 0x10, 0, 4),
+ PIN_FIELD_BASE(134, 134, 1, 0x00e0, 0x10, 4, 4),
+ PIN_FIELD_BASE(135, 135, 1, 0x00d0, 0x10, 0, 4),
+ PIN_FIELD_BASE(136, 136, 1, 0x00f0, 0x10, 4, 4),
+ PIN_FIELD_BASE(137, 137, 2, 0x00f0, 0x10, 28, 4),
+ PIN_FIELD_BASE(138, 138, 2, 0x00f0, 0x10, 28, 4),
+ PIN_FIELD_BASE(139, 139, 1, 0x00f0, 0x10, 12, 4),
+ PIN_FIELD_BASE(140, 140, 1, 0x00f0, 0x10, 12, 4),
+ PIN_FIELD_BASE(141, 141, 1, 0x00f0, 0x10, 12, 4),
+ PIN_FIELD_BASE(142, 142, 1, 0x00f0, 0x10, 12, 4),
+ PIN_FIELD_BASE(143, 143, 1, 0x00f0, 0x10, 12, 4),
+ PIN_FIELD_BASE(144, 144, 1, 0x00f0, 0x10, 12, 4),
+ PIN_FIELD_BASE(145, 145, 1, 0x00f0, 0x10, 8, 4),
+ PIN_FIELD_BASE(146, 146, 1, 0x00f0, 0x10, 8, 4),
+ PIN_FIELD_BASE(147, 147, 1, 0x00f0, 0x10, 8, 4),
+ PIN_FIELD_BASE(148, 148, 1, 0x00f0, 0x10, 8, 4),
+ PIN_FIELD_BASE(149, 149, 1, 0x00f0, 0x10, 8, 4),
+ PIN_FIELD_BASE(150, 150, 3, 0x0120, 0x10, 8, 4),
+ PIN_FIELD_BASE(151, 151, 1, 0x00f0, 0x10, 16, 4),
+ PIN_FIELD_BASE(152, 152, 3, 0x0120, 0x10, 8, 4),
+ PIN_FIELD_BASE(153, 153, 3, 0x0120, 0x10, 8, 4),
+ PIN_FIELD_BASE(154, 154, 3, 0x0120, 0x10, 8, 4),
+ PIN_FIELD_BASE(155, 155, 3, 0x0120, 0x10, 8, 4),
+ PIN_FIELD_BASE(156, 156, 5, 0x0130, 0x10, 24, 4),
+ PIN_FIELD_BASE(157, 157, 5, 0x0130, 0x10, 20, 4),
+ PIN_FIELD_BASE(158, 158, 5, 0x0130, 0x10, 16, 4),
+ PIN_FIELD_BASE(159, 159, 6, 0x00a0, 0x10, 8, 4),
+ PIN_FIELD_BASE(160, 160, 5, 0x0140, 0x10, 0, 4),
+ PIN_FIELD_BASE(161, 161, 5, 0x0130, 0x10, 4, 4),
+ PIN_FIELD_BASE(162, 162, 5, 0x0130, 0x10, 0, 4),
+ PIN_FIELD_BASE(163, 163, 6, 0x00a0, 0x10, 4, 4),
+ PIN_FIELD_BASE(164, 164, 5, 0x0130, 0x10, 12, 4),
+ PIN_FIELD_BASE(165, 165, 5, 0x0130, 0x10, 8, 4),
+ PIN_FIELD_BASE(166, 166, 6, 0x00a0, 0x10, 0, 4),
+ PIN_FIELD_BASE(167, 167, 5, 0x0130, 0x10, 28, 4),
+ PIN_FIELD_BASE(168, 168, 3, 0x0110, 0x10, 12, 4),
+ PIN_FIELD_BASE(169, 169, 3, 0x0110, 0x10, 8, 4),
+ PIN_FIELD_BASE(170, 170, 3, 0x0110, 0x10, 16, 4),
+ PIN_FIELD_BASE(171, 171, 3, 0x0110, 0x10, 20, 4),
+ PIN_FIELD_BASE(172, 172, 3, 0x0110, 0x10, 24, 4),
+ PIN_FIELD_BASE(173, 173, 3, 0x0110, 0x10, 28, 4),
+ PIN_FIELD_BASE(174, 174, 9, 0x0110, 0x10, 16, 4),
+ PIN_FIELD_BASE(175, 175, 9, 0x0110, 0x10, 12, 4),
+ PIN_FIELD_BASE(176, 176, 9, 0x0110, 0x10, 20, 4),
+ PIN_FIELD_BASE(177, 177, 9, 0x0110, 0x10, 24, 4),
+ PIN_FIELD_BASE(178, 178, 9, 0x0110, 0x10, 28, 4),
+ PIN_FIELD_BASE(179, 179, 9, 0x0120, 0x10, 0, 4),
+ PIN_FIELD_BASE(180, 180, 5, 0x0140, 0x10, 16, 4),
+ PIN_FIELD_BASE(181, 181, 5, 0x0140, 0x10, 20, 4),
+ PIN_FIELD_BASE(182, 182, 9, 0x0120, 0x10, 8, 4),
+};
+
+static const struct mtk_pin_field_calc mt8189_pin_rdsel_range[] = {
+ PIN_FIELD_BASE(0, 0, 7, 0x00d0, 0x10, 0, 2),
+ PIN_FIELD_BASE(1, 1, 8, 0x00a0, 0x10, 0, 2),
+ PIN_FIELD_BASE(2, 2, 8, 0x00a0, 0x10, 2, 2),
+ PIN_FIELD_BASE(3, 3, 8, 0x00a0, 0x10, 4, 2),
+ PIN_FIELD_BASE(4, 4, 8, 0x00a0, 0x10, 6, 2),
+ PIN_FIELD_BASE(5, 5, 8, 0x00a0, 0x10, 8, 2),
+ PIN_FIELD_BASE(6, 6, 7, 0x00d0, 0x10, 2, 2),
+ PIN_FIELD_BASE(7, 7, 7, 0x00d0, 0x10, 4, 2),
+ PIN_FIELD_BASE(8, 8, 7, 0x00d0, 0x10, 6, 2),
+ PIN_FIELD_BASE(9, 9, 7, 0x00d0, 0x10, 8, 2),
+ PIN_FIELD_BASE(10, 10, 7, 0x00d0, 0x10, 10, 2),
+ PIN_FIELD_BASE(11, 11, 7, 0x00d0, 0x10, 12, 2),
+ PIN_FIELD_BASE(12, 12, 2, 0x00c0, 0x10, 6, 2),
+ PIN_FIELD_BASE(13, 13, 2, 0x00c0, 0x10, 8, 2),
+ PIN_FIELD_BASE(14, 14, 3, 0x00d0, 0x10, 0, 2),
+ PIN_FIELD_BASE(15, 15, 3, 0x00d0, 0x10, 2, 2),
+ PIN_FIELD_BASE(16, 16, 2, 0x00c0, 0x10, 10, 2),
+ PIN_FIELD_BASE(17, 17, 2, 0x00c0, 0x10, 12, 2),
+ PIN_FIELD_BASE(18, 18, 7, 0x00d0, 0x10, 30, 2),
+ PIN_FIELD_BASE(19, 19, 7, 0x00d0, 0x10, 30, 2),
+ PIN_FIELD_BASE(20, 20, 7, 0x00d0, 0x10, 30, 2),
+ PIN_FIELD_BASE(21, 21, 7, 0x00d0, 0x10, 30, 2),
+ PIN_FIELD_BASE(22, 22, 9, 0x00c0, 0x10, 0, 2),
+ PIN_FIELD_BASE(23, 23, 9, 0x00c0, 0x10, 2, 2),
+ PIN_FIELD_BASE(24, 24, 9, 0x00c0, 0x10, 4, 2),
+ PIN_FIELD_BASE(25, 25, 4, 0x00a0, 0x10, 6, 2),
+ PIN_FIELD_BASE(26, 26, 4, 0x00a0, 0x10, 4, 2),
+ PIN_FIELD_BASE(27, 27, 2, 0x00c0, 0x10, 2, 2),
+ PIN_FIELD_BASE(28, 28, 2, 0x00c0, 0x10, 4, 2),
+ PIN_FIELD_BASE(29, 29, 4, 0x00a0, 0x10, 4, 2),
+ PIN_FIELD_BASE(30, 30, 2, 0x00c0, 0x10, 0, 2),
+ PIN_FIELD_BASE(31, 31, 3, 0x00e0, 0x10, 16, 2),
+ PIN_FIELD_BASE(32, 32, 1, 0x00b0, 0x10, 8, 2),
+ PIN_FIELD_BASE(33, 33, 3, 0x00e0, 0x10, 20, 2),
+ PIN_FIELD_BASE(34, 34, 3, 0x00e0, 0x10, 14, 2),
+ PIN_FIELD_BASE(35, 35, 3, 0x00e0, 0x10, 12, 2),
+ PIN_FIELD_BASE(36, 36, 3, 0x00e0, 0x10, 16, 2),
+ PIN_FIELD_BASE(37, 37, 3, 0x00e0, 0x10, 14, 2),
+ PIN_FIELD_BASE(38, 38, 3, 0x00e0, 0x10, 14, 2),
+ PIN_FIELD_BASE(39, 39, 3, 0x00e0, 0x10, 16, 2),
+ PIN_FIELD_BASE(40, 40, 3, 0x00e0, 0x10, 16, 2),
+ PIN_FIELD_BASE(41, 41, 3, 0x00e0, 0x10, 16, 2),
+ PIN_FIELD_BASE(42, 42, 3, 0x00e0, 0x10, 16, 2),
+ PIN_FIELD_BASE(43, 43, 3, 0x00e0, 0x10, 16, 2),
+ PIN_FIELD_BASE(44, 44, 7, 0x00d0, 0x10, 30, 2),
+ PIN_FIELD_BASE(45, 45, 7, 0x00d0, 0x10, 30, 2),
+ PIN_FIELD_BASE(46, 46, 7, 0x00d0, 0x10, 30, 2),
+ PIN_FIELD_BASE(47, 47, 7, 0x00d0, 0x10, 30, 2),
+ PIN_FIELD_BASE(48, 48, 4, 0x00a0, 0x10, 4, 2),
+ PIN_FIELD_BASE(49, 49, 4, 0x00a0, 0x10, 2, 2),
+ PIN_FIELD_BASE(50, 50, 4, 0x00a0, 0x10, 0, 2),
+ PIN_FIELD_BASE(51, 51, 8, 0x00a0, 0x10, 10, 2),
+ PIN_FIELD_BASE(52, 52, 8, 0x00a0, 0x10, 10, 2),
+ PIN_FIELD_BASE(53, 53, 8, 0x00a0, 0x10, 10, 2),
+ PIN_FIELD_BASE(54, 54, 8, 0x00a0, 0x10, 10, 2),
+ PIN_FIELD_BASE(55, 55, 4, 0x00a0, 0x10, 6, 2),
+ PIN_FIELD_BASE(56, 56, 4, 0x00a0, 0x10, 6, 2),
+ PIN_FIELD_BASE(57, 57, 2, 0x00c0, 0x10, 12, 2),
+ PIN_FIELD_BASE(58, 58, 2, 0x00c0, 0x10, 12, 2),
+ PIN_FIELD_BASE(59, 59, 2, 0x00c0, 0x10, 12, 2),
+ PIN_FIELD_BASE(60, 60, 2, 0x00c0, 0x10, 12, 2),
+ PIN_FIELD_BASE(61, 61, 2, 0x00c0, 0x10, 12, 2),
+ PIN_FIELD_BASE(62, 62, 2, 0x00c0, 0x10, 12, 2),
+ PIN_FIELD_BASE(63, 63, 2, 0x00c0, 0x10, 12, 2),
+ PIN_FIELD_BASE(64, 64, 2, 0x00c0, 0x10, 12, 2),
+ PIN_FIELD_BASE(65, 65, 9, 0x00d0, 0x10, 12, 2),
+ PIN_FIELD_BASE(66, 66, 9, 0x00d0, 0x10, 12, 2),
+ PIN_FIELD_BASE(67, 67, 9, 0x00d0, 0x10, 12, 2),
+ PIN_FIELD_BASE(68, 68, 9, 0x00d0, 0x10, 12, 2),
+ PIN_FIELD_BASE(69, 69, 2, 0x00c0, 0x10, 16, 2),
+ PIN_FIELD_BASE(70, 70, 2, 0x00c0, 0x10, 14, 2),
+ PIN_FIELD_BASE(71, 71, 2, 0x00c0, 0x10, 20, 2),
+ PIN_FIELD_BASE(72, 72, 2, 0x00c0, 0x10, 18, 2),
+ PIN_FIELD_BASE(73, 73, 2, 0x00c0, 0x10, 24, 2),
+ PIN_FIELD_BASE(74, 74, 2, 0x00c0, 0x10, 22, 2),
+ PIN_FIELD_BASE(75, 75, 3, 0x00e0, 0x10, 18, 2),
+ PIN_FIELD_BASE(76, 76, 2, 0x00c0, 0x10, 26, 2),
+ PIN_FIELD_BASE(77, 77, 8, 0x00a0, 0x10, 14, 2),
+ PIN_FIELD_BASE(78, 78, 8, 0x00a0, 0x10, 12, 2),
+ PIN_FIELD_BASE(79, 79, 8, 0x00a0, 0x10, 18, 2),
+ PIN_FIELD_BASE(80, 80, 8, 0x00a0, 0x10, 16, 2),
+ PIN_FIELD_BASE(81, 81, 2, 0x00c0, 0x10, 12, 2),
+ PIN_FIELD_BASE(82, 82, 2, 0x00c0, 0x10, 12, 2),
+ PIN_FIELD_BASE(83, 83, 2, 0x00c0, 0x10, 12, 2),
+ PIN_FIELD_BASE(84, 84, 7, 0x00d0, 0x10, 30, 2),
+ PIN_FIELD_BASE(85, 85, 7, 0x00d0, 0x10, 30, 2),
+ PIN_FIELD_BASE(86, 86, 7, 0x00d0, 0x10, 30, 2),
+ PIN_FIELD_BASE(87, 87, 7, 0x00d0, 0x10, 30, 2),
+ PIN_FIELD_BASE(88, 88, 5, 0x00f0, 0x10, 24, 2),
+ PIN_FIELD_BASE(89, 89, 5, 0x00f0, 0x10, 24, 2),
+ PIN_FIELD_BASE(90, 90, 5, 0x00f0, 0x10, 24, 2),
+ PIN_FIELD_BASE(91, 91, 5, 0x00f0, 0x10, 24, 2),
+ PIN_FIELD_BASE(92, 92, 5, 0x00f0, 0x10, 26, 2),
+ PIN_FIELD_BASE(93, 93, 5, 0x00f0, 0x10, 26, 2),
+ PIN_FIELD_BASE(94, 94, 5, 0x00f0, 0x10, 26, 2),
+ PIN_FIELD_BASE(95, 95, 5, 0x00f0, 0x10, 26, 2),
+ PIN_FIELD_BASE(96, 96, 5, 0x00f0, 0x10, 28, 2),
+ PIN_FIELD_BASE(97, 97, 5, 0x00f0, 0x10, 26, 2),
+ PIN_FIELD_BASE(98, 98, 5, 0x00f0, 0x10, 26, 2),
+ PIN_FIELD_BASE(99, 99, 5, 0x00f0, 0x10, 26, 2),
+ PIN_FIELD_BASE(100, 100, 5, 0x00f0, 0x10, 26, 2),
+ PIN_FIELD_BASE(101, 101, 5, 0x00f0, 0x10, 26, 2),
+ PIN_FIELD_BASE(102, 102, 5, 0x00f0, 0x10, 26, 2),
+ PIN_FIELD_BASE(103, 103, 7, 0x00d0, 0x10, 20, 2),
+ PIN_FIELD_BASE(104, 104, 7, 0x00d0, 0x10, 14, 2),
+ PIN_FIELD_BASE(105, 105, 7, 0x00d0, 0x10, 18, 2),
+ PIN_FIELD_BASE(106, 106, 7, 0x00d0, 0x10, 16, 2),
+ PIN_FIELD_BASE(107, 107, 7, 0x00d0, 0x10, 28, 2),
+ PIN_FIELD_BASE(108, 108, 7, 0x00d0, 0x10, 22, 2),
+ PIN_FIELD_BASE(109, 109, 7, 0x00d0, 0x10, 26, 2),
+ PIN_FIELD_BASE(110, 110, 7, 0x00d0, 0x10, 24, 2),
+ PIN_FIELD_BASE(111, 111, 7, 0x00d0, 0x10, 30, 2),
+ PIN_FIELD_BASE(112, 112, 8, 0x00a0, 0x10, 10, 2),
+ PIN_FIELD_BASE(113, 113, 8, 0x00a0, 0x10, 10, 2),
+ PIN_FIELD_BASE(114, 114, 8, 0x00a0, 0x10, 10, 2),
+ PIN_FIELD_BASE(115, 115, 2, 0x00c0, 0x10, 12, 2),
+ PIN_FIELD_BASE(116, 116, 2, 0x00c0, 0x10, 12, 2),
+ PIN_FIELD_BASE(117, 117, 2, 0x00c0, 0x10, 12, 2),
+ PIN_FIELD_BASE(118, 118, 2, 0x00c0, 0x10, 12, 2),
+ PIN_FIELD_BASE(119, 119, 1, 0x00a0, 0x10, 28, 2),
+ PIN_FIELD_BASE(120, 120, 1, 0x00a0, 0x10, 26, 2),
+ PIN_FIELD_BASE(121, 121, 1, 0x00a0, 0x10, 24, 2),
+ PIN_FIELD_BASE(122, 122, 1, 0x00a0, 0x10, 22, 2),
+ PIN_FIELD_BASE(123, 123, 1, 0x00a0, 0x10, 14, 2),
+ PIN_FIELD_BASE(124, 124, 1, 0x00a0, 0x10, 12, 2),
+ PIN_FIELD_BASE(125, 125, 1, 0x00a0, 0x10, 10, 2),
+ PIN_FIELD_BASE(126, 126, 1, 0x00a0, 0x10, 8, 2),
+ PIN_FIELD_BASE(127, 127, 1, 0x00a0, 0x10, 20, 2),
+ PIN_FIELD_BASE(128, 128, 1, 0x00a0, 0x10, 6, 2),
+ PIN_FIELD_BASE(129, 129, 1, 0x00a0, 0x10, 16, 2),
+ PIN_FIELD_BASE(130, 130, 1, 0x00a0, 0x10, 30, 2),
+ PIN_FIELD_BASE(131, 131, 1, 0x00a0, 0x10, 2, 2),
+ PIN_FIELD_BASE(132, 132, 1, 0x00a0, 0x10, 4, 2),
+ PIN_FIELD_BASE(133, 133, 1, 0x00b0, 0x10, 0, 2),
+ PIN_FIELD_BASE(134, 134, 1, 0x00a0, 0x10, 18, 2),
+ PIN_FIELD_BASE(135, 135, 1, 0x00a0, 0x10, 0, 2),
+ PIN_FIELD_BASE(136, 136, 1, 0x00b0, 0x10, 2, 2),
+ PIN_FIELD_BASE(137, 137, 2, 0x00c0, 0x10, 12, 2),
+ PIN_FIELD_BASE(138, 138, 2, 0x00c0, 0x10, 12, 2),
+ PIN_FIELD_BASE(139, 139, 1, 0x00b0, 0x10, 6, 2),
+ PIN_FIELD_BASE(140, 140, 1, 0x00b0, 0x10, 6, 2),
+ PIN_FIELD_BASE(141, 141, 1, 0x00b0, 0x10, 6, 2),
+ PIN_FIELD_BASE(142, 142, 1, 0x00b0, 0x10, 6, 2),
+ PIN_FIELD_BASE(143, 143, 1, 0x00b0, 0x10, 6, 2),
+ PIN_FIELD_BASE(144, 144, 1, 0x00b0, 0x10, 6, 2),
+ PIN_FIELD_BASE(145, 145, 1, 0x00b0, 0x10, 4, 2),
+ PIN_FIELD_BASE(146, 146, 1, 0x00b0, 0x10, 4, 2),
+ PIN_FIELD_BASE(147, 147, 1, 0x00b0, 0x10, 4, 2),
+ PIN_FIELD_BASE(148, 148, 1, 0x00b0, 0x10, 4, 2),
+ PIN_FIELD_BASE(149, 149, 1, 0x00b0, 0x10, 4, 2),
+ PIN_FIELD_BASE(150, 150, 3, 0x00e0, 0x10, 16, 2),
+ PIN_FIELD_BASE(151, 151, 1, 0x00b0, 0x10, 8, 2),
+ PIN_FIELD_BASE(152, 152, 3, 0x00e0, 0x10, 16, 2),
+ PIN_FIELD_BASE(153, 153, 3, 0x00e0, 0x10, 16, 2),
+ PIN_FIELD_BASE(154, 154, 3, 0x00e0, 0x10, 16, 2),
+ PIN_FIELD_BASE(155, 155, 3, 0x00e0, 0x10, 16, 2),
+ PIN_FIELD_BASE(156, 156, 5, 0x00f0, 0x10, 6, 6),
+ PIN_FIELD_BASE(157, 157, 5, 0x00f0, 0x10, 0, 6),
+ PIN_FIELD_BASE(158, 158, 5, 0x00e0, 0x10, 24, 6),
+ PIN_FIELD_BASE(159, 159, 6, 0x0080, 0x10, 12, 6),
+ PIN_FIELD_BASE(160, 160, 5, 0x00f0, 0x10, 18, 6),
+ PIN_FIELD_BASE(161, 161, 5, 0x00e0, 0x10, 6, 6),
+ PIN_FIELD_BASE(162, 162, 5, 0x00e0, 0x10, 0, 6),
+ PIN_FIELD_BASE(163, 163, 6, 0x0080, 0x10, 6, 6),
+ PIN_FIELD_BASE(164, 164, 5, 0x00e0, 0x10, 18, 6),
+ PIN_FIELD_BASE(165, 165, 5, 0x00e0, 0x10, 12, 6),
+ PIN_FIELD_BASE(166, 166, 6, 0x0080, 0x10, 0, 6),
+ PIN_FIELD_BASE(167, 167, 5, 0x00f0, 0x10, 12, 6),
+ PIN_FIELD_BASE(168, 168, 3, 0x00d0, 0x10, 10, 6),
+ PIN_FIELD_BASE(169, 169, 3, 0x00d0, 0x10, 4, 6),
+ PIN_FIELD_BASE(170, 170, 3, 0x00d0, 0x10, 16, 6),
+ PIN_FIELD_BASE(171, 171, 3, 0x00d0, 0x10, 22, 6),
+ PIN_FIELD_BASE(172, 172, 3, 0x00e0, 0x10, 0, 6),
+ PIN_FIELD_BASE(173, 173, 3, 0x00e0, 0x10, 6, 6),
+ PIN_FIELD_BASE(174, 174, 9, 0x00c0, 0x10, 12, 6),
+ PIN_FIELD_BASE(175, 175, 9, 0x00c0, 0x10, 6, 6),
+ PIN_FIELD_BASE(176, 176, 9, 0x00c0, 0x10, 18, 6),
+ PIN_FIELD_BASE(177, 177, 9, 0x00c0, 0x10, 24, 6),
+ PIN_FIELD_BASE(178, 178, 9, 0x00d0, 0x10, 0, 6),
+ PIN_FIELD_BASE(179, 179, 9, 0x00d0, 0x10, 6, 6),
+ PIN_FIELD_BASE(180, 180, 5, 0x00f0, 0x10, 30, 2),
+ PIN_FIELD_BASE(181, 181, 5, 0x0100, 0x10, 0, 2),
+ PIN_FIELD_BASE(182, 182, 9, 0x00d0, 0x10, 14, 2),
+};
+
+static const struct mtk_pin_field_calc mt8189_pin_pupd_range[] = {
+ PIN_FIELD_BASE(44, 44, 7, 0x0090, 0x10, 0, 1),
+ PIN_FIELD_BASE(45, 45, 7, 0x0090, 0x10, 1, 1),
+ PIN_FIELD_BASE(46, 46, 7, 0x0090, 0x10, 2, 1),
+ PIN_FIELD_BASE(47, 47, 7, 0x0090, 0x10, 3, 1),
+ PIN_FIELD_BASE(156, 156, 5, 0x00a0, 0x10, 6, 1),
+ PIN_FIELD_BASE(157, 157, 5, 0x00a0, 0x10, 5, 1),
+ PIN_FIELD_BASE(158, 158, 5, 0x00a0, 0x10, 4, 1),
+ PIN_FIELD_BASE(159, 159, 6, 0x0050, 0x10, 2, 1),
+ PIN_FIELD_BASE(160, 160, 5, 0x00a0, 0x10, 8, 1),
+ PIN_FIELD_BASE(161, 161, 5, 0x00a0, 0x10, 1, 1),
+ PIN_FIELD_BASE(162, 162, 5, 0x00a0, 0x10, 0, 1),
+ PIN_FIELD_BASE(163, 163, 6, 0x0050, 0x10, 1, 1),
+ PIN_FIELD_BASE(164, 164, 5, 0x00a0, 0x10, 3, 1),
+ PIN_FIELD_BASE(165, 165, 5, 0x00a0, 0x10, 2, 1),
+ PIN_FIELD_BASE(166, 166, 6, 0x0050, 0x10, 0, 1),
+ PIN_FIELD_BASE(167, 167, 5, 0x00a0, 0x10, 7, 1),
+ PIN_FIELD_BASE(168, 168, 3, 0x0090, 0x10, 1, 1),
+ PIN_FIELD_BASE(169, 169, 3, 0x0090, 0x10, 0, 1),
+ PIN_FIELD_BASE(170, 170, 3, 0x0090, 0x10, 2, 1),
+ PIN_FIELD_BASE(171, 171, 3, 0x0090, 0x10, 3, 1),
+ PIN_FIELD_BASE(172, 172, 3, 0x0090, 0x10, 4, 1),
+ PIN_FIELD_BASE(173, 173, 3, 0x0090, 0x10, 5, 1),
+ PIN_FIELD_BASE(174, 174, 9, 0x0080, 0x10, 1, 1),
+ PIN_FIELD_BASE(175, 175, 9, 0x0080, 0x10, 0, 1),
+ PIN_FIELD_BASE(176, 176, 9, 0x0080, 0x10, 2, 1),
+ PIN_FIELD_BASE(177, 177, 9, 0x0080, 0x10, 3, 1),
+ PIN_FIELD_BASE(178, 178, 9, 0x0080, 0x10, 4, 1),
+ PIN_FIELD_BASE(179, 179, 9, 0x0080, 0x10, 5, 1),
+};
+
+static const struct mtk_pin_field_calc mt8189_pin_r0_range[] = {
+ PIN_FIELD_BASE(44, 44, 7, 0x00b0, 0x10, 0, 1),
+ PIN_FIELD_BASE(45, 45, 7, 0x00b0, 0x10, 1, 1),
+ PIN_FIELD_BASE(46, 46, 7, 0x00b0, 0x10, 2, 1),
+ PIN_FIELD_BASE(47, 47, 7, 0x00b0, 0x10, 3, 1),
+ PIN_FIELD_BASE(156, 156, 5, 0x00c0, 0x10, 6, 1),
+ PIN_FIELD_BASE(157, 157, 5, 0x00c0, 0x10, 5, 1),
+ PIN_FIELD_BASE(158, 158, 5, 0x00c0, 0x10, 4, 1),
+ PIN_FIELD_BASE(159, 159, 6, 0x0060, 0x10, 2, 1),
+ PIN_FIELD_BASE(160, 160, 5, 0x00c0, 0x10, 8, 1),
+ PIN_FIELD_BASE(161, 161, 5, 0x00c0, 0x10, 1, 1),
+ PIN_FIELD_BASE(162, 162, 5, 0x00c0, 0x10, 0, 1),
+ PIN_FIELD_BASE(163, 163, 6, 0x0060, 0x10, 1, 1),
+ PIN_FIELD_BASE(164, 164, 5, 0x00c0, 0x10, 3, 1),
+ PIN_FIELD_BASE(165, 165, 5, 0x00c0, 0x10, 2, 1),
+ PIN_FIELD_BASE(166, 166, 6, 0x0060, 0x10, 0, 1),
+ PIN_FIELD_BASE(167, 167, 5, 0x00c0, 0x10, 7, 1),
+ PIN_FIELD_BASE(168, 168, 3, 0x00b0, 0x10, 1, 1),
+ PIN_FIELD_BASE(169, 169, 3, 0x00b0, 0x10, 0, 1),
+ PIN_FIELD_BASE(170, 170, 3, 0x00b0, 0x10, 2, 1),
+ PIN_FIELD_BASE(171, 171, 3, 0x00b0, 0x10, 3, 1),
+ PIN_FIELD_BASE(172, 172, 3, 0x00b0, 0x10, 4, 1),
+ PIN_FIELD_BASE(173, 173, 3, 0x00b0, 0x10, 5, 1),
+ PIN_FIELD_BASE(174, 174, 9, 0x00a0, 0x10, 1, 1),
+ PIN_FIELD_BASE(175, 175, 9, 0x00a0, 0x10, 0, 1),
+ PIN_FIELD_BASE(176, 176, 9, 0x00a0, 0x10, 2, 1),
+ PIN_FIELD_BASE(177, 177, 9, 0x00a0, 0x10, 3, 1),
+ PIN_FIELD_BASE(178, 178, 9, 0x00a0, 0x10, 4, 1),
+ PIN_FIELD_BASE(179, 179, 9, 0x00a0, 0x10, 5, 1),
+};
+
+static const struct mtk_pin_field_calc mt8189_pin_r1_range[] = {
+ PIN_FIELD_BASE(44, 44, 7, 0x00c0, 0x10, 0, 1),
+ PIN_FIELD_BASE(45, 45, 7, 0x00c0, 0x10, 1, 1),
+ PIN_FIELD_BASE(46, 46, 7, 0x00c0, 0x10, 2, 1),
+ PIN_FIELD_BASE(47, 47, 7, 0x00c0, 0x10, 3, 1),
+ PIN_FIELD_BASE(156, 156, 5, 0x00d0, 0x10, 6, 1),
+ PIN_FIELD_BASE(157, 157, 5, 0x00d0, 0x10, 5, 1),
+ PIN_FIELD_BASE(158, 158, 5, 0x00d0, 0x10, 4, 1),
+ PIN_FIELD_BASE(159, 159, 6, 0x0070, 0x10, 2, 1),
+ PIN_FIELD_BASE(160, 160, 5, 0x00d0, 0x10, 8, 1),
+ PIN_FIELD_BASE(161, 161, 5, 0x00d0, 0x10, 1, 1),
+ PIN_FIELD_BASE(162, 162, 5, 0x00d0, 0x10, 0, 1),
+ PIN_FIELD_BASE(163, 163, 6, 0x0070, 0x10, 1, 1),
+ PIN_FIELD_BASE(164, 164, 5, 0x00d0, 0x10, 3, 1),
+ PIN_FIELD_BASE(165, 165, 5, 0x00d0, 0x10, 2, 1),
+ PIN_FIELD_BASE(166, 166, 6, 0x0070, 0x10, 0, 1),
+ PIN_FIELD_BASE(167, 167, 5, 0x00d0, 0x10, 7, 1),
+ PIN_FIELD_BASE(168, 168, 3, 0x00c0, 0x10, 1, 1),
+ PIN_FIELD_BASE(169, 169, 3, 0x00c0, 0x10, 0, 1),
+ PIN_FIELD_BASE(170, 170, 3, 0x00c0, 0x10, 2, 1),
+ PIN_FIELD_BASE(171, 171, 3, 0x00c0, 0x10, 3, 1),
+ PIN_FIELD_BASE(172, 172, 3, 0x00c0, 0x10, 4, 1),
+ PIN_FIELD_BASE(173, 173, 3, 0x00c0, 0x10, 5, 1),
+ PIN_FIELD_BASE(174, 174, 9, 0x00b0, 0x10, 1, 1),
+ PIN_FIELD_BASE(175, 175, 9, 0x00b0, 0x10, 0, 1),
+ PIN_FIELD_BASE(176, 176, 9, 0x00b0, 0x10, 2, 1),
+ PIN_FIELD_BASE(177, 177, 9, 0x00b0, 0x10, 3, 1),
+ PIN_FIELD_BASE(178, 178, 9, 0x00b0, 0x10, 4, 1),
+ PIN_FIELD_BASE(179, 179, 9, 0x00b0, 0x10, 5, 1),
+};
+
+static const struct mtk_pin_field_calc mt8189_pin_pu_range[] = {
+ PIN_FIELD_BASE(0, 0, 7, 0x00a0, 0x10, 5, 1),
+ PIN_FIELD_BASE(1, 1, 8, 0x0090, 0x10, 3, 1),
+ PIN_FIELD_BASE(2, 2, 8, 0x0090, 0x10, 4, 1),
+ PIN_FIELD_BASE(3, 3, 8, 0x0090, 0x10, 5, 1),
+ PIN_FIELD_BASE(4, 4, 8, 0x0090, 0x10, 6, 1),
+ PIN_FIELD_BASE(5, 5, 8, 0x0090, 0x10, 7, 1),
+ PIN_FIELD_BASE(6, 6, 7, 0x00a0, 0x10, 6, 1),
+ PIN_FIELD_BASE(7, 7, 7, 0x00a0, 0x10, 7, 1),
+ PIN_FIELD_BASE(8, 8, 7, 0x00a0, 0x10, 8, 1),
+ PIN_FIELD_BASE(9, 9, 7, 0x00a0, 0x10, 9, 1),
+ PIN_FIELD_BASE(10, 10, 7, 0x00a0, 0x10, 10, 1),
+ PIN_FIELD_BASE(11, 11, 7, 0x00a0, 0x10, 11, 1),
+ PIN_FIELD_BASE(12, 12, 2, 0x00b0, 0x10, 5, 1),
+ PIN_FIELD_BASE(13, 13, 2, 0x00b0, 0x10, 6, 1),
+ PIN_FIELD_BASE(14, 14, 3, 0x00a0, 0x10, 0, 1),
+ PIN_FIELD_BASE(15, 15, 3, 0x00a0, 0x10, 1, 1),
+ PIN_FIELD_BASE(16, 16, 2, 0x00b0, 0x10, 7, 1),
+ PIN_FIELD_BASE(17, 17, 2, 0x00b0, 0x10, 8, 1),
+ PIN_FIELD_BASE(18, 18, 7, 0x00a0, 0x10, 0, 1),
+ PIN_FIELD_BASE(19, 19, 7, 0x00a0, 0x10, 2, 1),
+ PIN_FIELD_BASE(20, 20, 7, 0x00a0, 0x10, 1, 1),
+ PIN_FIELD_BASE(21, 21, 7, 0x00a0, 0x10, 3, 1),
+ PIN_FIELD_BASE(22, 22, 9, 0x0090, 0x10, 0, 1),
+ PIN_FIELD_BASE(23, 23, 9, 0x0090, 0x10, 1, 1),
+ PIN_FIELD_BASE(24, 24, 9, 0x0090, 0x10, 2, 1),
+ PIN_FIELD_BASE(25, 25, 4, 0x0090, 0x10, 2, 1),
+ PIN_FIELD_BASE(26, 26, 4, 0x0090, 0x10, 1, 1),
+ PIN_FIELD_BASE(27, 27, 2, 0x00b0, 0x10, 1, 1),
+ PIN_FIELD_BASE(28, 28, 2, 0x00b0, 0x10, 2, 1),
+ PIN_FIELD_BASE(29, 29, 4, 0x0090, 0x10, 0, 1),
+ PIN_FIELD_BASE(30, 30, 2, 0x00b0, 0x10, 0, 1),
+ PIN_FIELD_BASE(31, 31, 3, 0x00a0, 0x10, 13, 1),
+ PIN_FIELD_BASE(32, 32, 1, 0x0090, 0x10, 30, 1),
+ PIN_FIELD_BASE(33, 33, 3, 0x00a0, 0x10, 15, 1),
+ PIN_FIELD_BASE(34, 34, 3, 0x00a0, 0x10, 14, 1),
+ PIN_FIELD_BASE(35, 35, 3, 0x00a0, 0x10, 17, 1),
+ PIN_FIELD_BASE(36, 36, 3, 0x00a0, 0x10, 16, 1),
+ PIN_FIELD_BASE(37, 37, 3, 0x00a0, 0x10, 19, 1),
+ PIN_FIELD_BASE(38, 38, 3, 0x00a0, 0x10, 18, 1),
+ PIN_FIELD_BASE(39, 39, 3, 0x00a0, 0x10, 5, 1),
+ PIN_FIELD_BASE(40, 40, 3, 0x00a0, 0x10, 2, 1),
+ PIN_FIELD_BASE(41, 41, 3, 0x00a0, 0x10, 3, 1),
+ PIN_FIELD_BASE(42, 42, 3, 0x00a0, 0x10, 4, 1),
+ PIN_FIELD_BASE(43, 43, 3, 0x00a0, 0x10, 6, 1),
+ PIN_FIELD_BASE(48, 48, 4, 0x0090, 0x10, 5, 1),
+ PIN_FIELD_BASE(49, 49, 4, 0x0090, 0x10, 4, 1),
+ PIN_FIELD_BASE(50, 50, 4, 0x0090, 0x10, 3, 1),
+ PIN_FIELD_BASE(51, 51, 8, 0x0090, 0x10, 8, 1),
+ PIN_FIELD_BASE(52, 52, 8, 0x0090, 0x10, 10, 1),
+ PIN_FIELD_BASE(53, 53, 8, 0x0090, 0x10, 9, 1),
+ PIN_FIELD_BASE(54, 54, 8, 0x0090, 0x10, 11, 1),
+ PIN_FIELD_BASE(55, 55, 4, 0x0090, 0x10, 6, 1),
+ PIN_FIELD_BASE(56, 56, 4, 0x0090, 0x10, 7, 1),
+ PIN_FIELD_BASE(57, 57, 2, 0x00b0, 0x10, 13, 1),
+ PIN_FIELD_BASE(58, 58, 2, 0x00b0, 0x10, 17, 1),
+ PIN_FIELD_BASE(59, 59, 2, 0x00b0, 0x10, 14, 1),
+ PIN_FIELD_BASE(60, 60, 2, 0x00b0, 0x10, 18, 1),
+ PIN_FIELD_BASE(61, 61, 2, 0x00b0, 0x10, 15, 1),
+ PIN_FIELD_BASE(62, 62, 2, 0x00b0, 0x10, 19, 1),
+ PIN_FIELD_BASE(63, 63, 2, 0x00b0, 0x10, 16, 1),
+ PIN_FIELD_BASE(64, 64, 2, 0x00b0, 0x10, 20, 1),
+ PIN_FIELD_BASE(65, 65, 9, 0x0090, 0x10, 4, 1),
+ PIN_FIELD_BASE(66, 66, 9, 0x0090, 0x10, 6, 1),
+ PIN_FIELD_BASE(67, 67, 9, 0x0090, 0x10, 5, 1),
+ PIN_FIELD_BASE(68, 68, 9, 0x0090, 0x10, 7, 1),
+ PIN_FIELD_BASE(69, 69, 2, 0x00b0, 0x10, 22, 1),
+ PIN_FIELD_BASE(70, 70, 2, 0x00b0, 0x10, 21, 1),
+ PIN_FIELD_BASE(71, 71, 2, 0x00b0, 0x10, 24, 1),
+ PIN_FIELD_BASE(72, 72, 2, 0x00b0, 0x10, 23, 1),
+ PIN_FIELD_BASE(73, 73, 2, 0x00b0, 0x10, 26, 1),
+ PIN_FIELD_BASE(74, 74, 2, 0x00b0, 0x10, 25, 1),
+ PIN_FIELD_BASE(75, 75, 3, 0x00a0, 0x10, 7, 1),
+ PIN_FIELD_BASE(76, 76, 2, 0x00b0, 0x10, 27, 1),
+ PIN_FIELD_BASE(77, 77, 8, 0x0090, 0x10, 13, 1),
+ PIN_FIELD_BASE(78, 78, 8, 0x0090, 0x10, 12, 1),
+ PIN_FIELD_BASE(79, 79, 8, 0x0090, 0x10, 15, 1),
+ PIN_FIELD_BASE(80, 80, 8, 0x0090, 0x10, 14, 1),
+ PIN_FIELD_BASE(81, 81, 2, 0x00b0, 0x10, 29, 1),
+ PIN_FIELD_BASE(82, 82, 2, 0x00b0, 0x10, 28, 1),
+ PIN_FIELD_BASE(83, 83, 2, 0x00b0, 0x10, 30, 1),
+ PIN_FIELD_BASE(84, 84, 7, 0x00a0, 0x10, 22, 1),
+ PIN_FIELD_BASE(85, 85, 7, 0x00a0, 0x10, 23, 1),
+ PIN_FIELD_BASE(86, 86, 7, 0x00a0, 0x10, 24, 1),
+ PIN_FIELD_BASE(87, 87, 7, 0x00a0, 0x10, 25, 1),
+ PIN_FIELD_BASE(88, 88, 5, 0x00b0, 0x10, 11, 1),
+ PIN_FIELD_BASE(89, 89, 5, 0x00b0, 0x10, 10, 1),
+ PIN_FIELD_BASE(90, 90, 5, 0x00b0, 0x10, 13, 1),
+ PIN_FIELD_BASE(91, 91, 5, 0x00b0, 0x10, 12, 1),
+ PIN_FIELD_BASE(92, 92, 5, 0x00b0, 0x10, 7, 1),
+ PIN_FIELD_BASE(93, 93, 5, 0x00b0, 0x10, 8, 1),
+ PIN_FIELD_BASE(94, 94, 5, 0x00b0, 0x10, 14, 1),
+ PIN_FIELD_BASE(95, 95, 5, 0x00b0, 0x10, 6, 1),
+ PIN_FIELD_BASE(96, 96, 5, 0x00b0, 0x10, 9, 1),
+ PIN_FIELD_BASE(97, 97, 5, 0x00b0, 0x10, 0, 1),
+ PIN_FIELD_BASE(98, 98, 5, 0x00b0, 0x10, 5, 1),
+ PIN_FIELD_BASE(99, 99, 5, 0x00b0, 0x10, 3, 1),
+ PIN_FIELD_BASE(100, 100, 5, 0x00b0, 0x10, 4, 1),
+ PIN_FIELD_BASE(101, 101, 5, 0x00b0, 0x10, 1, 1),
+ PIN_FIELD_BASE(102, 102, 5, 0x00b0, 0x10, 2, 1),
+ PIN_FIELD_BASE(103, 103, 7, 0x00a0, 0x10, 15, 1),
+ PIN_FIELD_BASE(104, 104, 7, 0x00a0, 0x10, 12, 1),
+ PIN_FIELD_BASE(105, 105, 7, 0x00a0, 0x10, 14, 1),
+ PIN_FIELD_BASE(106, 106, 7, 0x00a0, 0x10, 13, 1),
+ PIN_FIELD_BASE(107, 107, 7, 0x00a0, 0x10, 19, 1),
+ PIN_FIELD_BASE(108, 108, 7, 0x00a0, 0x10, 16, 1),
+ PIN_FIELD_BASE(109, 109, 7, 0x00a0, 0x10, 18, 1),
+ PIN_FIELD_BASE(110, 110, 7, 0x00a0, 0x10, 17, 1),
+ PIN_FIELD_BASE(111, 111, 7, 0x00a0, 0x10, 4, 1),
+ PIN_FIELD_BASE(112, 112, 8, 0x0090, 0x10, 0, 1),
+ PIN_FIELD_BASE(113, 113, 8, 0x0090, 0x10, 1, 1),
+ PIN_FIELD_BASE(114, 114, 8, 0x0090, 0x10, 2, 1),
+ PIN_FIELD_BASE(115, 115, 2, 0x00b0, 0x10, 9, 1),
+ PIN_FIELD_BASE(116, 116, 2, 0x00b0, 0x10, 12, 1),
+ PIN_FIELD_BASE(117, 117, 2, 0x00b0, 0x10, 10, 1),
+ PIN_FIELD_BASE(118, 118, 2, 0x00b0, 0x10, 11, 1),
+ PIN_FIELD_BASE(119, 119, 1, 0x0090, 0x10, 26, 1),
+ PIN_FIELD_BASE(120, 120, 1, 0x0090, 0x10, 25, 1),
+ PIN_FIELD_BASE(121, 121, 1, 0x0090, 0x10, 24, 1),
+ PIN_FIELD_BASE(122, 122, 1, 0x0090, 0x10, 23, 1),
+ PIN_FIELD_BASE(123, 123, 1, 0x0090, 0x10, 19, 1),
+ PIN_FIELD_BASE(124, 124, 1, 0x0090, 0x10, 18, 1),
+ PIN_FIELD_BASE(125, 125, 1, 0x0090, 0x10, 17, 1),
+ PIN_FIELD_BASE(126, 126, 1, 0x0090, 0x10, 16, 1),
+ PIN_FIELD_BASE(127, 127, 1, 0x0090, 0x10, 22, 1),
+ PIN_FIELD_BASE(128, 128, 1, 0x0090, 0x10, 15, 1),
+ PIN_FIELD_BASE(129, 129, 1, 0x0090, 0x10, 20, 1),
+ PIN_FIELD_BASE(130, 130, 1, 0x0090, 0x10, 27, 1),
+ PIN_FIELD_BASE(131, 131, 1, 0x0090, 0x10, 13, 1),
+ PIN_FIELD_BASE(132, 132, 1, 0x0090, 0x10, 14, 1),
+ PIN_FIELD_BASE(133, 133, 1, 0x0090, 0x10, 28, 1),
+ PIN_FIELD_BASE(134, 134, 1, 0x0090, 0x10, 21, 1),
+ PIN_FIELD_BASE(135, 135, 1, 0x0090, 0x10, 11, 1),
+ PIN_FIELD_BASE(136, 136, 1, 0x0090, 0x10, 12, 1),
+ PIN_FIELD_BASE(137, 137, 2, 0x00b0, 0x10, 3, 1),
+ PIN_FIELD_BASE(138, 138, 2, 0x00b0, 0x10, 4, 1),
+ PIN_FIELD_BASE(139, 139, 1, 0x0090, 0x10, 3, 1),
+ PIN_FIELD_BASE(140, 140, 1, 0x0090, 0x10, 4, 1),
+ PIN_FIELD_BASE(141, 141, 1, 0x0090, 0x10, 0, 1),
+ PIN_FIELD_BASE(142, 142, 1, 0x0090, 0x10, 1, 1),
+ PIN_FIELD_BASE(143, 143, 1, 0x0090, 0x10, 2, 1),
+ PIN_FIELD_BASE(144, 144, 1, 0x0090, 0x10, 5, 1),
+ PIN_FIELD_BASE(145, 145, 1, 0x0090, 0x10, 6, 1),
+ PIN_FIELD_BASE(146, 146, 1, 0x0090, 0x10, 7, 1),
+ PIN_FIELD_BASE(147, 147, 1, 0x0090, 0x10, 8, 1),
+ PIN_FIELD_BASE(148, 148, 1, 0x0090, 0x10, 9, 1),
+ PIN_FIELD_BASE(149, 149, 1, 0x0090, 0x10, 10, 1),
+ PIN_FIELD_BASE(150, 150, 3, 0x00a0, 0x10, 8, 1),
+ PIN_FIELD_BASE(151, 151, 1, 0x0090, 0x10, 29, 1),
+ PIN_FIELD_BASE(152, 152, 3, 0x00a0, 0x10, 9, 1),
+ PIN_FIELD_BASE(153, 153, 3, 0x00a0, 0x10, 10, 1),
+ PIN_FIELD_BASE(154, 154, 3, 0x00a0, 0x10, 11, 1),
+ PIN_FIELD_BASE(155, 155, 3, 0x00a0, 0x10, 12, 1),
+ PIN_FIELD_BASE(180, 180, 5, 0x00b0, 0x10, 15, 1),
+ PIN_FIELD_BASE(181, 181, 5, 0x00b0, 0x10, 16, 1),
+ PIN_FIELD_BASE(182, 182, 9, 0x0090, 0x10, 3, 1),
+};
+
+static const struct mtk_pin_field_calc mt8189_pin_pd_range[] = {
+ PIN_FIELD_BASE(0, 0, 7, 0x0080, 0x10, 5, 1),
+ PIN_FIELD_BASE(1, 1, 8, 0x0080, 0x10, 3, 1),
+ PIN_FIELD_BASE(2, 2, 8, 0x0080, 0x10, 4, 1),
+ PIN_FIELD_BASE(3, 3, 8, 0x0080, 0x10, 5, 1),
+ PIN_FIELD_BASE(4, 4, 8, 0x0080, 0x10, 6, 1),
+ PIN_FIELD_BASE(5, 5, 8, 0x0080, 0x10, 7, 1),
+ PIN_FIELD_BASE(6, 6, 7, 0x0080, 0x10, 6, 1),
+ PIN_FIELD_BASE(7, 7, 7, 0x0080, 0x10, 7, 1),
+ PIN_FIELD_BASE(8, 8, 7, 0x0080, 0x10, 8, 1),
+ PIN_FIELD_BASE(9, 9, 7, 0x0080, 0x10, 9, 1),
+ PIN_FIELD_BASE(10, 10, 7, 0x0080, 0x10, 10, 1),
+ PIN_FIELD_BASE(11, 11, 7, 0x0080, 0x10, 11, 1),
+ PIN_FIELD_BASE(12, 12, 2, 0x00a0, 0x10, 5, 1),
+ PIN_FIELD_BASE(13, 13, 2, 0x00a0, 0x10, 6, 1),
+ PIN_FIELD_BASE(14, 14, 3, 0x0080, 0x10, 0, 1),
+ PIN_FIELD_BASE(15, 15, 3, 0x0080, 0x10, 1, 1),
+ PIN_FIELD_BASE(16, 16, 2, 0x00a0, 0x10, 7, 1),
+ PIN_FIELD_BASE(17, 17, 2, 0x00a0, 0x10, 8, 1),
+ PIN_FIELD_BASE(18, 18, 7, 0x0080, 0x10, 0, 1),
+ PIN_FIELD_BASE(19, 19, 7, 0x0080, 0x10, 2, 1),
+ PIN_FIELD_BASE(20, 20, 7, 0x0080, 0x10, 1, 1),
+ PIN_FIELD_BASE(21, 21, 7, 0x0080, 0x10, 3, 1),
+ PIN_FIELD_BASE(22, 22, 9, 0x0070, 0x10, 0, 1),
+ PIN_FIELD_BASE(23, 23, 9, 0x0070, 0x10, 1, 1),
+ PIN_FIELD_BASE(24, 24, 9, 0x0070, 0x10, 2, 1),
+ PIN_FIELD_BASE(25, 25, 4, 0x0080, 0x10, 2, 1),
+ PIN_FIELD_BASE(26, 26, 4, 0x0080, 0x10, 1, 1),
+ PIN_FIELD_BASE(27, 27, 2, 0x00a0, 0x10, 1, 1),
+ PIN_FIELD_BASE(28, 28, 2, 0x00a0, 0x10, 2, 1),
+ PIN_FIELD_BASE(29, 29, 4, 0x0080, 0x10, 0, 1),
+ PIN_FIELD_BASE(30, 30, 2, 0x00a0, 0x10, 0, 1),
+ PIN_FIELD_BASE(31, 31, 3, 0x0080, 0x10, 13, 1),
+ PIN_FIELD_BASE(32, 32, 1, 0x0080, 0x10, 30, 1),
+ PIN_FIELD_BASE(33, 33, 3, 0x0080, 0x10, 15, 1),
+ PIN_FIELD_BASE(34, 34, 3, 0x0080, 0x10, 14, 1),
+ PIN_FIELD_BASE(35, 35, 3, 0x0080, 0x10, 17, 1),
+ PIN_FIELD_BASE(36, 36, 3, 0x0080, 0x10, 16, 1),
+ PIN_FIELD_BASE(37, 37, 3, 0x0080, 0x10, 19, 1),
+ PIN_FIELD_BASE(38, 38, 3, 0x0080, 0x10, 18, 1),
+ PIN_FIELD_BASE(39, 39, 3, 0x0080, 0x10, 5, 1),
+ PIN_FIELD_BASE(40, 40, 3, 0x0080, 0x10, 2, 1),
+ PIN_FIELD_BASE(41, 41, 3, 0x0080, 0x10, 3, 1),
+ PIN_FIELD_BASE(42, 42, 3, 0x0080, 0x10, 4, 1),
+ PIN_FIELD_BASE(43, 43, 3, 0x0080, 0x10, 6, 1),
+ PIN_FIELD_BASE(48, 48, 4, 0x0080, 0x10, 5, 1),
+ PIN_FIELD_BASE(49, 49, 4, 0x0080, 0x10, 4, 1),
+ PIN_FIELD_BASE(50, 50, 4, 0x0080, 0x10, 3, 1),
+ PIN_FIELD_BASE(51, 51, 8, 0x0080, 0x10, 8, 1),
+ PIN_FIELD_BASE(52, 52, 8, 0x0080, 0x10, 10, 1),
+ PIN_FIELD_BASE(53, 53, 8, 0x0080, 0x10, 9, 1),
+ PIN_FIELD_BASE(54, 54, 8, 0x0080, 0x10, 11, 1),
+ PIN_FIELD_BASE(55, 55, 4, 0x0080, 0x10, 6, 1),
+ PIN_FIELD_BASE(56, 56, 4, 0x0080, 0x10, 7, 1),
+ PIN_FIELD_BASE(57, 57, 2, 0x00a0, 0x10, 13, 1),
+ PIN_FIELD_BASE(58, 58, 2, 0x00a0, 0x10, 17, 1),
+ PIN_FIELD_BASE(59, 59, 2, 0x00a0, 0x10, 14, 1),
+ PIN_FIELD_BASE(60, 60, 2, 0x00a0, 0x10, 18, 1),
+ PIN_FIELD_BASE(61, 61, 2, 0x00a0, 0x10, 15, 1),
+ PIN_FIELD_BASE(62, 62, 2, 0x00a0, 0x10, 19, 1),
+ PIN_FIELD_BASE(63, 63, 2, 0x00a0, 0x10, 16, 1),
+ PIN_FIELD_BASE(64, 64, 2, 0x00a0, 0x10, 20, 1),
+ PIN_FIELD_BASE(65, 65, 9, 0x0070, 0x10, 4, 1),
+ PIN_FIELD_BASE(66, 66, 9, 0x0070, 0x10, 6, 1),
+ PIN_FIELD_BASE(67, 67, 9, 0x0070, 0x10, 5, 1),
+ PIN_FIELD_BASE(68, 68, 9, 0x0070, 0x10, 7, 1),
+ PIN_FIELD_BASE(69, 69, 2, 0x00a0, 0x10, 22, 1),
+ PIN_FIELD_BASE(70, 70, 2, 0x00a0, 0x10, 21, 1),
+ PIN_FIELD_BASE(71, 71, 2, 0x00a0, 0x10, 24, 1),
+ PIN_FIELD_BASE(72, 72, 2, 0x00a0, 0x10, 23, 1),
+ PIN_FIELD_BASE(73, 73, 2, 0x00a0, 0x10, 26, 1),
+ PIN_FIELD_BASE(74, 74, 2, 0x00a0, 0x10, 25, 1),
+ PIN_FIELD_BASE(75, 75, 3, 0x0080, 0x10, 7, 1),
+ PIN_FIELD_BASE(76, 76, 2, 0x00a0, 0x10, 27, 1),
+ PIN_FIELD_BASE(77, 77, 8, 0x0080, 0x10, 13, 1),
+ PIN_FIELD_BASE(78, 78, 8, 0x0080, 0x10, 12, 1),
+ PIN_FIELD_BASE(79, 79, 8, 0x0080, 0x10, 15, 1),
+ PIN_FIELD_BASE(80, 80, 8, 0x0080, 0x10, 14, 1),
+ PIN_FIELD_BASE(81, 81, 2, 0x00a0, 0x10, 29, 1),
+ PIN_FIELD_BASE(82, 82, 2, 0x00a0, 0x10, 28, 1),
+ PIN_FIELD_BASE(83, 83, 2, 0x00a0, 0x10, 30, 1),
+ PIN_FIELD_BASE(84, 84, 7, 0x0080, 0x10, 22, 1),
+ PIN_FIELD_BASE(85, 85, 7, 0x0080, 0x10, 23, 1),
+ PIN_FIELD_BASE(86, 86, 7, 0x0080, 0x10, 24, 1),
+ PIN_FIELD_BASE(87, 87, 7, 0x0080, 0x10, 25, 1),
+ PIN_FIELD_BASE(88, 88, 5, 0x0090, 0x10, 11, 1),
+ PIN_FIELD_BASE(89, 89, 5, 0x0090, 0x10, 10, 1),
+ PIN_FIELD_BASE(90, 90, 5, 0x0090, 0x10, 13, 1),
+ PIN_FIELD_BASE(91, 91, 5, 0x0090, 0x10, 12, 1),
+ PIN_FIELD_BASE(92, 92, 5, 0x0090, 0x10, 7, 1),
+ PIN_FIELD_BASE(93, 93, 5, 0x0090, 0x10, 8, 1),
+ PIN_FIELD_BASE(94, 94, 5, 0x0090, 0x10, 14, 1),
+ PIN_FIELD_BASE(95, 95, 5, 0x0090, 0x10, 6, 1),
+ PIN_FIELD_BASE(96, 96, 5, 0x0090, 0x10, 9, 1),
+ PIN_FIELD_BASE(97, 97, 5, 0x0090, 0x10, 0, 1),
+ PIN_FIELD_BASE(98, 98, 5, 0x0090, 0x10, 5, 1),
+ PIN_FIELD_BASE(99, 99, 5, 0x0090, 0x10, 3, 1),
+ PIN_FIELD_BASE(100, 100, 5, 0x0090, 0x10, 4, 1),
+ PIN_FIELD_BASE(101, 101, 5, 0x0090, 0x10, 1, 1),
+ PIN_FIELD_BASE(102, 102, 5, 0x0090, 0x10, 2, 1),
+ PIN_FIELD_BASE(103, 103, 7, 0x0080, 0x10, 15, 1),
+ PIN_FIELD_BASE(104, 104, 7, 0x0080, 0x10, 12, 1),
+ PIN_FIELD_BASE(105, 105, 7, 0x0080, 0x10, 14, 1),
+ PIN_FIELD_BASE(106, 106, 7, 0x0080, 0x10, 13, 1),
+ PIN_FIELD_BASE(107, 107, 7, 0x0080, 0x10, 19, 1),
+ PIN_FIELD_BASE(108, 108, 7, 0x0080, 0x10, 16, 1),
+ PIN_FIELD_BASE(109, 109, 7, 0x0080, 0x10, 18, 1),
+ PIN_FIELD_BASE(110, 110, 7, 0x0080, 0x10, 17, 1),
+ PIN_FIELD_BASE(111, 111, 7, 0x0080, 0x10, 4, 1),
+ PIN_FIELD_BASE(112, 112, 8, 0x0080, 0x10, 0, 1),
+ PIN_FIELD_BASE(113, 113, 8, 0x0080, 0x10, 1, 1),
+ PIN_FIELD_BASE(114, 114, 8, 0x0080, 0x10, 2, 1),
+ PIN_FIELD_BASE(115, 115, 2, 0x00a0, 0x10, 9, 1),
+ PIN_FIELD_BASE(116, 116, 2, 0x00a0, 0x10, 12, 1),
+ PIN_FIELD_BASE(117, 117, 2, 0x00a0, 0x10, 10, 1),
+ PIN_FIELD_BASE(118, 118, 2, 0x00a0, 0x10, 11, 1),
+ PIN_FIELD_BASE(119, 119, 1, 0x0080, 0x10, 26, 1),
+ PIN_FIELD_BASE(120, 120, 1, 0x0080, 0x10, 25, 1),
+ PIN_FIELD_BASE(121, 121, 1, 0x0080, 0x10, 24, 1),
+ PIN_FIELD_BASE(122, 122, 1, 0x0080, 0x10, 23, 1),
+ PIN_FIELD_BASE(123, 123, 1, 0x0080, 0x10, 19, 1),
+ PIN_FIELD_BASE(124, 124, 1, 0x0080, 0x10, 18, 1),
+ PIN_FIELD_BASE(125, 125, 1, 0x0080, 0x10, 17, 1),
+ PIN_FIELD_BASE(126, 126, 1, 0x0080, 0x10, 16, 1),
+ PIN_FIELD_BASE(127, 127, 1, 0x0080, 0x10, 22, 1),
+ PIN_FIELD_BASE(128, 128, 1, 0x0080, 0x10, 15, 1),
+ PIN_FIELD_BASE(129, 129, 1, 0x0080, 0x10, 20, 1),
+ PIN_FIELD_BASE(130, 130, 1, 0x0080, 0x10, 27, 1),
+ PIN_FIELD_BASE(131, 131, 1, 0x0080, 0x10, 13, 1),
+ PIN_FIELD_BASE(132, 132, 1, 0x0080, 0x10, 14, 1),
+ PIN_FIELD_BASE(133, 133, 1, 0x0080, 0x10, 28, 1),
+ PIN_FIELD_BASE(134, 134, 1, 0x0080, 0x10, 21, 1),
+ PIN_FIELD_BASE(135, 135, 1, 0x0080, 0x10, 11, 1),
+ PIN_FIELD_BASE(136, 136, 1, 0x0080, 0x10, 12, 1),
+ PIN_FIELD_BASE(137, 137, 2, 0x00a0, 0x10, 3, 1),
+ PIN_FIELD_BASE(138, 138, 2, 0x00a0, 0x10, 4, 1),
+ PIN_FIELD_BASE(139, 139, 1, 0x0080, 0x10, 3, 1),
+ PIN_FIELD_BASE(140, 140, 1, 0x0080, 0x10, 4, 1),
+ PIN_FIELD_BASE(141, 141, 1, 0x0080, 0x10, 0, 1),
+ PIN_FIELD_BASE(142, 142, 1, 0x0080, 0x10, 1, 1),
+ PIN_FIELD_BASE(143, 143, 1, 0x0080, 0x10, 2, 1),
+ PIN_FIELD_BASE(144, 144, 1, 0x0080, 0x10, 5, 1),
+ PIN_FIELD_BASE(145, 145, 1, 0x0080, 0x10, 6, 1),
+ PIN_FIELD_BASE(146, 146, 1, 0x0080, 0x10, 7, 1),
+ PIN_FIELD_BASE(147, 147, 1, 0x0080, 0x10, 8, 1),
+ PIN_FIELD_BASE(148, 148, 1, 0x0080, 0x10, 9, 1),
+ PIN_FIELD_BASE(149, 149, 1, 0x0080, 0x10, 10, 1),
+ PIN_FIELD_BASE(150, 150, 3, 0x0080, 0x10, 8, 1),
+ PIN_FIELD_BASE(151, 151, 1, 0x0080, 0x10, 29, 1),
+ PIN_FIELD_BASE(152, 152, 3, 0x0080, 0x10, 9, 1),
+ PIN_FIELD_BASE(153, 153, 3, 0x0080, 0x10, 10, 1),
+ PIN_FIELD_BASE(154, 154, 3, 0x0080, 0x10, 11, 1),
+ PIN_FIELD_BASE(155, 155, 3, 0x0080, 0x10, 12, 1),
+ PIN_FIELD_BASE(180, 180, 5, 0x0090, 0x10, 15, 1),
+ PIN_FIELD_BASE(181, 181, 5, 0x0090, 0x10, 16, 1),
+ PIN_FIELD_BASE(182, 182, 9, 0x0070, 0x10, 3, 1),
+};
+
+static const struct mtk_pin_field_calc mt8189_pin_drv_range[] = {
+ PIN_FIELD_BASE(0, 0, 7, 0x0000, 0x10, 15, 3),
+ PIN_FIELD_BASE(1, 1, 8, 0x0000, 0x10, 9, 3),
+ PIN_FIELD_BASE(2, 2, 8, 0x0000, 0x10, 12, 3),
+ PIN_FIELD_BASE(3, 3, 8, 0x0000, 0x10, 15, 3),
+ PIN_FIELD_BASE(4, 4, 8, 0x0000, 0x10, 18, 3),
+ PIN_FIELD_BASE(5, 5, 8, 0x0000, 0x10, 21, 3),
+ PIN_FIELD_BASE(6, 6, 7, 0x0000, 0x10, 18, 3),
+ PIN_FIELD_BASE(7, 7, 7, 0x0000, 0x10, 21, 3),
+ PIN_FIELD_BASE(8, 8, 7, 0x0000, 0x10, 24, 3),
+ PIN_FIELD_BASE(9, 9, 7, 0x0000, 0x10, 27, 3),
+ PIN_FIELD_BASE(10, 10, 7, 0x0010, 0x10, 0, 3),
+ PIN_FIELD_BASE(11, 11, 7, 0x0010, 0x10, 3, 3),
+ PIN_FIELD_BASE(12, 12, 2, 0x0000, 0x10, 15, 3),
+ PIN_FIELD_BASE(13, 13, 2, 0x0000, 0x10, 18, 3),
+ PIN_FIELD_BASE(14, 14, 3, 0x0000, 0x10, 0, 3),
+ PIN_FIELD_BASE(15, 15, 3, 0x0000, 0x10, 3, 3),
+ PIN_FIELD_BASE(16, 16, 2, 0x0000, 0x10, 21, 3),
+ PIN_FIELD_BASE(17, 17, 2, 0x0000, 0x10, 24, 3),
+ PIN_FIELD_BASE(18, 18, 7, 0x0000, 0x10, 0, 3),
+ PIN_FIELD_BASE(19, 19, 7, 0x0000, 0x10, 6, 3),
+ PIN_FIELD_BASE(20, 20, 7, 0x0000, 0x10, 3, 3),
+ PIN_FIELD_BASE(21, 21, 7, 0x0000, 0x10, 9, 3),
+ PIN_FIELD_BASE(22, 22, 9, 0x0000, 0x10, 0, 3),
+ PIN_FIELD_BASE(23, 23, 9, 0x0000, 0x10, 3, 3),
+ PIN_FIELD_BASE(24, 24, 9, 0x0000, 0x10, 6, 3),
+ PIN_FIELD_BASE(25, 25, 4, 0x0000, 0x10, 6, 3),
+ PIN_FIELD_BASE(26, 26, 4, 0x0000, 0x10, 3, 3),
+ PIN_FIELD_BASE(27, 27, 2, 0x0000, 0x10, 3, 3),
+ PIN_FIELD_BASE(28, 28, 2, 0x0000, 0x10, 6, 3),
+ PIN_FIELD_BASE(29, 29, 4, 0x0000, 0x10, 0, 3),
+ PIN_FIELD_BASE(30, 30, 2, 0x0000, 0x10, 0, 3),
+ PIN_FIELD_BASE(31, 31, 3, 0x0010, 0x10, 27, 3),
+ PIN_FIELD_BASE(32, 32, 1, 0x0030, 0x10, 0, 3),
+ PIN_FIELD_BASE(33, 33, 3, 0x0020, 0x10, 3, 3),
+ PIN_FIELD_BASE(34, 34, 3, 0x0020, 0x10, 0, 3),
+ PIN_FIELD_BASE(35, 35, 3, 0x0020, 0x10, 9, 3),
+ PIN_FIELD_BASE(36, 36, 3, 0x0020, 0x10, 6, 3),
+ PIN_FIELD_BASE(37, 37, 3, 0x0020, 0x10, 15, 3),
+ PIN_FIELD_BASE(38, 38, 3, 0x0020, 0x10, 12, 3),
+ PIN_FIELD_BASE(39, 39, 3, 0x0000, 0x10, 15, 3),
+ PIN_FIELD_BASE(40, 40, 3, 0x0000, 0x10, 6, 3),
+ PIN_FIELD_BASE(41, 41, 3, 0x0000, 0x10, 9, 3),
+ PIN_FIELD_BASE(42, 42, 3, 0x0000, 0x10, 12, 3),
+ PIN_FIELD_BASE(43, 43, 3, 0x0000, 0x10, 18, 3),
+ PIN_FIELD_BASE(44, 44, 7, 0x0020, 0x10, 0, 3),
+ PIN_FIELD_BASE(45, 45, 7, 0x0020, 0x10, 3, 3),
+ PIN_FIELD_BASE(46, 46, 7, 0x0020, 0x10, 6, 3),
+ PIN_FIELD_BASE(47, 47, 7, 0x0020, 0x10, 9, 3),
+ PIN_FIELD_BASE(48, 48, 4, 0x0000, 0x10, 15, 3),
+ PIN_FIELD_BASE(49, 49, 4, 0x0000, 0x10, 12, 3),
+ PIN_FIELD_BASE(50, 50, 4, 0x0000, 0x10, 9, 3),
+ PIN_FIELD_BASE(51, 51, 8, 0x0000, 0x10, 24, 3),
+ PIN_FIELD_BASE(52, 52, 8, 0x0010, 0x10, 0, 3),
+ PIN_FIELD_BASE(53, 53, 8, 0x0000, 0x10, 27, 3),
+ PIN_FIELD_BASE(54, 54, 8, 0x0010, 0x10, 3, 3),
+ PIN_FIELD_BASE(55, 55, 4, 0x0000, 0x10, 18, 3),
+ PIN_FIELD_BASE(56, 56, 4, 0x0000, 0x10, 21, 3),
+ PIN_FIELD_BASE(57, 57, 2, 0x0010, 0x10, 9, 3),
+ PIN_FIELD_BASE(58, 58, 2, 0x0010, 0x10, 21, 3),
+ PIN_FIELD_BASE(59, 59, 2, 0x0010, 0x10, 12, 3),
+ PIN_FIELD_BASE(60, 60, 2, 0x0010, 0x10, 24, 3),
+ PIN_FIELD_BASE(61, 61, 2, 0x0010, 0x10, 15, 3),
+ PIN_FIELD_BASE(62, 62, 2, 0x0010, 0x10, 27, 3),
+ PIN_FIELD_BASE(63, 63, 2, 0x0010, 0x10, 18, 3),
+ PIN_FIELD_BASE(64, 64, 2, 0x0020, 0x10, 0, 3),
+ PIN_FIELD_BASE(65, 65, 9, 0x0010, 0x10, 0, 3),
+ PIN_FIELD_BASE(66, 66, 9, 0x0010, 0x10, 6, 3),
+ PIN_FIELD_BASE(67, 67, 9, 0x0010, 0x10, 3, 3),
+ PIN_FIELD_BASE(68, 68, 9, 0x0010, 0x10, 9, 3),
+ PIN_FIELD_BASE(69, 69, 2, 0x0020, 0x10, 6, 3),
+ PIN_FIELD_BASE(70, 70, 2, 0x0020, 0x10, 3, 3),
+ PIN_FIELD_BASE(71, 71, 2, 0x0020, 0x10, 12, 3),
+ PIN_FIELD_BASE(72, 72, 2, 0x0020, 0x10, 9, 3),
+ PIN_FIELD_BASE(73, 73, 2, 0x0020, 0x10, 18, 3),
+ PIN_FIELD_BASE(74, 74, 2, 0x0020, 0x10, 15, 3),
+ PIN_FIELD_BASE(75, 75, 3, 0x0010, 0x10, 9, 3),
+ PIN_FIELD_BASE(76, 76, 2, 0x0020, 0x10, 21, 3),
+ PIN_FIELD_BASE(77, 77, 8, 0x0010, 0x10, 9, 3),
+ PIN_FIELD_BASE(78, 78, 8, 0x0010, 0x10, 6, 3),
+ PIN_FIELD_BASE(79, 79, 8, 0x0010, 0x10, 15, 3),
+ PIN_FIELD_BASE(80, 80, 8, 0x0010, 0x10, 12, 3),
+ PIN_FIELD_BASE(81, 81, 2, 0x0020, 0x10, 27, 3),
+ PIN_FIELD_BASE(82, 82, 2, 0x0020, 0x10, 24, 3),
+ PIN_FIELD_BASE(83, 83, 2, 0x0030, 0x10, 0, 3),
+ PIN_FIELD_BASE(84, 84, 7, 0x0020, 0x10, 12, 3),
+ PIN_FIELD_BASE(85, 85, 7, 0x0020, 0x10, 15, 3),
+ PIN_FIELD_BASE(86, 86, 7, 0x0020, 0x10, 18, 3),
+ PIN_FIELD_BASE(87, 87, 7, 0x0020, 0x10, 21, 3),
+ PIN_FIELD_BASE(88, 88, 5, 0x0020, 0x10, 0, 3),
+ PIN_FIELD_BASE(89, 89, 5, 0x0010, 0x10, 27, 3),
+ PIN_FIELD_BASE(90, 90, 5, 0x0020, 0x10, 6, 3),
+ PIN_FIELD_BASE(91, 91, 5, 0x0020, 0x10, 3, 3),
+ PIN_FIELD_BASE(92, 92, 5, 0x0010, 0x10, 18, 3),
+ PIN_FIELD_BASE(93, 93, 5, 0x0010, 0x10, 21, 3),
+ PIN_FIELD_BASE(94, 94, 5, 0x0020, 0x10, 9, 3),
+ PIN_FIELD_BASE(95, 95, 5, 0x0010, 0x10, 15, 3),
+ PIN_FIELD_BASE(96, 96, 5, 0x0010, 0x10, 24, 3),
+ PIN_FIELD_BASE(97, 97, 5, 0x0000, 0x10, 0, 3),
+ PIN_FIELD_BASE(98, 98, 5, 0x0000, 0x10, 15, 3),
+ PIN_FIELD_BASE(99, 99, 5, 0x0000, 0x10, 9, 3),
+ PIN_FIELD_BASE(100, 100, 5, 0x0000, 0x10, 12, 3),
+ PIN_FIELD_BASE(101, 101, 5, 0x0000, 0x10, 3, 3),
+ PIN_FIELD_BASE(102, 102, 5, 0x0000, 0x10, 6, 3),
+ PIN_FIELD_BASE(103, 103, 7, 0x0010, 0x10, 15, 3),
+ PIN_FIELD_BASE(104, 104, 7, 0x0010, 0x10, 6, 3),
+ PIN_FIELD_BASE(105, 105, 7, 0x0010, 0x10, 12, 3),
+ PIN_FIELD_BASE(106, 106, 7, 0x0010, 0x10, 9, 3),
+ PIN_FIELD_BASE(107, 107, 7, 0x0010, 0x10, 27, 3),
+ PIN_FIELD_BASE(108, 108, 7, 0x0010, 0x10, 18, 3),
+ PIN_FIELD_BASE(109, 109, 7, 0x0010, 0x10, 24, 3),
+ PIN_FIELD_BASE(110, 110, 7, 0x0010, 0x10, 21, 3),
+ PIN_FIELD_BASE(111, 111, 7, 0x0000, 0x10, 12, 3),
+ PIN_FIELD_BASE(112, 112, 8, 0x0000, 0x10, 0, 3),
+ PIN_FIELD_BASE(113, 113, 8, 0x0000, 0x10, 3, 3),
+ PIN_FIELD_BASE(114, 114, 8, 0x0000, 0x10, 6, 3),
+ PIN_FIELD_BASE(115, 115, 2, 0x0000, 0x10, 27, 3),
+ PIN_FIELD_BASE(116, 116, 2, 0x0010, 0x10, 6, 3),
+ PIN_FIELD_BASE(117, 117, 2, 0x0010, 0x10, 0, 3),
+ PIN_FIELD_BASE(118, 118, 2, 0x0010, 0x10, 3, 3),
+ PIN_FIELD_BASE(119, 119, 1, 0x0020, 0x10, 18, 3),
+ PIN_FIELD_BASE(120, 120, 1, 0x0020, 0x10, 15, 3),
+ PIN_FIELD_BASE(121, 121, 1, 0x0020, 0x10, 12, 3),
+ PIN_FIELD_BASE(122, 122, 1, 0x0020, 0x10, 9, 3),
+ PIN_FIELD_BASE(123, 123, 1, 0x0010, 0x10, 27, 3),
+ PIN_FIELD_BASE(124, 124, 1, 0x0010, 0x10, 24, 3),
+ PIN_FIELD_BASE(125, 125, 1, 0x0010, 0x10, 21, 3),
+ PIN_FIELD_BASE(126, 126, 1, 0x0010, 0x10, 18, 3),
+ PIN_FIELD_BASE(127, 127, 1, 0x0020, 0x10, 6, 3),
+ PIN_FIELD_BASE(128, 128, 1, 0x0010, 0x10, 15, 3),
+ PIN_FIELD_BASE(129, 129, 1, 0x0020, 0x10, 0, 3),
+ PIN_FIELD_BASE(130, 130, 1, 0x0020, 0x10, 21, 3),
+ PIN_FIELD_BASE(131, 131, 1, 0x0010, 0x10, 9, 3),
+ PIN_FIELD_BASE(132, 132, 1, 0x0010, 0x10, 12, 3),
+ PIN_FIELD_BASE(133, 133, 1, 0x0020, 0x10, 24, 3),
+ PIN_FIELD_BASE(134, 134, 1, 0x0020, 0x10, 3, 3),
+ PIN_FIELD_BASE(135, 135, 1, 0x0010, 0x10, 3, 3),
+ PIN_FIELD_BASE(136, 136, 1, 0x0010, 0x10, 6, 3),
+ PIN_FIELD_BASE(137, 137, 2, 0x0000, 0x10, 9, 3),
+ PIN_FIELD_BASE(138, 138, 2, 0x0000, 0x10, 12, 3),
+ PIN_FIELD_BASE(139, 139, 1, 0x0000, 0x10, 9, 3),
+ PIN_FIELD_BASE(140, 140, 1, 0x0000, 0x10, 12, 3),
+ PIN_FIELD_BASE(141, 141, 1, 0x0000, 0x10, 0, 3),
+ PIN_FIELD_BASE(142, 142, 1, 0x0000, 0x10, 3, 3),
+ PIN_FIELD_BASE(143, 143, 1, 0x0000, 0x10, 6, 3),
+ PIN_FIELD_BASE(144, 144, 1, 0x0000, 0x10, 15, 3),
+ PIN_FIELD_BASE(145, 145, 1, 0x0000, 0x10, 18, 3),
+ PIN_FIELD_BASE(146, 146, 1, 0x0000, 0x10, 21, 3),
+ PIN_FIELD_BASE(147, 147, 1, 0x0000, 0x10, 24, 3),
+ PIN_FIELD_BASE(148, 148, 1, 0x0000, 0x10, 27, 3),
+ PIN_FIELD_BASE(149, 149, 1, 0x0010, 0x10, 0, 3),
+ PIN_FIELD_BASE(150, 150, 3, 0x0010, 0x10, 12, 3),
+ PIN_FIELD_BASE(151, 151, 1, 0x0020, 0x10, 27, 3),
+ PIN_FIELD_BASE(152, 152, 3, 0x0010, 0x10, 15, 3),
+ PIN_FIELD_BASE(153, 153, 3, 0x0010, 0x10, 18, 3),
+ PIN_FIELD_BASE(154, 154, 3, 0x0010, 0x10, 21, 3),
+ PIN_FIELD_BASE(155, 155, 3, 0x0010, 0x10, 24, 3),
+ PIN_FIELD_BASE(156, 156, 5, 0x0010, 0x10, 6, 3),
+ PIN_FIELD_BASE(157, 157, 5, 0x0010, 0x10, 3, 3),
+ PIN_FIELD_BASE(158, 158, 5, 0x0010, 0x10, 0, 3),
+ PIN_FIELD_BASE(159, 159, 6, 0x0000, 0x10, 6, 3),
+ PIN_FIELD_BASE(160, 160, 5, 0x0010, 0x10, 12, 3),
+ PIN_FIELD_BASE(161, 161, 5, 0x0000, 0x10, 21, 3),
+ PIN_FIELD_BASE(162, 162, 5, 0x0000, 0x10, 18, 3),
+ PIN_FIELD_BASE(163, 163, 6, 0x0000, 0x10, 3, 3),
+ PIN_FIELD_BASE(164, 164, 5, 0x0000, 0x10, 27, 3),
+ PIN_FIELD_BASE(165, 165, 5, 0x0000, 0x10, 24, 3),
+ PIN_FIELD_BASE(166, 166, 6, 0x0000, 0x10, 0, 3),
+ PIN_FIELD_BASE(167, 167, 5, 0x0010, 0x10, 9, 3),
+ PIN_FIELD_BASE(168, 168, 3, 0x0000, 0x10, 24, 3),
+ PIN_FIELD_BASE(169, 169, 3, 0x0000, 0x10, 21, 3),
+ PIN_FIELD_BASE(170, 170, 3, 0x0000, 0x10, 27, 3),
+ PIN_FIELD_BASE(171, 171, 3, 0x0010, 0x10, 0, 3),
+ PIN_FIELD_BASE(172, 172, 3, 0x0010, 0x10, 3, 3),
+ PIN_FIELD_BASE(173, 173, 3, 0x0010, 0x10, 6, 3),
+ PIN_FIELD_BASE(174, 174, 9, 0x0000, 0x10, 15, 3),
+ PIN_FIELD_BASE(175, 175, 9, 0x0000, 0x10, 12, 3),
+ PIN_FIELD_BASE(176, 176, 9, 0x0000, 0x10, 18, 3),
+ PIN_FIELD_BASE(177, 177, 9, 0x0000, 0x10, 21, 3),
+ PIN_FIELD_BASE(178, 178, 9, 0x0000, 0x10, 24, 3),
+ PIN_FIELD_BASE(179, 179, 9, 0x0000, 0x10, 27, 3),
+ PIN_FIELD_BASE(180, 180, 5, 0x0020, 0x10, 12, 3),
+ PIN_FIELD_BASE(181, 181, 5, 0x0020, 0x10, 15, 3),
+ PIN_FIELD_BASE(182, 182, 9, 0x0000, 0x10, 9, 3),
+};
+
+static const struct mtk_pin_field_calc mt8189_pin_drv_adv_range[] = {
+ PIN_FIELD_BASE(51, 51, 8, 0x0020, 0x10, 0, 3),
+ PIN_FIELD_BASE(52, 52, 8, 0x0020, 0x10, 6, 3),
+ PIN_FIELD_BASE(53, 53, 8, 0x0020, 0x10, 3, 3),
+ PIN_FIELD_BASE(54, 54, 8, 0x0020, 0x10, 9, 3),
+ PIN_FIELD_BASE(55, 55, 4, 0x0020, 0x10, 0, 3),
+ PIN_FIELD_BASE(56, 56, 4, 0x0020, 0x10, 3, 3),
+ PIN_FIELD_BASE(57, 57, 2, 0x0040, 0x10, 0, 3),
+ PIN_FIELD_BASE(58, 58, 2, 0x0040, 0x10, 12, 3),
+ PIN_FIELD_BASE(59, 59, 2, 0x0040, 0x10, 3, 3),
+ PIN_FIELD_BASE(60, 60, 2, 0x0040, 0x10, 15, 3),
+ PIN_FIELD_BASE(61, 61, 2, 0x0040, 0x10, 6, 3),
+ PIN_FIELD_BASE(62, 62, 2, 0x0040, 0x10, 18, 3),
+ PIN_FIELD_BASE(63, 63, 2, 0x0040, 0x10, 9, 3),
+ PIN_FIELD_BASE(64, 64, 2, 0x0040, 0x10, 21, 3),
+ PIN_FIELD_BASE(65, 65, 9, 0x0020, 0x10, 0, 3),
+ PIN_FIELD_BASE(66, 66, 9, 0x0020, 0x10, 6, 3),
+ PIN_FIELD_BASE(67, 67, 9, 0x0020, 0x10, 3, 3),
+ PIN_FIELD_BASE(68, 68, 9, 0x0020, 0x10, 9, 3),
+ PIN_FIELD_BASE(180, 180, 5, 0x0030, 0x10, 0, 3),
+ PIN_FIELD_BASE(181, 181, 5, 0x0030, 0x10, 3, 3),
+};
+
+static const struct mtk_pin_field_calc mt8189_pin_rsel_range[] = {
+ PIN_FIELD_BASE(51, 51, 8, 0x00b0, 0x10, 0, 3),
+ PIN_FIELD_BASE(52, 52, 8, 0x00b0, 0x10, 6, 3),
+ PIN_FIELD_BASE(53, 53, 8, 0x00b0, 0x10, 3, 3),
+ PIN_FIELD_BASE(54, 54, 8, 0x00b0, 0x10, 9, 3),
+ PIN_FIELD_BASE(55, 55, 4, 0x00b0, 0x10, 0, 3),
+ PIN_FIELD_BASE(56, 56, 4, 0x00b0, 0x10, 3, 3),
+ PIN_FIELD_BASE(57, 57, 2, 0x00d0, 0x10, 0, 3),
+ PIN_FIELD_BASE(58, 58, 2, 0x00d0, 0x10, 12, 3),
+ PIN_FIELD_BASE(59, 59, 2, 0x00d0, 0x10, 3, 3),
+ PIN_FIELD_BASE(60, 60, 2, 0x00d0, 0x10, 15, 3),
+ PIN_FIELD_BASE(61, 61, 2, 0x00d0, 0x10, 6, 3),
+ PIN_FIELD_BASE(62, 62, 2, 0x00d0, 0x10, 18, 3),
+ PIN_FIELD_BASE(63, 63, 2, 0x00d0, 0x10, 9, 3),
+ PIN_FIELD_BASE(64, 64, 2, 0x00d0, 0x10, 21, 3),
+ PIN_FIELD_BASE(65, 65, 9, 0x00e0, 0x10, 0, 3),
+ PIN_FIELD_BASE(66, 66, 9, 0x00e0, 0x10, 6, 3),
+ PIN_FIELD_BASE(67, 67, 9, 0x00e0, 0x10, 3, 3),
+ PIN_FIELD_BASE(68, 68, 9, 0x00e0, 0x10, 9, 3),
+ PIN_FIELD_BASE(180, 180, 5, 0x0110, 0x10, 0, 3),
+ PIN_FIELD_BASE(181, 181, 5, 0x0110, 0x10, 3, 3),
+};
+
+static const struct mtk_pin_rsel mt8189_pin_rsel_val_range[] = {
+ PIN_RSEL(51, 68, 0x0, 75000, 75000),
+ PIN_RSEL(51, 68, 0x1, 10000, 5000),
+ PIN_RSEL(51, 68, 0x2, 5000, 75000),
+ PIN_RSEL(51, 68, 0x3, 4000, 5000),
+ PIN_RSEL(51, 68, 0x4, 3000, 75000),
+ PIN_RSEL(51, 68, 0x5, 2000, 5000),
+ PIN_RSEL(51, 68, 0x6, 1500, 75000),
+ PIN_RSEL(51, 68, 0x7, 1000, 5000),
+ PIN_RSEL(180, 181, 0x0, 75000, 75000),
+ PIN_RSEL(180, 181, 0x1, 10000, 5000),
+ PIN_RSEL(180, 181, 0x2, 5000, 75000),
+ PIN_RSEL(180, 181, 0x3, 4000, 5000),
+ PIN_RSEL(180, 181, 0x4, 3000, 75000),
+ PIN_RSEL(180, 181, 0x5, 2000, 5000),
+ PIN_RSEL(180, 181, 0x6, 1500, 75000),
+ PIN_RSEL(180, 181, 0x7, 1000, 5000),
+};
+
+static const unsigned int mt8189_pull_type[] = {
+ MTK_PULL_PU_PD_TYPE, /*0*/
+ MTK_PULL_PU_PD_TYPE, /*1*/
+ MTK_PULL_PU_PD_TYPE, /*2*/
+ MTK_PULL_PU_PD_TYPE, /*3*/
+ MTK_PULL_PU_PD_TYPE, /*4*/
+ MTK_PULL_PU_PD_TYPE, /*5*/
+ MTK_PULL_PU_PD_TYPE, /*6*/
+ MTK_PULL_PU_PD_TYPE, /*7*/
+ MTK_PULL_PU_PD_TYPE, /*8*/
+ MTK_PULL_PU_PD_TYPE, /*9*/
+ MTK_PULL_PU_PD_TYPE, /*10*/
+ MTK_PULL_PU_PD_TYPE, /*11*/
+ MTK_PULL_PU_PD_TYPE, /*12*/
+ MTK_PULL_PU_PD_TYPE, /*13*/
+ MTK_PULL_PU_PD_TYPE, /*14*/
+ MTK_PULL_PU_PD_TYPE, /*15*/
+ MTK_PULL_PU_PD_TYPE, /*16*/
+ MTK_PULL_PU_PD_TYPE, /*17*/
+ MTK_PULL_PU_PD_TYPE, /*18*/
+ MTK_PULL_PU_PD_TYPE, /*19*/
+ MTK_PULL_PU_PD_TYPE, /*20*/
+ MTK_PULL_PU_PD_TYPE, /*21*/
+ MTK_PULL_PU_PD_TYPE, /*22*/
+ MTK_PULL_PU_PD_TYPE, /*23*/
+ MTK_PULL_PU_PD_TYPE, /*24*/
+ MTK_PULL_PU_PD_TYPE, /*25*/
+ MTK_PULL_PU_PD_TYPE, /*26*/
+ MTK_PULL_PU_PD_TYPE, /*27*/
+ MTK_PULL_PU_PD_TYPE, /*28*/
+ MTK_PULL_PU_PD_TYPE, /*29*/
+ MTK_PULL_PU_PD_TYPE, /*30*/
+ MTK_PULL_PU_PD_TYPE, /*31*/
+ MTK_PULL_PU_PD_TYPE, /*32*/
+ MTK_PULL_PU_PD_TYPE, /*33*/
+ MTK_PULL_PU_PD_TYPE, /*34*/
+ MTK_PULL_PU_PD_TYPE, /*35*/
+ MTK_PULL_PU_PD_TYPE, /*36*/
+ MTK_PULL_PU_PD_TYPE, /*37*/
+ MTK_PULL_PU_PD_TYPE, /*38*/
+ MTK_PULL_PU_PD_TYPE, /*39*/
+ MTK_PULL_PU_PD_TYPE, /*40*/
+ MTK_PULL_PU_PD_TYPE, /*41*/
+ MTK_PULL_PU_PD_TYPE, /*42*/
+ MTK_PULL_PU_PD_TYPE, /*43*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*44*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*45*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*46*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*47*/
+ MTK_PULL_PU_PD_TYPE, /*48*/
+ MTK_PULL_PU_PD_TYPE, /*49*/
+ MTK_PULL_PU_PD_TYPE, /*50*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*51*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*52*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*53*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*54*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*55*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*56*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*57*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*58*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*59*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*60*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*61*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*62*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*63*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*64*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*65*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*66*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*67*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*68*/
+ MTK_PULL_PU_PD_TYPE, /*69*/
+ MTK_PULL_PU_PD_TYPE, /*70*/
+ MTK_PULL_PU_PD_TYPE, /*71*/
+ MTK_PULL_PU_PD_TYPE, /*72*/
+ MTK_PULL_PU_PD_TYPE, /*73*/
+ MTK_PULL_PU_PD_TYPE, /*74*/
+ MTK_PULL_PU_PD_TYPE, /*75*/
+ MTK_PULL_PU_PD_TYPE, /*76*/
+ MTK_PULL_PU_PD_TYPE, /*77*/
+ MTK_PULL_PU_PD_TYPE, /*78*/
+ MTK_PULL_PU_PD_TYPE, /*79*/
+ MTK_PULL_PU_PD_TYPE, /*80*/
+ MTK_PULL_PU_PD_TYPE, /*81*/
+ MTK_PULL_PU_PD_TYPE, /*82*/
+ MTK_PULL_PU_PD_TYPE, /*83*/
+ MTK_PULL_PU_PD_TYPE, /*84*/
+ MTK_PULL_PU_PD_TYPE, /*85*/
+ MTK_PULL_PU_PD_TYPE, /*86*/
+ MTK_PULL_PU_PD_TYPE, /*87*/
+ MTK_PULL_PU_PD_TYPE, /*88*/
+ MTK_PULL_PU_PD_TYPE, /*89*/
+ MTK_PULL_PU_PD_TYPE, /*90*/
+ MTK_PULL_PU_PD_TYPE, /*91*/
+ MTK_PULL_PU_PD_TYPE, /*92*/
+ MTK_PULL_PU_PD_TYPE, /*93*/
+ MTK_PULL_PU_PD_TYPE, /*94*/
+ MTK_PULL_PU_PD_TYPE, /*95*/
+ MTK_PULL_PU_PD_TYPE, /*96*/
+ MTK_PULL_PU_PD_TYPE, /*97*/
+ MTK_PULL_PU_PD_TYPE, /*98*/
+ MTK_PULL_PU_PD_TYPE, /*99*/
+ MTK_PULL_PU_PD_TYPE, /*100*/
+ MTK_PULL_PU_PD_TYPE, /*101*/
+ MTK_PULL_PU_PD_TYPE, /*102*/
+ MTK_PULL_PU_PD_TYPE, /*103*/
+ MTK_PULL_PU_PD_TYPE, /*104*/
+ MTK_PULL_PU_PD_TYPE, /*105*/
+ MTK_PULL_PU_PD_TYPE, /*106*/
+ MTK_PULL_PU_PD_TYPE, /*107*/
+ MTK_PULL_PU_PD_TYPE, /*108*/
+ MTK_PULL_PU_PD_TYPE, /*109*/
+ MTK_PULL_PU_PD_TYPE, /*110*/
+ MTK_PULL_PU_PD_TYPE, /*111*/
+ MTK_PULL_PU_PD_TYPE, /*112*/
+ MTK_PULL_PU_PD_TYPE, /*113*/
+ MTK_PULL_PU_PD_TYPE, /*114*/
+ MTK_PULL_PU_PD_TYPE, /*115*/
+ MTK_PULL_PU_PD_TYPE, /*116*/
+ MTK_PULL_PU_PD_TYPE, /*117*/
+ MTK_PULL_PU_PD_TYPE, /*118*/
+ MTK_PULL_PU_PD_TYPE, /*119*/
+ MTK_PULL_PU_PD_TYPE, /*120*/
+ MTK_PULL_PU_PD_TYPE, /*121*/
+ MTK_PULL_PU_PD_TYPE, /*122*/
+ MTK_PULL_PU_PD_TYPE, /*123*/
+ MTK_PULL_PU_PD_TYPE, /*124*/
+ MTK_PULL_PU_PD_TYPE, /*125*/
+ MTK_PULL_PU_PD_TYPE, /*126*/
+ MTK_PULL_PU_PD_TYPE, /*127*/
+ MTK_PULL_PU_PD_TYPE, /*128*/
+ MTK_PULL_PU_PD_TYPE, /*129*/
+ MTK_PULL_PU_PD_TYPE, /*130*/
+ MTK_PULL_PU_PD_TYPE, /*131*/
+ MTK_PULL_PU_PD_TYPE, /*132*/
+ MTK_PULL_PU_PD_TYPE, /*133*/
+ MTK_PULL_PU_PD_TYPE, /*134*/
+ MTK_PULL_PU_PD_TYPE, /*135*/
+ MTK_PULL_PU_PD_TYPE, /*136*/
+ MTK_PULL_PU_PD_TYPE, /*137*/
+ MTK_PULL_PU_PD_TYPE, /*138*/
+ MTK_PULL_PU_PD_TYPE, /*139*/
+ MTK_PULL_PU_PD_TYPE, /*140*/
+ MTK_PULL_PU_PD_TYPE, /*141*/
+ MTK_PULL_PU_PD_TYPE, /*142*/
+ MTK_PULL_PU_PD_TYPE, /*143*/
+ MTK_PULL_PU_PD_TYPE, /*144*/
+ MTK_PULL_PU_PD_TYPE, /*145*/
+ MTK_PULL_PU_PD_TYPE, /*146*/
+ MTK_PULL_PU_PD_TYPE, /*147*/
+ MTK_PULL_PU_PD_TYPE, /*148*/
+ MTK_PULL_PU_PD_TYPE, /*149*/
+ MTK_PULL_PU_PD_TYPE, /*150*/
+ MTK_PULL_PU_PD_TYPE, /*151*/
+ MTK_PULL_PU_PD_TYPE, /*152*/
+ MTK_PULL_PU_PD_TYPE, /*153*/
+ MTK_PULL_PU_PD_TYPE, /*154*/
+ MTK_PULL_PU_PD_TYPE, /*155*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*156*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*157*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*158*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*159*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*160*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*161*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*162*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*163*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*164*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*165*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*166*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*167*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*168*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*169*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*170*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*171*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*172*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*173*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*174*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*175*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*176*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*177*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*178*/
+ MTK_PULL_PUPD_R1R0_TYPE, /*179*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*180*/
+ MTK_PULL_PU_PD_RSEL_TYPE, /*181*/
+ MTK_PULL_PU_PD_TYPE, /*182*/
+};
+
+static const struct mtk_pin_reg_calc mt8189_reg_cals[PINCTRL_PIN_REG_MAX] = {
+ [PINCTRL_PIN_REG_MODE] = MTK_RANGE(mt8189_pin_mode_range),
+ [PINCTRL_PIN_REG_DIR] = MTK_RANGE(mt8189_pin_dir_range),
+ [PINCTRL_PIN_REG_DI] = MTK_RANGE(mt8189_pin_di_range),
+ [PINCTRL_PIN_REG_DO] = MTK_RANGE(mt8189_pin_do_range),
+ [PINCTRL_PIN_REG_SMT] = MTK_RANGE(mt8189_pin_smt_range),
+ [PINCTRL_PIN_REG_IES] = MTK_RANGE(mt8189_pin_ies_range),
+ [PINCTRL_PIN_REG_TDSEL] = MTK_RANGE(mt8189_pin_tdsel_range),
+ [PINCTRL_PIN_REG_RDSEL] = MTK_RANGE(mt8189_pin_rdsel_range),
+ [PINCTRL_PIN_REG_PUPD] = MTK_RANGE(mt8189_pin_pupd_range),
+ [PINCTRL_PIN_REG_R0] = MTK_RANGE(mt8189_pin_r0_range),
+ [PINCTRL_PIN_REG_R1] = MTK_RANGE(mt8189_pin_r1_range),
+ [PINCTRL_PIN_REG_PU] = MTK_RANGE(mt8189_pin_pu_range),
+ [PINCTRL_PIN_REG_PD] = MTK_RANGE(mt8189_pin_pd_range),
+ [PINCTRL_PIN_REG_DRV] = MTK_RANGE(mt8189_pin_drv_range),
+ [PINCTRL_PIN_REG_DRV_ADV] = MTK_RANGE(mt8189_pin_drv_adv_range),
+ [PINCTRL_PIN_REG_RSEL] = MTK_RANGE(mt8189_pin_rsel_range),
+};
+
+static const char * const mt8189_pinctrl_register_base_names[] = {
+ "gpio_base", "iocfg_bm0_base", "iocfg_bm1_base", "iocfg_bm2_base", "iocfg_lm_base",
+ "iocfg_lt0_base", "iocfg_lt1_base", "iocfg_rb0_base", "iocfg_rb1_base",
+ "iocfg_rt_base"
+};
+
+static const struct mtk_eint_hw mt8189_eint_hw = {
+ .port_mask = 0xf,
+ .ports = 3,
+ .ap_num = 210,
+ .db_cnt = 32,
+ .db_time = debounce_time_mt6765,
+};
+
+static const struct mtk_pin_soc mt8189_data = {
+ .reg_cal = mt8189_reg_cals,
+ .pins = mtk_pins_mt8189,
+ .npins = ARRAY_SIZE(mtk_pins_mt8189),
+ .ngrps = ARRAY_SIZE(mtk_pins_mt8189),
+ .eint_pin = eint_pins_mt8189,
+ .eint_hw = &mt8189_eint_hw,
+ .nfuncs = 8,
+ .gpio_m = 0,
+ .base_names = mt8189_pinctrl_register_base_names,
+ .nbase_names = ARRAY_SIZE(mt8189_pinctrl_register_base_names),
+ .bias_set_combo = mtk_pinconf_bias_set_combo,
+ .bias_get_combo = mtk_pinconf_bias_get_combo,
+ .pull_type = mt8189_pull_type,
+ .pin_rsel = mt8189_pin_rsel_val_range,
+ .npin_rsel = ARRAY_SIZE(mt8189_pin_rsel_val_range),
+ .drive_set = mtk_pinconf_drive_set_rev1,
+ .drive_get = mtk_pinconf_drive_get_rev1,
+ .adv_drive_set = mtk_pinconf_adv_drive_set_raw,
+ .adv_drive_get = mtk_pinconf_adv_drive_get_raw,
+};
+
+static const struct of_device_id mt8189_pinctrl_of_match[] = {
+ { .compatible = "mediatek,mt8189-pinctrl", .data = &mt8189_data },
+ { /* sentinel */ }
+};
+
+static struct platform_driver mt8189_pinctrl_driver = {
+ .driver = {
+ .name = "mt8189-pinctrl",
+ .of_match_table = mt8189_pinctrl_of_match,
+ .pm = pm_sleep_ptr(&mtk_paris_pinctrl_pm_ops),
+ },
+ .probe = mtk_paris_pinctrl_probe,
+};
+
+static int __init mt8189_pinctrl_init(void)
+{
+ return platform_driver_register(&mt8189_pinctrl_driver);
+}
+arch_initcall(mt8189_pinctrl_init);
+
+MODULE_DESCRIPTION("MediaTek MT8189 Pinctrl Driver");
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-mt8189.h b/drivers/pinctrl/mediatek/pinctrl-mtk-mt8189.h
new file mode 100644
index 000000000000..771efb3da73f
--- /dev/null
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-mt8189.h
@@ -0,0 +1,2452 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2025 MediaTek Inc.
+ * Author: Lei Xue <lei.xue@mediatek.com>
+ * Cathy Xu <ot_cathy.xu@mediatek.com>
+ */
+
+#ifndef __PINCTRL_MTK_MT8189_H
+#define __PINCTRL_MTK_MT8189_H
+
+#include "pinctrl-paris.h"
+
+static const struct mtk_pin_desc mtk_pins_mt8189[] = {
+ MTK_PIN(
+ 0, "GPIO0",
+ MTK_EINT_FUNCTION(0, 0),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO0"),
+ MTK_FUNCTION(1, "TP_GPIO0_AO"),
+ MTK_FUNCTION(2, "SPIM3_A_CSB"),
+ MTK_FUNCTION(3, "I2SOUT0_MCK"),
+ MTK_FUNCTION(4, "SCP_SPI0_CS"),
+ MTK_FUNCTION(6, "CONN_BPI_BUS6"),
+ MTK_FUNCTION(7, "DBG_MON_A0")
+ ),
+
+ MTK_PIN(
+ 1, "GPIO1",
+ MTK_EINT_FUNCTION(0, 1),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO1"),
+ MTK_FUNCTION(1, "TP_GPIO1_AO"),
+ MTK_FUNCTION(2, "SPIM3_A_CLK"),
+ MTK_FUNCTION(3, "I2SOUT0_BCK"),
+ MTK_FUNCTION(4, "SCP_SPI0_CK"),
+ MTK_FUNCTION(6, "CONN_BPI_BUS7"),
+ MTK_FUNCTION(7, "DBG_MON_A1")
+ ),
+
+ MTK_PIN(
+ 2, "GPIO2",
+ MTK_EINT_FUNCTION(0, 2),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO2"),
+ MTK_FUNCTION(1, "TP_GPIO2_AO"),
+ MTK_FUNCTION(2, "SPIM3_A_MO"),
+ MTK_FUNCTION(3, "I2SOUT0_LRCK"),
+ MTK_FUNCTION(4, "SCP_SPI0_MO"),
+ MTK_FUNCTION(6, "CONN_BPI_BUS8"),
+ MTK_FUNCTION(7, "DBG_MON_A2")
+ ),
+
+ MTK_PIN(
+ 3, "GPIO3",
+ MTK_EINT_FUNCTION(0, 3),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO3"),
+ MTK_FUNCTION(1, "TP_GPIO3_AO"),
+ MTK_FUNCTION(2, "SPIM3_A_MI"),
+ MTK_FUNCTION(3, "I2SOUT0_DO"),
+ MTK_FUNCTION(4, "SCP_SPI0_MI"),
+ MTK_FUNCTION(6, "CONN_BPI_BUS9"),
+ MTK_FUNCTION(7, "DBG_MON_A3")
+ ),
+
+ MTK_PIN(
+ 4, "GPIO4",
+ MTK_EINT_FUNCTION(0, 4),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO4"),
+ MTK_FUNCTION(1, "TP_GPIO4_AO"),
+ MTK_FUNCTION(2, "SPIM4_A_CSB"),
+ MTK_FUNCTION(3, "I2SIN0_DI"),
+ MTK_FUNCTION(4, "SCP_SPI1_CS"),
+ MTK_FUNCTION(6, "CONN_BPI_BUS10"),
+ MTK_FUNCTION(7, "DBG_MON_A4")
+ ),
+
+ MTK_PIN(
+ 5, "GPIO5",
+ MTK_EINT_FUNCTION(0, 5),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO5"),
+ MTK_FUNCTION(1, "TP_GPIO5_AO"),
+ MTK_FUNCTION(2, "SPIM4_A_CLK"),
+ MTK_FUNCTION(3, "I2SIN0_BCK"),
+ MTK_FUNCTION(4, "SCP_SPI1_CK"),
+ MTK_FUNCTION(6, "CONN_BPI_BUS11_OLAT0"),
+ MTK_FUNCTION(7, "DBG_MON_A5")
+ ),
+
+ MTK_PIN(
+ 6, "GPIO6",
+ MTK_EINT_FUNCTION(0, 6),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO6"),
+ MTK_FUNCTION(1, "TP_GPIO6_AO"),
+ MTK_FUNCTION(2, "SPIM4_A_MO"),
+ MTK_FUNCTION(3, "I2SIN0_LRCK"),
+ MTK_FUNCTION(4, "SCP_SPI1_MO"),
+ MTK_FUNCTION(6, "CONN_BPI_BUS12_OLAT1"),
+ MTK_FUNCTION(7, "DBG_MON_A6")
+ ),
+
+ MTK_PIN(
+ 7, "GPIO7",
+ MTK_EINT_FUNCTION(0, 7),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO7"),
+ MTK_FUNCTION(1, "TP_GPIO7_AO"),
+ MTK_FUNCTION(2, "SPIM4_A_MI"),
+ MTK_FUNCTION(3, "I2SIN0_MCK"),
+ MTK_FUNCTION(4, "SCP_SPI1_MI"),
+ MTK_FUNCTION(6, "CONN_BPI_BUS13_OLAT2"),
+ MTK_FUNCTION(7, "DBG_MON_A7")
+ ),
+
+ MTK_PIN(
+ 8, "GPIO8",
+ MTK_EINT_FUNCTION(0, 8),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO8"),
+ MTK_FUNCTION(1, "TP_UTXD1_VLP"),
+ MTK_FUNCTION(2, "SPIM5_A_CSB"),
+ MTK_FUNCTION(3, "I2SOUT1_MCK"),
+ MTK_FUNCTION(4, "VADSP_UTXD0"),
+ MTK_FUNCTION(6, "CONN_BPI_BUS14_OLAT3"),
+ MTK_FUNCTION(7, "DBG_MON_A8")
+ ),
+
+ MTK_PIN(
+ 9, "GPIO9",
+ MTK_EINT_FUNCTION(0, 9),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO9"),
+ MTK_FUNCTION(1, "TP_URXD1_VLP"),
+ MTK_FUNCTION(2, "SPIM5_A_CLK"),
+ MTK_FUNCTION(3, "I2SOUT1_BCK"),
+ MTK_FUNCTION(4, "VADSP_URXD0"),
+ MTK_FUNCTION(6, "CONN_BPI_BUS15_OLAT4"),
+ MTK_FUNCTION(7, "DBG_MON_A9")
+ ),
+
+ MTK_PIN(
+ 10, "GPIO10",
+ MTK_EINT_FUNCTION(0, 10),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO10"),
+ MTK_FUNCTION(1, "TP_UCTS1_VLP"),
+ MTK_FUNCTION(2, "SPIM5_A_MO"),
+ MTK_FUNCTION(3, "I2SOUT1_LRCK"),
+ MTK_FUNCTION(4, "SRCLKENAI0"),
+ MTK_FUNCTION(6, "CONN_BPI_BUS16_OLAT5"),
+ MTK_FUNCTION(7, "DBG_MON_A10")
+ ),
+
+ MTK_PIN(
+ 11, "GPIO11",
+ MTK_EINT_FUNCTION(0, 11),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO11"),
+ MTK_FUNCTION(1, "TP_URTS1_VLP"),
+ MTK_FUNCTION(2, "SPIM5_A_MI"),
+ MTK_FUNCTION(3, "I2SOUT1_DO"),
+ MTK_FUNCTION(4, "SRCLKENAI1"),
+ MTK_FUNCTION(5, "PWM_vlp"),
+ MTK_FUNCTION(7, "DBG_MON_A11")
+ ),
+
+ MTK_PIN(
+ 12, "GPIO12",
+ MTK_EINT_FUNCTION(0, 12),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO12"),
+ MTK_FUNCTION(1, "TP_UTXD1_VCORE"),
+ MTK_FUNCTION(2, "UTXD3"),
+ MTK_FUNCTION(3, "CLKM0"),
+ MTK_FUNCTION(4, "CMFLASH0"),
+ MTK_FUNCTION(6, "ANT_SEL0"),
+ MTK_FUNCTION(7, "DBG_MON_B20")
+ ),
+
+ MTK_PIN(
+ 13, "GPIO13",
+ MTK_EINT_FUNCTION(0, 13),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO13"),
+ MTK_FUNCTION(1, "TP_URXD1_VCORE"),
+ MTK_FUNCTION(2, "URXD3"),
+ MTK_FUNCTION(3, "CLKM1"),
+ MTK_FUNCTION(4, "CMFLASH1"),
+ MTK_FUNCTION(6, "ANT_SEL1"),
+ MTK_FUNCTION(7, "DBG_MON_B21")
+ ),
+
+ MTK_PIN(
+ 14, "GPIO14",
+ MTK_EINT_FUNCTION(0, 14),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO14"),
+ MTK_FUNCTION(1, "TP_UCTS1_VCORE"),
+ MTK_FUNCTION(2, "UCTS3"),
+ MTK_FUNCTION(3, "CLKM2"),
+ MTK_FUNCTION(4, "CMFLASH2"),
+ MTK_FUNCTION(6, "ANT_SEL2"),
+ MTK_FUNCTION(7, "DBG_MON_B22")
+ ),
+
+ MTK_PIN(
+ 15, "GPIO15",
+ MTK_EINT_FUNCTION(0, 15),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO15"),
+ MTK_FUNCTION(1, "TP_URTS1_VCORE"),
+ MTK_FUNCTION(2, "URTS3"),
+ MTK_FUNCTION(3, "CLKM3"),
+ MTK_FUNCTION(4, "CMVREF0"),
+ MTK_FUNCTION(6, "ANT_SEL3"),
+ MTK_FUNCTION(7, "DBG_MON_B23")
+ ),
+
+ MTK_PIN(
+ 16, "GPIO16",
+ MTK_EINT_FUNCTION(0, 16),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO16"),
+ MTK_FUNCTION(1, "PWM_0"),
+ MTK_FUNCTION(2, "UCTS2"),
+ MTK_FUNCTION(3, "DP_TX_HPD"),
+ MTK_FUNCTION(4, "CMVREF1"),
+ MTK_FUNCTION(5, "MD32_0_GPIO0"),
+ MTK_FUNCTION(6, "ANT_SEL4"),
+ MTK_FUNCTION(7, "DBG_MON_B24")
+ ),
+
+ MTK_PIN(
+ 17, "GPIO17",
+ MTK_EINT_FUNCTION(0, 17),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO17"),
+ MTK_FUNCTION(1, "PWM_1"),
+ MTK_FUNCTION(2, "URTS2"),
+ MTK_FUNCTION(3, "EDP_TX_HPD"),
+ MTK_FUNCTION(4, "CMVREF2"),
+ MTK_FUNCTION(5, "MD32_1_GPIO0"),
+ MTK_FUNCTION(6, "PMSR_SMAP"),
+ MTK_FUNCTION(7, "DBG_MON_B25")
+ ),
+
+ MTK_PIN(
+ 18, "GPIO18",
+ MTK_EINT_FUNCTION(0, 18),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO18"),
+ MTK_FUNCTION(1, "CMFLASH0"),
+ MTK_FUNCTION(2, "CMVREF3"),
+ MTK_FUNCTION(3, "UTXD2"),
+ MTK_FUNCTION(4, "DISP_PWM1"),
+ MTK_FUNCTION(5, "I2SIN1_MCK"),
+ MTK_FUNCTION(6, "mbistreaden_trigger"),
+ MTK_FUNCTION(7, "DBG_MON_A12")
+ ),
+
+ MTK_PIN(
+ 19, "GPIO19",
+ MTK_EINT_FUNCTION(0, 19),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO19"),
+ MTK_FUNCTION(1, "CMFLASH1"),
+ MTK_FUNCTION(2, "CMVREF2"),
+ MTK_FUNCTION(3, "URXD2"),
+ MTK_FUNCTION(4, "USB_DRVVBUS_1P"),
+ MTK_FUNCTION(5, "I2SIN1_BCK"),
+ MTK_FUNCTION(6, "mbistwriteen_trigger"),
+ MTK_FUNCTION(7, "DBG_MON_A13")
+ ),
+
+ MTK_PIN(
+ 20, "GPIO20",
+ MTK_EINT_FUNCTION(0, 20),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO20"),
+ MTK_FUNCTION(1, "CMFLASH2"),
+ MTK_FUNCTION(2, "CMVREF1"),
+ MTK_FUNCTION(3, "UCTS2"),
+ MTK_FUNCTION(4, "PERSTN"),
+ MTK_FUNCTION(5, "I2SIN1_LRCK"),
+ MTK_FUNCTION(6, "DMIC0_DAT1"),
+ MTK_FUNCTION(7, "DBG_MON_A14")
+ ),
+
+ MTK_PIN(
+ 21, "GPIO21",
+ MTK_EINT_FUNCTION(0, 21),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO21"),
+ MTK_FUNCTION(1, "CMFLASH3"),
+ MTK_FUNCTION(2, "CMVREF0"),
+ MTK_FUNCTION(3, "URTS2"),
+ MTK_FUNCTION(4, "CLKREQN"),
+ MTK_FUNCTION(5, "I2SIN1_DI"),
+ MTK_FUNCTION(6, "DMIC1_DAT1"),
+ MTK_FUNCTION(7, "DBG_MON_A15")
+ ),
+
+ MTK_PIN(
+ 22, "GPIO22",
+ MTK_EINT_FUNCTION(0, 22),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO22"),
+ MTK_FUNCTION(1, "CMMCLK0"),
+ MTK_FUNCTION(2, "TP_GPIO4_AO")
+ ),
+
+ MTK_PIN(
+ 23, "GPIO23",
+ MTK_EINT_FUNCTION(0, 23),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO23"),
+ MTK_FUNCTION(1, "CMMCLK1"),
+ MTK_FUNCTION(2, "TP_GPIO5_AO"),
+ MTK_FUNCTION(3, "SSPM_UTXD_AO_VLP"),
+ MTK_FUNCTION(4, "PWM_vlp"),
+ MTK_FUNCTION(6, "SRCLKENAI0")
+ ),
+
+ MTK_PIN(
+ 24, "GPIO24",
+ MTK_EINT_FUNCTION(0, 24),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO24"),
+ MTK_FUNCTION(1, "CMMCLK2"),
+ MTK_FUNCTION(2, "TP_GPIO6_AO"),
+ MTK_FUNCTION(3, "SSPM_URXD_AO_VLP"),
+ MTK_FUNCTION(4, "WAKEN"),
+ MTK_FUNCTION(5, "SPMI_P_TRIG_FLAG"),
+ MTK_FUNCTION(6, "SRCLKENAI1")
+ ),
+
+ MTK_PIN(
+ 25, "GPIO25",
+ MTK_EINT_FUNCTION(0, 25),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO25"),
+ MTK_FUNCTION(1, "LCM_RST"),
+ MTK_FUNCTION(2, "DP_TX_HPD"),
+ MTK_FUNCTION(3, "CMFLASH3"),
+ MTK_FUNCTION(4, "MD32_0_GPIO0"),
+ MTK_FUNCTION(5, "USB_DRVVBUS_2P")
+ ),
+
+ MTK_PIN(
+ 26, "GPIO26",
+ MTK_EINT_FUNCTION(0, 26),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO26"),
+ MTK_FUNCTION(1, "DSI_TE"),
+ MTK_FUNCTION(2, "EDP_TX_HPD"),
+ MTK_FUNCTION(3, "CMVREF3"),
+ MTK_FUNCTION(4, "MD32_1_GPIO0"),
+ MTK_FUNCTION(5, "USB_DRVVBUS_3P")
+ ),
+
+ MTK_PIN(
+ 27, "GPIO27",
+ MTK_EINT_FUNCTION(0, 27),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO27"),
+ MTK_FUNCTION(1, "DP_TX_HPD"),
+ MTK_FUNCTION(2, "mbistreaden_trigger"),
+ MTK_FUNCTION(3, "MD32_0_GPIO0"),
+ MTK_FUNCTION(4, "TP_UCTS1_VCORE"),
+ MTK_FUNCTION(5, "CMVREF4"),
+ MTK_FUNCTION(6, "EXTIF0_ACT"),
+ MTK_FUNCTION(7, "ANT_SEL0")
+ ),
+
+ MTK_PIN(
+ 28, "GPIO28",
+ MTK_EINT_FUNCTION(0, 28),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO28"),
+ MTK_FUNCTION(1, "EDP_TX_HPD"),
+ MTK_FUNCTION(2, "mbistwriteen_trigger"),
+ MTK_FUNCTION(3, "MD32_1_GPIO0"),
+ MTK_FUNCTION(4, "TP_URTS1_VCORE"),
+ MTK_FUNCTION(6, "EXTIF0_PRI"),
+ MTK_FUNCTION(7, "ANT_SEL1")
+ ),
+
+ MTK_PIN(
+ 29, "GPIO29",
+ MTK_EINT_FUNCTION(0, 29),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO29"),
+ MTK_FUNCTION(1, "DISP_PWM0"),
+ MTK_FUNCTION(2, "MD32_1_TXD"),
+ MTK_FUNCTION(3, "SSPM_UTXD_AO_VCORE"),
+ MTK_FUNCTION(5, "USB_DRVVBUS_4P")
+ ),
+
+ MTK_PIN(
+ 30, "GPIO30",
+ MTK_EINT_FUNCTION(0, 30),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO30"),
+ MTK_FUNCTION(1, "DISP_PWM1"),
+ MTK_FUNCTION(2, "MD32_1_RXD"),
+ MTK_FUNCTION(3, "SSPM_URXD_AO_VCORE"),
+ MTK_FUNCTION(5, "PMSR_SMAP"),
+ MTK_FUNCTION(6, "EXTIF0_GNT_B"),
+ MTK_FUNCTION(7, "ANT_SEL2")
+ ),
+
+ MTK_PIN(
+ 31, "GPIO31",
+ MTK_EINT_FUNCTION(0, 31),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO31"),
+ MTK_FUNCTION(1, "UTXD0"),
+ MTK_FUNCTION(2, "MD32_0_TXD")
+ ),
+
+ MTK_PIN(
+ 32, "GPIO32",
+ MTK_EINT_FUNCTION(0, 32),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO32"),
+ MTK_FUNCTION(1, "URXD0"),
+ MTK_FUNCTION(2, "MD32_0_RXD")
+ ),
+
+ MTK_PIN(
+ 33, "GPIO33",
+ MTK_EINT_FUNCTION(0, 33),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO33"),
+ MTK_FUNCTION(1, "UTXD1"),
+ MTK_FUNCTION(2, "VADSP_UTXD0"),
+ MTK_FUNCTION(3, "TP_UTXD1_VLP"),
+ MTK_FUNCTION(4, "MD32_1_TXD"),
+ MTK_FUNCTION(5, "CONN_BGF_UART0_TXD"),
+ MTK_FUNCTION(6, "CONN_WIFI_TXD")
+ ),
+
+ MTK_PIN(
+ 34, "GPIO34",
+ MTK_EINT_FUNCTION(0, 34),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO34"),
+ MTK_FUNCTION(1, "URXD1"),
+ MTK_FUNCTION(2, "VADSP_URXD0"),
+ MTK_FUNCTION(3, "TP_URXD1_VLP"),
+ MTK_FUNCTION(4, "MD32_1_RXD"),
+ MTK_FUNCTION(5, "CONN_BGF_UART0_RXD")
+ ),
+
+ MTK_PIN(
+ 35, "GPIO35",
+ MTK_EINT_FUNCTION(0, 35),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO35"),
+ MTK_FUNCTION(1, "UTXD2"),
+ MTK_FUNCTION(2, "UCTS1"),
+ MTK_FUNCTION(3, "TP_UCTS1_VLP"),
+ MTK_FUNCTION(4, "SSPM_UTXD_AO_VLP"),
+ MTK_FUNCTION(5, "VADSP_UTXD0"),
+ MTK_FUNCTION(6, "CONN_BT_TXD")
+ ),
+
+ MTK_PIN(
+ 36, "GPIO36",
+ MTK_EINT_FUNCTION(0, 36),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO36"),
+ MTK_FUNCTION(1, "URXD2"),
+ MTK_FUNCTION(2, "URTS1"),
+ MTK_FUNCTION(3, "TP_URTS1_VLP"),
+ MTK_FUNCTION(4, "SSPM_URXD_AO_VLP"),
+ MTK_FUNCTION(5, "VADSP_URXD0")
+ ),
+
+ MTK_PIN(
+ 37, "GPIO37",
+ MTK_EINT_FUNCTION(0, 37),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO37"),
+ MTK_FUNCTION(1, "UTXD3"),
+ MTK_FUNCTION(2, "UCTS0"),
+ MTK_FUNCTION(3, "TP_UTXD1_VCORE"),
+ MTK_FUNCTION(4, "SSPM_UTXD_AO_VCORE"),
+ MTK_FUNCTION(6, "MD32_0_TXD"),
+ MTK_FUNCTION(7, "CONN_BGF_UART0_TXD")
+ ),
+
+ MTK_PIN(
+ 38, "GPIO38",
+ MTK_EINT_FUNCTION(0, 38),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO38"),
+ MTK_FUNCTION(1, "URXD3"),
+ MTK_FUNCTION(2, "URTS0"),
+ MTK_FUNCTION(3, "TP_URXD1_VCORE"),
+ MTK_FUNCTION(4, "SSPM_URXD_AO_VCORE"),
+ MTK_FUNCTION(6, "MD32_0_RXD"),
+ MTK_FUNCTION(7, "CONN_BGF_UART0_RXD")
+ ),
+
+ MTK_PIN(
+ 39, "GPIO39",
+ MTK_EINT_FUNCTION(0, 39),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO39"),
+ MTK_FUNCTION(1, "JTMS_SEL1")
+ ),
+
+ MTK_PIN(
+ 40, "GPIO40",
+ MTK_EINT_FUNCTION(0, 40),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO40"),
+ MTK_FUNCTION(1, "JTCK_SEL1")
+ ),
+
+ MTK_PIN(
+ 41, "GPIO41",
+ MTK_EINT_FUNCTION(0, 41),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO41"),
+ MTK_FUNCTION(1, "JTDI_SEL1")
+ ),
+
+ MTK_PIN(
+ 42, "GPIO42",
+ MTK_EINT_FUNCTION(0, 42),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO42"),
+ MTK_FUNCTION(1, "JTDO_SEL1")
+ ),
+
+ MTK_PIN(
+ 43, "GPIO43",
+ MTK_EINT_FUNCTION(0, 43),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO43"),
+ MTK_FUNCTION(1, "JTRSTn_SEL1")
+ ),
+
+ MTK_PIN(
+ 44, "GPIO44",
+ MTK_EINT_FUNCTION(0, 44),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO44"),
+ MTK_FUNCTION(1, "KPCOL0")
+ ),
+
+ MTK_PIN(
+ 45, "GPIO45",
+ MTK_EINT_FUNCTION(0, 45),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO45"),
+ MTK_FUNCTION(1, "KPCOL1"),
+ MTK_FUNCTION(2, "TP_GPIO0_AO"),
+ MTK_FUNCTION(3, "SRCLKENAI1"),
+ MTK_FUNCTION(7, "DBG_MON_A31")
+ ),
+
+ MTK_PIN(
+ 46, "GPIO46",
+ MTK_EINT_FUNCTION(0, 46),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO46"),
+ MTK_FUNCTION(1, "KPROW0"),
+ MTK_FUNCTION(2, "TP_GPIO1_AO")
+ ),
+
+ MTK_PIN(
+ 47, "GPIO47",
+ MTK_EINT_FUNCTION(0, 47),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO47"),
+ MTK_FUNCTION(1, "KPROW1"),
+ MTK_FUNCTION(2, "TP_GPIO2_AO"),
+ MTK_FUNCTION(3, "SRCLKENAI0"),
+ MTK_FUNCTION(7, "DBG_MON_A32")
+ ),
+
+ MTK_PIN(
+ 48, "GPIO48",
+ MTK_EINT_FUNCTION(0, 48),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO48"),
+ MTK_FUNCTION(1, "WAKEN"),
+ MTK_FUNCTION(2, "TP_GPIO3_AO"),
+ MTK_FUNCTION(3, "SPMI_P_TRIG_FLAG")
+ ),
+
+ MTK_PIN(
+ 49, "GPIO49",
+ MTK_EINT_FUNCTION(0, 49),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO49"),
+ MTK_FUNCTION(1, "PERSTN"),
+ MTK_FUNCTION(2, "MD32_0_GPIO0"),
+ MTK_FUNCTION(3, "UFS_MPHY_SCL"),
+ MTK_FUNCTION(7, "ANT_SEL3")
+ ),
+
+ MTK_PIN(
+ 50, "GPIO50",
+ MTK_EINT_FUNCTION(0, 50),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO50"),
+ MTK_FUNCTION(1, "CLKREQN"),
+ MTK_FUNCTION(2, "MD32_1_GPIO0"),
+ MTK_FUNCTION(3, "UFS_MPHY_SDA"),
+ MTK_FUNCTION(7, "ANT_SEL4")
+ ),
+
+ MTK_PIN(
+ 51, "GPIO51",
+ MTK_EINT_FUNCTION(0, 51),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO51"),
+ MTK_FUNCTION(1, "SCP_SCL0"),
+ MTK_FUNCTION(2, "SCL0")
+ ),
+
+ MTK_PIN(
+ 52, "GPIO52",
+ MTK_EINT_FUNCTION(0, 52),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO52"),
+ MTK_FUNCTION(1, "SCP_SDA0"),
+ MTK_FUNCTION(2, "SDA0")
+ ),
+
+ MTK_PIN(
+ 53, "GPIO53",
+ MTK_EINT_FUNCTION(0, 53),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO53"),
+ MTK_FUNCTION(1, "SCP_SCL1"),
+ MTK_FUNCTION(2, "SCL1")
+ ),
+
+ MTK_PIN(
+ 54, "GPIO54",
+ MTK_EINT_FUNCTION(0, 54),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO54"),
+ MTK_FUNCTION(1, "SCP_SDA1"),
+ MTK_FUNCTION(2, "SDA1")
+ ),
+
+ MTK_PIN(
+ 55, "GPIO55",
+ MTK_EINT_FUNCTION(0, 55),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO55"),
+ MTK_FUNCTION(1, "SCL2"),
+ MTK_FUNCTION(2, "UFS_MPHY_SCL"),
+ MTK_FUNCTION(3, "SSUSB_U2SIF_SCL")
+ ),
+
+ MTK_PIN(
+ 56, "GPIO56",
+ MTK_EINT_FUNCTION(0, 56),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO56"),
+ MTK_FUNCTION(1, "SDA2"),
+ MTK_FUNCTION(2, "UFS_MPHY_SDA"),
+ MTK_FUNCTION(3, "SSUSB_U2SIF_SDA")
+ ),
+
+ MTK_PIN(
+ 57, "GPIO57",
+ MTK_EINT_FUNCTION(0, 57),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO57"),
+ MTK_FUNCTION(1, "SCL3"),
+ MTK_FUNCTION(2, "PCIE_PHY_I2C_SCL"),
+ MTK_FUNCTION(3, "SSUSB_U2SIF_SCL_1P")
+ ),
+
+ MTK_PIN(
+ 58, "GPIO58",
+ MTK_EINT_FUNCTION(0, 58),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO58"),
+ MTK_FUNCTION(1, "SDA3"),
+ MTK_FUNCTION(2, "PCIE_PHY_I2C_SDA"),
+ MTK_FUNCTION(3, "SSUSB_U2SIF_SDA_1P")
+ ),
+
+ MTK_PIN(
+ 59, "GPIO59",
+ MTK_EINT_FUNCTION(0, 59),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO59"),
+ MTK_FUNCTION(1, "SCL4"),
+ MTK_FUNCTION(2, "SSUSB_U3PHY_I2C_SCL")
+ ),
+
+ MTK_PIN(
+ 60, "GPIO60",
+ MTK_EINT_FUNCTION(0, 60),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO60"),
+ MTK_FUNCTION(1, "SDA4"),
+ MTK_FUNCTION(2, "SSUSB_U3PHY_I2C_SDA")
+ ),
+
+ MTK_PIN(
+ 61, "GPIO61",
+ MTK_EINT_FUNCTION(0, 61),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO61"),
+ MTK_FUNCTION(1, "SCL5"),
+ MTK_FUNCTION(2, "SSPXTP_U3PHY_I2C_SCL")
+ ),
+
+ MTK_PIN(
+ 62, "GPIO62",
+ MTK_EINT_FUNCTION(0, 62),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO62"),
+ MTK_FUNCTION(1, "SDA5"),
+ MTK_FUNCTION(2, "SSPXTP_U3PHY_I2C_SDA")
+ ),
+
+ MTK_PIN(
+ 63, "GPIO63",
+ MTK_EINT_FUNCTION(0, 63),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO63"),
+ MTK_FUNCTION(1, "SCL6")
+ ),
+
+ MTK_PIN(
+ 64, "GPIO64",
+ MTK_EINT_FUNCTION(0, 64),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO64"),
+ MTK_FUNCTION(1, "SDA6")
+ ),
+
+ MTK_PIN(
+ 65, "GPIO65",
+ MTK_EINT_FUNCTION(0, 65),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO65"),
+ MTK_FUNCTION(1, "SCL7")
+ ),
+
+ MTK_PIN(
+ 66, "GPIO66",
+ MTK_EINT_FUNCTION(0, 66),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO66"),
+ MTK_FUNCTION(1, "SDA7")
+ ),
+
+ MTK_PIN(
+ 67, "GPIO67",
+ MTK_EINT_FUNCTION(0, 67),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO67"),
+ MTK_FUNCTION(1, "SCL8")
+ ),
+
+ MTK_PIN(
+ 68, "GPIO68",
+ MTK_EINT_FUNCTION(0, 68),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO68"),
+ MTK_FUNCTION(1, "SDA8")
+ ),
+
+ MTK_PIN(
+ 69, "GPIO69",
+ MTK_EINT_FUNCTION(0, 69),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO69"),
+ MTK_FUNCTION(1, "SPIM0_CSB"),
+ MTK_FUNCTION(2, "SCP_SPI0_CS"),
+ MTK_FUNCTION(3, "SPM_JTAG_TMS_VCORE"),
+ MTK_FUNCTION(4, "VADSP_JTAG0_TMS"),
+ MTK_FUNCTION(5, "SPM_JTAG_TMS"),
+ MTK_FUNCTION(6, "SSPM_JTAG_TMS_VLP"),
+ MTK_FUNCTION(7, "SCP_JTAG0_TMS_VLP")
+ ),
+
+ MTK_PIN(
+ 70, "GPIO70",
+ MTK_EINT_FUNCTION(0, 70),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO70"),
+ MTK_FUNCTION(1, "SPIM0_CLK"),
+ MTK_FUNCTION(2, "SCP_SPI0_CK"),
+ MTK_FUNCTION(3, "SPM_JTAG_TCK_VCORE"),
+ MTK_FUNCTION(4, "VADSP_JTAG0_TCK"),
+ MTK_FUNCTION(5, "SPM_JTAG_TCK"),
+ MTK_FUNCTION(6, "SSPM_JTAG_TCK_VLP"),
+ MTK_FUNCTION(7, "SCP_JTAG0_TCK_VLP")
+ ),
+
+ MTK_PIN(
+ 71, "GPIO71",
+ MTK_EINT_FUNCTION(0, 71),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO71"),
+ MTK_FUNCTION(1, "SPIM0_MO"),
+ MTK_FUNCTION(2, "SCP_SPI0_MO"),
+ MTK_FUNCTION(3, "SPM_JTAG_TDI_VCORE"),
+ MTK_FUNCTION(4, "VADSP_JTAG0_TDI"),
+ MTK_FUNCTION(5, "SPM_JTAG_TDI"),
+ MTK_FUNCTION(6, "SSPM_JTAG_TDI_VLP"),
+ MTK_FUNCTION(7, "SCP_JTAG0_TDI_VLP")
+ ),
+
+ MTK_PIN(
+ 72, "GPIO72",
+ MTK_EINT_FUNCTION(0, 72),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO72"),
+ MTK_FUNCTION(1, "SPIM0_MI"),
+ MTK_FUNCTION(2, "SCP_SPI0_MI"),
+ MTK_FUNCTION(3, "SPM_JTAG_TDO_VCORE"),
+ MTK_FUNCTION(4, "VADSP_JTAG0_TDO"),
+ MTK_FUNCTION(5, "SPM_JTAG_TDO"),
+ MTK_FUNCTION(6, "SSPM_JTAG_TDO_VLP"),
+ MTK_FUNCTION(7, "SCP_JTAG0_TDO_VLP")
+ ),
+
+ MTK_PIN(
+ 73, "GPIO73",
+ MTK_EINT_FUNCTION(0, 73),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO73"),
+ MTK_FUNCTION(1, "SPIM1_CSB"),
+ MTK_FUNCTION(2, "SCP_SPI1_CS"),
+ MTK_FUNCTION(3, "SPM_JTAG_TRSTN_VCORE"),
+ MTK_FUNCTION(4, "VADSP_JTAG0_TRSTN"),
+ MTK_FUNCTION(5, "SPM_JTAG_TRSTN"),
+ MTK_FUNCTION(6, "SSPM_JTAG_TRSTN_VLP"),
+ MTK_FUNCTION(7, "SCP_JTAG0_TRSTN_VLP")
+ ),
+
+ MTK_PIN(
+ 74, "GPIO74",
+ MTK_EINT_FUNCTION(0, 74),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO74"),
+ MTK_FUNCTION(1, "SPIM1_CLK"),
+ MTK_FUNCTION(2, "SCP_SPI1_CK")
+ ),
+
+ MTK_PIN(
+ 75, "GPIO75",
+ MTK_EINT_FUNCTION(0, 75),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO75"),
+ MTK_FUNCTION(1, "SPIM1_MO"),
+ MTK_FUNCTION(2, "SCP_SPI1_MO")
+ ),
+
+ MTK_PIN(
+ 76, "GPIO76",
+ MTK_EINT_FUNCTION(0, 76),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO76"),
+ MTK_FUNCTION(1, "SPIM1_MI"),
+ MTK_FUNCTION(2, "SCP_SPI1_MI")
+ ),
+
+ MTK_PIN(
+ 77, "GPIO77",
+ MTK_EINT_FUNCTION(0, 77),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO77"),
+ MTK_FUNCTION(1, "SPIM2_CSB"),
+ MTK_FUNCTION(2, "PCM0_SYNC"),
+ MTK_FUNCTION(3, "SSUSB_U2SIF_SCL"),
+ MTK_FUNCTION(7, "DBG_MON_A27")
+ ),
+
+ MTK_PIN(
+ 78, "GPIO78",
+ MTK_EINT_FUNCTION(0, 78),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO78"),
+ MTK_FUNCTION(1, "SPIM2_CLK"),
+ MTK_FUNCTION(2, "PCM0_CLK"),
+ MTK_FUNCTION(3, "SSUSB_U2SIF_SDA"),
+ MTK_FUNCTION(7, "DBG_MON_A28")
+ ),
+
+ MTK_PIN(
+ 79, "GPIO79",
+ MTK_EINT_FUNCTION(0, 79),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO79"),
+ MTK_FUNCTION(1, "SPIM2_MO"),
+ MTK_FUNCTION(2, "PCM0_DO"),
+ MTK_FUNCTION(3, "SSUSB_U2SIF_SCL_1P"),
+ MTK_FUNCTION(7, "DBG_MON_A29")
+ ),
+
+ MTK_PIN(
+ 80, "GPIO80",
+ MTK_EINT_FUNCTION(0, 80),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO80"),
+ MTK_FUNCTION(1, "SPIM2_MI"),
+ MTK_FUNCTION(2, "PCM0_DI"),
+ MTK_FUNCTION(3, "SSUSB_U2SIF_SDA_1P"),
+ MTK_FUNCTION(7, "DBG_MON_A30")
+ ),
+
+ MTK_PIN(
+ 81, "GPIO81",
+ MTK_EINT_FUNCTION(0, 81),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO81"),
+ MTK_FUNCTION(1, "IDDIG"),
+ MTK_FUNCTION(7, "DBG_MON_B32")
+ ),
+
+ MTK_PIN(
+ 82, "GPIO82",
+ MTK_EINT_FUNCTION(0, 82),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO82"),
+ MTK_FUNCTION(1, "USB_DRVVBUS")
+ ),
+
+ MTK_PIN(
+ 83, "GPIO83",
+ MTK_EINT_FUNCTION(0, 83),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO83"),
+ MTK_FUNCTION(1, "VBUSVALID")
+ ),
+
+ MTK_PIN(
+ 84, "GPIO84",
+ MTK_EINT_FUNCTION(0, 84),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO84"),
+ MTK_FUNCTION(1, "USB_DRVVBUS_1P"),
+ MTK_FUNCTION(7, "DBG_MON_A16")
+ ),
+
+ MTK_PIN(
+ 85, "GPIO85",
+ MTK_EINT_FUNCTION(0, 85),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO85"),
+ MTK_FUNCTION(1, "USB_DRVVBUS_2P"),
+ MTK_FUNCTION(7, "DBG_MON_A17")
+ ),
+
+ MTK_PIN(
+ 86, "GPIO86",
+ MTK_EINT_FUNCTION(0, 86),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO86"),
+ MTK_FUNCTION(1, "USB_DRVVBUS_3P"),
+ MTK_FUNCTION(7, "DBG_MON_A18")
+ ),
+
+ MTK_PIN(
+ 87, "GPIO87",
+ MTK_EINT_FUNCTION(0, 87),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO87"),
+ MTK_FUNCTION(1, "USB_DRVVBUS_4P"),
+ MTK_FUNCTION(6, "CMVREF4"),
+ MTK_FUNCTION(7, "DBG_MON_A19")
+ ),
+
+ MTK_PIN(
+ 88, "GPIO88",
+ MTK_EINT_FUNCTION(0, 88),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO88"),
+ MTK_FUNCTION(1, "PWRAP_SPI0_CSN")
+ ),
+
+ MTK_PIN(
+ 89, "GPIO89",
+ MTK_EINT_FUNCTION(0, 89),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO89"),
+ MTK_FUNCTION(1, "PWRAP_SPI0_CK")
+ ),
+
+ MTK_PIN(
+ 90, "GPIO90",
+ MTK_EINT_FUNCTION(0, 90),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO90"),
+ MTK_FUNCTION(1, "PWRAP_SPI0_MO")
+ ),
+
+ MTK_PIN(
+ 91, "GPIO91",
+ MTK_EINT_FUNCTION(0, 91),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO91"),
+ MTK_FUNCTION(1, "PWRAP_SPI0_MI")
+ ),
+
+ MTK_PIN(
+ 92, "GPIO92",
+ MTK_EINT_FUNCTION(0, 92),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO92"),
+ MTK_FUNCTION(1, "SRCLKENA0")
+ ),
+
+ MTK_PIN(
+ 93, "GPIO93",
+ MTK_EINT_FUNCTION(0, 93),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO93"),
+ MTK_FUNCTION(1, "SRCLKENA1")
+ ),
+
+ MTK_PIN(
+ 94, "GPIO94",
+ MTK_EINT_FUNCTION(0, 94),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO94"),
+ MTK_FUNCTION(1, "SCP_VREQ_VAO")
+ ),
+
+ MTK_PIN(
+ 95, "GPIO95",
+ MTK_EINT_FUNCTION(0, 95),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO95"),
+ MTK_FUNCTION(1, "RTC32K_CK")
+ ),
+
+ MTK_PIN(
+ 96, "GPIO96",
+ MTK_EINT_FUNCTION(0, 96),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO96"),
+ MTK_FUNCTION(1, "WATCHDOG")
+ ),
+
+ MTK_PIN(
+ 97, "GPIO97",
+ MTK_EINT_FUNCTION(0, 97),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO97"),
+ MTK_FUNCTION(1, "AUD_CLK_MOSI")
+ ),
+
+ MTK_PIN(
+ 98, "GPIO98",
+ MTK_EINT_FUNCTION(0, 98),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO98"),
+ MTK_FUNCTION(1, "AUD_SYNC_MOSI")
+ ),
+
+ MTK_PIN(
+ 99, "GPIO99",
+ MTK_EINT_FUNCTION(0, 99),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO99"),
+ MTK_FUNCTION(1, "AUD_DAT_MOSI0")
+ ),
+
+ MTK_PIN(
+ 100, "GPIO100",
+ MTK_EINT_FUNCTION(0, 100),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO100"),
+ MTK_FUNCTION(1, "AUD_DAT_MOSI1")
+ ),
+
+ MTK_PIN(
+ 101, "GPIO101",
+ MTK_EINT_FUNCTION(0, 101),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO101"),
+ MTK_FUNCTION(1, "AUD_DAT_MISO0")
+ ),
+
+ MTK_PIN(
+ 102, "GPIO102",
+ MTK_EINT_FUNCTION(0, 102),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO102"),
+ MTK_FUNCTION(1, "AUD_DAT_MISO1")
+ ),
+
+ MTK_PIN(
+ 103, "GPIO103",
+ MTK_EINT_FUNCTION(0, 103),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO103"),
+ MTK_FUNCTION(1, "I2SIN0_MCK"),
+ MTK_FUNCTION(2, "SPIM3_B_CSB"),
+ MTK_FUNCTION(3, "APU_JTAG_TMS"),
+ MTK_FUNCTION(4, "SCP_JTAG0_TMS_VCORE"),
+ MTK_FUNCTION(5, "CONN_WF_MCU_TMS"),
+ MTK_FUNCTION(6, "SSPM_JTAG_TMS_VCORE"),
+ MTK_FUNCTION(7, "IPU_JTAG_TMS")
+ ),
+
+ MTK_PIN(
+ 104, "GPIO104",
+ MTK_EINT_FUNCTION(0, 104),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO104"),
+ MTK_FUNCTION(1, "I2SIN0_BCK"),
+ MTK_FUNCTION(2, "SPIM3_B_CLK"),
+ MTK_FUNCTION(3, "APU_JTAG_TCK"),
+ MTK_FUNCTION(4, "SCP_JTAG0_TCK_VCORE"),
+ MTK_FUNCTION(5, "CONN_WF_MCU_TCK"),
+ MTK_FUNCTION(6, "SSPM_JTAG_TCK_VCORE"),
+ MTK_FUNCTION(7, "IPU_JTAG_TCK")
+ ),
+
+ MTK_PIN(
+ 105, "GPIO105",
+ MTK_EINT_FUNCTION(0, 105),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO105"),
+ MTK_FUNCTION(1, "I2SIN0_LRCK"),
+ MTK_FUNCTION(2, "SPIM3_B_MO"),
+ MTK_FUNCTION(3, "APU_JTAG_TDI"),
+ MTK_FUNCTION(4, "SCP_JTAG0_TDI_VCORE"),
+ MTK_FUNCTION(5, "CONN_WF_MCU_TDI"),
+ MTK_FUNCTION(6, "SSPM_JTAG_TDI_VCORE"),
+ MTK_FUNCTION(7, "IPU_JTAG_TDI")
+ ),
+
+ MTK_PIN(
+ 106, "GPIO106",
+ MTK_EINT_FUNCTION(0, 106),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO106"),
+ MTK_FUNCTION(1, "I2SIN0_DI"),
+ MTK_FUNCTION(2, "SPIM3_B_MI"),
+ MTK_FUNCTION(3, "APU_JTAG_TDO"),
+ MTK_FUNCTION(4, "SCP_JTAG0_TDO_VCORE"),
+ MTK_FUNCTION(5, "CONN_WF_MCU_TDO"),
+ MTK_FUNCTION(6, "SSPM_JTAG_TDO_VCORE"),
+ MTK_FUNCTION(7, "IPU_JTAG_TDO")
+ ),
+
+ MTK_PIN(
+ 107, "GPIO107",
+ MTK_EINT_FUNCTION(0, 107),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO107"),
+ MTK_FUNCTION(1, "I2SOUT0_MCK"),
+ MTK_FUNCTION(2, "SPIM4_B_CSB"),
+ MTK_FUNCTION(3, "APU_JTAG_TRST"),
+ MTK_FUNCTION(4, "SCP_JTAG0_TRSTN_VCORE"),
+ MTK_FUNCTION(5, "CONN_WF_MCU_TRST_B"),
+ MTK_FUNCTION(6, "SSPM_JTAG_TRSTN_VCORE"),
+ MTK_FUNCTION(7, "IPU_JTAG_TRST")
+ ),
+
+ MTK_PIN(
+ 108, "GPIO108",
+ MTK_EINT_FUNCTION(0, 108),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO108"),
+ MTK_FUNCTION(1, "I2SOUT0_BCK"),
+ MTK_FUNCTION(2, "SPIM4_B_CLK"),
+ MTK_FUNCTION(3, "EXTIF0_ACT"),
+ MTK_FUNCTION(4, "SPM_JTAG_TMS_VCORE"),
+ MTK_FUNCTION(6, "CLKM2"),
+ MTK_FUNCTION(7, "DBG_MON_A20")
+ ),
+
+ MTK_PIN(
+ 109, "GPIO109",
+ MTK_EINT_FUNCTION(0, 109),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO109"),
+ MTK_FUNCTION(1, "I2SOUT0_LRCK"),
+ MTK_FUNCTION(2, "SPIM4_B_MO"),
+ MTK_FUNCTION(3, "EXTIF0_PRI"),
+ MTK_FUNCTION(4, "SPM_JTAG_TCK_VCORE"),
+ MTK_FUNCTION(6, "CLKM3"),
+ MTK_FUNCTION(7, "DBG_MON_A21")
+ ),
+
+ MTK_PIN(
+ 110, "GPIO110",
+ MTK_EINT_FUNCTION(0, 110),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO110"),
+ MTK_FUNCTION(1, "I2SOUT0_DO"),
+ MTK_FUNCTION(2, "SPIM4_B_MI"),
+ MTK_FUNCTION(3, "EXTIF0_GNT_B"),
+ MTK_FUNCTION(4, "SPM_JTAG_TDI_VCORE"),
+ MTK_FUNCTION(7, "DBG_MON_A22")
+ ),
+
+ MTK_PIN(
+ 111, "GPIO111",
+ MTK_EINT_FUNCTION(0, 111),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO111"),
+ MTK_FUNCTION(1, "DMIC0_CLK"),
+ MTK_FUNCTION(2, "I2SIN1_MCK"),
+ MTK_FUNCTION(3, "I2SOUT1_MCK"),
+ MTK_FUNCTION(4, "SPM_JTAG_TDO_VCORE"),
+ MTK_FUNCTION(6, "CONN_MIPI0_SDATA"),
+ MTK_FUNCTION(7, "DBG_MON_A23")
+ ),
+
+ MTK_PIN(
+ 112, "GPIO112",
+ MTK_EINT_FUNCTION(0, 112),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO112"),
+ MTK_FUNCTION(1, "DMIC0_DAT0"),
+ MTK_FUNCTION(2, "I2SIN1_BCK"),
+ MTK_FUNCTION(3, "I2SOUT1_BCK"),
+ MTK_FUNCTION(4, "SPM_JTAG_TRSTN_VCORE"),
+ MTK_FUNCTION(6, "CONN_MIPI0_SCLK"),
+ MTK_FUNCTION(7, "DBG_MON_A24")
+ ),
+
+ MTK_PIN(
+ 113, "GPIO113",
+ MTK_EINT_FUNCTION(0, 113),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO113"),
+ MTK_FUNCTION(1, "DMIC1_CLK"),
+ MTK_FUNCTION(2, "I2SIN1_LRCK"),
+ MTK_FUNCTION(3, "I2SOUT1_LRCK"),
+ MTK_FUNCTION(4, "PMSR_SMAP"),
+ MTK_FUNCTION(6, "CONN_MIPI1_SDATA"),
+ MTK_FUNCTION(7, "DBG_MON_A25")
+ ),
+
+ MTK_PIN(
+ 114, "GPIO114",
+ MTK_EINT_FUNCTION(0, 114),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO114"),
+ MTK_FUNCTION(1, "DMIC1_DAT0"),
+ MTK_FUNCTION(2, "I2SIN1_DI"),
+ MTK_FUNCTION(3, "I2SOUT1_DO"),
+ MTK_FUNCTION(6, "CONN_MIPI1_SCLK"),
+ MTK_FUNCTION(7, "DBG_MON_A26")
+ ),
+
+ MTK_PIN(
+ 115, "GPIO115",
+ MTK_EINT_FUNCTION(0, 115),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO115"),
+ MTK_FUNCTION(1, "PCM0_CLK"),
+ MTK_FUNCTION(2, "USB_DRVVBUS_1P"),
+ MTK_FUNCTION(3, "PCIE_PHY_I2C_SCL"),
+ MTK_FUNCTION(4, "SSUSB_U3PHY_I2C_SCL"),
+ MTK_FUNCTION(6, "CMFLASH0"),
+ MTK_FUNCTION(7, "EXTIF0_ACT")
+ ),
+
+ MTK_PIN(
+ 116, "GPIO116",
+ MTK_EINT_FUNCTION(0, 116),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO116"),
+ MTK_FUNCTION(1, "PCM0_SYNC"),
+ MTK_FUNCTION(2, "USB_DRVVBUS_2P"),
+ MTK_FUNCTION(3, "PCIE_PHY_I2C_SDA"),
+ MTK_FUNCTION(4, "SSUSB_U3PHY_I2C_SDA"),
+ MTK_FUNCTION(6, "CMFLASH1"),
+ MTK_FUNCTION(7, "EXTIF0_PRI")
+ ),
+
+ MTK_PIN(
+ 117, "GPIO117",
+ MTK_EINT_FUNCTION(0, 117),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO117"),
+ MTK_FUNCTION(1, "PCM0_DI"),
+ MTK_FUNCTION(2, "USB_DRVVBUS_3P"),
+ MTK_FUNCTION(3, "DP_TX_HPD"),
+ MTK_FUNCTION(4, "SSPXTP_U3PHY_I2C_SCL"),
+ MTK_FUNCTION(6, "CMVREF0"),
+ MTK_FUNCTION(7, "EXTIF0_GNT_B")
+ ),
+
+ MTK_PIN(
+ 118, "GPIO118",
+ MTK_EINT_FUNCTION(0, 118),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO118"),
+ MTK_FUNCTION(1, "PCM0_DO"),
+ MTK_FUNCTION(2, "USB_DRVVBUS_4P"),
+ MTK_FUNCTION(3, "EDP_TX_HPD"),
+ MTK_FUNCTION(4, "SSPXTP_U3PHY_I2C_SDA"),
+ MTK_FUNCTION(6, "CMVREF1")
+ ),
+
+ MTK_PIN(
+ 119, "GPIO119",
+ MTK_EINT_FUNCTION(0, 119),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO119"),
+ MTK_FUNCTION(1, "GBE_TXD3"),
+ MTK_FUNCTION(2, "DMIC0_CLK"),
+ MTK_FUNCTION(3, "LVTS_FOUT"),
+ MTK_FUNCTION(4, "CONN_BGF_MCU_TMS"),
+ MTK_FUNCTION(5, "UDI_TMS"),
+ MTK_FUNCTION(6, "ANT_SEL5"),
+ MTK_FUNCTION(7, "DBG_MON_B0")
+ ),
+
+ MTK_PIN(
+ 120, "GPIO120",
+ MTK_EINT_FUNCTION(0, 120),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO120"),
+ MTK_FUNCTION(1, "GBE_TXD2"),
+ MTK_FUNCTION(2, "DMIC0_DAT0"),
+ MTK_FUNCTION(3, "LVTS_SDO"),
+ MTK_FUNCTION(4, "CONN_BGF_MCU_TCK"),
+ MTK_FUNCTION(5, "UDI_TCK"),
+ MTK_FUNCTION(6, "ANT_SEL6"),
+ MTK_FUNCTION(7, "DBG_MON_B1")
+ ),
+
+ MTK_PIN(
+ 121, "GPIO121",
+ MTK_EINT_FUNCTION(0, 121),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO121"),
+ MTK_FUNCTION(1, "GBE_TXD1"),
+ MTK_FUNCTION(2, "DMIC0_DAT1"),
+ MTK_FUNCTION(3, "LVTS_26M"),
+ MTK_FUNCTION(4, "CONN_BGF_MCU_TDI"),
+ MTK_FUNCTION(5, "UDI_TDI"),
+ MTK_FUNCTION(6, "ANT_SEL7"),
+ MTK_FUNCTION(7, "DBG_MON_B2")
+ ),
+
+ MTK_PIN(
+ 122, "GPIO122",
+ MTK_EINT_FUNCTION(0, 122),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO122"),
+ MTK_FUNCTION(1, "GBE_TXD0"),
+ MTK_FUNCTION(2, "DMIC1_CLK"),
+ MTK_FUNCTION(3, "LVTS_SCF"),
+ MTK_FUNCTION(4, "CONN_BGF_MCU_TDO"),
+ MTK_FUNCTION(5, "UDI_TDO"),
+ MTK_FUNCTION(6, "ANT_SEL8"),
+ MTK_FUNCTION(7, "DBG_MON_B3")
+ ),
+
+ MTK_PIN(
+ 123, "GPIO123",
+ MTK_EINT_FUNCTION(0, 123),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO123"),
+ MTK_FUNCTION(1, "GBE_RXD3"),
+ MTK_FUNCTION(2, "DMIC1_DAT0"),
+ MTK_FUNCTION(3, "LVTS_SCK"),
+ MTK_FUNCTION(4, "CONN_BGF_MCU_TRST_B"),
+ MTK_FUNCTION(5, "UDI_NTRST"),
+ MTK_FUNCTION(6, "ANT_SEL9"),
+ MTK_FUNCTION(7, "DBG_MON_B4")
+ ),
+
+ MTK_PIN(
+ 124, "GPIO124",
+ MTK_EINT_FUNCTION(0, 124),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO124"),
+ MTK_FUNCTION(1, "GBE_RXD2"),
+ MTK_FUNCTION(2, "DMIC1_DAT1"),
+ MTK_FUNCTION(3, "LVTS_SDI"),
+ MTK_FUNCTION(4, "CONN_WF_MCU_TMS"),
+ MTK_FUNCTION(5, "SCP_JTAG0_TMS_VCORE"),
+ MTK_FUNCTION(6, "ANT_SEL10"),
+ MTK_FUNCTION(7, "DBG_MON_B5")
+ ),
+
+ MTK_PIN(
+ 125, "GPIO125",
+ MTK_EINT_FUNCTION(0, 125),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO125"),
+ MTK_FUNCTION(1, "GBE_RXD1"),
+ MTK_FUNCTION(2, "CLKM2"),
+ MTK_FUNCTION(4, "CONN_WF_MCU_TCK"),
+ MTK_FUNCTION(5, "SCP_JTAG0_TCK_VCORE"),
+ MTK_FUNCTION(6, "ANT_SEL11"),
+ MTK_FUNCTION(7, "DBG_MON_B6")
+ ),
+
+ MTK_PIN(
+ 126, "GPIO126",
+ MTK_EINT_FUNCTION(0, 126),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO126"),
+ MTK_FUNCTION(1, "GBE_RXD0"),
+ MTK_FUNCTION(2, "CLKM3"),
+ MTK_FUNCTION(4, "CONN_WF_MCU_TDI"),
+ MTK_FUNCTION(5, "SCP_JTAG0_TDI_VCORE"),
+ MTK_FUNCTION(6, "ANT_SEL12"),
+ MTK_FUNCTION(7, "DBG_MON_B7")
+ ),
+
+ MTK_PIN(
+ 127, "GPIO127",
+ MTK_EINT_FUNCTION(0, 127),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO127"),
+ MTK_FUNCTION(1, "GBE_TXC"),
+ MTK_FUNCTION(2, "I2SIN1_MCK"),
+ MTK_FUNCTION(4, "CONN_WF_MCU_TDO"),
+ MTK_FUNCTION(5, "SCP_JTAG0_TDO_VCORE"),
+ MTK_FUNCTION(6, "ANT_SEL13"),
+ MTK_FUNCTION(7, "DBG_MON_B8")
+ ),
+
+ MTK_PIN(
+ 128, "GPIO128",
+ MTK_EINT_FUNCTION(0, 128),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO128"),
+ MTK_FUNCTION(1, "GBE_RXC"),
+ MTK_FUNCTION(2, "I2SIN1_BCK"),
+ MTK_FUNCTION(4, "CONN_WF_MCU_TRST_B"),
+ MTK_FUNCTION(5, "SCP_JTAG0_TRSTN_VCORE"),
+ MTK_FUNCTION(6, "ANT_SEL14"),
+ MTK_FUNCTION(7, "DBG_MON_B9")
+ ),
+
+ MTK_PIN(
+ 129, "GPIO129",
+ MTK_EINT_FUNCTION(0, 129),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO129"),
+ MTK_FUNCTION(1, "GBE_RXDV"),
+ MTK_FUNCTION(2, "I2SIN1_LRCK"),
+ MTK_FUNCTION(4, "CONN_BGF_MCU_AICE_TMSC"),
+ MTK_FUNCTION(5, "IPU_JTAG_TMS"),
+ MTK_FUNCTION(6, "ANT_SEL15"),
+ MTK_FUNCTION(7, "DBG_MON_B10")
+ ),
+
+ MTK_PIN(
+ 130, "GPIO130",
+ MTK_EINT_FUNCTION(0, 130),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO130"),
+ MTK_FUNCTION(1, "GBE_TXEN"),
+ MTK_FUNCTION(2, "I2SIN1_DI"),
+ MTK_FUNCTION(4, "CONN_BGF_MCU_AICE_TCKC"),
+ MTK_FUNCTION(5, "IPU_JTAG_TCK"),
+ MTK_FUNCTION(6, "ANT_SEL16"),
+ MTK_FUNCTION(7, "DBG_MON_B11")
+ ),
+
+ MTK_PIN(
+ 131, "GPIO131",
+ MTK_EINT_FUNCTION(0, 131),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO131"),
+ MTK_FUNCTION(1, "GBE_MDC"),
+ MTK_FUNCTION(2, "CLKM0"),
+ MTK_FUNCTION(3, "mbistreaden_trigger"),
+ MTK_FUNCTION(4, "CONN_BGF_UART0_TXD"),
+ MTK_FUNCTION(5, "IPU_JTAG_TDI"),
+ MTK_FUNCTION(6, "ANT_SEL17"),
+ MTK_FUNCTION(7, "DBG_MON_B12")
+ ),
+
+ MTK_PIN(
+ 132, "GPIO132",
+ MTK_EINT_FUNCTION(0, 132),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO132"),
+ MTK_FUNCTION(1, "GBE_MDIO"),
+ MTK_FUNCTION(2, "CLKM1"),
+ MTK_FUNCTION(3, "mbistwriteen_trigger"),
+ MTK_FUNCTION(4, "CONN_BGF_UART0_RXD"),
+ MTK_FUNCTION(5, "IPU_JTAG_TDO"),
+ MTK_FUNCTION(6, "ANT_SEL18"),
+ MTK_FUNCTION(7, "DBG_MON_B13")
+ ),
+
+ MTK_PIN(
+ 133, "GPIO133",
+ MTK_EINT_FUNCTION(0, 133),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO133"),
+ MTK_FUNCTION(1, "GBE_TXER"),
+ MTK_FUNCTION(2, "GBE_AUX_PPS2"),
+ MTK_FUNCTION(4, "CONN_BT_TXD"),
+ MTK_FUNCTION(5, "IPU_JTAG_TRST"),
+ MTK_FUNCTION(6, "ANT_SEL19"),
+ MTK_FUNCTION(7, "DBG_MON_B14")
+ ),
+
+ MTK_PIN(
+ 134, "GPIO134",
+ MTK_EINT_FUNCTION(0, 134),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO134"),
+ MTK_FUNCTION(1, "GBE_RXER"),
+ MTK_FUNCTION(2, "GBE_AUX_PPS3"),
+ MTK_FUNCTION(3, "MCUPM_JTAG_TMS"),
+ MTK_FUNCTION(4, "CONN_WF_MCU_AICE_TMSC"),
+ MTK_FUNCTION(5, "APU_JTAG_TMS"),
+ MTK_FUNCTION(6, "ANT_SEL20"),
+ MTK_FUNCTION(7, "DBG_MON_B15")
+ ),
+
+ MTK_PIN(
+ 135, "GPIO135",
+ MTK_EINT_FUNCTION(0, 135),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO135"),
+ MTK_FUNCTION(1, "GBE_COL"),
+ MTK_FUNCTION(2, "I2SOUT1_MCK"),
+ MTK_FUNCTION(3, "MCUPM_JTAG_TCK"),
+ MTK_FUNCTION(4, "CONN_WF_MCU_AICE_TCKC"),
+ MTK_FUNCTION(5, "APU_JTAG_TCK"),
+ MTK_FUNCTION(6, "ANT_SEL21"),
+ MTK_FUNCTION(7, "DBG_MON_B16")
+ ),
+
+ MTK_PIN(
+ 136, "GPIO136",
+ MTK_EINT_FUNCTION(0, 136),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO136"),
+ MTK_FUNCTION(1, "GBE_INTR"),
+ MTK_FUNCTION(2, "I2SOUT1_BCK"),
+ MTK_FUNCTION(3, "MCUPM_JTAG_TDI"),
+ MTK_FUNCTION(4, "CONN_WIFI_TXD"),
+ MTK_FUNCTION(5, "APU_JTAG_TDI"),
+ MTK_FUNCTION(6, "PWM_0"),
+ MTK_FUNCTION(7, "DBG_MON_B17")
+ ),
+
+ MTK_PIN(
+ 137, "GPIO137",
+ MTK_EINT_FUNCTION(0, 137),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO137"),
+ MTK_FUNCTION(1, "GBE_AUX_PPS0"),
+ MTK_FUNCTION(2, "I2SOUT1_LRCK"),
+ MTK_FUNCTION(3, "MCUPM_JTAG_TDO"),
+ MTK_FUNCTION(4, "DP_TX_HPD"),
+ MTK_FUNCTION(5, "APU_JTAG_TDO"),
+ MTK_FUNCTION(6, "PWM_1"),
+ MTK_FUNCTION(7, "DBG_MON_B18")
+ ),
+
+ MTK_PIN(
+ 138, "GPIO138",
+ MTK_EINT_FUNCTION(0, 138),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO138"),
+ MTK_FUNCTION(1, "GBE_AUX_PPS1"),
+ MTK_FUNCTION(2, "I2SOUT1_DO"),
+ MTK_FUNCTION(3, "MCUPM_JTAG_TRSTN"),
+ MTK_FUNCTION(4, "EDP_TX_HPD"),
+ MTK_FUNCTION(5, "APU_JTAG_TRST"),
+ MTK_FUNCTION(6, "PWM_2"),
+ MTK_FUNCTION(7, "DBG_MON_B19")
+ ),
+
+ MTK_PIN(
+ 139, "GPIO139",
+ MTK_EINT_FUNCTION(0, 139),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO139"),
+ MTK_FUNCTION(1, "CONN_TOP_CLK")
+ ),
+
+ MTK_PIN(
+ 140, "GPIO140",
+ MTK_EINT_FUNCTION(0, 140),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO140"),
+ MTK_FUNCTION(1, "CONN_TOP_DATA")
+ ),
+
+ MTK_PIN(
+ 141, "GPIO141",
+ MTK_EINT_FUNCTION(0, 141),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO141"),
+ MTK_FUNCTION(1, "CONN_BT_CLK")
+ ),
+
+ MTK_PIN(
+ 142, "GPIO142",
+ MTK_EINT_FUNCTION(0, 142),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO142"),
+ MTK_FUNCTION(1, "CONN_BT_DATA")
+ ),
+
+ MTK_PIN(
+ 143, "GPIO143",
+ MTK_EINT_FUNCTION(0, 143),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO143"),
+ MTK_FUNCTION(1, "CONN_HRST_B")
+ ),
+
+ MTK_PIN(
+ 144, "GPIO144",
+ MTK_EINT_FUNCTION(0, 144),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO144"),
+ MTK_FUNCTION(1, "CONN_WB_PTA")
+ ),
+
+ MTK_PIN(
+ 145, "GPIO145",
+ MTK_EINT_FUNCTION(0, 145),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO145"),
+ MTK_FUNCTION(1, "CONN_WF_CTRL0")
+ ),
+
+ MTK_PIN(
+ 146, "GPIO146",
+ MTK_EINT_FUNCTION(0, 146),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO146"),
+ MTK_FUNCTION(1, "CONN_WF_CTRL1")
+ ),
+
+ MTK_PIN(
+ 147, "GPIO147",
+ MTK_EINT_FUNCTION(0, 147),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO147"),
+ MTK_FUNCTION(1, "CONN_WF_CTRL2")
+ ),
+
+ MTK_PIN(
+ 148, "GPIO148",
+ MTK_EINT_FUNCTION(0, 148),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO148"),
+ MTK_FUNCTION(1, "CONN_WF_CTRL3")
+ ),
+
+ MTK_PIN(
+ 149, "GPIO149",
+ MTK_EINT_FUNCTION(0, 149),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO149"),
+ MTK_FUNCTION(1, "CONN_WF_CTRL4")
+ ),
+
+ MTK_PIN(
+ 150, "GPIO150",
+ MTK_EINT_FUNCTION(0, 150),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO150"),
+ MTK_FUNCTION(1, "SPINOR_CK"),
+ MTK_FUNCTION(2, "DMIC0_CLK"),
+ MTK_FUNCTION(3, "DP_TX_HPD"),
+ MTK_FUNCTION(4, "PWM_0"),
+ MTK_FUNCTION(5, "CONN_BPI_BUS17_ANT0"),
+ MTK_FUNCTION(6, "LVTS_FOUT"),
+ MTK_FUNCTION(7, "DBG_MON_B26")
+ ),
+
+ MTK_PIN(
+ 151, "GPIO151",
+ MTK_EINT_FUNCTION(0, 151),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO151"),
+ MTK_FUNCTION(1, "SPINOR_CS"),
+ MTK_FUNCTION(2, "DMIC0_DAT0"),
+ MTK_FUNCTION(3, "EDP_TX_HPD"),
+ MTK_FUNCTION(4, "PWM_1"),
+ MTK_FUNCTION(5, "CONN_BPI_BUS18_ANT1"),
+ MTK_FUNCTION(6, "LVTS_SDO"),
+ MTK_FUNCTION(7, "DBG_MON_B27")
+ ),
+
+ MTK_PIN(
+ 152, "GPIO152",
+ MTK_EINT_FUNCTION(0, 152),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO152"),
+ MTK_FUNCTION(1, "SPINOR_IO0"),
+ MTK_FUNCTION(2, "DMIC0_DAT1"),
+ MTK_FUNCTION(3, "UTXD2"),
+ MTK_FUNCTION(4, "USB_DRVVBUS_1P"),
+ MTK_FUNCTION(5, "CONN_BPI_BUS19_ANT2"),
+ MTK_FUNCTION(6, "LVTS_26M"),
+ MTK_FUNCTION(7, "DBG_MON_B28")
+ ),
+
+ MTK_PIN(
+ 153, "GPIO153",
+ MTK_EINT_FUNCTION(0, 153),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO153"),
+ MTK_FUNCTION(1, "SPINOR_IO1"),
+ MTK_FUNCTION(2, "DMIC1_CLK"),
+ MTK_FUNCTION(3, "UCTS2"),
+ MTK_FUNCTION(4, "USB_DRVVBUS_2P"),
+ MTK_FUNCTION(5, "CONN_BPI_BUS20_ANT3"),
+ MTK_FUNCTION(6, "LVTS_SCF"),
+ MTK_FUNCTION(7, "DBG_MON_B29")
+ ),
+
+ MTK_PIN(
+ 154, "GPIO154",
+ MTK_EINT_FUNCTION(0, 154),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO154"),
+ MTK_FUNCTION(1, "SPINOR_IO2"),
+ MTK_FUNCTION(2, "DMIC1_DAT0"),
+ MTK_FUNCTION(3, "URTS2"),
+ MTK_FUNCTION(4, "USB_DRVVBUS_3P"),
+ MTK_FUNCTION(5, "CONN_BPI_BUS21_ANT4"),
+ MTK_FUNCTION(6, "LVTS_SCK"),
+ MTK_FUNCTION(7, "DBG_MON_B30")
+ ),
+
+ MTK_PIN(
+ 155, "GPIO155",
+ MTK_EINT_FUNCTION(0, 155),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO155"),
+ MTK_FUNCTION(1, "SPINOR_IO3"),
+ MTK_FUNCTION(2, "DMIC1_DAT1"),
+ MTK_FUNCTION(3, "URXD2"),
+ MTK_FUNCTION(4, "USB_DRVVBUS_4P"),
+ MTK_FUNCTION(5, "DISP_PWM1"),
+ MTK_FUNCTION(6, "LVTS_SDI"),
+ MTK_FUNCTION(7, "DBG_MON_B31")
+ ),
+
+ MTK_PIN(
+ 156, "GPIO156",
+ MTK_EINT_FUNCTION(0, 156),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO156"),
+ MTK_FUNCTION(1, "MSDC0_DAT7")
+ ),
+
+ MTK_PIN(
+ 157, "GPIO157",
+ MTK_EINT_FUNCTION(0, 157),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO157"),
+ MTK_FUNCTION(1, "MSDC0_DAT6")
+ ),
+
+ MTK_PIN(
+ 158, "GPIO158",
+ MTK_EINT_FUNCTION(0, 158),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO158"),
+ MTK_FUNCTION(1, "MSDC0_DAT5")
+ ),
+
+ MTK_PIN(
+ 159, "GPIO159",
+ MTK_EINT_FUNCTION(0, 159),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO159"),
+ MTK_FUNCTION(1, "MSDC0_DAT4")
+ ),
+
+ MTK_PIN(
+ 160, "GPIO160",
+ MTK_EINT_FUNCTION(0, 160),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO160"),
+ MTK_FUNCTION(1, "MSDC0_RSTB")
+ ),
+
+ MTK_PIN(
+ 161, "GPIO161",
+ MTK_EINT_FUNCTION(0, 161),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO161"),
+ MTK_FUNCTION(1, "MSDC0_CMD")
+ ),
+
+ MTK_PIN(
+ 162, "GPIO162",
+ MTK_EINT_FUNCTION(0, 162),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO162"),
+ MTK_FUNCTION(1, "MSDC0_CLK")
+ ),
+
+ MTK_PIN(
+ 163, "GPIO163",
+ MTK_EINT_FUNCTION(0, 163),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO163"),
+ MTK_FUNCTION(1, "MSDC0_DAT3")
+ ),
+
+ MTK_PIN(
+ 164, "GPIO164",
+ MTK_EINT_FUNCTION(0, 164),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO164"),
+ MTK_FUNCTION(1, "MSDC0_DAT2")
+ ),
+
+ MTK_PIN(
+ 165, "GPIO165",
+ MTK_EINT_FUNCTION(0, 165),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO165"),
+ MTK_FUNCTION(1, "MSDC0_DAT1")
+ ),
+
+ MTK_PIN(
+ 166, "GPIO166",
+ MTK_EINT_FUNCTION(0, 166),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO166"),
+ MTK_FUNCTION(1, "MSDC0_DAT0")
+ ),
+
+ MTK_PIN(
+ 167, "GPIO167",
+ MTK_EINT_FUNCTION(0, 167),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO167"),
+ MTK_FUNCTION(1, "MSDC0_DSL")
+ ),
+
+ MTK_PIN(
+ 168, "GPIO168",
+ MTK_EINT_FUNCTION(0, 168),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO168"),
+ MTK_FUNCTION(1, "MSDC1_CMD"),
+ MTK_FUNCTION(2, "CONN_WF_MCU_AICE_TMSC"),
+ MTK_FUNCTION(3, "UCTS1"),
+ MTK_FUNCTION(4, "UDI_TMS"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TMS_VCORE"),
+ MTK_FUNCTION(6, "MCUPM_JTAG_TMS"),
+ MTK_FUNCTION(7, "CONN_BGF_MCU_TMS")
+ ),
+
+ MTK_PIN(
+ 169, "GPIO169",
+ MTK_EINT_FUNCTION(0, 169),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO169"),
+ MTK_FUNCTION(1, "MSDC1_CLK"),
+ MTK_FUNCTION(2, "CONN_WF_MCU_AICE_TCKC"),
+ MTK_FUNCTION(3, "URTS1"),
+ MTK_FUNCTION(4, "UDI_TCK"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TCK_VCORE"),
+ MTK_FUNCTION(6, "MCUPM_JTAG_TCK"),
+ MTK_FUNCTION(7, "CONN_BGF_MCU_TCK")
+ ),
+
+ MTK_PIN(
+ 170, "GPIO170",
+ MTK_EINT_FUNCTION(0, 170),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO170"),
+ MTK_FUNCTION(1, "MSDC1_DAT0"),
+ MTK_FUNCTION(2, "SPIM5_B_CSB"),
+ MTK_FUNCTION(3, "UCTS2"),
+ MTK_FUNCTION(4, "UDI_TDI"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TDI_VCORE"),
+ MTK_FUNCTION(6, "MCUPM_JTAG_TDI"),
+ MTK_FUNCTION(7, "CONN_BGF_MCU_TDI")
+ ),
+
+ MTK_PIN(
+ 171, "GPIO171",
+ MTK_EINT_FUNCTION(0, 171),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO171"),
+ MTK_FUNCTION(1, "MSDC1_DAT1"),
+ MTK_FUNCTION(2, "SPIM5_B_CLK"),
+ MTK_FUNCTION(3, "URTS2"),
+ MTK_FUNCTION(4, "UDI_TDO"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TDO_VCORE"),
+ MTK_FUNCTION(6, "MCUPM_JTAG_TDO"),
+ MTK_FUNCTION(7, "CONN_BGF_MCU_TDO")
+ ),
+
+ MTK_PIN(
+ 172, "GPIO172",
+ MTK_EINT_FUNCTION(0, 172),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO172"),
+ MTK_FUNCTION(1, "MSDC1_DAT2"),
+ MTK_FUNCTION(2, "SPIM5_B_MO"),
+ MTK_FUNCTION(3, "UCTS3"),
+ MTK_FUNCTION(4, "UDI_NTRST"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TRSTN_VCORE"),
+ MTK_FUNCTION(6, "MCUPM_JTAG_TRSTN"),
+ MTK_FUNCTION(7, "CONN_BGF_MCU_TRST_B")
+ ),
+
+ MTK_PIN(
+ 173, "GPIO173",
+ MTK_EINT_FUNCTION(0, 173),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO173"),
+ MTK_FUNCTION(1, "MSDC1_DAT3"),
+ MTK_FUNCTION(2, "SPIM5_B_MI"),
+ MTK_FUNCTION(3, "URTS3"),
+ MTK_FUNCTION(4, "CLKM0"),
+ MTK_FUNCTION(5, "PWM_2")
+ ),
+
+ MTK_PIN(
+ 174, "GPIO174",
+ MTK_EINT_FUNCTION(0, 174),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO174"),
+ MTK_FUNCTION(1, "MSDC2_CMD"),
+ MTK_FUNCTION(2, "CONN_BGF_MCU_AICE_TMSC"),
+ MTK_FUNCTION(3, "UTXD1"),
+ MTK_FUNCTION(4, "VADSP_JTAG0_TMS"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TMS_VLP"),
+ MTK_FUNCTION(6, "SPM_JTAG_TMS"),
+ MTK_FUNCTION(7, "SCP_JTAG0_TMS_VLP")
+ ),
+
+ MTK_PIN(
+ 175, "GPIO175",
+ MTK_EINT_FUNCTION(0, 175),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO175"),
+ MTK_FUNCTION(1, "MSDC2_CLK"),
+ MTK_FUNCTION(2, "CONN_BGF_MCU_AICE_TCKC"),
+ MTK_FUNCTION(3, "URXD1"),
+ MTK_FUNCTION(4, "VADSP_JTAG0_TCK"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TCK_VLP"),
+ MTK_FUNCTION(6, "SPM_JTAG_TCK"),
+ MTK_FUNCTION(7, "SCP_JTAG0_TCK_VLP")
+ ),
+
+ MTK_PIN(
+ 176, "GPIO176",
+ MTK_EINT_FUNCTION(0, 176),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO176"),
+ MTK_FUNCTION(1, "MSDC2_DAT0"),
+ MTK_FUNCTION(2, "SRCLKENAI0"),
+ MTK_FUNCTION(3, "UTXD2"),
+ MTK_FUNCTION(4, "VADSP_JTAG0_TDI"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TDI_VLP"),
+ MTK_FUNCTION(6, "SPM_JTAG_TDI"),
+ MTK_FUNCTION(7, "SCP_JTAG0_TDI_VLP")
+ ),
+
+ MTK_PIN(
+ 177, "GPIO177",
+ MTK_EINT_FUNCTION(0, 177),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO177"),
+ MTK_FUNCTION(1, "MSDC2_DAT1"),
+ MTK_FUNCTION(2, "SRCLKENAI1"),
+ MTK_FUNCTION(3, "URXD2"),
+ MTK_FUNCTION(4, "VADSP_JTAG0_TDO"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TDO_VLP"),
+ MTK_FUNCTION(6, "SPM_JTAG_TDO"),
+ MTK_FUNCTION(7, "SCP_JTAG0_TDO_VLP")
+ ),
+
+ MTK_PIN(
+ 178, "GPIO178",
+ MTK_EINT_FUNCTION(0, 178),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO178"),
+ MTK_FUNCTION(1, "MSDC2_DAT2"),
+ MTK_FUNCTION(3, "UTXD3"),
+ MTK_FUNCTION(4, "VADSP_JTAG0_TRSTN"),
+ MTK_FUNCTION(5, "SSPM_JTAG_TRSTN_VLP"),
+ MTK_FUNCTION(6, "SPM_JTAG_TRSTN"),
+ MTK_FUNCTION(7, "SCP_JTAG0_TRSTN_VLP")
+ ),
+
+ MTK_PIN(
+ 179, "GPIO179",
+ MTK_EINT_FUNCTION(0, 179),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO179"),
+ MTK_FUNCTION(1, "MSDC2_DAT3"),
+ MTK_FUNCTION(3, "URXD3"),
+ MTK_FUNCTION(4, "CLKM1"),
+ MTK_FUNCTION(5, "PWM_vlp"),
+ MTK_FUNCTION(7, "TP_GPIO7_AO")
+ ),
+
+ MTK_PIN(
+ 180, "GPIO180",
+ MTK_EINT_FUNCTION(0, 180),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO180"),
+ MTK_FUNCTION(1, "SPMI_P_SCL")
+ ),
+
+ MTK_PIN(
+ 181, "GPIO181",
+ MTK_EINT_FUNCTION(0, 181),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO181"),
+ MTK_FUNCTION(1, "SPMI_P_SDA")
+ ),
+
+ MTK_PIN(
+ 182, "GPIO182",
+ MTK_EINT_FUNCTION(0, NO_EINT_SUPPORT),
+ DRV_GRP4,
+ MTK_FUNCTION(0, "GPIO182"),
+ MTK_FUNCTION(1, "DDR_PAD_RRESETB")
+ ),
+
+ MTK_PIN(
+ 183, "GPIO183",
+ MTK_EINT_FUNCTION(0, 182),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 184, "GPIO184",
+ MTK_EINT_FUNCTION(0, 183),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 185, "GPIO185",
+ MTK_EINT_FUNCTION(0, 184),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 186, "GPIO186",
+ MTK_EINT_FUNCTION(0, 185),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 187, "GPIO187",
+ MTK_EINT_FUNCTION(0, 186),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 188, "GPIO188",
+ MTK_EINT_FUNCTION(0, 187),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 189, "GPIO189",
+ MTK_EINT_FUNCTION(0, 188),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 190, "GPIO190",
+ MTK_EINT_FUNCTION(0, 189),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 191, "GPIO191",
+ MTK_EINT_FUNCTION(0, 190),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 192, "GPIO192",
+ MTK_EINT_FUNCTION(0, 191),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 193, "GPIO193",
+ MTK_EINT_FUNCTION(0, 192),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 194, "GPIO194",
+ MTK_EINT_FUNCTION(0, 193),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 195, "GPIO195",
+ MTK_EINT_FUNCTION(0, 194),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 196, "GPIO196",
+ MTK_EINT_FUNCTION(0, 195),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 197, "GPIO197",
+ MTK_EINT_FUNCTION(0, 196),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 198, "GPIO198",
+ MTK_EINT_FUNCTION(0, 197),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 199, "GPIO199",
+ MTK_EINT_FUNCTION(0, 198),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 200, "GPIO200",
+ MTK_EINT_FUNCTION(0, 199),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 201, "GPIO201",
+ MTK_EINT_FUNCTION(0, 200),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 202, "GPIO202",
+ MTK_EINT_FUNCTION(0, 201),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 203, "GPIO203",
+ MTK_EINT_FUNCTION(0, 202),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 204, "GPIO204",
+ MTK_EINT_FUNCTION(0, 203),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 205, "GPIO205",
+ MTK_EINT_FUNCTION(0, 204),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 206, "GPIO206",
+ MTK_EINT_FUNCTION(0, 205),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 207, "GPIO207",
+ MTK_EINT_FUNCTION(0, 206),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 208, "GPIO208",
+ MTK_EINT_FUNCTION(0, 207),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 209, "GPIO209",
+ MTK_EINT_FUNCTION(0, 208),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+ MTK_PIN(
+ 210, "GPIO210",
+ MTK_EINT_FUNCTION(0, 209),
+ DRV_FIXED,
+ MTK_FUNCTION(0, NULL)
+ ),
+
+};
+
+static struct mtk_eint_pin eint_pins_mt8189[] = {
+ MTK_EINT_PIN(0, 0, 0, 1),
+ MTK_EINT_PIN(1, 0, 1, 1),
+ MTK_EINT_PIN(2, 0, 2, 1),
+ MTK_EINT_PIN(3, 0, 3, 1),
+ MTK_EINT_PIN(4, 0, 4, 1),
+ MTK_EINT_PIN(5, 0, 5, 1),
+ MTK_EINT_PIN(6, 0, 6, 1),
+ MTK_EINT_PIN(7, 0, 7, 1),
+ MTK_EINT_PIN(8, 0, 8, 1),
+ MTK_EINT_PIN(9, 0, 9, 1),
+ MTK_EINT_PIN(10, 0, 10, 1),
+ MTK_EINT_PIN(11, 0, 11, 1),
+ MTK_EINT_PIN(12, 1, 0, 1),
+ MTK_EINT_PIN(13, 1, 1, 1),
+ MTK_EINT_PIN(14, 1, 2, 1),
+ MTK_EINT_PIN(15, 1, 3, 1),
+ MTK_EINT_PIN(16, 1, 4, 1),
+ MTK_EINT_PIN(17, 1, 5, 1),
+ MTK_EINT_PIN(18, 0, 12, 1),
+ MTK_EINT_PIN(19, 0, 13, 1),
+ MTK_EINT_PIN(20, 0, 14, 1),
+ MTK_EINT_PIN(21, 0, 15, 1),
+ MTK_EINT_PIN(22, 0, 16, 1),
+ MTK_EINT_PIN(23, 0, 17, 1),
+ MTK_EINT_PIN(24, 0, 18, 1),
+ MTK_EINT_PIN(25, 2, 0, 1),
+ MTK_EINT_PIN(26, 2, 1, 1),
+ MTK_EINT_PIN(27, 1, 6, 1),
+ MTK_EINT_PIN(28, 1, 7, 1),
+ MTK_EINT_PIN(29, 2, 2, 1),
+ MTK_EINT_PIN(30, 1, 8, 1),
+ MTK_EINT_PIN(31, 1, 9, 1),
+ MTK_EINT_PIN(32, 1, 10, 1),
+ MTK_EINT_PIN(33, 1, 11, 1),
+ MTK_EINT_PIN(34, 1, 12, 1),
+ MTK_EINT_PIN(35, 1, 13, 1),
+ MTK_EINT_PIN(36, 1, 14, 1),
+ MTK_EINT_PIN(37, 1, 15, 1),
+ MTK_EINT_PIN(38, 1, 16, 1),
+ MTK_EINT_PIN(39, 1, 17, 1),
+ MTK_EINT_PIN(40, 1, 18, 1),
+ MTK_EINT_PIN(41, 1, 19, 1),
+ MTK_EINT_PIN(42, 1, 20, 1),
+ MTK_EINT_PIN(43, 1, 21, 1),
+ MTK_EINT_PIN(44, 0, 19, 1),
+ MTK_EINT_PIN(45, 0, 20, 1),
+ MTK_EINT_PIN(46, 0, 21, 1),
+ MTK_EINT_PIN(47, 0, 22, 1),
+ MTK_EINT_PIN(48, 2, 3, 1),
+ MTK_EINT_PIN(49, 2, 4, 1),
+ MTK_EINT_PIN(50, 2, 5, 1),
+ MTK_EINT_PIN(51, 0, 23, 1),
+ MTK_EINT_PIN(52, 0, 24, 1),
+ MTK_EINT_PIN(53, 0, 25, 1),
+ MTK_EINT_PIN(54, 0, 26, 1),
+ MTK_EINT_PIN(55, 2, 6, 1),
+ MTK_EINT_PIN(56, 2, 7, 1),
+ MTK_EINT_PIN(57, 1, 22, 1),
+ MTK_EINT_PIN(58, 1, 23, 1),
+ MTK_EINT_PIN(59, 1, 24, 1),
+ MTK_EINT_PIN(60, 1, 25, 1),
+ MTK_EINT_PIN(61, 1, 26, 1),
+ MTK_EINT_PIN(62, 1, 27, 1),
+ MTK_EINT_PIN(63, 1, 28, 1),
+ MTK_EINT_PIN(64, 1, 29, 1),
+ MTK_EINT_PIN(65, 0, 27, 1),
+ MTK_EINT_PIN(66, 0, 28, 1),
+ MTK_EINT_PIN(67, 0, 29, 1),
+ MTK_EINT_PIN(68, 0, 30, 1),
+ MTK_EINT_PIN(69, 1, 30, 1),
+ MTK_EINT_PIN(70, 1, 31, 1),
+ MTK_EINT_PIN(71, 1, 32, 1),
+ MTK_EINT_PIN(72, 1, 33, 1),
+ MTK_EINT_PIN(73, 1, 34, 1),
+ MTK_EINT_PIN(74, 1, 35, 1),
+ MTK_EINT_PIN(75, 1, 36, 1),
+ MTK_EINT_PIN(76, 1, 37, 1),
+ MTK_EINT_PIN(77, 0, 31, 1),
+ MTK_EINT_PIN(78, 0, 32, 1),
+ MTK_EINT_PIN(79, 0, 33, 1),
+ MTK_EINT_PIN(80, 0, 34, 1),
+ MTK_EINT_PIN(81, 1, 38, 1),
+ MTK_EINT_PIN(82, 1, 39, 1),
+ MTK_EINT_PIN(83, 1, 40, 1),
+ MTK_EINT_PIN(84, 0, 35, 1),
+ MTK_EINT_PIN(85, 0, 36, 1),
+ MTK_EINT_PIN(86, 0, 37, 1),
+ MTK_EINT_PIN(87, 0, 38, 1),
+ MTK_EINT_PIN(88, 2, 8, 1),
+ MTK_EINT_PIN(89, 2, 9, 1),
+ MTK_EINT_PIN(90, 2, 10, 1),
+ MTK_EINT_PIN(91, 2, 11, 1),
+ MTK_EINT_PIN(92, 2, 12, 1),
+ MTK_EINT_PIN(93, 2, 13, 1),
+ MTK_EINT_PIN(94, 2, 14, 1),
+ MTK_EINT_PIN(95, 2, 15, 1),
+ MTK_EINT_PIN(96, 2, 16, 1),
+ MTK_EINT_PIN(97, 2, 17, 1),
+ MTK_EINT_PIN(98, 2, 18, 1),
+ MTK_EINT_PIN(99, 2, 19, 1),
+ MTK_EINT_PIN(100, 2, 20, 1),
+ MTK_EINT_PIN(101, 2, 21, 1),
+ MTK_EINT_PIN(102, 2, 22, 1),
+ MTK_EINT_PIN(103, 0, 39, 1),
+ MTK_EINT_PIN(104, 0, 40, 1),
+ MTK_EINT_PIN(105, 0, 41, 1),
+ MTK_EINT_PIN(106, 0, 42, 1),
+ MTK_EINT_PIN(107, 0, 43, 1),
+ MTK_EINT_PIN(108, 0, 44, 1),
+ MTK_EINT_PIN(109, 0, 45, 1),
+ MTK_EINT_PIN(110, 0, 46, 1),
+ MTK_EINT_PIN(111, 0, 47, 1),
+ MTK_EINT_PIN(112, 0, 48, 0),
+ MTK_EINT_PIN(113, 0, 49, 1),
+ MTK_EINT_PIN(114, 0, 50, 0),
+ MTK_EINT_PIN(115, 1, 41, 1),
+ MTK_EINT_PIN(116, 1, 42, 1),
+ MTK_EINT_PIN(117, 1, 43, 1),
+ MTK_EINT_PIN(118, 1, 44, 1),
+ MTK_EINT_PIN(119, 1, 45, 1),
+ MTK_EINT_PIN(120, 1, 46, 1),
+ MTK_EINT_PIN(121, 1, 47, 1),
+ MTK_EINT_PIN(122, 1, 48, 1),
+ MTK_EINT_PIN(123, 1, 49, 1),
+ MTK_EINT_PIN(124, 1, 50, 1),
+ MTK_EINT_PIN(125, 1, 51, 1),
+ MTK_EINT_PIN(126, 1, 52, 1),
+ MTK_EINT_PIN(127, 1, 53, 1),
+ MTK_EINT_PIN(128, 1, 54, 1),
+ MTK_EINT_PIN(129, 1, 55, 1),
+ MTK_EINT_PIN(130, 1, 56, 1),
+ MTK_EINT_PIN(131, 1, 57, 1),
+ MTK_EINT_PIN(132, 1, 58, 1),
+ MTK_EINT_PIN(133, 1, 59, 1),
+ MTK_EINT_PIN(134, 1, 60, 1),
+ MTK_EINT_PIN(135, 1, 61, 1),
+ MTK_EINT_PIN(136, 1, 62, 1),
+ MTK_EINT_PIN(137, 1, 63, 1),
+ MTK_EINT_PIN(138, 1, 64, 1),
+ MTK_EINT_PIN(139, 1, 65, 1),
+ MTK_EINT_PIN(140, 1, 66, 1),
+ MTK_EINT_PIN(141, 1, 67, 1),
+ MTK_EINT_PIN(142, 1, 68, 1),
+ MTK_EINT_PIN(143, 1, 69, 1),
+ MTK_EINT_PIN(144, 1, 70, 1),
+ MTK_EINT_PIN(145, 1, 71, 1),
+ MTK_EINT_PIN(146, 1, 72, 1),
+ MTK_EINT_PIN(147, 1, 73, 1),
+ MTK_EINT_PIN(148, 1, 74, 1),
+ MTK_EINT_PIN(149, 1, 75, 1),
+ MTK_EINT_PIN(150, 1, 76, 1),
+ MTK_EINT_PIN(151, 1, 77, 1),
+ MTK_EINT_PIN(152, 1, 78, 1),
+ MTK_EINT_PIN(153, 1, 79, 1),
+ MTK_EINT_PIN(154, 1, 80, 1),
+ MTK_EINT_PIN(155, 1, 81, 1),
+ MTK_EINT_PIN(156, 2, 23, 1),
+ MTK_EINT_PIN(157, 2, 24, 1),
+ MTK_EINT_PIN(158, 2, 25, 1),
+ MTK_EINT_PIN(159, 4, 0, 1),
+ MTK_EINT_PIN(160, 2, 26, 1),
+ MTK_EINT_PIN(161, 2, 27, 1),
+ MTK_EINT_PIN(162, 2, 28, 1),
+ MTK_EINT_PIN(163, 4, 1, 1),
+ MTK_EINT_PIN(164, 2, 29, 1),
+ MTK_EINT_PIN(165, 2, 30, 1),
+ MTK_EINT_PIN(166, 4, 2, 1),
+ MTK_EINT_PIN(167, 2, 31, 0),
+ MTK_EINT_PIN(168, 1, 82, 1),
+ MTK_EINT_PIN(169, 1, 83, 1),
+ MTK_EINT_PIN(170, 1, 84, 1),
+ MTK_EINT_PIN(171, 1, 85, 0),
+ MTK_EINT_PIN(172, 1, 86, 1),
+ MTK_EINT_PIN(173, 1, 87, 0),
+ MTK_EINT_PIN(174, 4, 3, 1),
+ MTK_EINT_PIN(175, 4, 4, 1),
+ MTK_EINT_PIN(176, 4, 5, 1),
+ MTK_EINT_PIN(177, 4, 6, 1),
+ MTK_EINT_PIN(178, 4, 7, 1),
+ MTK_EINT_PIN(179, 4, 8, 1),
+ MTK_EINT_PIN(180, 2, 32, 1),
+ MTK_EINT_PIN(181, 2, 33, 0),
+ MTK_EINT_PIN(182, 3, 0, 1),
+ MTK_EINT_PIN(183, 3, 1, 1),
+ MTK_EINT_PIN(184, 3, 2, 1),
+ MTK_EINT_PIN(185, 3, 3, 1),
+ MTK_EINT_PIN(186, 3, 4, 1),
+ MTK_EINT_PIN(187, 3, 5, 1),
+ MTK_EINT_PIN(188, 3, 6, 1),
+ MTK_EINT_PIN(189, 3, 7, 1),
+ MTK_EINT_PIN(190, 3, 8, 1),
+ MTK_EINT_PIN(191, 3, 9, 1),
+ MTK_EINT_PIN(192, 3, 10, 1),
+ MTK_EINT_PIN(193, 3, 11, 1),
+ MTK_EINT_PIN(194, 3, 12, 1),
+ MTK_EINT_PIN(195, 3, 13, 1),
+ MTK_EINT_PIN(196, 3, 14, 1),
+ MTK_EINT_PIN(197, 3, 15, 1),
+ MTK_EINT_PIN(198, 3, 16, 1),
+ MTK_EINT_PIN(199, 3, 17, 1),
+ MTK_EINT_PIN(200, 3, 18, 1),
+ MTK_EINT_PIN(201, 3, 19, 1),
+ MTK_EINT_PIN(202, 3, 20, 1),
+ MTK_EINT_PIN(203, 3, 21, 1),
+ MTK_EINT_PIN(204, 3, 22, 1),
+ MTK_EINT_PIN(205, 3, 23, 1),
+ MTK_EINT_PIN(206, 3, 24, 1),
+ MTK_EINT_PIN(207, 3, 25, 1),
+ MTK_EINT_PIN(208, 3, 26, 1),
+ MTK_EINT_PIN(209, 3, 27, 1)
+};
+
+#endif /* __PINCTRL_MTK_MT8189_H */
diff --git a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c
index 385cc619df13..c8958222df8c 100644
--- a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c
+++ b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c
@@ -50,15 +50,23 @@ struct aml_pio_control {
u32 bit_offset[AML_NUM_REG];
};
-struct aml_reg_bit {
- u32 bank_id;
- u32 reg_offs[AML_NUM_REG];
- u32 bit_offs[AML_NUM_REG];
+/*
+ * partial bank(subordinate) pins mux config use other bank(main) mux registgers
+ * m_bank_id: the main bank which pin_id from 0, but register bit not from bit 0
+ * m_bit_offs: bit offset the main bank mux register
+ * sid: start pin_id of subordinate bank
+ * eid: end pin_id of subordinate bank
+ */
+struct multi_mux {
+ unsigned int m_bank_id;
+ unsigned int m_bit_offs;
+ unsigned int sid;
+ unsigned int eid;
};
struct aml_pctl_data {
unsigned int number;
- struct aml_reg_bit rb_offs[];
+ const struct multi_mux *p_mux;
};
struct aml_pmx_func {
@@ -78,10 +86,12 @@ struct aml_gpio_bank {
struct gpio_chip gpio_chip;
struct aml_pio_control pc;
u32 bank_id;
+ u32 mux_bit_offs;
unsigned int pin_base;
struct regmap *reg_mux;
struct regmap *reg_gpio;
struct regmap *reg_ds;
+ const struct multi_mux *p_mux;
};
struct aml_pinctrl {
@@ -113,13 +123,46 @@ static const char *aml_bank_name[31] = {
"GPIOCC", "TEST_N", "ANALOG"
};
+static const struct multi_mux multi_mux_s7[] = {
+ {
+ .m_bank_id = AMLOGIC_GPIO_CC,
+ .m_bit_offs = 24,
+ .sid = (AMLOGIC_GPIO_X << 8) + 16,
+ .eid = (AMLOGIC_GPIO_X << 8) + 19,
+ },
+};
+
+static const struct aml_pctl_data s7_priv_data = {
+ .number = ARRAY_SIZE(multi_mux_s7),
+ .p_mux = multi_mux_s7,
+};
+
+static const struct multi_mux multi_mux_s6[] = {
+ {
+ .m_bank_id = AMLOGIC_GPIO_CC,
+ .m_bit_offs = 24,
+ .sid = (AMLOGIC_GPIO_X << 8) + 16,
+ .eid = (AMLOGIC_GPIO_X << 8) + 19,
+ }, {
+ .m_bank_id = AMLOGIC_GPIO_F,
+ .m_bit_offs = 4,
+ .sid = (AMLOGIC_GPIO_D << 8) + 6,
+ .eid = (AMLOGIC_GPIO_D << 8) + 6,
+ },
+};
+
+static const struct aml_pctl_data s6_priv_data = {
+ .number = ARRAY_SIZE(multi_mux_s6),
+ .p_mux = multi_mux_s6,
+};
+
static int aml_pmx_calc_reg_and_offset(struct pinctrl_gpio_range *range,
unsigned int pin, unsigned int *reg,
unsigned int *offset)
{
unsigned int shift;
- shift = (pin - range->pin_base) << 2;
+ shift = ((pin - range->pin_base) << 2) + *offset;
*reg = (shift / 32) * 4;
*offset = shift % 32;
@@ -131,9 +174,36 @@ static int aml_pctl_set_function(struct aml_pinctrl *info,
int pin_id, int func)
{
struct aml_gpio_bank *bank = gpio_chip_to_bank(range->gc);
+ unsigned int shift;
int reg;
- int offset;
+ int i;
+ unsigned int offset = bank->mux_bit_offs;
+ const struct multi_mux *p_mux;
+
+ /* peculiar mux reg set */
+ if (bank->p_mux) {
+ p_mux = bank->p_mux;
+ if (pin_id >= p_mux->sid && pin_id <= p_mux->eid) {
+ bank = NULL;
+ for (i = 0; i < info->nbanks; i++) {
+ if (info->banks[i].bank_id == p_mux->m_bank_id) {
+ bank = &info->banks[i];
+ break;
+ }
+ }
+ if (!bank || !bank->reg_mux)
+ return -EINVAL;
+
+ shift = (pin_id - p_mux->sid) << 2;
+ reg = (shift / 32) * 4;
+ offset = shift % 32;
+ return regmap_update_bits(bank->reg_mux, reg,
+ 0xf << offset, (func & 0xf) << offset);
+ }
+ }
+
+ /* normal mux reg set */
if (!bank->reg_mux)
return 0;
@@ -830,29 +900,27 @@ static void init_bank_register_bit(struct aml_pinctrl *info,
struct aml_gpio_bank *bank)
{
const struct aml_pctl_data *data = info->data;
- const struct aml_reg_bit *aml_rb;
- bool def_offs = true;
+ const struct multi_mux *p_mux;
int i;
+ for (i = 0; i < AML_NUM_REG; i++) {
+ bank->pc.reg_offset[i] = aml_def_regoffs[i];
+ bank->pc.bit_offset[i] = 0;
+ }
+
+ bank->mux_bit_offs = 0;
+
if (data) {
for (i = 0; i < data->number; i++) {
- aml_rb = &data->rb_offs[i];
- if (bank->bank_id == aml_rb->bank_id) {
- def_offs = false;
+ p_mux = &data->p_mux[i];
+ if (bank->bank_id == p_mux->m_bank_id) {
+ bank->mux_bit_offs = p_mux->m_bit_offs;
+ break;
+ }
+ if (p_mux->sid >> 8 == bank->bank_id) {
+ bank->p_mux = p_mux;
break;
}
- }
- }
-
- if (def_offs) {
- for (i = 0; i < AML_NUM_REG; i++) {
- bank->pc.reg_offset[i] = aml_def_regoffs[i];
- bank->pc.bit_offset[i] = 0;
- }
- } else {
- for (i = 0; i < AML_NUM_REG; i++) {
- bank->pc.reg_offset[i] = aml_rb->reg_offs[i];
- bank->pc.bit_offset[i] = aml_rb->bit_offs[i];
}
}
}
@@ -1021,6 +1089,8 @@ static int aml_pctl_probe(struct platform_device *pdev)
static const struct of_device_id aml_pctl_of_match[] = {
{ .compatible = "amlogic,pinctrl-a4", },
+ { .compatible = "amlogic,pinctrl-s7", .data = &s7_priv_data, },
+ { .compatible = "amlogic,pinctrl-s6", .data = &s6_priv_data, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, aml_pctl_dt_match);
diff --git a/drivers/pinctrl/meson/pinctrl-meson-g12a.c b/drivers/pinctrl/meson/pinctrl-meson-g12a.c
index e2788bfc5874..8b9130c6e170 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-g12a.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-g12a.c
@@ -270,15 +270,21 @@ static const unsigned int pwm_a_pins[] = { GPIOX_6 };
/* pwm_b */
static const unsigned int pwm_b_x7_pins[] = { GPIOX_7 };
static const unsigned int pwm_b_x19_pins[] = { GPIOX_19 };
+static const unsigned int pwm_b_z0_pins[] = { GPIOZ_0 };
+static const unsigned int pwm_b_z13_pins[] = { GPIOZ_13 };
+static const unsigned int pwm_b_h_pins[] = { GPIOH_7 };
/* pwm_c */
static const unsigned int pwm_c_c_pins[] = { GPIOC_4 };
static const unsigned int pwm_c_x5_pins[] = { GPIOX_5 };
static const unsigned int pwm_c_x8_pins[] = { GPIOX_8 };
+static const unsigned int pwm_c_z_pins[] = { GPIOZ_1 };
/* pwm_d */
static const unsigned int pwm_d_x3_pins[] = { GPIOX_3 };
static const unsigned int pwm_d_x6_pins[] = { GPIOX_6 };
+static const unsigned int pwm_d_z_pins[] = { GPIOZ_2 };
+static const unsigned int pwm_d_a_pins[] = { GPIOA_4 };
/* pwm_e */
static const unsigned int pwm_e_pins[] = { GPIOX_16 };
@@ -649,12 +655,22 @@ static const struct meson_pmx_group meson_g12a_periphs_groups[] = {
GROUP(pwm_a, 1),
GROUP(pwm_b_x7, 4),
GROUP(pwm_b_x19, 1),
+ GROUP(pwm_b_z0, 5),
+ GROUP(pwm_b_z13, 5),
+ GROUP(pwm_b_h, 5),
GROUP(pwm_c_x5, 4),
GROUP(pwm_c_x8, 5),
+ GROUP(pwm_c_c, 5),
+ GROUP(pwm_c_z, 5),
+ GROUP(pwm_d_z, 4),
+ GROUP(pwm_d_a, 3),
GROUP(pwm_d_x3, 4),
GROUP(pwm_d_x6, 4),
GROUP(pwm_e, 1),
+ GROUP(pwm_f_a, 3),
+ GROUP(pwm_f_h, 4),
GROUP(pwm_f_x, 1),
+ GROUP(pwm_f_z, 5),
GROUP(tsin_a_valid, 3),
GROUP(tsin_a_sop, 3),
GROUP(tsin_a_din0, 3),
@@ -1058,15 +1074,15 @@ static const char * const pwm_a_groups[] = {
};
static const char * const pwm_b_groups[] = {
- "pwm_b_x7", "pwm_b_x19",
+ "pwm_b_h", "pwm_b_x7", "pwm_b_x19", "pwm_b_z0", "pwm_b_z13"
};
static const char * const pwm_c_groups[] = {
- "pwm_c_c", "pwm_c_x5", "pwm_c_x8",
+ "pwm_c_c", "pwm_c_x5", "pwm_c_x8", "pwm_c_z",
};
static const char * const pwm_d_groups[] = {
- "pwm_d_x3", "pwm_d_x6",
+ "pwm_d_a", "pwm_d_x3", "pwm_d_x6", "pwm_d_z",
};
static const char * const pwm_e_groups[] = {
diff --git a/drivers/pinctrl/nuvoton/pinctrl-ma35.c b/drivers/pinctrl/nuvoton/pinctrl-ma35.c
index b51704bafd81..da5220da5149 100644
--- a/drivers/pinctrl/nuvoton/pinctrl-ma35.c
+++ b/drivers/pinctrl/nuvoton/pinctrl-ma35.c
@@ -361,7 +361,7 @@ static int ma35_gpio_core_get(struct gpio_chip *gc, unsigned int gpio)
return !!(readl(reg_pin) & BIT(gpio));
}
-static void ma35_gpio_core_set(struct gpio_chip *gc, unsigned int gpio, int val)
+static int ma35_gpio_core_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct ma35_pin_bank *bank = gpiochip_get_data(gc);
void __iomem *reg_dout = bank->reg_base + MA35_GP_REG_DOUT;
@@ -373,6 +373,8 @@ static void ma35_gpio_core_set(struct gpio_chip *gc, unsigned int gpio, int val)
regval = readl(reg_dout) & ~BIT(gpio);
writel(regval, reg_dout);
+
+ return 0;
}
static int ma35_gpio_core_to_request(struct gpio_chip *gc, unsigned int gpio)
@@ -524,7 +526,7 @@ static int ma35_gpiolib_register(struct platform_device *pdev, struct ma35_pinct
bank->chip.direction_input = ma35_gpio_core_direction_in;
bank->chip.direction_output = ma35_gpio_core_direction_out;
bank->chip.get = ma35_gpio_core_get;
- bank->chip.set = ma35_gpio_core_set;
+ bank->chip.set_rv = ma35_gpio_core_set;
bank->chip.base = -1;
bank->chip.ngpio = bank->nr_pins;
bank->chip.can_sleep = false;
diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c
index dfd32feb3428..b8872d8f5930 100644
--- a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c
+++ b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c
@@ -1817,7 +1817,7 @@ static const struct pinconf_ops npcm7xx_pinconf_ops = {
};
/* pinctrl_desc */
-static struct pinctrl_desc npcm7xx_pinctrl_desc = {
+static const struct pinctrl_desc npcm7xx_pinctrl_desc = {
.name = "npcm7xx-pinctrl",
.pins = npcm7xx_pins,
.npins = ARRAY_SIZE(npcm7xx_pins),
diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c
index be3db8ab406c..3c3b9d8d3681 100644
--- a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c
+++ b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c
@@ -2299,7 +2299,7 @@ static const struct pinconf_ops npcm8xx_pinconf_ops = {
};
/* pinctrl_desc */
-static struct pinctrl_desc npcm8xx_pinctrl_desc = {
+static const struct pinctrl_desc npcm8xx_pinctrl_desc = {
.name = "npcm8xx-pinctrl",
.pins = npcm8xx_pins,
.npins = ARRAY_SIZE(npcm8xx_pins),
diff --git a/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c b/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c
index 4264ca749175..8d8314ba0e4c 100644
--- a/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c
+++ b/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c
@@ -989,7 +989,7 @@ static const struct pinconf_ops wpcm450_pinconf_ops = {
.pin_config_set = wpcm450_config_set,
};
-static struct pinctrl_desc wpcm450_pinctrl_desc = {
+static const struct pinctrl_desc wpcm450_pinctrl_desc = {
.name = "wpcm450-pinctrl",
.pins = wpcm450_pins,
.npins = ARRAY_SIZE(wpcm450_pins),
diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
index b3f0d02aeeb3..b90ef3a26ae8 100644
--- a/drivers/pinctrl/pinctrl-amd.c
+++ b/drivers/pinctrl/pinctrl-amd.c
@@ -872,7 +872,7 @@ static const struct pinconf_ops amd_pinconf_ops = {
static void amd_gpio_irq_init(struct amd_gpio *gpio_dev)
{
- struct pinctrl_desc *desc = gpio_dev->pctrl->desc;
+ const struct pinctrl_desc *desc = gpio_dev->pctrl->desc;
unsigned long flags;
u32 pin_reg, mask;
int i;
@@ -901,7 +901,7 @@ static void amd_gpio_irq_init(struct amd_gpio *gpio_dev)
static void amd_gpio_check_pending(void)
{
struct amd_gpio *gpio_dev = pinctrl_dev;
- struct pinctrl_desc *desc = gpio_dev->pctrl->desc;
+ const struct pinctrl_desc *desc = gpio_dev->pctrl->desc;
int i;
if (!pm_debug_messages_on)
@@ -957,7 +957,7 @@ static bool amd_gpio_should_save(struct amd_gpio *gpio_dev, unsigned int pin)
static int amd_gpio_suspend_hibernate_common(struct device *dev, bool is_suspend)
{
struct amd_gpio *gpio_dev = dev_get_drvdata(dev);
- struct pinctrl_desc *desc = gpio_dev->pctrl->desc;
+ const struct pinctrl_desc *desc = gpio_dev->pctrl->desc;
unsigned long flags;
int i;
u32 wake_mask = is_suspend ? WAKE_SOURCE_SUSPEND : WAKE_SOURCE_HIBERNATE;
@@ -1012,7 +1012,7 @@ static int amd_gpio_hibernate(struct device *dev)
static int amd_gpio_resume(struct device *dev)
{
struct amd_gpio *gpio_dev = dev_get_drvdata(dev);
- struct pinctrl_desc *desc = gpio_dev->pctrl->desc;
+ const struct pinctrl_desc *desc = gpio_dev->pctrl->desc;
unsigned long flags;
int i;
diff --git a/drivers/pinctrl/pinctrl-amdisp.c b/drivers/pinctrl/pinctrl-amdisp.c
index 9256ed67bb20..2e706bf8bcde 100644
--- a/drivers/pinctrl/pinctrl-amdisp.c
+++ b/drivers/pinctrl/pinctrl-amdisp.c
@@ -117,7 +117,7 @@ static int amdisp_gpio_get(struct gpio_chip *gc, unsigned int gpio)
return !!(pin_reg & BIT(GPIO_CONTROL_PIN));
}
-static void amdisp_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
+static int amdisp_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
{
unsigned long flags;
u32 pin_reg;
@@ -131,6 +131,8 @@ static void amdisp_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
pin_reg &= ~BIT(GPIO_CONTROL_PIN);
writel(pin_reg, pctrl->gpiobase + gpio_offset[gpio]);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ return 0;
}
static int amdisp_gpiochip_add(struct platform_device *pdev,
@@ -149,7 +151,7 @@ static int amdisp_gpiochip_add(struct platform_device *pdev,
gc->direction_input = amdisp_gpio_direction_input;
gc->direction_output = amdisp_gpio_direction_output;
gc->get = amdisp_gpio_get;
- gc->set = amdisp_gpio_set;
+ gc->set_rv = amdisp_gpio_set;
gc->base = -1;
gc->ngpio = ARRAY_SIZE(amdisp_range_pins);
diff --git a/drivers/pinctrl/pinctrl-apple-gpio.c b/drivers/pinctrl/pinctrl-apple-gpio.c
index 0f551d67d482..dcf3a921b4df 100644
--- a/drivers/pinctrl/pinctrl-apple-gpio.c
+++ b/drivers/pinctrl/pinctrl-apple-gpio.c
@@ -217,11 +217,13 @@ static int apple_gpio_get(struct gpio_chip *chip, unsigned offset)
return !!(reg & REG_GPIOx_DATA);
}
-static void apple_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+static int apple_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct apple_gpio_pinctrl *pctl = gpiochip_get_data(chip);
apple_gpio_set_reg(pctl, offset, REG_GPIOx_DATA, value ? REG_GPIOx_DATA : 0);
+
+ return 0;
}
static int apple_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
@@ -376,7 +378,7 @@ static int apple_gpio_register(struct apple_gpio_pinctrl *pctl)
pctl->gpio_chip.direction_input = apple_gpio_direction_input;
pctl->gpio_chip.direction_output = apple_gpio_direction_output;
pctl->gpio_chip.get = apple_gpio_get;
- pctl->gpio_chip.set = apple_gpio_set;
+ pctl->gpio_chip.set_rv = apple_gpio_set;
pctl->gpio_chip.base = -1;
pctl->gpio_chip.ngpio = pctl->pinctrl_desc.npins;
pctl->gpio_chip.parent = pctl->dev;
diff --git a/drivers/pinctrl/pinctrl-artpec6.c b/drivers/pinctrl/pinctrl-artpec6.c
index 717f9592b28b..af67057128ff 100644
--- a/drivers/pinctrl/pinctrl-artpec6.c
+++ b/drivers/pinctrl/pinctrl-artpec6.c
@@ -907,7 +907,7 @@ static const struct pinconf_ops artpec6_pconf_ops = {
.pin_config_group_set = artpec6_pconf_group_set,
};
-static struct pinctrl_desc artpec6_desc = {
+static const struct pinctrl_desc artpec6_desc = {
.name = "artpec6-pinctrl",
.owner = THIS_MODULE,
.pins = artpec6_pins,
diff --git a/drivers/pinctrl/pinctrl-as3722.c b/drivers/pinctrl/pinctrl-as3722.c
index 0d8c75ce20ed..30ed758bbe9d 100644
--- a/drivers/pinctrl/pinctrl-as3722.c
+++ b/drivers/pinctrl/pinctrl-as3722.c
@@ -422,6 +422,8 @@ static struct pinctrl_desc as3722_pinctrl_desc = {
.pmxops = &as3722_pinmux_ops,
.confops = &as3722_pinconf_ops,
.owner = THIS_MODULE,
+ .pins = as3722_pins_desc,
+ .npins = ARRAY_SIZE(as3722_pins_desc),
};
static int as3722_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -471,8 +473,8 @@ static int as3722_gpio_get(struct gpio_chip *chip, unsigned offset)
return (invert_enable) ? !val : val;
}
-static void as3722_gpio_set(struct gpio_chip *chip, unsigned offset,
- int value)
+static int as3722_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct as3722_pctrl_info *as_pci = gpiochip_get_data(chip);
struct as3722 *as3722 = as_pci->as3722;
@@ -484,7 +486,7 @@ static void as3722_gpio_set(struct gpio_chip *chip, unsigned offset,
if (ret < 0) {
dev_err(as_pci->dev,
"GPIO_CONTROL%d_REG read failed: %d\n", offset, ret);
- return;
+ return ret;
}
en_invert = !!(val & AS3722_GPIO_INV);
@@ -498,12 +500,19 @@ static void as3722_gpio_set(struct gpio_chip *chip, unsigned offset,
if (ret < 0)
dev_err(as_pci->dev,
"GPIO_SIGNAL_OUT_REG update failed: %d\n", ret);
+
+ return ret;
}
static int as3722_gpio_direction_output(struct gpio_chip *chip,
- unsigned offset, int value)
+ unsigned int offset, int value)
{
- as3722_gpio_set(chip, offset, value);
+ int ret;
+
+ ret = as3722_gpio_set(chip, offset, value);
+ if (ret)
+ return ret;
+
return pinctrl_gpio_direction_output(chip, offset);
}
@@ -520,7 +529,7 @@ static const struct gpio_chip as3722_gpio_chip = {
.request = gpiochip_generic_request,
.free = gpiochip_generic_free,
.get = as3722_gpio_get,
- .set = as3722_gpio_set,
+ .set_rv = as3722_gpio_set,
.direction_input = pinctrl_gpio_direction_input,
.direction_output = as3722_gpio_direction_output,
.to_irq = as3722_gpio_to_irq,
@@ -550,8 +559,6 @@ static int as3722_pinctrl_probe(struct platform_device *pdev)
as_pci->pin_groups = as3722_pingroups;
as_pci->num_pin_groups = ARRAY_SIZE(as3722_pingroups);
as3722_pinctrl_desc.name = dev_name(&pdev->dev);
- as3722_pinctrl_desc.pins = as3722_pins_desc;
- as3722_pinctrl_desc.npins = ARRAY_SIZE(as3722_pins_desc);
as_pci->pctl = devm_pinctrl_register(&pdev->dev, &as3722_pinctrl_desc,
as_pci);
if (IS_ERR(as_pci->pctl)) {
diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c
index ca8a54a43ff5..57f105ac962d 100644
--- a/drivers/pinctrl/pinctrl-at91-pio4.c
+++ b/drivers/pinctrl/pinctrl-at91-pio4.c
@@ -1212,9 +1212,9 @@ static int atmel_pinctrl_probe(struct platform_device *pdev)
dev_dbg(dev, "bank %i: irq=%d\n", i, ret);
}
- atmel_pioctrl->irq_domain = irq_domain_create_linear(of_fwnode_handle(dev->of_node),
- atmel_pioctrl->gpio_chip->ngpio,
- &irq_domain_simple_ops, NULL);
+ atmel_pioctrl->irq_domain = irq_domain_create_linear(dev_fwnode(dev),
+ atmel_pioctrl->gpio_chip->ngpio,
+ &irq_domain_simple_ops, NULL);
if (!atmel_pioctrl->irq_domain)
return dev_err_probe(dev, -ENODEV, "can't add the irq domain\n");
diff --git a/drivers/pinctrl/pinctrl-aw9523.c b/drivers/pinctrl/pinctrl-aw9523.c
index 04afb344e9e5..9570ef346af6 100644
--- a/drivers/pinctrl/pinctrl-aw9523.c
+++ b/drivers/pinctrl/pinctrl-aw9523.c
@@ -625,14 +625,14 @@ out:
return ret;
}
-static void aw9523_gpio_set_multiple(struct gpio_chip *chip,
+static int aw9523_gpio_set_multiple(struct gpio_chip *chip,
unsigned long *mask,
unsigned long *bits)
{
struct aw9523 *awi = gpiochip_get_data(chip);
u8 mask_lo, mask_hi, bits_lo, bits_hi;
unsigned int reg;
- int ret;
+ int ret = 0;
mask_lo = *mask;
mask_hi = *mask >> 8;
@@ -644,27 +644,33 @@ static void aw9523_gpio_set_multiple(struct gpio_chip *chip,
reg = AW9523_REG_OUT_STATE(AW9523_PINS_PER_PORT);
ret = regmap_write_bits(awi->regmap, reg, mask_hi, bits_hi);
if (ret)
- dev_warn(awi->dev, "Cannot write port1 out level\n");
+ goto out;
}
if (mask_lo) {
reg = AW9523_REG_OUT_STATE(0);
ret = regmap_write_bits(awi->regmap, reg, mask_lo, bits_lo);
if (ret)
- dev_warn(awi->dev, "Cannot write port0 out level\n");
+ goto out;
}
+
+out:
mutex_unlock(&awi->i2c_lock);
+ return ret;
}
-static void aw9523_gpio_set(struct gpio_chip *chip,
- unsigned int offset, int value)
+static int aw9523_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct aw9523 *awi = gpiochip_get_data(chip);
u8 regbit = offset % AW9523_PINS_PER_PORT;
+ int ret;
mutex_lock(&awi->i2c_lock);
- regmap_update_bits(awi->regmap, AW9523_REG_OUT_STATE(offset),
- BIT(regbit), value ? BIT(regbit) : 0);
+ ret = regmap_update_bits(awi->regmap, AW9523_REG_OUT_STATE(offset),
+ BIT(regbit), value ? BIT(regbit) : 0);
mutex_unlock(&awi->i2c_lock);
+
+ return ret;
}
@@ -779,8 +785,8 @@ static int aw9523_init_gpiochip(struct aw9523 *awi, unsigned int npins)
gc->direction_output = aw9523_direction_output;
gc->get = aw9523_gpio_get;
gc->get_multiple = aw9523_gpio_get_multiple;
- gc->set = aw9523_gpio_set;
- gc->set_multiple = aw9523_gpio_set_multiple;
+ gc->set_rv = aw9523_gpio_set;
+ gc->set_multiple_rv = aw9523_gpio_set_multiple;
gc->set_config = gpiochip_generic_config;
gc->parent = dev;
gc->owner = THIS_MODULE;
diff --git a/drivers/pinctrl/pinctrl-bm1880.c b/drivers/pinctrl/pinctrl-bm1880.c
index b0000fe5b31d..387798fb09be 100644
--- a/drivers/pinctrl/pinctrl-bm1880.c
+++ b/drivers/pinctrl/pinctrl-bm1880.c
@@ -1298,7 +1298,7 @@ static const struct pinmux_ops bm1880_pinmux_ops = {
.set_mux = bm1880_pinmux_set_mux,
};
-static struct pinctrl_desc bm1880_desc = {
+static const struct pinctrl_desc bm1880_desc = {
.name = "bm1880_pinctrl",
.pins = bm1880_pins,
.npins = ARRAY_SIZE(bm1880_pins),
diff --git a/drivers/pinctrl/pinctrl-da9062.c b/drivers/pinctrl/pinctrl-da9062.c
index 6f44a13b90ce..3295b09dfc3d 100644
--- a/drivers/pinctrl/pinctrl-da9062.c
+++ b/drivers/pinctrl/pinctrl-da9062.c
@@ -102,14 +102,14 @@ static int da9062_gpio_get(struct gpio_chip *gc, unsigned int offset)
return !!(val & BIT(offset));
}
-static void da9062_gpio_set(struct gpio_chip *gc, unsigned int offset,
- int value)
+static int da9062_gpio_set(struct gpio_chip *gc, unsigned int offset,
+ int value)
{
struct da9062_pctl *pctl = gpiochip_get_data(gc);
struct regmap *regmap = pctl->da9062->regmap;
- regmap_update_bits(regmap, DA9062AA_GPIO_MODE0_4, BIT(offset),
- value << offset);
+ return regmap_update_bits(regmap, DA9062AA_GPIO_MODE0_4, BIT(offset),
+ value << offset);
}
static int da9062_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
@@ -172,9 +172,7 @@ static int da9062_gpio_direction_output(struct gpio_chip *gc,
if (ret)
return ret;
- da9062_gpio_set(gc, offset, value);
-
- return 0;
+ return da9062_gpio_set(gc, offset, value);
}
static int da9062_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
@@ -235,7 +233,7 @@ static int da9062_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
static const struct gpio_chip reference_gc = {
.owner = THIS_MODULE,
.get = da9062_gpio_get,
- .set = da9062_gpio_set,
+ .set_rv = da9062_gpio_set,
.get_direction = da9062_gpio_get_direction,
.direction_input = da9062_gpio_direction_input,
.direction_output = da9062_gpio_direction_output,
diff --git a/drivers/pinctrl/pinctrl-digicolor.c b/drivers/pinctrl/pinctrl-digicolor.c
index a0423172bdd6..1676cb3cc4c9 100644
--- a/drivers/pinctrl/pinctrl-digicolor.c
+++ b/drivers/pinctrl/pinctrl-digicolor.c
@@ -182,7 +182,7 @@ static int dc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
return 0;
}
-static void dc_gpio_set(struct gpio_chip *chip, unsigned gpio, int value);
+static int dc_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value);
static int dc_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
int value)
@@ -216,7 +216,7 @@ static int dc_gpio_get(struct gpio_chip *chip, unsigned gpio)
return !!(input & BIT(bit_off));
}
-static void dc_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
+static int dc_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value)
{
struct dc_pinmap *pmap = gpiochip_get_data(chip);
int reg_off = GP_OUTPUT0(gpio/PINS_PER_COLLECTION);
@@ -232,6 +232,8 @@ static void dc_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
output &= ~BIT(bit_off);
writeb_relaxed(output, pmap->regs + reg_off);
spin_unlock_irqrestore(&pmap->lock, flags);
+
+ return 0;
}
static int dc_gpiochip_add(struct dc_pinmap *pmap)
@@ -246,7 +248,7 @@ static int dc_gpiochip_add(struct dc_pinmap *pmap)
chip->direction_input = dc_gpio_direction_input;
chip->direction_output = dc_gpio_direction_output;
chip->get = dc_gpio_get;
- chip->set = dc_gpio_set;
+ chip->set_rv = dc_gpio_set;
chip->base = -1;
chip->ngpio = PINS_COUNT;
diff --git a/drivers/pinctrl/pinctrl-eic7700.c b/drivers/pinctrl/pinctrl-eic7700.c
new file mode 100644
index 000000000000..4874b5532343
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-eic7700.c
@@ -0,0 +1,704 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ESWIN Pinctrl Controller Platform Device Driver
+ *
+ * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved.
+ *
+ * Authors: Samuel Holland <samuel.holland@sifive.com>
+ * Yulin Lu <luyulin@eswincomputing.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/regulator/consumer.h>
+
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "core.h"
+#include "pinmux.h"
+#include "pinconf.h"
+
+#define EIC7700_PIN_REG(i) (4 * (i))
+#define EIC7700_IE BIT(0)
+#define EIC7700_PU BIT(1)
+#define EIC7700_PD BIT(2)
+#define EIC7700_DS GENMASK(6, 3)
+#define EIC7700_ST BIT(7)
+#define EIC7700_FUNC_SEL GENMASK(18, 16)
+
+#define EIC7700_BIAS (EIC7700_PD | EIC7700_PU)
+#define EIC7700_PINCONF GENMASK(7, 0)
+
+#define EIC7700_RGMII0_SEL_MODE (0x310 - 0x80)
+#define EIC7700_RGMII1_SEL_MODE (0x314 - 0x80)
+#define EIC7700_MS GENMASK(1, 0)
+#define EIC7700_MS_3V3 0x0
+#define EIC7700_MS_1V8 0x3
+
+#define EIC7700_FUNCTIONS_PER_PIN 8
+
+struct eic7700_pin {
+ u8 functions[EIC7700_FUNCTIONS_PER_PIN];
+};
+
+struct eic7700_pinctrl {
+ void __iomem *base;
+ struct pinctrl_desc desc;
+ unsigned int functions_count;
+ struct pinfunction functions[] __counted_by(functions_count);
+};
+
+enum {
+ F_DISABLED,
+ F_BOOT_SEL,
+ F_CHIP_MODE,
+ F_EMMC,
+ F_FAN_TACH,
+ F_GPIO,
+ F_HDMI,
+ F_I2C,
+ F_I2S,
+ F_JTAG,
+ F_DDR_REF_CLK_SEL,
+ F_LPDDR_REF_CLK,
+ F_MIPI_CSI,
+ F_OSC,
+ F_PCIE,
+ F_PWM,
+ F_RGMII,
+ F_RESET,
+ F_SATA,
+ F_SDIO,
+ F_SPI,
+ F_S_MODE,
+ F_UART,
+ F_USB,
+ EIC7700_FUNCTIONS_COUNT
+};
+
+static const char *const eic7700_functions[EIC7700_FUNCTIONS_COUNT] = {
+ [F_DISABLED] = "disabled",
+ [F_BOOT_SEL] = "boot_sel",
+ [F_CHIP_MODE] = "chip_mode",
+ [F_EMMC] = "emmc",
+ [F_FAN_TACH] = "fan_tach",
+ [F_GPIO] = "gpio",
+ [F_HDMI] = "hdmi",
+ [F_I2C] = "i2c",
+ [F_I2S] = "i2s",
+ [F_JTAG] = "jtag",
+ [F_DDR_REF_CLK_SEL] = "ddr_ref_clk_sel",
+ [F_LPDDR_REF_CLK] = "lpddr_ref_clk",
+ [F_MIPI_CSI] = "mipi_csi",
+ [F_OSC] = "osc",
+ [F_PCIE] = "pcie",
+ [F_PWM] = "pwm",
+ [F_RGMII] = "rgmii",
+ [F_RESET] = "reset",
+ [F_SATA] = "sata",
+ [F_SDIO] = "sdio",
+ [F_SPI] = "spi",
+ [F_S_MODE] = "s_mode",
+ [F_UART] = "uart",
+ [F_USB] = "usb",
+};
+
+#define EIC7700_PIN(_number, _name, ...) \
+ { \
+ .number = _number, \
+ .name = _name, \
+ .drv_data = (void *)&(struct eic7700_pin) { { __VA_ARGS__ } } \
+ }
+
+static const struct pinctrl_pin_desc eic7700_pins[] = {
+ EIC7700_PIN(0, "chip_mode", [0] = F_CHIP_MODE),
+ EIC7700_PIN(1, "mode_set0", [0] = F_SDIO, [2] = F_GPIO),
+ EIC7700_PIN(2, "mode_set1", [0] = F_SDIO, [2] = F_GPIO),
+ EIC7700_PIN(3, "mode_set2", [0] = F_SDIO, [2] = F_GPIO),
+ EIC7700_PIN(4, "mode_set3", [0] = F_SDIO, [2] = F_GPIO),
+ EIC7700_PIN(5, "xin", [0] = F_OSC),
+ EIC7700_PIN(6, "rtc_xin", [0] = F_DISABLED),
+ EIC7700_PIN(7, "rst_out_n", [0] = F_RESET),
+ EIC7700_PIN(8, "key_reset_n", [0] = F_RESET),
+ EIC7700_PIN(9, "rst_in_n", [0] = F_DISABLED),
+ EIC7700_PIN(10, "por_in_n", [0] = F_DISABLED),
+ EIC7700_PIN(11, "por_out_n", [0] = F_DISABLED),
+ EIC7700_PIN(12, "gpio0", [0] = F_GPIO),
+ EIC7700_PIN(13, "por_sel", [0] = F_RESET),
+ EIC7700_PIN(14, "jtag0_tck", [0] = F_JTAG, [1] = F_SPI, [2] = F_GPIO),
+ EIC7700_PIN(15, "jtag0_tms", [0] = F_JTAG, [1] = F_SPI, [2] = F_GPIO),
+ EIC7700_PIN(16, "jtag0_tdi", [0] = F_JTAG, [1] = F_SPI, [2] = F_GPIO),
+ EIC7700_PIN(17, "jtag0_tdo", [0] = F_JTAG, [1] = F_SPI, [2] = F_GPIO),
+ EIC7700_PIN(18, "gpio5", [0] = F_GPIO, [1] = F_SPI),
+ EIC7700_PIN(19, "spi2_cs0_n", [0] = F_SPI, [2] = F_GPIO),
+ EIC7700_PIN(20, "jtag1_tck", [0] = F_JTAG, [2] = F_GPIO),
+ EIC7700_PIN(21, "jtag1_tms", [0] = F_JTAG, [2] = F_GPIO),
+ EIC7700_PIN(22, "jtag1_tdi", [0] = F_JTAG, [2] = F_GPIO),
+ EIC7700_PIN(23, "jtag1_tdo", [0] = F_JTAG, [2] = F_GPIO),
+ EIC7700_PIN(24, "gpio11", [0] = F_GPIO),
+ EIC7700_PIN(25, "spi2_cs1_n", [0] = F_SPI, [2] = F_GPIO),
+ EIC7700_PIN(26, "pcie_clkreq_n", [0] = F_PCIE),
+ EIC7700_PIN(27, "pcie_wake_n", [0] = F_PCIE),
+ EIC7700_PIN(28, "pcie_perst_n", [0] = F_PCIE),
+ EIC7700_PIN(29, "hdmi_scl", [0] = F_HDMI),
+ EIC7700_PIN(30, "hdmi_sda", [0] = F_HDMI),
+ EIC7700_PIN(31, "hdmi_cec", [0] = F_HDMI),
+ EIC7700_PIN(32, "jtag2_trst", [0] = F_JTAG, [2] = F_GPIO),
+ EIC7700_PIN(33, "rgmii0_clk_125", [0] = F_RGMII),
+ EIC7700_PIN(34, "rgmii0_txen", [0] = F_RGMII),
+ EIC7700_PIN(35, "rgmii0_txclk", [0] = F_RGMII),
+ EIC7700_PIN(36, "rgmii0_txd0", [0] = F_RGMII),
+ EIC7700_PIN(37, "rgmii0_txd1", [0] = F_RGMII),
+ EIC7700_PIN(38, "rgmii0_txd2", [0] = F_RGMII),
+ EIC7700_PIN(39, "rgmii0_txd3", [0] = F_RGMII),
+ EIC7700_PIN(40, "i2s0_bclk", [0] = F_I2S, [2] = F_GPIO),
+ EIC7700_PIN(41, "i2s0_wclk", [0] = F_I2S, [2] = F_GPIO),
+ EIC7700_PIN(42, "i2s0_sdi", [0] = F_I2S, [2] = F_GPIO),
+ EIC7700_PIN(43, "i2s0_sdo", [0] = F_I2S, [2] = F_GPIO),
+ EIC7700_PIN(44, "i2s_mclk", [0] = F_I2S, [2] = F_GPIO),
+ EIC7700_PIN(45, "rgmii0_rxclk", [0] = F_RGMII),
+ EIC7700_PIN(46, "rgmii0_rxdv", [0] = F_RGMII),
+ EIC7700_PIN(47, "rgmii0_rxd0", [0] = F_RGMII),
+ EIC7700_PIN(48, "rgmii0_rxd1", [0] = F_RGMII),
+ EIC7700_PIN(49, "rgmii0_rxd2", [0] = F_RGMII),
+ EIC7700_PIN(50, "rgmii0_rxd3", [0] = F_RGMII),
+ EIC7700_PIN(51, "i2s2_bclk", [0] = F_I2S, [2] = F_GPIO),
+ EIC7700_PIN(52, "i2s2_wclk", [0] = F_I2S, [2] = F_GPIO),
+ EIC7700_PIN(53, "i2s2_sdi", [0] = F_I2S, [2] = F_GPIO),
+ EIC7700_PIN(54, "i2s2_sdo", [0] = F_I2S, [2] = F_GPIO),
+ EIC7700_PIN(55, "gpio27", [0] = F_GPIO, [1] = F_SATA),
+ EIC7700_PIN(56, "gpio28", [0] = F_GPIO),
+ EIC7700_PIN(57, "gpio29", [0] = F_RESET, [1] = F_EMMC, [2] = F_GPIO),
+ EIC7700_PIN(58, "rgmii0_mdc", [0] = F_RGMII),
+ EIC7700_PIN(59, "rgmii0_mdio", [0] = F_RGMII),
+ EIC7700_PIN(60, "rgmii0_intb", [0] = F_RGMII),
+ EIC7700_PIN(61, "rgmii1_clk_125", [0] = F_RGMII),
+ EIC7700_PIN(62, "rgmii1_txen", [0] = F_RGMII),
+ EIC7700_PIN(63, "rgmii1_txclk", [0] = F_RGMII),
+ EIC7700_PIN(64, "rgmii1_txd0", [0] = F_RGMII),
+ EIC7700_PIN(65, "rgmii1_txd1", [0] = F_RGMII),
+ EIC7700_PIN(66, "rgmii1_txd2", [0] = F_RGMII),
+ EIC7700_PIN(67, "rgmii1_txd3", [0] = F_RGMII),
+ EIC7700_PIN(68, "i2s1_bclk", [0] = F_I2S, [2] = F_GPIO),
+ EIC7700_PIN(69, "i2s1_wclk", [0] = F_I2S, [2] = F_GPIO),
+ EIC7700_PIN(70, "i2s1_sdi", [0] = F_I2S, [2] = F_GPIO),
+ EIC7700_PIN(71, "i2s1_sdo", [0] = F_I2S, [2] = F_GPIO),
+ EIC7700_PIN(72, "gpio34", [0] = F_RESET, [1] = F_SDIO, [2] = F_GPIO),
+ EIC7700_PIN(73, "rgmii1_rxclk", [0] = F_RGMII),
+ EIC7700_PIN(74, "rgmii1_rxdv", [0] = F_RGMII),
+ EIC7700_PIN(75, "rgmii1_rxd0", [0] = F_RGMII),
+ EIC7700_PIN(76, "rgmii1_rxd1", [0] = F_RGMII),
+ EIC7700_PIN(77, "rgmii1_rxd2", [0] = F_RGMII),
+ EIC7700_PIN(78, "rgmii1_rxd3", [0] = F_RGMII),
+ EIC7700_PIN(79, "spi1_cs0_n", [0] = F_SPI, [2] = F_GPIO),
+ EIC7700_PIN(80, "spi1_clk", [0] = F_SPI, [2] = F_GPIO),
+ EIC7700_PIN(81, "spi1_d0", [0] = F_SPI, [1] = F_I2C, [2] = F_GPIO, [3] = F_UART),
+ EIC7700_PIN(82, "spi1_d1", [0] = F_SPI, [1] = F_I2C, [2] = F_GPIO, [3] = F_UART),
+ EIC7700_PIN(83, "spi1_d2", [0] = F_SPI, [1] = F_SDIO, [2] = F_GPIO),
+ EIC7700_PIN(84, "spi1_d3", [0] = F_SPI, [1] = F_PWM, [2] = F_GPIO),
+ EIC7700_PIN(85, "spi1_cs1_n", [0] = F_SPI, [1] = F_PWM, [2] = F_GPIO),
+ EIC7700_PIN(86, "rgmii1_mdc", [0] = F_RGMII),
+ EIC7700_PIN(87, "rgmii1_mdio", [0] = F_RGMII),
+ EIC7700_PIN(88, "rgmii1_intb", [0] = F_RGMII),
+ EIC7700_PIN(89, "usb0_pwren", [0] = F_USB, [2] = F_GPIO),
+ EIC7700_PIN(90, "usb1_pwren", [0] = F_USB, [2] = F_GPIO),
+ EIC7700_PIN(91, "i2c0_scl", [0] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(92, "i2c0_sda", [0] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(93, "i2c1_scl", [0] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(94, "i2c1_sda", [0] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(95, "i2c2_scl", [0] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(96, "i2c2_sda", [0] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(97, "i2c3_scl", [0] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(98, "i2c3_sda", [0] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(99, "i2c4_scl", [0] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(100, "i2c4_sda", [0] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(101, "i2c5_scl", [0] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(102, "i2c5_sda", [0] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(103, "uart0_tx", [0] = F_UART, [2] = F_GPIO),
+ EIC7700_PIN(104, "uart0_rx", [0] = F_UART, [2] = F_GPIO),
+ EIC7700_PIN(105, "uart1_tx", [0] = F_UART, [2] = F_GPIO),
+ EIC7700_PIN(106, "uart1_rx", [0] = F_UART, [2] = F_GPIO),
+ EIC7700_PIN(107, "uart1_cts", [0] = F_UART, [1] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(108, "uart1_rts", [0] = F_UART, [1] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(109, "uart2_tx", [0] = F_UART, [1] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(110, "uart2_rx", [0] = F_UART, [1] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(111, "jtag2_tck", [0] = F_JTAG, [2] = F_GPIO),
+ EIC7700_PIN(112, "jtag2_tms", [0] = F_JTAG, [2] = F_GPIO),
+ EIC7700_PIN(113, "jtag2_tdi", [0] = F_JTAG, [2] = F_GPIO),
+ EIC7700_PIN(114, "jtag2_tdo", [0] = F_JTAG, [2] = F_GPIO),
+ EIC7700_PIN(115, "fan_pwm", [0] = F_PWM, [2] = F_GPIO),
+ EIC7700_PIN(116, "fan_tach", [0] = F_FAN_TACH, [2] = F_GPIO),
+ EIC7700_PIN(117, "mipi_csi0_xvs", [0] = F_MIPI_CSI, [2] = F_GPIO),
+ EIC7700_PIN(118, "mipi_csi0_xhs", [0] = F_MIPI_CSI, [2] = F_GPIO),
+ EIC7700_PIN(119, "mipi_csi0_mclk", [0] = F_MIPI_CSI, [2] = F_GPIO),
+ EIC7700_PIN(120, "mipi_csi1_xvs", [0] = F_MIPI_CSI, [2] = F_GPIO),
+ EIC7700_PIN(121, "mipi_csi1_xhs", [0] = F_MIPI_CSI, [2] = F_GPIO),
+ EIC7700_PIN(122, "mipi_csi1_mclk", [0] = F_MIPI_CSI, [2] = F_GPIO),
+ EIC7700_PIN(123, "mipi_csi2_xvs", [0] = F_MIPI_CSI, [2] = F_GPIO),
+ EIC7700_PIN(124, "mipi_csi2_xhs", [0] = F_MIPI_CSI, [2] = F_GPIO),
+ EIC7700_PIN(125, "mipi_csi2_mclk", [0] = F_MIPI_CSI, [2] = F_GPIO),
+ EIC7700_PIN(126, "mipi_csi3_xvs", [0] = F_MIPI_CSI, [2] = F_GPIO),
+ EIC7700_PIN(127, "mipi_csi3_xhs", [0] = F_MIPI_CSI, [2] = F_GPIO),
+ EIC7700_PIN(128, "mipi_csi3_mclk", [0] = F_MIPI_CSI, [2] = F_GPIO),
+ EIC7700_PIN(129, "mipi_csi4_xvs", [0] = F_MIPI_CSI, [2] = F_GPIO),
+ EIC7700_PIN(130, "mipi_csi4_xhs", [0] = F_MIPI_CSI, [2] = F_GPIO),
+ EIC7700_PIN(131, "mipi_csi4_mclk", [0] = F_MIPI_CSI, [2] = F_GPIO),
+ EIC7700_PIN(132, "mipi_csi5_xvs", [0] = F_MIPI_CSI, [2] = F_GPIO),
+ EIC7700_PIN(133, "mipi_csi5_xhs", [0] = F_MIPI_CSI, [2] = F_GPIO),
+ EIC7700_PIN(134, "mipi_csi5_mclk", [0] = F_MIPI_CSI, [2] = F_GPIO),
+ EIC7700_PIN(135, "spi3_cs_n", [0] = F_SPI, [2] = F_GPIO),
+ EIC7700_PIN(136, "spi3_clk", [0] = F_SPI, [2] = F_GPIO),
+ EIC7700_PIN(137, "spi3_di", [0] = F_SPI, [2] = F_GPIO),
+ EIC7700_PIN(138, "spi3_do", [0] = F_SPI, [2] = F_GPIO),
+ EIC7700_PIN(139, "gpio92", [0] = F_I2C, [1] = F_MIPI_CSI, [2] = F_GPIO, [3] = F_UART),
+ EIC7700_PIN(140, "gpio93", [0] = F_I2C, [1] = F_MIPI_CSI, [2] = F_GPIO, [3] = F_UART),
+ EIC7700_PIN(141, "s_mode", [0] = F_S_MODE, [2] = F_GPIO),
+ EIC7700_PIN(142, "gpio95", [0] = F_DDR_REF_CLK_SEL, [2] = F_GPIO),
+ EIC7700_PIN(143, "spi0_cs_n", [0] = F_SPI, [2] = F_GPIO),
+ EIC7700_PIN(144, "spi0_clk", [0] = F_SPI, [2] = F_GPIO),
+ EIC7700_PIN(145, "spi0_d0", [0] = F_SPI, [2] = F_GPIO),
+ EIC7700_PIN(146, "spi0_d1", [0] = F_SPI, [2] = F_GPIO),
+ EIC7700_PIN(147, "spi0_d2", [0] = F_SPI, [2] = F_GPIO),
+ EIC7700_PIN(148, "spi0_d3", [0] = F_SPI, [2] = F_GPIO),
+ EIC7700_PIN(149, "i2c10_scl", [0] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(150, "i2c10_sda", [0] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(151, "i2c11_scl", [0] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(152, "i2c11_sda", [0] = F_I2C, [2] = F_GPIO),
+ EIC7700_PIN(153, "gpio106", [0] = F_GPIO),
+ EIC7700_PIN(154, "boot_sel0", [0] = F_BOOT_SEL, [2] = F_GPIO),
+ EIC7700_PIN(155, "boot_sel1", [0] = F_BOOT_SEL, [2] = F_GPIO),
+ EIC7700_PIN(156, "boot_sel2", [0] = F_BOOT_SEL, [2] = F_GPIO),
+ EIC7700_PIN(157, "boot_sel3", [0] = F_BOOT_SEL, [2] = F_GPIO),
+ EIC7700_PIN(158, "gpio111", [0] = F_GPIO),
+ EIC7700_PIN(159, "reserved0", [0] = F_DISABLED),
+ EIC7700_PIN(160, "reserved1", [0] = F_DISABLED),
+ EIC7700_PIN(161, "reserved2", [0] = F_DISABLED),
+ EIC7700_PIN(162, "reserved3", [0] = F_DISABLED),
+ EIC7700_PIN(163, "lpddr_ref_clk", [0] = F_LPDDR_REF_CLK),
+};
+
+static int eic7700_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ struct eic7700_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
+
+ return pc->desc.npins;
+}
+
+static const char *eic7700_get_group_name(struct pinctrl_dev *pctldev, unsigned int selector)
+{
+ struct eic7700_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
+
+ return pc->desc.pins[selector].name;
+}
+
+static int eic7700_get_group_pins(struct pinctrl_dev *pctldev, unsigned int selector,
+ const unsigned int **pins, unsigned int *npins)
+{
+ struct eic7700_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
+
+ *pins = &pc->desc.pins[selector].number;
+ *npins = 1;
+
+ return 0;
+}
+
+static const struct pinctrl_ops eic7700_pinctrl_ops = {
+ .get_groups_count = eic7700_get_groups_count,
+ .get_group_name = eic7700_get_group_name,
+ .get_group_pins = eic7700_get_group_pins,
+#ifdef CONFIG_OF
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
+ .dt_free_map = pinconf_generic_dt_free_map,
+#endif
+};
+
+static int eic7700_pin_config_get(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *config)
+{
+ struct eic7700_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
+ const struct eic7700_pin *pin_data = pc->desc.pins[pin].drv_data;
+ u32 arg, value;
+ int param;
+
+ if (pin_data->functions[0] == F_OSC || pin_data->functions[0] == F_DISABLED)
+ return -EOPNOTSUPP;
+
+ value = readl_relaxed(pc->base + EIC7700_PIN_REG(pin));
+
+ param = pinconf_to_config_param(*config);
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ arg = (value & EIC7700_BIAS) == 0;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ arg = (value & EIC7700_BIAS) == EIC7700_PD;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ arg = (value & EIC7700_BIAS) == EIC7700_PU;
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH_UA:
+ if (pin_data->functions[0] == F_RGMII ||
+ pin_data->functions[0] == F_LPDDR_REF_CLK)
+ arg = FIELD_GET(EIC7700_DS, value) * 3000 + 3000;
+ else
+ arg = FIELD_GET(EIC7700_DS, value) * 3000 + 6000;
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ arg = value & EIC7700_IE;
+ break;
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ arg = value & EIC7700_ST;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ *config = pinconf_to_config_packed(param, arg);
+ return arg ? 0 : -EINVAL;
+}
+
+static int eic7700_pin_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *configs, unsigned int num_configs)
+{
+ struct eic7700_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
+ const struct eic7700_pin *pin_data = pc->desc.pins[pin].drv_data;
+ u32 value;
+
+ if (pin_data->functions[0] == F_OSC || pin_data->functions[0] == F_DISABLED)
+ return -EOPNOTSUPP;
+
+ value = readl_relaxed(pc->base + EIC7700_PIN_REG(pin));
+
+ for (unsigned int i = 0; i < num_configs; i++) {
+ int param = pinconf_to_config_param(configs[i]);
+ u32 arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ value &= ~EIC7700_BIAS;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ if (arg == 0)
+ return -EOPNOTSUPP;
+ value &= ~EIC7700_BIAS;
+ value |= EIC7700_PD;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (arg == 0)
+ return -EOPNOTSUPP;
+ value &= ~EIC7700_BIAS;
+ value |= EIC7700_PU;
+ break;
+ case PIN_CONFIG_DRIVE_STRENGTH_UA:
+ value &= ~EIC7700_DS;
+ if (pin_data->functions[0] == F_RGMII ||
+ pin_data->functions[0] == F_LPDDR_REF_CLK) {
+ if (arg < 3000 || arg > 24000)
+ return -EOPNOTSUPP;
+ value |= FIELD_PREP(EIC7700_DS, (arg - 3000) / 3000);
+ } else {
+ if (arg < 6000 || arg > 27000)
+ return -EOPNOTSUPP;
+ value |= FIELD_PREP(EIC7700_DS, (arg - 6000) / 3000);
+ }
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ if (arg)
+ value |= EIC7700_IE;
+ else
+ value &= ~EIC7700_IE;
+ break;
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ if (arg)
+ value |= EIC7700_ST;
+ else
+ value &= ~EIC7700_ST;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+ }
+
+ writel_relaxed(value, pc->base + EIC7700_PIN_REG(pin));
+
+ return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void eic7700_pin_config_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+ unsigned int pin)
+{
+ struct eic7700_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
+ u32 value = readl_relaxed(pc->base + EIC7700_PIN_REG(pin)) & EIC7700_PINCONF;
+
+ seq_printf(s, " [0x%02x]", value);
+}
+#else
+#define eic7700_pin_config_dbg_show NULL
+#endif
+
+static const struct pinconf_ops eic7700_pinconf_ops = {
+ .is_generic = true,
+ .pin_config_get = eic7700_pin_config_get,
+ .pin_config_set = eic7700_pin_config_set,
+ .pin_config_group_get = eic7700_pin_config_get,
+ .pin_config_group_set = eic7700_pin_config_set,
+ .pin_config_dbg_show = eic7700_pin_config_dbg_show,
+ .pin_config_group_dbg_show = eic7700_pin_config_dbg_show,
+};
+
+static int eic7700_get_functions_count(struct pinctrl_dev *pctldev)
+{
+ struct eic7700_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
+
+ return pc->functions_count;
+}
+
+static const char *eic7700_get_function_name(struct pinctrl_dev *pctldev, unsigned int selector)
+{
+ struct eic7700_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
+
+ return pc->functions[selector].name;
+}
+
+static int eic7700_get_function_groups(struct pinctrl_dev *pctldev, unsigned int selector,
+ const char *const **groups, unsigned int *num_groups)
+{
+ struct eic7700_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = pc->functions[selector].groups;
+ *num_groups = pc->functions[selector].ngroups;
+
+ return 0;
+}
+
+static int eic7700_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector,
+ unsigned int group_selector)
+{
+ struct eic7700_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
+ const struct eic7700_pin *pin_data = pc->desc.pins[group_selector].drv_data;
+ u32 fs, value;
+
+ if (pin_data->functions[0] == F_OSC || pin_data->functions[0] == F_DISABLED)
+ return -EOPNOTSUPP;
+
+ for (fs = 0; fs < EIC7700_FUNCTIONS_PER_PIN; fs++)
+ if (pin_data->functions[fs] == func_selector)
+ break;
+
+ if (fs == EIC7700_FUNCTIONS_PER_PIN) {
+ dev_err(pctldev->dev, "invalid mux %s for pin %s\n",
+ pc->functions[func_selector].name,
+ pc->desc.pins[group_selector].name);
+ return -EINVAL;
+ }
+
+ value = readl_relaxed(pc->base + EIC7700_PIN_REG(group_selector));
+ value &= ~EIC7700_FUNC_SEL;
+ value |= FIELD_PREP(EIC7700_FUNC_SEL, fs);
+ writel_relaxed(value, pc->base + EIC7700_PIN_REG(group_selector));
+
+ return 0;
+}
+
+static int eic7700_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned int offset)
+{
+ return eic7700_set_mux(pctldev, F_GPIO, offset);
+}
+
+static void eic7700_gpio_disable_free(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned int offset)
+{
+ eic7700_set_mux(pctldev, F_DISABLED, offset);
+}
+
+static int eic7700_gpio_set_direction(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned int offset,
+ bool input)
+{
+ struct eic7700_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
+ u32 value;
+
+ value = readl_relaxed(pc->base + EIC7700_PIN_REG(offset));
+ if (input)
+ value |= EIC7700_IE;
+ else
+ value &= ~EIC7700_IE;
+ writel_relaxed(value, pc->base + EIC7700_PIN_REG(offset));
+
+ return 0;
+}
+
+static const struct pinmux_ops eic7700_pinmux_ops = {
+ .get_functions_count = eic7700_get_functions_count,
+ .get_function_name = eic7700_get_function_name,
+ .get_function_groups = eic7700_get_function_groups,
+ .set_mux = eic7700_set_mux,
+ .gpio_request_enable = eic7700_gpio_request_enable,
+ .gpio_disable_free = eic7700_gpio_disable_free,
+ .gpio_set_direction = eic7700_gpio_set_direction,
+ .strict = true,
+};
+
+static int eic7700_pinctrl_init_function_groups(struct device *dev, struct eic7700_pinctrl *pc,
+ const char *const *function_names)
+{
+ unsigned int ngroups = 0;
+ const char **groups;
+
+ /* Count the number of groups for each function */
+ for (unsigned int pin = 0; pin < pc->desc.npins; pin++) {
+ const struct eic7700_pin *pin_data = pc->desc.pins[pin].drv_data;
+ bool found_disabled = false;
+
+ for (unsigned int fs = 0; fs < EIC7700_FUNCTIONS_PER_PIN; fs++) {
+ unsigned int selector = pin_data->functions[fs];
+ struct pinfunction *function = &pc->functions[selector];
+
+ /* Only count F_DISABLED once per pin */
+ if (selector == F_DISABLED) {
+ if (found_disabled)
+ continue;
+ found_disabled = true;
+ }
+
+ function->ngroups++;
+ ngroups++;
+ }
+ }
+
+ groups = devm_kcalloc(dev, ngroups, sizeof(*groups), GFP_KERNEL);
+ if (!groups)
+ return -ENOMEM;
+
+ for (unsigned int selector = 0; selector < pc->functions_count; selector++) {
+ struct pinfunction *function = &pc->functions[selector];
+
+ function->name = function_names[selector];
+ function->groups = groups;
+ groups += function->ngroups;
+
+ /* Reset per-function ngroups for use as iterator below */
+ function->ngroups = 0;
+ }
+
+ /* Fill in the group pointers for each function */
+ for (unsigned int pin = 0; pin < pc->desc.npins; pin++) {
+ const struct pinctrl_pin_desc *desc = &pc->desc.pins[pin];
+ const struct eic7700_pin *pin_data = desc->drv_data;
+ bool found_disabled = false;
+
+ for (unsigned int fs = 0; fs < EIC7700_FUNCTIONS_PER_PIN; fs++) {
+ unsigned int selector = pin_data->functions[fs];
+ struct pinfunction *function = &pc->functions[selector];
+
+ /* Only count F_DISABLED once per pin */
+ if (selector == F_DISABLED) {
+ if (found_disabled)
+ continue;
+ found_disabled = true;
+ }
+
+ ((const char **)function->groups)[function->ngroups++] = desc->name;
+ }
+ }
+
+ return 0;
+}
+
+static int eic7700_pinctrl_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct pinctrl_dev *pctldev;
+ struct eic7700_pinctrl *pc;
+ struct regulator *regulator;
+ u32 rgmii0_mode, rgmii1_mode;
+ int ret, voltage;
+
+ pc = devm_kzalloc(dev, struct_size(pc, functions, EIC7700_FUNCTIONS_COUNT), GFP_KERNEL);
+ if (!pc)
+ return -ENOMEM;
+
+ pc->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(pc->base))
+ return PTR_ERR(pc->base);
+
+ regulator = devm_regulator_get(dev, "vrgmii");
+ if (IS_ERR_OR_NULL(regulator)) {
+ return dev_err_probe(dev, PTR_ERR(regulator),
+ "failed to get vrgmii regulator\n");
+ }
+
+ voltage = regulator_get_voltage(regulator);
+ if (voltage < 0) {
+ return dev_err_probe(&pdev->dev, voltage,
+ "Failed to get voltage from regulator\n");
+ }
+
+ rgmii0_mode = readl_relaxed(pc->base + EIC7700_RGMII0_SEL_MODE);
+ rgmii1_mode = readl_relaxed(pc->base + EIC7700_RGMII1_SEL_MODE);
+ rgmii0_mode &= ~EIC7700_MS;
+ rgmii1_mode &= ~EIC7700_MS;
+ if (voltage == 1800000) {
+ rgmii0_mode |= FIELD_PREP(EIC7700_MS, EIC7700_MS_1V8);
+ rgmii1_mode |= FIELD_PREP(EIC7700_MS, EIC7700_MS_1V8);
+ } else if (voltage == 3300000) {
+ rgmii0_mode |= FIELD_PREP(EIC7700_MS, EIC7700_MS_3V3);
+ rgmii1_mode |= FIELD_PREP(EIC7700_MS, EIC7700_MS_3V3);
+ } else {
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "Invalid voltage configuration, should be either 1.8V or 3.3V\n");
+ }
+
+ writel_relaxed(rgmii0_mode, pc->base + EIC7700_RGMII0_SEL_MODE);
+ writel_relaxed(rgmii1_mode, pc->base + EIC7700_RGMII1_SEL_MODE);
+
+ pc->desc.name = dev_name(dev);
+ pc->desc.pins = eic7700_pins;
+ pc->desc.npins = ARRAY_SIZE(eic7700_pins);
+ pc->desc.pctlops = &eic7700_pinctrl_ops;
+ pc->desc.pmxops = &eic7700_pinmux_ops;
+ pc->desc.confops = &eic7700_pinconf_ops;
+ pc->desc.owner = THIS_MODULE;
+
+ pc->functions_count = EIC7700_FUNCTIONS_COUNT;
+ ret = eic7700_pinctrl_init_function_groups(dev, pc, eic7700_functions);
+ if (ret)
+ return ret;
+
+ ret = devm_pinctrl_register_and_init(dev, &pc->desc, pc, &pctldev);
+ if (ret)
+ return dev_err_probe(dev, ret, "could not register pinctrl driver\n");
+
+ return pinctrl_enable(pctldev);
+}
+
+static const struct of_device_id eic7700_pinctrl_of_match[] = {
+ { .compatible = "eswin,eic7700-pinctrl" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, eic7700_pinctrl_of_match);
+
+static struct platform_driver eic7700_pinctrl_driver = {
+ .probe = eic7700_pinctrl_probe,
+ .driver = {
+ .name = "pinctrl-eic7700",
+ .of_match_table = eic7700_pinctrl_of_match,
+ },
+};
+module_platform_driver(eic7700_pinctrl_driver);
+
+MODULE_DESCRIPTION("Pinctrl driver for the ESWIN EIC7700 SoC");
+MODULE_AUTHOR("Samuel Holland <samuel.holland@sifive.com>");
+MODULE_AUTHOR("Yulin Lu <luyulin@eswincomputing.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/pinctrl-equilibrium.c b/drivers/pinctrl/pinctrl-equilibrium.c
index 3a9a0f059090..fce804d42e7d 100644
--- a/drivers/pinctrl/pinctrl-equilibrium.c
+++ b/drivers/pinctrl/pinctrl-equilibrium.c
@@ -182,6 +182,8 @@ static int gpiochip_setup(struct device *dev, struct eqbr_gpio_ctrl *gctrl)
gc = &gctrl->chip;
gc->label = gctrl->name;
gc->fwnode = gctrl->fwnode;
+ gc->request = gpiochip_generic_request;
+ gc->free = gpiochip_generic_free;
if (!fwnode_property_read_bool(gctrl->fwnode, "interrupt-controller")) {
dev_dbg(dev, "gc %s: doesn't act as interrupt controller!\n",
@@ -685,11 +687,8 @@ static int eqbr_build_functions(struct eqbr_pinctrl_drv_data *drvdata)
if (funcs[i].name == NULL)
continue;
- ret = pinmux_generic_add_function(drvdata->pctl_dev,
- funcs[i].name,
- funcs[i].groups,
- funcs[i].ngroups,
- drvdata);
+ ret = pinmux_generic_add_pinfunction(drvdata->pctl_dev,
+ &funcs[i], drvdata);
if (ret < 0) {
dev_err(dev, "Failed to register function %s\n",
funcs[i].name);
diff --git a/drivers/pinctrl/pinctrl-falcon.c b/drivers/pinctrl/pinctrl-falcon.c
index 0bf9ffbcc79f..100eed175c0d 100644
--- a/drivers/pinctrl/pinctrl-falcon.c
+++ b/drivers/pinctrl/pinctrl-falcon.c
@@ -505,7 +505,7 @@ static struct platform_driver pinctrl_falcon_driver = {
},
};
-int __init pinctrl_falcon_init(void)
+static int __init pinctrl_falcon_init(void)
{
return platform_driver_register(&pinctrl_falcon_driver);
}
diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c
index 3c660471ec69..79119cf20efc 100644
--- a/drivers/pinctrl/pinctrl-ingenic.c
+++ b/drivers/pinctrl/pinctrl-ingenic.c
@@ -4574,9 +4574,8 @@ static int __init ingenic_pinctrl_probe(struct platform_device *pdev)
const struct function_desc *function = &chip_info->functions[i];
const struct pinfunction *func = &function->func;
- err = pinmux_generic_add_function(jzpc->pctl, func->name,
- func->groups, func->ngroups,
- function->data);
+ err = pinmux_generic_add_pinfunction(jzpc->pctl, func,
+ function->data);
if (err < 0) {
dev_err(dev, "Failed to register function %s\n", func->name);
return err;
diff --git a/drivers/pinctrl/pinctrl-k210.c b/drivers/pinctrl/pinctrl-k210.c
index eddb01796a83..66c04120c29d 100644
--- a/drivers/pinctrl/pinctrl-k210.c
+++ b/drivers/pinctrl/pinctrl-k210.c
@@ -879,7 +879,7 @@ static const struct pinctrl_ops k210_pinctrl_ops = {
.dt_free_map = pinconf_generic_dt_free_map,
};
-static struct pinctrl_desc k210_pinctrl_desc = {
+static const struct pinctrl_desc k210_pinctrl_desc = {
.name = "k210-pinctrl",
.pins = k210_pins,
.npins = K210_NPINS,
diff --git a/drivers/pinctrl/pinctrl-k230.c b/drivers/pinctrl/pinctrl-k230.c
index a9b4627b46b0..d716f23d837f 100644
--- a/drivers/pinctrl/pinctrl-k230.c
+++ b/drivers/pinctrl/pinctrl-k230.c
@@ -477,6 +477,10 @@ static int k230_pinctrl_parse_groups(struct device_node *np,
grp->name = np->name;
list = of_get_property(np, "pinmux", &size);
+ if (!list) {
+ dev_err(dev, "failed to get pinmux property\n");
+ return -EINVAL;
+ }
size /= sizeof(*list);
grp->num_pins = size;
@@ -586,6 +590,7 @@ static int k230_pinctrl_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct k230_pinctrl *info;
struct pinctrl_desc *pctl;
+ int ret;
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
if (!info)
@@ -611,19 +616,21 @@ static int k230_pinctrl_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(info->regmap_base),
"failed to init regmap\n");
+ ret = k230_pinctrl_parse_dt(pdev, info);
+ if (ret)
+ return ret;
+
info->pctl_dev = devm_pinctrl_register(dev, pctl, info);
if (IS_ERR(info->pctl_dev))
return dev_err_probe(dev, PTR_ERR(info->pctl_dev),
"devm_pinctrl_register failed\n");
- k230_pinctrl_parse_dt(pdev, info);
-
return 0;
}
static const struct of_device_id k230_dt_ids[] = {
{ .compatible = "canaan,k230-pinctrl", },
- { /* sintenel */ }
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, k230_dt_ids);
diff --git a/drivers/pinctrl/pinctrl-keembay.c b/drivers/pinctrl/pinctrl-keembay.c
index 0d7cc8280ea2..30e641571cfe 100644
--- a/drivers/pinctrl/pinctrl-keembay.c
+++ b/drivers/pinctrl/pinctrl-keembay.c
@@ -1188,7 +1188,7 @@ static int keembay_gpio_get(struct gpio_chip *gc, unsigned int pin)
return keembay_read_pin(kpc->base0 + offset, pin);
}
-static void keembay_gpio_set(struct gpio_chip *gc, unsigned int pin, int val)
+static int keembay_gpio_set(struct gpio_chip *gc, unsigned int pin, int val)
{
struct keembay_pinctrl *kpc = gpiochip_get_data(gc);
unsigned int reg_val;
@@ -1200,6 +1200,8 @@ static void keembay_gpio_set(struct gpio_chip *gc, unsigned int pin, int val)
else
keembay_write_gpio_reg(~reg_val | BIT(pin % KEEMBAY_GPIO_MAX_PER_REG),
kpc->base0 + KEEMBAY_GPIO_DATA_LOW, pin);
+
+ return 0;
}
static int keembay_gpio_get_direction(struct gpio_chip *gc, unsigned int pin)
@@ -1231,9 +1233,8 @@ static int keembay_gpio_set_direction_out(struct gpio_chip *gc,
val = keembay_read_reg(kpc->base1 + KEEMBAY_GPIO_MODE, pin);
val &= ~KEEMBAY_GPIO_MODE_DIR;
keembay_write_reg(val, kpc->base1 + KEEMBAY_GPIO_MODE, pin);
- keembay_gpio_set(gc, pin, value);
- return 0;
+ return keembay_gpio_set(gc, pin, value);
}
static void keembay_gpio_irq_handler(struct irq_desc *desc)
@@ -1480,7 +1481,7 @@ static int keembay_gpiochip_probe(struct keembay_pinctrl *kpc,
gc->direction_input = keembay_gpio_set_direction_in;
gc->direction_output = keembay_gpio_set_direction_out;
gc->get = keembay_gpio_get;
- gc->set = keembay_gpio_set;
+ gc->set_rv = keembay_gpio_set;
gc->set_config = gpiochip_generic_config;
gc->base = -1;
gc->ngpio = kpc->npins;
@@ -1585,13 +1586,9 @@ static int keembay_add_functions(struct keembay_pinctrl *kpc,
}
/* Add all functions */
- for (i = 0; i < kpc->nfuncs; i++) {
- pinmux_generic_add_function(kpc->pctrl,
- functions[i].func.name,
- functions[i].func.groups,
- functions[i].func.ngroups,
- functions[i].data);
- }
+ for (i = 0; i < kpc->nfuncs; i++)
+ pinmux_generic_add_pinfunction(kpc->pctrl, &functions[i].func,
+ functions[i].data);
return 0;
}
diff --git a/drivers/pinctrl/pinctrl-lpc18xx.c b/drivers/pinctrl/pinctrl-lpc18xx.c
index 0f5a7bed2f81..5e0201768323 100644
--- a/drivers/pinctrl/pinctrl-lpc18xx.c
+++ b/drivers/pinctrl/pinctrl-lpc18xx.c
@@ -1257,7 +1257,7 @@ static const struct pinctrl_ops lpc18xx_pctl_ops = {
.dt_free_map = pinctrl_utils_free_map,
};
-static struct pinctrl_desc lpc18xx_scu_desc = {
+static const struct pinctrl_desc lpc18xx_scu_desc = {
.name = "lpc18xx/43xx-scu",
.pins = lpc18xx_pins,
.npins = ARRAY_SIZE(lpc18xx_pins),
diff --git a/drivers/pinctrl/pinctrl-max77620.c b/drivers/pinctrl/pinctrl-max77620.c
index d236daa7c13e..acb945a25743 100644
--- a/drivers/pinctrl/pinctrl-max77620.c
+++ b/drivers/pinctrl/pinctrl-max77620.c
@@ -543,6 +543,10 @@ static struct pinctrl_desc max77620_pinctrl_desc = {
.pctlops = &max77620_pinctrl_ops,
.pmxops = &max77620_pinmux_ops,
.confops = &max77620_pinconf_ops,
+ .pins = max77620_pins_desc,
+ .npins = ARRAY_SIZE(max77620_pins_desc),
+ .num_custom_params = ARRAY_SIZE(max77620_cfg_params),
+ .custom_params = max77620_cfg_params,
};
static int max77620_pinctrl_probe(struct platform_device *pdev)
@@ -569,11 +573,6 @@ static int max77620_pinctrl_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, mpci);
max77620_pinctrl_desc.name = dev_name(&pdev->dev);
- max77620_pinctrl_desc.pins = max77620_pins_desc;
- max77620_pinctrl_desc.npins = ARRAY_SIZE(max77620_pins_desc);
- max77620_pinctrl_desc.num_custom_params =
- ARRAY_SIZE(max77620_cfg_params);
- max77620_pinctrl_desc.custom_params = max77620_cfg_params;
for (i = 0; i < MAX77620_PIN_NUM; ++i) {
mpci->fps_config[i].active_fps_src = -1;
diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c
index c2f4b16f42d2..c8027ef03ecc 100644
--- a/drivers/pinctrl/pinctrl-mcp23s08.c
+++ b/drivers/pinctrl/pinctrl-mcp23s08.c
@@ -341,24 +341,30 @@ static int __mcp23s08_set(struct mcp23s08 *mcp, unsigned mask, bool value)
return mcp_update_bits(mcp, MCP_OLAT, mask, value ? mask : 0);
}
-static void mcp23s08_set(struct gpio_chip *chip, unsigned offset, int value)
+static int mcp23s08_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct mcp23s08 *mcp = gpiochip_get_data(chip);
unsigned mask = BIT(offset);
+ int ret;
mutex_lock(&mcp->lock);
- __mcp23s08_set(mcp, mask, !!value);
+ ret = __mcp23s08_set(mcp, mask, !!value);
mutex_unlock(&mcp->lock);
+
+ return ret;
}
-static void mcp23s08_set_multiple(struct gpio_chip *chip,
- unsigned long *mask, unsigned long *bits)
+static int mcp23s08_set_multiple(struct gpio_chip *chip,
+ unsigned long *mask, unsigned long *bits)
{
struct mcp23s08 *mcp = gpiochip_get_data(chip);
+ int ret;
mutex_lock(&mcp->lock);
- mcp_update_bits(mcp, MCP_OLAT, *mask, *bits);
+ ret = mcp_update_bits(mcp, MCP_OLAT, *mask, *bits);
mutex_unlock(&mcp->lock);
+
+ return ret;
}
static int
@@ -626,8 +632,8 @@ int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
mcp->chip.get = mcp23s08_get;
mcp->chip.get_multiple = mcp23s08_get_multiple;
mcp->chip.direction_output = mcp23s08_direction_output;
- mcp->chip.set = mcp23s08_set;
- mcp->chip.set_multiple = mcp23s08_set_multiple;
+ mcp->chip.set_rv = mcp23s08_set;
+ mcp->chip.set_multiple_rv = mcp23s08_set_multiple;
mcp->chip.base = base;
mcp->chip.can_sleep = true;
diff --git a/drivers/pinctrl/pinctrl-mlxbf3.c b/drivers/pinctrl/pinctrl-mlxbf3.c
index ffb5dda364dc..fcd9d46de89f 100644
--- a/drivers/pinctrl/pinctrl-mlxbf3.c
+++ b/drivers/pinctrl/pinctrl-mlxbf3.c
@@ -231,7 +231,7 @@ static const struct pinmux_ops mlxbf3_pmx_ops = {
.gpio_request_enable = mlxbf3_gpio_request_enable,
};
-static struct pinctrl_desc mlxbf3_pin_desc = {
+static const struct pinctrl_desc mlxbf3_pin_desc = {
.name = "pinctrl-mlxbf3",
.pins = mlxbf3_pins,
.npins = ARRAY_SIZE(mlxbf3_pins),
diff --git a/drivers/pinctrl/pinctrl-palmas.c b/drivers/pinctrl/pinctrl-palmas.c
index 9e272f9deb4f..d69f114e4642 100644
--- a/drivers/pinctrl/pinctrl-palmas.c
+++ b/drivers/pinctrl/pinctrl-palmas.c
@@ -956,6 +956,8 @@ static struct pinctrl_desc palmas_pinctrl_desc = {
.pmxops = &palmas_pinmux_ops,
.confops = &palmas_pinconf_ops,
.owner = THIS_MODULE,
+ .pins = palmas_pins_desc,
+ .npins = ARRAY_SIZE(palmas_pins_desc),
};
struct palmas_pinctrl_data {
@@ -1023,8 +1025,6 @@ static int palmas_pinctrl_probe(struct platform_device *pdev)
}
palmas_pinctrl_desc.name = dev_name(&pdev->dev);
- palmas_pinctrl_desc.pins = palmas_pins_desc;
- palmas_pinctrl_desc.npins = ARRAY_SIZE(palmas_pins_desc);
pci->pctl = devm_pinctrl_register(&pdev->dev, &palmas_pinctrl_desc,
pci);
if (IS_ERR(pci->pctl)) {
diff --git a/drivers/pinctrl/pinctrl-pic32.c b/drivers/pinctrl/pinctrl-pic32.c
index bf827ab081a1..6d64cab97e81 100644
--- a/drivers/pinctrl/pinctrl-pic32.c
+++ b/drivers/pinctrl/pinctrl-pic32.c
@@ -1828,8 +1828,8 @@ static int pic32_gpio_get(struct gpio_chip *chip, unsigned offset)
return !!(readl(bank->reg_base + PORT_REG) & BIT(offset));
}
-static void pic32_gpio_set(struct gpio_chip *chip, unsigned offset,
- int value)
+static int pic32_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct pic32_gpio_bank *bank = gpiochip_get_data(chip);
u32 mask = BIT(offset);
@@ -1838,6 +1838,8 @@ static void pic32_gpio_set(struct gpio_chip *chip, unsigned offset,
writel(mask, bank->reg_base + PIC32_SET(PORT_REG));
else
writel(mask, bank->reg_base + PIC32_CLR(PORT_REG));
+
+ return 0;
}
static int pic32_gpio_direction_output(struct gpio_chip *chip,
@@ -2118,7 +2120,7 @@ static void pic32_gpio_irq_handler(struct irq_desc *desc)
.direction_input = pic32_gpio_direction_input, \
.direction_output = pic32_gpio_direction_output, \
.get = pic32_gpio_get, \
- .set = pic32_gpio_set, \
+ .set_rv = pic32_gpio_set, \
.ngpio = _npins, \
.base = GPIO_BANK_START(_bank), \
.owner = THIS_MODULE, \
diff --git a/drivers/pinctrl/pinctrl-pistachio.c b/drivers/pinctrl/pinctrl-pistachio.c
index e7bf60960961..7f8b562c81c9 100644
--- a/drivers/pinctrl/pinctrl-pistachio.c
+++ b/drivers/pinctrl/pinctrl-pistachio.c
@@ -1156,11 +1156,14 @@ static const struct pinconf_ops pistachio_pinconf_ops = {
.is_generic = true,
};
-static struct pinctrl_desc pistachio_pinctrl_desc = {
+static const struct pinctrl_desc pistachio_pinctrl_desc = {
.name = "pistachio-pinctrl",
.pctlops = &pistachio_pinctrl_ops,
.pmxops = &pistachio_pinmux_ops,
.confops = &pistachio_pinconf_ops,
+ .pins = pistachio_pins,
+ .npins = ARRAY_SIZE(pistachio_pins),
+
};
static int pistachio_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
@@ -1474,9 +1477,6 @@ static int pistachio_pinctrl_probe(struct platform_device *pdev)
pctl->gpio_banks = pistachio_gpio_banks;
pctl->nbanks = ARRAY_SIZE(pistachio_gpio_banks);
- pistachio_pinctrl_desc.pins = pctl->pins;
- pistachio_pinctrl_desc.npins = pctl->npins;
-
pctl->pctldev = devm_pinctrl_register(&pdev->dev, &pistachio_pinctrl_desc,
pctl);
if (IS_ERR(pctl->pctldev)) {
diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c
index 8a2ef74862d3..574fe2cbfbec 100644
--- a/drivers/pinctrl/pinctrl-st.c
+++ b/drivers/pinctrl/pinctrl-st.c
@@ -706,10 +706,12 @@ static int st_gpio_get(struct gpio_chip *chip, unsigned offset)
return !!(readl(bank->base + REG_PIO_PIN) & BIT(offset));
}
-static void st_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static int st_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct st_gpio_bank *bank = gpiochip_get_data(chip);
__st_gpio_set(bank, offset, value);
+
+ return 0;
}
static int st_gpio_direction_output(struct gpio_chip *chip,
@@ -1465,7 +1467,7 @@ static const struct gpio_chip st_gpio_template = {
.request = gpiochip_generic_request,
.free = gpiochip_generic_free,
.get = st_gpio_get,
- .set = st_gpio_set,
+ .set_rv = st_gpio_set,
.direction_input = pinctrl_gpio_direction_input,
.direction_output = st_gpio_direction_output,
.get_direction = st_gpio_get_direction,
diff --git a/drivers/pinctrl/pinctrl-tb10x.c b/drivers/pinctrl/pinctrl-tb10x.c
index 4edb20e61951..129fa51d13b1 100644
--- a/drivers/pinctrl/pinctrl-tb10x.c
+++ b/drivers/pinctrl/pinctrl-tb10x.c
@@ -735,7 +735,7 @@ static const struct pinmux_ops tb10x_pinmux_ops = {
.set_mux = tb10x_pctl_set_mux,
};
-static struct pinctrl_desc tb10x_pindesc = {
+static const struct pinctrl_desc tb10x_pindesc = {
.name = "TB10x",
.pins = tb10x_pins,
.npins = ARRAY_SIZE(tb10x_pins),
diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c
index 48f8aabf3bfa..53c6c22ff24d 100644
--- a/drivers/pinctrl/pinctrl-xway.c
+++ b/drivers/pinctrl/pinctrl-xway.c
@@ -1228,10 +1228,10 @@ static int xway_pinconf_set(struct pinctrl_dev *pctldev,
return 0;
}
-int xway_pinconf_group_set(struct pinctrl_dev *pctldev,
- unsigned selector,
- unsigned long *configs,
- unsigned num_configs)
+static int xway_pinconf_group_set(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ unsigned long *configs,
+ unsigned int num_configs)
{
struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev);
int i, ret = 0;
@@ -1293,7 +1293,7 @@ static struct ltq_pinmux_info xway_info = {
};
/* --------- gpio_chip related code --------- */
-static void xway_gpio_set(struct gpio_chip *chip, unsigned int pin, int val)
+static int xway_gpio_set(struct gpio_chip *chip, unsigned int pin, int val)
{
struct ltq_pinmux_info *info = dev_get_drvdata(chip->parent);
@@ -1301,6 +1301,8 @@ static void xway_gpio_set(struct gpio_chip *chip, unsigned int pin, int val)
gpio_setbit(info->membase[0], GPIO_OUT(pin), PORT_PIN(pin));
else
gpio_clearbit(info->membase[0], GPIO_OUT(pin), PORT_PIN(pin));
+
+ return 0;
}
static int xway_gpio_get(struct gpio_chip *chip, unsigned int pin)
@@ -1328,9 +1330,7 @@ static int xway_gpio_dir_out(struct gpio_chip *chip, unsigned int pin, int val)
else
gpio_setbit(info->membase[0], GPIO_OD(pin), PORT_PIN(pin));
gpio_setbit(info->membase[0], GPIO_DIR(pin), PORT_PIN(pin));
- xway_gpio_set(chip, pin, val);
-
- return 0;
+ return xway_gpio_set(chip, pin, val);
}
/*
@@ -1354,7 +1354,7 @@ static struct gpio_chip xway_chip = {
.direction_input = xway_gpio_dir_in,
.direction_output = xway_gpio_dir_out,
.get = xway_gpio_get,
- .set = xway_gpio_set,
+ .set_rv = xway_gpio_set,
.request = gpiochip_generic_request,
.free = gpiochip_generic_free,
.to_irq = xway_gpio_to_irq,
diff --git a/drivers/pinctrl/pinctrl-zynq.c b/drivers/pinctrl/pinctrl-zynq.c
index caa8a2ca3e68..dcde86fed10d 100644
--- a/drivers/pinctrl/pinctrl-zynq.c
+++ b/drivers/pinctrl/pinctrl-zynq.c
@@ -1143,7 +1143,7 @@ static const struct pinconf_ops zynq_pinconf_ops = {
.pin_config_group_set = zynq_pinconf_group_set,
};
-static struct pinctrl_desc zynq_desc = {
+static const struct pinctrl_desc zynq_desc = {
.name = "zynq_pinctrl",
.pins = zynq_pins,
.npins = ARRAY_SIZE(zynq_pins),
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
index 0743190da59e..79814758a084 100644
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -236,18 +236,7 @@ static const char *pin_free(struct pinctrl_dev *pctldev, int pin,
if (desc->mux_usecount)
return NULL;
}
- }
-
- /*
- * If there is no kind of request function for the pin we just assume
- * we got it by default and proceed.
- */
- if (gpio_range && ops->gpio_disable_free)
- ops->gpio_disable_free(pctldev, gpio_range, pin);
- else if (ops->free)
- ops->free(pctldev, pin);
- scoped_guard(mutex, &desc->mux_lock) {
if (gpio_range) {
owner = desc->gpio_owner;
desc->gpio_owner = NULL;
@@ -258,6 +247,15 @@ static const char *pin_free(struct pinctrl_dev *pctldev, int pin,
}
}
+ /*
+ * If there is no kind of request function for the pin we just assume
+ * we got it by default and proceed.
+ */
+ if (gpio_range && ops->gpio_disable_free)
+ ops->gpio_disable_free(pctldev, gpio_range, pin);
+ else if (ops->free)
+ ops->free(pctldev, pin);
+
module_put(pctldev->owner);
return owner;
@@ -877,13 +875,25 @@ int pinmux_generic_add_function(struct pinctrl_dev *pctldev,
const unsigned int ngroups,
void *data)
{
+ struct pinfunction func = PINCTRL_PINFUNCTION(name, groups, ngroups);
+
+ return pinmux_generic_add_pinfunction(pctldev, &func, data);
+}
+EXPORT_SYMBOL_GPL(pinmux_generic_add_function);
+
+/**
+ * pinmux_generic_add_pinfunction() - adds a function group
+ * @pctldev: pin controller device
+ * @func: pinfunction structure describing the function group
+ * @data: pin controller driver specific data
+ */
+int pinmux_generic_add_pinfunction(struct pinctrl_dev *pctldev,
+ const struct pinfunction *func, void *data)
+{
struct function_desc *function;
int selector, error;
- if (!name)
- return -EINVAL;
-
- selector = pinmux_func_name_to_selector(pctldev, name);
+ selector = pinmux_func_name_to_selector(pctldev, func->name);
if (selector >= 0)
return selector;
@@ -893,7 +903,8 @@ int pinmux_generic_add_function(struct pinctrl_dev *pctldev,
if (!function)
return -ENOMEM;
- *function = PINCTRL_FUNCTION_DESC(name, groups, ngroups, data);
+ function->func = *func;
+ function->data = data;
error = radix_tree_insert(&pctldev->pin_function_tree, selector, function);
if (error)
@@ -903,7 +914,7 @@ int pinmux_generic_add_function(struct pinctrl_dev *pctldev,
return selector;
}
-EXPORT_SYMBOL_GPL(pinmux_generic_add_function);
+EXPORT_SYMBOL_GPL(pinmux_generic_add_pinfunction);
/**
* pinmux_generic_remove_function() - removes a numbered function
diff --git a/drivers/pinctrl/pinmux.h b/drivers/pinctrl/pinmux.h
index 2965ec20b77f..bdb5be1a636e 100644
--- a/drivers/pinctrl/pinmux.h
+++ b/drivers/pinctrl/pinmux.h
@@ -141,13 +141,6 @@ struct function_desc {
void *data;
};
-/* Convenient macro to define a generic pin function descriptor */
-#define PINCTRL_FUNCTION_DESC(_name, _grps, _num_grps, _data) \
-(struct function_desc) { \
- .func = PINCTRL_PINFUNCTION(_name, _grps, _num_grps), \
- .data = _data, \
-}
-
int pinmux_generic_get_function_count(struct pinctrl_dev *pctldev);
const char *
@@ -168,6 +161,9 @@ int pinmux_generic_add_function(struct pinctrl_dev *pctldev,
unsigned int const ngroups,
void *data);
+int pinmux_generic_add_pinfunction(struct pinctrl_dev *pctldev,
+ const struct pinfunction *func, void *data);
+
int pinmux_generic_remove_function(struct pinctrl_dev *pctldev,
unsigned int selector);
diff --git a/drivers/pinctrl/qcom/Kconfig.msm b/drivers/pinctrl/qcom/Kconfig.msm
index 0bb44c9a4c06..6dad942b00a3 100644
--- a/drivers/pinctrl/qcom/Kconfig.msm
+++ b/drivers/pinctrl/qcom/Kconfig.msm
@@ -371,6 +371,14 @@ config PINCTRL_SM7150
Qualcomm Technologies Inc TLMM block found on the Qualcomm
Technologies Inc SM7150 platform.
+config PINCTRL_MILOS
+ tristate "Qualcomm Technologies Inc Milos pin controller driver"
+ depends on ARM64 || COMPILE_TEST
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm Technologies Inc TLMM block found on the Qualcomm
+ Technologies Inc Milos platform.
+
config PINCTRL_SM8150
tristate "Qualcomm Technologies Inc SM8150 pin controller driver"
depends on ARM64 || COMPILE_TEST
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 954f5291cc37..2acff520a285 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_PINCTRL_QCS8300) += pinctrl-qcs8300.o
obj-$(CONFIG_PINCTRL_QDF2XXX) += pinctrl-qdf2xxx.o
obj-$(CONFIG_PINCTRL_MDM9607) += pinctrl-mdm9607.o
obj-$(CONFIG_PINCTRL_MDM9615) += pinctrl-mdm9615.o
+obj-$(CONFIG_PINCTRL_MILOS) += pinctrl-milos.o
obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o
obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o
obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o
diff --git a/drivers/pinctrl/qcom/pinctrl-milos.c b/drivers/pinctrl/qcom/pinctrl-milos.c
new file mode 100644
index 000000000000..d11a7bbcd733
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-milos.c
@@ -0,0 +1,1339 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2025, Luca Weiss <luca.weiss@fairphone.com>
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-msm.h"
+
+#define REG_SIZE 0x1000
+
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11) \
+ { \
+ .grp = PINCTRL_PINGROUP("gpio" #id, \
+ gpio##id##_pins, \
+ ARRAY_SIZE(gpio##id##_pins)), \
+ .funcs = (int[]){ \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9, \
+ msm_mux_##f10, \
+ msm_mux_##f11 /* egpio mode */ \
+ }, \
+ .nfuncs = 12, \
+ .ctl_reg = REG_SIZE * id, \
+ .io_reg = 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = 0x8 + REG_SIZE * id, \
+ .intr_status_reg = 0xc + REG_SIZE * id, \
+ .intr_target_reg = 0x8 + REG_SIZE * id, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .i2c_pull_bit = 13, \
+ .egpio_enable = 12, \
+ .egpio_present = 11, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_target_bit = 8, \
+ .intr_wakeup_enable_bit = 7, \
+ .intr_wakeup_present_bit = 6, \
+ .intr_target_kpss_val = 3, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .grp = PINCTRL_PINGROUP(#pg_name, \
+ pg_name##_pins, \
+ ARRAY_SIZE(pg_name##_pins)), \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+#define UFS_RESET(pg_name, ctl, io) \
+ { \
+ .grp = PINCTRL_PINGROUP(#pg_name, \
+ pg_name##_pins, \
+ ARRAY_SIZE(pg_name##_pins)), \
+ .ctl_reg = ctl, \
+ .io_reg = io, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = 3, \
+ .drv_bit = 0, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = 0, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+static const struct pinctrl_pin_desc milos_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+ PINCTRL_PIN(53, "GPIO_53"),
+ PINCTRL_PIN(54, "GPIO_54"),
+ PINCTRL_PIN(55, "GPIO_55"),
+ PINCTRL_PIN(56, "GPIO_56"),
+ PINCTRL_PIN(57, "GPIO_57"),
+ PINCTRL_PIN(58, "GPIO_58"),
+ PINCTRL_PIN(59, "GPIO_59"),
+ PINCTRL_PIN(60, "GPIO_60"),
+ PINCTRL_PIN(61, "GPIO_61"),
+ PINCTRL_PIN(62, "GPIO_62"),
+ PINCTRL_PIN(63, "GPIO_63"),
+ PINCTRL_PIN(64, "GPIO_64"),
+ PINCTRL_PIN(65, "GPIO_65"),
+ PINCTRL_PIN(66, "GPIO_66"),
+ PINCTRL_PIN(67, "GPIO_67"),
+ PINCTRL_PIN(68, "GPIO_68"),
+ PINCTRL_PIN(69, "GPIO_69"),
+ PINCTRL_PIN(70, "GPIO_70"),
+ PINCTRL_PIN(71, "GPIO_71"),
+ PINCTRL_PIN(72, "GPIO_72"),
+ PINCTRL_PIN(73, "GPIO_73"),
+ PINCTRL_PIN(74, "GPIO_74"),
+ PINCTRL_PIN(75, "GPIO_75"),
+ PINCTRL_PIN(76, "GPIO_76"),
+ PINCTRL_PIN(77, "GPIO_77"),
+ PINCTRL_PIN(78, "GPIO_78"),
+ PINCTRL_PIN(79, "GPIO_79"),
+ PINCTRL_PIN(80, "GPIO_80"),
+ PINCTRL_PIN(81, "GPIO_81"),
+ PINCTRL_PIN(82, "GPIO_82"),
+ PINCTRL_PIN(83, "GPIO_83"),
+ PINCTRL_PIN(84, "GPIO_84"),
+ PINCTRL_PIN(85, "GPIO_85"),
+ PINCTRL_PIN(86, "GPIO_86"),
+ PINCTRL_PIN(87, "GPIO_87"),
+ PINCTRL_PIN(88, "GPIO_88"),
+ PINCTRL_PIN(89, "GPIO_89"),
+ PINCTRL_PIN(90, "GPIO_90"),
+ PINCTRL_PIN(91, "GPIO_91"),
+ PINCTRL_PIN(92, "GPIO_92"),
+ PINCTRL_PIN(93, "GPIO_93"),
+ PINCTRL_PIN(94, "GPIO_94"),
+ PINCTRL_PIN(95, "GPIO_95"),
+ PINCTRL_PIN(96, "GPIO_96"),
+ PINCTRL_PIN(97, "GPIO_97"),
+ PINCTRL_PIN(98, "GPIO_98"),
+ PINCTRL_PIN(99, "GPIO_99"),
+ PINCTRL_PIN(100, "GPIO_100"),
+ PINCTRL_PIN(101, "GPIO_101"),
+ PINCTRL_PIN(102, "GPIO_102"),
+ PINCTRL_PIN(103, "GPIO_103"),
+ PINCTRL_PIN(104, "GPIO_104"),
+ PINCTRL_PIN(105, "GPIO_105"),
+ PINCTRL_PIN(106, "GPIO_106"),
+ PINCTRL_PIN(107, "GPIO_107"),
+ PINCTRL_PIN(108, "GPIO_108"),
+ PINCTRL_PIN(109, "GPIO_109"),
+ PINCTRL_PIN(110, "GPIO_110"),
+ PINCTRL_PIN(111, "GPIO_111"),
+ PINCTRL_PIN(112, "GPIO_112"),
+ PINCTRL_PIN(113, "GPIO_113"),
+ PINCTRL_PIN(114, "GPIO_114"),
+ PINCTRL_PIN(115, "GPIO_115"),
+ PINCTRL_PIN(116, "GPIO_116"),
+ PINCTRL_PIN(117, "GPIO_117"),
+ PINCTRL_PIN(118, "GPIO_118"),
+ PINCTRL_PIN(119, "GPIO_119"),
+ PINCTRL_PIN(120, "GPIO_120"),
+ PINCTRL_PIN(121, "GPIO_121"),
+ PINCTRL_PIN(122, "GPIO_122"),
+ PINCTRL_PIN(123, "GPIO_123"),
+ PINCTRL_PIN(124, "GPIO_124"),
+ PINCTRL_PIN(125, "GPIO_125"),
+ PINCTRL_PIN(126, "GPIO_126"),
+ PINCTRL_PIN(127, "GPIO_127"),
+ PINCTRL_PIN(128, "GPIO_128"),
+ PINCTRL_PIN(129, "GPIO_129"),
+ PINCTRL_PIN(130, "GPIO_130"),
+ PINCTRL_PIN(131, "GPIO_131"),
+ PINCTRL_PIN(132, "GPIO_132"),
+ PINCTRL_PIN(133, "GPIO_133"),
+ PINCTRL_PIN(134, "GPIO_134"),
+ PINCTRL_PIN(135, "GPIO_135"),
+ PINCTRL_PIN(136, "GPIO_136"),
+ PINCTRL_PIN(137, "GPIO_137"),
+ PINCTRL_PIN(138, "GPIO_138"),
+ PINCTRL_PIN(139, "GPIO_139"),
+ PINCTRL_PIN(140, "GPIO_140"),
+ PINCTRL_PIN(141, "GPIO_141"),
+ PINCTRL_PIN(142, "GPIO_142"),
+ PINCTRL_PIN(143, "GPIO_143"),
+ PINCTRL_PIN(144, "GPIO_144"),
+ PINCTRL_PIN(145, "GPIO_145"),
+ PINCTRL_PIN(146, "GPIO_146"),
+ PINCTRL_PIN(147, "GPIO_147"),
+ PINCTRL_PIN(148, "GPIO_148"),
+ PINCTRL_PIN(149, "GPIO_149"),
+ PINCTRL_PIN(150, "GPIO_150"),
+ PINCTRL_PIN(151, "GPIO_151"),
+ PINCTRL_PIN(152, "GPIO_152"),
+ PINCTRL_PIN(153, "GPIO_153"),
+ PINCTRL_PIN(154, "GPIO_154"),
+ PINCTRL_PIN(155, "GPIO_155"),
+ PINCTRL_PIN(156, "GPIO_156"),
+ PINCTRL_PIN(157, "GPIO_157"),
+ PINCTRL_PIN(158, "GPIO_158"),
+ PINCTRL_PIN(159, "GPIO_159"),
+ PINCTRL_PIN(160, "GPIO_160"),
+ PINCTRL_PIN(161, "GPIO_161"),
+ PINCTRL_PIN(162, "GPIO_162"),
+ PINCTRL_PIN(163, "GPIO_163"),
+ PINCTRL_PIN(164, "GPIO_164"),
+ PINCTRL_PIN(165, "GPIO_165"),
+ PINCTRL_PIN(166, "GPIO_166"),
+ PINCTRL_PIN(167, "UFS_RESET"),
+ PINCTRL_PIN(168, "SDC2_CLK"),
+ PINCTRL_PIN(169, "SDC2_CMD"),
+ PINCTRL_PIN(170, "SDC2_DATA"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+ static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+DECLARE_MSM_GPIO_PINS(134);
+DECLARE_MSM_GPIO_PINS(135);
+DECLARE_MSM_GPIO_PINS(136);
+DECLARE_MSM_GPIO_PINS(137);
+DECLARE_MSM_GPIO_PINS(138);
+DECLARE_MSM_GPIO_PINS(139);
+DECLARE_MSM_GPIO_PINS(140);
+DECLARE_MSM_GPIO_PINS(141);
+DECLARE_MSM_GPIO_PINS(142);
+DECLARE_MSM_GPIO_PINS(143);
+DECLARE_MSM_GPIO_PINS(144);
+DECLARE_MSM_GPIO_PINS(145);
+DECLARE_MSM_GPIO_PINS(146);
+DECLARE_MSM_GPIO_PINS(147);
+DECLARE_MSM_GPIO_PINS(148);
+DECLARE_MSM_GPIO_PINS(149);
+DECLARE_MSM_GPIO_PINS(150);
+DECLARE_MSM_GPIO_PINS(151);
+DECLARE_MSM_GPIO_PINS(152);
+DECLARE_MSM_GPIO_PINS(153);
+DECLARE_MSM_GPIO_PINS(154);
+DECLARE_MSM_GPIO_PINS(155);
+DECLARE_MSM_GPIO_PINS(156);
+DECLARE_MSM_GPIO_PINS(157);
+DECLARE_MSM_GPIO_PINS(158);
+DECLARE_MSM_GPIO_PINS(159);
+DECLARE_MSM_GPIO_PINS(160);
+DECLARE_MSM_GPIO_PINS(161);
+DECLARE_MSM_GPIO_PINS(162);
+DECLARE_MSM_GPIO_PINS(163);
+DECLARE_MSM_GPIO_PINS(164);
+DECLARE_MSM_GPIO_PINS(165);
+DECLARE_MSM_GPIO_PINS(166);
+
+static const unsigned int ufs_reset_pins[] = { 167 };
+static const unsigned int sdc2_clk_pins[] = { 168 };
+static const unsigned int sdc2_cmd_pins[] = { 169 };
+static const unsigned int sdc2_data_pins[] = { 170 };
+
+enum milos_functions {
+ msm_mux_gpio,
+ msm_mux_aoss_cti,
+ msm_mux_atest_char,
+ msm_mux_atest_usb,
+ msm_mux_audio_ext_mclk0,
+ msm_mux_audio_ext_mclk1,
+ msm_mux_audio_ref_clk,
+ msm_mux_cam_mclk,
+ msm_mux_cci_async_in0,
+ msm_mux_cci_i2c_scl,
+ msm_mux_cci_i2c_sda,
+ msm_mux_cci_timer,
+ msm_mux_coex_uart1_rx,
+ msm_mux_coex_uart1_tx,
+ msm_mux_dbg_out_clk,
+ msm_mux_ddr_bist_complete,
+ msm_mux_ddr_bist_fail,
+ msm_mux_ddr_bist_start,
+ msm_mux_ddr_bist_stop,
+ msm_mux_ddr_pxi0,
+ msm_mux_ddr_pxi1,
+ msm_mux_dp0_hot,
+ msm_mux_egpio,
+ msm_mux_gcc_gp1,
+ msm_mux_gcc_gp2,
+ msm_mux_gcc_gp3,
+ msm_mux_host2wlan_sol,
+ msm_mux_i2s0_data0,
+ msm_mux_i2s0_data1,
+ msm_mux_i2s0_sck,
+ msm_mux_i2s0_ws,
+ msm_mux_ibi_i3c,
+ msm_mux_jitter_bist,
+ msm_mux_mdp_vsync,
+ msm_mux_mdp_vsync0_out,
+ msm_mux_mdp_vsync1_out,
+ msm_mux_mdp_vsync2_out,
+ msm_mux_mdp_vsync3_out,
+ msm_mux_mdp_vsync_e,
+ msm_mux_nav_gpio0,
+ msm_mux_nav_gpio1,
+ msm_mux_nav_gpio2,
+ msm_mux_pcie0_clk_req_n,
+ msm_mux_pcie1_clk_req_n,
+ msm_mux_phase_flag,
+ msm_mux_pll_bist_sync,
+ msm_mux_pll_clk_aux,
+ msm_mux_prng_rosc0,
+ msm_mux_prng_rosc1,
+ msm_mux_prng_rosc2,
+ msm_mux_prng_rosc3,
+ msm_mux_qdss_cti,
+ msm_mux_qdss_gpio,
+ msm_mux_qlink0_enable,
+ msm_mux_qlink0_request,
+ msm_mux_qlink0_wmss,
+ msm_mux_qlink1_enable,
+ msm_mux_qlink1_request,
+ msm_mux_qlink1_wmss,
+ msm_mux_qspi0,
+ msm_mux_qup0_se0,
+ msm_mux_qup0_se1,
+ msm_mux_qup0_se2,
+ msm_mux_qup0_se3,
+ msm_mux_qup0_se4,
+ msm_mux_qup0_se5,
+ msm_mux_qup0_se6,
+ msm_mux_qup1_se0,
+ msm_mux_qup1_se1,
+ msm_mux_qup1_se2,
+ msm_mux_qup1_se3,
+ msm_mux_qup1_se4,
+ msm_mux_qup1_se5,
+ msm_mux_qup1_se6,
+ msm_mux_resout_gpio_n,
+ msm_mux_sd_write_protect,
+ msm_mux_sdc1_clk,
+ msm_mux_sdc1_cmd,
+ msm_mux_sdc1_data,
+ msm_mux_sdc1_rclk,
+ msm_mux_sdc2_clk,
+ msm_mux_sdc2_cmd,
+ msm_mux_sdc2_data,
+ msm_mux_sdc2_fb_clk,
+ msm_mux_tb_trig_sdc1,
+ msm_mux_tb_trig_sdc2,
+ msm_mux_tgu_ch0_trigout,
+ msm_mux_tgu_ch1_trigout,
+ msm_mux_tmess_prng0,
+ msm_mux_tmess_prng1,
+ msm_mux_tmess_prng2,
+ msm_mux_tmess_prng3,
+ msm_mux_tsense_pwm1,
+ msm_mux_tsense_pwm2,
+ msm_mux_uim0_clk,
+ msm_mux_uim0_data,
+ msm_mux_uim0_present,
+ msm_mux_uim0_reset,
+ msm_mux_uim1_clk_mira,
+ msm_mux_uim1_clk_mirb,
+ msm_mux_uim1_data_mira,
+ msm_mux_uim1_data_mirb,
+ msm_mux_uim1_present_mira,
+ msm_mux_uim1_present_mirb,
+ msm_mux_uim1_reset_mira,
+ msm_mux_uim1_reset_mirb,
+ msm_mux_usb0_hs,
+ msm_mux_usb0_phy_ps,
+ msm_mux_vfr_0,
+ msm_mux_vfr_1,
+ msm_mux_vsense_trigger_mirnat,
+ msm_mux_wcn_sw,
+ msm_mux_wcn_sw_ctrl,
+ msm_mux__,
+};
+
+static const char *const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5",
+ "gpio6", "gpio7", "gpio8", "gpio9", "gpio10", "gpio11",
+ "gpio12", "gpio13", "gpio14", "gpio15", "gpio16", "gpio17",
+ "gpio18", "gpio19", "gpio20", "gpio21", "gpio22", "gpio23",
+ "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29",
+ "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+ "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41",
+ "gpio42", "gpio43", "gpio44", "gpio45", "gpio46", "gpio47",
+ "gpio48", "gpio49", "gpio50", "gpio51", "gpio52", "gpio53",
+ "gpio54", "gpio55", "gpio56", "gpio57", "gpio58", "gpio59",
+ "gpio60", "gpio61", "gpio62", "gpio63", "gpio64", "gpio65",
+ "gpio66", "gpio67", "gpio68", "gpio69", "gpio70", "gpio71",
+ "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+ "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83",
+ "gpio84", "gpio85", "gpio86", "gpio87", "gpio88", "gpio89",
+ "gpio90", "gpio91", "gpio92", "gpio93", "gpio94", "gpio95",
+ "gpio96", "gpio97", "gpio98", "gpio99", "gpio100", "gpio101",
+ "gpio102", "gpio103", "gpio104", "gpio105", "gpio106", "gpio107",
+ "gpio108", "gpio109", "gpio110", "gpio111", "gpio112", "gpio113",
+ "gpio114", "gpio115", "gpio116", "gpio117", "gpio118", "gpio119",
+ "gpio120", "gpio121", "gpio122", "gpio123", "gpio124", "gpio125",
+ "gpio126", "gpio127", "gpio128", "gpio129", "gpio130", "gpio131",
+ "gpio132", "gpio133", "gpio134", "gpio135", "gpio136", "gpio137",
+ "gpio138", "gpio139", "gpio140", "gpio141", "gpio142", "gpio143",
+ "gpio144", "gpio145", "gpio146", "gpio147", "gpio148", "gpio149",
+ "gpio150", "gpio151", "gpio152", "gpio153", "gpio154", "gpio155",
+ "gpio156", "gpio157", "gpio158", "gpio159", "gpio160", "gpio161",
+ "gpio162", "gpio163", "gpio164", "gpio165", "gpio166",
+};
+static const char *const resout_gpio_n_groups[] = {
+ "gpio39",
+};
+static const char *const sdc1_clk_groups[] = {
+ "gpio77",
+};
+static const char *const sdc1_cmd_groups[] = {
+ "gpio78",
+};
+static const char *const sdc1_data_groups[] = {
+ "gpio73", "gpio74", "gpio75", "gpio76", "gpio79", "gpio80",
+ "gpio81", "gpio82",
+};
+static const char *const sdc1_rclk_groups[] = {
+ "gpio72",
+};
+static const char *const aoss_cti_groups[] = {
+ "gpio0",
+ "gpio1",
+ "gpio4",
+ "gpio5",
+};
+static const char *const atest_char_groups[] = {
+ "gpio44", "gpio45", "gpio46", "gpio47", "gpio63",
+};
+static const char *const atest_usb_groups[] = {
+ "gpio23", "gpio24", "gpio60",
+};
+static const char *const audio_ext_mclk0_groups[] = {
+ "gpio23",
+};
+static const char *const audio_ext_mclk1_groups[] = {
+ "gpio24",
+};
+static const char *const audio_ref_clk_groups[] = {
+ "gpio24",
+};
+static const char *const cam_mclk_groups[] = {
+ "gpio83", "gpio84", "gpio85", "gpio86", "gpio87",
+};
+static const char *const cci_async_in0_groups[] = {
+ "gpio86",
+};
+static const char *const cci_i2c_scl_groups[] = {
+ "gpio89", "gpio91", "gpio93", "gpio95",
+};
+static const char *const cci_i2c_sda_groups[] = {
+ "gpio88", "gpio90", "gpio92", "gpio94",
+};
+static const char *const cci_timer_groups[] = {
+ "gpio77", "gpio83", "gpio84", "gpio85",
+};
+static const char *const coex_uart1_rx_groups[] = {
+ "gpio64",
+};
+static const char *const coex_uart1_tx_groups[] = {
+ "gpio63",
+};
+static const char *const dbg_out_clk_groups[] = {
+ "gpio24",
+};
+static const char *const ddr_bist_complete_groups[] = {
+ "gpio137",
+};
+static const char *const ddr_bist_fail_groups[] = {
+ "gpio56",
+};
+static const char *const ddr_bist_start_groups[] = {
+ "gpio133",
+};
+static const char *const ddr_bist_stop_groups[] = {
+ "gpio47",
+};
+static const char *const ddr_pxi0_groups[] = {
+ "gpio23",
+ "gpio24",
+};
+static const char *const ddr_pxi1_groups[] = {
+ "gpio50",
+ "gpio51",
+};
+static const char *const dp0_hot_groups[] = {
+ "gpio75",
+};
+static const char *const egpio_groups[] = {
+ "gpio132", "gpio133", "gpio134", "gpio135", "gpio136", "gpio137",
+ "gpio138", "gpio139", "gpio140", "gpio141", "gpio142", "gpio143",
+ "gpio144", "gpio145", "gpio146", "gpio147", "gpio148", "gpio149",
+ "gpio150", "gpio151", "gpio152", "gpio153", "gpio154", "gpio155",
+ "gpio156", "gpio157", "gpio158", "gpio159", "gpio160", "gpio161",
+ "gpio162", "gpio163", "gpio164", "gpio165", "gpio166",
+};
+static const char *const gcc_gp1_groups[] = {
+ "gpio29",
+ "gpio32",
+};
+static const char *const gcc_gp2_groups[] = {
+ "gpio28",
+ "gpio30",
+};
+static const char *const gcc_gp3_groups[] = {
+ "gpio31",
+ "gpio33",
+};
+static const char *const host2wlan_sol_groups[] = {
+ "gpio46",
+};
+static const char *const i2s0_data0_groups[] = {
+ "gpio16",
+};
+static const char *const i2s0_data1_groups[] = {
+ "gpio17",
+};
+static const char *const i2s0_sck_groups[] = {
+ "gpio15",
+};
+static const char *const i2s0_ws_groups[] = {
+ "gpio18",
+};
+static const char *const ibi_i3c_groups[] = {
+ "gpio0", "gpio1", "gpio4", "gpio5",
+ "gpio32", "gpio33", "gpio36", "gpio37",
+};
+static const char *const jitter_bist_groups[] = {
+ "gpio141",
+};
+static const char *const mdp_vsync_groups[] = {
+ "gpio19",
+ "gpio37",
+ "gpio72",
+ "gpio129",
+};
+static const char *const mdp_vsync0_out_groups[] = {
+ "gpio12",
+};
+static const char *const mdp_vsync1_out_groups[] = {
+ "gpio12",
+};
+static const char *const mdp_vsync2_out_groups[] = {
+ "gpio40",
+};
+static const char *const mdp_vsync3_out_groups[] = {
+ "gpio40",
+};
+static const char *const mdp_vsync_e_groups[] = {
+ "gpio45",
+};
+static const char *const nav_gpio0_groups[] = {
+ "gpio124",
+};
+static const char *const nav_gpio1_groups[] = {
+ "gpio125",
+};
+static const char *const nav_gpio2_groups[] = {
+ "gpio126",
+};
+static const char *const pcie0_clk_req_n_groups[] = {
+ "gpio67",
+};
+static const char *const pcie1_clk_req_n_groups[] = {
+ "gpio70",
+};
+static const char *const phase_flag_groups[] = {
+ "gpio8", "gpio9", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio18", "gpio26", "gpio38", "gpio39",
+ "gpio40", "gpio41", "gpio42", "gpio43", "gpio44", "gpio45",
+ "gpio46", "gpio47", "gpio48", "gpio49", "gpio63", "gpio64",
+ "gpio127", "gpio138", "gpio139", "gpio140", "gpio142", "gpio143",
+ "gpio144", "gpio147",
+};
+static const char *const pll_bist_sync_groups[] = {
+ "gpio26",
+};
+static const char *const pll_clk_aux_groups[] = {
+ "gpio36",
+};
+static const char *const prng_rosc0_groups[] = {
+ "gpio66",
+};
+static const char *const prng_rosc1_groups[] = {
+ "gpio67",
+};
+static const char *const prng_rosc2_groups[] = {
+ "gpio68",
+};
+static const char *const prng_rosc3_groups[] = {
+ "gpio69",
+};
+static const char *const qdss_cti_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio44", "gpio45", "gpio54", "gpio87",
+};
+static const char *const qdss_gpio_groups[] = {
+ "gpio40", "gpio41", "gpio42", "gpio43", "gpio46", "gpio47",
+ "gpio48", "gpio49", "gpio50", "gpio51", "gpio52", "gpio53",
+ "gpio83", "gpio84", "gpio85", "gpio86", "gpio88", "gpio89",
+ "gpio138", "gpio139", "gpio140", "gpio141", "gpio149", "gpio150",
+ "gpio155", "gpio156", "gpio157", "gpio158", "gpio159", "gpio160",
+ "gpio161", "gpio162", "gpio163", "gpio164", "gpio165", "gpio166",
+};
+static const char *const qlink0_enable_groups[] = {
+ "gpio105",
+};
+static const char *const qlink0_request_groups[] = {
+ "gpio104",
+};
+static const char *const qlink0_wmss_groups[] = {
+ "gpio106",
+};
+static const char *const qlink1_enable_groups[] = {
+ "gpio108",
+};
+static const char *const qlink1_request_groups[] = {
+ "gpio107",
+};
+static const char *const qlink1_wmss_groups[] = {
+ "gpio109",
+};
+static const char *const qspi0_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+};
+static const char *const qup0_se0_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char *const qup0_se1_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char *const qup0_se2_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+};
+static const char *const qup0_se3_groups[] = {
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio23", "gpio24", "gpio26",
+};
+static const char *const qup0_se4_groups[] = {
+ "gpio19", "gpio20", "gpio21", "gpio22",
+};
+static const char *const qup0_se5_groups[] = {
+ "gpio23", "gpio24", "gpio25", "gpio26",
+};
+static const char *const qup0_se6_groups[] = {
+ "gpio27", "gpio28", "gpio29", "gpio30", "gpio31",
+};
+static const char *const qup1_se0_groups[] = {
+ "gpio32", "gpio33", "gpio94", "gpio95",
+};
+static const char *const qup1_se1_groups[] = {
+ "gpio36", "gpio37", "gpio38", "gpio39",
+};
+static const char *const qup1_se2_groups[] = {
+ "gpio36", "gpio37", "gpio38", "gpio40", "gpio41", "gpio42", "gpio43",
+};
+static const char *const qup1_se3_groups[] = {
+ "gpio92", "gpio93", "gpio94", "gpio95",
+};
+static const char *const qup1_se4_groups[] = {
+ "gpio48", "gpio49", "gpio50", "gpio51", "gpio52", "gpio53", "gpio54",
+};
+static const char *const qup1_se5_groups[] = {
+ "gpio55", "gpio56", "gpio59", "gpio60",
+};
+static const char *const qup1_se6_groups[] = {
+ "gpio55", "gpio56", "gpio59", "gpio60", "gpio90", "gpio91",
+};
+static const char *const sd_write_protect_groups[] = {
+ "gpio4",
+};
+static const char *const sdc2_data_groups[] = {
+ "gpio34",
+ "gpio35",
+ "gpio57",
+ "gpio58",
+};
+static const char *const sdc2_clk_groups[] = {
+ "gpio62",
+};
+static const char *const sdc2_cmd_groups[] = {
+ "gpio61",
+};
+static const char *const sdc2_fb_clk_groups[] = {
+ "gpio128",
+};
+static const char *const tb_trig_sdc1_groups[] = {
+ "gpio87",
+};
+static const char *const tb_trig_sdc2_groups[] = {
+ "gpio78",
+};
+static const char *const tgu_ch0_trigout_groups[] = {
+ "gpio87",
+};
+static const char *const tgu_ch1_trigout_groups[] = {
+ "gpio88",
+};
+static const char *const tmess_prng0_groups[] = {
+ "gpio86",
+};
+static const char *const tmess_prng1_groups[] = {
+ "gpio83",
+};
+static const char *const tmess_prng2_groups[] = {
+ "gpio84",
+};
+static const char *const tmess_prng3_groups[] = {
+ "gpio85",
+};
+static const char *const tsense_pwm1_groups[] = {
+ "gpio17",
+};
+static const char *const tsense_pwm2_groups[] = {
+ "gpio17",
+};
+static const char *const uim0_clk_groups[] = {
+ "gpio97",
+};
+static const char *const uim0_data_groups[] = {
+ "gpio96",
+};
+static const char *const uim0_present_groups[] = {
+ "gpio99",
+};
+static const char *const uim0_reset_groups[] = {
+ "gpio98",
+};
+static const char *const uim1_clk_mira_groups[] = {
+ "gpio111",
+};
+static const char *const uim1_clk_mirb_groups[] = {
+ "gpio101",
+};
+static const char *const uim1_data_mira_groups[] = {
+ "gpio110",
+};
+static const char *const uim1_data_mirb_groups[] = {
+ "gpio100",
+};
+static const char *const uim1_present_mira_groups[] = {
+ "gpio113",
+};
+static const char *const uim1_present_mirb_groups[] = {
+ "gpio103",
+};
+static const char *const uim1_reset_mira_groups[] = {
+ "gpio112",
+};
+static const char *const uim1_reset_mirb_groups[] = {
+ "gpio102",
+};
+static const char *const usb0_hs_groups[] = {
+ "gpio125",
+};
+static const char *const usb0_phy_ps_groups[] = {
+ "gpio131",
+};
+static const char *const vfr_0_groups[] = {
+ "gpio56",
+};
+static const char *const vfr_1_groups[] = {
+ "gpio126",
+};
+static const char *const vsense_trigger_mirnat_groups[] = {
+ "gpio94",
+};
+static const char *const wcn_sw_groups[] = {
+ "gpio52",
+};
+static const char *const wcn_sw_ctrl_groups[] = {
+ "gpio45",
+};
+
+static const struct pinfunction milos_functions[] = {
+ MSM_PIN_FUNCTION(gpio),
+ MSM_PIN_FUNCTION(aoss_cti),
+ MSM_PIN_FUNCTION(atest_char),
+ MSM_PIN_FUNCTION(atest_usb),
+ MSM_PIN_FUNCTION(audio_ext_mclk0),
+ MSM_PIN_FUNCTION(audio_ext_mclk1),
+ MSM_PIN_FUNCTION(audio_ref_clk),
+ MSM_PIN_FUNCTION(cam_mclk),
+ MSM_PIN_FUNCTION(cci_async_in0),
+ MSM_PIN_FUNCTION(cci_i2c_scl),
+ MSM_PIN_FUNCTION(cci_i2c_sda),
+ MSM_PIN_FUNCTION(cci_timer),
+ MSM_PIN_FUNCTION(coex_uart1_rx),
+ MSM_PIN_FUNCTION(coex_uart1_tx),
+ MSM_PIN_FUNCTION(dbg_out_clk),
+ MSM_PIN_FUNCTION(ddr_bist_complete),
+ MSM_PIN_FUNCTION(ddr_bist_fail),
+ MSM_PIN_FUNCTION(ddr_bist_start),
+ MSM_PIN_FUNCTION(ddr_bist_stop),
+ MSM_PIN_FUNCTION(ddr_pxi0),
+ MSM_PIN_FUNCTION(ddr_pxi1),
+ MSM_PIN_FUNCTION(dp0_hot),
+ MSM_PIN_FUNCTION(egpio),
+ MSM_PIN_FUNCTION(gcc_gp1),
+ MSM_PIN_FUNCTION(gcc_gp2),
+ MSM_PIN_FUNCTION(gcc_gp3),
+ MSM_PIN_FUNCTION(host2wlan_sol),
+ MSM_PIN_FUNCTION(i2s0_data0),
+ MSM_PIN_FUNCTION(i2s0_data1),
+ MSM_PIN_FUNCTION(i2s0_sck),
+ MSM_PIN_FUNCTION(i2s0_ws),
+ MSM_PIN_FUNCTION(ibi_i3c),
+ MSM_PIN_FUNCTION(jitter_bist),
+ MSM_PIN_FUNCTION(mdp_vsync),
+ MSM_PIN_FUNCTION(mdp_vsync0_out),
+ MSM_PIN_FUNCTION(mdp_vsync1_out),
+ MSM_PIN_FUNCTION(mdp_vsync2_out),
+ MSM_PIN_FUNCTION(mdp_vsync3_out),
+ MSM_PIN_FUNCTION(mdp_vsync_e),
+ MSM_PIN_FUNCTION(nav_gpio0),
+ MSM_PIN_FUNCTION(nav_gpio1),
+ MSM_PIN_FUNCTION(nav_gpio2),
+ MSM_PIN_FUNCTION(pcie0_clk_req_n),
+ MSM_PIN_FUNCTION(pcie1_clk_req_n),
+ MSM_PIN_FUNCTION(phase_flag),
+ MSM_PIN_FUNCTION(pll_bist_sync),
+ MSM_PIN_FUNCTION(pll_clk_aux),
+ MSM_PIN_FUNCTION(prng_rosc0),
+ MSM_PIN_FUNCTION(prng_rosc1),
+ MSM_PIN_FUNCTION(prng_rosc2),
+ MSM_PIN_FUNCTION(prng_rosc3),
+ MSM_PIN_FUNCTION(qdss_cti),
+ MSM_PIN_FUNCTION(qdss_gpio),
+ MSM_PIN_FUNCTION(qlink0_enable),
+ MSM_PIN_FUNCTION(qlink0_request),
+ MSM_PIN_FUNCTION(qlink0_wmss),
+ MSM_PIN_FUNCTION(qlink1_enable),
+ MSM_PIN_FUNCTION(qlink1_request),
+ MSM_PIN_FUNCTION(qlink1_wmss),
+ MSM_PIN_FUNCTION(qspi0),
+ MSM_PIN_FUNCTION(qup0_se0),
+ MSM_PIN_FUNCTION(qup0_se1),
+ MSM_PIN_FUNCTION(qup0_se2),
+ MSM_PIN_FUNCTION(qup0_se3),
+ MSM_PIN_FUNCTION(qup0_se4),
+ MSM_PIN_FUNCTION(qup0_se5),
+ MSM_PIN_FUNCTION(qup0_se6),
+ MSM_PIN_FUNCTION(qup1_se0),
+ MSM_PIN_FUNCTION(qup1_se1),
+ MSM_PIN_FUNCTION(qup1_se2),
+ MSM_PIN_FUNCTION(qup1_se3),
+ MSM_PIN_FUNCTION(qup1_se4),
+ MSM_PIN_FUNCTION(qup1_se5),
+ MSM_PIN_FUNCTION(qup1_se6),
+ MSM_PIN_FUNCTION(resout_gpio_n),
+ MSM_PIN_FUNCTION(sd_write_protect),
+ MSM_PIN_FUNCTION(sdc1_clk),
+ MSM_PIN_FUNCTION(sdc1_cmd),
+ MSM_PIN_FUNCTION(sdc1_data),
+ MSM_PIN_FUNCTION(sdc1_rclk),
+ MSM_PIN_FUNCTION(sdc2_clk),
+ MSM_PIN_FUNCTION(sdc2_cmd),
+ MSM_PIN_FUNCTION(sdc2_data),
+ MSM_PIN_FUNCTION(sdc2_fb_clk),
+ MSM_PIN_FUNCTION(tb_trig_sdc1),
+ MSM_PIN_FUNCTION(tb_trig_sdc2),
+ MSM_PIN_FUNCTION(tgu_ch0_trigout),
+ MSM_PIN_FUNCTION(tgu_ch1_trigout),
+ MSM_PIN_FUNCTION(tmess_prng0),
+ MSM_PIN_FUNCTION(tmess_prng1),
+ MSM_PIN_FUNCTION(tmess_prng2),
+ MSM_PIN_FUNCTION(tmess_prng3),
+ MSM_PIN_FUNCTION(tsense_pwm1),
+ MSM_PIN_FUNCTION(tsense_pwm2),
+ MSM_PIN_FUNCTION(uim0_clk),
+ MSM_PIN_FUNCTION(uim0_data),
+ MSM_PIN_FUNCTION(uim0_present),
+ MSM_PIN_FUNCTION(uim0_reset),
+ MSM_PIN_FUNCTION(uim1_clk_mira),
+ MSM_PIN_FUNCTION(uim1_clk_mirb),
+ MSM_PIN_FUNCTION(uim1_data_mira),
+ MSM_PIN_FUNCTION(uim1_data_mirb),
+ MSM_PIN_FUNCTION(uim1_present_mira),
+ MSM_PIN_FUNCTION(uim1_present_mirb),
+ MSM_PIN_FUNCTION(uim1_reset_mira),
+ MSM_PIN_FUNCTION(uim1_reset_mirb),
+ MSM_PIN_FUNCTION(usb0_hs),
+ MSM_PIN_FUNCTION(usb0_phy_ps),
+ MSM_PIN_FUNCTION(vfr_0),
+ MSM_PIN_FUNCTION(vfr_1),
+ MSM_PIN_FUNCTION(vsense_trigger_mirnat),
+ MSM_PIN_FUNCTION(wcn_sw),
+ MSM_PIN_FUNCTION(wcn_sw_ctrl),
+};
+
+/*
+ * Every pin is maintained as a single group, and missing or non-existing pin
+ * would be maintained as dummy group to synchronize pin group index with
+ * pin descriptor registered with pinctrl core.
+ * Clients would not be able to request these dummy pin groups.
+ */
+static const struct msm_pingroup milos_groups[] = {
+ [0] = PINGROUP(0, qup0_se0, ibi_i3c, aoss_cti, _, _, _, _, _, _, _, _),
+ [1] = PINGROUP(1, qup0_se0, ibi_i3c, aoss_cti, _, _, _, _, _, _, _, _),
+ [2] = PINGROUP(2, qup0_se0, _, _, _, _, _, _, _, _, _, _),
+ [3] = PINGROUP(3, qup0_se0, _, _, _, _, _, _, _, _, _, _),
+ [4] = PINGROUP(4, qup0_se1, ibi_i3c, aoss_cti, sd_write_protect, qdss_cti, _, _, _, _, _, _),
+ [5] = PINGROUP(5, qup0_se1, ibi_i3c, aoss_cti, qdss_cti, _, _, _, _, _, _, _),
+ [6] = PINGROUP(6, qup0_se1, qdss_cti, _, _, _, _, _, _, _, _, _),
+ [7] = PINGROUP(7, qup0_se1, qdss_cti, _, _, _, _, _, _, _, _, _),
+ [8] = PINGROUP(8, qup0_se2, qspi0, _, phase_flag, _, _, _, _, _, _, _),
+ [9] = PINGROUP(9, qup0_se2, qspi0, _, phase_flag, _, _, _, _, _, _, _),
+ [10] = PINGROUP(10, qup0_se2, qspi0, _, _, _, _, _, _, _, _, _),
+ [11] = PINGROUP(11, qup0_se2, qspi0, _, phase_flag, _, _, _, _, _, _, _),
+ [12] = PINGROUP(12, qup0_se2, qspi0, mdp_vsync0_out, mdp_vsync1_out, _, phase_flag, _, _, _, _, _),
+ [13] = PINGROUP(13, qup0_se2, qspi0, _, phase_flag, _, _, _, _, _, _, _),
+ [14] = PINGROUP(14, qup0_se2, qspi0, _, phase_flag, _, _, _, _, _, _, _),
+ [15] = PINGROUP(15, qup0_se3, i2s0_sck, _, phase_flag, _, _, _, _, _, _, _),
+ [16] = PINGROUP(16, qup0_se3, i2s0_data0, _, phase_flag, _, _, _, _, _, _, _),
+ [17] = PINGROUP(17, qup0_se3, i2s0_data1, tsense_pwm1, tsense_pwm2, _, _, _, _, _, _, _),
+ [18] = PINGROUP(18, qup0_se3, i2s0_ws, _, phase_flag, _, _, _, _, _, _, _),
+ [19] = PINGROUP(19, qup0_se4, mdp_vsync, _, _, _, _, _, _, _, _, _),
+ [20] = PINGROUP(20, qup0_se4, _, _, _, _, _, _, _, _, _, _),
+ [21] = PINGROUP(21, qup0_se4, _, _, _, _, _, _, _, _, _, _),
+ [22] = PINGROUP(22, qup0_se4, _, _, _, _, _, _, _, _, _, _),
+ [23] = PINGROUP(23, qup0_se5, qup0_se3, audio_ext_mclk0, _, atest_usb, ddr_pxi0, _, _, _, _, _),
+ [24] = PINGROUP(24, qup0_se5, qup0_se3, audio_ext_mclk1, audio_ref_clk, dbg_out_clk, _, atest_usb, ddr_pxi0, _, _, _),
+ [25] = PINGROUP(25, qup0_se5, _, _, _, _, _, _, _, _, _, _),
+ [26] = PINGROUP(26, qup0_se5, qup0_se3, pll_bist_sync, _, phase_flag, _, _, _, _, _, _),
+ [27] = PINGROUP(27, qup0_se6, _, _, _, _, _, _, _, _, _, _),
+ [28] = PINGROUP(28, qup0_se6, gcc_gp2, _, _, _, _, _, _, _, _, _),
+ [29] = PINGROUP(29, qup0_se6, gcc_gp1, _, _, _, _, _, _, _, _, _),
+ [30] = PINGROUP(30, qup0_se6, gcc_gp2, _, _, _, _, _, _, _, _, _),
+ [31] = PINGROUP(31, qup0_se6, gcc_gp3, _, _, _, _, _, _, _, _, _),
+ [32] = PINGROUP(32, qup1_se0, ibi_i3c, gcc_gp1, _, _, _, _, _, _, _, _),
+ [33] = PINGROUP(33, qup1_se0, ibi_i3c, gcc_gp3, _, _, _, _, _, _, _, _),
+ [34] = PINGROUP(34, sdc2_data, _, _, _, _, _, _, _, _, _, _),
+ [35] = PINGROUP(35, sdc2_data, _, _, _, _, _, _, _, _, _, _),
+ [36] = PINGROUP(36, qup1_se1, qup1_se2, ibi_i3c, pll_clk_aux, _, _, _, _, _, _, _),
+ [37] = PINGROUP(37, qup1_se1, qup1_se2, ibi_i3c, mdp_vsync, _, _, _, _, _, _, _),
+ [38] = PINGROUP(38, qup1_se1, qup1_se2, _, phase_flag, _, _, _, _, _, _, _),
+ [39] = PINGROUP(39, qup1_se1, resout_gpio_n, _, phase_flag, _, _, _, _, _, _, _),
+ [40] = PINGROUP(40, qup1_se2, mdp_vsync2_out, mdp_vsync3_out, _, phase_flag, qdss_gpio, _, _, _, _, _),
+ [41] = PINGROUP(41, qup1_se2, _, phase_flag, qdss_gpio, _, _, _, _, _, _, _),
+ [42] = PINGROUP(42, qup1_se2, _, phase_flag, qdss_gpio, _, _, _, _, _, _, _),
+ [43] = PINGROUP(43, qup1_se2, _, _, phase_flag, qdss_gpio, _, _, _, _, _, _),
+ [44] = PINGROUP(44, _, _, phase_flag, qdss_cti, atest_char, _, _, _, _, _, _),
+ [45] = PINGROUP(45, wcn_sw_ctrl, mdp_vsync_e, _, _, phase_flag, qdss_cti, atest_char, _, _, _, _),
+ [46] = PINGROUP(46, host2wlan_sol, _, phase_flag, qdss_gpio, atest_char, _, _, _, _, _, _),
+ [47] = PINGROUP(47, ddr_bist_stop, _, phase_flag, qdss_gpio, atest_char, _, _, _, _, _, _),
+ [48] = PINGROUP(48, qup1_se4, _, phase_flag, qdss_gpio, _, _, _, _, _, _, _),
+ [49] = PINGROUP(49, qup1_se4, _, phase_flag, qdss_gpio, _, _, _, _, _, _, _),
+ [50] = PINGROUP(50, qup1_se4, qdss_gpio, ddr_pxi1, _, _, _, _, _, _, _, _),
+ [51] = PINGROUP(51, qup1_se4, qdss_gpio, ddr_pxi1, _, _, _, _, _, _, _, _),
+ [52] = PINGROUP(52, qup1_se4, wcn_sw, qdss_gpio, _, _, _, _, _, _, _, _),
+ [53] = PINGROUP(53, qup1_se4, qdss_gpio, _, _, _, _, _, _, _, _, _),
+ [54] = PINGROUP(54, qup1_se4, qdss_cti, _, _, _, _, _, _, _, _, _),
+ [55] = PINGROUP(55, qup1_se5, qup1_se6, _, _, _, _, _, _, _, _, _),
+ [56] = PINGROUP(56, qup1_se5, qup1_se6, vfr_0, ddr_bist_fail, _, _, _, _, _, _, _),
+ [57] = PINGROUP(57, sdc2_data, _, _, _, _, _, _, _, _, _, _),
+ [58] = PINGROUP(58, sdc2_data, _, _, _, _, _, _, _, _, _, _),
+ [59] = PINGROUP(59, qup1_se6, _, qup1_se5, _, _, _, _, _, _, _, _),
+ [60] = PINGROUP(60, qup1_se6, _, qup1_se5, atest_usb, _, _, _, _, _, _, _),
+ [61] = PINGROUP(61, sdc2_cmd, _, _, _, _, _, _, _, _, _, _),
+ [62] = PINGROUP(62, sdc2_clk, _, _, _, _, _, _, _, _, _, _),
+ [63] = PINGROUP(63, coex_uart1_tx, _, phase_flag, atest_char, _, _, _, _, _, _, _),
+ [64] = PINGROUP(64, coex_uart1_rx, _, phase_flag, _, _, _, _, _, _, _, _),
+ [65] = PINGROUP(65, _, _, _, _, _, _, _, _, _, _, _),
+ [66] = PINGROUP(66, prng_rosc0, _, _, _, _, _, _, _, _, _, _),
+ [67] = PINGROUP(67, pcie0_clk_req_n, prng_rosc1, _, _, _, _, _, _, _, _, _),
+ [68] = PINGROUP(68, prng_rosc2, _, _, _, _, _, _, _, _, _, _),
+ [69] = PINGROUP(69, prng_rosc3, _, _, _, _, _, _, _, _, _, _),
+ [70] = PINGROUP(70, pcie1_clk_req_n, _, _, _, _, _, _, _, _, _, _),
+ [71] = PINGROUP(71, _, _, _, _, _, _, _, _, _, _, _),
+ [72] = PINGROUP(72, sdc1_rclk, mdp_vsync, _, _, _, _, _, _, _, _, _),
+ [73] = PINGROUP(73, sdc1_data, _, _, _, _, _, _, _, _, _, _),
+ [74] = PINGROUP(74, sdc1_data, _, _, _, _, _, _, _, _, _, _),
+ [75] = PINGROUP(75, sdc1_data, dp0_hot, _, _, _, _, _, _, _, _, _),
+ [76] = PINGROUP(76, sdc1_data, _, _, _, _, _, _, _, _, _, _),
+ [77] = PINGROUP(77, sdc1_clk, cci_timer, _, _, _, _, _, _, _, _, _),
+ [78] = PINGROUP(78, sdc1_cmd, tb_trig_sdc2, _, _, _, _, _, _, _, _, _),
+ [79] = PINGROUP(79, sdc1_data, _, _, _, _, _, _, _, _, _, _),
+ [80] = PINGROUP(80, sdc1_data, _, _, _, _, _, _, _, _, _, _),
+ [81] = PINGROUP(81, sdc1_data, _, _, _, _, _, _, _, _, _, _),
+ [82] = PINGROUP(82, sdc1_data, _, _, _, _, _, _, _, _, _, _),
+ [83] = PINGROUP(83, cam_mclk, cci_timer, tmess_prng1, qdss_gpio, _, _, _, _, _, _, _),
+ [84] = PINGROUP(84, cam_mclk, cci_timer, tmess_prng2, qdss_gpio, _, _, _, _, _, _, _),
+ [85] = PINGROUP(85, cam_mclk, cci_timer, tmess_prng3, qdss_gpio, _, _, _, _, _, _, _),
+ [86] = PINGROUP(86, cam_mclk, cci_async_in0, tmess_prng0, qdss_gpio, _, _, _, _, _, _, _),
+ [87] = PINGROUP(87, cam_mclk, tb_trig_sdc1, tgu_ch0_trigout, qdss_cti, _, _, _, _, _, _, _),
+ [88] = PINGROUP(88, cci_i2c_sda, tgu_ch1_trigout, _, qdss_gpio, _, _, _, _, _, _, _),
+ [89] = PINGROUP(89, cci_i2c_scl, _, qdss_gpio, _, _, _, _, _, _, _, _),
+ [90] = PINGROUP(90, cci_i2c_sda, qup1_se6, _, _, _, _, _, _, _, _, _),
+ [91] = PINGROUP(91, cci_i2c_scl, qup1_se6, _, _, _, _, _, _, _, _, _),
+ [92] = PINGROUP(92, cci_i2c_sda, qup1_se3, _, _, _, _, _, _, _, _, _),
+ [93] = PINGROUP(93, cci_i2c_scl, qup1_se3, _, _, _, _, _, _, _, _, _),
+ [94] = PINGROUP(94, cci_i2c_sda, qup1_se3, qup1_se0, _, vsense_trigger_mirnat, _, _, _, _, _, _),
+ [95] = PINGROUP(95, cci_i2c_scl, qup1_se3, qup1_se0, _, _, _, _, _, _, _, _),
+ [96] = PINGROUP(96, uim0_data, _, _, _, _, _, _, _, _, _, _),
+ [97] = PINGROUP(97, uim0_clk, _, _, _, _, _, _, _, _, _, _),
+ [98] = PINGROUP(98, uim0_reset, _, _, _, _, _, _, _, _, _, _),
+ [99] = PINGROUP(99, uim0_present, _, _, _, _, _, _, _, _, _, _),
+ [100] = PINGROUP(100, uim1_data_mirb, _, _, _, _, _, _, _, _, _, _),
+ [101] = PINGROUP(101, uim1_clk_mirb, _, _, _, _, _, _, _, _, _, _),
+ [102] = PINGROUP(102, uim1_reset_mirb, _, _, _, _, _, _, _, _, _, _),
+ [103] = PINGROUP(103, uim1_present_mirb, _, _, _, _, _, _, _, _, _, _),
+ [104] = PINGROUP(104, qlink0_request, _, _, _, _, _, _, _, _, _, _),
+ [105] = PINGROUP(105, qlink0_enable, _, _, _, _, _, _, _, _, _, _),
+ [106] = PINGROUP(106, qlink0_wmss, _, _, _, _, _, _, _, _, _, _),
+ [107] = PINGROUP(107, qlink1_request, _, _, _, _, _, _, _, _, _, _),
+ [108] = PINGROUP(108, qlink1_enable, _, _, _, _, _, _, _, _, _, _),
+ [109] = PINGROUP(109, qlink1_wmss, _, _, _, _, _, _, _, _, _, _),
+ [110] = PINGROUP(110, uim1_data_mira, _, _, _, _, _, _, _, _, _, _),
+ [111] = PINGROUP(111, uim1_clk_mira, _, _, _, _, _, _, _, _, _, _),
+ [112] = PINGROUP(112, uim1_reset_mira, _, _, _, _, _, _, _, _, _, _),
+ [113] = PINGROUP(113, uim1_present_mira, _, _, _, _, _, _, _, _, _, _),
+ [114] = PINGROUP(114, _, _, _, _, _, _, _, _, _, _, _),
+ [115] = PINGROUP(115, _, _, _, _, _, _, _, _, _, _, _),
+ [116] = PINGROUP(116, _, _, _, _, _, _, _, _, _, _, _),
+ [117] = PINGROUP(117, _, _, _, _, _, _, _, _, _, _, _),
+ [118] = PINGROUP(118, _, _, _, _, _, _, _, _, _, _, _),
+ [119] = PINGROUP(119, _, _, _, _, _, _, _, _, _, _, _),
+ [120] = PINGROUP(120, _, _, _, _, _, _, _, _, _, _, _),
+ [121] = PINGROUP(121, _, _, _, _, _, _, _, _, _, _, _),
+ [122] = PINGROUP(122, _, _, _, _, _, _, _, _, _, _, _),
+ [123] = PINGROUP(123, _, _, _, _, _, _, _, _, _, _, _),
+ [124] = PINGROUP(124, nav_gpio0, _, _, _, _, _, _, _, _, _, _),
+ [125] = PINGROUP(125, nav_gpio1, usb0_hs, _, _, _, _, _, _, _, _, _),
+ [126] = PINGROUP(126, _, nav_gpio2, vfr_1, _, _, _, _, _, _, _, _),
+ [127] = PINGROUP(127, _, _, phase_flag, _, _, _, _, _, _, _, _),
+ [128] = PINGROUP(128, sdc2_fb_clk, _, _, _, _, _, _, _, _, _, _),
+ [129] = PINGROUP(129, mdp_vsync, _, _, _, _, _, _, _, _, _, _),
+ [130] = PINGROUP(130, _, _, _, _, _, _, _, _, _, _, _),
+ [131] = PINGROUP(131, usb0_phy_ps, _, _, _, _, _, _, _, _, _, _),
+ [132] = PINGROUP(132, _, _, _, _, _, _, _, _, _, _, egpio),
+ [133] = PINGROUP(133, ddr_bist_start, _, _, _, _, _, _, _, _, _, egpio),
+ [134] = PINGROUP(134, _, _, _, _, _, _, _, _, _, _, egpio),
+ [135] = PINGROUP(135, _, _, _, _, _, _, _, _, _, _, egpio),
+ [136] = PINGROUP(136, _, _, _, _, _, _, _, _, _, _, egpio),
+ [137] = PINGROUP(137, ddr_bist_complete, _, _, _, _, _, _, _, _, _, egpio),
+ [138] = PINGROUP(138, _, phase_flag, qdss_gpio, _, _, _, _, _, _, _, egpio),
+ [139] = PINGROUP(139, _, phase_flag, qdss_gpio, _, _, _, _, _, _, _, egpio),
+ [140] = PINGROUP(140, _, phase_flag, qdss_gpio, _, _, _, _, _, _, _, egpio),
+ [141] = PINGROUP(141, jitter_bist, qdss_gpio, _, _, _, _, _, _, _, _, egpio),
+ [142] = PINGROUP(142, _, phase_flag, _, _, _, _, _, _, _, _, egpio),
+ [143] = PINGROUP(143, _, phase_flag, _, _, _, _, _, _, _, _, egpio),
+ [144] = PINGROUP(144, _, phase_flag, _, _, _, _, _, _, _, _, egpio),
+ [145] = PINGROUP(145, _, _, _, _, _, _, _, _, _, _, egpio),
+ [146] = PINGROUP(146, _, _, _, _, _, _, _, _, _, _, egpio),
+ [147] = PINGROUP(147, _, phase_flag, _, _, _, _, _, _, _, _, egpio),
+ [148] = PINGROUP(148, _, _, _, _, _, _, _, _, _, _, egpio),
+ [149] = PINGROUP(149, _, qdss_gpio, _, _, _, _, _, _, _, _, egpio),
+ [150] = PINGROUP(150, _, qdss_gpio, _, _, _, _, _, _, _, _, egpio),
+ [151] = PINGROUP(151, _, _, _, _, _, _, _, _, _, _, egpio),
+ [152] = PINGROUP(152, _, _, _, _, _, _, _, _, _, _, egpio),
+ [153] = PINGROUP(153, _, _, _, _, _, _, _, _, _, _, egpio),
+ [154] = PINGROUP(154, _, _, _, _, _, _, _, _, _, _, egpio),
+ [155] = PINGROUP(155, _, qdss_gpio, _, _, _, _, _, _, _, _, egpio),
+ [156] = PINGROUP(156, _, qdss_gpio, _, _, _, _, _, _, _, _, egpio),
+ [157] = PINGROUP(157, _, qdss_gpio, _, _, _, _, _, _, _, _, egpio),
+ [158] = PINGROUP(158, qdss_gpio, _, _, _, _, _, _, _, _, _, egpio),
+ [159] = PINGROUP(159, qdss_gpio, _, _, _, _, _, _, _, _, _, egpio),
+ [160] = PINGROUP(160, qdss_gpio, _, _, _, _, _, _, _, _, _, egpio),
+ [161] = PINGROUP(161, qdss_gpio, _, _, _, _, _, _, _, _, _, egpio),
+ [162] = PINGROUP(162, qdss_gpio, _, _, _, _, _, _, _, _, _, egpio),
+ [163] = PINGROUP(163, qdss_gpio, _, _, _, _, _, _, _, _, _, egpio),
+ [164] = PINGROUP(164, qdss_gpio, _, _, _, _, _, _, _, _, _, egpio),
+ [165] = PINGROUP(165, qdss_gpio, _, _, _, _, _, _, _, _, _, egpio),
+ [166] = PINGROUP(166, qdss_gpio, _, _, _, _, _, _, _, _, _, egpio),
+ [167] = UFS_RESET(ufs_reset, 0xb4004, 0xb5000),
+ [168] = SDC_QDSD_PINGROUP(sdc2_clk, 0xab000, 0, 6),
+ [169] = SDC_QDSD_PINGROUP(sdc2_cmd, 0xab000, 12, 3),
+ [170] = SDC_QDSD_PINGROUP(sdc2_data, 0xab000, 9, 0),
+};
+
+static const struct msm_gpio_wakeirq_map milos_pdc_map[] = {
+ { 0, 122 }, { 3, 95 }, { 4, 100 }, { 6, 52 }, { 7, 119 },
+ { 8, 92 }, { 11, 54 }, { 12, 56 }, { 13, 64 }, { 14, 75 },
+ { 15, 82 }, { 18, 89 }, { 19, 90 }, { 22, 93 }, { 23, 94 },
+ { 26, 91 }, { 27, 57 }, { 30, 138 }, { 31, 96 }, { 32, 67 },
+ { 34, 128 }, { 35, 98 }, { 36, 99 }, { 38, 101 }, { 39, 102 },
+ { 40, 69 }, { 43, 103 }, { 44, 104 }, { 45, 126 }, { 47, 59 },
+ { 48, 106 }, { 51, 107 }, { 52, 108 }, { 54, 110 }, { 55, 140 },
+ { 56, 58 }, { 57, 129 }, { 58, 111 }, { 59, 112 }, { 60, 115 },
+ { 61, 113 }, { 62, 114 }, { 64, 105 }, { 65, 55 }, { 67, 116 },
+ { 68, 117 }, { 70, 120 }, { 71, 121 }, { 72, 97 }, { 73, 109 },
+ { 74, 118 }, { 75, 132 }, { 76, 144 }, { 77, 127 }, { 78, 133 },
+ { 79, 134 }, { 80, 135 }, { 81, 124 }, { 82, 136 }, { 87, 60 },
+ { 91, 123 }, { 92, 125 }, { 95, 139 }, { 99, 53 }, { 103, 61 },
+ { 104, 71 }, { 107, 137 }, { 113, 51 }, { 124, 72 }, { 125, 62 },
+ { 126, 73 }, { 128, 63 }, { 129, 130 }, { 130, 65 }, { 131, 66 },
+ { 133, 68 }, { 136, 70 }, { 143, 78 }, { 144, 79 }, { 145, 142 },
+ { 148, 81 }, { 149, 76 }, { 150, 83 }, { 151, 84 }, { 153, 74 },
+ { 155, 131 }, { 158, 85 }, { 159, 77 }, { 161, 80 }, { 162, 143 },
+ { 163, 86 }, { 164, 87 }, { 166, 88 },
+};
+
+static const struct msm_pinctrl_soc_data milos_tlmm = {
+ .pins = milos_pins,
+ .npins = ARRAY_SIZE(milos_pins),
+ .functions = milos_functions,
+ .nfunctions = ARRAY_SIZE(milos_functions),
+ .groups = milos_groups,
+ .ngroups = ARRAY_SIZE(milos_groups),
+ .ngpios = 168,
+ .wakeirq_map = milos_pdc_map,
+ .nwakeirq_map = ARRAY_SIZE(milos_pdc_map),
+ .egpio_func = 11,
+};
+
+static int milos_tlmm_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &milos_tlmm);
+}
+
+static const struct of_device_id milos_tlmm_of_match[] = {
+ { .compatible = "qcom,milos-tlmm" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver milos_tlmm_driver = {
+ .driver = {
+ .name = "milos-tlmm",
+ .of_match_table = milos_tlmm_of_match,
+ },
+ .probe = milos_tlmm_probe,
+};
+
+static int __init milos_tlmm_init(void)
+{
+ return platform_driver_register(&milos_tlmm_driver);
+}
+arch_initcall(milos_tlmm_init);
+
+static void __exit milos_tlmm_exit(void)
+{
+ platform_driver_unregister(&milos_tlmm_driver);
+}
+module_exit(milos_tlmm_exit);
+
+MODULE_DESCRIPTION("QTI Milos TLMM driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, milos_tlmm_of_match);
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
index bc082bfb52ef..606becc160eb 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -1206,6 +1206,7 @@ static const struct of_device_id pmic_gpio_of_match[] = {
{ .compatible = "qcom,pm6450-gpio", .data = (void *) 9 },
{ .compatible = "qcom,pm7250b-gpio", .data = (void *) 12 },
{ .compatible = "qcom,pm7325-gpio", .data = (void *) 10 },
+ { .compatible = "qcom,pm7550-gpio", .data = (void *) 12 },
{ .compatible = "qcom,pm7550ba-gpio", .data = (void *) 8},
{ .compatible = "qcom,pm8005-gpio", .data = (void *) 4 },
{ .compatible = "qcom,pm8019-gpio", .data = (void *) 6 },
@@ -1244,6 +1245,7 @@ static const struct of_device_id pmic_gpio_of_match[] = {
{ .compatible = "qcom,pmi8994-gpio", .data = (void *) 10 },
{ .compatible = "qcom,pmi8998-gpio", .data = (void *) 14 },
{ .compatible = "qcom,pmih0108-gpio", .data = (void *) 18 },
+ { .compatible = "qcom,pmiv0104-gpio", .data = (void *) 10 },
{ .compatible = "qcom,pmk8350-gpio", .data = (void *) 4 },
{ .compatible = "qcom,pmk8550-gpio", .data = (void *) 6 },
{ .compatible = "qcom,pmm8155au-gpio", .data = (void *) 10 },
diff --git a/drivers/pinctrl/qcom/tlmm-test.c b/drivers/pinctrl/qcom/tlmm-test.c
index 7b99e89e0f67..7d7fff538755 100644
--- a/drivers/pinctrl/qcom/tlmm-test.c
+++ b/drivers/pinctrl/qcom/tlmm-test.c
@@ -16,6 +16,7 @@
#include <linux/of_irq.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
/*
* This TLMM test module serves the purpose of validating that the TLMM driver
@@ -38,7 +39,10 @@
#define TLMM_REG_SIZE 0x1000
static int tlmm_test_gpio = -1;
+static char *tlmm_reg_name = "default_region";
+
module_param_named(gpio, tlmm_test_gpio, int, 0600);
+module_param_named(name, tlmm_reg_name, charp, 0600);
static struct {
void __iomem *base;
@@ -570,6 +574,47 @@ static const struct of_device_id tlmm_of_match[] = {
{}
};
+static int tlmm_reg_base(struct device_node *tlmm, struct resource *res)
+{
+ const char **reg_names;
+ int count;
+ int ret;
+ int i;
+
+ count = of_property_count_strings(tlmm, "reg-names");
+ if (count <= 0) {
+ pr_err("failed to find tlmm reg name\n");
+ return count;
+ }
+
+ reg_names = kcalloc(count, sizeof(char *), GFP_KERNEL);
+ if (!reg_names)
+ return -ENOMEM;
+
+ ret = of_property_read_string_array(tlmm, "reg-names", reg_names, count);
+ if (ret != count) {
+ kfree(reg_names);
+ return -EINVAL;
+ }
+
+ if (!strcmp(tlmm_reg_name, "default_region")) {
+ ret = of_address_to_resource(tlmm, 0, res);
+ } else {
+ for (i = 0; i < count; i++) {
+ if (!strcmp(reg_names[i], tlmm_reg_name)) {
+ ret = of_address_to_resource(tlmm, i, res);
+ break;
+ }
+ }
+ if (i == count)
+ ret = -EINVAL;
+ }
+
+ kfree(reg_names);
+
+ return ret;
+}
+
static int tlmm_test_init_suite(struct kunit_suite *suite)
{
struct of_phandle_args args = {};
@@ -588,7 +633,7 @@ static int tlmm_test_init_suite(struct kunit_suite *suite)
return -EINVAL;
}
- ret = of_address_to_resource(tlmm, 0, &res);
+ ret = tlmm_reg_base(tlmm, &res);
if (ret < 0)
return ret;
diff --git a/drivers/pinctrl/renesas/Kconfig b/drivers/pinctrl/renesas/Kconfig
index e16034fc1bbf..99ae34a56871 100644
--- a/drivers/pinctrl/renesas/Kconfig
+++ b/drivers/pinctrl/renesas/Kconfig
@@ -86,89 +86,178 @@ config PINCTRL_PFC_EMEV2
bool "pin control support for Emma Mobile EV2" if COMPILE_TEST
select PINCTRL_SH_PFC
-config PINCTRL_PFC_R8A77995
- bool "pin control support for R-Car D3" if COMPILE_TEST
+config PINCTRL_PFC_R8A73A4
+ bool "pin control support for R8A73A4 (R-Mobile APE6)" if COMPILE_TEST
+ select PINCTRL_SH_PFC_GPIO
+
+config PINCTRL_PFC_R8A7740
+ bool "pin control support for R8A7740 (R-Mobile A1)" if COMPILE_TEST
+ select PINCTRL_SH_PFC_GPIO
+
+config PINCTRL_PFC_R8A7742
+ bool "pin control support for R8A7742 (RZ/G1H)" if COMPILE_TEST
select PINCTRL_SH_PFC
-config PINCTRL_PFC_R8A7794
- bool "pin control support for R-Car E2" if COMPILE_TEST
+config PINCTRL_PFC_R8A7743
+ bool "pin control support for R8A7743 (RZ/G1M)" if COMPILE_TEST
select PINCTRL_SH_PFC
-config PINCTRL_PFC_R8A77990
- bool "pin control support for R-Car E3" if COMPILE_TEST
+config PINCTRL_PFC_R8A7744
+ bool "pin control support for R8A7744 (RZ/G1N)" if COMPILE_TEST
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_R8A7745
+ bool "pin control support for R8A7745 (RZ/G1E)" if COMPILE_TEST
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_R8A77470
+ bool "pin control support for R8A77470 (RZ/G1C)" if COMPILE_TEST
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_R8A774A1
+ bool "pin control support for R8A774A1 (RZ/G2M)" if COMPILE_TEST
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_R8A774B1
+ bool "pin control support for R8A774B1 (RZ/G2N)" if COMPILE_TEST
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_R8A774C0
+ bool "pin control support for R8A774C0 (RZ/G2E)" if COMPILE_TEST
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_R8A774E1
+ bool "pin control support for R8A774E1 (RZ/G2H)" if COMPILE_TEST
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_R8A7778
+ bool "pin control support for R8A7778 (R-Car M1A)" if COMPILE_TEST
select PINCTRL_SH_PFC
config PINCTRL_PFC_R8A7779
- bool "pin control support for R-Car H1" if COMPILE_TEST
+ bool "pin control support for R8A7779 (R-Car H1)" if COMPILE_TEST
select PINCTRL_SH_PFC
config PINCTRL_PFC_R8A7790
- bool "pin control support for R-Car H2" if COMPILE_TEST
+ bool "pin control support for R8A7790 (R-Car H2)" if COMPILE_TEST
select PINCTRL_SH_PFC
-config PINCTRL_PFC_R8A77951
- bool "pin control support for R-Car H3 ES2.0+" if COMPILE_TEST
+config PINCTRL_PFC_R8A7791
+ bool "pin control support for R8A7791 (R-Car M2-W)" if COMPILE_TEST
select PINCTRL_SH_PFC
-config PINCTRL_PFC_R8A7778
- bool "pin control support for R-Car M1A" if COMPILE_TEST
+config PINCTRL_PFC_R8A7792
+ bool "pin control support for R8A7792 (R-Car V2H)" if COMPILE_TEST
select PINCTRL_SH_PFC
config PINCTRL_PFC_R8A7793
- bool "pin control support for R-Car M2-N" if COMPILE_TEST
+ bool "pin control support for R8A7793 (R-Car M2-N)" if COMPILE_TEST
select PINCTRL_SH_PFC
-config PINCTRL_PFC_R8A7791
- bool "pin control support for R-Car M2-W" if COMPILE_TEST
+config PINCTRL_PFC_R8A7794
+ bool "pin control support for R8A7794 (R-Car E2)" if COMPILE_TEST
select PINCTRL_SH_PFC
-config PINCTRL_PFC_R8A77965
- bool "pin control support for R-Car M3-N" if COMPILE_TEST
+config PINCTRL_PFC_R8A77951
+ bool "pin control support for R8A77951 (R-Car H3 ES2.0+)" if COMPILE_TEST
select PINCTRL_SH_PFC
config PINCTRL_PFC_R8A77960
- bool "pin control support for R-Car M3-W" if COMPILE_TEST
+ bool "pin control support for R8A77960 (R-Car M3-W)" if COMPILE_TEST
select PINCTRL_SH_PFC
config PINCTRL_PFC_R8A77961
- bool "pin control support for R-Car M3-W+" if COMPILE_TEST
+ bool "pin control support for R8A77961 (R-Car M3-W+)" if COMPILE_TEST
select PINCTRL_SH_PFC
-config PINCTRL_PFC_R8A779F0
- bool "pin control support for R-Car S4-8" if COMPILE_TEST
+config PINCTRL_PFC_R8A77965
+ bool "pin control support for R8A77965 (R-Car M3-N)" if COMPILE_TEST
select PINCTRL_SH_PFC
-config PINCTRL_PFC_R8A7792
- bool "pin control support for R-Car V2H" if COMPILE_TEST
+config PINCTRL_PFC_R8A77970
+ bool "pin control support for R8A77970 (R-Car V3M)" if COMPILE_TEST
select PINCTRL_SH_PFC
config PINCTRL_PFC_R8A77980
- bool "pin control support for R-Car V3H" if COMPILE_TEST
+ bool "pin control support for R8A77980 (R-Car V3H)" if COMPILE_TEST
select PINCTRL_SH_PFC
-config PINCTRL_PFC_R8A77970
- bool "pin control support for R-Car V3M" if COMPILE_TEST
+config PINCTRL_PFC_R8A77990
+ bool "pin control support for R8A77990 (R-Car E3)" if COMPILE_TEST
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_R8A77995
+ bool "pin control support for R8A77995 (R-Car D3)" if COMPILE_TEST
select PINCTRL_SH_PFC
config PINCTRL_PFC_R8A779A0
- bool "pin control support for R-Car V3U" if COMPILE_TEST
+ bool "pin control support for R8A779A0 (R-Car V3U)" if COMPILE_TEST
+ select PINCTRL_SH_PFC
+
+config PINCTRL_PFC_R8A779F0
+ bool "pin control support for R8A779F0 (R-Car S4-8)" if COMPILE_TEST
select PINCTRL_SH_PFC
config PINCTRL_PFC_R8A779G0
- bool "pin control support for R-Car V4H" if COMPILE_TEST
+ bool "pin control support for R8A779G0 (R-Car V4H)" if COMPILE_TEST
select PINCTRL_SH_PFC
config PINCTRL_PFC_R8A779H0
- bool "pin control support for R-Car V4M" if COMPILE_TEST
+ bool "pin control support for R8A779H0 (R-Car V4M)" if COMPILE_TEST
select PINCTRL_SH_PFC
-config PINCTRL_PFC_R8A7740
- bool "pin control support for R-Mobile A1" if COMPILE_TEST
- select PINCTRL_SH_PFC_GPIO
+config PINCTRL_PFC_SH7203
+ bool "pin control support for SH7203" if COMPILE_TEST
+ select PINCTRL_SH_FUNC_GPIO
-config PINCTRL_PFC_R8A73A4
- bool "pin control support for R-Mobile APE6" if COMPILE_TEST
+config PINCTRL_PFC_SH7264
+ bool "pin control support for SH7264" if COMPILE_TEST
+ select PINCTRL_SH_FUNC_GPIO
+
+config PINCTRL_PFC_SH7269
+ bool "pin control support for SH7269" if COMPILE_TEST
+ select PINCTRL_SH_FUNC_GPIO
+
+config PINCTRL_PFC_SH73A0
+ bool "pin control support for SH73A0 (SH-Mobile AG5)" if COMPILE_TEST
select PINCTRL_SH_PFC_GPIO
+ select REGULATOR
+
+config PINCTRL_PFC_SH7720
+ bool "pin control support for SH7720" if COMPILE_TEST
+ select PINCTRL_SH_FUNC_GPIO
+
+config PINCTRL_PFC_SH7722
+ bool "pin control support for SH7722" if COMPILE_TEST
+ select PINCTRL_SH_FUNC_GPIO
+
+config PINCTRL_PFC_SH7723
+ bool "pin control support for SH7723 (SH-Mobile R2)" if COMPILE_TEST
+ select PINCTRL_SH_FUNC_GPIO
+
+config PINCTRL_PFC_SH7724
+ bool "pin control support for SH7724 (SH-Mobile R2R)" if COMPILE_TEST
+ select PINCTRL_SH_FUNC_GPIO
+
+config PINCTRL_PFC_SH7734
+ bool "pin control support for SH7734" if COMPILE_TEST
+ select PINCTRL_SH_FUNC_GPIO
+
+config PINCTRL_PFC_SH7757
+ bool "pin control support for SH7757" if COMPILE_TEST
+ select PINCTRL_SH_FUNC_GPIO
+
+config PINCTRL_PFC_SH7785
+ bool "pin control support for SH7785" if COMPILE_TEST
+ select PINCTRL_SH_FUNC_GPIO
+
+config PINCTRL_PFC_SH7786
+ bool "pin control support for SH7786" if COMPILE_TEST
+ select PINCTRL_SH_FUNC_GPIO
+
+config PINCTRL_PFC_SHX3
+ bool "pin control support for SH-X3" if COMPILE_TEST
+ select PINCTRL_SH_FUNC_GPIO
config PINCTRL_RZA1
bool "pin control support for RZ/A1"
@@ -204,42 +293,6 @@ config PINCTRL_RZG2L
This selects GPIO and pinctrl driver for Renesas RZ/{G2L,G2UL,V2L}
platforms.
-config PINCTRL_PFC_R8A77470
- bool "pin control support for RZ/G1C" if COMPILE_TEST
- select PINCTRL_SH_PFC
-
-config PINCTRL_PFC_R8A7745
- bool "pin control support for RZ/G1E" if COMPILE_TEST
- select PINCTRL_SH_PFC
-
-config PINCTRL_PFC_R8A7742
- bool "pin control support for RZ/G1H" if COMPILE_TEST
- select PINCTRL_SH_PFC
-
-config PINCTRL_PFC_R8A7743
- bool "pin control support for RZ/G1M" if COMPILE_TEST
- select PINCTRL_SH_PFC
-
-config PINCTRL_PFC_R8A7744
- bool "pin control support for RZ/G1N" if COMPILE_TEST
- select PINCTRL_SH_PFC
-
-config PINCTRL_PFC_R8A774C0
- bool "pin control support for RZ/G2E" if COMPILE_TEST
- select PINCTRL_SH_PFC
-
-config PINCTRL_PFC_R8A774E1
- bool "pin control support for RZ/G2H" if COMPILE_TEST
- select PINCTRL_SH_PFC
-
-config PINCTRL_PFC_R8A774A1
- bool "pin control support for RZ/G2M" if COMPILE_TEST
- select PINCTRL_SH_PFC
-
-config PINCTRL_PFC_R8A774B1
- bool "pin control support for RZ/G2N" if COMPILE_TEST
- select PINCTRL_SH_PFC
-
config PINCTRL_RZN1
bool "pin control support for RZ/N1"
depends on OF
@@ -250,9 +303,8 @@ config PINCTRL_RZN1
This selects pinctrl driver for Renesas RZ/N1 devices.
config PINCTRL_RZV2M
- bool "pin control support for RZ/V2M"
+ bool "pin control support for RZ/V2M" if COMPILE_TEST
depends on OF
- depends on ARCH_R9A09G011 || COMPILE_TEST
select GPIOLIB
select GENERIC_PINCTRL_GROUPS
select GENERIC_PINMUX_FUNCTIONS
@@ -261,57 +313,4 @@ config PINCTRL_RZV2M
This selects GPIO and pinctrl driver for Renesas RZ/V2M
platforms.
-config PINCTRL_PFC_SH7203
- bool "pin control support for SH7203" if COMPILE_TEST
- select PINCTRL_SH_FUNC_GPIO
-
-config PINCTRL_PFC_SH7264
- bool "pin control support for SH7264" if COMPILE_TEST
- select PINCTRL_SH_FUNC_GPIO
-
-config PINCTRL_PFC_SH7269
- bool "pin control support for SH7269" if COMPILE_TEST
- select PINCTRL_SH_FUNC_GPIO
-
-config PINCTRL_PFC_SH7720
- bool "pin control support for SH7720" if COMPILE_TEST
- select PINCTRL_SH_FUNC_GPIO
-
-config PINCTRL_PFC_SH7722
- bool "pin control support for SH7722" if COMPILE_TEST
- select PINCTRL_SH_FUNC_GPIO
-
-config PINCTRL_PFC_SH7734
- bool "pin control support for SH7734" if COMPILE_TEST
- select PINCTRL_SH_FUNC_GPIO
-
-config PINCTRL_PFC_SH7757
- bool "pin control support for SH7757" if COMPILE_TEST
- select PINCTRL_SH_FUNC_GPIO
-
-config PINCTRL_PFC_SH7785
- bool "pin control support for SH7785" if COMPILE_TEST
- select PINCTRL_SH_FUNC_GPIO
-
-config PINCTRL_PFC_SH7786
- bool "pin control support for SH7786" if COMPILE_TEST
- select PINCTRL_SH_FUNC_GPIO
-
-config PINCTRL_PFC_SH73A0
- bool "pin control support for SH-Mobile AG5" if COMPILE_TEST
- select PINCTRL_SH_PFC_GPIO
- select REGULATOR
-
-config PINCTRL_PFC_SH7723
- bool "pin control support for SH-Mobile R2" if COMPILE_TEST
- select PINCTRL_SH_FUNC_GPIO
-
-config PINCTRL_PFC_SH7724
- bool "pin control support for SH-Mobile R2R" if COMPILE_TEST
- select PINCTRL_SH_FUNC_GPIO
-
-config PINCTRL_PFC_SHX3
- bool "pin control support for SH-X3" if COMPILE_TEST
- select PINCTRL_SH_FUNC_GPIO
-
endmenu
diff --git a/drivers/pinctrl/renesas/gpio.c b/drivers/pinctrl/renesas/gpio.c
index a5136dacaaf2..8efbdc1b0078 100644
--- a/drivers/pinctrl/renesas/gpio.c
+++ b/drivers/pinctrl/renesas/gpio.c
@@ -189,9 +189,11 @@ static int gpio_pin_get(struct gpio_chip *gc, unsigned offset)
return (gpio_read_data_reg(chip, reg->info) >> pos) & 1;
}
-static void gpio_pin_set(struct gpio_chip *gc, unsigned offset, int value)
+static int gpio_pin_set(struct gpio_chip *gc, unsigned int offset, int value)
{
gpio_pin_set_value(gpiochip_get_data(gc), offset, value);
+
+ return 0;
}
static int gpio_pin_to_irq(struct gpio_chip *gc, unsigned offset)
@@ -232,7 +234,7 @@ static int gpio_pin_setup(struct sh_pfc_chip *chip)
gc->direction_input = gpio_pin_direction_input;
gc->get = gpio_pin_get;
gc->direction_output = gpio_pin_direction_output;
- gc->set = gpio_pin_set;
+ gc->set_rv = gpio_pin_set;
gc->to_irq = gpio_pin_to_irq;
gc->label = pfc->info->name;
diff --git a/drivers/pinctrl/renesas/pinctrl-rza1.c b/drivers/pinctrl/renesas/pinctrl-rza1.c
index b1058504e0bb..3d8492c91710 100644
--- a/drivers/pinctrl/renesas/pinctrl-rza1.c
+++ b/drivers/pinctrl/renesas/pinctrl-rza1.c
@@ -830,12 +830,13 @@ static int rza1_gpio_get(struct gpio_chip *chip, unsigned int gpio)
return rza1_pin_get(port, gpio);
}
-static void rza1_gpio_set(struct gpio_chip *chip, unsigned int gpio,
- int value)
+static int rza1_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value)
{
struct rza1_port *port = gpiochip_get_data(chip);
rza1_pin_set(port, gpio, value);
+
+ return 0;
}
static const struct gpio_chip rza1_gpiochip_template = {
@@ -845,7 +846,7 @@ static const struct gpio_chip rza1_gpiochip_template = {
.direction_input = rza1_gpio_direction_input,
.direction_output = rza1_gpio_direction_output,
.get = rza1_gpio_get,
- .set = rza1_gpio_set,
+ .set_rv = rza1_gpio_set,
};
/* ----------------------------------------------------------------------------
* pinctrl operations
diff --git a/drivers/pinctrl/renesas/pinctrl-rza2.c b/drivers/pinctrl/renesas/pinctrl-rza2.c
index 3b5812963850..7a0b268d3eb9 100644
--- a/drivers/pinctrl/renesas/pinctrl-rza2.c
+++ b/drivers/pinctrl/renesas/pinctrl-rza2.c
@@ -172,8 +172,7 @@ static int rza2_chip_get(struct gpio_chip *chip, unsigned int offset)
return !!(readb(priv->base + RZA2_PIDR(port)) & BIT(pin));
}
-static void rza2_chip_set(struct gpio_chip *chip, unsigned int offset,
- int value)
+static int rza2_chip_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct rza2_pinctrl_priv *priv = gpiochip_get_data(chip);
u8 port = RZA2_PIN_ID_TO_PORT(offset);
@@ -188,6 +187,8 @@ static void rza2_chip_set(struct gpio_chip *chip, unsigned int offset,
new_value &= ~BIT(pin);
writeb(new_value, priv->base + RZA2_PODR(port));
+
+ return 0;
}
static int rza2_chip_direction_output(struct gpio_chip *chip,
@@ -236,7 +237,7 @@ static struct gpio_chip chip = {
.direction_input = rza2_chip_direction_input,
.direction_output = rza2_chip_direction_output,
.get = rza2_chip_get,
- .set = rza2_chip_set,
+ .set_rv = rza2_chip_set,
};
static int rza2_gpio_register(struct rza2_pinctrl_priv *priv)
diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
index 78fa08ff0faa..2a10ae0bf5bd 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
@@ -493,6 +493,23 @@ static void rzv2h_pmc_writeb(struct rzg2l_pinctrl *pctrl, u8 val, u16 offset)
writeb(pwpr & ~PWPR_REGWE_A, pctrl->base + regs->pwpr);
}
+static int rzg2l_validate_pin(struct rzg2l_pinctrl *pctrl,
+ u64 cfg, u32 port, u8 bit)
+{
+ u8 pinmap = FIELD_GET(PIN_CFG_PIN_MAP_MASK, cfg);
+ u32 off = RZG2L_PIN_CFG_TO_PORT_OFFSET(cfg);
+ u64 data;
+
+ if (!(pinmap & BIT(bit)) || port >= pctrl->data->n_port_pins)
+ return -EINVAL;
+
+ data = pctrl->data->port_pin_configs[port];
+ if (off != RZG2L_PIN_CFG_TO_PORT_OFFSET(data))
+ return -EINVAL;
+
+ return 0;
+}
+
static void rzg2l_pinctrl_set_pfc_mode(struct rzg2l_pinctrl *pctrl,
u8 pin, u8 off, u8 func)
{
@@ -536,6 +553,7 @@ static int rzg2l_pinctrl_set_mux(struct pinctrl_dev *pctldev,
unsigned int i, *psel_val;
struct group_desc *group;
const unsigned int *pins;
+ int ret;
func = pinmux_generic_get_function(pctldev, func_selector);
if (!func)
@@ -552,6 +570,10 @@ static int rzg2l_pinctrl_set_mux(struct pinctrl_dev *pctldev,
u32 off = RZG2L_PIN_CFG_TO_PORT_OFFSET(*pin_data);
u32 pin = RZG2L_PIN_ID_TO_PIN(pins[i]);
+ ret = rzg2l_validate_pin(pctrl, *pin_data, RZG2L_PIN_ID_TO_PORT(pins[i]), pin);
+ if (ret)
+ return ret;
+
dev_dbg(pctrl->dev, "port:%u pin: %u off:%x PSEL:%u\n",
RZG2L_PIN_ID_TO_PORT(pins[i]), pin, off, psel_val[i] - hwcfg->func_base);
@@ -806,23 +828,6 @@ done:
return ret;
}
-static int rzg2l_validate_gpio_pin(struct rzg2l_pinctrl *pctrl,
- u64 cfg, u32 port, u8 bit)
-{
- u8 pinmap = FIELD_GET(PIN_CFG_PIN_MAP_MASK, cfg);
- u32 off = RZG2L_PIN_CFG_TO_PORT_OFFSET(cfg);
- u64 data;
-
- if (!(pinmap & BIT(bit)) || port >= pctrl->data->n_port_pins)
- return -EINVAL;
-
- data = pctrl->data->port_pin_configs[port];
- if (off != RZG2L_PIN_CFG_TO_PORT_OFFSET(data))
- return -EINVAL;
-
- return 0;
-}
-
static u32 rzg2l_read_pin_config(struct rzg2l_pinctrl *pctrl, u32 offset,
u8 bit, u32 mask)
{
@@ -1287,7 +1292,7 @@ static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev,
} else {
bit = RZG2L_PIN_ID_TO_PIN(_pin);
- if (rzg2l_validate_gpio_pin(pctrl, *pin_data, RZG2L_PIN_ID_TO_PORT(_pin), bit))
+ if (rzg2l_validate_pin(pctrl, *pin_data, RZG2L_PIN_ID_TO_PORT(_pin), bit))
return -EINVAL;
}
@@ -1447,7 +1452,7 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
} else {
bit = RZG2L_PIN_ID_TO_PIN(_pin);
- if (rzg2l_validate_gpio_pin(pctrl, *pin_data, RZG2L_PIN_ID_TO_PORT(_pin), bit))
+ if (rzg2l_validate_pin(pctrl, *pin_data, RZG2L_PIN_ID_TO_PORT(_pin), bit))
return -EINVAL;
}
@@ -1687,7 +1692,7 @@ static int rzg2l_gpio_request(struct gpio_chip *chip, unsigned int offset)
u8 reg8;
int ret;
- ret = rzg2l_validate_gpio_pin(pctrl, *pin_data, port, bit);
+ ret = rzg2l_validate_pin(pctrl, *pin_data, port, bit);
if (ret)
return ret;
@@ -1758,8 +1763,8 @@ static int rzg2l_gpio_direction_input(struct gpio_chip *chip,
return 0;
}
-static void rzg2l_gpio_set(struct gpio_chip *chip, unsigned int offset,
- int value)
+static int rzg2l_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct rzg2l_pinctrl *pctrl = gpiochip_get_data(chip);
const struct pinctrl_pin_desc *pin_desc = &pctrl->desc.pins[offset];
@@ -1779,6 +1784,8 @@ static void rzg2l_gpio_set(struct gpio_chip *chip, unsigned int offset,
writeb(reg8 & ~BIT(bit), pctrl->base + P(off));
spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ return 0;
}
static int rzg2l_gpio_direction_output(struct gpio_chip *chip,
@@ -2788,7 +2795,7 @@ static int rzg2l_gpio_register(struct rzg2l_pinctrl *pctrl)
chip->direction_input = rzg2l_gpio_direction_input;
chip->direction_output = rzg2l_gpio_direction_output;
chip->get = rzg2l_gpio_get;
- chip->set = rzg2l_gpio_set;
+ chip->set_rv = rzg2l_gpio_set;
chip->label = name;
chip->parent = pctrl->dev;
chip->owner = THIS_MODULE;
diff --git a/drivers/pinctrl/renesas/pinctrl-rzn1.c b/drivers/pinctrl/renesas/pinctrl-rzn1.c
index d442d4f9981c..fb874867dbfb 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzn1.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzn1.c
@@ -680,6 +680,8 @@ static struct pinctrl_desc rzn1_pinctrl_desc = {
.pmxops = &rzn1_pmx_ops,
.confops = &rzn1_pinconf_ops,
.owner = THIS_MODULE,
+ .pins = rzn1_pins,
+ .npins = ARRAY_SIZE(rzn1_pins),
};
static int rzn1_pinctrl_parse_groups(struct device_node *np,
@@ -878,8 +880,6 @@ static int rzn1_pinctrl_probe(struct platform_device *pdev)
ipctl->dev = &pdev->dev;
rzn1_pinctrl_desc.name = dev_name(&pdev->dev);
- rzn1_pinctrl_desc.pins = rzn1_pins;
- rzn1_pinctrl_desc.npins = ARRAY_SIZE(rzn1_pins);
ret = rzn1_pinctrl_probe_dt(pdev, ipctl);
if (ret) {
diff --git a/drivers/pinctrl/renesas/pinctrl-rzv2m.c b/drivers/pinctrl/renesas/pinctrl-rzv2m.c
index 8c7169db4fcc..a17b68b4c466 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzv2m.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzv2m.c
@@ -790,14 +790,16 @@ static int rzv2m_gpio_direction_input(struct gpio_chip *chip,
return 0;
}
-static void rzv2m_gpio_set(struct gpio_chip *chip, unsigned int offset,
- int value)
+static int rzv2m_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct rzv2m_pinctrl *pctrl = gpiochip_get_data(chip);
u32 port = RZV2M_PIN_ID_TO_PORT(offset);
u8 bit = RZV2M_PIN_ID_TO_PIN(offset);
rzv2m_writel_we(pctrl->base + DO(port), bit, !!value);
+
+ return 0;
}
static int rzv2m_gpio_direction_output(struct gpio_chip *chip,
@@ -955,7 +957,7 @@ static int rzv2m_gpio_register(struct rzv2m_pinctrl *pctrl)
chip->direction_input = rzv2m_gpio_direction_input;
chip->direction_output = rzv2m_gpio_direction_output;
chip->get = rzv2m_gpio_get;
- chip->set = rzv2m_gpio_set;
+ chip->set_rv = rzv2m_gpio_set;
chip->label = name;
chip->parent = pctrl->dev;
chip->owner = THIS_MODULE;
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
index 9fd894729a7b..5fe7c4b9f7bd 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
@@ -1405,7 +1405,7 @@ static const struct samsung_pin_bank_data exynosautov920_pin_banks7[] = {
EXYNOSV920_PIN_BANK_EINTG(8, 0x8000, "gpg1", 0x18, 0x24, 0x28),
};
-static const struct samsung_retention_data exynosautov920_retention_data __initconst = {
+static const struct samsung_retention_data no_retention_data __initconst = {
.regs = NULL,
.nr_regs = 0,
.value = 0,
@@ -1421,7 +1421,7 @@ static const struct samsung_pin_ctrl exynosautov920_pin_ctrl[] = {
.eint_wkup_init = exynos_eint_wkup_init,
.suspend = exynosautov920_pinctrl_suspend,
.resume = exynosautov920_pinctrl_resume,
- .retention_data = &exynosautov920_retention_data,
+ .retention_data = &no_retention_data,
}, {
/* pin-controller instance 1 AUD data */
.pin_banks = exynosautov920_pin_banks1,
@@ -1764,6 +1764,7 @@ static const struct samsung_pin_ctrl gs101_pin_ctrl[] __initconst = {
.eint_wkup_init = exynos_eint_wkup_init,
.suspend = gs101_pinctrl_suspend,
.resume = gs101_pinctrl_resume,
+ .retention_data = &no_retention_data,
}, {
/* pin banks of gs101 pin-controller (FAR_ALIVE) */
.pin_banks = gs101_pin_far_alive,
@@ -1771,6 +1772,7 @@ static const struct samsung_pin_ctrl gs101_pin_ctrl[] __initconst = {
.eint_wkup_init = exynos_eint_wkup_init,
.suspend = gs101_pinctrl_suspend,
.resume = gs101_pinctrl_resume,
+ .retention_data = &no_retention_data,
}, {
/* pin banks of gs101 pin-controller (GSACORE) */
.pin_banks = gs101_pin_gsacore,
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c
index f3e1c11abe55..81fe0b08a9af 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.c
@@ -32,18 +32,24 @@
#include "pinctrl-samsung.h"
#include "pinctrl-exynos.h"
+#define MAX_WAKEUP_REG 3
+
struct exynos_irq_chip {
struct irq_chip chip;
u32 eint_con;
u32 eint_mask;
u32 eint_pend;
- u32 *eint_wake_mask_value;
+ u32 eint_num_wakeup_reg;
u32 eint_wake_mask_reg;
void (*set_eint_wakeup_mask)(struct samsung_pinctrl_drv_data *drvdata,
struct exynos_irq_chip *irq_chip);
};
+static u32 eint_wake_mask_values[MAX_WAKEUP_REG] = { EXYNOS_EINT_WAKEUP_MASK_DISABLED,
+ EXYNOS_EINT_WAKEUP_MASK_DISABLED,
+ EXYNOS_EINT_WAKEUP_MASK_DISABLED};
+
static inline struct exynos_irq_chip *to_exynos_irq_chip(struct irq_chip *chip)
{
return container_of(chip, struct exynos_irq_chip, chip);
@@ -307,7 +313,7 @@ static const struct exynos_irq_chip exynos_gpio_irq_chip __initconst = {
.eint_con = EXYNOS_GPIO_ECON_OFFSET,
.eint_mask = EXYNOS_GPIO_EMASK_OFFSET,
.eint_pend = EXYNOS_GPIO_EPEND_OFFSET,
- /* eint_wake_mask_value not used */
+ /* eint_wake_mask_values not used */
};
static int exynos_eint_irq_map(struct irq_domain *h, unsigned int virq,
@@ -467,10 +473,55 @@ err_domains:
return ret;
}
+#define BITS_PER_U32 32
+static int gs101_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on)
+{
+ struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
+ struct samsung_pinctrl_drv_data *d = bank->drvdata;
+ u32 bit, wakeup_reg, shift;
+
+ bit = bank->eint_num + irqd->hwirq;
+ wakeup_reg = bit / BITS_PER_U32;
+ shift = bit - (wakeup_reg * BITS_PER_U32);
+
+ if (!on)
+ eint_wake_mask_values[wakeup_reg] |= BIT_U32(shift);
+ else
+ eint_wake_mask_values[wakeup_reg] &= ~BIT_U32(shift);
+
+ dev_info(d->dev, "wake %s for irq %d\n", str_enabled_disabled(on),
+ irqd->irq);
+
+ return 0;
+}
+
+static void
+gs101_pinctrl_set_eint_wakeup_mask(struct samsung_pinctrl_drv_data *drvdata,
+ struct exynos_irq_chip *irq_chip)
+{
+ struct regmap *pmu_regs;
+
+ if (!drvdata->retention_ctrl || !drvdata->retention_ctrl->priv) {
+ dev_warn(drvdata->dev,
+ "No PMU syscon available. Wake-up mask will not be set.\n");
+ return;
+ }
+
+ pmu_regs = drvdata->retention_ctrl->priv;
+
+ dev_dbg(drvdata->dev, "Setting external wakeup interrupt mask:\n");
+
+ for (int i = 0; i < irq_chip->eint_num_wakeup_reg; i++) {
+ dev_dbg(drvdata->dev, "\tWAKEUP_MASK%d[0x%X] value[0x%X]\n",
+ i, irq_chip->eint_wake_mask_reg + i * 4,
+ eint_wake_mask_values[i]);
+ regmap_write(pmu_regs, irq_chip->eint_wake_mask_reg + i * 4,
+ eint_wake_mask_values[i]);
+ }
+}
+
static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on)
{
- struct irq_chip *chip = irq_data_get_irq_chip(irqd);
- struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
unsigned long bit = 1UL << (2 * bank->eint_offset + irqd->hwirq);
@@ -478,9 +529,9 @@ static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on)
irqd->irq, bank->name, irqd->hwirq);
if (!on)
- *our_chip->eint_wake_mask_value |= bit;
+ eint_wake_mask_values[0] |= bit;
else
- *our_chip->eint_wake_mask_value &= ~bit;
+ eint_wake_mask_values[0] &= ~bit;
return 0;
}
@@ -500,10 +551,10 @@ exynos_pinctrl_set_eint_wakeup_mask(struct samsung_pinctrl_drv_data *drvdata,
pmu_regs = drvdata->retention_ctrl->priv;
dev_info(drvdata->dev,
"Setting external wakeup interrupt mask: 0x%x\n",
- *irq_chip->eint_wake_mask_value);
+ eint_wake_mask_values[0]);
regmap_write(pmu_regs, irq_chip->eint_wake_mask_reg,
- *irq_chip->eint_wake_mask_value);
+ eint_wake_mask_values[0]);
}
static void
@@ -522,11 +573,10 @@ s5pv210_pinctrl_set_eint_wakeup_mask(struct samsung_pinctrl_drv_data *drvdata,
clk_base = (void __iomem *) drvdata->retention_ctrl->priv;
- __raw_writel(*irq_chip->eint_wake_mask_value,
+ __raw_writel(eint_wake_mask_values[0],
clk_base + irq_chip->eint_wake_mask_reg);
}
-static u32 eint_wake_mask_value = EXYNOS_EINT_WAKEUP_MASK_DISABLED;
/*
* irq_chip for wakeup interrupts
*/
@@ -544,7 +594,7 @@ static const struct exynos_irq_chip s5pv210_wkup_irq_chip __initconst = {
.eint_con = EXYNOS_WKUP_ECON_OFFSET,
.eint_mask = EXYNOS_WKUP_EMASK_OFFSET,
.eint_pend = EXYNOS_WKUP_EPEND_OFFSET,
- .eint_wake_mask_value = &eint_wake_mask_value,
+ .eint_num_wakeup_reg = 1,
/* Only differences with exynos4210_wkup_irq_chip: */
.eint_wake_mask_reg = S5PV210_EINT_WAKEUP_MASK,
.set_eint_wakeup_mask = s5pv210_pinctrl_set_eint_wakeup_mask,
@@ -564,7 +614,7 @@ static const struct exynos_irq_chip exynos4210_wkup_irq_chip __initconst = {
.eint_con = EXYNOS_WKUP_ECON_OFFSET,
.eint_mask = EXYNOS_WKUP_EMASK_OFFSET,
.eint_pend = EXYNOS_WKUP_EPEND_OFFSET,
- .eint_wake_mask_value = &eint_wake_mask_value,
+ .eint_num_wakeup_reg = 1,
.eint_wake_mask_reg = EXYNOS_EINT_WAKEUP_MASK,
.set_eint_wakeup_mask = exynos_pinctrl_set_eint_wakeup_mask,
};
@@ -583,7 +633,7 @@ static const struct exynos_irq_chip exynos7_wkup_irq_chip __initconst = {
.eint_con = EXYNOS7_WKUP_ECON_OFFSET,
.eint_mask = EXYNOS7_WKUP_EMASK_OFFSET,
.eint_pend = EXYNOS7_WKUP_EPEND_OFFSET,
- .eint_wake_mask_value = &eint_wake_mask_value,
+ .eint_num_wakeup_reg = 1,
.eint_wake_mask_reg = EXYNOS5433_EINT_WAKEUP_MASK,
.set_eint_wakeup_mask = exynos_pinctrl_set_eint_wakeup_mask,
};
@@ -599,13 +649,34 @@ static const struct exynos_irq_chip exynosautov920_wkup_irq_chip __initconst = {
.irq_request_resources = exynos_irq_request_resources,
.irq_release_resources = exynos_irq_release_resources,
},
- .eint_wake_mask_value = &eint_wake_mask_value,
+ .eint_num_wakeup_reg = 1,
.eint_wake_mask_reg = EXYNOS5433_EINT_WAKEUP_MASK,
.set_eint_wakeup_mask = exynos_pinctrl_set_eint_wakeup_mask,
};
+static const struct exynos_irq_chip gs101_wkup_irq_chip __initconst = {
+ .chip = {
+ .name = "gs101_wkup_irq_chip",
+ .irq_unmask = exynos_irq_unmask,
+ .irq_mask = exynos_irq_mask,
+ .irq_ack = exynos_irq_ack,
+ .irq_set_type = exynos_irq_set_type,
+ .irq_set_wake = gs101_wkup_irq_set_wake,
+ .irq_request_resources = exynos_irq_request_resources,
+ .irq_release_resources = exynos_irq_release_resources,
+ },
+ .eint_con = EXYNOS7_WKUP_ECON_OFFSET,
+ .eint_mask = EXYNOS7_WKUP_EMASK_OFFSET,
+ .eint_pend = EXYNOS7_WKUP_EPEND_OFFSET,
+ .eint_num_wakeup_reg = 3,
+ .eint_wake_mask_reg = GS101_EINT_WAKEUP_MASK,
+ .set_eint_wakeup_mask = gs101_pinctrl_set_eint_wakeup_mask,
+};
+
/* list of external wakeup controllers supported */
static const struct of_device_id exynos_wkup_irq_ids[] = {
+ { .compatible = "google,gs101-wakeup-eint",
+ .data = &gs101_wkup_irq_chip },
{ .compatible = "samsung,s5pv210-wakeup-eint",
.data = &s5pv210_wkup_irq_chip },
{ .compatible = "samsung,exynos4210-wakeup-eint",
@@ -688,6 +759,7 @@ out:
chained_irq_exit(chip, desc);
}
+static int eint_num;
/*
* exynos_eint_wkup_init() - setup handling of external wakeup interrupts.
* @d: driver data of samsung pinctrl driver.
@@ -736,6 +808,9 @@ __init int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
return -ENXIO;
}
+ bank->eint_num = eint_num;
+ eint_num = eint_num + bank->nr_pins;
+
if (!fwnode_property_present(bank->fwnode, "interrupts")) {
bank->eint_type = EINT_TYPE_WKUP_MUX;
++muxed_banks;
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h
index fcc57c244d16..1cabcbe1401a 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.h
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.h
@@ -141,6 +141,7 @@ struct samsung_pin_bank_type {
* @eint_type: type of the external interrupt supported by the bank.
* @eint_mask: bit mask of pins which support EINT function.
* @eint_offset: SoC-specific EINT register or interrupt offset of bank.
+ * @eint_num: total number of eint pins.
* @eint_con_offset: ExynosAuto SoC-specific EINT control register offset of bank.
* @eint_mask_offset: ExynosAuto SoC-specific EINT mask register offset of bank.
* @eint_pend_offset: ExynosAuto SoC-specific EINT pend register offset of bank.
@@ -156,6 +157,7 @@ struct samsung_pin_bank_data {
enum eint_type eint_type;
u32 eint_mask;
u32 eint_offset;
+ u32 eint_num;
u32 eint_con_offset;
u32 eint_mask_offset;
u32 eint_pend_offset;
@@ -174,6 +176,7 @@ struct samsung_pin_bank_data {
* @eint_type: type of the external interrupt supported by the bank.
* @eint_mask: bit mask of pins which support EINT function.
* @eint_offset: SoC-specific EINT register or interrupt offset of bank.
+ * @eint_num: total number of eint pins.
* @eint_con_offset: ExynosAuto SoC-specific EINT register or interrupt offset of bank.
* @eint_mask_offset: ExynosAuto SoC-specific EINT mask register offset of bank.
* @eint_pend_offset: ExynosAuto SoC-specific EINT pend register offset of bank.
@@ -201,6 +204,7 @@ struct samsung_pin_bank {
enum eint_type eint_type;
u32 eint_mask;
u32 eint_offset;
+ u32 eint_num;
u32 eint_con_offset;
u32 eint_mask_offset;
u32 eint_pend_offset;
diff --git a/drivers/pinctrl/spear/pinctrl-plgpio.c b/drivers/pinctrl/spear/pinctrl-plgpio.c
index a05570c7d833..e8234d2156da 100644
--- a/drivers/pinctrl/spear/pinctrl-plgpio.c
+++ b/drivers/pinctrl/spear/pinctrl-plgpio.c
@@ -181,24 +181,27 @@ static int plgpio_get_value(struct gpio_chip *chip, unsigned offset)
return is_plgpio_set(plgpio->regmap, offset, plgpio->regs.rdata);
}
-static void plgpio_set_value(struct gpio_chip *chip, unsigned offset, int value)
+static int plgpio_set_value(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct plgpio *plgpio = gpiochip_get_data(chip);
if (offset >= chip->ngpio)
- return;
+ return -EINVAL;
/* get correct offset for "offset" pin */
if (plgpio->p2o && (plgpio->p2o_regs & PTO_WDATA_REG)) {
offset = plgpio->p2o(offset);
if (offset == -1)
- return;
+ return -EINVAL;
}
if (value)
plgpio_reg_set(plgpio->regmap, offset, plgpio->regs.wdata);
else
plgpio_reg_reset(plgpio->regmap, offset, plgpio->regs.wdata);
+
+ return 0;
}
static int plgpio_request(struct gpio_chip *chip, unsigned offset)
@@ -579,7 +582,7 @@ static int plgpio_probe(struct platform_device *pdev)
plgpio->chip.direction_input = plgpio_direction_input;
plgpio->chip.direction_output = plgpio_direction_output;
plgpio->chip.get = plgpio_get_value;
- plgpio->chip.set = plgpio_set_value;
+ plgpio->chip.set_rv = plgpio_set_value;
plgpio->chip.label = dev_name(&pdev->dev);
plgpio->chip.parent = &pdev->dev;
plgpio->chip.owner = THIS_MODULE;
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c
index 27f99183d994..b729ca4de422 100644
--- a/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c
@@ -898,7 +898,7 @@ static const struct pinconf_ops starfive_pinconf_ops = {
.is_generic = true,
};
-static struct pinctrl_desc starfive_desc = {
+static const struct pinctrl_desc starfive_desc = {
.name = DRIVER_NAME,
.pins = starfive_pins,
.npins = ARRAY_SIZE(starfive_pins),
@@ -969,8 +969,8 @@ static int starfive_gpio_get(struct gpio_chip *gc, unsigned int gpio)
return !!(readl_relaxed(din) & BIT(gpio % 32));
}
-static void starfive_gpio_set(struct gpio_chip *gc, unsigned int gpio,
- int value)
+static int starfive_gpio_set(struct gpio_chip *gc, unsigned int gpio,
+ int value)
{
struct starfive_pinctrl *sfp = container_of(gc, struct starfive_pinctrl, gc);
void __iomem *dout = sfp->base + GPON_DOUT_CFG + 8 * gpio;
@@ -979,6 +979,8 @@ static void starfive_gpio_set(struct gpio_chip *gc, unsigned int gpio,
raw_spin_lock_irqsave(&sfp->lock, flags);
writel_relaxed(value, dout);
raw_spin_unlock_irqrestore(&sfp->lock, flags);
+
+ return 0;
}
static int starfive_gpio_set_config(struct gpio_chip *gc, unsigned int gpio,
@@ -1300,7 +1302,7 @@ static int starfive_probe(struct platform_device *pdev)
sfp->gc.direction_input = starfive_gpio_direction_input;
sfp->gc.direction_output = starfive_gpio_direction_output;
sfp->gc.get = starfive_gpio_get;
- sfp->gc.set = starfive_gpio_set;
+ sfp->gc.set_rv = starfive_gpio_set;
sfp->gc.set_config = starfive_gpio_set_config;
sfp->gc.add_pin_ranges = starfive_gpio_add_pin_ranges;
sfp->gc.base = -1;
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c
index 1d0d6c224c10..082bb1c6cea9 100644
--- a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c
@@ -608,8 +608,7 @@ static int jh7110_gpio_get(struct gpio_chip *gc, unsigned int gpio)
return !!(readl_relaxed(reg) & BIT(gpio % 32));
}
-static void jh7110_gpio_set(struct gpio_chip *gc,
- unsigned int gpio, int value)
+static int jh7110_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
{
struct jh7110_pinctrl *sfp = container_of(gc,
struct jh7110_pinctrl, gc);
@@ -625,6 +624,8 @@ static void jh7110_gpio_set(struct gpio_chip *gc,
dout |= readl_relaxed(reg_dout) & ~mask;
writel_relaxed(dout, reg_dout);
raw_spin_unlock_irqrestore(&sfp->lock, flags);
+
+ return 0;
}
static int jh7110_gpio_set_config(struct gpio_chip *gc,
@@ -934,7 +935,7 @@ int jh7110_pinctrl_probe(struct platform_device *pdev)
sfp->gc.direction_input = jh7110_gpio_direction_input;
sfp->gc.direction_output = jh7110_gpio_direction_output;
sfp->gc.get = jh7110_gpio_get;
- sfp->gc.set = jh7110_gpio_set;
+ sfp->gc.set_rv = jh7110_gpio_set;
sfp->gc.set_config = jh7110_gpio_set_config;
sfp->gc.add_pin_ranges = jh7110_gpio_add_pin_ranges;
sfp->gc.base = info->gc_base;
diff --git a/drivers/pinctrl/stm32/Kconfig b/drivers/pinctrl/stm32/Kconfig
index 2656d3d3ae40..5f67e1ee66dd 100644
--- a/drivers/pinctrl/stm32/Kconfig
+++ b/drivers/pinctrl/stm32/Kconfig
@@ -2,7 +2,7 @@
if ARCH_STM32 || COMPILE_TEST
config PINCTRL_STM32
- bool
+ tristate
depends on OF
select PINMUX
select GENERIC_PINCONF
@@ -53,8 +53,22 @@ config PINCTRL_STM32MP157
select PINCTRL_STM32
config PINCTRL_STM32MP257
- bool "STMicroelectronics STM32MP257 pin control" if COMPILE_TEST && !MACH_STM32MP25
+ tristate "STMicroelectronics STM32MP257 pin control"
depends on OF && HAS_IOMEM
- default MACH_STM32MP25
+ default MACH_STM32MP25 || (ARCH_STM32 && ARM64)
select PINCTRL_STM32
+
+config PINCTRL_STM32_HDP
+ tristate "STMicroelectronics STM32 Hardware Debug Port (HDP) pin control"
+ depends on OF && HAS_IOMEM
+ default ARCH_STM32 && !ARM_SINGLE_ARMV7M
+ select PINMUX
+ select GENERIC_PINCONF
+ select GPIOLIB
+ help
+ The Hardware Debug Port allows the observation of internal signals.
+ It uses configurable multiplexer to route signals in a dedicated observation register.
+ This driver also permits the observation of signals on external SoC pins.
+ It permits the observation of up to 16 signals per HDP line.
+
endif
diff --git a/drivers/pinctrl/stm32/Makefile b/drivers/pinctrl/stm32/Makefile
index 7b17464d8de1..98a1bbc7e16c 100644
--- a/drivers/pinctrl/stm32/Makefile
+++ b/drivers/pinctrl/stm32/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_PINCTRL_STM32H743) += pinctrl-stm32h743.o
obj-$(CONFIG_PINCTRL_STM32MP135) += pinctrl-stm32mp135.o
obj-$(CONFIG_PINCTRL_STM32MP157) += pinctrl-stm32mp157.o
obj-$(CONFIG_PINCTRL_STM32MP257) += pinctrl-stm32mp257.o
+obj-$(CONFIG_PINCTRL_STM32_HDP) += pinctrl-stm32-hdp.o
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32-hdp.c b/drivers/pinctrl/stm32/pinctrl-stm32-hdp.c
new file mode 100644
index 000000000000..e91442eb566b
--- /dev/null
+++ b/drivers/pinctrl/stm32/pinctrl-stm32-hdp.c
@@ -0,0 +1,720 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) STMicroelectronics 2025 - All Rights Reserved
+ * Author: Clément Le Goffic <clement.legoffic@foss.st.com> for STMicroelectronics.
+ */
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+
+#include "../core.h"
+
+#define DRIVER_NAME "stm32_hdp"
+#define HDP_CTRL_ENABLE 1
+#define HDP_CTRL_DISABLE 0
+
+#define HDP_CTRL 0x000
+#define HDP_MUX 0x004
+#define HDP_VAL 0x010
+#define HDP_GPOSET 0x014
+#define HDP_GPOCLR 0x018
+#define HDP_GPOVAL 0x01c
+#define HDP_VERR 0x3f4
+#define HDP_IPIDR 0x3f8
+#define HDP_SIDR 0x3fc
+
+#define HDP_MUX_SHIFT(n) ((n) * 4)
+#define HDP_MUX_MASK(n) (GENMASK(3, 0) << HDP_MUX_SHIFT(n))
+#define HDP_MUX_GPOVAL(n) (0xf << HDP_MUX_SHIFT(n))
+
+#define HDP_PIN 8
+#define HDP_FUNC 16
+#define HDP_FUNC_TOTAL (HDP_PIN * HDP_FUNC)
+
+struct stm32_hdp {
+ struct device *dev;
+ void __iomem *base;
+ struct clk *clk;
+ struct pinctrl_dev *pctl_dev;
+ struct gpio_chip gpio_chip;
+ u32 mux_conf;
+ u32 gposet_conf;
+ const char * const *func_name;
+};
+
+static const struct pinctrl_pin_desc stm32_hdp_pins[] = {
+ PINCTRL_PIN(0, "HDP0"),
+ PINCTRL_PIN(1, "HDP1"),
+ PINCTRL_PIN(2, "HDP2"),
+ PINCTRL_PIN(3, "HDP3"),
+ PINCTRL_PIN(4, "HDP4"),
+ PINCTRL_PIN(5, "HDP5"),
+ PINCTRL_PIN(6, "HDP6"),
+ PINCTRL_PIN(7, "HDP7"),
+};
+
+static const char * const func_name_mp13[] = {
+ //HDP0 functions:
+ "pwr_pwrwake_sys",
+ "pwr_stop_forbidden",
+ "pwr_stdby_wakeup",
+ "pwr_encomp_vddcore",
+ "bsec_out_sec_niden",
+ "aiec_sys_wakeup",
+ "none",
+ "none",
+ "ddrctrl_lp_req",
+ "pwr_ddr_ret_enable_n",
+ "dts_clk_ptat",
+ "none",
+ "sram3ctrl_tamp_erase_act",
+ "none",
+ "none",
+ "gpoval0",
+ //HDP1 functions:
+ "pwr_sel_vth_vddcpu",
+ "pwr_mpu_ram_lowspeed",
+ "ca7_naxierrirq",
+ "pwr_okin_mr",
+ "bsec_out_sec_dbgen",
+ "aiec_c1_wakeup",
+ "rcc_pwrds_mpu",
+ "none",
+ "ddrctrl_dfi_ctrlupd_req",
+ "ddrctrl_cactive_ddrc_asr",
+ "none",
+ "none",
+ "sram3ctrl_hw_erase_act",
+ "nic400_s0_bready",
+ "none",
+ "gpoval1",
+ //HDP2 functions:
+ "pwr_pwrwake_mpu",
+ "pwr_mpu_clock_disable_ack",
+ "ca7_ndbgreset_i",
+ "none",
+ "bsec_in_rstcore_n",
+ "bsec_out_sec_bsc_dis",
+ "none",
+ "none",
+ "ddrctrl_dfi_init_complete",
+ "ddrctrl_perf_op_is_refresh",
+ "ddrctrl_gskp_dfi_lp_req",
+ "none",
+ "sram3ctrl_sw_erase_act",
+ "nic400_s0_bvalid",
+ "none",
+ "gpoval2",
+ //HDP3 functions:
+ "pwr_sel_vth_vddcore",
+ "pwr_mpu_clock_disable_req",
+ "ca7_npmuirq0",
+ "ca7_nfiqout0",
+ "bsec_out_sec_dftlock",
+ "bsec_out_sec_jtag_dis",
+ "rcc_pwrds_sys",
+ "sram3ctrl_tamp_erase_req",
+ "ddrctrl_stat_ddrc_reg_selfref_type0",
+ "none",
+ "dts_valobus1_0",
+ "dts_valobus2_0",
+ "tamp_potential_tamp_erfcfg",
+ "nic400_s0_wready",
+ "nic400_s0_rready",
+ "gpoval3",
+ //HDP4 functions:
+ "none",
+ "pwr_stop2_active",
+ "ca7_nl2reset_i",
+ "ca7_npreset_varm_i",
+ "bsec_out_sec_dften",
+ "bsec_out_sec_dbgswenable",
+ "eth1_out_pmt_intr_o",
+ "eth2_out_pmt_intr_o",
+ "ddrctrl_stat_ddrc_reg_selfref_type1",
+ "ddrctrl_cactive_0",
+ "dts_valobus1_1",
+ "dts_valobus2_1",
+ "tamp_nreset_sram_ercfg",
+ "nic400_s0_wlast",
+ "nic400_s0_rlast",
+ "gpoval4",
+ //HDP5 functions:
+ "ca7_standbywfil2",
+ "pwr_vth_vddcore_ack",
+ "ca7_ncorereset_i",
+ "ca7_nirqout0",
+ "bsec_in_pwrok",
+ "bsec_out_sec_deviceen",
+ "eth1_out_lpi_intr_o",
+ "eth2_out_lpi_intr_o",
+ "ddrctrl_cactive_ddrc",
+ "ddrctrl_wr_credit_cnt",
+ "dts_valobus1_2",
+ "dts_valobus2_2",
+ "pka_pka_itamp_out",
+ "nic400_s0_wvalid",
+ "nic400_s0_rvalid",
+ "gpoval5",
+ //HDP6 functions:
+ "ca7_standbywfe0",
+ "pwr_vth_vddcpu_ack",
+ "ca7_evento",
+ "none",
+ "bsec_in_tamper_det",
+ "bsec_out_sec_spniden",
+ "eth1_out_mac_speed_o1",
+ "eth2_out_mac_speed_o1",
+ "ddrctrl_csysack_ddrc",
+ "ddrctrl_lpr_credit_cnt",
+ "dts_valobus1_3",
+ "dts_valobus2_3",
+ "saes_tamper_out",
+ "nic400_s0_awready",
+ "nic400_s0_arready",
+ "gpoval6",
+ //HDP7 functions:
+ "ca7_standbywfi0",
+ "pwr_rcc_vcpu_rdy",
+ "ca7_eventi",
+ "ca7_dbgack0",
+ "bsec_out_fuse_ok",
+ "bsec_out_sec_spiden",
+ "eth1_out_mac_speed_o0",
+ "eth2_out_mac_speed_o0",
+ "ddrctrl_csysreq_ddrc",
+ "ddrctrl_hpr_credit_cnt",
+ "dts_valobus1_4",
+ "dts_valobus2_4",
+ "rng_tamper_out",
+ "nic400_s0_awavalid",
+ "nic400_s0_aravalid",
+ "gpoval7",
+};
+
+static const char * const func_name_mp15[] = {
+ //HDP0 functions:
+ "pwr_pwrwake_sys",
+ "cm4_sleepdeep",
+ "pwr_stdby_wkup",
+ "pwr_encomp_vddcore",
+ "bsec_out_sec_niden",
+ "none",
+ "rcc_cm4_sleepdeep",
+ "gpu_dbg7",
+ "ddrctrl_lp_req",
+ "pwr_ddr_ret_enable_n",
+ "dts_clk_ptat",
+ "none",
+ "none",
+ "none",
+ "none",
+ "gpoval0",
+ //HDP1 functions:
+ "pwr_pwrwake_mcu",
+ "cm4_halted",
+ "ca7_naxierrirq",
+ "pwr_okin_mr",
+ "bsec_out_sec_dbgen",
+ "exti_sys_wakeup",
+ "rcc_pwrds_mpu",
+ "gpu_dbg6",
+ "ddrctrl_dfi_ctrlupd_req",
+ "ddrctrl_cactive_ddrc_asr",
+ "none",
+ "none",
+ "none",
+ "none",
+ "none",
+ "gpoval1",
+ //HDP2 functions:
+ "pwr_pwrwake_mpu",
+ "cm4_rxev",
+ "ca7_npmuirq1",
+ "ca7_nfiqout1",
+ "bsec_in_rstcore_n",
+ "exti_c2_wakeup",
+ "rcc_pwrds_mcu",
+ "gpu_dbg5",
+ "ddrctrl_dfi_init_complete",
+ "ddrctrl_perf_op_is_refresh",
+ "ddrctrl_gskp_dfi_lp_req",
+ "none",
+ "none",
+ "none",
+ "none",
+ "gpoval2",
+ //HDP3 functions:
+ "pwr_sel_vth_vddcore",
+ "cm4_txev",
+ "ca7_npmuirq0",
+ "ca7_nfiqout0",
+ "bsec_out_sec_dftlock",
+ "exti_c1_wakeup",
+ "rcc_pwrds_sys",
+ "gpu_dbg4",
+ "ddrctrl_stat_ddrc_reg_selfref_type0",
+ "ddrctrl_cactive_1",
+ "dts_valobus1_0",
+ "dts_valobus2_0",
+ "none",
+ "none",
+ "none",
+ "gpoval3",
+ //HDP4 functions:
+ "pwr_mpu_pdds_not_cstbydis",
+ "cm4_sleeping",
+ "ca7_nreset1",
+ "ca7_nirqout1",
+ "bsec_out_sec_dften",
+ "bsec_out_sec_dbgswenable",
+ "eth_out_pmt_intr_o",
+ "gpu_dbg3",
+ "ddrctrl_stat_ddrc_reg_selfref_type1",
+ "ddrctrl_cactive_0",
+ "dts_valobus1_1",
+ "dts_valobus2_1",
+ "none",
+ "none",
+ "none",
+ "gpoval4",
+ //HDP5 functions:
+ "ca7_standbywfil2",
+ "pwr_vth_vddcore_ack",
+ "ca7_nreset0",
+ "ca7_nirqout0",
+ "bsec_in_pwrok",
+ "bsec_out_sec_deviceen",
+ "eth_out_lpi_intr_o",
+ "gpu_dbg2",
+ "ddrctrl_cactive_ddrc",
+ "ddrctrl_wr_credit_cnt",
+ "dts_valobus1_2",
+ "dts_valobus2_2",
+ "none",
+ "none",
+ "none",
+ "gpoval5",
+ //HDP6 functions:
+ "ca7_standbywfi1",
+ "ca7_standbywfe1",
+ "ca7_evento",
+ "ca7_dbgack1",
+ "none",
+ "bsec_out_sec_spniden",
+ "eth_out_mac_speed_o1",
+ "gpu_dbg1",
+ "ddrctrl_csysack_ddrc",
+ "ddrctrl_lpr_credit_cnt",
+ "dts_valobus1_3",
+ "dts_valobus2_3",
+ "none",
+ "none",
+ "none",
+ "gpoval6",
+ //HDP7 functions:
+ "ca7_standbywfi0",
+ "ca7_standbywfe0",
+ "none",
+ "ca7_dbgack0",
+ "bsec_out_fuse_ok",
+ "bsec_out_sec_spiden",
+ "eth_out_mac_speed_o0",
+ "gpu_dbg0",
+ "ddrctrl_csysreq_ddrc",
+ "ddrctrl_hpr_credit_cnt",
+ "dts_valobus1_4",
+ "dts_valobus2_4",
+ "none",
+ "none",
+ "none",
+ "gpoval7"
+};
+
+static const char * const func_name_mp25[] = {
+ //HDP0 functions:
+ "pwr_pwrwake_sys",
+ "cpu2_sleep_deep",
+ "bsec_out_tst_sdr_unlock_or_disable_scan",
+ "bsec_out_nidenm",
+ "bsec_out_nidena",
+ "cpu2_state_0",
+ "rcc_pwrds_sys",
+ "gpu_dbg7",
+ "ddrss_csysreq_ddrc",
+ "ddrss_dfi_phyupd_req",
+ "cpu3_sleep_deep",
+ "d2_gbl_per_clk_bus_req",
+ "pcie_usb_cxpl_debug_info_ei_0",
+ "pcie_usb_cxpl_debug_info_ei_8",
+ "d3_state_0",
+ "gpoval0",
+ //HDP1 functions:
+ "pwr_pwrwake_cpu2",
+ "cpu2_halted",
+ "cpu2_state_1",
+ "bsec_out_dbgenm",
+ "bsec_out_dbgena",
+ "exti1_sys_wakeup",
+ "rcc_pwrds_cpu2",
+ "gpu_dbg6",
+ "ddrss_csysack_ddrc",
+ "ddrss_dfi_phymstr_req",
+ "cpu3_halted",
+ "d2_gbl_per_dma_req",
+ "pcie_usb_cxpl_debug_info_ei_1",
+ "pcie_usb_cxpl_debug_info_ei_9",
+ "d3_state_1",
+ "gpoval1",
+ //HDP2 functions:
+ "pwr_pwrwake_cpu1",
+ "cpu2_rxev",
+ "cpu1_npumirq1",
+ "cpu1_nfiqout1",
+ "bsec_out_shdbgen",
+ "exti1_cpu2_wakeup",
+ "rcc_pwrds_cpu1",
+ "gpu_dbg5",
+ "ddrss_cactive_ddrc",
+ "ddrss_dfi_lp_req",
+ "cpu3_rxev",
+ "hpdma1_clk_bus_req",
+ "pcie_usb_cxpl_debug_info_ei_2",
+ "pcie_usb_cxpl_debug_info_ei_10",
+ "d3_state_2",
+ "gpoval2",
+ //HDP3 functions:
+ "pwr_sel_vth_vddcpu",
+ "cpu2_txev",
+ "cpu1_npumirq0",
+ "cpu1_nfiqout0",
+ "bsec_out_ddbgen",
+ "exti1_cpu1_wakeup",
+ "cpu3_state_0",
+ "gpu_dbg4",
+ "ddrss_mcdcg_en",
+ "ddrss_dfi_freq_0",
+ "cpu3_txev",
+ "hpdma2_clk_bus_req",
+ "pcie_usb_cxpl_debug_info_ei_3",
+ "pcie_usb_cxpl_debug_info_ei_11",
+ "d1_state_0",
+ "gpoval3",
+ //HDP4 functions:
+ "pwr_sel_vth_vddcore",
+ "cpu2_sleeping",
+ "cpu1_evento",
+ "cpu1_nirqout1",
+ "bsec_out_spnidena",
+ "exti2_d3_wakeup",
+ "eth1_out_pmt_intr_o",
+ "gpu_dbg3",
+ "ddrss_dphycg_en",
+ "ddrss_obsp0",
+ "cpu3_sleeping",
+ "hpdma3_clk_bus_req",
+ "pcie_usb_cxpl_debug_info_ei_4",
+ "pcie_usb_cxpl_debug_info_ei_12",
+ "d1_state_1",
+ "gpoval4",
+ //HDP5 functions:
+ "cpu1_standby_wfil2",
+ "none",
+ "none",
+ "cpu1_nirqout0",
+ "bsec_out_spidena",
+ "exti2_cpu3_wakeup",
+ "eth1_out_lpi_intr_o",
+ "gpu_dbg2",
+ "ddrctrl_dfi_init_start",
+ "ddrss_obsp1",
+ "cpu3_state_1",
+ "d3_gbl_per_clk_bus_req",
+ "pcie_usb_cxpl_debug_info_ei_5",
+ "pcie_usb_cxpl_debug_info_ei_13",
+ "d1_state_2",
+ "gpoval5",
+ //HDP6 functions:
+ "cpu1_standby_wfi1",
+ "cpu1_standby_wfe1",
+ "cpu1_halted1",
+ "cpu1_naxierrirq",
+ "bsec_out_spnidenm",
+ "exti2_cpu2_wakeup",
+ "eth2_out_pmt_intr_o",
+ "gpu_dbg1",
+ "ddrss_dfi_init_complete",
+ "ddrss_obsp2",
+ "d2_state_0",
+ "d3_gbl_per_dma_req",
+ "pcie_usb_cxpl_debug_info_ei_6",
+ "pcie_usb_cxpl_debug_info_ei_14",
+ "cpu1_state_0",
+ "gpoval6",
+ //HDP7 functions:
+ "cpu1_standby_wfi0",
+ "cpu1_standby_wfe0",
+ "cpu1_halted0",
+ "none",
+ "bsec_out_spidenm",
+ "exti2_cpu1__wakeup",
+ "eth2_out_lpi_intr_o",
+ "gpu_dbg0",
+ "ddrss_dfi_ctrlupd_req",
+ "ddrss_obsp3",
+ "d2_state_1",
+ "lpdma1_clk_bus_req",
+ "pcie_usb_cxpl_debug_info_ei_7",
+ "pcie_usb_cxpl_debug_info_ei_15",
+ "cpu1_state_1",
+ "gpoval7",
+};
+
+static const char * const stm32_hdp_pins_group[] = {
+ "HDP0",
+ "HDP1",
+ "HDP2",
+ "HDP3",
+ "HDP4",
+ "HDP5",
+ "HDP6",
+ "HDP7"
+};
+
+static int stm32_hdp_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static int stm32_hdp_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(stm32_hdp_pins);
+}
+
+static const char *stm32_hdp_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ return stm32_hdp_pins[selector].name;
+}
+
+static int stm32_hdp_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, unsigned int selector,
+ const unsigned int **pins, unsigned int *num_pins)
+{
+ *pins = &stm32_hdp_pins[selector].number;
+ *num_pins = 1;
+
+ return 0;
+}
+
+static const struct pinctrl_ops stm32_hdp_pinctrl_ops = {
+ .get_groups_count = stm32_hdp_pinctrl_get_groups_count,
+ .get_group_name = stm32_hdp_pinctrl_get_group_name,
+ .get_group_pins = stm32_hdp_pinctrl_get_group_pins,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_all,
+ .dt_free_map = pinconf_generic_dt_free_map,
+};
+
+static int stm32_hdp_pinmux_get_functions_count(struct pinctrl_dev *pctldev)
+{
+ return HDP_FUNC_TOTAL;
+}
+
+static const char *stm32_hdp_pinmux_get_function_name(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ struct stm32_hdp *hdp = pinctrl_dev_get_drvdata(pctldev);
+
+ return hdp->func_name[selector];
+}
+
+static int stm32_hdp_pinmux_get_function_groups(struct pinctrl_dev *pctldev, unsigned int selector,
+ const char *const **groups,
+ unsigned int *num_groups)
+{
+ u32 index = selector / HDP_FUNC;
+
+ *groups = &stm32_hdp_pins[index].name;
+ *num_groups = 1;
+
+ return 0;
+}
+
+static int stm32_hdp_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector,
+ unsigned int group_selector)
+{
+ struct stm32_hdp *hdp = pinctrl_dev_get_drvdata(pctldev);
+
+ unsigned int pin = stm32_hdp_pins[group_selector].number;
+ u32 mux;
+
+ func_selector %= HDP_FUNC;
+ mux = readl_relaxed(hdp->base + HDP_MUX);
+ mux &= ~HDP_MUX_MASK(pin);
+ mux |= func_selector << HDP_MUX_SHIFT(pin);
+
+ writel_relaxed(mux, hdp->base + HDP_MUX);
+ hdp->mux_conf = mux;
+
+ return 0;
+}
+
+static const struct pinmux_ops stm32_hdp_pinmux_ops = {
+ .get_functions_count = stm32_hdp_pinmux_get_functions_count,
+ .get_function_name = stm32_hdp_pinmux_get_function_name,
+ .get_function_groups = stm32_hdp_pinmux_get_function_groups,
+ .set_mux = stm32_hdp_pinmux_set_mux,
+ .gpio_set_direction = NULL,
+};
+
+static struct pinctrl_desc stm32_hdp_pdesc = {
+ .name = DRIVER_NAME,
+ .pins = stm32_hdp_pins,
+ .npins = ARRAY_SIZE(stm32_hdp_pins),
+ .pctlops = &stm32_hdp_pinctrl_ops,
+ .pmxops = &stm32_hdp_pinmux_ops,
+ .owner = THIS_MODULE,
+};
+
+static const struct of_device_id stm32_hdp_of_match[] = {
+ {
+ .compatible = "st,stm32mp131-hdp",
+ .data = &func_name_mp13,
+ },
+ {
+ .compatible = "st,stm32mp151-hdp",
+ .data = &func_name_mp15,
+ },
+ {
+ .compatible = "st,stm32mp251-hdp",
+ .data = &func_name_mp25,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, stm32_hdp_of_match);
+
+static int stm32_hdp_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct stm32_hdp *hdp;
+ u8 version;
+ int err;
+
+ hdp = devm_kzalloc(dev, sizeof(*hdp), GFP_KERNEL);
+ if (!hdp)
+ return -ENOMEM;
+ hdp->dev = dev;
+
+ platform_set_drvdata(pdev, hdp);
+
+ hdp->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(hdp->base))
+ return PTR_ERR(hdp->base);
+
+ hdp->func_name = of_device_get_match_data(dev);
+ if (!hdp->func_name)
+ return dev_err_probe(dev, -ENODEV, "No function name provided\n");
+
+ hdp->clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(hdp->clk))
+ return dev_err_probe(dev, PTR_ERR(hdp->clk), "No HDP clock provided\n");
+
+ err = devm_pinctrl_register_and_init(dev, &stm32_hdp_pdesc, hdp, &hdp->pctl_dev);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to register pinctrl\n");
+
+ err = pinctrl_enable(hdp->pctl_dev);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to enable pinctrl\n");
+
+ hdp->gpio_chip.get_direction = stm32_hdp_gpio_get_direction;
+ hdp->gpio_chip.ngpio = ARRAY_SIZE(stm32_hdp_pins);
+ hdp->gpio_chip.can_sleep = true;
+ hdp->gpio_chip.names = stm32_hdp_pins_group;
+
+ err = bgpio_init(&hdp->gpio_chip, dev, 4,
+ hdp->base + HDP_GPOVAL,
+ hdp->base + HDP_GPOSET,
+ hdp->base + HDP_GPOCLR,
+ NULL, NULL, BGPIOF_NO_INPUT);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to init bgpio\n");
+
+
+ err = devm_gpiochip_add_data(dev, &hdp->gpio_chip, hdp);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to add gpiochip\n");
+
+ writel_relaxed(HDP_CTRL_ENABLE, hdp->base + HDP_CTRL);
+
+ version = readl_relaxed(hdp->base + HDP_VERR);
+ dev_dbg(dev, "STM32 HDP version %u.%u initialized\n", version >> 4, version & 0x0f);
+
+ return 0;
+}
+
+static void stm32_hdp_remove(struct platform_device *pdev)
+{
+ struct stm32_hdp *hdp = platform_get_drvdata(pdev);
+
+ writel_relaxed(HDP_CTRL_DISABLE, hdp->base + HDP_CTRL);
+}
+
+static int stm32_hdp_suspend(struct device *dev)
+{
+ struct stm32_hdp *hdp = dev_get_drvdata(dev);
+
+ hdp->gposet_conf = readl_relaxed(hdp->base + HDP_GPOSET);
+
+ pinctrl_pm_select_sleep_state(dev);
+
+ clk_disable_unprepare(hdp->clk);
+
+ return 0;
+}
+
+static int stm32_hdp_resume(struct device *dev)
+{
+ struct stm32_hdp *hdp = dev_get_drvdata(dev);
+ int err;
+
+ err = clk_prepare_enable(hdp->clk);
+ if (err) {
+ dev_err(dev, "Failed to prepare_enable clk (%d)\n", err);
+ return err;
+ }
+
+ writel_relaxed(HDP_CTRL_ENABLE, hdp->base + HDP_CTRL);
+ writel_relaxed(hdp->gposet_conf, hdp->base + HDP_GPOSET);
+ writel_relaxed(hdp->mux_conf, hdp->base + HDP_MUX);
+
+ pinctrl_pm_select_default_state(dev);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(stm32_hdp_pm_ops, stm32_hdp_suspend, stm32_hdp_resume);
+
+static struct platform_driver stm32_hdp_driver = {
+ .probe = stm32_hdp_probe,
+ .remove = stm32_hdp_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .pm = pm_sleep_ptr(&stm32_hdp_pm_ops),
+ .of_match_table = stm32_hdp_of_match,
+ }
+};
+
+module_platform_driver(stm32_hdp_driver);
+
+MODULE_AUTHOR("Clément Le Goffic");
+MODULE_DESCRIPTION("STMicroelectronics STM32 Hardware Debug Port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c
index ba49d48c3a1d..f47c4e6f12b4 100644
--- a/drivers/pinctrl/stm32/pinctrl-stm32.c
+++ b/drivers/pinctrl/stm32/pinctrl-stm32.c
@@ -6,7 +6,9 @@
*
* Heavily based on Mediatek's pinctrl driver
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
+#include <linux/export.h>
#include <linux/gpio/driver.h>
#include <linux/hwspinlock.h>
#include <linux/io.h>
@@ -36,6 +38,8 @@
#include "../pinctrl-utils.h"
#include "pinctrl-stm32.h"
+#define STM32_GPIO_CID1 1
+
#define STM32_GPIO_MODER 0x00
#define STM32_GPIO_TYPER 0x04
#define STM32_GPIO_SPEEDR 0x08
@@ -47,6 +51,8 @@
#define STM32_GPIO_AFRL 0x20
#define STM32_GPIO_AFRH 0x24
#define STM32_GPIO_SECCFGR 0x30
+#define STM32_GPIO_CIDCFGR(x) (0x50 + (0x8 * (x)))
+#define STM32_GPIO_SEMCR(x) (0x54 + (0x8 * (x)))
/* custom bitfield to backup pin status */
#define STM32_GPIO_BKP_MODE_SHIFT 0
@@ -60,6 +66,14 @@
#define STM32_GPIO_BKP_TYPE 10
#define STM32_GPIO_BKP_VAL 11
+#define STM32_GPIO_CIDCFGR_CFEN BIT(0)
+#define STM32_GPIO_CIDCFGR_SEMEN BIT(1)
+#define STM32_GPIO_CIDCFGR_SCID_MASK GENMASK(5, 4)
+#define STM32_GPIO_CIDCFGR_SEMWL_CID1 BIT(16 + STM32_GPIO_CID1)
+
+#define STM32_GPIO_SEMCR_SEM_MUTEX BIT(0)
+#define STM32_GPIO_SEMCR_SEMCID_MASK GENMASK(5, 4)
+
#define STM32_GPIO_PINS_PER_BANK 16
#define STM32_GPIO_IRQ_LINE 16
@@ -77,6 +91,7 @@ static const char * const stm32_gpio_functions[] = {
"af8", "af9", "af10",
"af11", "af12", "af13",
"af14", "af15", "analog",
+ "reserved",
};
struct stm32_pinctrl_group {
@@ -98,6 +113,7 @@ struct stm32_gpio_bank {
u32 pin_backup[STM32_GPIO_PINS_PER_BANK];
u8 irq_type[STM32_GPIO_PINS_PER_BANK];
bool secure_control;
+ bool rif_control;
};
struct stm32_pinctrl {
@@ -122,6 +138,8 @@ struct stm32_pinctrl {
spinlock_t irqmux_lock;
};
+static void stm32_pmx_get_mode(struct stm32_gpio_bank *bank, int pin, u32 *mode, u32 *alt);
+
static inline int stm32_gpio_pin(int gpio)
{
return gpio % STM32_GPIO_PINS_PER_BANK;
@@ -192,6 +210,80 @@ static void stm32_gpio_backup_bias(struct stm32_gpio_bank *bank, u32 offset,
bank->pin_backup[offset] |= bias << STM32_GPIO_BKP_PUPD_SHIFT;
}
+/* RIF functions */
+
+static bool stm32_gpio_rif_valid(struct stm32_gpio_bank *bank, unsigned int gpio_nr)
+{
+ u32 cid;
+
+ cid = readl_relaxed(bank->base + STM32_GPIO_CIDCFGR(gpio_nr));
+
+ if (!(cid & STM32_GPIO_CIDCFGR_CFEN))
+ return true;
+
+ if (!(cid & STM32_GPIO_CIDCFGR_SEMEN)) {
+ if (FIELD_GET(STM32_GPIO_CIDCFGR_SCID_MASK, cid) == STM32_GPIO_CID1)
+ return true;
+
+ return false;
+ }
+
+ if (cid & STM32_GPIO_CIDCFGR_SEMWL_CID1)
+ return true;
+
+ return false;
+}
+
+static bool stm32_gpio_rif_acquire_semaphore(struct stm32_gpio_bank *bank, unsigned int gpio_nr)
+{
+ u32 cid, sem;
+
+ cid = readl_relaxed(bank->base + STM32_GPIO_CIDCFGR(gpio_nr));
+
+ if (!(cid & STM32_GPIO_CIDCFGR_CFEN))
+ return true;
+
+ if (!(cid & STM32_GPIO_CIDCFGR_SEMEN)) {
+ if (FIELD_GET(STM32_GPIO_CIDCFGR_SCID_MASK, cid) == STM32_GPIO_CID1)
+ return true;
+
+ return false;
+ }
+
+ if (!(cid & STM32_GPIO_CIDCFGR_SEMWL_CID1))
+ return false;
+
+ sem = readl_relaxed(bank->base + STM32_GPIO_SEMCR(gpio_nr));
+ if (sem & STM32_GPIO_SEMCR_SEM_MUTEX) {
+ if (FIELD_GET(STM32_GPIO_SEMCR_SEMCID_MASK, sem) == STM32_GPIO_CID1)
+ return true;
+
+ return false;
+ }
+
+ writel_relaxed(STM32_GPIO_SEMCR_SEM_MUTEX, bank->base + STM32_GPIO_SEMCR(gpio_nr));
+
+ sem = readl_relaxed(bank->base + STM32_GPIO_SEMCR(gpio_nr));
+ if (sem & STM32_GPIO_SEMCR_SEM_MUTEX &&
+ FIELD_GET(STM32_GPIO_SEMCR_SEMCID_MASK, sem) == STM32_GPIO_CID1)
+ return true;
+
+ return false;
+}
+
+static void stm32_gpio_rif_release_semaphore(struct stm32_gpio_bank *bank, unsigned int gpio_nr)
+{
+ u32 cid;
+
+ cid = readl_relaxed(bank->base + STM32_GPIO_CIDCFGR(gpio_nr));
+
+ if (!(cid & STM32_GPIO_CIDCFGR_CFEN))
+ return;
+
+ if (cid & STM32_GPIO_CIDCFGR_SEMEN)
+ writel_relaxed(0, bank->base + STM32_GPIO_SEMCR(gpio_nr));
+}
+
/* GPIO functions */
static inline void __stm32_gpio_set(struct stm32_gpio_bank *bank,
@@ -218,9 +310,26 @@ static int stm32_gpio_request(struct gpio_chip *chip, unsigned offset)
return -EINVAL;
}
+ if (bank->rif_control) {
+ if (!stm32_gpio_rif_acquire_semaphore(bank, offset)) {
+ dev_err(pctl->dev, "pin %d not available.\n", pin);
+ return -EINVAL;
+ }
+ }
+
return pinctrl_gpio_request(chip, offset);
}
+static void stm32_gpio_free(struct gpio_chip *chip, unsigned int offset)
+{
+ struct stm32_gpio_bank *bank = gpiochip_get_data(chip);
+
+ pinctrl_gpio_free(chip, offset);
+
+ if (bank->rif_control)
+ stm32_gpio_rif_release_semaphore(bank, offset);
+}
+
static int stm32_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct stm32_gpio_bank *bank = gpiochip_get_data(chip);
@@ -304,12 +413,25 @@ static int stm32_gpio_init_valid_mask(struct gpio_chip *chip,
}
}
+ if (bank->rif_control) {
+ for (i = 0; i < ngpios; i++) {
+ if (!test_bit(i, valid_mask))
+ continue;
+
+ if (stm32_gpio_rif_valid(bank, i))
+ continue;
+
+ dev_dbg(pctl->dev, "RIF semaphore ownership conflict, GPIO %u", i);
+ clear_bit(i, valid_mask);
+ }
+ }
+
return 0;
}
static const struct gpio_chip stm32_gpio_template = {
.request = stm32_gpio_request,
- .free = pinctrl_gpio_free,
+ .free = stm32_gpio_free,
.get = stm32_gpio_get,
.set_rv = stm32_gpio_set,
.direction_input = pinctrl_gpio_direction_input,
@@ -411,6 +533,7 @@ static struct irq_chip stm32_gpio_irq_chip = {
.irq_set_wake = irq_chip_set_wake_parent,
.irq_request_resources = stm32_gpio_irq_request_resources,
.irq_release_resources = stm32_gpio_irq_release_resources,
+ .irq_set_affinity = IS_ENABLED(CONFIG_SMP) ? irq_chip_set_affinity_parent : NULL,
};
static int stm32_gpio_domain_translate(struct irq_domain *d,
@@ -541,6 +664,9 @@ static bool stm32_pctrl_is_function_valid(struct stm32_pinctrl *pctl,
if (pin->pin.number != pin_num)
continue;
+ if (fnum == STM32_PIN_RSVD)
+ return true;
+
for (k = 0; k < STM32_CONFIG_NUM; k++) {
if (func->num == fnum)
return true;
@@ -798,8 +924,7 @@ unlock:
return err;
}
-void stm32_pmx_get_mode(struct stm32_gpio_bank *bank, int pin, u32 *mode,
- u32 *alt)
+static void stm32_pmx_get_mode(struct stm32_gpio_bank *bank, int pin, u32 *mode, u32 *alt)
{
u32 val;
int alt_shift = (pin % 8) * 4;
@@ -841,6 +966,11 @@ static int stm32_pmx_set_mux(struct pinctrl_dev *pctldev,
return -EINVAL;
}
+ if (function == STM32_PIN_RSVD) {
+ dev_dbg(pctl->dev, "Reserved pins, skipping HW update.\n");
+ return 0;
+ }
+
bank = gpiochip_get_data(range->gc);
pin = stm32_gpio_pin(g->pin);
@@ -1348,6 +1478,7 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, struct fwnode
bank->bank_nr = bank_nr;
bank->bank_ioport_nr = bank_ioport_nr;
bank->secure_control = pctl->match_data->secure_control;
+ bank->rif_control = pctl->match_data->rif_control;
spin_lock_init(&bank->lock);
if (pctl->domain) {
@@ -1664,6 +1795,7 @@ err_register:
clk_bulk_disable_unprepare(banks, pctl->clks);
return ret;
}
+EXPORT_SYMBOL(stm32_pctl_probe);
static int __maybe_unused stm32_pinctrl_restore_gpio_regs(
struct stm32_pinctrl *pctl, u32 pin)
@@ -1736,6 +1868,7 @@ int __maybe_unused stm32_pinctrl_suspend(struct device *dev)
return 0;
}
+EXPORT_SYMBOL(stm32_pinctrl_suspend);
int __maybe_unused stm32_pinctrl_resume(struct device *dev)
{
@@ -1752,3 +1885,8 @@ int __maybe_unused stm32_pinctrl_resume(struct device *dev)
return 0;
}
+EXPORT_SYMBOL(stm32_pinctrl_resume);
+
+MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@foss.st.com>");
+MODULE_DESCRIPTION("STM32 core pinctrl driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.h b/drivers/pinctrl/stm32/pinctrl-stm32.h
index 5e5de92ddd58..b98a4141bf2c 100644
--- a/drivers/pinctrl/stm32/pinctrl-stm32.h
+++ b/drivers/pinctrl/stm32/pinctrl-stm32.h
@@ -17,7 +17,8 @@
#define STM32_PIN_GPIO 0
#define STM32_PIN_AF(x) ((x) + 1)
#define STM32_PIN_ANALOG (STM32_PIN_AF(15) + 1)
-#define STM32_CONFIG_NUM (STM32_PIN_ANALOG + 1)
+#define STM32_PIN_RSVD (STM32_PIN_ANALOG + 1)
+#define STM32_CONFIG_NUM (STM32_PIN_RSVD + 1)
/* package information */
#define STM32MP_PKG_AA BIT(0)
@@ -63,14 +64,25 @@ struct stm32_pinctrl_match_data {
const struct stm32_desc_pin *pins;
const unsigned int npins;
bool secure_control;
+ bool rif_control;
};
-struct stm32_gpio_bank;
-
+/**
+ * stm32_pctl_probe() - Common probe for stm32 pinctrl drivers.
+ * @pdev: Pinctrl platform device.
+ */
int stm32_pctl_probe(struct platform_device *pdev);
-void stm32_pmx_get_mode(struct stm32_gpio_bank *bank,
- int pin, u32 *mode, u32 *alt);
+
+/**
+ * stm32_pinctrl_suspend() - Common suspend for stm32 pinctrl drivers.
+ * @dev: Pinctrl device.
+ */
int stm32_pinctrl_suspend(struct device *dev);
+
+/**
+ * stm32_pinctrl_resume() - Common resume for stm32 pinctrl drivers.
+ * @dev: Pinctrl device.
+ */
int stm32_pinctrl_resume(struct device *dev);
#endif /* __PINCTRL_STM32_H */
diff --git a/drivers/pinctrl/stm32/pinctrl-stm32mp257.c b/drivers/pinctrl/stm32/pinctrl-stm32mp257.c
index 23aebd4695e9..d226de524bfc 100644
--- a/drivers/pinctrl/stm32/pinctrl-stm32mp257.c
+++ b/drivers/pinctrl/stm32/pinctrl-stm32mp257.c
@@ -4,6 +4,7 @@
* Author: Alexandre Torgue <alexandre.torgue@foss.st.com> for STMicroelectronics.
*/
#include <linux/init.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -2542,11 +2543,15 @@ static const struct stm32_desc_pin stm32mp257_z_pins[] = {
static struct stm32_pinctrl_match_data stm32mp257_match_data = {
.pins = stm32mp257_pins,
.npins = ARRAY_SIZE(stm32mp257_pins),
+ .secure_control = true,
+ .rif_control = true,
};
static struct stm32_pinctrl_match_data stm32mp257_z_match_data = {
.pins = stm32mp257_z_pins,
.npins = ARRAY_SIZE(stm32mp257_z_pins),
+ .secure_control = true,
+ .rif_control = true,
};
static const struct of_device_id stm32mp257_pctrl_match[] = {
@@ -2560,6 +2565,7 @@ static const struct of_device_id stm32mp257_pctrl_match[] = {
},
{ }
};
+MODULE_DEVICE_TABLE(of, stm32mp257_pctrl_match);
static const struct dev_pm_ops stm32_pinctrl_dev_pm_ops = {
SET_LATE_SYSTEM_SLEEP_PM_OPS(stm32_pinctrl_suspend, stm32_pinctrl_resume)
@@ -2573,9 +2579,8 @@ static struct platform_driver stm32mp257_pinctrl_driver = {
.pm = &stm32_pinctrl_dev_pm_ops,
},
};
+module_platform_driver(stm32mp257_pinctrl_driver);
-static int __init stm32mp257_pinctrl_init(void)
-{
- return platform_driver_register(&stm32mp257_pinctrl_driver);
-}
-arch_initcall(stm32mp257_pinctrl_init);
+MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@foss.st.com>");
+MODULE_DESCRIPTION("STM32MP257 pinctrl driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/sunplus/sppctl.c b/drivers/pinctrl/sunplus/sppctl.c
index ae156f779a16..3c3357f80889 100644
--- a/drivers/pinctrl/sunplus/sppctl.c
+++ b/drivers/pinctrl/sunplus/sppctl.c
@@ -461,13 +461,15 @@ static int sppctl_gpio_get(struct gpio_chip *chip, unsigned int offset)
return (reg & BIT(bit_off)) ? 1 : 0;
}
-static void sppctl_gpio_set(struct gpio_chip *chip, unsigned int offset, int val)
+static int sppctl_gpio_set(struct gpio_chip *chip, unsigned int offset, int val)
{
struct sppctl_gpio_chip *spp_gchip = gpiochip_get_data(chip);
u32 reg_off, reg;
reg = sppctl_prep_moon_reg_and_offset(offset, &reg_off, val);
sppctl_gpio_out_writel(spp_gchip, reg, reg_off);
+
+ return 0;
}
static int sppctl_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
@@ -545,7 +547,7 @@ static int sppctl_gpio_new(struct platform_device *pdev, struct sppctl_pdata *pc
gchip->direction_input = sppctl_gpio_direction_input;
gchip->direction_output = sppctl_gpio_direction_output;
gchip->get = sppctl_gpio_get;
- gchip->set = sppctl_gpio_set;
+ gchip->set_rv = sppctl_gpio_set;
gchip->set_config = sppctl_gpio_set_config;
gchip->dbg_show = IS_ENABLED(CONFIG_DEBUG_FS) ?
sppctl_gpio_dbg_show : NULL;
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c
index 696d7dd8d87b..2e3bd36a4410 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-v3s.c
@@ -45,7 +45,7 @@ static const struct sunxi_desc_pin sun8i_v3s_pins[] = {
SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
- SUNXI_FUNCTION(0x2, "uart2"), /* D1 */
+ SUNXI_FUNCTION(0x2, "uart2"), /* CTS */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)), /* PB_EINT3 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4),
SUNXI_FUNCTION(0x0, "gpio_in"),
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index bf8612d72daa..0db8429a013f 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -408,6 +408,7 @@ static int sunxi_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
const char *function, *pin_prop;
const char *group;
int ret, npins, nmaps, configlen = 0, i = 0;
+ struct pinctrl_map *new_map;
*map = NULL;
*num_maps = 0;
@@ -482,9 +483,13 @@ static int sunxi_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
* We know have the number of maps we need, we can resize our
* map array
*/
- *map = krealloc(*map, i * sizeof(struct pinctrl_map), GFP_KERNEL);
- if (!*map)
- return -ENOMEM;
+ new_map = krealloc(*map, i * sizeof(struct pinctrl_map), GFP_KERNEL);
+ if (!new_map) {
+ ret = -ENOMEM;
+ goto err_free_map;
+ }
+
+ *map = new_map;
return 0;
@@ -955,8 +960,8 @@ static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
return val;
}
-static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip,
- unsigned offset, int value)
+static int sunxi_pinctrl_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
u32 reg, shift, mask, val;
@@ -976,6 +981,8 @@ static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip,
writel(val, pctl->membase + reg);
raw_spin_unlock_irqrestore(&pctl->lock, flags);
+
+ return 0;
}
static int sunxi_pinctrl_gpio_direction_output(struct gpio_chip *chip,
@@ -1597,7 +1604,7 @@ int sunxi_pinctrl_init_with_flags(struct platform_device *pdev,
pctl->chip->direction_input = sunxi_pinctrl_gpio_direction_input;
pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output;
pctl->chip->get = sunxi_pinctrl_gpio_get;
- pctl->chip->set = sunxi_pinctrl_gpio_set;
+ pctl->chip->set_rv = sunxi_pinctrl_gpio_set;
pctl->chip->of_xlate = sunxi_pinctrl_gpio_of_xlate;
pctl->chip->to_irq = sunxi_pinctrl_gpio_to_irq;
pctl->chip->of_gpio_n_cells = 3;
@@ -1646,7 +1653,7 @@ int sunxi_pinctrl_init_with_flags(struct platform_device *pdev,
}
}
- pctl->domain = irq_domain_create_linear(of_fwnode_handle(node),
+ pctl->domain = irq_domain_create_linear(dev_fwnode(&pdev->dev),
pctl->desc->irq_banks * IRQ_PER_BANK,
&sunxi_pinctrl_irq_domain_ops, pctl);
if (!pctl->domain) {
diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.c b/drivers/pinctrl/vt8500/pinctrl-wmt.c
index fce92111a32e..767c6808a463 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wmt.c
+++ b/drivers/pinctrl/vt8500/pinctrl-wmt.c
@@ -507,8 +507,8 @@ static int wmt_gpio_get_value(struct gpio_chip *chip, unsigned offset)
return !!(readl_relaxed(data->base + reg_data_in) & BIT(bit));
}
-static void wmt_gpio_set_value(struct gpio_chip *chip, unsigned offset,
- int val)
+static int wmt_gpio_set_value(struct gpio_chip *chip, unsigned int offset,
+ int val)
{
struct wmt_pinctrl_data *data = gpiochip_get_data(chip);
u32 bank = WMT_BANK_FROM_PIN(offset);
@@ -517,19 +517,26 @@ static void wmt_gpio_set_value(struct gpio_chip *chip, unsigned offset,
if (reg_data_out == NO_REG) {
dev_err(data->dev, "no data out register defined\n");
- return;
+ return -EINVAL;
}
if (val)
wmt_setbits(data, reg_data_out, BIT(bit));
else
wmt_clearbits(data, reg_data_out, BIT(bit));
+
+ return 0;
}
static int wmt_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
int value)
{
- wmt_gpio_set_value(chip, offset, value);
+ int ret;
+
+ ret = wmt_gpio_set_value(chip, offset, value);
+ if (ret)
+ return ret;
+
return pinctrl_gpio_direction_output(chip, offset);
}
@@ -542,7 +549,7 @@ static const struct gpio_chip wmt_gpio_chip = {
.direction_input = pinctrl_gpio_direction_input,
.direction_output = wmt_gpio_direction_output,
.get = wmt_gpio_get_value,
- .set = wmt_gpio_set_value,
+ .set_rv = wmt_gpio_set_value,
.can_sleep = false,
};
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 9aec922613ce..64f6e9756aff 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -483,15 +483,6 @@ config RTC_DRV_PCF8523
This driver can also be built as a module. If so, the module
will be called rtc-pcf8523.
-config RTC_DRV_PCF85063
- tristate "NXP PCF85063"
- select REGMAP_I2C
- help
- If you say yes here you get support for the PCF85063 RTC chip
-
- This driver can also be built as a module. If so, the module
- will be called rtc-pcf85063.
-
config RTC_DRV_PCF85363
tristate "NXP PCF85363"
select REGMAP_I2C
@@ -971,6 +962,18 @@ config RTC_DRV_PCF2127
This driver can also be built as a module. If so, the module
will be called rtc-pcf2127.
+config RTC_DRV_PCF85063
+ tristate "NXP PCF85063"
+ depends on RTC_I2C_AND_SPI
+ select REGMAP_I2C if I2C
+ select REGMAP_SPI if SPI_MASTER
+ help
+ If you say yes here you get support for the PCF85063 and RV8063
+ RTC chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-pcf85063.
+
config RTC_DRV_RV3029C2
tristate "Micro Crystal RV3029/3049"
depends on RTC_I2C_AND_SPI
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 4619aa2ac469..789bddfea99d 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -15,7 +15,7 @@ rtc-core-$(CONFIG_RTC_INTF_DEV) += dev.o
rtc-core-$(CONFIG_RTC_INTF_PROC) += proc.o
rtc-core-$(CONFIG_RTC_INTF_SYSFS) += sysfs.o
-obj-$(CONFIG_RTC_LIB_KUNIT_TEST) += lib_test.o
+obj-$(CONFIG_RTC_LIB_KUNIT_TEST) += test_rtc_lib.o
# Keep the list ordered.
diff --git a/drivers/rtc/lib.c b/drivers/rtc/lib.c
index 13b5b1f20465..f7051592a6e3 100644
--- a/drivers/rtc/lib.c
+++ b/drivers/rtc/lib.c
@@ -51,7 +51,7 @@ EXPORT_SYMBOL(rtc_year_days);
*/
void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
{
- int days, secs;
+ int secs;
u64 u64tmp;
u32 u32tmp, udays, century, day_of_century, year_of_century, year,
@@ -59,28 +59,26 @@ void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
bool is_Jan_or_Feb, is_leap_year;
/*
- * Get days and seconds while preserving the sign to
- * handle negative time values (dates before 1970-01-01)
+ * The time represented by `time` is given in seconds since 1970-01-01
+ * (UTC). As the division done below might misbehave for negative
+ * values, we convert it to seconds since 0000-03-01 and then assume it
+ * will be non-negative.
+ * Below we do 4 * udays + 3 which should fit into a 32 bit unsigned
+ * variable. So the latest date this algorithm works for is 1073741823
+ * days after 0000-03-01 which is in the year 2939805.
*/
- days = div_s64_rem(time, 86400, &secs);
+ time += (u64)719468 * 86400;
+
+ udays = div_s64_rem(time, 86400, &secs);
/*
- * We need 0 <= secs < 86400 which isn't given for negative
- * values of time. Fixup accordingly.
+ * day of the week, 0000-03-01 was a Wednesday (in the proleptic
+ * Gregorian calendar)
*/
- if (secs < 0) {
- days -= 1;
- secs += 86400;
- }
-
- /* day of the week, 1970-01-01 was a Thursday */
- tm->tm_wday = (days + 4) % 7;
- /* Ensure tm_wday is always positive */
- if (tm->tm_wday < 0)
- tm->tm_wday += 7;
+ tm->tm_wday = (udays + 3) % 7;
/*
- * The following algorithm is, basically, Proposition 6.3 of Neri
+ * The following algorithm is, basically, Figure 12 of Neri
* and Schneider [1]. In a few words: it works on the computational
* (fictitious) calendar where the year starts in March, month = 2
* (*), and finishes in February, month = 13. This calendar is
@@ -100,15 +98,15 @@ void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
* (using just arithmetics) it's easy to convert it to the
* corresponding date in the Gregorian calendar.
*
- * [1] "Euclidean Affine Functions and Applications to Calendar
- * Algorithms". https://arxiv.org/abs/2102.06959
+ * [1] Neri C, Schneider L. Euclidean affine functions and their
+ * application to calendar algorithms. Softw Pract Exper.
+ * 2023;53(4):937-970. doi: 10.1002/spe.3172
+ * https://doi.org/10.1002/spe.3172
*
* (*) The numbering of months follows rtc_time more closely and
* thus, is slightly different from [1].
*/
- udays = days + 719468;
-
u32tmp = 4 * udays + 3;
century = u32tmp / 146097;
day_of_century = u32tmp % 146097 / 4;
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 5efbe69bf5ca..7205c59ff729 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -279,6 +279,13 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
if (tmp & DS1340_BIT_OSF)
return -EINVAL;
break;
+ case ds_1341:
+ ret = regmap_read(ds1307->regmap, DS1337_REG_STATUS, &tmp);
+ if (ret)
+ return ret;
+ if (tmp & DS1337_BIT_OSF)
+ return -EINVAL;
+ break;
case ds_1388:
ret = regmap_read(ds1307->regmap, DS1388_REG_FLAG, &tmp);
if (ret)
@@ -377,6 +384,10 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
regmap_update_bits(ds1307->regmap, DS1340_REG_FLAG,
DS1340_BIT_OSF, 0);
break;
+ case ds_1341:
+ regmap_update_bits(ds1307->regmap, DS1337_REG_STATUS,
+ DS1337_BIT_OSF, 0);
+ break;
case ds_1388:
regmap_update_bits(ds1307->regmap, DS1388_REG_FLAG,
DS1388_BIT_OSF, 0);
@@ -1456,16 +1467,21 @@ static unsigned long ds3231_clk_sqw_recalc_rate(struct clk_hw *hw,
return ds3231_clk_sqw_rates[rate_sel];
}
-static long ds3231_clk_sqw_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int ds3231_clk_sqw_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
int i;
for (i = ARRAY_SIZE(ds3231_clk_sqw_rates) - 1; i >= 0; i--) {
- if (ds3231_clk_sqw_rates[i] <= rate)
- return ds3231_clk_sqw_rates[i];
+ if (ds3231_clk_sqw_rates[i] <= req->rate) {
+ req->rate = ds3231_clk_sqw_rates[i];
+
+ return 0;
+ }
}
+ req->rate = ds3231_clk_sqw_rates[ARRAY_SIZE(ds3231_clk_sqw_rates) - 1];
+
return 0;
}
@@ -1525,7 +1541,7 @@ static const struct clk_ops ds3231_clk_sqw_ops = {
.unprepare = ds3231_clk_sqw_unprepare,
.is_prepared = ds3231_clk_sqw_is_prepared,
.recalc_rate = ds3231_clk_sqw_recalc_rate,
- .round_rate = ds3231_clk_sqw_round_rate,
+ .determine_rate = ds3231_clk_sqw_determine_rate,
.set_rate = ds3231_clk_sqw_set_rate,
};
@@ -1813,10 +1829,8 @@ static int ds1307_probe(struct i2c_client *client)
regmap_write(ds1307->regmap, DS1337_REG_CONTROL,
regs[0]);
- /* oscillator fault? clear flag, and warn */
+ /* oscillator fault? warn */
if (regs[1] & DS1337_BIT_OSF) {
- regmap_write(ds1307->regmap, DS1337_REG_STATUS,
- regs[1] & ~DS1337_BIT_OSF);
dev_warn(ds1307->dev, "SET TIME!\n");
}
break;
diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c
index 38e25f63597a..97423f1d0361 100644
--- a/drivers/rtc/rtc-ds1685.c
+++ b/drivers/rtc/rtc-ds1685.c
@@ -3,7 +3,7 @@
* An rtc driver for the Dallas/Maxim DS1685/DS1687 and related real-time
* chips.
*
- * Copyright (C) 2011-2014 Joshua Kinard <kumba@gentoo.org>.
+ * Copyright (C) 2011-2014 Joshua Kinard <linux@kumba.dev>.
* Copyright (C) 2009 Matthias Fuchs <matthias.fuchs@esd-electronics.com>.
*
* References:
@@ -1436,7 +1436,7 @@ EXPORT_SYMBOL_GPL(ds1685_rtc_poweroff);
/* ----------------------------------------------------------------------- */
-MODULE_AUTHOR("Joshua Kinard <kumba@gentoo.org>");
+MODULE_AUTHOR("Joshua Kinard <linux@kumba.dev>");
MODULE_AUTHOR("Matthias Fuchs <matthias.fuchs@esd-electronics.com>");
MODULE_DESCRIPTION("Dallas/Maxim DS1685/DS1687-series RTC driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c
index 63f11ea3589d..7a170c0f9710 100644
--- a/drivers/rtc/rtc-hym8563.c
+++ b/drivers/rtc/rtc-hym8563.c
@@ -285,14 +285,19 @@ static unsigned long hym8563_clkout_recalc_rate(struct clk_hw *hw,
return clkout_rates[ret];
}
-static long hym8563_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int hym8563_clkout_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
int i;
for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
- if (clkout_rates[i] <= rate)
- return clkout_rates[i];
+ if (clkout_rates[i] <= req->rate) {
+ req->rate = clkout_rates[i];
+
+ return 0;
+ }
+
+ req->rate = clkout_rates[0];
return 0;
}
@@ -363,7 +368,7 @@ static const struct clk_ops hym8563_clkout_ops = {
.unprepare = hym8563_clkout_unprepare,
.is_prepared = hym8563_clkout_is_prepared,
.recalc_rate = hym8563_clkout_recalc_rate,
- .round_rate = hym8563_clkout_round_rate,
+ .determine_rate = hym8563_clkout_determine_rate,
.set_rate = hym8563_clkout_set_rate,
};
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index c568639d2151..740cab013f59 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -72,7 +72,7 @@
static const struct i2c_device_id m41t80_id[] = {
{ "m41t62", M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT },
- { "m41t65", M41T80_FEATURE_HT | M41T80_FEATURE_WD },
+ { "m41t65", M41T80_FEATURE_WD },
{ "m41t80", M41T80_FEATURE_SQ },
{ "m41t81", M41T80_FEATURE_HT | M41T80_FEATURE_SQ},
{ "m41t81s", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
@@ -93,7 +93,7 @@ static const __maybe_unused struct of_device_id m41t80_of_match[] = {
},
{
.compatible = "st,m41t65",
- .data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_WD)
+ .data = (void *)(M41T80_FEATURE_WD)
},
{
.compatible = "st,m41t80",
@@ -484,16 +484,17 @@ static unsigned long m41t80_sqw_recalc_rate(struct clk_hw *hw,
return sqw_to_m41t80_data(hw)->freq;
}
-static long m41t80_sqw_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int m41t80_sqw_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
- if (rate >= M41T80_SQW_MAX_FREQ)
- return M41T80_SQW_MAX_FREQ;
- if (rate >= M41T80_SQW_MAX_FREQ / 4)
- return M41T80_SQW_MAX_FREQ / 4;
- if (!rate)
- return 0;
- return 1 << ilog2(rate);
+ if (req->rate >= M41T80_SQW_MAX_FREQ)
+ req->rate = M41T80_SQW_MAX_FREQ;
+ else if (req->rate >= M41T80_SQW_MAX_FREQ / 4)
+ req->rate = M41T80_SQW_MAX_FREQ / 4;
+ else if (req->rate)
+ req->rate = 1 << ilog2(req->rate);
+
+ return 0;
}
static int m41t80_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -564,7 +565,7 @@ static const struct clk_ops m41t80_sqw_ops = {
.unprepare = m41t80_sqw_unprepare,
.is_prepared = m41t80_sqw_is_prepared,
.recalc_rate = m41t80_sqw_recalc_rate,
- .round_rate = m41t80_sqw_round_rate,
+ .determine_rate = m41t80_sqw_determine_rate,
.set_rate = m41t80_sqw_set_rate,
};
diff --git a/drivers/rtc/rtc-max31335.c b/drivers/rtc/rtc-max31335.c
index a7bb37aaab9e..dfb5bad3a369 100644
--- a/drivers/rtc/rtc-max31335.c
+++ b/drivers/rtc/rtc-max31335.c
@@ -497,15 +497,17 @@ static unsigned long max31335_clkout_recalc_rate(struct clk_hw *hw,
return max31335_clkout_freq[reg & freq_mask];
}
-static long max31335_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int max31335_clkout_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
int index;
- index = find_closest(rate, max31335_clkout_freq,
+ index = find_closest(req->rate, max31335_clkout_freq,
ARRAY_SIZE(max31335_clkout_freq));
- return max31335_clkout_freq[index];
+ req->rate = max31335_clkout_freq[index];
+
+ return 0;
}
static int max31335_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -554,7 +556,7 @@ static int max31335_clkout_is_enabled(struct clk_hw *hw)
static const struct clk_ops max31335_clkout_ops = {
.recalc_rate = max31335_clkout_recalc_rate,
- .round_rate = max31335_clkout_round_rate,
+ .determine_rate = max31335_clkout_determine_rate,
.set_rate = max31335_clkout_set_rate,
.enable = max31335_clkout_enable,
.disable = max31335_clkout_disable,
diff --git a/drivers/rtc/rtc-nct3018y.c b/drivers/rtc/rtc-nct3018y.c
index 76c5f464b2da..cd4b1db902e9 100644
--- a/drivers/rtc/rtc-nct3018y.c
+++ b/drivers/rtc/rtc-nct3018y.c
@@ -367,14 +367,19 @@ static unsigned long nct3018y_clkout_recalc_rate(struct clk_hw *hw,
return clkout_rates[flags];
}
-static long nct3018y_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int nct3018y_clkout_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
int i;
for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
- if (clkout_rates[i] <= rate)
- return clkout_rates[i];
+ if (clkout_rates[i] <= req->rate) {
+ req->rate = clkout_rates[i];
+
+ return 0;
+ }
+
+ req->rate = clkout_rates[0];
return 0;
}
@@ -446,7 +451,7 @@ static const struct clk_ops nct3018y_clkout_ops = {
.unprepare = nct3018y_clkout_unprepare,
.is_prepared = nct3018y_clkout_is_prepared,
.recalc_rate = nct3018y_clkout_recalc_rate,
- .round_rate = nct3018y_clkout_round_rate,
+ .determine_rate = nct3018y_clkout_determine_rate,
.set_rate = nct3018y_clkout_set_rate,
};
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index 4fa5c4ecdd5a..f643e0bd7351 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -17,6 +17,7 @@
#include <linux/of.h>
#include <linux/pm_wakeirq.h>
#include <linux/regmap.h>
+#include <linux/spi/spi.h>
/*
* Information for this driver was pulled from the following datasheets.
@@ -29,6 +30,9 @@
*
* https://www.microcrystal.com/fileadmin/Media/Products/RTC/App.Manual/RV-8263-C7_App-Manual.pdf
* RV8263 -- Rev. 1.0 — January 2019
+ *
+ * https://www.microcrystal.com/fileadmin/Media/Products/RTC/App.Manual/RV-8063-C7_App-Manual.pdf
+ * RV8063 -- Rev. 1.1 - October 2018
*/
#define PCF85063_REG_CTRL1 0x00 /* status */
@@ -401,14 +405,19 @@ static unsigned long pcf85063_clkout_recalc_rate(struct clk_hw *hw,
return clkout_rates[buf];
}
-static long pcf85063_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int pcf85063_clkout_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
int i;
for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
- if (clkout_rates[i] <= rate)
- return clkout_rates[i];
+ if (clkout_rates[i] <= req->rate) {
+ req->rate = clkout_rates[i];
+
+ return 0;
+ }
+
+ req->rate = clkout_rates[0];
return 0;
}
@@ -482,7 +491,7 @@ static const struct clk_ops pcf85063_clkout_ops = {
.unprepare = pcf85063_clkout_unprepare,
.is_prepared = pcf85063_clkout_is_prepared,
.recalc_rate = pcf85063_clkout_recalc_rate,
- .round_rate = pcf85063_clkout_round_rate,
+ .determine_rate = pcf85063_clkout_determine_rate,
.set_rate = pcf85063_clkout_set_rate,
};
@@ -524,47 +533,12 @@ static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063)
}
#endif
-static const struct pcf85063_config config_pcf85063 = {
- .regmap = {
- .reg_bits = 8,
- .val_bits = 8,
- .max_register = 0x0a,
- },
-};
-
-static const struct pcf85063_config config_pcf85063tp = {
- .regmap = {
- .reg_bits = 8,
- .val_bits = 8,
- .max_register = 0x0a,
- },
-};
-
-static const struct pcf85063_config config_pcf85063a = {
- .regmap = {
- .reg_bits = 8,
- .val_bits = 8,
- .max_register = 0x11,
- },
- .has_alarms = 1,
-};
-
-static const struct pcf85063_config config_rv8263 = {
- .regmap = {
- .reg_bits = 8,
- .val_bits = 8,
- .max_register = 0x11,
- },
- .has_alarms = 1,
- .force_cap_7000 = 1,
-};
-
-static int pcf85063_probe(struct i2c_client *client)
+static int pcf85063_probe(struct device *dev, struct regmap *regmap, int irq,
+ const struct pcf85063_config *config)
{
struct pcf85063 *pcf85063;
unsigned int tmp;
int err;
- const struct pcf85063_config *config;
struct nvmem_config nvmem_cfg = {
.name = "pcf85063_nvram",
.reg_read = pcf85063_nvmem_read,
@@ -573,28 +547,22 @@ static int pcf85063_probe(struct i2c_client *client)
.size = 1,
};
- dev_dbg(&client->dev, "%s\n", __func__);
+ dev_dbg(dev, "%s\n", __func__);
- pcf85063 = devm_kzalloc(&client->dev, sizeof(struct pcf85063),
+ pcf85063 = devm_kzalloc(dev, sizeof(struct pcf85063),
GFP_KERNEL);
if (!pcf85063)
return -ENOMEM;
- config = i2c_get_match_data(client);
- if (!config)
- return -ENODEV;
-
- pcf85063->regmap = devm_regmap_init_i2c(client, &config->regmap);
- if (IS_ERR(pcf85063->regmap))
- return PTR_ERR(pcf85063->regmap);
+ pcf85063->regmap = regmap;
- i2c_set_clientdata(client, pcf85063);
+ dev_set_drvdata(dev, pcf85063);
err = regmap_read(pcf85063->regmap, PCF85063_REG_SC, &tmp);
if (err)
- return dev_err_probe(&client->dev, err, "RTC chip is not present\n");
+ return dev_err_probe(dev, err, "RTC chip is not present\n");
- pcf85063->rtc = devm_rtc_allocate_device(&client->dev);
+ pcf85063->rtc = devm_rtc_allocate_device(dev);
if (IS_ERR(pcf85063->rtc))
return PTR_ERR(pcf85063->rtc);
@@ -605,19 +573,17 @@ static int pcf85063_probe(struct i2c_client *client)
* of the registers after the automatic power-on reset...
*/
if (tmp & PCF85063_REG_SC_OS) {
- dev_warn(&client->dev,
- "POR issue detected, sending a SW reset\n");
+ dev_warn(dev, "POR issue detected, sending a SW reset\n");
err = regmap_write(pcf85063->regmap, PCF85063_REG_CTRL1,
PCF85063_REG_CTRL1_SWR);
if (err < 0)
- dev_warn(&client->dev,
- "SW reset failed, trying to continue\n");
+ dev_warn(dev, "SW reset failed, trying to continue\n");
}
- err = pcf85063_load_capacitance(pcf85063, client->dev.of_node,
+ err = pcf85063_load_capacitance(pcf85063, dev->of_node,
config->force_cap_7000 ? 7000 : 0);
if (err < 0)
- dev_warn(&client->dev, "failed to set xtal load capacitance: %d",
+ dev_warn(dev, "failed to set xtal load capacitance: %d",
err);
pcf85063->rtc->ops = &pcf85063_rtc_ops;
@@ -627,13 +593,13 @@ static int pcf85063_probe(struct i2c_client *client)
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, pcf85063->rtc->features);
clear_bit(RTC_FEATURE_ALARM, pcf85063->rtc->features);
- if (config->has_alarms && client->irq > 0) {
+ if (config->has_alarms && irq > 0) {
unsigned long irqflags = IRQF_TRIGGER_LOW;
- if (dev_fwnode(&client->dev))
+ if (dev_fwnode(dev))
irqflags = 0;
- err = devm_request_threaded_irq(&client->dev, client->irq,
+ err = devm_request_threaded_irq(dev, irq,
NULL, pcf85063_rtc_handle_irq,
irqflags | IRQF_ONESHOT,
"pcf85063", pcf85063);
@@ -642,8 +608,8 @@ static int pcf85063_probe(struct i2c_client *client)
"unable to request IRQ, alarms disabled\n");
} else {
set_bit(RTC_FEATURE_ALARM, pcf85063->rtc->features);
- device_init_wakeup(&client->dev, true);
- err = dev_pm_set_wake_irq(&client->dev, client->irq);
+ device_init_wakeup(dev, true);
+ err = dev_pm_set_wake_irq(dev, irq);
if (err)
dev_err(&pcf85063->rtc->dev,
"failed to enable irq wake\n");
@@ -661,6 +627,43 @@ static int pcf85063_probe(struct i2c_client *client)
return devm_rtc_register_device(pcf85063->rtc);
}
+#if IS_ENABLED(CONFIG_I2C)
+
+static const struct pcf85063_config config_pcf85063 = {
+ .regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x0a,
+ },
+};
+
+static const struct pcf85063_config config_pcf85063tp = {
+ .regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x0a,
+ },
+};
+
+static const struct pcf85063_config config_pcf85063a = {
+ .regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x11,
+ },
+ .has_alarms = 1,
+};
+
+static const struct pcf85063_config config_rv8263 = {
+ .regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x11,
+ },
+ .has_alarms = 1,
+ .force_cap_7000 = 1,
+};
+
static const struct i2c_device_id pcf85063_ids[] = {
{ "pca85073a", .driver_data = (kernel_ulong_t)&config_pcf85063a },
{ "pcf85063", .driver_data = (kernel_ulong_t)&config_pcf85063 },
@@ -683,16 +686,146 @@ static const struct of_device_id pcf85063_of_match[] = {
MODULE_DEVICE_TABLE(of, pcf85063_of_match);
#endif
+static int pcf85063_i2c_probe(struct i2c_client *client)
+{
+ const struct pcf85063_config *config;
+ struct regmap *regmap;
+
+ config = i2c_get_match_data(client);
+ if (!config)
+ return -ENODEV;
+
+ regmap = devm_regmap_init_i2c(client, &config->regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return pcf85063_probe(&client->dev, regmap, client->irq, config);
+}
+
static struct i2c_driver pcf85063_driver = {
.driver = {
.name = "rtc-pcf85063",
.of_match_table = of_match_ptr(pcf85063_of_match),
},
- .probe = pcf85063_probe,
+ .probe = pcf85063_i2c_probe,
.id_table = pcf85063_ids,
};
-module_i2c_driver(pcf85063_driver);
+static int pcf85063_register_driver(void)
+{
+ return i2c_add_driver(&pcf85063_driver);
+}
+
+static void pcf85063_unregister_driver(void)
+{
+ i2c_del_driver(&pcf85063_driver);
+}
+
+#else
+
+static int pcf85063_register_driver(void)
+{
+ return 0;
+}
+
+static void pcf85063_unregister_driver(void)
+{
+}
+
+#endif /* IS_ENABLED(CONFIG_I2C) */
+
+#if IS_ENABLED(CONFIG_SPI_MASTER)
+
+static const struct pcf85063_config config_rv8063 = {
+ .regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x11,
+ .read_flag_mask = BIT(7) | BIT(5),
+ .write_flag_mask = BIT(5),
+ },
+ .has_alarms = 1,
+ .force_cap_7000 = 1,
+};
+
+static const struct spi_device_id rv8063_id[] = {
+ { "rv8063" },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, rv8063_id);
+
+static const struct of_device_id rv8063_of_match[] = {
+ { .compatible = "microcrystal,rv8063" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rv8063_of_match);
+
+static int rv8063_probe(struct spi_device *spi)
+{
+ const struct pcf85063_config *config = &config_rv8063;
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_spi(spi, &config->regmap);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ return pcf85063_probe(&spi->dev, regmap, spi->irq, config);
+}
+
+static struct spi_driver rv8063_driver = {
+ .driver = {
+ .name = "rv8063",
+ .of_match_table = rv8063_of_match,
+ },
+ .probe = rv8063_probe,
+ .id_table = rv8063_id,
+};
+
+static int __init rv8063_register_driver(void)
+{
+ return spi_register_driver(&rv8063_driver);
+}
+
+static void __exit rv8063_unregister_driver(void)
+{
+ spi_unregister_driver(&rv8063_driver);
+}
+
+#else
+
+static int __init rv8063_register_driver(void)
+{
+ return 0;
+}
+
+static void __exit rv8063_unregister_driver(void)
+{
+}
+
+#endif /* IS_ENABLED(CONFIG_SPI_MASTER) */
+
+static int __init pcf85063_init(void)
+{
+ int ret;
+
+ ret = pcf85063_register_driver();
+ if (ret)
+ return ret;
+
+ ret = rv8063_register_driver();
+ if (ret)
+ pcf85063_unregister_driver();
+
+ return ret;
+}
+module_init(pcf85063_init);
+
+static void __exit pcf85063_exit(void)
+{
+ rv8063_unregister_driver();
+ pcf85063_unregister_driver();
+}
+module_exit(pcf85063_exit);
MODULE_AUTHOR("Søren Andersen <san@rosetechnology.dk>");
MODULE_DESCRIPTION("PCF85063 RTC driver");
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index b2611697fa5e..4e61011fb7a9 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -330,14 +330,19 @@ static unsigned long pcf8563_clkout_recalc_rate(struct clk_hw *hw,
return clkout_rates[buf];
}
-static long pcf8563_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int pcf8563_clkout_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
int i;
for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
- if (clkout_rates[i] <= rate)
- return clkout_rates[i];
+ if (clkout_rates[i] <= req->rate) {
+ req->rate = clkout_rates[i];
+
+ return 0;
+ }
+
+ req->rate = clkout_rates[0];
return 0;
}
@@ -413,7 +418,7 @@ static const struct clk_ops pcf8563_clkout_ops = {
.unprepare = pcf8563_clkout_unprepare,
.is_prepared = pcf8563_clkout_is_prepared,
.recalc_rate = pcf8563_clkout_recalc_rate,
- .round_rate = pcf8563_clkout_round_rate,
+ .determine_rate = pcf8563_clkout_determine_rate,
.set_rate = pcf8563_clkout_set_rate,
};
diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c
index 868d1b1eb0f4..c2a531f0e125 100644
--- a/drivers/rtc/rtc-rv3028.c
+++ b/drivers/rtc/rtc-rv3028.c
@@ -731,14 +731,19 @@ static unsigned long rv3028_clkout_recalc_rate(struct clk_hw *hw,
return clkout_rates[clkout];
}
-static long rv3028_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int rv3028_clkout_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
int i;
for (i = 0; i < ARRAY_SIZE(clkout_rates); i++)
- if (clkout_rates[i] <= rate)
- return clkout_rates[i];
+ if (clkout_rates[i] <= req->rate) {
+ req->rate = clkout_rates[i];
+
+ return 0;
+ }
+
+ req->rate = clkout_rates[0];
return 0;
}
@@ -802,7 +807,7 @@ static const struct clk_ops rv3028_clkout_ops = {
.unprepare = rv3028_clkout_unprepare,
.is_prepared = rv3028_clkout_is_prepared,
.recalc_rate = rv3028_clkout_recalc_rate,
- .round_rate = rv3028_clkout_round_rate,
+ .determine_rate = rv3028_clkout_determine_rate,
.set_rate = rv3028_clkout_set_rate,
};
diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c
index 2c6a8918acba..b8376bd1d905 100644
--- a/drivers/rtc/rtc-rv3032.c
+++ b/drivers/rtc/rtc-rv3032.c
@@ -646,19 +646,24 @@ static unsigned long rv3032_clkout_recalc_rate(struct clk_hw *hw,
return clkout_xtal_rates[FIELD_GET(RV3032_CLKOUT2_FD_MSK, clkout)];
}
-static long rv3032_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int rv3032_clkout_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
int i, hfd;
- if (rate < RV3032_HFD_STEP)
+ if (req->rate < RV3032_HFD_STEP)
for (i = 0; i < ARRAY_SIZE(clkout_xtal_rates); i++)
- if (clkout_xtal_rates[i] <= rate)
- return clkout_xtal_rates[i];
+ if (clkout_xtal_rates[i] <= req->rate) {
+ req->rate = clkout_xtal_rates[i];
- hfd = DIV_ROUND_CLOSEST(rate, RV3032_HFD_STEP);
+ return 0;
+ }
+
+ hfd = DIV_ROUND_CLOSEST(req->rate, RV3032_HFD_STEP);
- return RV3032_HFD_STEP * clamp(hfd, 0, 8192);
+ req->rate = RV3032_HFD_STEP * clamp(hfd, 0, 8192);
+
+ return 0;
}
static int rv3032_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -738,7 +743,7 @@ static const struct clk_ops rv3032_clkout_ops = {
.unprepare = rv3032_clkout_unprepare,
.is_prepared = rv3032_clkout_is_prepared,
.recalc_rate = rv3032_clkout_recalc_rate,
- .round_rate = rv3032_clkout_round_rate,
+ .determine_rate = rv3032_clkout_determine_rate,
.set_rate = rv3032_clkout_set_rate,
};
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 5dd575865adf..79b2a16f15ad 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -549,25 +549,25 @@ static void s3c6410_rtc_irq(struct s3c_rtc *info, int mask)
writeb(mask, info->base + S3C2410_INTP);
}
-static struct s3c_rtc_data const s3c2410_rtc_data = {
+static const struct s3c_rtc_data s3c2410_rtc_data = {
.irq_handler = s3c24xx_rtc_irq,
.enable = s3c24xx_rtc_enable,
.disable = s3c24xx_rtc_disable,
};
-static struct s3c_rtc_data const s3c2416_rtc_data = {
+static const struct s3c_rtc_data s3c2416_rtc_data = {
.irq_handler = s3c24xx_rtc_irq,
.enable = s3c24xx_rtc_enable,
.disable = s3c24xx_rtc_disable,
};
-static struct s3c_rtc_data const s3c2443_rtc_data = {
+static const struct s3c_rtc_data s3c2443_rtc_data = {
.irq_handler = s3c24xx_rtc_irq,
.enable = s3c24xx_rtc_enable,
.disable = s3c24xx_rtc_disable,
};
-static struct s3c_rtc_data const s3c6410_rtc_data = {
+static const struct s3c_rtc_data s3c6410_rtc_data = {
.needs_src_clk = true,
.irq_handler = s3c6410_rtc_irq,
.enable = s3c24xx_rtc_enable,
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index f15ef3aa82a0..619800a00479 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -455,7 +455,7 @@ static void __exit sh_rtc_remove(struct platform_device *pdev)
clk_disable(rtc->clk);
}
-static int __maybe_unused sh_rtc_suspend(struct device *dev)
+static int sh_rtc_suspend(struct device *dev)
{
struct sh_rtc *rtc = dev_get_drvdata(dev);
@@ -465,7 +465,7 @@ static int __maybe_unused sh_rtc_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused sh_rtc_resume(struct device *dev)
+static int sh_rtc_resume(struct device *dev)
{
struct sh_rtc *rtc = dev_get_drvdata(dev);
@@ -475,7 +475,7 @@ static int __maybe_unused sh_rtc_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(sh_rtc_pm_ops, sh_rtc_suspend, sh_rtc_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(sh_rtc_pm_ops, sh_rtc_suspend, sh_rtc_resume);
static const struct of_device_id sh_rtc_of_match[] = {
{ .compatible = "renesas,sh-rtc", },
@@ -492,7 +492,7 @@ MODULE_DEVICE_TABLE(of, sh_rtc_of_match);
static struct platform_driver sh_rtc_platform_driver __refdata = {
.driver = {
.name = DRV_NAME,
- .pm = &sh_rtc_pm_ops,
+ .pm = pm_sleep_ptr(&sh_rtc_pm_ops),
.of_match_table = sh_rtc_of_match,
},
.remove = __exit_p(sh_rtc_remove),
diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
index ef8fb88aab48..d4ebf3eb54aa 100644
--- a/drivers/rtc/rtc-stm32.c
+++ b/drivers/rtc/rtc-stm32.c
@@ -393,7 +393,7 @@ static const struct pinmux_ops stm32_rtc_pinmux_ops = {
.strict = true,
};
-static struct pinctrl_desc stm32_rtc_pdesc = {
+static const struct pinctrl_desc stm32_rtc_pdesc = {
.name = DRIVER_NAME,
.pins = stm32_rtc_pinctrl_pins,
.npins = ARRAY_SIZE(stm32_rtc_pinctrl_pins),
diff --git a/drivers/rtc/sysfs.c b/drivers/rtc/sysfs.c
index e3062c4d3f2c..4ab05e105a76 100644
--- a/drivers/rtc/sysfs.c
+++ b/drivers/rtc/sysfs.c
@@ -24,8 +24,8 @@
static ssize_t
name_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "%s %s\n", dev_driver_string(dev->parent),
- dev_name(dev->parent));
+ return sysfs_emit(buf, "%s %s\n", dev_driver_string(dev->parent),
+ dev_name(dev->parent));
}
static DEVICE_ATTR_RO(name);
@@ -39,7 +39,7 @@ date_show(struct device *dev, struct device_attribute *attr, char *buf)
if (retval)
return retval;
- return sprintf(buf, "%ptRd\n", &tm);
+ return sysfs_emit(buf, "%ptRd\n", &tm);
}
static DEVICE_ATTR_RO(date);
@@ -53,7 +53,7 @@ time_show(struct device *dev, struct device_attribute *attr, char *buf)
if (retval)
return retval;
- return sprintf(buf, "%ptRt\n", &tm);
+ return sysfs_emit(buf, "%ptRt\n", &tm);
}
static DEVICE_ATTR_RO(time);
@@ -64,21 +64,17 @@ since_epoch_show(struct device *dev, struct device_attribute *attr, char *buf)
struct rtc_time tm;
retval = rtc_read_time(to_rtc_device(dev), &tm);
- if (retval == 0) {
- time64_t time;
-
- time = rtc_tm_to_time64(&tm);
- retval = sprintf(buf, "%lld\n", time);
- }
+ if (retval)
+ return retval;
- return retval;
+ return sysfs_emit(buf, "%lld\n", rtc_tm_to_time64(&tm));
}
static DEVICE_ATTR_RO(since_epoch);
static ssize_t
max_user_freq_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq);
+ return sysfs_emit(buf, "%d\n", to_rtc_device(dev)->max_user_freq);
}
static ssize_t
@@ -118,9 +114,9 @@ hctosys_show(struct device *dev, struct device_attribute *attr, char *buf)
if (rtc_hctosys_ret == 0 &&
strcmp(dev_name(&to_rtc_device(dev)->dev),
CONFIG_RTC_HCTOSYS_DEVICE) == 0)
- return sprintf(buf, "1\n");
+ return sysfs_emit(buf, "1\n");
#endif
- return sprintf(buf, "0\n");
+ return sysfs_emit(buf, "0\n");
}
static DEVICE_ATTR_RO(hctosys);
@@ -128,7 +124,6 @@ static ssize_t
wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf)
{
ssize_t retval;
- time64_t alarm;
struct rtc_wkalrm alm;
/* Don't show disabled alarms. For uniformity, RTC alarms are
@@ -140,12 +135,13 @@ wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf)
* alarms after they trigger, to ensure one-shot semantics.
*/
retval = rtc_read_alarm(to_rtc_device(dev), &alm);
- if (retval == 0 && alm.enabled) {
- alarm = rtc_tm_to_time64(&alm.time);
- retval = sprintf(buf, "%lld\n", alarm);
- }
+ if (retval)
+ return retval;
- return retval;
+ if (alm.enabled)
+ return sysfs_emit(buf, "%lld\n", rtc_tm_to_time64(&alm.time));
+
+ return 0;
}
static ssize_t
@@ -222,10 +218,10 @@ offset_show(struct device *dev, struct device_attribute *attr, char *buf)
long offset;
retval = rtc_read_offset(to_rtc_device(dev), &offset);
- if (retval == 0)
- retval = sprintf(buf, "%ld\n", offset);
+ if (retval)
+ return retval;
- return retval;
+ return sysfs_emit(buf, "%ld\n", offset);
}
static ssize_t
@@ -246,8 +242,8 @@ static DEVICE_ATTR_RW(offset);
static ssize_t
range_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- return sprintf(buf, "[%lld,%llu]\n", to_rtc_device(dev)->range_min,
- to_rtc_device(dev)->range_max);
+ return sysfs_emit(buf, "[%lld,%llu]\n", to_rtc_device(dev)->range_min,
+ to_rtc_device(dev)->range_max);
}
static DEVICE_ATTR_RO(range);
@@ -302,11 +298,7 @@ static struct attribute_group rtc_attr_group = {
.is_visible = rtc_attr_is_visible,
.attrs = rtc_attrs,
};
-
-static const struct attribute_group *rtc_attr_groups[] = {
- &rtc_attr_group,
- NULL
-};
+__ATTRIBUTE_GROUPS(rtc_attr);
const struct attribute_group **rtc_get_dev_attribute_groups(void)
{
@@ -318,17 +310,21 @@ int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps)
size_t old_cnt = 0, add_cnt = 0, new_cnt;
const struct attribute_group **groups, **old;
- if (!grps)
+ if (grps) {
+ for (groups = grps; *groups; groups++)
+ add_cnt++;
+ /* No need to modify current groups if nothing new is provided */
+ if (add_cnt == 0)
+ return 0;
+ } else {
return -EINVAL;
+ }
groups = rtc->dev.groups;
if (groups)
for (; *groups; groups++)
old_cnt++;
- for (groups = grps; *groups; groups++)
- add_cnt++;
-
new_cnt = old_cnt + add_cnt + 1;
groups = devm_kcalloc(&rtc->dev, new_cnt, sizeof(*groups), GFP_KERNEL);
if (!groups)
diff --git a/drivers/rtc/lib_test.c b/drivers/rtc/test_rtc_lib.c
index 0eebad1fe2a0..0eebad1fe2a0 100644
--- a/drivers/rtc/lib_test.c
+++ b/drivers/rtc/test_rtc_lib.c
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 55c6686f091e..c21484d15f0c 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -660,7 +660,7 @@ config FB_ATMEL
config FB_NVIDIA
tristate "nVidia Framebuffer Support"
- depends on FB && PCI
+ depends on FB && PCI && HAS_IOPORT
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
diff --git a/drivers/video/fbdev/core/Kconfig b/drivers/video/fbdev/core/Kconfig
index b38c3b776bce..006638eefa41 100644
--- a/drivers/video/fbdev/core/Kconfig
+++ b/drivers/video/fbdev/core/Kconfig
@@ -16,7 +16,7 @@ config FB_DEVICE
default FB
help
Say Y here if you want the legacy /dev/fb* device file and
- interfaces within sysfs anc procfs. It is only required if you
+ interfaces within sysfs and procfs. It is only required if you
have userspace programs that depend on fbdev for graphics output.
This does not affect the framebuffer console. If unsure, say N.
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index d8eab4859fd4..eabbc4bd7cf6 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -135,9 +135,9 @@ static int logo_shown = FBCON_LOGO_CANSHOW;
/* console mappings */
static unsigned int first_fb_vc;
static unsigned int last_fb_vc = MAX_NR_CONSOLES - 1;
-static int fbcon_is_default = 1;
+static bool fbcon_is_default = true;
static int primary_device = -1;
-static int fbcon_has_console_bind;
+static bool fbcon_has_console_bind;
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
static int map_override;
@@ -172,7 +172,7 @@ static const struct consw fb_con;
#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
-static int fbcon_cursor_noblink;
+static bool fbcon_cursor_blink = true;
#define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1)
@@ -289,16 +289,16 @@ static bool fbcon_skip_panic(struct fb_info *info)
#endif
}
-static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info)
+static inline bool fbcon_is_active(struct vc_data *vc, struct fb_info *info)
{
struct fbcon_ops *ops = info->fbcon_par;
- return (info->state != FBINFO_STATE_RUNNING ||
- vc->vc_mode != KD_TEXT || ops->graphics || fbcon_skip_panic(info));
+ return info->state == FBINFO_STATE_RUNNING &&
+ vc->vc_mode == KD_TEXT && !ops->graphics && !fbcon_skip_panic(info);
}
static int get_color(struct vc_data *vc, struct fb_info *info,
- u16 c, int is_fg)
+ u16 c, bool is_fg)
{
int depth = fb_get_color_depth(&info->var, &info->fix);
int color = 0;
@@ -364,6 +364,16 @@ static int get_color(struct vc_data *vc, struct fb_info *info,
return color;
}
+static int get_fg_color(struct vc_data *vc, struct fb_info *info, u16 c)
+{
+ return get_color(vc, info, c, true);
+}
+
+static int get_bg_color(struct vc_data *vc, struct fb_info *info, u16 c)
+{
+ return get_color(vc, info, c, false);
+}
+
static void fb_flashcursor(struct work_struct *work)
{
struct fbcon_ops *ops = container_of(work, struct fbcon_ops, cursor_work.work);
@@ -395,8 +405,9 @@ static void fb_flashcursor(struct work_struct *work)
c = scr_readw((u16 *) vc->vc_pos);
enable = ops->cursor_flash && !ops->cursor_state.enable;
- ops->cursor(vc, info, enable, get_color(vc, info, c, 1),
- get_color(vc, info, c, 0));
+ ops->cursor(vc, info, enable,
+ get_fg_color(vc, info, c),
+ get_bg_color(vc, info, c));
console_unlock();
queue_delayed_work(system_power_efficient_wq, &ops->cursor_work,
@@ -407,7 +418,7 @@ static void fbcon_add_cursor_work(struct fb_info *info)
{
struct fbcon_ops *ops = info->fbcon_par;
- if (!fbcon_cursor_noblink)
+ if (fbcon_cursor_blink)
queue_delayed_work(system_power_efficient_wq, &ops->cursor_work,
ops->cur_blink_jiffies);
}
@@ -464,7 +475,7 @@ static int __init fb_console_setup(char *this_opt)
last_fb_vc = simple_strtoul(options, &options, 10) - 1;
if (last_fb_vc < first_fb_vc || last_fb_vc >= MAX_NR_CONSOLES)
last_fb_vc = MAX_NR_CONSOLES - 1;
- fbcon_is_default = 0;
+ fbcon_is_default = false;
continue;
}
@@ -559,7 +570,7 @@ static int do_fbcon_takeover(int show_logo)
con2fb_map[i] = -1;
info_idx = -1;
} else {
- fbcon_has_console_bind = 1;
+ fbcon_has_console_bind = true;
}
return err;
@@ -1267,7 +1278,7 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
struct fbcon_display *p = &fb_display[vc->vc_num];
u_int y_break;
- if (fbcon_is_inactive(vc, info))
+ if (!fbcon_is_active(vc, info))
return;
if (!height || !width)
@@ -1311,10 +1322,10 @@ static void fbcon_putcs(struct vc_data *vc, const u16 *s, unsigned int count,
struct fbcon_display *p = &fb_display[vc->vc_num];
struct fbcon_ops *ops = info->fbcon_par;
- if (!fbcon_is_inactive(vc, info))
+ if (fbcon_is_active(vc, info))
ops->putcs(vc, info, s, count, real_y(p, ypos), xpos,
- get_color(vc, info, scr_readw(s), 1),
- get_color(vc, info, scr_readw(s), 0));
+ get_fg_color(vc, info, scr_readw(s)),
+ get_bg_color(vc, info, scr_readw(s)));
}
static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)
@@ -1322,7 +1333,7 @@ static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)
struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par;
- if (!fbcon_is_inactive(vc, info))
+ if (fbcon_is_active(vc, info))
ops->clear_margins(vc, info, margin_color, bottom_only);
}
@@ -1334,7 +1345,7 @@ static void fbcon_cursor(struct vc_data *vc, bool enable)
ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
- if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1)
+ if (!fbcon_is_active(vc, info) || vc->vc_deccm != 1)
return;
if (vc->vc_cursor_type & CUR_SW)
@@ -1347,8 +1358,9 @@ static void fbcon_cursor(struct vc_data *vc, bool enable)
if (!ops->cursor)
return;
- ops->cursor(vc, info, enable, get_color(vc, info, c, 1),
- get_color(vc, info, c, 0));
+ ops->cursor(vc, info, enable,
+ get_fg_color(vc, info, c),
+ get_bg_color(vc, info, c));
}
static int scrollback_phys_max = 0;
@@ -1740,7 +1752,7 @@ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_display *p = &fb_display[vc->vc_num];
- if (fbcon_is_inactive(vc, info))
+ if (!fbcon_is_active(vc, info))
return;
if (!width || !height)
@@ -1764,7 +1776,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
struct fbcon_display *p = &fb_display[vc->vc_num];
int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
- if (fbcon_is_inactive(vc, info))
+ if (!fbcon_is_active(vc, info))
return true;
fbcon_cursor(vc, false);
@@ -2148,7 +2160,7 @@ static bool fbcon_switch(struct vc_data *vc)
fbcon_del_cursor_work(old_info);
}
- if (fbcon_is_inactive(vc, info) ||
+ if (!fbcon_is_active(vc, info) ||
ops->blank_state != FB_BLANK_UNBLANK)
fbcon_del_cursor_work(info);
else
@@ -2188,7 +2200,7 @@ static bool fbcon_switch(struct vc_data *vc)
scrollback_max = 0;
scrollback_current = 0;
- if (!fbcon_is_inactive(vc, info)) {
+ if (fbcon_is_active(vc, info)) {
ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
ops->update_start(info);
}
@@ -2244,7 +2256,7 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
}
}
- if (!fbcon_is_inactive(vc, info)) {
+ if (fbcon_is_active(vc, info)) {
if (ops->blank_state != blank) {
ops->blank_state = blank;
fbcon_cursor(vc, !blank);
@@ -2258,7 +2270,7 @@ static bool fbcon_blank(struct vc_data *vc, enum vesa_blank_mode blank,
update_screen(vc);
}
- if (mode_switch || fbcon_is_inactive(vc, info) ||
+ if (mode_switch || !fbcon_is_active(vc, info) ||
ops->blank_state != FB_BLANK_UNBLANK)
fbcon_del_cursor_work(info);
else
@@ -2588,7 +2600,7 @@ static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table)
int i, j, k, depth;
u8 val;
- if (fbcon_is_inactive(vc, info))
+ if (!fbcon_is_active(vc, info))
return;
if (!con_is_visible(vc))
@@ -2688,7 +2700,7 @@ static void fbcon_modechanged(struct fb_info *info)
scrollback_max = 0;
scrollback_current = 0;
- if (!fbcon_is_inactive(vc, info)) {
+ if (fbcon_is_active(vc, info)) {
ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
ops->update_start(info);
}
@@ -2806,7 +2818,7 @@ static void fbcon_unbind(void)
fbcon_is_default);
if (!ret)
- fbcon_has_console_bind = 0;
+ fbcon_has_console_bind = false;
}
#else
static inline void fbcon_unbind(void) {}
@@ -3257,8 +3269,9 @@ static ssize_t cursor_blink_store(struct device *device,
const char *buf, size_t count)
{
struct fb_info *info;
- int blink, idx;
char **last = NULL;
+ bool blink;
+ int idx;
console_lock();
idx = con2fb_map[fg_console];
@@ -3274,10 +3287,10 @@ static ssize_t cursor_blink_store(struct device *device,
blink = simple_strtoul(buf, last, 0);
if (blink) {
- fbcon_cursor_noblink = 0;
+ fbcon_cursor_blink = true;
fbcon_add_cursor_work(info);
} else {
- fbcon_cursor_noblink = 1;
+ fbcon_cursor_blink = false;
fbcon_del_cursor_work(info);
}
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index dfcf5e4d1d4c..53f1719b1ae1 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -449,6 +449,9 @@ static int do_register_framebuffer(struct fb_info *fb_info)
if (!registered_fb[i])
break;
+ if (i >= FB_MAX)
+ return -ENXIO;
+
if (!fb_info->modelist.prev || !fb_info->modelist.next)
INIT_LIST_HEAD(&fb_info->modelist);
diff --git a/drivers/video/fbdev/core/svgalib.c b/drivers/video/fbdev/core/svgalib.c
index d6053af749f6..0e0ce4e024d9 100644
--- a/drivers/video/fbdev/core/svgalib.c
+++ b/drivers/video/fbdev/core/svgalib.c
@@ -20,7 +20,6 @@
#include <asm/types.h>
#include <asm/io.h>
-
/* Write a CRT register value spread across multiple registers */
void svga_wcrt_multi(void __iomem *regbase, const struct vga_regset *regset, u32 value)
{
@@ -32,12 +31,13 @@ void svga_wcrt_multi(void __iomem *regbase, const struct vga_regset *regset, u32
while (bitnum <= regset->highbit) {
bitval = 1 << bitnum;
regval = regval & ~bitval;
- if (value & 1) regval = regval | bitval;
- bitnum ++;
+ if (value & 1)
+ regval = regval | bitval;
+ bitnum++;
value = value >> 1;
}
vga_wcrt(regbase, regset->regnum, regval);
- regset ++;
+ regset++;
}
}
@@ -52,12 +52,13 @@ void svga_wseq_multi(void __iomem *regbase, const struct vga_regset *regset, u32
while (bitnum <= regset->highbit) {
bitval = 1 << bitnum;
regval = regval & ~bitval;
- if (value & 1) regval = regval | bitval;
- bitnum ++;
+ if (value & 1)
+ regval = regval | bitval;
+ bitnum++;
value = value >> 1;
}
vga_wseq(regbase, regset->regnum, regval);
- regset ++;
+ regset++;
}
}
@@ -67,15 +68,13 @@ static unsigned int svga_regset_size(const struct vga_regset *regset)
while (regset->regnum != VGA_REGSET_END_VAL) {
count += regset->highbit - regset->lowbit + 1;
- regset ++;
+ regset++;
}
return 1 << count;
}
-
/* ------------------------------------------------------------------------- */
-
/* Set graphics controller registers to sane values */
void svga_set_default_gfx_regs(void __iomem *regbase)
{
@@ -103,7 +102,7 @@ void svga_set_default_atc_regs(void __iomem *regbase)
vga_w(regbase, VGA_ATT_W, 0x00);
/* All standard ATC registers (AR00 - AR14) */
- for (count = 0; count <= 0xF; count ++)
+ for (count = 0; count <= 0xF; count++)
svga_wattr(regbase, count, count);
svga_wattr(regbase, VGA_ATC_MODE, 0x01);
@@ -188,10 +187,8 @@ void svga_dump_var(struct fb_var_screeninfo *var, int node)
}
#endif /* 0 */
-
/* ------------------------------------------------------------------------- */
-
void svga_settile(struct fb_info *info, struct fb_tilemap *map)
{
const u8 *font = map->data;
@@ -230,7 +227,7 @@ void svga_tilecopy(struct fb_info *info, struct fb_tilearea *area)
((area->sy == area->dy) && (area->sx > area->dx))) {
src = fb + area->sx * colstride + area->sy * rowstride;
dst = fb + area->dx * colstride + area->dy * rowstride;
- } else {
+ } else {
src = fb + (area->sx + area->width - 1) * colstride
+ (area->sy + area->height - 1) * rowstride;
dst = fb + (area->dx + area->width - 1) * colstride
@@ -238,7 +235,7 @@ void svga_tilecopy(struct fb_info *info, struct fb_tilearea *area)
colstride = -colstride;
rowstride = -rowstride;
- }
+ }
for (dy = 0; dy < area->height; dy++) {
u16 __iomem *src2 = src;
@@ -285,19 +282,19 @@ void svga_tileblit(struct fb_info *info, struct fb_tileblit *blit)
u8 __iomem *fb = (u8 __iomem *)info->screen_base;
fb += blit->sx * colstride + blit->sy * rowstride;
- i=0;
- for (dy=0; dy < blit->height; dy ++) {
+ i = 0;
+ for (dy = 0; dy < blit->height; dy++) {
u8 __iomem *fb2 = fb;
- for (dx = 0; dx < blit->width; dx ++) {
+ for (dx = 0; dx < blit->width; dx++) {
fb_writeb(blit->indices[i], fb2);
fb_writeb(attr, fb2 + 1);
fb2 += colstride;
- i ++;
- if (i == blit->length) return;
+ i++;
+ if (i == blit->length)
+ return;
}
fb += rowstride;
}
-
}
/* Set cursor in text (tileblit) mode */
@@ -309,15 +306,15 @@ void svga_tilecursor(void __iomem *regbase, struct fb_info *info, struct fb_tile
+ (cursor->sy + (info->var.yoffset / 16))
* (info->var.xres_virtual / 8);
- if (! cursor -> mode)
+ if (!cursor->mode)
return;
svga_wcrt_mask(regbase, 0x0A, 0x20, 0x20); /* disable cursor */
- if (cursor -> shape == FB_TILE_CURSOR_NONE)
+ if (cursor->shape == FB_TILE_CURSOR_NONE)
return;
- switch (cursor -> shape) {
+ switch (cursor->shape) {
case FB_TILE_CURSOR_UNDERLINE:
cs = 0x0d;
break;
@@ -375,7 +372,6 @@ EXPORT_SYMBOL(svga_get_caps);
/* ------------------------------------------------------------------------- */
-
/*
* Compute PLL settings (M, N, R)
* F_VCO = (F_BASE * M) / N
@@ -386,7 +382,7 @@ int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u
u16 am, an, ar;
u32 f_vco, f_current, delta_current, delta_best;
- pr_debug("fb%d: ideal frequency: %d kHz\n", node, (unsigned int) f_wanted);
+ pr_debug("fb%d: ideal frequency: %d kHz\n", node, (unsigned int)f_wanted);
ar = pll->r_max;
f_vco = f_wanted << ar;
@@ -417,7 +413,7 @@ int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u
while ((am <= pll->m_max) && (an <= pll->n_max)) {
f_current = (pll->f_base * am) / an;
- delta_current = abs_diff (f_current, f_vco);
+ delta_current = abs_diff(f_current, f_vco);
if (delta_current < delta_best) {
delta_best = delta_current;
@@ -425,58 +421,55 @@ int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u
*n = an;
}
- if (f_current <= f_vco) {
- am ++;
- } else {
- an ++;
- }
+ if (f_current <= f_vco)
+ am++;
+ else
+ an++;
}
f_current = (pll->f_base * *m) / *n;
- pr_debug("fb%d: found frequency: %d kHz (VCO %d kHz)\n", node, (int) (f_current >> ar), (int) f_current);
- pr_debug("fb%d: m = %d n = %d r = %d\n", node, (unsigned int) *m, (unsigned int) *n, (unsigned int) *r);
+ pr_debug("fb%d: found frequency: %d kHz (VCO %d kHz)\n", node, (int)(f_current >> ar), (int)f_current);
+ pr_debug("fb%d: m = %d n = %d r = %d\n", node, (unsigned int)*m, (unsigned int)*n, (unsigned int)*r);
return 0;
}
-
/* ------------------------------------------------------------------------- */
-
/* Check CRT timing values */
int svga_check_timings(const struct svga_timing_regs *tm, struct fb_var_screeninfo *var, int node)
{
u32 value;
- var->xres = (var->xres+7)&~7;
- var->left_margin = (var->left_margin+7)&~7;
- var->right_margin = (var->right_margin+7)&~7;
- var->hsync_len = (var->hsync_len+7)&~7;
+ var->xres = (var->xres + 7) & ~7;
+ var->left_margin = (var->left_margin + 7) & ~7;
+ var->right_margin = (var->right_margin + 7) & ~7;
+ var->hsync_len = (var->hsync_len + 7) & ~7;
/* Check horizontal total */
value = var->xres + var->left_margin + var->right_margin + var->hsync_len;
- if (((value / 8) - 5) >= svga_regset_size (tm->h_total_regs))
+ if (((value / 8) - 5) >= svga_regset_size(tm->h_total_regs))
return -EINVAL;
/* Check horizontal display and blank start */
value = var->xres;
- if (((value / 8) - 1) >= svga_regset_size (tm->h_display_regs))
+ if (((value / 8) - 1) >= svga_regset_size(tm->h_display_regs))
return -EINVAL;
- if (((value / 8) - 1) >= svga_regset_size (tm->h_blank_start_regs))
+ if (((value / 8) - 1) >= svga_regset_size(tm->h_blank_start_regs))
return -EINVAL;
/* Check horizontal sync start */
value = var->xres + var->right_margin;
- if (((value / 8) - 1) >= svga_regset_size (tm->h_sync_start_regs))
+ if (((value / 8) - 1) >= svga_regset_size(tm->h_sync_start_regs))
return -EINVAL;
/* Check horizontal blank end (or length) */
value = var->left_margin + var->right_margin + var->hsync_len;
- if ((value == 0) || ((value / 8) >= svga_regset_size (tm->h_blank_end_regs)))
+ if ((value == 0) || ((value / 8) >= svga_regset_size(tm->h_blank_end_regs)))
return -EINVAL;
/* Check horizontal sync end (or length) */
value = var->hsync_len;
- if ((value == 0) || ((value / 8) >= svga_regset_size (tm->h_sync_end_regs)))
+ if ((value == 0) || ((value / 8) >= svga_regset_size(tm->h_sync_end_regs)))
return -EINVAL;
/* Check vertical total */
@@ -498,12 +491,12 @@ int svga_check_timings(const struct svga_timing_regs *tm, struct fb_var_screenin
/* Check vertical blank end (or length) */
value = var->upper_margin + var->lower_margin + var->vsync_len;
- if ((value == 0) || (value >= svga_regset_size (tm->v_blank_end_regs)))
+ if ((value == 0) || (value >= svga_regset_size(tm->v_blank_end_regs)))
return -EINVAL;
/* Check vertical sync end (or length) */
value = var->vsync_len;
- if ((value == 0) || (value >= svga_regset_size (tm->v_sync_end_regs)))
+ if ((value == 0) || (value >= svga_regset_size(tm->v_sync_end_regs)))
return -EINVAL;
return 0;
@@ -597,18 +590,15 @@ void svga_set_timings(void __iomem *regbase, const struct svga_timing_regs *tm,
vga_w(regbase, VGA_MIS_W, regval);
}
-
/* ------------------------------------------------------------------------- */
-
static inline int match_format(const struct svga_fb_format *frm,
struct fb_var_screeninfo *var)
{
int i = 0;
int stored = -EINVAL;
- while (frm->bits_per_pixel != SVGA_FORMAT_END_VAL)
- {
+ while (frm->bits_per_pixel != SVGA_FORMAT_END_VAL) {
if ((var->bits_per_pixel == frm->bits_per_pixel) &&
(var->red.length <= frm->red.length) &&
(var->green.length <= frm->green.length) &&
@@ -648,7 +638,6 @@ int svga_match_format(const struct svga_fb_format *frm,
return i;
}
-
EXPORT_SYMBOL(svga_wcrt_multi);
EXPORT_SYMBOL(svga_wseq_multi);
diff --git a/drivers/video/fbdev/imxfb.c b/drivers/video/fbdev/imxfb.c
index f30da32cdaed..a077bf346bdf 100644
--- a/drivers/video/fbdev/imxfb.c
+++ b/drivers/video/fbdev/imxfb.c
@@ -996,8 +996,13 @@ static int imxfb_probe(struct platform_device *pdev)
info->fix.smem_start = fbi->map_dma;
INIT_LIST_HEAD(&info->modelist);
- for (i = 0; i < fbi->num_modes; i++)
- fb_add_videomode(&fbi->mode[i].mode, &info->modelist);
+ for (i = 0; i < fbi->num_modes; i++) {
+ ret = fb_add_videomode(&fbi->mode[i].mode, &info->modelist);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add videomode\n");
+ goto failed_cmap;
+ }
+ }
/*
* This makes sure that our colour bitfield
diff --git a/drivers/video/fbdev/kyro/fbdev.c b/drivers/video/fbdev/kyro/fbdev.c
index 08ee8baa79f8..c8b1dfa456a3 100644
--- a/drivers/video/fbdev/kyro/fbdev.c
+++ b/drivers/video/fbdev/kyro/fbdev.c
@@ -679,7 +679,8 @@ static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
return err;
- if ((err = pci_enable_device(pdev))) {
+ err = pcim_enable_device(pdev);
+ if (err) {
printk(KERN_WARNING "kyrofb: Can't enable pdev: %d\n", err);
return err;
}
@@ -688,6 +689,10 @@ static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!info)
return -ENOMEM;
+ err = pcim_request_all_regions(pdev, "kyrofb");
+ if (err)
+ goto out_free_fb;
+
currentpar = info->par;
kyro_fix.smem_start = pci_resource_start(pdev, 0);
@@ -696,13 +701,15 @@ static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
kyro_fix.mmio_len = pci_resource_len(pdev, 1);
currentpar->regbase = deviceInfo.pSTGReg =
- ioremap(kyro_fix.mmio_start, kyro_fix.mmio_len);
+ devm_ioremap(&pdev->dev, kyro_fix.mmio_start,
+ kyro_fix.mmio_len);
if (!currentpar->regbase)
goto out_free_fb;
- info->screen_base = pci_ioremap_wc_bar(pdev, 0);
+ info->screen_base = devm_ioremap_wc(&pdev->dev, kyro_fix.smem_start,
+ kyro_fix.smem_len);
if (!info->screen_base)
- goto out_unmap_regs;
+ goto out_free_fb;
if (!nomtrr)
currentpar->wc_cookie = arch_phys_wc_add(kyro_fix.smem_start,
@@ -737,7 +744,7 @@ static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
fb_memset_io(info->screen_base, 0, size);
if (register_framebuffer(info) < 0)
- goto out_unmap;
+ goto out_free_fb;
fb_info(info, "%s frame buffer device, at %dx%d@%d using %ldk/%ldk of VRAM\n",
info->fix.id,
@@ -748,10 +755,6 @@ static int kyrofb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
-out_unmap:
- iounmap(info->screen_base);
-out_unmap_regs:
- iounmap(currentpar->regbase);
out_free_fb:
framebuffer_release(info);
@@ -773,9 +776,6 @@ static void kyrofb_remove(struct pci_dev *pdev)
deviceInfo.ulNextFreeVidMem = 0;
deviceInfo.ulOverlayOffset = 0;
- iounmap(info->screen_base);
- iounmap(par->regbase);
-
arch_phys_wc_del(par->wc_cookie);
unregister_framebuffer(info);
diff --git a/drivers/video/fbdev/nvidia/nv_local.h b/drivers/video/fbdev/nvidia/nv_local.h
index 68e508daa417..93aff35305a9 100644
--- a/drivers/video/fbdev/nvidia/nv_local.h
+++ b/drivers/video/fbdev/nvidia/nv_local.h
@@ -80,7 +80,7 @@
(par)->dmaFree -= ((size) + 1); \
}
-#if defined(__i386__)
+#if defined(__i386__) && !defined(CONFIG_UML)
#define _NV_FENCE() outb(0, 0x3D0);
#else
#define _NV_FENCE() mb();
diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c
index be95fcddce4c..1893815dc67f 100644
--- a/drivers/video/fbdev/simplefb.c
+++ b/drivers/video/fbdev/simplefb.c
@@ -21,9 +21,9 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/of.h>
-#include <linux/of_address.h>
#include <linux/of_clk.h>
#include <linux/of_platform.h>
+#include <linux/of_reserved_mem.h>
#include <linux/parser.h>
#include <linux/pm_domain.h>
#include <linux/regulator/consumer.h>
@@ -134,7 +134,7 @@ struct simplefb_params {
static int simplefb_parse_dt(struct platform_device *pdev,
struct simplefb_params *params)
{
- struct device_node *np = pdev->dev.of_node, *mem;
+ struct device_node *np = pdev->dev.of_node;
int ret;
const char *format;
int i;
@@ -174,19 +174,10 @@ static int simplefb_parse_dt(struct platform_device *pdev,
return -EINVAL;
}
- mem = of_parse_phandle(np, "memory-region", 0);
- if (mem) {
- ret = of_address_to_resource(mem, 0, &params->memory);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to parse memory-region\n");
- of_node_put(mem);
- return ret;
- }
-
+ ret = of_reserved_mem_region_to_resource(np, 0, &params->memory);
+ if (!ret) {
if (of_property_present(np, "reg"))
dev_warn(&pdev->dev, "preferring \"memory-region\" over \"reg\" property\n");
-
- of_node_put(mem);
} else {
memset(&params->memory, 0, sizeof(params->memory));
}
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c
index 1db348f8f887..a7061c2ad8e4 100644
--- a/fs/fat/fatent.c
+++ b/fs/fat/fatent.c
@@ -356,7 +356,7 @@ int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry)
if (!fat_valid_entry(sbi, entry)) {
fatent_brelse(fatent);
- fat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", entry);
+ fat_fs_error_ratelimit(sb, "invalid access to FAT (entry 0x%08x)", entry);
return -EIO;
}
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index c7a2d27120ba..950da09f0961 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -158,9 +158,9 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster)
mark_inode_dirty(inode);
}
if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) {
- fat_fs_error(sb, "clusters badly computed (%d != %llu)",
- new_fclus,
- (llu)(inode->i_blocks >> (sbi->cluster_bits - 9)));
+ fat_fs_error_ratelimit(
+ sb, "clusters badly computed (%d != %llu)", new_fclus,
+ (llu)(inode->i_blocks >> (sbi->cluster_bits - 9)));
fat_cache_inval_inode(inode);
}
inode->i_blocks += nr_cluster << (sbi->cluster_bits - 9);
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index 2203438738f6..76c86f1c2b1c 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -1071,6 +1071,7 @@ static int ocfs2_grab_folios_for_write(struct address_space *mapping,
if (IS_ERR(wc->w_folios[i])) {
ret = PTR_ERR(wc->w_folios[i]);
mlog_errno(ret);
+ wc->w_folios[i] = NULL;
goto out;
}
}
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index 7799f4d16ce9..8c9c4825f984 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -798,6 +798,14 @@ static int ocfs2_dx_dir_lookup_rec(struct inode *inode,
}
}
+ if (le16_to_cpu(el->l_next_free_rec) == 0) {
+ ret = ocfs2_error(inode->i_sb,
+ "Inode %lu has empty extent list at depth %u\n",
+ inode->i_ino,
+ le16_to_cpu(el->l_tree_depth));
+ goto out;
+ }
+
found = 0;
for (i = le16_to_cpu(el->l_next_free_rec) - 1; i >= 0; i--) {
rec = &el->l_recs[i];
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
index 67fc62a49a76..00f52812dbb0 100644
--- a/fs/ocfs2/dlm/dlmrecovery.c
+++ b/fs/ocfs2/dlm/dlmrecovery.c
@@ -2632,7 +2632,7 @@ again:
dlm_reco_master_ready(dlm),
msecs_to_jiffies(1000));
if (!dlm_reco_master_ready(dlm)) {
- mlog(0, "%s: reco master taking awhile\n",
+ mlog(0, "%s: reco master taking a while\n",
dlm->name);
goto again;
}
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 12e5d1f73325..14bf440ea4df 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -50,8 +50,6 @@ struct ocfs2_find_inode_args
unsigned int fi_sysfile_type;
};
-static struct lock_class_key ocfs2_sysfile_lock_key[NUM_SYSTEM_INODES];
-
static int ocfs2_read_locked_inode(struct inode *inode,
struct ocfs2_find_inode_args *args);
static int ocfs2_init_locked_inode(struct inode *inode, void *opaque);
@@ -250,14 +248,77 @@ bail:
static int ocfs2_init_locked_inode(struct inode *inode, void *opaque)
{
struct ocfs2_find_inode_args *args = opaque;
+#ifdef CONFIG_LOCKDEP
+ static struct lock_class_key ocfs2_sysfile_lock_key[NUM_SYSTEM_INODES];
static struct lock_class_key ocfs2_quota_ip_alloc_sem_key,
ocfs2_file_ip_alloc_sem_key;
+#endif
inode->i_ino = args->fi_ino;
OCFS2_I(inode)->ip_blkno = args->fi_blkno;
- if (args->fi_sysfile_type != 0)
+#ifdef CONFIG_LOCKDEP
+ switch (args->fi_sysfile_type) {
+ case BAD_BLOCK_SYSTEM_INODE:
+ break;
+ case GLOBAL_INODE_ALLOC_SYSTEM_INODE:
+ lockdep_set_class(&inode->i_rwsem,
+ &ocfs2_sysfile_lock_key[GLOBAL_INODE_ALLOC_SYSTEM_INODE]);
+ break;
+ case SLOT_MAP_SYSTEM_INODE:
+ lockdep_set_class(&inode->i_rwsem,
+ &ocfs2_sysfile_lock_key[SLOT_MAP_SYSTEM_INODE]);
+ break;
+ case HEARTBEAT_SYSTEM_INODE:
+ lockdep_set_class(&inode->i_rwsem,
+ &ocfs2_sysfile_lock_key[HEARTBEAT_SYSTEM_INODE]);
+ break;
+ case GLOBAL_BITMAP_SYSTEM_INODE:
+ lockdep_set_class(&inode->i_rwsem,
+ &ocfs2_sysfile_lock_key[GLOBAL_BITMAP_SYSTEM_INODE]);
+ break;
+ case USER_QUOTA_SYSTEM_INODE:
+ lockdep_set_class(&inode->i_rwsem,
+ &ocfs2_sysfile_lock_key[USER_QUOTA_SYSTEM_INODE]);
+ break;
+ case GROUP_QUOTA_SYSTEM_INODE:
+ lockdep_set_class(&inode->i_rwsem,
+ &ocfs2_sysfile_lock_key[GROUP_QUOTA_SYSTEM_INODE]);
+ break;
+ case ORPHAN_DIR_SYSTEM_INODE:
+ lockdep_set_class(&inode->i_rwsem,
+ &ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]);
+ break;
+ case EXTENT_ALLOC_SYSTEM_INODE:
lockdep_set_class(&inode->i_rwsem,
- &ocfs2_sysfile_lock_key[args->fi_sysfile_type]);
+ &ocfs2_sysfile_lock_key[EXTENT_ALLOC_SYSTEM_INODE]);
+ break;
+ case INODE_ALLOC_SYSTEM_INODE:
+ lockdep_set_class(&inode->i_rwsem,
+ &ocfs2_sysfile_lock_key[INODE_ALLOC_SYSTEM_INODE]);
+ break;
+ case JOURNAL_SYSTEM_INODE:
+ lockdep_set_class(&inode->i_rwsem,
+ &ocfs2_sysfile_lock_key[JOURNAL_SYSTEM_INODE]);
+ break;
+ case LOCAL_ALLOC_SYSTEM_INODE:
+ lockdep_set_class(&inode->i_rwsem,
+ &ocfs2_sysfile_lock_key[LOCAL_ALLOC_SYSTEM_INODE]);
+ break;
+ case TRUNCATE_LOG_SYSTEM_INODE:
+ lockdep_set_class(&inode->i_rwsem,
+ &ocfs2_sysfile_lock_key[TRUNCATE_LOG_SYSTEM_INODE]);
+ break;
+ case LOCAL_USER_QUOTA_SYSTEM_INODE:
+ lockdep_set_class(&inode->i_rwsem,
+ &ocfs2_sysfile_lock_key[LOCAL_USER_QUOTA_SYSTEM_INODE]);
+ break;
+ case LOCAL_GROUP_QUOTA_SYSTEM_INODE:
+ lockdep_set_class(&inode->i_rwsem,
+ &ocfs2_sysfile_lock_key[LOCAL_GROUP_QUOTA_SYSTEM_INODE]);
+ break;
+ default:
+ WARN_ONCE(1, "Unknown sysfile type %d\n", args->fi_sysfile_type);
+ }
if (args->fi_sysfile_type == USER_QUOTA_SYSTEM_INODE ||
args->fi_sysfile_type == GROUP_QUOTA_SYSTEM_INODE ||
args->fi_sysfile_type == LOCAL_USER_QUOTA_SYSTEM_INODE ||
@@ -267,6 +328,7 @@ static int ocfs2_init_locked_inode(struct inode *inode, void *opaque)
else
lockdep_set_class(&OCFS2_I(inode)->ip_alloc_sem,
&ocfs2_file_ip_alloc_sem_key);
+#endif
return 0;
}
diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c
index 369c7d27befd..cbe2f8ed8897 100644
--- a/fs/ocfs2/move_extents.c
+++ b/fs/ocfs2/move_extents.c
@@ -617,6 +617,8 @@ static int ocfs2_move_extent(struct ocfs2_move_extents_context *context,
*/
credits += OCFS2_INODE_UPDATE_CREDITS + 1;
+ inode_lock(tl_inode);
+
/*
* ocfs2_move_extent() didn't reserve any clusters in lock_allocators()
* logic, while we still need to lock the global_bitmap.
@@ -626,7 +628,7 @@ static int ocfs2_move_extent(struct ocfs2_move_extents_context *context,
if (!gb_inode) {
mlog(ML_ERROR, "unable to get global_bitmap inode\n");
ret = -EIO;
- goto out;
+ goto out_unlock_tl_inode;
}
inode_lock(gb_inode);
@@ -634,16 +636,14 @@ static int ocfs2_move_extent(struct ocfs2_move_extents_context *context,
ret = ocfs2_inode_lock(gb_inode, &gb_bh, 1);
if (ret) {
mlog_errno(ret);
- goto out_unlock_gb_mutex;
+ goto out_unlock_gb_inode;
}
- inode_lock(tl_inode);
-
handle = ocfs2_start_trans(osb, credits);
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
mlog_errno(ret);
- goto out_unlock_tl_inode;
+ goto out_unlock;
}
new_phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, *new_phys_cpos);
@@ -703,15 +703,14 @@ static int ocfs2_move_extent(struct ocfs2_move_extents_context *context,
out_commit:
ocfs2_commit_trans(osb, handle);
brelse(gd_bh);
-
-out_unlock_tl_inode:
- inode_unlock(tl_inode);
-
+out_unlock:
ocfs2_inode_unlock(gb_inode, 1);
-out_unlock_gb_mutex:
+out_unlock_gb_inode:
inode_unlock(gb_inode);
brelse(gb_bh);
iput(gb_inode);
+out_unlock_tl_inode:
+ inode_unlock(tl_inode);
out:
if (context->meta_ac) {
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 99278c8f0e24..c90b254da75e 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -142,6 +142,8 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
bail_add:
ret = d_splice_alias(inode, dentry);
+ if (IS_ERR(ret))
+ goto bail_unlock;
if (inode) {
/*
@@ -154,15 +156,16 @@ bail_add:
* NOTE: This dentry already has ->d_op set from
* ocfs2_get_parent() and ocfs2_get_dentry()
*/
- if (!IS_ERR_OR_NULL(ret))
+ if (ret)
dentry = ret;
status = ocfs2_dentry_attach_lock(dentry, inode,
OCFS2_I(dir)->ip_blkno);
if (status) {
mlog_errno(status);
+ if (ret)
+ dput(ret);
ret = ERR_PTR(status);
- goto bail_unlock;
}
} else
ocfs2_dentry_attach_gen(dentry);
@@ -1452,8 +1455,8 @@ static int ocfs2_rename(struct mnt_idmap *idmap,
newfe = (struct ocfs2_dinode *) newfe_bh->b_data;
trace_ocfs2_rename_over_existing(
- (unsigned long long)newfe_blkno, newfe_bh, newfe_bh ?
- (unsigned long long)newfe_bh->b_blocknr : 0ULL);
+ (unsigned long long)newfe_blkno, newfe_bh,
+ (unsigned long long)newfe_bh->b_blocknr);
if (S_ISDIR(new_inode->i_mode) || (new_inode->i_nlink == 1)) {
status = ocfs2_prepare_orphan_dir(osb, &orphan_dir,
diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c
index 77edcd70f72c..0f045e45fa0c 100644
--- a/fs/ocfs2/stack_user.c
+++ b/fs/ocfs2/stack_user.c
@@ -360,7 +360,6 @@ static int ocfs2_control_do_setnode_msg(struct file *file,
struct ocfs2_control_message_setn *msg)
{
long nodenum;
- char *ptr = NULL;
struct ocfs2_control_private *p = file->private_data;
if (ocfs2_control_get_handshake_state(file) !=
@@ -375,8 +374,7 @@ static int ocfs2_control_do_setnode_msg(struct file *file,
return -EINVAL;
msg->space = msg->newline = '\0';
- nodenum = simple_strtol(msg->nodestr, &ptr, 16);
- if (!ptr || *ptr)
+ if (kstrtol(msg->nodestr, 16, &nodenum))
return -EINVAL;
if ((nodenum == LONG_MIN) || (nodenum == LONG_MAX) ||
@@ -391,7 +389,6 @@ static int ocfs2_control_do_setversion_msg(struct file *file,
struct ocfs2_control_message_setv *msg)
{
long major, minor;
- char *ptr = NULL;
struct ocfs2_control_private *p = file->private_data;
struct ocfs2_protocol_version *max =
&ocfs2_user_plugin.sp_max_proto;
@@ -409,11 +406,9 @@ static int ocfs2_control_do_setversion_msg(struct file *file,
return -EINVAL;
msg->space1 = msg->space2 = msg->newline = '\0';
- major = simple_strtol(msg->major, &ptr, 16);
- if (!ptr || *ptr)
+ if (kstrtol(msg->major, 16, &major))
return -EINVAL;
- minor = simple_strtol(msg->minor, &ptr, 16);
- if (!ptr || *ptr)
+ if (kstrtol(msg->minor, 16, &minor))
return -EINVAL;
/*
@@ -441,7 +436,6 @@ static int ocfs2_control_do_down_msg(struct file *file,
struct ocfs2_control_message_down *msg)
{
long nodenum;
- char *p = NULL;
if (ocfs2_control_get_handshake_state(file) !=
OCFS2_CONTROL_HANDSHAKE_VALID)
@@ -456,8 +450,7 @@ static int ocfs2_control_do_down_msg(struct file *file,
return -EINVAL;
msg->space1 = msg->space2 = msg->newline = '\0';
- nodenum = simple_strtol(msg->nodestr, &p, 16);
- if (!p || *p)
+ if (kstrtol(msg->nodestr, 16, &nodenum))
return -EINVAL;
if ((nodenum == LONG_MIN) || (nodenum == LONG_MAX) ||
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index 10d01eb09c43..f188bd900eb2 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -1490,10 +1490,8 @@ int vmcore_add_device_dump(struct vmcoredd_data *data)
return -EINVAL;
dump = vzalloc(sizeof(*dump));
- if (!dump) {
- ret = -ENOMEM;
- goto out_err;
- }
+ if (!dump)
+ return -ENOMEM;
/* Keep size of the buffer page aligned so that it can be mmaped */
data_size = roundup(sizeof(struct vmcoredd_header) + data->size,
@@ -1519,22 +1517,19 @@ int vmcore_add_device_dump(struct vmcoredd_data *data)
dump->size = data_size;
/* Add the dump to driver sysfs list and update the elfcore hdr */
- mutex_lock(&vmcore_mutex);
- if (vmcore_opened)
- pr_warn_once("Unexpected adding of device dump\n");
- if (vmcore_open) {
- ret = -EBUSY;
- goto unlock;
- }
+ scoped_guard(mutex, &vmcore_mutex) {
+ if (vmcore_opened)
+ pr_warn_once("Unexpected adding of device dump\n");
+ if (vmcore_open) {
+ ret = -EBUSY;
+ goto out_err;
+ }
- list_add_tail(&dump->list, &vmcoredd_list);
- vmcoredd_update_size(data_size);
- mutex_unlock(&vmcore_mutex);
+ list_add_tail(&dump->list, &vmcoredd_list);
+ vmcoredd_update_size(data_size);
+ }
return 0;
-unlock:
- mutex_unlock(&vmcore_mutex);
-
out_err:
vfree(buf);
vfree(dump);
diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c
index 3061043e915c..b69c294e3ef0 100644
--- a/fs/squashfs/block.c
+++ b/fs/squashfs/block.c
@@ -80,23 +80,22 @@ static int squashfs_bio_read_cached(struct bio *fullbio,
struct address_space *cache_mapping, u64 index, int length,
u64 read_start, u64 read_end, int page_count)
{
- struct page *head_to_cache = NULL, *tail_to_cache = NULL;
+ struct folio *head_to_cache = NULL, *tail_to_cache = NULL;
struct block_device *bdev = fullbio->bi_bdev;
int start_idx = 0, end_idx = 0;
- struct bvec_iter_all iter_all;
+ struct folio_iter fi;
struct bio *bio = NULL;
- struct bio_vec *bv;
int idx = 0;
int err = 0;
#ifdef CONFIG_SQUASHFS_COMP_CACHE_FULL
- struct page **cache_pages = kmalloc_array(page_count,
- sizeof(void *), GFP_KERNEL | __GFP_ZERO);
+ struct folio **cache_folios = kmalloc_array(page_count,
+ sizeof(*cache_folios), GFP_KERNEL | __GFP_ZERO);
#endif
- bio_for_each_segment_all(bv, fullbio, iter_all) {
- struct page *page = bv->bv_page;
+ bio_for_each_folio_all(fi, fullbio) {
+ struct folio *folio = fi.folio;
- if (page->mapping == cache_mapping) {
+ if (folio->mapping == cache_mapping) {
idx++;
continue;
}
@@ -111,13 +110,13 @@ static int squashfs_bio_read_cached(struct bio *fullbio,
* adjacent blocks.
*/
if (idx == 0 && index != read_start)
- head_to_cache = page;
+ head_to_cache = folio;
else if (idx == page_count - 1 && index + length != read_end)
- tail_to_cache = page;
+ tail_to_cache = folio;
#ifdef CONFIG_SQUASHFS_COMP_CACHE_FULL
/* Cache all pages in the BIO for repeated reads */
- else if (cache_pages)
- cache_pages[idx] = page;
+ else if (cache_folios)
+ cache_folios[idx] = folio;
#endif
if (!bio || idx != end_idx) {
@@ -150,45 +149,45 @@ static int squashfs_bio_read_cached(struct bio *fullbio,
return err;
if (head_to_cache) {
- int ret = add_to_page_cache_lru(head_to_cache, cache_mapping,
+ int ret = filemap_add_folio(cache_mapping, head_to_cache,
read_start >> PAGE_SHIFT,
GFP_NOIO);
if (!ret) {
- SetPageUptodate(head_to_cache);
- unlock_page(head_to_cache);
+ folio_mark_uptodate(head_to_cache);
+ folio_unlock(head_to_cache);
}
}
if (tail_to_cache) {
- int ret = add_to_page_cache_lru(tail_to_cache, cache_mapping,
+ int ret = filemap_add_folio(cache_mapping, tail_to_cache,
(read_end >> PAGE_SHIFT) - 1,
GFP_NOIO);
if (!ret) {
- SetPageUptodate(tail_to_cache);
- unlock_page(tail_to_cache);
+ folio_mark_uptodate(tail_to_cache);
+ folio_unlock(tail_to_cache);
}
}
#ifdef CONFIG_SQUASHFS_COMP_CACHE_FULL
- if (!cache_pages)
+ if (!cache_folios)
goto out;
for (idx = 0; idx < page_count; idx++) {
- if (!cache_pages[idx])
+ if (!cache_folios[idx])
continue;
- int ret = add_to_page_cache_lru(cache_pages[idx], cache_mapping,
+ int ret = filemap_add_folio(cache_mapping, cache_folios[idx],
(read_start >> PAGE_SHIFT) + idx,
GFP_NOIO);
if (!ret) {
- SetPageUptodate(cache_pages[idx]);
- unlock_page(cache_pages[idx]);
+ folio_mark_uptodate(cache_folios[idx]);
+ folio_unlock(cache_folios[idx]);
}
}
- kfree(cache_pages);
+ kfree(cache_folios);
out:
#endif
return 0;
diff --git a/fs/squashfs/file.c b/fs/squashfs/file.c
index 5ca2baa16dc2..ce7d661d5ad8 100644
--- a/fs/squashfs/file.c
+++ b/fs/squashfs/file.c
@@ -493,10 +493,9 @@ out:
return res;
}
-static int squashfs_readahead_fragment(struct page **page,
+static int squashfs_readahead_fragment(struct inode *inode, struct page **page,
unsigned int pages, unsigned int expected, loff_t start)
{
- struct inode *inode = page[0]->mapping->host;
struct squashfs_cache_entry *buffer = squashfs_get_fragment(inode->i_sb,
squashfs_i(inode)->fragment_block,
squashfs_i(inode)->fragment_size);
@@ -605,8 +604,8 @@ static void squashfs_readahead(struct readahead_control *ractl)
if (start >> msblk->block_log == file_end &&
squashfs_i(inode)->fragment_block != SQUASHFS_INVALID_BLK) {
- res = squashfs_readahead_fragment(pages, nr_pages,
- expected, start);
+ res = squashfs_readahead_fragment(inode, pages,
+ nr_pages, expected, start);
if (res)
goto skip_pages;
continue;
diff --git a/include/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h
index 28ad0235086a..af3fd388329a 100644
--- a/include/dt-bindings/pinctrl/stm32-pinfunc.h
+++ b/include/dt-bindings/pinctrl/stm32-pinfunc.h
@@ -26,6 +26,7 @@
#define AF14 0xf
#define AF15 0x10
#define ANALOG 0x11
+#define RSVD 0x12
/* define Pins number*/
#define PIN_NO(port, line) (((port) - 'A') * 0x10 + (line))
diff --git a/include/linux/crash_reserve.h b/include/linux/crash_reserve.h
index 1fe7e7d1b214..7b44b41d0a20 100644
--- a/include/linux/crash_reserve.h
+++ b/include/linux/crash_reserve.h
@@ -13,10 +13,23 @@
*/
extern struct resource crashk_res;
extern struct resource crashk_low_res;
+extern struct range crashk_cma_ranges[];
+#if defined(CONFIG_CMA) && defined(CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION)
+#define CRASHKERNEL_CMA
+#define CRASHKERNEL_CMA_RANGES_MAX 4
+extern int crashk_cma_cnt;
+#else
+#define crashk_cma_cnt 0
+#define CRASHKERNEL_CMA_RANGES_MAX 0
+#endif
+
int __init parse_crashkernel(char *cmdline, unsigned long long system_ram,
unsigned long long *crash_size, unsigned long long *crash_base,
- unsigned long long *low_size, bool *high);
+ unsigned long long *low_size, unsigned long long *cma_size,
+ bool *high);
+
+void __init reserve_crashkernel_cma(unsigned long long cma_size);
#ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
#ifndef DEFAULT_CRASH_KERNEL_LOW_SIZE
diff --git a/include/linux/gcd.h b/include/linux/gcd.h
index cb572677fd7f..616e81a7f7e3 100644
--- a/include/linux/gcd.h
+++ b/include/linux/gcd.h
@@ -3,6 +3,9 @@
#define _GCD_H
#include <linux/compiler.h>
+#include <linux/jump_label.h>
+
+DECLARE_STATIC_KEY_TRUE(efficient_ffs_key);
unsigned long gcd(unsigned long a, unsigned long b) __attribute_const__;
diff --git a/include/linux/hung_task.h b/include/linux/hung_task.h
index 1bc2b3244613..34e615c76ca5 100644
--- a/include/linux/hung_task.h
+++ b/include/linux/hung_task.h
@@ -21,17 +21,17 @@
* type.
*
* Type encoding:
- * 00 - Blocked on mutex (BLOCKER_TYPE_MUTEX)
- * 01 - Blocked on semaphore (BLOCKER_TYPE_SEM)
- * 10 - Blocked on rt-mutex (BLOCKER_TYPE_RTMUTEX)
- * 11 - Blocked on rw-semaphore (BLOCKER_TYPE_RWSEM)
+ * 00 - Blocked on mutex (BLOCKER_TYPE_MUTEX)
+ * 01 - Blocked on semaphore (BLOCKER_TYPE_SEM)
+ * 10 - Blocked on rw-semaphore as READER (BLOCKER_TYPE_RWSEM_READER)
+ * 11 - Blocked on rw-semaphore as WRITER (BLOCKER_TYPE_RWSEM_WRITER)
*/
-#define BLOCKER_TYPE_MUTEX 0x00UL
-#define BLOCKER_TYPE_SEM 0x01UL
-#define BLOCKER_TYPE_RTMUTEX 0x02UL
-#define BLOCKER_TYPE_RWSEM 0x03UL
+#define BLOCKER_TYPE_MUTEX 0x00UL
+#define BLOCKER_TYPE_SEM 0x01UL
+#define BLOCKER_TYPE_RWSEM_READER 0x02UL
+#define BLOCKER_TYPE_RWSEM_WRITER 0x03UL
-#define BLOCKER_TYPE_MASK 0x03UL
+#define BLOCKER_TYPE_MASK 0x03UL
#ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
static inline void hung_task_set_blocker(void *lock, unsigned long type)
diff --git a/include/linux/i3c/device.h b/include/linux/i3c/device.h
index b674f64d0822..7f136de4b73e 100644
--- a/include/linux/i3c/device.h
+++ b/include/linux/i3c/device.h
@@ -245,7 +245,7 @@ void i3c_driver_unregister(struct i3c_driver *drv);
*
* Return: 0 if both registrations succeeds, a negative error code otherwise.
*/
-static inline int i3c_i2c_driver_register(struct i3c_driver *i3cdrv,
+static __always_inline int i3c_i2c_driver_register(struct i3c_driver *i3cdrv,
struct i2c_driver *i2cdrv)
{
int ret;
@@ -270,7 +270,7 @@ static inline int i3c_i2c_driver_register(struct i3c_driver *i3cdrv,
* Note that when CONFIG_I3C is not enabled, this function only unregisters the
* @i2cdrv.
*/
-static inline void i3c_i2c_driver_unregister(struct i3c_driver *i3cdrv,
+static __always_inline void i3c_i2c_driver_unregister(struct i3c_driver *i3cdrv,
struct i2c_driver *i2cdrv)
{
if (IS_ENABLED(CONFIG_I3C))
diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
index c67922ece617..043f5c7ff398 100644
--- a/include/linux/i3c/master.h
+++ b/include/linux/i3c/master.h
@@ -249,10 +249,15 @@ struct i3c_device {
*/
#define I3C_BUS_MAX_DEVS 11
-#define I3C_BUS_MAX_I3C_SCL_RATE 12900000
-#define I3C_BUS_TYP_I3C_SCL_RATE 12500000
-#define I3C_BUS_I2C_FM_PLUS_SCL_RATE 1000000
-#define I3C_BUS_I2C_FM_SCL_RATE 400000
+/* Taken from the I3C Spec V1.1.1, chapter 6.2. "Timing specification" */
+#define I3C_BUS_I2C_FM_PLUS_SCL_MAX_RATE 1000000
+#define I3C_BUS_I2C_FM_SCL_MAX_RATE 400000
+#define I3C_BUS_I3C_SCL_MAX_RATE 12900000
+#define I3C_BUS_I3C_SCL_TYP_RATE 12500000
+#define I3C_BUS_TAVAL_MIN_NS 1000
+#define I3C_BUS_TBUF_MIXED_FM_MIN_NS 1300
+#define I3C_BUS_THIGH_MIXED_MAX_NS 41
+#define I3C_BUS_TIDLE_MIN_NS 200000
#define I3C_BUS_TLOW_OD_MIN_NS 200
/**
diff --git a/include/linux/jhash.h b/include/linux/jhash.h
index fa26a2dd3b52..7c1c1821c694 100644
--- a/include/linux/jhash.h
+++ b/include/linux/jhash.h
@@ -24,7 +24,7 @@
* Jozsef
*/
#include <linux/bitops.h>
-#include <linux/unaligned/packed_struct.h>
+#include <linux/unaligned.h>
/* Best hash sizes are of power of two */
#define jhash_size(n) ((u32)1<<(n))
@@ -77,9 +77,9 @@ static inline u32 jhash(const void *key, u32 length, u32 initval)
/* All but the last block: affect some 32 bits of (a,b,c) */
while (length > 12) {
- a += __get_unaligned_cpu32(k);
- b += __get_unaligned_cpu32(k + 4);
- c += __get_unaligned_cpu32(k + 8);
+ a += get_unaligned((u32 *)k);
+ b += get_unaligned((u32 *)(k + 4));
+ c += get_unaligned((u32 *)(k + 8));
__jhash_mix(a, b, c);
length -= 12;
k += 12;
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index 03f85ad03025..1b10a5d84b68 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -79,6 +79,12 @@ extern note_buf_t __percpu *crash_notes;
typedef unsigned long kimage_entry_t;
+/*
+ * This is a copy of the UAPI struct kexec_segment and must be identical
+ * to it because it gets copied straight from user space into kernel
+ * memory. Do not modify this structure unless you change the way segments
+ * get ingested from user space.
+ */
struct kexec_segment {
/*
* This pointer can point to user memory if kexec_load() system
@@ -172,6 +178,7 @@ int kexec_image_post_load_cleanup_default(struct kimage *image);
* @buf_align: Minimum alignment needed.
* @buf_min: The buffer can't be placed below this address.
* @buf_max: The buffer can't be placed above this address.
+ * @cma: CMA page if the buffer is backed by CMA.
* @top_down: Allocate from top of memory.
* @random: Place the buffer at a random position.
*/
@@ -184,6 +191,7 @@ struct kexec_buf {
unsigned long buf_align;
unsigned long buf_min;
unsigned long buf_max;
+ struct page *cma;
bool top_down;
#ifdef CONFIG_CRASH_DUMP
bool random;
@@ -340,6 +348,7 @@ struct kimage {
unsigned long nr_segments;
struct kexec_segment segment[KEXEC_SEGMENT_MAX];
+ struct page *segment_cma[KEXEC_SEGMENT_MAX];
struct list_head control_pages;
struct list_head dest_pages;
@@ -361,6 +370,7 @@ struct kimage {
*/
unsigned int hotplug_support:1;
#endif
+ unsigned int no_cma:1;
#ifdef ARCH_HAS_KIMAGE_ARCH
struct kimage_arch arch;
diff --git a/include/linux/module.h b/include/linux/module.h
index a7cac01d95e7..313ecb8e5181 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -33,7 +33,7 @@
#include <linux/percpu.h>
#include <asm/module.h>
-#define MODULE_NAME_LEN MAX_PARAM_PREFIX_LEN
+#define MODULE_NAME_LEN __MODULE_NAME_LEN
struct modversion_info {
unsigned long crc;
@@ -303,23 +303,6 @@ static typeof(name) __mod_device_table__##type##__##name \
struct notifier_block;
-#ifdef CONFIG_MODULES
-
-/* Get/put a kernel symbol (calls must be symmetric) */
-void *__symbol_get(const char *symbol);
-void *__symbol_get_gpl(const char *symbol);
-#define symbol_get(x) ({ \
- static const char __notrim[] \
- __used __section(".no_trim_symbol") = __stringify(x); \
- (typeof(&x))(__symbol_get(__stringify(x))); })
-
-/* modules using other modules: kdb wants to see this. */
-struct module_use {
- struct list_head source_list;
- struct list_head target_list;
- struct module *source, *target;
-};
-
enum module_state {
MODULE_STATE_LIVE, /* Normal state. */
MODULE_STATE_COMING, /* Full formed, running module_init. */
@@ -604,6 +587,16 @@ struct module {
#define MODULE_ARCH_INIT {}
#endif
+#ifdef CONFIG_MODULES
+
+/* Get/put a kernel symbol (calls must be symmetric) */
+void *__symbol_get(const char *symbol);
+void *__symbol_get_gpl(const char *symbol);
+#define symbol_get(x) ({ \
+ static const char __notrim[] \
+ __used __section(".no_trim_symbol") = __stringify(x); \
+ (typeof(&x))(__symbol_get(__stringify(x))); })
+
#ifndef HAVE_ARCH_KALLSYMS_SYMBOL_VALUE
static inline unsigned long kallsyms_symbol_value(const Elf_Sym *sym)
{
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index bfb85fd13e1f..a04a2bc4f51e 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -6,6 +6,13 @@
#include <linux/stringify.h>
#include <linux/kernel.h>
+/*
+ * The maximum module name length, including the NUL byte.
+ * Chosen so that structs with an unsigned long line up, specifically
+ * modversion_info.
+ */
+#define __MODULE_NAME_LEN (64 - sizeof(unsigned long))
+
/* You can override this manually, but generally this should match the
module name. */
#ifdef MODULE
@@ -17,9 +24,6 @@
#define __MODULE_INFO_PREFIX KBUILD_MODNAME "."
#endif
-/* Chosen so that structs with an unsigned long line up. */
-#define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long))
-
#define __MODULE_INFO(tag, name, info) \
static const char __UNIQUE_ID(name)[] \
__used __section(".modinfo") __aligned(1) \
@@ -282,10 +286,9 @@ struct kparam_array
#define __moduleparam_const const
#endif
-/* This is the fundamental function for registering boot/module
- parameters. */
+/* This is the fundamental function for registering boot/module parameters. */
#define __module_param_call(prefix, name, ops, arg, perm, level, flags) \
- /* Default value instead of permissions? */ \
+ static_assert(sizeof(""prefix) - 1 <= __MODULE_NAME_LEN); \
static const char __param_str_##name[] = prefix #name; \
static struct kernel_param __moduleparam_const __param_##name \
__used __section("__param") \
diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
index 9a8189ffd0f2..d138e1815645 100644
--- a/include/linux/pinctrl/pinctrl.h
+++ b/include/linux/pinctrl/pinctrl.h
@@ -165,25 +165,25 @@ struct pinctrl_desc {
/* External interface to pin controller */
-extern int pinctrl_register_and_init(struct pinctrl_desc *pctldesc,
+extern int pinctrl_register_and_init(const struct pinctrl_desc *pctldesc,
struct device *dev, void *driver_data,
struct pinctrl_dev **pctldev);
extern int pinctrl_enable(struct pinctrl_dev *pctldev);
/* Please use pinctrl_register_and_init() and pinctrl_enable() instead */
-extern struct pinctrl_dev *pinctrl_register(struct pinctrl_desc *pctldesc,
+extern struct pinctrl_dev *pinctrl_register(const struct pinctrl_desc *pctldesc,
struct device *dev, void *driver_data);
extern void pinctrl_unregister(struct pinctrl_dev *pctldev);
extern int devm_pinctrl_register_and_init(struct device *dev,
- struct pinctrl_desc *pctldesc,
+ const struct pinctrl_desc *pctldesc,
void *driver_data,
struct pinctrl_dev **pctldev);
/* Please use devm_pinctrl_register_and_init() instead */
extern struct pinctrl_dev *devm_pinctrl_register(struct device *dev,
- struct pinctrl_desc *pctldesc,
+ const struct pinctrl_desc *pctldesc,
void *driver_data);
extern void devm_pinctrl_unregister(struct device *dev,
diff --git a/include/linux/raid/pq.h b/include/linux/raid/pq.h
index 72ff44cca864..2467b3be15c9 100644
--- a/include/linux/raid/pq.h
+++ b/include/linux/raid/pq.h
@@ -11,8 +11,13 @@
#ifdef __KERNEL__
#include <linux/blkdev.h>
+#include <linux/mm.h>
-extern const char raid6_empty_zero_page[PAGE_SIZE];
+/* This should be const but the raid6 code is too convoluted for that. */
+static inline void *raid6_get_zero_page(void)
+{
+ return page_address(ZERO_PAGE(0));
+}
#else /* ! __KERNEL__ */
/* Used for testing in user space */
@@ -191,6 +196,11 @@ static inline uint32_t raid6_jiffies(void)
return tv.tv_sec*1000 + tv.tv_usec/1000;
}
+static inline void *raid6_get_zero_page(void)
+{
+ return raid6_empty_zero_page;
+}
+
#endif /* ! __KERNEL__ */
#endif /* LINUX_RAID_RAID6_H */
diff --git a/include/linux/relay.h b/include/linux/relay.h
index b3224111d074..6772a7075840 100644
--- a/include/linux/relay.h
+++ b/include/linux/relay.h
@@ -29,6 +29,22 @@
#define RELAYFS_CHANNEL_VERSION 7
/*
+ * Relay buffer statistics
+ */
+enum {
+ RELAY_STATS_BUF_FULL = (1 << 0),
+ RELAY_STATS_WRT_BIG = (1 << 1),
+
+ RELAY_STATS_LAST = RELAY_STATS_WRT_BIG,
+};
+
+struct rchan_buf_stats
+{
+ unsigned int full_count; /* counter for buffer full */
+ unsigned int big_count; /* counter for too big to write */
+};
+
+/*
* Per-cpu relay channel buffer
*/
struct rchan_buf
@@ -43,11 +59,11 @@ struct rchan_buf
struct irq_work wakeup_work; /* reader wakeup */
struct dentry *dentry; /* channel file dentry */
struct kref kref; /* channel buffer refcount */
+ struct rchan_buf_stats stats; /* buffer stats */
struct page **page_array; /* array of current buffer pages */
unsigned int page_count; /* number of current buffer pages */
unsigned int finalized; /* buffer has been finalized */
size_t *padding; /* padding counts per sub-buffer */
- size_t prev_padding; /* temporary variable */
size_t bytes_consumed; /* bytes consumed in cur read subbuf */
size_t early_bytes; /* bytes consumed before VFS inited */
unsigned int cpu; /* this buf's cpu */
@@ -65,7 +81,6 @@ struct rchan
const struct rchan_callbacks *cb; /* client callbacks */
struct kref kref; /* channel refcount */
void *private_data; /* for user-defined data */
- size_t last_toobig; /* tried to log event > subbuf size */
struct rchan_buf * __percpu *buf; /* per-cpu channel buffers */
int is_global; /* One global buffer ? */
struct list_head list; /* for channel list */
@@ -84,7 +99,6 @@ struct rchan_callbacks
* @buf: the channel buffer containing the new sub-buffer
* @subbuf: the start of the new sub-buffer
* @prev_subbuf: the start of the previous sub-buffer
- * @prev_padding: unused space at the end of previous sub-buffer
*
* The client should return 1 to continue logging, 0 to stop
* logging.
@@ -100,8 +114,7 @@ struct rchan_callbacks
*/
int (*subbuf_start) (struct rchan_buf *buf,
void *subbuf,
- void *prev_subbuf,
- size_t prev_padding);
+ void *prev_subbuf);
/*
* create_buf_file - create file to represent a relay channel buffer
@@ -161,6 +174,7 @@ struct rchan *relay_open(const char *base_filename,
void *private_data);
extern void relay_close(struct rchan *chan);
extern void relay_flush(struct rchan *chan);
+size_t relay_stats(struct rchan *chan, int flags);
extern void relay_subbufs_consumed(struct rchan *chan,
unsigned int cpu,
size_t consumed);
diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
index bc90c3c7b5fd..876358cfe1b1 100644
--- a/include/linux/ring_buffer.h
+++ b/include/linux/ring_buffer.h
@@ -144,6 +144,9 @@ int ring_buffer_write(struct trace_buffer *buffer,
void ring_buffer_nest_start(struct trace_buffer *buffer);
void ring_buffer_nest_end(struct trace_buffer *buffer);
+DEFINE_GUARD(ring_buffer_nest, struct trace_buffer *,
+ ring_buffer_nest_start(_T), ring_buffer_nest_end(_T))
+
struct ring_buffer_event *
ring_buffer_peek(struct trace_buffer *buffer, int cpu, u64 *ts,
unsigned long *lost_events);
diff --git a/include/linux/rtc/ds1685.h b/include/linux/rtc/ds1685.h
index 5a41c3bbcbe3..01da4582db6d 100644
--- a/include/linux/rtc/ds1685.h
+++ b/include/linux/rtc/ds1685.h
@@ -8,7 +8,7 @@
* include larger, battery-backed NV-SRAM, burst-mode access, and an RTC
* write counter.
*
- * Copyright (C) 2011-2014 Joshua Kinard <kumba@gentoo.org>.
+ * Copyright (C) 2011-2014 Joshua Kinard <linux@kumba.dev>.
* Copyright (C) 2009 Matthias Fuchs <matthias.fuchs@esd-electronics.com>.
*
* References:
diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h
index cbafdc12e743..f1aaf676a874 100644
--- a/include/linux/rwsem.h
+++ b/include/linux/rwsem.h
@@ -132,6 +132,18 @@ static inline int rwsem_is_contended(struct rw_semaphore *sem)
return !list_empty(&sem->wait_list);
}
+#if defined(CONFIG_DEBUG_RWSEMS) || defined(CONFIG_DETECT_HUNG_TASK_BLOCKER)
+/*
+ * Return just the real task structure pointer of the owner
+ */
+extern struct task_struct *rwsem_owner(struct rw_semaphore *sem);
+
+/*
+ * Return true if the rwsem is owned by a reader.
+ */
+extern bool is_rwsem_reader_owned(struct rw_semaphore *sem);
+#endif
+
#else /* !CONFIG_PREEMPT_RT */
#include <linux/rwbase_rt.h>
diff --git a/include/linux/soc/samsung/exynos-regs-pmu.h b/include/linux/soc/samsung/exynos-regs-pmu.h
index fa28a8784d65..71e0c09a49eb 100644
--- a/include/linux/soc/samsung/exynos-regs-pmu.h
+++ b/include/linux/soc/samsung/exynos-regs-pmu.h
@@ -677,6 +677,7 @@
#define GS101_CPU_INFORM(cpu) \
(GS101_CPU0_INFORM + (cpu*4))
#define GS101_SYSTEM_CONFIGURATION (0x3A00)
+#define GS101_EINT_WAKEUP_MASK (0x3A80)
#define GS101_PHY_CTRL_USB20 (0x3EB0)
#define GS101_PHY_CTRL_USBDP (0x3EB4)
diff --git a/include/linux/sys_info.h b/include/linux/sys_info.h
new file mode 100644
index 000000000000..89d77dc4f2ed
--- /dev/null
+++ b/include/linux/sys_info.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_SYS_INFO_H
+#define _LINUX_SYS_INFO_H
+
+#include <linux/sysctl.h>
+
+/*
+ * SYS_INFO_PANIC_CONSOLE_REPLAY is for panic case only, as it needs special
+ * handling which only fits panic case.
+ */
+#define SYS_INFO_TASKS 0x00000001
+#define SYS_INFO_MEM 0x00000002
+#define SYS_INFO_TIMERS 0x00000004
+#define SYS_INFO_LOCKS 0x00000008
+#define SYS_INFO_FTRACE 0x00000010
+#define SYS_INFO_PANIC_CONSOLE_REPLAY 0x00000020
+#define SYS_INFO_ALL_CPU_BT 0x00000040
+#define SYS_INFO_BLOCKED_TASKS 0x00000080
+
+void sys_info(unsigned long si_mask);
+unsigned long sys_info_parse_param(char *str);
+
+#ifdef CONFIG_SYSCTL
+int sysctl_sys_info_handler(const struct ctl_table *ro_table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos);
+#endif
+#endif /* _LINUX_SYS_INFO_H */
diff --git a/include/linux/xxhash.h b/include/linux/xxhash.h
index df42511438d0..27f57eca8cb1 100644
--- a/include/linux/xxhash.h
+++ b/include/linux/xxhash.h
@@ -178,32 +178,6 @@ struct xxh64_state {
void xxh32_reset(struct xxh32_state *state, uint32_t seed);
/**
- * xxh32_update() - hash the data given and update the xxh32 state
- *
- * @state: The xxh32 state to update.
- * @input: The data to hash.
- * @length: The length of the data to hash.
- *
- * After calling xxh32_reset() call xxh32_update() as many times as necessary.
- *
- * Return: Zero on success, otherwise an error code.
- */
-int xxh32_update(struct xxh32_state *state, const void *input, size_t length);
-
-/**
- * xxh32_digest() - produce the current xxh32 hash
- *
- * @state: Produce the current xxh32 hash of this state.
- *
- * A hash value can be produced at any time. It is still possible to continue
- * inserting input into the hash state after a call to xxh32_digest(), and
- * generate new hashes later on, by calling xxh32_digest() again.
- *
- * Return: The xxh32 hash stored in the state.
- */
-uint32_t xxh32_digest(const struct xxh32_state *state);
-
-/**
* xxh64_reset() - reset the xxh64 state to start a new hashing operation
*
* @state: The xxh64 state to reset.
diff --git a/include/uapi/linux/kexec.h b/include/uapi/linux/kexec.h
index 5ae1741ea8ea..8958ebfcff94 100644
--- a/include/uapi/linux/kexec.h
+++ b/include/uapi/linux/kexec.h
@@ -27,6 +27,7 @@
#define KEXEC_FILE_ON_CRASH 0x00000002
#define KEXEC_FILE_NO_INITRAMFS 0x00000004
#define KEXEC_FILE_DEBUG 0x00000008
+#define KEXEC_FILE_NO_CMA 0x00000010
/* These values match the ELF architecture values.
* Unless there is a good reason that should continue to be the case.
diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h
index 1c23e6387f13..7dab04cf4a36 100644
--- a/include/xen/xenbus.h
+++ b/include/xen/xenbus.h
@@ -178,7 +178,7 @@ int xenbus_printf(struct xenbus_transaction t,
* sprintf-style type string, and pointer. Returns 0 or errno.*/
int xenbus_gather(struct xenbus_transaction t, const char *dir, ...);
-/* notifer routines for when the xenstore comes up */
+/* notifier routines for when the xenstore comes up */
extern int xenstored_ready;
int register_xenstore_notifier(struct notifier_block *nb);
void unregister_xenstore_notifier(struct notifier_block *nb);
diff --git a/init/Kconfig b/init/Kconfig
index 2357458fb451..836320251219 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -172,6 +172,10 @@ menu "General setup"
config BROKEN
bool
+ help
+ This option allows you to choose whether you want to try to
+ compile (and fix) old drivers that haven't been updated to
+ new infrastructure.
config BROKEN_ON_SMP
bool
diff --git a/init/main.c b/init/main.c
index f9f401b6fdfb..0ee0ee7b7c2c 100644
--- a/init/main.c
+++ b/init/main.c
@@ -1587,7 +1587,11 @@ static noinline void __init kernel_init_freeable(void)
* check if there is an early userspace init. If yes, let it do all
* the work
*/
- if (init_eaccess(ramdisk_execute_command) != 0) {
+ int ramdisk_command_access;
+ ramdisk_command_access = init_eaccess(ramdisk_execute_command);
+ if (ramdisk_command_access != 0) {
+ pr_warn("check access for rdinit=%s failed: %i, ignoring\n",
+ ramdisk_execute_command, ramdisk_command_access);
ramdisk_execute_command = NULL;
prepare_namespace();
}
diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index 335b8425dd4b..a4ef79591eb2 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -21,6 +21,7 @@
#include <linux/reboot.h>
#include <linux/btf.h>
#include <linux/objtool.h>
+#include <linux/delay.h>
#include <asm/page.h>
#include <asm/sections.h>
@@ -33,6 +34,11 @@
/* Per cpu memory for storing cpu states in case of system crash. */
note_buf_t __percpu *crash_notes;
+/* time to wait for possible DMA to finish before starting the kdump kernel
+ * when a CMA reservation is used
+ */
+#define CMA_DMA_TIMEOUT_SEC 10
+
#ifdef CONFIG_CRASH_DUMP
int kimage_crash_copy_vmcoreinfo(struct kimage *image)
@@ -97,6 +103,14 @@ int kexec_crash_loaded(void)
}
EXPORT_SYMBOL_GPL(kexec_crash_loaded);
+static void crash_cma_clear_pending_dma(void)
+{
+ if (!crashk_cma_cnt)
+ return;
+
+ mdelay(CMA_DMA_TIMEOUT_SEC * 1000);
+}
+
/*
* No panic_cpu check version of crash_kexec(). This function is called
* only when panic_cpu holds the current CPU number; this is the only CPU
@@ -119,6 +133,7 @@ void __noclone __crash_kexec(struct pt_regs *regs)
crash_setup_regs(&fixed_regs, regs);
crash_save_vmcoreinfo();
machine_crash_shutdown(&fixed_regs);
+ crash_cma_clear_pending_dma();
machine_kexec(kexec_crash_image);
}
kexec_unlock();
diff --git a/kernel/crash_reserve.c b/kernel/crash_reserve.c
index acb6bf42e30d..87bf4d41eabb 100644
--- a/kernel/crash_reserve.c
+++ b/kernel/crash_reserve.c
@@ -14,6 +14,8 @@
#include <linux/cpuhotplug.h>
#include <linux/memblock.h>
#include <linux/kmemleak.h>
+#include <linux/cma.h>
+#include <linux/crash_reserve.h>
#include <asm/page.h>
#include <asm/sections.h>
@@ -172,17 +174,19 @@ static int __init parse_crashkernel_simple(char *cmdline,
#define SUFFIX_HIGH 0
#define SUFFIX_LOW 1
-#define SUFFIX_NULL 2
+#define SUFFIX_CMA 2
+#define SUFFIX_NULL 3
static __initdata char *suffix_tbl[] = {
[SUFFIX_HIGH] = ",high",
[SUFFIX_LOW] = ",low",
+ [SUFFIX_CMA] = ",cma",
[SUFFIX_NULL] = NULL,
};
/*
* That function parses "suffix" crashkernel command lines like
*
- * crashkernel=size,[high|low]
+ * crashkernel=size,[high|low|cma]
*
* It returns 0 on success and -EINVAL on failure.
*/
@@ -298,9 +302,11 @@ int __init parse_crashkernel(char *cmdline,
unsigned long long *crash_size,
unsigned long long *crash_base,
unsigned long long *low_size,
+ unsigned long long *cma_size,
bool *high)
{
int ret;
+ unsigned long long __always_unused cma_base;
/* crashkernel=X[@offset] */
ret = __parse_crashkernel(cmdline, system_ram, crash_size,
@@ -331,6 +337,14 @@ int __init parse_crashkernel(char *cmdline,
*high = true;
}
+
+ /*
+ * optional CMA reservation
+ * cma_base is ignored
+ */
+ if (cma_size)
+ __parse_crashkernel(cmdline, 0, cma_size,
+ &cma_base, suffix_tbl[SUFFIX_CMA]);
#endif
if (!*crash_size)
ret = -EINVAL;
@@ -457,6 +471,56 @@ retry:
#endif
}
+struct range crashk_cma_ranges[CRASHKERNEL_CMA_RANGES_MAX];
+#ifdef CRASHKERNEL_CMA
+int crashk_cma_cnt;
+void __init reserve_crashkernel_cma(unsigned long long cma_size)
+{
+ unsigned long long request_size = roundup(cma_size, PAGE_SIZE);
+ unsigned long long reserved_size = 0;
+
+ if (!cma_size)
+ return;
+
+ while (cma_size > reserved_size &&
+ crashk_cma_cnt < CRASHKERNEL_CMA_RANGES_MAX) {
+
+ struct cma *res;
+
+ if (cma_declare_contiguous(0, request_size, 0, 0, 0, false,
+ "crashkernel", &res)) {
+ /* reservation failed, try half-sized blocks */
+ if (request_size <= PAGE_SIZE)
+ break;
+
+ request_size = roundup(request_size / 2, PAGE_SIZE);
+ continue;
+ }
+
+ crashk_cma_ranges[crashk_cma_cnt].start = cma_get_base(res);
+ crashk_cma_ranges[crashk_cma_cnt].end =
+ crashk_cma_ranges[crashk_cma_cnt].start +
+ cma_get_size(res) - 1;
+ ++crashk_cma_cnt;
+ reserved_size += request_size;
+ }
+
+ if (cma_size > reserved_size)
+ pr_warn("crashkernel CMA reservation failed: %lld MB requested, %lld MB reserved in %d ranges\n",
+ cma_size >> 20, reserved_size >> 20, crashk_cma_cnt);
+ else
+ pr_info("crashkernel CMA reserved: %lld MB in %d ranges\n",
+ reserved_size >> 20, crashk_cma_cnt);
+}
+
+#else /* CRASHKERNEL_CMA */
+void __init reserve_crashkernel_cma(unsigned long long cma_size)
+{
+ if (cma_size)
+ pr_warn("crashkernel CMA reservation not supported\n");
+}
+#endif
+
#ifndef HAVE_ARCH_ADD_CRASH_RES_TO_IOMEM_EARLY
static __init int insert_crashkernel_resources(void)
{
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index f774367c8e71..7ca1940607bd 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -580,8 +580,8 @@ retry:
out:
/* Revert back reference counter if instruction update failed. */
- if (ret < 0 && is_register && ref_ctr_updated)
- update_ref_ctr(uprobe, mm, -1);
+ if (ret < 0 && ref_ctr_updated)
+ update_ref_ctr(uprobe, mm, is_register ? -1 : 1);
/* try collapse pmd for compound page */
if (ret > 0)
diff --git a/kernel/exit.c b/kernel/exit.c
index 1d8c8ac33c4f..343eb97543d5 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -693,12 +693,7 @@ static void reparent_leader(struct task_struct *father, struct task_struct *p,
}
/*
- * This does two things:
- *
- * A. Make init inherit all the child processes
- * B. Check to see if any process groups have become orphaned
- * as a result of our exiting, and if they have any stopped
- * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2)
+ * Make init inherit all the child processes
*/
static void forget_original_parent(struct task_struct *father,
struct list_head *dead)
diff --git a/kernel/fork.c b/kernel/fork.c
index e45354cc7cac..9ce93fd20f82 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -189,33 +189,33 @@ static inline void free_task_struct(struct task_struct *tsk)
kmem_cache_free(task_struct_cachep, tsk);
}
-/*
- * Allocate pages if THREAD_SIZE is >= PAGE_SIZE, otherwise use a
- * kmemcache based allocator.
- */
-# if THREAD_SIZE >= PAGE_SIZE || defined(CONFIG_VMAP_STACK)
-
-# ifdef CONFIG_VMAP_STACK
+#ifdef CONFIG_VMAP_STACK
/*
* vmalloc() is a bit slow, and calling vfree() enough times will force a TLB
* flush. Try to minimize the number of calls by caching stacks.
*/
#define NR_CACHED_STACKS 2
static DEFINE_PER_CPU(struct vm_struct *, cached_stacks[NR_CACHED_STACKS]);
+/*
+ * Allocated stacks are cached and later reused by new threads, so memcg
+ * accounting is performed by the code assigning/releasing stacks to tasks.
+ * We need a zeroed memory without __GFP_ACCOUNT.
+ */
+#define GFP_VMAP_STACK (GFP_KERNEL | __GFP_ZERO)
struct vm_stack {
struct rcu_head rcu;
struct vm_struct *stack_vm_area;
};
-static bool try_release_thread_stack_to_cache(struct vm_struct *vm)
+static bool try_release_thread_stack_to_cache(struct vm_struct *vm_area)
{
unsigned int i;
for (i = 0; i < NR_CACHED_STACKS; i++) {
struct vm_struct *tmp = NULL;
- if (this_cpu_try_cmpxchg(cached_stacks[i], &tmp, vm))
+ if (this_cpu_try_cmpxchg(cached_stacks[i], &tmp, vm_area))
return true;
}
return false;
@@ -224,11 +224,12 @@ static bool try_release_thread_stack_to_cache(struct vm_struct *vm)
static void thread_stack_free_rcu(struct rcu_head *rh)
{
struct vm_stack *vm_stack = container_of(rh, struct vm_stack, rcu);
+ struct vm_struct *vm_area = vm_stack->stack_vm_area;
if (try_release_thread_stack_to_cache(vm_stack->stack_vm_area))
return;
- vfree(vm_stack);
+ vfree(vm_area->addr);
}
static void thread_stack_delayed_free(struct task_struct *tsk)
@@ -241,32 +242,32 @@ static void thread_stack_delayed_free(struct task_struct *tsk)
static int free_vm_stack_cache(unsigned int cpu)
{
- struct vm_struct **cached_vm_stacks = per_cpu_ptr(cached_stacks, cpu);
+ struct vm_struct **cached_vm_stack_areas = per_cpu_ptr(cached_stacks, cpu);
int i;
for (i = 0; i < NR_CACHED_STACKS; i++) {
- struct vm_struct *vm_stack = cached_vm_stacks[i];
+ struct vm_struct *vm_area = cached_vm_stack_areas[i];
- if (!vm_stack)
+ if (!vm_area)
continue;
- vfree(vm_stack->addr);
- cached_vm_stacks[i] = NULL;
+ vfree(vm_area->addr);
+ cached_vm_stack_areas[i] = NULL;
}
return 0;
}
-static int memcg_charge_kernel_stack(struct vm_struct *vm)
+static int memcg_charge_kernel_stack(struct vm_struct *vm_area)
{
int i;
int ret;
int nr_charged = 0;
- BUG_ON(vm->nr_pages != THREAD_SIZE / PAGE_SIZE);
+ BUG_ON(vm_area->nr_pages != THREAD_SIZE / PAGE_SIZE);
for (i = 0; i < THREAD_SIZE / PAGE_SIZE; i++) {
- ret = memcg_kmem_charge_page(vm->pages[i], GFP_KERNEL, 0);
+ ret = memcg_kmem_charge_page(vm_area->pages[i], GFP_KERNEL, 0);
if (ret)
goto err;
nr_charged++;
@@ -274,55 +275,47 @@ static int memcg_charge_kernel_stack(struct vm_struct *vm)
return 0;
err:
for (i = 0; i < nr_charged; i++)
- memcg_kmem_uncharge_page(vm->pages[i], 0);
+ memcg_kmem_uncharge_page(vm_area->pages[i], 0);
return ret;
}
static int alloc_thread_stack_node(struct task_struct *tsk, int node)
{
- struct vm_struct *vm;
+ struct vm_struct *vm_area;
void *stack;
int i;
for (i = 0; i < NR_CACHED_STACKS; i++) {
- struct vm_struct *s;
-
- s = this_cpu_xchg(cached_stacks[i], NULL);
-
- if (!s)
+ vm_area = this_cpu_xchg(cached_stacks[i], NULL);
+ if (!vm_area)
continue;
/* Reset stack metadata. */
- kasan_unpoison_range(s->addr, THREAD_SIZE);
+ kasan_unpoison_range(vm_area->addr, THREAD_SIZE);
- stack = kasan_reset_tag(s->addr);
+ stack = kasan_reset_tag(vm_area->addr);
/* Clear stale pointers from reused stack. */
memset(stack, 0, THREAD_SIZE);
- if (memcg_charge_kernel_stack(s)) {
- vfree(s->addr);
+ if (memcg_charge_kernel_stack(vm_area)) {
+ vfree(vm_area->addr);
return -ENOMEM;
}
- tsk->stack_vm_area = s;
+ tsk->stack_vm_area = vm_area;
tsk->stack = stack;
return 0;
}
- /*
- * Allocated stacks are cached and later reused by new threads,
- * so memcg accounting is performed manually on assigning/releasing
- * stacks to tasks. Drop __GFP_ACCOUNT.
- */
stack = __vmalloc_node(THREAD_SIZE, THREAD_ALIGN,
- THREADINFO_GFP & ~__GFP_ACCOUNT,
+ GFP_VMAP_STACK,
node, __builtin_return_address(0));
if (!stack)
return -ENOMEM;
- vm = find_vm_area(stack);
- if (memcg_charge_kernel_stack(vm)) {
+ vm_area = find_vm_area(stack);
+ if (memcg_charge_kernel_stack(vm_area)) {
vfree(stack);
return -ENOMEM;
}
@@ -331,7 +324,7 @@ static int alloc_thread_stack_node(struct task_struct *tsk, int node)
* free_thread_stack() can be called in interrupt context,
* so cache the vm_struct.
*/
- tsk->stack_vm_area = vm;
+ tsk->stack_vm_area = vm_area;
stack = kasan_reset_tag(stack);
tsk->stack = stack;
return 0;
@@ -346,7 +339,13 @@ static void free_thread_stack(struct task_struct *tsk)
tsk->stack_vm_area = NULL;
}
-# else /* !CONFIG_VMAP_STACK */
+#else /* !CONFIG_VMAP_STACK */
+
+/*
+ * Allocate pages if THREAD_SIZE is >= PAGE_SIZE, otherwise use a
+ * kmemcache based allocator.
+ */
+#if THREAD_SIZE >= PAGE_SIZE
static void thread_stack_free_rcu(struct rcu_head *rh)
{
@@ -378,8 +377,7 @@ static void free_thread_stack(struct task_struct *tsk)
tsk->stack = NULL;
}
-# endif /* CONFIG_VMAP_STACK */
-# else /* !(THREAD_SIZE >= PAGE_SIZE || defined(CONFIG_VMAP_STACK)) */
+#else /* !(THREAD_SIZE >= PAGE_SIZE) */
static struct kmem_cache *thread_stack_cache;
@@ -418,7 +416,8 @@ void thread_stack_cache_init(void)
BUG_ON(thread_stack_cache == NULL);
}
-# endif /* THREAD_SIZE >= PAGE_SIZE || defined(CONFIG_VMAP_STACK) */
+#endif /* THREAD_SIZE >= PAGE_SIZE */
+#endif /* CONFIG_VMAP_STACK */
/* SLAB cache for signal_struct structures (tsk->signal) */
static struct kmem_cache *signal_cachep;
@@ -438,11 +437,11 @@ static struct kmem_cache *mm_cachep;
static void account_kernel_stack(struct task_struct *tsk, int account)
{
if (IS_ENABLED(CONFIG_VMAP_STACK)) {
- struct vm_struct *vm = task_stack_vm_area(tsk);
+ struct vm_struct *vm_area = task_stack_vm_area(tsk);
int i;
for (i = 0; i < THREAD_SIZE / PAGE_SIZE; i++)
- mod_lruvec_page_state(vm->pages[i], NR_KERNEL_STACK_KB,
+ mod_lruvec_page_state(vm_area->pages[i], NR_KERNEL_STACK_KB,
account * (PAGE_SIZE / 1024));
} else {
void *stack = task_stack_page(tsk);
@@ -458,12 +457,12 @@ void exit_task_stack_account(struct task_struct *tsk)
account_kernel_stack(tsk, -1);
if (IS_ENABLED(CONFIG_VMAP_STACK)) {
- struct vm_struct *vm;
+ struct vm_struct *vm_area;
int i;
- vm = task_stack_vm_area(tsk);
+ vm_area = task_stack_vm_area(tsk);
for (i = 0; i < THREAD_SIZE / PAGE_SIZE; i++)
- memcg_kmem_uncharge_page(vm->pages[i], 0);
+ memcg_kmem_uncharge_page(vm_area->pages[i], 0);
}
}
diff --git a/kernel/hung_task.c b/kernel/hung_task.c
index d2432df2b905..8708a1205f82 100644
--- a/kernel/hung_task.c
+++ b/kernel/hung_task.c
@@ -23,6 +23,7 @@
#include <linux/sched/debug.h>
#include <linux/sched/sysctl.h>
#include <linux/hung_task.h>
+#include <linux/rwsem.h>
#include <trace/events/sched.h>
@@ -100,6 +101,7 @@ static void debug_show_blocker(struct task_struct *task)
{
struct task_struct *g, *t;
unsigned long owner, blocker, blocker_type;
+ const char *rwsem_blocked_by, *rwsem_blocked_as;
RCU_LOCKDEP_WARN(!rcu_read_lock_held(), "No rcu lock held");
@@ -111,12 +113,20 @@ static void debug_show_blocker(struct task_struct *task)
switch (blocker_type) {
case BLOCKER_TYPE_MUTEX:
- owner = mutex_get_owner(
- (struct mutex *)hung_task_blocker_to_lock(blocker));
+ owner = mutex_get_owner(hung_task_blocker_to_lock(blocker));
break;
case BLOCKER_TYPE_SEM:
- owner = sem_last_holder(
- (struct semaphore *)hung_task_blocker_to_lock(blocker));
+ owner = sem_last_holder(hung_task_blocker_to_lock(blocker));
+ break;
+ case BLOCKER_TYPE_RWSEM_READER:
+ case BLOCKER_TYPE_RWSEM_WRITER:
+ owner = (unsigned long)rwsem_owner(
+ hung_task_blocker_to_lock(blocker));
+ rwsem_blocked_as = (blocker_type == BLOCKER_TYPE_RWSEM_READER) ?
+ "reader" : "writer";
+ rwsem_blocked_by = is_rwsem_reader_owned(
+ hung_task_blocker_to_lock(blocker)) ?
+ "reader" : "writer";
break;
default:
WARN_ON_ONCE(1);
@@ -134,6 +144,11 @@ static void debug_show_blocker(struct task_struct *task)
pr_err("INFO: task %s:%d is blocked on a semaphore, but the last holder is not found.\n",
task->comm, task->pid);
break;
+ case BLOCKER_TYPE_RWSEM_READER:
+ case BLOCKER_TYPE_RWSEM_WRITER:
+ pr_err("INFO: task %s:%d is blocked on an rw-semaphore, but the owner is not found.\n",
+ task->comm, task->pid);
+ break;
}
return;
}
@@ -152,6 +167,12 @@ static void debug_show_blocker(struct task_struct *task)
pr_err("INFO: task %s:%d blocked on a semaphore likely last held by task %s:%d\n",
task->comm, task->pid, t->comm, t->pid);
break;
+ case BLOCKER_TYPE_RWSEM_READER:
+ case BLOCKER_TYPE_RWSEM_WRITER:
+ pr_err("INFO: task %s:%d <%s> blocked on an rw-semaphore likely owned by task %s:%d <%s>\n",
+ task->comm, task->pid, rwsem_blocked_as, t->comm,
+ t->pid, rwsem_blocked_by);
+ break;
}
sched_show_task(t);
return;
diff --git a/kernel/kcov.c b/kernel/kcov.c
index 187ba1b80bda..1d85597057e1 100644
--- a/kernel/kcov.c
+++ b/kernel/kcov.c
@@ -552,7 +552,7 @@ static int kcov_get_mode(unsigned long arg)
/*
* Fault in a lazily-faulted vmalloc area before it can be used by
- * __santizer_cov_trace_pc(), to avoid recursion issues if any code on the
+ * __sanitizer_cov_trace_pc(), to avoid recursion issues if any code on the
* vmalloc fault handling path is instrumented.
*/
static void kcov_fault_in_area(struct kcov *kcov)
diff --git a/kernel/kexec.c b/kernel/kexec.c
index a6b3f96bb50c..28008e3d462e 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -152,7 +152,7 @@ static int do_kexec_load(unsigned long entry, unsigned long nr_segments,
goto out;
for (i = 0; i < nr_segments; i++) {
- ret = kimage_load_segment(image, &image->segment[i]);
+ ret = kimage_load_segment(image, i);
if (ret)
goto out;
}
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index 351cd7d76dfa..31203f0bacaf 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -40,6 +40,7 @@
#include <linux/hugetlb.h>
#include <linux/objtool.h>
#include <linux/kmsg_dump.h>
+#include <linux/dma-map-ops.h>
#include <asm/page.h>
#include <asm/sections.h>
@@ -553,6 +554,24 @@ static void kimage_free_entry(kimage_entry_t entry)
kimage_free_pages(page);
}
+static void kimage_free_cma(struct kimage *image)
+{
+ unsigned long i;
+
+ for (i = 0; i < image->nr_segments; i++) {
+ struct page *cma = image->segment_cma[i];
+ u32 nr_pages = image->segment[i].memsz >> PAGE_SHIFT;
+
+ if (!cma)
+ continue;
+
+ arch_kexec_pre_free_pages(page_address(cma), nr_pages);
+ dma_release_from_contiguous(NULL, cma, nr_pages);
+ image->segment_cma[i] = NULL;
+ }
+
+}
+
void kimage_free(struct kimage *image)
{
kimage_entry_t *ptr, entry;
@@ -591,6 +610,9 @@ void kimage_free(struct kimage *image)
/* Free the kexec control pages... */
kimage_free_page_list(&image->control_pages);
+ /* Free CMA allocations */
+ kimage_free_cma(image);
+
/*
* Free up any temporary buffers allocated. This might hit if
* error occurred much later after buffer allocation.
@@ -716,9 +738,69 @@ static struct page *kimage_alloc_page(struct kimage *image,
return page;
}
-static int kimage_load_normal_segment(struct kimage *image,
- struct kexec_segment *segment)
+static int kimage_load_cma_segment(struct kimage *image, int idx)
+{
+ struct kexec_segment *segment = &image->segment[idx];
+ struct page *cma = image->segment_cma[idx];
+ char *ptr = page_address(cma);
+ unsigned long maddr;
+ size_t ubytes, mbytes;
+ int result = 0;
+ unsigned char __user *buf = NULL;
+ unsigned char *kbuf = NULL;
+
+ if (image->file_mode)
+ kbuf = segment->kbuf;
+ else
+ buf = segment->buf;
+ ubytes = segment->bufsz;
+ mbytes = segment->memsz;
+ maddr = segment->mem;
+
+ /* Then copy from source buffer to the CMA one */
+ while (mbytes) {
+ size_t uchunk, mchunk;
+
+ ptr += maddr & ~PAGE_MASK;
+ mchunk = min_t(size_t, mbytes,
+ PAGE_SIZE - (maddr & ~PAGE_MASK));
+ uchunk = min(ubytes, mchunk);
+
+ if (uchunk) {
+ /* For file based kexec, source pages are in kernel memory */
+ if (image->file_mode)
+ memcpy(ptr, kbuf, uchunk);
+ else
+ result = copy_from_user(ptr, buf, uchunk);
+ ubytes -= uchunk;
+ if (image->file_mode)
+ kbuf += uchunk;
+ else
+ buf += uchunk;
+ }
+
+ if (result) {
+ result = -EFAULT;
+ goto out;
+ }
+
+ ptr += mchunk;
+ maddr += mchunk;
+ mbytes -= mchunk;
+
+ cond_resched();
+ }
+
+ /* Clear any remainder */
+ memset(ptr, 0, mbytes);
+
+out:
+ return result;
+}
+
+static int kimage_load_normal_segment(struct kimage *image, int idx)
{
+ struct kexec_segment *segment = &image->segment[idx];
unsigned long maddr;
size_t ubytes, mbytes;
int result;
@@ -733,6 +815,9 @@ static int kimage_load_normal_segment(struct kimage *image,
mbytes = segment->memsz;
maddr = segment->mem;
+ if (image->segment_cma[idx])
+ return kimage_load_cma_segment(image, idx);
+
result = kimage_set_destination(image, maddr);
if (result < 0)
goto out;
@@ -787,13 +872,13 @@ out:
}
#ifdef CONFIG_CRASH_DUMP
-static int kimage_load_crash_segment(struct kimage *image,
- struct kexec_segment *segment)
+static int kimage_load_crash_segment(struct kimage *image, int idx)
{
/* For crash dumps kernels we simply copy the data from
* user space to it's destination.
* We do things a page at a time for the sake of kmap.
*/
+ struct kexec_segment *segment = &image->segment[idx];
unsigned long maddr;
size_t ubytes, mbytes;
int result;
@@ -858,18 +943,17 @@ out:
}
#endif
-int kimage_load_segment(struct kimage *image,
- struct kexec_segment *segment)
+int kimage_load_segment(struct kimage *image, int idx)
{
int result = -ENOMEM;
switch (image->type) {
case KEXEC_TYPE_DEFAULT:
- result = kimage_load_normal_segment(image, segment);
+ result = kimage_load_normal_segment(image, idx);
break;
#ifdef CONFIG_CRASH_DUMP
case KEXEC_TYPE_CRASH:
- result = kimage_load_crash_segment(image, segment);
+ result = kimage_load_crash_segment(image, idx);
break;
#endif
}
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index b835033c65eb..91d46502a817 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -26,6 +26,7 @@
#include <linux/kernel_read_file.h>
#include <linux/syscalls.h>
#include <linux/vmalloc.h>
+#include <linux/dma-map-ops.h>
#include "kexec_internal.h"
#ifdef CONFIG_KEXEC_SIG
@@ -253,6 +254,8 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
ret = 0;
}
+ image->no_cma = !!(flags & KEXEC_FILE_NO_CMA);
+
if (cmdline_len) {
image->cmdline_buf = memdup_user(cmdline_ptr, cmdline_len);
if (IS_ERR(image->cmdline_buf)) {
@@ -434,7 +437,7 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd,
i, ksegment->buf, ksegment->bufsz, ksegment->mem,
ksegment->memsz);
- ret = kimage_load_segment(image, &image->segment[i]);
+ ret = kimage_load_segment(image, i);
if (ret)
goto out;
}
@@ -663,6 +666,43 @@ static int kexec_walk_resources(struct kexec_buf *kbuf,
return walk_system_ram_res(0, ULONG_MAX, kbuf, func);
}
+static int kexec_alloc_contig(struct kexec_buf *kbuf)
+{
+ size_t nr_pages = kbuf->memsz >> PAGE_SHIFT;
+ unsigned long mem;
+ struct page *p;
+
+ /* User space disabled CMA allocations, bail out. */
+ if (kbuf->image->no_cma)
+ return -EPERM;
+
+ /* Skip CMA logic for crash kernel */
+ if (kbuf->image->type == KEXEC_TYPE_CRASH)
+ return -EPERM;
+
+ p = dma_alloc_from_contiguous(NULL, nr_pages, get_order(kbuf->buf_align), true);
+ if (!p)
+ return -ENOMEM;
+
+ pr_debug("allocated %zu DMA pages at 0x%lx", nr_pages, page_to_boot_pfn(p));
+
+ mem = page_to_boot_pfn(p) << PAGE_SHIFT;
+
+ if (kimage_is_destination_range(kbuf->image, mem, mem + kbuf->memsz)) {
+ /* Our region is already in use by a statically defined one. Bail out. */
+ pr_debug("CMA overlaps existing mem: 0x%lx+0x%lx\n", mem, kbuf->memsz);
+ dma_release_from_contiguous(NULL, p, nr_pages);
+ return -EBUSY;
+ }
+
+ kbuf->mem = page_to_boot_pfn(p) << PAGE_SHIFT;
+ kbuf->cma = p;
+
+ arch_kexec_post_alloc_pages(page_address(p), (int)nr_pages, 0);
+
+ return 0;
+}
+
/**
* kexec_locate_mem_hole - find free memory for the purgatory or the next kernel
* @kbuf: Parameters for the memory search.
@@ -687,6 +727,13 @@ int kexec_locate_mem_hole(struct kexec_buf *kbuf)
if (ret <= 0)
return ret;
+ /*
+ * Try to find a free physically contiguous block of memory first. With that, we
+ * can avoid any copying at kexec time.
+ */
+ if (!kexec_alloc_contig(kbuf))
+ return 0;
+
if (!IS_ENABLED(CONFIG_ARCH_KEEP_MEMBLOCK))
ret = kexec_walk_resources(kbuf, locate_mem_hole_callback);
else
@@ -732,6 +779,7 @@ int kexec_add_buffer(struct kexec_buf *kbuf)
/* Ensure minimum alignment needed for segments. */
kbuf->memsz = ALIGN(kbuf->memsz, PAGE_SIZE);
kbuf->buf_align = max(kbuf->buf_align, PAGE_SIZE);
+ kbuf->cma = NULL;
/* Walk the RAM ranges and allocate a suitable range for the buffer */
ret = arch_kexec_locate_mem_hole(kbuf);
@@ -744,6 +792,7 @@ int kexec_add_buffer(struct kexec_buf *kbuf)
ksegment->bufsz = kbuf->bufsz;
ksegment->mem = kbuf->mem;
ksegment->memsz = kbuf->memsz;
+ kbuf->image->segment_cma[kbuf->image->nr_segments] = kbuf->cma;
kbuf->image->nr_segments++;
return 0;
}
diff --git a/kernel/kexec_internal.h b/kernel/kexec_internal.h
index 30a733a55a67..228bb88c018b 100644
--- a/kernel/kexec_internal.h
+++ b/kernel/kexec_internal.h
@@ -10,7 +10,7 @@ struct kimage *do_kimage_alloc_init(void);
int sanity_check_segment_list(struct kimage *image);
void kimage_free_page_list(struct list_head *list);
void kimage_free(struct kimage *image);
-int kimage_load_segment(struct kimage *image, struct kexec_segment *segment);
+int kimage_load_segment(struct kimage *image, int idx);
void kimage_terminate(struct kimage *image);
int kimage_is_destination_range(struct kimage *image,
unsigned long start, unsigned long end);
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 85fc068f0083..0e98b228a8ef 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -88,13 +88,12 @@ static inline struct kthread *to_kthread(struct task_struct *k)
/*
* Variant of to_kthread() that doesn't assume @p is a kthread.
*
- * Per construction; when:
+ * When "(p->flags & PF_KTHREAD)" is set the task is a kthread and will
+ * always remain a kthread. For kthreads p->worker_private always
+ * points to a struct kthread. For tasks that are not kthreads
+ * p->worker_private is used to point to other things.
*
- * (p->flags & PF_KTHREAD) && p->worker_private
- *
- * the task is both a kthread and struct kthread is persistent. However
- * PF_KTHREAD on it's own is not, kernel_thread() can exec() (See umh.c and
- * begin_new_exec()).
+ * Return NULL for any task that is not a kthread.
*/
static inline struct kthread *__to_kthread(struct task_struct *p)
{
diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c
index 8572dba95af4..24df4d98f7d2 100644
--- a/kernel/locking/rwsem.c
+++ b/kernel/locking/rwsem.c
@@ -27,6 +27,7 @@
#include <linux/export.h>
#include <linux/rwsem.h>
#include <linux/atomic.h>
+#include <linux/hung_task.h>
#include <trace/events/lock.h>
#ifndef CONFIG_PREEMPT_RT
@@ -181,11 +182,11 @@ static inline void rwsem_set_reader_owned(struct rw_semaphore *sem)
__rwsem_set_reader_owned(sem, current);
}
-#ifdef CONFIG_DEBUG_RWSEMS
+#if defined(CONFIG_DEBUG_RWSEMS) || defined(CONFIG_DETECT_HUNG_TASK_BLOCKER)
/*
* Return just the real task structure pointer of the owner
*/
-static inline struct task_struct *rwsem_owner(struct rw_semaphore *sem)
+struct task_struct *rwsem_owner(struct rw_semaphore *sem)
{
return (struct task_struct *)
(atomic_long_read(&sem->owner) & ~RWSEM_OWNER_FLAGS_MASK);
@@ -194,7 +195,7 @@ static inline struct task_struct *rwsem_owner(struct rw_semaphore *sem)
/*
* Return true if the rwsem is owned by a reader.
*/
-static inline bool is_rwsem_reader_owned(struct rw_semaphore *sem)
+bool is_rwsem_reader_owned(struct rw_semaphore *sem)
{
/*
* Check the count to see if it is write-locked.
@@ -207,10 +208,10 @@ static inline bool is_rwsem_reader_owned(struct rw_semaphore *sem)
}
/*
- * With CONFIG_DEBUG_RWSEMS configured, it will make sure that if there
- * is a task pointer in owner of a reader-owned rwsem, it will be the
- * real owner or one of the real owners. The only exception is when the
- * unlock is done by up_read_non_owner().
+ * With CONFIG_DEBUG_RWSEMS or CONFIG_DETECT_HUNG_TASK_BLOCKER configured,
+ * it will make sure that the owner field of a reader-owned rwsem either
+ * points to a real reader-owner(s) or gets cleared. The only exception is
+ * when the unlock is done by up_read_non_owner().
*/
static inline void rwsem_clear_reader_owned(struct rw_semaphore *sem)
{
@@ -1063,10 +1064,13 @@ queue:
wake_up_q(&wake_q);
trace_contention_begin(sem, LCB_F_READ);
+ set_current_state(state);
+
+ if (state == TASK_UNINTERRUPTIBLE)
+ hung_task_set_blocker(sem, BLOCKER_TYPE_RWSEM_READER);
/* wait to be given the lock */
for (;;) {
- set_current_state(state);
if (!smp_load_acquire(&waiter.task)) {
/* Matches rwsem_mark_wake()'s smp_store_release(). */
break;
@@ -1081,8 +1085,12 @@ queue:
}
schedule_preempt_disabled();
lockevent_inc(rwsem_sleep_reader);
+ set_current_state(state);
}
+ if (state == TASK_UNINTERRUPTIBLE)
+ hung_task_clear_blocker();
+
__set_current_state(TASK_RUNNING);
lockevent_inc(rwsem_rlock);
trace_contention_end(sem, 0);
@@ -1144,6 +1152,9 @@ rwsem_down_write_slowpath(struct rw_semaphore *sem, int state)
set_current_state(state);
trace_contention_begin(sem, LCB_F_WRITE);
+ if (state == TASK_UNINTERRUPTIBLE)
+ hung_task_set_blocker(sem, BLOCKER_TYPE_RWSEM_WRITER);
+
for (;;) {
if (rwsem_try_write_lock(sem, &waiter)) {
/* rwsem_try_write_lock() implies ACQUIRE on success */
@@ -1177,6 +1188,10 @@ rwsem_down_write_slowpath(struct rw_semaphore *sem, int state)
trylock_again:
raw_spin_lock_irq(&sem->wait_lock);
}
+
+ if (state == TASK_UNINTERRUPTIBLE)
+ hung_task_clear_blocker();
+
__set_current_state(TASK_RUNNING);
raw_spin_unlock_irq(&sem->wait_lock);
lockevent_inc(rwsem_wlock);
diff --git a/kernel/module/internal.h b/kernel/module/internal.h
index 51ddd8866ef3..618202578b42 100644
--- a/kernel/module/internal.h
+++ b/kernel/module/internal.h
@@ -112,6 +112,13 @@ struct find_symbol_arg {
enum mod_license license;
};
+/* modules using other modules */
+struct module_use {
+ struct list_head source_list;
+ struct list_head target_list;
+ struct module *source, *target;
+};
+
int mod_verify_sig(const void *mod, struct load_info *info);
int try_to_force_load(struct module *mod, const char *reason);
bool find_symbol(struct find_symbol_arg *fsa);
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 81f9df8859dc..7f8bb51aedd4 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -608,7 +608,7 @@ MODINFO_ATTR(version);
MODINFO_ATTR(srcversion);
static struct {
- char name[MODULE_NAME_LEN + 1];
+ char name[MODULE_NAME_LEN];
char taints[MODULE_FLAGS_BUF_SIZE];
} last_unloaded_module;
@@ -779,14 +779,16 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
struct module *mod;
char name[MODULE_NAME_LEN];
char buf[MODULE_FLAGS_BUF_SIZE];
- int ret, forced = 0;
+ int ret, len, forced = 0;
if (!capable(CAP_SYS_MODULE) || modules_disabled)
return -EPERM;
- if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0)
- return -EFAULT;
- name[MODULE_NAME_LEN-1] = '\0';
+ len = strncpy_from_user(name, name_user, MODULE_NAME_LEN);
+ if (len == 0 || len == MODULE_NAME_LEN)
+ return -ENOENT;
+ if (len < 0)
+ return len;
audit_log_kern_module(name);
diff --git a/kernel/panic.c b/kernel/panic.c
index 43817111c979..72fcbb5a071b 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -36,6 +36,7 @@
#include <linux/sysfs.h>
#include <linux/context_tracking.h>
#include <linux/seq_buf.h>
+#include <linux/sys_info.h>
#include <trace/events/error_report.h>
#include <asm/sections.h>
@@ -63,20 +64,13 @@ int panic_on_warn __read_mostly;
unsigned long panic_on_taint;
bool panic_on_taint_nousertaint = false;
static unsigned int warn_limit __read_mostly;
+static bool panic_console_replay;
bool panic_triggering_all_cpu_backtrace;
int panic_timeout = CONFIG_PANIC_TIMEOUT;
EXPORT_SYMBOL_GPL(panic_timeout);
-#define PANIC_PRINT_TASK_INFO 0x00000001
-#define PANIC_PRINT_MEM_INFO 0x00000002
-#define PANIC_PRINT_TIMER_INFO 0x00000004
-#define PANIC_PRINT_LOCK_INFO 0x00000008
-#define PANIC_PRINT_FTRACE_INFO 0x00000010
-#define PANIC_PRINT_ALL_PRINTK_MSG 0x00000020
-#define PANIC_PRINT_ALL_CPU_BT 0x00000040
-#define PANIC_PRINT_BLOCKED_TASKS 0x00000080
unsigned long panic_print;
ATOMIC_NOTIFIER_HEAD(panic_notifier_list);
@@ -128,6 +122,13 @@ static int proc_taint(const struct ctl_table *table, int write,
return err;
}
+static int sysctl_panic_print_handler(const struct ctl_table *table, int write,
+ void *buffer, size_t *lenp, loff_t *ppos)
+{
+ pr_info_once("Kernel: 'panic_print' sysctl interface will be obsoleted by both 'panic_sys_info' and 'panic_console_replay'\n");
+ return proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
+}
+
static const struct ctl_table kern_panic_table[] = {
#ifdef CONFIG_SMP
{
@@ -165,7 +166,7 @@ static const struct ctl_table kern_panic_table[] = {
.data = &panic_print,
.maxlen = sizeof(unsigned long),
.mode = 0644,
- .proc_handler = proc_doulongvec_minmax,
+ .proc_handler = sysctl_panic_print_handler,
},
{
.procname = "panic_on_warn",
@@ -193,6 +194,13 @@ static const struct ctl_table kern_panic_table[] = {
.proc_handler = proc_dointvec,
},
#endif
+ {
+ .procname = "panic_sys_info",
+ .data = &panic_print,
+ .maxlen = sizeof(panic_print),
+ .mode = 0644,
+ .proc_handler = sysctl_sys_info_handler,
+ },
};
static __init int kernel_panic_sysctls_init(void)
@@ -203,6 +211,15 @@ static __init int kernel_panic_sysctls_init(void)
late_initcall(kernel_panic_sysctls_init);
#endif
+/* The format is "panic_sys_info=tasks,mem,locks,ftrace,..." */
+static int __init setup_panic_sys_info(char *buf)
+{
+ /* There is no risk of race in kernel boot phase */
+ panic_print = sys_info_parse_param(buf);
+ return 1;
+}
+__setup("panic_sys_info=", setup_panic_sys_info);
+
static atomic_t warn_count = ATOMIC_INIT(0);
#ifdef CONFIG_SYSFS
@@ -298,33 +315,6 @@ void nmi_panic(struct pt_regs *regs, const char *msg)
}
EXPORT_SYMBOL(nmi_panic);
-static void panic_print_sys_info(bool console_flush)
-{
- if (console_flush) {
- if (panic_print & PANIC_PRINT_ALL_PRINTK_MSG)
- console_flush_on_panic(CONSOLE_REPLAY_ALL);
- return;
- }
-
- if (panic_print & PANIC_PRINT_TASK_INFO)
- show_state();
-
- if (panic_print & PANIC_PRINT_MEM_INFO)
- show_mem();
-
- if (panic_print & PANIC_PRINT_TIMER_INFO)
- sysrq_timer_list_show();
-
- if (panic_print & PANIC_PRINT_LOCK_INFO)
- debug_show_all_locks();
-
- if (panic_print & PANIC_PRINT_FTRACE_INFO)
- ftrace_dump(DUMP_ALL);
-
- if (panic_print & PANIC_PRINT_BLOCKED_TASKS)
- show_state_filter(TASK_UNINTERRUPTIBLE);
-}
-
void check_panic_on_warn(const char *origin)
{
unsigned int limit;
@@ -345,7 +335,7 @@ void check_panic_on_warn(const char *origin)
*/
static void panic_other_cpus_shutdown(bool crash_kexec)
{
- if (panic_print & PANIC_PRINT_ALL_CPU_BT) {
+ if (panic_print & SYS_INFO_ALL_CPU_BT) {
/* Temporary allow non-panic CPUs to write their backtraces. */
panic_triggering_all_cpu_backtrace = true;
trigger_all_cpu_backtrace();
@@ -468,7 +458,7 @@ void vpanic(const char *fmt, va_list args)
*/
atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
- panic_print_sys_info(false);
+ sys_info(panic_print);
kmsg_dump_desc(KMSG_DUMP_PANIC, buf);
@@ -497,7 +487,9 @@ void vpanic(const char *fmt, va_list args)
debug_locks_off();
console_flush_on_panic(CONSOLE_FLUSH_PENDING);
- panic_print_sys_info(true);
+ if ((panic_print & SYS_INFO_PANIC_CONSOLE_REPLAY) ||
+ panic_console_replay)
+ console_flush_on_panic(CONSOLE_REPLAY_ALL);
if (!panic_blink)
panic_blink = no_blink;
@@ -949,6 +941,7 @@ core_param(panic_print, panic_print, ulong, 0644);
core_param(pause_on_oops, pause_on_oops, int, 0644);
core_param(panic_on_warn, panic_on_warn, int, 0644);
core_param(crash_kexec_post_notifiers, crash_kexec_post_notifiers, bool, 0644);
+core_param(panic_console_replay, panic_console_replay, bool, 0644);
static int __init oops_setup(char *s)
{
diff --git a/kernel/relay.c b/kernel/relay.c
index c0c93a04d4ce..8d915fe98198 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -118,7 +118,7 @@ static void *relay_alloc_buf(struct rchan_buf *buf, size_t *size)
return NULL;
for (i = 0; i < n_pages; i++) {
- buf->page_array[i] = alloc_page(GFP_KERNEL);
+ buf->page_array[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (unlikely(!buf->page_array[i]))
goto depopulate;
set_page_private(buf->page_array[i], (unsigned long)buf);
@@ -127,7 +127,6 @@ static void *relay_alloc_buf(struct rchan_buf *buf, size_t *size)
if (!mem)
goto depopulate;
- memset(mem, 0, *size);
buf->page_count = n_pages;
return mem;
@@ -250,13 +249,18 @@ EXPORT_SYMBOL_GPL(relay_buf_full);
*/
static int relay_subbuf_start(struct rchan_buf *buf, void *subbuf,
- void *prev_subbuf, size_t prev_padding)
+ void *prev_subbuf)
{
+ int full = relay_buf_full(buf);
+
+ if (full)
+ buf->stats.full_count++;
+
if (!buf->chan->cb->subbuf_start)
- return !relay_buf_full(buf);
+ return !full;
return buf->chan->cb->subbuf_start(buf, subbuf,
- prev_subbuf, prev_padding);
+ prev_subbuf);
}
/**
@@ -298,11 +302,13 @@ static void __relay_reset(struct rchan_buf *buf, unsigned int init)
buf->finalized = 0;
buf->data = buf->start;
buf->offset = 0;
+ buf->stats.full_count = 0;
+ buf->stats.big_count = 0;
for (i = 0; i < buf->chan->n_subbufs; i++)
buf->padding[i] = 0;
- relay_subbuf_start(buf, buf->data, NULL, 0);
+ relay_subbuf_start(buf, buf->data, NULL);
}
/**
@@ -555,9 +561,11 @@ size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length)
goto toobig;
if (buf->offset != buf->chan->subbuf_size + 1) {
- buf->prev_padding = buf->chan->subbuf_size - buf->offset;
+ size_t prev_padding;
+
+ prev_padding = buf->chan->subbuf_size - buf->offset;
old_subbuf = buf->subbufs_produced % buf->chan->n_subbufs;
- buf->padding[old_subbuf] = buf->prev_padding;
+ buf->padding[old_subbuf] = prev_padding;
buf->subbufs_produced++;
if (buf->dentry)
d_inode(buf->dentry)->i_size +=
@@ -582,7 +590,7 @@ size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length)
new_subbuf = buf->subbufs_produced % buf->chan->n_subbufs;
new = buf->start + new_subbuf * buf->chan->subbuf_size;
buf->offset = 0;
- if (!relay_subbuf_start(buf, new, old, buf->prev_padding)) {
+ if (!relay_subbuf_start(buf, new, old)) {
buf->offset = buf->chan->subbuf_size + 1;
return 0;
}
@@ -595,7 +603,7 @@ size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length)
return length;
toobig:
- buf->chan->last_toobig = length;
+ buf->stats.big_count++;
return 0;
}
EXPORT_SYMBOL_GPL(relay_switch_subbuf);
@@ -655,11 +663,6 @@ void relay_close(struct rchan *chan)
if ((buf = *per_cpu_ptr(chan->buf, i)))
relay_close_buf(buf);
- if (chan->last_toobig)
- printk(KERN_WARNING "relay: one or more items not logged "
- "[item size (%zd) > sub-buffer size (%zd)]\n",
- chan->last_toobig, chan->subbuf_size);
-
list_del(&chan->list);
kref_put(&chan->kref, relay_destroy_channel);
mutex_unlock(&relay_channels_mutex);
@@ -694,6 +697,42 @@ void relay_flush(struct rchan *chan)
EXPORT_SYMBOL_GPL(relay_flush);
/**
+ * relay_stats - get channel buffer statistics
+ * @chan: the channel
+ * @flags: select particular information to get
+ *
+ * Returns the count of certain field that caller specifies.
+ */
+size_t relay_stats(struct rchan *chan, int flags)
+{
+ unsigned int i, count = 0;
+ struct rchan_buf *rbuf;
+
+ if (!chan || flags > RELAY_STATS_LAST)
+ return 0;
+
+ if (chan->is_global) {
+ rbuf = *per_cpu_ptr(chan->buf, 0);
+ if (flags & RELAY_STATS_BUF_FULL)
+ count = rbuf->stats.full_count;
+ else if (flags & RELAY_STATS_WRT_BIG)
+ count = rbuf->stats.big_count;
+ } else {
+ for_each_online_cpu(i) {
+ rbuf = *per_cpu_ptr(chan->buf, i);
+ if (rbuf) {
+ if (flags & RELAY_STATS_BUF_FULL)
+ count += rbuf->stats.full_count;
+ else if (flags & RELAY_STATS_WRT_BIG)
+ count += rbuf->stats.big_count;
+ }
+ }
+ }
+
+ return count;
+}
+
+/**
* relay_file_open - open file op for relay files
* @inode: the inode
* @filp: the file
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
index 47168d2afbf1..6941145b5058 100644
--- a/kernel/trace/blktrace.c
+++ b/kernel/trace/blktrace.c
@@ -415,9 +415,10 @@ static ssize_t blk_dropped_read(struct file *filp, char __user *buffer,
size_t count, loff_t *ppos)
{
struct blk_trace *bt = filp->private_data;
+ size_t dropped = relay_stats(bt->rchan, RELAY_STATS_BUF_FULL);
char buf[16];
- snprintf(buf, sizeof(buf), "%u\n", atomic_read(&bt->dropped));
+ snprintf(buf, sizeof(buf), "%zu\n", dropped);
return simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
}
@@ -456,23 +457,6 @@ static const struct file_operations blk_msg_fops = {
.llseek = noop_llseek,
};
-/*
- * Keep track of how many times we encountered a full subbuffer, to aid
- * the user space app in telling how many lost events there were.
- */
-static int blk_subbuf_start_callback(struct rchan_buf *buf, void *subbuf,
- void *prev_subbuf, size_t prev_padding)
-{
- struct blk_trace *bt;
-
- if (!relay_buf_full(buf))
- return 1;
-
- bt = buf->chan->private_data;
- atomic_inc(&bt->dropped);
- return 0;
-}
-
static int blk_remove_buf_file_callback(struct dentry *dentry)
{
debugfs_remove(dentry);
@@ -491,7 +475,6 @@ static struct dentry *blk_create_buf_file_callback(const char *filename,
}
static const struct rchan_callbacks blk_relay_callbacks = {
- .subbuf_start = blk_subbuf_start_callback,
.create_buf_file = blk_create_buf_file_callback,
.remove_buf_file = blk_remove_buf_file_callback,
};
@@ -580,7 +563,6 @@ static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
}
bt->dev = dev;
- atomic_set(&bt->dropped, 0);
INIT_LIST_HEAD(&bt->running_list);
ret = -EIO;
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 5176e0270f07..bb71a0dc9d69 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -4812,26 +4812,26 @@ int ring_buffer_write(struct trace_buffer *buffer,
int ret = -EBUSY;
int cpu;
- preempt_disable_notrace();
+ guard(preempt_notrace)();
if (atomic_read(&buffer->record_disabled))
- goto out;
+ return -EBUSY;
cpu = raw_smp_processor_id();
if (!cpumask_test_cpu(cpu, buffer->cpumask))
- goto out;
+ return -EBUSY;
cpu_buffer = buffer->buffers[cpu];
if (atomic_read(&cpu_buffer->record_disabled))
- goto out;
+ return -EBUSY;
if (length > buffer->max_data_size)
- goto out;
+ return -EBUSY;
if (unlikely(trace_recursive_lock(cpu_buffer)))
- goto out;
+ return -EBUSY;
event = rb_reserve_next_event(buffer, cpu_buffer, length);
if (!event)
@@ -4849,10 +4849,6 @@ int ring_buffer_write(struct trace_buffer *buffer,
out_unlock:
trace_recursive_unlock(cpu_buffer);
-
- out:
- preempt_enable_notrace();
-
return ret;
}
EXPORT_SYMBOL_GPL(ring_buffer_write);
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index b9716178f728..4283ed4e8f59 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -432,15 +432,13 @@ static void ftrace_exports(struct ring_buffer_event *event, int flag)
{
struct trace_export *export;
- preempt_disable_notrace();
+ guard(preempt_notrace)();
export = rcu_dereference_raw_check(ftrace_exports_list);
while (export) {
trace_process_export(export, event, flag);
export = rcu_dereference_raw_check(export->next);
}
-
- preempt_enable_notrace();
}
static inline void
@@ -497,27 +495,18 @@ int register_ftrace_export(struct trace_export *export)
if (WARN_ON_ONCE(!export->write))
return -1;
- mutex_lock(&ftrace_export_lock);
+ guard(mutex)(&ftrace_export_lock);
add_ftrace_export(&ftrace_exports_list, export);
- mutex_unlock(&ftrace_export_lock);
-
return 0;
}
EXPORT_SYMBOL_GPL(register_ftrace_export);
int unregister_ftrace_export(struct trace_export *export)
{
- int ret;
-
- mutex_lock(&ftrace_export_lock);
-
- ret = rm_ftrace_export(&ftrace_exports_list, export);
-
- mutex_unlock(&ftrace_export_lock);
-
- return ret;
+ guard(mutex)(&ftrace_export_lock);
+ return rm_ftrace_export(&ftrace_exports_list, export);
}
EXPORT_SYMBOL_GPL(unregister_ftrace_export);
@@ -640,9 +629,8 @@ void trace_array_put(struct trace_array *this_tr)
if (!this_tr)
return;
- mutex_lock(&trace_types_lock);
+ guard(mutex)(&trace_types_lock);
__trace_array_put(this_tr);
- mutex_unlock(&trace_types_lock);
}
EXPORT_SYMBOL_GPL(trace_array_put);
@@ -1160,13 +1148,11 @@ int __trace_array_puts(struct trace_array *tr, unsigned long ip,
trace_ctx = tracing_gen_ctx();
buffer = tr->array_buffer.buffer;
- ring_buffer_nest_start(buffer);
+ guard(ring_buffer_nest)(buffer);
event = __trace_buffer_lock_reserve(buffer, TRACE_PRINT, alloc,
trace_ctx);
- if (!event) {
- size = 0;
- goto out;
- }
+ if (!event)
+ return 0;
entry = ring_buffer_event_data(event);
entry->ip = ip;
@@ -1182,8 +1168,6 @@ int __trace_array_puts(struct trace_array *tr, unsigned long ip,
__buffer_unlock_commit(buffer, event);
ftrace_trace_stack(tr, buffer, trace_ctx, 4, NULL);
- out:
- ring_buffer_nest_end(buffer);
return size;
}
EXPORT_SYMBOL_GPL(__trace_array_puts);
@@ -1213,7 +1197,6 @@ int __trace_bputs(unsigned long ip, const char *str)
struct bputs_entry *entry;
unsigned int trace_ctx;
int size = sizeof(struct bputs_entry);
- int ret = 0;
if (!printk_binsafe(tr))
return __trace_puts(ip, str, strlen(str));
@@ -1227,11 +1210,11 @@ int __trace_bputs(unsigned long ip, const char *str)
trace_ctx = tracing_gen_ctx();
buffer = tr->array_buffer.buffer;
- ring_buffer_nest_start(buffer);
+ guard(ring_buffer_nest)(buffer);
event = __trace_buffer_lock_reserve(buffer, TRACE_BPUTS, size,
trace_ctx);
if (!event)
- goto out;
+ return 0;
entry = ring_buffer_event_data(event);
entry->ip = ip;
@@ -1240,10 +1223,7 @@ int __trace_bputs(unsigned long ip, const char *str)
__buffer_unlock_commit(buffer, event);
ftrace_trace_stack(tr, buffer, trace_ctx, 4, NULL);
- ret = 1;
- out:
- ring_buffer_nest_end(buffer);
- return ret;
+ return 1;
}
EXPORT_SYMBOL_GPL(__trace_bputs);
@@ -1432,13 +1412,8 @@ static int tracing_arm_snapshot_locked(struct trace_array *tr)
int tracing_arm_snapshot(struct trace_array *tr)
{
- int ret;
-
- mutex_lock(&trace_types_lock);
- ret = tracing_arm_snapshot_locked(tr);
- mutex_unlock(&trace_types_lock);
-
- return ret;
+ guard(mutex)(&trace_types_lock);
+ return tracing_arm_snapshot_locked(tr);
}
void tracing_disarm_snapshot(struct trace_array *tr)
@@ -1841,7 +1816,7 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
ret = get_user(ch, ubuf++);
if (ret)
- goto out;
+ return ret;
read++;
cnt--;
@@ -1855,7 +1830,7 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
while (cnt && isspace(ch)) {
ret = get_user(ch, ubuf++);
if (ret)
- goto out;
+ return ret;
read++;
cnt--;
}
@@ -1865,8 +1840,7 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
/* only spaces were written */
if (isspace(ch) || !ch) {
*ppos += read;
- ret = read;
- goto out;
+ return read;
}
}
@@ -1874,13 +1848,12 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
while (cnt && !isspace(ch) && ch) {
if (parser->idx < parser->size - 1)
parser->buffer[parser->idx++] = ch;
- else {
- ret = -EINVAL;
- goto out;
- }
+ else
+ return -EINVAL;
+
ret = get_user(ch, ubuf++);
if (ret)
- goto out;
+ return ret;
read++;
cnt--;
}
@@ -1895,15 +1868,11 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
/* Make sure the parsed string always terminates with '\0'. */
parser->buffer[parser->idx] = 0;
} else {
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
*ppos += read;
- ret = read;
-
-out:
- return ret;
+ return read;
}
/* TODO add a seq_buf_to_buffer() */
@@ -2405,10 +2374,10 @@ int __init register_tracer(struct tracer *type)
mutex_unlock(&trace_types_lock);
if (ret || !default_bootup_tracer)
- goto out_unlock;
+ return ret;
if (strncmp(default_bootup_tracer, type->name, MAX_TRACER_SIZE))
- goto out_unlock;
+ return 0;
printk(KERN_INFO "Starting tracer '%s'\n", type->name);
/* Do we want this tracer to start on bootup? */
@@ -2420,8 +2389,7 @@ int __init register_tracer(struct tracer *type)
/* disable other selftests, since this will break it. */
disable_tracing_selftest("running a tracer");
- out_unlock:
- return ret;
+ return 0;
}
static void tracing_reset_cpu(struct array_buffer *buf, int cpu)
@@ -2498,9 +2466,8 @@ void tracing_reset_all_online_cpus_unlocked(void)
void tracing_reset_all_online_cpus(void)
{
- mutex_lock(&trace_types_lock);
+ guard(mutex)(&trace_types_lock);
tracing_reset_all_online_cpus_unlocked();
- mutex_unlock(&trace_types_lock);
}
int is_tracing_stopped(void)
@@ -2511,18 +2478,17 @@ int is_tracing_stopped(void)
static void tracing_start_tr(struct trace_array *tr)
{
struct trace_buffer *buffer;
- unsigned long flags;
if (tracing_disabled)
return;
- raw_spin_lock_irqsave(&tr->start_lock, flags);
+ guard(raw_spinlock_irqsave)(&tr->start_lock);
if (--tr->stop_count) {
if (WARN_ON_ONCE(tr->stop_count < 0)) {
/* Someone screwed up their debugging */
tr->stop_count = 0;
}
- goto out;
+ return;
}
/* Prevent the buffers from switching */
@@ -2539,9 +2505,6 @@ static void tracing_start_tr(struct trace_array *tr)
#endif
arch_spin_unlock(&tr->max_lock);
-
- out:
- raw_spin_unlock_irqrestore(&tr->start_lock, flags);
}
/**
@@ -2559,11 +2522,10 @@ void tracing_start(void)
static void tracing_stop_tr(struct trace_array *tr)
{
struct trace_buffer *buffer;
- unsigned long flags;
- raw_spin_lock_irqsave(&tr->start_lock, flags);
+ guard(raw_spinlock_irqsave)(&tr->start_lock);
if (tr->stop_count++)
- goto out;
+ return;
/* Prevent the buffers from switching */
arch_spin_lock(&tr->max_lock);
@@ -2579,9 +2541,6 @@ static void tracing_stop_tr(struct trace_array *tr)
#endif
arch_spin_unlock(&tr->max_lock);
-
- out:
- raw_spin_unlock_irqrestore(&tr->start_lock, flags);
}
/**
@@ -2694,12 +2653,12 @@ void trace_buffered_event_enable(void)
per_cpu(trace_buffered_event, cpu) = event;
- preempt_disable();
- if (cpu == smp_processor_id() &&
- __this_cpu_read(trace_buffered_event) !=
- per_cpu(trace_buffered_event, cpu))
- WARN_ON_ONCE(1);
- preempt_enable();
+ scoped_guard(preempt,) {
+ if (cpu == smp_processor_id() &&
+ __this_cpu_read(trace_buffered_event) !=
+ per_cpu(trace_buffered_event, cpu))
+ WARN_ON_ONCE(1);
+ }
}
}
@@ -3044,7 +3003,7 @@ static void __ftrace_trace_stack(struct trace_array *tr,
skip++;
#endif
- preempt_disable_notrace();
+ guard(preempt_notrace)();
stackidx = __this_cpu_inc_return(ftrace_stack_reserve) - 1;
@@ -3102,8 +3061,6 @@ static void __ftrace_trace_stack(struct trace_array *tr,
/* Again, don't let gcc optimize things here */
barrier();
__this_cpu_dec(ftrace_stack_reserve);
- preempt_enable_notrace();
-
}
static inline void ftrace_trace_stack(struct trace_array *tr,
@@ -3186,9 +3143,9 @@ ftrace_trace_userstack(struct trace_array *tr,
* prevent recursion, since the user stack tracing may
* trigger other kernel events.
*/
- preempt_disable();
+ guard(preempt)();
if (__this_cpu_read(user_stack_count))
- goto out;
+ return;
__this_cpu_inc(user_stack_count);
@@ -3206,8 +3163,6 @@ ftrace_trace_userstack(struct trace_array *tr,
out_drop_count:
__this_cpu_dec(user_stack_count);
- out:
- preempt_enable();
}
#else /* CONFIG_USER_STACKTRACE_SUPPORT */
static void ftrace_trace_userstack(struct trace_array *tr,
@@ -3389,7 +3344,7 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
pause_graph_tracing();
trace_ctx = tracing_gen_ctx();
- preempt_disable_notrace();
+ guard(preempt_notrace)();
tbuffer = get_trace_buf();
if (!tbuffer) {
@@ -3404,26 +3359,23 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
size = sizeof(*entry) + sizeof(u32) * len;
buffer = tr->array_buffer.buffer;
- ring_buffer_nest_start(buffer);
- event = __trace_buffer_lock_reserve(buffer, TRACE_BPRINT, size,
- trace_ctx);
- if (!event)
- goto out;
- entry = ring_buffer_event_data(event);
- entry->ip = ip;
- entry->fmt = fmt;
-
- memcpy(entry->buf, tbuffer, sizeof(u32) * len);
- __buffer_unlock_commit(buffer, event);
- ftrace_trace_stack(tr, buffer, trace_ctx, 6, NULL);
+ scoped_guard(ring_buffer_nest, buffer) {
+ event = __trace_buffer_lock_reserve(buffer, TRACE_BPRINT, size,
+ trace_ctx);
+ if (!event)
+ goto out_put;
+ entry = ring_buffer_event_data(event);
+ entry->ip = ip;
+ entry->fmt = fmt;
-out:
- ring_buffer_nest_end(buffer);
+ memcpy(entry->buf, tbuffer, sizeof(u32) * len);
+ __buffer_unlock_commit(buffer, event);
+ ftrace_trace_stack(tr, buffer, trace_ctx, 6, NULL);
+ }
out_put:
put_trace_buf();
out_nobuffer:
- preempt_enable_notrace();
unpause_graph_tracing();
return len;
@@ -3447,7 +3399,7 @@ int __trace_array_vprintk(struct trace_buffer *buffer,
pause_graph_tracing();
trace_ctx = tracing_gen_ctx();
- preempt_disable_notrace();
+ guard(preempt_notrace)();
tbuffer = get_trace_buf();
@@ -3459,24 +3411,22 @@ int __trace_array_vprintk(struct trace_buffer *buffer,
len = vscnprintf(tbuffer, TRACE_BUF_SIZE, fmt, args);
size = sizeof(*entry) + len + 1;
- ring_buffer_nest_start(buffer);
- event = __trace_buffer_lock_reserve(buffer, TRACE_PRINT, size,
- trace_ctx);
- if (!event)
- goto out;
- entry = ring_buffer_event_data(event);
- entry->ip = ip;
-
- memcpy(&entry->buf, tbuffer, len + 1);
- __buffer_unlock_commit(buffer, event);
- ftrace_trace_stack(printk_trace, buffer, trace_ctx, 6, NULL);
+ scoped_guard(ring_buffer_nest, buffer) {
+ event = __trace_buffer_lock_reserve(buffer, TRACE_PRINT, size,
+ trace_ctx);
+ if (!event)
+ goto out;
+ entry = ring_buffer_event_data(event);
+ entry->ip = ip;
+ memcpy(&entry->buf, tbuffer, len + 1);
+ __buffer_unlock_commit(buffer, event);
+ ftrace_trace_stack(printk_trace, buffer, trace_ctx, 6, NULL);
+ }
out:
- ring_buffer_nest_end(buffer);
put_trace_buf();
out_nobuffer:
- preempt_enable_notrace();
unpause_graph_tracing();
return len;
@@ -4800,20 +4750,16 @@ int tracing_open_file_tr(struct inode *inode, struct file *filp)
if (ret)
return ret;
- mutex_lock(&event_mutex);
+ guard(mutex)(&event_mutex);
/* Fail if the file is marked for removal */
if (file->flags & EVENT_FILE_FL_FREED) {
trace_array_put(file->tr);
- ret = -ENODEV;
+ return -ENODEV;
} else {
event_file_get(file);
}
- mutex_unlock(&event_mutex);
- if (ret)
- return ret;
-
filp->private_data = inode->i_private;
return 0;
@@ -5090,7 +5036,7 @@ tracing_cpumask_read(struct file *filp, char __user *ubuf,
size_t count, loff_t *ppos)
{
struct trace_array *tr = file_inode(filp)->i_private;
- char *mask_str;
+ char *mask_str __free(kfree) = NULL;
int len;
len = snprintf(NULL, 0, "%*pb\n",
@@ -5101,16 +5047,10 @@ tracing_cpumask_read(struct file *filp, char __user *ubuf,
len = snprintf(mask_str, len, "%*pb\n",
cpumask_pr_args(tr->tracing_cpumask));
- if (len >= count) {
- count = -EINVAL;
- goto out_err;
- }
- count = simple_read_from_buffer(ubuf, count, ppos, mask_str, len);
-
-out_err:
- kfree(mask_str);
+ if (len >= count)
+ return -EINVAL;
- return count;
+ return simple_read_from_buffer(ubuf, count, ppos, mask_str, len);
}
int tracing_set_cpumask(struct trace_array *tr,
@@ -5957,9 +5897,9 @@ tracing_set_trace_read(struct file *filp, char __user *ubuf,
char buf[MAX_TRACER_SIZE+2];
int r;
- mutex_lock(&trace_types_lock);
- r = sprintf(buf, "%s\n", tr->current_trace->name);
- mutex_unlock(&trace_types_lock);
+ scoped_guard(mutex, &trace_types_lock) {
+ r = sprintf(buf, "%s\n", tr->current_trace->name);
+ }
return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
}
@@ -6261,15 +6201,13 @@ int tracing_update_buffers(struct trace_array *tr)
{
int ret = 0;
- mutex_lock(&trace_types_lock);
+ guard(mutex)(&trace_types_lock);
update_last_data(tr);
if (!tr->ring_buffer_expanded)
ret = __tracing_resize_ring_buffer(tr, trace_buf_size,
RING_BUFFER_ALL_CPUS);
- mutex_unlock(&trace_types_lock);
-
return ret;
}
@@ -6566,7 +6504,7 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
if (ret)
return ret;
- mutex_lock(&trace_types_lock);
+ guard(mutex)(&trace_types_lock);
cpu = tracing_get_cpu(inode);
ret = open_pipe_on_cpu(tr, cpu);
if (ret)
@@ -6610,7 +6548,6 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
tr->trace_ref++;
- mutex_unlock(&trace_types_lock);
return ret;
fail:
@@ -6619,7 +6556,6 @@ fail_alloc_iter:
close_pipe_on_cpu(tr, cpu);
fail_pipe_on_cpu:
__trace_array_put(tr);
- mutex_unlock(&trace_types_lock);
return ret;
}
@@ -6628,14 +6564,13 @@ static int tracing_release_pipe(struct inode *inode, struct file *file)
struct trace_iterator *iter = file->private_data;
struct trace_array *tr = inode->i_private;
- mutex_lock(&trace_types_lock);
-
- tr->trace_ref--;
+ scoped_guard(mutex, &trace_types_lock) {
+ tr->trace_ref--;
- if (iter->trace->pipe_close)
- iter->trace->pipe_close(iter);
- close_pipe_on_cpu(tr, iter->cpu_file);
- mutex_unlock(&trace_types_lock);
+ if (iter->trace->pipe_close)
+ iter->trace->pipe_close(iter);
+ close_pipe_on_cpu(tr, iter->cpu_file);
+ }
free_trace_iter_content(iter);
kfree(iter);
@@ -7438,7 +7373,7 @@ int tracing_set_clock(struct trace_array *tr, const char *clockstr)
if (i == ARRAY_SIZE(trace_clocks))
return -EINVAL;
- mutex_lock(&trace_types_lock);
+ guard(mutex)(&trace_types_lock);
tr->clock_id = i;
@@ -7462,8 +7397,6 @@ int tracing_set_clock(struct trace_array *tr, const char *clockstr)
tscratch->clock_id = i;
}
- mutex_unlock(&trace_types_lock);
-
return 0;
}
@@ -7515,15 +7448,13 @@ static int tracing_time_stamp_mode_show(struct seq_file *m, void *v)
{
struct trace_array *tr = m->private;
- mutex_lock(&trace_types_lock);
+ guard(mutex)(&trace_types_lock);
if (ring_buffer_time_stamp_abs(tr->array_buffer.buffer))
seq_puts(m, "delta [absolute]\n");
else
seq_puts(m, "[delta] absolute\n");
- mutex_unlock(&trace_types_lock);
-
return 0;
}
@@ -8111,14 +8042,14 @@ static void clear_tracing_err_log(struct trace_array *tr)
{
struct tracing_log_err *err, *next;
- mutex_lock(&tracing_err_log_lock);
+ guard(mutex)(&tracing_err_log_lock);
+
list_for_each_entry_safe(err, next, &tr->err_log, list) {
list_del(&err->list);
free_tracing_log_err(err);
}
tr->n_err_log_entries = 0;
- mutex_unlock(&tracing_err_log_lock);
}
static void *tracing_err_log_seq_start(struct seq_file *m, loff_t *pos)
@@ -8389,7 +8320,7 @@ static int tracing_buffers_release(struct inode *inode, struct file *file)
struct ftrace_buffer_info *info = file->private_data;
struct trace_iterator *iter = &info->iter;
- mutex_lock(&trace_types_lock);
+ guard(mutex)(&trace_types_lock);
iter->tr->trace_ref--;
@@ -8400,8 +8331,6 @@ static int tracing_buffers_release(struct inode *inode, struct file *file)
info->spare_cpu, info->spare);
kvfree(info);
- mutex_unlock(&trace_types_lock);
-
return 0;
}
@@ -8609,14 +8538,13 @@ static long tracing_buffers_ioctl(struct file *file, unsigned int cmd, unsigned
* An ioctl call with cmd 0 to the ring buffer file will wake up all
* waiters
*/
- mutex_lock(&trace_types_lock);
+ guard(mutex)(&trace_types_lock);
/* Make sure the waiters see the new wait_index */
(void)atomic_fetch_inc_release(&iter->wait_index);
ring_buffer_wake_waiters(iter->array_buffer->buffer, iter->cpu_file);
- mutex_unlock(&trace_types_lock);
return 0;
}
@@ -8957,12 +8885,12 @@ ftrace_trace_snapshot_callback(struct trace_array *tr, struct ftrace_hash *hash,
out_reg:
ret = tracing_arm_snapshot(tr);
if (ret < 0)
- goto out;
+ return ret;
ret = register_ftrace_function_probe(glob, tr, ops, count);
if (ret < 0)
tracing_disarm_snapshot(tr);
- out:
+
return ret < 0 ? ret : 0;
}
@@ -9106,10 +9034,9 @@ trace_options_write(struct file *filp, const char __user *ubuf, size_t cnt,
return -EINVAL;
if (!!(topt->flags->val & topt->opt->bit) != val) {
- mutex_lock(&trace_types_lock);
+ guard(mutex)(&trace_types_lock);
ret = __set_tracer_option(topt->tr, topt->flags,
topt->opt, !val);
- mutex_unlock(&trace_types_lock);
if (ret)
return ret;
}
@@ -9418,7 +9345,7 @@ rb_simple_write(struct file *filp, const char __user *ubuf,
return ret;
if (buffer) {
- mutex_lock(&trace_types_lock);
+ guard(mutex)(&trace_types_lock);
if (!!val == tracer_tracing_is_on(tr)) {
val = 0; /* do nothing */
} else if (val) {
@@ -9432,7 +9359,6 @@ rb_simple_write(struct file *filp, const char __user *ubuf,
/* Wake up any waiters */
ring_buffer_wake_waiters(buffer, RING_BUFFER_ALL_CPUS);
}
- mutex_unlock(&trace_types_lock);
}
(*ppos)++;
@@ -9816,10 +9742,9 @@ static void __update_tracer_options(struct trace_array *tr)
static void update_tracer_options(struct trace_array *tr)
{
- mutex_lock(&trace_types_lock);
+ guard(mutex)(&trace_types_lock);
tracer_options_updated = true;
__update_tracer_options(tr);
- mutex_unlock(&trace_types_lock);
}
/* Must have trace_types_lock held */
@@ -9841,11 +9766,10 @@ struct trace_array *trace_array_find_get(const char *instance)
{
struct trace_array *tr;
- mutex_lock(&trace_types_lock);
+ guard(mutex)(&trace_types_lock);
tr = trace_array_find(instance);
if (tr)
tr->ref++;
- mutex_unlock(&trace_types_lock);
return tr;
}
@@ -10376,7 +10300,7 @@ bool module_exists(const char *module)
{
/* All modules have the symbol __this_module */
static const char this_mod[] = "__this_module";
- char modname[MAX_PARAM_PREFIX_LEN + sizeof(this_mod) + 2];
+ char modname[MODULE_NAME_LEN + sizeof(this_mod) + 2];
unsigned long val;
int n;
@@ -10803,7 +10727,8 @@ ssize_t trace_parse_run_command(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos,
int (*createfn)(const char *))
{
- char *kbuf, *buf, *tmp;
+ char *kbuf __free(kfree) = NULL;
+ char *buf, *tmp;
int ret = 0;
size_t done = 0;
size_t size;
@@ -10818,10 +10743,9 @@ ssize_t trace_parse_run_command(struct file *file, const char __user *buffer,
if (size >= WRITE_BUFSIZE)
size = WRITE_BUFSIZE - 1;
- if (copy_from_user(kbuf, buffer + done, size)) {
- ret = -EFAULT;
- goto out;
- }
+ if (copy_from_user(kbuf, buffer + done, size))
+ return -EFAULT;
+
kbuf[size] = '\0';
buf = kbuf;
do {
@@ -10837,8 +10761,7 @@ ssize_t trace_parse_run_command(struct file *file, const char __user *buffer,
/* This can accept WRITE_BUFSIZE - 2 ('\n' + '\0') */
pr_warn("Line length is too long: Should be less than %d\n",
WRITE_BUFSIZE - 2);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
}
done += size;
@@ -10851,17 +10774,12 @@ ssize_t trace_parse_run_command(struct file *file, const char __user *buffer,
ret = createfn(buf);
if (ret)
- goto out;
+ return ret;
buf += size;
} while (done < count);
}
- ret = done;
-
-out:
- kfree(kbuf);
-
- return ret;
+ return done;
}
#ifdef CONFIG_TRACER_MAX_TRACE
@@ -11064,7 +10982,7 @@ __init static int tracer_alloc_buffers(void)
BUILD_BUG_ON(TRACE_ITER_LAST_BIT > TRACE_FLAGS_MAX_SIZE);
if (!alloc_cpumask_var(&tracing_buffer_mask, GFP_KERNEL))
- goto out;
+ return -ENOMEM;
if (!alloc_cpumask_var(&global_trace.tracing_cpumask, GFP_KERNEL))
goto out_free_buffer_mask;
@@ -11182,7 +11100,6 @@ out_free_cpumask:
free_cpumask_var(global_trace.tracing_cpumask);
out_free_buffer_mask:
free_cpumask_var(tracing_buffer_mask);
-out:
return ret;
}
diff --git a/kernel/trace/trace_events_synth.c b/kernel/trace/trace_events_synth.c
index 33cfbd4ed76d..f24ee61f8884 100644
--- a/kernel/trace/trace_events_synth.c
+++ b/kernel/trace/trace_events_synth.c
@@ -536,12 +536,12 @@ static notrace void trace_event_raw_event_synth(void *__data,
* is being performed within another event.
*/
buffer = trace_file->tr->array_buffer.buffer;
- ring_buffer_nest_start(buffer);
+ guard(ring_buffer_nest)(buffer);
entry = trace_event_buffer_reserve(&fbuffer, trace_file,
sizeof(*entry) + fields_size);
if (!entry)
- goto out;
+ return;
for (i = 0, n_u64 = 0; i < event->n_fields; i++) {
val_idx = var_ref_idx[i];
@@ -584,8 +584,6 @@ static notrace void trace_event_raw_event_synth(void *__data,
}
trace_event_buffer_commit(&fbuffer);
-out:
- ring_buffer_nest_end(buffer);
}
static void free_synth_event_print_fmt(struct trace_event_call *call)
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
index 0b3db02030a7..97db0b0ccf3e 100644
--- a/kernel/trace/trace_output.c
+++ b/kernel/trace/trace_output.c
@@ -701,6 +701,7 @@ void print_function_args(struct trace_seq *s, unsigned long *args,
struct btf *btf;
s32 tid, nr = 0;
int a, p, x;
+ u16 encode;
trace_seq_printf(s, "(");
@@ -744,7 +745,12 @@ void print_function_args(struct trace_seq *s, unsigned long *args,
trace_seq_printf(s, "0x%lx", arg);
break;
case BTF_KIND_INT:
- trace_seq_printf(s, "%ld", arg);
+ encode = btf_int_encoding(t);
+ /* Print unsigned ints as hex */
+ if (encode & BTF_INT_SIGNED)
+ trace_seq_printf(s, "%ld", arg);
+ else
+ trace_seq_printf(s, "0x%lx", arg);
break;
case BTF_KIND_ENUM:
trace_seq_printf(s, "%ld", arg);
diff --git a/kernel/ucount.c b/kernel/ucount.c
index 8686e329b8f2..586af49fc03e 100644
--- a/kernel/ucount.c
+++ b/kernel/ucount.c
@@ -199,18 +199,16 @@ void put_ucounts(struct ucounts *ucounts)
}
}
-static inline bool atomic_long_inc_below(atomic_long_t *v, int u)
+static inline bool atomic_long_inc_below(atomic_long_t *v, long u)
{
- long c, old;
- c = atomic_long_read(v);
- for (;;) {
+ long c = atomic_long_read(v);
+
+ do {
if (unlikely(c >= u))
return false;
- old = atomic_long_cmpxchg(v, c, c+1);
- if (likely(old == c))
- return true;
- c = old;
- }
+ } while (!atomic_long_try_cmpxchg(v, &c, c+1));
+
+ return true;
}
struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid,
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 53332a1d8af4..dc0e0c6ed075 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -3214,6 +3214,26 @@ config TEST_OBJPOOL
If unsure, say N.
+config TEST_KEXEC_HANDOVER
+ bool "Test for Kexec HandOver"
+ default n
+ depends on KEXEC_HANDOVER
+ help
+ This option enables test for Kexec HandOver (KHO).
+ The test consists of two parts: saving kernel data before kexec and
+ restoring the data after kexec and verifying that it was properly
+ handed over. This test module creates and saves data on the boot of
+ the first kernel and restores and verifies the data on the boot of
+ kexec'ed kernel.
+
+ For detailed documentation about KHO, see Documentation/core-api/kho.
+
+ To run the test run:
+
+ tools/testing/selftests/kho/vmtest.sh -h
+
+ If unsure, say N.
+
config RATELIMIT_KUNIT_TEST
tristate "KUnit Test for correctness and stress of ratelimit" if !KUNIT_ALL_TESTS
depends on KUNIT
diff --git a/lib/Makefile b/lib/Makefile
index 06b954473222..392ff808c9b9 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -40,7 +40,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
is_single_threaded.o plist.o decompress.o kobject_uevent.o \
earlycpio.o seq_buf.o siphash.o dec_and_lock.o \
nmi_backtrace.o win_minmax.o memcat_p.o \
- buildid.o objpool.o iomem_copy.o
+ buildid.o objpool.o iomem_copy.o sys_info.o
lib-$(CONFIG_UNION_FIND) += union_find.o
lib-$(CONFIG_PRINTK) += dump_stack.o
@@ -102,6 +102,7 @@ obj-$(CONFIG_TEST_HMM) += test_hmm.o
obj-$(CONFIG_TEST_FREE_PAGES) += test_free_pages.o
obj-$(CONFIG_TEST_REF_TRACKER) += test_ref_tracker.o
obj-$(CONFIG_TEST_OBJPOOL) += test_objpool.o
+obj-$(CONFIG_TEST_KEXEC_HANDOVER) += test_kho.o
obj-$(CONFIG_TEST_FPU) += test_fpu.o
test_fpu-y := test_fpu_glue.o test_fpu_impl.o
diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index f3c6b11f12b8..d2bfa331a2b1 100644
--- a/lib/kunit/test.c
+++ b/lib/kunit/test.c
@@ -802,7 +802,6 @@ void __kunit_test_suites_exit(struct kunit_suite **suites, int num_suites)
}
EXPORT_SYMBOL_GPL(__kunit_test_suites_exit);
-#ifdef CONFIG_MODULES
static void kunit_module_init(struct module *mod)
{
struct kunit_suite_set suite_set, filtered_set;
@@ -890,7 +889,6 @@ static struct notifier_block kunit_mod_nb = {
.notifier_call = kunit_module_notify,
.priority = 0,
};
-#endif
KUNIT_DEFINE_ACTION_WRAPPER(kfree_action_wrapper, kfree, const void *)
@@ -981,20 +979,14 @@ static int __init kunit_init(void)
kunit_debugfs_init();
kunit_bus_init();
-#ifdef CONFIG_MODULES
return register_module_notifier(&kunit_mod_nb);
-#else
- return 0;
-#endif
}
late_initcall(kunit_init);
static void __exit kunit_exit(void)
{
memset(&kunit_hooks, 0, sizeof(kunit_hooks));
-#ifdef CONFIG_MODULES
unregister_module_notifier(&kunit_mod_nb);
-#endif
kunit_bus_shutdown();
diff --git a/lib/math/div64.c b/lib/math/div64.c
index 5faa29208bdb..bf77b9843175 100644
--- a/lib/math/div64.c
+++ b/lib/math/div64.c
@@ -212,12 +212,13 @@ u64 mul_u64_u64_div_u64(u64 a, u64 b, u64 c)
#endif
- /* make sure c is not zero, trigger exception otherwise */
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdiv-by-zero"
- if (unlikely(c == 0))
- return 1/0;
-#pragma GCC diagnostic pop
+ /* make sure c is not zero, trigger runtime exception otherwise */
+ if (unlikely(c == 0)) {
+ unsigned long zero = 0;
+
+ OPTIMIZER_HIDE_VAR(zero);
+ return ~0UL/zero;
+ }
int shift = __builtin_ctzll(c);
diff --git a/lib/math/gcd.c b/lib/math/gcd.c
index e3b042214d1b..62efca6787ae 100644
--- a/lib/math/gcd.c
+++ b/lib/math/gcd.c
@@ -11,22 +11,16 @@
* has decent hardware division.
*/
+DEFINE_STATIC_KEY_TRUE(efficient_ffs_key);
+
#if !defined(CONFIG_CPU_NO_EFFICIENT_FFS)
/* If __ffs is available, the even/odd algorithm benchmarks slower. */
-/**
- * gcd - calculate and return the greatest common divisor of 2 unsigned longs
- * @a: first value
- * @b: second value
- */
-unsigned long gcd(unsigned long a, unsigned long b)
+static unsigned long binary_gcd(unsigned long a, unsigned long b)
{
unsigned long r = a | b;
- if (!a || !b)
- return r;
-
b >>= __ffs(b);
if (b == 1)
return r & -r;
@@ -44,9 +38,15 @@ unsigned long gcd(unsigned long a, unsigned long b)
}
}
-#else
+#endif
/* If normalization is done by loops, the even/odd algorithm is a win. */
+
+/**
+ * gcd - calculate and return the greatest common divisor of 2 unsigned longs
+ * @a: first value
+ * @b: second value
+ */
unsigned long gcd(unsigned long a, unsigned long b)
{
unsigned long r = a | b;
@@ -54,6 +54,11 @@ unsigned long gcd(unsigned long a, unsigned long b)
if (!a || !b)
return r;
+#if !defined(CONFIG_CPU_NO_EFFICIENT_FFS)
+ if (static_branch_likely(&efficient_ffs_key))
+ return binary_gcd(a, b);
+#endif
+
/* Isolate lsbit of r */
r &= -r;
@@ -80,6 +85,4 @@ unsigned long gcd(unsigned long a, unsigned long b)
}
}
-#endif
-
EXPORT_SYMBOL_GPL(gcd);
diff --git a/lib/raid6/algos.c b/lib/raid6/algos.c
index 75ce3e134b7c..799e0e5eac26 100644
--- a/lib/raid6/algos.c
+++ b/lib/raid6/algos.c
@@ -18,9 +18,6 @@
#else
#include <linux/module.h>
#include <linux/gfp.h>
-/* In .bss so it's zeroed */
-const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256)));
-EXPORT_SYMBOL(raid6_empty_zero_page);
#endif
struct raid6_calls raid6_call;
diff --git a/lib/raid6/recov.c b/lib/raid6/recov.c
index a7c1b2bbe40d..b5e47c008b41 100644
--- a/lib/raid6/recov.c
+++ b/lib/raid6/recov.c
@@ -31,10 +31,10 @@ static void raid6_2data_recov_intx1(int disks, size_t bytes, int faila,
Use the dead data pages as temporary storage for
delta p and delta q */
dp = (u8 *)ptrs[faila];
- ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[faila] = raid6_get_zero_page();
ptrs[disks-2] = dp;
dq = (u8 *)ptrs[failb];
- ptrs[failb] = (void *)raid6_empty_zero_page;
+ ptrs[failb] = raid6_get_zero_page();
ptrs[disks-1] = dq;
raid6_call.gen_syndrome(disks, bytes, ptrs);
@@ -72,7 +72,7 @@ static void raid6_datap_recov_intx1(int disks, size_t bytes, int faila,
/* Compute syndrome with zero for the missing data page
Use the dead data page as temporary storage for delta q */
dq = (u8 *)ptrs[faila];
- ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[faila] = raid6_get_zero_page();
ptrs[disks-1] = dq;
raid6_call.gen_syndrome(disks, bytes, ptrs);
diff --git a/lib/raid6/recov_avx2.c b/lib/raid6/recov_avx2.c
index 4e8095403ee2..97d598d2535c 100644
--- a/lib/raid6/recov_avx2.c
+++ b/lib/raid6/recov_avx2.c
@@ -28,10 +28,10 @@ static void raid6_2data_recov_avx2(int disks, size_t bytes, int faila,
Use the dead data pages as temporary storage for
delta p and delta q */
dp = (u8 *)ptrs[faila];
- ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[faila] = raid6_get_zero_page();
ptrs[disks-2] = dp;
dq = (u8 *)ptrs[failb];
- ptrs[failb] = (void *)raid6_empty_zero_page;
+ ptrs[failb] = raid6_get_zero_page();
ptrs[disks-1] = dq;
raid6_call.gen_syndrome(disks, bytes, ptrs);
@@ -196,7 +196,7 @@ static void raid6_datap_recov_avx2(int disks, size_t bytes, int faila,
/* Compute syndrome with zero for the missing data page
Use the dead data page as temporary storage for delta q */
dq = (u8 *)ptrs[faila];
- ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[faila] = raid6_get_zero_page();
ptrs[disks-1] = dq;
raid6_call.gen_syndrome(disks, bytes, ptrs);
diff --git a/lib/raid6/recov_avx512.c b/lib/raid6/recov_avx512.c
index 310c715db313..7986120ca444 100644
--- a/lib/raid6/recov_avx512.c
+++ b/lib/raid6/recov_avx512.c
@@ -37,10 +37,10 @@ static void raid6_2data_recov_avx512(int disks, size_t bytes, int faila,
*/
dp = (u8 *)ptrs[faila];
- ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[faila] = raid6_get_zero_page();
ptrs[disks-2] = dp;
dq = (u8 *)ptrs[failb];
- ptrs[failb] = (void *)raid6_empty_zero_page;
+ ptrs[failb] = raid6_get_zero_page();
ptrs[disks-1] = dq;
raid6_call.gen_syndrome(disks, bytes, ptrs);
@@ -238,7 +238,7 @@ static void raid6_datap_recov_avx512(int disks, size_t bytes, int faila,
*/
dq = (u8 *)ptrs[faila];
- ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[faila] = raid6_get_zero_page();
ptrs[disks-1] = dq;
raid6_call.gen_syndrome(disks, bytes, ptrs);
diff --git a/lib/raid6/recov_loongarch_simd.c b/lib/raid6/recov_loongarch_simd.c
index 94aeac85e6f7..93dc515997a1 100644
--- a/lib/raid6/recov_loongarch_simd.c
+++ b/lib/raid6/recov_loongarch_simd.c
@@ -42,10 +42,10 @@ static void raid6_2data_recov_lsx(int disks, size_t bytes, int faila,
* delta p and delta q
*/
dp = (u8 *)ptrs[faila];
- ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[faila] = raid6_get_zero_page();
ptrs[disks - 2] = dp;
dq = (u8 *)ptrs[failb];
- ptrs[failb] = (void *)raid6_empty_zero_page;
+ ptrs[failb] = raid6_get_zero_page();
ptrs[disks - 1] = dq;
raid6_call.gen_syndrome(disks, bytes, ptrs);
@@ -197,7 +197,7 @@ static void raid6_datap_recov_lsx(int disks, size_t bytes, int faila,
* Use the dead data page as temporary storage for delta q
*/
dq = (u8 *)ptrs[faila];
- ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[faila] = raid6_get_zero_page();
ptrs[disks - 1] = dq;
raid6_call.gen_syndrome(disks, bytes, ptrs);
@@ -316,10 +316,10 @@ static void raid6_2data_recov_lasx(int disks, size_t bytes, int faila,
* delta p and delta q
*/
dp = (u8 *)ptrs[faila];
- ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[faila] = raid6_get_zero_page();
ptrs[disks - 2] = dp;
dq = (u8 *)ptrs[failb];
- ptrs[failb] = (void *)raid6_empty_zero_page;
+ ptrs[failb] = raid6_get_zero_page();
ptrs[disks - 1] = dq;
raid6_call.gen_syndrome(disks, bytes, ptrs);
@@ -436,7 +436,7 @@ static void raid6_datap_recov_lasx(int disks, size_t bytes, int faila,
* Use the dead data page as temporary storage for delta q
*/
dq = (u8 *)ptrs[faila];
- ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[faila] = raid6_get_zero_page();
ptrs[disks - 1] = dq;
raid6_call.gen_syndrome(disks, bytes, ptrs);
diff --git a/lib/raid6/recov_neon.c b/lib/raid6/recov_neon.c
index 1bfc14174d4d..70e1404c1512 100644
--- a/lib/raid6/recov_neon.c
+++ b/lib/raid6/recov_neon.c
@@ -36,10 +36,10 @@ static void raid6_2data_recov_neon(int disks, size_t bytes, int faila,
* delta p and delta q
*/
dp = (u8 *)ptrs[faila];
- ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[faila] = raid6_get_zero_page();
ptrs[disks - 2] = dp;
dq = (u8 *)ptrs[failb];
- ptrs[failb] = (void *)raid6_empty_zero_page;
+ ptrs[failb] = raid6_get_zero_page();
ptrs[disks - 1] = dq;
raid6_call.gen_syndrome(disks, bytes, ptrs);
@@ -74,7 +74,7 @@ static void raid6_datap_recov_neon(int disks, size_t bytes, int faila,
* Use the dead data page as temporary storage for delta q
*/
dq = (u8 *)ptrs[faila];
- ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[faila] = raid6_get_zero_page();
ptrs[disks - 1] = dq;
raid6_call.gen_syndrome(disks, bytes, ptrs);
diff --git a/lib/raid6/recov_rvv.c b/lib/raid6/recov_rvv.c
index f29303795ccf..5d54c4b437df 100644
--- a/lib/raid6/recov_rvv.c
+++ b/lib/raid6/recov_rvv.c
@@ -165,10 +165,10 @@ static void raid6_2data_recov_rvv(int disks, size_t bytes, int faila,
* delta p and delta q
*/
dp = (u8 *)ptrs[faila];
- ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[faila] = raid6_get_zero_page();
ptrs[disks - 2] = dp;
dq = (u8 *)ptrs[failb];
- ptrs[failb] = (void *)raid6_empty_zero_page;
+ ptrs[failb] = raid6_get_zero_page();
ptrs[disks - 1] = dq;
raid6_call.gen_syndrome(disks, bytes, ptrs);
@@ -203,7 +203,7 @@ static void raid6_datap_recov_rvv(int disks, size_t bytes, int faila,
* Use the dead data page as temporary storage for delta q
*/
dq = (u8 *)ptrs[faila];
- ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[faila] = raid6_get_zero_page();
ptrs[disks - 1] = dq;
raid6_call.gen_syndrome(disks, bytes, ptrs);
diff --git a/lib/raid6/recov_s390xc.c b/lib/raid6/recov_s390xc.c
index 4a7aa466f0ef..487018f81192 100644
--- a/lib/raid6/recov_s390xc.c
+++ b/lib/raid6/recov_s390xc.c
@@ -34,10 +34,10 @@ static void raid6_2data_recov_s390xc(int disks, size_t bytes, int faila,
Use the dead data pages as temporary storage for
delta p and delta q */
dp = (u8 *)ptrs[faila];
- ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[faila] = raid6_get_zero_page();
ptrs[disks-2] = dp;
dq = (u8 *)ptrs[failb];
- ptrs[failb] = (void *)raid6_empty_zero_page;
+ ptrs[failb] = raid6_get_zero_page();
ptrs[disks-1] = dq;
raid6_call.gen_syndrome(disks, bytes, ptrs);
@@ -81,7 +81,7 @@ static void raid6_datap_recov_s390xc(int disks, size_t bytes, int faila,
/* Compute syndrome with zero for the missing data page
Use the dead data page as temporary storage for delta q */
dq = (u8 *)ptrs[faila];
- ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[faila] = raid6_get_zero_page();
ptrs[disks-1] = dq;
raid6_call.gen_syndrome(disks, bytes, ptrs);
diff --git a/lib/raid6/recov_ssse3.c b/lib/raid6/recov_ssse3.c
index 4bfa3c6b60de..2e849185c32b 100644
--- a/lib/raid6/recov_ssse3.c
+++ b/lib/raid6/recov_ssse3.c
@@ -30,10 +30,10 @@ static void raid6_2data_recov_ssse3(int disks, size_t bytes, int faila,
Use the dead data pages as temporary storage for
delta p and delta q */
dp = (u8 *)ptrs[faila];
- ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[faila] = raid6_get_zero_page();
ptrs[disks-2] = dp;
dq = (u8 *)ptrs[failb];
- ptrs[failb] = (void *)raid6_empty_zero_page;
+ ptrs[failb] = raid6_get_zero_page();
ptrs[disks-1] = dq;
raid6_call.gen_syndrome(disks, bytes, ptrs);
@@ -203,7 +203,7 @@ static void raid6_datap_recov_ssse3(int disks, size_t bytes, int faila,
/* Compute syndrome with zero for the missing data page
Use the dead data page as temporary storage for delta q */
dq = (u8 *)ptrs[faila];
- ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[faila] = raid6_get_zero_page();
ptrs[disks-1] = dq;
raid6_call.gen_syndrome(disks, bytes, ptrs);
diff --git a/lib/stackdepot.c b/lib/stackdepot.c
index 73d7b50924ef..de0b0025af2b 100644
--- a/lib/stackdepot.c
+++ b/lib/stackdepot.c
@@ -36,11 +36,11 @@
#include <linux/memblock.h>
#include <linux/kasan-enabled.h>
-#define DEPOT_POOLS_CAP 8192
-/* The pool_index is offset by 1 so the first record does not have a 0 handle. */
-#define DEPOT_MAX_POOLS \
- (((1LL << (DEPOT_POOL_INDEX_BITS)) - 1 < DEPOT_POOLS_CAP) ? \
- (1LL << (DEPOT_POOL_INDEX_BITS)) - 1 : DEPOT_POOLS_CAP)
+/*
+ * The pool_index is offset by 1 so the first record does not have a 0 handle.
+ */
+static unsigned int stack_max_pools __read_mostly =
+ MIN((1LL << DEPOT_POOL_INDEX_BITS) - 1, 8192);
static bool stack_depot_disabled;
static bool __stack_depot_early_init_requested __initdata = IS_ENABLED(CONFIG_STACKDEPOT_ALWAYS_INIT);
@@ -62,7 +62,7 @@ static unsigned int stack_bucket_number_order;
static unsigned int stack_hash_mask;
/* Array of memory regions that store stack records. */
-static void *stack_pools[DEPOT_MAX_POOLS];
+static void **stack_pools;
/* Newly allocated pool that is not yet added to stack_pools. */
static void *new_pool;
/* Number of pools in stack_pools. */
@@ -101,6 +101,34 @@ static int __init disable_stack_depot(char *str)
}
early_param("stack_depot_disable", disable_stack_depot);
+static int __init parse_max_pools(char *str)
+{
+ const long long limit = (1LL << (DEPOT_POOL_INDEX_BITS)) - 1;
+ unsigned int max_pools;
+ int rv;
+
+ rv = kstrtouint(str, 0, &max_pools);
+ if (rv)
+ return rv;
+
+ if (max_pools < 1024) {
+ pr_err("stack_depot_max_pools below 1024, using default of %u\n",
+ stack_max_pools);
+ goto out;
+ }
+
+ if (max_pools > limit) {
+ pr_err("stack_depot_max_pools exceeds %lld, using default of %u\n",
+ limit, stack_max_pools);
+ goto out;
+ }
+
+ stack_max_pools = max_pools;
+out:
+ return 0;
+}
+early_param("stack_depot_max_pools", parse_max_pools);
+
void __init stack_depot_request_early_init(void)
{
/* Too late to request early init now. */
@@ -182,6 +210,17 @@ int __init stack_depot_early_init(void)
}
init_stack_table(entries);
+ pr_info("allocating space for %u stack pools via memblock\n",
+ stack_max_pools);
+ stack_pools =
+ memblock_alloc(stack_max_pools * sizeof(void *), PAGE_SIZE);
+ if (!stack_pools) {
+ pr_err("stack pools allocation failed, disabling\n");
+ memblock_free(stack_table, entries * sizeof(struct list_head));
+ stack_depot_disabled = true;
+ return -ENOMEM;
+ }
+
return 0;
}
@@ -231,6 +270,16 @@ int stack_depot_init(void)
stack_hash_mask = entries - 1;
init_stack_table(entries);
+ pr_info("allocating space for %u stack pools via kvcalloc\n",
+ stack_max_pools);
+ stack_pools = kvcalloc(stack_max_pools, sizeof(void *), GFP_KERNEL);
+ if (!stack_pools) {
+ pr_err("stack pools allocation failed, disabling\n");
+ kvfree(stack_table);
+ stack_depot_disabled = true;
+ ret = -ENOMEM;
+ }
+
out_unlock:
mutex_unlock(&stack_depot_init_mutex);
@@ -245,9 +294,9 @@ static bool depot_init_pool(void **prealloc)
{
lockdep_assert_held(&pool_lock);
- if (unlikely(pools_num >= DEPOT_MAX_POOLS)) {
+ if (unlikely(pools_num >= stack_max_pools)) {
/* Bail out if we reached the pool limit. */
- WARN_ON_ONCE(pools_num > DEPOT_MAX_POOLS); /* should never happen */
+ WARN_ON_ONCE(pools_num > stack_max_pools); /* should never happen */
WARN_ON_ONCE(!new_pool); /* to avoid unnecessary pre-allocation */
WARN_ONCE(1, "Stack depot reached limit capacity");
return false;
@@ -273,7 +322,7 @@ static bool depot_init_pool(void **prealloc)
* NULL; do not reset to NULL if we have reached the maximum number of
* pools.
*/
- if (pools_num < DEPOT_MAX_POOLS)
+ if (pools_num < stack_max_pools)
WRITE_ONCE(new_pool, NULL);
else
WRITE_ONCE(new_pool, STACK_DEPOT_POISON);
diff --git a/lib/sys_info.c b/lib/sys_info.c
new file mode 100644
index 000000000000..5bf503fd7ec1
--- /dev/null
+++ b/lib/sys_info.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/sched/debug.h>
+#include <linux/console.h>
+#include <linux/kernel.h>
+#include <linux/ftrace.h>
+#include <linux/sysctl.h>
+#include <linux/nmi.h>
+
+#include <linux/sys_info.h>
+
+struct sys_info_name {
+ unsigned long bit;
+ const char *name;
+};
+
+/*
+ * When 'si_names' gets updated, please make sure the 'sys_info_avail'
+ * below is updated accordingly.
+ */
+static const struct sys_info_name si_names[] = {
+ { SYS_INFO_TASKS, "tasks" },
+ { SYS_INFO_MEM, "mem" },
+ { SYS_INFO_TIMERS, "timers" },
+ { SYS_INFO_LOCKS, "locks" },
+ { SYS_INFO_FTRACE, "ftrace" },
+ { SYS_INFO_ALL_CPU_BT, "all_bt" },
+ { SYS_INFO_BLOCKED_TASKS, "blocked_tasks" },
+};
+
+/* Expecting string like "xxx_sys_info=tasks,mem,timers,locks,ftrace,..." */
+unsigned long sys_info_parse_param(char *str)
+{
+ unsigned long si_bits = 0;
+ char *s, *name;
+ int i;
+
+ s = str;
+ while ((name = strsep(&s, ",")) && *name) {
+ for (i = 0; i < ARRAY_SIZE(si_names); i++) {
+ if (!strcmp(name, si_names[i].name)) {
+ si_bits |= si_names[i].bit;
+ break;
+ }
+ }
+ }
+
+ return si_bits;
+}
+
+#ifdef CONFIG_SYSCTL
+
+static const char sys_info_avail[] __maybe_unused = "tasks,mem,timers,locks,ftrace,all_bt,blocked_tasks";
+
+int sysctl_sys_info_handler(const struct ctl_table *ro_table, int write,
+ void *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ char names[sizeof(sys_info_avail) + 1];
+ struct ctl_table table;
+ unsigned long *si_bits_global;
+
+ si_bits_global = ro_table->data;
+
+ if (write) {
+ unsigned long si_bits;
+ int ret;
+
+ table = *ro_table;
+ table.data = names;
+ table.maxlen = sizeof(names);
+ ret = proc_dostring(&table, write, buffer, lenp, ppos);
+ if (ret)
+ return ret;
+
+ si_bits = sys_info_parse_param(names);
+ /* The access to the global value is not synchronized. */
+ WRITE_ONCE(*si_bits_global, si_bits);
+ return 0;
+ } else {
+ /* for 'read' operation */
+ char *delim = "";
+ int i, len = 0;
+
+ for (i = 0; i < ARRAY_SIZE(si_names); i++) {
+ if (*si_bits_global & si_names[i].bit) {
+ len += scnprintf(names + len, sizeof(names) - len,
+ "%s%s", delim, si_names[i].name);
+ delim = ",";
+ }
+ }
+
+ table = *ro_table;
+ table.data = names;
+ table.maxlen = sizeof(names);
+ return proc_dostring(&table, write, buffer, lenp, ppos);
+ }
+}
+#endif
+
+void sys_info(unsigned long si_mask)
+{
+ if (si_mask & SYS_INFO_TASKS)
+ show_state();
+
+ if (si_mask & SYS_INFO_MEM)
+ show_mem();
+
+ if (si_mask & SYS_INFO_TIMERS)
+ sysrq_timer_list_show();
+
+ if (si_mask & SYS_INFO_LOCKS)
+ debug_show_all_locks();
+
+ if (si_mask & SYS_INFO_FTRACE)
+ ftrace_dump(DUMP_ALL);
+
+ if (si_mask & SYS_INFO_ALL_CPU_BT)
+ trigger_all_cpu_backtrace();
+
+ if (si_mask & SYS_INFO_BLOCKED_TASKS)
+ show_state_filter(TASK_UNINTERRUPTIBLE);
+}
diff --git a/lib/test_kho.c b/lib/test_kho.c
new file mode 100644
index 000000000000..c2eb899c3b45
--- /dev/null
+++ b/lib/test_kho.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Test module for KHO
+ * Copyright (c) 2025 Microsoft Corporation.
+ *
+ * Authors:
+ * Saurabh Sengar <ssengar@microsoft.com>
+ * Mike Rapoport <rppt@kernel.org>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/mm.h>
+#include <linux/gfp.h>
+#include <linux/slab.h>
+#include <linux/kexec.h>
+#include <linux/libfdt.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/vmalloc.h>
+#include <linux/kexec_handover.h>
+
+#include <net/checksum.h>
+
+#define KHO_TEST_MAGIC 0x4b484f21 /* KHO! */
+#define KHO_TEST_FDT "kho_test"
+#define KHO_TEST_COMPAT "kho-test-v1"
+
+static long max_mem = (PAGE_SIZE << MAX_PAGE_ORDER) * 2;
+module_param(max_mem, long, 0644);
+
+struct kho_test_state {
+ unsigned int nr_folios;
+ struct folio **folios;
+ struct folio *fdt;
+ __wsum csum;
+};
+
+static struct kho_test_state kho_test_state;
+
+static int kho_test_notifier(struct notifier_block *self, unsigned long cmd,
+ void *v)
+{
+ struct kho_test_state *state = &kho_test_state;
+ struct kho_serialization *ser = v;
+ int err = 0;
+
+ switch (cmd) {
+ case KEXEC_KHO_ABORT:
+ return NOTIFY_DONE;
+ case KEXEC_KHO_FINALIZE:
+ /* Handled below */
+ break;
+ default:
+ return NOTIFY_BAD;
+ }
+
+ err |= kho_preserve_folio(state->fdt);
+ err |= kho_add_subtree(ser, KHO_TEST_FDT, folio_address(state->fdt));
+
+ return err ? NOTIFY_BAD : NOTIFY_DONE;
+}
+
+static struct notifier_block kho_test_nb = {
+ .notifier_call = kho_test_notifier,
+};
+
+static int kho_test_save_data(struct kho_test_state *state, void *fdt)
+{
+ phys_addr_t *folios_info __free(kvfree) = NULL;
+ int err = 0;
+
+ folios_info = kvmalloc_array(state->nr_folios, sizeof(*folios_info),
+ GFP_KERNEL);
+ if (!folios_info)
+ return -ENOMEM;
+
+ for (int i = 0; i < state->nr_folios; i++) {
+ struct folio *folio = state->folios[i];
+ unsigned int order = folio_order(folio);
+
+ folios_info[i] = virt_to_phys(folio_address(folio)) | order;
+
+ err = kho_preserve_folio(folio);
+ if (err)
+ return err;
+ }
+
+ err |= fdt_begin_node(fdt, "data");
+ err |= fdt_property(fdt, "nr_folios", &state->nr_folios,
+ sizeof(state->nr_folios));
+ err |= fdt_property(fdt, "folios_info", folios_info,
+ state->nr_folios * sizeof(*folios_info));
+ err |= fdt_property(fdt, "csum", &state->csum, sizeof(state->csum));
+ err |= fdt_end_node(fdt);
+
+ return err;
+}
+
+static int kho_test_prepare_fdt(struct kho_test_state *state)
+{
+ const char compatible[] = KHO_TEST_COMPAT;
+ unsigned int magic = KHO_TEST_MAGIC;
+ ssize_t fdt_size;
+ int err = 0;
+ void *fdt;
+
+ fdt_size = state->nr_folios * sizeof(phys_addr_t) + PAGE_SIZE;
+ state->fdt = folio_alloc(GFP_KERNEL, get_order(fdt_size));
+ if (!state->fdt)
+ return -ENOMEM;
+
+ fdt = folio_address(state->fdt);
+
+ err |= fdt_create(fdt, fdt_size);
+ err |= fdt_finish_reservemap(fdt);
+
+ err |= fdt_begin_node(fdt, "");
+ err |= fdt_property(fdt, "compatible", compatible, sizeof(compatible));
+ err |= fdt_property(fdt, "magic", &magic, sizeof(magic));
+ err |= kho_test_save_data(state, fdt);
+ err |= fdt_end_node(fdt);
+
+ err |= fdt_finish(fdt);
+
+ if (err)
+ folio_put(state->fdt);
+
+ return err;
+}
+
+static int kho_test_generate_data(struct kho_test_state *state)
+{
+ size_t alloc_size = 0;
+ __wsum csum = 0;
+
+ while (alloc_size < max_mem) {
+ int order = get_random_u32() % NR_PAGE_ORDERS;
+ struct folio *folio;
+ unsigned int size;
+ void *addr;
+
+ /* cap allocation so that we won't exceed max_mem */
+ if (alloc_size + (PAGE_SIZE << order) > max_mem) {
+ order = get_order(max_mem - alloc_size);
+ if (order)
+ order--;
+ }
+ size = PAGE_SIZE << order;
+
+ folio = folio_alloc(GFP_KERNEL | __GFP_NORETRY, order);
+ if (!folio)
+ goto err_free_folios;
+
+ state->folios[state->nr_folios++] = folio;
+ addr = folio_address(folio);
+ get_random_bytes(addr, size);
+ csum = csum_partial(addr, size, csum);
+ alloc_size += size;
+ }
+
+ state->csum = csum;
+ return 0;
+
+err_free_folios:
+ for (int i = 0; i < state->nr_folios; i++)
+ folio_put(state->folios[i]);
+ return -ENOMEM;
+}
+
+static int kho_test_save(void)
+{
+ struct kho_test_state *state = &kho_test_state;
+ struct folio **folios __free(kvfree) = NULL;
+ unsigned long max_nr;
+ int err;
+
+ max_mem = PAGE_ALIGN(max_mem);
+ max_nr = max_mem >> PAGE_SHIFT;
+
+ folios = kvmalloc_array(max_nr, sizeof(*state->folios), GFP_KERNEL);
+ if (!folios)
+ return -ENOMEM;
+ state->folios = folios;
+
+ err = kho_test_generate_data(state);
+ if (err)
+ return err;
+
+ err = kho_test_prepare_fdt(state);
+ if (err)
+ return err;
+
+ return register_kho_notifier(&kho_test_nb);
+}
+
+static int kho_test_restore_data(const void *fdt, int node)
+{
+ const unsigned int *nr_folios;
+ const phys_addr_t *folios_info;
+ const __wsum *old_csum;
+ __wsum csum = 0;
+ int len;
+
+ node = fdt_path_offset(fdt, "/data");
+
+ nr_folios = fdt_getprop(fdt, node, "nr_folios", &len);
+ if (!nr_folios || len != sizeof(*nr_folios))
+ return -EINVAL;
+
+ old_csum = fdt_getprop(fdt, node, "csum", &len);
+ if (!old_csum || len != sizeof(*old_csum))
+ return -EINVAL;
+
+ folios_info = fdt_getprop(fdt, node, "folios_info", &len);
+ if (!folios_info || len != sizeof(*folios_info) * *nr_folios)
+ return -EINVAL;
+
+ for (int i = 0; i < *nr_folios; i++) {
+ unsigned int order = folios_info[i] & ~PAGE_MASK;
+ phys_addr_t phys = folios_info[i] & PAGE_MASK;
+ unsigned int size = PAGE_SIZE << order;
+ struct folio *folio;
+
+ folio = kho_restore_folio(phys);
+ if (!folio)
+ break;
+
+ if (folio_order(folio) != order)
+ break;
+
+ csum = csum_partial(folio_address(folio), size, csum);
+ folio_put(folio);
+ }
+
+ if (csum != *old_csum)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int kho_test_restore(phys_addr_t fdt_phys)
+{
+ void *fdt = phys_to_virt(fdt_phys);
+ const unsigned int *magic;
+ int node, len, err;
+
+ node = fdt_path_offset(fdt, "/");
+ if (node < 0)
+ return -EINVAL;
+
+ if (fdt_node_check_compatible(fdt, node, KHO_TEST_COMPAT))
+ return -EINVAL;
+
+ magic = fdt_getprop(fdt, node, "magic", &len);
+ if (!magic || len != sizeof(*magic))
+ return -EINVAL;
+
+ if (*magic != KHO_TEST_MAGIC)
+ return -EINVAL;
+
+ err = kho_test_restore_data(fdt, node);
+ if (err)
+ return err;
+
+ pr_info("KHO restore succeeded\n");
+ return 0;
+}
+
+static int __init kho_test_init(void)
+{
+ phys_addr_t fdt_phys;
+ int err;
+
+ err = kho_retrieve_subtree(KHO_TEST_FDT, &fdt_phys);
+ if (!err)
+ return kho_test_restore(fdt_phys);
+
+ if (err != -ENOENT) {
+ pr_warn("failed to retrieve %s FDT: %d\n", KHO_TEST_FDT, err);
+ return err;
+ }
+
+ return kho_test_save();
+}
+module_init(kho_test_init);
+
+static void kho_test_cleanup(void)
+{
+ for (int i = 0; i < kho_test_state.nr_folios; i++)
+ folio_put(kho_test_state.folios[i]);
+
+ kvfree(kho_test_state.folios);
+}
+
+static void __exit kho_test_exit(void)
+{
+ unregister_kho_notifier(&kho_test_nb);
+ kho_test_cleanup();
+}
+module_exit(kho_test_exit);
+
+MODULE_AUTHOR("Mike Rapoport <rppt@kernel.org>");
+MODULE_DESCRIPTION("KHO test module");
+MODULE_LICENSE("GPL");
diff --git a/lib/xxhash.c b/lib/xxhash.c
index b5bd567aa6b3..cf629766f376 100644
--- a/lib/xxhash.c
+++ b/lib/xxhash.c
@@ -267,113 +267,6 @@ void xxh64_reset(struct xxh64_state *statePtr, const uint64_t seed)
}
EXPORT_SYMBOL(xxh64_reset);
-int xxh32_update(struct xxh32_state *state, const void *input, const size_t len)
-{
- const uint8_t *p = (const uint8_t *)input;
- const uint8_t *const b_end = p + len;
-
- if (input == NULL)
- return -EINVAL;
-
- state->total_len_32 += (uint32_t)len;
- state->large_len |= (len >= 16) | (state->total_len_32 >= 16);
-
- if (state->memsize + len < 16) { /* fill in tmp buffer */
- memcpy((uint8_t *)(state->mem32) + state->memsize, input, len);
- state->memsize += (uint32_t)len;
- return 0;
- }
-
- if (state->memsize) { /* some data left from previous update */
- const uint32_t *p32 = state->mem32;
-
- memcpy((uint8_t *)(state->mem32) + state->memsize, input,
- 16 - state->memsize);
-
- state->v1 = xxh32_round(state->v1, get_unaligned_le32(p32));
- p32++;
- state->v2 = xxh32_round(state->v2, get_unaligned_le32(p32));
- p32++;
- state->v3 = xxh32_round(state->v3, get_unaligned_le32(p32));
- p32++;
- state->v4 = xxh32_round(state->v4, get_unaligned_le32(p32));
- p32++;
-
- p += 16-state->memsize;
- state->memsize = 0;
- }
-
- if (p <= b_end - 16) {
- const uint8_t *const limit = b_end - 16;
- uint32_t v1 = state->v1;
- uint32_t v2 = state->v2;
- uint32_t v3 = state->v3;
- uint32_t v4 = state->v4;
-
- do {
- v1 = xxh32_round(v1, get_unaligned_le32(p));
- p += 4;
- v2 = xxh32_round(v2, get_unaligned_le32(p));
- p += 4;
- v3 = xxh32_round(v3, get_unaligned_le32(p));
- p += 4;
- v4 = xxh32_round(v4, get_unaligned_le32(p));
- p += 4;
- } while (p <= limit);
-
- state->v1 = v1;
- state->v2 = v2;
- state->v3 = v3;
- state->v4 = v4;
- }
-
- if (p < b_end) {
- memcpy(state->mem32, p, (size_t)(b_end-p));
- state->memsize = (uint32_t)(b_end-p);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(xxh32_update);
-
-uint32_t xxh32_digest(const struct xxh32_state *state)
-{
- const uint8_t *p = (const uint8_t *)state->mem32;
- const uint8_t *const b_end = (const uint8_t *)(state->mem32) +
- state->memsize;
- uint32_t h32;
-
- if (state->large_len) {
- h32 = xxh_rotl32(state->v1, 1) + xxh_rotl32(state->v2, 7) +
- xxh_rotl32(state->v3, 12) + xxh_rotl32(state->v4, 18);
- } else {
- h32 = state->v3 /* == seed */ + PRIME32_5;
- }
-
- h32 += state->total_len_32;
-
- while (p + 4 <= b_end) {
- h32 += get_unaligned_le32(p) * PRIME32_3;
- h32 = xxh_rotl32(h32, 17) * PRIME32_4;
- p += 4;
- }
-
- while (p < b_end) {
- h32 += (*p) * PRIME32_5;
- h32 = xxh_rotl32(h32, 11) * PRIME32_1;
- p++;
- }
-
- h32 ^= h32 >> 15;
- h32 *= PRIME32_2;
- h32 ^= h32 >> 13;
- h32 *= PRIME32_3;
- h32 ^= h32 >> 16;
-
- return h32;
-}
-EXPORT_SYMBOL(xxh32_digest);
-
int xxh64_update(struct xxh64_state *state, const void *input, const size_t len)
{
const uint8_t *p = (const uint8_t *)input;
diff --git a/rust/Makefile b/rust/Makefile
index 115b63b7d1e3..4263462b8470 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -34,6 +34,9 @@ obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated.o
obj-$(CONFIG_RUST_KERNEL_DOCTESTS) += doctests_kernel_generated_kunit.o
always-$(subst y,$(CONFIG_RUST),$(CONFIG_JUMP_LABEL)) += kernel/generated_arch_static_branch_asm.rs
+ifndef CONFIG_UML
+always-$(subst y,$(CONFIG_RUST),$(CONFIG_BUG)) += kernel/generated_arch_warn_asm.rs kernel/generated_arch_reachable_asm.rs
+endif
# Avoids running `$(RUSTC)` when it may not be available.
ifdef CONFIG_RUST
@@ -541,5 +544,10 @@ $(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/build_error.o $(obj)/pin_init.o \
ifdef CONFIG_JUMP_LABEL
$(obj)/kernel.o: $(obj)/kernel/generated_arch_static_branch_asm.rs
endif
+ifndef CONFIG_UML
+ifdef CONFIG_BUG
+$(obj)/kernel.o: $(obj)/kernel/generated_arch_warn_asm.rs $(obj)/kernel/generated_arch_reachable_asm.rs
+endif
+endif
endif # CONFIG_RUST
diff --git a/rust/bindings/lib.rs b/rust/bindings/lib.rs
index a08eb5518cac..474cc98c48a3 100644
--- a/rust/bindings/lib.rs
+++ b/rust/bindings/lib.rs
@@ -25,6 +25,9 @@
)]
#[allow(dead_code)]
+#[allow(clippy::cast_lossless)]
+#[allow(clippy::ptr_as_ptr)]
+#[allow(clippy::ref_as_ptr)]
#[allow(clippy::undocumented_unsafe_blocks)]
#[cfg_attr(CONFIG_RUSTC_HAS_UNNECESSARY_TRANSMUTES, allow(unnecessary_transmutes))]
mod bindings_raw {
diff --git a/rust/helpers/bug.c b/rust/helpers/bug.c
index e2d13babc737..a62c96f507d1 100644
--- a/rust/helpers/bug.c
+++ b/rust/helpers/bug.c
@@ -6,3 +6,8 @@ __noreturn void rust_helper_BUG(void)
{
BUG();
}
+
+bool rust_helper_WARN_ON(bool cond)
+{
+ return WARN_ON(cond);
+}
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index 2bb13285825b..7cf7fe95e41d 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -30,21 +30,22 @@
#include "mutex.c"
#include "of.c"
#include "page.c"
-#include "platform.c"
#include "pci.c"
#include "pid_namespace.c"
+#include "platform.c"
#include "poll.c"
#include "property.c"
#include "rbtree.c"
-#include "regulator.c"
#include "rcu.c"
#include "refcount.c"
+#include "regulator.c"
#include "security.c"
#include "signal.c"
#include "slab.c"
#include "spinlock.c"
#include "sync.c"
#include "task.c"
+#include "time.c"
#include "uaccess.c"
#include "vmalloc.c"
#include "wait.c"
diff --git a/rust/helpers/time.c b/rust/helpers/time.c
new file mode 100644
index 000000000000..a318e9fa4408
--- /dev/null
+++ b/rust/helpers/time.c
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/delay.h>
+#include <linux/ktime.h>
+#include <linux/timekeeping.h>
+
+void rust_helper_fsleep(unsigned long usecs)
+{
+ fsleep(usecs);
+}
+
+ktime_t rust_helper_ktime_get_real(void)
+{
+ return ktime_get_real();
+}
+
+ktime_t rust_helper_ktime_get_boottime(void)
+{
+ return ktime_get_boottime();
+}
+
+ktime_t rust_helper_ktime_get_clocktai(void)
+{
+ return ktime_get_clocktai();
+}
+
+s64 rust_helper_ktime_to_us(const ktime_t kt)
+{
+ return ktime_to_us(kt);
+}
+
+s64 rust_helper_ktime_to_ms(const ktime_t kt)
+{
+ return ktime_to_ms(kt);
+}
diff --git a/rust/kernel/.gitignore b/rust/kernel/.gitignore
index 6ba39a178f30..f636ad95aaf3 100644
--- a/rust/kernel/.gitignore
+++ b/rust/kernel/.gitignore
@@ -1,3 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
/generated_arch_static_branch_asm.rs
+/generated_arch_warn_asm.rs
+/generated_arch_reachable_asm.rs
diff --git a/rust/kernel/alloc/allocator_test.rs b/rust/kernel/alloc/allocator_test.rs
index d19c06ef0498..a3074480bd8d 100644
--- a/rust/kernel/alloc/allocator_test.rs
+++ b/rust/kernel/alloc/allocator_test.rs
@@ -82,7 +82,7 @@ unsafe impl Allocator for Cmalloc {
// SAFETY: Returns either NULL or a pointer to a memory allocation that satisfies or
// exceeds the given size and alignment requirements.
- let dst = unsafe { libc_aligned_alloc(layout.align(), layout.size()) } as *mut u8;
+ let dst = unsafe { libc_aligned_alloc(layout.align(), layout.size()) }.cast::<u8>();
let dst = NonNull::new(dst).ok_or(AllocError)?;
if flags.contains(__GFP_ZERO) {
diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs
index c386ff771d50..856d05aa60f1 100644
--- a/rust/kernel/alloc/kbox.rs
+++ b/rust/kernel/alloc/kbox.rs
@@ -6,6 +6,7 @@
use super::allocator::{KVmalloc, Kmalloc, Vmalloc};
use super::{AllocError, Allocator, Flags};
use core::alloc::Layout;
+use core::borrow::{Borrow, BorrowMut};
use core::fmt;
use core::marker::PhantomData;
use core::mem::ManuallyDrop;
@@ -15,6 +16,7 @@ use core::pin::Pin;
use core::ptr::NonNull;
use core::result::Result;
+use crate::ffi::c_void;
use crate::init::InPlaceInit;
use crate::types::ForeignOwnable;
use pin_init::{InPlaceWrite, Init, PinInit, ZeroableOption};
@@ -398,70 +400,74 @@ where
}
}
-// SAFETY: The `into_foreign` function returns a pointer that is well-aligned.
+// SAFETY: The pointer returned by `into_foreign` comes from a well aligned
+// pointer to `T`.
unsafe impl<T: 'static, A> ForeignOwnable for Box<T, A>
where
A: Allocator,
{
- type PointedTo = T;
+ const FOREIGN_ALIGN: usize = core::mem::align_of::<T>();
type Borrowed<'a> = &'a T;
type BorrowedMut<'a> = &'a mut T;
- fn into_foreign(self) -> *mut Self::PointedTo {
- Box::into_raw(self)
+ fn into_foreign(self) -> *mut c_void {
+ Box::into_raw(self).cast()
}
- unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self {
+ unsafe fn from_foreign(ptr: *mut c_void) -> Self {
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
// call to `Self::into_foreign`.
- unsafe { Box::from_raw(ptr) }
+ unsafe { Box::from_raw(ptr.cast()) }
}
- unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> &'a T {
+ unsafe fn borrow<'a>(ptr: *mut c_void) -> &'a T {
// SAFETY: The safety requirements of this method ensure that the object remains alive and
// immutable for the duration of 'a.
- unsafe { &*ptr }
+ unsafe { &*ptr.cast() }
}
- unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> &'a mut T {
+ unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> &'a mut T {
+ let ptr = ptr.cast();
// SAFETY: The safety requirements of this method ensure that the pointer is valid and that
// nothing else will access the value for the duration of 'a.
unsafe { &mut *ptr }
}
}
-// SAFETY: The `into_foreign` function returns a pointer that is well-aligned.
+// SAFETY: The pointer returned by `into_foreign` comes from a well aligned
+// pointer to `T`.
unsafe impl<T: 'static, A> ForeignOwnable for Pin<Box<T, A>>
where
A: Allocator,
{
- type PointedTo = T;
+ const FOREIGN_ALIGN: usize = core::mem::align_of::<T>();
type Borrowed<'a> = Pin<&'a T>;
type BorrowedMut<'a> = Pin<&'a mut T>;
- fn into_foreign(self) -> *mut Self::PointedTo {
+ fn into_foreign(self) -> *mut c_void {
// SAFETY: We are still treating the box as pinned.
- Box::into_raw(unsafe { Pin::into_inner_unchecked(self) })
+ Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }).cast()
}
- unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self {
+ unsafe fn from_foreign(ptr: *mut c_void) -> Self {
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
// call to `Self::into_foreign`.
- unsafe { Pin::new_unchecked(Box::from_raw(ptr)) }
+ unsafe { Pin::new_unchecked(Box::from_raw(ptr.cast())) }
}
- unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> Pin<&'a T> {
+ unsafe fn borrow<'a>(ptr: *mut c_void) -> Pin<&'a T> {
// SAFETY: The safety requirements for this function ensure that the object is still alive,
// so it is safe to dereference the raw pointer.
// The safety requirements of `from_foreign` also ensure that the object remains alive for
// the lifetime of the returned value.
- let r = unsafe { &*ptr };
+ let r = unsafe { &*ptr.cast() };
// SAFETY: This pointer originates from a `Pin<Box<T>>`.
unsafe { Pin::new_unchecked(r) }
}
- unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> Pin<&'a mut T> {
+ unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> Pin<&'a mut T> {
+ let ptr = ptr.cast();
// SAFETY: The safety requirements for this function ensure that the object is still alive,
// so it is safe to dereference the raw pointer.
// The safety requirements of `from_foreign` also ensure that the object remains alive for
@@ -499,6 +505,62 @@ where
}
}
+/// # Examples
+///
+/// ```
+/// # use core::borrow::Borrow;
+/// # use kernel::alloc::KBox;
+/// struct Foo<B: Borrow<u32>>(B);
+///
+/// // Owned instance.
+/// let owned = Foo(1);
+///
+/// // Owned instance using `KBox`.
+/// let owned_kbox = Foo(KBox::new(1, GFP_KERNEL)?);
+///
+/// let i = 1;
+/// // Borrowed from `i`.
+/// let borrowed = Foo(&i);
+/// # Ok::<(), Error>(())
+/// ```
+impl<T, A> Borrow<T> for Box<T, A>
+where
+ T: ?Sized,
+ A: Allocator,
+{
+ fn borrow(&self) -> &T {
+ self.deref()
+ }
+}
+
+/// # Examples
+///
+/// ```
+/// # use core::borrow::BorrowMut;
+/// # use kernel::alloc::KBox;
+/// struct Foo<B: BorrowMut<u32>>(B);
+///
+/// // Owned instance.
+/// let owned = Foo(1);
+///
+/// // Owned instance using `KBox`.
+/// let owned_kbox = Foo(KBox::new(1, GFP_KERNEL)?);
+///
+/// let mut i = 1;
+/// // Borrowed from `i`.
+/// let borrowed = Foo(&mut i);
+/// # Ok::<(), Error>(())
+/// ```
+impl<T, A> BorrowMut<T> for Box<T, A>
+where
+ T: ?Sized,
+ A: Allocator,
+{
+ fn borrow_mut(&mut self) -> &mut T {
+ self.deref_mut()
+ }
+}
+
impl<T, A> fmt::Display for Box<T, A>
where
T: ?Sized + fmt::Display,
diff --git a/rust/kernel/alloc/kvec.rs b/rust/kernel/alloc/kvec.rs
index 1a0dd852a468..3c72e0bdddb8 100644
--- a/rust/kernel/alloc/kvec.rs
+++ b/rust/kernel/alloc/kvec.rs
@@ -8,6 +8,7 @@ use super::{
AllocError, Allocator, Box, Flags,
};
use core::{
+ borrow::{Borrow, BorrowMut},
fmt,
marker::PhantomData,
mem::{ManuallyDrop, MaybeUninit},
@@ -288,7 +289,7 @@ where
// - `self.len` is smaller than `self.capacity` by the type invariant and hence, the
// resulting pointer is guaranteed to be part of the same allocated object.
// - `self.len` can not overflow `isize`.
- let ptr = unsafe { self.as_mut_ptr().add(self.len) } as *mut MaybeUninit<T>;
+ let ptr = unsafe { self.as_mut_ptr().add(self.len) }.cast::<MaybeUninit<T>>();
// SAFETY: The memory between `self.len` and `self.capacity` is guaranteed to be allocated
// and valid, but uninitialized.
@@ -847,11 +848,11 @@ where
// - `ptr` points to memory with at least a size of `size_of::<T>() * len`,
// - all elements within `b` are initialized values of `T`,
// - `len` does not exceed `isize::MAX`.
- unsafe { Vec::from_raw_parts(ptr as _, len, len) }
+ unsafe { Vec::from_raw_parts(ptr.cast(), len, len) }
}
}
-impl<T> Default for KVec<T> {
+impl<T, A: Allocator> Default for Vec<T, A> {
#[inline]
fn default() -> Self {
Self::new()
@@ -890,6 +891,58 @@ where
}
}
+/// # Examples
+///
+/// ```
+/// # use core::borrow::Borrow;
+/// struct Foo<B: Borrow<[u32]>>(B);
+///
+/// // Owned array.
+/// let owned_array = Foo([1, 2, 3]);
+///
+/// // Owned vector.
+/// let owned_vec = Foo(KVec::from_elem(0, 3, GFP_KERNEL)?);
+///
+/// let arr = [1, 2, 3];
+/// // Borrowed slice from `arr`.
+/// let borrowed_slice = Foo(&arr[..]);
+/// # Ok::<(), Error>(())
+/// ```
+impl<T, A> Borrow<[T]> for Vec<T, A>
+where
+ A: Allocator,
+{
+ fn borrow(&self) -> &[T] {
+ self.as_slice()
+ }
+}
+
+/// # Examples
+///
+/// ```
+/// # use core::borrow::BorrowMut;
+/// struct Foo<B: BorrowMut<[u32]>>(B);
+///
+/// // Owned array.
+/// let owned_array = Foo([1, 2, 3]);
+///
+/// // Owned vector.
+/// let owned_vec = Foo(KVec::from_elem(0, 3, GFP_KERNEL)?);
+///
+/// let mut arr = [1, 2, 3];
+/// // Borrowed slice from `arr`.
+/// let borrowed_slice = Foo(&mut arr[..]);
+/// # Ok::<(), Error>(())
+/// ```
+impl<T, A> BorrowMut<[T]> for Vec<T, A>
+where
+ A: Allocator,
+{
+ fn borrow_mut(&mut self) -> &mut [T] {
+ self.as_mut_slice()
+ }
+}
+
impl<T: Eq, A> Eq for Vec<T, A> where A: Allocator {}
impl<T, I: SliceIndex<[T]>, A> Index<I> for Vec<T, A>
diff --git a/rust/kernel/bits.rs b/rust/kernel/bits.rs
new file mode 100644
index 000000000000..553d50265883
--- /dev/null
+++ b/rust/kernel/bits.rs
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Bit manipulation macros.
+//!
+//! C header: [`include/linux/bits.h`](srctree/include/linux/bits.h)
+
+use crate::prelude::*;
+use core::ops::RangeInclusive;
+use macros::paste;
+
+macro_rules! impl_bit_fn {
+ (
+ $ty:ty
+ ) => {
+ paste! {
+ /// Computes `1 << n` if `n` is in bounds, i.e.: if `n` is smaller than
+ /// the maximum number of bits supported by the type.
+ ///
+ /// Returns [`None`] otherwise.
+ #[inline]
+ pub fn [<checked_bit_ $ty>](n: u32) -> Option<$ty> {
+ (1 as $ty).checked_shl(n)
+ }
+
+ /// Computes `1 << n` by performing a compile-time assertion that `n` is
+ /// in bounds.
+ ///
+ /// This version is the default and should be used if `n` is known at
+ /// compile time.
+ #[inline]
+ pub const fn [<bit_ $ty>](n: u32) -> $ty {
+ build_assert!(n < <$ty>::BITS);
+ (1 as $ty) << n
+ }
+ }
+ };
+}
+
+impl_bit_fn!(u64);
+impl_bit_fn!(u32);
+impl_bit_fn!(u16);
+impl_bit_fn!(u8);
+
+macro_rules! impl_genmask_fn {
+ (
+ $ty:ty,
+ $(#[$genmask_checked_ex:meta])*,
+ $(#[$genmask_ex:meta])*
+ ) => {
+ paste! {
+ /// Creates a contiguous bitmask for the given range by validating
+ /// the range at runtime.
+ ///
+ /// Returns [`None`] if the range is invalid, i.e.: if the start is
+ /// greater than the end or if the range is outside of the
+ /// representable range for the type.
+ $(#[$genmask_checked_ex])*
+ #[inline]
+ pub fn [<genmask_checked_ $ty>](range: RangeInclusive<u32>) -> Option<$ty> {
+ let start = *range.start();
+ let end = *range.end();
+
+ if start > end {
+ return None;
+ }
+
+ let high = [<checked_bit_ $ty>](end)?;
+ let low = [<checked_bit_ $ty>](start)?;
+ Some((high | (high - 1)) & !(low - 1))
+ }
+
+ /// Creates a compile-time contiguous bitmask for the given range by
+ /// performing a compile-time assertion that the range is valid.
+ ///
+ /// This version is the default and should be used if the range is known
+ /// at compile time.
+ $(#[$genmask_ex])*
+ #[inline]
+ pub const fn [<genmask_ $ty>](range: RangeInclusive<u32>) -> $ty {
+ let start = *range.start();
+ let end = *range.end();
+
+ build_assert!(start <= end);
+
+ let high = [<bit_ $ty>](end);
+ let low = [<bit_ $ty>](start);
+ (high | (high - 1)) & !(low - 1)
+ }
+ }
+ };
+}
+
+impl_genmask_fn!(
+ u64,
+ /// # Examples
+ ///
+ /// ```
+ /// # #![expect(clippy::reversed_empty_ranges)]
+ /// # use kernel::bits::genmask_checked_u64;
+ /// assert_eq!(genmask_checked_u64(0..=0), Some(0b1));
+ /// assert_eq!(genmask_checked_u64(0..=63), Some(u64::MAX));
+ /// assert_eq!(genmask_checked_u64(21..=39), Some(0x0000_00ff_ffe0_0000));
+ ///
+ /// // `80` is out of the supported bit range.
+ /// assert_eq!(genmask_checked_u64(21..=80), None);
+ ///
+ /// // Invalid range where the start is bigger than the end.
+ /// assert_eq!(genmask_checked_u64(15..=8), None);
+ /// ```
+ ,
+ /// # Examples
+ ///
+ /// ```
+ /// # use kernel::bits::genmask_u64;
+ /// assert_eq!(genmask_u64(21..=39), 0x0000_00ff_ffe0_0000);
+ /// assert_eq!(genmask_u64(0..=0), 0b1);
+ /// assert_eq!(genmask_u64(0..=63), u64::MAX);
+ /// ```
+);
+
+impl_genmask_fn!(
+ u32,
+ /// # Examples
+ ///
+ /// ```
+ /// # #![expect(clippy::reversed_empty_ranges)]
+ /// # use kernel::bits::genmask_checked_u32;
+ /// assert_eq!(genmask_checked_u32(0..=0), Some(0b1));
+ /// assert_eq!(genmask_checked_u32(0..=31), Some(u32::MAX));
+ /// assert_eq!(genmask_checked_u32(21..=31), Some(0xffe0_0000));
+ ///
+ /// // `40` is out of the supported bit range.
+ /// assert_eq!(genmask_checked_u32(21..=40), None);
+ ///
+ /// // Invalid range where the start is bigger than the end.
+ /// assert_eq!(genmask_checked_u32(15..=8), None);
+ /// ```
+ ,
+ /// # Examples
+ ///
+ /// ```
+ /// # use kernel::bits::genmask_u32;
+ /// assert_eq!(genmask_u32(21..=31), 0xffe0_0000);
+ /// assert_eq!(genmask_u32(0..=0), 0b1);
+ /// assert_eq!(genmask_u32(0..=31), u32::MAX);
+ /// ```
+);
+
+impl_genmask_fn!(
+ u16,
+ /// # Examples
+ ///
+ /// ```
+ /// # #![expect(clippy::reversed_empty_ranges)]
+ /// # use kernel::bits::genmask_checked_u16;
+ /// assert_eq!(genmask_checked_u16(0..=0), Some(0b1));
+ /// assert_eq!(genmask_checked_u16(0..=15), Some(u16::MAX));
+ /// assert_eq!(genmask_checked_u16(6..=15), Some(0xffc0));
+ ///
+ /// // `20` is out of the supported bit range.
+ /// assert_eq!(genmask_checked_u16(6..=20), None);
+ ///
+ /// // Invalid range where the start is bigger than the end.
+ /// assert_eq!(genmask_checked_u16(10..=5), None);
+ /// ```
+ ,
+ /// # Examples
+ ///
+ /// ```
+ /// # use kernel::bits::genmask_u16;
+ /// assert_eq!(genmask_u16(6..=15), 0xffc0);
+ /// assert_eq!(genmask_u16(0..=0), 0b1);
+ /// assert_eq!(genmask_u16(0..=15), u16::MAX);
+ /// ```
+);
+
+impl_genmask_fn!(
+ u8,
+ /// # Examples
+ ///
+ /// ```
+ /// # #![expect(clippy::reversed_empty_ranges)]
+ /// # use kernel::bits::genmask_checked_u8;
+ /// assert_eq!(genmask_checked_u8(0..=0), Some(0b1));
+ /// assert_eq!(genmask_checked_u8(0..=7), Some(u8::MAX));
+ /// assert_eq!(genmask_checked_u8(6..=7), Some(0xc0));
+ ///
+ /// // `10` is out of the supported bit range.
+ /// assert_eq!(genmask_checked_u8(6..=10), None);
+ ///
+ /// // Invalid range where the start is bigger than the end.
+ /// assert_eq!(genmask_checked_u8(5..=2), None);
+ /// ```
+ ,
+ /// # Examples
+ ///
+ /// ```
+ /// # use kernel::bits::genmask_u8;
+ /// assert_eq!(genmask_u8(6..=7), 0xc0);
+ /// assert_eq!(genmask_u8(0..=0), 0b1);
+ /// assert_eq!(genmask_u8(0..=7), u8::MAX);
+ /// ```
+);
diff --git a/rust/kernel/block/mq.rs b/rust/kernel/block/mq.rs
index fb0f393c1cea..831445d37181 100644
--- a/rust/kernel/block/mq.rs
+++ b/rust/kernel/block/mq.rs
@@ -53,7 +53,7 @@
//! [`GenDiskBuilder`]: gen_disk::GenDiskBuilder
//! [`GenDiskBuilder::build`]: gen_disk::GenDiskBuilder::build
//!
-//! # Example
+//! # Examples
//!
//! ```rust
//! use kernel::{
diff --git a/rust/kernel/block/mq/operations.rs b/rust/kernel/block/mq/operations.rs
index 864ff379dc91..c2b98f507bcb 100644
--- a/rust/kernel/block/mq/operations.rs
+++ b/rust/kernel/block/mq/operations.rs
@@ -101,7 +101,7 @@ impl<T: Operations> OperationsVTable<T> {
if let Err(e) = ret {
e.to_blk_status()
} else {
- bindings::BLK_STS_OK as _
+ bindings::BLK_STS_OK as bindings::blk_status_t
}
}
diff --git a/rust/kernel/block/mq/request.rs b/rust/kernel/block/mq/request.rs
index 4a5b7ec914ef..fefd394f064a 100644
--- a/rust/kernel/block/mq/request.rs
+++ b/rust/kernel/block/mq/request.rs
@@ -69,7 +69,7 @@ impl<T: Operations> Request<T> {
// INVARIANT: By the safety requirements of this function, invariants are upheld.
// SAFETY: By the safety requirement of this function, we own a
// reference count that we can pass to `ARef`.
- unsafe { ARef::from_raw(NonNull::new_unchecked(ptr as *const Self as *mut Self)) }
+ unsafe { ARef::from_raw(NonNull::new_unchecked(ptr.cast())) }
}
/// Notify the block layer that a request is going to be processed now.
@@ -125,7 +125,12 @@ impl<T: Operations> Request<T> {
// success of the call to `try_set_end` guarantees that there are no
// `ARef`s pointing to this request. Therefore it is safe to hand it
// back to the block layer.
- unsafe { bindings::blk_mq_end_request(request_ptr, bindings::BLK_STS_OK as _) };
+ unsafe {
+ bindings::blk_mq_end_request(
+ request_ptr,
+ bindings::BLK_STS_OK as bindings::blk_status_t,
+ )
+ };
Ok(())
}
@@ -155,7 +160,7 @@ impl<T: Operations> Request<T> {
// the private data associated with this request is initialized and
// valid. The existence of `&self` guarantees that the private data is
// valid as a shared reference.
- unsafe { Self::wrapper_ptr(self as *const Self as *mut Self).as_ref() }
+ unsafe { Self::wrapper_ptr(core::ptr::from_ref(self).cast_mut()).as_ref() }
}
}
diff --git a/rust/kernel/bug.rs b/rust/kernel/bug.rs
new file mode 100644
index 000000000000..36aef43e5ebe
--- /dev/null
+++ b/rust/kernel/bug.rs
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0
+
+// Copyright (C) 2024, 2025 FUJITA Tomonori <fujita.tomonori@gmail.com>
+
+//! Support for BUG and WARN functionality.
+//!
+//! C header: [`include/asm-generic/bug.h`](srctree/include/asm-generic/bug.h)
+
+#[macro_export]
+#[doc(hidden)]
+#[cfg(all(CONFIG_BUG, not(CONFIG_UML), not(CONFIG_LOONGARCH), not(CONFIG_ARM)))]
+#[cfg(CONFIG_DEBUG_BUGVERBOSE)]
+macro_rules! warn_flags {
+ ($flags:expr) => {
+ const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags;
+ const _FILE: &[u8] = file!().as_bytes();
+ // Plus one for null-terminator.
+ static FILE: [u8; _FILE.len() + 1] = {
+ let mut bytes = [0; _FILE.len() + 1];
+ let mut i = 0;
+ while i < _FILE.len() {
+ bytes[i] = _FILE[i];
+ i += 1;
+ }
+ bytes
+ };
+
+ // SAFETY:
+ // - `file`, `line`, `flags`, and `size` are all compile-time constants or
+ // symbols, preventing any invalid memory access.
+ // - The asm block has no side effects and does not modify any registers
+ // or memory. It is purely for embedding metadata into the ELF section.
+ unsafe {
+ $crate::asm!(
+ concat!(
+ "/* {size} */",
+ include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_warn_asm.rs")),
+ include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_reachable_asm.rs")));
+ file = sym FILE,
+ line = const line!(),
+ flags = const FLAGS,
+ size = const ::core::mem::size_of::<$crate::bindings::bug_entry>(),
+ );
+ }
+ }
+}
+
+#[macro_export]
+#[doc(hidden)]
+#[cfg(all(CONFIG_BUG, not(CONFIG_UML), not(CONFIG_LOONGARCH), not(CONFIG_ARM)))]
+#[cfg(not(CONFIG_DEBUG_BUGVERBOSE))]
+macro_rules! warn_flags {
+ ($flags:expr) => {
+ const FLAGS: u32 = $crate::bindings::BUGFLAG_WARNING | $flags;
+
+ // SAFETY:
+ // - `flags` and `size` are all compile-time constants, preventing
+ // any invalid memory access.
+ // - The asm block has no side effects and does not modify any registers
+ // or memory. It is purely for embedding metadata into the ELF section.
+ unsafe {
+ $crate::asm!(
+ concat!(
+ "/* {size} */",
+ include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_warn_asm.rs")),
+ include!(concat!(env!("OBJTREE"), "/rust/kernel/generated_arch_reachable_asm.rs")));
+ flags = const FLAGS,
+ size = const ::core::mem::size_of::<$crate::bindings::bug_entry>(),
+ );
+ }
+ }
+}
+
+#[macro_export]
+#[doc(hidden)]
+#[cfg(all(CONFIG_BUG, CONFIG_UML))]
+macro_rules! warn_flags {
+ ($flags:expr) => {
+ // SAFETY: It is always safe to call `warn_slowpath_fmt()`
+ // with a valid null-terminated string.
+ unsafe {
+ $crate::bindings::warn_slowpath_fmt(
+ $crate::c_str!(::core::file!()).as_char_ptr(),
+ line!() as $crate::ffi::c_int,
+ $flags as $crate::ffi::c_uint,
+ ::core::ptr::null(),
+ );
+ }
+ };
+}
+
+#[macro_export]
+#[doc(hidden)]
+#[cfg(all(CONFIG_BUG, any(CONFIG_LOONGARCH, CONFIG_ARM)))]
+macro_rules! warn_flags {
+ ($flags:expr) => {
+ // SAFETY: It is always safe to call `WARN_ON()`.
+ unsafe { $crate::bindings::WARN_ON(true) }
+ };
+}
+
+#[macro_export]
+#[doc(hidden)]
+#[cfg(not(CONFIG_BUG))]
+macro_rules! warn_flags {
+ ($flags:expr) => {};
+}
+
+#[doc(hidden)]
+pub const fn bugflag_taint(value: u32) -> u32 {
+ value << 8
+}
+
+/// Report a warning if `cond` is true and return the condition's evaluation result.
+#[macro_export]
+macro_rules! warn_on {
+ ($cond:expr) => {{
+ let cond = $cond;
+ if cond {
+ const WARN_ON_FLAGS: u32 = $crate::bug::bugflag_taint($crate::bindings::TAINT_WARN);
+
+ $crate::warn_flags!(WARN_ON_FLAGS);
+ }
+ cond
+ }};
+}
diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
index fbcea31dbcca..1e6c8c42fb3a 100644
--- a/rust/kernel/clk.rs
+++ b/rust/kernel/clk.rs
@@ -12,7 +12,7 @@ use crate::ffi::c_ulong;
///
/// Represents a frequency in hertz, wrapping a [`c_ulong`] value.
///
-/// ## Examples
+/// # Examples
///
/// ```
/// use kernel::clk::Hertz;
@@ -99,7 +99,7 @@ mod common_clk {
/// Instances of this type are reference-counted. Calling [`Clk::get`] ensures that the
/// allocation remains valid for the lifetime of the [`Clk`].
///
- /// ## Examples
+ /// # Examples
///
/// The following example demonstrates how to obtain and configure a clock for a device.
///
@@ -266,7 +266,7 @@ mod common_clk {
/// Instances of this type are reference-counted. Calling [`OptionalClk::get`] ensures that the
/// allocation remains valid for the lifetime of the [`OptionalClk`].
///
- /// ## Examples
+ /// # Examples
///
/// The following example demonstrates how to obtain and configure an optional clock for a
/// device. The code functions correctly whether or not the clock is available.
diff --git a/rust/kernel/configfs.rs b/rust/kernel/configfs.rs
index 34d0bea4f9a5..2736b798cdc6 100644
--- a/rust/kernel/configfs.rs
+++ b/rust/kernel/configfs.rs
@@ -17,7 +17,7 @@
//!
//! C header: [`include/linux/configfs.h`](srctree/include/linux/configfs.h)
//!
-//! # Example
+//! # Examples
//!
//! ```ignore
//! use kernel::alloc::flags;
@@ -151,7 +151,7 @@ impl<Data> Subsystem<Data> {
data: impl PinInit<Data, Error>,
) -> impl PinInit<Self, Error> {
try_pin_init!(Self {
- subsystem <- pin_init::zeroed().chain(
+ subsystem <- pin_init::init_zeroed().chain(
|place: &mut Opaque<bindings::configfs_subsystem>| {
// SAFETY: We initialized the required fields of `place.group` above.
unsafe {
@@ -261,7 +261,7 @@ impl<Data> Group<Data> {
data: impl PinInit<Data, Error>,
) -> impl PinInit<Self, Error> {
try_pin_init!(Self {
- group <- pin_init::zeroed().chain(|v: &mut Opaque<bindings::config_group>| {
+ group <- pin_init::init_zeroed().chain(|v: &mut Opaque<bindings::config_group>| {
let place = v.get();
let name = name.as_bytes_with_nul().as_ptr();
// SAFETY: It is safe to initialize a group once it has been zeroed.
@@ -279,7 +279,7 @@ impl<Data> Group<Data> {
// within the `group` field.
unsafe impl<Data> HasGroup<Data> for Group<Data> {
unsafe fn group(this: *const Self) -> *const bindings::config_group {
- Opaque::raw_get(
+ Opaque::cast_into(
// SAFETY: By impl and function safety requirements this field
// projection is within bounds of the allocation.
unsafe { &raw const (*this).group },
@@ -426,7 +426,7 @@ where
};
const fn vtable_ptr() -> *const bindings::configfs_group_operations {
- &Self::VTABLE as *const bindings::configfs_group_operations
+ &Self::VTABLE
}
}
@@ -464,7 +464,7 @@ where
};
const fn vtable_ptr() -> *const bindings::configfs_item_operations {
- &Self::VTABLE as *const bindings::configfs_item_operations
+ &Self::VTABLE
}
}
@@ -476,7 +476,7 @@ impl<Data> ItemOperationsVTable<Subsystem<Data>, Data> {
};
const fn vtable_ptr() -> *const bindings::configfs_item_operations {
- &Self::VTABLE as *const bindings::configfs_item_operations
+ &Self::VTABLE
}
}
@@ -561,7 +561,7 @@ where
let data: &Data = unsafe { get_group_data(c_group) };
// SAFETY: By function safety requirements, `page` is writable for `PAGE_SIZE`.
- let ret = O::show(data, unsafe { &mut *(page as *mut [u8; PAGE_SIZE]) });
+ let ret = O::show(data, unsafe { &mut *(page.cast::<[u8; PAGE_SIZE]>()) });
match ret {
Ok(size) => size as isize,
@@ -717,11 +717,7 @@ impl<const N: usize, Data> AttributeList<N, Data> {
// SAFETY: By function safety requirements, we have exclusive access to
// `self` and the reference created below will be exclusive.
- unsafe {
- (&mut *self.0.get())[I] = (attribute as *const Attribute<ID, O, Data>)
- .cast_mut()
- .cast()
- };
+ unsafe { (&mut *self.0.get())[I] = core::ptr::from_ref(attribute).cast_mut().cast() };
}
}
@@ -761,9 +757,7 @@ macro_rules! impl_item_type {
ct_owner: owner.as_ptr(),
ct_group_ops: GroupOperationsVTable::<Data, Child>::vtable_ptr().cast_mut(),
ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(),
- ct_attrs: (attributes as *const AttributeList<N, Data>)
- .cast_mut()
- .cast(),
+ ct_attrs: core::ptr::from_ref(attributes).cast_mut().cast(),
ct_bin_attrs: core::ptr::null_mut(),
}),
_p: PhantomData,
@@ -780,9 +774,7 @@ macro_rules! impl_item_type {
ct_owner: owner.as_ptr(),
ct_group_ops: core::ptr::null_mut(),
ct_item_ops: ItemOperationsVTable::<$tpe, Data>::vtable_ptr().cast_mut(),
- ct_attrs: (attributes as *const AttributeList<N, Data>)
- .cast_mut()
- .cast(),
+ ct_attrs: core::ptr::from_ref(attributes).cast_mut().cast(),
ct_bin_attrs: core::ptr::null_mut(),
}),
_p: PhantomData,
diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs
index d0ea24236ae4..afc15e72a7c3 100644
--- a/rust/kernel/cpufreq.rs
+++ b/rust/kernel/cpufreq.rs
@@ -202,7 +202,7 @@ impl From<TableIndex> for usize {
/// The callers must ensure that the `struct cpufreq_frequency_table` is valid for access and
/// remains valid for the lifetime of the returned reference.
///
-/// ## Examples
+/// # Examples
///
/// The following example demonstrates how to read a frequency value from [`Table`].
///
@@ -318,7 +318,7 @@ impl Deref for TableBox {
///
/// This is used by the CPU frequency drivers to build a frequency table dynamically.
///
-/// ## Examples
+/// # Examples
///
/// The following example demonstrates how to create a CPU frequency table.
///
@@ -395,7 +395,7 @@ impl TableBuilder {
/// The callers must ensure that the `struct cpufreq_policy` is valid for access and remains valid
/// for the lifetime of the returned reference.
///
-/// ## Examples
+/// # Examples
///
/// The following example demonstrates how to create a CPU frequency table.
///
@@ -649,7 +649,7 @@ impl Policy {
fn set_data<T: ForeignOwnable>(&mut self, data: T) -> Result {
if self.as_ref().driver_data.is_null() {
// Transfer the ownership of the data to the foreign interface.
- self.as_mut_ref().driver_data = <T as ForeignOwnable>::into_foreign(data) as _;
+ self.as_mut_ref().driver_data = <T as ForeignOwnable>::into_foreign(data).cast();
Ok(())
} else {
Err(EBUSY)
@@ -834,7 +834,7 @@ pub trait Driver {
/// CPU frequency driver Registration.
///
-/// ## Examples
+/// # Examples
///
/// The following example demonstrates how to register a cpufreq driver.
///
diff --git a/rust/kernel/cpumask.rs b/rust/kernel/cpumask.rs
index e07f8ff5e3fd..3fcbff438670 100644
--- a/rust/kernel/cpumask.rs
+++ b/rust/kernel/cpumask.rs
@@ -27,7 +27,7 @@ use core::ops::{Deref, DerefMut};
/// The callers must ensure that the `struct cpumask` is valid for access and
/// remains valid for the lifetime of the returned reference.
///
-/// ## Examples
+/// # Examples
///
/// The following example demonstrates how to update a [`Cpumask`].
///
@@ -172,7 +172,7 @@ impl Cpumask {
/// The callers must ensure that the `struct cpumask_var_t` is valid for access and remains valid
/// for the lifetime of [`CpumaskVar`].
///
-/// ## Examples
+/// # Examples
///
/// The following example demonstrates how to create and update a [`CpumaskVar`].
///
diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
index ca82926fd67f..b8613289de8e 100644
--- a/rust/kernel/device.rs
+++ b/rust/kernel/device.rs
@@ -262,10 +262,10 @@ impl<Ctx: DeviceContext> Device<Ctx> {
#[cfg(CONFIG_PRINTK)]
unsafe {
bindings::_dev_printk(
- klevel as *const _ as *const crate::ffi::c_char,
+ klevel.as_ptr().cast::<crate::ffi::c_char>(),
self.as_raw(),
c_str!("%pA").as_char_ptr(),
- &msg as *const _ as *const crate::ffi::c_void,
+ core::ptr::from_ref(&msg).cast::<crate::ffi::c_void>(),
)
};
}
diff --git a/rust/kernel/device_id.rs b/rust/kernel/device_id.rs
index 8ed2c946144c..70d57814ff79 100644
--- a/rust/kernel/device_id.rs
+++ b/rust/kernel/device_id.rs
@@ -100,7 +100,7 @@ impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
unsafe {
raw_ids[i]
.as_mut_ptr()
- .byte_offset(data_offset as _)
+ .byte_add(data_offset)
.cast::<usize>()
.write(i);
}
@@ -177,7 +177,7 @@ impl<T: RawDeviceId, U, const N: usize> IdTable<T, U> for IdArray<T, U, N> {
fn as_ptr(&self) -> *const T::RawType {
// This cannot be `self.ids.as_ptr()`, as the return pointer must have correct provenance
// to access the sentinel.
- (self as *const Self).cast()
+ core::ptr::from_ref(self).cast()
}
fn id(&self, index: usize) -> &T::RawType {
diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
index 152a89b78943..da18091143a6 100644
--- a/rust/kernel/devres.rs
+++ b/rust/kernel/devres.rs
@@ -49,7 +49,7 @@ struct Inner<T: Send> {
/// [`Devres`] users should make sure to simply free the corresponding backing resource in `T`'s
/// [`Drop`] implementation.
///
-/// # Example
+/// # Examples
///
/// ```no_run
/// # use kernel::{bindings, device::{Bound, Device}, devres::Devres, io::{Io, IoRaw}};
@@ -66,19 +66,19 @@ struct Inner<T: Send> {
/// unsafe fn new(paddr: usize) -> Result<Self>{
/// // SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is
/// // valid for `ioremap`.
-/// let addr = unsafe { bindings::ioremap(paddr as _, SIZE as _) };
+/// let addr = unsafe { bindings::ioremap(paddr as bindings::phys_addr_t, SIZE) };
/// if addr.is_null() {
/// return Err(ENOMEM);
/// }
///
-/// Ok(IoMem(IoRaw::new(addr as _, SIZE)?))
+/// Ok(IoMem(IoRaw::new(addr as usize, SIZE)?))
/// }
/// }
///
/// impl<const SIZE: usize> Drop for IoMem<SIZE> {
/// fn drop(&mut self) {
/// // SAFETY: `self.0.addr()` is guaranteed to be properly mapped by `Self::new`.
-/// unsafe { bindings::iounmap(self.0.addr() as _); };
+/// unsafe { bindings::iounmap(self.0.addr() as *mut c_void); };
/// }
/// }
///
@@ -219,7 +219,7 @@ impl<T: Send> Devres<T> {
/// An error is returned if `dev` does not match the same [`Device`] this [`Devres`] instance
/// has been created with.
///
- /// # Example
+ /// # Examples
///
/// ```no_run
/// # #![cfg(CONFIG_PCI)]
diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs
index b320779ea26f..2bc8ab51ec28 100644
--- a/rust/kernel/dma.rs
+++ b/rust/kernel/dma.rs
@@ -180,7 +180,7 @@ pub struct Attrs(u32);
impl Attrs {
/// Get the raw representation of this attribute.
pub(crate) fn as_raw(self) -> crate::ffi::c_ulong {
- self.0 as _
+ self.0 as crate::ffi::c_ulong
}
/// Check whether `flags` is contained in `self`.
@@ -333,7 +333,7 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> {
dev: dev.into(),
dma_handle,
count,
- cpu_addr: ret as *mut T,
+ cpu_addr: ret.cast::<T>(),
dma_attrs,
})
}
@@ -436,7 +436,7 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> {
/// slice is live.
/// * Callers must ensure that this call does not race with a read or write to the same region
/// while the returned slice is live.
- pub unsafe fn as_slice_mut(&self, offset: usize, count: usize) -> Result<&mut [T]> {
+ pub unsafe fn as_slice_mut(&mut self, offset: usize, count: usize) -> Result<&mut [T]> {
self.validate_range(offset, count)?;
// SAFETY:
// - The pointer is valid due to type invariant on `CoherentAllocation`,
@@ -468,7 +468,7 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> {
/// unsafe { alloc.write(buf, 0)?; }
/// # Ok::<(), Error>(()) }
/// ```
- pub unsafe fn write(&self, src: &[T], offset: usize) -> Result {
+ pub unsafe fn write(&mut self, src: &[T], offset: usize) -> Result {
self.validate_range(offset, src.len())?;
// SAFETY:
// - The pointer is valid due to type invariant on `CoherentAllocation`
@@ -556,7 +556,7 @@ impl<T: AsBytes + FromBytes> Drop for CoherentAllocation<T> {
bindings::dma_free_attrs(
self.dev.as_raw(),
size,
- self.cpu_addr as _,
+ self.cpu_addr.cast(),
self.dma_handle,
self.dma_attrs.as_raw(),
)
diff --git a/rust/kernel/drm/device.rs b/rust/kernel/drm/device.rs
index 32029fde55eb..3bb7c83966cf 100644
--- a/rust/kernel/drm/device.rs
+++ b/rust/kernel/drm/device.rs
@@ -83,13 +83,13 @@ impl<T: drm::Driver> Device<T> {
major: T::INFO.major,
minor: T::INFO.minor,
patchlevel: T::INFO.patchlevel,
- name: T::INFO.name.as_char_ptr() as *mut _,
- desc: T::INFO.desc.as_char_ptr() as *mut _,
+ name: T::INFO.name.as_char_ptr().cast_mut(),
+ desc: T::INFO.desc.as_char_ptr().cast_mut(),
driver_features: drm::driver::FEAT_GEM,
ioctls: T::IOCTLS.as_ptr(),
num_ioctls: T::IOCTLS.len() as i32,
- fops: &Self::GEM_FOPS as _,
+ fops: &Self::GEM_FOPS,
};
const GEM_FOPS: bindings::file_operations = drm::gem::create_fops();
@@ -135,11 +135,9 @@ impl<T: drm::Driver> Device<T> {
///
/// `ptr` must be a valid pointer to a `struct device` embedded in `Self`.
unsafe fn from_drm_device(ptr: *const bindings::drm_device) -> *mut Self {
- let ptr: *const Opaque<bindings::drm_device> = ptr.cast();
-
// SAFETY: By the safety requirements of this function `ptr` is a valid pointer to a
// `struct drm_device` embedded in `Self`.
- unsafe { crate::container_of!(ptr, Self, dev) }.cast_mut()
+ unsafe { crate::container_of!(Opaque::cast_from(ptr), Self, dev) }.cast_mut()
}
/// Not intended to be called externally, except via declare_drm_ioctls!()
diff --git a/rust/kernel/drm/gem/mod.rs b/rust/kernel/drm/gem/mod.rs
index a24c9a2fc201..b71821cfb5ea 100644
--- a/rust/kernel/drm/gem/mod.rs
+++ b/rust/kernel/drm/gem/mod.rs
@@ -125,11 +125,9 @@ impl<T: DriverObject> IntoGEMObject for Object<T> {
}
unsafe fn from_raw<'a>(self_ptr: *mut bindings::drm_gem_object) -> &'a Self {
- let self_ptr: *mut Opaque<bindings::drm_gem_object> = self_ptr.cast();
-
// SAFETY: `obj` is guaranteed to be in an `Object<T>` via the safety contract of this
// function
- unsafe { &*crate::container_of!(self_ptr, Object<T>, obj) }
+ unsafe { &*crate::container_of!(Opaque::cast_from(self_ptr), Object<T>, obj) }
}
}
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index 083c7b068cf4..a41de293dcd1 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -6,10 +6,10 @@
use crate::{
alloc::{layout::LayoutError, AllocError},
+ fmt,
str::CStr,
};
-use core::fmt;
use core::num::NonZeroI32;
use core::num::TryFromIntError;
use core::str::Utf8Error;
@@ -154,7 +154,7 @@ impl Error {
/// Returns the error encoded as a pointer.
pub fn to_ptr<T>(self) -> *mut T {
// SAFETY: `self.0` is a valid error due to its invariant.
- unsafe { bindings::ERR_PTR(self.0.get() as _) as *mut _ }
+ unsafe { bindings::ERR_PTR(self.0.get() as crate::ffi::c_long).cast() }
}
/// Returns a string representing the error, if one exists.
@@ -189,7 +189,7 @@ impl fmt::Debug for Error {
Some(name) => f
.debug_tuple(
// SAFETY: These strings are ASCII-only.
- unsafe { core::str::from_utf8_unchecked(name) },
+ unsafe { core::str::from_utf8_unchecked(name.to_bytes()) },
)
.finish(),
}
@@ -220,8 +220,8 @@ impl From<LayoutError> for Error {
}
}
-impl From<core::fmt::Error> for Error {
- fn from(_: core::fmt::Error) -> Error {
+impl From<fmt::Error> for Error {
+ fn from(_: fmt::Error) -> Error {
code::EINVAL
}
}
diff --git a/rust/kernel/firmware.rs b/rust/kernel/firmware.rs
index 4fe621f35716..1abab5b2f052 100644
--- a/rust/kernel/firmware.rs
+++ b/rust/kernel/firmware.rs
@@ -62,10 +62,11 @@ impl Firmware {
fn request_internal(name: &CStr, dev: &Device, func: FwFunc) -> Result<Self> {
let mut fw: *mut bindings::firmware = core::ptr::null_mut();
let pfw: *mut *mut bindings::firmware = &mut fw;
+ let pfw: *mut *const bindings::firmware = pfw.cast();
// SAFETY: `pfw` is a valid pointer to a NULL initialized `bindings::firmware` pointer.
// `name` and `dev` are valid as by their type invariants.
- let ret = unsafe { func.0(pfw as _, name.as_char_ptr(), dev.as_raw()) };
+ let ret = unsafe { func.0(pfw, name.as_char_ptr(), dev.as_raw()) };
if ret != 0 {
return Err(Error::from_errno(ret));
}
@@ -139,7 +140,7 @@ unsafe impl Sync for Firmware {}
/// Typically, such contracts would be enforced by a trait, however traits do not (yet) support
/// const functions.
///
-/// # Example
+/// # Examples
///
/// ```
/// # mod module_firmware_test {
@@ -181,7 +182,7 @@ unsafe impl Sync for Firmware {}
/// module! {
/// type: MyModule,
/// name: "module_firmware_test",
-/// author: "Rust for Linux",
+/// authors: ["Rust for Linux"],
/// description: "module_firmware! test module",
/// license: "GPL",
/// }
@@ -261,7 +262,7 @@ impl<const N: usize> ModInfoBuilder<N> {
/// Append path components to the [`ModInfoBuilder`] instance. Paths need to be separated
/// with [`ModInfoBuilder::new_entry`].
///
- /// # Example
+ /// # Examples
///
/// ```
/// use kernel::firmware::ModInfoBuilder;
diff --git a/rust/kernel/fmt.rs b/rust/kernel/fmt.rs
new file mode 100644
index 000000000000..0306e8388968
--- /dev/null
+++ b/rust/kernel/fmt.rs
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Formatting utilities.
+//!
+//! This module is intended to be used in place of `core::fmt` in kernel code.
+
+pub use core::fmt::{Arguments, Debug, Display, Error, Formatter, Result, Write};
diff --git a/rust/kernel/fs/file.rs b/rust/kernel/fs/file.rs
index 72d84fb0e266..35fd5db35c46 100644
--- a/rust/kernel/fs/file.rs
+++ b/rust/kernel/fs/file.rs
@@ -366,7 +366,7 @@ impl core::ops::Deref for File {
//
// By the type invariants, there are no `fdget_pos` calls that did not take the
// `f_pos_lock` mutex.
- unsafe { LocalFile::from_raw_file(self as *const File as *const bindings::file) }
+ unsafe { LocalFile::from_raw_file(core::ptr::from_ref(self).cast()) }
}
}
diff --git a/rust/kernel/generated_arch_reachable_asm.rs.S b/rust/kernel/generated_arch_reachable_asm.rs.S
new file mode 100644
index 000000000000..3886a9ad3a99
--- /dev/null
+++ b/rust/kernel/generated_arch_reachable_asm.rs.S
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/bug.h>
+
+// Cut here.
+
+::kernel::concat_literals!(ARCH_WARN_REACHABLE)
diff --git a/rust/kernel/generated_arch_warn_asm.rs.S b/rust/kernel/generated_arch_warn_asm.rs.S
new file mode 100644
index 000000000000..409eb4c2d3a1
--- /dev/null
+++ b/rust/kernel/generated_arch_warn_asm.rs.S
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/bug.h>
+
+// Cut here.
+
+::kernel::concat_literals!(ARCH_WARN_ASM("{file}", "{line}", "{flags}", "{size}"))
diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs
index 21ef202ab0db..4949047af8d7 100644
--- a/rust/kernel/init.rs
+++ b/rust/kernel/init.rs
@@ -29,15 +29,15 @@
//!
//! ## General Examples
//!
-//! ```rust,ignore
-//! # #![allow(clippy::disallowed_names)]
+//! ```rust
+//! # #![expect(clippy::disallowed_names, clippy::undocumented_unsafe_blocks)]
//! use kernel::types::Opaque;
//! use pin_init::pin_init_from_closure;
//!
//! // assume we have some `raw_foo` type in C:
//! #[repr(C)]
//! struct RawFoo([u8; 16]);
-//! extern {
+//! extern "C" {
//! fn init_foo(_: *mut RawFoo);
//! }
//!
@@ -66,25 +66,17 @@
//! });
//! ```
//!
-//! ```rust,ignore
-//! # #![allow(unreachable_pub, clippy::disallowed_names)]
+//! ```rust
+//! # #![expect(unreachable_pub, clippy::disallowed_names)]
//! use kernel::{prelude::*, types::Opaque};
//! use core::{ptr::addr_of_mut, marker::PhantomPinned, pin::Pin};
//! # mod bindings {
-//! # #![allow(non_camel_case_types)]
+//! # #![expect(non_camel_case_types, clippy::missing_safety_doc)]
//! # pub struct foo;
//! # pub unsafe fn init_foo(_ptr: *mut foo) {}
//! # pub unsafe fn destroy_foo(_ptr: *mut foo) {}
//! # pub unsafe fn enable_foo(_ptr: *mut foo, _flags: u32) -> i32 { 0 }
//! # }
-//! # // `Error::from_errno` is `pub(crate)` in the `kernel` crate, thus provide a workaround.
-//! # trait FromErrno {
-//! # fn from_errno(errno: core::ffi::c_int) -> Error {
-//! # // Dummy error that can be constructed outside the `kernel` crate.
-//! # Error::from(core::fmt::Error)
-//! # }
-//! # }
-//! # impl FromErrno for Error {}
//! /// # Invariants
//! ///
//! /// `foo` is always initialized
@@ -108,13 +100,13 @@
//! let foo = addr_of_mut!((*slot).foo);
//!
//! // Initialize the `foo`
-//! bindings::init_foo(Opaque::raw_get(foo));
+//! bindings::init_foo(Opaque::cast_into(foo));
//!
//! // Try to enable it.
-//! let err = bindings::enable_foo(Opaque::raw_get(foo), flags);
+//! let err = bindings::enable_foo(Opaque::cast_into(foo), flags);
//! if err != 0 {
//! // Enabling has failed, first clean up the foo and then return the error.
-//! bindings::destroy_foo(Opaque::raw_get(foo));
+//! bindings::destroy_foo(Opaque::cast_into(foo));
//! return Err(Error::from_errno(err));
//! }
//!
@@ -206,7 +198,7 @@ pub trait InPlaceInit<T>: Sized {
///
/// ```rust
/// use kernel::error::Error;
-/// use pin_init::zeroed;
+/// use pin_init::init_zeroed;
/// struct BigBuf {
/// big: KBox<[u8; 1024 * 1024 * 1024]>,
/// small: [u8; 1024 * 1024],
@@ -215,7 +207,7 @@ pub trait InPlaceInit<T>: Sized {
/// impl BigBuf {
/// fn new() -> impl Init<Self, Error> {
/// try_init!(Self {
-/// big: KBox::init(zeroed(), GFP_KERNEL)?,
+/// big: KBox::init(init_zeroed(), GFP_KERNEL)?,
/// small: [0; 1024 * 1024],
/// }? Error)
/// }
@@ -264,7 +256,7 @@ macro_rules! try_init {
/// ```rust
/// # #![feature(new_uninit)]
/// use kernel::error::Error;
-/// use pin_init::zeroed;
+/// use pin_init::init_zeroed;
/// #[pin_data]
/// struct BigBuf {
/// big: KBox<[u8; 1024 * 1024 * 1024]>,
@@ -275,7 +267,7 @@ macro_rules! try_init {
/// impl BigBuf {
/// fn new() -> impl PinInit<Self, Error> {
/// try_pin_init!(Self {
-/// big: KBox::init(zeroed(), GFP_KERNEL)?,
+/// big: KBox::init(init_zeroed(), GFP_KERNEL)?,
/// small: [0; 1024 * 1024],
/// ptr: core::ptr::null_mut(),
/// }? Error)
diff --git a/rust/kernel/io.rs b/rust/kernel/io.rs
index b7fc759f8b5d..03b467722b86 100644
--- a/rust/kernel/io.rs
+++ b/rust/kernel/io.rs
@@ -5,7 +5,7 @@
//! C header: [`include/asm-generic/io.h`](srctree/include/asm-generic/io.h)
use crate::error::{code::EINVAL, Result};
-use crate::{bindings, build_assert};
+use crate::{bindings, build_assert, ffi::c_void};
pub mod mem;
pub mod resource;
@@ -48,7 +48,7 @@ impl<const SIZE: usize> IoRaw<SIZE> {
}
}
-/// IO-mapped memory, starting at the base address @addr and spanning @maxlen bytes.
+/// IO-mapped memory region.
///
/// The creator (usually a subsystem / bus such as PCI) is responsible for creating the
/// mapping, performing an additional region request etc.
@@ -61,7 +61,7 @@ impl<const SIZE: usize> IoRaw<SIZE> {
/// # Examples
///
/// ```no_run
-/// # use kernel::{bindings, io::{Io, IoRaw}};
+/// # use kernel::{bindings, ffi::c_void, io::{Io, IoRaw}};
/// # use core::ops::Deref;
///
/// // See also [`pci::Bar`] for a real example.
@@ -75,19 +75,19 @@ impl<const SIZE: usize> IoRaw<SIZE> {
/// unsafe fn new(paddr: usize) -> Result<Self>{
/// // SAFETY: By the safety requirements of this function [`paddr`, `paddr` + `SIZE`) is
/// // valid for `ioremap`.
-/// let addr = unsafe { bindings::ioremap(paddr as _, SIZE as _) };
+/// let addr = unsafe { bindings::ioremap(paddr as bindings::phys_addr_t, SIZE) };
/// if addr.is_null() {
/// return Err(ENOMEM);
/// }
///
-/// Ok(IoMem(IoRaw::new(addr as _, SIZE)?))
+/// Ok(IoMem(IoRaw::new(addr as usize, SIZE)?))
/// }
/// }
///
/// impl<const SIZE: usize> Drop for IoMem<SIZE> {
/// fn drop(&mut self) {
/// // SAFETY: `self.0.addr()` is guaranteed to be properly mapped by `Self::new`.
-/// unsafe { bindings::iounmap(self.0.addr() as _); };
+/// unsafe { bindings::iounmap(self.0.addr() as *mut c_void); };
/// }
/// }
///
@@ -124,7 +124,7 @@ macro_rules! define_read {
let addr = self.io_addr_assert::<$type_name>(offset);
// SAFETY: By the type invariant `addr` is a valid address for MMIO operations.
- unsafe { bindings::$c_fn(addr as _) }
+ unsafe { bindings::$c_fn(addr as *const c_void) }
}
/// Read IO data from a given offset.
@@ -136,7 +136,7 @@ macro_rules! define_read {
let addr = self.io_addr::<$type_name>(offset)?;
// SAFETY: By the type invariant `addr` is a valid address for MMIO operations.
- Ok(unsafe { bindings::$c_fn(addr as _) })
+ Ok(unsafe { bindings::$c_fn(addr as *const c_void) })
}
};
}
@@ -153,7 +153,7 @@ macro_rules! define_write {
let addr = self.io_addr_assert::<$type_name>(offset);
// SAFETY: By the type invariant `addr` is a valid address for MMIO operations.
- unsafe { bindings::$c_fn(value, addr as _, ) }
+ unsafe { bindings::$c_fn(value, addr as *mut c_void) }
}
/// Write IO data from a given offset.
@@ -165,7 +165,7 @@ macro_rules! define_write {
let addr = self.io_addr::<$type_name>(offset)?;
// SAFETY: By the type invariant `addr` is a valid address for MMIO operations.
- unsafe { bindings::$c_fn(value, addr as _) }
+ unsafe { bindings::$c_fn(value, addr as *mut c_void) }
Ok(())
}
};
diff --git a/rust/kernel/kunit.rs b/rust/kernel/kunit.rs
index b9e65905e121..41efd87595d6 100644
--- a/rust/kernel/kunit.rs
+++ b/rust/kernel/kunit.rs
@@ -7,7 +7,10 @@
//! Reference: <https://docs.kernel.org/dev-tools/kunit/index.html>
use crate::prelude::*;
-use core::{ffi::c_void, fmt};
+use core::fmt;
+
+#[cfg(CONFIG_PRINTK)]
+use crate::c_str;
/// Prints a KUnit error-level message.
///
@@ -19,8 +22,8 @@ pub fn err(args: fmt::Arguments<'_>) {
#[cfg(CONFIG_PRINTK)]
unsafe {
bindings::_printk(
- c"\x013%pA".as_ptr() as _,
- &args as *const _ as *const c_void,
+ c_str!("\x013%pA").as_char_ptr(),
+ core::ptr::from_ref(&args).cast::<c_void>(),
);
}
}
@@ -35,8 +38,8 @@ pub fn info(args: fmt::Arguments<'_>) {
#[cfg(CONFIG_PRINTK)]
unsafe {
bindings::_printk(
- c"\x016%pA".as_ptr() as _,
- &args as *const _ as *const c_void,
+ c_str!("\x016%pA").as_char_ptr(),
+ core::ptr::from_ref(&args).cast::<c_void>(),
);
}
}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index c2d1b9375205..ed53169e795c 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -62,8 +62,10 @@ pub mod acpi;
pub mod alloc;
#[cfg(CONFIG_AUXILIARY_BUS)]
pub mod auxiliary;
+pub mod bits;
#[cfg(CONFIG_BLOCK)]
pub mod block;
+pub mod bug;
#[doc(hidden)]
pub mod build_assert;
pub mod clk;
@@ -85,6 +87,7 @@ pub mod error;
pub mod faux;
#[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)]
pub mod firmware;
+pub mod fmt;
pub mod fs;
pub mod init;
pub mod io;
@@ -213,6 +216,13 @@ fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
/// Produces a pointer to an object from a pointer to one of its fields.
///
+/// If you encounter a type mismatch due to the [`Opaque`] type, then use [`Opaque::cast_into`] or
+/// [`Opaque::cast_from`] to resolve the mismatch.
+///
+/// [`Opaque`]: crate::types::Opaque
+/// [`Opaque::cast_into`]: crate::types::Opaque::cast_into
+/// [`Opaque::cast_from`]: crate::types::Opaque::cast_from
+///
/// # Safety
///
/// The pointer passed to this macro, and the pointer returned by this macro, must both be in
diff --git a/rust/kernel/list.rs b/rust/kernel/list.rs
index c391c30b80f8..44e5219cfcbc 100644
--- a/rust/kernel/list.rs
+++ b/rust/kernel/list.rs
@@ -57,14 +57,11 @@ pub use self::arc_field::{define_list_arc_field_getter, ListArcField};
/// }
/// }
///
-/// impl_has_list_links! {
-/// impl HasListLinks<0> for BasicItem { self.links }
-/// }
/// impl_list_arc_safe! {
/// impl ListArcSafe<0> for BasicItem { untracked; }
/// }
/// impl_list_item! {
-/// impl ListItem<0> for BasicItem { using ListLinks; }
+/// impl ListItem<0> for BasicItem { using ListLinks { self.links }; }
/// }
///
/// // Create a new empty list.
@@ -82,9 +79,9 @@ pub use self::arc_field::{define_list_arc_field_getter, ListArcField};
/// // [15, 10, 30]
/// {
/// let mut iter = list.iter();
-/// assert_eq!(iter.next().unwrap().value, 15);
-/// assert_eq!(iter.next().unwrap().value, 10);
-/// assert_eq!(iter.next().unwrap().value, 30);
+/// assert_eq!(iter.next().ok_or(EINVAL)?.value, 15);
+/// assert_eq!(iter.next().ok_or(EINVAL)?.value, 10);
+/// assert_eq!(iter.next().ok_or(EINVAL)?.value, 30);
/// assert!(iter.next().is_none());
///
/// // Verify the length of the list.
@@ -93,9 +90,9 @@ pub use self::arc_field::{define_list_arc_field_getter, ListArcField};
///
/// // Pop the items from the list using `pop_back()` and verify the content.
/// {
-/// assert_eq!(list.pop_back().unwrap().value, 30);
-/// assert_eq!(list.pop_back().unwrap().value, 10);
-/// assert_eq!(list.pop_back().unwrap().value, 15);
+/// assert_eq!(list.pop_back().ok_or(EINVAL)?.value, 30);
+/// assert_eq!(list.pop_back().ok_or(EINVAL)?.value, 10);
+/// assert_eq!(list.pop_back().ok_or(EINVAL)?.value, 15);
/// }
///
/// // Insert 3 elements using `push_front()`.
@@ -107,9 +104,9 @@ pub use self::arc_field::{define_list_arc_field_getter, ListArcField};
/// // [30, 10, 15]
/// {
/// let mut iter = list.iter();
-/// assert_eq!(iter.next().unwrap().value, 30);
-/// assert_eq!(iter.next().unwrap().value, 10);
-/// assert_eq!(iter.next().unwrap().value, 15);
+/// assert_eq!(iter.next().ok_or(EINVAL)?.value, 30);
+/// assert_eq!(iter.next().ok_or(EINVAL)?.value, 10);
+/// assert_eq!(iter.next().ok_or(EINVAL)?.value, 15);
/// assert!(iter.next().is_none());
///
/// // Verify the length of the list.
@@ -118,8 +115,8 @@ pub use self::arc_field::{define_list_arc_field_getter, ListArcField};
///
/// // Pop the items from the list using `pop_front()` and verify the content.
/// {
-/// assert_eq!(list.pop_front().unwrap().value, 30);
-/// assert_eq!(list.pop_front().unwrap().value, 10);
+/// assert_eq!(list.pop_front().ok_or(EINVAL)?.value, 30);
+/// assert_eq!(list.pop_front().ok_or(EINVAL)?.value, 10);
/// }
///
/// // Push `list2` to `list` through `push_all_back()`.
@@ -135,9 +132,9 @@ pub use self::arc_field::{define_list_arc_field_getter, ListArcField};
/// // list: [15, 25, 35]
/// // list2: []
/// let mut iter = list.iter();
-/// assert_eq!(iter.next().unwrap().value, 15);
-/// assert_eq!(iter.next().unwrap().value, 25);
-/// assert_eq!(iter.next().unwrap().value, 35);
+/// assert_eq!(iter.next().ok_or(EINVAL)?.value, 15);
+/// assert_eq!(iter.next().ok_or(EINVAL)?.value, 25);
+/// assert_eq!(iter.next().ok_or(EINVAL)?.value, 35);
/// assert!(iter.next().is_none());
/// assert!(list2.is_empty());
/// }
@@ -284,7 +281,7 @@ impl<const ID: u64> ListLinks<ID> {
#[inline]
unsafe fn fields(me: *mut Self) -> *mut ListLinksFields {
// SAFETY: The caller promises that the pointer is valid.
- unsafe { Opaque::raw_get(ptr::addr_of!((*me).inner)) }
+ unsafe { Opaque::cast_into(ptr::addr_of!((*me).inner)) }
}
/// # Safety
@@ -320,9 +317,6 @@ unsafe impl<T: ?Sized + Send, const ID: u64> Send for ListLinksSelfPtr<T, ID> {}
unsafe impl<T: ?Sized + Sync, const ID: u64> Sync for ListLinksSelfPtr<T, ID> {}
impl<T: ?Sized, const ID: u64> ListLinksSelfPtr<T, ID> {
- /// The offset from the [`ListLinks`] to the self pointer field.
- pub const LIST_LINKS_SELF_PTR_OFFSET: usize = core::mem::offset_of!(Self, self_ptr);
-
/// Creates a new initializer for this type.
pub fn new() -> impl PinInit<Self> {
// INVARIANT: Pin-init initializers can't be used on an existing `Arc`, so this value will
@@ -337,6 +331,16 @@ impl<T: ?Sized, const ID: u64> ListLinksSelfPtr<T, ID> {
self_ptr: Opaque::uninit(),
}
}
+
+ /// Returns a pointer to the self pointer.
+ ///
+ /// # Safety
+ ///
+ /// The provided pointer must point at a valid struct of type `Self`.
+ pub unsafe fn raw_get_self_ptr(me: *const Self) -> *const Opaque<*const T> {
+ // SAFETY: The caller promises that the pointer is valid.
+ unsafe { ptr::addr_of!((*me).self_ptr) }
+ }
}
impl<T: ?Sized + ListItem<ID>, const ID: u64> List<T, ID> {
@@ -711,14 +715,11 @@ impl<'a, T: ?Sized + ListItem<ID>, const ID: u64> Iterator for Iter<'a, T, ID> {
/// }
/// }
///
-/// kernel::list::impl_has_list_links! {
-/// impl HasListLinks<0> for ListItem { self.links }
-/// }
/// kernel::list::impl_list_arc_safe! {
/// impl ListArcSafe<0> for ListItem { untracked; }
/// }
/// kernel::list::impl_list_item! {
-/// impl ListItem<0> for ListItem { using ListLinks; }
+/// impl ListItem<0> for ListItem { using ListLinks { self.links }; }
/// }
///
/// // Use a cursor to remove the first element with the given value.
@@ -809,11 +810,11 @@ impl<'a, T: ?Sized + ListItem<ID>, const ID: u64> Iterator for Iter<'a, T, ID> {
/// merge_sorted(&mut list, list2);
///
/// let mut items = list.into_iter();
-/// assert_eq!(items.next().unwrap().value, 10);
-/// assert_eq!(items.next().unwrap().value, 11);
-/// assert_eq!(items.next().unwrap().value, 12);
-/// assert_eq!(items.next().unwrap().value, 13);
-/// assert_eq!(items.next().unwrap().value, 14);
+/// assert_eq!(items.next().ok_or(EINVAL)?.value, 10);
+/// assert_eq!(items.next().ok_or(EINVAL)?.value, 11);
+/// assert_eq!(items.next().ok_or(EINVAL)?.value, 12);
+/// assert_eq!(items.next().ok_or(EINVAL)?.value, 13);
+/// assert_eq!(items.next().ok_or(EINVAL)?.value, 14);
/// assert!(items.next().is_none());
/// # Result::<(), Error>::Ok(())
/// ```
diff --git a/rust/kernel/list/impl_list_item_mod.rs b/rust/kernel/list/impl_list_item_mod.rs
index a0438537cee1..202bc6f97c13 100644
--- a/rust/kernel/list/impl_list_item_mod.rs
+++ b/rust/kernel/list/impl_list_item_mod.rs
@@ -4,60 +4,48 @@
//! Helpers for implementing list traits safely.
-use crate::list::ListLinks;
-
-/// Declares that this type has a `ListLinks<ID>` field at a fixed offset.
+/// Declares that this type has a [`ListLinks<ID>`] field.
///
-/// This trait is only used to help implement `ListItem` safely. If `ListItem` is implemented
+/// This trait is only used to help implement [`ListItem`] safely. If [`ListItem`] is implemented
/// manually, then this trait is not needed. Use the [`impl_has_list_links!`] macro to implement
/// this trait.
///
/// # Safety
///
-/// All values of this type must have a `ListLinks<ID>` field at the given offset.
+/// The methods on this trait must have exactly the behavior that the definitions given below have.
///
-/// The behavior of `raw_get_list_links` must not be changed.
+/// [`ListLinks<ID>`]: crate::list::ListLinks
+/// [`ListItem`]: crate::list::ListItem
pub unsafe trait HasListLinks<const ID: u64 = 0> {
- /// The offset of the `ListLinks` field.
- const OFFSET: usize;
-
- /// Returns a pointer to the [`ListLinks<T, ID>`] field.
+ /// Returns a pointer to the [`ListLinks<ID>`] field.
///
/// # Safety
///
/// The provided pointer must point at a valid struct of type `Self`.
///
- /// [`ListLinks<T, ID>`]: ListLinks
- // We don't really need this method, but it's necessary for the implementation of
- // `impl_has_list_links!` to be correct.
- #[inline]
- unsafe fn raw_get_list_links(ptr: *mut Self) -> *mut ListLinks<ID> {
- // SAFETY: The caller promises that the pointer is valid. The implementer promises that the
- // `OFFSET` constant is correct.
- unsafe { (ptr as *mut u8).add(Self::OFFSET) as *mut ListLinks<ID> }
- }
+ /// [`ListLinks<ID>`]: crate::list::ListLinks
+ unsafe fn raw_get_list_links(ptr: *mut Self) -> *mut crate::list::ListLinks<ID>;
}
/// Implements the [`HasListLinks`] trait for the given type.
#[macro_export]
macro_rules! impl_has_list_links {
- ($(impl$(<$($implarg:ident),*>)?
+ ($(impl$({$($generics:tt)*})?
HasListLinks$(<$id:tt>)?
- for $self:ident $(<$($selfarg:ty),*>)?
+ for $self:ty
{ self$(.$field:ident)* }
)*) => {$(
// SAFETY: The implementation of `raw_get_list_links` only compiles if the field has the
// right type.
- //
- // The behavior of `raw_get_list_links` is not changed since the `addr_of_mut!` macro is
- // equivalent to the pointer offset operation in the trait definition.
- unsafe impl$(<$($implarg),*>)? $crate::list::HasListLinks$(<$id>)? for
- $self $(<$($selfarg),*>)?
- {
- const OFFSET: usize = ::core::mem::offset_of!(Self, $($field).*) as usize;
-
+ unsafe impl$(<$($generics)*>)? $crate::list::HasListLinks$(<$id>)? for $self {
#[inline]
unsafe fn raw_get_list_links(ptr: *mut Self) -> *mut $crate::list::ListLinks$(<$id>)? {
+ // Statically ensure that `$(.field)*` doesn't follow any pointers.
+ //
+ // Cannot be `const` because `$self` may contain generics and E0401 says constants
+ // "can't use {`Self`,generic parameters} from outer item".
+ if false { let _: usize = ::core::mem::offset_of!(Self, $($field).*); }
+
// SAFETY: The caller promises that the pointer is not dangling. We know that this
// expression doesn't follow any pointers, as the `offset_of!` invocation above
// would otherwise not compile.
@@ -68,12 +56,16 @@ macro_rules! impl_has_list_links {
}
pub use impl_has_list_links;
-/// Declares that the `ListLinks<ID>` field in this struct is inside a `ListLinksSelfPtr<T, ID>`.
+/// Declares that the [`ListLinks<ID>`] field in this struct is inside a
+/// [`ListLinksSelfPtr<T, ID>`].
///
/// # Safety
///
-/// The `ListLinks<ID>` field of this struct at the offset `HasListLinks<ID>::OFFSET` must be
-/// inside a `ListLinksSelfPtr<T, ID>`.
+/// The [`ListLinks<ID>`] field of this struct at [`HasListLinks<ID>::raw_get_list_links`] must be
+/// inside a [`ListLinksSelfPtr<T, ID>`].
+///
+/// [`ListLinks<ID>`]: crate::list::ListLinks
+/// [`ListLinksSelfPtr<T, ID>`]: crate::list::ListLinksSelfPtr
pub unsafe trait HasSelfPtr<T: ?Sized, const ID: u64 = 0>
where
Self: HasListLinks<ID>,
@@ -83,27 +75,21 @@ where
/// Implements the [`HasListLinks`] and [`HasSelfPtr`] traits for the given type.
#[macro_export]
macro_rules! impl_has_list_links_self_ptr {
- ($(impl$({$($implarg:tt)*})?
+ ($(impl$({$($generics:tt)*})?
HasSelfPtr<$item_type:ty $(, $id:tt)?>
- for $self:ident $(<$($selfarg:ty),*>)?
- { self.$field:ident }
+ for $self:ty
+ { self$(.$field:ident)* }
)*) => {$(
// SAFETY: The implementation of `raw_get_list_links` only compiles if the field has the
// right type.
- unsafe impl$(<$($implarg)*>)? $crate::list::HasSelfPtr<$item_type $(, $id)?> for
- $self $(<$($selfarg),*>)?
- {}
-
- unsafe impl$(<$($implarg)*>)? $crate::list::HasListLinks$(<$id>)? for
- $self $(<$($selfarg),*>)?
- {
- const OFFSET: usize = ::core::mem::offset_of!(Self, $field) as usize;
+ unsafe impl$(<$($generics)*>)? $crate::list::HasSelfPtr<$item_type $(, $id)?> for $self {}
+ unsafe impl$(<$($generics)*>)? $crate::list::HasListLinks$(<$id>)? for $self {
#[inline]
unsafe fn raw_get_list_links(ptr: *mut Self) -> *mut $crate::list::ListLinks$(<$id>)? {
// SAFETY: The caller promises that the pointer is not dangling.
let ptr: *mut $crate::list::ListLinksSelfPtr<$item_type $(, $id)?> =
- unsafe { ::core::ptr::addr_of_mut!((*ptr).$field) };
+ unsafe { ::core::ptr::addr_of_mut!((*ptr)$(.$field)*) };
ptr.cast()
}
}
@@ -117,15 +103,95 @@ pub use impl_has_list_links_self_ptr;
/// implement that trait.
///
/// [`ListItem`]: crate::list::ListItem
+///
+/// # Examples
+///
+/// ```
+/// #[pin_data]
+/// struct SimpleListItem {
+/// value: u32,
+/// #[pin]
+/// links: kernel::list::ListLinks,
+/// }
+///
+/// kernel::list::impl_list_arc_safe! {
+/// impl ListArcSafe<0> for SimpleListItem { untracked; }
+/// }
+///
+/// kernel::list::impl_list_item! {
+/// impl ListItem<0> for SimpleListItem { using ListLinks { self.links }; }
+/// }
+///
+/// struct ListLinksHolder {
+/// inner: kernel::list::ListLinks,
+/// }
+///
+/// #[pin_data]
+/// struct ComplexListItem<T, U> {
+/// value: Result<T, U>,
+/// #[pin]
+/// links: ListLinksHolder,
+/// }
+///
+/// kernel::list::impl_list_arc_safe! {
+/// impl{T, U} ListArcSafe<0> for ComplexListItem<T, U> { untracked; }
+/// }
+///
+/// kernel::list::impl_list_item! {
+/// impl{T, U} ListItem<0> for ComplexListItem<T, U> { using ListLinks { self.links.inner }; }
+/// }
+/// ```
+///
+/// ```
+/// #[pin_data]
+/// struct SimpleListItem {
+/// value: u32,
+/// #[pin]
+/// links: kernel::list::ListLinksSelfPtr<SimpleListItem>,
+/// }
+///
+/// kernel::list::impl_list_arc_safe! {
+/// impl ListArcSafe<0> for SimpleListItem { untracked; }
+/// }
+///
+/// kernel::list::impl_list_item! {
+/// impl ListItem<0> for SimpleListItem { using ListLinksSelfPtr { self.links }; }
+/// }
+///
+/// struct ListLinksSelfPtrHolder<T, U> {
+/// inner: kernel::list::ListLinksSelfPtr<ComplexListItem<T, U>>,
+/// }
+///
+/// #[pin_data]
+/// struct ComplexListItem<T, U> {
+/// value: Result<T, U>,
+/// #[pin]
+/// links: ListLinksSelfPtrHolder<T, U>,
+/// }
+///
+/// kernel::list::impl_list_arc_safe! {
+/// impl{T, U} ListArcSafe<0> for ComplexListItem<T, U> { untracked; }
+/// }
+///
+/// kernel::list::impl_list_item! {
+/// impl{T, U} ListItem<0> for ComplexListItem<T, U> {
+/// using ListLinksSelfPtr { self.links.inner };
+/// }
+/// }
+/// ```
#[macro_export]
macro_rules! impl_list_item {
(
- $(impl$({$($generics:tt)*})? ListItem<$num:tt> for $t:ty {
- using ListLinks;
+ $(impl$({$($generics:tt)*})? ListItem<$num:tt> for $self:ty {
+ using ListLinks { self$(.$field:ident)* };
})*
) => {$(
+ $crate::list::impl_has_list_links! {
+ impl$({$($generics)*})? HasListLinks<$num> for $self { self$(.$field)* }
+ }
+
// SAFETY: See GUARANTEES comment on each method.
- unsafe impl$(<$($generics)*>)? $crate::list::ListItem<$num> for $t {
+ unsafe impl$(<$($generics)*>)? $crate::list::ListItem<$num> for $self {
// GUARANTEES:
// * This returns the same pointer as `prepare_to_insert` because `prepare_to_insert`
// is implemented in terms of `view_links`.
@@ -139,20 +205,19 @@ macro_rules! impl_list_item {
}
// GUARANTEES:
- // * `me` originates from the most recent call to `prepare_to_insert`, which just added
- // `offset` to the pointer passed to `prepare_to_insert`. This method subtracts
- // `offset` from `me` so it returns the pointer originally passed to
- // `prepare_to_insert`.
+ // * `me` originates from the most recent call to `prepare_to_insert`, which calls
+ // `raw_get_list_link`, which is implemented using `addr_of_mut!((*self)$(.$field)*)`.
+ // This method uses `container_of` to perform the inverse operation, so it returns the
+ // pointer originally passed to `prepare_to_insert`.
// * The pointer remains valid until the next call to `post_remove` because the caller
// of the most recent call to `prepare_to_insert` promised to retain ownership of the
// `ListArc` containing `Self` until the next call to `post_remove`. The value cannot
// be destroyed while a `ListArc` reference exists.
unsafe fn view_value(me: *mut $crate::list::ListLinks<$num>) -> *const Self {
- let offset = <Self as $crate::list::HasListLinks<$num>>::OFFSET;
// SAFETY: `me` originates from the most recent call to `prepare_to_insert`, so it
- // points at the field at offset `offset` in a value of type `Self`. Thus,
- // subtracting `offset` from `me` is still in-bounds of the allocation.
- unsafe { (me as *const u8).sub(offset) as *const Self }
+ // points at the field `$field` in a value of type `Self`. Thus, reversing that
+ // operation is still in-bounds of the allocation.
+ $crate::container_of!(me, Self, $($field).*)
}
// GUARANTEES:
@@ -169,27 +234,30 @@ macro_rules! impl_list_item {
}
// GUARANTEES:
- // * `me` originates from the most recent call to `prepare_to_insert`, which just added
- // `offset` to the pointer passed to `prepare_to_insert`. This method subtracts
- // `offset` from `me` so it returns the pointer originally passed to
- // `prepare_to_insert`.
+ // * `me` originates from the most recent call to `prepare_to_insert`, which calls
+ // `raw_get_list_link`, which is implemented using `addr_of_mut!((*self)$(.$field)*)`.
+ // This method uses `container_of` to perform the inverse operation, so it returns the
+ // pointer originally passed to `prepare_to_insert`.
unsafe fn post_remove(me: *mut $crate::list::ListLinks<$num>) -> *const Self {
- let offset = <Self as $crate::list::HasListLinks<$num>>::OFFSET;
// SAFETY: `me` originates from the most recent call to `prepare_to_insert`, so it
- // points at the field at offset `offset` in a value of type `Self`. Thus,
- // subtracting `offset` from `me` is still in-bounds of the allocation.
- unsafe { (me as *const u8).sub(offset) as *const Self }
+ // points at the field `$field` in a value of type `Self`. Thus, reversing that
+ // operation is still in-bounds of the allocation.
+ $crate::container_of!(me, Self, $($field).*)
}
}
)*};
(
- $(impl$({$($generics:tt)*})? ListItem<$num:tt> for $t:ty {
- using ListLinksSelfPtr;
+ $(impl$({$($generics:tt)*})? ListItem<$num:tt> for $self:ty {
+ using ListLinksSelfPtr { self$(.$field:ident)* };
})*
) => {$(
+ $crate::list::impl_has_list_links_self_ptr! {
+ impl$({$($generics)*})? HasSelfPtr<$self> for $self { self$(.$field)* }
+ }
+
// SAFETY: See GUARANTEES comment on each method.
- unsafe impl$(<$($generics)*>)? $crate::list::ListItem<$num> for $t {
+ unsafe impl$(<$($generics)*>)? $crate::list::ListItem<$num> for $self {
// GUARANTEES:
// This implementation of `ListItem` will not give out exclusive access to the same
// `ListLinks` several times because calls to `prepare_to_insert` and `post_remove`
@@ -202,14 +270,16 @@ macro_rules! impl_list_item {
// SAFETY: The caller promises that `me` points at a valid value of type `Self`.
let links_field = unsafe { <Self as $crate::list::ListItem<$num>>::view_links(me) };
- let spoff = $crate::list::ListLinksSelfPtr::<Self, $num>::LIST_LINKS_SELF_PTR_OFFSET;
- // Goes via the offset as the field is private.
- //
- // SAFETY: The constant is equal to `offset_of!(ListLinksSelfPtr, self_ptr)`, so
- // the pointer stays in bounds of the allocation.
- let self_ptr = unsafe { (links_field as *const u8).add(spoff) }
- as *const $crate::types::Opaque<*const Self>;
- let cell_inner = $crate::types::Opaque::raw_get(self_ptr);
+ let container = $crate::container_of!(
+ links_field, $crate::list::ListLinksSelfPtr<Self, $num>, inner
+ );
+
+ // SAFETY: By the same reasoning above, `links_field` is a valid pointer.
+ let self_ptr = unsafe {
+ $crate::list::ListLinksSelfPtr::raw_get_self_ptr(container)
+ };
+
+ let cell_inner = $crate::types::Opaque::cast_into(self_ptr);
// SAFETY: This value is not accessed in any other places than `prepare_to_insert`,
// `post_remove`, or `view_value`. By the safety requirements of those methods,
@@ -228,7 +298,9 @@ macro_rules! impl_list_item {
// this value is not in a list.
unsafe fn view_links(me: *const Self) -> *mut $crate::list::ListLinks<$num> {
// SAFETY: The caller promises that `me` points at a valid value of type `Self`.
- unsafe { <Self as HasListLinks<$num>>::raw_get_list_links(me.cast_mut()) }
+ unsafe {
+ <Self as $crate::list::HasListLinks<$num>>::raw_get_list_links(me.cast_mut())
+ }
}
// This function is also used as the implementation of `post_remove`, so the caller
@@ -247,12 +319,17 @@ macro_rules! impl_list_item {
// `ListArc` containing `Self` until the next call to `post_remove`. The value cannot
// be destroyed while a `ListArc` reference exists.
unsafe fn view_value(links_field: *mut $crate::list::ListLinks<$num>) -> *const Self {
- let spoff = $crate::list::ListLinksSelfPtr::<Self, $num>::LIST_LINKS_SELF_PTR_OFFSET;
- // SAFETY: The constant is equal to `offset_of!(ListLinksSelfPtr, self_ptr)`, so
- // the pointer stays in bounds of the allocation.
- let self_ptr = unsafe { (links_field as *const u8).add(spoff) }
- as *const ::core::cell::UnsafeCell<*const Self>;
- let cell_inner = ::core::cell::UnsafeCell::raw_get(self_ptr);
+ let container = $crate::container_of!(
+ links_field, $crate::list::ListLinksSelfPtr<Self, $num>, inner
+ );
+
+ // SAFETY: By the same reasoning above, `links_field` is a valid pointer.
+ let self_ptr = unsafe {
+ $crate::list::ListLinksSelfPtr::raw_get_self_ptr(container)
+ };
+
+ let cell_inner = $crate::types::Opaque::cast_into(self_ptr);
+
// SAFETY: This is not a data race, because the only function that writes to this
// value is `prepare_to_insert`, but by the safety requirements the
// `prepare_to_insert` method may not be called in parallel with `view_value` or
diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
index a1eb5737e3cb..6373fe183b27 100644
--- a/rust/kernel/miscdevice.rs
+++ b/rust/kernel/miscdevice.rs
@@ -33,7 +33,7 @@ impl MiscDeviceOptions {
pub const fn into_raw<T: MiscDevice>(self) -> bindings::miscdevice {
// SAFETY: All zeros is valid for this C type.
let mut result: bindings::miscdevice = unsafe { MaybeUninit::zeroed().assume_init() };
- result.minor = bindings::MISC_DYNAMIC_MINOR as _;
+ result.minor = bindings::MISC_DYNAMIC_MINOR as ffi::c_int;
result.name = self.name.as_char_ptr();
result.fops = MiscdeviceVTable::<T>::build();
result
@@ -222,7 +222,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
// type.
//
// SAFETY: The open call of a file can access the private data.
- unsafe { (*raw_file).private_data = ptr.into_foreign().cast() };
+ unsafe { (*raw_file).private_data = ptr.into_foreign() };
0
}
@@ -233,7 +233,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
/// must be associated with a `MiscDeviceRegistration<T>`.
unsafe extern "C" fn release(_inode: *mut bindings::inode, file: *mut bindings::file) -> c_int {
// SAFETY: The release call of a file owns the private data.
- let private = unsafe { (*file).private_data }.cast();
+ let private = unsafe { (*file).private_data };
// SAFETY: The release call of a file owns the private data.
let ptr = unsafe { <T::Ptr as ForeignOwnable>::from_foreign(private) };
@@ -277,7 +277,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
/// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
unsafe extern "C" fn ioctl(file: *mut bindings::file, cmd: c_uint, arg: c_ulong) -> c_long {
// SAFETY: The ioctl call of a file can access the private data.
- let private = unsafe { (*file).private_data }.cast();
+ let private = unsafe { (*file).private_data };
// SAFETY: Ioctl calls can borrow the private data of the file.
let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
@@ -302,7 +302,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
arg: c_ulong,
) -> c_long {
// SAFETY: The compat ioctl call of a file can access the private data.
- let private = unsafe { (*file).private_data }.cast();
+ let private = unsafe { (*file).private_data };
// SAFETY: Ioctl calls can borrow the private data of the file.
let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
@@ -323,7 +323,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
/// - `seq_file` must be a valid `struct seq_file` that we can write to.
unsafe extern "C" fn show_fdinfo(seq_file: *mut bindings::seq_file, file: *mut bindings::file) {
// SAFETY: The release call of a file owns the private data.
- let private = unsafe { (*file).private_data }.cast();
+ let private = unsafe { (*file).private_data };
// SAFETY: Ioctl calls can borrow the private data of the file.
let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
// SAFETY:
diff --git a/rust/kernel/mm/virt.rs b/rust/kernel/mm/virt.rs
index 31803674aecc..6086ca981b06 100644
--- a/rust/kernel/mm/virt.rs
+++ b/rust/kernel/mm/virt.rs
@@ -392,80 +392,80 @@ pub mod flags {
use crate::bindings;
/// No flags are set.
- pub const NONE: vm_flags_t = bindings::VM_NONE as _;
+ pub const NONE: vm_flags_t = bindings::VM_NONE as vm_flags_t;
/// Mapping allows reads.
- pub const READ: vm_flags_t = bindings::VM_READ as _;
+ pub const READ: vm_flags_t = bindings::VM_READ as vm_flags_t;
/// Mapping allows writes.
- pub const WRITE: vm_flags_t = bindings::VM_WRITE as _;
+ pub const WRITE: vm_flags_t = bindings::VM_WRITE as vm_flags_t;
/// Mapping allows execution.
- pub const EXEC: vm_flags_t = bindings::VM_EXEC as _;
+ pub const EXEC: vm_flags_t = bindings::VM_EXEC as vm_flags_t;
/// Mapping is shared.
- pub const SHARED: vm_flags_t = bindings::VM_SHARED as _;
+ pub const SHARED: vm_flags_t = bindings::VM_SHARED as vm_flags_t;
/// Mapping may be updated to allow reads.
- pub const MAYREAD: vm_flags_t = bindings::VM_MAYREAD as _;
+ pub const MAYREAD: vm_flags_t = bindings::VM_MAYREAD as vm_flags_t;
/// Mapping may be updated to allow writes.
- pub const MAYWRITE: vm_flags_t = bindings::VM_MAYWRITE as _;
+ pub const MAYWRITE: vm_flags_t = bindings::VM_MAYWRITE as vm_flags_t;
/// Mapping may be updated to allow execution.
- pub const MAYEXEC: vm_flags_t = bindings::VM_MAYEXEC as _;
+ pub const MAYEXEC: vm_flags_t = bindings::VM_MAYEXEC as vm_flags_t;
/// Mapping may be updated to be shared.
- pub const MAYSHARE: vm_flags_t = bindings::VM_MAYSHARE as _;
+ pub const MAYSHARE: vm_flags_t = bindings::VM_MAYSHARE as vm_flags_t;
/// Page-ranges managed without `struct page`, just pure PFN.
- pub const PFNMAP: vm_flags_t = bindings::VM_PFNMAP as _;
+ pub const PFNMAP: vm_flags_t = bindings::VM_PFNMAP as vm_flags_t;
/// Memory mapped I/O or similar.
- pub const IO: vm_flags_t = bindings::VM_IO as _;
+ pub const IO: vm_flags_t = bindings::VM_IO as vm_flags_t;
/// Do not copy this vma on fork.
- pub const DONTCOPY: vm_flags_t = bindings::VM_DONTCOPY as _;
+ pub const DONTCOPY: vm_flags_t = bindings::VM_DONTCOPY as vm_flags_t;
/// Cannot expand with mremap().
- pub const DONTEXPAND: vm_flags_t = bindings::VM_DONTEXPAND as _;
+ pub const DONTEXPAND: vm_flags_t = bindings::VM_DONTEXPAND as vm_flags_t;
/// Lock the pages covered when they are faulted in.
- pub const LOCKONFAULT: vm_flags_t = bindings::VM_LOCKONFAULT as _;
+ pub const LOCKONFAULT: vm_flags_t = bindings::VM_LOCKONFAULT as vm_flags_t;
/// Is a VM accounted object.
- pub const ACCOUNT: vm_flags_t = bindings::VM_ACCOUNT as _;
+ pub const ACCOUNT: vm_flags_t = bindings::VM_ACCOUNT as vm_flags_t;
/// Should the VM suppress accounting.
- pub const NORESERVE: vm_flags_t = bindings::VM_NORESERVE as _;
+ pub const NORESERVE: vm_flags_t = bindings::VM_NORESERVE as vm_flags_t;
/// Huge TLB Page VM.
- pub const HUGETLB: vm_flags_t = bindings::VM_HUGETLB as _;
+ pub const HUGETLB: vm_flags_t = bindings::VM_HUGETLB as vm_flags_t;
/// Synchronous page faults. (DAX-specific)
- pub const SYNC: vm_flags_t = bindings::VM_SYNC as _;
+ pub const SYNC: vm_flags_t = bindings::VM_SYNC as vm_flags_t;
/// Architecture-specific flag.
- pub const ARCH_1: vm_flags_t = bindings::VM_ARCH_1 as _;
+ pub const ARCH_1: vm_flags_t = bindings::VM_ARCH_1 as vm_flags_t;
/// Wipe VMA contents in child on fork.
- pub const WIPEONFORK: vm_flags_t = bindings::VM_WIPEONFORK as _;
+ pub const WIPEONFORK: vm_flags_t = bindings::VM_WIPEONFORK as vm_flags_t;
/// Do not include in the core dump.
- pub const DONTDUMP: vm_flags_t = bindings::VM_DONTDUMP as _;
+ pub const DONTDUMP: vm_flags_t = bindings::VM_DONTDUMP as vm_flags_t;
/// Not soft dirty clean area.
- pub const SOFTDIRTY: vm_flags_t = bindings::VM_SOFTDIRTY as _;
+ pub const SOFTDIRTY: vm_flags_t = bindings::VM_SOFTDIRTY as vm_flags_t;
/// Can contain `struct page` and pure PFN pages.
- pub const MIXEDMAP: vm_flags_t = bindings::VM_MIXEDMAP as _;
+ pub const MIXEDMAP: vm_flags_t = bindings::VM_MIXEDMAP as vm_flags_t;
/// MADV_HUGEPAGE marked this vma.
- pub const HUGEPAGE: vm_flags_t = bindings::VM_HUGEPAGE as _;
+ pub const HUGEPAGE: vm_flags_t = bindings::VM_HUGEPAGE as vm_flags_t;
/// MADV_NOHUGEPAGE marked this vma.
- pub const NOHUGEPAGE: vm_flags_t = bindings::VM_NOHUGEPAGE as _;
+ pub const NOHUGEPAGE: vm_flags_t = bindings::VM_NOHUGEPAGE as vm_flags_t;
/// KSM may merge identical pages.
- pub const MERGEABLE: vm_flags_t = bindings::VM_MERGEABLE as _;
+ pub const MERGEABLE: vm_flags_t = bindings::VM_MERGEABLE as vm_flags_t;
}
diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index 602609027aa6..7de5cc7a0eee 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -142,7 +142,7 @@ impl Device {
// SAFETY: The struct invariant ensures that we may access
// this field without additional synchronization.
let bit_field = unsafe { &(*self.0.get())._bitfield_1 };
- bit_field.get(13, 1) == bindings::AUTONEG_ENABLE as u64
+ bit_field.get(13, 1) == u64::from(bindings::AUTONEG_ENABLE)
}
/// Gets the current auto-negotiation state.
@@ -419,7 +419,7 @@ impl<T: Driver> Adapter<T> {
// where we hold `phy_device->lock`, so the accessors on
// `Device` are okay to call.
let dev = unsafe { Device::from_raw(phydev) };
- T::match_phy_device(dev) as i32
+ T::match_phy_device(dev).into()
}
/// # Safety
diff --git a/rust/kernel/of.rs b/rust/kernel/of.rs
index 0888469bddb7..b76b35265df2 100644
--- a/rust/kernel/of.rs
+++ b/rust/kernel/of.rs
@@ -27,7 +27,7 @@ unsafe impl RawDeviceIdIndex for DeviceId {
const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::of_device_id, data);
fn index(&self) -> usize {
- self.0.data as _
+ self.0.data as usize
}
}
@@ -39,10 +39,10 @@ impl DeviceId {
// SAFETY: FFI type is valid to be zero-initialized.
let mut of: bindings::of_device_id = unsafe { core::mem::zeroed() };
- // TODO: Use `clone_from_slice` once the corresponding types do match.
+ // TODO: Use `copy_from_slice` once stabilized for `const`.
let mut i = 0;
while i < src.len() {
- of.compatible[i] = src[i] as _;
+ of.compatible[i] = src[i];
i += 1;
}
diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs
index 846583da9a2f..08126035d2c6 100644
--- a/rust/kernel/opp.rs
+++ b/rust/kernel/opp.rs
@@ -92,7 +92,7 @@ fn to_c_str_array(names: &[CString]) -> Result<KVec<*const u8>> {
let mut list = KVec::with_capacity(names.len() + 1, GFP_KERNEL)?;
for name in names.iter() {
- list.push(name.as_ptr() as _, GFP_KERNEL)?;
+ list.push(name.as_ptr().cast(), GFP_KERNEL)?;
}
list.push(ptr::null(), GFP_KERNEL)?;
@@ -103,7 +103,7 @@ fn to_c_str_array(names: &[CString]) -> Result<KVec<*const u8>> {
///
/// Represents voltage in microvolts, wrapping a [`c_ulong`] value.
///
-/// ## Examples
+/// # Examples
///
/// ```
/// use kernel::opp::MicroVolt;
@@ -128,7 +128,7 @@ impl From<MicroVolt> for c_ulong {
///
/// Represents power in microwatts, wrapping a [`c_ulong`] value.
///
-/// ## Examples
+/// # Examples
///
/// ```
/// use kernel::opp::MicroWatt;
@@ -153,7 +153,7 @@ impl From<MicroWatt> for c_ulong {
///
/// The associated [`OPP`] is automatically removed when the [`Token`] is dropped.
///
-/// ## Examples
+/// # Examples
///
/// The following example demonstrates how to create an [`OPP`] dynamically.
///
@@ -202,7 +202,7 @@ impl Drop for Token {
/// Rust abstraction for the C `struct dev_pm_opp_data`, used to define operating performance
/// points (OPPs) dynamically.
///
-/// ## Examples
+/// # Examples
///
/// The following example demonstrates how to create an [`OPP`] with [`Data`].
///
@@ -254,7 +254,7 @@ impl Data {
/// [`OPP`] search options.
///
-/// ## Examples
+/// # Examples
///
/// Defines how to search for an [`OPP`] in a [`Table`] relative to a frequency.
///
@@ -326,7 +326,7 @@ impl Drop for ConfigToken {
///
/// Rust abstraction for the C `struct dev_pm_opp_config`.
///
-/// ## Examples
+/// # Examples
///
/// The following example demonstrates how to set OPP property-name configuration for a [`Device`].
///
@@ -345,7 +345,7 @@ impl Drop for ConfigToken {
/// impl ConfigOps for Driver {}
///
/// fn configure(dev: &ARef<Device>) -> Result<ConfigToken> {
-/// let name = CString::try_from_fmt(fmt!("{}", "slow"))?;
+/// let name = CString::try_from_fmt(fmt!("slow"))?;
///
/// // The OPP configuration is cleared once the [`ConfigToken`] goes out of scope.
/// Config::<Driver>::new()
@@ -569,7 +569,7 @@ impl<T: ConfigOps + Default> Config<T> {
///
/// Instances of this type are reference-counted.
///
-/// ## Examples
+/// # Examples
///
/// The following example demonstrates how to get OPP [`Table`] for a [`Cpumask`] and set its
/// frequency.
@@ -1011,7 +1011,7 @@ impl Drop for Table {
///
/// A reference to the [`OPP`], &[`OPP`], isn't refcounted by the Rust code.
///
-/// ## Examples
+/// # Examples
///
/// The following example demonstrates how to get [`OPP`] corresponding to a frequency value and
/// configure the device with it.
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index 44a2f3d2884a..887ee611b553 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -98,7 +98,7 @@ impl<T: Driver + 'static> Adapter<T> {
/// Declares a kernel module that exposes a single PCI driver.
///
-/// # Example
+/// # Examples
///
///```ignore
/// kernel::module_pci_driver! {
@@ -170,7 +170,7 @@ unsafe impl RawDeviceIdIndex for DeviceId {
const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::pci_device_id, driver_data);
fn index(&self) -> usize {
- self.0.driver_data as _
+ self.0.driver_data
}
}
@@ -193,7 +193,7 @@ macro_rules! pci_device_table {
/// The PCI driver trait.
///
-/// # Example
+/// # Examples
///
///```
/// # use kernel::{bindings, device::Core, pci};
@@ -205,7 +205,10 @@ macro_rules! pci_device_table {
/// MODULE_PCI_TABLE,
/// <MyDriver as pci::Driver>::IdInfo,
/// [
-/// (pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, bindings::PCI_ANY_ID as _), ())
+/// (
+/// pci::DeviceId::from_id(bindings::PCI_VENDOR_ID_REDHAT, bindings::PCI_ANY_ID as u32),
+/// (),
+/// )
/// ]
/// );
///
@@ -344,7 +347,7 @@ impl<const SIZE: usize> Bar<SIZE> {
// `ioptr` is valid by the safety requirements.
// `num` is valid by the safety requirements.
unsafe {
- bindings::pci_iounmap(pdev.as_raw(), ioptr as _);
+ bindings::pci_iounmap(pdev.as_raw(), ioptr as *mut kernel::ffi::c_void);
bindings::pci_release_region(pdev.as_raw(), num);
}
}
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
index b4d3087aff52..8f028c76f9fa 100644
--- a/rust/kernel/platform.rs
+++ b/rust/kernel/platform.rs
@@ -132,7 +132,7 @@ macro_rules! module_platform_driver {
///
/// Drivers must implement this trait in order to get a platform driver registered.
///
-/// # Example
+/// # Examples
///
///```
/// # use kernel::{acpi, bindings, c_str, device::Core, of, platform};
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index 2f30a398dddd..25fe97aafd02 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -31,9 +31,9 @@ pub use super::{build_assert, build_error};
// `super::std_vendor` is hidden, which makes the macro inline for some reason.
#[doc(no_inline)]
pub use super::dbg;
-pub use super::fmt;
pub use super::{dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn};
pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
+pub use core::format_args as fmt;
pub use super::{try_init, try_pin_init};
@@ -46,3 +46,5 @@ pub use super::{str::CStr, ThisModule};
pub use super::init::InPlaceInit;
pub use super::current;
+
+pub use super::uaccess::UserPtr;
diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs
index 9783d960a97a..2d743d78d220 100644
--- a/rust/kernel/print.rs
+++ b/rust/kernel/print.rs
@@ -8,10 +8,10 @@
use crate::{
ffi::{c_char, c_void},
+ fmt,
prelude::*,
str::RawFormatter,
};
-use core::fmt;
// Called from `vsprintf` with format specifier `%pA`.
#[expect(clippy::missing_safety_doc)]
@@ -25,7 +25,7 @@ unsafe extern "C" fn rust_fmt_argument(
// SAFETY: The C contract guarantees that `buf` is valid if it's less than `end`.
let mut w = unsafe { RawFormatter::from_ptrs(buf.cast(), end.cast()) };
// SAFETY: TODO.
- let _ = w.write_fmt(unsafe { *(ptr as *const fmt::Arguments<'_>) });
+ let _ = w.write_fmt(unsafe { *ptr.cast::<fmt::Arguments<'_>>() });
w.pos().cast()
}
@@ -109,7 +109,7 @@ pub unsafe fn call_printk(
bindings::_printk(
format_string.as_ptr(),
module_name.as_ptr(),
- &args as *const _ as *const c_void,
+ core::ptr::from_ref(&args).cast::<c_void>(),
);
}
}
@@ -129,7 +129,7 @@ pub fn call_printk_cont(args: fmt::Arguments<'_>) {
unsafe {
bindings::_printk(
format_strings::CONT.as_ptr(),
- &args as *const _ as *const c_void,
+ core::ptr::from_ref(&args).cast::<c_void>(),
);
}
}
@@ -149,7 +149,7 @@ macro_rules! print_macro (
// takes borrows on the arguments, but does not extend the scope of temporaries.
// Therefore, a `match` expression is used to keep them around, since
// the scrutinee is kept until the end of the `match`.
- match format_args!($($arg)+) {
+ match $crate::prelude::fmt!($($arg)+) {
// SAFETY: This hidden macro should only be called by the documented
// printing macros which ensure the format string is one of the fixed
// ones. All `__LOG_PREFIX`s are null-terminated as they are generated
@@ -168,7 +168,7 @@ macro_rules! print_macro (
// The `CONT` case.
($format_string:path, true, $($arg:tt)+) => (
$crate::print::call_printk_cont(
- format_args!($($arg)+),
+ $crate::prelude::fmt!($($arg)+),
);
);
);
diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs
index 8d978c896747..b8fe6be6fcc4 100644
--- a/rust/kernel/rbtree.rs
+++ b/rust/kernel/rbtree.rs
@@ -191,6 +191,12 @@ impl<K, V> RBTree<K, V> {
}
}
+ /// Returns true if this tree is empty.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.root.rb_node.is_null()
+ }
+
/// Returns an iterator over the tree nodes, sorted by key.
pub fn iter(&self) -> Iter<'_, K, V> {
Iter {
@@ -769,23 +775,14 @@ impl<'a, K, V> Cursor<'a, K, V> {
// the tree cannot change. By the tree invariant, all nodes are valid.
unsafe { bindings::rb_erase(&mut (*this).links, addr_of_mut!(self.tree.root)) };
- let current = match (prev, next) {
- (_, Some(next)) => next,
- (Some(prev), None) => prev,
- (None, None) => {
- return (None, node);
- }
- };
+ // INVARIANT:
+ // - `current` is a valid node in the [`RBTree`] pointed to by `self.tree`.
+ let cursor = next.or(prev).map(|current| Self {
+ current,
+ tree: self.tree,
+ });
- (
- // INVARIANT:
- // - `current` is a valid node in the [`RBTree`] pointed to by `self.tree`.
- Some(Self {
- current,
- tree: self.tree,
- }),
- node,
- )
+ (cursor, node)
}
/// Remove the previous node, returning it if it exists.
diff --git a/rust/kernel/revocable.rs b/rust/kernel/revocable.rs
index 46768b374656..0f4ae673256d 100644
--- a/rust/kernel/revocable.rs
+++ b/rust/kernel/revocable.rs
@@ -233,6 +233,10 @@ impl<T> PinnedDrop for Revocable<T> {
///
/// The RCU read-side lock is held while the guard is alive.
pub struct RevocableGuard<'a, T> {
+ // This can't use the `&'a T` type because references that appear in function arguments must
+ // not become dangling during the execution of the function, which can happen if the
+ // `RevocableGuard` is passed as a function argument and then dropped during execution of the
+ // function.
data_ref: *const T,
_rcu_guard: rcu::Guard,
_p: PhantomData<&'a ()>,
diff --git a/rust/kernel/seq_file.rs b/rust/kernel/seq_file.rs
index 7a9403eb6e5b..8f199b1a3bb1 100644
--- a/rust/kernel/seq_file.rs
+++ b/rust/kernel/seq_file.rs
@@ -37,7 +37,7 @@ impl SeqFile {
bindings::seq_printf(
self.inner.get(),
c_str!("%pA").as_char_ptr(),
- &args as *const _ as *const crate::ffi::c_void,
+ core::ptr::from_ref(&args).cast::<crate::ffi::c_void>(),
);
}
}
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index a927db8e079c..6c892550c0ba 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -3,7 +3,7 @@
//! String representations.
use crate::alloc::{flags::*, AllocError, KVec};
-use core::fmt::{self, Write};
+use crate::fmt::{self, Write};
use core::ops::{self, Deref, DerefMut, Index};
use crate::prelude::*;
@@ -29,7 +29,7 @@ impl BStr {
#[inline]
pub const fn from_bytes(bytes: &[u8]) -> &Self {
// SAFETY: `BStr` is transparent to `[u8]`.
- unsafe { &*(bytes as *const [u8] as *const BStr) }
+ unsafe { &*(core::ptr::from_ref(bytes) as *const BStr) }
}
/// Strip a prefix from `self`. Delegates to [`slice::strip_prefix`].
@@ -54,14 +54,14 @@ impl fmt::Display for BStr {
/// Formats printable ASCII characters, escaping the rest.
///
/// ```
- /// # use kernel::{fmt, b_str, str::{BStr, CString}};
+ /// # use kernel::{prelude::fmt, b_str, str::{BStr, CString}};
/// let ascii = b_str!("Hello, BStr!");
- /// let s = CString::try_from_fmt(fmt!("{}", ascii))?;
- /// assert_eq!(s.as_bytes(), "Hello, BStr!".as_bytes());
+ /// let s = CString::try_from_fmt(fmt!("{ascii}"))?;
+ /// assert_eq!(s.to_bytes(), "Hello, BStr!".as_bytes());
///
/// let non_ascii = b_str!("🦀");
- /// let s = CString::try_from_fmt(fmt!("{}", non_ascii))?;
- /// assert_eq!(s.as_bytes(), "\\xf0\\x9f\\xa6\\x80".as_bytes());
+ /// let s = CString::try_from_fmt(fmt!("{non_ascii}"))?;
+ /// assert_eq!(s.to_bytes(), "\\xf0\\x9f\\xa6\\x80".as_bytes());
/// # Ok::<(), kernel::error::Error>(())
/// ```
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -85,15 +85,15 @@ impl fmt::Debug for BStr {
/// escaping the rest.
///
/// ```
- /// # use kernel::{fmt, b_str, str::{BStr, CString}};
+ /// # use kernel::{prelude::fmt, b_str, str::{BStr, CString}};
/// // Embedded double quotes are escaped.
/// let ascii = b_str!("Hello, \"BStr\"!");
- /// let s = CString::try_from_fmt(fmt!("{:?}", ascii))?;
- /// assert_eq!(s.as_bytes(), "\"Hello, \\\"BStr\\\"!\"".as_bytes());
+ /// let s = CString::try_from_fmt(fmt!("{ascii:?}"))?;
+ /// assert_eq!(s.to_bytes(), "\"Hello, \\\"BStr\\\"!\"".as_bytes());
///
/// let non_ascii = b_str!("😺");
- /// let s = CString::try_from_fmt(fmt!("{:?}", non_ascii))?;
- /// assert_eq!(s.as_bytes(), "\"\\xf0\\x9f\\x98\\xba\"".as_bytes());
+ /// let s = CString::try_from_fmt(fmt!("{non_ascii:?}"))?;
+ /// assert_eq!(s.to_bytes(), "\"\\xf0\\x9f\\x98\\xba\"".as_bytes());
/// # Ok::<(), kernel::error::Error>(())
/// ```
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -175,6 +175,15 @@ macro_rules! b_str {
}};
}
+/// Returns a C pointer to the string.
+// It is a free function rather than a method on an extension trait because:
+//
+// - error[E0379]: functions in trait impls cannot be declared const
+#[inline]
+pub const fn as_char_ptr_in_const_context(c_str: &CStr) -> *const c_char {
+ c_str.0.as_ptr()
+}
+
/// Possible errors when using conversion functions in [`CStr`].
#[derive(Debug, Clone, Copy)]
pub enum CStrConvertError {
@@ -232,12 +241,12 @@ impl CStr {
/// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr`
/// must not be mutated.
#[inline]
- pub unsafe fn from_char_ptr<'a>(ptr: *const crate::ffi::c_char) -> &'a Self {
+ pub unsafe fn from_char_ptr<'a>(ptr: *const c_char) -> &'a Self {
// SAFETY: The safety precondition guarantees `ptr` is a valid pointer
// to a `NUL`-terminated C string.
let len = unsafe { bindings::strlen(ptr) } + 1;
// SAFETY: Lifetime guaranteed by the safety precondition.
- let bytes = unsafe { core::slice::from_raw_parts(ptr as _, len) };
+ let bytes = unsafe { core::slice::from_raw_parts(ptr.cast(), len) };
// SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`.
// As we have added 1 to `len`, the last byte is known to be `NUL`.
unsafe { Self::from_bytes_with_nul_unchecked(bytes) }
@@ -290,27 +299,49 @@ impl CStr {
#[inline]
pub unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut CStr {
// SAFETY: Properties of `bytes` guaranteed by the safety precondition.
- unsafe { &mut *(bytes as *mut [u8] as *mut CStr) }
+ unsafe { &mut *(core::ptr::from_mut(bytes) as *mut CStr) }
}
/// Returns a C pointer to the string.
+ ///
+ /// Using this function in a const context is deprecated in favor of
+ /// [`as_char_ptr_in_const_context`] in preparation for replacing `CStr` with `core::ffi::CStr`
+ /// which does not have this method.
#[inline]
- pub const fn as_char_ptr(&self) -> *const crate::ffi::c_char {
- self.0.as_ptr()
+ pub const fn as_char_ptr(&self) -> *const c_char {
+ as_char_ptr_in_const_context(self)
}
/// Convert the string to a byte slice without the trailing `NUL` byte.
#[inline]
- pub fn as_bytes(&self) -> &[u8] {
+ pub fn to_bytes(&self) -> &[u8] {
&self.0[..self.len()]
}
+ /// Convert the string to a byte slice without the trailing `NUL` byte.
+ ///
+ /// This function is deprecated in favor of [`Self::to_bytes`] in preparation for replacing
+ /// `CStr` with `core::ffi::CStr` which does not have this method.
+ #[inline]
+ pub fn as_bytes(&self) -> &[u8] {
+ self.to_bytes()
+ }
+
/// Convert the string to a byte slice containing the trailing `NUL` byte.
#[inline]
- pub const fn as_bytes_with_nul(&self) -> &[u8] {
+ pub const fn to_bytes_with_nul(&self) -> &[u8] {
&self.0
}
+ /// Convert the string to a byte slice containing the trailing `NUL` byte.
+ ///
+ /// This function is deprecated in favor of [`Self::to_bytes_with_nul`] in preparation for
+ /// replacing `CStr` with `core::ffi::CStr` which does not have this method.
+ #[inline]
+ pub const fn as_bytes_with_nul(&self) -> &[u8] {
+ self.to_bytes_with_nul()
+ }
+
/// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8.
///
/// If the contents of the [`CStr`] are valid UTF-8 data, this
@@ -429,20 +460,20 @@ impl fmt::Display for CStr {
///
/// ```
/// # use kernel::c_str;
- /// # use kernel::fmt;
+ /// # use kernel::prelude::fmt;
/// # use kernel::str::CStr;
/// # use kernel::str::CString;
/// let penguin = c_str!("🐧");
- /// let s = CString::try_from_fmt(fmt!("{}", penguin))?;
- /// assert_eq!(s.as_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes());
+ /// let s = CString::try_from_fmt(fmt!("{penguin}"))?;
+ /// assert_eq!(s.to_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes());
///
/// let ascii = c_str!("so \"cool\"");
- /// let s = CString::try_from_fmt(fmt!("{}", ascii))?;
- /// assert_eq!(s.as_bytes_with_nul(), "so \"cool\"\0".as_bytes());
+ /// let s = CString::try_from_fmt(fmt!("{ascii}"))?;
+ /// assert_eq!(s.to_bytes_with_nul(), "so \"cool\"\0".as_bytes());
/// # Ok::<(), kernel::error::Error>(())
/// ```
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- for &c in self.as_bytes() {
+ for &c in self.to_bytes() {
if (0x20..0x7f).contains(&c) {
// Printable character.
f.write_char(c as char)?;
@@ -459,16 +490,16 @@ impl fmt::Debug for CStr {
///
/// ```
/// # use kernel::c_str;
- /// # use kernel::fmt;
+ /// # use kernel::prelude::fmt;
/// # use kernel::str::CStr;
/// # use kernel::str::CString;
/// let penguin = c_str!("🐧");
- /// let s = CString::try_from_fmt(fmt!("{:?}", penguin))?;
+ /// let s = CString::try_from_fmt(fmt!("{penguin:?}"))?;
/// assert_eq!(s.as_bytes_with_nul(), "\"\\xf0\\x9f\\x90\\xa7\"\0".as_bytes());
///
/// // Embedded double quotes are escaped.
/// let ascii = c_str!("so \"cool\"");
- /// let s = CString::try_from_fmt(fmt!("{:?}", ascii))?;
+ /// let s = CString::try_from_fmt(fmt!("{ascii:?}"))?;
/// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes());
/// # Ok::<(), kernel::error::Error>(())
/// ```
@@ -578,7 +609,7 @@ mod tests {
macro_rules! format {
($($f:tt)*) => ({
- CString::try_from_fmt(::kernel::fmt!($($f)*))?.to_str()?
+ CString::try_from_fmt(fmt!($($f)*))?.to_str()?
})
}
@@ -728,9 +759,9 @@ impl RawFormatter {
pub(crate) unsafe fn from_ptrs(pos: *mut u8, end: *mut u8) -> Self {
// INVARIANT: The safety requirements guarantee the type invariants.
Self {
- beg: pos as _,
- pos: pos as _,
- end: end as _,
+ beg: pos as usize,
+ pos: pos as usize,
+ end: end as usize,
}
}
@@ -755,7 +786,7 @@ impl RawFormatter {
///
/// N.B. It may point to invalid memory.
pub(crate) fn pos(&self) -> *mut u8 {
- self.pos as _
+ self.pos as *mut u8
}
/// Returns the number of bytes written to the formatter.
@@ -840,14 +871,14 @@ impl fmt::Write for Formatter {
/// # Examples
///
/// ```
-/// use kernel::{str::CString, fmt};
+/// use kernel::{str::CString, prelude::fmt};
///
/// let s = CString::try_from_fmt(fmt!("{}{}{}", "abc", 10, 20))?;
-/// assert_eq!(s.as_bytes_with_nul(), "abc1020\0".as_bytes());
+/// assert_eq!(s.to_bytes_with_nul(), "abc1020\0".as_bytes());
///
/// let tmp = "testing";
/// let s = CString::try_from_fmt(fmt!("{tmp}{}", 123))?;
-/// assert_eq!(s.as_bytes_with_nul(), "testing123\0".as_bytes());
+/// assert_eq!(s.to_bytes_with_nul(), "testing123\0".as_bytes());
///
/// // This fails because it has an embedded `NUL` byte.
/// let s = CString::try_from_fmt(fmt!("a\0b{}", 123));
@@ -917,7 +948,7 @@ impl<'a> TryFrom<&'a CStr> for CString {
fn try_from(cstr: &'a CStr) -> Result<CString, AllocError> {
let mut buf = KVec::new();
- buf.extend_from_slice(cstr.as_bytes_with_nul(), GFP_KERNEL)?;
+ buf.extend_from_slice(cstr.to_bytes_with_nul(), GFP_KERNEL)?;
// INVARIANT: The `CStr` and `CString` types have the same invariants for
// the string data, and we copied it over without changes.
@@ -930,9 +961,3 @@ impl fmt::Debug for CString {
fmt::Debug::fmt(&**self, f)
}
}
-
-/// A convenience alias for [`core::format_args`].
-#[macro_export]
-macro_rules! fmt {
- ($($f:tt)*) => ( ::core::format_args!($($f)*) )
-}
diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs
index c23a12639924..00f9b558a3ad 100644
--- a/rust/kernel/sync.rs
+++ b/rust/kernel/sync.rs
@@ -10,6 +10,7 @@ use crate::types::Opaque;
use pin_init;
mod arc;
+pub mod aref;
pub mod completion;
mod condvar;
pub mod lock;
@@ -41,7 +42,7 @@ impl LockClassKey {
/// Initializes a dynamically allocated lock class key. In the common case of using a
/// statically allocated lock class key, the static_lock_class! macro should be used instead.
///
- /// # Example
+ /// # Examples
/// ```
/// # use kernel::c_str;
/// # use kernel::alloc::KBox;
@@ -95,8 +96,11 @@ impl PinnedDrop for LockClassKey {
macro_rules! static_lock_class {
() => {{
static CLASS: $crate::sync::LockClassKey =
- // SAFETY: lockdep expects uninitialized memory when it's handed a statically allocated
- // lock_class_key
+ // Lockdep expects uninitialized memory when it's handed a statically allocated `struct
+ // lock_class_key`.
+ //
+ // SAFETY: `LockClassKey` transparently wraps `Opaque` which permits uninitialized
+ // memory.
unsafe { ::core::mem::MaybeUninit::uninit().assume_init() };
$crate::prelude::Pin::static_ref(&CLASS)
}};
diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs
index c7af0aa48a0a..63a66761d0c7 100644
--- a/rust/kernel/sync/arc.rs
+++ b/rust/kernel/sync/arc.rs
@@ -19,12 +19,14 @@
use crate::{
alloc::{AllocError, Flags, KBox},
bindings,
+ ffi::c_void,
init::InPlaceInit,
try_init,
types::{ForeignOwnable, Opaque},
};
use core::{
alloc::Layout,
+ borrow::{Borrow, BorrowMut},
fmt,
marker::PhantomData,
mem::{ManuallyDrop, MaybeUninit},
@@ -140,10 +142,9 @@ pub struct Arc<T: ?Sized> {
_p: PhantomData<ArcInner<T>>,
}
-#[doc(hidden)]
#[pin_data]
#[repr(C)]
-pub struct ArcInner<T: ?Sized> {
+struct ArcInner<T: ?Sized> {
refcount: Opaque<bindings::refcount_t>,
data: T,
}
@@ -372,20 +373,22 @@ impl<T: ?Sized> Arc<T> {
}
}
-// SAFETY: The `into_foreign` function returns a pointer that is well-aligned.
+// SAFETY: The pointer returned by `into_foreign` comes from a well aligned
+// pointer to `ArcInner<T>`.
unsafe impl<T: 'static> ForeignOwnable for Arc<T> {
- type PointedTo = ArcInner<T>;
+ const FOREIGN_ALIGN: usize = core::mem::align_of::<ArcInner<T>>();
+
type Borrowed<'a> = ArcBorrow<'a, T>;
type BorrowedMut<'a> = Self::Borrowed<'a>;
- fn into_foreign(self) -> *mut Self::PointedTo {
- ManuallyDrop::new(self).ptr.as_ptr()
+ fn into_foreign(self) -> *mut c_void {
+ ManuallyDrop::new(self).ptr.as_ptr().cast()
}
- unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self {
+ unsafe fn from_foreign(ptr: *mut c_void) -> Self {
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
// call to `Self::into_foreign`.
- let inner = unsafe { NonNull::new_unchecked(ptr) };
+ let inner = unsafe { NonNull::new_unchecked(ptr.cast::<ArcInner<T>>()) };
// SAFETY: By the safety requirement of this function, we know that `ptr` came from
// a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and
@@ -393,20 +396,20 @@ unsafe impl<T: 'static> ForeignOwnable for Arc<T> {
unsafe { Self::from_inner(inner) }
}
- unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> ArcBorrow<'a, T> {
+ unsafe fn borrow<'a>(ptr: *mut c_void) -> ArcBorrow<'a, T> {
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
// call to `Self::into_foreign`.
- let inner = unsafe { NonNull::new_unchecked(ptr) };
+ let inner = unsafe { NonNull::new_unchecked(ptr.cast::<ArcInner<T>>()) };
// SAFETY: The safety requirements of `from_foreign` ensure that the object remains alive
// for the lifetime of the returned value.
unsafe { ArcBorrow::new(inner) }
}
- unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> ArcBorrow<'a, T> {
+ unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> ArcBorrow<'a, T> {
// SAFETY: The safety requirements for `borrow_mut` are a superset of the safety
// requirements for `borrow`.
- unsafe { Self::borrow(ptr) }
+ unsafe { <Self as ForeignOwnable>::borrow(ptr) }
}
}
@@ -426,6 +429,31 @@ impl<T: ?Sized> AsRef<T> for Arc<T> {
}
}
+/// # Examples
+///
+/// ```
+/// # use core::borrow::Borrow;
+/// # use kernel::sync::Arc;
+/// struct Foo<B: Borrow<u32>>(B);
+///
+/// // Owned instance.
+/// let owned = Foo(1);
+///
+/// // Shared instance.
+/// let arc = Arc::new(1, GFP_KERNEL)?;
+/// let shared = Foo(arc.clone());
+///
+/// let i = 1;
+/// // Borrowed from `i`.
+/// let borrowed = Foo(&i);
+/// # Ok::<(), Error>(())
+/// ```
+impl<T: ?Sized> Borrow<T> for Arc<T> {
+ fn borrow(&self) -> &T {
+ self.deref()
+ }
+}
+
impl<T: ?Sized> Clone for Arc<T> {
fn clone(&self) -> Self {
// SAFETY: By the type invariant, there is necessarily a reference to the object, so it is
@@ -834,6 +862,56 @@ impl<T: ?Sized> DerefMut for UniqueArc<T> {
}
}
+/// # Examples
+///
+/// ```
+/// # use core::borrow::Borrow;
+/// # use kernel::sync::UniqueArc;
+/// struct Foo<B: Borrow<u32>>(B);
+///
+/// // Owned instance.
+/// let owned = Foo(1);
+///
+/// // Owned instance using `UniqueArc`.
+/// let arc = UniqueArc::new(1, GFP_KERNEL)?;
+/// let shared = Foo(arc);
+///
+/// let i = 1;
+/// // Borrowed from `i`.
+/// let borrowed = Foo(&i);
+/// # Ok::<(), Error>(())
+/// ```
+impl<T: ?Sized> Borrow<T> for UniqueArc<T> {
+ fn borrow(&self) -> &T {
+ self.deref()
+ }
+}
+
+/// # Examples
+///
+/// ```
+/// # use core::borrow::BorrowMut;
+/// # use kernel::sync::UniqueArc;
+/// struct Foo<B: BorrowMut<u32>>(B);
+///
+/// // Owned instance.
+/// let owned = Foo(1);
+///
+/// // Owned instance using `UniqueArc`.
+/// let arc = UniqueArc::new(1, GFP_KERNEL)?;
+/// let shared = Foo(arc);
+///
+/// let mut i = 1;
+/// // Borrowed from `i`.
+/// let borrowed = Foo(&mut i);
+/// # Ok::<(), Error>(())
+/// ```
+impl<T: ?Sized> BorrowMut<T> for UniqueArc<T> {
+ fn borrow_mut(&mut self) -> &mut T {
+ self.deref_mut()
+ }
+}
+
impl<T: fmt::Display + ?Sized> fmt::Display for UniqueArc<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.deref(), f)
diff --git a/rust/kernel/sync/aref.rs b/rust/kernel/sync/aref.rs
new file mode 100644
index 000000000000..dbd77bb68617
--- /dev/null
+++ b/rust/kernel/sync/aref.rs
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Internal reference counting support.
+
+use core::{marker::PhantomData, mem::ManuallyDrop, ops::Deref, ptr::NonNull};
+
+/// Types that are _always_ reference counted.
+///
+/// It allows such types to define their own custom ref increment and decrement functions.
+/// Additionally, it allows users to convert from a shared reference `&T` to an owned reference
+/// [`ARef<T>`].
+///
+/// This is usually implemented by wrappers to existing structures on the C side of the code. For
+/// Rust code, the recommendation is to use [`Arc`](crate::sync::Arc) to create reference-counted
+/// instances of a type.
+///
+/// # Safety
+///
+/// Implementers must ensure that increments to the reference count keep the object alive in memory
+/// at least until matching decrements are performed.
+///
+/// Implementers must also ensure that all instances are reference-counted. (Otherwise they
+/// won't be able to honour the requirement that [`AlwaysRefCounted::inc_ref`] keep the object
+/// alive.)
+pub unsafe trait AlwaysRefCounted {
+ /// Increments the reference count on the object.
+ fn inc_ref(&self);
+
+ /// Decrements the reference count on the object.
+ ///
+ /// Frees the object when the count reaches zero.
+ ///
+ /// # Safety
+ ///
+ /// Callers must ensure that there was a previous matching increment to the reference count,
+ /// and that the object is no longer used after its reference count is decremented (as it may
+ /// result in the object being freed), unless the caller owns another increment on the refcount
+ /// (e.g., it calls [`AlwaysRefCounted::inc_ref`] twice, then calls
+ /// [`AlwaysRefCounted::dec_ref`] once).
+ unsafe fn dec_ref(obj: NonNull<Self>);
+}
+
+/// An owned reference to an always-reference-counted object.
+///
+/// The object's reference count is automatically decremented when an instance of [`ARef`] is
+/// dropped. It is also automatically incremented when a new instance is created via
+/// [`ARef::clone`].
+///
+/// # Invariants
+///
+/// The pointer stored in `ptr` is non-null and valid for the lifetime of the [`ARef`] instance. In
+/// particular, the [`ARef`] instance owns an increment on the underlying object's reference count.
+pub struct ARef<T: AlwaysRefCounted> {
+ ptr: NonNull<T>,
+ _p: PhantomData<T>,
+}
+
+// SAFETY: It is safe to send `ARef<T>` to another thread when the underlying `T` is `Sync` because
+// it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, it needs
+// `T` to be `Send` because any thread that has an `ARef<T>` may ultimately access `T` using a
+// mutable reference, for example, when the reference count reaches zero and `T` is dropped.
+unsafe impl<T: AlwaysRefCounted + Sync + Send> Send for ARef<T> {}
+
+// SAFETY: It is safe to send `&ARef<T>` to another thread when the underlying `T` is `Sync`
+// because it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally,
+// it needs `T` to be `Send` because any thread that has a `&ARef<T>` may clone it and get an
+// `ARef<T>` on that thread, so the thread may ultimately access `T` using a mutable reference, for
+// example, when the reference count reaches zero and `T` is dropped.
+unsafe impl<T: AlwaysRefCounted + Sync + Send> Sync for ARef<T> {}
+
+impl<T: AlwaysRefCounted> ARef<T> {
+ /// Creates a new instance of [`ARef`].
+ ///
+ /// It takes over an increment of the reference count on the underlying object.
+ ///
+ /// # Safety
+ ///
+ /// Callers must ensure that the reference count was incremented at least once, and that they
+ /// are properly relinquishing one increment. That is, if there is only one increment, callers
+ /// must not use the underlying object anymore -- it is only safe to do so via the newly
+ /// created [`ARef`].
+ pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
+ // INVARIANT: The safety requirements guarantee that the new instance now owns the
+ // increment on the refcount.
+ Self {
+ ptr,
+ _p: PhantomData,
+ }
+ }
+
+ /// Consumes the `ARef`, returning a raw pointer.
+ ///
+ /// This function does not change the refcount. After calling this function, the caller is
+ /// responsible for the refcount previously managed by the `ARef`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use core::ptr::NonNull;
+ /// use kernel::types::{ARef, AlwaysRefCounted};
+ ///
+ /// struct Empty {}
+ ///
+ /// # // SAFETY: TODO.
+ /// unsafe impl AlwaysRefCounted for Empty {
+ /// fn inc_ref(&self) {}
+ /// unsafe fn dec_ref(_obj: NonNull<Self>) {}
+ /// }
+ ///
+ /// let mut data = Empty {};
+ /// let ptr = NonNull::<Empty>::new(&mut data).unwrap();
+ /// # // SAFETY: TODO.
+ /// let data_ref: ARef<Empty> = unsafe { ARef::from_raw(ptr) };
+ /// let raw_ptr: NonNull<Empty> = ARef::into_raw(data_ref);
+ ///
+ /// assert_eq!(ptr, raw_ptr);
+ /// ```
+ pub fn into_raw(me: Self) -> NonNull<T> {
+ ManuallyDrop::new(me).ptr
+ }
+}
+
+impl<T: AlwaysRefCounted> Clone for ARef<T> {
+ fn clone(&self) -> Self {
+ self.inc_ref();
+ // SAFETY: We just incremented the refcount above.
+ unsafe { Self::from_raw(self.ptr) }
+ }
+}
+
+impl<T: AlwaysRefCounted> Deref for ARef<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ // SAFETY: The type invariants guarantee that the object is valid.
+ unsafe { self.ptr.as_ref() }
+ }
+}
+
+impl<T: AlwaysRefCounted> From<&T> for ARef<T> {
+ fn from(b: &T) -> Self {
+ b.inc_ref();
+ // SAFETY: We just incremented the refcount above.
+ unsafe { Self::from_raw(NonNull::from(b)) }
+ }
+}
+
+impl<T: AlwaysRefCounted> Drop for ARef<T> {
+ fn drop(&mut self) {
+ // SAFETY: The type invariants guarantee that the `ARef` owns the reference we're about to
+ // decrement.
+ unsafe { T::dec_ref(self.ptr) };
+ }
+}
diff --git a/rust/kernel/time.rs b/rust/kernel/time.rs
index a8089a98da9e..64c8dcf548d6 100644
--- a/rust/kernel/time.rs
+++ b/rust/kernel/time.rs
@@ -24,6 +24,9 @@
//! C header: [`include/linux/jiffies.h`](srctree/include/linux/jiffies.h).
//! C header: [`include/linux/ktime.h`](srctree/include/linux/ktime.h).
+use core::marker::PhantomData;
+
+pub mod delay;
pub mod hrtimer;
/// The number of nanoseconds per microsecond.
@@ -49,26 +52,141 @@ pub fn msecs_to_jiffies(msecs: Msecs) -> Jiffies {
unsafe { bindings::__msecs_to_jiffies(msecs) }
}
+/// Trait for clock sources.
+///
+/// Selection of the clock source depends on the use case. In some cases the usage of a
+/// particular clock is mandatory, e.g. in network protocols, filesystems. In other
+/// cases the user of the clock has to decide which clock is best suited for the
+/// purpose. In most scenarios clock [`Monotonic`] is the best choice as it
+/// provides a accurate monotonic notion of time (leap second smearing ignored).
+pub trait ClockSource {
+ /// The kernel clock ID associated with this clock source.
+ ///
+ /// This constant corresponds to the C side `clockid_t` value.
+ const ID: bindings::clockid_t;
+
+ /// Get the current time from the clock source.
+ ///
+ /// The function must return a value in the range from 0 to `KTIME_MAX`.
+ fn ktime_get() -> bindings::ktime_t;
+}
+
+/// A monotonically increasing clock.
+///
+/// A nonsettable system-wide clock that represents monotonic time since as
+/// described by POSIX, "some unspecified point in the past". On Linux, that
+/// point corresponds to the number of seconds that the system has been
+/// running since it was booted.
+///
+/// The CLOCK_MONOTONIC clock is not affected by discontinuous jumps in the
+/// CLOCK_REAL (e.g., if the system administrator manually changes the
+/// clock), but is affected by frequency adjustments. This clock does not
+/// count time that the system is suspended.
+pub struct Monotonic;
+
+impl ClockSource for Monotonic {
+ const ID: bindings::clockid_t = bindings::CLOCK_MONOTONIC as bindings::clockid_t;
+
+ fn ktime_get() -> bindings::ktime_t {
+ // SAFETY: It is always safe to call `ktime_get()` outside of NMI context.
+ unsafe { bindings::ktime_get() }
+ }
+}
+
+/// A settable system-wide clock that measures real (i.e., wall-clock) time.
+///
+/// Setting this clock requires appropriate privileges. This clock is
+/// affected by discontinuous jumps in the system time (e.g., if the system
+/// administrator manually changes the clock), and by frequency adjustments
+/// performed by NTP and similar applications via adjtime(3), adjtimex(2),
+/// clock_adjtime(2), and ntp_adjtime(3). This clock normally counts the
+/// number of seconds since 1970-01-01 00:00:00 Coordinated Universal Time
+/// (UTC) except that it ignores leap seconds; near a leap second it may be
+/// adjusted by leap second smearing to stay roughly in sync with UTC. Leap
+/// second smearing applies frequency adjustments to the clock to speed up
+/// or slow down the clock to account for the leap second without
+/// discontinuities in the clock. If leap second smearing is not applied,
+/// the clock will experience discontinuity around leap second adjustment.
+pub struct RealTime;
+
+impl ClockSource for RealTime {
+ const ID: bindings::clockid_t = bindings::CLOCK_REALTIME as bindings::clockid_t;
+
+ fn ktime_get() -> bindings::ktime_t {
+ // SAFETY: It is always safe to call `ktime_get_real()` outside of NMI context.
+ unsafe { bindings::ktime_get_real() }
+ }
+}
+
+/// A monotonic that ticks while system is suspended.
+///
+/// A nonsettable system-wide clock that is identical to CLOCK_MONOTONIC,
+/// except that it also includes any time that the system is suspended. This
+/// allows applications to get a suspend-aware monotonic clock without
+/// having to deal with the complications of CLOCK_REALTIME, which may have
+/// discontinuities if the time is changed using settimeofday(2) or similar.
+pub struct BootTime;
+
+impl ClockSource for BootTime {
+ const ID: bindings::clockid_t = bindings::CLOCK_BOOTTIME as bindings::clockid_t;
+
+ fn ktime_get() -> bindings::ktime_t {
+ // SAFETY: It is always safe to call `ktime_get_boottime()` outside of NMI context.
+ unsafe { bindings::ktime_get_boottime() }
+ }
+}
+
+/// International Atomic Time.
+///
+/// A system-wide clock derived from wall-clock time but counting leap seconds.
+///
+/// This clock is coupled to CLOCK_REALTIME and will be set when CLOCK_REALTIME is
+/// set, or when the offset to CLOCK_REALTIME is changed via adjtimex(2). This
+/// usually happens during boot and **should** not happen during normal operations.
+/// However, if NTP or another application adjusts CLOCK_REALTIME by leap second
+/// smearing, this clock will not be precise during leap second smearing.
+///
+/// The acronym TAI refers to International Atomic Time.
+pub struct Tai;
+
+impl ClockSource for Tai {
+ const ID: bindings::clockid_t = bindings::CLOCK_TAI as bindings::clockid_t;
+
+ fn ktime_get() -> bindings::ktime_t {
+ // SAFETY: It is always safe to call `ktime_get_tai()` outside of NMI context.
+ unsafe { bindings::ktime_get_clocktai() }
+ }
+}
+
/// A specific point in time.
///
/// # Invariants
///
/// The `inner` value is in the range from 0 to `KTIME_MAX`.
#[repr(transparent)]
-#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord)]
-pub struct Instant {
+#[derive(PartialEq, PartialOrd, Eq, Ord)]
+pub struct Instant<C: ClockSource> {
inner: bindings::ktime_t,
+ _c: PhantomData<C>,
+}
+
+impl<C: ClockSource> Clone for Instant<C> {
+ fn clone(&self) -> Self {
+ *self
+ }
}
-impl Instant {
- /// Get the current time using `CLOCK_MONOTONIC`.
+impl<C: ClockSource> Copy for Instant<C> {}
+
+impl<C: ClockSource> Instant<C> {
+ /// Get the current time from the clock source.
#[inline]
pub fn now() -> Self {
- // INVARIANT: The `ktime_get()` function returns a value in the range
+ // INVARIANT: The `ClockSource::ktime_get()` function returns a value in the range
// from 0 to `KTIME_MAX`.
Self {
- // SAFETY: It is always safe to call `ktime_get()` outside of NMI context.
- inner: unsafe { bindings::ktime_get() },
+ inner: C::ktime_get(),
+ _c: PhantomData,
}
}
@@ -77,86 +195,25 @@ impl Instant {
pub fn elapsed(&self) -> Delta {
Self::now() - *self
}
+
+ #[inline]
+ pub(crate) fn as_nanos(&self) -> i64 {
+ self.inner
+ }
}
-impl core::ops::Sub for Instant {
+impl<C: ClockSource> core::ops::Sub for Instant<C> {
type Output = Delta;
// By the type invariant, it never overflows.
#[inline]
- fn sub(self, other: Instant) -> Delta {
+ fn sub(self, other: Instant<C>) -> Delta {
Delta {
nanos: self.inner - other.inner,
}
}
}
-/// An identifier for a clock. Used when specifying clock sources.
-///
-///
-/// Selection of the clock depends on the use case. In some cases the usage of a
-/// particular clock is mandatory, e.g. in network protocols, filesystems.In other
-/// cases the user of the clock has to decide which clock is best suited for the
-/// purpose. In most scenarios clock [`ClockId::Monotonic`] is the best choice as it
-/// provides a accurate monotonic notion of time (leap second smearing ignored).
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-#[repr(u32)]
-pub enum ClockId {
- /// A settable system-wide clock that measures real (i.e., wall-clock) time.
- ///
- /// Setting this clock requires appropriate privileges. This clock is
- /// affected by discontinuous jumps in the system time (e.g., if the system
- /// administrator manually changes the clock), and by frequency adjustments
- /// performed by NTP and similar applications via adjtime(3), adjtimex(2),
- /// clock_adjtime(2), and ntp_adjtime(3). This clock normally counts the
- /// number of seconds since 1970-01-01 00:00:00 Coordinated Universal Time
- /// (UTC) except that it ignores leap seconds; near a leap second it may be
- /// adjusted by leap second smearing to stay roughly in sync with UTC. Leap
- /// second smearing applies frequency adjustments to the clock to speed up
- /// or slow down the clock to account for the leap second without
- /// discontinuities in the clock. If leap second smearing is not applied,
- /// the clock will experience discontinuity around leap second adjustment.
- RealTime = bindings::CLOCK_REALTIME,
- /// A monotonically increasing clock.
- ///
- /// A nonsettable system-wide clock that represents monotonic time since—as
- /// described by POSIX—"some unspecified point in the past". On Linux, that
- /// point corresponds to the number of seconds that the system has been
- /// running since it was booted.
- ///
- /// The CLOCK_MONOTONIC clock is not affected by discontinuous jumps in the
- /// CLOCK_REAL (e.g., if the system administrator manually changes the
- /// clock), but is affected by frequency adjustments. This clock does not
- /// count time that the system is suspended.
- Monotonic = bindings::CLOCK_MONOTONIC,
- /// A monotonic that ticks while system is suspended.
- ///
- /// A nonsettable system-wide clock that is identical to CLOCK_MONOTONIC,
- /// except that it also includes any time that the system is suspended. This
- /// allows applications to get a suspend-aware monotonic clock without
- /// having to deal with the complications of CLOCK_REALTIME, which may have
- /// discontinuities if the time is changed using settimeofday(2) or similar.
- BootTime = bindings::CLOCK_BOOTTIME,
- /// International Atomic Time.
- ///
- /// A system-wide clock derived from wall-clock time but counting leap seconds.
- ///
- /// This clock is coupled to CLOCK_REALTIME and will be set when CLOCK_REALTIME is
- /// set, or when the offset to CLOCK_REALTIME is changed via adjtimex(2). This
- /// usually happens during boot and **should** not happen during normal operations.
- /// However, if NTP or another application adjusts CLOCK_REALTIME by leap second
- /// smearing, this clock will not be precise during leap second smearing.
- ///
- /// The acronym TAI refers to International Atomic Time.
- TAI = bindings::CLOCK_TAI,
-}
-
-impl ClockId {
- fn into_c(self) -> bindings::clockid_t {
- self as bindings::clockid_t
- }
-}
-
/// A span of time.
///
/// This struct represents a span of time, with its value stored as nanoseconds.
@@ -228,13 +285,31 @@ impl Delta {
/// Return the smallest number of microseconds greater than or equal
/// to the value in the [`Delta`].
#[inline]
- pub const fn as_micros_ceil(self) -> i64 {
- self.as_nanos().saturating_add(NSEC_PER_USEC - 1) / NSEC_PER_USEC
+ pub fn as_micros_ceil(self) -> i64 {
+ #[cfg(CONFIG_64BIT)]
+ {
+ self.as_nanos().saturating_add(NSEC_PER_USEC - 1) / NSEC_PER_USEC
+ }
+
+ #[cfg(not(CONFIG_64BIT))]
+ // SAFETY: It is always safe to call `ktime_to_us()` with any value.
+ unsafe {
+ bindings::ktime_to_us(self.as_nanos().saturating_add(NSEC_PER_USEC - 1))
+ }
}
/// Return the number of milliseconds in the [`Delta`].
#[inline]
- pub const fn as_millis(self) -> i64 {
- self.as_nanos() / NSEC_PER_MSEC
+ pub fn as_millis(self) -> i64 {
+ #[cfg(CONFIG_64BIT)]
+ {
+ self.as_nanos() / NSEC_PER_MSEC
+ }
+
+ #[cfg(not(CONFIG_64BIT))]
+ // SAFETY: It is always safe to call `ktime_to_ms()` with any value.
+ unsafe {
+ bindings::ktime_to_ms(self.as_nanos())
+ }
}
}
diff --git a/rust/kernel/time/delay.rs b/rust/kernel/time/delay.rs
new file mode 100644
index 000000000000..eb8838da62bc
--- /dev/null
+++ b/rust/kernel/time/delay.rs
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Delay and sleep primitives.
+//!
+//! This module contains the kernel APIs related to delay and sleep that
+//! have been ported or wrapped for usage by Rust code in the kernel.
+//!
+//! C header: [`include/linux/delay.h`](srctree/include/linux/delay.h).
+
+use super::Delta;
+use crate::prelude::*;
+
+/// Sleeps for a given duration at least.
+///
+/// Equivalent to the C side [`fsleep()`], flexible sleep function,
+/// which automatically chooses the best sleep method based on a duration.
+///
+/// `delta` must be within `[0, i32::MAX]` microseconds;
+/// otherwise, it is erroneous behavior. That is, it is considered a bug
+/// to call this function with an out-of-range value, in which case the function
+/// will sleep for at least the maximum value in the range and may warn
+/// in the future.
+///
+/// The behavior above differs from the C side [`fsleep()`] for which out-of-range
+/// values mean "infinite timeout" instead.
+///
+/// This function can only be used in a nonatomic context.
+///
+/// [`fsleep()`]: https://docs.kernel.org/timers/delay_sleep_functions.html#c.fsleep
+pub fn fsleep(delta: Delta) {
+ // The maximum value is set to `i32::MAX` microseconds to prevent integer
+ // overflow inside fsleep, which could lead to unintentional infinite sleep.
+ const MAX_DELTA: Delta = Delta::from_micros(i32::MAX as i64);
+
+ let delta = if (Delta::ZERO..=MAX_DELTA).contains(&delta) {
+ delta
+ } else {
+ // TODO: Add WARN_ONCE() when it's supported.
+ MAX_DELTA
+ };
+
+ // SAFETY: It is always safe to call `fsleep()` with any duration.
+ unsafe {
+ // Convert the duration to microseconds and round up to preserve
+ // the guarantee; `fsleep()` sleeps for at least the provided duration,
+ // but that it may sleep for longer under some circumstances.
+ bindings::fsleep(delta.as_micros_ceil() as c_ulong)
+ }
+}
diff --git a/rust/kernel/time/hrtimer.rs b/rust/kernel/time/hrtimer.rs
index 36e1290cd079..144e3b57cc78 100644
--- a/rust/kernel/time/hrtimer.rs
+++ b/rust/kernel/time/hrtimer.rs
@@ -67,27 +67,11 @@
//! A `restart` operation on a timer in the **stopped** state is equivalent to a
//! `start` operation.
-use super::ClockId;
+use super::{ClockSource, Delta, Instant};
use crate::{prelude::*, types::Opaque};
use core::marker::PhantomData;
use pin_init::PinInit;
-/// A Rust wrapper around a `ktime_t`.
-// NOTE: Ktime is going to be removed when hrtimer is converted to Instant/Delta.
-#[repr(transparent)]
-#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord)]
-pub struct Ktime {
- inner: bindings::ktime_t,
-}
-
-impl Ktime {
- /// Returns the number of nanoseconds.
- #[inline]
- pub fn to_ns(self) -> i64 {
- self.inner
- }
-}
-
/// A timer backed by a C `struct hrtimer`.
///
/// # Invariants
@@ -98,7 +82,6 @@ impl Ktime {
pub struct HrTimer<T> {
#[pin]
timer: Opaque<bindings::hrtimer>,
- mode: HrTimerMode,
_t: PhantomData<T>,
}
@@ -112,9 +95,10 @@ unsafe impl<T> Sync for HrTimer<T> {}
impl<T> HrTimer<T> {
/// Return an initializer for a new timer instance.
- pub fn new(mode: HrTimerMode, clock: ClockId) -> impl PinInit<Self>
+ pub fn new() -> impl PinInit<Self>
where
T: HrTimerCallback,
+ T: HasHrTimer<T>,
{
pin_init!(Self {
// INVARIANT: We initialize `timer` with `hrtimer_setup` below.
@@ -126,12 +110,11 @@ impl<T> HrTimer<T> {
bindings::hrtimer_setup(
place,
Some(T::Pointer::run),
- clock.into_c(),
- mode.into_c(),
+ <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Clock::ID,
+ <T as HasHrTimer<T>>::TimerMode::C_MODE,
);
}
}),
- mode: mode,
_t: PhantomData,
})
}
@@ -148,7 +131,7 @@ impl<T> HrTimer<T> {
// SAFETY: The field projection to `timer` does not go out of bounds,
// because the caller of this function promises that `this` points to an
// allocation of at least the size of `Self`.
- unsafe { Opaque::raw_get(core::ptr::addr_of!((*this).timer)) }
+ unsafe { Opaque::cast_into(core::ptr::addr_of!((*this).timer)) }
}
/// Cancel an initialized and potentially running timer.
@@ -193,6 +176,11 @@ impl<T> HrTimer<T> {
/// exist. A timer can be manipulated through any of the handles, and a handle
/// may represent a cancelled timer.
pub trait HrTimerPointer: Sync + Sized {
+ /// The operational mode associated with this timer.
+ ///
+ /// This defines how the expiration value is interpreted.
+ type TimerMode: HrTimerMode;
+
/// A handle representing a started or restarted timer.
///
/// If the timer is running or if the timer callback is executing when the
@@ -205,7 +193,7 @@ pub trait HrTimerPointer: Sync + Sized {
/// Start the timer with expiry after `expires` time units. If the timer was
/// already running, it is restarted with the new expiry time.
- fn start(self, expires: Ktime) -> Self::TimerHandle;
+ fn start(self, expires: <Self::TimerMode as HrTimerMode>::Expires) -> Self::TimerHandle;
}
/// Unsafe version of [`HrTimerPointer`] for situations where leaking the
@@ -220,6 +208,11 @@ pub trait HrTimerPointer: Sync + Sized {
/// [`UnsafeHrTimerPointer`] outlives any associated [`HrTimerPointer::TimerHandle`]
/// instances.
pub unsafe trait UnsafeHrTimerPointer: Sync + Sized {
+ /// The operational mode associated with this timer.
+ ///
+ /// This defines how the expiration value is interpreted.
+ type TimerMode: HrTimerMode;
+
/// A handle representing a running timer.
///
/// # Safety
@@ -236,7 +229,7 @@ pub unsafe trait UnsafeHrTimerPointer: Sync + Sized {
///
/// Caller promises keep the timer structure alive until the timer is dead.
/// Caller can ensure this by not leaking the returned [`Self::TimerHandle`].
- unsafe fn start(self, expires: Ktime) -> Self::TimerHandle;
+ unsafe fn start(self, expires: <Self::TimerMode as HrTimerMode>::Expires) -> Self::TimerHandle;
}
/// A trait for stack allocated timers.
@@ -246,9 +239,14 @@ pub unsafe trait UnsafeHrTimerPointer: Sync + Sized {
/// Implementers must ensure that `start_scoped` does not return until the
/// timer is dead and the timer handler is not running.
pub unsafe trait ScopedHrTimerPointer {
+ /// The operational mode associated with this timer.
+ ///
+ /// This defines how the expiration value is interpreted.
+ type TimerMode: HrTimerMode;
+
/// Start the timer to run after `expires` time units and immediately
/// after call `f`. When `f` returns, the timer is cancelled.
- fn start_scoped<T, F>(self, expires: Ktime, f: F) -> T
+ fn start_scoped<T, F>(self, expires: <Self::TimerMode as HrTimerMode>::Expires, f: F) -> T
where
F: FnOnce() -> T;
}
@@ -260,7 +258,13 @@ unsafe impl<T> ScopedHrTimerPointer for T
where
T: UnsafeHrTimerPointer,
{
- fn start_scoped<U, F>(self, expires: Ktime, f: F) -> U
+ type TimerMode = T::TimerMode;
+
+ fn start_scoped<U, F>(
+ self,
+ expires: <<T as UnsafeHrTimerPointer>::TimerMode as HrTimerMode>::Expires,
+ f: F,
+ ) -> U
where
F: FnOnce() -> U,
{
@@ -335,6 +339,11 @@ pub unsafe trait HrTimerHandle {
/// their documentation. All the methods of this trait must operate on the same
/// field.
pub unsafe trait HasHrTimer<T> {
+ /// The operational mode associated with this timer.
+ ///
+ /// This defines how the expiration value is interpreted.
+ type TimerMode: HrTimerMode;
+
/// Return a pointer to the [`HrTimer`] within `Self`.
///
/// This function is useful to get access to the value without creating
@@ -382,14 +391,14 @@ pub unsafe trait HasHrTimer<T> {
/// - `this` must point to a valid `Self`.
/// - Caller must ensure that the pointee of `this` lives until the timer
/// fires or is canceled.
- unsafe fn start(this: *const Self, expires: Ktime) {
+ unsafe fn start(this: *const Self, expires: <Self::TimerMode as HrTimerMode>::Expires) {
// SAFETY: By function safety requirement, `this` is a valid `Self`.
unsafe {
bindings::hrtimer_start_range_ns(
Self::c_timer_ptr(this).cast_mut(),
- expires.to_ns(),
+ expires.as_nanos(),
0,
- (*Self::raw_get_timer(this)).mode.into_c(),
+ <Self::TimerMode as HrTimerMode>::C_MODE,
);
}
}
@@ -411,80 +420,171 @@ impl HrTimerRestart {
}
}
-/// Operational mode of [`HrTimer`].
-// NOTE: Some of these have the same encoding on the C side, so we keep
-// `repr(Rust)` and convert elsewhere.
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub enum HrTimerMode {
- /// Timer expires at the given expiration time.
- Absolute,
- /// Timer expires after the given expiration time interpreted as a duration from now.
- Relative,
- /// Timer does not move between CPU cores.
- Pinned,
- /// Timer handler is executed in soft irq context.
- Soft,
- /// Timer handler is executed in hard irq context.
- Hard,
- /// Timer expires at the given expiration time.
- /// Timer does not move between CPU cores.
- AbsolutePinned,
- /// Timer expires after the given expiration time interpreted as a duration from now.
- /// Timer does not move between CPU cores.
- RelativePinned,
- /// Timer expires at the given expiration time.
- /// Timer handler is executed in soft irq context.
- AbsoluteSoft,
- /// Timer expires after the given expiration time interpreted as a duration from now.
- /// Timer handler is executed in soft irq context.
- RelativeSoft,
- /// Timer expires at the given expiration time.
- /// Timer does not move between CPU cores.
- /// Timer handler is executed in soft irq context.
- AbsolutePinnedSoft,
- /// Timer expires after the given expiration time interpreted as a duration from now.
- /// Timer does not move between CPU cores.
- /// Timer handler is executed in soft irq context.
- RelativePinnedSoft,
- /// Timer expires at the given expiration time.
- /// Timer handler is executed in hard irq context.
- AbsoluteHard,
- /// Timer expires after the given expiration time interpreted as a duration from now.
- /// Timer handler is executed in hard irq context.
- RelativeHard,
- /// Timer expires at the given expiration time.
- /// Timer does not move between CPU cores.
- /// Timer handler is executed in hard irq context.
- AbsolutePinnedHard,
- /// Timer expires after the given expiration time interpreted as a duration from now.
- /// Timer does not move between CPU cores.
- /// Timer handler is executed in hard irq context.
- RelativePinnedHard,
+/// Time representations that can be used as expiration values in [`HrTimer`].
+pub trait HrTimerExpires {
+ /// Converts the expiration time into a nanosecond representation.
+ ///
+ /// This value corresponds to a raw ktime_t value, suitable for passing to kernel
+ /// timer functions. The interpretation (absolute vs relative) depends on the
+ /// associated [HrTimerMode] in use.
+ fn as_nanos(&self) -> i64;
}
-impl HrTimerMode {
- fn into_c(self) -> bindings::hrtimer_mode {
- use bindings::*;
- match self {
- HrTimerMode::Absolute => hrtimer_mode_HRTIMER_MODE_ABS,
- HrTimerMode::Relative => hrtimer_mode_HRTIMER_MODE_REL,
- HrTimerMode::Pinned => hrtimer_mode_HRTIMER_MODE_PINNED,
- HrTimerMode::Soft => hrtimer_mode_HRTIMER_MODE_SOFT,
- HrTimerMode::Hard => hrtimer_mode_HRTIMER_MODE_HARD,
- HrTimerMode::AbsolutePinned => hrtimer_mode_HRTIMER_MODE_ABS_PINNED,
- HrTimerMode::RelativePinned => hrtimer_mode_HRTIMER_MODE_REL_PINNED,
- HrTimerMode::AbsoluteSoft => hrtimer_mode_HRTIMER_MODE_ABS_SOFT,
- HrTimerMode::RelativeSoft => hrtimer_mode_HRTIMER_MODE_REL_SOFT,
- HrTimerMode::AbsolutePinnedSoft => hrtimer_mode_HRTIMER_MODE_ABS_PINNED_SOFT,
- HrTimerMode::RelativePinnedSoft => hrtimer_mode_HRTIMER_MODE_REL_PINNED_SOFT,
- HrTimerMode::AbsoluteHard => hrtimer_mode_HRTIMER_MODE_ABS_HARD,
- HrTimerMode::RelativeHard => hrtimer_mode_HRTIMER_MODE_REL_HARD,
- HrTimerMode::AbsolutePinnedHard => hrtimer_mode_HRTIMER_MODE_ABS_PINNED_HARD,
- HrTimerMode::RelativePinnedHard => hrtimer_mode_HRTIMER_MODE_REL_PINNED_HARD,
- }
+impl<C: ClockSource> HrTimerExpires for Instant<C> {
+ #[inline]
+ fn as_nanos(&self) -> i64 {
+ Instant::<C>::as_nanos(self)
+ }
+}
+
+impl HrTimerExpires for Delta {
+ #[inline]
+ fn as_nanos(&self) -> i64 {
+ Delta::as_nanos(*self)
}
}
+mod private {
+ use crate::time::ClockSource;
+
+ pub trait Sealed {}
+
+ impl<C: ClockSource> Sealed for super::AbsoluteMode<C> {}
+ impl<C: ClockSource> Sealed for super::RelativeMode<C> {}
+ impl<C: ClockSource> Sealed for super::AbsolutePinnedMode<C> {}
+ impl<C: ClockSource> Sealed for super::RelativePinnedMode<C> {}
+ impl<C: ClockSource> Sealed for super::AbsoluteSoftMode<C> {}
+ impl<C: ClockSource> Sealed for super::RelativeSoftMode<C> {}
+ impl<C: ClockSource> Sealed for super::AbsolutePinnedSoftMode<C> {}
+ impl<C: ClockSource> Sealed for super::RelativePinnedSoftMode<C> {}
+ impl<C: ClockSource> Sealed for super::AbsoluteHardMode<C> {}
+ impl<C: ClockSource> Sealed for super::RelativeHardMode<C> {}
+ impl<C: ClockSource> Sealed for super::AbsolutePinnedHardMode<C> {}
+ impl<C: ClockSource> Sealed for super::RelativePinnedHardMode<C> {}
+}
+
+/// Operational mode of [`HrTimer`].
+pub trait HrTimerMode: private::Sealed {
+ /// The C representation of hrtimer mode.
+ const C_MODE: bindings::hrtimer_mode;
+
+ /// Type representing the clock source.
+ type Clock: ClockSource;
+
+ /// Type representing the expiration specification (absolute or relative time).
+ type Expires: HrTimerExpires;
+}
+
+/// Timer that expires at a fixed point in time.
+pub struct AbsoluteMode<C: ClockSource>(PhantomData<C>);
+
+impl<C: ClockSource> HrTimerMode for AbsoluteMode<C> {
+ const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS;
+
+ type Clock = C;
+ type Expires = Instant<C>;
+}
+
+/// Timer that expires after a delay from now.
+pub struct RelativeMode<C: ClockSource>(PhantomData<C>);
+
+impl<C: ClockSource> HrTimerMode for RelativeMode<C> {
+ const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL;
+
+ type Clock = C;
+ type Expires = Delta;
+}
+
+/// Timer with absolute expiration time, pinned to its current CPU.
+pub struct AbsolutePinnedMode<C: ClockSource>(PhantomData<C>);
+impl<C: ClockSource> HrTimerMode for AbsolutePinnedMode<C> {
+ const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_PINNED;
+
+ type Clock = C;
+ type Expires = Instant<C>;
+}
+
+/// Timer with relative expiration time, pinned to its current CPU.
+pub struct RelativePinnedMode<C: ClockSource>(PhantomData<C>);
+impl<C: ClockSource> HrTimerMode for RelativePinnedMode<C> {
+ const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_PINNED;
+
+ type Clock = C;
+ type Expires = Delta;
+}
+
+/// Timer with absolute expiration, handled in soft irq context.
+pub struct AbsoluteSoftMode<C: ClockSource>(PhantomData<C>);
+impl<C: ClockSource> HrTimerMode for AbsoluteSoftMode<C> {
+ const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_SOFT;
+
+ type Clock = C;
+ type Expires = Instant<C>;
+}
+
+/// Timer with relative expiration, handled in soft irq context.
+pub struct RelativeSoftMode<C: ClockSource>(PhantomData<C>);
+impl<C: ClockSource> HrTimerMode for RelativeSoftMode<C> {
+ const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_SOFT;
+
+ type Clock = C;
+ type Expires = Delta;
+}
+
+/// Timer with absolute expiration, pinned to CPU and handled in soft irq context.
+pub struct AbsolutePinnedSoftMode<C: ClockSource>(PhantomData<C>);
+impl<C: ClockSource> HrTimerMode for AbsolutePinnedSoftMode<C> {
+ const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_PINNED_SOFT;
+
+ type Clock = C;
+ type Expires = Instant<C>;
+}
+
+/// Timer with absolute expiration, pinned to CPU and handled in soft irq context.
+pub struct RelativePinnedSoftMode<C: ClockSource>(PhantomData<C>);
+impl<C: ClockSource> HrTimerMode for RelativePinnedSoftMode<C> {
+ const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_PINNED_SOFT;
+
+ type Clock = C;
+ type Expires = Delta;
+}
+
+/// Timer with absolute expiration, handled in hard irq context.
+pub struct AbsoluteHardMode<C: ClockSource>(PhantomData<C>);
+impl<C: ClockSource> HrTimerMode for AbsoluteHardMode<C> {
+ const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_HARD;
+
+ type Clock = C;
+ type Expires = Instant<C>;
+}
+
+/// Timer with relative expiration, handled in hard irq context.
+pub struct RelativeHardMode<C: ClockSource>(PhantomData<C>);
+impl<C: ClockSource> HrTimerMode for RelativeHardMode<C> {
+ const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_HARD;
+
+ type Clock = C;
+ type Expires = Delta;
+}
+
+/// Timer with absolute expiration, pinned to CPU and handled in hard irq context.
+pub struct AbsolutePinnedHardMode<C: ClockSource>(PhantomData<C>);
+impl<C: ClockSource> HrTimerMode for AbsolutePinnedHardMode<C> {
+ const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_ABS_PINNED_HARD;
+
+ type Clock = C;
+ type Expires = Instant<C>;
+}
+
+/// Timer with relative expiration, pinned to CPU and handled in hard irq context.
+pub struct RelativePinnedHardMode<C: ClockSource>(PhantomData<C>);
+impl<C: ClockSource> HrTimerMode for RelativePinnedHardMode<C> {
+ const C_MODE: bindings::hrtimer_mode = bindings::hrtimer_mode_HRTIMER_MODE_REL_PINNED_HARD;
+
+ type Clock = C;
+ type Expires = Delta;
+}
+
/// Use to implement the [`HasHrTimer<T>`] trait.
///
/// See [`module`] documentation for an example.
@@ -496,12 +596,16 @@ macro_rules! impl_has_hr_timer {
impl$({$($generics:tt)*})?
HasHrTimer<$timer_type:ty>
for $self:ty
- { self.$field:ident }
+ {
+ mode : $mode:ty,
+ field : self.$field:ident $(,)?
+ }
$($rest:tt)*
) => {
// SAFETY: This implementation of `raw_get_timer` only compiles if the
// field has the right type.
unsafe impl$(<$($generics)*>)? $crate::time::hrtimer::HasHrTimer<$timer_type> for $self {
+ type TimerMode = $mode;
#[inline]
unsafe fn raw_get_timer(
diff --git a/rust/kernel/time/hrtimer/arc.rs b/rust/kernel/time/hrtimer/arc.rs
index ccf1e66e5b2d..ed490a7a8950 100644
--- a/rust/kernel/time/hrtimer/arc.rs
+++ b/rust/kernel/time/hrtimer/arc.rs
@@ -4,8 +4,8 @@ use super::HasHrTimer;
use super::HrTimer;
use super::HrTimerCallback;
use super::HrTimerHandle;
+use super::HrTimerMode;
use super::HrTimerPointer;
-use super::Ktime;
use super::RawHrTimerCallback;
use crate::sync::Arc;
use crate::sync::ArcBorrow;
@@ -54,9 +54,13 @@ where
T: HasHrTimer<T>,
T: for<'a> HrTimerCallback<Pointer<'a> = Self>,
{
+ type TimerMode = <T as HasHrTimer<T>>::TimerMode;
type TimerHandle = ArcHrTimerHandle<T>;
- fn start(self, expires: Ktime) -> ArcHrTimerHandle<T> {
+ fn start(
+ self,
+ expires: <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Expires,
+ ) -> ArcHrTimerHandle<T> {
// SAFETY:
// - We keep `self` alive by wrapping it in a handle below.
// - Since we generate the pointer passed to `start` from a valid
diff --git a/rust/kernel/time/hrtimer/pin.rs b/rust/kernel/time/hrtimer/pin.rs
index 293ca9cf058c..aef16d9ee2f0 100644
--- a/rust/kernel/time/hrtimer/pin.rs
+++ b/rust/kernel/time/hrtimer/pin.rs
@@ -4,7 +4,7 @@ use super::HasHrTimer;
use super::HrTimer;
use super::HrTimerCallback;
use super::HrTimerHandle;
-use super::Ktime;
+use super::HrTimerMode;
use super::RawHrTimerCallback;
use super::UnsafeHrTimerPointer;
use core::pin::Pin;
@@ -54,9 +54,13 @@ where
T: HasHrTimer<T>,
T: HrTimerCallback<Pointer<'a> = Self>,
{
+ type TimerMode = <T as HasHrTimer<T>>::TimerMode;
type TimerHandle = PinHrTimerHandle<'a, T>;
- unsafe fn start(self, expires: Ktime) -> Self::TimerHandle {
+ unsafe fn start(
+ self,
+ expires: <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Expires,
+ ) -> Self::TimerHandle {
// Cast to pointer
let self_ptr: *const T = self.get_ref();
@@ -79,7 +83,7 @@ where
unsafe extern "C" fn run(ptr: *mut bindings::hrtimer) -> bindings::hrtimer_restart {
// `HrTimer` is `repr(C)`
- let timer_ptr = ptr as *mut HrTimer<T>;
+ let timer_ptr = ptr.cast::<HrTimer<T>>();
// SAFETY: By the safety requirement of this function, `timer_ptr`
// points to a `HrTimer<T>` contained in an `T`.
diff --git a/rust/kernel/time/hrtimer/pin_mut.rs b/rust/kernel/time/hrtimer/pin_mut.rs
index 6033572d35ad..767d0a4e8a2c 100644
--- a/rust/kernel/time/hrtimer/pin_mut.rs
+++ b/rust/kernel/time/hrtimer/pin_mut.rs
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
use super::{
- HasHrTimer, HrTimer, HrTimerCallback, HrTimerHandle, Ktime, RawHrTimerCallback,
+ HasHrTimer, HrTimer, HrTimerCallback, HrTimerHandle, HrTimerMode, RawHrTimerCallback,
UnsafeHrTimerPointer,
};
use core::{marker::PhantomData, pin::Pin, ptr::NonNull};
@@ -52,9 +52,13 @@ where
T: HasHrTimer<T>,
T: HrTimerCallback<Pointer<'a> = Self>,
{
+ type TimerMode = <T as HasHrTimer<T>>::TimerMode;
type TimerHandle = PinMutHrTimerHandle<'a, T>;
- unsafe fn start(mut self, expires: Ktime) -> Self::TimerHandle {
+ unsafe fn start(
+ mut self,
+ expires: <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Expires,
+ ) -> Self::TimerHandle {
// SAFETY:
// - We promise not to move out of `self`. We only pass `self`
// back to the caller as a `Pin<&mut self>`.
@@ -83,7 +87,7 @@ where
unsafe extern "C" fn run(ptr: *mut bindings::hrtimer) -> bindings::hrtimer_restart {
// `HrTimer` is `repr(C)`
- let timer_ptr = ptr as *mut HrTimer<T>;
+ let timer_ptr = ptr.cast::<HrTimer<T>>();
// SAFETY: By the safety requirement of this function, `timer_ptr`
// points to a `HrTimer<T>` contained in an `T`.
diff --git a/rust/kernel/time/hrtimer/tbox.rs b/rust/kernel/time/hrtimer/tbox.rs
index 29526a5da203..ec08303315f2 100644
--- a/rust/kernel/time/hrtimer/tbox.rs
+++ b/rust/kernel/time/hrtimer/tbox.rs
@@ -4,8 +4,8 @@ use super::HasHrTimer;
use super::HrTimer;
use super::HrTimerCallback;
use super::HrTimerHandle;
+use super::HrTimerMode;
use super::HrTimerPointer;
-use super::Ktime;
use super::RawHrTimerCallback;
use crate::prelude::*;
use core::ptr::NonNull;
@@ -64,9 +64,13 @@ where
T: for<'a> HrTimerCallback<Pointer<'a> = Pin<Box<T, A>>>,
A: crate::alloc::Allocator,
{
+ type TimerMode = <T as HasHrTimer<T>>::TimerMode;
type TimerHandle = BoxHrTimerHandle<T, A>;
- fn start(self, expires: Ktime) -> Self::TimerHandle {
+ fn start(
+ self,
+ expires: <<T as HasHrTimer<T>>::TimerMode as HrTimerMode>::Expires,
+ ) -> Self::TimerHandle {
// SAFETY:
// - We will not move out of this box during timer callback (we pass an
// immutable reference to the callback).
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index 3958a5f44d56..dc0a02f5c3cf 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -2,15 +2,17 @@
//! Kernel types.
+use crate::ffi::c_void;
use core::{
cell::UnsafeCell,
marker::{PhantomData, PhantomPinned},
- mem::{ManuallyDrop, MaybeUninit},
+ mem::MaybeUninit,
ops::{Deref, DerefMut},
- ptr::NonNull,
};
use pin_init::{PinInit, Wrapper, Zeroable};
+pub use crate::sync::aref::{ARef, AlwaysRefCounted};
+
/// Used to transfer ownership to and from foreign (non-Rust) languages.
///
/// Ownership is transferred from Rust to a foreign language by calling [`Self::into_foreign`] and
@@ -21,15 +23,10 @@ use pin_init::{PinInit, Wrapper, Zeroable};
///
/// # Safety
///
-/// Implementers must ensure that [`into_foreign`] returns a pointer which meets the alignment
-/// requirements of [`PointedTo`].
-///
-/// [`into_foreign`]: Self::into_foreign
-/// [`PointedTo`]: Self::PointedTo
+/// - Implementations must satisfy the guarantees of [`Self::into_foreign`].
pub unsafe trait ForeignOwnable: Sized {
- /// Type used when the value is foreign-owned. In practical terms only defines the alignment of
- /// the pointer.
- type PointedTo;
+ /// The alignment of pointers returned by `into_foreign`.
+ const FOREIGN_ALIGN: usize;
/// Type used to immutably borrow a value that is currently foreign-owned.
type Borrowed<'a>;
@@ -39,18 +36,21 @@ pub unsafe trait ForeignOwnable: Sized {
/// Converts a Rust-owned object to a foreign-owned one.
///
+ /// The foreign representation is a pointer to void. Aside from the guarantees listed below,
+ /// there are no other guarantees for this pointer. For example, it might be invalid, dangling
+ /// or pointing to uninitialized memory. Using it in any way except for [`from_foreign`],
+ /// [`try_from_foreign`], [`borrow`], or [`borrow_mut`] can result in undefined behavior.
+ ///
/// # Guarantees
///
- /// The return value is guaranteed to be well-aligned, but there are no other guarantees for
- /// this pointer. For example, it might be null, dangling, or point to uninitialized memory.
- /// Using it in any way except for [`ForeignOwnable::from_foreign`], [`ForeignOwnable::borrow`],
- /// [`ForeignOwnable::try_from_foreign`] can result in undefined behavior.
+ /// - Minimum alignment of returned pointer is [`Self::FOREIGN_ALIGN`].
+ /// - The returned pointer is not null.
///
/// [`from_foreign`]: Self::from_foreign
/// [`try_from_foreign`]: Self::try_from_foreign
/// [`borrow`]: Self::borrow
/// [`borrow_mut`]: Self::borrow_mut
- fn into_foreign(self) -> *mut Self::PointedTo;
+ fn into_foreign(self) -> *mut c_void;
/// Converts a foreign-owned object back to a Rust-owned one.
///
@@ -60,7 +60,7 @@ pub unsafe trait ForeignOwnable: Sized {
/// must not be passed to `from_foreign` more than once.
///
/// [`into_foreign`]: Self::into_foreign
- unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self;
+ unsafe fn from_foreign(ptr: *mut c_void) -> Self;
/// Tries to convert a foreign-owned object back to a Rust-owned one.
///
@@ -72,7 +72,7 @@ pub unsafe trait ForeignOwnable: Sized {
/// `ptr` must either be null or satisfy the safety requirements for [`from_foreign`].
///
/// [`from_foreign`]: Self::from_foreign
- unsafe fn try_from_foreign(ptr: *mut Self::PointedTo) -> Option<Self> {
+ unsafe fn try_from_foreign(ptr: *mut c_void) -> Option<Self> {
if ptr.is_null() {
None
} else {
@@ -95,7 +95,7 @@ pub unsafe trait ForeignOwnable: Sized {
///
/// [`into_foreign`]: Self::into_foreign
/// [`from_foreign`]: Self::from_foreign
- unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> Self::Borrowed<'a>;
+ unsafe fn borrow<'a>(ptr: *mut c_void) -> Self::Borrowed<'a>;
/// Borrows a foreign-owned object mutably.
///
@@ -123,23 +123,24 @@ pub unsafe trait ForeignOwnable: Sized {
/// [`from_foreign`]: Self::from_foreign
/// [`borrow`]: Self::borrow
/// [`Arc`]: crate::sync::Arc
- unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> Self::BorrowedMut<'a>;
+ unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> Self::BorrowedMut<'a>;
}
-// SAFETY: The `into_foreign` function returns a pointer that is dangling, but well-aligned.
+// SAFETY: The pointer returned by `into_foreign` comes from a well aligned
+// pointer to `()`.
unsafe impl ForeignOwnable for () {
- type PointedTo = ();
+ const FOREIGN_ALIGN: usize = core::mem::align_of::<()>();
type Borrowed<'a> = ();
type BorrowedMut<'a> = ();
- fn into_foreign(self) -> *mut Self::PointedTo {
+ fn into_foreign(self) -> *mut c_void {
core::ptr::NonNull::dangling().as_ptr()
}
- unsafe fn from_foreign(_: *mut Self::PointedTo) -> Self {}
+ unsafe fn from_foreign(_: *mut c_void) -> Self {}
- unsafe fn borrow<'a>(_: *mut Self::PointedTo) -> Self::Borrowed<'a> {}
- unsafe fn borrow_mut<'a>(_: *mut Self::PointedTo) -> Self::BorrowedMut<'a> {}
+ unsafe fn borrow<'a>(_: *mut c_void) -> Self::Borrowed<'a> {}
+ unsafe fn borrow_mut<'a>(_: *mut c_void) -> Self::BorrowedMut<'a> {}
}
/// Runs a cleanup function/closure when dropped.
@@ -366,7 +367,7 @@ impl<T> Opaque<T> {
// initialize the `T`.
unsafe {
pin_init::pin_init_from_closure::<_, ::core::convert::Infallible>(move |slot| {
- init_func(Self::raw_get(slot));
+ init_func(Self::cast_into(slot));
Ok(())
})
}
@@ -386,7 +387,7 @@ impl<T> Opaque<T> {
// SAFETY: We contain a `MaybeUninit`, so it is OK for the `init_func` to not fully
// initialize the `T`.
unsafe {
- pin_init::pin_init_from_closure::<_, E>(move |slot| init_func(Self::raw_get(slot)))
+ pin_init::pin_init_from_closure::<_, E>(move |slot| init_func(Self::cast_into(slot)))
}
}
@@ -399,9 +400,14 @@ impl<T> Opaque<T> {
///
/// This function is useful to get access to the value without creating intermediate
/// references.
- pub const fn raw_get(this: *const Self) -> *mut T {
+ pub const fn cast_into(this: *const Self) -> *mut T {
UnsafeCell::raw_get(this.cast::<UnsafeCell<MaybeUninit<T>>>()).cast::<T>()
}
+
+ /// The opposite operation of [`Opaque::cast_into`].
+ pub const fn cast_from(this: *const T) -> *const Self {
+ this.cast()
+ }
}
impl<T> Wrapper<T> for Opaque<T> {
@@ -417,173 +423,6 @@ impl<T> Wrapper<T> for Opaque<T> {
}
}
-/// Types that are _always_ reference counted.
-///
-/// It allows such types to define their own custom ref increment and decrement functions.
-/// Additionally, it allows users to convert from a shared reference `&T` to an owned reference
-/// [`ARef<T>`].
-///
-/// This is usually implemented by wrappers to existing structures on the C side of the code. For
-/// Rust code, the recommendation is to use [`Arc`](crate::sync::Arc) to create reference-counted
-/// instances of a type.
-///
-/// # Safety
-///
-/// Implementers must ensure that increments to the reference count keep the object alive in memory
-/// at least until matching decrements are performed.
-///
-/// Implementers must also ensure that all instances are reference-counted. (Otherwise they
-/// won't be able to honour the requirement that [`AlwaysRefCounted::inc_ref`] keep the object
-/// alive.)
-pub unsafe trait AlwaysRefCounted {
- /// Increments the reference count on the object.
- fn inc_ref(&self);
-
- /// Decrements the reference count on the object.
- ///
- /// Frees the object when the count reaches zero.
- ///
- /// # Safety
- ///
- /// Callers must ensure that there was a previous matching increment to the reference count,
- /// and that the object is no longer used after its reference count is decremented (as it may
- /// result in the object being freed), unless the caller owns another increment on the refcount
- /// (e.g., it calls [`AlwaysRefCounted::inc_ref`] twice, then calls
- /// [`AlwaysRefCounted::dec_ref`] once).
- unsafe fn dec_ref(obj: NonNull<Self>);
-}
-
-/// An owned reference to an always-reference-counted object.
-///
-/// The object's reference count is automatically decremented when an instance of [`ARef`] is
-/// dropped. It is also automatically incremented when a new instance is created via
-/// [`ARef::clone`].
-///
-/// # Invariants
-///
-/// The pointer stored in `ptr` is non-null and valid for the lifetime of the [`ARef`] instance. In
-/// particular, the [`ARef`] instance owns an increment on the underlying object's reference count.
-pub struct ARef<T: AlwaysRefCounted> {
- ptr: NonNull<T>,
- _p: PhantomData<T>,
-}
-
-// SAFETY: It is safe to send `ARef<T>` to another thread when the underlying `T` is `Sync` because
-// it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally, it needs
-// `T` to be `Send` because any thread that has an `ARef<T>` may ultimately access `T` using a
-// mutable reference, for example, when the reference count reaches zero and `T` is dropped.
-unsafe impl<T: AlwaysRefCounted + Sync + Send> Send for ARef<T> {}
-
-// SAFETY: It is safe to send `&ARef<T>` to another thread when the underlying `T` is `Sync`
-// because it effectively means sharing `&T` (which is safe because `T` is `Sync`); additionally,
-// it needs `T` to be `Send` because any thread that has a `&ARef<T>` may clone it and get an
-// `ARef<T>` on that thread, so the thread may ultimately access `T` using a mutable reference, for
-// example, when the reference count reaches zero and `T` is dropped.
-unsafe impl<T: AlwaysRefCounted + Sync + Send> Sync for ARef<T> {}
-
-impl<T: AlwaysRefCounted> ARef<T> {
- /// Creates a new instance of [`ARef`].
- ///
- /// It takes over an increment of the reference count on the underlying object.
- ///
- /// # Safety
- ///
- /// Callers must ensure that the reference count was incremented at least once, and that they
- /// are properly relinquishing one increment. That is, if there is only one increment, callers
- /// must not use the underlying object anymore -- it is only safe to do so via the newly
- /// created [`ARef`].
- pub unsafe fn from_raw(ptr: NonNull<T>) -> Self {
- // INVARIANT: The safety requirements guarantee that the new instance now owns the
- // increment on the refcount.
- Self {
- ptr,
- _p: PhantomData,
- }
- }
-
- /// Consumes the `ARef`, returning a raw pointer.
- ///
- /// This function does not change the refcount. After calling this function, the caller is
- /// responsible for the refcount previously managed by the `ARef`.
- ///
- /// # Examples
- ///
- /// ```
- /// use core::ptr::NonNull;
- /// use kernel::types::{ARef, AlwaysRefCounted};
- ///
- /// struct Empty {}
- ///
- /// # // SAFETY: TODO.
- /// unsafe impl AlwaysRefCounted for Empty {
- /// fn inc_ref(&self) {}
- /// unsafe fn dec_ref(_obj: NonNull<Self>) {}
- /// }
- ///
- /// let mut data = Empty {};
- /// let ptr = NonNull::<Empty>::new(&mut data).unwrap();
- /// # // SAFETY: TODO.
- /// let data_ref: ARef<Empty> = unsafe { ARef::from_raw(ptr) };
- /// let raw_ptr: NonNull<Empty> = ARef::into_raw(data_ref);
- ///
- /// assert_eq!(ptr, raw_ptr);
- /// ```
- pub fn into_raw(me: Self) -> NonNull<T> {
- ManuallyDrop::new(me).ptr
- }
-}
-
-impl<T: AlwaysRefCounted> Clone for ARef<T> {
- fn clone(&self) -> Self {
- self.inc_ref();
- // SAFETY: We just incremented the refcount above.
- unsafe { Self::from_raw(self.ptr) }
- }
-}
-
-impl<T: AlwaysRefCounted> Deref for ARef<T> {
- type Target = T;
-
- fn deref(&self) -> &Self::Target {
- // SAFETY: The type invariants guarantee that the object is valid.
- unsafe { self.ptr.as_ref() }
- }
-}
-
-impl<T: AlwaysRefCounted> From<&T> for ARef<T> {
- fn from(b: &T) -> Self {
- b.inc_ref();
- // SAFETY: We just incremented the refcount above.
- unsafe { Self::from_raw(NonNull::from(b)) }
- }
-}
-
-impl<T: AlwaysRefCounted> Drop for ARef<T> {
- fn drop(&mut self) {
- // SAFETY: The type invariants guarantee that the `ARef` owns the reference we're about to
- // decrement.
- unsafe { T::dec_ref(self.ptr) };
- }
-}
-
-/// A sum type that always holds either a value of type `L` or `R`.
-///
-/// # Examples
-///
-/// ```
-/// use kernel::types::Either;
-///
-/// let left_value: Either<i32, &str> = Either::Left(7);
-/// let right_value: Either<i32, &str> = Either::Right("right value");
-/// ```
-pub enum Either<L, R> {
- /// Constructs an instance of [`Either`] containing a value of type `L`.
- Left(L),
-
- /// Constructs an instance of [`Either`] containing a value of type `R`.
- Right(R),
-}
-
/// Zero-sized type to mark types not [`Send`].
///
/// Add this type as a field to your struct if your type should not be sent to a different task.
diff --git a/rust/kernel/uaccess.rs b/rust/kernel/uaccess.rs
index 6d70edd8086a..a8fb4764185a 100644
--- a/rust/kernel/uaccess.rs
+++ b/rust/kernel/uaccess.rs
@@ -8,14 +8,57 @@ use crate::{
alloc::{Allocator, Flags},
bindings,
error::Result,
- ffi::c_void,
+ ffi::{c_char, c_void},
prelude::*,
transmute::{AsBytes, FromBytes},
};
use core::mem::{size_of, MaybeUninit};
-/// The type used for userspace addresses.
-pub type UserPtr = usize;
+/// A pointer into userspace.
+///
+/// This is the Rust equivalent to C pointers tagged with `__user`.
+#[repr(transparent)]
+#[derive(Copy, Clone)]
+pub struct UserPtr(*mut c_void);
+
+impl UserPtr {
+ /// Create a `UserPtr` from an integer representing the userspace address.
+ #[inline]
+ pub fn from_addr(addr: usize) -> Self {
+ Self(addr as *mut c_void)
+ }
+
+ /// Create a `UserPtr` from a pointer representing the userspace address.
+ #[inline]
+ pub fn from_ptr(addr: *mut c_void) -> Self {
+ Self(addr)
+ }
+
+ /// Cast this userspace pointer to a raw const void pointer.
+ ///
+ /// It is up to the caller to use the returned pointer correctly.
+ #[inline]
+ pub fn as_const_ptr(self) -> *const c_void {
+ self.0
+ }
+
+ /// Cast this userspace pointer to a raw mutable void pointer.
+ ///
+ /// It is up to the caller to use the returned pointer correctly.
+ #[inline]
+ pub fn as_mut_ptr(self) -> *mut c_void {
+ self.0
+ }
+
+ /// Increment this user pointer by `add` bytes.
+ ///
+ /// This addition is wrapping, so wrapping around the address space does not result in a panic
+ /// even if `CONFIG_RUST_OVERFLOW_CHECKS` is enabled.
+ #[inline]
+ pub fn wrapping_byte_add(self, add: usize) -> UserPtr {
+ UserPtr(self.0.wrapping_byte_add(add))
+ }
+}
/// A pointer to an area in userspace memory, which can be either read-only or read-write.
///
@@ -177,7 +220,7 @@ impl UserSliceReader {
pub fn skip(&mut self, num_skip: usize) -> Result {
// Update `self.length` first since that's the fallible part of this operation.
self.length = self.length.checked_sub(num_skip).ok_or(EFAULT)?;
- self.ptr = self.ptr.wrapping_add(num_skip);
+ self.ptr = self.ptr.wrapping_byte_add(num_skip);
Ok(())
}
@@ -224,11 +267,11 @@ impl UserSliceReader {
}
// SAFETY: `out_ptr` points into a mutable slice of length `len`, so we may write
// that many bytes to it.
- let res = unsafe { bindings::copy_from_user(out_ptr, self.ptr as *const c_void, len) };
+ let res = unsafe { bindings::copy_from_user(out_ptr, self.ptr.as_const_ptr(), len) };
if res != 0 {
return Err(EFAULT);
}
- self.ptr = self.ptr.wrapping_add(len);
+ self.ptr = self.ptr.wrapping_byte_add(len);
self.length -= len;
Ok(())
}
@@ -240,7 +283,7 @@ impl UserSliceReader {
pub fn read_slice(&mut self, out: &mut [u8]) -> Result {
// SAFETY: The types are compatible and `read_raw` doesn't write uninitialized bytes to
// `out`.
- let out = unsafe { &mut *(out as *mut [u8] as *mut [MaybeUninit<u8>]) };
+ let out = unsafe { &mut *(core::ptr::from_mut(out) as *mut [MaybeUninit<u8>]) };
self.read_raw(out)
}
@@ -262,14 +305,14 @@ impl UserSliceReader {
let res = unsafe {
bindings::_copy_from_user(
out.as_mut_ptr().cast::<c_void>(),
- self.ptr as *const c_void,
+ self.ptr.as_const_ptr(),
len,
)
};
if res != 0 {
return Err(EFAULT);
}
- self.ptr = self.ptr.wrapping_add(len);
+ self.ptr = self.ptr.wrapping_byte_add(len);
self.length -= len;
// SAFETY: The read above has initialized all bytes in `out`, and since `T` implements
// `FromBytes`, any bit-pattern is a valid value for this type.
@@ -291,6 +334,65 @@ impl UserSliceReader {
unsafe { buf.inc_len(len) };
Ok(())
}
+
+ /// Read a NUL-terminated string from userspace and return it.
+ ///
+ /// The string is read into `buf` and a NUL-terminator is added if the end of `buf` is reached.
+ /// Since there must be space to add a NUL-terminator, the buffer must not be empty. The
+ /// returned `&CStr` points into `buf`.
+ ///
+ /// Fails with [`EFAULT`] if the read happens on a bad address (some data may have been
+ /// copied).
+ #[doc(alias = "strncpy_from_user")]
+ pub fn strcpy_into_buf<'buf>(self, buf: &'buf mut [u8]) -> Result<&'buf CStr> {
+ if buf.is_empty() {
+ return Err(EINVAL);
+ }
+
+ // SAFETY: The types are compatible and `strncpy_from_user` doesn't write uninitialized
+ // bytes to `buf`.
+ let mut dst = unsafe { &mut *(core::ptr::from_mut(buf) as *mut [MaybeUninit<u8>]) };
+
+ // We never read more than `self.length` bytes.
+ if dst.len() > self.length {
+ dst = &mut dst[..self.length];
+ }
+
+ let mut len = raw_strncpy_from_user(dst, self.ptr)?;
+ if len < dst.len() {
+ // Add one to include the NUL-terminator.
+ len += 1;
+ } else if len < buf.len() {
+ // This implies that `len == dst.len() < buf.len()`.
+ //
+ // This means that we could not fill the entire buffer, but we had to stop reading
+ // because we hit the `self.length` limit of this `UserSliceReader`. Since we did not
+ // fill the buffer, we treat this case as if we tried to read past the `self.length`
+ // limit and received a page fault, which is consistent with other `UserSliceReader`
+ // methods that also return page faults when you exceed `self.length`.
+ return Err(EFAULT);
+ } else {
+ // This implies that `len == buf.len()`.
+ //
+ // This means that we filled the buffer exactly. In this case, we add a NUL-terminator
+ // and return it. Unlike the `len < dst.len()` branch, don't modify `len` because it
+ // already represents the length including the NUL-terminator.
+ //
+ // SAFETY: Due to the check at the beginning, the buffer is not empty.
+ unsafe { *buf.last_mut().unwrap_unchecked() = 0 };
+ }
+
+ // This method consumes `self`, so it can only be called once, thus we do not need to
+ // update `self.length`. This sidesteps concerns such as whether `self.length` should be
+ // incremented by `len` or `len-1` in the `len == buf.len()` case.
+
+ // SAFETY: There are two cases:
+ // * If we hit the `len < dst.len()` case, then `raw_strncpy_from_user` guarantees that
+ // this slice contains exactly one NUL byte at the end of the string.
+ // * Otherwise, `raw_strncpy_from_user` guarantees that the string contained no NUL bytes,
+ // and we have since added a NUL byte at the end.
+ Ok(unsafe { CStr::from_bytes_with_nul_unchecked(&buf[..len]) })
+ }
}
/// A writer for [`UserSlice`].
@@ -327,11 +429,11 @@ impl UserSliceWriter {
}
// SAFETY: `data_ptr` points into an immutable slice of length `len`, so we may read
// that many bytes from it.
- let res = unsafe { bindings::copy_to_user(self.ptr as *mut c_void, data_ptr, len) };
+ let res = unsafe { bindings::copy_to_user(self.ptr.as_mut_ptr(), data_ptr, len) };
if res != 0 {
return Err(EFAULT);
}
- self.ptr = self.ptr.wrapping_add(len);
+ self.ptr = self.ptr.wrapping_byte_add(len);
self.length -= len;
Ok(())
}
@@ -354,16 +456,53 @@ impl UserSliceWriter {
// is a compile-time constant.
let res = unsafe {
bindings::_copy_to_user(
- self.ptr as *mut c_void,
- (value as *const T).cast::<c_void>(),
+ self.ptr.as_mut_ptr(),
+ core::ptr::from_ref(value).cast::<c_void>(),
len,
)
};
if res != 0 {
return Err(EFAULT);
}
- self.ptr = self.ptr.wrapping_add(len);
+ self.ptr = self.ptr.wrapping_byte_add(len);
self.length -= len;
Ok(())
}
}
+
+/// Reads a nul-terminated string into `dst` and returns the length.
+///
+/// This reads from userspace until a NUL byte is encountered, or until `dst.len()` bytes have been
+/// read. Fails with [`EFAULT`] if a read happens on a bad address (some data may have been
+/// copied). When the end of the buffer is encountered, no NUL byte is added, so the string is
+/// *not* guaranteed to be NUL-terminated when `Ok(dst.len())` is returned.
+///
+/// # Guarantees
+///
+/// When this function returns `Ok(len)`, it is guaranteed that the first `len` bytes of `dst` are
+/// initialized and non-zero. Furthermore, if `len < dst.len()`, then `dst[len]` is a NUL byte.
+#[inline]
+fn raw_strncpy_from_user(dst: &mut [MaybeUninit<u8>], src: UserPtr) -> Result<usize> {
+ // CAST: Slice lengths are guaranteed to be `<= isize::MAX`.
+ let len = dst.len() as isize;
+
+ // SAFETY: `dst` is valid for writing `dst.len()` bytes.
+ let res = unsafe {
+ bindings::strncpy_from_user(
+ dst.as_mut_ptr().cast::<c_char>(),
+ src.as_const_ptr().cast::<c_char>(),
+ len,
+ )
+ };
+
+ if res < 0 {
+ return Err(Error::from_errno(res as i32));
+ }
+
+ #[cfg(CONFIG_RUST_OVERFLOW_CHECKS)]
+ assert!(res <= len);
+
+ // GUARANTEES: `strncpy_from_user` was successful, so `dst` has contents in accordance with the
+ // guarantees of this function.
+ Ok(res as usize)
+}
diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
index d092112d843f..b9343d5bc00f 100644
--- a/rust/kernel/workqueue.rs
+++ b/rust/kernel/workqueue.rs
@@ -26,7 +26,7 @@
//! * The [`WorkItemPointer`] trait is implemented for the pointer type that points at a something
//! that implements [`WorkItem`].
//!
-//! ## Example
+//! ## Examples
//!
//! This example defines a struct that holds an integer and can be scheduled on the workqueue. When
//! the struct is executed, it will print the integer. Since there is only one `work_struct` field,
@@ -131,10 +131,69 @@
//! # print_2_later(MyStruct::new(41, 42).unwrap());
//! ```
//!
+//! This example shows how you can schedule delayed work items:
+//!
+//! ```
+//! use kernel::sync::Arc;
+//! use kernel::workqueue::{self, impl_has_delayed_work, new_delayed_work, DelayedWork, WorkItem};
+//!
+//! #[pin_data]
+//! struct MyStruct {
+//! value: i32,
+//! #[pin]
+//! work: DelayedWork<MyStruct>,
+//! }
+//!
+//! impl_has_delayed_work! {
+//! impl HasDelayedWork<Self> for MyStruct { self.work }
+//! }
+//!
+//! impl MyStruct {
+//! fn new(value: i32) -> Result<Arc<Self>> {
+//! Arc::pin_init(
+//! pin_init!(MyStruct {
+//! value,
+//! work <- new_delayed_work!("MyStruct::work"),
+//! }),
+//! GFP_KERNEL,
+//! )
+//! }
+//! }
+//!
+//! impl WorkItem for MyStruct {
+//! type Pointer = Arc<MyStruct>;
+//!
+//! fn run(this: Arc<MyStruct>) {
+//! pr_info!("The value is: {}\n", this.value);
+//! }
+//! }
+//!
+//! /// This method will enqueue the struct for execution on the system workqueue, where its value
+//! /// will be printed 12 jiffies later.
+//! fn print_later(val: Arc<MyStruct>) {
+//! let _ = workqueue::system().enqueue_delayed(val, 12);
+//! }
+//!
+//! /// It is also possible to use the ordinary `enqueue` method together with `DelayedWork`. This
+//! /// is equivalent to calling `enqueue_delayed` with a delay of zero.
+//! fn print_now(val: Arc<MyStruct>) {
+//! let _ = workqueue::system().enqueue(val);
+//! }
+//! # print_later(MyStruct::new(42).unwrap());
+//! # print_now(MyStruct::new(42).unwrap());
+//! ```
+//!
//! C header: [`include/linux/workqueue.h`](srctree/include/linux/workqueue.h)
-use crate::alloc::{AllocError, Flags};
-use crate::{prelude::*, sync::Arc, sync::LockClassKey, types::Opaque};
+use crate::{
+ alloc::{AllocError, Flags},
+ container_of,
+ prelude::*,
+ sync::Arc,
+ sync::LockClassKey,
+ time::Jiffies,
+ types::Opaque,
+};
use core::marker::PhantomData;
/// Creates a [`Work`] initialiser with the given name and a newly-created lock class.
@@ -146,6 +205,33 @@ macro_rules! new_work {
}
pub use new_work;
+/// Creates a [`DelayedWork`] initialiser with the given name and a newly-created lock class.
+#[macro_export]
+macro_rules! new_delayed_work {
+ () => {
+ $crate::workqueue::DelayedWork::new(
+ $crate::optional_name!(),
+ $crate::static_lock_class!(),
+ $crate::c_str!(::core::concat!(
+ ::core::file!(),
+ ":",
+ ::core::line!(),
+ "_timer"
+ )),
+ $crate::static_lock_class!(),
+ )
+ };
+ ($name:literal) => {
+ $crate::workqueue::DelayedWork::new(
+ $crate::c_str!($name),
+ $crate::static_lock_class!(),
+ $crate::c_str!(::core::concat!($name, "_timer")),
+ $crate::static_lock_class!(),
+ )
+ };
+}
+pub use new_delayed_work;
+
/// A kernel work queue.
///
/// Wraps the kernel's C `struct workqueue_struct`.
@@ -170,7 +256,7 @@ impl Queue {
pub unsafe fn from_raw<'a>(ptr: *const bindings::workqueue_struct) -> &'a Queue {
// SAFETY: The `Queue` type is `#[repr(transparent)]`, so the pointer cast is valid. The
// caller promises that the pointer is not dangling.
- unsafe { &*(ptr as *const Queue) }
+ unsafe { &*ptr.cast::<Queue>() }
}
/// Enqueues a work item.
@@ -198,7 +284,7 @@ impl Queue {
unsafe {
w.__enqueue(move |work_ptr| {
bindings::queue_work_on(
- bindings::wq_misc_consts_WORK_CPU_UNBOUND as _,
+ bindings::wq_misc_consts_WORK_CPU_UNBOUND as ffi::c_int,
queue_ptr,
work_ptr,
)
@@ -206,6 +292,42 @@ impl Queue {
}
}
+ /// Enqueues a delayed work item.
+ ///
+ /// This may fail if the work item is already enqueued in a workqueue.
+ ///
+ /// The work item will be submitted using `WORK_CPU_UNBOUND`.
+ pub fn enqueue_delayed<W, const ID: u64>(&self, w: W, delay: Jiffies) -> W::EnqueueOutput
+ where
+ W: RawDelayedWorkItem<ID> + Send + 'static,
+ {
+ let queue_ptr = self.0.get();
+
+ // SAFETY: We only return `false` if the `work_struct` is already in a workqueue. The other
+ // `__enqueue` requirements are not relevant since `W` is `Send` and static.
+ //
+ // The call to `bindings::queue_delayed_work_on` will dereference the provided raw pointer,
+ // which is ok because `__enqueue` guarantees that the pointer is valid for the duration of
+ // this closure, and the safety requirements of `RawDelayedWorkItem` expands this
+ // requirement to apply to the entire `delayed_work`.
+ //
+ // Furthermore, if the C workqueue code accesses the pointer after this call to
+ // `__enqueue`, then the work item was successfully enqueued, and
+ // `bindings::queue_delayed_work_on` will have returned true. In this case, `__enqueue`
+ // promises that the raw pointer will stay valid until we call the function pointer in the
+ // `work_struct`, so the access is ok.
+ unsafe {
+ w.__enqueue(move |work_ptr| {
+ bindings::queue_delayed_work_on(
+ bindings::wq_misc_consts_WORK_CPU_UNBOUND as ffi::c_int,
+ queue_ptr,
+ container_of!(work_ptr, bindings::delayed_work, work),
+ delay,
+ )
+ })
+ }
+ }
+
/// Tries to spawn the given function or closure as a work item.
///
/// This method can fail because it allocates memory to store the work item.
@@ -298,6 +420,16 @@ pub unsafe trait RawWorkItem<const ID: u64> {
F: FnOnce(*mut bindings::work_struct) -> bool;
}
+/// A raw delayed work item.
+///
+/// # Safety
+///
+/// If the `__enqueue` method in the `RawWorkItem` implementation calls the closure, then the
+/// provided pointer must point at the `work` field of a valid `delayed_work`, and the guarantees
+/// that `__enqueue` provides about accessing the `work_struct` must also apply to the rest of the
+/// `delayed_work` struct.
+pub unsafe trait RawDelayedWorkItem<const ID: u64>: RawWorkItem<ID> {}
+
/// Defines the method that should be called directly when a work item is executed.
///
/// This trait is implemented by `Pin<KBox<T>>` and [`Arc<T>`], and is mainly intended to be
@@ -403,11 +535,11 @@ impl<T: ?Sized, const ID: u64> Work<T, ID> {
//
// A pointer cast would also be ok due to `#[repr(transparent)]`. We use `addr_of!` so that
// the compiler does not complain that the `work` field is unused.
- unsafe { Opaque::raw_get(core::ptr::addr_of!((*ptr).work)) }
+ unsafe { Opaque::cast_into(core::ptr::addr_of!((*ptr).work)) }
}
}
-/// Declares that a type has a [`Work<T, ID>`] field.
+/// Declares that a type contains a [`Work<T, ID>`].
///
/// The intended way of using this trait is via the [`impl_has_work!`] macro. You can use the macro
/// like this:
@@ -506,6 +638,178 @@ impl_has_work! {
impl{T} HasWork<Self> for ClosureWork<T> { self.work }
}
+/// Links for a delayed work item.
+///
+/// This struct contains a function pointer to the [`run`] function from the [`WorkItemPointer`]
+/// trait, and defines the linked list pointers necessary to enqueue a work item in a workqueue in
+/// a delayed manner.
+///
+/// Wraps the kernel's C `struct delayed_work`.
+///
+/// This is a helper type used to associate a `delayed_work` with the [`WorkItem`] that uses it.
+///
+/// [`run`]: WorkItemPointer::run
+#[pin_data]
+#[repr(transparent)]
+pub struct DelayedWork<T: ?Sized, const ID: u64 = 0> {
+ #[pin]
+ dwork: Opaque<bindings::delayed_work>,
+ _inner: PhantomData<T>,
+}
+
+// SAFETY: Kernel work items are usable from any thread.
+//
+// We do not need to constrain `T` since the work item does not actually contain a `T`.
+unsafe impl<T: ?Sized, const ID: u64> Send for DelayedWork<T, ID> {}
+// SAFETY: Kernel work items are usable from any thread.
+//
+// We do not need to constrain `T` since the work item does not actually contain a `T`.
+unsafe impl<T: ?Sized, const ID: u64> Sync for DelayedWork<T, ID> {}
+
+impl<T: ?Sized, const ID: u64> DelayedWork<T, ID> {
+ /// Creates a new instance of [`DelayedWork`].
+ #[inline]
+ pub fn new(
+ work_name: &'static CStr,
+ work_key: Pin<&'static LockClassKey>,
+ timer_name: &'static CStr,
+ timer_key: Pin<&'static LockClassKey>,
+ ) -> impl PinInit<Self>
+ where
+ T: WorkItem<ID>,
+ {
+ pin_init!(Self {
+ dwork <- Opaque::ffi_init(|slot: *mut bindings::delayed_work| {
+ // SAFETY: The `WorkItemPointer` implementation promises that `run` can be used as
+ // the work item function.
+ unsafe {
+ bindings::init_work_with_key(
+ core::ptr::addr_of_mut!((*slot).work),
+ Some(T::Pointer::run),
+ false,
+ work_name.as_char_ptr(),
+ work_key.as_ptr(),
+ )
+ }
+
+ // SAFETY: The `delayed_work_timer_fn` function pointer can be used here because
+ // the timer is embedded in a `struct delayed_work`, and only ever scheduled via
+ // the core workqueue code, and configured to run in irqsafe context.
+ unsafe {
+ bindings::timer_init_key(
+ core::ptr::addr_of_mut!((*slot).timer),
+ Some(bindings::delayed_work_timer_fn),
+ bindings::TIMER_IRQSAFE,
+ timer_name.as_char_ptr(),
+ timer_key.as_ptr(),
+ )
+ }
+ }),
+ _inner: PhantomData,
+ })
+ }
+
+ /// Get a pointer to the inner `delayed_work`.
+ ///
+ /// # Safety
+ ///
+ /// The provided pointer must not be dangling and must be properly aligned. (But the memory
+ /// need not be initialized.)
+ #[inline]
+ pub unsafe fn raw_as_work(ptr: *const Self) -> *mut Work<T, ID> {
+ // SAFETY: The caller promises that the pointer is aligned and not dangling.
+ let dw: *mut bindings::delayed_work =
+ unsafe { Opaque::cast_into(core::ptr::addr_of!((*ptr).dwork)) };
+ // SAFETY: The caller promises that the pointer is aligned and not dangling.
+ let wrk: *mut bindings::work_struct = unsafe { core::ptr::addr_of_mut!((*dw).work) };
+ // CAST: Work and work_struct have compatible layouts.
+ wrk.cast()
+ }
+}
+
+/// Declares that a type contains a [`DelayedWork<T, ID>`].
+///
+/// # Safety
+///
+/// The `HasWork<T, ID>` implementation must return a `work_struct` that is stored in the `work`
+/// field of a `delayed_work` with the same access rules as the `work_struct`.
+pub unsafe trait HasDelayedWork<T, const ID: u64 = 0>: HasWork<T, ID> {}
+
+/// Used to safely implement the [`HasDelayedWork<T, ID>`] trait.
+///
+/// This macro also implements the [`HasWork`] trait, so you do not need to use [`impl_has_work!`]
+/// when using this macro.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::sync::Arc;
+/// use kernel::workqueue::{self, impl_has_delayed_work, DelayedWork};
+///
+/// struct MyStruct<'a, T, const N: usize> {
+/// work_field: DelayedWork<MyStruct<'a, T, N>, 17>,
+/// f: fn(&'a [T; N]),
+/// }
+///
+/// impl_has_delayed_work! {
+/// impl{'a, T, const N: usize} HasDelayedWork<MyStruct<'a, T, N>, 17>
+/// for MyStruct<'a, T, N> { self.work_field }
+/// }
+/// ```
+#[macro_export]
+macro_rules! impl_has_delayed_work {
+ ($(impl$({$($generics:tt)*})?
+ HasDelayedWork<$work_type:ty $(, $id:tt)?>
+ for $self:ty
+ { self.$field:ident }
+ )*) => {$(
+ // SAFETY: The implementation of `raw_get_work` only compiles if the field has the right
+ // type.
+ unsafe impl$(<$($generics)+>)?
+ $crate::workqueue::HasDelayedWork<$work_type $(, $id)?> for $self {}
+
+ // SAFETY: The implementation of `raw_get_work` only compiles if the field has the right
+ // type.
+ unsafe impl$(<$($generics)+>)? $crate::workqueue::HasWork<$work_type $(, $id)?> for $self {
+ #[inline]
+ unsafe fn raw_get_work(
+ ptr: *mut Self
+ ) -> *mut $crate::workqueue::Work<$work_type $(, $id)?> {
+ // SAFETY: The caller promises that the pointer is not dangling.
+ let ptr: *mut $crate::workqueue::DelayedWork<$work_type $(, $id)?> = unsafe {
+ ::core::ptr::addr_of_mut!((*ptr).$field)
+ };
+
+ // SAFETY: The caller promises that the pointer is not dangling.
+ unsafe { $crate::workqueue::DelayedWork::raw_as_work(ptr) }
+ }
+
+ #[inline]
+ unsafe fn work_container_of(
+ ptr: *mut $crate::workqueue::Work<$work_type $(, $id)?>,
+ ) -> *mut Self {
+ // SAFETY: The caller promises that the pointer points at a field of the right type
+ // in the right kind of struct.
+ let ptr = unsafe { $crate::workqueue::Work::raw_get(ptr) };
+
+ // SAFETY: The caller promises that the pointer points at a field of the right type
+ // in the right kind of struct.
+ let delayed_work = unsafe {
+ $crate::container_of!(ptr, $crate::bindings::delayed_work, work)
+ };
+
+ let delayed_work: *mut $crate::workqueue::DelayedWork<$work_type $(, $id)?> =
+ delayed_work.cast();
+
+ // SAFETY: The caller promises that the pointer points at a field of the right type
+ // in the right kind of struct.
+ unsafe { $crate::container_of!(delayed_work, Self, $field) }
+ }
+ }
+ )*};
+}
+pub use impl_has_delayed_work;
+
// SAFETY: The `__enqueue` implementation in RawWorkItem uses a `work_struct` initialized with the
// `run` method of this trait as the function pointer because:
// - `__enqueue` gets the `work_struct` from the `Work` field, using `T::raw_get_work`.
@@ -522,7 +826,7 @@ where
{
unsafe extern "C" fn run(ptr: *mut bindings::work_struct) {
// The `__enqueue` method always uses a `work_struct` stored in a `Work<T, ID>`.
- let ptr = ptr as *mut Work<T, ID>;
+ let ptr = ptr.cast::<Work<T, ID>>();
// SAFETY: This computes the pointer that `__enqueue` got from `Arc::into_raw`.
let ptr = unsafe { T::work_container_of(ptr) };
// SAFETY: This pointer comes from `Arc::into_raw` and we've been given back ownership.
@@ -567,6 +871,16 @@ where
}
}
+// SAFETY: By the safety requirements of `HasDelayedWork`, the `work_struct` returned by methods in
+// `HasWork` provides a `work_struct` that is the `work` field of a `delayed_work`, and the rest of
+// the `delayed_work` has the same access rules as its `work` field.
+unsafe impl<T, const ID: u64> RawDelayedWorkItem<ID> for Arc<T>
+where
+ T: WorkItem<ID, Pointer = Self>,
+ T: HasDelayedWork<T, ID>,
+{
+}
+
// SAFETY: TODO.
unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Pin<KBox<T>>
where
@@ -575,7 +889,7 @@ where
{
unsafe extern "C" fn run(ptr: *mut bindings::work_struct) {
// The `__enqueue` method always uses a `work_struct` stored in a `Work<T, ID>`.
- let ptr = ptr as *mut Work<T, ID>;
+ let ptr = ptr.cast::<Work<T, ID>>();
// SAFETY: This computes the pointer that `__enqueue` got from `Arc::into_raw`.
let ptr = unsafe { T::work_container_of(ptr) };
// SAFETY: This pointer comes from `Arc::into_raw` and we've been given back ownership.
@@ -617,6 +931,16 @@ where
}
}
+// SAFETY: By the safety requirements of `HasDelayedWork`, the `work_struct` returned by methods in
+// `HasWork` provides a `work_struct` that is the `work` field of a `delayed_work`, and the rest of
+// the `delayed_work` has the same access rules as its `work` field.
+unsafe impl<T, const ID: u64> RawDelayedWorkItem<ID> for Pin<KBox<T>>
+where
+ T: WorkItem<ID, Pointer = Self>,
+ T: HasDelayedWork<T, ID>,
+{
+}
+
/// Returns the system work queue (`system_wq`).
///
/// It is the one used by `schedule[_delayed]_work[_on]()`. Multi-CPU multi-threaded. There are
diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs
index 75719e7bb491..a49d6db28845 100644
--- a/rust/kernel/xarray.rs
+++ b/rust/kernel/xarray.rs
@@ -7,9 +7,10 @@
use crate::{
alloc, bindings, build_assert,
error::{Error, Result},
+ ffi::c_void,
types::{ForeignOwnable, NotThreadSafe, Opaque},
};
-use core::{iter, marker::PhantomData, mem, pin::Pin, ptr::NonNull};
+use core::{iter, marker::PhantomData, pin::Pin, ptr::NonNull};
use pin_init::{pin_data, pin_init, pinned_drop, PinInit};
/// An array which efficiently maps sparse integer indices to owned objects.
@@ -101,7 +102,7 @@ impl<T: ForeignOwnable> XArray<T> {
})
}
- fn iter(&self) -> impl Iterator<Item = NonNull<T::PointedTo>> + '_ {
+ fn iter(&self) -> impl Iterator<Item = NonNull<c_void>> + '_ {
let mut index = 0;
// SAFETY: `self.xa` is always valid by the type invariant.
@@ -179,7 +180,7 @@ impl<T> From<StoreError<T>> for Error {
impl<'a, T: ForeignOwnable> Guard<'a, T> {
fn load<F, U>(&self, index: usize, f: F) -> Option<U>
where
- F: FnOnce(NonNull<T::PointedTo>) -> U,
+ F: FnOnce(NonNull<c_void>) -> U,
{
// SAFETY: `self.xa.xa` is always valid by the type invariant.
let ptr = unsafe { bindings::xa_load(self.xa.xa.get(), index) };
@@ -230,7 +231,7 @@ impl<'a, T: ForeignOwnable> Guard<'a, T> {
gfp: alloc::Flags,
) -> Result<Option<T>, StoreError<T>> {
build_assert!(
- mem::align_of::<T::PointedTo>() >= 4,
+ T::FOREIGN_ALIGN >= 4,
"pointers stored in XArray must be 4-byte aligned"
);
let new = value.into_foreign();
diff --git a/rust/macros/module.rs b/rust/macros/module.rs
index 75efc6eeeafc..5ee54a00c0b6 100644
--- a/rust/macros/module.rs
+++ b/rust/macros/module.rs
@@ -94,7 +94,6 @@ struct ModuleInfo {
type_: String,
license: String,
name: String,
- author: Option<String>,
authors: Option<Vec<String>>,
description: Option<String>,
alias: Option<Vec<String>>,
@@ -108,7 +107,6 @@ impl ModuleInfo {
const EXPECTED_KEYS: &[&str] = &[
"type",
"name",
- "author",
"authors",
"description",
"license",
@@ -134,7 +132,6 @@ impl ModuleInfo {
match key.as_str() {
"type" => info.type_ = expect_ident(it),
"name" => info.name = expect_string_ascii(it),
- "author" => info.author = Some(expect_string(it)),
"authors" => info.authors = Some(expect_string_array(it)),
"description" => info.description = Some(expect_string(it)),
"license" => info.license = expect_string_ascii(it),
@@ -179,9 +176,6 @@ pub(crate) fn module(ts: TokenStream) -> TokenStream {
// Rust does not allow hyphens in identifiers, use underscore instead.
let ident = info.name.replace('-', "_");
let mut modinfo = ModInfoBuilder::new(ident.as_ref());
- if let Some(author) = info.author {
- modinfo.emit("author", &author);
- }
if let Some(authors) = info.authors {
for author in authors {
modinfo.emit("author", &author);
diff --git a/rust/pin-init/README.md b/rust/pin-init/README.md
index 2d0cda961d45..a4c01a8d78b2 100644
--- a/rust/pin-init/README.md
+++ b/rust/pin-init/README.md
@@ -125,7 +125,7 @@ impl DriverData {
fn new() -> impl PinInit<Self, Error> {
try_pin_init!(Self {
status <- CMutex::new(0),
- buffer: Box::init(pin_init::zeroed())?,
+ buffer: Box::init(pin_init::init_zeroed())?,
}? Error)
}
}
diff --git a/rust/pin-init/examples/big_struct_in_place.rs b/rust/pin-init/examples/big_struct_in_place.rs
index 30d44a334ffd..c05139927486 100644
--- a/rust/pin-init/examples/big_struct_in_place.rs
+++ b/rust/pin-init/examples/big_struct_in_place.rs
@@ -4,6 +4,7 @@ use pin_init::*;
// Struct with size over 1GiB
#[derive(Debug)]
+#[allow(dead_code)]
pub struct BigStruct {
buf: [u8; 1024 * 1024 * 1024],
a: u64,
@@ -20,20 +21,23 @@ pub struct ManagedBuf {
impl ManagedBuf {
pub fn new() -> impl Init<Self> {
- init!(ManagedBuf { buf <- zeroed() })
+ init!(ManagedBuf { buf <- init_zeroed() })
}
}
fn main() {
- // we want to initialize the struct in-place, otherwise we would get a stackoverflow
- let buf: Box<BigStruct> = Box::init(init!(BigStruct {
- buf <- zeroed(),
- a: 7,
- b: 186,
- c: 7789,
- d: 34,
- managed_buf <- ManagedBuf::new(),
- }))
- .unwrap();
- println!("{}", core::mem::size_of_val(&*buf));
+ #[cfg(any(feature = "std", feature = "alloc"))]
+ {
+ // we want to initialize the struct in-place, otherwise we would get a stackoverflow
+ let buf: Box<BigStruct> = Box::init(init!(BigStruct {
+ buf <- init_zeroed(),
+ a: 7,
+ b: 186,
+ c: 7789,
+ d: 34,
+ managed_buf <- ManagedBuf::new(),
+ }))
+ .unwrap();
+ println!("{}", core::mem::size_of_val(&*buf));
+ }
}
diff --git a/rust/pin-init/examples/linked_list.rs b/rust/pin-init/examples/linked_list.rs
index 0bbc7b8d83a1..f9e117c7dfe0 100644
--- a/rust/pin-init/examples/linked_list.rs
+++ b/rust/pin-init/examples/linked_list.rs
@@ -14,8 +14,9 @@ use core::{
use pin_init::*;
-#[expect(unused_attributes)]
+#[allow(unused_attributes)]
mod error;
+#[allow(unused_imports)]
use error::Error;
#[pin_data(PinnedDrop)]
@@ -39,6 +40,7 @@ impl ListHead {
}
#[inline]
+ #[allow(dead_code)]
pub fn insert_next(list: &ListHead) -> impl PinInit<Self, Infallible> + '_ {
try_pin_init!(&this in Self {
prev: list.next.prev().replace(unsafe { Link::new_unchecked(this)}),
@@ -112,6 +114,7 @@ impl Link {
}
#[inline]
+ #[allow(dead_code)]
fn prev(&self) -> &Link {
unsafe { &(*self.0.get().as_ptr()).prev }
}
@@ -138,7 +141,12 @@ impl Link {
}
#[allow(dead_code)]
+#[cfg(not(any(feature = "std", feature = "alloc")))]
+fn main() {}
+
+#[allow(dead_code)]
#[cfg_attr(test, test)]
+#[cfg(any(feature = "std", feature = "alloc"))]
fn main() -> Result<(), Error> {
let a = Box::pin_init(ListHead::new())?;
stack_pin_init!(let b = ListHead::insert_next(&a));
diff --git a/rust/pin-init/examples/mutex.rs b/rust/pin-init/examples/mutex.rs
index 3e3630780c96..9f295226cd64 100644
--- a/rust/pin-init/examples/mutex.rs
+++ b/rust/pin-init/examples/mutex.rs
@@ -12,14 +12,15 @@ use core::{
pin::Pin,
sync::atomic::{AtomicBool, Ordering},
};
+#[cfg(feature = "std")]
use std::{
sync::Arc,
- thread::{self, park, sleep, Builder, Thread},
+ thread::{self, sleep, Builder, Thread},
time::Duration,
};
use pin_init::*;
-#[expect(unused_attributes)]
+#[allow(unused_attributes)]
#[path = "./linked_list.rs"]
pub mod linked_list;
use linked_list::*;
@@ -36,6 +37,7 @@ impl SpinLock {
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
.is_err()
{
+ #[cfg(feature = "std")]
while self.inner.load(Ordering::Relaxed) {
thread::yield_now();
}
@@ -94,7 +96,8 @@ impl<T> CMutex<T> {
// println!("wait list length: {}", self.wait_list.size());
while self.locked.get() {
drop(sguard);
- park();
+ #[cfg(feature = "std")]
+ thread::park();
sguard = self.spin_lock.acquire();
}
// This does have an effect, as the ListHead inside wait_entry implements Drop!
@@ -131,8 +134,11 @@ impl<T> Drop for CMutexGuard<'_, T> {
let sguard = self.mtx.spin_lock.acquire();
self.mtx.locked.set(false);
if let Some(list_field) = self.mtx.wait_list.next() {
- let wait_entry = list_field.as_ptr().cast::<WaitEntry>();
- unsafe { (*wait_entry).thread.unpark() };
+ let _wait_entry = list_field.as_ptr().cast::<WaitEntry>();
+ #[cfg(feature = "std")]
+ unsafe {
+ (*_wait_entry).thread.unpark()
+ };
}
drop(sguard);
}
@@ -159,52 +165,61 @@ impl<T> DerefMut for CMutexGuard<'_, T> {
struct WaitEntry {
#[pin]
wait_list: ListHead,
+ #[cfg(feature = "std")]
thread: Thread,
}
impl WaitEntry {
#[inline]
fn insert_new(list: &ListHead) -> impl PinInit<Self> + '_ {
- pin_init!(Self {
- thread: thread::current(),
- wait_list <- ListHead::insert_prev(list),
- })
+ #[cfg(feature = "std")]
+ {
+ pin_init!(Self {
+ thread: thread::current(),
+ wait_list <- ListHead::insert_prev(list),
+ })
+ }
+ #[cfg(not(feature = "std"))]
+ {
+ pin_init!(Self {
+ wait_list <- ListHead::insert_prev(list),
+ })
+ }
}
}
-#[cfg(not(any(feature = "std", feature = "alloc")))]
-fn main() {}
-
-#[allow(dead_code)]
#[cfg_attr(test, test)]
-#[cfg(any(feature = "std", feature = "alloc"))]
+#[allow(dead_code)]
fn main() {
- let mtx: Pin<Arc<CMutex<usize>>> = Arc::pin_init(CMutex::new(0)).unwrap();
- let mut handles = vec![];
- let thread_count = 20;
- let workload = if cfg!(miri) { 100 } else { 1_000 };
- for i in 0..thread_count {
- let mtx = mtx.clone();
- handles.push(
- Builder::new()
- .name(format!("worker #{i}"))
- .spawn(move || {
- for _ in 0..workload {
- *mtx.lock() += 1;
- }
- println!("{i} halfway");
- sleep(Duration::from_millis((i as u64) * 10));
- for _ in 0..workload {
- *mtx.lock() += 1;
- }
- println!("{i} finished");
- })
- .expect("should not fail"),
- );
- }
- for h in handles {
- h.join().expect("thread panicked");
+ #[cfg(feature = "std")]
+ {
+ let mtx: Pin<Arc<CMutex<usize>>> = Arc::pin_init(CMutex::new(0)).unwrap();
+ let mut handles = vec![];
+ let thread_count = 20;
+ let workload = if cfg!(miri) { 100 } else { 1_000 };
+ for i in 0..thread_count {
+ let mtx = mtx.clone();
+ handles.push(
+ Builder::new()
+ .name(format!("worker #{i}"))
+ .spawn(move || {
+ for _ in 0..workload {
+ *mtx.lock() += 1;
+ }
+ println!("{i} halfway");
+ sleep(Duration::from_millis((i as u64) * 10));
+ for _ in 0..workload {
+ *mtx.lock() += 1;
+ }
+ println!("{i} finished");
+ })
+ .expect("should not fail"),
+ );
+ }
+ for h in handles {
+ h.join().expect("thread panicked");
+ }
+ println!("{:?}", &*mtx.lock());
+ assert_eq!(*mtx.lock(), workload * thread_count * 2);
}
- println!("{:?}", &*mtx.lock());
- assert_eq!(*mtx.lock(), workload * thread_count * 2);
}
diff --git a/rust/pin-init/examples/pthread_mutex.rs b/rust/pin-init/examples/pthread_mutex.rs
index 5acc5108b954..49b004c8c137 100644
--- a/rust/pin-init/examples/pthread_mutex.rs
+++ b/rust/pin-init/examples/pthread_mutex.rs
@@ -44,6 +44,7 @@ mod pthread_mtx {
pub enum Error {
#[allow(dead_code)]
IO(std::io::Error),
+ #[allow(dead_code)]
Alloc,
}
@@ -61,6 +62,7 @@ mod pthread_mtx {
}
impl<T> PThreadMutex<T> {
+ #[allow(dead_code)]
pub fn new(data: T) -> impl PinInit<Self, Error> {
fn init_raw() -> impl PinInit<UnsafeCell<libc::pthread_mutex_t>, Error> {
let init = |slot: *mut UnsafeCell<libc::pthread_mutex_t>| {
@@ -103,6 +105,7 @@ mod pthread_mtx {
}? Error)
}
+ #[allow(dead_code)]
pub fn lock(&self) -> PThreadMutexGuard<'_, T> {
// SAFETY: raw is always initialized
unsafe { libc::pthread_mutex_lock(self.raw.get()) };
@@ -137,6 +140,7 @@ mod pthread_mtx {
}
#[cfg_attr(test, test)]
+#[cfg_attr(all(test, miri), ignore)]
fn main() {
#[cfg(all(any(feature = "std", feature = "alloc"), not(windows)))]
{
diff --git a/rust/pin-init/examples/static_init.rs b/rust/pin-init/examples/static_init.rs
index 48531413ab94..0e165daa9798 100644
--- a/rust/pin-init/examples/static_init.rs
+++ b/rust/pin-init/examples/static_init.rs
@@ -3,6 +3,7 @@
#![allow(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(feature = "alloc", feature(allocator_api))]
#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
+#![allow(unused_imports)]
use core::{
cell::{Cell, UnsafeCell},
@@ -12,12 +13,13 @@ use core::{
time::Duration,
};
use pin_init::*;
+#[cfg(feature = "std")]
use std::{
sync::Arc,
thread::{sleep, Builder},
};
-#[expect(unused_attributes)]
+#[allow(unused_attributes)]
mod mutex;
use mutex::*;
@@ -82,42 +84,41 @@ unsafe impl PinInit<CMutex<usize>> for CountInit {
pub static COUNT: StaticInit<CMutex<usize>, CountInit> = StaticInit::new(CountInit);
-#[cfg(not(any(feature = "std", feature = "alloc")))]
-fn main() {}
-
-#[cfg(any(feature = "std", feature = "alloc"))]
fn main() {
- let mtx: Pin<Arc<CMutex<usize>>> = Arc::pin_init(CMutex::new(0)).unwrap();
- let mut handles = vec![];
- let thread_count = 20;
- let workload = 1_000;
- for i in 0..thread_count {
- let mtx = mtx.clone();
- handles.push(
- Builder::new()
- .name(format!("worker #{i}"))
- .spawn(move || {
- for _ in 0..workload {
- *COUNT.lock() += 1;
- std::thread::sleep(std::time::Duration::from_millis(10));
- *mtx.lock() += 1;
- std::thread::sleep(std::time::Duration::from_millis(10));
- *COUNT.lock() += 1;
- }
- println!("{i} halfway");
- sleep(Duration::from_millis((i as u64) * 10));
- for _ in 0..workload {
- std::thread::sleep(std::time::Duration::from_millis(10));
- *mtx.lock() += 1;
- }
- println!("{i} finished");
- })
- .expect("should not fail"),
- );
- }
- for h in handles {
- h.join().expect("thread panicked");
+ #[cfg(feature = "std")]
+ {
+ let mtx: Pin<Arc<CMutex<usize>>> = Arc::pin_init(CMutex::new(0)).unwrap();
+ let mut handles = vec![];
+ let thread_count = 20;
+ let workload = 1_000;
+ for i in 0..thread_count {
+ let mtx = mtx.clone();
+ handles.push(
+ Builder::new()
+ .name(format!("worker #{i}"))
+ .spawn(move || {
+ for _ in 0..workload {
+ *COUNT.lock() += 1;
+ std::thread::sleep(std::time::Duration::from_millis(10));
+ *mtx.lock() += 1;
+ std::thread::sleep(std::time::Duration::from_millis(10));
+ *COUNT.lock() += 1;
+ }
+ println!("{i} halfway");
+ sleep(Duration::from_millis((i as u64) * 10));
+ for _ in 0..workload {
+ std::thread::sleep(std::time::Duration::from_millis(10));
+ *mtx.lock() += 1;
+ }
+ println!("{i} finished");
+ })
+ .expect("should not fail"),
+ );
+ }
+ for h in handles {
+ h.join().expect("thread panicked");
+ }
+ println!("{:?}, {:?}", &*mtx.lock(), &*COUNT.lock());
+ assert_eq!(*mtx.lock(), workload * thread_count * 2);
}
- println!("{:?}, {:?}", &*mtx.lock(), &*COUNT.lock());
- assert_eq!(*mtx.lock(), workload * thread_count * 2);
}
diff --git a/rust/pin-init/src/__internal.rs b/rust/pin-init/src/__internal.rs
index 557b5948cddc..90f18e9a2912 100644
--- a/rust/pin-init/src/__internal.rs
+++ b/rust/pin-init/src/__internal.rs
@@ -188,6 +188,7 @@ impl<T> StackInit<T> {
}
#[test]
+#[cfg(feature = "std")]
fn stack_init_reuse() {
use ::std::{borrow::ToOwned, println, string::String};
use core::pin::pin;
diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs
index f4e034497cdd..62e013a5cc20 100644
--- a/rust/pin-init/src/lib.rs
+++ b/rust/pin-init/src/lib.rs
@@ -148,7 +148,7 @@
//! fn new() -> impl PinInit<Self, Error> {
//! try_pin_init!(Self {
//! status <- CMutex::new(0),
-//! buffer: Box::init(pin_init::zeroed())?,
+//! buffer: Box::init(pin_init::init_zeroed())?,
//! }? Error)
//! }
//! }
@@ -742,7 +742,7 @@ macro_rules! stack_try_pin_init {
/// - Fields that you want to initialize in-place have to use `<-` instead of `:`.
/// - In front of the initializer you can write `&this in` to have access to a [`NonNull<Self>`]
/// pointer named `this` inside of the initializer.
-/// - Using struct update syntax one can place `..Zeroable::zeroed()` at the very end of the
+/// - Using struct update syntax one can place `..Zeroable::init_zeroed()` at the very end of the
/// struct, this initializes every field with 0 and then runs all initializers specified in the
/// body. This can only be done if [`Zeroable`] is implemented for the struct.
///
@@ -769,7 +769,7 @@ macro_rules! stack_try_pin_init {
/// });
/// let init = pin_init!(Buf {
/// buf: [1; 64],
-/// ..Zeroable::zeroed()
+/// ..Zeroable::init_zeroed()
/// });
/// ```
///
@@ -805,7 +805,7 @@ macro_rules! pin_init {
/// ```rust
/// # #![feature(allocator_api)]
/// # #[path = "../examples/error.rs"] mod error; use error::Error;
-/// use pin_init::{pin_data, try_pin_init, PinInit, InPlaceInit, zeroed};
+/// use pin_init::{pin_data, try_pin_init, PinInit, InPlaceInit, init_zeroed};
///
/// #[pin_data]
/// struct BigBuf {
@@ -817,7 +817,7 @@ macro_rules! pin_init {
/// impl BigBuf {
/// fn new() -> impl PinInit<Self, Error> {
/// try_pin_init!(Self {
-/// big: Box::init(zeroed())?,
+/// big: Box::init(init_zeroed())?,
/// small: [0; 1024 * 1024],
/// ptr: core::ptr::null_mut(),
/// }? Error)
@@ -866,7 +866,7 @@ macro_rules! try_pin_init {
/// # #[path = "../examples/error.rs"] mod error; use error::Error;
/// # #[path = "../examples/mutex.rs"] mod mutex; use mutex::*;
/// # use pin_init::InPlaceInit;
-/// use pin_init::{init, Init, zeroed};
+/// use pin_init::{init, Init, init_zeroed};
///
/// struct BigBuf {
/// small: [u8; 1024 * 1024],
@@ -875,7 +875,7 @@ macro_rules! try_pin_init {
/// impl BigBuf {
/// fn new() -> impl Init<Self> {
/// init!(Self {
-/// small <- zeroed(),
+/// small <- init_zeroed(),
/// })
/// }
/// }
@@ -913,7 +913,7 @@ macro_rules! init {
/// # #![feature(allocator_api)]
/// # use core::alloc::AllocError;
/// # use pin_init::InPlaceInit;
-/// use pin_init::{try_init, Init, zeroed};
+/// use pin_init::{try_init, Init, init_zeroed};
///
/// struct BigBuf {
/// big: Box<[u8; 1024 * 1024 * 1024]>,
@@ -923,7 +923,7 @@ macro_rules! init {
/// impl BigBuf {
/// fn new() -> impl Init<Self, AllocError> {
/// try_init!(Self {
-/// big: Box::init(zeroed())?,
+/// big: Box::init(init_zeroed())?,
/// small: [0; 1024 * 1024],
/// }? AllocError)
/// }
@@ -953,7 +953,7 @@ macro_rules! try_init {
/// Asserts that a field on a struct using `#[pin_data]` is marked with `#[pin]` ie. that it is
/// structurally pinned.
///
-/// # Example
+/// # Examples
///
/// This will succeed:
/// ```
@@ -1170,7 +1170,7 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> {
///
/// ```rust
/// # #![expect(clippy::disallowed_names)]
- /// use pin_init::{init, zeroed, Init};
+ /// use pin_init::{init, init_zeroed, Init};
///
/// struct Foo {
/// buf: [u8; 1_000_000],
@@ -1183,7 +1183,7 @@ pub unsafe trait Init<T: ?Sized, E = Infallible>: PinInit<T, E> {
/// }
///
/// let foo = init!(Foo {
- /// buf <- zeroed()
+ /// buf <- init_zeroed()
/// }).chain(|foo| {
/// foo.setup();
/// Ok(())
@@ -1495,7 +1495,45 @@ pub unsafe trait PinnedDrop: __internal::HasPinData {
/// ```rust,ignore
/// let val: Self = unsafe { core::mem::zeroed() };
/// ```
-pub unsafe trait Zeroable {}
+pub unsafe trait Zeroable {
+ /// Create a new zeroed `Self`.
+ ///
+ /// The returned initializer will write `0x00` to every byte of the given `slot`.
+ #[inline]
+ fn init_zeroed() -> impl Init<Self>
+ where
+ Self: Sized,
+ {
+ init_zeroed()
+ }
+
+ /// Create a `Self` consisting of all zeroes.
+ ///
+ /// Whenever a type implements [`Zeroable`], this function should be preferred over
+ /// [`core::mem::zeroed()`] or using `MaybeUninit<T>::zeroed().assume_init()`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use pin_init::{Zeroable, zeroed};
+ ///
+ /// #[derive(Zeroable)]
+ /// struct Point {
+ /// x: u32,
+ /// y: u32,
+ /// }
+ ///
+ /// let point: Point = zeroed();
+ /// assert_eq!(point.x, 0);
+ /// assert_eq!(point.y, 0);
+ /// ```
+ fn zeroed() -> Self
+ where
+ Self: Sized,
+ {
+ zeroed()
+ }
+}
/// Marker trait for types that allow `Option<Self>` to be set to all zeroes in order to write
/// `None` to that location.
@@ -1508,11 +1546,21 @@ pub unsafe trait ZeroableOption {}
// SAFETY: by the safety requirement of `ZeroableOption`, this is valid.
unsafe impl<T: ZeroableOption> Zeroable for Option<T> {}
-/// Create a new zeroed T.
+// SAFETY: `Option<&T>` is part of the option layout optimization guarantee:
+// <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
+unsafe impl<T> ZeroableOption for &T {}
+// SAFETY: `Option<&mut T>` is part of the option layout optimization guarantee:
+// <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
+unsafe impl<T> ZeroableOption for &mut T {}
+// SAFETY: `Option<NonNull<T>>` is part of the option layout optimization guarantee:
+// <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
+unsafe impl<T> ZeroableOption for NonNull<T> {}
+
+/// Create an initializer for a zeroed `T`.
///
/// The returned initializer will write `0x00` to every byte of the given `slot`.
#[inline]
-pub fn zeroed<T: Zeroable>() -> impl Init<T> {
+pub fn init_zeroed<T: Zeroable>() -> impl Init<T> {
// SAFETY: Because `T: Zeroable`, all bytes zero is a valid bit pattern for `T`
// and because we write all zeroes, the memory is initialized.
unsafe {
@@ -1523,6 +1571,31 @@ pub fn zeroed<T: Zeroable>() -> impl Init<T> {
}
}
+/// Create a `T` consisting of all zeroes.
+///
+/// Whenever a type implements [`Zeroable`], this function should be preferred over
+/// [`core::mem::zeroed()`] or using `MaybeUninit<T>::zeroed().assume_init()`.
+///
+/// # Examples
+///
+/// ```
+/// use pin_init::{Zeroable, zeroed};
+///
+/// #[derive(Zeroable)]
+/// struct Point {
+/// x: u32,
+/// y: u32,
+/// }
+///
+/// let point: Point = zeroed();
+/// assert_eq!(point.x, 0);
+/// assert_eq!(point.y, 0);
+/// ```
+pub const fn zeroed<T: Zeroable>() -> T {
+ // SAFETY:By the type invariants of `Zeroable`, all zeroes is a valid bit pattern for `T`.
+ unsafe { core::mem::zeroed() }
+}
+
macro_rules! impl_zeroable {
($($({$($generics:tt)*})? $t:ty, )*) => {
// SAFETY: Safety comments written in the macro invocation.
@@ -1560,7 +1633,6 @@ impl_zeroable! {
Option<NonZeroU128>, Option<NonZeroUsize>,
Option<NonZeroI8>, Option<NonZeroI16>, Option<NonZeroI32>, Option<NonZeroI64>,
Option<NonZeroI128>, Option<NonZeroIsize>,
- {<T>} Option<NonNull<T>>,
// SAFETY: `null` pointer is valid.
//
@@ -1590,6 +1662,22 @@ macro_rules! impl_tuple_zeroable {
impl_tuple_zeroable!(A, B, C, D, E, F, G, H, I, J);
+macro_rules! impl_fn_zeroable_option {
+ ([$($abi:literal),* $(,)?] $args:tt) => {
+ $(impl_fn_zeroable_option!({extern $abi} $args);)*
+ $(impl_fn_zeroable_option!({unsafe extern $abi} $args);)*
+ };
+ ({$($prefix:tt)*} {$(,)?}) => {};
+ ({$($prefix:tt)*} {$ret:ident, $($rest:ident),* $(,)?}) => {
+ // SAFETY: function pointers are part of the option layout optimization:
+ // <https://doc.rust-lang.org/stable/std/option/index.html#representation>.
+ unsafe impl<$ret, $($rest),*> ZeroableOption for $($prefix)* fn($($rest),*) -> $ret {}
+ impl_fn_zeroable_option!({$($prefix)*} {$($rest),*,});
+ };
+}
+
+impl_fn_zeroable_option!(["Rust", "C"] { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U });
+
/// This trait allows creating an instance of `Self` which contains exactly one
/// [structurally pinned value](https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning).
///
diff --git a/rust/pin-init/src/macros.rs b/rust/pin-init/src/macros.rs
index 935d77745d1d..9ced630737b8 100644
--- a/rust/pin-init/src/macros.rs
+++ b/rust/pin-init/src/macros.rs
@@ -1030,7 +1030,7 @@ macro_rules! __pin_data {
///
/// This macro has multiple internal call configurations, these are always the very first ident:
/// - nothing: this is the base case and called by the `{try_}{pin_}init!` macros.
-/// - `with_update_parsed`: when the `..Zeroable::zeroed()` syntax has been handled.
+/// - `with_update_parsed`: when the `..Zeroable::init_zeroed()` syntax has been handled.
/// - `init_slot`: recursively creates the code that initializes all fields in `slot`.
/// - `make_initializer`: recursively create the struct initializer that guarantees that every
/// field has been initialized exactly once.
@@ -1059,7 +1059,7 @@ macro_rules! __init_internal {
@data($data, $($use_data)?),
@has_data($has_data, $get_data),
@construct_closure($construct_closure),
- @zeroed(), // Nothing means default behavior.
+ @init_zeroed(), // Nothing means default behavior.
)
};
(
@@ -1074,7 +1074,7 @@ macro_rules! __init_internal {
@has_data($has_data:ident, $get_data:ident),
// `pin_init_from_closure` or `init_from_closure`.
@construct_closure($construct_closure:ident),
- @munch_fields(..Zeroable::zeroed()),
+ @munch_fields(..Zeroable::init_zeroed()),
) => {
$crate::__init_internal!(with_update_parsed:
@this($($this)?),
@@ -1084,7 +1084,7 @@ macro_rules! __init_internal {
@data($data, $($use_data)?),
@has_data($has_data, $get_data),
@construct_closure($construct_closure),
- @zeroed(()), // `()` means zero all fields not mentioned.
+ @init_zeroed(()), // `()` means zero all fields not mentioned.
)
};
(
@@ -1124,7 +1124,7 @@ macro_rules! __init_internal {
@has_data($has_data:ident, $get_data:ident),
// `pin_init_from_closure` or `init_from_closure`.
@construct_closure($construct_closure:ident),
- @zeroed($($init_zeroed:expr)?),
+ @init_zeroed($($init_zeroed:expr)?),
) => {{
// We do not want to allow arbitrary returns, so we declare this type as the `Ok` return
// type and shadow it later when we insert the arbitrary user code. That way there will be
@@ -1196,7 +1196,7 @@ macro_rules! __init_internal {
@data($data:ident),
@slot($slot:ident),
@guards($($guards:ident,)*),
- @munch_fields($(..Zeroable::zeroed())? $(,)?),
+ @munch_fields($(..Zeroable::init_zeroed())? $(,)?),
) => {
// Endpoint of munching, no fields are left. If execution reaches this point, all fields
// have been initialized. Therefore we can now dismiss the guards by forgetting them.
@@ -1300,11 +1300,11 @@ macro_rules! __init_internal {
(make_initializer:
@slot($slot:ident),
@type_name($t:path),
- @munch_fields(..Zeroable::zeroed() $(,)?),
+ @munch_fields(..Zeroable::init_zeroed() $(,)?),
@acc($($acc:tt)*),
) => {
// Endpoint, nothing more to munch, create the initializer. Since the users specified
- // `..Zeroable::zeroed()`, the slot will already have been zeroed and all field that have
+ // `..Zeroable::init_zeroed()`, the slot will already have been zeroed and all field that have
// not been overwritten are thus zero and initialized. We still check that all fields are
// actually accessible by using the struct update syntax ourselves.
// We are inside of a closure that is never executed and thus we can abuse `slot` to
diff --git a/rust/uapi/lib.rs b/rust/uapi/lib.rs
index c98d7a8cde77..31c2f713313f 100644
--- a/rust/uapi/lib.rs
+++ b/rust/uapi/lib.rs
@@ -14,6 +14,9 @@
#![cfg_attr(test, allow(unsafe_op_in_unsafe_fn))]
#![allow(
clippy::all,
+ clippy::cast_lossless,
+ clippy::ptr_as_ptr,
+ clippy::ref_as_ptr,
clippy::undocumented_unsafe_blocks,
dead_code,
missing_docs,
diff --git a/samples/Kconfig b/samples/Kconfig
index ffef99950206..6e072a5f1ed8 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -54,7 +54,7 @@ config SAMPLE_FTRACE_OPS
measures the time taken to invoke one function a number of times.
config SAMPLE_TRACE_ARRAY
- tristate "Build sample module for kernel access to Ftrace instancess"
+ tristate "Build sample module for kernel access to Ftrace instances"
depends on EVENT_TRACING && m
help
This builds a module that demonstrates the use of various APIs to
@@ -316,10 +316,9 @@ config SAMPLE_HUNG_TASK
depends on DETECT_HUNG_TASK && DEBUG_FS
help
Build a module that provides debugfs files (e.g., mutex, semaphore,
- etc.) under <debugfs>/hung_task. If user reads one of these files,
- it will sleep long time (256 seconds) with holding a lock. Thus,
- if 2 or more processes read the same file concurrently, it will
- be detected by the hung_task watchdog.
+ rw_semaphore_read, rw_semaphore_write) under <debugfs>/hung_task.
+ Reading these files with multiple processes triggers hung task
+ detection by holding locks for a long time (256 seconds).
source "samples/rust/Kconfig"
diff --git a/samples/hung_task/hung_task_tests.c b/samples/hung_task/hung_task_tests.c
index a5c09bd3a47d..0360ec916890 100644
--- a/samples/hung_task/hung_task_tests.c
+++ b/samples/hung_task/hung_task_tests.c
@@ -4,11 +4,12 @@
* semaphore, etc.
*
* Usage: Load this module and read `<debugfs>/hung_task/mutex`,
- * `<debugfs>/hung_task/semaphore`, etc., with 2 or more processes.
+ * `<debugfs>/hung_task/semaphore`, `<debugfs>/hung_task/rw_semaphore_read`,
+ * `<debugfs>/hung_task/rw_semaphore_write`, etc., with 2 or more processes.
*
* This is for testing kernel hung_task error messages with various locking
- * mechanisms (e.g., mutex, semaphore, etc.). Note that this may freeze
- * your system or cause a panic. Use only for testing purposes.
+ * mechanisms (e.g., mutex, semaphore, rw_semaphore_read, rw_semaphore_write, etc.).
+ * Note that this may freeze your system or cause a panic. Use only for testing purposes.
*/
#include <linux/debugfs.h>
@@ -17,21 +18,29 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/semaphore.h>
+#include <linux/rwsem.h>
-#define HUNG_TASK_DIR "hung_task"
-#define HUNG_TASK_MUTEX_FILE "mutex"
-#define HUNG_TASK_SEM_FILE "semaphore"
-#define SLEEP_SECOND 256
+#define HUNG_TASK_DIR "hung_task"
+#define HUNG_TASK_MUTEX_FILE "mutex"
+#define HUNG_TASK_SEM_FILE "semaphore"
+#define HUNG_TASK_RWSEM_READ_FILE "rw_semaphore_read"
+#define HUNG_TASK_RWSEM_WRITE_FILE "rw_semaphore_write"
+#define SLEEP_SECOND 256
static const char dummy_string[] = "This is a dummy string.";
static DEFINE_MUTEX(dummy_mutex);
static DEFINE_SEMAPHORE(dummy_sem, 1);
+static DECLARE_RWSEM(dummy_rwsem);
static struct dentry *hung_task_dir;
/* Mutex-based read function */
static ssize_t read_dummy_mutex(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
+ /* Check if data is already read */
+ if (*ppos >= sizeof(dummy_string))
+ return 0;
+
/* Second task waits on mutex, entering uninterruptible sleep */
guard(mutex)(&dummy_mutex);
@@ -46,6 +55,10 @@ static ssize_t read_dummy_mutex(struct file *file, char __user *user_buf,
static ssize_t read_dummy_semaphore(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
+ /* Check if data is already read */
+ if (*ppos >= sizeof(dummy_string))
+ return 0;
+
/* Second task waits on semaphore, entering uninterruptible sleep */
down(&dummy_sem);
@@ -58,6 +71,46 @@ static ssize_t read_dummy_semaphore(struct file *file, char __user *user_buf,
sizeof(dummy_string));
}
+/* Read-write semaphore read function */
+static ssize_t read_dummy_rwsem_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ /* Check if data is already read */
+ if (*ppos >= sizeof(dummy_string))
+ return 0;
+
+ /* Acquires read lock, allowing concurrent readers but blocks if write lock is held */
+ down_read(&dummy_rwsem);
+
+ /* Sleeps here, potentially triggering hung task detection if lock is held too long */
+ msleep_interruptible(SLEEP_SECOND * 1000);
+
+ up_read(&dummy_rwsem);
+
+ return simple_read_from_buffer(user_buf, count, ppos, dummy_string,
+ sizeof(dummy_string));
+}
+
+/* Read-write semaphore write function */
+static ssize_t read_dummy_rwsem_write(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ /* Check if data is already read */
+ if (*ppos >= sizeof(dummy_string))
+ return 0;
+
+ /* Acquires exclusive write lock, blocking all other readers and writers */
+ down_write(&dummy_rwsem);
+
+ /* Sleeps here, potentially triggering hung task detection if lock is held too long */
+ msleep_interruptible(SLEEP_SECOND * 1000);
+
+ up_write(&dummy_rwsem);
+
+ return simple_read_from_buffer(user_buf, count, ppos, dummy_string,
+ sizeof(dummy_string));
+}
+
/* File operations for mutex */
static const struct file_operations hung_task_mutex_fops = {
.read = read_dummy_mutex,
@@ -68,6 +121,16 @@ static const struct file_operations hung_task_sem_fops = {
.read = read_dummy_semaphore,
};
+/* File operations for rw_semaphore read */
+static const struct file_operations hung_task_rwsem_read_fops = {
+ .read = read_dummy_rwsem_read,
+};
+
+/* File operations for rw_semaphore write */
+static const struct file_operations hung_task_rwsem_write_fops = {
+ .read = read_dummy_rwsem_write,
+};
+
static int __init hung_task_tests_init(void)
{
hung_task_dir = debugfs_create_dir(HUNG_TASK_DIR, NULL);
@@ -79,6 +142,10 @@ static int __init hung_task_tests_init(void)
&hung_task_mutex_fops);
debugfs_create_file(HUNG_TASK_SEM_FILE, 0400, hung_task_dir, NULL,
&hung_task_sem_fops);
+ debugfs_create_file(HUNG_TASK_RWSEM_READ_FILE, 0400, hung_task_dir, NULL,
+ &hung_task_rwsem_read_fops);
+ debugfs_create_file(HUNG_TASK_RWSEM_WRITE_FILE, 0400, hung_task_dir, NULL,
+ &hung_task_rwsem_write_fops);
return 0;
}
diff --git a/samples/rust/rust_configfs.rs b/samples/rust/rust_configfs.rs
index 60ddbe62cda3..af04bfa35cb2 100644
--- a/samples/rust/rust_configfs.rs
+++ b/samples/rust/rust_configfs.rs
@@ -14,7 +14,7 @@ use kernel::sync::Mutex;
module! {
type: RustConfigfs,
name: "rust_configfs",
- author: "Rust for Linux Contributors",
+ authors: ["Rust for Linux Contributors"],
description: "Rust configfs sample",
license: "GPL",
}
diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs
index b25628604a93..f2a820683fc3 100644
--- a/samples/rust/rust_driver_auxiliary.rs
+++ b/samples/rust/rust_driver_auxiliary.rs
@@ -113,7 +113,7 @@ impl InPlaceModule for SampleModule {
module! {
type: SampleModule,
name: "rust_driver_auxiliary",
- author: "Danilo Krummrich",
+ authors: ["Danilo Krummrich"],
description: "Rust auxiliary driver",
license: "GPL v2",
}
diff --git a/samples/rust/rust_misc_device.rs b/samples/rust/rust_misc_device.rs
index c881fd6dbd08..e7ab77448f75 100644
--- a/samples/rust/rust_misc_device.rs
+++ b/samples/rust/rust_misc_device.rs
@@ -176,6 +176,8 @@ impl MiscDevice for RustMiscDevice {
fn ioctl(me: Pin<&RustMiscDevice>, _file: &File, cmd: u32, arg: usize) -> Result<isize> {
dev_info!(me.dev, "IOCTLing Rust Misc Device Sample\n");
+ // Treat the ioctl argument as a user pointer.
+ let arg = UserPtr::from_addr(arg);
let size = _IOC_SIZE(cmd);
match cmd {
diff --git a/samples/rust/rust_print_main.rs b/samples/rust/rust_print_main.rs
index 8ea95e8c2f36..4095c72afeab 100644
--- a/samples/rust/rust_print_main.rs
+++ b/samples/rust/rust_print_main.rs
@@ -40,7 +40,7 @@ fn arc_print() -> Result {
// behaviour, contract or protocol on both `i32` and `&str` into a single `Arc` of
// type `Arc<dyn Display>`.
- use core::fmt::Display;
+ use kernel::fmt::Display;
fn arc_dyn_print(arc: &Arc<dyn Display>) {
pr_info!("Arc<dyn Display> says {arc}");
}
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index ba71b27aa363..d0ee33a487be 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -309,14 +309,15 @@ $(obj)/%.lst: $(obj)/%.c FORCE
# The features in this list are the ones allowed for non-`rust/` code.
#
# - Stable since Rust 1.81.0: `feature(lint_reasons)`.
-# - Stable since Rust 1.82.0: `feature(asm_const)`, `feature(raw_ref_op)`.
+# - Stable since Rust 1.82.0: `feature(asm_const)`,
+# `feature(offset_of_nested)`, `feature(raw_ref_op)`.
# - Stable since Rust 1.87.0: `feature(asm_goto)`.
# - Expected to become stable: `feature(arbitrary_self_types)`.
# - To be determined: `feature(used_with_arg)`.
#
# Please see https://github.com/Rust-for-Linux/linux/issues/2 for details on
# the unstable features in use.
-rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,lint_reasons,raw_ref_op,used_with_arg
+rust_allowed_features := asm_const,asm_goto,arbitrary_self_types,lint_reasons,offset_of_nested,raw_ref_op,used_with_arg
# `--out-dir` is required to avoid temporaries being created by `rustc` in the
# current working directory, which may be not accessible in the out-of-tree
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 22a6de59b77b..e722dd6fa8ef 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -685,6 +685,9 @@ our $tracing_logging_tags = qr{(?xi:
[\.\!:\s]*
)};
+# Device ID types like found in include/linux/mod_devicetable.h.
+our $dev_id_types = qr{\b[a-z]\w*_device_id\b};
+
sub edit_distance_min {
my (@arr) = @_;
my $len = scalar @arr;
@@ -3500,9 +3503,10 @@ sub process {
# Check for various typo / spelling mistakes
if (defined($misspellings) &&
($in_commit_log || $line =~ /^(?:\+|Subject:)/i)) {
- while ($rawline =~ /(?:^|[^\w\-'`])($misspellings)(?:[^\w\-'`]|$)/gi) {
+ my $rawline_utf8 = decode("utf8", $rawline);
+ while ($rawline_utf8 =~ /(?:^|[^\w\-'`])($misspellings)(?:[^\w\-'`]|$)/gi) {
my $typo = $1;
- my $blank = copy_spacing($rawline);
+ my $blank = copy_spacing($rawline_utf8);
my $ptr = substr($blank, 0, $-[1]) . "^" x length($typo);
my $hereptr = "$hereline$ptr\n";
my $typo_fix = $spelling_fix{lc($typo)};
@@ -7688,6 +7692,31 @@ sub process {
WARN("DUPLICATED_SYSCTL_CONST",
"duplicated sysctl range checking value '$1', consider using the shared one in include/linux/sysctl.h\n" . $herecurr);
}
+
+# Check that *_device_id tables have sentinel entries.
+ if (defined $stat && $line =~ /struct\s+$dev_id_types\s+\w+\s*\[\s*\]\s*=\s*\{/) {
+ my $stripped = $stat;
+
+ # Strip diff line prefixes.
+ $stripped =~ s/(^|\n)./$1/g;
+ # Line continuations.
+ $stripped =~ s/\\\n/\n/g;
+ # Strip whitespace, empty strings, zeroes, and commas.
+ $stripped =~ s/""//g;
+ $stripped =~ s/0x0//g;
+ $stripped =~ s/[\s$;,0]//g;
+ # Strip field assignments.
+ $stripped =~ s/\.$Ident=//g;
+
+ if (!(substr($stripped, -4) eq "{}};" ||
+ substr($stripped, -6) eq "{{}}};" ||
+ $stripped =~ /ISAPNP_DEVICE_SINGLE_END}};$/ ||
+ $stripped =~ /ISAPNP_CARD_END}};$/ ||
+ $stripped =~ /NULL};$/ ||
+ $stripped =~ /PCMCIA_DEVICE_NULL};$/)) {
+ ERROR("MISSING_SENTINEL", "missing sentinel in ID array\n" . "$here\n$stat\n");
+ }
+ }
}
# If we have no input at all, then there is nothing to report on
diff --git a/scripts/coccinelle/misc/secs_to_jiffies.cocci b/scripts/coccinelle/misc/secs_to_jiffies.cocci
index 416f348174ca..f3241ce75a7b 100644
--- a/scripts/coccinelle/misc/secs_to_jiffies.cocci
+++ b/scripts/coccinelle/misc/secs_to_jiffies.cocci
@@ -7,26 +7,65 @@
// Confidence: High
// Copyright: (C) 2024 Easwar Hariharan, Microsoft
// Keywords: secs, seconds, jiffies
-//
+// Options: --include-headers
virtual patch
+virtual report
+virtual context
-@depends on patch@ constant C; @@
+@pconst depends on patch@ constant C; @@
- msecs_to_jiffies(C * 1000)
+ secs_to_jiffies(C)
-@depends on patch@ constant C; @@
+@pconstms depends on patch@ constant C; @@
- msecs_to_jiffies(C * MSEC_PER_SEC)
+ secs_to_jiffies(C)
-@depends on patch@ expression E; @@
+@pexpr depends on patch@ expression E; @@
- msecs_to_jiffies(E * 1000)
+ secs_to_jiffies(E)
-@depends on patch@ expression E; @@
+@pexprms depends on patch@ expression E; @@
- msecs_to_jiffies(E * MSEC_PER_SEC)
+ secs_to_jiffies(E)
+
+@r depends on report && !patch@
+constant C;
+expression E;
+position p;
+@@
+
+(
+ msecs_to_jiffies(C@p * 1000)
+|
+ msecs_to_jiffies(C@p * MSEC_PER_SEC)
+|
+ msecs_to_jiffies(E@p * 1000)
+|
+ msecs_to_jiffies(E@p * MSEC_PER_SEC)
+)
+
+@c depends on context && !patch@
+constant C;
+expression E;
+@@
+
+(
+* msecs_to_jiffies(C * 1000)
+|
+* msecs_to_jiffies(C * MSEC_PER_SEC)
+|
+* msecs_to_jiffies(E * 1000)
+|
+* msecs_to_jiffies(E * MSEC_PER_SEC)
+)
+
+@script:python depends on report@
+p << r.p;
+@@
+
+coccilib.report.print_report(p[0], "WARNING opportunity for secs_to_jiffies()")
diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in
index f795302ddfa8..c3886739a028 100644
--- a/scripts/gdb/linux/constants.py.in
+++ b/scripts/gdb/linux/constants.py.in
@@ -74,12 +74,12 @@ if IS_BUILTIN(CONFIG_MODULES):
LX_GDBPARSED(MOD_RO_AFTER_INIT)
/* linux/mount.h */
-LX_VALUE(MNT_NOSUID)
-LX_VALUE(MNT_NODEV)
-LX_VALUE(MNT_NOEXEC)
-LX_VALUE(MNT_NOATIME)
-LX_VALUE(MNT_NODIRATIME)
-LX_VALUE(MNT_RELATIME)
+LX_GDBPARSED(MNT_NOSUID)
+LX_GDBPARSED(MNT_NODEV)
+LX_GDBPARSED(MNT_NOEXEC)
+LX_GDBPARSED(MNT_NOATIME)
+LX_GDBPARSED(MNT_NODIRATIME)
+LX_GDBPARSED(MNT_RELATIME)
/* linux/threads.h */
LX_VALUE(NR_CPUS)
diff --git a/scripts/rustdoc_test_gen.rs b/scripts/rustdoc_test_gen.rs
index 1ca253594d38..abb34ada2508 100644
--- a/scripts/rustdoc_test_gen.rs
+++ b/scripts/rustdoc_test_gen.rs
@@ -85,24 +85,25 @@ fn find_real_path<'a>(srctree: &Path, valid_paths: &'a mut Vec<PathBuf>, file: &
}
}
- assert!(
- valid_paths.len() > 0,
- "No path candidates found for `{file}`. This is likely a bug in the build system, or some \
- files went away while compiling."
- );
-
- if valid_paths.len() > 1 {
- eprintln!("Several path candidates found:");
- for path in valid_paths {
- eprintln!(" {path:?}");
+ match valid_paths.as_slice() {
+ [] => panic!(
+ "No path candidates found for `{file}`. This is likely a bug in the build system, or \
+ some files went away while compiling."
+ ),
+ [valid_path] => valid_path.to_str().unwrap(),
+ valid_paths => {
+ use std::fmt::Write;
+
+ let mut candidates = String::new();
+ for path in valid_paths {
+ writeln!(&mut candidates, " {path:?}").unwrap();
+ }
+ panic!(
+ "Several path candidates found for `{file}`, please resolve the ambiguity by \
+ renaming a file or folder. Candidates:\n{candidates}",
+ );
}
- panic!(
- "Several path candidates found for `{file}`, please resolve the ambiguity by renaming \
- a file or folder."
- );
}
-
- valid_paths[0].to_str().unwrap()
}
fn main() {
diff --git a/scripts/spelling.txt b/scripts/spelling.txt
index ac94fa1c2415..1e89b92c2f9a 100644
--- a/scripts/spelling.txt
+++ b/scripts/spelling.txt
@@ -1099,6 +1099,7 @@ notication||notification
notications||notifications
notifcations||notifications
notifed||notified
+notifer||notifier
notity||notify
notfify||notify
nubmer||number
diff --git a/tools/accounting/Makefile b/tools/accounting/Makefile
index 11def1ad046c..20bbd461515e 100644
--- a/tools/accounting/Makefile
+++ b/tools/accounting/Makefile
@@ -2,7 +2,7 @@
CC := $(CROSS_COMPILE)gcc
CFLAGS := -I../../usr/include
-PROGS := getdelays procacct
+PROGS := getdelays procacct delaytop
all: $(PROGS)
diff --git a/tools/accounting/delaytop.c b/tools/accounting/delaytop.c
new file mode 100644
index 000000000000..9afb1ffc00ba
--- /dev/null
+++ b/tools/accounting/delaytop.c
@@ -0,0 +1,862 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * delaytop.c - system-wide delay monitoring tool.
+ *
+ * This tool provides real-time monitoring and statistics of
+ * system, container, and task-level delays, including CPU,
+ * memory, IO, and IRQ. It supports both interactive (top-like),
+ * and can output delay information for the whole system, specific
+ * containers (cgroups), or individual tasks (PIDs).
+ *
+ * Key features:
+ * - Collects per-task delay accounting statistics via taskstats.
+ * - Collects system-wide PSI information.
+ * - Supports sorting, filtering.
+ * - Supports both interactive (screen refresh).
+ *
+ * Copyright (C) Fan Yu, ZTE Corp. 2025
+ * Copyright (C) Wang Yaxin, ZTE Corp. 2025
+ *
+ * Compile with
+ * gcc -I/usr/src/linux/include delaytop.c -o delaytop
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <signal.h>
+#include <time.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <termios.h>
+#include <limits.h>
+#include <linux/genetlink.h>
+#include <linux/taskstats.h>
+#include <linux/cgroupstats.h>
+
+#define PSI_CPU_SOME "/proc/pressure/cpu"
+#define PSI_CPU_FULL "/proc/pressure/cpu"
+#define PSI_MEMORY_SOME "/proc/pressure/memory"
+#define PSI_MEMORY_FULL "/proc/pressure/memory"
+#define PSI_IO_SOME "/proc/pressure/io"
+#define PSI_IO_FULL "/proc/pressure/io"
+#define PSI_IRQ_FULL "/proc/pressure/irq"
+
+#define NLA_NEXT(na) ((struct nlattr *)((char *)(na) + NLA_ALIGN((na)->nla_len)))
+#define NLA_DATA(na) ((void *)((char *)(na) + NLA_HDRLEN))
+#define NLA_PAYLOAD(len) (len - NLA_HDRLEN)
+
+#define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
+#define GENLMSG_PAYLOAD(glh) (NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN)
+
+#define TASK_COMM_LEN 16
+#define MAX_MSG_SIZE 1024
+#define MAX_TASKS 1000
+#define SET_TASK_STAT(task_count, field) tasks[task_count].field = stats.field
+#define BOOL_FPRINT(stream, fmt, ...) \
+({ \
+ int ret = fprintf(stream, fmt, ##__VA_ARGS__); \
+ ret >= 0; \
+})
+#define PSI_LINE_FORMAT "%-12s %6.1f%%/%6.1f%%/%6.1f%%/%8llu(ms)\n"
+
+/* Program settings structure */
+struct config {
+ int delay; /* Update interval in seconds */
+ int iterations; /* Number of iterations, 0 == infinite */
+ int max_processes; /* Maximum number of processes to show */
+ char sort_field; /* Field to sort by */
+ int output_one_time; /* Output once and exit */
+ int monitor_pid; /* Monitor specific PID */
+ char *container_path; /* Path to container cgroup */
+};
+
+/* PSI statistics structure */
+struct psi_stats {
+ double cpu_some_avg10, cpu_some_avg60, cpu_some_avg300;
+ unsigned long long cpu_some_total;
+ double cpu_full_avg10, cpu_full_avg60, cpu_full_avg300;
+ unsigned long long cpu_full_total;
+ double memory_some_avg10, memory_some_avg60, memory_some_avg300;
+ unsigned long long memory_some_total;
+ double memory_full_avg10, memory_full_avg60, memory_full_avg300;
+ unsigned long long memory_full_total;
+ double io_some_avg10, io_some_avg60, io_some_avg300;
+ unsigned long long io_some_total;
+ double io_full_avg10, io_full_avg60, io_full_avg300;
+ unsigned long long io_full_total;
+ double irq_full_avg10, irq_full_avg60, irq_full_avg300;
+ unsigned long long irq_full_total;
+};
+
+/* Task delay information structure */
+struct task_info {
+ int pid;
+ int tgid;
+ char command[TASK_COMM_LEN];
+ unsigned long long cpu_count;
+ unsigned long long cpu_delay_total;
+ unsigned long long blkio_count;
+ unsigned long long blkio_delay_total;
+ unsigned long long swapin_count;
+ unsigned long long swapin_delay_total;
+ unsigned long long freepages_count;
+ unsigned long long freepages_delay_total;
+ unsigned long long thrashing_count;
+ unsigned long long thrashing_delay_total;
+ unsigned long long compact_count;
+ unsigned long long compact_delay_total;
+ unsigned long long wpcopy_count;
+ unsigned long long wpcopy_delay_total;
+ unsigned long long irq_count;
+ unsigned long long irq_delay_total;
+};
+
+/* Container statistics structure */
+struct container_stats {
+ int nr_sleeping; /* Number of sleeping processes */
+ int nr_running; /* Number of running processes */
+ int nr_stopped; /* Number of stopped processes */
+ int nr_uninterruptible; /* Number of uninterruptible processes */
+ int nr_io_wait; /* Number of processes in IO wait */
+};
+
+/* Global variables */
+static struct config cfg;
+static struct psi_stats psi;
+static struct task_info tasks[MAX_TASKS];
+static int task_count;
+static int running = 1;
+static struct container_stats container_stats;
+
+/* Netlink socket variables */
+static int nl_sd = -1;
+static int family_id;
+
+/* Set terminal to non-canonical mode for q-to-quit */
+static struct termios orig_termios;
+static void enable_raw_mode(void)
+{
+ struct termios raw;
+
+ tcgetattr(STDIN_FILENO, &orig_termios);
+ raw = orig_termios;
+ raw.c_lflag &= ~(ICANON | ECHO);
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
+}
+static void disable_raw_mode(void)
+{
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios);
+}
+
+/* Display usage information and command line options */
+static void usage(void)
+{
+ printf("Usage: delaytop [Options]\n"
+ "Options:\n"
+ " -h, --help Show this help message and exit\n"
+ " -d, --delay=SECONDS Set refresh interval (default: 2 seconds, min: 1)\n"
+ " -n, --iterations=COUNT Set number of updates (default: 0 = infinite)\n"
+ " -P, --processes=NUMBER Set maximum number of processes to show (default: 20, max: 1000)\n"
+ " -o, --once Display once and exit\n"
+ " -p, --pid=PID Monitor only the specified PID\n"
+ " -C, --container=PATH Monitor the container at specified cgroup path\n");
+ exit(0);
+}
+
+/* Parse command line arguments and set configuration */
+static void parse_args(int argc, char **argv)
+{
+ int c;
+ struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"delay", required_argument, 0, 'd'},
+ {"iterations", required_argument, 0, 'n'},
+ {"pid", required_argument, 0, 'p'},
+ {"once", no_argument, 0, 'o'},
+ {"processes", required_argument, 0, 'P'},
+ {"container", required_argument, 0, 'C'},
+ {0, 0, 0, 0}
+ };
+
+ /* Set defaults */
+ cfg.delay = 2;
+ cfg.iterations = 0;
+ cfg.max_processes = 20;
+ cfg.sort_field = 'c'; /* Default sort by CPU delay */
+ cfg.output_one_time = 0;
+ cfg.monitor_pid = 0; /* 0 means monitor all PIDs */
+ cfg.container_path = NULL;
+
+ while (1) {
+ int option_index = 0;
+
+ c = getopt_long(argc, argv, "hd:n:p:oP:C:", long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'h':
+ usage();
+ break;
+ case 'd':
+ cfg.delay = atoi(optarg);
+ if (cfg.delay < 1) {
+ fprintf(stderr, "Error: delay must be >= 1.\n");
+ exit(1);
+ }
+ break;
+ case 'n':
+ cfg.iterations = atoi(optarg);
+ if (cfg.iterations < 0) {
+ fprintf(stderr, "Error: iterations must be >= 0.\n");
+ exit(1);
+ }
+ break;
+ case 'p':
+ cfg.monitor_pid = atoi(optarg);
+ if (cfg.monitor_pid < 1) {
+ fprintf(stderr, "Error: pid must be >= 1.\n");
+ exit(1);
+ }
+ break;
+ case 'o':
+ cfg.output_one_time = 1;
+ break;
+ case 'P':
+ cfg.max_processes = atoi(optarg);
+ if (cfg.max_processes < 1) {
+ fprintf(stderr, "Error: processes must be >= 1.\n");
+ exit(1);
+ }
+ if (cfg.max_processes > MAX_TASKS) {
+ fprintf(stderr, "Warning: processes capped to %d.\n",
+ MAX_TASKS);
+ cfg.max_processes = MAX_TASKS;
+ }
+ break;
+ case 'C':
+ cfg.container_path = strdup(optarg);
+ break;
+ default:
+ fprintf(stderr, "Try 'delaytop --help' for more information.\n");
+ exit(1);
+ }
+ }
+}
+
+/* Create a raw netlink socket and bind */
+static int create_nl_socket(void)
+{
+ int fd;
+ struct sockaddr_nl local;
+
+ fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (fd < 0)
+ return -1;
+
+ memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+
+ if (bind(fd, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ fprintf(stderr, "Failed to bind socket when create nl_socket\n");
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+/* Send a command via netlink */
+static int send_cmd(int sd, __u16 nlmsg_type, __u32 nlmsg_pid,
+ __u8 genl_cmd, __u16 nla_type,
+ void *nla_data, int nla_len)
+{
+ struct sockaddr_nl nladdr;
+ struct nlattr *na;
+ int r, buflen;
+ char *buf;
+
+ struct {
+ struct nlmsghdr n;
+ struct genlmsghdr g;
+ char buf[MAX_MSG_SIZE];
+ } msg;
+
+ msg.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+ msg.n.nlmsg_type = nlmsg_type;
+ msg.n.nlmsg_flags = NLM_F_REQUEST;
+ msg.n.nlmsg_seq = 0;
+ msg.n.nlmsg_pid = nlmsg_pid;
+ msg.g.cmd = genl_cmd;
+ msg.g.version = 0x1;
+ na = (struct nlattr *) GENLMSG_DATA(&msg);
+ na->nla_type = nla_type;
+ na->nla_len = nla_len + NLA_HDRLEN;
+ memcpy(NLA_DATA(na), nla_data, nla_len);
+ msg.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
+
+ buf = (char *) &msg;
+ buflen = msg.n.nlmsg_len;
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+ while ((r = sendto(sd, buf, buflen, 0, (struct sockaddr *) &nladdr,
+ sizeof(nladdr))) < buflen) {
+ if (r > 0) {
+ buf += r;
+ buflen -= r;
+ } else if (errno != EAGAIN)
+ return -1;
+ }
+ return 0;
+}
+
+/* Get family ID for taskstats via netlink */
+static int get_family_id(int sd)
+{
+ struct {
+ struct nlmsghdr n;
+ struct genlmsghdr g;
+ char buf[256];
+ } ans;
+
+ int id = 0, rc;
+ struct nlattr *na;
+ int rep_len;
+ char name[100];
+
+ strncpy(name, TASKSTATS_GENL_NAME, sizeof(name) - 1);
+ name[sizeof(name) - 1] = '\0';
+ rc = send_cmd(sd, GENL_ID_CTRL, getpid(), CTRL_CMD_GETFAMILY,
+ CTRL_ATTR_FAMILY_NAME, (void *)name,
+ strlen(TASKSTATS_GENL_NAME)+1);
+ if (rc < 0) {
+ fprintf(stderr, "Failed to send cmd for family id\n");
+ return 0;
+ }
+
+ rep_len = recv(sd, &ans, sizeof(ans), 0);
+ if (ans.n.nlmsg_type == NLMSG_ERROR ||
+ (rep_len < 0) || !NLMSG_OK((&ans.n), rep_len)) {
+ fprintf(stderr, "Failed to receive response for family id\n");
+ return 0;
+ }
+
+ na = (struct nlattr *) GENLMSG_DATA(&ans);
+ na = (struct nlattr *) ((char *) na + NLA_ALIGN(na->nla_len));
+ if (na->nla_type == CTRL_ATTR_FAMILY_ID)
+ id = *(__u16 *) NLA_DATA(na);
+ return id;
+}
+
+static void read_psi_stats(void)
+{
+ FILE *fp;
+ char line[256];
+ int ret = 0;
+ /* Zero all fields */
+ memset(&psi, 0, sizeof(psi));
+ /* CPU pressure */
+ fp = fopen(PSI_CPU_SOME, "r");
+ if (fp) {
+ while (fgets(line, sizeof(line), fp)) {
+ if (strncmp(line, "some", 4) == 0) {
+ ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
+ &psi.cpu_some_avg10, &psi.cpu_some_avg60,
+ &psi.cpu_some_avg300, &psi.cpu_some_total);
+ if (ret != 4)
+ fprintf(stderr, "Failed to parse CPU some PSI data\n");
+ } else if (strncmp(line, "full", 4) == 0) {
+ ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
+ &psi.cpu_full_avg10, &psi.cpu_full_avg60,
+ &psi.cpu_full_avg300, &psi.cpu_full_total);
+ if (ret != 4)
+ fprintf(stderr, "Failed to parse CPU full PSI data\n");
+ }
+ }
+ fclose(fp);
+ }
+ /* Memory pressure */
+ fp = fopen(PSI_MEMORY_SOME, "r");
+ if (fp) {
+ while (fgets(line, sizeof(line), fp)) {
+ if (strncmp(line, "some", 4) == 0) {
+ ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
+ &psi.memory_some_avg10, &psi.memory_some_avg60,
+ &psi.memory_some_avg300, &psi.memory_some_total);
+ if (ret != 4)
+ fprintf(stderr, "Failed to parse Memory some PSI data\n");
+ } else if (strncmp(line, "full", 4) == 0) {
+ ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
+ &psi.memory_full_avg10, &psi.memory_full_avg60,
+ &psi.memory_full_avg300, &psi.memory_full_total);
+ }
+ if (ret != 4)
+ fprintf(stderr, "Failed to parse Memory full PSI data\n");
+ }
+ fclose(fp);
+ }
+ /* IO pressure */
+ fp = fopen(PSI_IO_SOME, "r");
+ if (fp) {
+ while (fgets(line, sizeof(line), fp)) {
+ if (strncmp(line, "some", 4) == 0) {
+ ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
+ &psi.io_some_avg10, &psi.io_some_avg60,
+ &psi.io_some_avg300, &psi.io_some_total);
+ if (ret != 4)
+ fprintf(stderr, "Failed to parse IO some PSI data\n");
+ } else if (strncmp(line, "full", 4) == 0) {
+ ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
+ &psi.io_full_avg10, &psi.io_full_avg60,
+ &psi.io_full_avg300, &psi.io_full_total);
+ if (ret != 4)
+ fprintf(stderr, "Failed to parse IO full PSI data\n");
+ }
+ }
+ fclose(fp);
+ }
+ /* IRQ pressure (only full) */
+ fp = fopen(PSI_IRQ_FULL, "r");
+ if (fp) {
+ while (fgets(line, sizeof(line), fp)) {
+ if (strncmp(line, "full", 4) == 0) {
+ ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
+ &psi.irq_full_avg10, &psi.irq_full_avg60,
+ &psi.irq_full_avg300, &psi.irq_full_total);
+ if (ret != 4)
+ fprintf(stderr, "Failed to parse IRQ full PSI data\n");
+ }
+ }
+ fclose(fp);
+ }
+}
+
+static int read_comm(int pid, char *comm_buf, size_t buf_size)
+{
+ char path[64];
+ int ret = -1;
+ size_t len;
+ FILE *fp;
+
+ snprintf(path, sizeof(path), "/proc/%d/comm", pid);
+ fp = fopen(path, "r");
+ if (!fp) {
+ fprintf(stderr, "Failed to open comm file /proc/%d/comm\n", pid);
+ return ret;
+ }
+
+ if (fgets(comm_buf, buf_size, fp)) {
+ len = strlen(comm_buf);
+ if (len > 0 && comm_buf[len - 1] == '\n')
+ comm_buf[len - 1] = '\0';
+ ret = 0;
+ }
+
+ fclose(fp);
+
+ return ret;
+}
+
+static void fetch_and_fill_task_info(int pid, const char *comm)
+{
+ struct {
+ struct nlmsghdr n;
+ struct genlmsghdr g;
+ char buf[MAX_MSG_SIZE];
+ } resp;
+ struct taskstats stats;
+ struct nlattr *nested;
+ struct nlattr *na;
+ int nested_len;
+ int nl_len;
+ int rc;
+
+ /* Send request for task stats */
+ if (send_cmd(nl_sd, family_id, getpid(), TASKSTATS_CMD_GET,
+ TASKSTATS_CMD_ATTR_PID, &pid, sizeof(pid)) < 0) {
+ fprintf(stderr, "Failed to send request for task stats\n");
+ return;
+ }
+
+ /* Receive response */
+ rc = recv(nl_sd, &resp, sizeof(resp), 0);
+ if (rc < 0 || resp.n.nlmsg_type == NLMSG_ERROR) {
+ fprintf(stderr, "Failed to receive response for task stats\n");
+ return;
+ }
+
+ /* Parse response */
+ nl_len = GENLMSG_PAYLOAD(&resp.n);
+ na = (struct nlattr *) GENLMSG_DATA(&resp);
+ while (nl_len > 0) {
+ if (na->nla_type == TASKSTATS_TYPE_AGGR_PID) {
+ nested = (struct nlattr *) NLA_DATA(na);
+ nested_len = NLA_PAYLOAD(na->nla_len);
+ while (nested_len > 0) {
+ if (nested->nla_type == TASKSTATS_TYPE_STATS) {
+ memcpy(&stats, NLA_DATA(nested), sizeof(stats));
+ if (task_count < MAX_TASKS) {
+ tasks[task_count].pid = pid;
+ tasks[task_count].tgid = pid;
+ strncpy(tasks[task_count].command, comm,
+ TASK_COMM_LEN - 1);
+ tasks[task_count].command[TASK_COMM_LEN - 1] = '\0';
+ SET_TASK_STAT(task_count, cpu_count);
+ SET_TASK_STAT(task_count, cpu_delay_total);
+ SET_TASK_STAT(task_count, blkio_count);
+ SET_TASK_STAT(task_count, blkio_delay_total);
+ SET_TASK_STAT(task_count, swapin_count);
+ SET_TASK_STAT(task_count, swapin_delay_total);
+ SET_TASK_STAT(task_count, freepages_count);
+ SET_TASK_STAT(task_count, freepages_delay_total);
+ SET_TASK_STAT(task_count, thrashing_count);
+ SET_TASK_STAT(task_count, thrashing_delay_total);
+ SET_TASK_STAT(task_count, compact_count);
+ SET_TASK_STAT(task_count, compact_delay_total);
+ SET_TASK_STAT(task_count, wpcopy_count);
+ SET_TASK_STAT(task_count, wpcopy_delay_total);
+ SET_TASK_STAT(task_count, irq_count);
+ SET_TASK_STAT(task_count, irq_delay_total);
+ task_count++;
+ }
+ break;
+ }
+ nested_len -= NLA_ALIGN(nested->nla_len);
+ nested = NLA_NEXT(nested);
+ }
+ }
+ nl_len -= NLA_ALIGN(na->nla_len);
+ na = NLA_NEXT(na);
+ }
+ return;
+}
+
+static void get_task_delays(void)
+{
+ char comm[TASK_COMM_LEN];
+ struct dirent *entry;
+ DIR *dir;
+ int pid;
+
+ task_count = 0;
+ if (cfg.monitor_pid > 0) {
+ if (read_comm(cfg.monitor_pid, comm, sizeof(comm)) == 0)
+ fetch_and_fill_task_info(cfg.monitor_pid, comm);
+ return;
+ }
+
+ dir = opendir("/proc");
+ if (!dir) {
+ fprintf(stderr, "Error opening /proc directory\n");
+ return;
+ }
+
+ while ((entry = readdir(dir)) != NULL && task_count < MAX_TASKS) {
+ if (!isdigit(entry->d_name[0]))
+ continue;
+ pid = atoi(entry->d_name);
+ if (pid == 0)
+ continue;
+ if (read_comm(pid, comm, sizeof(comm)) != 0)
+ continue;
+ fetch_and_fill_task_info(pid, comm);
+ }
+ closedir(dir);
+}
+
+/* Calculate average delay in milliseconds */
+static double average_ms(unsigned long long total, unsigned long long count)
+{
+ if (count == 0)
+ return 0;
+ return (double)total / 1000000.0 / count;
+}
+
+/* Comparison function for sorting tasks */
+static int compare_tasks(const void *a, const void *b)
+{
+ const struct task_info *t1 = (const struct task_info *)a;
+ const struct task_info *t2 = (const struct task_info *)b;
+ double avg1, avg2;
+
+ switch (cfg.sort_field) {
+ case 'c': /* CPU */
+ avg1 = average_ms(t1->cpu_delay_total, t1->cpu_count);
+ avg2 = average_ms(t2->cpu_delay_total, t2->cpu_count);
+ if (avg1 != avg2)
+ return avg2 > avg1 ? 1 : -1;
+ return t2->cpu_delay_total > t1->cpu_delay_total ? 1 : -1;
+
+ default:
+ return t2->cpu_delay_total > t1->cpu_delay_total ? 1 : -1;
+ }
+}
+
+/* Sort tasks by selected field */
+static void sort_tasks(void)
+{
+ if (task_count > 0)
+ qsort(tasks, task_count, sizeof(struct task_info), compare_tasks);
+}
+
+/* Get container statistics via cgroupstats */
+static void get_container_stats(void)
+{
+ int rc, cfd;
+ struct {
+ struct nlmsghdr n;
+ struct genlmsghdr g;
+ char buf[MAX_MSG_SIZE];
+ } req, resp;
+ struct nlattr *na;
+ int nl_len;
+ struct cgroupstats stats;
+
+ /* Check if container path is set */
+ if (!cfg.container_path)
+ return;
+
+ /* Open container cgroup */
+ cfd = open(cfg.container_path, O_RDONLY);
+ if (cfd < 0) {
+ fprintf(stderr, "Error opening container path: %s\n", cfg.container_path);
+ return;
+ }
+
+ /* Send request for container stats */
+ if (send_cmd(nl_sd, family_id, getpid(), CGROUPSTATS_CMD_GET,
+ CGROUPSTATS_CMD_ATTR_FD, &cfd, sizeof(__u32)) < 0) {
+ fprintf(stderr, "Failed to send request for container stats\n");
+ close(cfd);
+ return;
+ }
+
+ /* Receive response */
+ rc = recv(nl_sd, &resp, sizeof(resp), 0);
+ if (rc < 0 || resp.n.nlmsg_type == NLMSG_ERROR) {
+ fprintf(stderr, "Failed to receive response for container stats\n");
+ close(cfd);
+ return;
+ }
+
+ /* Parse response */
+ nl_len = GENLMSG_PAYLOAD(&resp.n);
+ na = (struct nlattr *) GENLMSG_DATA(&resp);
+ while (nl_len > 0) {
+ if (na->nla_type == CGROUPSTATS_TYPE_CGROUP_STATS) {
+ /* Get the cgroupstats structure */
+ memcpy(&stats, NLA_DATA(na), sizeof(stats));
+
+ /* Fill container stats */
+ container_stats.nr_sleeping = stats.nr_sleeping;
+ container_stats.nr_running = stats.nr_running;
+ container_stats.nr_stopped = stats.nr_stopped;
+ container_stats.nr_uninterruptible = stats.nr_uninterruptible;
+ container_stats.nr_io_wait = stats.nr_io_wait;
+ break;
+ }
+ nl_len -= NLA_ALIGN(na->nla_len);
+ na = (struct nlattr *) ((char *) na + NLA_ALIGN(na->nla_len));
+ }
+
+ close(cfd);
+}
+
+/* Display results to stdout or log file */
+static void display_results(void)
+{
+ time_t now = time(NULL);
+ struct tm *tm_now = localtime(&now);
+ FILE *out = stdout;
+ char timestamp[32];
+ bool suc = true;
+ int i, count;
+
+ /* Clear terminal screen */
+ suc &= BOOL_FPRINT(out, "\033[H\033[J");
+
+ /* PSI output (one-line, no cat style) */
+ suc &= BOOL_FPRINT(out, "System Pressure Information: (avg10/avg60/avg300/total)\n");
+ suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
+ "CPU some:",
+ psi.cpu_some_avg10,
+ psi.cpu_some_avg60,
+ psi.cpu_some_avg300,
+ psi.cpu_some_total / 1000);
+ suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
+ "CPU full:",
+ psi.cpu_full_avg10,
+ psi.cpu_full_avg60,
+ psi.cpu_full_avg300,
+ psi.cpu_full_total / 1000);
+ suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
+ "Memory full:",
+ psi.memory_full_avg10,
+ psi.memory_full_avg60,
+ psi.memory_full_avg300,
+ psi.memory_full_total / 1000);
+ suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
+ "Memory some:",
+ psi.memory_some_avg10,
+ psi.memory_some_avg60,
+ psi.memory_some_avg300,
+ psi.memory_some_total / 1000);
+ suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
+ "IO full:",
+ psi.io_full_avg10,
+ psi.io_full_avg60,
+ psi.io_full_avg300,
+ psi.io_full_total / 1000);
+ suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
+ "IO some:",
+ psi.io_some_avg10,
+ psi.io_some_avg60,
+ psi.io_some_avg300,
+ psi.io_some_total / 1000);
+ suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
+ "IRQ full:",
+ psi.irq_full_avg10,
+ psi.irq_full_avg60,
+ psi.irq_full_avg300,
+ psi.irq_full_total / 1000);
+
+ if (cfg.container_path) {
+ suc &= BOOL_FPRINT(out, "Container Information (%s):\n", cfg.container_path);
+ suc &= BOOL_FPRINT(out, "Processes: running=%d, sleeping=%d, ",
+ container_stats.nr_running, container_stats.nr_sleeping);
+ suc &= BOOL_FPRINT(out, "stopped=%d, uninterruptible=%d, io_wait=%d\n\n",
+ container_stats.nr_stopped, container_stats.nr_uninterruptible,
+ container_stats.nr_io_wait);
+ }
+ suc &= BOOL_FPRINT(out, "Top %d processes (sorted by CPU delay):\n",
+ cfg.max_processes);
+ suc &= BOOL_FPRINT(out, "%5s %5s %-17s", "PID", "TGID", "COMMAND");
+ suc &= BOOL_FPRINT(out, "%7s %7s %7s %7s %7s %7s %7s %7s\n",
+ "CPU(ms)", "IO(ms)", "SWAP(ms)", "RCL(ms)",
+ "THR(ms)", "CMP(ms)", "WP(ms)", "IRQ(ms)");
+
+ suc &= BOOL_FPRINT(out, "-----------------------------------------------");
+ suc &= BOOL_FPRINT(out, "----------------------------------------------\n");
+ count = task_count < cfg.max_processes ? task_count : cfg.max_processes;
+
+ for (i = 0; i < count; i++) {
+ suc &= BOOL_FPRINT(out, "%5d %5d %-15s",
+ tasks[i].pid, tasks[i].tgid, tasks[i].command);
+ suc &= BOOL_FPRINT(out, "%7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",
+ average_ms(tasks[i].cpu_delay_total, tasks[i].cpu_count),
+ average_ms(tasks[i].blkio_delay_total, tasks[i].blkio_count),
+ average_ms(tasks[i].swapin_delay_total, tasks[i].swapin_count),
+ average_ms(tasks[i].freepages_delay_total, tasks[i].freepages_count),
+ average_ms(tasks[i].thrashing_delay_total, tasks[i].thrashing_count),
+ average_ms(tasks[i].compact_delay_total, tasks[i].compact_count),
+ average_ms(tasks[i].wpcopy_delay_total, tasks[i].wpcopy_count),
+ average_ms(tasks[i].irq_delay_total, tasks[i].irq_count));
+ }
+
+ suc &= BOOL_FPRINT(out, "\n");
+
+ if (!suc)
+ perror("Error writing to output");
+}
+
+/* Main function */
+int main(int argc, char **argv)
+{
+ int iterations = 0;
+ int use_q_quit = 0;
+
+ /* Parse command line arguments */
+ parse_args(argc, argv);
+
+ /* Setup netlink socket */
+ nl_sd = create_nl_socket();
+ if (nl_sd < 0) {
+ fprintf(stderr, "Error creating netlink socket\n");
+ exit(1);
+ }
+
+ /* Get family ID for taskstats via netlink */
+ family_id = get_family_id(nl_sd);
+ if (!family_id) {
+ fprintf(stderr, "Error getting taskstats family ID\n");
+ close(nl_sd);
+ exit(1);
+ }
+
+ if (!cfg.output_one_time) {
+ use_q_quit = 1;
+ enable_raw_mode();
+ printf("Press 'q' to quit.\n");
+ fflush(stdout);
+ }
+
+ /* Main loop */
+ while (running) {
+ /* Read PSI statistics */
+ read_psi_stats();
+
+ /* Get container stats if container path provided */
+ if (cfg.container_path)
+ get_container_stats();
+
+ /* Get task delays */
+ get_task_delays();
+
+ /* Sort tasks */
+ sort_tasks();
+
+ /* Display results to stdout or log file */
+ display_results();
+
+ /* Check for iterations */
+ if (cfg.iterations > 0 && ++iterations >= cfg.iterations)
+ break;
+
+ /* Exit if output_one_time is set */
+ if (cfg.output_one_time)
+ break;
+
+ /* Check for 'q' key to quit */
+ if (use_q_quit) {
+ struct timeval tv = {cfg.delay, 0};
+ fd_set readfds;
+
+ FD_ZERO(&readfds);
+ FD_SET(STDIN_FILENO, &readfds);
+ int r = select(STDIN_FILENO+1, &readfds, NULL, NULL, &tv);
+
+ if (r > 0 && FD_ISSET(STDIN_FILENO, &readfds)) {
+ char ch = 0;
+
+ read(STDIN_FILENO, &ch, 1);
+ if (ch == 'q' || ch == 'Q') {
+ running = 0;
+ break;
+ }
+ }
+ } else {
+ sleep(cfg.delay);
+ }
+ }
+
+ /* Restore terminal mode */
+ if (use_q_quit)
+ disable_raw_mode();
+
+ /* Cleanup */
+ close(nl_sd);
+ if (cfg.container_path)
+ free(cfg.container_path);
+
+ return 0;
+}
diff --git a/tools/accounting/getdelays.c b/tools/accounting/getdelays.c
index 3feac0482fe9..21cb3c3d1331 100644
--- a/tools/accounting/getdelays.c
+++ b/tools/accounting/getdelays.c
@@ -194,75 +194,108 @@ static int get_family_id(int sd)
#define average_ms(t, c) (t / 1000000ULL / (c ? c : 1))
#define delay_ms(t) (t / 1000000ULL)
+/*
+ * Version compatibility note:
+ * Field availability depends on taskstats version (t->version),
+ * corresponding to TASKSTATS_VERSION in kernel headers
+ * see include/uapi/linux/taskstats.h
+ *
+ * Version feature mapping:
+ * version >= 11 - supports COMPACT statistics
+ * version >= 13 - supports WPCOPY statistics
+ * version >= 14 - supports IRQ statistics
+ * version >= 16 - supports *_max and *_min delay statistics
+ *
+ * Always verify version before accessing version-dependent fields
+ * to maintain backward compatibility.
+ */
+#define PRINT_CPU_DELAY(version, t) \
+ do { \
+ if (version >= 16) { \
+ printf("%-10s%15s%15s%15s%15s%15s%15s%15s\n", \
+ "CPU", "count", "real total", "virtual total", \
+ "delay total", "delay average", "delay max", "delay min"); \
+ printf(" %15llu%15llu%15llu%15llu%15.3fms%13.6fms%13.6fms\n", \
+ (unsigned long long)(t)->cpu_count, \
+ (unsigned long long)(t)->cpu_run_real_total, \
+ (unsigned long long)(t)->cpu_run_virtual_total, \
+ (unsigned long long)(t)->cpu_delay_total, \
+ average_ms((double)(t)->cpu_delay_total, (t)->cpu_count), \
+ delay_ms((double)(t)->cpu_delay_max), \
+ delay_ms((double)(t)->cpu_delay_min)); \
+ } else { \
+ printf("%-10s%15s%15s%15s%15s%15s\n", \
+ "CPU", "count", "real total", "virtual total", \
+ "delay total", "delay average"); \
+ printf(" %15llu%15llu%15llu%15llu%15.3fms\n", \
+ (unsigned long long)(t)->cpu_count, \
+ (unsigned long long)(t)->cpu_run_real_total, \
+ (unsigned long long)(t)->cpu_run_virtual_total, \
+ (unsigned long long)(t)->cpu_delay_total, \
+ average_ms((double)(t)->cpu_delay_total, (t)->cpu_count)); \
+ } \
+ } while (0)
+#define PRINT_FILED_DELAY(name, version, t, count, total, max, min) \
+ do { \
+ if (version >= 16) { \
+ printf("%-10s%15s%15s%15s%15s%15s\n", \
+ name, "count", "delay total", "delay average", \
+ "delay max", "delay min"); \
+ printf(" %15llu%15llu%15.3fms%13.6fms%13.6fms\n", \
+ (unsigned long long)(t)->count, \
+ (unsigned long long)(t)->total, \
+ average_ms((double)(t)->total, (t)->count), \
+ delay_ms((double)(t)->max), \
+ delay_ms((double)(t)->min)); \
+ } else { \
+ printf("%-10s%15s%15s%15s\n", \
+ name, "count", "delay total", "delay average"); \
+ printf(" %15llu%15llu%15.3fms\n", \
+ (unsigned long long)(t)->count, \
+ (unsigned long long)(t)->total, \
+ average_ms((double)(t)->total, (t)->count)); \
+ } \
+ } while (0)
+
static void print_delayacct(struct taskstats *t)
{
- printf("\n\nCPU %15s%15s%15s%15s%15s%15s%15s\n"
- " %15llu%15llu%15llu%15llu%15.3fms%13.6fms%13.6fms\n"
- "IO %15s%15s%15s%15s%15s\n"
- " %15llu%15llu%15.3fms%13.6fms%13.6fms\n"
- "SWAP %15s%15s%15s%15s%15s\n"
- " %15llu%15llu%15.3fms%13.6fms%13.6fms\n"
- "RECLAIM %12s%15s%15s%15s%15s\n"
- " %15llu%15llu%15.3fms%13.6fms%13.6fms\n"
- "THRASHING%12s%15s%15s%15s%15s\n"
- " %15llu%15llu%15.3fms%13.6fms%13.6fms\n"
- "COMPACT %12s%15s%15s%15s%15s\n"
- " %15llu%15llu%15.3fms%13.6fms%13.6fms\n"
- "WPCOPY %12s%15s%15s%15s%15s\n"
- " %15llu%15llu%15.3fms%13.6fms%13.6fms\n"
- "IRQ %15s%15s%15s%15s%15s\n"
- " %15llu%15llu%15.3fms%13.6fms%13.6fms\n",
- "count", "real total", "virtual total",
- "delay total", "delay average", "delay max", "delay min",
- (unsigned long long)t->cpu_count,
- (unsigned long long)t->cpu_run_real_total,
- (unsigned long long)t->cpu_run_virtual_total,
- (unsigned long long)t->cpu_delay_total,
- average_ms((double)t->cpu_delay_total, t->cpu_count),
- delay_ms((double)t->cpu_delay_max),
- delay_ms((double)t->cpu_delay_min),
- "count", "delay total", "delay average", "delay max", "delay min",
- (unsigned long long)t->blkio_count,
- (unsigned long long)t->blkio_delay_total,
- average_ms((double)t->blkio_delay_total, t->blkio_count),
- delay_ms((double)t->blkio_delay_max),
- delay_ms((double)t->blkio_delay_min),
- "count", "delay total", "delay average", "delay max", "delay min",
- (unsigned long long)t->swapin_count,
- (unsigned long long)t->swapin_delay_total,
- average_ms((double)t->swapin_delay_total, t->swapin_count),
- delay_ms((double)t->swapin_delay_max),
- delay_ms((double)t->swapin_delay_min),
- "count", "delay total", "delay average", "delay max", "delay min",
- (unsigned long long)t->freepages_count,
- (unsigned long long)t->freepages_delay_total,
- average_ms((double)t->freepages_delay_total, t->freepages_count),
- delay_ms((double)t->freepages_delay_max),
- delay_ms((double)t->freepages_delay_min),
- "count", "delay total", "delay average", "delay max", "delay min",
- (unsigned long long)t->thrashing_count,
- (unsigned long long)t->thrashing_delay_total,
- average_ms((double)t->thrashing_delay_total, t->thrashing_count),
- delay_ms((double)t->thrashing_delay_max),
- delay_ms((double)t->thrashing_delay_min),
- "count", "delay total", "delay average", "delay max", "delay min",
- (unsigned long long)t->compact_count,
- (unsigned long long)t->compact_delay_total,
- average_ms((double)t->compact_delay_total, t->compact_count),
- delay_ms((double)t->compact_delay_max),
- delay_ms((double)t->compact_delay_min),
- "count", "delay total", "delay average", "delay max", "delay min",
- (unsigned long long)t->wpcopy_count,
- (unsigned long long)t->wpcopy_delay_total,
- average_ms((double)t->wpcopy_delay_total, t->wpcopy_count),
- delay_ms((double)t->wpcopy_delay_max),
- delay_ms((double)t->wpcopy_delay_min),
- "count", "delay total", "delay average", "delay max", "delay min",
- (unsigned long long)t->irq_count,
- (unsigned long long)t->irq_delay_total,
- average_ms((double)t->irq_delay_total, t->irq_count),
- delay_ms((double)t->irq_delay_max),
- delay_ms((double)t->irq_delay_min));
+ printf("\n\n");
+
+ PRINT_CPU_DELAY(t->version, t);
+
+ PRINT_FILED_DELAY("IO", t->version, t,
+ blkio_count, blkio_delay_total,
+ blkio_delay_max, blkio_delay_min);
+
+ PRINT_FILED_DELAY("SWAP", t->version, t,
+ swapin_count, swapin_delay_total,
+ swapin_delay_max, swapin_delay_min);
+
+ PRINT_FILED_DELAY("RECLAIM", t->version, t,
+ freepages_count, freepages_delay_total,
+ freepages_delay_max, freepages_delay_min);
+
+ PRINT_FILED_DELAY("THRASHING", t->version, t,
+ thrashing_count, thrashing_delay_total,
+ thrashing_delay_max, thrashing_delay_min);
+
+ if (t->version >= 11) {
+ PRINT_FILED_DELAY("COMPACT", t->version, t,
+ compact_count, compact_delay_total,
+ compact_delay_max, compact_delay_min);
+ }
+
+ if (t->version >= 13) {
+ PRINT_FILED_DELAY("WPCOPY", t->version, t,
+ wpcopy_count, wpcopy_delay_total,
+ wpcopy_delay_max, wpcopy_delay_min);
+ }
+
+ if (t->version >= 14) {
+ PRINT_FILED_DELAY("IRQ", t->version, t,
+ irq_count, irq_delay_total,
+ irq_delay_max, irq_delay_min);
+ }
}
static void task_context_switch_counts(struct taskstats *t)
diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h
index 530752ddde8e..c1cfd297aabf 100644
--- a/tools/testing/selftests/bpf/progs/bpf_misc.h
+++ b/tools/testing/selftests/bpf/progs/bpf_misc.h
@@ -229,7 +229,8 @@
#if __clang_major__ >= 18 && defined(ENABLE_ATOMICS_TESTS) && \
(defined(__TARGET_ARCH_arm64) || defined(__TARGET_ARCH_x86) || \
- (defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64))
+ (defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64)) || \
+ (defined(__TARGET_ARCH_powerpc))
#define CAN_USE_LOAD_ACQ_STORE_REL
#endif
diff --git a/tools/testing/selftests/kho/arm64.conf b/tools/testing/selftests/kho/arm64.conf
new file mode 100644
index 000000000000..ee696807cd35
--- /dev/null
+++ b/tools/testing/selftests/kho/arm64.conf
@@ -0,0 +1,9 @@
+QEMU_CMD="qemu-system-aarch64 -M virt -cpu max"
+QEMU_KCONFIG="
+CONFIG_SERIAL_AMBA_PL010=y
+CONFIG_SERIAL_AMBA_PL010_CONSOLE=y
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+"
+KERNEL_IMAGE="Image"
+KERNEL_CMDLINE="console=ttyAMA0"
diff --git a/tools/testing/selftests/kho/init.c b/tools/testing/selftests/kho/init.c
new file mode 100644
index 000000000000..8034e24c6bf6
--- /dev/null
+++ b/tools/testing/selftests/kho/init.c
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#ifndef NOLIBC
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <syscall.h>
+#include <sys/mount.h>
+#include <sys/reboot.h>
+#endif
+
+/* from arch/x86/include/asm/setup.h */
+#define COMMAND_LINE_SIZE 2048
+
+/* from include/linux/kexex.h */
+#define KEXEC_FILE_NO_INITRAMFS 0x00000004
+
+#define KHO_FINILIZE "/debugfs/kho/out/finalize"
+#define KERNEL_IMAGE "/kernel"
+
+static int mount_filesystems(void)
+{
+ if (mount("debugfs", "/debugfs", "debugfs", 0, NULL) < 0)
+ return -1;
+
+ return mount("proc", "/proc", "proc", 0, NULL);
+}
+
+static int kho_enable(void)
+{
+ const char enable[] = "1";
+ int fd;
+
+ fd = open(KHO_FINILIZE, O_RDWR);
+ if (fd < 0)
+ return -1;
+
+ if (write(fd, enable, sizeof(enable)) != sizeof(enable))
+ return 1;
+
+ close(fd);
+ return 0;
+}
+
+static long kexec_file_load(int kernel_fd, int initrd_fd,
+ unsigned long cmdline_len, const char *cmdline,
+ unsigned long flags)
+{
+ return syscall(__NR_kexec_file_load, kernel_fd, initrd_fd, cmdline_len,
+ cmdline, flags);
+}
+
+static int kexec_load(void)
+{
+ char cmdline[COMMAND_LINE_SIZE];
+ ssize_t len;
+ int fd, err;
+
+ fd = open("/proc/cmdline", O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ len = read(fd, cmdline, sizeof(cmdline));
+ close(fd);
+ if (len < 0)
+ return -1;
+
+ /* replace \n with \0 */
+ cmdline[len - 1] = 0;
+ fd = open(KERNEL_IMAGE, O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ err = kexec_file_load(fd, -1, len, cmdline, KEXEC_FILE_NO_INITRAMFS);
+ close(fd);
+
+ return err ? : 0;
+}
+
+int main(int argc, char *argv[])
+{
+ if (mount_filesystems())
+ goto err_reboot;
+
+ if (kho_enable())
+ goto err_reboot;
+
+ if (kexec_load())
+ goto err_reboot;
+
+ if (reboot(RB_KEXEC))
+ goto err_reboot;
+
+ return 0;
+
+err_reboot:
+ reboot(RB_AUTOBOOT);
+ return -1;
+}
diff --git a/tools/testing/selftests/kho/vmtest.sh b/tools/testing/selftests/kho/vmtest.sh
new file mode 100755
index 000000000000..ec70a17bd476
--- /dev/null
+++ b/tools/testing/selftests/kho/vmtest.sh
@@ -0,0 +1,183 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+set -ue
+
+CROSS_COMPILE="${CROSS_COMPILE:-""}"
+
+test_dir=$(realpath "$(dirname "$0")")
+kernel_dir=$(realpath "$test_dir/../../../..")
+
+tmp_dir=$(mktemp -d /tmp/kho-test.XXXXXXXX)
+headers_dir="$tmp_dir/usr"
+initrd_dir="$tmp_dir/initrd"
+initrd="$tmp_dir/initrd.cpio"
+
+source "$test_dir/../kselftest/ktap_helpers.sh"
+
+function usage() {
+ cat <<EOF
+$0 [-d build_dir] [-j jobs] [-t target_arch] [-h]
+Options:
+ -d) path to the kernel build directory
+ -j) number of jobs for compilation, similar to -j in make
+ -t) run test for target_arch, requires CROSS_COMPILE set
+ supported targets: aarch64, x86_64
+ -h) display this help
+EOF
+}
+
+function cleanup() {
+ rm -fr "$tmp_dir"
+ ktap_finished
+}
+trap cleanup EXIT
+
+function skip() {
+ local msg=${1:-""}
+
+ ktap_test_skip "$msg"
+ exit "$KSFT_SKIP"
+}
+
+function fail() {
+ local msg=${1:-""}
+
+ ktap_test_fail "$msg"
+ exit "$KSFT_FAIL"
+}
+
+function build_kernel() {
+ local build_dir=$1
+ local make_cmd=$2
+ local arch_kconfig=$3
+ local kimage=$4
+
+ local kho_config="$tmp_dir/kho.config"
+ local kconfig="$build_dir/.config"
+
+ # enable initrd, KHO and KHO test in kernel configuration
+ tee "$kconfig" > "$kho_config" <<EOF
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_KEXEC_HANDOVER=y
+CONFIG_TEST_KEXEC_HANDOVER=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_VM=y
+$arch_kconfig
+EOF
+
+ make_cmd="$make_cmd -C $kernel_dir O=$build_dir"
+ $make_cmd olddefconfig
+
+ # verify that kernel confiration has all necessary options
+ while read -r opt ; do
+ grep "$opt" "$kconfig" &>/dev/null || skip "$opt is missing"
+ done < "$kho_config"
+
+ $make_cmd "$kimage"
+ $make_cmd headers_install INSTALL_HDR_PATH="$headers_dir"
+}
+
+function mkinitrd() {
+ local kernel=$1
+
+ mkdir -p "$initrd_dir"/{dev,debugfs,proc}
+ sudo mknod "$initrd_dir/dev/console" c 5 1
+
+ "$CROSS_COMPILE"gcc -s -static -Os -nostdinc -I"$headers_dir/include" \
+ -fno-asynchronous-unwind-tables -fno-ident -nostdlib \
+ -include "$test_dir/../../../include/nolibc/nolibc.h" \
+ -o "$initrd_dir/init" "$test_dir/init.c" \
+
+ cp "$kernel" "$initrd_dir/kernel"
+
+ pushd "$initrd_dir" &>/dev/null
+ find . | cpio -H newc --create > "$initrd" 2>/dev/null
+ popd &>/dev/null
+}
+
+function run_qemu() {
+ local qemu_cmd=$1
+ local cmdline=$2
+ local kernel=$3
+ local serial="$tmp_dir/qemu.serial"
+
+ cmdline="$cmdline kho=on panic=-1"
+
+ $qemu_cmd -m 1G -smp 2 -no-reboot -nographic -nodefaults \
+ -accel kvm -accel hvf -accel tcg \
+ -serial file:"$serial" \
+ -append "$cmdline" \
+ -kernel "$kernel" \
+ -initrd "$initrd"
+
+ grep "KHO restore succeeded" "$serial" &> /dev/null || fail "KHO failed"
+}
+
+function target_to_arch() {
+ local target=$1
+
+ case $target in
+ aarch64) echo "arm64" ;;
+ x86_64) echo "x86" ;;
+ *) skip "architecture $target is not supported"
+ esac
+}
+
+function main() {
+ local build_dir="$kernel_dir/.kho"
+ local jobs=$(($(nproc) * 2))
+ local target="$(uname -m)"
+
+ # skip the test if any of the preparation steps fails
+ set -o errtrace
+ trap skip ERR
+
+ while getopts 'hd:j:t:' opt; do
+ case $opt in
+ d)
+ build_dir="$OPTARG"
+ ;;
+ j)
+ jobs="$OPTARG"
+ ;;
+ t)
+ target="$OPTARG"
+ ;;
+ h)
+ usage
+ exit 0
+ ;;
+ *)
+ echo Unknown argument "$opt"
+ usage
+ exit 1
+ ;;
+ esac
+ done
+
+ ktap_print_header
+ ktap_set_plan 1
+
+ if [[ "$target" != "$(uname -m)" ]] && [[ -z "$CROSS_COMPILE" ]]; then
+ skip "Cross-platform testing needs to specify CROSS_COMPILE"
+ fi
+
+ mkdir -p "$build_dir"
+ local arch=$(target_to_arch "$target")
+ source "$test_dir/$arch.conf"
+
+ # build the kernel and create initrd
+ # initrd includes the kernel image that will be kexec'ed
+ local make_cmd="make ARCH=$arch CROSS_COMPILE=$CROSS_COMPILE -j$jobs"
+ build_kernel "$build_dir" "$make_cmd" "$QEMU_KCONFIG" "$KERNEL_IMAGE"
+
+ local kernel="$build_dir/arch/$arch/boot/$KERNEL_IMAGE"
+ mkinitrd "$kernel"
+
+ run_qemu "$QEMU_CMD" "$KERNEL_CMDLINE" "$kernel"
+
+ ktap_test_pass "KHO succeeded"
+}
+
+main "$@"
diff --git a/tools/testing/selftests/kho/x86.conf b/tools/testing/selftests/kho/x86.conf
new file mode 100644
index 000000000000..b419e610ca22
--- /dev/null
+++ b/tools/testing/selftests/kho/x86.conf
@@ -0,0 +1,7 @@
+QEMU_CMD=qemu-system-x86_64
+QEMU_KCONFIG="
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+"
+KERNEL_IMAGE="bzImage"
+KERNEL_CMDLINE="console=ttyS0"
diff --git a/tools/testing/selftests/ptrace/.gitignore b/tools/testing/selftests/ptrace/.gitignore
index b7dde152e75a..f6be8efd57ea 100644
--- a/tools/testing/selftests/ptrace/.gitignore
+++ b/tools/testing/selftests/ptrace/.gitignore
@@ -3,3 +3,4 @@ get_syscall_info
get_set_sud
peeksiginfo
vmaccess
+set_syscall_info
diff --git a/tools/testing/selftests/thermal/intel/workload_hint/workload_hint_test.c b/tools/testing/selftests/thermal/intel/workload_hint/workload_hint_test.c
index a40097232967..ba58589a1145 100644
--- a/tools/testing/selftests/thermal/intel/workload_hint/workload_hint_test.c
+++ b/tools/testing/selftests/thermal/intel/workload_hint/workload_hint_test.c
@@ -32,12 +32,12 @@ void workload_hint_exit(int signum)
fd = open(WORKLOAD_ENABLE_ATTRIBUTE, O_RDWR);
if (fd < 0) {
- perror("Unable to open workload type feature enable file\n");
+ perror("Unable to open workload type feature enable file");
exit(1);
}
if (write(fd, "0\n", 2) < 0) {
- perror("Can't disable workload hints\n");
+ perror("Can't disable workload hints");
exit(1);
}
@@ -68,16 +68,14 @@ int main(int argc, char **argv)
exit(1);
sprintf(delay_str, "%s\n", argv[1]);
-
- sprintf(delay_str, "%s\n", argv[1]);
fd = open(WORKLOAD_NOTIFICATION_DELAY_ATTRIBUTE, O_RDWR);
if (fd < 0) {
- perror("Unable to open workload notification delay\n");
+ perror("Unable to open workload notification delay");
exit(1);
}
if (write(fd, delay_str, strlen(delay_str)) < 0) {
- perror("Can't set delay\n");
+ perror("Can't set delay");
exit(1);
}
@@ -94,12 +92,12 @@ int main(int argc, char **argv)
/* Enable feature via sysfs knob */
fd = open(WORKLOAD_ENABLE_ATTRIBUTE, O_RDWR);
if (fd < 0) {
- perror("Unable to open workload type feature enable file\n");
+ perror("Unable to open workload type feature enable file");
exit(1);
}
if (write(fd, "1\n", 2) < 0) {
- perror("Can't enable workload hints\n");
+ perror("Can't enable workload hints");
exit(1);
}
@@ -110,7 +108,7 @@ int main(int argc, char **argv)
while (1) {
fd = open(WORKLOAD_TYPE_INDEX_ATTRIBUTE, O_RDONLY);
if (fd < 0) {
- perror("Unable to open workload type file\n");
+ perror("Unable to open workload type file");
exit(1);
}