summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Abeni <pabeni@redhat.com>2026-07-03 07:42:04 +0200
committerPaolo Abeni <pabeni@redhat.com>2026-07-03 07:46:27 +0200
commit2bb62a85aff6d4c14a62a476dfabaada3c1cc014 (patch)
tree89fe2bb7d5d671e24077d57a276c08c48561ab27
parent08bc5b2636afcbadc31bb17243eec094e048bd79 (diff)
parent87320be9f0d24fce67631b7eef919f0b79c3e45c (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Cross-merge networking fixes after downstream PR (net-7.2-rc2). No conflicts. Adjacent changes: MAINTAINERS: 56114690ff3c ("MAINTAINERS: Update Marvell octeontx2 driver maintainers") eb56577ae9a5 ("ehea: remove the ehea driver") net/core/netpoll.c: 45f1458a8501 ("netpoll: fix a use-after-free on shutdown path") 84c0ff1efb62 ("netpoll: do not warn when the best-effort pool refill fails") Signed-off-by: Paolo Abeni <pabeni@redhat.com>
-rw-r--r--.mailmap1
-rw-r--r--Documentation/devicetree/bindings/clock/amlogic,t7-peripherals-clkc.yaml12
-rw-r--r--Documentation/devicetree/bindings/clock/amlogic,t7-pll-clkc.yaml2
-rw-r--r--Documentation/devicetree/bindings/clock/canaan,k230-clk.yaml59
-rw-r--r--Documentation/devicetree/bindings/clock/marvell,pxa1908.yaml34
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,dispcc-sm6125.yaml17
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,hawi-gcc.yaml63
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml1
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,kaanapali-gxclkctl.yaml2
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,milos-camcc.yaml8
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,milos-gxclkctl.yaml61
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml1
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,sm8450-videocc.yaml3
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml2
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,x1e80100-camcc.yaml1
-rw-r--r--Documentation/devicetree/bindings/clock/renesas,cpg-div6-clock.yaml2
-rw-r--r--Documentation/devicetree/bindings/mfd/khadas,mcu.yaml1
-rw-r--r--Documentation/devicetree/bindings/regulator/sprd,sc2730-regulator.yaml44
-rw-r--r--Documentation/devicetree/bindings/rtc/epson,rx6110.txt39
-rw-r--r--Documentation/devicetree/bindings/rtc/epson,rx6110.yaml68
-rw-r--r--Documentation/devicetree/bindings/rtc/rtc-ds1307.yaml1
-rw-r--r--Documentation/devicetree/bindings/rtc/st,m41t93.yaml50
-rw-r--r--Documentation/devicetree/bindings/rtc/trivial-rtc.yaml2
-rw-r--r--Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml6
-rw-r--r--Documentation/devicetree/bindings/spmi/qcom,glymur-spmi-pmic-arb.yaml1
-rw-r--r--Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml5
-rw-r--r--Documentation/features/core/thread-info-in-task/arch-support.txt2
-rw-r--r--Documentation/hwmon/ltc4283.rst4
-rw-r--r--MAINTAINERS20
-rw-r--r--Makefile4
-rw-r--r--arch/arm64/kernel/hw_breakpoint.c9
-rw-r--r--arch/arm64/kernel/static_call.c1
-rw-r--r--arch/arm64/mm/mmu.c11
-rw-r--r--arch/loongarch/Kconfig1
-rw-r--r--arch/loongarch/boot/dts/loongson-2k0500.dtsi12
-rw-r--r--arch/loongarch/boot/dts/loongson-2k1000.dtsi4
-rw-r--r--arch/loongarch/boot/dts/loongson-2k2000.dtsi4
-rw-r--r--arch/loongarch/include/asm/acpi.h2
-rw-r--r--arch/loongarch/include/asm/current.h31
-rw-r--r--arch/loongarch/include/asm/kexec.h3
-rw-r--r--arch/loongarch/include/asm/percpu.h1
-rw-r--r--arch/loongarch/include/asm/pgtable.h4
-rw-r--r--arch/loongarch/include/asm/smp.h3
-rw-r--r--arch/loongarch/include/asm/stackframe.h10
-rw-r--r--arch/loongarch/include/asm/switch_to.h7
-rw-r--r--arch/loongarch/include/asm/thread_info.h10
-rw-r--r--arch/loongarch/kernel/acpi.c28
-rw-r--r--arch/loongarch/kernel/asm-offsets.c6
-rw-r--r--arch/loongarch/kernel/entry.S7
-rw-r--r--arch/loongarch/kernel/head.S18
-rw-r--r--arch/loongarch/kernel/process.c2
-rw-r--r--arch/loongarch/kernel/relocate.c2
-rw-r--r--arch/loongarch/kernel/setup.c3
-rw-r--r--arch/loongarch/kernel/smp.c7
-rw-r--r--arch/loongarch/kernel/switch.S14
-rw-r--r--arch/loongarch/kernel/traps.c8
-rw-r--r--arch/loongarch/mm/pageattr.c2
-rw-r--r--arch/loongarch/net/bpf_jit.c54
-rw-r--r--arch/loongarch/pci/acpi.c2
-rw-r--r--arch/loongarch/vdso/elf.S3
-rw-r--r--drivers/accel/amdxdna/amdxdna_gem.c2
-rw-r--r--drivers/accel/ivpu/ivpu_job.c10
-rw-r--r--drivers/acpi/acpi_ipmi.c2
-rw-r--r--drivers/acpi/acpica/utnonansi.c9
-rw-r--r--drivers/acpi/processor_idle.c4
-rw-r--r--drivers/acpi/resource.c6
-rw-r--r--drivers/acpi/riscv/cpuidle.c2
-rw-r--r--drivers/acpi/sysfs.c14
-rw-r--r--drivers/base/regmap/regcache.c2
-rw-r--r--drivers/block/rbd.c23
-rw-r--r--drivers/clk/Kconfig6
-rw-r--r--drivers/clk/Makefile3
-rw-r--r--drivers/clk/at91/pmc.c2
-rw-r--r--drivers/clk/at91/sam9x7.c21
-rw-r--r--drivers/clk/at91/sama7d65.c1
-rw-r--r--drivers/clk/bcm/clk-iproc-asiu.c27
-rw-r--r--drivers/clk/clk-axi-clkgen.c5
-rw-r--r--drivers/clk/clk-bulk.c14
-rw-r--r--drivers/clk/clk-k230.c2452
-rw-r--r--drivers/clk/clk-max77686.c32
-rw-r--r--drivers/clk/hisilicon/clk.c4
-rw-r--r--drivers/clk/hisilicon/clkdivider-hi6220.c26
-rw-r--r--drivers/clk/keystone/sci-clk.c10
-rw-r--r--drivers/clk/mediatek/clk-mt7988-infracfg.c80
-rw-r--r--drivers/clk/mediatek/clk-mt8192.c4
-rw-r--r--drivers/clk/mediatek/clk-mux.h5
-rw-r--r--drivers/clk/microchip/Makefile2
-rw-r--r--drivers/clk/microchip/clk-mpfs-ccc.c15
-rw-r--r--drivers/clk/microchip/clk-pic32.c (renamed from drivers/clk/microchip/clk-core.c)2
-rw-r--r--drivers/clk/microchip/clk-pic32.h (renamed from drivers/clk/microchip/clk-core.h)0
-rw-r--r--drivers/clk/microchip/clk-pic32mzda.c2
-rw-r--r--drivers/clk/mmp/clk-pxa1908-apbc.c58
-rw-r--r--drivers/clk/mmp/clk-pxa1908-apbcp.c31
-rw-r--r--drivers/clk/mvebu/common.c21
-rw-r--r--drivers/clk/nxp/clk-lpc18xx-ccu.c14
-rw-r--r--drivers/clk/qcom/Kconfig48
-rw-r--r--drivers/clk/qcom/Makefile7
-rw-r--r--drivers/clk/qcom/a53-pll.c2
-rw-r--r--drivers/clk/qcom/camcc-milos.c7
-rw-r--r--drivers/clk/qcom/camcc-x1e80100.c64
-rw-r--r--drivers/clk/qcom/camcc-x1p42100.c2223
-rw-r--r--drivers/clk/qcom/clk-alpha-pll.h6
-rw-r--r--drivers/clk/qcom/clk-regmap-phy-mux.c52
-rw-r--r--drivers/clk/qcom/clk-rpmh.c41
-rw-r--r--drivers/clk/qcom/dispcc-x1e80100.c2
-rw-r--r--drivers/clk/qcom/gcc-hawi.c3657
-rw-r--r--drivers/clk/qcom/gcc-ipq9650.c3445
-rw-r--r--drivers/clk/qcom/gcc-nord.c2
-rw-r--r--drivers/clk/qcom/gdsc.c33
-rw-r--r--drivers/clk/qcom/gdsc.h5
-rw-r--r--drivers/clk/qcom/gpucc-sm8750.c4
-rw-r--r--drivers/clk/qcom/gxclkctl-kaanapali.c1
-rw-r--r--drivers/clk/qcom/ipq-cmn-pll.c30
-rw-r--r--drivers/clk/qcom/negcc-nord.c3
-rw-r--r--drivers/clk/qcom/nwgcc-nord.c4
-rw-r--r--drivers/clk/qcom/segcc-nord.c2
-rw-r--r--drivers/clk/qcom/tcsrcc-hawi.c158
-rw-r--r--drivers/clk/qcom/videocc-x1p42100.c585
-rw-r--r--drivers/clk/renesas/clk-r8a73a4.c2
-rw-r--r--drivers/clk/renesas/clk-r8a7740.c2
-rw-r--r--drivers/clk/renesas/r8a779g0-cpg-mssr.c1
-rw-r--r--drivers/clk/renesas/r9a07g043-cpg.c2
-rw-r--r--drivers/clk/renesas/r9a07g044-cpg.c2
-rw-r--r--drivers/clk/renesas/r9a08g045-cpg.c13
-rw-r--r--drivers/clk/renesas/r9a08g046-cpg.c355
-rw-r--r--drivers/clk/renesas/r9a09g011-cpg.c7
-rw-r--r--drivers/clk/renesas/r9a09g047-cpg.c84
-rw-r--r--drivers/clk/renesas/r9a09g077-cpg.c1
-rw-r--r--drivers/clk/renesas/renesas-cpg-mssr.c3
-rw-r--r--drivers/clk/renesas/rzg2l-cpg.c88
-rw-r--r--drivers/clk/renesas/rzg2l-cpg.h18
-rw-r--r--drivers/clk/renesas/rzv2h-cpg.c181
-rw-r--r--drivers/clk/renesas/rzv2h-cpg.h12
-rw-r--r--drivers/clk/rockchip/Kconfig2
-rw-r--r--drivers/clk/rockchip/clk-rk3588.c16
-rw-r--r--drivers/clk/rockchip/clk.c25
-rw-r--r--drivers/clk/rockchip/clk.h3
-rw-r--r--drivers/clk/samsung/clk-exynos850.c5
-rw-r--r--drivers/clk/samsung/clk-exynos990.c307
-rw-r--r--drivers/clk/socfpga/clk-agilex.c2
-rw-r--r--drivers/clk/spacemit/ccu-k3.c30
-rw-r--r--drivers/clk/visconti/pll.c17
-rw-r--r--drivers/cpuidle/driver.c8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c23
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c16
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c71
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c220
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_device.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c30
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_lockdep.c103
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c18
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c50
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c91
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c39
-rw-r--r--drivers/gpu/drm/amd/amdgpu/ih_v6_1.c2
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_chardev.c56
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c8
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_migrate.c8
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process.c46
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c12
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c99
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_smi_events.h14
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_svm.c15
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c10
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c13
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c2
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c7
-rw-r--r--drivers/gpu/drm/drm_connector.c12
-rw-r--r--drivers/gpu/drm/drm_displayid_internal.h2
-rw-r--r--drivers/gpu/drm/drm_edid.c8
-rw-r--r--drivers/gpu/drm/i915/display/intel_atomic.c6
-rw-r--r--drivers/gpu/drm/i915/display/intel_cdclk.c41
-rw-r--r--drivers/gpu/drm/i915/display/intel_ddi.c11
-rw-r--r--drivers/gpu/drm/i915/display/intel_dp_mst.c4
-rw-r--r--drivers/gpu/drm/i915/gem/i915_gem_context.c1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_exec.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_uvmm.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c1
-rw-r--r--drivers/gpu/drm/radeon/r100.c13
-rw-r--r--drivers/gpu/drm/sysfb/drm_sysfb_helper.h2
-rw-r--r--drivers/gpu/drm/sysfb/drm_sysfb_screen_info.c13
-rw-r--r--drivers/gpu/drm/sysfb/efidrm.c7
-rw-r--r--drivers/gpu/drm/sysfb/vesadrm.c6
-rw-r--r--drivers/gpu/drm/xe/Makefile4
-rw-r--r--drivers/gpu/drm/xe/regs/xe_gtt_defs.h6
-rw-r--r--drivers/gpu/drm/xe/xe_device.c3
-rw-r--r--drivers/gpu/drm/xe/xe_guc_capture.c10
-rw-r--r--drivers/gpu/drm/xe/xe_pt.c133
-rw-r--r--drivers/hwmon/Kconfig3
-rw-r--r--drivers/hwmon/aspeed-g6-pwm-tach.c5
-rw-r--r--drivers/hwmon/asus_atk0110.c3
-rw-r--r--drivers/hwmon/occ/common.c34
-rw-r--r--drivers/hwmon/occ/common.h1
-rw-r--r--drivers/hwmon/pmbus/adm1275.c20
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c37
-rw-r--r--drivers/hwmon/w83627hf.c4
-rw-r--r--drivers/hwmon/w83793.c1
-rw-r--r--drivers/i2c/busses/i2c-i801.c2
-rw-r--r--drivers/i2c/busses/i2c-mpc.c2
-rw-r--r--drivers/input/rmi4/rmi_driver.c39
-rw-r--r--drivers/input/rmi4/rmi_f30.c2
-rw-r--r--drivers/input/rmi4/rmi_f3a.c2
-rw-r--r--drivers/input/serio/gscps2.c1
-rw-r--r--drivers/interconnect/core.c20
-rw-r--r--drivers/net/ethernet/airoha/airoha_eth.c129
-rw-r--r--drivers/net/ethernet/airoha/airoha_eth.h9
-rw-r--r--drivers/net/ethernet/airoha/airoha_ppe.c39
-rw-r--r--drivers/net/ethernet/airoha/airoha_regs.h9
-rw-r--r--drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c18
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.c8
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc.c7
-rw-r--r--drivers/net/ethernet/freescale/fman/fman.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c47
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c1
-rw-r--r--drivers/net/ethernet/meta/fbnic/fbnic_txrx.c11
-rw-r--r--drivers/net/ethernet/microchip/lan743x_main.c2
-rw-r--r--drivers/net/ethernet/qlogic/qede/qede_fp.c4
-rw-r--r--drivers/net/ethernet/wangxun/libwx/wx_lib.c1
-rw-r--r--drivers/net/ethernet/wangxun/libwx/wx_type.h1
-rw-r--r--drivers/net/ipa/ipa_smp2p.c30
-rw-r--r--drivers/net/mdio/mdio-i2c.c59
-rw-r--r--drivers/net/netdevsim/ethtool.c6
-rw-r--r--drivers/net/netdevsim/netdev.c2
-rw-r--r--drivers/net/netdevsim/netdevsim.h2
-rw-r--r--drivers/net/phy/sfp.c15
-rw-r--r--drivers/net/pse-pd/pse_core.c6
-rw-r--r--drivers/net/usb/gl620a.c6
-rw-r--r--drivers/net/virtio_net.c3
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_mux_codec.c40
-rw-r--r--drivers/ntb/hw/amd/ntb_hw_amd.c20
-rw-r--r--drivers/ntb/hw/epf/ntb_hw_epf.c3
-rw-r--r--drivers/of/base.c4
-rw-r--r--drivers/of/property.c8
-rw-r--r--drivers/platform/x86/amd/pmc/pmc.c9
-rw-r--r--drivers/pwm/pwm-rzg2l-gpt.c8
-rw-r--r--drivers/regulator/da9121-regulator.c18
-rw-r--r--drivers/regulator/pca9450-regulator.c7
-rw-r--r--drivers/rtc/Kconfig7
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/interface.c44
-rw-r--r--drivers/rtc/rtc-88pm886.c2
-rw-r--r--drivers/rtc/rtc-ab-b5ze-s3.c2
-rw-r--r--drivers/rtc/rtc-ab-eoz9.c2
-rw-r--r--drivers/rtc/rtc-ab8500.c8
-rw-r--r--drivers/rtc/rtc-abx80x.c23
-rw-r--r--drivers/rtc/rtc-aspeed.c1
-rw-r--r--drivers/rtc/rtc-bd70528.c8
-rw-r--r--drivers/rtc/rtc-bq32k.c11
-rw-r--r--drivers/rtc/rtc-cmos.c6
-rw-r--r--drivers/rtc/rtc-cros-ec.c4
-rw-r--r--drivers/rtc/rtc-ds1307.c207
-rw-r--r--drivers/rtc/rtc-ds1374.c2
-rw-r--r--drivers/rtc/rtc-ds1672.c2
-rw-r--r--drivers/rtc/rtc-ds3232.c2
-rw-r--r--drivers/rtc/rtc-em3027.c2
-rw-r--r--drivers/rtc/rtc-fm3130.c2
-rw-r--r--drivers/rtc/rtc-hym8563.c4
-rw-r--r--drivers/rtc/rtc-isl12022.c2
-rw-r--r--drivers/rtc/rtc-isl12026.c4
-rw-r--r--drivers/rtc/rtc-isl1208.c25
-rw-r--r--drivers/rtc/rtc-m41t80.c22
-rw-r--r--drivers/rtc/rtc-m41t93.c488
-rw-r--r--drivers/rtc/rtc-max31335.c4
-rw-r--r--drivers/rtc/rtc-max6900.c2
-rw-r--r--drivers/rtc/rtc-max77686.c10
-rw-r--r--drivers/rtc/rtc-max8997.c4
-rw-r--r--drivers/rtc/rtc-max8998.c4
-rw-r--r--drivers/rtc/rtc-mpfs.c2
-rw-r--r--drivers/rtc/rtc-msc313.c4
-rw-r--r--drivers/rtc/rtc-mv.c23
-rw-r--r--drivers/rtc/rtc-nct3018y.c2
-rw-r--r--drivers/rtc/rtc-pcap.c179
-rw-r--r--drivers/rtc/rtc-pcf2127.c8
-rw-r--r--drivers/rtc/rtc-pcf85063.c12
-rw-r--r--drivers/rtc/rtc-pcf8523.c2
-rw-r--r--drivers/rtc/rtc-pcf8563.c6
-rw-r--r--drivers/rtc/rtc-pcf8583.c2
-rw-r--r--drivers/rtc/rtc-renesas-rtca3.c26
-rw-r--r--drivers/rtc/rtc-rs5c372.c12
-rw-r--r--drivers/rtc/rtc-rv3029c2.c4
-rw-r--r--drivers/rtc/rtc-rv8803.c8
-rw-r--r--drivers/rtc/rtc-rx6110.c2
-rw-r--r--drivers/rtc/rtc-rx8010.c2
-rw-r--r--drivers/rtc/rtc-rx8025.c4
-rw-r--r--drivers/rtc/rtc-rx8581.c2
-rw-r--r--drivers/rtc/rtc-s35390a.c4
-rw-r--r--drivers/rtc/rtc-s5m.c12
-rw-r--r--drivers/rtc/rtc-sd2405al.c2
-rw-r--r--drivers/rtc/rtc-sd3078.c2
-rw-r--r--drivers/rtc/rtc-tps6594.c4
-rw-r--r--drivers/rtc/rtc-x1205.c2
-rw-r--r--drivers/soundwire/bus.c28
-rw-r--r--drivers/spi/spi-dw-mmio.c1
-rw-r--r--drivers/spi/spi-dw.h1
-rw-r--r--drivers/spi/spi-imx.c3
-rw-r--r--drivers/spi/spi-rpc-if.c6
-rw-r--r--drivers/spi/spi-uniphier.c4
-rw-r--r--drivers/spi/spi.c10
-rw-r--r--drivers/spmi/spmi-pmic-arb.c142
-rw-r--r--drivers/spmi/spmi.c4
-rw-r--r--drivers/thermal/intel/therm_throt.c7
-rw-r--r--drivers/thermal/testing/command.c36
-rw-r--r--drivers/thermal/testing/thermal_testing.h8
-rw-r--r--drivers/thermal/testing/zone.c7
-rw-r--r--drivers/video/fbdev/core/fbcon.c14
-rw-r--r--drivers/video/fbdev/core/fbmem.c12
-rw-r--r--drivers/video/fbdev/core/fbsysfs.c10
-rw-r--r--drivers/video/fbdev/goldfishfb.c13
-rw-r--r--drivers/video/fbdev/pm2fb.c1
-rw-r--r--drivers/video/fbdev/vga16fb.c4
-rw-r--r--drivers/video/fbdev/via/via-core.c7
-rw-r--r--fs/ceph/addr.c20
-rw-r--r--fs/ceph/caps.c34
-rw-r--r--fs/ceph/debugfs.c103
-rw-r--r--fs/ceph/file.c13
-rw-r--r--fs/ceph/inode.c5
-rw-r--r--fs/ceph/locks.c38
-rw-r--r--fs/ceph/mds_client.c800
-rw-r--r--fs/ceph/mds_client.h52
-rw-r--r--fs/ceph/snap.c2
-rw-r--r--fs/ceph/super.h70
-rw-r--r--fs/ceph/xattr.c2
-rw-r--r--fs/crypto/fscrypt_private.h84
-rw-r--r--fs/crypto/inline_crypt.c8
-rw-r--r--fs/crypto/keyring.c239
-rw-r--r--fs/crypto/keysetup.c118
-rw-r--r--fs/ecryptfs/crypto.c24
-rw-r--r--fs/ecryptfs/keystore.c16
-rw-r--r--fs/gfs2/bmap.c19
-rw-r--r--fs/gfs2/bmap.h1
-rw-r--r--fs/gfs2/file.c15
-rw-r--r--fs/gfs2/quota.c36
-rw-r--r--fs/gfs2/super.c1
-rw-r--r--fs/smb/client/cifsacl.c38
-rw-r--r--fs/smb/client/cifsglob.h2
-rw-r--r--fs/smb/client/connect.c4
-rw-r--r--fs/smb/client/file.c2
-rw-r--r--fs/smb/client/inode.c16
-rw-r--r--fs/smb/client/readdir.c2
-rw-r--r--fs/smb/client/smb2ops.c42
-rw-r--r--fs/smb/client/smb2pdu.c28
-rw-r--r--fs/smb/common/smb2pdu.h24
-rw-r--r--fs/smb/server/auth.c20
-rw-r--r--fs/smb/server/ksmbd_work.c58
-rw-r--r--fs/smb/server/ksmbd_work.h4
-rw-r--r--fs/smb/server/misc.c14
-rw-r--r--fs/smb/server/oplock.c679
-rw-r--r--fs/smb/server/oplock.h14
-rw-r--r--fs/smb/server/smb2pdu.c676
-rw-r--r--fs/smb/server/smb2pdu.h2
-rw-r--r--fs/smb/server/vfs.c12
-rw-r--r--fs/smb/server/vfs_cache.c265
-rw-r--r--fs/smb/server/vfs_cache.h18
-rw-r--r--include/drm/drm_connector.h6
-rw-r--r--include/dt-bindings/clock/canaan,k230-clk.h220
-rw-r--r--include/dt-bindings/clock/qcom,hawi-gcc.h253
-rw-r--r--include/dt-bindings/clock/qcom,hawi-tcsrcc.h16
-rw-r--r--include/dt-bindings/clock/qcom,ipq5332-cmn-pll.h19
-rw-r--r--include/dt-bindings/clock/qcom,nord-negcc.h1
-rw-r--r--include/dt-bindings/clock/qcom,rpmh.h2
-rw-r--r--include/dt-bindings/clock/qcom,x1e80100-camcc.h3
-rw-r--r--include/dt-bindings/clock/qcom,x1p42100-videocc.h48
-rw-r--r--include/dt-bindings/clock/rockchip,rk3588-cru.h4
-rw-r--r--include/dt-bindings/clock/spacemit,k3-clocks.h5
-rw-r--r--include/linux/adi-axi-common.h2
-rw-r--r--include/linux/clk/renesas.h20
-rw-r--r--include/linux/interconnect.h6
-rw-r--r--include/linux/ntb.h4
-rw-r--r--include/linux/rtc.h2
-rw-r--r--include/linux/soundwire/sdw.h38
-rw-r--r--include/linux/spmi.h5
-rw-r--r--include/net/tcp_ao.h1
-rw-r--r--include/soc/rockchip/rk3588_grf.h2
-rw-r--r--include/soc/spacemit/k3-syscon.h4
-rw-r--r--include/sound/soc-component.h4
-rw-r--r--include/sound/tas2781.h4
-rw-r--r--include/trace/events/ceph.h67
-rw-r--r--kernel/bpf/bpf_lsm.c3
-rw-r--r--kernel/bpf/btf.c209
-rw-r--r--kernel/bpf/cgroup.c108
-rw-r--r--kernel/bpf/stackmap.c183
-rw-r--r--kernel/bpf/states.c13
-rw-r--r--kernel/bpf/syscall.c2
-rw-r--r--kernel/bpf/verifier.c8
-rw-r--r--kernel/sched/cpufreq_schedutil.c1
-rw-r--r--kernel/trace/bpf_trace.c11
-rw-r--r--kernel/trace/fprobe.c10
-rw-r--r--kernel/trace/trace_eprobe.c2
-rw-r--r--kernel/trace/trace_probe.c15
-rw-r--r--kernel/trace/trace_probe.h2
-rw-r--r--lib/bootconfig.c23
-rw-r--r--net/batman-adv/distributed-arp-table.c28
-rw-r--r--net/batman-adv/gateway_client.c3
-rw-r--r--net/batman-adv/main.c3
-rw-r--r--net/batman-adv/mesh-interface.c1
-rw-r--r--net/batman-adv/routing.c3
-rw-r--r--net/bpf/test_run.c8
-rw-r--r--net/bridge/br_if.c3
-rw-r--r--net/bridge/br_stp.c3
-rw-r--r--net/core/filter.c4
-rw-r--r--net/core/netpoll.c9
-rw-r--r--net/dsa/tag.c12
-rw-r--r--net/dsa/tag_ar9331.c10
-rw-r--r--net/dsa/tag_brcm.c39
-rw-r--r--net/dsa/tag_dsa.c15
-rw-r--r--net/dsa/tag_gswip.c8
-rw-r--r--net/dsa/tag_hellcreek.c9
-rw-r--r--net/dsa/tag_ksz.c44
-rw-r--r--net/dsa/tag_lan9303.c2
-rw-r--r--net/dsa/tag_mtk.c8
-rw-r--r--net/dsa/tag_mxl-gsw1xx.c3
-rw-r--r--net/dsa/tag_mxl862xx.c3
-rw-r--r--net/dsa/tag_netc.c18
-rw-r--r--net/dsa/tag_ocelot.c4
-rw-r--r--net/dsa/tag_ocelot_8021q.c20
-rw-r--r--net/dsa/tag_qca.c14
-rw-r--r--net/dsa/tag_rtl4_a.c8
-rw-r--r--net/dsa/tag_rtl8_4.c24
-rw-r--r--net/dsa/tag_rzn1_a5psw.c8
-rw-r--r--net/dsa/tag_sja1105.c42
-rw-r--r--net/dsa/tag_trailer.c16
-rw-r--r--net/dsa/tag_vsc73xx_8021q.c1
-rw-r--r--net/dsa/tag_xrs700x.c12
-rw-r--r--net/dsa/tag_yt921x.c7
-rw-r--r--net/dsa/user.c7
-rw-r--r--net/ipv4/tcp_ao.c5
-rw-r--r--net/ipv4/tcp_ipv4.c4
-rw-r--r--net/ipv4/tcp_output.c8
-rw-r--r--net/ipv6/ip6_fib.c17
-rw-r--r--net/ipv6/seg6.c3
-rw-r--r--net/netfilter/ipset/ip_set_core.c8
-rw-r--r--net/netfilter/nf_conntrack_bpf.c35
-rw-r--r--net/netfilter/nf_conntrack_expect.c3
-rw-r--r--net/netfilter/nf_conntrack_netlink.c11
-rw-r--r--net/netfilter/nf_conntrack_sip.c7
-rw-r--r--net/netfilter/nfnetlink_cthelper.c2
-rw-r--r--net/netfilter/nfnetlink_queue.c170
-rw-r--r--net/netfilter/nft_fib.c9
-rw-r--r--net/netfilter/nft_fib_netdev.c29
-rw-r--r--net/netfilter/nft_payload.c270
-rw-r--r--net/netfilter/nft_set_pipapo.c34
-rw-r--r--net/netfilter/nft_set_pipapo.h8
-rw-r--r--net/sched/act_bpf.c2
-rw-r--r--net/sched/sch_dualpi2.c6
-rw-r--r--net/sched/sch_hhf.c27
-rw-r--r--net/sched/sch_multiq.c2
-rw-r--r--net/sched/sch_taprio.c2
-rw-r--r--net/sched/sch_teql.c125
-rw-r--r--net/sctp/protocol.c3
-rw-r--r--net/sctp/sm_make_chunk.c5
-rw-r--r--net/sctp/sm_statefuns.c36
-rw-r--r--net/sctp/socket.c9
-rw-r--r--net/tipc/bcast.c22
-rw-r--r--net/tipc/bcast.h2
-rw-r--r--net/tipc/node.c15
-rw-r--r--samples/trace_events/trace-events-sample.c4
-rw-r--r--sound/core/compress_offload.c13
-rw-r--r--sound/core/pcm_lib.c2
-rw-r--r--sound/core/seq/seq_memory.c2
-rw-r--r--sound/firewire/isight.c3
-rw-r--r--sound/hda/codecs/conexant.c12
-rw-r--r--sound/hda/codecs/realtek/alc269.c10
-rw-r--r--sound/hda/codecs/side-codecs/cs35l41_hda_property.c2
-rw-r--r--sound/pci/emu10k1/emupcm.c18
-rw-r--r--sound/sh/aica.c8
-rw-r--r--sound/soc/codecs/cs530x.c29
-rw-r--r--sound/soc/codecs/cs530x.h6
-rw-r--r--sound/soc/codecs/es9356.c4
-rw-r--r--sound/soc/codecs/max98373-sdw.c4
-rw-r--r--sound/soc/codecs/pcm512x.c2
-rw-r--r--sound/soc/codecs/rt1017-sdca-sdw.c4
-rw-r--r--sound/soc/codecs/rt1308-sdw.c4
-rw-r--r--sound/soc/codecs/rt1316-sdw.c4
-rw-r--r--sound/soc/codecs/rt5575-spi.c2
-rw-r--r--sound/soc/codecs/rt5645.c6
-rw-r--r--sound/soc/codecs/rt5645.h1
-rw-r--r--sound/soc/codecs/rt5682-sdw.c4
-rw-r--r--sound/soc/codecs/rt700-sdw.c4
-rw-r--r--sound/soc/codecs/rt711-sdca-sdw.c4
-rw-r--r--sound/soc/codecs/rt712-sdca-dmic.c4
-rw-r--r--sound/soc/codecs/rt712-sdca-sdw.c4
-rw-r--r--sound/soc/codecs/rt715-sdca-sdw.c4
-rw-r--r--sound/soc/codecs/rt715-sdw.c4
-rw-r--r--sound/soc/codecs/rt721-sdca-sdw.c4
-rw-r--r--sound/soc/codecs/rt722-sdca-sdw.c4
-rw-r--r--sound/soc/codecs/tac5xx2-sdw.c4
-rw-r--r--sound/soc/codecs/tas2783-sdw.c77
-rw-r--r--sound/soc/codecs/tlv320aic3x.c25
-rw-r--r--sound/soc/fsl/fsl_asrc_dma.c20
-rw-r--r--sound/soc/generic/audio-graph-card2.c12
-rw-r--r--sound/soc/qcom/qdsp6/q6apm.c8
-rw-r--r--sound/soc/rockchip/rockchip_sai.c263
-rw-r--r--sound/soc/sdca/sdca_asoc.c3
-rw-r--r--sound/soc/soc-core.c35
-rw-r--r--sound/usb/caiaq/input.c12
-rw-r--r--sound/usb/fcp.c2
-rw-r--r--sound/usb/midi2.c5
-rw-r--r--sound/usb/mixer_quirks.c41
-rw-r--r--sound/usb/qcom/qc_audio_offload.c16
-rw-r--r--sound/usb/quirks-table.h14
-rw-r--r--sound/usb/quirks.c2
-rw-r--r--tools/bpf/bpftool/cgroup.c14
-rw-r--r--tools/testing/selftests/bpf/bpf_experimental.h7
-rw-r--r--tools/testing/selftests/bpf/prog_tests/bpf_nf.c6
-rw-r--r--tools/testing/selftests/bpf/prog_tests/btf.c12
-rw-r--r--tools/testing/selftests/bpf/prog_tests/cgroup_preorder.c77
-rw-r--r--tools/testing/selftests/bpf/progs/bpf_misc.h1
-rw-r--r--tools/testing/selftests/bpf/progs/test_bpf_nf.c26
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_jit_inline.c13
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_lsm.c15
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_spill_fill.c18
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_unpriv.c22
-rw-r--r--tools/testing/selftests/bpf/test_loader.c5
-rwxr-xr-xtools/testing/selftests/drivers/net/hw/tso.py16
-rw-r--r--tools/testing/selftests/net/lib/py/utils.py4
-rw-r--r--tools/tracing/rtla/.gitignore13
-rw-r--r--tools/tracing/rtla/tests/scripts/lib/get_workload_pids.sh2
526 files changed, 22500 insertions, 3496 deletions
diff --git a/.mailmap b/.mailmap
index 23eb9a4b04f4..e7e639aeb23c 100644
--- a/.mailmap
+++ b/.mailmap
@@ -373,6 +373,7 @@ Jarkko Sakkinen <jarkko@kernel.org> <jarkko.sakkinen@opinsys.com>
Jason Gunthorpe <jgg@ziepe.ca> <jgg@mellanox.com>
Jason Gunthorpe <jgg@ziepe.ca> <jgg@nvidia.com>
Jason Gunthorpe <jgg@ziepe.ca> <jgunthorpe@obsidianresearch.com>
+Jason Wang <jasowangio@gmail.com> <jasowang@redhat.com>
Jason Xing <kerneljasonxing@gmail.com> <kernelxing@tencent.com>
<javier@osg.samsung.com> <javier.martinez@collabora.co.uk>
Javi Merino <javi.merino@kernel.org> <javi.merino@arm.com>
diff --git a/Documentation/devicetree/bindings/clock/amlogic,t7-peripherals-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,t7-peripherals-clkc.yaml
index 55bb73707d58..a4b214a941ea 100644
--- a/Documentation/devicetree/bindings/clock/amlogic,t7-peripherals-clkc.yaml
+++ b/Documentation/devicetree/bindings/clock/amlogic,t7-peripherals-clkc.yaml
@@ -24,7 +24,7 @@ properties:
const: 1
clocks:
- minItems: 14
+ minItems: 15
items:
- description: input oscillator
- description: input sys clk
@@ -40,12 +40,13 @@ properties:
- description: input gp1 pll
- description: input mpll1
- description: input mpll2
+ - description: input mpll3
- description: external input rmii oscillator (optional)
- description: input video pll0 (optional)
- description: external pad input for rtc (optional)
clock-names:
- minItems: 14
+ minItems: 15
items:
- const: xtal
- const: sys
@@ -61,6 +62,7 @@ properties:
- const: gp1
- const: mpll1
- const: mpll2
+ - const: mpll3
- const: ext_rmii
- const: vid_pll0
- const: ext_rtc
@@ -97,7 +99,8 @@ examples:
<&gp0 1>,
<&gp1 1>,
<&mpll 4>,
- <&mpll 6>;
+ <&mpll 6>,
+ <&mpll 8>;
clock-names = "xtal",
"sys",
"fix",
@@ -111,6 +114,7 @@ examples:
"gp0",
"gp1",
"mpll1",
- "mpll2";
+ "mpll2",
+ "mpll3";
};
};
diff --git a/Documentation/devicetree/bindings/clock/amlogic,t7-pll-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,t7-pll-clkc.yaml
index 49c61f65deff..b488d92b7984 100644
--- a/Documentation/devicetree/bindings/clock/amlogic,t7-pll-clkc.yaml
+++ b/Documentation/devicetree/bindings/clock/amlogic,t7-pll-clkc.yaml
@@ -72,7 +72,7 @@ allOf:
contains:
enum:
- amlogic,t7-gp0-pll
- - amlogic,t7-gp1--pll
+ - amlogic,t7-gp1-pll
- amlogic,t7-hifi-pll
- amlogic,t7-pcie-pll
- amlogic,t7-mpll
diff --git a/Documentation/devicetree/bindings/clock/canaan,k230-clk.yaml b/Documentation/devicetree/bindings/clock/canaan,k230-clk.yaml
new file mode 100644
index 000000000000..34c93cb5db40
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/canaan,k230-clk.yaml
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/canaan,k230-clk.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Canaan Kendryte K230 Clock
+
+maintainers:
+ - Xukai Wang <kingxukai@zohomail.com>
+
+description:
+ The Canaan K230 clock controller generates various clocks for SoC
+ peripherals. See include/dt-bindings/clock/canaan,k230-clk.h for
+ valid clock IDs.
+
+properties:
+ compatible:
+ const: canaan,k230-clk
+
+ reg:
+ items:
+ - description: PLL control registers
+ - description: Sysclk control registers
+
+ clocks:
+ items:
+ - description: Main external reference clock
+ - description:
+ External clock which used as the pulse input
+ for the timer to provide timing signals.
+
+ clock-names:
+ items:
+ - const: osc24m
+ - const: timer-pulse-in
+
+ '#clock-cells':
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - '#clock-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ clock-controller@91102000 {
+ compatible = "canaan,k230-clk";
+ reg = <0x91102000 0x40>,
+ <0x91100000 0x108>;
+ clocks = <&osc24m>, <&timerx_pulse_in>;
+ clock-names = "osc24m", "timer-pulse-in";
+ #clock-cells = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/marvell,pxa1908.yaml b/Documentation/devicetree/bindings/clock/marvell,pxa1908.yaml
index 6f3a8578fe2a..0db5504013d5 100644
--- a/Documentation/devicetree/bindings/clock/marvell,pxa1908.yaml
+++ b/Documentation/devicetree/bindings/clock/marvell,pxa1908.yaml
@@ -37,6 +37,9 @@ properties:
'#power-domain-cells':
const: 1
+ '#reset-cells':
+ const: 1
+
required:
- compatible
- reg
@@ -44,16 +47,27 @@ required:
additionalProperties: false
-if:
- not:
- properties:
- compatible:
- contains:
- const: marvell,pxa1908-apmu
-
-then:
- properties:
- '#power-domain-cells': false
+allOf:
+ - if:
+ not:
+ properties:
+ compatible:
+ contains:
+ const: marvell,pxa1908-apmu
+ then:
+ properties:
+ '#power-domain-cells': false
+ - if:
+ not:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - marvell,pxa1908-apbc
+ - marvell,pxa1908-apbcp
+ then:
+ properties:
+ '#reset-cells': false
examples:
# APMU block:
diff --git a/Documentation/devicetree/bindings/clock/qcom,dispcc-sm6125.yaml b/Documentation/devicetree/bindings/clock/qcom,dispcc-sm6125.yaml
index ef2b1e204430..a177a1934b19 100644
--- a/Documentation/devicetree/bindings/clock/qcom,dispcc-sm6125.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,dispcc-sm6125.yaml
@@ -42,12 +42,6 @@ properties:
- const: cfg_ahb_clk
- const: gcc_disp_gpll0_div_clk_src
- '#clock-cells':
- const: 1
-
- '#power-domain-cells':
- const: 1
-
power-domains:
description:
A phandle and PM domain specifier for the CX power domain.
@@ -58,18 +52,16 @@ properties:
A phandle to an OPP node describing the power domain's performance point.
maxItems: 1
- reg:
- maxItems: 1
-
required:
- compatible
- - reg
- clocks
- clock-names
- - '#clock-cells'
- '#power-domain-cells'
-additionalProperties: false
+allOf:
+ - $ref: qcom,gcc.yaml#
+
+unevaluatedProperties: false
examples:
- |
@@ -101,6 +93,7 @@ examples:
power-domains = <&rpmpd SM6125_VDDCX>;
#clock-cells = <1>;
+ #reset-cells = <1>;
#power-domain-cells = <1>;
};
...
diff --git a/Documentation/devicetree/bindings/clock/qcom,hawi-gcc.yaml b/Documentation/devicetree/bindings/clock/qcom,hawi-gcc.yaml
new file mode 100644
index 000000000000..4f428c0f7286
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,hawi-gcc.yaml
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/qcom,hawi-gcc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Global Clock & Reset Controller on Hawi
+
+maintainers:
+ - Vivek Aknurwar <vivek.aknurwar@oss.qualcomm.com>
+
+description: |
+ Qualcomm global clock control module provides the clocks, resets and power
+ domains on Hawi.
+
+ See also: include/dt-bindings/clock/qcom,hawi-gcc.h
+
+properties:
+ compatible:
+ const: qcom,hawi-gcc
+
+ clocks:
+ items:
+ - description: Board XO source
+ - description: Board Always On XO source
+ - description: Sleep clock source
+ - description: PCIE 0 Pipe clock source
+ - description: PCIE 1 Pipe clock source
+ - description: UFS PHY RX symbol 0 clock
+ - description: UFS PHY RX symbol 1 clock
+ - description: UFS PHY TX symbol 0 clock
+ - description: USB3 PHY wrapper pipe clock
+
+required:
+ - compatible
+ - clocks
+ - '#power-domain-cells'
+
+allOf:
+ - $ref: qcom,gcc.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/qcom,rpmh.h>
+ clock-controller@100000 {
+ compatible = "qcom,hawi-gcc";
+ reg = <0x00100000 0x1f4200>;
+ clocks = <&rpmhcc RPMH_CXO_CLK>,
+ <&rpmhcc RPMH_CXO_CLK_A>,
+ <&sleep_clk>,
+ <&pcie0_phy>,
+ <&pcie1_phy>,
+ <&ufs_mem_phy 0>,
+ <&ufs_mem_phy 1>,
+ <&ufs_mem_phy 2>,
+ <&usb_1_qmpphy>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ #power-domain-cells = <1>;
+ };
+...
diff --git a/Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml b/Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml
index 8cb86d74e489..a4f9af8fa187 100644
--- a/Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,ipq9574-cmn-pll.yaml
@@ -25,6 +25,7 @@ properties:
compatible:
enum:
- qcom,ipq5018-cmn-pll
+ - qcom,ipq5332-cmn-pll
- qcom,ipq5424-cmn-pll
- qcom,ipq6018-cmn-pll
- qcom,ipq8074-cmn-pll
diff --git a/Documentation/devicetree/bindings/clock/qcom,kaanapali-gxclkctl.yaml b/Documentation/devicetree/bindings/clock/qcom,kaanapali-gxclkctl.yaml
index 466c884aa2ba..e868963f659b 100644
--- a/Documentation/devicetree/bindings/clock/qcom,kaanapali-gxclkctl.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,kaanapali-gxclkctl.yaml
@@ -44,7 +44,7 @@ required:
- power-domains
- '#power-domain-cells'
-unevaluatedProperties: false
+additionalProperties: false
examples:
- |
diff --git a/Documentation/devicetree/bindings/clock/qcom,milos-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,milos-camcc.yaml
index f63149ecf3e1..707b25d2c11e 100644
--- a/Documentation/devicetree/bindings/clock/qcom,milos-camcc.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,milos-camcc.yaml
@@ -25,6 +25,10 @@ properties:
- description: Sleep clock source
- description: Camera AHB clock from GCC
+ interconnects:
+ items:
+ - description: Interconnect path to enable the MultiMedia NoC
+
required:
- compatible
- clocks
@@ -37,12 +41,16 @@ unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,milos-gcc.h>
+ #include <dt-bindings/interconnect/qcom,icc.h>
+ #include <dt-bindings/interconnect/qcom,milos-rpmh.h>
clock-controller@adb0000 {
compatible = "qcom,milos-camcc";
reg = <0x0adb0000 0x40000>;
clocks = <&bi_tcxo_div2>,
<&sleep_clk>,
<&gcc GCC_CAMERA_AHB_CLK>;
+ interconnects = <&mmss_noc MASTER_CAMNOC_HF QCOM_ICC_TAG_ALWAYS
+ &mmss_noc SLAVE_MNOC_HF_MEM_NOC QCOM_ICC_TAG_ALWAYS>;
#clock-cells = <1>;
#reset-cells = <1>;
#power-domain-cells = <1>;
diff --git a/Documentation/devicetree/bindings/clock/qcom,milos-gxclkctl.yaml b/Documentation/devicetree/bindings/clock/qcom,milos-gxclkctl.yaml
new file mode 100644
index 000000000000..fbcb5d3f3e3d
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,milos-gxclkctl.yaml
@@ -0,0 +1,61 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/qcom,milos-gxclkctl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Graphics Power Domain Controller on Milos
+
+maintainers:
+ - Luca Weiss <luca.weiss@fairphone.com>
+
+description: |
+ Qualcomm GX(graphics) is a clock controller which has PLLs, clocks and
+ Power domains (GDSC). This module provides the power domains control
+ of gxclkctl on Qualcomm SoCs which helps the recovery of Graphics subsystem.
+
+ See also:
+ include/dt-bindings/clock/qcom,kaanapali-gxclkctl.h
+
+properties:
+ compatible:
+ enum:
+ - qcom,milos-gxclkctl
+
+ reg:
+ maxItems: 1
+
+ power-domains:
+ description:
+ Power domains required for the clock controller to operate
+ items:
+ - description: GFX power domain
+ - description: GPUCC(CX) power domain
+
+ '#power-domain-cells':
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - power-domains
+ - '#power-domain-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/power/qcom,rpmhpd.h>
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ clock-controller@3d64000 {
+ compatible = "qcom,milos-gxclkctl";
+ reg = <0x0 0x03d64000 0x0 0x6000>;
+ power-domains = <&rpmhpd RPMHPD_GFX>,
+ <&gpucc 0>;
+ #power-domain-cells = <1>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml
index a2c404a57981..d344b3386042 100644
--- a/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,rpmhcc.yaml
@@ -19,6 +19,7 @@ properties:
enum:
- qcom,eliza-rpmh-clk
- qcom,glymur-rpmh-clk
+ - qcom,hawi-rpmh-clk
- qcom,kaanapali-rpmh-clk
- qcom,milos-rpmh-clk
- qcom,nord-rpmh-clk
diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-videocc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-videocc.yaml
index 7bbf120d928c..5d77029bfaf8 100644
--- a/Documentation/devicetree/bindings/clock/qcom,sm8450-videocc.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-videocc.yaml
@@ -20,6 +20,7 @@ description: |
include/dt-bindings/clock/qcom,sm8450-videocc.h
include/dt-bindings/clock/qcom,sm8650-videocc.h
include/dt-bindings/clock/qcom,sm8750-videocc.h
+ include/dt-bindings/clock/qcom,x1p42100-videocc.h
properties:
compatible:
@@ -32,6 +33,7 @@ properties:
- qcom,sm8650-videocc
- qcom,sm8750-videocc
- qcom,x1e80100-videocc
+ - qcom,x1p42100-videocc
clocks:
items:
@@ -70,6 +72,7 @@ allOf:
- qcom,sm8450-videocc
- qcom,sm8550-videocc
- qcom,sm8750-videocc
+ - qcom,x1p42100-videocc
then:
required:
- required-opps
diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml
index 1ccdf4b0f5dd..08824f848973 100644
--- a/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,sm8550-tcsr.yaml
@@ -17,6 +17,7 @@ description: |
See also:
- include/dt-bindings/clock/qcom,eliza-tcsr.h
- include/dt-bindings/clock/qcom,glymur-tcsr.h
+ - include/dt-bindings/clock/qcom,hawi-tcsrcc.h
- include/dt-bindings/clock/qcom,nord-tcsrcc.h
- include/dt-bindings/clock/qcom,sm8550-tcsr.h
- include/dt-bindings/clock/qcom,sm8650-tcsr.h
@@ -28,6 +29,7 @@ properties:
- enum:
- qcom,eliza-tcsr
- qcom,glymur-tcsr
+ - qcom,hawi-tcsrcc
- qcom,kaanapali-tcsr
- qcom,milos-tcsr
- qcom,nord-tcsrcc
diff --git a/Documentation/devicetree/bindings/clock/qcom,x1e80100-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,x1e80100-camcc.yaml
index 938a2f1ff3fc..b28614186cc0 100644
--- a/Documentation/devicetree/bindings/clock/qcom,x1e80100-camcc.yaml
+++ b/Documentation/devicetree/bindings/clock/qcom,x1e80100-camcc.yaml
@@ -23,6 +23,7 @@ properties:
compatible:
enum:
- qcom,x1e80100-camcc
+ - qcom,x1p42100-camcc
reg:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clock.yaml b/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clock.yaml
index 2197c952e21d..b6ee8c8efd46 100644
--- a/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/renesas,cpg-div6-clock.yaml
@@ -60,7 +60,7 @@ examples:
clock-output-names = "main", "pll0", "pll1", "pll2",
"pll2s", "pll2h", "z", "z2",
"i", "m3", "b", "m1", "m2",
- "zx", "zs", "hp";
+ "zx", "zs", "hp", "ztr", "zt";
};
sdhi2_clk: sdhi2_clk@e615007c {
diff --git a/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml b/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
index 1f135618e3b6..c6f91e7bc8aa 100644
--- a/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
+++ b/Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
@@ -28,7 +28,6 @@ properties:
fan-supply:
description: Phandle to the regulator that powers the fan.
- $ref: /schemas/types.yaml#/definitions/phandle
required:
- compatible
diff --git a/Documentation/devicetree/bindings/regulator/sprd,sc2730-regulator.yaml b/Documentation/devicetree/bindings/regulator/sprd,sc2730-regulator.yaml
new file mode 100644
index 000000000000..ab945c46b08e
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/sprd,sc2730-regulator.yaml
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/regulator/sprd,sc2730-regulator.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Unisoc SC2730 Power Management IC regulators
+
+maintainers:
+ - Otto Pflüger <otto.pflueger@abscue.de>
+
+patternProperties:
+ "^dcdc-(core|cpu|gen[0-1]|gpu|mem|memq|modem|sram)$":
+ type: object
+ $ref: regulator.yaml#
+ unevaluatedProperties: false
+
+ "^ldo-avdd(12|18)$":
+ type: object
+ $ref: regulator.yaml#
+ unevaluatedProperties: false
+
+ "^ldo-vdd(18-dcxo|28)$":
+ type: object
+ $ref: regulator.yaml#
+ unevaluatedProperties: false
+
+ "^ldo-vdd(emmccore|kpled|ldo[0-2]|sd(core|io)|sim[0-2]|usb33|wcn|wifipa)$":
+ type: object
+ $ref: regulator.yaml#
+ unevaluatedProperties: false
+
+ "^ldo-vddcam(a0|a1|d0|d1|io|mot)$":
+ type: object
+ $ref: regulator.yaml#
+ unevaluatedProperties: false
+
+ "^ldo-vddrf(1v25|18)$":
+ type: object
+ $ref: regulator.yaml#
+ unevaluatedProperties: false
+
+additionalProperties: false
+...
diff --git a/Documentation/devicetree/bindings/rtc/epson,rx6110.txt b/Documentation/devicetree/bindings/rtc/epson,rx6110.txt
deleted file mode 100644
index 3dc313e01f77..000000000000
--- a/Documentation/devicetree/bindings/rtc/epson,rx6110.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-Epson RX6110 Real Time Clock
-============================
-
-The Epson RX6110 can be used with SPI or I2C busses. The kind of
-bus depends on the SPISEL pin and can not be configured via software.
-
-I2C mode
---------
-
-Required properties:
- - compatible: should be: "epson,rx6110"
- - reg : the I2C address of the device for I2C
-
-Example:
-
- rtc: rtc@32 {
- compatible = "epson,rx6110"
- reg = <0x32>;
- };
-
-SPI mode
---------
-
-Required properties:
- - compatible: should be: "epson,rx6110"
- - reg: chip select number
- - spi-cs-high: RX6110 needs chipselect high
- - spi-cpha: RX6110 works with SPI shifted clock phase
- - spi-cpol: RX6110 works with SPI inverse clock polarity
-
-Example:
-
- rtc: rtc@3 {
- compatible = "epson,rx6110"
- reg = <3>
- spi-cs-high;
- spi-cpha;
- spi-cpol;
- };
diff --git a/Documentation/devicetree/bindings/rtc/epson,rx6110.yaml b/Documentation/devicetree/bindings/rtc/epson,rx6110.yaml
new file mode 100644
index 000000000000..55086ac7d1e2
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/epson,rx6110.yaml
@@ -0,0 +1,68 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/epson,rx6110.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Epson RX6110 Real Time Clock
+
+description:
+ The Epson RX6110 can be used with SPI or I2C busses. The kind of bus depends
+ on the SPISEL pin and cannot be configured via software.
+
+maintainers:
+ - Alexandre Belloni <alexandre.belloni@bootlin.com>
+
+allOf:
+ - $ref: rtc.yaml#
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+properties:
+ compatible:
+ const: epson,rx6110
+
+ reg:
+ maxItems: 1
+
+ spi-cs-high: true
+ spi-cpha: true
+ spi-cpol: true
+
+required:
+ - compatible
+ - reg
+
+dependencies:
+ spi-cs-high: [ spi-cpha, spi-cpol ]
+ spi-cpha: [ spi-cs-high, spi-cpol ]
+ spi-cpol: [ spi-cs-high, spi-cpha ]
+
+unevaluatedProperties: false
+
+examples:
+ # I2C mode
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rtc@32 {
+ compatible = "epson,rx6110";
+ reg = <0x32>;
+ };
+ };
+
+ # SPI mode
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rtc@3 {
+ compatible = "epson,rx6110";
+ reg = <3>;
+ spi-cs-high;
+ spi-cpha;
+ spi-cpol;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/rtc/rtc-ds1307.yaml b/Documentation/devicetree/bindings/rtc/rtc-ds1307.yaml
index 98d10e680144..9b2796804f07 100644
--- a/Documentation/devicetree/bindings/rtc/rtc-ds1307.yaml
+++ b/Documentation/devicetree/bindings/rtc/rtc-ds1307.yaml
@@ -31,6 +31,7 @@ properties:
- epson,rx8025
- isil,isl12057
- epson,rx8130
+ - epson,rx8901
- items:
- enum:
diff --git a/Documentation/devicetree/bindings/rtc/st,m41t93.yaml b/Documentation/devicetree/bindings/rtc/st,m41t93.yaml
new file mode 100644
index 000000000000..bdd995c5c1f4
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/st,m41t93.yaml
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/st,m41t93.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ST M41T93 RTC and compatible
+
+maintainers:
+ - Akhilesh Patil <akhilesh@ee.iitb.ac.in>
+
+description:
+ ST M41T93 is spi based Real Time Clock (RTC) with time, date,
+ alarm, watchdog, square wave clock output, 8 bit timer and
+ 7 bytes of user SRAM.
+
+properties:
+ compatible:
+ enum:
+ - st,m41t93
+
+ reg:
+ maxItems: 1
+
+ "#clock-cells":
+ const: 0
+
+required:
+ - compatible
+ - reg
+
+allOf:
+ - $ref: rtc.yaml
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ rtc@0 {
+ compatible = "st,m41t93";
+ reg = <0>;
+ #clock-cells = <0>;
+ spi-max-frequency = <2000000>;
+ };
+ };
+
diff --git a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml
index 722176c831aa..f4d0eed98a08 100644
--- a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml
+++ b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml
@@ -30,6 +30,8 @@ properties:
- aspeed,ast2500-rtc
# ASPEED BMC ast2600 Real-time Clock
- aspeed,ast2600-rtc
+ # ASPEED BMC ast2700 Real-time Clock
+ - aspeed,ast2700-rtc
# Conexant Digicolor Real Time Clock Controller
- cnxt,cx92755-rtc
# I2C, 32-Bit Binary Counter Watchdog RTC with Trickle Charger and Reset Input/Output
diff --git a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml
index 8ebebcebca16..4458316326fc 100644
--- a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml
+++ b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml
@@ -54,6 +54,12 @@ properties:
- sophgo,sg2042-spi
- thead,th1520-spi
- const: snps,dw-apb-ssi
+ - description: Vendor controllers which use snps,dwc-ssi-2.00a as fallback
+ items:
+ - enum:
+ - starfive,jhb100-spi
+ - const: snps,dwc-ssi-2.00a
+ - const: snps,dwc-ssi-1.01a
- description: Intel Keem Bay SPI Controller
const: intel,keembay-ssi
- description: Intel Mount Evans Integrated Management Complex SPI Controller
diff --git a/Documentation/devicetree/bindings/spmi/qcom,glymur-spmi-pmic-arb.yaml b/Documentation/devicetree/bindings/spmi/qcom,glymur-spmi-pmic-arb.yaml
index 3b5005b96c6d..1593a1183a36 100644
--- a/Documentation/devicetree/bindings/spmi/qcom,glymur-spmi-pmic-arb.yaml
+++ b/Documentation/devicetree/bindings/spmi/qcom,glymur-spmi-pmic-arb.yaml
@@ -25,6 +25,7 @@ properties:
oneOf:
- items:
- enum:
+ - qcom,hawi-spmi-pmic-arb
- qcom,kaanapali-spmi-pmic-arb
- const: qcom,glymur-spmi-pmic-arb
- enum:
diff --git a/Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml b/Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml
index e28612510d67..8cfa44dcda58 100644
--- a/Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml
+++ b/Documentation/devicetree/bindings/thermal/amlogic,thermal.yaml
@@ -87,9 +87,12 @@ examples:
amlogic,ao-secure = <&sec_AO>;
};
- |
+ #include <dt-bindings/clock/amlogic,t7-peripherals-clkc.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
temperature-sensor@20000 {
compatible = "amlogic,t7-thermal";
- reg = <0x0 0x20000 0x0 0x50>;
+ reg = <0x20000 0x50>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clkc_periphs CLKID_TS>;
#thermal-sensor-cells = <0>;
diff --git a/Documentation/features/core/thread-info-in-task/arch-support.txt b/Documentation/features/core/thread-info-in-task/arch-support.txt
index f3d744c76061..e26efdfbb6b4 100644
--- a/Documentation/features/core/thread-info-in-task/arch-support.txt
+++ b/Documentation/features/core/thread-info-in-task/arch-support.txt
@@ -12,7 +12,7 @@
| arm64: | ok |
| csky: | TODO |
| hexagon: | TODO |
- | loongarch: | TODO |
+ | loongarch: | ok |
| m68k: | TODO |
| microblaze: | TODO |
| mips: | TODO |
diff --git a/Documentation/hwmon/ltc4283.rst b/Documentation/hwmon/ltc4283.rst
index a650c595bc8f..99b1ee05f629 100644
--- a/Documentation/hwmon/ltc4283.rst
+++ b/Documentation/hwmon/ltc4283.rst
@@ -256,7 +256,7 @@ these logs can be cleared by writing in the proper reset_history attribute.
``/sys/kernel/debug/i2c/i2c-[X]/[X]-addr/``
contains the following attributes:
-======================= ==========================================
+============================== ==========================================================
power1_failed_fault_log Set to 1 by a power1 fault occurring.
power1_good_input_fault_log Set to 1 by a power1 good input fault occurring at PGIO3.
in11_fet_short_fault_log Set to 1 when a FET-short fault occurs.
@@ -264,4 +264,4 @@ in11_fet_bad_fault_log Set to 1 when a FET-BAD fault occurs.
in0_lcrit_fault_log Set to 1 by a VIN undervoltage fault occurring.
in0_crit_fault_log Set to 1 by a VIN overvoltage fault occurring.
curr1_crit_fault_log Set to 1 by an overcurrent fault occurring.
-======================= ==========================================
+============================== ==========================================================
diff --git a/MAINTAINERS b/MAINTAINERS
index ee4ee7b8e947..52f1a55eca99 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15733,8 +15733,8 @@ F: drivers/net/ethernet/marvell/octeon_ep_vf
MARVELL OCTEONTX2 PHYSICAL FUNCTION DRIVER
M: Sunil Goutham <sgoutham@marvell.com>
M: Geetha sowjanya <gakula@marvell.com>
+M: Ratheesh Kannoth <rkannoth@marvell.com>
M: Subbaraya Sundeep <sbhatta@marvell.com>
-M: hariprasad <hkelam@marvell.com>
M: Bharat Bhushan <bbhushan2@marvell.com>
L: netdev@vger.kernel.org
S: Maintained
@@ -15743,9 +15743,8 @@ F: include/linux/soc/marvell/octeontx2/
MARVELL OCTEONTX2 RVU ADMIN FUNCTION DRIVER
M: Sunil Goutham <sgoutham@marvell.com>
-M: Linu Cherian <lcherian@marvell.com>
+M: Ratheesh Kannoth <rkannoth@marvell.com>
M: Geetha sowjanya <gakula@marvell.com>
-M: hariprasad <hkelam@marvell.com>
M: Subbaraya Sundeep <sbhatta@marvell.com>
L: netdev@vger.kernel.org
S: Maintained
@@ -15753,8 +15752,8 @@ F: Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst
F: drivers/net/ethernet/marvell/octeontx2/af/
MARVELL PEM PMU DRIVER
-M: Linu Cherian <lcherian@marvell.com>
M: Gowthami Thiagarajan <gthiagarajan@marvell.com>
+M: Geetha sowjanya <gakula@marvell.com>
S: Supported
F: drivers/perf/marvell_pem_pmu.c
@@ -18437,6 +18436,7 @@ F: drivers/net/ethernet/mucse/
MULTIFUNCTION DEVICES (MFD)
M: Lee Jones <lee@kernel.org>
+L: mfd@lists.linux.dev
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git
F: Documentation/devicetree/bindings/mfd/
@@ -27515,7 +27515,7 @@ F: drivers/net/ethernet/dec/tulip/
TUN/TAP DRIVER
M: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
-M: Jason Wang <jasowang@redhat.com>
+M: Jason Wang <jasowangio@gmail.com>
S: Maintained
W: http://vtun.sourceforge.net/tun
F: Documentation/networking/tuntap.rst
@@ -28507,7 +28507,7 @@ F: include/uapi/linux/virtio_balloon.h
VIRTIO BLOCK AND SCSI DRIVERS
M: "Michael S. Tsirkin" <mst@redhat.com>
-M: Jason Wang <jasowang@redhat.com>
+M: Jason Wang <jasowangio@gmail.com>
R: Paolo Bonzini <pbonzini@redhat.com>
R: Stefan Hajnoczi <stefanha@redhat.com>
R: Eugenio Pérez <eperezma@redhat.com>
@@ -28536,7 +28536,7 @@ F: include/uapi/linux/virtio_console.h
VIRTIO CORE
M: "Michael S. Tsirkin" <mst@redhat.com>
-M: Jason Wang <jasowang@redhat.com>
+M: Jason Wang <jasowangio@gmail.com>
R: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
R: Eugenio Pérez <eperezma@redhat.com>
L: virtualization@lists.linux.dev
@@ -28614,7 +28614,7 @@ F: include/uapi/linux/virtio_gpu.h
VIRTIO HOST (VHOST)
M: "Michael S. Tsirkin" <mst@redhat.com>
-M: Jason Wang <jasowang@redhat.com>
+M: Jason Wang <jasowangio@gmail.com>
R: Eugenio Pérez <eperezma@redhat.com>
L: kvm@vger.kernel.org
L: virtualization@lists.linux.dev
@@ -28629,7 +28629,7 @@ F: kernel/vhost_task.c
VIRTIO HOST (VHOST-SCSI)
M: "Michael S. Tsirkin" <mst@redhat.com>
-M: Jason Wang <jasowang@redhat.com>
+M: Jason Wang <jasowangio@gmail.com>
M: Mike Christie <michael.christie@oracle.com>
R: Paolo Bonzini <pbonzini@redhat.com>
R: Stefan Hajnoczi <stefanha@redhat.com>
@@ -28669,7 +28669,7 @@ F: include/uapi/linux/virtio_mem.h
VIRTIO NET DRIVER
M: "Michael S. Tsirkin" <mst@redhat.com>
-M: Jason Wang <jasowang@redhat.com>
+M: Jason Wang <jasowangio@gmail.com>
R: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
R: Eugenio Pérez <eperezma@redhat.com>
L: netdev@vger.kernel.org
diff --git a/Makefile b/Makefile
index 12fd3d2d47b5..b9c5792c79e0 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
VERSION = 7
-PATCHLEVEL = 1
+PATCHLEVEL = 2
SUBLEVEL = 0
-EXTRAVERSION =
+EXTRAVERSION = -rc1
NAME = Baby Opossum Posse
# *DOCUMENTATION*
diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
index ab76b36dce82..73cce8ac8368 100644
--- a/arch/arm64/kernel/hw_breakpoint.c
+++ b/arch/arm64/kernel/hw_breakpoint.c
@@ -559,6 +559,15 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,
else
alignment_mask = 0x7;
offset = hw->address & alignment_mask;
+
+ /*
+ * BAS is an 8-bit field in WCR/BCR; the shift below would
+ * silently drop the high bits of ctrl.len when offset + len
+ * exceeds 8, programming hardware to watch fewer bytes than
+ * the user requested.
+ */
+ if (((u32)hw->ctrl.len << offset) > ARM_BREAKPOINT_LEN_8)
+ return -EINVAL;
}
hw->address &= ~alignment_mask;
diff --git a/arch/arm64/kernel/static_call.c b/arch/arm64/kernel/static_call.c
index 8b3a19e10871..c126edced022 100644
--- a/arch/arm64/kernel/static_call.c
+++ b/arch/arm64/kernel/static_call.c
@@ -2,6 +2,7 @@
#include <linux/static_call.h>
#include <linux/memory.h>
#include <asm/text-patching.h>
+#include <asm/insn.h>
void arch_static_call_transform(void *site, void *tramp, void *func, bool tail)
{
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 12e862c96642..f2be501468ce 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -1198,11 +1198,6 @@ static void __init map_mem(void)
__map_memblock(start, end, pgprot_tagged(PAGE_KERNEL),
flags);
}
-
- /* Map the kernel data/bss read-only in the linear map */
- __map_memblock(init_end, kernel_end, PAGE_KERNEL_RO, flags);
- flush_tlb_kernel_range((unsigned long)lm_alias(__init_end),
- (unsigned long)lm_alias(__bss_stop));
}
void mark_rodata_ro(void)
@@ -1221,6 +1216,12 @@ void mark_rodata_ro(void)
update_mapping_prot(__pa_symbol(_text), (unsigned long)_text,
(unsigned long)_stext - (unsigned long)_text,
PAGE_KERNEL_RO);
+
+ /* Map the kernel data/bss read-only in the linear map */
+ update_mapping_prot(__pa_symbol(__init_end),
+ (unsigned long)lm_alias(__init_end),
+ (unsigned long)__bss_stop - (unsigned long)__init_end,
+ PAGE_KERNEL_RO);
}
static void __init declare_vma(struct vm_struct *vma,
diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig
index bec7cc1d72ee..d8d252325017 100644
--- a/arch/loongarch/Kconfig
+++ b/arch/loongarch/Kconfig
@@ -209,6 +209,7 @@ config LOONGARCH
select SYSCTL_ARCH_UNALIGN_NO_WARN
select SYSCTL_EXCEPTION_TRACE
select SWIOTLB if 64BIT
+ select THREAD_INFO_IN_TASK
select TRACE_IRQFLAGS_SUPPORT
select USE_PERCPU_NUMA_NODE_ID
select USER_STACKTRACE_SUPPORT
diff --git a/arch/loongarch/boot/dts/loongson-2k0500.dtsi b/arch/loongarch/boot/dts/loongson-2k0500.dtsi
index 1b502064df11..992b1d0de9ec 100644
--- a/arch/loongarch/boot/dts/loongson-2k0500.dtsi
+++ b/arch/loongarch/boot/dts/loongson-2k0500.dtsi
@@ -405,6 +405,8 @@
i2c0: i2c@1ff48000 {
compatible = "loongson,ls2k-i2c";
reg = <0x0 0x1ff48000 0x0 0x0800>;
+ clock-frequency = <100000>;
+ clocks = <&clk LOONGSON2_APB_CLK>;
interrupt-parent = <&eiointc>;
interrupts = <14>;
status = "disabled";
@@ -413,6 +415,8 @@
i2c@1ff48800 {
compatible = "loongson,ls2k-i2c";
reg = <0x0 0x1ff48800 0x0 0x0800>;
+ clock-frequency = <100000>;
+ clocks = <&clk LOONGSON2_APB_CLK>;
interrupt-parent = <&eiointc>;
interrupts = <15>;
status = "disabled";
@@ -421,6 +425,8 @@
i2c@1ff49000 {
compatible = "loongson,ls2k-i2c";
reg = <0x0 0x1ff49000 0x0 0x0800>;
+ clock-frequency = <100000>;
+ clocks = <&clk LOONGSON2_APB_CLK>;
interrupt-parent = <&eiointc>;
interrupts = <16>;
status = "disabled";
@@ -429,6 +435,8 @@
i2c@1ff49800 {
compatible = "loongson,ls2k-i2c";
reg = <0x0 0x1ff49800 0x0 0x0800>;
+ clock-frequency = <100000>;
+ clocks = <&clk LOONGSON2_APB_CLK>;
interrupt-parent = <&eiointc>;
interrupts = <17>;
status = "disabled";
@@ -437,6 +445,8 @@
i2c@1ff4a000 {
compatible = "loongson,ls2k-i2c";
reg = <0x0 0x1ff4a000 0x0 0x0800>;
+ clock-frequency = <100000>;
+ clocks = <&clk LOONGSON2_APB_CLK>;
interrupt-parent = <&eiointc>;
interrupts = <18>;
status = "disabled";
@@ -445,6 +455,8 @@
i2c@1ff4a800 {
compatible = "loongson,ls2k-i2c";
reg = <0x0 0x1ff4a800 0x0 0x0800>;
+ clock-frequency = <100000>;
+ clocks = <&clk LOONGSON2_APB_CLK>;
interrupt-parent = <&eiointc>;
interrupts = <19>;
status = "disabled";
diff --git a/arch/loongarch/boot/dts/loongson-2k1000.dtsi b/arch/loongarch/boot/dts/loongson-2k1000.dtsi
index ab6a55937e9e..e6f0fe093ab3 100644
--- a/arch/loongarch/boot/dts/loongson-2k1000.dtsi
+++ b/arch/loongarch/boot/dts/loongson-2k1000.dtsi
@@ -311,6 +311,8 @@
i2c2: i2c@1fe21000 {
compatible = "loongson,ls2k-i2c";
reg = <0x0 0x1fe21000 0x0 0x8>;
+ clock-frequency = <100000>;
+ clocks = <&clk LOONGSON2_APB_CLK>;
interrupt-parent = <&liointc0>;
interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -319,6 +321,8 @@
i2c3: i2c@1fe21800 {
compatible = "loongson,ls2k-i2c";
reg = <0x0 0x1fe21800 0x0 0x8>;
+ clock-frequency = <100000>;
+ clocks = <&clk LOONGSON2_APB_CLK>;
interrupt-parent = <&liointc0>;
interrupts = <23 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
diff --git a/arch/loongarch/boot/dts/loongson-2k2000.dtsi b/arch/loongarch/boot/dts/loongson-2k2000.dtsi
index 3678c084adf7..7fdc4192d2f2 100644
--- a/arch/loongarch/boot/dts/loongson-2k2000.dtsi
+++ b/arch/loongarch/boot/dts/loongson-2k2000.dtsi
@@ -239,6 +239,8 @@
i2c@1fe00120 {
compatible = "loongson,ls2k-i2c";
reg = <0x0 0x1fe00120 0x0 0x8>;
+ clock-frequency = <100000>;
+ clocks = <&clk LOONGSON2_MISC_CLK>;
interrupt-parent = <&liointc>;
interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -247,6 +249,8 @@
i2c@1fe00130 {
compatible = "loongson,ls2k-i2c";
reg = <0x0 0x1fe00130 0x0 0x8>;
+ clock-frequency = <100000>;
+ clocks = <&clk LOONGSON2_MISC_CLK>;
interrupt-parent = <&liointc>;
interrupts = <9 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
diff --git a/arch/loongarch/include/asm/acpi.h b/arch/loongarch/include/asm/acpi.h
index eda9d4d0a493..c05168aedcaa 100644
--- a/arch/loongarch/include/asm/acpi.h
+++ b/arch/loongarch/include/asm/acpi.h
@@ -38,6 +38,8 @@ static inline bool acpi_has_cpu_in_madt(void)
extern struct list_head acpi_wakeup_device_list;
extern struct acpi_madt_core_pic acpi_core_pic[MAX_CORE_PIC];
+extern void acpi_add_early_pio(void);
+extern void acpi_remove_early_pio(void);
extern int __init parse_acpi_topology(void);
#endif /* !CONFIG_ACPI */
diff --git a/arch/loongarch/include/asm/current.h b/arch/loongarch/include/asm/current.h
new file mode 100644
index 000000000000..fa4fb7987075
--- /dev/null
+++ b/arch/loongarch/include/asm/current.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_LOONGARCH_CURRENT_H
+#define __ASM_LOONGARCH_CURRENT_H
+
+#include <linux/compiler.h>
+
+#ifndef __ASSEMBLER__
+
+#include <asm/percpu.h>
+
+struct task_struct;
+
+DECLARE_PER_CPU(struct task_struct *, cpu_tasks);
+
+register struct task_struct *current_thread_pointer __asm__("$tp");
+
+static __always_inline struct task_struct *get_current(void)
+{
+ return current_thread_pointer;
+}
+
+#define current get_current()
+
+static __always_inline void set_current(struct task_struct *task)
+{
+ __this_cpu_write(cpu_tasks, task);
+}
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* __ASM_LOONGARCH_CURRENT_H */
diff --git a/arch/loongarch/include/asm/kexec.h b/arch/loongarch/include/asm/kexec.h
index 209fa43222e1..6be136e9f0a0 100644
--- a/arch/loongarch/include/asm/kexec.h
+++ b/arch/loongarch/include/asm/kexec.h
@@ -41,6 +41,8 @@ struct kimage_arch {
unsigned long systable_ptr;
};
+struct kimage;
+
#ifdef CONFIG_KEXEC_FILE
extern const struct kexec_file_ops kexec_efi_ops;
extern const struct kexec_file_ops kexec_elf_ops;
@@ -59,7 +61,6 @@ typedef void (*do_kexec_t)(unsigned long efi_boot,
unsigned long start_addr,
unsigned long first_ind_entry);
-struct kimage;
extern const unsigned char relocate_new_kernel[];
extern const size_t relocate_new_kernel_size;
extern void kexec_reboot(void);
diff --git a/arch/loongarch/include/asm/percpu.h b/arch/loongarch/include/asm/percpu.h
index 583f2466262f..500c51754ea5 100644
--- a/arch/loongarch/include/asm/percpu.h
+++ b/arch/loongarch/include/asm/percpu.h
@@ -5,7 +5,6 @@
#ifndef __ASM_PERCPU_H
#define __ASM_PERCPU_H
-#include <asm/cmpxchg.h>
#include <asm/loongarch.h>
/*
diff --git a/arch/loongarch/include/asm/pgtable.h b/arch/loongarch/include/asm/pgtable.h
index 2a0b63ae421f..223528c04d73 100644
--- a/arch/loongarch/include/asm/pgtable.h
+++ b/arch/loongarch/include/asm/pgtable.h
@@ -429,6 +429,8 @@ static inline pte_t pte_mkwrite_novma(pte_t pte)
static inline pte_t pte_wrprotect(pte_t pte)
{
+ if (pte_val(pte) & _PAGE_DIRTY)
+ pte_val(pte) |= _PAGE_MODIFIED;
pte_val(pte) &= ~(_PAGE_WRITE | _PAGE_DIRTY);
return pte;
}
@@ -535,6 +537,8 @@ static inline pmd_t pmd_mkwrite_novma(pmd_t pmd)
static inline pmd_t pmd_wrprotect(pmd_t pmd)
{
+ if (pmd_val(pmd) & _PAGE_DIRTY)
+ pmd_val(pmd) |= _PAGE_MODIFIED;
pmd_val(pmd) &= ~(_PAGE_WRITE | _PAGE_DIRTY);
return pmd;
}
diff --git a/arch/loongarch/include/asm/smp.h b/arch/loongarch/include/asm/smp.h
index 3a47f52959a8..dd1457065690 100644
--- a/arch/loongarch/include/asm/smp.h
+++ b/arch/loongarch/include/asm/smp.h
@@ -81,8 +81,9 @@ extern int __cpu_logical_map[NR_CPUS];
struct seq_file;
struct secondary_data {
+ unsigned long task;
unsigned long stack;
- unsigned long thread_info;
+ unsigned long offset;
};
extern struct secondary_data cpuboot_data;
diff --git a/arch/loongarch/include/asm/stackframe.h b/arch/loongarch/include/asm/stackframe.h
index ecc8e50fffa8..79526fa423a7 100644
--- a/arch/loongarch/include/asm/stackframe.h
+++ b/arch/loongarch/include/asm/stackframe.h
@@ -184,6 +184,7 @@
.cfi_rel_offset ra, PT_ERA
.endif
cfi_st tp, PT_R2, \docfi
+ cfi_st u0, PT_R21, \docfi
cfi_st fp, PT_R22, \docfi
/* Set thread_info if we're coming from user mode */
@@ -191,10 +192,13 @@
andi t0, t0, 0x3 /* extract pplv bit */
beqz t0, 9f
- LONG_LI tp, ~_THREAD_MASK
- and tp, tp, sp
- cfi_st u0, PT_R21, \docfi
csrrd u0, PERCPU_BASE_KS
+
+ la_abs t1, cpu_tasks
+#ifdef CONFIG_SMP
+ LONG_ADD t1, t1, u0
+#endif
+ LONG_L tp, t1, 0
9:
#ifdef CONFIG_KGDB
li.w t0, CSR_CRMD_WE
diff --git a/arch/loongarch/include/asm/switch_to.h b/arch/loongarch/include/asm/switch_to.h
index 5b225aff3ba2..27acbf913774 100644
--- a/arch/loongarch/include/asm/switch_to.h
+++ b/arch/loongarch/include/asm/switch_to.h
@@ -15,7 +15,6 @@ struct task_struct;
* __switch_to - switch execution of a task
* @prev: The task previously executed.
* @next: The task to begin executing.
- * @next_ti: task_thread_info(next).
* @sched_ra: __schedule return address.
* @sched_cfa: __schedule call frame address.
*
@@ -23,8 +22,7 @@ struct task_struct;
* the context of next. Returns prev.
*/
extern asmlinkage struct task_struct *__switch_to(struct task_struct *prev,
- struct task_struct *next, struct thread_info *next_ti,
- void *sched_ra, void *sched_cfa);
+ struct task_struct *next, void *sched_ra, void *sched_cfa);
/*
* For newly created kernel threads switch_to() will return to
@@ -37,7 +35,8 @@ do { \
lose_fpu_inatomic(1, prev); \
lose_lbt_inatomic(1, prev); \
hw_breakpoint_thread_switch(next); \
- (last) = __switch_to(prev, next, task_thread_info(next), \
+ set_current(next); \
+ (last) = __switch_to(prev, next, \
__builtin_return_address(0), __builtin_frame_address(0)); \
} while (0)
diff --git a/arch/loongarch/include/asm/thread_info.h b/arch/loongarch/include/asm/thread_info.h
index 4d7117fcdc78..41eabe4fb647 100644
--- a/arch/loongarch/include/asm/thread_info.h
+++ b/arch/loongarch/include/asm/thread_info.h
@@ -22,7 +22,6 @@
* must also be changed
*/
struct thread_info {
- struct task_struct *task; /* main task structure */
unsigned long flags; /* low level flags */
unsigned long tp_value; /* thread pointer */
__u32 cpu; /* current CPU */
@@ -37,20 +36,11 @@ struct thread_info {
*/
#define INIT_THREAD_INFO(tsk) \
{ \
- .task = &tsk, \
.flags = _TIF_FIXADE, \
.cpu = 0, \
.preempt_count = INIT_PREEMPT_COUNT, \
}
-/* How to get the thread information struct from C. */
-register struct thread_info *__current_thread_info __asm__("$tp");
-
-static inline struct thread_info *current_thread_info(void)
-{
- return __current_thread_info;
-}
-
register unsigned long current_stack_pointer __asm__("$sp");
#endif /* !__ASSEMBLER__ */
diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c
index 058f0dbe8e8f..8f650c9ffecd 100644
--- a/arch/loongarch/kernel/acpi.c
+++ b/arch/loongarch/kernel/acpi.c
@@ -16,6 +16,7 @@
#include <linux/memblock.h>
#include <linux/of_fdt.h>
#include <linux/serial_core.h>
+#include <linux/vmalloc.h>
#include <asm/io.h>
#include <asm/numa.h>
#include <asm/loongson.h>
@@ -59,6 +60,33 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
return ioremap_cache(phys, size);
}
+#define PIO_BASE (unsigned long)PCI_IOBASE
+#define PIO_SIZE ALIGN(ISA_IOSIZE, PAGE_SIZE)
+
+static bool acpi_pio;
+
+/* Add PIO for early access */
+void acpi_add_early_pio(void)
+{
+ if (!acpi_disabled) {
+ acpi_pio = true;
+ vmap_page_range(PIO_BASE, PIO_BASE + PIO_SIZE,
+ LOONGSON_LIO_BASE, pgprot_device(PAGE_KERNEL));
+ }
+}
+
+/* Remove PIO for PCI register */
+void acpi_remove_early_pio(void)
+{
+ if (!acpi_pio)
+ return;
+
+ if (!acpi_disabled) {
+ acpi_pio = false;
+ vunmap_range(PIO_BASE, PIO_BASE + PIO_SIZE);
+ }
+}
+
#ifdef CONFIG_SMP
static int set_processor_mask(u32 id, u32 pass)
{
diff --git a/arch/loongarch/kernel/asm-offsets.c b/arch/loongarch/kernel/asm-offsets.c
index 2cc953f113ac..1b861cbc5e10 100644
--- a/arch/loongarch/kernel/asm-offsets.c
+++ b/arch/loongarch/kernel/asm-offsets.c
@@ -70,7 +70,7 @@ static void __used output_task_defines(void)
{
COMMENT("LoongArch task_struct offsets.");
OFFSET(TASK_STATE, task_struct, __state);
- OFFSET(TASK_THREAD_INFO, task_struct, stack);
+ OFFSET(TASK_STACK, task_struct, stack);
OFFSET(TASK_FLAGS, task_struct, flags);
OFFSET(TASK_MM, task_struct, mm);
OFFSET(TASK_PID, task_struct, pid);
@@ -84,7 +84,6 @@ static void __used output_task_defines(void)
static void __used output_thread_info_defines(void)
{
COMMENT("LoongArch thread_info offsets.");
- OFFSET(TI_TASK, thread_info, task);
OFFSET(TI_FLAGS, thread_info, flags);
OFFSET(TI_TP_VALUE, thread_info, tp_value);
OFFSET(TI_CPU, thread_info, cpu);
@@ -266,8 +265,9 @@ static void __used output_signal_defines(void)
static void __used output_smpboot_defines(void)
{
COMMENT("Linux smp cpu boot offsets.");
+ OFFSET(CPU_BOOT_TASK, secondary_data, task);
OFFSET(CPU_BOOT_STACK, secondary_data, stack);
- OFFSET(CPU_BOOT_TINFO, secondary_data, thread_info);
+ OFFSET(CPU_BOOT_OFFSET, secondary_data, offset);
BLANK();
}
#endif
diff --git a/arch/loongarch/kernel/entry.S b/arch/loongarch/kernel/entry.S
index b53d333a7c42..53bce27f516b 100644
--- a/arch/loongarch/kernel/entry.S
+++ b/arch/loongarch/kernel/entry.S
@@ -67,8 +67,11 @@ SYM_CODE_START(handle_syscall)
#endif
move u0, t0
- LONG_LI tp, ~_THREAD_MASK
- and tp, tp, sp
+ la_abs t1, cpu_tasks
+#ifdef CONFIG_SMP
+ LONG_ADD t1, t1, u0
+#endif
+ LONG_L tp, t1, 0
move a0, sp
bl do_syscall
diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S
index 4eed7bc312a8..601ddd78b233 100644
--- a/arch/loongarch/kernel/head.S
+++ b/arch/loongarch/kernel/head.S
@@ -74,10 +74,11 @@ SYM_CODE_START(kernel_entry) # kernel entry point
/* GPR21 used for percpu base (runtime), initialized as 0 */
move u0, zero
- la.pcrel tp, init_thread_union
- /* Set the SP after an empty pt_regs. */
- PTR_LI sp, (_THREAD_SIZE - PT_SIZE)
- PTR_ADD sp, sp, tp
+ la.pcrel tp, init_task
+ la.pcrel t0, init_stack
+ PTR_LI t1, _THREAD_SIZE
+ PTR_ADD t0, t0, t1
+ PTR_ADDI sp, t0, -PT_SIZE
set_saved_sp sp, t0, t1
#ifdef CONFIG_RELOCATABLE
@@ -86,8 +87,10 @@ SYM_CODE_START(kernel_entry) # kernel entry point
#ifdef CONFIG_RANDOMIZE_BASE
/* Repoint the sp into the new kernel */
- PTR_LI sp, (_THREAD_SIZE - PT_SIZE)
- PTR_ADD sp, sp, tp
+ LONG_LPTR t0, tp, TASK_STACK
+ PTR_LI t1, _THREAD_SIZE
+ PTR_ADD t0, t0, t1
+ PTR_ADDI sp, t0, -PT_SIZE
set_saved_sp sp, t0, t1
/* Jump to the new kernel: new_pc = current_pc + random_offset */
@@ -127,8 +130,9 @@ SYM_CODE_START(smpboot_entry)
csrxchg t0, t1, LOONGARCH_CSR_IMPCTL1
#endif
la.pcrel t0, cpuboot_data
+ ld.d tp, t0, CPU_BOOT_TASK
ld.d sp, t0, CPU_BOOT_STACK
- ld.d tp, t0, CPU_BOOT_TINFO
+ ld.d u0, t0, CPU_BOOT_OFFSET
bl start_secondary
ASM_BUG()
diff --git a/arch/loongarch/kernel/process.c b/arch/loongarch/kernel/process.c
index 5505fc355e1b..baa683fbfc53 100644
--- a/arch/loongarch/kernel/process.c
+++ b/arch/loongarch/kernel/process.c
@@ -60,6 +60,8 @@ unsigned long __stack_chk_guard __read_mostly;
EXPORT_SYMBOL(__stack_chk_guard);
#endif
+DEFINE_PER_CPU(struct task_struct *, cpu_tasks);
+
/*
* Idle related variables and functions
*/
diff --git a/arch/loongarch/kernel/relocate.c b/arch/loongarch/kernel/relocate.c
index 4b61a9632a98..2a42874e5eb7 100644
--- a/arch/loongarch/kernel/relocate.c
+++ b/arch/loongarch/kernel/relocate.c
@@ -313,7 +313,7 @@ unsigned long __init relocate_kernel(void)
reloc_offset += random_offset;
/* The current thread is now within the relocated kernel */
- __current_thread_info = RELOCATED_KASLR(__current_thread_info);
+ current_thread_pointer = RELOCATED_KASLR(current_thread_pointer);
update_reloc_offset(&reloc_offset, random_offset);
}
diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
index 839b23edee87..eaebb52bd36e 100644
--- a/arch/loongarch/kernel/setup.c
+++ b/arch/loongarch/kernel/setup.c
@@ -502,6 +502,8 @@ static __init int arch_reserve_pio_range(void)
{
struct device_node *np;
+ acpi_add_early_pio();
+
for_each_node_by_name(np, "isa") {
struct of_range range;
struct of_range_parser parser;
@@ -593,6 +595,7 @@ void __init setup_arch(char **cmdline_p)
{
cpu_probe();
unwind_init();
+ set_current(current);
init_environ();
efi_init();
diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c
index 50922610758b..5d792256bbb9 100644
--- a/arch/loongarch/kernel/smp.c
+++ b/arch/loongarch/kernel/smp.c
@@ -400,8 +400,9 @@ void loongson_boot_secondary(int cpu, struct task_struct *idle)
pr_info("Booting CPU#%d...\n", cpu);
entry = __pa_symbol((unsigned long)&smpboot_entry);
- cpuboot_data.stack = (unsigned long)__KSTK_TOS(idle);
- cpuboot_data.thread_info = (unsigned long)task_thread_info(idle);
+ cpuboot_data.task = (unsigned long)idle;
+ cpuboot_data.stack = (unsigned long)task_pt_regs(idle);
+ cpuboot_data.offset = per_cpu_offset(cpu);
csr_mail_send(entry, cpu_logical_map(cpu), 0);
@@ -663,6 +664,7 @@ asmlinkage void start_secondary(void)
set_my_cpu_offset(per_cpu_offset(cpu));
cpu_probe();
+ set_current(current);
constant_clockevent_init();
loongson_init_secondary();
@@ -705,6 +707,7 @@ static void stop_this_cpu(void *dummy)
set_cpu_online(smp_processor_id(), false);
calculate_cpu_foreign_map();
local_irq_disable();
+ rcutree_report_cpu_dead();
while (true);
}
diff --git a/arch/loongarch/kernel/switch.S b/arch/loongarch/kernel/switch.S
index f377d8f5c51a..d6e0d05d6fd3 100644
--- a/arch/loongarch/kernel/switch.S
+++ b/arch/loongarch/kernel/switch.S
@@ -12,7 +12,7 @@
/*
* task_struct *__switch_to(task_struct *prev, task_struct *next,
- * struct thread_info *next_ti, void *sched_ra, void *sched_cfa)
+ * void *sched_ra, void *sched_cfa)
*/
.align 5
SYM_FUNC_START(__switch_to)
@@ -24,8 +24,8 @@ SYM_FUNC_START(__switch_to)
LONG_SPTR t1, a0, (THREAD_CSRPRMD - TASK_STRUCT_OFFSET)
cpu_save_nonscratch a0
- LONG_SPTR a3, a0, (THREAD_SCHED_RA - TASK_STRUCT_OFFSET)
- LONG_SPTR a4, a0, (THREAD_SCHED_CFA - TASK_STRUCT_OFFSET)
+ LONG_SPTR a2, a0, (THREAD_SCHED_RA - TASK_STRUCT_OFFSET)
+ LONG_SPTR a3, a0, (THREAD_SCHED_CFA - TASK_STRUCT_OFFSET)
#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_SMP)
la t7, __stack_chk_guard
@@ -33,11 +33,12 @@ SYM_FUNC_START(__switch_to)
LONG_SPTR t8, t7, 0
#endif
- move tp, a2
+ move tp, a1
cpu_restore_nonscratch a1
- li.w t0, _THREAD_SIZE
- PTR_ADD t0, t0, tp
+ LONG_LPTR t0, a1, (TASK_STACK - TASK_STRUCT_OFFSET)
+ PTR_LI t1, _THREAD_SIZE
+ PTR_ADD t0, t0, t1
set_saved_sp t0, t1, t2
LONG_LPTR t1, a1, (THREAD_CSRPRMD - TASK_STRUCT_OFFSET)
@@ -45,6 +46,7 @@ SYM_FUNC_START(__switch_to)
#ifdef CONFIG_32BIT
PTR_ADDI a0, a0, -TASK_STRUCT_OFFSET
+ PTR_ADDI tp, tp, -TASK_STRUCT_OFFSET
#endif
jr ra
SYM_FUNC_END(__switch_to)
diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c
index 5d49b742e3bf..776523747ea3 100644
--- a/arch/loongarch/kernel/traps.c
+++ b/arch/loongarch/kernel/traps.c
@@ -107,6 +107,12 @@ static void show_stacktrace(struct task_struct *task,
unsigned long stackdata;
unsigned long *sp = (unsigned long *)regs->regs[3];
+ if (!task)
+ task = current;
+
+ if (!try_get_task_stack(task))
+ return;
+
printk("%sStack :", loglvl);
i = 0;
while ((unsigned long) sp & (PAGE_SIZE - 1)) {
@@ -129,6 +135,8 @@ static void show_stacktrace(struct task_struct *task,
}
pr_cont("\n");
show_backtrace(task, regs, loglvl, user);
+
+ put_task_stack(task);
}
void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl)
diff --git a/arch/loongarch/mm/pageattr.c b/arch/loongarch/mm/pageattr.c
index f5e910b68229..614ccc7afccb 100644
--- a/arch/loongarch/mm/pageattr.c
+++ b/arch/loongarch/mm/pageattr.c
@@ -234,5 +234,5 @@ int set_direct_map_valid_noflush(struct page *page, unsigned nr, bool valid)
clear = __pgprot(_PAGE_PRESENT | _PAGE_VALID);
}
- return __set_memory(addr, 1, set, clear);
+ return __set_memory(addr, nr, set, clear);
}
diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c
index 058ffbbaad85..ad7e28375aa9 100644
--- a/arch/loongarch/net/bpf_jit.c
+++ b/arch/loongarch/net/bpf_jit.c
@@ -5,11 +5,18 @@
* Copyright (C) 2022 Loongson Technology Corporation Limited
*/
#include <linux/memory.h>
+#include <asm/asm-offsets.h>
#include "bpf_jit.h"
#define LOONGARCH_MAX_REG_ARGS 8
+#define LOONGARCH_SAVE_RA_NINSNS 1
#define LOONGARCH_LONG_JUMP_NINSNS 5
+#define LOONGARCH_TCC_SLOT_NINSNS 1
+
+#define LOONGARCH_PROLOGUE_SKIP_INSNS \
+ (LOONGARCH_SAVE_RA_NINSNS + LOONGARCH_LONG_JUMP_NINSNS + LOONGARCH_TCC_SLOT_NINSNS)
+
#define LOONGARCH_LONG_JUMP_NBYTES (LOONGARCH_LONG_JUMP_NINSNS * 4)
#define LOONGARCH_FENTRY_NINSNS 2
@@ -143,8 +150,13 @@ static void build_prologue(struct jit_ctx *ctx)
stack_adjust = round_up(stack_adjust, 16);
stack_adjust += bpf_stack_adjust;
+ /*
+ * Save the original return address to a temporary register to prevent
+ * it from being overwritten, then reserve space for the long jump and
+ * fentry trampoline slot for dynamically patching by ftrace at runtime.
+ * These instructions are bypassed during a tail call invocation.
+ */
move_reg(ctx, LOONGARCH_GPR_T0, LOONGARCH_GPR_RA);
- /* Reserve space for the move_imm + jirl instruction */
for (i = 0; i < LOONGARCH_LONG_JUMP_NINSNS; i++)
emit_insn(ctx, nop);
@@ -253,10 +265,11 @@ static void __build_epilogue(struct jit_ctx *ctx, bool is_tail_call)
emit_insn(ctx, jirl, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_RA, 0);
} else {
/*
- * Call the next bpf prog and skip the first instruction
- * of TCC initialization.
+ * Tail call to the next BPF program, passing offset in number
+ * of instructions to jirl to bypass the initial setup slots.
*/
- emit_insn(ctx, jirl, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_T3, 7);
+ emit_insn(ctx, jirl, LOONGARCH_GPR_ZERO,
+ LOONGARCH_GPR_T3, LOONGARCH_PROLOGUE_SKIP_INSNS);
}
}
@@ -312,12 +325,12 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx, int insn)
*/
emit_insn(ctx, ldd, REG_TCC, LOONGARCH_GPR_SP, tcc_ptr_off);
emit_insn(ctx, ldd, t3, REG_TCC, 0);
- emit_insn(ctx, addid, t3, t3, 1);
- emit_insn(ctx, std, t3, REG_TCC, 0);
emit_insn(ctx, addid, t2, LOONGARCH_GPR_ZERO, MAX_TAIL_CALL_CNT);
- if (emit_tailcall_jmp(ctx, BPF_JSGT, t3, t2, jmp_offset) < 0)
+ if (emit_tailcall_jmp(ctx, BPF_JSGE, t3, t2, jmp_offset) < 0)
goto toofar;
+ emit_insn(ctx, addid, t3, t3, 1);
+
/*
* prog = array->ptrs[index];
* if (!prog)
@@ -330,6 +343,8 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx, int insn)
if (emit_tailcall_jmp(ctx, BPF_JEQ, t2, LOONGARCH_GPR_ZERO, jmp_offset) < 0)
goto toofar;
+ emit_insn(ctx, std, t3, REG_TCC, 0);
+
/* goto *(prog->bpf_func + 4); */
off = offsetof(struct bpf_prog, bpf_func);
emit_insn(ctx, ldd, t3, t2, off);
@@ -1147,6 +1162,19 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
/* function call */
case BPF_JMP | BPF_CALL:
+ /* Implement helper call to bpf_get_current_task/_btf() inline */
+ if (insn->src_reg == 0 && (insn->imm == BPF_FUNC_get_current_task ||
+ insn->imm == BPF_FUNC_get_current_task_btf)) {
+ move_reg(ctx, regmap[BPF_REG_0], LOONGARCH_GPR_TP);
+ break;
+ }
+
+ /* Implement helper call to bpf_get_smp_processor_id() inline */
+ if (insn->src_reg == 0 && insn->imm == BPF_FUNC_get_smp_processor_id) {
+ emit_insn(ctx, ldwu, regmap[BPF_REG_0], LOONGARCH_GPR_TP, TI_CPU);
+ break;
+ }
+
ret = bpf_jit_get_func_addr(ctx->prog, insn, extra_pass,
&func_addr, &func_addr_fixed);
if (ret < 0)
@@ -2367,3 +2395,15 @@ bool bpf_jit_supports_subprog_tailcalls(void)
{
return true;
}
+
+bool bpf_jit_inlines_helper_call(s32 imm)
+{
+ switch (imm) {
+ case BPF_FUNC_get_current_task:
+ case BPF_FUNC_get_current_task_btf:
+ case BPF_FUNC_get_smp_processor_id:
+ return true;
+ default:
+ return false;
+ }
+}
diff --git a/arch/loongarch/pci/acpi.c b/arch/loongarch/pci/acpi.c
index b02698a338ee..ccbcea61fcd9 100644
--- a/arch/loongarch/pci/acpi.c
+++ b/arch/loongarch/pci/acpi.c
@@ -65,6 +65,8 @@ static int acpi_prepare_root_resources(struct acpi_pci_root_info *ci)
struct resource_entry *entry, *tmp;
struct acpi_device *device = ci->bridge;
+ acpi_remove_early_pio();
+
status = acpi_pci_probe_root_resources(ci);
if (status > 0) {
acpi_evaluate_integer(device->handle, "PCIH", NULL, &pci_h);
diff --git a/arch/loongarch/vdso/elf.S b/arch/loongarch/vdso/elf.S
index 9bb21b9f9583..d6e000003b85 100644
--- a/arch/loongarch/vdso/elf.S
+++ b/arch/loongarch/vdso/elf.S
@@ -7,9 +7,12 @@
#include <asm/vdso/vdso.h>
+#include <linux/build-salt.h>
#include <linux/elfnote.h>
#include <linux/version.h>
ELFNOTE_START(Linux, 0, "a")
.long LINUX_VERSION_CODE
ELFNOTE_END
+
+BUILD_SALT
diff --git a/drivers/accel/amdxdna/amdxdna_gem.c b/drivers/accel/amdxdna/amdxdna_gem.c
index 63976c3bcbe0..891112c2cddf 100644
--- a/drivers/accel/amdxdna/amdxdna_gem.c
+++ b/drivers/accel/amdxdna/amdxdna_gem.c
@@ -1300,7 +1300,7 @@ int amdxdna_drm_sync_bo_ioctl(struct drm_device *dev,
args->handle, args->offset, args->size);
if (args->direction == SYNC_DIRECT_FROM_DEVICE)
- ret = amdxdna_hwctx_sync_debug_bo(abo->client, args->handle);
+ ret = amdxdna_hwctx_sync_debug_bo(client, args->handle);
put_obj:
drm_gem_object_put(gobj);
diff --git a/drivers/accel/ivpu/ivpu_job.c b/drivers/accel/ivpu/ivpu_job.c
index 521931d1f7fc..b24f31a8b567 100644
--- a/drivers/accel/ivpu/ivpu_job.c
+++ b/drivers/accel/ivpu/ivpu_job.c
@@ -208,9 +208,9 @@ static int ivpu_hws_cmdq_init(struct ivpu_file_priv *file_priv, struct ivpu_cmdq
ret = ivpu_jsm_hws_set_context_sched_properties(vdev, file_priv->ctx.id, cmdq->id,
priority);
if (ret)
- return ret;
+ ivpu_jsm_hws_destroy_cmdq(vdev, file_priv->ctx.id, cmdq->id);
- return 0;
+ return ret;
}
static int ivpu_register_db(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq)
@@ -281,10 +281,10 @@ static int ivpu_cmdq_register(struct ivpu_file_priv *file_priv, struct ivpu_cmdq
}
ret = ivpu_register_db(file_priv, cmdq);
- if (ret)
- return ret;
+ if (ret && vdev->fw->sched_mode == VPU_SCHEDULING_MODE_HW)
+ ivpu_jsm_hws_destroy_cmdq(vdev, file_priv->ctx.id, cmdq->id);
- return 0;
+ return ret;
}
static int ivpu_cmdq_unregister(struct ivpu_file_priv *file_priv, struct ivpu_cmdq *cmdq)
diff --git a/drivers/acpi/acpi_ipmi.c b/drivers/acpi/acpi_ipmi.c
index 79ce6e72bf29..2dbed92d54b3 100644
--- a/drivers/acpi/acpi_ipmi.c
+++ b/drivers/acpi/acpi_ipmi.c
@@ -490,7 +490,7 @@ static void ipmi_bmc_gone(int iface)
mutex_lock(&driver_data.ipmi_lock);
list_for_each_entry_safe(iter, temp,
&driver_data.ipmi_devices, head) {
- if (iter->ipmi_ifnum != iface) {
+ if (iter->ipmi_ifnum == iface) {
ipmi_device = iter;
__ipmi_dev_kill(iter);
break;
diff --git a/drivers/acpi/acpica/utnonansi.c b/drivers/acpi/acpica/utnonansi.c
index 3a7952be6545..93867ad7f342 100644
--- a/drivers/acpi/acpica/utnonansi.c
+++ b/drivers/acpi/acpica/utnonansi.c
@@ -168,7 +168,16 @@ void acpi_ut_safe_strncpy(char *dest, char *source, acpi_size dest_size)
{
/* Always terminate destination string */
+#ifdef __KERNEL__
strscpy_pad(dest, source, dest_size);
+#else
+ /*
+ * strscpy_pad() is not defined in ACPICA tools builds, so use strncpy()
+ * and directly NUL-terminate the destination string in that case.
+ */
+ strncpy(dest, source, dest_size);
+ dest[dest_size - 1] = 0;
+#endif
}
#endif
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 390ab5f1d313..4482cf28f56a 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -1143,7 +1143,7 @@ static int acpi_processor_get_lpi_info(struct acpi_processor *pr)
return 0;
}
-int __weak acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
+int __weak __cpuidle acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
{
return -ENODEV;
}
@@ -1156,7 +1156,7 @@ int __weak acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
*
* Return: 0 for success or negative value for error
*/
-static int acpi_idle_lpi_enter(struct cpuidle_device *dev,
+static int __cpuidle acpi_idle_lpi_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
struct acpi_processor *pr;
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index bc8050d8a6f5..56df4599d360 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -871,7 +871,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt);
/**
- * acpi_dev_free_resource_list - Free resource from %acpi_dev_get_resources().
+ * acpi_dev_free_resource_list - Free resource from acpi_dev_get_resources().
* @list: The head of the resource list to free.
*/
void acpi_dev_free_resource_list(struct list_head *list)
@@ -991,7 +991,7 @@ static int __acpi_dev_get_resources(struct acpi_device *adev,
*
* The resultant struct resource objects are put on the list pointed to by
* @list, that must be empty initially, as members of struct resource_entry
- * objects. Callers of this routine should use %acpi_dev_free_resource_list() to
+ * objects. Callers of this routine should use acpi_dev_free_resource_list() to
* free that list.
*
* The number of resources in the output list is returned on success, an error
@@ -1032,7 +1032,7 @@ static int is_memory(struct acpi_resource *ares, void *not_used)
* The resultant struct resource objects are put on the list pointed to
* by @list, that must be empty initially, as members of struct
* resource_entry objects. Callers of this routine should use
- * %acpi_dev_free_resource_list() to free that list.
+ * acpi_dev_free_resource_list() to free that list.
*
* The number of resources in the output list is returned on success,
* an error code reflecting the error condition is returned otherwise.
diff --git a/drivers/acpi/riscv/cpuidle.c b/drivers/acpi/riscv/cpuidle.c
index 624f9bbdb58c..c76dbabff702 100644
--- a/drivers/acpi/riscv/cpuidle.c
+++ b/drivers/acpi/riscv/cpuidle.c
@@ -66,7 +66,7 @@ int acpi_processor_ffh_lpi_probe(unsigned int cpu)
return acpi_cpu_init_idle(cpu);
}
-int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
+int __cpuidle acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
{
u32 state = lpi->address;
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index a625de3c3c8b..908cc5c7e643 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -17,12 +17,12 @@
#ifdef CONFIG_ACPI_DEBUG
/*
* ACPI debug sysfs I/F, including:
- * /sys/modules/acpi/parameters/debug_layer
- * /sys/modules/acpi/parameters/debug_level
- * /sys/modules/acpi/parameters/trace_method_name
- * /sys/modules/acpi/parameters/trace_state
- * /sys/modules/acpi/parameters/trace_debug_layer
- * /sys/modules/acpi/parameters/trace_debug_level
+ * /sys/module/acpi/parameters/debug_layer
+ * /sys/module/acpi/parameters/debug_level
+ * /sys/module/acpi/parameters/trace_method_name
+ * /sys/module/acpi/parameters/trace_state
+ * /sys/module/acpi/parameters/trace_debug_layer
+ * /sys/module/acpi/parameters/trace_debug_level
*/
struct acpi_dlayer {
@@ -269,7 +269,7 @@ module_param_call(trace_state, param_set_trace_state, param_get_trace_state,
#endif /* CONFIG_ACPI_DEBUG */
-/* /sys/modules/acpi/parameters/aml_debug_output */
+/* /sys/module/acpi/parameters/aml_debug_output */
module_param_named(aml_debug_output, acpi_gbl_enable_aml_debug_object,
byte, 0644);
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 27616b05111c..aa8f2efed779 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -245,7 +245,7 @@ err_exit:
if (map->cache_ops->exit) {
dev_dbg(map->dev, "Destroying %s cache\n", map->cache_ops->name);
map->lock(map->lock_arg);
- ret = map->cache_ops->exit(map);
+ map->cache_ops->exit(map);
map->unlock(map->lock_arg);
}
err_free_reg_defaults:
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 90c13de47cff..ac90d81aa294 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -580,14 +580,7 @@ static const struct bus_type rbd_bus_type = {
.bus_groups = rbd_bus_groups,
};
-static void rbd_root_dev_release(struct device *dev)
-{
-}
-
-static struct device rbd_root_dev = {
- .init_name = "rbd",
- .release = rbd_root_dev_release,
-};
+static struct device *rbd_root_dev;
static __printf(2, 3)
void rbd_warn(struct rbd_device *rbd_dev, const char *fmt, ...)
@@ -5378,7 +5371,7 @@ static struct rbd_device *__rbd_dev_create(struct rbd_spec *spec)
rbd_dev->dev.bus = &rbd_bus_type;
rbd_dev->dev.type = &rbd_device_type;
- rbd_dev->dev.parent = &rbd_root_dev;
+ rbd_dev->dev.parent = rbd_root_dev;
device_initialize(&rbd_dev->dev);
return rbd_dev;
@@ -7324,15 +7317,13 @@ static int __init rbd_sysfs_init(void)
{
int ret;
- ret = device_register(&rbd_root_dev);
- if (ret < 0) {
- put_device(&rbd_root_dev);
- return ret;
- }
+ rbd_root_dev = root_device_register("rbd");
+ if (IS_ERR(rbd_root_dev))
+ return PTR_ERR(rbd_root_dev);
ret = bus_register(&rbd_bus_type);
if (ret < 0)
- device_unregister(&rbd_root_dev);
+ root_device_unregister(rbd_root_dev);
return ret;
}
@@ -7340,7 +7331,7 @@ static int __init rbd_sysfs_init(void)
static void __exit rbd_sysfs_cleanup(void)
{
bus_unregister(&rbd_bus_type);
- device_unregister(&rbd_root_dev);
+ root_device_unregister(rbd_root_dev);
}
static int __init rbd_slab_init(void)
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index b2efbe9f6acb..1717ce75a907 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -480,6 +480,12 @@ config COMMON_CLK_K210
help
Support for the Canaan Kendryte K210 RISC-V SoC clocks.
+config COMMON_CLK_K230
+ bool "Clock driver for the Canaan Kendryte K230 SoC"
+ depends on ARCH_CANAAN || COMPILE_TEST
+ help
+ Support for the Canaan Kendryte K230 RISC-V SoC clocks.
+
config COMMON_CLK_SP7021
tristate "Clock driver for Sunplus SP7021 SoC"
depends on SOC_SP7021 || COMPILE_TEST
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index a3e2862ebd7e..cc108a75a900 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o
obj-$(CONFIG_COMMON_CLK_K210) += clk-k210.o
+obj-$(CONFIG_COMMON_CLK_K230) += clk-k230.o
obj-$(CONFIG_LMK04832) += clk-lmk04832.o
obj-$(CONFIG_COMMON_CLK_LAN966X) += clk-lan966x.o
obj-$(CONFIG_COMMON_CLK_LOCHNAGAR) += clk-lochnagar.o
@@ -141,7 +142,7 @@ obj-$(CONFIG_COMMON_CLK_PXA) += pxa/
obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/
obj-y += ralink/
obj-y += renesas/
-obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
+obj-$(CONFIG_COMMON_CLK_ROCKCHIP) += rockchip/
obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
obj-$(CONFIG_CLK_SIFIVE) += sifive/
obj-y += socfpga/
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index b618a5e00b00..03a6c31d6aa8 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -180,9 +180,9 @@ static int __init pmc_register_ops(void)
of_node_put(np);
return -ENODEV;
}
- of_node_put(np);
at91_pmc_backup_suspend = of_iomap(np, 0);
+ of_node_put(np);
if (!at91_pmc_backup_suspend) {
pr_warn("%s(): unable to map securam\n", __func__);
return -ENOMEM;
diff --git a/drivers/clk/at91/sam9x7.c b/drivers/clk/at91/sam9x7.c
index 89868a0aeaba..8b52da194849 100644
--- a/drivers/clk/at91/sam9x7.c
+++ b/drivers/clk/at91/sam9x7.c
@@ -387,7 +387,7 @@ static const struct {
{ .n = "dma0_clk", .id = 20, },
{ .n = "uhphs_clk", .id = 22, },
{ .n = "udphs_clk", .id = 23, },
- { .n = "macb0_clk", .id = 24, },
+ { .n = "gmac_clk", .id = 24, },
{ .n = "lcd_clk", .id = 25, },
{ .n = "sdmmc1_clk", .id = 26, },
{ .n = "ssc_clk", .id = 28, },
@@ -420,7 +420,6 @@ static const struct {
{ .n = "lvdsc_clk", .id = 56, },
{ .n = "pit64b1_clk", .id = 58, },
{ .n = "puf_clk", .id = 59, },
- { .n = "gmactsu_clk", .id = 67, },
};
/*
@@ -570,6 +569,15 @@ static const struct {
},
{
+ .n = "gmac_gclk",
+ .id = 24,
+ .pp = { "audiopll_divpmcck", "plla_div2pmcck", },
+ .pp_mux_table = { 6, 8, },
+ .pp_count = 2,
+ .pp_chg_id = INT_MIN,
+ },
+
+ {
.n = "lcd_gclk",
.id = 25,
.r = { .max = 75000000 },
@@ -702,15 +710,6 @@ static const struct {
.pp_count = 1,
.pp_chg_id = INT_MIN,
},
-
- {
- .n = "gmac_gclk",
- .id = 67,
- .pp = { "audiopll_divpmcck", "plla_div2pmcck", },
- .pp_mux_table = { 6, 8, },
- .pp_count = 2,
- .pp_chg_id = INT_MIN,
- },
};
static void __init sam9x7_pmc_setup(struct device_node *np)
diff --git a/drivers/clk/at91/sama7d65.c b/drivers/clk/at91/sama7d65.c
index 7dee2b160ffb..ba8ff413fa2c 100644
--- a/drivers/clk/at91/sama7d65.c
+++ b/drivers/clk/at91/sama7d65.c
@@ -677,6 +677,7 @@ static struct {
{ .n = "uhphs_clk", .p = PCK_PARENT_HW_MCK5, .id = 101, },
{ .n = "dsi_clk", .p = PCK_PARENT_HW_MCK3, .id = 103, },
{ .n = "lvdsc_clk", .p = PCK_PARENT_HW_MCK3, .id = 104, },
+ { .n = "i3cc_clk", .p = PCK_PARENT_HW_MCK8, .id = 105, },
};
/*
diff --git a/drivers/clk/bcm/clk-iproc-asiu.c b/drivers/clk/bcm/clk-iproc-asiu.c
index 819ab1b55df3..56a813227981 100644
--- a/drivers/clk/bcm/clk-iproc-asiu.c
+++ b/drivers/clk/bcm/clk-iproc-asiu.c
@@ -27,8 +27,7 @@ struct iproc_asiu {
void __iomem *div_base;
void __iomem *gate_base;
- struct clk_hw_onecell_data *clk_data;
- struct iproc_asiu_clk *clks;
+ struct iproc_asiu_clk clks[];
};
#define to_asiu_clk(hw) container_of(hw, struct iproc_asiu_clk, hw)
@@ -184,22 +183,19 @@ void __init iproc_asiu_setup(struct device_node *node,
{
int i, ret;
struct iproc_asiu *asiu;
+ struct clk_hw_onecell_data *clk_data;
if (WARN_ON(!gate || !div))
return;
- asiu = kzalloc_obj(*asiu);
+ asiu = kzalloc_flex(*asiu, clks, num_clks);
if (WARN_ON(!asiu))
return;
- asiu->clk_data = kzalloc_flex(*asiu->clk_data, hws, num_clks);
- if (WARN_ON(!asiu->clk_data))
+ clk_data = kzalloc_flex(*clk_data, hws, num_clks);
+ if (WARN_ON(!clk_data))
goto err_clks;
- asiu->clk_data->num = num_clks;
-
- asiu->clks = kzalloc_objs(*asiu->clks, num_clks);
- if (WARN_ON(!asiu->clks))
- goto err_asiu_clks;
+ clk_data->num = num_clks;
asiu->div_base = of_iomap(node, 0);
if (WARN_ON(!asiu->div_base))
@@ -236,11 +232,11 @@ void __init iproc_asiu_setup(struct device_node *node,
ret = clk_hw_register(NULL, &asiu_clk->hw);
if (WARN_ON(ret))
goto err_clk_register;
- asiu->clk_data->hws[i] = &asiu_clk->hw;
+ clk_data->hws[i] = &asiu_clk->hw;
}
ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get,
- asiu->clk_data);
+ clk_data);
if (WARN_ON(ret))
goto err_clk_register;
@@ -248,17 +244,14 @@ void __init iproc_asiu_setup(struct device_node *node,
err_clk_register:
while (--i >= 0)
- clk_hw_unregister(asiu->clk_data->hws[i]);
+ clk_hw_unregister(clk_data->hws[i]);
iounmap(asiu->gate_base);
err_iomap_gate:
iounmap(asiu->div_base);
err_iomap_div:
- kfree(asiu->clks);
-
-err_asiu_clks:
- kfree(asiu->clk_data);
+ kfree(clk_data);
err_clks:
kfree(asiu);
diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c
index fa5ccef73e60..26f76a6db820 100644
--- a/drivers/clk/clk-axi-clkgen.c
+++ b/drivers/clk/clk-axi-clkgen.c
@@ -521,7 +521,7 @@ static int axi_clkgen_setup_limits(struct axi_clkgen *axi_clkgen,
axi_clkgen->limits.fvco_max = 1200000;
axi_clkgen->limits.fpfd_max = 450000;
break;
- case ADI_AXI_FPGA_SPEED_2 ... ADI_AXI_FPGA_SPEED_2LV:
+ case ADI_AXI_FPGA_SPEED_2 ... ADI_AXI_FPGA_SPEED_2MP:
axi_clkgen->limits.fvco_max = 1440000;
axi_clkgen->limits.fpfd_max = 500000;
if (family == ADI_AXI_FPGA_FAMILY_KINTEX || family == ADI_AXI_FPGA_FAMILY_ARTIX) {
@@ -546,6 +546,9 @@ static int axi_clkgen_setup_limits(struct axi_clkgen *axi_clkgen,
if (tech == ADI_AXI_FPGA_TECH_ULTRASCALE_PLUS) {
axi_clkgen->limits.fvco_max = 1600000;
axi_clkgen->limits.fvco_min = 800000;
+ } else if (tech == ADI_AXI_FPGA_TECH_VERSAL) {
+ axi_clkgen->limits.fvco_max = 4320000;
+ axi_clkgen->limits.fvco_min = 2160000;
}
return 0;
diff --git a/drivers/clk/clk-bulk.c b/drivers/clk/clk-bulk.c
index d85dae4bdf89..acd9dff30072 100644
--- a/drivers/clk/clk-bulk.c
+++ b/drivers/clk/clk-bulk.c
@@ -12,7 +12,8 @@
#include <linux/of.h>
#include <linux/slab.h>
-static int __must_check of_clk_bulk_get(struct device_node *np, int num_clks,
+static int __must_check of_clk_bulk_get(struct device *dev,
+ struct device_node *np, int num_clks,
struct clk_bulk_data *clks)
{
int ret;
@@ -28,8 +29,8 @@ static int __must_check of_clk_bulk_get(struct device_node *np, int num_clks,
clks[i].clk = of_clk_get(np, i);
if (IS_ERR(clks[i].clk)) {
ret = PTR_ERR(clks[i].clk);
- pr_err("%pOF: Failed to get clk index: %d ret: %d\n",
- np, i, ret);
+ dev_err_probe(dev, ret, "%pOF: Failed to get clk index: %d (%s)\n",
+ np, i, clks[i].id);
clks[i].clk = NULL;
goto err;
}
@@ -43,7 +44,8 @@ err:
return ret;
}
-static int __must_check of_clk_bulk_get_all(struct device_node *np,
+static int __must_check of_clk_bulk_get_all(struct device *dev,
+ struct device_node *np,
struct clk_bulk_data **clks)
{
struct clk_bulk_data *clk_bulk;
@@ -58,7 +60,7 @@ static int __must_check of_clk_bulk_get_all(struct device_node *np,
if (!clk_bulk)
return -ENOMEM;
- ret = of_clk_bulk_get(np, num_clks, clk_bulk);
+ ret = of_clk_bulk_get(dev, np, num_clks, clk_bulk);
if (ret) {
kfree(clk_bulk);
return ret;
@@ -144,7 +146,7 @@ int __must_check clk_bulk_get_all(struct device *dev,
if (!np)
return 0;
- return of_clk_bulk_get_all(np, clks);
+ return of_clk_bulk_get_all(dev, np, clks);
}
EXPORT_SYMBOL(clk_bulk_get_all);
diff --git a/drivers/clk/clk-k230.c b/drivers/clk/clk-k230.c
new file mode 100644
index 000000000000..cfc437038e4e
--- /dev/null
+++ b/drivers/clk/clk-k230.c
@@ -0,0 +1,2452 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Kendryte Canaan K230 Clock Drivers
+ *
+ * Author: Xukai Wang <kingxukai@zohomail.com>
+ * Author: Troy Mitchell <troymitchell988@gmail.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/iopoll.h>
+#include <linux/platform_device.h>
+#include <linux/rational.h>
+#include <linux/spinlock.h>
+
+#include <dt-bindings/clock/canaan,k230-clk.h>
+
+/* PLL control register bits. */
+#define K230_PLL_BYPASS_ENABLE BIT(19)
+#define K230_PLL_GATE_ENABLE BIT(2)
+#define K230_PLL_GATE_WRITE_ENABLE BIT(18)
+#define K230_PLL_OD_MASK GENMASK(27, 24)
+#define K230_PLL_R_MASK GENMASK(21, 16)
+#define K230_PLL_F_MASK GENMASK(12, 0)
+#define K230_PLL_DIV_REG_OFFSET 0x00
+#define K230_PLL_BYPASS_REG_OFFSET 0x04
+#define K230_PLL_GATE_REG_OFFSET 0x08
+#define K230_PLL_LOCK_REG_OFFSET 0x0C
+
+/* PLL lock register */
+#define K230_PLL_LOCK_STATUS_MASK BIT(0)
+#define K230_PLL_LOCK_TIME_DELAY 400
+#define K230_PLL_LOCK_TIMEOUT 0
+
+/* K230 CLK registers offset */
+#define K230_CLK_AUDIO_CLKDIV_OFFSET 0x34
+#define K230_CLK_PDM_CLKDIV_OFFSET 0x40
+#define K230_CLK_CODEC_ADC_MCLKDIV_OFFSET 0x38
+#define K230_CLK_CODEC_DAC_MCLKDIV_OFFSET 0x3c
+
+#define K230_PLLX_DIV_ADDR(base, idx) \
+ (K230_PLL_DIV_REG_OFFSET + (base) + (idx) * 0x10)
+
+#define K230_PLLX_BYPASS_ADDR(base, idx) \
+ (K230_PLL_BYPASS_REG_OFFSET + (base) + (idx) * 0x10)
+
+#define K230_PLLX_GATE_ADDR(base, idx) \
+ (K230_PLL_GATE_REG_OFFSET + (base) + (idx) * 0x10)
+
+#define K230_PLLX_LOCK_ADDR(base, idx) \
+ (K230_PLL_LOCK_REG_OFFSET + (base) + (idx) * 0x10)
+
+#define K230_CLK_RATE_FORMAT_PNAME(_var, _id, \
+ _mul_min, _mul_max, _mul_shift, _mul_mask, \
+ _div_min, _div_max, _div_shift, _div_mask, \
+ _reg, _bit, _method, _reg2, \
+ _read_only, _flags, \
+ _pname) \
+ static struct k230_clk_rate _var = { \
+ .div_reg_off = _reg, \
+ .mul_reg_off = _reg2, \
+ .id = _id, \
+ .clk = { \
+ .write_enable_bit = _bit, \
+ .mul_min = _mul_min, \
+ .mul_max = _mul_max, \
+ .mul_shift = _mul_shift, \
+ .mul_mask = _mul_mask, \
+ .div_min = _div_min, \
+ .div_max = _div_max, \
+ .div_shift = _div_shift, \
+ .div_mask = _div_mask, \
+ .read_only = _read_only, \
+ .hw.init = CLK_HW_INIT_FW_NAME(#_var, \
+ _pname, &k230_clk_ops_##_method, \
+ _flags), \
+ }, \
+ }
+
+#define K230_CLK_RATE_FORMAT(_var, _id, \
+ _mul_min, _mul_max, _mul_shift, _mul_mask, \
+ _div_min, _div_max, _div_shift, _div_mask, \
+ _reg, _bit, _method, _reg2, \
+ _read_only, _flags, \
+ _phw) \
+ static struct k230_clk_rate _var = { \
+ .div_reg_off = _reg, \
+ .mul_reg_off = _reg2, \
+ .id = _id, \
+ .clk = { \
+ .write_enable_bit = _bit, \
+ .mul_min = _mul_min, \
+ .mul_max = _mul_max, \
+ .mul_shift = _mul_shift, \
+ .mul_mask = _mul_mask, \
+ .div_min = _div_min, \
+ .div_max = _div_max, \
+ .div_shift = _div_shift, \
+ .div_mask = _div_mask, \
+ .read_only = _read_only, \
+ .hw.init = CLK_HW_INIT_HW(#_var, \
+ _phw, &k230_clk_ops_##_method, \
+ _flags), \
+ }, \
+ }
+
+#define K230_CLK_GATE_FORMAT_PNAME(_var, _id, \
+ _reg, _bit, _flags, _gate_flags, \
+ _pname) \
+ static struct k230_clk_gate _var = { \
+ .reg_off = _reg, \
+ .id = _id, \
+ .clk = { \
+ .bit_idx = _bit, \
+ .flags = _gate_flags, \
+ .hw.init = CLK_HW_INIT_FW_NAME(#_var, \
+ _pname, &clk_gate_ops, _flags), \
+ }, \
+ }
+
+#define K230_CLK_GATE_FORMAT(_var, _id, \
+ _reg, _bit, _flags, _gate_flags, \
+ _phw) \
+ static struct k230_clk_gate _var = { \
+ .reg_off = _reg, \
+ .id = _id, \
+ .clk = { \
+ .bit_idx = _bit, \
+ .flags = _gate_flags, \
+ .hw.init = CLK_HW_INIT_HW(#_var, \
+ _phw, &clk_gate_ops, _flags), \
+ }, \
+ }
+
+#define K230_CLK_MUX_FORMAT(_var, _id, \
+ _reg, _shift, _mask, _flags, _mux_flags, _pdata) \
+ static struct k230_clk_mux _var = { \
+ .reg_off = _reg, \
+ .id = _id, \
+ .clk = { \
+ .flags = _mux_flags, \
+ .shift = _shift, \
+ .mask = _mask, \
+ .hw.init = CLK_HW_INIT_PARENTS_DATA(#_var, \
+ _pdata, &clk_mux_ops, _flags), \
+ }, \
+ }
+
+#define K230_CLK_FIXED_FACTOR_FORMAT(_var, \
+ _mul, _div, _flags, \
+ _phw) \
+ static struct clk_fixed_factor _var = { \
+ .mult = _mul, \
+ .div = _div, \
+ .hw.init = CLK_HW_INIT_HW(#_var, \
+ _phw, &clk_fixed_factor_ops, _flags), \
+ }
+
+#define K230_CLK_PLL_FORMAT(_var, _id, _flags, _pname) \
+ static struct k230_pll _var = { \
+ .hw.init = CLK_HW_INIT_FW_NAME(#_var, \
+ _pname, &k230_pll_ops, _flags), \
+ .id = _id, \
+ }
+
+struct k230_pll {
+ struct clk_hw hw;
+ void __iomem *reg;
+ /* ensures mutual exclusion for concurrent register access. */
+ spinlock_t *lock;
+ int id;
+};
+
+#define hw_to_k230_pll(_hw) container_of(_hw, struct k230_pll, hw)
+
+struct k230_clk_rate_self {
+ struct clk_hw hw;
+ void __iomem *reg;
+ bool read_only;
+ u32 write_enable_bit;
+ u32 mul_min;
+ u32 mul_max;
+ u32 mul_shift;
+ u32 mul_mask;
+ u32 div_min;
+ u32 div_max;
+ u32 div_shift;
+ u32 div_mask;
+ /* ensures mutual exclusion for concurrent register access. */
+ spinlock_t *lock;
+};
+
+#define hw_to_k230_clk_rate_self(_hw) container_of(_hw, \
+ struct k230_clk_rate_self, hw)
+
+struct k230_clk_rate {
+ u32 mul_reg_off;
+ u32 div_reg_off;
+ struct k230_clk_rate_self clk;
+ int id;
+};
+
+static inline struct k230_clk_rate *hw_to_k230_clk_rate(struct clk_hw *hw)
+{
+ return container_of(hw_to_k230_clk_rate_self(hw), struct k230_clk_rate,
+ clk);
+}
+
+struct k230_clk_gate {
+ u32 reg_off;
+ struct clk_gate clk;
+ int id;
+};
+
+struct k230_clk_mux {
+ u32 reg_off;
+ struct clk_mux clk;
+ int id;
+};
+
+static int k230_pll_prepare(struct clk_hw *hw);
+static int k230_pll_enable(struct clk_hw *hw);
+static void k230_pll_disable(struct clk_hw *hw);
+static int k230_pll_is_enabled(struct clk_hw *hw);
+static unsigned long k230_pll_get_rate(struct clk_hw *hw, unsigned long parent_rate);
+static int k230_clk_set_rate_mul(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate);
+static int k230_clk_determine_rate_mul(struct clk_hw *hw, struct clk_rate_request *req);
+static unsigned long k230_clk_get_rate_mul(struct clk_hw *hw,
+ unsigned long parent_rate);
+static int k230_clk_set_rate_div(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate);
+static int k230_clk_determine_rate_div(struct clk_hw *hw, struct clk_rate_request *req);
+static unsigned long k230_clk_get_rate_div(struct clk_hw *hw,
+ unsigned long parent_rate);
+static int k230_clk_set_rate_mul_div(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate);
+static int k230_clk_determine_rate_mul_div(struct clk_hw *hw, struct clk_rate_request *req);
+static unsigned long k230_clk_get_rate_mul_div(struct clk_hw *hw,
+ unsigned long parent_rate);
+
+static const struct clk_ops k230_pll_ops = {
+ .prepare = k230_pll_prepare,
+ .enable = k230_pll_enable,
+ .disable = k230_pll_disable,
+ .is_enabled = k230_pll_is_enabled,
+ .recalc_rate = k230_pll_get_rate,
+};
+
+/* clk_ops for clocks whose rate is determined by a configurable multiplier */
+static const struct clk_ops k230_clk_ops_mul = {
+ .set_rate = k230_clk_set_rate_mul,
+ .determine_rate = k230_clk_determine_rate_mul,
+ .recalc_rate = k230_clk_get_rate_mul,
+};
+
+/* clk_ops for clocks whose rate is determined by a configurable divider */
+static const struct clk_ops k230_clk_ops_div = {
+ .set_rate = k230_clk_set_rate_div,
+ .determine_rate = k230_clk_determine_rate_div,
+ .recalc_rate = k230_clk_get_rate_div,
+};
+
+/* clk_ops for clocks whose rate is determined by both a multiplier and a divider */
+static const struct clk_ops k230_clk_ops_mul_div = {
+ .set_rate = k230_clk_set_rate_mul_div,
+ .determine_rate = k230_clk_determine_rate_mul_div,
+ .recalc_rate = k230_clk_get_rate_mul_div,
+};
+
+K230_CLK_PLL_FORMAT(pll0, 0, CLK_IS_CRITICAL, NULL);
+K230_CLK_PLL_FORMAT(pll1, 1, CLK_IS_CRITICAL, NULL);
+K230_CLK_PLL_FORMAT(pll2, 2, CLK_IS_CRITICAL, NULL);
+K230_CLK_PLL_FORMAT(pll3, 3, CLK_IS_CRITICAL, NULL);
+
+static struct k230_pll *k230_plls[] = {
+ &pll0,
+ &pll1,
+ &pll2,
+ &pll3,
+};
+
+K230_CLK_FIXED_FACTOR_FORMAT(pll0_div2, 1, 2, 0, &pll0.hw);
+K230_CLK_FIXED_FACTOR_FORMAT(pll0_div3, 1, 3, 0, &pll0.hw);
+K230_CLK_FIXED_FACTOR_FORMAT(pll0_div4, 1, 4, 0, &pll0.hw);
+K230_CLK_FIXED_FACTOR_FORMAT(pll0_div16, 1, 16, 0, &pll0.hw);
+K230_CLK_FIXED_FACTOR_FORMAT(pll1_div2, 1, 2, 0, &pll1.hw);
+K230_CLK_FIXED_FACTOR_FORMAT(pll1_div3, 1, 3, 0, &pll1.hw);
+K230_CLK_FIXED_FACTOR_FORMAT(pll1_div4, 1, 4, 0, &pll1.hw);
+K230_CLK_FIXED_FACTOR_FORMAT(pll2_div2, 1, 2, 0, &pll2.hw);
+K230_CLK_FIXED_FACTOR_FORMAT(pll2_div3, 1, 3, 0, &pll2.hw);
+K230_CLK_FIXED_FACTOR_FORMAT(pll2_div4, 1, 4, 0, &pll2.hw);
+K230_CLK_FIXED_FACTOR_FORMAT(pll3_div2, 1, 2, 0, &pll3.hw);
+K230_CLK_FIXED_FACTOR_FORMAT(pll3_div3, 1, 3, 0, &pll3.hw);
+K230_CLK_FIXED_FACTOR_FORMAT(pll3_div4, 1, 4, 0, &pll3.hw);
+
+static struct clk_fixed_factor *k230_pll_divs[] = {
+ &pll0_div2,
+ &pll0_div3,
+ &pll0_div4,
+ &pll0_div16,
+ &pll1_div2,
+ &pll1_div3,
+ &pll1_div4,
+ &pll2_div2,
+ &pll2_div3,
+ &pll2_div4,
+ &pll3_div2,
+ &pll3_div3,
+ &pll3_div4,
+};
+
+K230_CLK_GATE_FORMAT(cpu0_src_gate,
+ K230_CPU0_SRC_GATE,
+ 0, 0, CLK_IS_CRITICAL, 0,
+ &pll0_div2.hw);
+
+K230_CLK_RATE_FORMAT(cpu0_src_rate,
+ K230_CPU0_SRC_RATE,
+ 1, 16, 1, 0xF,
+ 16, 16, 0, 0x0,
+ 0x0, 31, mul, 0x0,
+ false, 0,
+ &cpu0_src_gate.clk.hw);
+
+K230_CLK_RATE_FORMAT(cpu0_axi_rate,
+ K230_CPU0_AXI_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 6, 0x7,
+ 0x0, 31, div, 0x0,
+ 0, 0,
+ &cpu0_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(cpu0_plic_gate,
+ K230_CPU0_PLIC_GATE,
+ 0x0, 9, CLK_IS_CRITICAL, 0,
+ &cpu0_src_rate.clk.hw);
+
+K230_CLK_RATE_FORMAT(cpu0_plic_rate,
+ K230_CPU0_PLIC_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 10, 0x7,
+ 0x0, 31, div, 0x0,
+ false, 0,
+ &cpu0_plic_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(cpu0_noc_ddrcp4_gate,
+ K230_CPU0_NOC_DDRCP4_GATE,
+ 0x60, 7, CLK_IS_CRITICAL, 0,
+ &cpu0_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(cpu0_apb_gate,
+ K230_CPU0_APB_GATE,
+ 0x0, 13, CLK_IS_CRITICAL, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(cpu0_apb_rate,
+ K230_CPU0_APB_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 15, 0x7,
+ 0x0, 31, div, 0x0,
+ false, 0,
+ &cpu0_apb_gate.clk.hw);
+
+static const struct clk_parent_data k230_cpu1_src_mux_pdata[] = {
+ { .hw = &pll1_div2.hw, },
+ { .hw = &pll3.hw, },
+ { .hw = &pll0.hw, },
+};
+
+K230_CLK_MUX_FORMAT(cpu1_src_mux,
+ K230_CPU1_SRC_MUX,
+ 0x4, 1, 0x3,
+ 0, 0,
+ k230_cpu1_src_mux_pdata);
+
+K230_CLK_GATE_FORMAT(cpu1_src_gate,
+ K230_CPU1_SRC_GATE,
+ 0x4, 0, CLK_IS_CRITICAL, 0,
+ &cpu1_src_mux.clk.hw);
+
+K230_CLK_RATE_FORMAT(cpu1_src_rate,
+ K230_CPU1_SRC_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 3, 0x7,
+ 0x4, 31, div, 0x0,
+ false, 0,
+ &cpu1_src_gate.clk.hw);
+
+K230_CLK_RATE_FORMAT(cpu1_axi_rate,
+ K230_CPU1_AXI_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 12, 0x7,
+ 0x4, 31, div, 0x0,
+ false, 0,
+ &cpu1_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(cpu1_plic_gate,
+ K230_CPU1_PLIC_GATE,
+ 0x4, 15, CLK_IS_CRITICAL, 0,
+ &cpu1_src_rate.clk.hw);
+
+K230_CLK_RATE_FORMAT(cpu1_plic_rate,
+ K230_CPU1_PLIC_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 16, 0x7,
+ 0x4, 31, div, 0x0,
+ false, 0,
+ &cpu1_plic_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(cpu1_apb_gate,
+ K230_CPU1_APB_GATE,
+ 0x4, 19, CLK_IS_CRITICAL, 0,
+ &pll0_div4.hw);
+
+K230_CLK_GATE_FORMAT_PNAME(pmu_apb_gate,
+ K230_PMU_APB_GATE,
+ 0x10, 0, 0, 0,
+ "osc24m");
+
+K230_CLK_GATE_FORMAT(hs_hclk_high_gate,
+ K230_HS_HCLK_HIGH_GATE,
+ 0x18, 1, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(hs_hclk_high_rate,
+ K230_HS_HCLK_HIGH_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 0, 0x7,
+ 0x1C, 31, div, 0x0,
+ false, 0,
+ &hs_hclk_high_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_hclk_gate,
+ K230_HS_HCLK_GATE,
+ 0x18, 0, 0, 0,
+ &hs_hclk_high_rate.clk.hw);
+
+K230_CLK_RATE_FORMAT(hs_hclk_rate,
+ K230_HS_HCLK_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 3, 0x7,
+ 0x1C, 31, div, 0x0,
+ false, 0,
+ &hs_hclk_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_sd0_ahb_gate,
+ K230_HS_SD0_AHB_GATE,
+ 0x18, 2, 0, 0,
+ &hs_hclk_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_sd1_ahb_gate,
+ K230_HS_SD1_AHB_GATE,
+ 0x18, 3, 0, 0,
+ &hs_hclk_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_ssi1_ahb_gate,
+ K230_HS_SSI1_AHB_GATE,
+ 0x18, 7, 0, 0,
+ &hs_hclk_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_ssi2_ahb_gate,
+ K230_HS_SSI2_AHB_GATE,
+ 0x18, 8, 0, 0,
+ &hs_hclk_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_usb0_ahb_gate,
+ K230_HS_USB0_AHB_GATE,
+ 0x18, 4, 0, 0,
+ &hs_hclk_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_usb1_ahb_gate,
+ K230_HS_USB1_AHB_GATE,
+ 0x18, 5, 0, 0,
+ &hs_hclk_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_ssi0_axi_gate,
+ K230_HS_SSI0_AXI_GATE,
+ 0x18, 27, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(hs_ssi0_axi_rate,
+ K230_HS_SSI0_AXI_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 9, 0x7,
+ 0x20, 31, div, 0x0,
+ false, 0,
+ &hs_ssi0_axi_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_ssi1_gate,
+ K230_HS_SSI1_GATE,
+ 0x18, 25, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(hs_ssi1_rate,
+ K230_HS_SSI1_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 3, 0x7,
+ 0x20, 31, div, 0x0,
+ false, 0,
+ &hs_ssi1_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_ssi2_gate,
+ K230_HS_SSI2_GATE,
+ 0x18, 26, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(hs_ssi2_rate,
+ K230_HS_SSI2_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 6, 0x7,
+ 0x20, 31, div, 0x0,
+ false, 0,
+ &hs_ssi2_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_qspi_axi_src_gate,
+ K230_HS_QSPI_AXI_SRC_GATE,
+ 0x18, 28, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(hs_qspi_axi_src_rate,
+ K230_HS_QSPI_AXI_SRC_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 12, 0x7,
+ 0x20, 31, div, 0x0,
+ false, 0,
+ &hs_qspi_axi_src_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_ssi1_axi_gate,
+ K230_HS_SSI1_AXI_GATE,
+ 0x18, 29, 0, 0,
+ &hs_qspi_axi_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_ssi2_axi_gate,
+ K230_HS_SSI2_AXI_GATE,
+ 0x18, 30, 0, 0,
+ &hs_qspi_axi_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_sd_card_src_gate,
+ K230_HS_SD_CARD_SRC_GATE,
+ 0x18, 11, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(hs_sd_card_src_rate,
+ K230_HS_SD_CARD_SRC_RATE,
+ 1, 1, 0, 0,
+ 2, 8, 12, 0x7,
+ 0x1C, 31, div, 0x0,
+ false, 0,
+ &hs_sd_card_src_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_sd0_card_gate,
+ K230_HS_SD0_CARD_GATE,
+ 0x18, 15, 0, 0,
+ &hs_sd_card_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_sd1_card_gate,
+ K230_HS_SD1_CARD_GATE,
+ 0x18, 19, 0, 0,
+ &hs_sd_card_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_sd_axi_src_gate,
+ K230_HS_SD_AXI_SRC_GATE,
+ 0x18, 9, 0, 0,
+ &pll2_div4.hw);
+
+K230_CLK_RATE_FORMAT(hs_sd_axi_src_rate,
+ K230_HS_SD_AXI_SRC_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 6, 0x7,
+ 0x1C, 31, div, 0x0,
+ false, 0,
+ &hs_sd_axi_src_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_sd0_axi_gate,
+ K230_HS_SD0_AXI_GATE,
+ 0x18, 13, 0, 0,
+ &hs_sd_axi_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_sd1_axi_gate,
+ K230_HS_SD1_AXI_GATE,
+ 0x18, 17, 0, 0,
+ &hs_sd_axi_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_sd0_base_gate,
+ K230_HS_SD0_BASE_GATE,
+ 0x18, 14, 0, 0,
+ &hs_sd_axi_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_sd1_base_gate,
+ K230_HS_SD1_BASE_GATE,
+ 0x18, 18, 0, 0,
+ &hs_sd_axi_src_rate.clk.hw);
+
+static const struct clk_parent_data k230_hs_ssi0_mux_pdata[] = {
+ { .hw = &pll0_div2.hw, },
+ { .hw = &pll2_div4.hw, },
+};
+
+K230_CLK_MUX_FORMAT(hs_ssi0_mux,
+ K230_HS_SSI0_MUX,
+ 0x20, 18, 0x1,
+ 0, 0,
+ k230_hs_ssi0_mux_pdata);
+
+K230_CLK_GATE_FORMAT(hs_ssi0_gate,
+ K230_HS_SSI0_GATE,
+ 0x18, 24, CLK_IGNORE_UNUSED, 0,
+ &hs_ssi0_mux.clk.hw);
+
+K230_CLK_RATE_FORMAT(hs_usb_ref_50m_rate,
+ K230_HS_USB_REF_50M_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 15, 0x7,
+ 0x20, 31, div, 0x0,
+ false, 0,
+ &pll0_div16.hw);
+
+K230_CLK_GATE_FORMAT_PNAME(hs_sd_timer_src_gate,
+ K230_HS_SD_TIMER_SRC_GATE,
+ 0x18, 12, 0, 0,
+ "osc24m");
+
+K230_CLK_RATE_FORMAT(hs_sd_timer_src_rate,
+ K230_HS_SD_TIMER_SRC_RATE,
+ 1, 1, 0, 0,
+ 24, 32, 15, 0x1F,
+ 0x1C, 31, div, 0x0,
+ false, 0,
+ &hs_sd_timer_src_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_sd0_timer_gate,
+ K230_HS_SD0_TIMER_GATE,
+ 0x18, 16, 0, 0,
+ &hs_sd_timer_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_sd1_timer_gate,
+ K230_HS_SD1_TIMER_GATE,
+ 0x18, 20, 0, 0,
+ &hs_sd_timer_src_rate.clk.hw);
+
+static const struct clk_parent_data k230_hs_usb_ref_mux_pdata[] = {
+ { .fw_name = "osc24m", },
+ { .hw = &hs_usb_ref_50m_rate.clk.hw, },
+};
+
+K230_CLK_MUX_FORMAT(hs_usb_ref_mux,
+ K230_HS_USB_REF_MUX,
+ 0x18, 23, 0x1,
+ 0, 0,
+ k230_hs_usb_ref_mux_pdata);
+
+K230_CLK_GATE_FORMAT(hs_usb0_ref_gate,
+ K230_HS_USB0_REF_GATE,
+ 0x18, 21, CLK_IGNORE_UNUSED, 0,
+ &hs_usb_ref_mux.clk.hw);
+
+K230_CLK_GATE_FORMAT(hs_usb1_ref_gate,
+ K230_HS_USB1_REF_GATE,
+ 0x18, 22, CLK_IGNORE_UNUSED, 0,
+ &hs_usb_ref_mux.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_apb_src_gate,
+ K230_LS_APB_SRC_GATE,
+ 0x24, 0, CLK_IS_CRITICAL, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(ls_apb_src_rate,
+ K230_LS_APB_SRC_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 0, 0x7,
+ 0x30, 31, div, 0x0,
+ false, 0,
+ &ls_apb_src_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_uart0_apb_gate,
+ K230_LS_UART0_APB_GATE,
+ 0x24, 1, CLK_IS_CRITICAL, 0,
+ &ls_apb_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_uart1_apb_gate,
+ K230_LS_UART1_APB_GATE,
+ 0x24, 2, CLK_IS_CRITICAL, 0,
+ &ls_apb_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_uart2_apb_gate,
+ K230_LS_UART2_APB_GATE,
+ 0x24, 3, CLK_IS_CRITICAL, 0,
+ &ls_apb_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_uart3_apb_gate,
+ K230_LS_UART3_APB_GATE,
+ 0x24, 4, CLK_IS_CRITICAL, 0,
+ &ls_apb_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_uart4_apb_gate,
+ K230_LS_UART4_APB_GATE,
+ 0x24, 5, CLK_IS_CRITICAL, 0,
+ &ls_apb_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_i2c0_apb_gate,
+ K230_LS_I2C0_APB_GATE,
+ 0x24, 6, 0, 0,
+ &ls_apb_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_i2c1_apb_gate,
+ K230_LS_I2C1_APB_GATE,
+ 0x24, 7, 0, 0,
+ &ls_apb_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_i2c2_apb_gate,
+ K230_LS_I2C2_APB_GATE,
+ 0x24, 8, 0, 0,
+ &ls_apb_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_i2c3_apb_gate,
+ K230_LS_I2C3_APB_GATE,
+ 0x24, 9, 0, 0,
+ &ls_apb_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_i2c4_apb_gate,
+ K230_LS_I2C4_APB_GATE,
+ 0x24, 10, 0, 0,
+ &ls_apb_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_gpio_apb_gate,
+ K230_LS_GPIO_APB_GATE,
+ 0x24, 11, 0, 0,
+ &ls_apb_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_pwm_apb_gate,
+ K230_LS_PWM_APB_GATE,
+ 0x24, 12, 0, 0,
+ &ls_apb_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_jamlink0_apb_gate,
+ K230_LS_JAMLINK0_APB_GATE,
+ 0x28, 4, 0, 0,
+ &ls_apb_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_jamlink1_apb_gate,
+ K230_LS_JAMLINK1_APB_GATE,
+ 0x28, 5, 0, 0,
+ &ls_apb_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_jamlink2_apb_gate,
+ K230_LS_JAMLINK2_APB_GATE,
+ 0x28, 6, 0, 0,
+ &ls_apb_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_jamlink3_apb_gate,
+ K230_LS_JAMLINK3_APB_GATE,
+ 0x28, 7, 0, 0,
+ &ls_apb_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_audio_apb_gate,
+ K230_LS_AUDIO_APB_GATE,
+ 0x24, 13, 0, 0,
+ &ls_apb_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_adc_apb_gate,
+ K230_LS_ADC_APB_GATE,
+ 0x24, 15, 0, 0,
+ &ls_apb_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_codec_apb_gate,
+ K230_LS_CODEC_APB_GATE,
+ 0x24, 14, 0, 0,
+ &ls_apb_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_i2c0_gate,
+ K230_LS_I2C0_GATE,
+ 0x24, 21, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(ls_i2c0_rate,
+ K230_LS_I2C0_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 15, 0x7,
+ 0x2C, 31, div, 0x0,
+ false, 0,
+ &ls_i2c0_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_i2c1_gate,
+ K230_LS_I2C1_GATE,
+ 0x24, 22, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(ls_i2c1_rate,
+ K230_LS_I2C1_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 18, 0x7,
+ 0x2C, 31, div, 0x0,
+ false, 0,
+ &ls_i2c1_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_i2c2_gate,
+ K230_LS_I2C2_GATE,
+ 0x24, 23, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(ls_i2c2_rate,
+ K230_LS_I2C2_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 21, 0x7,
+ 0x2C, 31, div, 0x0,
+ false, 0,
+ &ls_i2c2_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_i2c3_gate,
+ K230_LS_I2C3_GATE,
+ 0x24, 24, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(ls_i2c3_rate,
+ K230_LS_I2C3_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 24, 0x7,
+ 0x2C, 31, div, 0x0,
+ false, 0,
+ &ls_i2c3_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_i2c4_gate,
+ K230_LS_I2C4_GATE,
+ 0x24, 25, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(ls_i2c4_rate,
+ K230_LS_I2C4_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 27, 0x7,
+ 0x2C, 31, div, 0x0,
+ false, 0,
+ &ls_i2c4_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_codec_adc_gate,
+ K230_LS_CODEC_ADC_GATE,
+ 0x24, 29, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(ls_codec_adc_rate,
+ K230_LS_CODEC_ADC_RATE,
+ 0x10, 0x1B9, 14, 0x1FFF,
+ 0xC35, 0x3D09, 0, 0x3FFF,
+ 0x38, 31, mul_div, 0x38,
+ false, 0,
+ &ls_codec_adc_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_codec_dac_gate,
+ K230_LS_CODEC_DAC_GATE,
+ 0x24, 30, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(ls_codec_dac_rate,
+ K230_LS_CODEC_DAC_RATE,
+ 0x10, 0x1B9, 14, 0x1FFF,
+ 0xC35, 0x3D09, 0, 0x3FFF,
+ 0x3C, 31, mul_div, 0x3C,
+ false, 0,
+ &ls_codec_dac_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_audio_dev_gate,
+ K230_LS_AUDIO_DEV_GATE,
+ 0x24, 28, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(ls_audio_dev_rate,
+ K230_LS_AUDIO_DEV_RATE,
+ 0x4, 0x1B9, 16, 0x7FFF,
+ 0xC35, 0xF424, 0, 0xFFFF,
+ 0x34, 31, mul_div, 0x34,
+ false, 0,
+ &ls_audio_dev_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_pdm_gate,
+ K230_LS_PDM_GATE,
+ 0x24, 31, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(ls_pdm_rate,
+ K230_LS_PDM_RATE,
+ 0x2, 0x1B9, 0, 0xFFFF,
+ 0xC35, 0x1E848, 0, 0x1FFFF,
+ 0x40, 0, mul_div, 0x44,
+ false, 0,
+ &ls_pdm_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_adc_gate,
+ K230_LS_ADC_GATE,
+ 0x24, 26, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(ls_adc_rate,
+ K230_LS_ADC_RATE,
+ 1, 1, 0, 0,
+ 1, 1024, 3, 0x3FF,
+ 0x30, 31, div, 0x0,
+ false, 0,
+ &ls_adc_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_uart0_gate,
+ K230_LS_UART0_GATE,
+ 0x24, 16, CLK_IS_CRITICAL, 0,
+ &pll0_div16.hw);
+
+K230_CLK_RATE_FORMAT(ls_uart0_rate,
+ K230_LS_UART0_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 0, 0x7,
+ 0x2C, 31, div, 0x0,
+ false, 0,
+ &ls_uart0_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_uart1_gate,
+ K230_LS_UART1_GATE,
+ 0x24, 17, CLK_IS_CRITICAL, 0,
+ &pll0_div16.hw);
+
+K230_CLK_RATE_FORMAT(ls_uart1_rate,
+ K230_LS_UART1_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 3, 0x7,
+ 0x2C, 31, div, 0x0,
+ false, 0,
+ &ls_uart1_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_uart2_gate,
+ K230_LS_UART2_GATE,
+ 0x24, 18, CLK_IS_CRITICAL, 0,
+ &pll0_div16.hw);
+
+K230_CLK_RATE_FORMAT(ls_uart2_rate,
+ K230_LS_UART2_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 6, 0x7,
+ 0x2C, 31, div, 0x0,
+ false, 0,
+ &ls_uart2_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_uart3_gate,
+ K230_LS_UART3_GATE,
+ 0x24, 19, CLK_IS_CRITICAL, 0,
+ &pll0_div16.hw);
+
+K230_CLK_RATE_FORMAT(ls_uart3_rate,
+ K230_LS_UART3_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 9, 0x7,
+ 0x2C, 31, div, 0x0,
+ false, 0,
+ &ls_uart3_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_uart4_gate,
+ K230_LS_UART4_GATE,
+ 0x24, 20, CLK_IS_CRITICAL, 0,
+ &pll0_div16.hw);
+
+K230_CLK_RATE_FORMAT(ls_uart4_rate,
+ K230_LS_UART4_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 12, 0x7,
+ 0x2C, 31, div, 0x0,
+ false, 0,
+ &ls_uart4_gate.clk.hw);
+
+K230_CLK_RATE_FORMAT(ls_jamlinkco_src_rate,
+ K230_LS_JAMLINKCO_SRC_RATE,
+ 1, 1, 0, 0,
+ 2, 512, 23, 0xFF,
+ 0x30, 31, div, 0x0,
+ false, 0,
+ &pll0_div16.hw);
+
+K230_CLK_GATE_FORMAT(ls_jamlink0co_gate,
+ K230_LS_JAMLINK0CO_GATE,
+ 0x28, 0, 0, 0,
+ &ls_jamlinkco_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_jamlink1co_gate,
+ K230_LS_JAMLINK1CO_GATE,
+ 0x28, 1, 0, 0,
+ &ls_jamlinkco_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_jamlink2co_gate,
+ K230_LS_JAMLINK2CO_GATE,
+ 0x28, 2, 0, 0,
+ &ls_jamlinkco_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ls_jamlink3co_gate,
+ K230_LS_JAMLINK3CO_GATE,
+ 0x28, 3, 0, 0,
+ &ls_jamlinkco_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT_PNAME(ls_gpio_debounce_gate,
+ K230_LS_GPIO_DEBOUNCE_GATE,
+ 0x24, 27, 0, 0,
+ "osc24m");
+
+K230_CLK_RATE_FORMAT(ls_gpio_debounce_rate,
+ K230_LS_GPIO_DEBOUNCE_RATE,
+ 1, 1, 0, 0,
+ 1, 1024, 13, 0x3FF,
+ 0x30, 31, div, 0x0,
+ false, 0,
+ &ls_gpio_debounce_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(sysctl_wdt0_apb_gate,
+ K230_SYSCTL_WDT0_APB_GATE,
+ 0x50, 1, 0, 0,
+ &pll0_div16.hw);
+
+K230_CLK_GATE_FORMAT(sysctl_wdt1_apb_gate,
+ K230_SYSCTL_WDT1_APB_GATE,
+ 0x50, 2, 0, 0,
+ &pll0_div16.hw);
+
+K230_CLK_GATE_FORMAT(sysctl_timer_apb_gate,
+ K230_SYSCTL_TIMER_APB_GATE,
+ 0x50, 3, 0, 0,
+ &pll0_div16.hw);
+
+K230_CLK_GATE_FORMAT(sysctl_iomux_apb_gate,
+ K230_SYSCTL_IOMUX_APB_GATE,
+ 0x50, 20, 0, 0,
+ &pll0_div16.hw);
+
+K230_CLK_GATE_FORMAT(sysctl_mailbox_apb_gate,
+ K230_SYSCTL_MAILBOX_APB_GATE,
+ 0x50, 4, 0, 0,
+ &pll0_div16.hw);
+
+K230_CLK_GATE_FORMAT(sysctl_hdi_gate,
+ K230_SYSCTL_HDI_GATE,
+ 0x50, 21, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(sysctl_hdi_rate,
+ K230_SYSCTL_HDI_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 28, 0x7,
+ 0x58, 31, div, 0x0,
+ false, 0,
+ &sysctl_hdi_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(sysctl_time_stamp_gate,
+ K230_SYSCTL_TIME_STAMP_GATE,
+ 0x50, 19, CLK_IS_CRITICAL, 0,
+ &pll1_div4.hw);
+
+K230_CLK_RATE_FORMAT(sysctl_time_stamp_rate,
+ K230_SYSCTL_TIME_STAMP_RATE,
+ 1, 1, 0, 0,
+ 1, 32, 15, 0x1F,
+ 0x58, 31, div, 0x0,
+ false, 0,
+ &sysctl_time_stamp_gate.clk.hw);
+
+K230_CLK_RATE_FORMAT_PNAME(sysctl_temp_sensor_rate,
+ K230_SYSCTL_TEMP_SENSOR_RATE,
+ 1, 1, 0, 0,
+ 1, 256, 20, 0xFF,
+ 0x58, 31, div, 0x0,
+ false, 0,
+ "osc24m");
+
+K230_CLK_GATE_FORMAT_PNAME(sysctl_wdt0_gate,
+ K230_SYSCTL_WDT0_GATE,
+ 0x50, 5, 0, 0,
+ "osc24m");
+
+K230_CLK_RATE_FORMAT(sysctl_wdt0_rate,
+ K230_SYSCTL_WDT0_RATE,
+ 1, 1, 0, 0,
+ 1, 64, 3, 0x3F,
+ 0x58, 31, div, 0x0,
+ false, 0,
+ &sysctl_wdt0_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT_PNAME(sysctl_wdt1_gate,
+ K230_SYSCTL_WDT1_GATE,
+ 0x50, 6, 0, 0,
+ "osc24m");
+
+K230_CLK_RATE_FORMAT(sysctl_wdt1_rate,
+ K230_SYSCTL_WDT1_RATE,
+ 1, 1, 0, 0,
+ 1, 64, 9, 0x3F,
+ 0x58, 31, div, 0x0,
+ false, 0,
+ &sysctl_wdt1_gate.clk.hw);
+
+K230_CLK_RATE_FORMAT(timer0_src_rate,
+ K230_TIMER0_SRC_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 0, 0x7,
+ 0x54, 31, div, 0x0,
+ false, 0,
+ &pll0_div16.hw);
+
+K230_CLK_RATE_FORMAT(timer1_src_rate,
+ K230_TIMER1_SRC_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 3, 0x7,
+ 0x54, 31, div, 0x0,
+ false, 0,
+ &pll0_div16.hw);
+
+K230_CLK_RATE_FORMAT(timer2_src_rate,
+ K230_TIMER2_SRC_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 6, 0x7,
+ 0x54, 31, div, 0x0,
+ false, 0,
+ &pll0_div16.hw);
+
+K230_CLK_RATE_FORMAT(timer3_src_rate,
+ K230_TIMER3_SRC_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 9, 0x7,
+ 0x54, 31, div, 0x0,
+ false, 0,
+ &pll0_div16.hw);
+
+K230_CLK_RATE_FORMAT(timer4_src_rate,
+ K230_TIMER4_SRC_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 12, 0x7,
+ 0x54, 31, div, 0x0,
+ false, 0,
+ &pll0_div16.hw);
+
+K230_CLK_RATE_FORMAT(timer5_src_rate,
+ K230_TIMER5_SRC_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 15, 0x7,
+ 0x54, 31, div, 0x0,
+ false, 0,
+ &pll0_div16.hw);
+
+static const struct clk_parent_data k230_timer0_mux_pdata[] = {
+ { .fw_name = "timer-pulse-in", },
+ { .hw = &timer0_src_rate.clk.hw, },
+};
+
+K230_CLK_MUX_FORMAT(timer0_mux,
+ K230_TIMER0_MUX,
+ 0x50, 7, 0x1,
+ 0, 0,
+ k230_timer0_mux_pdata);
+
+K230_CLK_GATE_FORMAT(timer0_gate,
+ K230_TIMER0_GATE,
+ 0x50, 13, CLK_IGNORE_UNUSED, 0,
+ &timer0_mux.clk.hw);
+
+static const struct clk_parent_data k230_timer1_mux_pdata[] = {
+ { .fw_name = "timer-pulse-in", },
+ { .hw = &timer1_src_rate.clk.hw, },
+};
+
+K230_CLK_MUX_FORMAT(timer1_mux,
+ K230_TIMER1_MUX,
+ 0x50, 8, 0x1,
+ 0, 0,
+ k230_timer1_mux_pdata);
+
+K230_CLK_GATE_FORMAT(timer1_gate,
+ K230_TIMER1_GATE,
+ 0x50, 14, CLK_IGNORE_UNUSED, 0,
+ &timer1_mux.clk.hw);
+
+static const struct clk_parent_data k230_timer2_mux_pdata[] = {
+ { .fw_name = "timer-pulse-in", },
+ { .hw = &timer2_src_rate.clk.hw, },
+};
+
+K230_CLK_MUX_FORMAT(timer2_mux,
+ K230_TIMER2_MUX,
+ 0x50, 9, 0x1,
+ 0, 0,
+ k230_timer2_mux_pdata);
+
+K230_CLK_GATE_FORMAT(timer2_gate,
+ K230_TIMER2_GATE,
+ 0x50, 15, CLK_IGNORE_UNUSED, 0,
+ &timer2_mux.clk.hw);
+
+static const struct clk_parent_data k230_timer3_mux_pdata[] = {
+ { .fw_name = "timer-pulse-in", },
+ { .hw = &timer3_src_rate.clk.hw, },
+};
+
+K230_CLK_MUX_FORMAT(timer3_mux,
+ K230_TIMER3_MUX,
+ 0x50, 10, 0x1,
+ 0, 0,
+ k230_timer3_mux_pdata);
+
+K230_CLK_GATE_FORMAT(timer3_gate,
+ K230_TIMER3_GATE,
+ 0x50, 16, CLK_IGNORE_UNUSED, 0,
+ &timer3_mux.clk.hw);
+
+static const struct clk_parent_data k230_timer4_mux_pdata[] = {
+ { .fw_name = "timer-pulse-in", },
+ { .hw = &timer4_src_rate.clk.hw, },
+};
+
+K230_CLK_MUX_FORMAT(timer4_mux,
+ K230_TIMER4_MUX,
+ 0x50, 11, 0x1,
+ 0, 0,
+ k230_timer4_mux_pdata);
+
+K230_CLK_GATE_FORMAT(timer4_gate,
+ K230_TIMER4_GATE,
+ 0x50, 17, CLK_IGNORE_UNUSED, 0,
+ &timer4_mux.clk.hw);
+
+static const struct clk_parent_data k230_timer5_mux_pdata[] = {
+ { .fw_name = "timer-pulse-in", },
+ { .hw = &timer5_src_rate.clk.hw, },
+};
+
+K230_CLK_MUX_FORMAT(timer5_mux,
+ K230_TIMER5_MUX,
+ 0x50, 12, 0x1,
+ 0, 0,
+ k230_timer5_mux_pdata);
+
+K230_CLK_GATE_FORMAT(timer5_gate,
+ K230_TIMER5_GATE,
+ 0x50, 18, CLK_IGNORE_UNUSED, 0,
+ &timer5_mux.clk.hw);
+
+K230_CLK_GATE_FORMAT(shrm_apb_gate,
+ K230_SHRM_APB_GATE,
+ 0x5C, 0, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(shrm_apb_rate,
+ K230_SHRM_APB_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 18, 0x7,
+ 0x5C, 31, div, 0x0,
+ false, 0,
+ &shrm_apb_gate.clk.hw);
+
+static const struct clk_parent_data k230_shrm_sram_mux_pdata[] = {
+ { .hw = &pll3_div2.hw, },
+ { .hw = &pll0_div2.hw, },
+};
+
+K230_CLK_MUX_FORMAT(shrm_sram_mux,
+ K230_SHRM_SRAM_MUX,
+ 0x50, 14, 0x1,
+ 0, 0,
+ k230_shrm_sram_mux_pdata);
+
+K230_CLK_GATE_FORMAT(shrm_sram_gate,
+ K230_SHRM_SRAM_GATE,
+ 0x5c, 10, CLK_IGNORE_UNUSED, 0,
+ &shrm_sram_mux.clk.hw);
+
+K230_CLK_FIXED_FACTOR_FORMAT(shrm_sram_div2,
+ 1, 2, 0,
+ &shrm_sram_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(shrm_axi_slave_gate,
+ K230_SHRM_AXI_SLAVE_GATE,
+ 0x5C, 11, CLK_IGNORE_UNUSED, 0,
+ &shrm_sram_div2.hw);
+
+K230_CLK_GATE_FORMAT(shrm_axi_gate,
+ K230_SHRM_AXI_GATE,
+ 0x5C, 12, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_GATE_FORMAT(shrm_nonai2d_axi_gate,
+ K230_SHRM_NONAI2D_AXI_GATE,
+ 0x5C, 9, 0, 0,
+ &shrm_axi_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(shrm_decompress_axi_gate,
+ K230_SHRM_DECOMPRESS_AXI_GATE,
+ 0x5C, 7, CLK_IGNORE_UNUSED, 0,
+ &shrm_sram_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(shrm_sdma_axi_gate,
+ K230_SHRM_SDMA_AXI_GATE,
+ 0x5C, 5, 0, 0,
+ &shrm_axi_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(shrm_pdma_axi_gate,
+ K230_SHRM_PDMA_AXI_GATE,
+ 0x5C, 3, 0, 0,
+ &shrm_axi_gate.clk.hw);
+
+static const struct clk_parent_data k230_ddrc_src_mux_pdata[] = {
+ { .hw = &pll0_div2.hw, },
+ { .hw = &pll0_div3.hw, },
+ { .hw = &pll2_div4.hw, },
+};
+
+K230_CLK_MUX_FORMAT(ddrc_src_mux,
+ K230_DDRC_SRC_MUX,
+ 0x60, 0, 0x3,
+ 0, 0,
+ k230_ddrc_src_mux_pdata);
+
+K230_CLK_GATE_FORMAT(ddrc_src_gate,
+ K230_DDRC_SRC_GATE,
+ 0x60, 2, CLK_IGNORE_UNUSED, 0,
+ &ddrc_src_mux.clk.hw);
+
+K230_CLK_RATE_FORMAT(ddrc_src_rate,
+ K230_DDRC_SRC_RATE,
+ 1, 1, 0, 0,
+ 1, 16, 10, 0xF,
+ 0x60, 31, div, 0x0,
+ false, 0,
+ &ddrc_src_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ddrc_bypass_gate,
+ K230_DDRC_BYPASS_GATE,
+ 0x60, 8, 0, 0,
+ &pll2_div4.hw);
+
+K230_CLK_GATE_FORMAT(ddrc_apb_gate,
+ K230_DDRC_APB_GATE,
+ 0x60, 9, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(ddrc_apb_rate,
+ K230_DDRC_APB_RATE,
+ 1, 1, 0, 0,
+ 1, 16, 14, 0xF,
+ 0x60, 31, div, 0x0,
+ false, 0,
+ &ddrc_apb_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(display_ahb_gate,
+ K230_DISPLAY_AHB_GATE,
+ 0x74, 0, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(display_ahb_rate,
+ K230_DISPLAY_AHB_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 0, 0x7,
+ 0x78, 31, div, 0x0,
+ false, 0,
+ &display_ahb_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(display_axi_gate,
+ K230_DISPLAY_AXI_GATE,
+ 0x74, 1, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(display_clkext_rate,
+ K230_DISPLAY_CLKEXT_RATE,
+ 1, 1, 0, 0,
+ 1, 16, 16, 0xF,
+ 0x78, 31, div, 0x0,
+ false, 0,
+ &pll0_div3.hw);
+
+K230_CLK_GATE_FORMAT(display_gpu_gate,
+ K230_DISPLAY_GPU_GATE,
+ 0x74, 6, 0, 0,
+ &pll0_div3.hw);
+
+K230_CLK_RATE_FORMAT(display_gpu_rate,
+ K230_DISPLAY_GPU_RATE,
+ 1, 1, 0, 0,
+ 1, 16, 20, 0xF,
+ 0x78, 31, div, 0x0,
+ false, 0,
+ &display_gpu_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(display_dpip_gate,
+ K230_DISPLAY_DPIP_GATE,
+ 0x74, 2, 0, 0,
+ &pll1_div4.hw);
+
+K230_CLK_RATE_FORMAT(display_dpip_rate,
+ K230_DISPLAY_DPIP_RATE,
+ 1, 1, 0, 0,
+ 1, 256, 3, 0xFF,
+ 0x78, 31, div, 0x0,
+ false, 0,
+ &display_dpip_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(display_cfg_gate,
+ K230_DISPLAY_CFG_GATE,
+ 0x74, 4, 0, 0,
+ &pll1_div4.hw);
+
+K230_CLK_RATE_FORMAT(display_cfg_rate,
+ K230_DISPLAY_CFG_RATE,
+ 1, 1, 0, 0,
+ 1, 32, 11, 0x1F,
+ 0x78, 31, div, 0x0,
+ false, 0,
+ &display_cfg_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT_PNAME(display_ref_gate,
+ K230_DISPLAY_REF_GATE,
+ 0x74, 3, 0, 0,
+ "osc24m");
+
+K230_CLK_GATE_FORMAT(vpu_src_gate,
+ K230_VPU_SRC_GATE,
+ 0xC, 0, 0, 0,
+ &pll0_div2.hw);
+
+K230_CLK_RATE_FORMAT(vpu_src_rate,
+ K230_VPU_SRC_RATE,
+ 1, 16, 1, 0xF,
+ 16, 16, 0, 0,
+ 0x0, 31, mul, 0xC,
+ false, 0,
+ &vpu_src_gate.clk.hw);
+
+K230_CLK_RATE_FORMAT(vpu_axi_src_rate,
+ K230_VPU_AXI_SRC_RATE,
+ 1, 1, 0, 0,
+ 1, 16, 6, 0xF,
+ 0xC, 31, div, 0x0,
+ false, 0,
+ &vpu_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(vpu_axi_gate,
+ K230_VPU_AXI_GATE,
+ 0xC, 5, 0, 0,
+ &vpu_axi_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(vpu_ddrcp2_gate,
+ K230_VPU_DDRCP2_GATE,
+ 0x60, 5, 0, 0,
+ &vpu_axi_src_rate.clk.hw);
+
+K230_CLK_GATE_FORMAT(vpu_cfg_gate,
+ K230_VPU_CFG_GATE,
+ 0xC, 10, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(vpu_cfg_rate,
+ K230_VPU_CFG_RATE,
+ 1, 1, 0, 0,
+ 1, 16, 11, 0xF,
+ 0xC, 31, div, 0x0,
+ false, 0,
+ &vpu_cfg_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(sec_apb_gate,
+ K230_SEC_APB_GATE,
+ 0x80, 0, 0, 0,
+ &pll1_div4.hw);
+
+K230_CLK_RATE_FORMAT(sec_apb_rate,
+ K230_SEC_APB_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 1, 0x7,
+ 0x80, 31, div, 0x0,
+ false, 0,
+ &sec_apb_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(sec_fix_gate,
+ K230_SEC_FIX_GATE,
+ 0x80, 5, 0, 0,
+ &pll1_div4.hw);
+
+K230_CLK_RATE_FORMAT(sec_fix_rate,
+ K230_SEC_FIX_RATE,
+ 1, 1, 0, 0,
+ 1, 32, 6, 0x1F,
+ 0x80, 31, div, 0x0,
+ false, 0,
+ &sec_fix_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(sec_axi_gate,
+ K230_SEC_AXI_GATE,
+ 0x80, 4, 0, 0,
+ &pll1_div4.hw);
+
+K230_CLK_RATE_FORMAT(sec_axi_rate,
+ K230_SEC_AXI_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 11, 0x3,
+ 0x80, 31, div, 0,
+ false, 0,
+ &sec_axi_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(usb_480m_gate,
+ K230_USB_480M_GATE,
+ 0x100, 0, 0, 0,
+ &pll1.hw);
+
+K230_CLK_RATE_FORMAT(usb_480m_rate,
+ K230_USB_480M_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 1, 0x7,
+ 0x100, 31, div, 0,
+ false, 0,
+ &usb_480m_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(usb_100m_gate,
+ K230_USB_100M_GATE,
+ 0x100, 0, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(usb_100m_rate,
+ K230_USB_100M_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 4, 0x7,
+ 0x100, 31, div, 0,
+ false, 0,
+ &usb_100m_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(dphy_dft_gate,
+ K230_DPHY_DFT_GATE,
+ 0x100, 0, 0, 0,
+ &pll0.hw);
+
+K230_CLK_RATE_FORMAT(dphy_dft_rate,
+ K230_DPHY_DFT_RATE,
+ 1, 1, 0, 0,
+ 1, 16, 1, 0xF,
+ 0x104, 31, div, 0,
+ false, 0,
+ &dphy_dft_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(spi2axi_gate,
+ K230_SPI2AXI_GATE,
+ 0x108, 0, 0, 0,
+ &pll0_div4.hw);
+
+K230_CLK_RATE_FORMAT(spi2axi_rate,
+ K230_SPI2AXI_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 1, 0x7,
+ 0x108, 31, div, 0x0,
+ false, 0,
+ &spi2axi_gate.clk.hw);
+
+static const struct clk_parent_data k230_ai_src_mux_pdata[] = {
+ { .hw = &pll0_div2.hw, },
+ { .hw = &pll3_div2.hw, },
+};
+
+K230_CLK_MUX_FORMAT(ai_src_mux,
+ K230_AI_SRC_MUX,
+ 0x8, 2, 0x1,
+ 0, 0,
+ k230_ai_src_mux_pdata);
+
+K230_CLK_GATE_FORMAT(ai_src_gate,
+ K230_AI_SRC_GATE,
+ 0x8, 0, CLK_IGNORE_UNUSED, 0,
+ &ai_src_mux.clk.hw);
+
+K230_CLK_RATE_FORMAT(ai_src_rate,
+ K230_AI_SRC_RATE,
+ 1, 1, 0, 0,
+ 1, 8, 3, 0x7,
+ 0x8, 31, div, 0x0,
+ false, 0,
+ &ai_src_gate.clk.hw);
+
+K230_CLK_GATE_FORMAT(ai_axi_gate,
+ K230_AI_AXI_GATE,
+ 0x8, 10, 0, 0,
+ &pll0_div4.hw);
+
+static const struct clk_parent_data k230_camera0_mux_pdata[] = {
+ { .hw = &pll1_div3.hw, },
+ { .hw = &pll1_div4.hw, },
+ { .hw = &pll0_div4.hw, },
+};
+
+K230_CLK_MUX_FORMAT(camera0_mux,
+ K230_CAMERA0_MUX,
+ 0x6C, 3, 0x3,
+ 0, 0,
+ k230_camera0_mux_pdata);
+
+K230_CLK_GATE_FORMAT(camera0_gate,
+ K230_CAMERA0_GATE,
+ 0x6C, 0, CLK_IGNORE_UNUSED, 0,
+ &camera0_mux.clk.hw);
+
+K230_CLK_RATE_FORMAT(camera0_rate,
+ K230_CAMERA0_RATE,
+ 1, 1, 0, 0,
+ 1, 32, 5, 0x1f,
+ 0x6C, 31, div, 0x0,
+ false, 0,
+ &camera0_gate.clk.hw);
+
+static const struct clk_parent_data k230_camera1_mux_pdata[] = {
+ { .hw = &pll1_div3.hw, },
+ { .hw = &pll1_div4.hw, },
+ { .hw = &pll0_div4.hw, },
+};
+
+K230_CLK_MUX_FORMAT(camera1_mux,
+ K230_CAMERA1_MUX,
+ 0x6C, 10, 0x3,
+ 0, 0,
+ k230_camera1_mux_pdata);
+
+K230_CLK_GATE_FORMAT(camera1_gate,
+ K230_CAMERA1_GATE,
+ 0x6C, 1, CLK_IGNORE_UNUSED, 0,
+ &camera1_mux.clk.hw);
+
+K230_CLK_RATE_FORMAT(camera1_rate,
+ K230_CAMERA1_RATE,
+ 1, 1, 0, 0,
+ 1, 32, 12, 0x1f,
+ 0x6C, 31, div, 0x0,
+ false, 0,
+ &camera1_gate.clk.hw);
+
+static const struct clk_parent_data k230_camera2_mux_pdata[] = {
+ { .hw = &pll1_div3.hw, },
+ { .hw = &pll1_div4.hw, },
+ { .hw = &pll0_div4.hw, },
+};
+
+K230_CLK_MUX_FORMAT(camera2_mux,
+ K230_CAMERA2_MUX,
+ 0x6C, 17, 0x3,
+ 0, 0,
+ k230_camera2_mux_pdata);
+
+K230_CLK_GATE_FORMAT(camera2_gate,
+ K230_CAMERA2_GATE,
+ 0x6C, 2, CLK_IGNORE_UNUSED, 0,
+ &camera2_mux.clk.hw);
+
+K230_CLK_RATE_FORMAT(camera2_rate,
+ K230_CAMERA2_RATE,
+ 1, 1, 0, 0,
+ 1, 32, 19, 0x1f,
+ 0x6C, 31, div, 0x0,
+ false, 0,
+ &camera2_gate.clk.hw);
+
+static struct k230_clk_mux *k230_clk_muxs[] = {
+ &hs_ssi0_mux,
+ &hs_usb_ref_mux,
+ &cpu1_src_mux,
+ &timer0_mux,
+ &timer1_mux,
+ &timer2_mux,
+ &timer3_mux,
+ &timer4_mux,
+ &timer5_mux,
+ &shrm_sram_mux,
+ &ddrc_src_mux,
+ &ai_src_mux,
+ &camera0_mux,
+ &camera1_mux,
+ &camera2_mux,
+};
+
+#define K230_CLK_MUX_NUM ARRAY_SIZE(k230_clk_muxs)
+
+static struct k230_clk_gate *k230_clk_gates[] = {
+ &cpu0_src_gate,
+ &cpu0_plic_gate,
+ &cpu0_noc_ddrcp4_gate,
+ &cpu0_apb_gate,
+ &cpu1_src_gate,
+ &cpu1_plic_gate,
+ &cpu1_apb_gate,
+ &pmu_apb_gate,
+ &hs_hclk_high_gate,
+ &hs_hclk_gate,
+ &hs_sd0_ahb_gate,
+ &hs_sd1_ahb_gate,
+ &hs_ssi1_ahb_gate,
+ &hs_ssi2_ahb_gate,
+ &hs_usb0_ahb_gate,
+ &hs_usb1_ahb_gate,
+ &hs_ssi0_axi_gate,
+ &hs_ssi1_gate,
+ &hs_ssi2_gate,
+ &hs_qspi_axi_src_gate,
+ &hs_ssi1_axi_gate,
+ &hs_ssi2_axi_gate,
+ &hs_sd_card_src_gate,
+ &hs_sd0_card_gate,
+ &hs_sd1_card_gate,
+ &hs_sd_axi_src_gate,
+ &hs_sd0_axi_gate,
+ &hs_sd1_axi_gate,
+ &hs_sd0_base_gate,
+ &hs_sd1_base_gate,
+ &hs_ssi0_gate,
+ &hs_sd_timer_src_gate,
+ &hs_sd0_timer_gate,
+ &hs_sd1_timer_gate,
+ &hs_usb0_ref_gate,
+ &hs_usb1_ref_gate,
+ &ls_apb_src_gate,
+ &ls_uart0_apb_gate,
+ &ls_uart1_apb_gate,
+ &ls_uart2_apb_gate,
+ &ls_uart3_apb_gate,
+ &ls_uart4_apb_gate,
+ &ls_i2c0_apb_gate,
+ &ls_i2c1_apb_gate,
+ &ls_i2c2_apb_gate,
+ &ls_i2c3_apb_gate,
+ &ls_i2c4_apb_gate,
+ &ls_gpio_apb_gate,
+ &ls_pwm_apb_gate,
+ &ls_jamlink0_apb_gate,
+ &ls_jamlink1_apb_gate,
+ &ls_jamlink2_apb_gate,
+ &ls_jamlink3_apb_gate,
+ &ls_audio_apb_gate,
+ &ls_adc_apb_gate,
+ &ls_codec_apb_gate,
+ &ls_i2c0_gate,
+ &ls_i2c1_gate,
+ &ls_i2c2_gate,
+ &ls_i2c3_gate,
+ &ls_i2c4_gate,
+ &ls_codec_adc_gate,
+ &ls_codec_dac_gate,
+ &ls_audio_dev_gate,
+ &ls_pdm_gate,
+ &ls_adc_gate,
+ &ls_uart0_gate,
+ &ls_uart1_gate,
+ &ls_uart2_gate,
+ &ls_uart3_gate,
+ &ls_uart4_gate,
+ &ls_jamlink0co_gate,
+ &ls_jamlink1co_gate,
+ &ls_jamlink2co_gate,
+ &ls_jamlink3co_gate,
+ &ls_gpio_debounce_gate,
+ &sysctl_wdt0_apb_gate,
+ &sysctl_wdt1_apb_gate,
+ &sysctl_timer_apb_gate,
+ &sysctl_iomux_apb_gate,
+ &sysctl_mailbox_apb_gate,
+ &sysctl_hdi_gate,
+ &sysctl_time_stamp_gate,
+ &sysctl_wdt0_gate,
+ &sysctl_wdt1_gate,
+ &timer0_gate,
+ &timer1_gate,
+ &timer2_gate,
+ &timer3_gate,
+ &timer4_gate,
+ &timer5_gate,
+ &shrm_apb_gate,
+ &shrm_sram_gate,
+ &shrm_axi_gate,
+ &shrm_axi_slave_gate,
+ &shrm_nonai2d_axi_gate,
+ &shrm_decompress_axi_gate,
+ &shrm_sdma_axi_gate,
+ &shrm_pdma_axi_gate,
+ &ddrc_src_gate,
+ &ddrc_bypass_gate,
+ &ddrc_apb_gate,
+ &display_ahb_gate,
+ &display_axi_gate,
+ &display_gpu_gate,
+ &display_dpip_gate,
+ &display_cfg_gate,
+ &display_ref_gate,
+ &vpu_src_gate,
+ &vpu_axi_gate,
+ &vpu_ddrcp2_gate,
+ &vpu_cfg_gate,
+ &sec_apb_gate,
+ &sec_fix_gate,
+ &sec_axi_gate,
+ &usb_480m_gate,
+ &usb_100m_gate,
+ &dphy_dft_gate,
+ &spi2axi_gate,
+ &ai_src_gate,
+ &ai_axi_gate,
+ &camera0_gate,
+ &camera1_gate,
+ &camera2_gate,
+};
+
+#define K230_CLK_GATE_NUM ARRAY_SIZE(k230_clk_gates)
+
+static struct k230_clk_rate *k230_clk_rates[] = {
+ &cpu0_src_rate,
+ &cpu0_axi_rate,
+ &cpu0_plic_rate,
+ &cpu0_apb_rate,
+ &cpu1_src_rate,
+ &cpu1_axi_rate,
+ &cpu1_plic_rate,
+ &hs_hclk_high_rate,
+ &hs_hclk_rate,
+ &hs_ssi0_axi_rate,
+ &hs_ssi1_rate,
+ &hs_ssi2_rate,
+ &hs_qspi_axi_src_rate,
+ &hs_sd_card_src_rate,
+ &hs_sd_axi_src_rate,
+ &hs_usb_ref_50m_rate,
+ &hs_sd_timer_src_rate,
+ &ls_apb_src_rate,
+ &ls_gpio_debounce_rate,
+ &ls_i2c0_rate,
+ &ls_i2c1_rate,
+ &ls_i2c2_rate,
+ &ls_i2c3_rate,
+ &ls_i2c4_rate,
+ &ls_codec_adc_rate,
+ &ls_codec_dac_rate,
+ &ls_audio_dev_rate,
+ &ls_pdm_rate,
+ &ls_adc_rate,
+ &ls_uart0_rate,
+ &ls_uart1_rate,
+ &ls_uart2_rate,
+ &ls_uart3_rate,
+ &ls_uart4_rate,
+ &ls_jamlinkco_src_rate,
+ &sysctl_hdi_rate,
+ &sysctl_time_stamp_rate,
+ &sysctl_temp_sensor_rate,
+ &sysctl_wdt0_rate,
+ &sysctl_wdt1_rate,
+ &timer0_src_rate,
+ &timer1_src_rate,
+ &timer2_src_rate,
+ &timer3_src_rate,
+ &timer4_src_rate,
+ &timer5_src_rate,
+ &shrm_apb_rate,
+ &ddrc_src_rate,
+ &ddrc_apb_rate,
+ &display_ahb_rate,
+ &display_clkext_rate,
+ &display_gpu_rate,
+ &display_dpip_rate,
+ &display_cfg_rate,
+ &vpu_src_rate,
+ &vpu_axi_src_rate,
+ &vpu_cfg_rate,
+ &sec_apb_rate,
+ &sec_fix_rate,
+ &sec_axi_rate,
+ &usb_480m_rate,
+ &usb_100m_rate,
+ &dphy_dft_rate,
+ &spi2axi_rate,
+ &ai_src_rate,
+ &camera0_rate,
+ &camera1_rate,
+ &camera2_rate,
+};
+
+#define K230_CLK_RATE_NUM ARRAY_SIZE(k230_clk_rates)
+
+#define K230_CLK_NUM (K230_CLK_MUX_NUM + K230_CLK_GATE_NUM + K230_CLK_RATE_NUM + 1)
+
+static int k230_pll_prepare(struct clk_hw *hw)
+{
+ struct k230_pll *pll = hw_to_k230_pll(hw);
+ u32 reg;
+
+ /* wait for PLL lock until it reaches lock status */
+ return readl_poll_timeout(K230_PLLX_LOCK_ADDR(pll->reg, pll->id), reg,
+ reg & K230_PLL_LOCK_STATUS_MASK,
+ K230_PLL_LOCK_TIME_DELAY, K230_PLL_LOCK_TIMEOUT);
+}
+
+static inline bool k230_pll_hw_is_enabled(struct k230_pll *pll)
+{
+ return readl(K230_PLLX_GATE_ADDR(pll->reg, pll->id)) & K230_PLL_GATE_ENABLE;
+}
+
+static void k230_pll_enable_hw(struct k230_pll *pll)
+{
+ u32 reg;
+
+ if (k230_pll_hw_is_enabled(pll))
+ return;
+
+ reg = readl(K230_PLLX_GATE_ADDR(pll->reg, pll->id));
+ reg |= K230_PLL_GATE_ENABLE | K230_PLL_GATE_WRITE_ENABLE;
+ writel(reg, K230_PLLX_GATE_ADDR(pll->reg, pll->id));
+}
+
+static int k230_pll_enable(struct clk_hw *hw)
+{
+ struct k230_pll *pll = hw_to_k230_pll(hw);
+
+ guard(spinlock)(pll->lock);
+
+ k230_pll_enable_hw(pll);
+
+ return 0;
+}
+
+static void k230_pll_disable(struct clk_hw *hw)
+{
+ struct k230_pll *pll = hw_to_k230_pll(hw);
+ u32 reg;
+
+ guard(spinlock)(pll->lock);
+
+ reg = readl(K230_PLLX_GATE_ADDR(pll->reg, pll->id));
+ reg &= ~(K230_PLL_GATE_ENABLE);
+ reg |= (K230_PLL_GATE_WRITE_ENABLE);
+ writel(reg, K230_PLLX_GATE_ADDR(pll->reg, pll->id));
+}
+
+static int k230_pll_is_enabled(struct clk_hw *hw)
+{
+ return k230_pll_hw_is_enabled(hw_to_k230_pll(hw));
+}
+
+static unsigned long k230_pll_get_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct k230_pll *pll = hw_to_k230_pll(hw);
+ u32 reg;
+ u32 r, f, od;
+
+ guard(spinlock)(pll->lock);
+
+ reg = readl(K230_PLLX_BYPASS_ADDR(pll->reg, pll->id));
+ if (reg & K230_PLL_BYPASS_ENABLE)
+ return parent_rate;
+
+ reg = readl(K230_PLLX_LOCK_ADDR(pll->reg, pll->id));
+ if (!(reg & (K230_PLL_LOCK_STATUS_MASK)))
+ return 0;
+
+ reg = readl(K230_PLLX_DIV_ADDR(pll->reg, pll->id));
+ r = FIELD_GET(K230_PLL_R_MASK, reg) + 1;
+ f = FIELD_GET(K230_PLL_F_MASK, reg) + 1;
+ od = FIELD_GET(K230_PLL_OD_MASK, reg) + 1;
+
+ return mul_u64_u32_div(parent_rate, f, r * od);
+}
+
+static int k230_register_plls(struct platform_device *pdev, spinlock_t *lock,
+ void __iomem *reg)
+{
+ int i, ret;
+ struct k230_pll *pll;
+
+ for (i = 0; i < ARRAY_SIZE(k230_plls); i++) {
+ const char *name;
+
+ pll = k230_plls[i];
+
+ name = pll->hw.init->name;
+ pll->lock = lock;
+ pll->reg = reg;
+
+ ret = devm_clk_hw_register(&pdev->dev, &pll->hw);
+ if (ret)
+ return ret;
+
+ ret = devm_clk_hw_register_clkdev(&pdev->dev, &pll->hw, name, NULL);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int k230_register_pll_divs(struct platform_device *pdev)
+{
+ struct clk_fixed_factor *pll_div;
+ int ret;
+
+ for (int i = 0; i < ARRAY_SIZE(k230_pll_divs); i++) {
+ const char *name;
+
+ pll_div = k230_pll_divs[i];
+
+ name = pll_div->hw.init->name;
+
+ ret = devm_clk_hw_register(&pdev->dev, &pll_div->hw);
+ if (ret)
+ return ret;
+
+ ret = devm_clk_hw_register_clkdev(&pdev->dev, &pll_div->hw,
+ name, NULL);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static unsigned long k230_clk_get_rate_mul(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct k230_clk_rate *clk = hw_to_k230_clk_rate(hw);
+ struct k230_clk_rate_self *rate_self = &clk->clk;
+ u32 mul, div;
+
+ guard(spinlock)(rate_self->lock);
+
+ div = rate_self->div_max;
+ mul = (readl(rate_self->reg + clk->mul_reg_off) >> rate_self->mul_shift)
+ & rate_self->mul_mask;
+
+ return mul_u64_u32_div(parent_rate, mul + 1, div);
+}
+
+static unsigned long k230_clk_get_rate_div(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct k230_clk_rate *clk = hw_to_k230_clk_rate(hw);
+ struct k230_clk_rate_self *rate_self = &clk->clk;
+ u32 mul, div;
+
+ guard(spinlock)(rate_self->lock);
+
+ mul = rate_self->mul_max;
+ div = (readl(rate_self->reg + clk->div_reg_off) >> rate_self->div_shift)
+ & rate_self->div_mask;
+
+ return mul_u64_u32_div(parent_rate, mul, div + 1);
+}
+
+static unsigned long k230_clk_get_rate_mul_div(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct k230_clk_rate *clk = hw_to_k230_clk_rate(hw);
+ struct k230_clk_rate_self *rate_self = &clk->clk;
+ u32 mul, div;
+
+ guard(spinlock)(rate_self->lock);
+
+ div = (readl(rate_self->reg + clk->div_reg_off) >> rate_self->div_shift)
+ & rate_self->div_mask;
+ mul = (readl(rate_self->reg + clk->mul_reg_off) >> rate_self->mul_shift)
+ & rate_self->mul_mask;
+
+ return mul_u64_u32_div(parent_rate, mul, div);
+}
+
+static int k230_clk_find_approximate_mul(u32 mul_min, u32 mul_max,
+ u32 div_min, u32 div_max,
+ unsigned long rate, unsigned long parent_rate,
+ u32 *div, u32 *mul)
+{
+ long abs_min;
+ long abs_current;
+ long perfect_divide;
+
+ if (!rate || !parent_rate || !mul_min)
+ return -EINVAL;
+
+ perfect_divide = (long)((parent_rate * 1000) / rate);
+ abs_min = abs(perfect_divide -
+ (long)(((long)div_max * 1000) / (long)mul_min));
+ *mul = mul_min;
+
+ for (u32 i = mul_min + 1; i <= mul_max; i++) {
+ abs_current = abs(perfect_divide -
+ (long)(((long)div_max * 1000) / (long)i));
+
+ if (abs_min > abs_current) {
+ abs_min = abs_current;
+ *mul = i;
+ }
+ }
+
+ *div = div_max;
+
+ return 0;
+}
+
+static int k230_clk_find_approximate_div(u32 mul_min, u32 mul_max,
+ u32 div_min, u32 div_max,
+ unsigned long rate, unsigned long parent_rate,
+ u32 *div, u32 *mul)
+{
+ long abs_min;
+ long abs_current;
+ long perfect_divide;
+
+ if (!rate || !parent_rate || !mul_max)
+ return -EINVAL;
+
+ perfect_divide = (long)((parent_rate * 1000) / rate);
+ abs_min = abs(perfect_divide -
+ (long)(((long)div_min * 1000) / (long)mul_max));
+ *div = div_min;
+
+ for (u32 i = div_min + 1; i <= div_max; i++) {
+ abs_current = abs(perfect_divide -
+ (long)(((long)i * 1000) / (long)mul_max));
+
+ if (abs_min > abs_current) {
+ abs_min = abs_current;
+ *div = i;
+ }
+ }
+
+ *mul = mul_max;
+
+ return 0;
+}
+
+static int k230_clk_find_approximate_mul_div(u32 mul_min, u32 mul_max,
+ u32 div_min, u32 div_max,
+ unsigned long rate,
+ unsigned long parent_rate,
+ u32 *div, u32 *mul)
+{
+ unsigned long best_mul, best_div;
+
+ if (!rate || !parent_rate || !mul_min)
+ return -EINVAL;
+
+ rational_best_approximation(rate, parent_rate,
+ (unsigned long)mul_max, (unsigned long)div_max,
+ &best_mul, &best_div);
+
+ if (best_mul < mul_min)
+ best_mul = mul_min;
+
+ if (best_div < div_min)
+ best_div = div_min;
+
+ *mul = (u32)best_mul;
+ *div = (u32)best_div;
+
+ return 0;
+}
+
+static int k230_clk_determine_rate_mul(struct clk_hw *hw, struct clk_rate_request *req)
+{
+ int ret;
+ struct k230_clk_rate_self *rate_self = hw_to_k230_clk_rate_self(hw);
+ unsigned long rate = req->rate;
+ unsigned long parent_rate = req->best_parent_rate;
+ u32 div, mul;
+
+ ret = k230_clk_find_approximate_mul(rate_self->mul_min, rate_self->mul_max,
+ rate_self->div_min, rate_self->div_max,
+ rate, parent_rate, &div, &mul);
+ if (ret)
+ return ret;
+
+ req->rate = mul_u64_u32_div(parent_rate, mul, div);
+
+ return 0;
+}
+
+static int k230_clk_determine_rate_div(struct clk_hw *hw, struct clk_rate_request *req)
+{
+ int ret;
+ struct k230_clk_rate_self *rate_self = hw_to_k230_clk_rate_self(hw);
+ unsigned long rate = req->rate;
+ unsigned long parent_rate = req->best_parent_rate;
+ u32 div, mul;
+
+ ret = k230_clk_find_approximate_div(rate_self->mul_min, rate_self->mul_max,
+ rate_self->div_min, rate_self->div_max,
+ rate, parent_rate, &div, &mul);
+ if (ret)
+ return ret;
+
+ req->rate = mul_u64_u32_div(parent_rate, mul, div);
+
+ return 0;
+}
+
+static int k230_clk_determine_rate_mul_div(struct clk_hw *hw, struct clk_rate_request *req)
+{
+ int ret;
+ struct k230_clk_rate_self *rate_self = hw_to_k230_clk_rate_self(hw);
+ unsigned long rate = req->rate;
+ unsigned long parent_rate = req->best_parent_rate;
+ u32 div, mul;
+
+ ret = k230_clk_find_approximate_mul_div(rate_self->mul_min, rate_self->mul_max,
+ rate_self->div_min, rate_self->div_max,
+ rate, parent_rate, &div, &mul);
+ if (ret)
+ return ret;
+
+ req->rate = mul_u64_u32_div(parent_rate, mul, div);
+
+ return 0;
+}
+
+static int k230_clk_set_rate_mul(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ int ret;
+ struct k230_clk_rate *clk = hw_to_k230_clk_rate(hw);
+ struct k230_clk_rate_self *rate_self = &clk->clk;
+ u32 div, mul, mul_reg;
+
+ if (rate > parent_rate)
+ return -EINVAL;
+
+ if (rate_self->read_only)
+ return 0;
+
+ ret = k230_clk_find_approximate_mul(rate_self->mul_min, rate_self->mul_max,
+ rate_self->div_min, rate_self->div_max,
+ rate, parent_rate, &div, &mul);
+ if (ret)
+ return ret;
+
+ guard(spinlock)(rate_self->lock);
+
+ mul_reg = readl(rate_self->reg + clk->mul_reg_off);
+ mul_reg |= ((mul - 1) & rate_self->mul_mask) << (rate_self->mul_shift);
+ mul_reg |= BIT(rate_self->write_enable_bit);
+ writel(mul_reg, rate_self->reg + clk->mul_reg_off);
+
+ return 0;
+}
+
+static int k230_clk_set_rate_div(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ int ret;
+ struct k230_clk_rate *clk = hw_to_k230_clk_rate(hw);
+ struct k230_clk_rate_self *rate_self = &clk->clk;
+ u32 div, mul, div_reg;
+
+ if (rate > parent_rate)
+ return -EINVAL;
+
+ if (rate_self->read_only)
+ return 0;
+
+ ret = k230_clk_find_approximate_div(rate_self->mul_min, rate_self->mul_max,
+ rate_self->div_min, rate_self->div_max,
+ rate, parent_rate, &div, &mul);
+ if (ret)
+ return ret;
+
+ guard(spinlock)(rate_self->lock);
+
+ div_reg = readl(rate_self->reg + clk->div_reg_off);
+ div_reg |= ((div - 1) & rate_self->div_mask) << (rate_self->div_shift);
+ div_reg |= BIT(rate_self->write_enable_bit);
+ writel(div_reg, rate_self->reg + clk->div_reg_off);
+
+ return 0;
+}
+
+static int k230_clk_set_rate_mul_div(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ int ret;
+ struct k230_clk_rate *clk = hw_to_k230_clk_rate(hw);
+ struct k230_clk_rate_self *rate_self = &clk->clk;
+ u32 div, mul, div_reg, mul_reg;
+
+ if (rate > parent_rate)
+ return -EINVAL;
+
+ if (rate_self->read_only)
+ return 0;
+
+ ret = k230_clk_find_approximate_mul_div(rate_self->mul_min, rate_self->mul_max,
+ rate_self->div_min, rate_self->div_max,
+ rate, parent_rate, &div, &mul);
+ if (ret)
+ return ret;
+
+ guard(spinlock)(rate_self->lock);
+
+ div_reg = readl(rate_self->reg + clk->div_reg_off);
+ div_reg |= ((div - 1) & rate_self->div_mask) << (rate_self->div_shift);
+ div_reg |= BIT(rate_self->write_enable_bit);
+ writel(div_reg, rate_self->reg + clk->div_reg_off);
+
+ mul_reg = readl(rate_self->reg + clk->mul_reg_off);
+ mul_reg |= ((mul - 1) & rate_self->mul_mask) << (rate_self->mul_shift);
+ mul_reg |= BIT(rate_self->write_enable_bit);
+ writel(mul_reg, rate_self->reg + clk->mul_reg_off);
+
+ return 0;
+}
+
+static int k230_register_clk(int id, struct clk_hw *hw, struct device *dev,
+ struct clk_hw_onecell_data *hw_data)
+{
+ int ret;
+
+ ret = devm_clk_hw_register(dev, hw);
+ if (ret)
+ return ret;
+
+ hw_data->hws[id] = hw;
+
+ return 0;
+}
+
+static int k230_register_clks(struct platform_device *pdev,
+ struct clk_hw_onecell_data *hw_data,
+ spinlock_t *lock, void __iomem *reg)
+{
+ int i, ret;
+ struct device *dev = &pdev->dev;
+ struct clk_fixed_factor *fixed_factor = &shrm_sram_div2;
+ struct k230_clk_mux *mux;
+ struct k230_clk_gate *gate;
+ struct k230_clk_rate *rate;
+
+ for (i = 0; i < K230_CLK_MUX_NUM; i++) {
+ mux = k230_clk_muxs[i];
+ mux->clk.lock = lock;
+ mux->clk.reg = reg + mux->reg_off;
+
+ ret = k230_register_clk(mux->id, &mux->clk.hw, dev, hw_data);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < K230_CLK_GATE_NUM; i++) {
+ gate = k230_clk_gates[i];
+ gate->clk.lock = lock;
+ gate->clk.reg = reg + gate->reg_off;
+
+ ret = k230_register_clk(gate->id, &gate->clk.hw, dev, hw_data);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < K230_CLK_RATE_NUM; i++) {
+ rate = k230_clk_rates[i];
+ rate->clk.lock = lock;
+ rate->clk.reg = reg;
+
+ ret = k230_register_clk(rate->id, &rate->clk.hw, dev, hw_data);
+ if (ret)
+ return ret;
+ }
+
+ ret = k230_register_clk(K230_SHRM_SRAM_DIV2, &fixed_factor->hw, dev, hw_data);
+ if (ret)
+ return ret;
+
+ return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get, hw_data);
+}
+
+static int k230_clk_init_plls(struct platform_device *pdev)
+{
+ int ret;
+ void __iomem *reg;
+ /* used for all the plls */
+ spinlock_t *lock;
+
+ lock = devm_kzalloc(&pdev->dev, sizeof(*lock), GFP_KERNEL);
+ if (!lock)
+ return -ENOMEM;
+
+ spin_lock_init(lock);
+
+ reg = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
+
+ ret = k230_register_plls(pdev, lock, reg);
+ if (ret)
+ return ret;
+
+ ret = k230_register_pll_divs(pdev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int k230_clk_init_clks(struct platform_device *pdev,
+ struct clk_hw_onecell_data *hw_data)
+{
+ int ret;
+ void __iomem *reg;
+ /* used for all the clocks */
+ spinlock_t *lock;
+
+ lock = devm_kzalloc(&pdev->dev, sizeof(*lock), GFP_KERNEL);
+ if (!lock)
+ return -ENOMEM;
+
+ spin_lock_init(lock);
+
+ hw_data->num = K230_CLK_NUM;
+
+ reg = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
+
+ ret = k230_register_clks(pdev, hw_data, lock, reg);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int k230_clk_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct clk_hw_onecell_data *hw_data;
+
+ hw_data = devm_kzalloc(&pdev->dev, struct_size(hw_data, hws, K230_CLK_NUM),
+ GFP_KERNEL);
+ if (!hw_data)
+ return -ENOMEM;
+
+ ret = k230_clk_init_plls(pdev);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "init plls failed\n");
+
+ ret = k230_clk_init_clks(pdev, hw_data);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "init clks failed\n");
+
+ return 0;
+}
+
+static const struct of_device_id k230_clk_ids[] = {
+ { .compatible = "canaan,k230-clk" },
+ { /* Sentinel */ }
+};
+
+static struct platform_driver k230_clk_driver = {
+ .driver = {
+ .name = "k230_clock_controller",
+ .of_match_table = k230_clk_ids,
+ },
+ .probe = k230_clk_probe,
+};
+builtin_platform_driver(k230_clk_driver);
diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c
index 3727d5472450..9149ce4f702d 100644
--- a/drivers/clk/clk-max77686.c
+++ b/drivers/clk/clk-max77686.c
@@ -47,8 +47,8 @@ struct max77686_clk_init_data {
struct max77686_clk_driver_data {
enum max77686_chip_name chip;
- struct max77686_clk_init_data *max_clk_data;
size_t num_clks;
+ struct max77686_clk_init_data max_clk_data[] __counted_by(num_clks);
};
static const struct
@@ -168,19 +168,7 @@ static int max77686_clk_probe(struct platform_device *pdev)
struct regmap *regmap;
int i, ret, num_clks;
- drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
- if (!drv_data)
- return -ENOMEM;
-
- regmap = dev_get_regmap(parent, NULL);
- if (!regmap) {
- dev_err(dev, "Failed to get rtc regmap\n");
- return -ENODEV;
- }
-
- drv_data->chip = id->driver_data;
-
- switch (drv_data->chip) {
+ switch (id->driver_data) {
case CHIP_MAX77686:
num_clks = MAX77686_CLKS_NUM;
hw_clks = max77686_hw_clks_info;
@@ -201,13 +189,19 @@ static int max77686_clk_probe(struct platform_device *pdev)
return -EINVAL;
}
- drv_data->num_clks = num_clks;
- drv_data->max_clk_data = devm_kcalloc(dev, num_clks,
- sizeof(*drv_data->max_clk_data),
- GFP_KERNEL);
- if (!drv_data->max_clk_data)
+ drv_data = devm_kzalloc(dev, struct_size(drv_data, max_clk_data, num_clks), GFP_KERNEL);
+ if (!drv_data)
return -ENOMEM;
+ drv_data->num_clks = num_clks;
+ drv_data->chip = id->driver_data;
+
+ regmap = dev_get_regmap(parent, NULL);
+ if (!regmap) {
+ dev_err(dev, "Failed to get rtc regmap\n");
+ return -ENODEV;
+ }
+
for (i = 0; i < num_clks; i++) {
struct max77686_clk_init_data *max_clk_data;
const char *clk_name;
diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c
index fae65127cd4a..08050ff1c8cf 100644
--- a/drivers/clk/hisilicon/clk.c
+++ b/drivers/clk/hisilicon/clk.c
@@ -70,7 +70,7 @@ struct hisi_clock_data *hisi_clk_init(struct device_node *np,
clk_data = kzalloc_obj(*clk_data);
if (!clk_data)
- goto err;
+ goto err_base;
clk_data->base = base;
clk_table = kzalloc_objs(*clk_table, nr_clks);
@@ -83,6 +83,8 @@ struct hisi_clock_data *hisi_clk_init(struct device_node *np,
return clk_data;
err_data:
kfree(clk_data);
+err_base:
+ iounmap(base);
err:
return NULL;
}
diff --git a/drivers/clk/hisilicon/clkdivider-hi6220.c b/drivers/clk/hisilicon/clkdivider-hi6220.c
index 1787ecefe601..20a337383a1e 100644
--- a/drivers/clk/hisilicon/clkdivider-hi6220.c
+++ b/drivers/clk/hisilicon/clkdivider-hi6220.c
@@ -26,8 +26,8 @@
* @shift: shift to the divider bit field
* @width: width of the divider bit field
* @mask: mask for setting divider rate
- * @table: the div table that the divider supports
* @lock: register lock
+ * @table: the div table that the divider supports
*/
struct hi6220_clk_divider {
struct clk_hw hw;
@@ -35,8 +35,8 @@ struct hi6220_clk_divider {
u8 shift;
u8 width;
u32 mask;
- const struct clk_div_table *table;
spinlock_t *lock;
+ struct clk_div_table table[];
};
#define to_hi6220_clk_divider(_hw) \
@@ -108,24 +108,19 @@ struct clk *hi6220_register_clkdiv(struct device *dev, const char *name,
u32 max_div, min_div;
int i;
- /* allocate the divider */
- div = kzalloc_obj(*div);
- if (!div)
- return ERR_PTR(-ENOMEM);
-
/* Init the divider table */
max_div = div_mask(width) + 1;
min_div = 1;
- table = kzalloc_objs(*table, max_div + 1);
- if (!table) {
- kfree(div);
+ /* allocate the divider */
+ div = kzalloc_flex(*div, table, max_div + 1);
+ if (!div)
return ERR_PTR(-ENOMEM);
- }
for (i = 0; i < max_div; i++) {
- table[i].div = min_div + i;
- table[i].val = table[i].div - 1;
+ table = &div->table[i];
+ table->div = min_div + i;
+ table->val = table->div - 1;
}
init.name = name;
@@ -141,14 +136,11 @@ struct clk *hi6220_register_clkdiv(struct device *dev, const char *name,
div->mask = mask_bit ? BIT(mask_bit) : 0;
div->lock = lock;
div->hw.init = &init;
- div->table = table;
/* register the clock */
clk = clk_register(dev, &div->hw);
- if (IS_ERR(clk)) {
- kfree(table);
+ if (IS_ERR(clk))
kfree(div);
- }
return clk;
}
diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c
index 7c0f7b3e89e0..9d2094bd48e3 100644
--- a/drivers/clk/keystone/sci-clk.c
+++ b/drivers/clk/keystone/sci-clk.c
@@ -362,6 +362,14 @@ static int _sci_clk_build(struct sci_clk_provider *provider,
init.ops = &sci_clk_ops;
init.num_parents = sci_clk->num_parents;
+
+ /*
+ * A clock rate query to the SCI firmware will return 0 if either the
+ * clock itself is disabled or the attached device/consumer is disabled.
+ * This makes it inherently unsuitable for the caching of the clk
+ * framework.
+ */
+ init.flags = CLK_GET_RATE_NOCACHE;
sci_clk->hw.init = &init;
ret = devm_clk_hw_register(provider->dev, &sci_clk->hw);
@@ -417,7 +425,7 @@ static struct clk_hw *sci_clk_get(struct of_phandle_args *clkspec, void *data)
key.clk_id = clkspec->args[1];
clk = bsearch(&key, provider->clocks, provider->num_clocks,
- sizeof(clk), _cmp_sci_clk);
+ sizeof(*clk), _cmp_sci_clk);
if (!clk)
return ERR_PTR(-ENODEV);
diff --git a/drivers/clk/mediatek/clk-mt7988-infracfg.c b/drivers/clk/mediatek/clk-mt7988-infracfg.c
index ef8267319d91..13ffa9d88e24 100644
--- a/drivers/clk/mediatek/clk-mt7988-infracfg.c
+++ b/drivers/clk/mediatek/clk-mt7988-infracfg.c
@@ -56,49 +56,45 @@ static const char *const infra_pcie_gfmux_tl_ck_o_p3_parents[] __initconst = {
static const struct mtk_mux infra_muxes[] = {
/* MODULE_CLK_SEL_0 */
- MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_UART0_SEL, "infra_mux_uart0_sel",
- infra_mux_uart0_parents, 0x0018, 0x0010, 0x0014, 0, 1, -1, -1, -1),
- MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_UART1_SEL, "infra_mux_uart1_sel",
- infra_mux_uart1_parents, 0x0018, 0x0010, 0x0014, 1, 1, -1, -1, -1),
- MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_UART2_SEL, "infra_mux_uart2_sel",
- infra_mux_uart2_parents, 0x0018, 0x0010, 0x0014, 2, 1, -1, -1, -1),
- MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_SPI0_SEL, "infra_mux_spi0_sel", infra_mux_spi0_parents,
- 0x0018, 0x0010, 0x0014, 4, 1, -1, -1, -1),
- MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_SPI1_SEL, "infra_mux_spi1_sel", infra_mux_spi1_parents,
- 0x0018, 0x0010, 0x0014, 5, 1, -1, -1, -1),
- MUX_GATE_CLR_SET_UPD(CLK_INFRA_MUX_SPI2_SEL, "infra_mux_spi2_sel", infra_mux_spi0_parents,
- 0x0018, 0x0010, 0x0014, 6, 1, -1, -1, -1),
- MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_SEL, "infra_pwm_sel", infra_pwm_bck_parents, 0x0018,
- 0x0010, 0x0014, 14, 2, -1, -1, -1),
- MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK1_SEL, "infra_pwm_ck1_sel", infra_pwm_bck_parents,
- 0x0018, 0x0010, 0x0014, 16, 2, -1, -1, -1),
- MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK2_SEL, "infra_pwm_ck2_sel", infra_pwm_bck_parents,
- 0x0018, 0x0010, 0x0014, 18, 2, -1, -1, -1),
- MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK3_SEL, "infra_pwm_ck3_sel", infra_pwm_bck_parents,
- 0x0018, 0x0010, 0x0014, 20, 2, -1, -1, -1),
- MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK4_SEL, "infra_pwm_ck4_sel", infra_pwm_bck_parents,
- 0x0018, 0x0010, 0x0014, 22, 2, -1, -1, -1),
- MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK5_SEL, "infra_pwm_ck5_sel", infra_pwm_bck_parents,
- 0x0018, 0x0010, 0x0014, 24, 2, -1, -1, -1),
- MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK6_SEL, "infra_pwm_ck6_sel", infra_pwm_bck_parents,
- 0x0018, 0x0010, 0x0014, 26, 2, -1, -1, -1),
- MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK7_SEL, "infra_pwm_ck7_sel", infra_pwm_bck_parents,
- 0x0018, 0x0010, 0x0014, 28, 2, -1, -1, -1),
- MUX_GATE_CLR_SET_UPD(CLK_INFRA_PWM_CK8_SEL, "infra_pwm_ck8_sel", infra_pwm_bck_parents,
- 0x0018, 0x0010, 0x0014, 30, 2, -1, -1, -1),
+ MUX_CLR_SET(CLK_INFRA_MUX_UART0_SEL, "infra_mux_uart0_sel",
+ infra_mux_uart0_parents, 0x0018, 0x0010, 0x0014, 0, 1),
+ MUX_CLR_SET(CLK_INFRA_MUX_UART1_SEL, "infra_mux_uart1_sel",
+ infra_mux_uart1_parents, 0x0018, 0x0010, 0x0014, 1, 1),
+ MUX_CLR_SET(CLK_INFRA_MUX_UART2_SEL, "infra_mux_uart2_sel",
+ infra_mux_uart2_parents, 0x0018, 0x0010, 0x0014, 2, 1),
+ MUX_CLR_SET(CLK_INFRA_MUX_SPI0_SEL, "infra_mux_spi0_sel",
+ infra_mux_spi0_parents, 0x0018, 0x0010, 0x0014, 4, 1),
+ MUX_CLR_SET(CLK_INFRA_MUX_SPI1_SEL, "infra_mux_spi1_sel",
+ infra_mux_spi1_parents, 0x0018, 0x0010, 0x0014, 5, 1),
+ MUX_CLR_SET(CLK_INFRA_MUX_SPI2_SEL, "infra_mux_spi2_sel",
+ infra_mux_spi0_parents, 0x0018, 0x0010, 0x0014, 6, 1),
+ MUX_CLR_SET(CLK_INFRA_PWM_SEL, "infra_pwm_sel",
+ infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 14, 2),
+ MUX_CLR_SET(CLK_INFRA_PWM_CK1_SEL, "infra_pwm_ck1_sel",
+ infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 16, 2),
+ MUX_CLR_SET(CLK_INFRA_PWM_CK2_SEL, "infra_pwm_ck2_sel",
+ infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 18, 2),
+ MUX_CLR_SET(CLK_INFRA_PWM_CK3_SEL, "infra_pwm_ck3_sel",
+ infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 20, 2),
+ MUX_CLR_SET(CLK_INFRA_PWM_CK4_SEL, "infra_pwm_ck4_sel",
+ infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 22, 2),
+ MUX_CLR_SET(CLK_INFRA_PWM_CK5_SEL, "infra_pwm_ck5_sel",
+ infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 24, 2),
+ MUX_CLR_SET(CLK_INFRA_PWM_CK6_SEL, "infra_pwm_ck6_sel",
+ infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 26, 2),
+ MUX_CLR_SET(CLK_INFRA_PWM_CK7_SEL, "infra_pwm_ck7_sel",
+ infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 28, 2),
+ MUX_CLR_SET(CLK_INFRA_PWM_CK8_SEL, "infra_pwm_ck8_sel",
+ infra_pwm_bck_parents, 0x0018, 0x0010, 0x0014, 30, 2),
/* MODULE_CLK_SEL_1 */
- MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P0_SEL, "infra_pcie_gfmux_tl_o_p0_sel",
- infra_pcie_gfmux_tl_ck_o_p0_parents, 0x0028, 0x0020, 0x0024, 0, 2, -1,
- -1, -1),
- MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P1_SEL, "infra_pcie_gfmux_tl_o_p1_sel",
- infra_pcie_gfmux_tl_ck_o_p1_parents, 0x0028, 0x0020, 0x0024, 2, 2, -1,
- -1, -1),
- MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P2_SEL, "infra_pcie_gfmux_tl_o_p2_sel",
- infra_pcie_gfmux_tl_ck_o_p2_parents, 0x0028, 0x0020, 0x0024, 4, 2, -1,
- -1, -1),
- MUX_GATE_CLR_SET_UPD(CLK_INFRA_PCIE_GFMUX_TL_O_P3_SEL, "infra_pcie_gfmux_tl_o_p3_sel",
- infra_pcie_gfmux_tl_ck_o_p3_parents, 0x0028, 0x0020, 0x0024, 6, 2, -1,
- -1, -1),
+ MUX_CLR_SET(CLK_INFRA_PCIE_GFMUX_TL_O_P0_SEL, "infra_pcie_gfmux_tl_o_p0_sel",
+ infra_pcie_gfmux_tl_ck_o_p0_parents, 0x0028, 0x0020, 0x0024, 0, 2),
+ MUX_CLR_SET(CLK_INFRA_PCIE_GFMUX_TL_O_P1_SEL, "infra_pcie_gfmux_tl_o_p1_sel",
+ infra_pcie_gfmux_tl_ck_o_p1_parents, 0x0028, 0x0020, 0x0024, 2, 2),
+ MUX_CLR_SET(CLK_INFRA_PCIE_GFMUX_TL_O_P2_SEL, "infra_pcie_gfmux_tl_o_p2_sel",
+ infra_pcie_gfmux_tl_ck_o_p2_parents, 0x0028, 0x0020, 0x0024, 4, 2),
+ MUX_CLR_SET(CLK_INFRA_PCIE_GFMUX_TL_O_P3_SEL, "infra_pcie_gfmux_tl_o_p3_sel",
+ infra_pcie_gfmux_tl_ck_o_p3_parents, 0x0028, 0x0020, 0x0024, 6, 2),
};
static const struct mtk_gate_regs infra0_cg_regs = {
diff --git a/drivers/clk/mediatek/clk-mt8192.c b/drivers/clk/mediatek/clk-mt8192.c
index 50b43807c60c..12c8890d922f 100644
--- a/drivers/clk/mediatek/clk-mt8192.c
+++ b/drivers/clk/mediatek/clk-mt8192.c
@@ -579,8 +579,8 @@ static const struct mtk_mux top_mtk_muxes[] = {
dsp7_parents, 0x050, 0x054, 0x058, 0, 3, 7, 0x004, 16),
MUX_GATE_CLR_SET_UPD(CLK_TOP_MFG_REF_SEL, "mfg_ref_sel",
mfg_ref_parents, 0x050, 0x054, 0x058, 16, 2, 23, 0x004, 18),
- MUX_CLR_SET_UPD(CLK_TOP_MFG_PLL_SEL, "mfg_pll_sel",
- mfg_pll_parents, 0x050, 0x054, 0x058, 18, 1, -1, -1),
+ MUX_CLR_SET(CLK_TOP_MFG_PLL_SEL, "mfg_pll_sel", mfg_pll_parents,
+ 0x050, 0x054, 0x058, 18, 1),
MUX_GATE_CLR_SET_UPD(CLK_TOP_CAMTG_SEL, "camtg_sel",
camtg_parents, 0x050, 0x054, 0x058, 24, 3, 31, 0x004, 19),
/* CLK_CFG_5 */
diff --git a/drivers/clk/mediatek/clk-mux.h b/drivers/clk/mediatek/clk-mux.h
index 151e56dcf884..1a9baf306b4a 100644
--- a/drivers/clk/mediatek/clk-mux.h
+++ b/drivers/clk/mediatek/clk-mux.h
@@ -126,6 +126,11 @@ extern const struct clk_ops mtk_mux_gate_hwv_fenc_clr_set_upd_ops;
0, _upd_ofs, _upd, CLK_SET_RATE_PARENT, \
mtk_mux_clr_set_upd_ops)
+#define MUX_CLR_SET(_id, _name, _parents, _mux_ofs, \
+ _mux_set_ofs, _mux_clr_ofs, _shift, _width) \
+ MUX_CLR_SET_UPD(_id, _name, _parents, _mux_ofs, \
+ _mux_set_ofs, _mux_clr_ofs, _shift, _width, 0, -1)
+
#define MUX_GATE_HWV_FENC_CLR_SET_UPD_FLAGS(_id, _name, _parents, \
_mux_ofs, _mux_set_ofs, _mux_clr_ofs, \
_hwv_sta_ofs, _hwv_set_ofs, _hwv_clr_ofs, \
diff --git a/drivers/clk/microchip/Makefile b/drivers/clk/microchip/Makefile
index 13250e04e46c..8e60bc1a03ae 100644
--- a/drivers/clk/microchip/Makefile
+++ b/drivers/clk/microchip/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_COMMON_CLK_PIC32) += clk-core.o
+obj-$(CONFIG_COMMON_CLK_PIC32) += clk-pic32.o
obj-$(CONFIG_PIC32MZDA) += clk-pic32mzda.o
obj-$(CONFIG_MCHP_CLK_MPFS) += clk-mpfs.o
obj-$(CONFIG_MCHP_CLK_MPFS) += clk-mpfs-ccc.o
diff --git a/drivers/clk/microchip/clk-mpfs-ccc.c b/drivers/clk/microchip/clk-mpfs-ccc.c
index 0a76a1aaa50f..40c17593e594 100644
--- a/drivers/clk/microchip/clk-mpfs-ccc.c
+++ b/drivers/clk/microchip/clk-mpfs-ccc.c
@@ -32,6 +32,7 @@
#define MPFS_CCC_FIXED_DIV 4
#define MPFS_CCC_OUTPUTS_PER_PLL 4
#define MPFS_CCC_REFS_PER_PLL 2
+#define MPFS_CCC_NUM_CLKS 16
struct mpfs_ccc_data {
void __iomem **pll_base;
@@ -178,7 +179,7 @@ static int mpfs_ccc_register_outputs(struct device *dev, struct mpfs_ccc_out_hw_
return dev_err_probe(dev, ret, "failed to register clock id: %d\n",
out_hw->id);
- data->hw_data.hws[out_hw->id - 2] = &out_hw->divider.hw;
+ data->hw_data.hws[out_hw->id] = &out_hw->divider.hw;
}
return 0;
@@ -231,17 +232,9 @@ static int mpfs_ccc_probe(struct platform_device *pdev)
{
struct mpfs_ccc_data *clk_data;
void __iomem *pll_base[ARRAY_SIZE(mpfs_ccc_pll_clks)];
- unsigned int num_clks;
int ret;
- /*
- * If DLLs get added here, mpfs_ccc_register_outputs() currently packs
- * sparse clock IDs in the hws array
- */
- num_clks = ARRAY_SIZE(mpfs_ccc_pll_clks) + ARRAY_SIZE(mpfs_ccc_pll0out_clks) +
- ARRAY_SIZE(mpfs_ccc_pll1out_clks);
-
- clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hw_data.hws, num_clks),
+ clk_data = devm_kzalloc(&pdev->dev, struct_size(clk_data, hw_data.hws, MPFS_CCC_NUM_CLKS),
GFP_KERNEL);
if (!clk_data)
return -ENOMEM;
@@ -255,7 +248,7 @@ static int mpfs_ccc_probe(struct platform_device *pdev)
return PTR_ERR(pll_base[1]);
clk_data->pll_base = pll_base;
- clk_data->hw_data.num = num_clks;
+ clk_data->hw_data.num = MPFS_CCC_NUM_CLKS;
clk_data->dev = &pdev->dev;
ret = mpfs_ccc_register_plls(clk_data->dev, mpfs_ccc_pll_clks,
diff --git a/drivers/clk/microchip/clk-core.c b/drivers/clk/microchip/clk-pic32.c
index 692152b5094e..9d128fba2cde 100644
--- a/drivers/clk/microchip/clk-core.c
+++ b/drivers/clk/microchip/clk-pic32.c
@@ -11,7 +11,7 @@
#include <linux/iopoll.h>
#include <linux/platform_data/pic32.h>
-#include "clk-core.h"
+#include "clk-pic32.h"
/* OSCCON Reg fields */
#define OSC_CUR_MASK 0x07
diff --git a/drivers/clk/microchip/clk-core.h b/drivers/clk/microchip/clk-pic32.h
index acb81739a16f..acb81739a16f 100644
--- a/drivers/clk/microchip/clk-core.h
+++ b/drivers/clk/microchip/clk-pic32.h
diff --git a/drivers/clk/microchip/clk-pic32mzda.c b/drivers/clk/microchip/clk-pic32mzda.c
index 27599829ea40..e11cbdd982a6 100644
--- a/drivers/clk/microchip/clk-pic32mzda.c
+++ b/drivers/clk/microchip/clk-pic32mzda.c
@@ -14,7 +14,7 @@
#include <linux/platform_device.h>
#include <asm/traps.h>
-#include "clk-core.h"
+#include "clk-pic32.h"
/* FRC Postscaler */
#define OSC_FRCDIV_MASK 0x07
diff --git a/drivers/clk/mmp/clk-pxa1908-apbc.c b/drivers/clk/mmp/clk-pxa1908-apbc.c
index 3fd7b5e644f3..438ece4f047d 100644
--- a/drivers/clk/mmp/clk-pxa1908-apbc.c
+++ b/drivers/clk/mmp/clk-pxa1908-apbc.c
@@ -7,6 +7,7 @@
#include <dt-bindings/clock/marvell,pxa1908.h>
#include "clk.h"
+#include "reset.h"
#define APBC_UART0 0x0
#define APBC_UART1 0x4
@@ -44,22 +45,25 @@ static const char * const uart_parent_names[] = {"pll1_117", "uart_pll"};
static const char * const ssp_parent_names[] = {"pll1_d16", "pll1_d48", "pll1_d24", "pll1_d12"};
static struct mmp_param_gate_clk apbc_gate_clks[] = {
- {PXA1908_CLK_TWSI0, "twsi0_clk", "pll1_32", CLK_SET_RATE_PARENT, APBC_TWSI0, 0x7, 3, 0, 0, NULL},
- {PXA1908_CLK_TWSI1, "twsi1_clk", "pll1_32", CLK_SET_RATE_PARENT, APBC_TWSI1, 0x7, 3, 0, 0, NULL},
- {PXA1908_CLK_TWSI3, "twsi3_clk", "pll1_32", CLK_SET_RATE_PARENT, APBC_TWSI3, 0x7, 3, 0, 0, NULL},
- {PXA1908_CLK_GPIO, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_GPIO, 0x7, 3, 0, 0, NULL},
- {PXA1908_CLK_KPC, "kpc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_KPC, 0x7, 3, 0, MMP_CLK_GATE_NEED_DELAY, NULL},
- {PXA1908_CLK_RTC, "rtc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_RTC, 0x87, 0x83, 0, MMP_CLK_GATE_NEED_DELAY, NULL},
+ {PXA1908_CLK_TWSI0, "twsi0_clk", "pll1_32", CLK_SET_RATE_PARENT, APBC_TWSI0, 0x3, 3, 0, 0, NULL},
+ {PXA1908_CLK_TWSI1, "twsi1_clk", "pll1_32", CLK_SET_RATE_PARENT, APBC_TWSI1, 0x3, 3, 0, 0, NULL},
+ {PXA1908_CLK_TWSI3, "twsi3_clk", "pll1_32", CLK_SET_RATE_PARENT, APBC_TWSI3, 0x3, 3, 0, 0, NULL},
+ {PXA1908_CLK_GPIO, "gpio_clk", "vctcxo", CLK_SET_RATE_PARENT, APBC_GPIO, 0x3, 3, 0, 0, NULL},
+ {PXA1908_CLK_KPC, "kpc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_KPC, 0x3, 3, 0, MMP_CLK_GATE_NEED_DELAY, NULL},
+ {PXA1908_CLK_RTC, "rtc_clk", "clk32", CLK_SET_RATE_PARENT, APBC_RTC, 0x83, 0x83, 0, MMP_CLK_GATE_NEED_DELAY, NULL},
+ {PXA1908_CLK_PWM1, "pwm1_clk", "pwm01_apb_share", CLK_SET_RATE_PARENT, APBC_PWM1, 0x2, 2, 0, 0, NULL},
+ {PXA1908_CLK_PWM3, "pwm3_clk", "pwm23_apb_share", CLK_SET_RATE_PARENT, APBC_PWM3, 0x2, 2, 0, 0, NULL},
+ {PXA1908_CLK_UART0, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT, APBC_UART0, 0x3, 3, 0, 0, &uart0_lock},
+ {PXA1908_CLK_UART1, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, APBC_UART1, 0x3, 3, 0, 0, &uart1_lock},
+ {PXA1908_CLK_THERMAL, "thermal_clk", NULL, 0, APBC_THERMAL, 0x3, 3, 0, 0, NULL},
+ {PXA1908_CLK_IPC_RST, "ipc_clk", NULL, 0, APBC_IPC_RST, 0x3, 3, 0, 0, NULL},
+ {PXA1908_CLK_SSP0, "ssp0_clk", "ssp0_mux", 0, APBC_SSP0, 0x3, 3, 0, 0, NULL},
+ {PXA1908_CLK_SSP2, "ssp2_clk", "ssp2_mux", 0, APBC_SSP2, 0x3, 3, 0, 0, NULL},
+};
+
+static struct mmp_param_gate_clk apbc_gate_no_reset_clks[] = {
{PXA1908_CLK_PWM0, "pwm0_clk", "pwm01_apb_share", CLK_SET_RATE_PARENT, APBC_PWM0, 0x2, 2, 0, 0, &pwm0_lock},
- {PXA1908_CLK_PWM1, "pwm1_clk", "pwm01_apb_share", CLK_SET_RATE_PARENT, APBC_PWM1, 0x6, 2, 0, 0, NULL},
{PXA1908_CLK_PWM2, "pwm2_clk", "pwm23_apb_share", CLK_SET_RATE_PARENT, APBC_PWM2, 0x2, 2, 0, 0, NULL},
- {PXA1908_CLK_PWM3, "pwm3_clk", "pwm23_apb_share", CLK_SET_RATE_PARENT, APBC_PWM3, 0x6, 2, 0, 0, NULL},
- {PXA1908_CLK_UART0, "uart0_clk", "uart0_mux", CLK_SET_RATE_PARENT, APBC_UART0, 0x7, 3, 0, 0, &uart0_lock},
- {PXA1908_CLK_UART1, "uart1_clk", "uart1_mux", CLK_SET_RATE_PARENT, APBC_UART1, 0x7, 3, 0, 0, &uart1_lock},
- {PXA1908_CLK_THERMAL, "thermal_clk", NULL, 0, APBC_THERMAL, 0x7, 3, 0, 0, NULL},
- {PXA1908_CLK_IPC_RST, "ipc_clk", NULL, 0, APBC_IPC_RST, 0x7, 3, 0, 0, NULL},
- {PXA1908_CLK_SSP0, "ssp0_clk", "ssp0_mux", 0, APBC_SSP0, 0x7, 3, 0, 0, NULL},
- {PXA1908_CLK_SSP2, "ssp2_clk", "ssp2_mux", 0, APBC_SSP2, 0x7, 3, 0, 0, NULL},
};
static struct mmp_param_mux_clk apbc_mux_clks[] = {
@@ -89,6 +93,30 @@ static void pxa1908_apb_periph_clk_init(struct pxa1908_clk_unit *pxa_unit)
ARRAY_SIZE(apbc_mux_clks));
mmp_register_gate_clks(unit, apbc_gate_clks, pxa_unit->base,
ARRAY_SIZE(apbc_gate_clks));
+ mmp_register_gate_clks(unit, apbc_gate_no_reset_clks, pxa_unit->base,
+ ARRAY_SIZE(apbc_gate_no_reset_clks));
+}
+
+/* Taken from clk-of-pxa1928.c */
+static void pxa1908_clk_reset_init(struct device_node *np,
+ struct pxa1908_clk_unit *pxa_unit)
+{
+ struct mmp_clk_reset_cell *cells;
+ int nr_cells = ARRAY_SIZE(apbc_gate_clks);
+
+ cells = kzalloc_objs(*cells, nr_cells);
+ if (!cells)
+ return;
+
+ for (int i = 0; i < nr_cells; i++) {
+ cells[i].clk_id = apbc_gate_clks[i].id;
+ cells[i].reg = pxa_unit->base + apbc_gate_clks[i].offset;
+ cells[i].bits = BIT(2);
+ cells[i].flags = 0;
+ cells[i].lock = apbc_gate_clks[i].lock;
+ };
+
+ mmp_clk_reset_register(np, cells, nr_cells);
}
static int pxa1908_apbc_probe(struct platform_device *pdev)
@@ -107,6 +135,8 @@ static int pxa1908_apbc_probe(struct platform_device *pdev)
pxa1908_apb_periph_clk_init(pxa_unit);
+ pxa1908_clk_reset_init(pdev->dev.of_node, pxa_unit);
+
return 0;
}
diff --git a/drivers/clk/mmp/clk-pxa1908-apbcp.c b/drivers/clk/mmp/clk-pxa1908-apbcp.c
index f638d7e89b47..1aa476103553 100644
--- a/drivers/clk/mmp/clk-pxa1908-apbcp.c
+++ b/drivers/clk/mmp/clk-pxa1908-apbcp.c
@@ -7,6 +7,7 @@
#include <dt-bindings/clock/marvell,pxa1908.h>
#include "clk.h"
+#include "reset.h"
#define APBCP_UART2 0x1c
#define APBCP_TWSI2 0x28
@@ -24,9 +25,9 @@ static DEFINE_SPINLOCK(uart2_lock);
static const char * const uart_parent_names[] = {"pll1_117", "uart_pll"};
static struct mmp_param_gate_clk apbcp_gate_clks[] = {
- {PXA1908_CLK_UART2, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT, APBCP_UART2, 0x7, 0x3, 0x0, 0, &uart2_lock},
- {PXA1908_CLK_TWSI2, "twsi2_clk", "pll1_32", CLK_SET_RATE_PARENT, APBCP_TWSI2, 0x7, 0x3, 0x0, 0, NULL},
- {PXA1908_CLK_AICER, "ripc_clk", NULL, 0, APBCP_AICER, 0x7, 0x2, 0x0, 0, NULL},
+ {PXA1908_CLK_UART2, "uart2_clk", "uart2_mux", CLK_SET_RATE_PARENT, APBCP_UART2, 0x3, 0x3, 0x0, 0, &uart2_lock},
+ {PXA1908_CLK_TWSI2, "twsi2_clk", "pll1_32", CLK_SET_RATE_PARENT, APBCP_TWSI2, 0x3, 0x3, 0x0, 0, NULL},
+ {PXA1908_CLK_AICER, "ripc_clk", NULL, 0, APBCP_AICER, 0x3, 0x2, 0x0, 0, NULL},
};
static struct mmp_param_mux_clk apbcp_mux_clks[] = {
@@ -43,6 +44,28 @@ static void pxa1908_apb_p_periph_clk_init(struct pxa1908_clk_unit *pxa_unit)
ARRAY_SIZE(apbcp_gate_clks));
}
+/* Taken from clk-of-pxa1928.c */
+static void pxa1908_clk_reset_init(struct device_node *np,
+ struct pxa1908_clk_unit *pxa_unit)
+{
+ struct mmp_clk_reset_cell *cells;
+ int nr_cells = ARRAY_SIZE(apbcp_gate_clks);
+
+ cells = kzalloc_objs(*cells, nr_cells);
+ if (!cells)
+ return;
+
+ for (int i = 0; i < nr_cells; i++) {
+ cells[i].clk_id = apbcp_gate_clks[i].id;
+ cells[i].reg = pxa_unit->base + apbcp_gate_clks[i].offset;
+ cells[i].bits = BIT(2);
+ cells[i].flags = 0;
+ cells[i].lock = apbcp_gate_clks[i].lock;
+ };
+
+ mmp_clk_reset_register(np, cells, nr_cells);
+}
+
static int pxa1908_apbcp_probe(struct platform_device *pdev)
{
struct pxa1908_clk_unit *pxa_unit;
@@ -59,6 +82,8 @@ static int pxa1908_apbcp_probe(struct platform_device *pdev)
pxa1908_apb_p_periph_clk_init(pxa_unit);
+ pxa1908_clk_reset_init(pdev->dev.of_node, pxa_unit);
+
return 0;
}
diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c
index 28f2e1b2a932..0f9ae5f5cefd 100644
--- a/drivers/clk/mvebu/common.c
+++ b/drivers/clk/mvebu/common.c
@@ -189,10 +189,10 @@ DEFINE_SPINLOCK(ctrl_gating_lock);
struct clk_gating_ctrl {
spinlock_t *lock;
- struct clk **gates;
int num_gates;
void __iomem *base;
u32 saved_reg;
+ struct clk *gates[] __counted_by(num_gates);
};
static struct clk_gating_ctrl *ctrl;
@@ -257,24 +257,21 @@ void __init mvebu_clk_gating_setup(struct device_node *np,
clk_put(clk);
}
- ctrl = kzalloc_obj(*ctrl);
+ /* Count, allocate, and register clock gates */
+ for (n = 0; desc[n].name;)
+ n++;
+
+ ctrl = kzalloc_flex(*ctrl, gates, n);
if (WARN_ON(!ctrl))
goto ctrl_out;
+ ctrl->num_gates = n;
+
/* lock must already be initialized */
ctrl->lock = &ctrl_gating_lock;
ctrl->base = base;
- /* Count, allocate, and register clock gates */
- for (n = 0; desc[n].name;)
- n++;
-
- ctrl->num_gates = n;
- ctrl->gates = kzalloc_objs(*ctrl->gates, ctrl->num_gates);
- if (WARN_ON(!ctrl->gates))
- goto gates_out;
-
for (n = 0; n < ctrl->num_gates; n++) {
const char *parent =
(desc[n].parent) ? desc[n].parent : default_parent;
@@ -289,8 +286,6 @@ void __init mvebu_clk_gating_setup(struct device_node *np,
register_syscore(&clk_gate_syscore);
return;
-gates_out:
- kfree(ctrl);
ctrl_out:
iounmap(base);
}
diff --git a/drivers/clk/nxp/clk-lpc18xx-ccu.c b/drivers/clk/nxp/clk-lpc18xx-ccu.c
index dcb6d0c0b41a..3793e701835f 100644
--- a/drivers/clk/nxp/clk-lpc18xx-ccu.c
+++ b/drivers/clk/nxp/clk-lpc18xx-ccu.c
@@ -27,8 +27,8 @@
#define CCU_BRANCH_HAVE_DIV2 BIT(1)
struct lpc18xx_branch_clk_data {
- const char **name;
int num;
+ const char *name[] __counted_by(num);
};
struct lpc18xx_clk_branch {
@@ -266,6 +266,7 @@ static void __init lpc18xx_ccu_init(struct device_node *np)
{
struct lpc18xx_branch_clk_data *clk_data;
void __iomem *reg_base;
+ size_t size;
int i, ret;
reg_base = of_iomap(np, 0);
@@ -274,19 +275,14 @@ static void __init lpc18xx_ccu_init(struct device_node *np)
return;
}
- clk_data = kzalloc_obj(*clk_data);
+ size = of_property_count_strings(np, "clock-names");
+ clk_data = kzalloc_flex(*clk_data, name, size);
if (!clk_data) {
iounmap(reg_base);
return;
}
- clk_data->num = of_property_count_strings(np, "clock-names");
- clk_data->name = kcalloc(clk_data->num, sizeof(char *), GFP_KERNEL);
- if (!clk_data->name) {
- iounmap(reg_base);
- kfree(clk_data);
- return;
- }
+ clk_data->num = size;
for (i = 0; i < clk_data->num; i++) {
ret = of_property_read_string_index(np, "clock-names", i,
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index df21ef5ffd68..7d84c2f1d911 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -200,6 +200,17 @@ config CLK_X1E80100_TCSRCC
Support for the TCSR clock controller on X1E80100 devices.
Say Y if you want to use peripheral devices such as SD/UFS.
+config CLK_X1P42100_CAMCC
+ tristate "X1P42100 Camera Clock Controller"
+ depends on ARM64 || COMPILE_TEST
+ select CLK_X1E80100_GCC
+ default m if ARCH_QCOM
+ help
+ Support for the camera clock controller on Qualcomm Technologies, Inc.
+ X1P42100 devices.
+ Say Y if you want to support camera devices and camera functionality
+ such as capturing pictures.
+
config CLK_X1P42100_GPUCC
tristate "X1P42100 Graphics Clock Controller"
depends on ARM64 || COMPILE_TEST
@@ -209,6 +220,17 @@ config CLK_X1P42100_GPUCC
Say Y if you want to support graphics controller devices and
functionality such as 3D graphics.
+config CLK_X1P42100_VIDEOCC
+ tristate "X1P42100 Video Clock Controller"
+ depends on ARM64 || COMPILE_TEST
+ select CLK_X1E80100_GCC
+ default m if ARCH_QCOM
+ help
+ Support for the video clock controller on Qualcomm Technologies, Inc.
+ X1P42100 devices.
+ Say Y if you want to support video devices and functionality such as
+ video encode/decode.
+
config CLK_QCM2290_GPUCC
tristate "QCM2290 Graphics Clock Controller"
depends on ARM64 || COMPILE_TEST
@@ -296,6 +318,22 @@ config QCOM_CLK_RPMH
Say Y if you want to support the clocks exposed by RPMh on
platforms such as SDM845.
+config CLK_HAWI_GCC
+ tristate "Hawi Global Clock Controller"
+ depends on ARM64 || COMPILE_TEST
+ select QCOM_GDSC
+ help
+ Support for the global clock controller on Hawi devices.
+ Say Y if you want to use peripheral devices such as UART, SPI,
+ I2C, USB, UFS, SD/eMMC, PCIe, etc.
+
+config CLK_HAWI_TCSRCC
+ tristate "Hawi TCSR Clock Controller"
+ depends on ARM64 || COMPILE_TEST
+ help
+ Support for the TCSR clock controller on Hawi devices.
+ Say Y if you want to use peripheral devices such as PCIe, USB, UFS.
+
config APQ_GCC_8084
tristate "APQ8084 Global Clock Controller"
depends on ARM || COMPILE_TEST
@@ -434,6 +472,16 @@ config IPQ_GCC_9574
i2c, USB, SD/eMMC, etc. Select this for the root clock
of ipq9574.
+config IPQ_GCC_9650
+ tristate "IPQ9650 Global Clock Controller"
+ depends on ARM64 || COMPILE_TEST
+ default ARCH_QCOM
+ help
+ Support for global clock controller on ipq9650 devices.
+ Say Y if you want to use peripheral devices such as UART, SPI,
+ i2c, USB, SD/eMMC, etc. Select this for the root clock
+ of ipq9650.
+
config IPQ_NSSCC_5424
tristate "IPQ5424 NSS Clock Controller"
depends on ARM64 || COMPILE_TEST
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 89d07c35e4d9..58f9a5eb6fd7 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -29,6 +29,8 @@ obj-$(CONFIG_CLK_GLYMUR_GCC) += gcc-glymur.o
obj-$(CONFIG_CLK_GLYMUR_GPUCC) += gpucc-glymur.o gxclkctl-kaanapali.o
obj-$(CONFIG_CLK_GLYMUR_TCSRCC) += tcsrcc-glymur.o
obj-$(CONFIG_CLK_GLYMUR_VIDEOCC) += videocc-glymur.o
+obj-$(CONFIG_CLK_HAWI_GCC) += gcc-hawi.o
+obj-$(CONFIG_CLK_HAWI_TCSRCC) += tcsrcc-hawi.o
obj-$(CONFIG_CLK_KAANAPALI_CAMCC) += cambistmclkcc-kaanapali.o camcc-kaanapali.o
obj-$(CONFIG_CLK_KAANAPALI_DISPCC) += dispcc-kaanapali.o
obj-$(CONFIG_CLK_KAANAPALI_GCC) += gcc-kaanapali.o
@@ -42,7 +44,9 @@ obj-$(CONFIG_CLK_X1E80100_DISPCC) += dispcc-x1e80100.o
obj-$(CONFIG_CLK_X1E80100_GCC) += gcc-x1e80100.o
obj-$(CONFIG_CLK_X1E80100_GPUCC) += gpucc-x1e80100.o
obj-$(CONFIG_CLK_X1E80100_TCSRCC) += tcsrcc-x1e80100.o
+obj-$(CONFIG_CLK_X1P42100_CAMCC) += camcc-x1p42100.o
obj-$(CONFIG_CLK_X1P42100_GPUCC) += gpucc-x1p42100.o
+obj-$(CONFIG_CLK_X1P42100_VIDEOCC) += videocc-x1p42100.o
obj-$(CONFIG_CLK_QCM2290_GPUCC) += gpucc-qcm2290.o
obj-$(CONFIG_IPQ_APSS_PLL) += apss-ipq-pll.o
obj-$(CONFIG_IPQ_APSS_5424) += apss-ipq5424.o
@@ -57,6 +61,7 @@ obj-$(CONFIG_IPQ_GCC_6018) += gcc-ipq6018.o
obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o
obj-$(CONFIG_IPQ_GCC_8074) += gcc-ipq8074.o
obj-$(CONFIG_IPQ_GCC_9574) += gcc-ipq9574.o
+obj-$(CONFIG_IPQ_GCC_9650) += gcc-ipq9650.o
obj-$(CONFIG_IPQ_NSSCC_5424) += nsscc-ipq5424.o
obj-$(CONFIG_IPQ_NSSCC_9574) += nsscc-ipq9574.o
obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o
@@ -189,7 +194,7 @@ obj-$(CONFIG_SM_GPUCC_8450) += gpucc-sm8450.o
obj-$(CONFIG_SM_GPUCC_8550) += gpucc-sm8550.o
obj-$(CONFIG_SM_GPUCC_8650) += gpucc-sm8650.o
obj-$(CONFIG_SM_GPUCC_8750) += gpucc-sm8750.o gxclkctl-kaanapali.o
-obj-$(CONFIG_SM_GPUCC_MILOS) += gpucc-milos.o
+obj-$(CONFIG_SM_GPUCC_MILOS) += gpucc-milos.o gxclkctl-kaanapali.o
obj-$(CONFIG_SM_LPASSCC_6115) += lpasscc-sm6115.o
obj-$(CONFIG_SM_TCSRCC_8550) += tcsrcc-sm8550.o
obj-$(CONFIG_SM_TCSRCC_8650) += tcsrcc-sm8650.o
diff --git a/drivers/clk/qcom/a53-pll.c b/drivers/clk/qcom/a53-pll.c
index 724a642311e5..0549b214fcfc 100644
--- a/drivers/clk/qcom/a53-pll.c
+++ b/drivers/clk/qcom/a53-pll.c
@@ -20,7 +20,7 @@
static const struct pll_freq_tbl a53pll_freq[] = {
{ 998400000, 52, 0x0, 0x1, 0 },
{ 1094400000, 57, 0x0, 0x1, 0 },
- { 1152000000, 62, 0x0, 0x1, 0 },
+ { 1152000000, 60, 0x0, 0x1, 0 },
{ 1209600000, 63, 0x0, 0x1, 0 },
{ 1248000000, 65, 0x0, 0x1, 0 },
{ 1363200000, 71, 0x0, 0x1, 0 },
diff --git a/drivers/clk/qcom/camcc-milos.c b/drivers/clk/qcom/camcc-milos.c
index 409d47098c10..579b71e0e089 100644
--- a/drivers/clk/qcom/camcc-milos.c
+++ b/drivers/clk/qcom/camcc-milos.c
@@ -30,6 +30,11 @@ enum {
DT_IFACE,
};
+/* Need to match the order of interconnects in DT binding */
+enum {
+ DT_ICC_TOP_GDSC,
+};
+
enum {
P_BI_TCXO,
P_CAM_CC_PLL0_OUT_EVEN,
@@ -1971,6 +1976,8 @@ static struct gdsc cam_cc_camss_top_gdsc = {
},
.pwrsts = PWRSTS_OFF_ON,
.flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+ .needs_icc = true,
+ .icc_path_index = DT_ICC_TOP_GDSC,
};
static struct clk_regmap *cam_cc_milos_clocks[] = {
diff --git a/drivers/clk/qcom/camcc-x1e80100.c b/drivers/clk/qcom/camcc-x1e80100.c
index 81f579ff6993..c12994af42cf 100644
--- a/drivers/clk/qcom/camcc-x1e80100.c
+++ b/drivers/clk/qcom/camcc-x1e80100.c
@@ -1052,6 +1052,31 @@ static struct clk_rcg2 cam_cc_mclk7_clk_src = {
},
};
+static const struct freq_tbl ftbl_cam_cc_qdss_debug_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(60000000, P_CAM_CC_PLL8_OUT_EVEN, 8, 0, 0),
+ F(75000000, P_CAM_CC_PLL0_OUT_EVEN, 8, 0, 0),
+ F(150000000, P_CAM_CC_PLL0_OUT_EVEN, 4, 0, 0),
+ F(300000000, P_CAM_CC_PLL0_OUT_MAIN, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_qdss_debug_clk_src = {
+ .cmd_rcgr = 0x13938,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_qdss_debug_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_qdss_debug_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
static const struct freq_tbl ftbl_cam_cc_sfe_0_clk_src[] = {
F(345600000, P_CAM_CC_PLL6_OUT_EVEN, 1, 0, 0),
F(432000000, P_CAM_CC_PLL6_OUT_EVEN, 1, 0, 0),
@@ -2182,6 +2207,42 @@ static struct clk_branch cam_cc_mclk7_clk = {
},
};
+static struct clk_branch cam_cc_qdss_debug_clk = {
+ .halt_reg = 0x13a64,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x13a64,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_qdss_debug_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_qdss_debug_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_qdss_debug_xo_clk = {
+ .halt_reg = 0x13a68,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x13a68,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_qdss_debug_xo_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch cam_cc_sfe_0_clk = {
.halt_reg = 0x133c0,
.halt_check = BRANCH_HALT,
@@ -2398,6 +2459,9 @@ static struct clk_regmap *cam_cc_x1e80100_clocks[] = {
[CAM_CC_PLL6_OUT_EVEN] = &cam_cc_pll6_out_even.clkr,
[CAM_CC_PLL8] = &cam_cc_pll8.clkr,
[CAM_CC_PLL8_OUT_EVEN] = &cam_cc_pll8_out_even.clkr,
+ [CAM_CC_QDSS_DEBUG_CLK] = &cam_cc_qdss_debug_clk.clkr,
+ [CAM_CC_QDSS_DEBUG_CLK_SRC] = &cam_cc_qdss_debug_clk_src.clkr,
+ [CAM_CC_QDSS_DEBUG_XO_CLK] = &cam_cc_qdss_debug_xo_clk.clkr,
[CAM_CC_SFE_0_CLK] = &cam_cc_sfe_0_clk.clkr,
[CAM_CC_SFE_0_CLK_SRC] = &cam_cc_sfe_0_clk_src.clkr,
[CAM_CC_SFE_0_FAST_AHB_CLK] = &cam_cc_sfe_0_fast_ahb_clk.clkr,
diff --git a/drivers/clk/qcom/camcc-x1p42100.c b/drivers/clk/qcom/camcc-x1p42100.c
new file mode 100644
index 000000000000..c1a61c267919
--- /dev/null
+++ b/drivers/clk/qcom/camcc-x1p42100.c
@@ -0,0 +1,2223 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,x1e80100-camcc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "common.h"
+#include "gdsc.h"
+#include "reset.h"
+
+enum {
+ DT_IFACE,
+ DT_BI_TCXO,
+ DT_BI_TCXO_AO,
+ DT_SLEEP_CLK,
+};
+
+enum {
+ P_BI_TCXO,
+ P_BI_TCXO_AO,
+ P_CAM_CC_PLL0_OUT_EVEN,
+ P_CAM_CC_PLL0_OUT_MAIN,
+ P_CAM_CC_PLL0_OUT_ODD,
+ P_CAM_CC_PLL1_OUT_EVEN,
+ P_CAM_CC_PLL2_OUT_EVEN,
+ P_CAM_CC_PLL2_OUT_MAIN,
+ P_CAM_CC_PLL3_OUT_EVEN,
+ P_CAM_CC_PLL6_OUT_EVEN,
+ P_SLEEP_CLK,
+};
+
+static const struct pll_vco lucid_ole_vco[] = {
+ { 249600000, 2300000000, 0 },
+};
+
+static const struct pll_vco rivian_ole_vco[] = {
+ { 777000000, 1285000000, 0 },
+};
+
+/* 1200.0 MHz Configuration */
+static const struct alpha_pll_config cam_cc_pll0_config = {
+ .l = 0x3e,
+ .alpha = 0x8000,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00008400,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll cam_cc_pll0 = {
+ .offset = 0x0,
+ .config = &cam_cc_pll0_config,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll0",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll0_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll0_out_even = {
+ .offset = 0x0,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_cam_cc_pll0_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll0_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll0_out_even",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll0_out_odd[] = {
+ { 0x2, 3 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll0_out_odd = {
+ .offset = 0x0,
+ .post_div_shift = 14,
+ .post_div_table = post_div_table_cam_cc_pll0_out_odd,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll0_out_odd),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll0_out_odd",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+ },
+};
+
+/* 728.0 MHz Configuration */
+static const struct alpha_pll_config cam_cc_pll1_config = {
+ .l = 0x25,
+ .alpha = 0xeaaa,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00000400,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll cam_cc_pll1 = {
+ .offset = 0x1000,
+ .config = &cam_cc_pll1_config,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll1",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll1_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll1_out_even = {
+ .offset = 0x1000,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_cam_cc_pll1_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll1_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll1_out_even",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll1.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+ },
+};
+
+/* 960.0 MHz Configuration */
+static const struct alpha_pll_config cam_cc_pll2_config = {
+ .l = 0x32,
+ .alpha = 0x0,
+ .config_ctl_val = 0x10000030,
+ .config_ctl_hi_val = 0x80890263,
+ .config_ctl_hi1_val = 0x00000217,
+ .user_ctl_val = 0x00000000,
+ .user_ctl_hi_val = 0x00100000,
+};
+
+static struct clk_alpha_pll cam_cc_pll2 = {
+ .offset = 0x2000,
+ .config = &cam_cc_pll2_config,
+ .vco_table = rivian_ole_vco,
+ .num_vco = ARRAY_SIZE(rivian_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_RIVIAN_EVO],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll2",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_rivian_evo_ops,
+ },
+ },
+};
+
+/* 864.0 MHz Configuration */
+static const struct alpha_pll_config cam_cc_pll3_config = {
+ .l = 0x2d,
+ .alpha = 0x0,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00000400,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll cam_cc_pll3 = {
+ .offset = 0x3000,
+ .config = &cam_cc_pll3_config,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll3",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll3_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll3_out_even = {
+ .offset = 0x3000,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_cam_cc_pll3_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll3_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll3_out_even",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll3.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+ },
+};
+
+/* 960.0 MHz Configuration */
+static const struct alpha_pll_config cam_cc_pll6_config = {
+ .l = 0x32,
+ .alpha = 0x0,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00000400,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll cam_cc_pll6 = {
+ .offset = 0x6000,
+ .config = &cam_cc_pll6_config,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll6",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_cam_cc_pll6_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv cam_cc_pll6_out_even = {
+ .offset = 0x6000,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_cam_cc_pll6_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_cam_cc_pll6_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_pll6_out_even",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_pll6.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_alpha_pll_postdiv_lucid_ole_ops,
+ },
+};
+
+static const struct parent_map cam_cc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAM_CC_PLL0_OUT_MAIN, 1 },
+ { P_CAM_CC_PLL0_OUT_EVEN, 2 },
+ { P_CAM_CC_PLL0_OUT_ODD, 3 },
+ { P_CAM_CC_PLL6_OUT_EVEN, 5 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_0[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &cam_cc_pll0.clkr.hw },
+ { .hw = &cam_cc_pll0_out_even.clkr.hw },
+ { .hw = &cam_cc_pll0_out_odd.clkr.hw },
+ { .hw = &cam_cc_pll6_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAM_CC_PLL2_OUT_EVEN, 3 },
+ { P_CAM_CC_PLL2_OUT_MAIN, 5 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_1[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &cam_cc_pll2.clkr.hw },
+ { .hw = &cam_cc_pll2.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAM_CC_PLL3_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_2[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &cam_cc_pll3_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_3[] = {
+ { P_BI_TCXO, 0 },
+ { P_CAM_CC_PLL1_OUT_EVEN, 4 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_3[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &cam_cc_pll1_out_even.clkr.hw },
+};
+
+static const struct parent_map cam_cc_parent_map_4[] = {
+ { P_SLEEP_CLK, 0 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_4[] = {
+ { .index = DT_SLEEP_CLK },
+};
+
+static const struct parent_map cam_cc_parent_map_5[] = {
+ { P_BI_TCXO, 0 },
+};
+
+static const struct clk_parent_data cam_cc_parent_data_5[] = {
+ { .index = DT_BI_TCXO },
+};
+
+static const struct freq_tbl ftbl_cam_cc_bps_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(200000000, P_CAM_CC_PLL0_OUT_ODD, 2, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0),
+ F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_bps_clk_src = {
+ .cmd_rcgr = 0x10278,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_bps_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_bps_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_camnoc_axi_rt_clk_src[] = {
+ F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_camnoc_axi_rt_clk_src = {
+ .cmd_rcgr = 0x138f8,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_camnoc_axi_rt_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_axi_rt_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_cci_0_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(37500000, P_CAM_CC_PLL0_OUT_EVEN, 16, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_cci_0_clk_src = {
+ .cmd_rcgr = 0x1365c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_cci_0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cci_0_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_cci_1_clk_src = {
+ .cmd_rcgr = 0x1378c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_cci_0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cci_1_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_cphy_rx_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(480000000, P_CAM_CC_PLL0_OUT_MAIN, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_cphy_rx_clk_src = {
+ .cmd_rcgr = 0x11164,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cphy_rx_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_csi0phytimer_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_csi0phytimer_clk_src = {
+ .cmd_rcgr = 0x150e0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi0phytimer_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_csi1phytimer_clk_src = {
+ .cmd_rcgr = 0x15104,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi1phytimer_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_csi2phytimer_clk_src = {
+ .cmd_rcgr = 0x15124,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi2phytimer_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_csi3phytimer_clk_src = {
+ .cmd_rcgr = 0x15258,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi3phytimer_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_csi4phytimer_clk_src = {
+ .cmd_rcgr = 0x1538c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi4phytimer_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_csi5phytimer_clk_src = {
+ .cmd_rcgr = 0x154c0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi5phytimer_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_csid_clk_src[] = {
+ F(400000000, P_CAM_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ F(480000000, P_CAM_CC_PLL0_OUT_MAIN, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_csid_clk_src = {
+ .cmd_rcgr = 0x138d4,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_csid_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csid_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_fast_ahb_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0),
+ F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0),
+ F(300000000, P_CAM_CC_PLL0_OUT_MAIN, 4, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_fast_ahb_clk_src = {
+ .cmd_rcgr = 0x10018,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_fast_ahb_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_fast_ahb_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_icp_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0),
+ F(480000000, P_CAM_CC_PLL6_OUT_EVEN, 1, 0, 0),
+ F(600000000, P_CAM_CC_PLL0_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_icp_clk_src = {
+ .cmd_rcgr = 0x13520,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_icp_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_icp_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_ife_0_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(432000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+ F(594000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+ F(675000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+ F(727000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_ife_0_clk_src = {
+ .cmd_rcgr = 0x11018,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_2,
+ .freq_tbl = ftbl_cam_cc_ife_0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ife_0_clk_src",
+ .parent_data = cam_cc_parent_data_2,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_ife_lite_clk_src[] = {
+ F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0),
+ F(480000000, P_CAM_CC_PLL6_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_ife_lite_clk_src = {
+ .cmd_rcgr = 0x13000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_ife_lite_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ife_lite_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_ife_lite_csid_clk_src = {
+ .cmd_rcgr = 0x1313c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_ife_lite_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ife_lite_csid_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_ipe_nps_clk_src[] = {
+ F(364000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0),
+ F(500000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0),
+ F(600000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0),
+ F(700000000, P_CAM_CC_PLL1_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_ipe_nps_clk_src = {
+ .cmd_rcgr = 0x103cc,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_3,
+ .freq_tbl = ftbl_cam_cc_ipe_nps_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ipe_nps_clk_src",
+ .parent_data = cam_cc_parent_data_3,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_jpeg_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(200000000, P_CAM_CC_PLL0_OUT_ODD, 2, 0, 0),
+ F(400000000, P_CAM_CC_PLL0_OUT_ODD, 1, 0, 0),
+ F(480000000, P_CAM_CC_PLL6_OUT_EVEN, 1, 0, 0),
+ F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_jpeg_clk_src = {
+ .cmd_rcgr = 0x133dc,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_jpeg_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_jpeg_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_mclk0_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(24000000, P_CAM_CC_PLL2_OUT_MAIN, 10, 1, 4),
+ F(68571429, P_CAM_CC_PLL2_OUT_MAIN, 14, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_mclk0_clk_src = {
+ .cmd_rcgr = 0x15000,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_mclk0_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_mclk1_clk_src = {
+ .cmd_rcgr = 0x1501c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_mclk1_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_mclk2_clk_src = {
+ .cmd_rcgr = 0x15038,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_mclk2_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_mclk3_clk_src = {
+ .cmd_rcgr = 0x15054,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_mclk3_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_mclk4_clk_src = {
+ .cmd_rcgr = 0x15070,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_mclk4_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_mclk5_clk_src = {
+ .cmd_rcgr = 0x1508c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_mclk5_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_mclk6_clk_src = {
+ .cmd_rcgr = 0x150a8,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_mclk6_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_rcg2 cam_cc_mclk7_clk_src = {
+ .cmd_rcgr = 0x150c4,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_1,
+ .freq_tbl = ftbl_cam_cc_mclk0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_mclk7_clk_src",
+ .parent_data = cam_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_qdss_debug_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(75000000, P_CAM_CC_PLL0_OUT_EVEN, 8, 0, 0),
+ F(150000000, P_CAM_CC_PLL0_OUT_EVEN, 4, 0, 0),
+ F(300000000, P_CAM_CC_PLL0_OUT_MAIN, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_qdss_debug_clk_src = {
+ .cmd_rcgr = 0x13938,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_qdss_debug_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_qdss_debug_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_sleep_clk_src[] = {
+ F(32000, P_SLEEP_CLK, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_sleep_clk_src = {
+ .cmd_rcgr = 0x13aa0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_4,
+ .freq_tbl = ftbl_cam_cc_sleep_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_sleep_clk_src",
+ .parent_data = cam_cc_parent_data_4,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_4),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_slow_ahb_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(80000000, P_CAM_CC_PLL0_OUT_EVEN, 7.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_slow_ahb_clk_src = {
+ .cmd_rcgr = 0x10148,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_0,
+ .freq_tbl = ftbl_cam_cc_slow_ahb_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_slow_ahb_clk_src",
+ .parent_data = cam_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_cam_cc_xo_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 cam_cc_xo_clk_src = {
+ .cmd_rcgr = 0x13a84,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = cam_cc_parent_map_5,
+ .freq_tbl = ftbl_cam_cc_xo_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_xo_clk_src",
+ .parent_data = cam_cc_parent_data_5,
+ .num_parents = ARRAY_SIZE(cam_cc_parent_data_5),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_branch cam_cc_bps_ahb_clk = {
+ .halt_reg = 0x10274,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10274,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_bps_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_bps_clk = {
+ .halt_reg = 0x103a4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x103a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_bps_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_bps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_bps_fast_ahb_clk = {
+ .halt_reg = 0x10144,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10144,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_bps_fast_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_axi_nrt_clk = {
+ .halt_reg = 0x13920,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x13920,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x13920,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_axi_nrt_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_camnoc_axi_rt_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_axi_rt_clk = {
+ .halt_reg = 0x13910,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x13910,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_axi_rt_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_camnoc_axi_rt_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_dcd_xo_clk = {
+ .halt_reg = 0x1392c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1392c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_dcd_xo_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_camnoc_xo_clk = {
+ .halt_reg = 0x13930,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x13930,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_camnoc_xo_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_cci_0_clk = {
+ .halt_reg = 0x13788,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x13788,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cci_0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cci_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_cci_1_clk = {
+ .halt_reg = 0x138b8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x138b8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cci_1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cci_1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_core_ahb_clk = {
+ .halt_reg = 0x13a80,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x13a80,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_core_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_cpas_ahb_clk = {
+ .halt_reg = 0x138bc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x138bc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cpas_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_cpas_bps_clk = {
+ .halt_reg = 0x103b0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x103b0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cpas_bps_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_bps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_cpas_fast_ahb_clk = {
+ .halt_reg = 0x138c8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x138c8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cpas_fast_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_cpas_ife_0_clk = {
+ .halt_reg = 0x11150,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11150,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cpas_ife_0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_cpas_ife_lite_clk = {
+ .halt_reg = 0x13138,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x13138,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cpas_ife_lite_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_lite_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_cpas_ipe_nps_clk = {
+ .halt_reg = 0x10504,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10504,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_cpas_ipe_nps_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ipe_nps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi0phytimer_clk = {
+ .halt_reg = 0x150f8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x150f8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi0phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi0phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi1phytimer_clk = {
+ .halt_reg = 0x1511c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1511c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi1phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi1phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi2phytimer_clk = {
+ .halt_reg = 0x15250,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x15250,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi2phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi2phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi3phytimer_clk = {
+ .halt_reg = 0x15384,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x15384,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi3phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi3phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi4phytimer_clk = {
+ .halt_reg = 0x154b8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x154b8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi4phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi4phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csi5phytimer_clk = {
+ .halt_reg = 0x155ec,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x155ec,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csi5phytimer_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csi5phytimer_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csid_clk = {
+ .halt_reg = 0x138ec,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x138ec,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csid_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_csid_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csid_csiphy_rx_clk = {
+ .halt_reg = 0x15100,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x15100,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csid_csiphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy0_clk = {
+ .halt_reg = 0x150fc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x150fc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csiphy0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy1_clk = {
+ .halt_reg = 0x15120,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x15120,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csiphy1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy2_clk = {
+ .halt_reg = 0x15254,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x15254,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csiphy2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy3_clk = {
+ .halt_reg = 0x15388,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x15388,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csiphy3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy4_clk = {
+ .halt_reg = 0x154bc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x154bc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csiphy4_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_csiphy5_clk = {
+ .halt_reg = 0x155f0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x155f0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_csiphy5_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_icp_ahb_clk = {
+ .halt_reg = 0x13658,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x13658,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_icp_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_icp_clk = {
+ .halt_reg = 0x1364c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1364c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_icp_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_icp_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_0_clk = {
+ .halt_reg = 0x11144,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11144,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ife_0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_0_dsp_clk = {
+ .halt_reg = 0x11154,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11154,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ife_0_dsp_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_0_fast_ahb_clk = {
+ .halt_reg = 0x11160,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x11160,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ife_0_fast_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_lite_ahb_clk = {
+ .halt_reg = 0x13278,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x13278,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ife_lite_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_lite_clk = {
+ .halt_reg = 0x1312c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1312c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ife_lite_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_lite_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_lite_cphy_rx_clk = {
+ .halt_reg = 0x13274,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x13274,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ife_lite_cphy_rx_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_cphy_rx_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ife_lite_csid_clk = {
+ .halt_reg = 0x13268,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x13268,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ife_lite_csid_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ife_lite_csid_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_nps_ahb_clk = {
+ .halt_reg = 0x1051c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1051c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ipe_nps_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_slow_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_nps_clk = {
+ .halt_reg = 0x104f8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x104f8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ipe_nps_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ipe_nps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_nps_fast_ahb_clk = {
+ .halt_reg = 0x10520,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10520,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ipe_nps_fast_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_pps_clk = {
+ .halt_reg = 0x10508,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10508,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ipe_pps_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_ipe_nps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_ipe_pps_fast_ahb_clk = {
+ .halt_reg = 0x10524,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x10524,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_ipe_pps_fast_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_fast_ahb_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_jpeg_clk = {
+ .halt_reg = 0x13508,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x13508,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_jpeg_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_jpeg_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_mclk0_clk = {
+ .halt_reg = 0x15018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x15018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_mclk0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_mclk1_clk = {
+ .halt_reg = 0x15034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x15034,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_mclk1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_mclk2_clk = {
+ .halt_reg = 0x15050,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x15050,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_mclk2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_mclk3_clk = {
+ .halt_reg = 0x1506c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1506c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_mclk3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_mclk4_clk = {
+ .halt_reg = 0x15088,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x15088,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_mclk4_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_mclk5_clk = {
+ .halt_reg = 0x150a4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x150a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_mclk5_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_mclk6_clk = {
+ .halt_reg = 0x150c0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x150c0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_mclk6_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk6_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_mclk7_clk = {
+ .halt_reg = 0x150dc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x150dc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_mclk7_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_mclk7_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_qdss_debug_clk = {
+ .halt_reg = 0x13a64,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x13a64,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_qdss_debug_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_qdss_debug_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch cam_cc_qdss_debug_xo_clk = {
+ .halt_reg = 0x13a68,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x13a68,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "cam_cc_qdss_debug_xo_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &cam_cc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc cam_cc_titan_top_gdsc = {
+ .gdscr = 0x13a6c,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "cam_cc_titan_top_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc cam_cc_bps_gdsc = {
+ .gdscr = 0x10004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "cam_cc_bps_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .parent = &cam_cc_titan_top_gdsc.pd,
+ .flags = HW_CTRL_TRIGGER | POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc cam_cc_ife_0_gdsc = {
+ .gdscr = 0x11004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "cam_cc_ife_0_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .parent = &cam_cc_titan_top_gdsc.pd,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc cam_cc_ipe_0_gdsc = {
+ .gdscr = 0x103b8,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "cam_cc_ipe_0_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .parent = &cam_cc_titan_top_gdsc.pd,
+ .flags = HW_CTRL_TRIGGER | POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct clk_regmap *cam_cc_x1p42100_clocks[] = {
+ [CAM_CC_BPS_AHB_CLK] = &cam_cc_bps_ahb_clk.clkr,
+ [CAM_CC_BPS_CLK] = &cam_cc_bps_clk.clkr,
+ [CAM_CC_BPS_CLK_SRC] = &cam_cc_bps_clk_src.clkr,
+ [CAM_CC_BPS_FAST_AHB_CLK] = &cam_cc_bps_fast_ahb_clk.clkr,
+ [CAM_CC_CAMNOC_AXI_NRT_CLK] = &cam_cc_camnoc_axi_nrt_clk.clkr,
+ [CAM_CC_CAMNOC_AXI_RT_CLK] = &cam_cc_camnoc_axi_rt_clk.clkr,
+ [CAM_CC_CAMNOC_AXI_RT_CLK_SRC] = &cam_cc_camnoc_axi_rt_clk_src.clkr,
+ [CAM_CC_CAMNOC_DCD_XO_CLK] = &cam_cc_camnoc_dcd_xo_clk.clkr,
+ [CAM_CC_CAMNOC_XO_CLK] = &cam_cc_camnoc_xo_clk.clkr,
+ [CAM_CC_CCI_0_CLK] = &cam_cc_cci_0_clk.clkr,
+ [CAM_CC_CCI_0_CLK_SRC] = &cam_cc_cci_0_clk_src.clkr,
+ [CAM_CC_CCI_1_CLK] = &cam_cc_cci_1_clk.clkr,
+ [CAM_CC_CCI_1_CLK_SRC] = &cam_cc_cci_1_clk_src.clkr,
+ [CAM_CC_CORE_AHB_CLK] = &cam_cc_core_ahb_clk.clkr,
+ [CAM_CC_CPAS_AHB_CLK] = &cam_cc_cpas_ahb_clk.clkr,
+ [CAM_CC_CPAS_BPS_CLK] = &cam_cc_cpas_bps_clk.clkr,
+ [CAM_CC_CPAS_FAST_AHB_CLK] = &cam_cc_cpas_fast_ahb_clk.clkr,
+ [CAM_CC_CPAS_IFE_0_CLK] = &cam_cc_cpas_ife_0_clk.clkr,
+ [CAM_CC_CPAS_IFE_LITE_CLK] = &cam_cc_cpas_ife_lite_clk.clkr,
+ [CAM_CC_CPAS_IPE_NPS_CLK] = &cam_cc_cpas_ipe_nps_clk.clkr,
+ [CAM_CC_CPHY_RX_CLK_SRC] = &cam_cc_cphy_rx_clk_src.clkr,
+ [CAM_CC_CSI0PHYTIMER_CLK] = &cam_cc_csi0phytimer_clk.clkr,
+ [CAM_CC_CSI0PHYTIMER_CLK_SRC] = &cam_cc_csi0phytimer_clk_src.clkr,
+ [CAM_CC_CSI1PHYTIMER_CLK] = &cam_cc_csi1phytimer_clk.clkr,
+ [CAM_CC_CSI1PHYTIMER_CLK_SRC] = &cam_cc_csi1phytimer_clk_src.clkr,
+ [CAM_CC_CSI2PHYTIMER_CLK] = &cam_cc_csi2phytimer_clk.clkr,
+ [CAM_CC_CSI2PHYTIMER_CLK_SRC] = &cam_cc_csi2phytimer_clk_src.clkr,
+ [CAM_CC_CSI3PHYTIMER_CLK] = &cam_cc_csi3phytimer_clk.clkr,
+ [CAM_CC_CSI3PHYTIMER_CLK_SRC] = &cam_cc_csi3phytimer_clk_src.clkr,
+ [CAM_CC_CSI4PHYTIMER_CLK] = &cam_cc_csi4phytimer_clk.clkr,
+ [CAM_CC_CSI4PHYTIMER_CLK_SRC] = &cam_cc_csi4phytimer_clk_src.clkr,
+ [CAM_CC_CSI5PHYTIMER_CLK] = &cam_cc_csi5phytimer_clk.clkr,
+ [CAM_CC_CSI5PHYTIMER_CLK_SRC] = &cam_cc_csi5phytimer_clk_src.clkr,
+ [CAM_CC_CSID_CLK] = &cam_cc_csid_clk.clkr,
+ [CAM_CC_CSID_CLK_SRC] = &cam_cc_csid_clk_src.clkr,
+ [CAM_CC_CSID_CSIPHY_RX_CLK] = &cam_cc_csid_csiphy_rx_clk.clkr,
+ [CAM_CC_CSIPHY0_CLK] = &cam_cc_csiphy0_clk.clkr,
+ [CAM_CC_CSIPHY1_CLK] = &cam_cc_csiphy1_clk.clkr,
+ [CAM_CC_CSIPHY2_CLK] = &cam_cc_csiphy2_clk.clkr,
+ [CAM_CC_CSIPHY3_CLK] = &cam_cc_csiphy3_clk.clkr,
+ [CAM_CC_CSIPHY4_CLK] = &cam_cc_csiphy4_clk.clkr,
+ [CAM_CC_CSIPHY5_CLK] = &cam_cc_csiphy5_clk.clkr,
+ [CAM_CC_FAST_AHB_CLK_SRC] = &cam_cc_fast_ahb_clk_src.clkr,
+ [CAM_CC_ICP_AHB_CLK] = &cam_cc_icp_ahb_clk.clkr,
+ [CAM_CC_ICP_CLK] = &cam_cc_icp_clk.clkr,
+ [CAM_CC_ICP_CLK_SRC] = &cam_cc_icp_clk_src.clkr,
+ [CAM_CC_IFE_0_CLK] = &cam_cc_ife_0_clk.clkr,
+ [CAM_CC_IFE_0_CLK_SRC] = &cam_cc_ife_0_clk_src.clkr,
+ [CAM_CC_IFE_0_DSP_CLK] = &cam_cc_ife_0_dsp_clk.clkr,
+ [CAM_CC_IFE_0_FAST_AHB_CLK] = &cam_cc_ife_0_fast_ahb_clk.clkr,
+ [CAM_CC_IFE_LITE_AHB_CLK] = &cam_cc_ife_lite_ahb_clk.clkr,
+ [CAM_CC_IFE_LITE_CLK] = &cam_cc_ife_lite_clk.clkr,
+ [CAM_CC_IFE_LITE_CLK_SRC] = &cam_cc_ife_lite_clk_src.clkr,
+ [CAM_CC_IFE_LITE_CPHY_RX_CLK] = &cam_cc_ife_lite_cphy_rx_clk.clkr,
+ [CAM_CC_IFE_LITE_CSID_CLK] = &cam_cc_ife_lite_csid_clk.clkr,
+ [CAM_CC_IFE_LITE_CSID_CLK_SRC] = &cam_cc_ife_lite_csid_clk_src.clkr,
+ [CAM_CC_IPE_NPS_AHB_CLK] = &cam_cc_ipe_nps_ahb_clk.clkr,
+ [CAM_CC_IPE_NPS_CLK] = &cam_cc_ipe_nps_clk.clkr,
+ [CAM_CC_IPE_NPS_CLK_SRC] = &cam_cc_ipe_nps_clk_src.clkr,
+ [CAM_CC_IPE_NPS_FAST_AHB_CLK] = &cam_cc_ipe_nps_fast_ahb_clk.clkr,
+ [CAM_CC_IPE_PPS_CLK] = &cam_cc_ipe_pps_clk.clkr,
+ [CAM_CC_IPE_PPS_FAST_AHB_CLK] = &cam_cc_ipe_pps_fast_ahb_clk.clkr,
+ [CAM_CC_JPEG_CLK] = &cam_cc_jpeg_clk.clkr,
+ [CAM_CC_JPEG_CLK_SRC] = &cam_cc_jpeg_clk_src.clkr,
+ [CAM_CC_MCLK0_CLK] = &cam_cc_mclk0_clk.clkr,
+ [CAM_CC_MCLK0_CLK_SRC] = &cam_cc_mclk0_clk_src.clkr,
+ [CAM_CC_MCLK1_CLK] = &cam_cc_mclk1_clk.clkr,
+ [CAM_CC_MCLK1_CLK_SRC] = &cam_cc_mclk1_clk_src.clkr,
+ [CAM_CC_MCLK2_CLK] = &cam_cc_mclk2_clk.clkr,
+ [CAM_CC_MCLK2_CLK_SRC] = &cam_cc_mclk2_clk_src.clkr,
+ [CAM_CC_MCLK3_CLK] = &cam_cc_mclk3_clk.clkr,
+ [CAM_CC_MCLK3_CLK_SRC] = &cam_cc_mclk3_clk_src.clkr,
+ [CAM_CC_MCLK4_CLK] = &cam_cc_mclk4_clk.clkr,
+ [CAM_CC_MCLK4_CLK_SRC] = &cam_cc_mclk4_clk_src.clkr,
+ [CAM_CC_MCLK5_CLK] = &cam_cc_mclk5_clk.clkr,
+ [CAM_CC_MCLK5_CLK_SRC] = &cam_cc_mclk5_clk_src.clkr,
+ [CAM_CC_MCLK6_CLK] = &cam_cc_mclk6_clk.clkr,
+ [CAM_CC_MCLK6_CLK_SRC] = &cam_cc_mclk6_clk_src.clkr,
+ [CAM_CC_MCLK7_CLK] = &cam_cc_mclk7_clk.clkr,
+ [CAM_CC_MCLK7_CLK_SRC] = &cam_cc_mclk7_clk_src.clkr,
+ [CAM_CC_PLL0] = &cam_cc_pll0.clkr,
+ [CAM_CC_PLL0_OUT_EVEN] = &cam_cc_pll0_out_even.clkr,
+ [CAM_CC_PLL0_OUT_ODD] = &cam_cc_pll0_out_odd.clkr,
+ [CAM_CC_PLL1] = &cam_cc_pll1.clkr,
+ [CAM_CC_PLL1_OUT_EVEN] = &cam_cc_pll1_out_even.clkr,
+ [CAM_CC_PLL2] = &cam_cc_pll2.clkr,
+ [CAM_CC_PLL3] = &cam_cc_pll3.clkr,
+ [CAM_CC_PLL3_OUT_EVEN] = &cam_cc_pll3_out_even.clkr,
+ [CAM_CC_PLL6] = &cam_cc_pll6.clkr,
+ [CAM_CC_PLL6_OUT_EVEN] = &cam_cc_pll6_out_even.clkr,
+ [CAM_CC_QDSS_DEBUG_CLK] = &cam_cc_qdss_debug_clk.clkr,
+ [CAM_CC_QDSS_DEBUG_CLK_SRC] = &cam_cc_qdss_debug_clk_src.clkr,
+ [CAM_CC_QDSS_DEBUG_XO_CLK] = &cam_cc_qdss_debug_xo_clk.clkr,
+ [CAM_CC_SLEEP_CLK_SRC] = &cam_cc_sleep_clk_src.clkr,
+ [CAM_CC_SLOW_AHB_CLK_SRC] = &cam_cc_slow_ahb_clk_src.clkr,
+ [CAM_CC_XO_CLK_SRC] = &cam_cc_xo_clk_src.clkr,
+};
+
+static struct gdsc *cam_cc_x1p42100_gdscs[] = {
+ [CAM_CC_BPS_GDSC] = &cam_cc_bps_gdsc,
+ [CAM_CC_IFE_0_GDSC] = &cam_cc_ife_0_gdsc,
+ [CAM_CC_IPE_0_GDSC] = &cam_cc_ipe_0_gdsc,
+ [CAM_CC_TITAN_TOP_GDSC] = &cam_cc_titan_top_gdsc,
+};
+
+static const struct qcom_reset_map cam_cc_x1p42100_resets[] = {
+ [CAM_CC_BPS_BCR] = { 0x10000 },
+ [CAM_CC_ICP_BCR] = { 0x1351c },
+ [CAM_CC_IFE_0_BCR] = { 0x11000 },
+ [CAM_CC_IPE_0_BCR] = { 0x103b4 },
+};
+
+static struct clk_alpha_pll *cam_cc_x1p42100_plls[] = {
+ &cam_cc_pll0,
+ &cam_cc_pll1,
+ &cam_cc_pll2,
+ &cam_cc_pll3,
+ &cam_cc_pll6,
+};
+
+static u32 cam_cc_x1p42100_critical_cbcrs[] = {
+ 0x13a9c, /* CAM_CC_GDSC_CLK */
+ 0x13ab8, /* CAM_CC_SLEEP_CLK */
+};
+
+static const struct regmap_config cam_cc_x1p42100_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x1603c,
+ .fast_io = true,
+};
+
+static struct qcom_cc_driver_data cam_cc_x1p42100_driver_data = {
+ .alpha_plls = cam_cc_x1p42100_plls,
+ .num_alpha_plls = ARRAY_SIZE(cam_cc_x1p42100_plls),
+ .clk_cbcrs = cam_cc_x1p42100_critical_cbcrs,
+ .num_clk_cbcrs = ARRAY_SIZE(cam_cc_x1p42100_critical_cbcrs),
+};
+
+static struct qcom_cc_desc cam_cc_x1p42100_desc = {
+ .config = &cam_cc_x1p42100_regmap_config,
+ .clks = cam_cc_x1p42100_clocks,
+ .num_clks = ARRAY_SIZE(cam_cc_x1p42100_clocks),
+ .resets = cam_cc_x1p42100_resets,
+ .num_resets = ARRAY_SIZE(cam_cc_x1p42100_resets),
+ .gdscs = cam_cc_x1p42100_gdscs,
+ .num_gdscs = ARRAY_SIZE(cam_cc_x1p42100_gdscs),
+ .use_rpm = true,
+ .driver_data = &cam_cc_x1p42100_driver_data,
+};
+
+static const struct of_device_id cam_cc_x1p42100_match_table[] = {
+ { .compatible = "qcom,x1p42100-camcc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, cam_cc_x1p42100_match_table);
+
+static int cam_cc_x1p42100_probe(struct platform_device *pdev)
+{
+ return qcom_cc_probe(pdev, &cam_cc_x1p42100_desc);
+}
+
+static struct platform_driver cam_cc_x1p42100_driver = {
+ .probe = cam_cc_x1p42100_probe,
+ .driver = {
+ .name = "camcc-x1p42100",
+ .of_match_table = cam_cc_x1p42100_match_table,
+ },
+};
+
+module_platform_driver(cam_cc_x1p42100_driver);
+
+MODULE_DESCRIPTION("QTI CAMCC X1P42100 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h
index 42d334492145..3a2157bebc52 100644
--- a/drivers/clk/qcom/clk-alpha-pll.h
+++ b/drivers/clk/qcom/clk-alpha-pll.h
@@ -31,6 +31,7 @@ enum {
CLK_ALPHA_PLL_TYPE_PONGO_EKO_T = CLK_ALPHA_PLL_TYPE_PONGO_ELU,
CLK_ALPHA_PLL_TYPE_TAYCAN_ELU,
CLK_ALPHA_PLL_TYPE_TAYCAN_EKO_T = CLK_ALPHA_PLL_TYPE_TAYCAN_ELU,
+ CLK_ALPHA_PLL_TYPE_TAYCAN_EHA_T = CLK_ALPHA_PLL_TYPE_TAYCAN_ELU,
CLK_ALPHA_PLL_TYPE_RIVIAN_EVO,
CLK_ALPHA_PLL_TYPE_RIVIAN_ELU,
CLK_ALPHA_PLL_TYPE_RIVIAN_EKO_T = CLK_ALPHA_PLL_TYPE_RIVIAN_ELU,
@@ -198,16 +199,19 @@ extern const struct clk_ops clk_alpha_pll_zonda_ops;
extern const struct clk_ops clk_alpha_pll_lucid_evo_ops;
#define clk_alpha_pll_taycan_elu_ops clk_alpha_pll_lucid_evo_ops
#define clk_alpha_pll_taycan_eko_t_ops clk_alpha_pll_lucid_evo_ops
+#define clk_alpha_pll_taycan_eha_t_ops clk_alpha_pll_lucid_evo_ops
extern const struct clk_ops clk_alpha_pll_reset_lucid_evo_ops;
#define clk_alpha_pll_reset_lucid_ole_ops clk_alpha_pll_reset_lucid_evo_ops
extern const struct clk_ops clk_alpha_pll_fixed_lucid_evo_ops;
#define clk_alpha_pll_fixed_lucid_ole_ops clk_alpha_pll_fixed_lucid_evo_ops
#define clk_alpha_pll_fixed_taycan_elu_ops clk_alpha_pll_fixed_lucid_evo_ops
#define clk_alpha_pll_fixed_taycan_eko_t_ops clk_alpha_pll_fixed_lucid_evo_ops
+#define clk_alpha_pll_fixed_taycan_eha_t_ops clk_alpha_pll_fixed_lucid_evo_ops
extern const struct clk_ops clk_alpha_pll_postdiv_lucid_evo_ops;
#define clk_alpha_pll_postdiv_lucid_ole_ops clk_alpha_pll_postdiv_lucid_evo_ops
#define clk_alpha_pll_postdiv_taycan_elu_ops clk_alpha_pll_postdiv_lucid_evo_ops
#define clk_alpha_pll_postdiv_taycan_eko_t_ops clk_alpha_pll_postdiv_lucid_evo_ops
+#define clk_alpha_pll_postdiv_taycan_eha_t_ops clk_alpha_pll_postdiv_lucid_evo_ops
extern const struct clk_ops clk_alpha_pll_pongo_elu_ops;
#define clk_alpha_pll_pongo_eko_t_ops clk_alpha_pll_pongo_elu_ops
@@ -246,6 +250,8 @@ void clk_pongo_elu_pll_configure(struct clk_alpha_pll *pll, struct regmap *regma
clk_lucid_evo_pll_configure(pll, regmap, config)
#define clk_taycan_eko_t_pll_configure(pll, regmap, config) \
clk_lucid_evo_pll_configure(pll, regmap, config)
+#define clk_taycan_eha_t_pll_configure(pll, regmap, config) \
+ clk_lucid_evo_pll_configure(pll, regmap, config)
void clk_rivian_evo_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
const struct alpha_pll_config *config);
diff --git a/drivers/clk/qcom/clk-regmap-phy-mux.c b/drivers/clk/qcom/clk-regmap-phy-mux.c
index 7b7243b7107d..b7d1c69d62f7 100644
--- a/drivers/clk/qcom/clk-regmap-phy-mux.c
+++ b/drivers/clk/qcom/clk-regmap-phy-mux.c
@@ -15,48 +15,66 @@
#define PHY_MUX_PHY_SRC 0
#define PHY_MUX_REF_SRC 2
+#define XO_RATE 19200000UL
+
static inline struct clk_regmap_phy_mux *to_clk_regmap_phy_mux(struct clk_regmap *clkr)
{
return container_of(clkr, struct clk_regmap_phy_mux, clkr);
}
-static int phy_mux_is_enabled(struct clk_hw *hw)
+static unsigned long phy_mux_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
{
struct clk_regmap *clkr = to_clk_regmap(hw);
struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(clkr);
- unsigned int val;
+ u32 val;
regmap_read(clkr->regmap, phy_mux->reg, &val);
- val = FIELD_GET(PHY_MUX_MASK, val);
-
- WARN_ON(val != PHY_MUX_PHY_SRC && val != PHY_MUX_REF_SRC);
- return val == PHY_MUX_PHY_SRC;
+ switch (FIELD_GET(PHY_MUX_MASK, val)) {
+ case PHY_MUX_PHY_SRC:
+ return ULONG_MAX;
+ case PHY_MUX_REF_SRC:
+ return XO_RATE;
+ default:
+ return 0;
+ }
}
-static int phy_mux_enable(struct clk_hw *hw)
+static int phy_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
{
- struct clk_regmap *clkr = to_clk_regmap(hw);
- struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(clkr);
+ if (req->rate == XO_RATE || req->rate == ULONG_MAX)
+ return 0;
- return regmap_update_bits(clkr->regmap, phy_mux->reg,
- PHY_MUX_MASK,
- FIELD_PREP(PHY_MUX_MASK, PHY_MUX_PHY_SRC));
+ return -EINVAL;
}
-static void phy_mux_disable(struct clk_hw *hw)
+static int phy_mux_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
{
struct clk_regmap *clkr = to_clk_regmap(hw);
struct clk_regmap_phy_mux *phy_mux = to_clk_regmap_phy_mux(clkr);
+ u32 val;
+
+ switch (rate) {
+ case XO_RATE:
+ val = PHY_MUX_REF_SRC;
+ break;
+ case ULONG_MAX:
+ val = PHY_MUX_PHY_SRC;
+ break;
+ default:
+ return -EINVAL;
+ }
regmap_update_bits(clkr->regmap, phy_mux->reg,
PHY_MUX_MASK,
- FIELD_PREP(PHY_MUX_MASK, PHY_MUX_REF_SRC));
+ FIELD_PREP(PHY_MUX_MASK, val));
+
+ return 0;
}
const struct clk_ops clk_regmap_phy_mux_ops = {
- .enable = phy_mux_enable,
- .disable = phy_mux_disable,
- .is_enabled = phy_mux_is_enabled,
+ .recalc_rate = phy_mux_recalc_rate,
+ .determine_rate = phy_mux_determine_rate,
+ .set_rate = phy_mux_set_rate,
};
EXPORT_SYMBOL_GPL(clk_regmap_phy_mux_ops);
diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c
index 339a6bbcdc4c..6367b2a5a4e0 100644
--- a/drivers/clk/qcom/clk-rpmh.c
+++ b/drivers/clk/qcom/clk-rpmh.c
@@ -66,8 +66,6 @@ struct clk_rpmh {
struct clk_rpmh_desc {
struct clk_hw **clks;
size_t num_clks;
- /* RPMh clock clkaN are optional for this platform */
- bool clka_optional;
};
static DEFINE_MUTEX(rpmh_clk_lock);
@@ -409,7 +407,9 @@ DEFINE_CLK_RPMH_VRM(clk5, _a2_e0, "C5A_E0", 2);
DEFINE_CLK_RPMH_VRM(clk6, _a2_e0, "C6A_E0", 2);
DEFINE_CLK_RPMH_VRM(clk7, _a2_e0, "C7A_E0", 2);
DEFINE_CLK_RPMH_VRM(clk8, _a2_e0, "C8A_E0", 2);
+DEFINE_CLK_RPMH_VRM(clk9, _a2_e0, "C9A_E0", 2);
+DEFINE_CLK_RPMH_VRM(clk7, _a4_e0, "C7A_E0", 4);
DEFINE_CLK_RPMH_VRM(clk11, _a4_e0, "C11A_E0", 4);
DEFINE_CLK_RPMH_BCM(ce, "CE0");
@@ -697,7 +697,6 @@ static struct clk_hw *sm8550_rpmh_clocks[] = {
static const struct clk_rpmh_desc clk_rpmh_sm8550 = {
.clks = sm8550_rpmh_clocks,
.num_clks = ARRAY_SIZE(sm8550_rpmh_clocks),
- .clka_optional = true,
};
static struct clk_hw *sm8650_rpmh_clocks[] = {
@@ -729,7 +728,6 @@ static struct clk_hw *sm8650_rpmh_clocks[] = {
static const struct clk_rpmh_desc clk_rpmh_sm8650 = {
.clks = sm8650_rpmh_clocks,
.num_clks = ARRAY_SIZE(sm8650_rpmh_clocks),
- .clka_optional = true,
};
static struct clk_hw *sc7280_rpmh_clocks[] = {
@@ -899,7 +897,6 @@ static struct clk_hw *sm8750_rpmh_clocks[] = {
static const struct clk_rpmh_desc clk_rpmh_sm8750 = {
.clks = sm8750_rpmh_clocks,
.num_clks = ARRAY_SIZE(sm8750_rpmh_clocks),
- .clka_optional = true,
};
static struct clk_hw *glymur_rpmh_clocks[] = {
@@ -984,6 +981,36 @@ static const struct clk_rpmh_desc clk_rpmh_nord = {
.num_clks = ARRAY_SIZE(nord_rpmh_clocks),
};
+static struct clk_hw *hawi_rpmh_clocks[] = {
+ [RPMH_CXO_CLK] = &clk_rpmh_bi_tcxo_div2.hw,
+ [RPMH_CXO_CLK_A] = &clk_rpmh_bi_tcxo_div2_ao.hw,
+ [RPMH_DIV_CLK1] = &clk_rpmh_clk11_a4_e0.hw,
+ [RPMH_LN_BB_CLK1] = &clk_rpmh_clk6_a2_e0.hw,
+ [RPMH_LN_BB_CLK1_A] = &clk_rpmh_clk6_a2_e0_ao.hw,
+ [RPMH_LN_BB_CLK2] = &clk_rpmh_clk7_a4_e0.hw,
+ [RPMH_LN_BB_CLK2_A] = &clk_rpmh_clk7_a4_e0_ao.hw,
+ [RPMH_LN_BB_CLK3] = &clk_rpmh_clk8_a2_e0.hw,
+ [RPMH_LN_BB_CLK3_A] = &clk_rpmh_clk8_a2_e0_ao.hw,
+ [RPMH_LN_BB_CLK4] = &clk_rpmh_clk9_a2_e0.hw,
+ [RPMH_LN_BB_CLK4_A] = &clk_rpmh_clk9_a2_e0_ao.hw,
+ [RPMH_RF_CLK1] = &clk_rpmh_clk1_a1_e0.hw,
+ [RPMH_RF_CLK1_A] = &clk_rpmh_clk1_a1_e0_ao.hw,
+ [RPMH_RF_CLK2] = &clk_rpmh_clk2_a1_e0.hw,
+ [RPMH_RF_CLK2_A] = &clk_rpmh_clk2_a1_e0_ao.hw,
+ [RPMH_RF_CLK3] = &clk_rpmh_clk3_a2_e0.hw,
+ [RPMH_RF_CLK3_A] = &clk_rpmh_clk3_a2_e0_ao.hw,
+ [RPMH_RF_CLK4] = &clk_rpmh_clk4_a2_e0.hw,
+ [RPMH_RF_CLK4_A] = &clk_rpmh_clk4_a2_e0_ao.hw,
+ [RPMH_RF_CLK5] = &clk_rpmh_clk5_a2_e0.hw,
+ [RPMH_RF_CLK5_A] = &clk_rpmh_clk5_a2_e0_ao.hw,
+ [RPMH_IPA_CLK] = &clk_rpmh_ipa.hw,
+};
+
+static const struct clk_rpmh_desc clk_rpmh_hawi = {
+ .clks = hawi_rpmh_clocks,
+ .num_clks = ARRAY_SIZE(hawi_rpmh_clocks),
+};
+
static struct clk_hw *of_clk_rpmh_hw_get(struct of_phandle_args *clkspec,
void *data)
{
@@ -1027,8 +1054,7 @@ static int clk_rpmh_probe(struct platform_device *pdev)
if (!res_addr) {
hw_clks[i] = NULL;
- if (desc->clka_optional &&
- !strncmp(rpmh_clk->res_name, "clka", sizeof("clka") - 1))
+ if (rpmh_clk->res_addr == CLK_RPMH_VRM_EN_OFFSET)
continue;
dev_err(&pdev->dev, "missing RPMh resource address for %s\n",
@@ -1075,6 +1101,7 @@ static int clk_rpmh_probe(struct platform_device *pdev)
static const struct of_device_id clk_rpmh_match_table[] = {
{ .compatible = "qcom,eliza-rpmh-clk", .data = &clk_rpmh_eliza},
{ .compatible = "qcom,glymur-rpmh-clk", .data = &clk_rpmh_glymur},
+ { .compatible = "qcom,hawi-rpmh-clk", .data = &clk_rpmh_hawi},
{ .compatible = "qcom,kaanapali-rpmh-clk", .data = &clk_rpmh_kaanapali},
{ .compatible = "qcom,milos-rpmh-clk", .data = &clk_rpmh_milos},
{ .compatible = "qcom,nord-rpmh-clk", .data = &clk_rpmh_nord},
diff --git a/drivers/clk/qcom/dispcc-x1e80100.c b/drivers/clk/qcom/dispcc-x1e80100.c
index cd45bedf2649..1d7c569dc082 100644
--- a/drivers/clk/qcom/dispcc-x1e80100.c
+++ b/drivers/clk/qcom/dispcc-x1e80100.c
@@ -1634,7 +1634,7 @@ static const struct regmap_config disp_cc_x1e80100_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
- .max_register = 0x11008,
+ .max_register = 0xf004, /* 0x10000, 0x10004 and maybe others are for TZ */
.fast_io = true,
};
diff --git a/drivers/clk/qcom/gcc-hawi.c b/drivers/clk/qcom/gcc-hawi.c
new file mode 100644
index 000000000000..6dd07c772c29
--- /dev/null
+++ b/drivers/clk/qcom/gcc-hawi.c
@@ -0,0 +1,3657 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,hawi-gcc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+#include "clk-regmap-phy-mux.h"
+#include "common.h"
+#include "gdsc.h"
+#include "reset.h"
+
+enum {
+ DT_BI_TCXO,
+ DT_BI_TCXO_AO,
+ DT_SLEEP_CLK,
+ DT_PCIE_0_PIPE_CLK,
+ DT_PCIE_1_PIPE_CLK,
+ DT_UFS_PHY_RX_SYMBOL_0_CLK,
+ DT_UFS_PHY_RX_SYMBOL_1_CLK,
+ DT_UFS_PHY_TX_SYMBOL_0_CLK,
+ DT_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK,
+};
+
+enum {
+ P_BI_TCXO,
+ P_GCC_GPLL0_OUT_EVEN,
+ P_GCC_GPLL0_OUT_MAIN,
+ P_GCC_GPLL4_OUT_MAIN,
+ P_GCC_GPLL5_OUT_MAIN,
+ P_GCC_GPLL7_OUT_MAIN,
+ P_GCC_GPLL9_OUT_MAIN,
+ P_PCIE_0_PIPE_CLK,
+ P_PCIE_1_PIPE_CLK,
+ P_SLEEP_CLK,
+ P_UFS_PHY_RX_SYMBOL_0_CLK,
+ P_UFS_PHY_RX_SYMBOL_1_CLK,
+ P_UFS_PHY_TX_SYMBOL_0_CLK,
+ P_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK,
+};
+
+static struct clk_alpha_pll gcc_gpll0 = {
+ .offset = 0x0,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EHA_T],
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll0",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_taycan_eha_t_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gcc_gpll0_out_even[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gcc_gpll0_out_even = {
+ .offset = 0x0,
+ .post_div_shift = 10,
+ .post_div_table = post_div_table_gcc_gpll0_out_even,
+ .num_post_div = ARRAY_SIZE(post_div_table_gcc_gpll0_out_even),
+ .width = 4,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EHA_T],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll0_out_even",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_taycan_eha_t_ops,
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll4 = {
+ .offset = 0x4000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EHA_T],
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll4",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_taycan_eha_t_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll5 = {
+ .offset = 0x5000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EHA_T],
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(5),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll5",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_taycan_eha_t_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll7 = {
+ .offset = 0x7000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EHA_T],
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(7),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll7",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_taycan_eha_t_ops,
+ },
+ },
+};
+
+static struct clk_alpha_pll gcc_gpll9 = {
+ .offset = 0x9000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_TAYCAN_EHA_T],
+ .clkr = {
+ .enable_reg = 0x52028,
+ .enable_mask = BIT(9),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpll9",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_taycan_eha_t_ops,
+ },
+ },
+};
+
+static const struct parent_map gcc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_0[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL7_OUT_MAIN, 2 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_1[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll7.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_SLEEP_CLK, 5 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_2[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .index = DT_SLEEP_CLK },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_3[] = {
+ { P_BI_TCXO, 0 },
+};
+
+static const struct clk_parent_data gcc_parent_data_3[] = {
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map gcc_parent_map_4[] = {
+ { P_BI_TCXO, 0 },
+ { P_SLEEP_CLK, 5 },
+};
+
+static const struct clk_parent_data gcc_parent_data_4[] = {
+ { .index = DT_BI_TCXO },
+ { .index = DT_SLEEP_CLK },
+};
+
+static const struct parent_map gcc_parent_map_5[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL5_OUT_MAIN, 3 },
+ { P_GCC_GPLL4_OUT_MAIN, 5 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_5[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll5.clkr.hw },
+ { .hw = &gcc_gpll4.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_8[] = {
+ { P_BI_TCXO, 0 },
+ { P_GCC_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL9_OUT_MAIN, 2 },
+ { P_GCC_GPLL4_OUT_MAIN, 5 },
+ { P_GCC_GPLL0_OUT_EVEN, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_8[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &gcc_gpll0.clkr.hw },
+ { .hw = &gcc_gpll9.clkr.hw },
+ { .hw = &gcc_gpll4.clkr.hw },
+ { .hw = &gcc_gpll0_out_even.clkr.hw },
+};
+
+static struct clk_regmap_phy_mux gcc_pcie_0_pipe_clk_src = {
+ .reg = 0x6b0a8,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_PCIE_0_PIPE_CLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_pcie_1_pipe_clk_src = {
+ .reg = 0x670a4,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_PCIE_1_PIPE_CLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_ufs_phy_rx_symbol_0_clk_src = {
+ .reg = 0x77068,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_rx_symbol_0_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_UFS_PHY_RX_SYMBOL_0_CLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_ufs_phy_rx_symbol_1_clk_src = {
+ .reg = 0x770ec,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_rx_symbol_1_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_UFS_PHY_RX_SYMBOL_1_CLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_ufs_phy_tx_symbol_0_clk_src = {
+ .reg = 0x77058,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_tx_symbol_0_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_UFS_PHY_TX_SYMBOL_0_CLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_usb3_prim_phy_pipe_clk_src = {
+ .reg = 0x39074,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_USB3_PHY_WRAPPER_GCC_USB30_PIPE_CLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_gp1_clk_src[] = {
+ F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0),
+ F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_gp1_clk_src = {
+ .cmd_rcgr = 0x64004,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp1_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_gp2_clk_src = {
+ .cmd_rcgr = 0x65004,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp2_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_gp3_clk_src = {
+ .cmd_rcgr = 0x66004,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_gp1_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp3_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pcie_0_aux_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pcie_0_aux_clk_src = {
+ .cmd_rcgr = 0x6b0ac,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_aux_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_0_phy_aux_clk_src = {
+ .cmd_rcgr = 0x6b0c4,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pcie_0_phy_rchng_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pcie_0_phy_rchng_clk_src = {
+ .cmd_rcgr = 0x6b08c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_phy_rchng_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_1_aux_clk_src = {
+ .cmd_rcgr = 0x670a8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_aux_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_1_phy_aux_clk_src = {
+ .cmd_rcgr = 0x670c0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie_1_phy_rchng_clk_src = {
+ .cmd_rcgr = 0x67088,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_phy_rchng_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_phy_rchng_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pdm2_clk_src[] = {
+ F(60000000, P_GCC_GPLL0_OUT_MAIN, 10, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pdm2_clk_src = {
+ .cmd_rcgr = 0x33010,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pdm2_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_i2c_s0_clk_src = {
+ .cmd_rcgr = 0x17008,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s0_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_i2c_s1_clk_src = {
+ .cmd_rcgr = 0x17024,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s1_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_i2c_s2_clk_src = {
+ .cmd_rcgr = 0x17040,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_i2c_s3_clk_src = {
+ .cmd_rcgr = 0x1705c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s3_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_i2c_s4_clk_src = {
+ .cmd_rcgr = 0x17078,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s4_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap1_qspi_ref_clk_src[] = {
+ F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625),
+ F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625),
+ F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75),
+ F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25),
+ F(51200000, P_GCC_GPLL0_OUT_EVEN, 1, 64, 375),
+ F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75),
+ F(66666667, P_GCC_GPLL0_OUT_MAIN, 9, 0, 0),
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15),
+ F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25),
+ F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(102400000, P_GCC_GPLL0_OUT_EVEN, 1, 128, 375),
+ F(112000000, P_GCC_GPLL0_OUT_EVEN, 1, 28, 75),
+ F(117964800, P_GCC_GPLL0_OUT_EVEN, 1, 6144, 15625),
+ F(120000000, P_GCC_GPLL0_OUT_EVEN, 2.5, 0, 0),
+ F(150000000, P_GCC_GPLL0_OUT_EVEN, 2, 0, 0),
+ F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_qspi_ref_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_qspi_ref_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_qspi_ref_clk_src = {
+ .cmd_rcgr = 0x188c0,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_qspi_ref_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap1_qspi_ref_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap1_s0_clk_src[] = {
+ F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625),
+ F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625),
+ F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75),
+ F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25),
+ F(51200000, P_GCC_GPLL0_OUT_EVEN, 1, 64, 375),
+ F(60000000, P_GCC_GPLL0_OUT_EVEN, 5, 0, 0),
+ F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75),
+ F(66666667, P_GCC_GPLL0_OUT_MAIN, 9, 0, 0),
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15),
+ F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25),
+ F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s0_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s0_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = {
+ .cmd_rcgr = 0x18014,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s0_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s1_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s1_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = {
+ .cmd_rcgr = 0x18150,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s3_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s3_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = {
+ .cmd_rcgr = 0x182a0,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s3_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap1_s4_clk_src[] = {
+ F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625),
+ F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625),
+ F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75),
+ F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25),
+ F(51200000, P_GCC_GPLL0_OUT_EVEN, 1, 64, 375),
+ F(60000000, P_GCC_GPLL0_OUT_EVEN, 5, 0, 0),
+ F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75),
+ F(66666667, P_GCC_GPLL0_OUT_MAIN, 9, 0, 0),
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15),
+ F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25),
+ F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(102400000, P_GCC_GPLL0_OUT_EVEN, 1, 128, 375),
+ F(112000000, P_GCC_GPLL0_OUT_EVEN, 1, 28, 75),
+ F(117964800, P_GCC_GPLL0_OUT_EVEN, 1, 6144, 15625),
+ F(120000000, P_GCC_GPLL0_OUT_MAIN, 5, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s4_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s4_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = {
+ .cmd_rcgr = 0x183dc,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s4_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s5_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s5_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = {
+ .cmd_rcgr = 0x18518,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s5_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s6_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s6_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = {
+ .cmd_rcgr = 0x18654,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s6_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap1_s7_clk_src_init = {
+ .name = "gcc_qupv3_wrap1_s7_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = {
+ .cmd_rcgr = 0x18790,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap1_s7_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s0_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s0_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s0_clk_src = {
+ .cmd_rcgr = 0x1e01c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s0_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s1_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s1_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s1_clk_src = {
+ .cmd_rcgr = 0x1e160,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s1_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s2_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s2_clk_src = {
+ .cmd_rcgr = 0x1e29c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s2_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s3_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s3_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s3_clk_src = {
+ .cmd_rcgr = 0x1e3d8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s3_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap2_s4_clk_src_init = {
+ .name = "gcc_qupv3_wrap2_s4_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap2_s4_clk_src = {
+ .cmd_rcgr = 0x1e514,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap2_s4_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap3_qspi_ref_clk_src[] = {
+ F(7372800, P_GCC_GPLL0_OUT_EVEN, 1, 384, 15625),
+ F(14745600, P_GCC_GPLL0_OUT_EVEN, 1, 768, 15625),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ F(29491200, P_GCC_GPLL0_OUT_EVEN, 1, 1536, 15625),
+ F(32000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 75),
+ F(48000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 25),
+ F(51200000, P_GCC_GPLL0_OUT_EVEN, 1, 64, 375),
+ F(64000000, P_GCC_GPLL0_OUT_EVEN, 1, 16, 75),
+ F(66666667, P_GCC_GPLL0_OUT_MAIN, 9, 0, 0),
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ F(80000000, P_GCC_GPLL0_OUT_EVEN, 1, 4, 15),
+ F(96000000, P_GCC_GPLL0_OUT_EVEN, 1, 8, 25),
+ F(100000000, P_GCC_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(102400000, P_GCC_GPLL0_OUT_EVEN, 1, 128, 375),
+ F(112000000, P_GCC_GPLL0_OUT_EVEN, 1, 28, 75),
+ F(117964800, P_GCC_GPLL0_OUT_EVEN, 1, 6144, 15625),
+ F(120000000, P_GCC_GPLL0_OUT_EVEN, 2.5, 0, 0),
+ F(150000000, P_GCC_GPLL0_OUT_EVEN, 2, 0, 0),
+ F(240000000, P_GCC_GPLL0_OUT_MAIN, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_init_data gcc_qupv3_wrap3_qspi_ref_clk_src_init = {
+ .name = "gcc_qupv3_wrap3_qspi_ref_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap3_qspi_ref_clk_src = {
+ .cmd_rcgr = 0xa8650,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap3_qspi_ref_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap3_qspi_ref_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap3_s0_clk_src_init = {
+ .name = "gcc_qupv3_wrap3_s0_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap3_s0_clk_src = {
+ .cmd_rcgr = 0xa8014,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap3_s0_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap3_s2_clk_src_init = {
+ .name = "gcc_qupv3_wrap3_s2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap3_s2_clk_src = {
+ .cmd_rcgr = 0xa8168,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap3_s2_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap3_s3_clk_src_init = {
+ .name = "gcc_qupv3_wrap3_s3_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap3_s3_clk_src = {
+ .cmd_rcgr = 0xa82a4,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap3_s3_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap3_s4_clk_src_init = {
+ .name = "gcc_qupv3_wrap3_s4_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap3_s4_clk_src = {
+ .cmd_rcgr = 0xa83e0,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap3_s4_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap3_s5_clk_src_init = {
+ .name = "gcc_qupv3_wrap3_s5_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap3_s5_clk_src = {
+ .cmd_rcgr = 0xa851c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap3_s5_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap4_s0_clk_src_init = {
+ .name = "gcc_qupv3_wrap4_s0_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap4_s0_clk_src = {
+ .cmd_rcgr = 0xa9014,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap4_s0_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap4_s1_clk_src_init = {
+ .name = "gcc_qupv3_wrap4_s1_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap4_s1_clk_src = {
+ .cmd_rcgr = 0xa9150,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap4_s1_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap4_s2_clk_src_init = {
+ .name = "gcc_qupv3_wrap4_s2_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap4_s2_clk_src = {
+ .cmd_rcgr = 0xa928c,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s4_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap4_s2_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap4_s3_clk_src_init = {
+ .name = "gcc_qupv3_wrap4_s3_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap4_s3_clk_src = {
+ .cmd_rcgr = 0xa93c8,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap4_s3_clk_src_init,
+};
+
+static struct clk_init_data gcc_qupv3_wrap4_s4_clk_src_init = {
+ .name = "gcc_qupv3_wrap4_s4_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap4_s4_clk_src = {
+ .cmd_rcgr = 0xa9504,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_qupv3_wrap1_s0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &gcc_qupv3_wrap4_s4_clk_src_init,
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc2_apps_clk_src[] = {
+ F(400000, P_BI_TCXO, 12, 1, 4),
+ F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0),
+ F(37500000, P_GCC_GPLL0_OUT_EVEN, 8, 0, 0),
+ F(50000000, P_GCC_GPLL0_OUT_EVEN, 6, 0, 0),
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0),
+ F(202000000, P_GCC_GPLL9_OUT_MAIN, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc2_apps_clk_src = {
+ .cmd_rcgr = 0x1401c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_8,
+ .freq_tbl = ftbl_gcc_sdcc2_apps_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc2_apps_clk_src",
+ .parent_data = gcc_parent_data_8,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_8),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_floor_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src[] = {
+ F(400000, P_BI_TCXO, 12, 1, 4),
+ F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0),
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc4_apps_clk_src = {
+ .cmd_rcgr = 0x1601c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_sdcc4_apps_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc4_apps_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_floor_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_phy_axi_clk_src[] = {
+ F(25000000, P_GCC_GPLL0_OUT_EVEN, 12, 0, 0),
+ F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0),
+ F(225000000, P_GCC_GPLL5_OUT_MAIN, 4, 0, 0),
+ F(450000000, P_GCC_GPLL5_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = {
+ .cmd_rcgr = 0x77034,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_ufs_phy_axi_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_axi_clk_src",
+ .parent_data = gcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_5),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_phy_ice_core_clk_src[] = {
+ F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0),
+ F(225000000, P_GCC_GPLL5_OUT_MAIN, 4, 0, 0),
+ F(450000000, P_GCC_GPLL5_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = {
+ .cmd_rcgr = 0x7708c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_ufs_phy_ice_core_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_ice_core_clk_src",
+ .parent_data = gcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_5),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_phy_phy_aux_clk_src[] = {
+ F(9600000, P_BI_TCXO, 2, 0, 0),
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = {
+ .cmd_rcgr = 0x770c0,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_ufs_phy_phy_aux_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_ufs_phy_unipro_5_core_clk_src[] = {
+ F(75000000, P_GCC_GPLL0_OUT_EVEN, 4, 0, 0),
+ F(100000000, P_GCC_GPLL0_OUT_EVEN, 3, 0, 0),
+ F(201500000, P_GCC_GPLL4_OUT_MAIN, 4, 0, 0),
+ F(403000000, P_GCC_GPLL4_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_ufs_phy_unipro_5_core_clk_src = {
+ .cmd_rcgr = 0x770a4,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_ufs_phy_unipro_5_core_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_unipro_5_core_clk_src",
+ .parent_data = gcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_5),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb30_prim_master_clk_src[] = {
+ F(66666667, P_GCC_GPLL0_OUT_EVEN, 4.5, 0, 0),
+ F(133333333, P_GCC_GPLL0_OUT_MAIN, 4.5, 0, 0),
+ F(200000000, P_GCC_GPLL0_OUT_MAIN, 3, 0, 0),
+ F(240000000, P_GCC_GPLL0_OUT_MAIN, 2.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_usb30_prim_master_clk_src = {
+ .cmd_rcgr = 0x39034,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_usb30_prim_master_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_master_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x3904c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_mock_utmi_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = {
+ .cmd_rcgr = 0x39078,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_aux_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_no_init_park_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_pcie_0_pipe_div_clk_src = {
+ .reg = 0x6b0a4,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_pipe_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_pcie_1_pipe_div_clk_src = {
+ .reg = 0x670a0,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_pipe_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_qupv3_wrap1_s2_clk_src = {
+ .reg = 0x1828c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s2_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_qspi_ref_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_qupv3_wrap3_s1_clk_src = {
+ .reg = 0xa8154,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap3_s1_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap3_qspi_ref_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_usb30_prim_mock_utmi_postdiv_clk_src = {
+ .reg = 0x39064,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_mock_utmi_postdiv_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_mock_utmi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_branch gcc_aggre_noc_pcie_axi_clk = {
+ .halt_reg = 0x10068,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x10068,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(24),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_noc_pcie_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_stardustnoc_usb3_prim_axi_clk = {
+ .halt_reg = 0x39094,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x39094,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x39094,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_stardustnoc_usb3_prim_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre_ufs_phy_axi_clk = {
+ .halt_reg = 0x770f0,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x770f0,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x770f0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_aggre_ufs_phy_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_boot_rom_ahb_clk = {
+ .halt_reg = 0x38004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x38004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(18),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_boot_rom_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camera_hf_axi_clk = {
+ .halt_reg = 0x26014,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x26014,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x26014,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camera_hf_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_camera_sf_axi_clk = {
+ .halt_reg = 0x2601c,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x2601c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x2601c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_camera_sf_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_pcie_anoc_ahb_clk = {
+ .halt_reg = 0x10050,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x10050,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(20),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cfg_noc_pcie_anoc_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cfg_noc_usb3_prim_axi_clk = {
+ .halt_reg = 0x39090,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x39090,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x39090,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cfg_noc_usb3_prim_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cnoc_pcie_sf_axi_clk = {
+ .halt_reg = 0x10058,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(6),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cnoc_pcie_sf_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_eva_axi0_clk = {
+ .halt_reg = 0x9f008,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x9f008,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x9f008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_eva_axi0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_eva_axi0c_clk = {
+ .halt_reg = 0x9f010,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x9f010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x9f010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_eva_axi0c_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp1_clk = {
+ .halt_reg = 0x64000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x64000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp2_clk = {
+ .halt_reg = 0x65000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x65000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gp3_clk = {
+ .halt_reg = 0x66000,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x66000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gp3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gp3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_gemnoc_gfx_clk = {
+ .halt_reg = 0x71010,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x71010,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x71010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpu_gemnoc_gfx_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_gpll0_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(15),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpu_gpll0_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll0.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_gpll0_div_clk_src = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x52000,
+ .enable_mask = BIT(16),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpu_gpll0_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_gpll0_out_even.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_gpu_smmu_vote_clk = {
+ .halt_reg = 0x7d000,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7d000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_gpu_smmu_vote_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mmu_tcu_vote_clk = {
+ .halt_reg = 0x7d02c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x7d02c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_mmu_tcu_vote_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_aux_clk = {
+ .halt_reg = 0x6b044,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x6b044,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_cfg_ahb_clk = {
+ .halt_reg = 0x6b040,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x6b040,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(3),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_mstr_axi_clk = {
+ .halt_reg = 0x6b030,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x6b030,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(2),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_mstr_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_phy_aux_clk = {
+ .halt_reg = 0x6b054,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x6b054,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(5),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_phy_rchng_clk = {
+ .halt_reg = 0x6b084,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x6b084,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(8),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_phy_rchng_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_phy_rchng_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_pipe_clk = {
+ .halt_reg = 0x6b074,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x6b074,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(7),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_pipe_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_pipe_div2_clk = {
+ .halt_reg = 0x6b064,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x6b064,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(6),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_pipe_div2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_0_pipe_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_slv_axi_clk = {
+ .halt_reg = 0x6b020,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x6b020,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_slv_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_0_slv_q2a_axi_clk = {
+ .halt_reg = 0x6b01c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x6b01c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_0_slv_q2a_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_aux_clk = {
+ .halt_reg = 0x67040,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(10),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_cfg_ahb_clk = {
+ .halt_reg = 0x6703c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x6703c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(9),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_cfg_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_mstr_axi_clk = {
+ .halt_reg = 0x6702c,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x6702c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(17),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_mstr_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_phy_aux_clk = {
+ .halt_reg = 0x67050,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(14),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_phy_rchng_clk = {
+ .halt_reg = 0x67080,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(26),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_phy_rchng_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_phy_rchng_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_pipe_clk = {
+ .halt_reg = 0x67070,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(17),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_pipe_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_pipe_div2_clk = {
+ .halt_reg = 0x67060,
+ .halt_check = BRANCH_HALT_SKIP,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(15),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_pipe_div2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_1_pipe_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_slv_axi_clk = {
+ .halt_reg = 0x6701c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x6701c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(16),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_slv_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie_1_slv_q2a_axi_clk = {
+ .halt_reg = 0x67018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(15),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_1_slv_q2a_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm2_clk = {
+ .halt_reg = 0x3300c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3300c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pdm2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_ahb_clk = {
+ .halt_reg = 0x33004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x33004,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x33004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pdm_xo4_clk = {
+ .halt_reg = 0x33008,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x33008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pdm_xo4_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_i2c_core_clk = {
+ .halt_reg = 0x23004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(8),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_i2c_s0_clk = {
+ .halt_reg = 0x17004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(10),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_i2c_s1_clk = {
+ .halt_reg = 0x17020,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(11),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_i2c_s2_clk = {
+ .halt_reg = 0x1703c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(12),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_i2c_s3_clk = {
+ .halt_reg = 0x17058,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(13),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_i2c_s4_clk = {
+ .halt_reg = 0x17074,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(14),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s4_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_i2c_s4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_i2c_s_ahb_clk = {
+ .halt_reg = 0x23000,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x23000,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(7),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_i2c_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_core_2x_clk = {
+ .halt_reg = 0x2315c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(18),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_core_clk = {
+ .halt_reg = 0x23148,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(19),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_qspi_ref_clk = {
+ .halt_reg = 0x188bc,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(29),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_qspi_ref_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_qspi_ref_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s0_clk = {
+ .halt_reg = 0x18004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(22),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s1_clk = {
+ .halt_reg = 0x18140,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(23),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s2_clk = {
+ .halt_reg = 0x1827c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(24),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s3_clk = {
+ .halt_reg = 0x18290,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(25),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s4_clk = {
+ .halt_reg = 0x183cc,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(26),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s4_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s5_clk = {
+ .halt_reg = 0x18508,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(27),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s5_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s6_clk = {
+ .halt_reg = 0x18644,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(28),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s6_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s6_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap1_s7_clk = {
+ .halt_reg = 0x18780,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(16),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap1_s7_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap1_s7_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_core_2x_clk = {
+ .halt_reg = 0x232b4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(3),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_core_clk = {
+ .halt_reg = 0x232a0,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s0_clk = {
+ .halt_reg = 0x1e004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s1_clk = {
+ .halt_reg = 0x1e148,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(5),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s2_clk = {
+ .halt_reg = 0x1e28c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(6),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s3_clk = {
+ .halt_reg = 0x1e3c8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(7),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap2_s4_clk = {
+ .halt_reg = 0x1e504,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(8),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap2_s4_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap2_s4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap3_core_2x_clk = {
+ .halt_reg = 0x2340c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(11),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap3_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap3_core_clk = {
+ .halt_reg = 0x233f8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(10),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap3_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap3_qspi_ref_clk = {
+ .halt_reg = 0xa8648,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(25),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap3_qspi_ref_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap3_qspi_ref_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap3_s0_clk = {
+ .halt_reg = 0xa8004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(12),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap3_s0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap3_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap3_s1_clk = {
+ .halt_reg = 0xa8140,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(13),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap3_s1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap3_s1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap3_s2_clk = {
+ .halt_reg = 0xa8158,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(14),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap3_s2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap3_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap3_s3_clk = {
+ .halt_reg = 0xa8294,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(15),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap3_s3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap3_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap3_s4_clk = {
+ .halt_reg = 0xa83d0,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(16),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap3_s4_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap3_s4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap3_s5_clk = {
+ .halt_reg = 0xa850c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(17),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap3_s5_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap3_s5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap4_core_2x_clk = {
+ .halt_reg = 0x23564,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(25),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap4_core_2x_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap4_core_clk = {
+ .halt_reg = 0x23550,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(24),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap4_core_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap4_s0_clk = {
+ .halt_reg = 0xa9004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(26),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap4_s0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap4_s0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap4_s1_clk = {
+ .halt_reg = 0xa9140,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(27),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap4_s1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap4_s1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap4_s2_clk = {
+ .halt_reg = 0xa927c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(28),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap4_s2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap4_s2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap4_s3_clk = {
+ .halt_reg = 0xa93b8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(29),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap4_s3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap4_s3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap4_s4_clk = {
+ .halt_reg = 0xa94f4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(30),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap4_s4_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap4_s4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_1_m_axi_clk = {
+ .halt_reg = 0x23140,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x23140,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(20),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_1_m_axi_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_1_s_ahb_clk = {
+ .halt_reg = 0x23144,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x23144,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52008,
+ .enable_mask = BIT(21),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_1_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_2_m_ahb_clk = {
+ .halt_reg = 0x23298,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x23298,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(2),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_2_m_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_2_s_ahb_clk = {
+ .halt_reg = 0x2329c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2329c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52010,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_2_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_3_m_ahb_clk = {
+ .halt_reg = 0x233f0,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x233f0,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(8),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_3_m_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_3_s_ahb_clk = {
+ .halt_reg = 0x233f4,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x233f4,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(9),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_3_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_4_m_ahb_clk = {
+ .halt_reg = 0x23548,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x23548,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(22),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_4_m_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_4_s_ahb_clk = {
+ .halt_reg = 0x2354c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x2354c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x52018,
+ .enable_mask = BIT(23),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_4_s_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc2_ahb_clk = {
+ .halt_reg = 0x14014,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x14014,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc2_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc2_apps_clk = {
+ .halt_reg = 0x14004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x14004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc2_apps_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc2_apps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc4_ahb_clk = {
+ .halt_reg = 0x16014,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x16014,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc4_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc4_apps_clk = {
+ .halt_reg = 0x16004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x16004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc4_apps_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc4_apps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_ahb_clk = {
+ .halt_reg = 0x77028,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x77028,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x77028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_ahb_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_axi_clk = {
+ .halt_reg = 0x77018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x77018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x77018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_axi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_axi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_ice_core_clk = {
+ .halt_reg = 0x7707c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x7707c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7707c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_ice_core_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_ice_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_phy_aux_clk = {
+ .halt_reg = 0x770bc,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x770bc,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x770bc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = {
+ .halt_reg = 0x77030,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x77030,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_rx_symbol_0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_rx_symbol_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_rx_symbol_1_clk = {
+ .halt_reg = 0x770d8,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x770d8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_rx_symbol_1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_rx_symbol_1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = {
+ .halt_reg = 0x7702c,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x7702c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_tx_symbol_0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_tx_symbol_0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_ufs_phy_unipro_5_core_clk = {
+ .halt_reg = 0x7706c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x7706c,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x7706c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_ufs_phy_unipro_5_core_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_ufs_phy_unipro_5_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_master_clk = {
+ .halt_reg = 0x39018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_master_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_mock_utmi_clk = {
+ .halt_reg = 0x3902c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3902c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_mock_utmi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb30_prim_sleep_clk = {
+ .halt_reg = 0x39028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb30_prim_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_aux_clk = {
+ .halt_reg = 0x39068,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x39068,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = {
+ .halt_reg = 0x3906c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3906c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_com_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb3_prim_phy_pipe_clk = {
+ .halt_reg = 0x39070,
+ .halt_check = BRANCH_HALT_DELAY,
+ .hwcg_reg = 0x39070,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x39070,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb3_prim_phy_pipe_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb3_prim_phy_pipe_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_axi0_clk = {
+ .halt_reg = 0x32018,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x32018,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x32018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_video_axi0_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_video_axi0c_clk = {
+ .halt_reg = 0x32020,
+ .halt_check = BRANCH_HALT_SKIP,
+ .hwcg_reg = 0x32020,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x32020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_video_axi0c_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc gcc_pcie_0_gdsc = {
+ .gdscr = 0x6b004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .collapse_ctrl = 0x52154,
+ .collapse_mask = BIT(0),
+ .pd = {
+ .name = "gcc_pcie_0_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_0_phy_gdsc = {
+ .gdscr = 0x6c000,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x2,
+ .collapse_ctrl = 0x52154,
+ .collapse_mask = BIT(1),
+ .pd = {
+ .name = "gcc_pcie_0_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_1_gdsc = {
+ .gdscr = 0x67004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .collapse_ctrl = 0x5214c,
+ .collapse_mask = BIT(2),
+ .pd = {
+ .name = "gcc_pcie_1_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_pcie_1_phy_gdsc = {
+ .gdscr = 0x68000,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x2,
+ .collapse_ctrl = 0x5214c,
+ .collapse_mask = BIT(3),
+ .pd = {
+ .name = "gcc_pcie_1_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE | VOTABLE,
+};
+
+static struct gdsc gcc_ufs_mem_phy_gdsc = {
+ .gdscr = 0x9e000,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x2,
+ .pd = {
+ .name = "gcc_ufs_mem_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_ufs_phy_gdsc = {
+ .gdscr = 0x77004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_ufs_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_usb30_prim_gdsc = {
+ .gdscr = 0x39004,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "gcc_usb30_prim_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc gcc_usb3_phy_gdsc = {
+ .gdscr = 0x50018,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x2,
+ .pd = {
+ .name = "gcc_usb3_phy_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct clk_regmap *gcc_hawi_clocks[] = {
+ [GCC_AGGRE_NOC_PCIE_AXI_CLK] = &gcc_aggre_noc_pcie_axi_clk.clkr,
+ [GCC_AGGRE_STARDUSTNOC_USB3_PRIM_AXI_CLK] = &gcc_aggre_stardustnoc_usb3_prim_axi_clk.clkr,
+ [GCC_AGGRE_UFS_PHY_AXI_CLK] = &gcc_aggre_ufs_phy_axi_clk.clkr,
+ [GCC_BOOT_ROM_AHB_CLK] = &gcc_boot_rom_ahb_clk.clkr,
+ [GCC_CAMERA_HF_AXI_CLK] = &gcc_camera_hf_axi_clk.clkr,
+ [GCC_CAMERA_SF_AXI_CLK] = &gcc_camera_sf_axi_clk.clkr,
+ [GCC_CFG_NOC_PCIE_ANOC_AHB_CLK] = &gcc_cfg_noc_pcie_anoc_ahb_clk.clkr,
+ [GCC_CFG_NOC_USB3_PRIM_AXI_CLK] = &gcc_cfg_noc_usb3_prim_axi_clk.clkr,
+ [GCC_CNOC_PCIE_SF_AXI_CLK] = &gcc_cnoc_pcie_sf_axi_clk.clkr,
+ [GCC_EVA_AXI0_CLK] = &gcc_eva_axi0_clk.clkr,
+ [GCC_EVA_AXI0C_CLK] = &gcc_eva_axi0c_clk.clkr,
+ [GCC_GP1_CLK] = &gcc_gp1_clk.clkr,
+ [GCC_GP1_CLK_SRC] = &gcc_gp1_clk_src.clkr,
+ [GCC_GP2_CLK] = &gcc_gp2_clk.clkr,
+ [GCC_GP2_CLK_SRC] = &gcc_gp2_clk_src.clkr,
+ [GCC_GP3_CLK] = &gcc_gp3_clk.clkr,
+ [GCC_GP3_CLK_SRC] = &gcc_gp3_clk_src.clkr,
+ [GCC_GPLL0] = &gcc_gpll0.clkr,
+ [GCC_GPLL0_OUT_EVEN] = &gcc_gpll0_out_even.clkr,
+ [GCC_GPLL4] = &gcc_gpll4.clkr,
+ [GCC_GPLL5] = &gcc_gpll5.clkr,
+ [GCC_GPLL7] = &gcc_gpll7.clkr,
+ [GCC_GPLL9] = &gcc_gpll9.clkr,
+ [GCC_GPU_GEMNOC_GFX_CLK] = &gcc_gpu_gemnoc_gfx_clk.clkr,
+ [GCC_GPU_GPLL0_CLK_SRC] = &gcc_gpu_gpll0_clk_src.clkr,
+ [GCC_GPU_GPLL0_DIV_CLK_SRC] = &gcc_gpu_gpll0_div_clk_src.clkr,
+ [GCC_GPU_SMMU_VOTE_CLK] = &gcc_gpu_smmu_vote_clk.clkr,
+ [GCC_MMU_TCU_VOTE_CLK] = &gcc_mmu_tcu_vote_clk.clkr,
+ [GCC_PCIE_0_AUX_CLK] = &gcc_pcie_0_aux_clk.clkr,
+ [GCC_PCIE_0_AUX_CLK_SRC] = &gcc_pcie_0_aux_clk_src.clkr,
+ [GCC_PCIE_0_CFG_AHB_CLK] = &gcc_pcie_0_cfg_ahb_clk.clkr,
+ [GCC_PCIE_0_MSTR_AXI_CLK] = &gcc_pcie_0_mstr_axi_clk.clkr,
+ [GCC_PCIE_0_PHY_AUX_CLK] = &gcc_pcie_0_phy_aux_clk.clkr,
+ [GCC_PCIE_0_PHY_AUX_CLK_SRC] = &gcc_pcie_0_phy_aux_clk_src.clkr,
+ [GCC_PCIE_0_PHY_RCHNG_CLK] = &gcc_pcie_0_phy_rchng_clk.clkr,
+ [GCC_PCIE_0_PHY_RCHNG_CLK_SRC] = &gcc_pcie_0_phy_rchng_clk_src.clkr,
+ [GCC_PCIE_0_PIPE_CLK] = &gcc_pcie_0_pipe_clk.clkr,
+ [GCC_PCIE_0_PIPE_CLK_SRC] = &gcc_pcie_0_pipe_clk_src.clkr,
+ [GCC_PCIE_0_PIPE_DIV2_CLK] = &gcc_pcie_0_pipe_div2_clk.clkr,
+ [GCC_PCIE_0_PIPE_DIV_CLK_SRC] = &gcc_pcie_0_pipe_div_clk_src.clkr,
+ [GCC_PCIE_0_SLV_AXI_CLK] = &gcc_pcie_0_slv_axi_clk.clkr,
+ [GCC_PCIE_0_SLV_Q2A_AXI_CLK] = &gcc_pcie_0_slv_q2a_axi_clk.clkr,
+ [GCC_PCIE_1_AUX_CLK] = &gcc_pcie_1_aux_clk.clkr,
+ [GCC_PCIE_1_AUX_CLK_SRC] = &gcc_pcie_1_aux_clk_src.clkr,
+ [GCC_PCIE_1_CFG_AHB_CLK] = &gcc_pcie_1_cfg_ahb_clk.clkr,
+ [GCC_PCIE_1_MSTR_AXI_CLK] = &gcc_pcie_1_mstr_axi_clk.clkr,
+ [GCC_PCIE_1_PHY_AUX_CLK] = &gcc_pcie_1_phy_aux_clk.clkr,
+ [GCC_PCIE_1_PHY_AUX_CLK_SRC] = &gcc_pcie_1_phy_aux_clk_src.clkr,
+ [GCC_PCIE_1_PHY_RCHNG_CLK] = &gcc_pcie_1_phy_rchng_clk.clkr,
+ [GCC_PCIE_1_PHY_RCHNG_CLK_SRC] = &gcc_pcie_1_phy_rchng_clk_src.clkr,
+ [GCC_PCIE_1_PIPE_CLK] = &gcc_pcie_1_pipe_clk.clkr,
+ [GCC_PCIE_1_PIPE_CLK_SRC] = &gcc_pcie_1_pipe_clk_src.clkr,
+ [GCC_PCIE_1_PIPE_DIV2_CLK] = &gcc_pcie_1_pipe_div2_clk.clkr,
+ [GCC_PCIE_1_PIPE_DIV_CLK_SRC] = &gcc_pcie_1_pipe_div_clk_src.clkr,
+ [GCC_PCIE_1_SLV_AXI_CLK] = &gcc_pcie_1_slv_axi_clk.clkr,
+ [GCC_PCIE_1_SLV_Q2A_AXI_CLK] = &gcc_pcie_1_slv_q2a_axi_clk.clkr,
+ [GCC_PDM2_CLK] = &gcc_pdm2_clk.clkr,
+ [GCC_PDM2_CLK_SRC] = &gcc_pdm2_clk_src.clkr,
+ [GCC_PDM_AHB_CLK] = &gcc_pdm_ahb_clk.clkr,
+ [GCC_PDM_XO4_CLK] = &gcc_pdm_xo4_clk.clkr,
+ [GCC_QUPV3_I2C_CORE_CLK] = &gcc_qupv3_i2c_core_clk.clkr,
+ [GCC_QUPV3_I2C_S0_CLK] = &gcc_qupv3_i2c_s0_clk.clkr,
+ [GCC_QUPV3_I2C_S0_CLK_SRC] = &gcc_qupv3_i2c_s0_clk_src.clkr,
+ [GCC_QUPV3_I2C_S1_CLK] = &gcc_qupv3_i2c_s1_clk.clkr,
+ [GCC_QUPV3_I2C_S1_CLK_SRC] = &gcc_qupv3_i2c_s1_clk_src.clkr,
+ [GCC_QUPV3_I2C_S2_CLK] = &gcc_qupv3_i2c_s2_clk.clkr,
+ [GCC_QUPV3_I2C_S2_CLK_SRC] = &gcc_qupv3_i2c_s2_clk_src.clkr,
+ [GCC_QUPV3_I2C_S3_CLK] = &gcc_qupv3_i2c_s3_clk.clkr,
+ [GCC_QUPV3_I2C_S3_CLK_SRC] = &gcc_qupv3_i2c_s3_clk_src.clkr,
+ [GCC_QUPV3_I2C_S4_CLK] = &gcc_qupv3_i2c_s4_clk.clkr,
+ [GCC_QUPV3_I2C_S4_CLK_SRC] = &gcc_qupv3_i2c_s4_clk_src.clkr,
+ [GCC_QUPV3_I2C_S_AHB_CLK] = &gcc_qupv3_i2c_s_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP1_CORE_2X_CLK] = &gcc_qupv3_wrap1_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP1_CORE_CLK] = &gcc_qupv3_wrap1_core_clk.clkr,
+ [GCC_QUPV3_WRAP1_QSPI_REF_CLK] = &gcc_qupv3_wrap1_qspi_ref_clk.clkr,
+ [GCC_QUPV3_WRAP1_QSPI_REF_CLK_SRC] = &gcc_qupv3_wrap1_qspi_ref_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S0_CLK] = &gcc_qupv3_wrap1_s0_clk.clkr,
+ [GCC_QUPV3_WRAP1_S0_CLK_SRC] = &gcc_qupv3_wrap1_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S1_CLK] = &gcc_qupv3_wrap1_s1_clk.clkr,
+ [GCC_QUPV3_WRAP1_S1_CLK_SRC] = &gcc_qupv3_wrap1_s1_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S2_CLK] = &gcc_qupv3_wrap1_s2_clk.clkr,
+ [GCC_QUPV3_WRAP1_S2_CLK_SRC] = &gcc_qupv3_wrap1_s2_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S3_CLK] = &gcc_qupv3_wrap1_s3_clk.clkr,
+ [GCC_QUPV3_WRAP1_S3_CLK_SRC] = &gcc_qupv3_wrap1_s3_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S4_CLK] = &gcc_qupv3_wrap1_s4_clk.clkr,
+ [GCC_QUPV3_WRAP1_S4_CLK_SRC] = &gcc_qupv3_wrap1_s4_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S5_CLK] = &gcc_qupv3_wrap1_s5_clk.clkr,
+ [GCC_QUPV3_WRAP1_S5_CLK_SRC] = &gcc_qupv3_wrap1_s5_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S6_CLK] = &gcc_qupv3_wrap1_s6_clk.clkr,
+ [GCC_QUPV3_WRAP1_S6_CLK_SRC] = &gcc_qupv3_wrap1_s6_clk_src.clkr,
+ [GCC_QUPV3_WRAP1_S7_CLK] = &gcc_qupv3_wrap1_s7_clk.clkr,
+ [GCC_QUPV3_WRAP1_S7_CLK_SRC] = &gcc_qupv3_wrap1_s7_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_CORE_2X_CLK] = &gcc_qupv3_wrap2_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP2_CORE_CLK] = &gcc_qupv3_wrap2_core_clk.clkr,
+ [GCC_QUPV3_WRAP2_S0_CLK] = &gcc_qupv3_wrap2_s0_clk.clkr,
+ [GCC_QUPV3_WRAP2_S0_CLK_SRC] = &gcc_qupv3_wrap2_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S1_CLK] = &gcc_qupv3_wrap2_s1_clk.clkr,
+ [GCC_QUPV3_WRAP2_S1_CLK_SRC] = &gcc_qupv3_wrap2_s1_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S2_CLK] = &gcc_qupv3_wrap2_s2_clk.clkr,
+ [GCC_QUPV3_WRAP2_S2_CLK_SRC] = &gcc_qupv3_wrap2_s2_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S3_CLK] = &gcc_qupv3_wrap2_s3_clk.clkr,
+ [GCC_QUPV3_WRAP2_S3_CLK_SRC] = &gcc_qupv3_wrap2_s3_clk_src.clkr,
+ [GCC_QUPV3_WRAP2_S4_CLK] = &gcc_qupv3_wrap2_s4_clk.clkr,
+ [GCC_QUPV3_WRAP2_S4_CLK_SRC] = &gcc_qupv3_wrap2_s4_clk_src.clkr,
+ [GCC_QUPV3_WRAP3_CORE_2X_CLK] = &gcc_qupv3_wrap3_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP3_CORE_CLK] = &gcc_qupv3_wrap3_core_clk.clkr,
+ [GCC_QUPV3_WRAP3_QSPI_REF_CLK] = &gcc_qupv3_wrap3_qspi_ref_clk.clkr,
+ [GCC_QUPV3_WRAP3_QSPI_REF_CLK_SRC] = &gcc_qupv3_wrap3_qspi_ref_clk_src.clkr,
+ [GCC_QUPV3_WRAP3_S0_CLK] = &gcc_qupv3_wrap3_s0_clk.clkr,
+ [GCC_QUPV3_WRAP3_S0_CLK_SRC] = &gcc_qupv3_wrap3_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP3_S1_CLK] = &gcc_qupv3_wrap3_s1_clk.clkr,
+ [GCC_QUPV3_WRAP3_S1_CLK_SRC] = &gcc_qupv3_wrap3_s1_clk_src.clkr,
+ [GCC_QUPV3_WRAP3_S2_CLK] = &gcc_qupv3_wrap3_s2_clk.clkr,
+ [GCC_QUPV3_WRAP3_S2_CLK_SRC] = &gcc_qupv3_wrap3_s2_clk_src.clkr,
+ [GCC_QUPV3_WRAP3_S3_CLK] = &gcc_qupv3_wrap3_s3_clk.clkr,
+ [GCC_QUPV3_WRAP3_S3_CLK_SRC] = &gcc_qupv3_wrap3_s3_clk_src.clkr,
+ [GCC_QUPV3_WRAP3_S4_CLK] = &gcc_qupv3_wrap3_s4_clk.clkr,
+ [GCC_QUPV3_WRAP3_S4_CLK_SRC] = &gcc_qupv3_wrap3_s4_clk_src.clkr,
+ [GCC_QUPV3_WRAP3_S5_CLK] = &gcc_qupv3_wrap3_s5_clk.clkr,
+ [GCC_QUPV3_WRAP3_S5_CLK_SRC] = &gcc_qupv3_wrap3_s5_clk_src.clkr,
+ [GCC_QUPV3_WRAP4_CORE_2X_CLK] = &gcc_qupv3_wrap4_core_2x_clk.clkr,
+ [GCC_QUPV3_WRAP4_CORE_CLK] = &gcc_qupv3_wrap4_core_clk.clkr,
+ [GCC_QUPV3_WRAP4_S0_CLK] = &gcc_qupv3_wrap4_s0_clk.clkr,
+ [GCC_QUPV3_WRAP4_S0_CLK_SRC] = &gcc_qupv3_wrap4_s0_clk_src.clkr,
+ [GCC_QUPV3_WRAP4_S1_CLK] = &gcc_qupv3_wrap4_s1_clk.clkr,
+ [GCC_QUPV3_WRAP4_S1_CLK_SRC] = &gcc_qupv3_wrap4_s1_clk_src.clkr,
+ [GCC_QUPV3_WRAP4_S2_CLK] = &gcc_qupv3_wrap4_s2_clk.clkr,
+ [GCC_QUPV3_WRAP4_S2_CLK_SRC] = &gcc_qupv3_wrap4_s2_clk_src.clkr,
+ [GCC_QUPV3_WRAP4_S3_CLK] = &gcc_qupv3_wrap4_s3_clk.clkr,
+ [GCC_QUPV3_WRAP4_S3_CLK_SRC] = &gcc_qupv3_wrap4_s3_clk_src.clkr,
+ [GCC_QUPV3_WRAP4_S4_CLK] = &gcc_qupv3_wrap4_s4_clk.clkr,
+ [GCC_QUPV3_WRAP4_S4_CLK_SRC] = &gcc_qupv3_wrap4_s4_clk_src.clkr,
+ [GCC_QUPV3_WRAP_1_M_AXI_CLK] = &gcc_qupv3_wrap_1_m_axi_clk.clkr,
+ [GCC_QUPV3_WRAP_1_S_AHB_CLK] = &gcc_qupv3_wrap_1_s_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_2_M_AHB_CLK] = &gcc_qupv3_wrap_2_m_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_2_S_AHB_CLK] = &gcc_qupv3_wrap_2_s_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_3_M_AHB_CLK] = &gcc_qupv3_wrap_3_m_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_3_S_AHB_CLK] = &gcc_qupv3_wrap_3_s_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_4_M_AHB_CLK] = &gcc_qupv3_wrap_4_m_ahb_clk.clkr,
+ [GCC_QUPV3_WRAP_4_S_AHB_CLK] = &gcc_qupv3_wrap_4_s_ahb_clk.clkr,
+ [GCC_SDCC2_AHB_CLK] = &gcc_sdcc2_ahb_clk.clkr,
+ [GCC_SDCC2_APPS_CLK] = &gcc_sdcc2_apps_clk.clkr,
+ [GCC_SDCC2_APPS_CLK_SRC] = &gcc_sdcc2_apps_clk_src.clkr,
+ [GCC_SDCC4_AHB_CLK] = &gcc_sdcc4_ahb_clk.clkr,
+ [GCC_SDCC4_APPS_CLK] = &gcc_sdcc4_apps_clk.clkr,
+ [GCC_SDCC4_APPS_CLK_SRC] = &gcc_sdcc4_apps_clk_src.clkr,
+ [GCC_UFS_PHY_AHB_CLK] = &gcc_ufs_phy_ahb_clk.clkr,
+ [GCC_UFS_PHY_AXI_CLK] = &gcc_ufs_phy_axi_clk.clkr,
+ [GCC_UFS_PHY_AXI_CLK_SRC] = &gcc_ufs_phy_axi_clk_src.clkr,
+ [GCC_UFS_PHY_ICE_CORE_CLK] = &gcc_ufs_phy_ice_core_clk.clkr,
+ [GCC_UFS_PHY_ICE_CORE_CLK_SRC] = &gcc_ufs_phy_ice_core_clk_src.clkr,
+ [GCC_UFS_PHY_PHY_AUX_CLK] = &gcc_ufs_phy_phy_aux_clk.clkr,
+ [GCC_UFS_PHY_PHY_AUX_CLK_SRC] = &gcc_ufs_phy_phy_aux_clk_src.clkr,
+ [GCC_UFS_PHY_RX_SYMBOL_0_CLK] = &gcc_ufs_phy_rx_symbol_0_clk.clkr,
+ [GCC_UFS_PHY_RX_SYMBOL_0_CLK_SRC] = &gcc_ufs_phy_rx_symbol_0_clk_src.clkr,
+ [GCC_UFS_PHY_RX_SYMBOL_1_CLK] = &gcc_ufs_phy_rx_symbol_1_clk.clkr,
+ [GCC_UFS_PHY_RX_SYMBOL_1_CLK_SRC] = &gcc_ufs_phy_rx_symbol_1_clk_src.clkr,
+ [GCC_UFS_PHY_TX_SYMBOL_0_CLK] = &gcc_ufs_phy_tx_symbol_0_clk.clkr,
+ [GCC_UFS_PHY_TX_SYMBOL_0_CLK_SRC] = &gcc_ufs_phy_tx_symbol_0_clk_src.clkr,
+ [GCC_UFS_PHY_UNIPRO_5_CORE_CLK] = &gcc_ufs_phy_unipro_5_core_clk.clkr,
+ [GCC_UFS_PHY_UNIPRO_5_CORE_CLK_SRC] = &gcc_ufs_phy_unipro_5_core_clk_src.clkr,
+ [GCC_USB30_PRIM_MASTER_CLK] = &gcc_usb30_prim_master_clk.clkr,
+ [GCC_USB30_PRIM_MASTER_CLK_SRC] = &gcc_usb30_prim_master_clk_src.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_CLK] = &gcc_usb30_prim_mock_utmi_clk.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC] = &gcc_usb30_prim_mock_utmi_clk_src.clkr,
+ [GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC] = &gcc_usb30_prim_mock_utmi_postdiv_clk_src.clkr,
+ [GCC_USB30_PRIM_SLEEP_CLK] = &gcc_usb30_prim_sleep_clk.clkr,
+ [GCC_USB3_PRIM_PHY_AUX_CLK] = &gcc_usb3_prim_phy_aux_clk.clkr,
+ [GCC_USB3_PRIM_PHY_AUX_CLK_SRC] = &gcc_usb3_prim_phy_aux_clk_src.clkr,
+ [GCC_USB3_PRIM_PHY_COM_AUX_CLK] = &gcc_usb3_prim_phy_com_aux_clk.clkr,
+ [GCC_USB3_PRIM_PHY_PIPE_CLK] = &gcc_usb3_prim_phy_pipe_clk.clkr,
+ [GCC_USB3_PRIM_PHY_PIPE_CLK_SRC] = &gcc_usb3_prim_phy_pipe_clk_src.clkr,
+ [GCC_VIDEO_AXI0_CLK] = &gcc_video_axi0_clk.clkr,
+ [GCC_VIDEO_AXI0C_CLK] = &gcc_video_axi0c_clk.clkr,
+};
+
+static struct gdsc *gcc_hawi_gdscs[] = {
+ [GCC_PCIE_0_GDSC] = &gcc_pcie_0_gdsc,
+ [GCC_PCIE_0_PHY_GDSC] = &gcc_pcie_0_phy_gdsc,
+ [GCC_PCIE_1_GDSC] = &gcc_pcie_1_gdsc,
+ [GCC_PCIE_1_PHY_GDSC] = &gcc_pcie_1_phy_gdsc,
+ [GCC_UFS_MEM_PHY_GDSC] = &gcc_ufs_mem_phy_gdsc,
+ [GCC_UFS_PHY_GDSC] = &gcc_ufs_phy_gdsc,
+ [GCC_USB30_PRIM_GDSC] = &gcc_usb30_prim_gdsc,
+ [GCC_USB3_PHY_GDSC] = &gcc_usb3_phy_gdsc,
+};
+
+static const struct qcom_reset_map gcc_hawi_resets[] = {
+ [GCC_CAMERA_BCR] = { 0x26000 },
+ [GCC_EVA_AXI0_CLK_ARES] = { 0x9f008, 2 },
+ [GCC_EVA_AXI0C_CLK_ARES] = { 0x9f010, 2 },
+ [GCC_EVA_BCR] = { 0x9f000 },
+ [GCC_GPU_BCR] = { 0x71000 },
+ [GCC_PCIE_0_BCR] = { 0x6b000 },
+ [GCC_PCIE_0_LINK_DOWN_BCR] = { 0x6c014 },
+ [GCC_PCIE_0_NOCSR_COM_PHY_BCR] = { 0x6c020 },
+ [GCC_PCIE_0_PHY_BCR] = { 0x6c01c },
+ [GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR] = { 0x6c028 },
+ [GCC_PCIE_1_BCR] = { 0x67000 },
+ [GCC_PCIE_1_LINK_DOWN_BCR] = { 0x8e014 },
+ [GCC_PCIE_1_NOCSR_COM_PHY_BCR] = { 0x8e020 },
+ [GCC_PCIE_1_PHY_BCR] = { 0x8e01c },
+ [GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR] = { 0x8e024 },
+ [GCC_PCIE_PHY_BCR] = { 0x6f000 },
+ [GCC_PCIE_PHY_CFG_AHB_BCR] = { 0x6f00c },
+ [GCC_PCIE_PHY_COM_BCR] = { 0x6f010 },
+ [GCC_PCIE_RSCC_BCR] = { 0x11000 },
+ [GCC_PDM_BCR] = { 0x33000 },
+ [GCC_QUPV3_WRAPPER_1_BCR] = { 0x18000 },
+ [GCC_QUPV3_WRAPPER_2_BCR] = { 0x1e000 },
+ [GCC_QUPV3_WRAPPER_3_BCR] = { 0xa8000 },
+ [GCC_QUPV3_WRAPPER_4_BCR] = { 0xa9000 },
+ [GCC_QUPV3_WRAPPER_I2C_BCR] = { 0x17000 },
+ [GCC_QUSB2PHY_PRIM_BCR] = { 0x12000 },
+ [GCC_QUSB2PHY_SEC_BCR] = { 0x12004 },
+ [GCC_SDCC2_BCR] = { 0x14000 },
+ [GCC_SDCC4_BCR] = { 0x16000 },
+ [GCC_TCSR_PCIE_BCR] = { 0x6f018 },
+ [GCC_UFS_PHY_BCR] = { 0x77000 },
+ [GCC_USB30_PRIM_BCR] = { 0x39000 },
+ [GCC_USB3_DP_PHY_PRIM_BCR] = { 0x50008 },
+ [GCC_USB3_DP_PHY_SEC_BCR] = { 0x50014 },
+ [GCC_USB3_PHY_PRIM_BCR] = { 0x50000 },
+ [GCC_USB3_PHY_SEC_BCR] = { 0x5000c },
+ [GCC_USB3PHY_PHY_PRIM_BCR] = { 0x50004 },
+ [GCC_USB3PHY_PHY_SEC_BCR] = { 0x50010 },
+ [GCC_VIDEO_AXI0_CLK_ARES] = { 0x32018, 2 },
+ [GCC_VIDEO_AXI0C_CLK_ARES] = { 0x32020, 2 },
+ [GCC_VIDEO_BCR] = { 0x32000 },
+ [GCC_VIDEO_XO_CLK_ARES] = { 0x32028, 2 },
+};
+
+static const u32 gcc_hawi_critical_cbcrs[] = {
+ 0xa0004, /* GCC_CAM_BIST_MCLK_AHB_CLK */
+ 0x26004, /* GCC_CAMERA_AHB_CLK */
+ 0x26028, /* GCC_CAMERA_RSC_CORE_CLK */
+ 0x26024, /* GCC_CAMERA_XO_CLK */
+ 0x9f004, /* GCC_EVA_AHB_CLK */
+ 0x9f018, /* GCC_EVA_XO_CLK */
+ 0x71004, /* GCC_GPU_CFG_AHB_CLK */
+ 0x7101c, /* GCC_GPU_RSC_CORE_CLK */
+ 0x67084, /* GCC_PCIE_1_RSC_CORE_CLK */
+ 0x43014, /* GCC_PCIE_LINK_XO_CLK */
+ 0x6b088, /* GCC_PCIE_RSC_CORE_CLK */
+ 0x52010, /* GCC_PCIE_RSCC_CFG_AHB_CLK */
+ 0x52010, /* GCC_PCIE_RSCC_XO_CLK */
+ 0x32004, /* GCC_VIDEO_AHB_CLK */
+ 0x32028, /* GCC_VIDEO_XO_CLK */
+};
+
+static const struct clk_rcg_dfs_data gcc_hawi_dfs_clocks[] = {
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_qspi_ref_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s0_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s1_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s3_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s4_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s5_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s6_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap1_s7_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s0_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s1_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s2_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s3_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap2_s4_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap3_qspi_ref_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap3_s0_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap3_s2_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap3_s3_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap3_s4_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap3_s5_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap4_s0_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap4_s1_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap4_s2_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap4_s3_clk_src),
+ DEFINE_RCG_DFS(gcc_qupv3_wrap4_s4_clk_src),
+};
+
+static const struct regmap_config gcc_hawi_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x1f41f4,
+ .fast_io = true,
+};
+
+static void clk_hawi_regs_configure(struct device *dev, struct regmap *regmap)
+{
+ /* FORCE_MEM_CORE_ON for ufs phy ice core clocks */
+ qcom_branch_set_force_mem_core(regmap, gcc_ufs_phy_ice_core_clk, true);
+}
+
+static const struct qcom_cc_driver_data gcc_hawi_driver_data = {
+ .clk_cbcrs = gcc_hawi_critical_cbcrs,
+ .num_clk_cbcrs = ARRAY_SIZE(gcc_hawi_critical_cbcrs),
+ .dfs_rcgs = gcc_hawi_dfs_clocks,
+ .num_dfs_rcgs = ARRAY_SIZE(gcc_hawi_dfs_clocks),
+ .clk_regs_configure = clk_hawi_regs_configure,
+};
+
+static const struct qcom_cc_desc gcc_hawi_desc = {
+ .config = &gcc_hawi_regmap_config,
+ .clks = gcc_hawi_clocks,
+ .num_clks = ARRAY_SIZE(gcc_hawi_clocks),
+ .resets = gcc_hawi_resets,
+ .num_resets = ARRAY_SIZE(gcc_hawi_resets),
+ .gdscs = gcc_hawi_gdscs,
+ .num_gdscs = ARRAY_SIZE(gcc_hawi_gdscs),
+ .use_rpm = true,
+ .driver_data = &gcc_hawi_driver_data,
+};
+
+static const struct of_device_id gcc_hawi_match_table[] = {
+ { .compatible = "qcom,hawi-gcc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gcc_hawi_match_table);
+
+static int gcc_hawi_probe(struct platform_device *pdev)
+{
+ return qcom_cc_probe(pdev, &gcc_hawi_desc);
+}
+
+static struct platform_driver gcc_hawi_driver = {
+ .probe = gcc_hawi_probe,
+ .driver = {
+ .name = "gcc-hawi",
+ .of_match_table = gcc_hawi_match_table,
+ },
+};
+
+static int __init gcc_hawi_init(void)
+{
+ return platform_driver_register(&gcc_hawi_driver);
+}
+subsys_initcall(gcc_hawi_init);
+
+static void __exit gcc_hawi_exit(void)
+{
+ platform_driver_unregister(&gcc_hawi_driver);
+}
+module_exit(gcc_hawi_exit);
+
+MODULE_DESCRIPTION("QTI GCC HAWI Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/gcc-ipq9650.c b/drivers/clk/qcom/gcc-ipq9650.c
new file mode 100644
index 000000000000..c556c2bbfd96
--- /dev/null
+++ b/drivers/clk/qcom/gcc-ipq9650.c
@@ -0,0 +1,3445 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,ipq9650-gcc.h>
+#include <dt-bindings/reset/qcom,ipq9650-gcc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+#include "clk-regmap-phy-mux.h"
+#include "reset.h"
+
+enum {
+ DT_XO,
+ DT_SLEEP_CLK,
+ DT_PCIE30_PHY0_PIPE_CLK,
+ DT_PCIE30_PHY1_PIPE_CLK,
+ DT_PCIE30_PHY2_PIPE_CLK,
+ DT_PCIE30_PHY3_PIPE_CLK,
+ DT_PCIE30_PHY4_PIPE_CLK,
+ DT_USB3_PHY0_CC_PIPE_CLK,
+ DT_NSS_CMN_CLK,
+};
+
+enum {
+ P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC,
+ P_GPLL0_OUT_MAIN,
+ P_GPLL0_OUT_ODD,
+ P_GPLL2_OUT_AUX,
+ P_GPLL2_OUT_MAIN,
+ P_GPLL4_OUT_MAIN,
+ P_GPLL4_OUT_ODD,
+ P_NSS_CMN_CLK,
+ P_SLEEP_CLK,
+ P_XO,
+};
+
+static const struct clk_parent_data gcc_parent_data_xo = { .index = DT_XO };
+
+static struct clk_alpha_pll gpll0_main = {
+ .offset = 0x20000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr = {
+ .enable_reg = 0xb000,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpll0_main",
+ .parent_data = &gcc_parent_data_xo,
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_fixed_lucid_ops,
+ },
+ },
+};
+
+static struct clk_fixed_factor gpll0_div2 = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpll0_div2",
+ .parent_hws = (const struct clk_hw *[]) {
+ &gpll0_main.clkr.hw
+ },
+ .num_parents = 1,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_alpha_pll_postdiv gpll0 = {
+ .offset = 0x20000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gpll0",
+ .parent_hws = (const struct clk_hw *[]) {
+ &gpll0_main.clkr.hw },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_ro_ops,
+ },
+};
+
+static struct clk_alpha_pll gpll2 = {
+ .offset = 0x21000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_ZONDA],
+ .clkr = {
+ .enable_reg = 0xb000,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpll2",
+ .parent_data = &gcc_parent_data_xo,
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_zonda_ops,
+ },
+ },
+};
+
+static const struct clk_div_table post_div_table_gpll2_out_main[] = {
+ { 0x1, 2 },
+ { }
+};
+
+static struct clk_alpha_pll_postdiv gpll2_out_main = {
+ .offset = 0x21000,
+ .post_div_shift = 8,
+ .post_div_table = post_div_table_gpll2_out_main,
+ .num_post_div = ARRAY_SIZE(post_div_table_gpll2_out_main),
+ .width = 2,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_ZONDA],
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gpll2_out_main",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gpll2.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_postdiv_zonda_ops,
+ },
+};
+
+static struct clk_alpha_pll gpll4 = {
+ .offset = 0x22000,
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID],
+ .clkr = {
+ .enable_reg = 0xb000,
+ .enable_mask = BIT(2),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gpll4",
+ .parent_data = &gcc_parent_data_xo,
+ .num_parents = 1,
+ /*
+ * There are no consumers for this GPLL in kernel yet,
+ * (will be added soon), so the clock framework
+ * disables this source. But some of the clocks
+ * initialized by boot loaders uses this source. So we
+ * need to keep this clock ON. Add the
+ * CLK_IGNORE_UNUSED flag so the clock will not be
+ * disabled. Once the consumer in kernel is added, we
+ * can get rid of this flag.
+ */
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_alpha_pll_fixed_lucid_ops,
+ },
+ },
+};
+
+static const struct parent_map gcc_parent_map_xo[] = {
+ { P_XO, 0 },
+};
+
+static const struct parent_map gcc_parent_map_0[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 4 },
+};
+
+static const struct clk_parent_data gcc_parent_data_0[] = {
+ { .index = DT_XO },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll0_div2.hw },
+};
+
+static const struct parent_map gcc_parent_map_1[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_GPLL4_OUT_MAIN, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_1[] = {
+ { .index = DT_XO },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll4.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_2[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+};
+
+static const struct clk_parent_data gcc_parent_data_2[] = {
+ { .index = DT_XO },
+ { .hw = &gpll0.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_3[] = {
+ { P_XO, 0 },
+};
+
+static const struct clk_parent_data gcc_parent_data_3[] = {
+ { .index = DT_XO },
+};
+
+static const struct parent_map gcc_parent_map_4[] = {
+ { P_XO, 0 },
+ { P_GPLL4_OUT_MAIN, 1 },
+ { P_GPLL0_OUT_ODD, 2 },
+ { P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 4 },
+};
+
+static const struct clk_parent_data gcc_parent_data_4[] = {
+ { .index = DT_XO },
+ { .hw = &gpll4.clkr.hw },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll0_div2.hw },
+};
+
+static const struct parent_map gcc_parent_map_5[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_GPLL2_OUT_AUX, 2 },
+};
+
+static const struct clk_parent_data gcc_parent_data_5[] = {
+ { .index = DT_XO },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll2.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_6[] = {
+ { P_XO, 0 },
+ { P_GPLL4_OUT_ODD, 1 },
+ { P_GPLL0_OUT_MAIN, 3 },
+ { P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 4 },
+};
+
+static const struct clk_parent_data gcc_parent_data_6[] = {
+ { .index = DT_XO },
+ { .hw = &gpll4.clkr.hw },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll0_div2.hw },
+};
+
+static const struct parent_map gcc_parent_map_7[] = {
+ { P_XO, 0 },
+ { P_NSS_CMN_CLK, 1 },
+ { P_GPLL0_OUT_ODD, 2 },
+ { P_GPLL2_OUT_AUX, 3 },
+};
+
+static const struct clk_parent_data gcc_parent_data_7[] = {
+ { .index = DT_XO },
+ { .index = DT_NSS_CMN_CLK },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll2.clkr.hw },
+};
+
+static const struct parent_map gcc_parent_map_8[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_GPLL0_OUT_ODD, 2 },
+ { P_SLEEP_CLK, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_8[] = {
+ { .index = DT_XO },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll0.clkr.hw },
+ { .index = DT_SLEEP_CLK },
+};
+
+static const struct parent_map gcc_parent_map_9[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_GPLL2_OUT_MAIN, 2 },
+ { P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 4 },
+};
+
+static const struct clk_parent_data gcc_parent_data_9[] = {
+ { .index = DT_XO },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll2_out_main.clkr.hw },
+ { .hw = &gpll0_div2.hw },
+};
+
+static const struct parent_map gcc_parent_map_10[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_GPLL4_OUT_MAIN, 2 },
+ { P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 4 },
+};
+
+static const struct clk_parent_data gcc_parent_data_10[] = {
+ { .index = DT_XO },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll4.clkr.hw },
+ { .hw = &gpll0_div2.hw },
+};
+
+static const struct parent_map gcc_parent_map_11[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_ODD, 2 },
+ { P_SLEEP_CLK, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_11[] = {
+ { .index = DT_XO },
+ { .hw = &gpll0.clkr.hw },
+ { .index = DT_SLEEP_CLK },
+};
+
+static const struct parent_map gcc_parent_map_12[] = {
+ { P_SLEEP_CLK, 6 },
+};
+
+static const struct clk_parent_data gcc_parent_data_12[] = {
+ { .index = DT_SLEEP_CLK },
+};
+
+static const struct parent_map gcc_parent_map_13[] = {
+ { P_XO, 0 },
+ { P_GPLL0_OUT_MAIN, 1 },
+ { P_GPLL4_OUT_MAIN, 2 },
+ { P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 3 },
+};
+
+static const struct clk_parent_data gcc_parent_data_13[] = {
+ { .index = DT_XO },
+ { .hw = &gpll0.clkr.hw },
+ { .hw = &gpll4.clkr.hw },
+ { .hw = &gpll0_div2.hw },
+};
+
+static const struct freq_tbl ftbl_gcc_adss_pwm_clk_src[] = {
+ F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_adss_pwm_clk_src = {
+ .cmd_rcgr = 0x1c004,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_adss_pwm_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_adss_pwm_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_gemnoc_anoc_pcie_clk_src[] = {
+ F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
+ { }
+};
+
+static const struct freq_tbl ftbl_gcc_nss_ts_clk_src[] = {
+ F(24000000, P_XO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_xo_clk_src = {
+ .cmd_rcgr = 0x34004,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_xo,
+ .freq_tbl = ftbl_gcc_nss_ts_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_xo_clk_src",
+ .parent_data = &gcc_parent_data_xo,
+ .num_parents = 1,
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_fixed_factor gcc_xo_div4_clk_src = {
+ .mult = 1,
+ .div = 4,
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_xo_div4_clk_src",
+ .parent_hws = (const struct clk_hw *[]) {
+ &gcc_xo_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_nss_ts_clk_src = {
+ .cmd_rcgr = 0x17088,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_nss_ts_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_nss_ts_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_nssnoc_memnoc_bfdcd_clk_src[] = {
+ F(462000000, P_NSS_CMN_CLK, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_nssnoc_memnoc_bfdcd_clk_src = {
+ .cmd_rcgr = 0x17004,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_7,
+ .freq_tbl = ftbl_gcc_nssnoc_memnoc_bfdcd_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_nssnoc_memnoc_bfdcd_clk_src",
+ .parent_data = gcc_parent_data_7,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_7),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_system_noc_bfdcd_clk_src[] = {
+ F(24000000, P_XO, 1, 0, 0),
+ F(133333333, P_GPLL0_OUT_MAIN, 6, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
+ F(266666667, P_GPLL4_OUT_MAIN, 4.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_system_noc_bfdcd_clk_src = {
+ .cmd_rcgr = 0x2e004,
+ .freq_tbl = ftbl_gcc_system_noc_bfdcd_clk_src,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_13,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_system_noc_bfdcd_clk_src",
+ .parent_data = gcc_parent_data_13,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_13),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pcnoc_bfdcd_clk_src[] = {
+ F(24000000, P_XO, 1, 0, 0),
+ F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pcnoc_bfdcd_clk_src = {
+ .cmd_rcgr = 0x31004,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_pcnoc_bfdcd_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcnoc_bfdcd_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ /*
+ * There are no consumers for this source in kernel yet,
+ * (will be added soon), so the clock framework
+ * disables this source. But some of the clocks
+ * initialized by boot loaders uses this source. So we
+ * need to keep this clock ON. Add the
+ * CLK_IGNORE_UNUSED flag so the clock will not be
+ * disabled. Once the consumer in kernel is added, we
+ * can get rid of this flag.
+ */
+ .flags = CLK_IS_CRITICAL,
+ .ops = &clk_rcg2_ops,
+ },
+};
+static const struct freq_tbl ftbl_gcc_pcie0_axi_m_clk_src[] = {
+ F(200000000, P_GPLL4_OUT_MAIN, 6, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pcie0_axi_m_clk_src = {
+ .cmd_rcgr = 0x28018,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie0_axi_m_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie0_axi_m_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie0_axi_s_clk_src = {
+ .cmd_rcgr = 0x28020,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie0_axi_m_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie0_axi_s_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie0_rchng_clk_src = {
+ .cmd_rcgr = 0x28028,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_adss_pwm_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie0_rchng_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pcie1_axi_m_clk_src[] = {
+ F(266666667, P_GPLL4_OUT_MAIN, 4.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_pcie1_axi_m_clk_src = {
+ .cmd_rcgr = 0x29018,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie1_axi_m_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie1_axi_m_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie1_axi_s_clk_src = {
+ .cmd_rcgr = 0x29020,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie0_axi_m_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie1_axi_s_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie1_rchng_clk_src = {
+ .cmd_rcgr = 0x29028,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_adss_pwm_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie1_rchng_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie2_axi_m_clk_src = {
+ .cmd_rcgr = 0x2a018,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie1_axi_m_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie2_axi_m_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie2_axi_s_clk_src = {
+ .cmd_rcgr = 0x2a020,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie0_axi_m_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie2_axi_s_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie2_rchng_clk_src = {
+ .cmd_rcgr = 0x2a028,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_adss_pwm_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie2_rchng_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie3_axi_m_clk_src = {
+ .cmd_rcgr = 0x2b018,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie1_axi_m_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie3_axi_m_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie3_axi_s_clk_src = {
+ .cmd_rcgr = 0x2b020,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie0_axi_m_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie3_axi_s_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie3_rchng_clk_src = {
+ .cmd_rcgr = 0x2b028,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_adss_pwm_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie3_rchng_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie4_axi_m_clk_src = {
+ .cmd_rcgr = 0x25004,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie0_axi_m_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie4_axi_m_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie4_axi_s_clk_src = {
+ .cmd_rcgr = 0x2500c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_1,
+ .freq_tbl = ftbl_gcc_pcie0_axi_m_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie4_axi_s_clk_src",
+ .parent_data = gcc_parent_data_1,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_1),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_pcie4_rchng_clk_src = {
+ .cmd_rcgr = 0x25014,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_2,
+ .freq_tbl = ftbl_gcc_adss_pwm_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie4_rchng_clk_src",
+ .parent_data = gcc_parent_data_2,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_2),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_pcie_aux_clk_src[] = {
+ F(20000000, P_GPLL0_OUT_MAIN, 10, 1, 4),
+ { }
+};
+
+static struct clk_rcg2 gcc_pcie_aux_clk_src = {
+ .cmd_rcgr = 0x28004,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_8,
+ .freq_tbl = ftbl_gcc_pcie_aux_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie_aux_clk_src",
+ .parent_data = gcc_parent_data_8,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_8),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_qdss_at_clk_src[] = {
+ F(240000000, P_GPLL4_OUT_MAIN, 5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_qdss_at_clk_src = {
+ .cmd_rcgr = 0x2d004,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_qdss_at_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qdss_at_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_fixed_factor gcc_eud_at_div_clk_src = {
+ .mult = 1,
+ .div = 6,
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_eud_at_div_clk_src",
+ .parent_hws = (const struct clk_hw *[]) {
+ &gcc_qdss_at_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_qdss_tsctr_clk_src[] = {
+ F(600000000, P_GPLL4_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_qdss_tsctr_clk_src = {
+ .cmd_rcgr = 0x2d01c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_4,
+ .freq_tbl = ftbl_gcc_qdss_tsctr_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qdss_tsctr_clk_src",
+ .parent_data = gcc_parent_data_4,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_4),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_fixed_factor gcc_qdss_dap_sync_clk_src = {
+ .mult = 1,
+ .div = 4,
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qdss_dap_sync_clk_src",
+ .parent_hws = (const struct clk_hw *[]) {
+ &gcc_qdss_tsctr_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .ops = &clk_fixed_factor_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_sleep_clk_src[] = {
+ F(32000, P_SLEEP_CLK, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sleep_clk_src = {
+ .cmd_rcgr = 0x3400c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_12,
+ .freq_tbl = ftbl_gcc_sleep_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sleep_clk_src",
+ .parent_data = gcc_parent_data_12,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_12),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_qpic_io_macro_clk_src[] = {
+ F(24000000, P_XO, 1, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
+ F(320000000, P_GPLL0_OUT_MAIN, 2.5, 0, 0),
+ F(400000000, P_GPLL0_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_qpic_clk_src = {
+ .cmd_rcgr = 0x32020,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_qpic_io_macro_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qpic_clk_src",
+ .parent_data = gcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_5),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qpic_io_macro_clk_src = {
+ .cmd_rcgr = 0x32004,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_5,
+ .freq_tbl = ftbl_gcc_qpic_io_macro_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qpic_io_macro_clk_src",
+ .parent_data = gcc_parent_data_5,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_5),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_2x_core_clk_src = {
+ .cmd_rcgr = 0x100c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_gemnoc_anoc_pcie_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_2x_core_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap_se0_clk_src[] = {
+ F(960000, P_XO, 10, 2, 5),
+ F(3686636, P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 1, 2, 217),
+ F(4800000, P_XO, 5, 0, 0),
+ F(7373272, P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 1, 4, 217),
+ F(9600000, P_XO, 2.5, 0, 0),
+ F(14746544, P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 1, 8, 217),
+ F(16000000, P_GPLL0_OUT_MAIN, 10, 1, 5),
+ F(24000000, P_XO, 1, 0, 0),
+ F(25000000, P_GPLL0_OUT_MAIN, 16, 1, 2),
+ F(32000000, P_GPLL0_OUT_MAIN, 1, 1, 25),
+ F(40000000, P_GPLL0_OUT_MAIN, 1, 1, 20),
+ F(46400000, P_GPLL0_OUT_MAIN, 2, 29, 250),
+ F(48000000, P_GPLL0_OUT_MAIN, 1, 3, 50),
+ F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0),
+ F(51200000, P_GPLL0_OUT_MAIN, 1, 8, 125),
+ F(56000000, P_GPLL0_OUT_MAIN, 1, 7, 100),
+ F(58986175, P_GPLL0_OUT_MAIN, 1, 16, 217),
+ F(60000000, P_GPLL0_OUT_MAIN, 1, 3, 40),
+ F(64000000, P_GPLL0_OUT_MAIN, 12.5, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap_se0_clk_src = {
+ .cmd_rcgr = 0x2018,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap_se0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_se0_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap_se1_clk_src = {
+ .cmd_rcgr = 0x3018,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap_se0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_se1_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap_se2_clk_src = {
+ .cmd_rcgr = 0x3034,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap_se0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_se2_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap_se3_clk_src = {
+ .cmd_rcgr = 0x3050,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap_se0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_se3_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_qupv3_wrap_se4_clk_src[] = {
+ F(960000, P_XO, 10, 2, 5),
+ F(3686636, P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 1, 2, 217),
+ F(4800000, P_XO, 5, 0, 0),
+ F(7373272, P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 1, 4, 217),
+ F(9600000, P_XO, 2.5, 0, 0),
+ F(14746544, P_GCC_GPLL0_OUT_MAIN_DIV_CLK_SRC, 1, 8, 217),
+ F(16000000, P_GPLL0_OUT_MAIN, 10, 1, 5),
+ F(24000000, P_XO, 1, 0, 0),
+ F(25000000, P_GPLL0_OUT_MAIN, 16, 1, 2),
+ F(32000000, P_GPLL0_OUT_MAIN, 1, 1, 25),
+ F(40000000, P_GPLL0_OUT_MAIN, 1, 1, 20),
+ F(46400000, P_GPLL0_OUT_MAIN, 2, 29, 250),
+ F(48000000, P_GPLL0_OUT_MAIN, 1, 3, 50),
+ F(50000000, P_GPLL0_OUT_MAIN, 16, 0, 0),
+ F(51200000, P_GPLL0_OUT_MAIN, 1, 8, 125),
+ F(56000000, P_GPLL0_OUT_MAIN, 1, 7, 100),
+ F(58986175, P_GPLL0_OUT_MAIN, 1, 16, 217),
+ F(60000000, P_GPLL0_OUT_MAIN, 1, 3, 40),
+ F(64000000, P_GPLL0_OUT_MAIN, 12.5, 0, 0),
+ F(100000000, P_GPLL0_OUT_MAIN, 8, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap_se4_clk_src = {
+ .cmd_rcgr = 0x306c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap_se4_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_se4_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap_se5_clk_src = {
+ .cmd_rcgr = 0x3090,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap_se4_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_se5_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap_se6_clk_src = {
+ .cmd_rcgr = 0x4004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap_se0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_se6_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_qupv3_wrap_se7_clk_src = {
+ .cmd_rcgr = 0x4020,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_qupv3_wrap_se0_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_se7_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_src[] = {
+ F(144000, P_XO, 16, 12, 125),
+ F(400000, P_XO, 12, 1, 5),
+ F(24000000, P_GPLL2_OUT_MAIN, 12, 1, 2),
+ F(48000000, P_GPLL2_OUT_MAIN, 12, 0, 0),
+ F(96000000, P_GPLL2_OUT_MAIN, 6, 0, 0),
+ F(177777778, P_GPLL0_OUT_MAIN, 4.5, 0, 0),
+ F(192000000, P_GPLL2_OUT_MAIN, 3, 0, 0),
+ F(200000000, P_GPLL0_OUT_MAIN, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc1_apps_clk_src = {
+ .cmd_rcgr = 0x33004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_9,
+ .freq_tbl = ftbl_gcc_sdcc1_apps_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc1_apps_clk_src",
+ .parent_data = gcc_parent_data_9,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_9),
+ .ops = &clk_rcg2_floor_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_sdcc1_ice_core_clk_src[] = {
+ F(300000000, P_GPLL4_OUT_MAIN, 4, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = {
+ .cmd_rcgr = 0x33018,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_10,
+ .freq_tbl = ftbl_gcc_sdcc1_ice_core_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc1_ice_core_clk_src",
+ .parent_data = gcc_parent_data_10,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_10),
+ .ops = &clk_rcg2_floor_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_uniphy_sys_clk_src = {
+ .cmd_rcgr = 0x17090,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_3,
+ .freq_tbl = ftbl_gcc_nss_ts_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_uniphy_sys_clk_src",
+ .parent_data = gcc_parent_data_3,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_3),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb0_aux_clk_src = {
+ .cmd_rcgr = 0x2c018,
+ .mnd_width = 16,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_11,
+ .freq_tbl = ftbl_gcc_nss_ts_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb0_aux_clk_src",
+ .parent_data = gcc_parent_data_11,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_11),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb0_master_clk_src = {
+ .cmd_rcgr = 0x2c004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_0,
+ .freq_tbl = ftbl_gcc_gemnoc_anoc_pcie_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb0_master_clk_src",
+ .parent_data = gcc_parent_data_0,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_0),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_gcc_usb0_mock_utmi_clk_src[] = {
+ F(24000000, P_XO, 1, 0, 0),
+ F(60000000, P_GPLL4_OUT_ODD, 10, 1, 2),
+ { }
+};
+
+static struct clk_rcg2 gcc_usb0_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x2c02c,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_6,
+ .freq_tbl = ftbl_gcc_usb0_mock_utmi_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb0_mock_utmi_clk_src",
+ .parent_data = gcc_parent_data_6,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_6),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_rcg2 gcc_usb1_mock_utmi_clk_src = {
+ .cmd_rcgr = 0x3c004,
+ .mnd_width = 8,
+ .hid_width = 5,
+ .parent_map = gcc_parent_map_6,
+ .freq_tbl = ftbl_gcc_usb0_mock_utmi_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb1_mock_utmi_clk_src",
+ .parent_data = gcc_parent_data_6,
+ .num_parents = ARRAY_SIZE(gcc_parent_data_6),
+ .ops = &clk_rcg2_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_nssnoc_memnoc_div_clk_src = {
+ .reg = 0x1700c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_nssnoc_memnoc_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_nssnoc_memnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_usb0_mock_utmi_div_clk_src = {
+ .reg = 0x2c040,
+ .shift = 0,
+ .width = 2,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb0_mock_utmi_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb0_mock_utmi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div gcc_usb1_mock_utmi_div_clk_src = {
+ .reg = 0x3c018,
+ .shift = 0,
+ .width = 2,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb1_mock_utmi_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb1_mock_utmi_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_branch gcc_adss_pwm_clk = {
+ .halt_reg = 0x1c00c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1c00c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_adss_pwm_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_adss_pwm_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_anoc_pcie0_1lane_m_clk = {
+ .halt_reg = 0x2e07c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2e07c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_anoc_pcie0_1lane_m_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie0_axi_m_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_anoc_pcie0_1lane_s_clk = {
+ .halt_reg = 0x2e0cc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2e0cc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_anoc_pcie0_1lane_s_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie0_axi_s_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_anoc_pcie1_2lane_m_clk = {
+ .halt_reg = 0x2e084,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2e084,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_anoc_pcie1_2lane_m_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie1_axi_m_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_anoc_pcie1_2lane_s_clk = {
+ .halt_reg = 0x2e0d0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2e0d0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_anoc_pcie1_2lane_s_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie1_axi_s_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_anoc_pcie2_2lane_m_clk = {
+ .halt_reg = 0x2e080,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2e080,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_anoc_pcie2_2lane_m_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie2_axi_m_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_anoc_pcie2_2lane_s_clk = {
+ .halt_reg = 0x2e0d4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2e0d4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_anoc_pcie2_2lane_s_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie2_axi_s_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_anoc_pcie3_2lane_m_clk = {
+ .halt_reg = 0x2e0bc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2e0bc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_anoc_pcie3_2lane_m_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie3_axi_m_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_anoc_pcie3_2lane_s_clk = {
+ .halt_reg = 0x2e0d8,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2e0d8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_anoc_pcie3_2lane_s_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie3_axi_s_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_anoc_pcie4_1lane_m_clk = {
+ .halt_reg = 0x2e0c0,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2e0c0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_anoc_pcie4_1lane_m_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie4_axi_m_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_anoc_pcie4_1lane_s_clk = {
+ .halt_reg = 0x2e0dc,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2e0dc,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_anoc_pcie4_1lane_s_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie4_axi_s_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cmn_12gpll_ahb_clk = {
+ .halt_reg = 0x3a004,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3a004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cmn_12gpll_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_cmn_12gpll_sys_clk = {
+ .halt_reg = 0x3a008,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x3a008,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_cmn_12gpll_sys_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_uniphy_sys_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mdio_ahb_clk = {
+ .halt_reg = 0x17040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17040,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_mdio_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_nss_ts_clk = {
+ .halt_reg = 0x17018,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x17018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_nss_ts_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_nss_ts_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_nsscc_clk = {
+ .halt_reg = 0x17034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17034,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_nsscc_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_nsscfg_clk = {
+ .halt_reg = 0x1702c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1702c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_nsscfg_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_nssnoc_atb_clk = {
+ .halt_reg = 0x17014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x17014,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_nssnoc_atb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qdss_at_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_nssnoc_memnoc_1_clk = {
+ .halt_reg = 0x17084,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17084,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_nssnoc_memnoc_1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_nssnoc_memnoc_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_nssnoc_memnoc_clk = {
+ .halt_reg = 0x17024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_nssnoc_memnoc_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_nssnoc_memnoc_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_nssnoc_nsscc_clk = {
+ .halt_reg = 0x17030,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17030,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_nssnoc_nsscc_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_nssnoc_pcnoc_1_clk = {
+ .halt_reg = 0x17080,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17080,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_nssnoc_pcnoc_1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_nssnoc_qosgen_ref_clk = {
+ .halt_reg = 0x1701c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1701c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_nssnoc_qosgen_ref_clk",
+ .parent_hws = (const struct clk_hw *[]) {
+ &gcc_xo_div4_clk_src.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_nssnoc_snoc_1_clk = {
+ .halt_reg = 0x1707c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1707c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_nssnoc_snoc_1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_system_noc_bfdcd_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_nssnoc_snoc_clk = {
+ .halt_reg = 0x17028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_nssnoc_snoc_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_system_noc_bfdcd_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_nssnoc_timeout_ref_clk = {
+ .halt_reg = 0x17020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_nssnoc_timeout_ref_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_xo_div4_clk_src.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_nssnoc_xo_dcd_clk = {
+ .halt_reg = 0x17074,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x17074,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_nssnoc_xo_dcd_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie0_ahb_clk = {
+ .halt_reg = 0x28030,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x28030,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie0_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie0_aux_clk = {
+ .halt_reg = 0x28070,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x28070,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie0_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie0_axi_m_clk = {
+ .halt_reg = 0x28038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x28038,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie0_axi_m_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie0_axi_m_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie0_axi_s_bridge_clk = {
+ .halt_reg = 0x28048,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x28048,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie0_axi_s_bridge_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie0_axi_s_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie0_axi_s_clk = {
+ .halt_reg = 0x28040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x28040,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie0_axi_s_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie0_axi_s_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_pcie0_pipe_clk_src = {
+ .reg = 0x28064,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "pcie0_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_PCIE30_PHY0_PIPE_CLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie0_pipe_clk = {
+ .halt_reg = 0x28068,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x28068,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie0_pipe_clk",
+ .parent_hws = (const struct clk_hw *[]) {
+ &gcc_pcie0_pipe_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie1_ahb_clk = {
+ .halt_reg = 0x29030,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x29030,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie1_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie1_aux_clk = {
+ .halt_reg = 0x29074,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x29074,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie1_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie1_axi_m_clk = {
+ .halt_reg = 0x29038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x29038,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie1_axi_m_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie1_axi_m_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie1_axi_s_bridge_clk = {
+ .halt_reg = 0x29048,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x29048,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie1_axi_s_bridge_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie1_axi_s_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie1_axi_s_clk = {
+ .halt_reg = 0x29040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x29040,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie1_axi_s_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie1_axi_s_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_pcie1_pipe_clk_src = {
+ .reg = 0x29064,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "pcie1_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_PCIE30_PHY1_PIPE_CLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie1_pipe_clk = {
+ .halt_reg = 0x29068,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x29068,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie1_pipe_clk",
+ .parent_hws = (const struct clk_hw *[]) {
+ &gcc_pcie1_pipe_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie2_ahb_clk = {
+ .halt_reg = 0x2a030,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2a030,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie2_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie2_aux_clk = {
+ .halt_reg = 0x2a078,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2a078,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie2_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie2_axi_m_clk = {
+ .halt_reg = 0x2a038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2a038,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie2_axi_m_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie2_axi_m_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie2_axi_s_bridge_clk = {
+ .halt_reg = 0x2a048,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2a048,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie2_axi_s_bridge_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie2_axi_s_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie2_axi_s_clk = {
+ .halt_reg = 0x2a040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2a040,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie2_axi_s_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie2_axi_s_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_pcie2_pipe_clk_src = {
+ .reg = 0x2a064,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "pcie2_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_PCIE30_PHY2_PIPE_CLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie2_pipe_clk = {
+ .halt_reg = 0x2a068,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x2a068,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie2_pipe_clk",
+ .parent_hws = (const struct clk_hw *[]) {
+ &gcc_pcie2_pipe_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie3_ahb_clk = {
+ .halt_reg = 0x2b030,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2b030,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie3_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie3_aux_clk = {
+ .halt_reg = 0x2b07c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2b07c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie3_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie3_axi_m_clk = {
+ .halt_reg = 0x2b038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2b038,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie3_axi_m_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie3_axi_m_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie3_axi_s_bridge_clk = {
+ .halt_reg = 0x2b048,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2b048,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie3_axi_s_bridge_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie3_axi_s_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie3_axi_s_clk = {
+ .halt_reg = 0x2b040,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2b040,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie3_axi_s_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie3_axi_s_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_pcie3_pipe_clk_src = {
+ .reg = 0x2b064,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "pcie3_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_PCIE30_PHY3_PIPE_CLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie3_pipe_clk = {
+ .halt_reg = 0x2b068,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x2b068,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie3_pipe_clk",
+ .parent_hws = (const struct clk_hw *[]) {
+ &gcc_pcie3_pipe_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie4_ahb_clk = {
+ .halt_reg = 0x2501c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2501c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie4_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie4_aux_clk = {
+ .halt_reg = 0x25020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x25020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie4_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie4_axi_m_clk = {
+ .halt_reg = 0x25028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x25028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie4_axi_m_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie4_axi_m_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie4_axi_s_bridge_clk = {
+ .halt_reg = 0x25038,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x25038,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie4_axi_s_bridge_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie4_axi_s_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie4_axi_s_clk = {
+ .halt_reg = 0x25030,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x25030,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie4_axi_s_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcie4_axi_s_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_pcie4_pipe_clk_src = {
+ .reg = 0x25058,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "pcie4_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_PCIE30_PHY4_PIPE_CLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie4_pipe_clk = {
+ .halt_reg = 0x2503c,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x2503c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie4_pipe_clk",
+ .parent_hws = (const struct clk_hw *[]) {
+ &gcc_pcie4_pipe_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie0_rchng_clk = {
+ .halt_reg = 0x28028,
+ .clkr = {
+ .enable_reg = 0x28028,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie0_rchng_clk",
+ .parent_hws = (const struct clk_hw *[]) {
+ &gcc_pcie0_rchng_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie1_rchng_clk = {
+ .halt_reg = 0x29028,
+ .clkr = {
+ .enable_reg = 0x29028,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie1_rchng_clk",
+ .parent_hws = (const struct clk_hw *[]) {
+ &gcc_pcie1_rchng_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie2_rchng_clk = {
+ .halt_reg = 0x2a028,
+ .clkr = {
+ .enable_reg = 0x2a028,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie2_rchng_clk",
+ .parent_hws = (const struct clk_hw *[]) {
+ &gcc_pcie2_rchng_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie3_rchng_clk = {
+ .halt_reg = 0x2b028,
+ .clkr = {
+ .enable_reg = 0x2b028,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie3_rchng_clk",
+ .parent_hws = (const struct clk_hw *[]) {
+ &gcc_pcie3_rchng_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_pcie4_rchng_clk = {
+ .halt_reg = 0x25014,
+ .clkr = {
+ .enable_reg = 0x25014,
+ .enable_mask = BIT(1),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_pcie4_rchng_clk",
+ .parent_hws = (const struct clk_hw *[]) {
+ &gcc_pcie4_rchng_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qdss_at_clk = {
+ .halt_reg = 0x2d034,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x2d034,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qdss_at_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qdss_at_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qdss_dap_clk = {
+ .halt_reg = 0x2d058,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0xb004,
+ .enable_mask = BIT(2),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qdss_dap_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qdss_dap_sync_clk_src.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qpic_ahb_clk = {
+ .halt_reg = 0x32010,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x32010,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qpic_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qpic_clk = {
+ .halt_reg = 0x32028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x32028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qpic_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qpic_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qpic_io_macro_clk = {
+ .halt_reg = 0x3200c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3200c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qpic_io_macro_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qpic_io_macro_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qpic_sleep_clk = {
+ .halt_reg = 0x32018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x32018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qpic_sleep_clk",
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_ahb_mst_clk = {
+ .halt_reg = 0x1014,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0xb004,
+ .enable_mask = BIT(14),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_ahb_mst_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_ahb_slv_clk = {
+ .halt_reg = 0x102c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0xb004,
+ .enable_mask = BIT(4),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_ahb_slv_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_se0_clk = {
+ .halt_reg = 0x202c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x202c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_se0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap_se0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_se1_clk = {
+ .halt_reg = 0x302c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x302c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_se1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap_se1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_se2_clk = {
+ .halt_reg = 0x3048,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3048,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_se2_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap_se2_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_se3_clk = {
+ .halt_reg = 0x3064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3064,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_se3_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap_se3_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_se4_clk = {
+ .halt_reg = 0x3080,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3080,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_se4_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap_se4_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_se5_clk = {
+ .halt_reg = 0x30a4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x30a4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_se5_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap_se5_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_se6_clk = {
+ .halt_reg = 0x4018,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4018,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_se6_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap_se6_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_qupv3_wrap_se7_clk = {
+ .halt_reg = 0x4034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x4034,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_qupv3_wrap_se7_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_qupv3_wrap_se7_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_ahb_clk = {
+ .halt_reg = 0x3303c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3303c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc1_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_apps_clk = {
+ .halt_reg = 0x3302c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3302c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc1_apps_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc1_apps_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_sdcc1_ice_core_clk = {
+ .halt_reg = 0x33034,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x33034,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_sdcc1_ice_core_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sdcc1_ice_core_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_snoc_usb_clk = {
+ .halt_reg = 0x2e0c4,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x2e0c4,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_snoc_usb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb0_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_uniphy0_ahb_clk = {
+ .halt_reg = 0x1704c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1704c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_uniphy0_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_uniphy0_sys_clk = {
+ .halt_reg = 0x17048,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x17048,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_uniphy0_sys_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_uniphy_sys_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_uniphy1_ahb_clk = {
+ .halt_reg = 0x1705c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1705c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_uniphy1_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_uniphy1_sys_clk = {
+ .halt_reg = 0x17058,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x17058,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_uniphy1_sys_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_uniphy_sys_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_uniphy2_ahb_clk = {
+ .halt_reg = 0x1706c,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x1706c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_uniphy2_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_uniphy2_sys_clk = {
+ .halt_reg = 0x17068,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x17068,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_uniphy2_sys_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_uniphy_sys_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb0_aux_clk = {
+ .halt_reg = 0x2c04c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x2c04c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb0_aux_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb0_aux_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb0_eud_at_clk = {
+ .halt_reg = 0x30004,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x30004,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb0_eud_at_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_eud_at_div_clk_src.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb0_master_clk = {
+ .halt_reg = 0x2c044,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x2c044,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb0_master_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb0_master_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb0_mock_utmi_clk = {
+ .halt_reg = 0x2c050,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x2c050,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb0_mock_utmi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb0_mock_utmi_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb0_phy_cfg_ahb_clk = {
+ .halt_reg = 0x2c05c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x2c05c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb0_phy_cfg_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap_phy_mux gcc_usb0_pipe_clk_src = {
+ .reg = 0x2c074,
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb0_pipe_clk_src",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_USB3_PHY0_CC_PIPE_CLK,
+ },
+ .num_parents = 1,
+ .ops = &clk_regmap_phy_mux_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb0_pipe_clk = {
+ .halt_reg = 0x2c054,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x2c054,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb0_pipe_clk",
+ .parent_hws = (const struct clk_hw *[]) {
+ &gcc_usb0_pipe_clk_src.clkr.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb0_sleep_clk = {
+ .halt_reg = 0x2c058,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x2c058,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb0_sleep_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sleep_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb1_master_clk = {
+ .halt_reg = 0x3c028,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3c028,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb1_master_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb1_mock_utmi_clk = {
+ .halt_reg = 0x3c024,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3c024,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb1_mock_utmi_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_usb1_mock_utmi_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb1_phy_cfg_ahb_clk = {
+ .halt_reg = 0x3c01c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x3c01c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb1_phy_cfg_ahb_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_pcnoc_bfdcd_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_usb1_sleep_clk = {
+ .halt_reg = 0x3c020,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x3c020,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "gcc_usb1_sleep_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &gcc_sleep_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap *gcc_ipq9650_clocks[] = {
+ [GCC_ADSS_PWM_CLK] = &gcc_adss_pwm_clk.clkr,
+ [GCC_ADSS_PWM_CLK_SRC] = &gcc_adss_pwm_clk_src.clkr,
+ [GCC_ANOC_PCIE0_1LANE_M_CLK] = &gcc_anoc_pcie0_1lane_m_clk.clkr,
+ [GCC_ANOC_PCIE0_1LANE_S_CLK] = &gcc_anoc_pcie0_1lane_s_clk.clkr,
+ [GCC_ANOC_PCIE1_2LANE_M_CLK] = &gcc_anoc_pcie1_2lane_m_clk.clkr,
+ [GCC_ANOC_PCIE1_2LANE_S_CLK] = &gcc_anoc_pcie1_2lane_s_clk.clkr,
+ [GCC_ANOC_PCIE2_2LANE_M_CLK] = &gcc_anoc_pcie2_2lane_m_clk.clkr,
+ [GCC_ANOC_PCIE2_2LANE_S_CLK] = &gcc_anoc_pcie2_2lane_s_clk.clkr,
+ [GCC_ANOC_PCIE3_2LANE_M_CLK] = &gcc_anoc_pcie3_2lane_m_clk.clkr,
+ [GCC_ANOC_PCIE3_2LANE_S_CLK] = &gcc_anoc_pcie3_2lane_s_clk.clkr,
+ [GCC_ANOC_PCIE4_1LANE_M_CLK] = &gcc_anoc_pcie4_1lane_m_clk.clkr,
+ [GCC_ANOC_PCIE4_1LANE_S_CLK] = &gcc_anoc_pcie4_1lane_s_clk.clkr,
+ [GCC_CMN_12GPLL_AHB_CLK] = &gcc_cmn_12gpll_ahb_clk.clkr,
+ [GCC_CMN_12GPLL_SYS_CLK] = &gcc_cmn_12gpll_sys_clk.clkr,
+ [GCC_MDIO_AHB_CLK] = &gcc_mdio_ahb_clk.clkr,
+ [GCC_NSS_TS_CLK] = &gcc_nss_ts_clk.clkr,
+ [GCC_NSS_TS_CLK_SRC] = &gcc_nss_ts_clk_src.clkr,
+ [GCC_NSSCC_CLK] = &gcc_nsscc_clk.clkr,
+ [GCC_NSSCFG_CLK] = &gcc_nsscfg_clk.clkr,
+ [GCC_NSSNOC_ATB_CLK] = &gcc_nssnoc_atb_clk.clkr,
+ [GCC_NSSNOC_MEMNOC_1_CLK] = &gcc_nssnoc_memnoc_1_clk.clkr,
+ [GCC_NSSNOC_MEMNOC_BFDCD_CLK_SRC] = &gcc_nssnoc_memnoc_bfdcd_clk_src.clkr,
+ [GCC_NSSNOC_MEMNOC_CLK] = &gcc_nssnoc_memnoc_clk.clkr,
+ [GCC_NSSNOC_MEMNOC_DIV_CLK_SRC] = &gcc_nssnoc_memnoc_div_clk_src.clkr,
+ [GCC_NSSNOC_NSSCC_CLK] = &gcc_nssnoc_nsscc_clk.clkr,
+ [GCC_NSSNOC_PCNOC_1_CLK] = &gcc_nssnoc_pcnoc_1_clk.clkr,
+ [GCC_NSSNOC_QOSGEN_REF_CLK] = &gcc_nssnoc_qosgen_ref_clk.clkr,
+ [GCC_NSSNOC_SNOC_1_CLK] = &gcc_nssnoc_snoc_1_clk.clkr,
+ [GCC_NSSNOC_SNOC_CLK] = &gcc_nssnoc_snoc_clk.clkr,
+ [GCC_NSSNOC_TIMEOUT_REF_CLK] = &gcc_nssnoc_timeout_ref_clk.clkr,
+ [GCC_NSSNOC_XO_DCD_CLK] = &gcc_nssnoc_xo_dcd_clk.clkr,
+ [GCC_PCIE0_AHB_CLK] = &gcc_pcie0_ahb_clk.clkr,
+ [GCC_PCIE0_AUX_CLK] = &gcc_pcie0_aux_clk.clkr,
+ [GCC_PCIE0_AXI_M_CLK] = &gcc_pcie0_axi_m_clk.clkr,
+ [GCC_PCIE0_AXI_M_CLK_SRC] = &gcc_pcie0_axi_m_clk_src.clkr,
+ [GCC_PCIE0_AXI_S_BRIDGE_CLK] = &gcc_pcie0_axi_s_bridge_clk.clkr,
+ [GCC_PCIE0_AXI_S_CLK] = &gcc_pcie0_axi_s_clk.clkr,
+ [GCC_PCIE0_AXI_S_CLK_SRC] = &gcc_pcie0_axi_s_clk_src.clkr,
+ [GCC_PCIE0_PIPE_CLK] = &gcc_pcie0_pipe_clk.clkr,
+ [GCC_PCIE0_PIPE_CLK_SRC] = &gcc_pcie0_pipe_clk_src.clkr,
+ [GCC_PCIE0_RCHNG_CLK_SRC] = &gcc_pcie0_rchng_clk_src.clkr,
+ [GCC_PCIE0_RCHNG_CLK] = &gcc_pcie0_rchng_clk.clkr,
+ [GCC_PCIE1_AHB_CLK] = &gcc_pcie1_ahb_clk.clkr,
+ [GCC_PCIE1_AUX_CLK] = &gcc_pcie1_aux_clk.clkr,
+ [GCC_PCIE1_AXI_M_CLK] = &gcc_pcie1_axi_m_clk.clkr,
+ [GCC_PCIE1_AXI_M_CLK_SRC] = &gcc_pcie1_axi_m_clk_src.clkr,
+ [GCC_PCIE1_AXI_S_BRIDGE_CLK] = &gcc_pcie1_axi_s_bridge_clk.clkr,
+ [GCC_PCIE1_AXI_S_CLK] = &gcc_pcie1_axi_s_clk.clkr,
+ [GCC_PCIE1_AXI_S_CLK_SRC] = &gcc_pcie1_axi_s_clk_src.clkr,
+ [GCC_PCIE1_PIPE_CLK] = &gcc_pcie1_pipe_clk.clkr,
+ [GCC_PCIE1_PIPE_CLK_SRC] = &gcc_pcie1_pipe_clk_src.clkr,
+ [GCC_PCIE1_RCHNG_CLK_SRC] = &gcc_pcie1_rchng_clk_src.clkr,
+ [GCC_PCIE1_RCHNG_CLK] = &gcc_pcie1_rchng_clk.clkr,
+ [GCC_PCIE2_AHB_CLK] = &gcc_pcie2_ahb_clk.clkr,
+ [GCC_PCIE2_AUX_CLK] = &gcc_pcie2_aux_clk.clkr,
+ [GCC_PCIE2_AXI_M_CLK] = &gcc_pcie2_axi_m_clk.clkr,
+ [GCC_PCIE2_AXI_M_CLK_SRC] = &gcc_pcie2_axi_m_clk_src.clkr,
+ [GCC_PCIE2_AXI_S_BRIDGE_CLK] = &gcc_pcie2_axi_s_bridge_clk.clkr,
+ [GCC_PCIE2_AXI_S_CLK] = &gcc_pcie2_axi_s_clk.clkr,
+ [GCC_PCIE2_AXI_S_CLK_SRC] = &gcc_pcie2_axi_s_clk_src.clkr,
+ [GCC_PCIE2_PIPE_CLK] = &gcc_pcie2_pipe_clk.clkr,
+ [GCC_PCIE2_PIPE_CLK_SRC] = &gcc_pcie2_pipe_clk_src.clkr,
+ [GCC_PCIE2_RCHNG_CLK_SRC] = &gcc_pcie2_rchng_clk_src.clkr,
+ [GCC_PCIE2_RCHNG_CLK] = &gcc_pcie2_rchng_clk.clkr,
+ [GCC_PCIE3_AHB_CLK] = &gcc_pcie3_ahb_clk.clkr,
+ [GCC_PCIE3_AUX_CLK] = &gcc_pcie3_aux_clk.clkr,
+ [GCC_PCIE3_AXI_M_CLK] = &gcc_pcie3_axi_m_clk.clkr,
+ [GCC_PCIE3_AXI_M_CLK_SRC] = &gcc_pcie3_axi_m_clk_src.clkr,
+ [GCC_PCIE3_AXI_S_BRIDGE_CLK] = &gcc_pcie3_axi_s_bridge_clk.clkr,
+ [GCC_PCIE3_AXI_S_CLK] = &gcc_pcie3_axi_s_clk.clkr,
+ [GCC_PCIE3_AXI_S_CLK_SRC] = &gcc_pcie3_axi_s_clk_src.clkr,
+ [GCC_PCIE3_PIPE_CLK] = &gcc_pcie3_pipe_clk.clkr,
+ [GCC_PCIE3_PIPE_CLK_SRC] = &gcc_pcie3_pipe_clk_src.clkr,
+ [GCC_PCIE3_RCHNG_CLK_SRC] = &gcc_pcie3_rchng_clk_src.clkr,
+ [GCC_PCIE3_RCHNG_CLK] = &gcc_pcie3_rchng_clk.clkr,
+ [GCC_PCIE4_AHB_CLK] = &gcc_pcie4_ahb_clk.clkr,
+ [GCC_PCIE4_AUX_CLK] = &gcc_pcie4_aux_clk.clkr,
+ [GCC_PCIE4_AXI_M_CLK] = &gcc_pcie4_axi_m_clk.clkr,
+ [GCC_PCIE4_AXI_M_CLK_SRC] = &gcc_pcie4_axi_m_clk_src.clkr,
+ [GCC_PCIE4_AXI_S_BRIDGE_CLK] = &gcc_pcie4_axi_s_bridge_clk.clkr,
+ [GCC_PCIE4_AXI_S_CLK] = &gcc_pcie4_axi_s_clk.clkr,
+ [GCC_PCIE4_AXI_S_CLK_SRC] = &gcc_pcie4_axi_s_clk_src.clkr,
+ [GCC_PCIE4_PIPE_CLK] = &gcc_pcie4_pipe_clk.clkr,
+ [GCC_PCIE4_PIPE_CLK_SRC] = &gcc_pcie4_pipe_clk_src.clkr,
+ [GCC_PCIE4_RCHNG_CLK_SRC] = &gcc_pcie4_rchng_clk_src.clkr,
+ [GCC_PCIE4_RCHNG_CLK] = &gcc_pcie4_rchng_clk.clkr,
+ [GCC_PCIE_AUX_CLK_SRC] = &gcc_pcie_aux_clk_src.clkr,
+ [GCC_PCNOC_BFDCD_CLK_SRC] = &gcc_pcnoc_bfdcd_clk_src.clkr,
+ [GCC_QDSS_AT_CLK] = &gcc_qdss_at_clk.clkr,
+ [GCC_QDSS_AT_CLK_SRC] = &gcc_qdss_at_clk_src.clkr,
+ [GCC_QDSS_DAP_CLK] = &gcc_qdss_dap_clk.clkr,
+ [GCC_QDSS_TSCTR_CLK_SRC] = &gcc_qdss_tsctr_clk_src.clkr,
+ [GCC_QPIC_AHB_CLK] = &gcc_qpic_ahb_clk.clkr,
+ [GCC_QPIC_CLK] = &gcc_qpic_clk.clkr,
+ [GCC_QPIC_CLK_SRC] = &gcc_qpic_clk_src.clkr,
+ [GCC_QPIC_IO_MACRO_CLK] = &gcc_qpic_io_macro_clk.clkr,
+ [GCC_QPIC_IO_MACRO_CLK_SRC] = &gcc_qpic_io_macro_clk_src.clkr,
+ [GCC_QPIC_SLEEP_CLK] = &gcc_qpic_sleep_clk.clkr,
+ [GCC_QUPV3_2X_CORE_CLK_SRC] = &gcc_qupv3_2x_core_clk_src.clkr,
+ [GCC_QUPV3_AHB_MST_CLK] = &gcc_qupv3_ahb_mst_clk.clkr,
+ [GCC_QUPV3_AHB_SLV_CLK] = &gcc_qupv3_ahb_slv_clk.clkr,
+ [GCC_QUPV3_WRAP_SE0_CLK] = &gcc_qupv3_wrap_se0_clk.clkr,
+ [GCC_QUPV3_WRAP_SE0_CLK_SRC] = &gcc_qupv3_wrap_se0_clk_src.clkr,
+ [GCC_QUPV3_WRAP_SE1_CLK] = &gcc_qupv3_wrap_se1_clk.clkr,
+ [GCC_QUPV3_WRAP_SE1_CLK_SRC] = &gcc_qupv3_wrap_se1_clk_src.clkr,
+ [GCC_QUPV3_WRAP_SE2_CLK] = &gcc_qupv3_wrap_se2_clk.clkr,
+ [GCC_QUPV3_WRAP_SE2_CLK_SRC] = &gcc_qupv3_wrap_se2_clk_src.clkr,
+ [GCC_QUPV3_WRAP_SE3_CLK] = &gcc_qupv3_wrap_se3_clk.clkr,
+ [GCC_QUPV3_WRAP_SE3_CLK_SRC] = &gcc_qupv3_wrap_se3_clk_src.clkr,
+ [GCC_QUPV3_WRAP_SE4_CLK] = &gcc_qupv3_wrap_se4_clk.clkr,
+ [GCC_QUPV3_WRAP_SE4_CLK_SRC] = &gcc_qupv3_wrap_se4_clk_src.clkr,
+ [GCC_QUPV3_WRAP_SE5_CLK] = &gcc_qupv3_wrap_se5_clk.clkr,
+ [GCC_QUPV3_WRAP_SE5_CLK_SRC] = &gcc_qupv3_wrap_se5_clk_src.clkr,
+ [GCC_QUPV3_WRAP_SE6_CLK] = &gcc_qupv3_wrap_se6_clk.clkr,
+ [GCC_QUPV3_WRAP_SE6_CLK_SRC] = &gcc_qupv3_wrap_se6_clk_src.clkr,
+ [GCC_QUPV3_WRAP_SE7_CLK] = &gcc_qupv3_wrap_se7_clk.clkr,
+ [GCC_QUPV3_WRAP_SE7_CLK_SRC] = &gcc_qupv3_wrap_se7_clk_src.clkr,
+ [GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr,
+ [GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr,
+ [GCC_SDCC1_APPS_CLK_SRC] = &gcc_sdcc1_apps_clk_src.clkr,
+ [GCC_SDCC1_ICE_CORE_CLK] = &gcc_sdcc1_ice_core_clk.clkr,
+ [GCC_SDCC1_ICE_CORE_CLK_SRC] = &gcc_sdcc1_ice_core_clk_src.clkr,
+ [GCC_SLEEP_CLK_SRC] = &gcc_sleep_clk_src.clkr,
+ [GCC_SNOC_USB_CLK] = &gcc_snoc_usb_clk.clkr,
+ [GCC_SYSTEM_NOC_BFDCD_CLK_SRC] = &gcc_system_noc_bfdcd_clk_src.clkr,
+ [GCC_UNIPHY0_AHB_CLK] = &gcc_uniphy0_ahb_clk.clkr,
+ [GCC_UNIPHY0_SYS_CLK] = &gcc_uniphy0_sys_clk.clkr,
+ [GCC_UNIPHY1_AHB_CLK] = &gcc_uniphy1_ahb_clk.clkr,
+ [GCC_UNIPHY1_SYS_CLK] = &gcc_uniphy1_sys_clk.clkr,
+ [GCC_UNIPHY2_AHB_CLK] = &gcc_uniphy2_ahb_clk.clkr,
+ [GCC_UNIPHY2_SYS_CLK] = &gcc_uniphy2_sys_clk.clkr,
+ [GCC_UNIPHY_SYS_CLK_SRC] = &gcc_uniphy_sys_clk_src.clkr,
+ [GCC_USB0_AUX_CLK] = &gcc_usb0_aux_clk.clkr,
+ [GCC_USB0_AUX_CLK_SRC] = &gcc_usb0_aux_clk_src.clkr,
+ [GCC_USB0_EUD_AT_CLK] = &gcc_usb0_eud_at_clk.clkr,
+ [GCC_USB0_MASTER_CLK] = &gcc_usb0_master_clk.clkr,
+ [GCC_USB0_MASTER_CLK_SRC] = &gcc_usb0_master_clk_src.clkr,
+ [GCC_USB0_MOCK_UTMI_CLK] = &gcc_usb0_mock_utmi_clk.clkr,
+ [GCC_USB0_MOCK_UTMI_CLK_SRC] = &gcc_usb0_mock_utmi_clk_src.clkr,
+ [GCC_USB0_MOCK_UTMI_DIV_CLK_SRC] = &gcc_usb0_mock_utmi_div_clk_src.clkr,
+ [GCC_USB0_PHY_CFG_AHB_CLK] = &gcc_usb0_phy_cfg_ahb_clk.clkr,
+ [GCC_USB0_PIPE_CLK] = &gcc_usb0_pipe_clk.clkr,
+ [GCC_USB0_PIPE_CLK_SRC] = &gcc_usb0_pipe_clk_src.clkr,
+ [GCC_USB0_SLEEP_CLK] = &gcc_usb0_sleep_clk.clkr,
+ [GCC_USB1_MASTER_CLK] = &gcc_usb1_master_clk.clkr,
+ [GCC_USB1_MOCK_UTMI_CLK] = &gcc_usb1_mock_utmi_clk.clkr,
+ [GCC_USB1_MOCK_UTMI_CLK_SRC] = &gcc_usb1_mock_utmi_clk_src.clkr,
+ [GCC_USB1_MOCK_UTMI_DIV_CLK_SRC] = &gcc_usb1_mock_utmi_div_clk_src.clkr,
+ [GCC_USB1_PHY_CFG_AHB_CLK] = &gcc_usb1_phy_cfg_ahb_clk.clkr,
+ [GCC_USB1_SLEEP_CLK] = &gcc_usb1_sleep_clk.clkr,
+ [GCC_XO_CLK_SRC] = &gcc_xo_clk_src.clkr,
+ [GPLL0_MAIN] = &gpll0_main.clkr,
+ [GPLL0] = &gpll0.clkr,
+ [GPLL2] = &gpll2.clkr,
+ [GPLL2_OUT_MAIN] = &gpll2_out_main.clkr,
+ [GPLL4] = &gpll4.clkr,
+};
+
+static const struct qcom_reset_map gcc_ipq9650_resets[] = {
+ [GCC_ADSS_BCR] = { 0x1c000 },
+ [GCC_ADSS_PWM_CLK_ARES] = { 0x1c00c, 2 },
+ [GCC_APC0_VOLTAGE_DROOP_DETECTOR_BCR] = { 0x38000 },
+ [GCC_APC0_VOLTAGE_DROOP_DETECTOR_GPLL0_CLK_ARES] = { 0x3800c, 2 },
+ [GCC_APSS_AHB_CLK_ARES] = { 0x24014, 2 },
+ [GCC_APSS_ATB_CLK_ARES] = { 0x24034, 2 },
+ [GCC_APSS_AXI_CLK_ARES] = { 0x24018, 2 },
+ [GCC_APSS_TS_CLK_ARES] = { 0x24030, 2 },
+ [GCC_BOOT_ROM_AHB_CLK_ARES] = { 0x1302c, 2 },
+ [GCC_BOOT_ROM_BCR] = { 0x13028 },
+ [GCC_CPUSS_TRIG_CLK_ARES] = { 0x2401c, 2 },
+ [GCC_GP1_CLK_ARES] = { 0x8018, 2 },
+ [GCC_GP2_CLK_ARES] = { 0x8030, 2 },
+ [GCC_GP3_CLK_ARES] = { 0x8048, 2 },
+ [GCC_MDIO_AHB_CLK_ARES] = { 0x17040, 2 },
+ [GCC_MDIO_BCR] = { 0x1703c },
+ [GCC_NSS_BCR] = { 0x17000 },
+ [GCC_NSS_TS_CLK_ARES] = { 0x17018, 2 },
+ [GCC_NSSCC_CLK_ARES] = { 0x17034, 2 },
+ [GCC_NSSCFG_CLK_ARES] = { 0x1702c, 2 },
+ [GCC_NSSNOC_ATB_CLK_ARES] = { 0x17014, 2 },
+ [GCC_NSSNOC_MEMNOC_1_CLK_ARES] = { 0x17084, 2 },
+ [GCC_NSSNOC_MEMNOC_CLK_ARES] = { 0x17024, 2 },
+ [GCC_NSSNOC_NSSCC_CLK_ARES] = { 0x17030, 2 },
+ [GCC_NSSNOC_PCNOC_1_CLK_ARES] = { 0x17080, 2 },
+ [GCC_NSSNOC_QOSGEN_REF_CLK_ARES] = { 0x1701c, 2 },
+ [GCC_NSSNOC_SNOC_1_CLK_ARES] = { 0x1707c, 2 },
+ [GCC_NSSNOC_SNOC_CLK_ARES] = { 0x17028, 2 },
+ [GCC_NSSNOC_TIMEOUT_REF_CLK_ARES] = { 0x17020, 2 },
+ [GCC_NSSNOC_XO_DCD_CLK_ARES] = { 0x17074, 2 },
+ [GCC_PCIE0_AHB_CLK_ARES] = { 0x28030, 2 },
+ [GCC_PCIE0_AUX_CLK_ARES] = { 0x28070, 2 },
+ [GCC_PCIE0_AXI_M_CLK_ARES] = { 0x28038, 2 },
+ [GCC_PCIE0_AXI_S_BRIDGE_CLK_ARES] = { 0x28048, 2 },
+ [GCC_PCIE0_AXI_S_CLK_ARES] = { 0x28040, 2 },
+ [GCC_PCIE0_BCR] = { 0x28000 },
+ [GCC_PCIE0_LINK_DOWN_BCR] = { 0x28054 },
+ [GCC_PCIE0_PHY_BCR] = { 0x28060 },
+ [GCC_PCIE0_PIPE_CLK_ARES] = { 0x28068, 2 },
+ [GCC_PCIE0PHY_PHY_BCR] = { 0x2805c },
+ [GCC_PCIE0_PIPE_RESET] = { 0x28058, 0 },
+ [GCC_PCIE0_CORE_STICKY_RESET] = { 0x28058, 1 },
+ [GCC_PCIE0_AXI_S_STICKY_RESET] = { 0x28058, 2 },
+ [GCC_PCIE0_AXI_S_RESET] = { 0x28058, 3 },
+ [GCC_PCIE0_AXI_M_STICKY_RESET] = { 0x28058, 4 },
+ [GCC_PCIE0_AXI_M_RESET] = { 0x28058, 5 },
+ [GCC_PCIE0_AUX_RESET] = { 0x28058, 6 },
+ [GCC_PCIE0_AHB_RESET] = { 0x28058, 7 },
+ [GCC_PCIE1_AHB_CLK_ARES] = { 0x29030, 2 },
+ [GCC_PCIE1_AUX_CLK_ARES] = { 0x29074, 2 },
+ [GCC_PCIE1_AXI_M_CLK_ARES] = { 0x29038, 2 },
+ [GCC_PCIE1_AXI_S_BRIDGE_CLK_ARES] = { 0x29048, 2 },
+ [GCC_PCIE1_AXI_S_CLK_ARES] = { 0x29040, 2 },
+ [GCC_PCIE1_BCR] = { 0x29000 },
+ [GCC_PCIE1_LINK_DOWN_BCR] = { 0x29054 },
+ [GCC_PCIE1_PHY_BCR] = { 0x29060 },
+ [GCC_PCIE1_PIPE_CLK_ARES] = { 0x29068, 2 },
+ [GCC_PCIE1PHY_PHY_BCR] = { 0x2905c },
+ [GCC_PCIE1_PIPE_RESET] = { 0x29058, 0 },
+ [GCC_PCIE1_CORE_STICKY_RESET] = { 0x29058, 1 },
+ [GCC_PCIE1_AXI_S_STICKY_RESET] = { 0x29058, 2 },
+ [GCC_PCIE1_AXI_S_RESET] = { 0x29058, 3 },
+ [GCC_PCIE1_AXI_M_STICKY_RESET] = { 0x29058, 4 },
+ [GCC_PCIE1_AXI_M_RESET] = { 0x29058, 5 },
+ [GCC_PCIE1_AUX_RESET] = { 0x29058, 6 },
+ [GCC_PCIE1_AHB_RESET] = { 0x29058, 7 },
+ [GCC_PCIE2_AHB_CLK_ARES] = { 0x2a030, 2 },
+ [GCC_PCIE2_AUX_CLK_ARES] = { 0x2a078, 2 },
+ [GCC_PCIE2_AXI_M_CLK_ARES] = { 0x2a038, 2 },
+ [GCC_PCIE2_AXI_S_BRIDGE_CLK_ARES] = { 0x2a048, 2 },
+ [GCC_PCIE2_AXI_S_CLK_ARES] = { 0x2a040, 2 },
+ [GCC_PCIE2_BCR] = { 0x2a000 },
+ [GCC_PCIE2_LINK_DOWN_BCR] = { 0x2a054 },
+ [GCC_PCIE2_PHY_BCR] = { 0x2a060 },
+ [GCC_PCIE2_PIPE_CLK_ARES] = { 0x2a068, 2 },
+ [GCC_PCIE2PHY_PHY_BCR] = { 0x2a05c },
+ [GCC_PCIE2_PIPE_RESET] = { 0x2a058, 0 },
+ [GCC_PCIE2_CORE_STICKY_RESET] = { 0x2a058, 1 },
+ [GCC_PCIE2_AXI_S_STICKY_RESET] = { 0x2a058, 2 },
+ [GCC_PCIE2_AXI_S_RESET] = { 0x2a058, 3 },
+ [GCC_PCIE2_AXI_M_STICKY_RESET] = { 0x2a058, 4 },
+ [GCC_PCIE2_AXI_M_RESET] = { 0x2a058, 5 },
+ [GCC_PCIE2_AUX_RESET] = { 0x2a058, 6 },
+ [GCC_PCIE2_AHB_RESET] = { 0x2a058, 7 },
+ [GCC_PCIE3_AHB_CLK_ARES] = { 0x2b030, 2 },
+ [GCC_PCIE3_AUX_CLK_ARES] = { 0x2b07c, 2 },
+ [GCC_PCIE3_AXI_M_CLK_ARES] = { 0x2b038, 2 },
+ [GCC_PCIE3_AXI_S_BRIDGE_CLK_ARES] = { 0x2b048, 2 },
+ [GCC_PCIE3_AXI_S_CLK_ARES] = { 0x2b040, 2 },
+ [GCC_PCIE3_BCR] = { 0x2b000 },
+ [GCC_PCIE3_LINK_DOWN_BCR] = { 0x2b054 },
+ [GCC_PCIE3_PHY_BCR] = { 0x2b060 },
+ [GCC_PCIE3_PIPE_CLK_ARES] = { 0x2b068, 2 },
+ [GCC_PCIE3PHY_PHY_BCR] = { 0x2b05c },
+ [GCC_PCIE3_PIPE_RESET] = { 0x2b058, 0 },
+ [GCC_PCIE3_CORE_STICKY_RESET] = { 0x2b058, 1 },
+ [GCC_PCIE3_AXI_S_STICKY_RESET] = { 0x2b058, 2 },
+ [GCC_PCIE3_AXI_S_RESET] = { 0x2b058, 3 },
+ [GCC_PCIE3_AXI_M_STICKY_RESET] = { 0x2b058, 4 },
+ [GCC_PCIE3_AXI_M_RESET] = { 0x2b058, 5 },
+ [GCC_PCIE3_AUX_RESET] = { 0x2b058, 6 },
+ [GCC_PCIE3_AHB_RESET] = { 0x2b058, 7 },
+ [GCC_PCIE4_AHB_CLK_ARES] = { 0x2501c, 2 },
+ [GCC_PCIE4_AUX_CLK_ARES] = { 0x25020, 2 },
+ [GCC_PCIE4_AXI_M_CLK_ARES] = { 0x25028, 2 },
+ [GCC_PCIE4_AXI_S_BRIDGE_CLK_ARES] = { 0x25038, 2 },
+ [GCC_PCIE4_AXI_S_CLK_ARES] = { 0x25030, 2 },
+ [GCC_PCIE4_BCR] = { 0x25000 },
+ [GCC_PCIE4_LINK_DOWN_BCR] = { 0x25044 },
+ [GCC_PCIE4_PHY_BCR] = { 0x2504c },
+ [GCC_PCIE4_PIPE_CLK_ARES] = { 0x2503c, 2 },
+ [GCC_PCIE4_PIPE_RESET] = { 0x25054, 0 },
+ [GCC_PCIE4_CORE_STICKY_RESET] = { 0x25054, 1 },
+ [GCC_PCIE4_AXI_S_STICKY_RESET] = { 0x25054, 2 },
+ [GCC_PCIE4_AXI_S_RESET] = { 0x25054, 3 },
+ [GCC_PCIE4_AXI_M_STICKY_RESET] = { 0x25054, 4 },
+ [GCC_PCIE4_AXI_M_RESET] = { 0x25054, 5 },
+ [GCC_PCIE4_AUX_RESET] = { 0x25054, 6 },
+ [GCC_PCIE4_AHB_RESET] = { 0x25054, 7 },
+ [GCC_PCIE4PHY_PHY_BCR] = { 0x25048 },
+ [GCC_QDSS_APB2JTAG_CLK_ARES] = { 0x2d05c, 2 },
+ [GCC_QDSS_AT_CLK_ARES] = { 0x2d034, 2 },
+ [GCC_QDSS_BCR] = { 0x2d000 },
+ [GCC_QDSS_CFG_AHB_CLK_ARES] = { 0x2d068, 2 },
+ [GCC_QDSS_DAP_AHB_CLK_ARES] = { 0x2d064, 2 },
+ [GCC_QDSS_DAP_CLK_ARES] = { 0x2d058, 2 },
+ [GCC_QDSS_ETR_USB_CLK_ARES] = { 0x2d060, 2 },
+ [GCC_QDSS_EUD_AT_CLK_ARES] = { 0x2d06c, 2 },
+ [GCC_QDSS_STM_CLK_ARES] = { 0x2d03c, 2 },
+ [GCC_QDSS_TRACECLKIN_CLK_ARES] = { 0x2d040, 2 },
+ [GCC_QDSS_TS_CLK_ARES] = { 0x2d078, 2 },
+ [GCC_QDSS_TSCTR_DIV16_CLK_ARES] = { 0x2d054, 2 },
+ [GCC_QDSS_TSCTR_DIV2_CLK_ARES] = { 0x2d044, 2 },
+ [GCC_QDSS_TSCTR_DIV3_CLK_ARES] = { 0x2d048, 2 },
+ [GCC_QDSS_TSCTR_DIV4_CLK_ARES] = { 0x2d04c, 2 },
+ [GCC_QDSS_TSCTR_DIV8_CLK_ARES] = { 0x2d050, 2 },
+ [GCC_QPIC_AHB_CLK_ARES] = { 0x32010, 2 },
+ [GCC_QPIC_CLK_ARES] = { 0x32028, 2 },
+ [GCC_QPIC_BCR] = { 0x32000 },
+ [GCC_QPIC_IO_MACRO_CLK_ARES] = { 0x3200c, 2 },
+ [GCC_QPIC_SLEEP_CLK_ARES] = { 0x32018, 2 },
+ [GCC_QUPV3_2X_CORE_CLK_ARES] = { 0x1020, 2 },
+ [GCC_QUPV3_AHB_MST_CLK_ARES] = { 0x1014, 2 },
+ [GCC_QUPV3_AHB_SLV_CLK_ARES] = { 0x102c, 2 },
+ [GCC_QUPV3_BCR] = { 0x1000 },
+ [GCC_QUPV3_CORE_CLK_ARES] = { 0x1018, 2 },
+ [GCC_QUPV3_WRAP_SE0_CLK_ARES] = { 0x202c, 2 },
+ [GCC_QUPV3_WRAP_SE0_BCR] = { 0x2000 },
+ [GCC_QUPV3_WRAP_SE1_CLK_ARES] = { 0x302c, 2 },
+ [GCC_QUPV3_WRAP_SE1_BCR] = { 0x3000 },
+ [GCC_QUPV3_WRAP_SE2_CLK_ARES] = { 0x3048, 2 },
+ [GCC_QUPV3_WRAP_SE2_BCR] = { 0x3030 },
+ [GCC_QUPV3_WRAP_SE3_CLK_ARES] = { 0x3064, 2 },
+ [GCC_QUPV3_WRAP_SE3_BCR] = { 0x304c },
+ [GCC_QUPV3_WRAP_SE4_CLK_ARES] = { 0x3080, 2 },
+ [GCC_QUPV3_WRAP_SE4_BCR] = { 0x3068 },
+ [GCC_QUPV3_WRAP_SE5_CLK_ARES] = { 0x30a4, 2 },
+ [GCC_QUPV3_WRAP_SE5_BCR] = { 0x308c },
+ [GCC_QUPV3_WRAP_SE6_CLK_ARES] = { 0x4018, 2 },
+ [GCC_QUPV3_WRAP_SE6_BCR] = { 0x4000 },
+ [GCC_QUPV3_WRAP_SE7_CLK_ARES] = { 0x4034, 2 },
+ [GCC_QUPV3_WRAP_SE7_BCR] = { 0x401c },
+ [GCC_QUSB2_0_PHY_BCR] = { 0x2c068 },
+ [GCC_QUSB2_1_PHY_BCR] = { 0x3c030 },
+ [GCC_SDCC1_APPS_CLK_ARES] = { 0x3302c, 2 },
+ [GCC_SDCC1_ICE_CORE_CLK_ARES] = { 0x33034, 2 },
+ [GCC_SDCC_BCR] = { 0x33000 },
+ [GCC_TLMM_AHB_CLK_ARES] = { 0x3e004, 2 },
+ [GCC_TLMM_CLK_ARES] = { 0x3e008, 2 },
+ [GCC_TLMM_BCR] = { 0x3e000 },
+ [GCC_UNIPHY0_AHB_CLK_ARES] = { 0x1704c, 2 },
+ [GCC_UNIPHY0_BCR] = { 0x17044 },
+ [GCC_UNIPHY0_PMA_BCR] = { 0x17098 },
+ [GCC_UNIPHY0_SYS_CLK_ARES] = { 0x17048, 2 },
+ [GCC_UNIPHY1_AHB_CLK_ARES] = { 0x1705c, 2 },
+ [GCC_UNIPHY1_BCR] = { 0x17054 },
+ [GCC_UNIPHY1_PMA_BCR] = { 0x1709c },
+ [GCC_UNIPHY1_SYS_CLK_ARES] = { 0x17058, 2 },
+ [GCC_UNIPHY2_AHB_CLK_ARES] = { 0x1706c, 2 },
+ [GCC_UNIPHY2_BCR] = { 0x17064 },
+ [GCC_UNIPHY2_PMA_BCR] = { 0x170a0 },
+ [GCC_UNIPHY2_SYS_CLK_ARES] = { 0x17068, 2 },
+ [GCC_UNIPHY0_XPCS_ARES] = { 0x17050, 2 },
+ [GCC_UNIPHY1_XLGPCS_ARES] = { 0x17060, 1 },
+ [GCC_UNIPHY1_XPCS_ARES] = { 0x17060, 2 },
+ [GCC_UNIPHY2_XLGPCS_ARES] = { 0x17070, 1 },
+ [GCC_UNIPHY2_XPCS_ARES] = { 0x17070, 2 },
+ [GCC_USB0_AUX_CLK_ARES] = { 0x2c04c, 2 },
+ [GCC_USB0_MASTER_CLK_ARES] = { 0x2c044, 2 },
+ [GCC_USB0_MOCK_UTMI_CLK_ARES] = { 0x2c050, 2 },
+ [GCC_USB0_PHY_BCR] = { 0x2c06c },
+ [GCC_USB0_PHY_CFG_AHB_CLK_ARES] = { 0x2c05c, 2 },
+ [GCC_USB0_PIPE_CLK_ARES] = { 0x2c054, 2 },
+ [GCC_USB0_SLEEP_CLK_ARES] = { 0x2c058, 2 },
+ [GCC_USB1_BCR] = { 0x3c000 },
+ [GCC_USB1_MASTER_CLK_ARES] = { 0x3c028, 2 },
+ [GCC_USB1_MOCK_UTMI_CLK_ARES] = { 0x3c024, 2 },
+ [GCC_USB1_PHY_CFG_AHB_CLK_ARES] = { 0x3c01c, 2 },
+ [GCC_USB1_SLEEP_CLK_ARES] = { 0x3c020, 2 },
+ [GCC_USB3PHY_0_PHY_BCR] = { 0x2c070 },
+ [GCC_USB_BCR] = { 0x2c000 },
+};
+
+static const struct of_device_id gcc_ipq9650_match_table[] = {
+ { .compatible = "qcom,ipq9650-gcc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, gcc_ipq9650_match_table);
+
+static const struct regmap_config gcc_ipq9650_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x3f024,
+ .fast_io = true,
+};
+
+static struct clk_hw *gcc_ipq9650_hws[] = {
+ &gpll0_div2.hw,
+ &gcc_xo_div4_clk_src.hw,
+ &gcc_qdss_dap_sync_clk_src.hw,
+ &gcc_eud_at_div_clk_src.hw,
+};
+
+static const struct qcom_cc_desc gcc_ipq9650_desc = {
+ .config = &gcc_ipq9650_regmap_config,
+ .clks = gcc_ipq9650_clocks,
+ .num_clks = ARRAY_SIZE(gcc_ipq9650_clocks),
+ .resets = gcc_ipq9650_resets,
+ .num_resets = ARRAY_SIZE(gcc_ipq9650_resets),
+ .clk_hws = gcc_ipq9650_hws,
+ .num_clk_hws = ARRAY_SIZE(gcc_ipq9650_hws),
+};
+
+static int gcc_ipq9650_probe(struct platform_device *pdev)
+{
+ return qcom_cc_probe(pdev, &gcc_ipq9650_desc);
+}
+
+static struct platform_driver gcc_ipq9650_driver = {
+ .probe = gcc_ipq9650_probe,
+ .driver = {
+ .name = "qcom,gcc-ipq9650",
+ .of_match_table = gcc_ipq9650_match_table,
+ },
+};
+
+static int __init gcc_ipq9650_init(void)
+{
+ return platform_driver_register(&gcc_ipq9650_driver);
+}
+core_initcall(gcc_ipq9650_init);
+
+static void __exit gcc_ipq9650_exit(void)
+{
+ platform_driver_unregister(&gcc_ipq9650_driver);
+}
+module_exit(gcc_ipq9650_exit);
+
+MODULE_DESCRIPTION("QTI GCC IPQ9650 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/gcc-nord.c b/drivers/clk/qcom/gcc-nord.c
index 3098d8fac0fb..8a6e429f2640 100644
--- a/drivers/clk/qcom/gcc-nord.c
+++ b/drivers/clk/qcom/gcc-nord.c
@@ -1850,7 +1850,7 @@ static const struct regmap_config gcc_nord_regmap_config = {
.fast_io = true,
};
-static struct qcom_cc_driver_data gcc_nord_driver_data = {
+static const struct qcom_cc_driver_data gcc_nord_driver_data = {
.dfs_rcgs = gcc_nord_dfs_clocks,
.num_dfs_rcgs = ARRAY_SIZE(gcc_nord_dfs_clocks),
};
diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c
index 95aa07120245..ee5f86ca50cb 100644
--- a/drivers/clk/qcom/gdsc.c
+++ b/drivers/clk/qcom/gdsc.c
@@ -7,6 +7,7 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/export.h>
+#include <linux/interconnect.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/ktime.h>
@@ -147,6 +148,12 @@ static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status,
return ret;
}
+ if (status == GDSC_ON) {
+ ret = icc_set_bw(sc->icc_path, 1, 1);
+ if (ret)
+ goto err_disable_supply;
+ }
+
ret = gdsc_update_collapse_bit(sc, status == GDSC_OFF);
/* If disabling votable gdscs, don't poll on status */
@@ -177,6 +184,12 @@ static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status,
ret = gdsc_poll_status(sc, status);
WARN(ret, "%s status stuck at 'o%s'", sc->pd.name, status ? "ff" : "n");
+ if (!ret && status == GDSC_OFF) {
+ ret = icc_set_bw(sc->icc_path, 0, 0);
+ if (ret)
+ return ret;
+ }
+
if (!ret && status == GDSC_OFF && sc->rsupply) {
ret = regulator_disable(sc->rsupply);
if (ret < 0)
@@ -184,6 +197,12 @@ static int gdsc_toggle_logic(struct gdsc *sc, enum gdsc_status status,
}
return ret;
+
+err_disable_supply:
+ if (status == GDSC_ON && sc->rsupply)
+ regulator_disable(sc->rsupply);
+
+ return ret;
}
static inline int gdsc_deassert_reset(struct gdsc *sc)
@@ -585,6 +604,20 @@ int gdsc_register(struct gdsc_desc *desc,
return -ENOMEM;
for (i = 0; i < num; i++) {
+ if (!scs[i] || !scs[i]->needs_icc)
+ continue;
+
+ scs[i]->icc_path = devm_of_icc_get_by_index(dev, scs[i]->icc_path_index);
+ if (IS_ERR(scs[i]->icc_path)) {
+ ret = PTR_ERR(scs[i]->icc_path);
+ if (ret != -ENODEV)
+ return ret;
+
+ scs[i]->icc_path = NULL;
+ }
+ }
+
+ for (i = 0; i < num; i++) {
if (!scs[i] || !scs[i]->supply)
continue;
diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h
index dd843e86c05b..92ff6bcce7b1 100644
--- a/drivers/clk/qcom/gdsc.h
+++ b/drivers/clk/qcom/gdsc.h
@@ -9,6 +9,7 @@
#include <linux/err.h>
#include <linux/pm_domain.h>
+struct icc_path;
struct regmap;
struct regulator;
struct reset_controller_dev;
@@ -74,6 +75,10 @@ struct gdsc {
const char *supply;
struct regulator *rsupply;
+
+ bool needs_icc;
+ unsigned int icc_path_index;
+ struct icc_path *icc_path;
};
struct gdsc_desc {
diff --git a/drivers/clk/qcom/gpucc-sm8750.c b/drivers/clk/qcom/gpucc-sm8750.c
index 5d52c6d8b5e5..1466bd36403f 100644
--- a/drivers/clk/qcom/gpucc-sm8750.c
+++ b/drivers/clk/qcom/gpucc-sm8750.c
@@ -421,7 +421,7 @@ static struct clk_alpha_pll *gpu_cc_alpha_plls[] = {
&gpu_cc_pll0,
};
-static u32 gpu_cc_sm8750_critical_cbcrs[] = {
+static const u32 gpu_cc_sm8750_critical_cbcrs[] = {
0x9004, /* GPU_CC_RSCC_XO_AON_CLK */
0x9008, /* GPU_CC_CXO_AON_CLK */
0x9064, /* GPU_CC_GX_AHB_FF_CLK */
@@ -430,7 +430,7 @@ static u32 gpu_cc_sm8750_critical_cbcrs[] = {
0x93a8, /* GPU_CC_RSCC_HUB_AON_CLK */
};
-static struct qcom_cc_driver_data gpu_cc_sm8750_driver_data = {
+static const struct qcom_cc_driver_data gpu_cc_sm8750_driver_data = {
.alpha_plls = gpu_cc_alpha_plls,
.num_alpha_plls = ARRAY_SIZE(gpu_cc_alpha_plls),
.clk_cbcrs = gpu_cc_sm8750_critical_cbcrs,
diff --git a/drivers/clk/qcom/gxclkctl-kaanapali.c b/drivers/clk/qcom/gxclkctl-kaanapali.c
index 40d856378a74..7b0af0ba1e68 100644
--- a/drivers/clk/qcom/gxclkctl-kaanapali.c
+++ b/drivers/clk/qcom/gxclkctl-kaanapali.c
@@ -53,6 +53,7 @@ static const struct qcom_cc_desc gx_clkctl_kaanapali_desc = {
static const struct of_device_id gx_clkctl_kaanapali_match_table[] = {
{ .compatible = "qcom,glymur-gxclkctl" },
{ .compatible = "qcom,kaanapali-gxclkctl" },
+ { .compatible = "qcom,milos-gxclkctl" },
{ .compatible = "qcom,sm8750-gxclkctl" },
{ }
};
diff --git a/drivers/clk/qcom/ipq-cmn-pll.c b/drivers/clk/qcom/ipq-cmn-pll.c
index 5763e4df59a1..441e88101ea3 100644
--- a/drivers/clk/qcom/ipq-cmn-pll.c
+++ b/drivers/clk/qcom/ipq-cmn-pll.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
/*
@@ -20,6 +20,11 @@
* and an output clock to NSS (network subsystem) at 300 MHZ. The other output
* clocks from CMN PLL on IPQ5424 are the same as IPQ9574.
*
+ * On the IPQ5332 SoC, the CMN PLL provides a single 50 MHZ clock output to
+ * the Ethernet PHY (or switch) via the UNIPHY (PCS). It also supplies a 200
+ * MHZ clock to the PPE. The remaining fixed-rate clocks to the GCC and PCS
+ * are the same as those in the IPQ9574 SoC.
+ *
* +---------+
* | GCC |
* +--+---+--+
@@ -51,6 +56,7 @@
#include <dt-bindings/clock/qcom,ipq-cmn-pll.h>
#include <dt-bindings/clock/qcom,ipq5018-cmn-pll.h>
+#include <dt-bindings/clock/qcom,ipq5332-cmn-pll.h>
#include <dt-bindings/clock/qcom,ipq5424-cmn-pll.h>
#include <dt-bindings/clock/qcom,ipq6018-cmn-pll.h>
#include <dt-bindings/clock/qcom,ipq8074-cmn-pll.h>
@@ -131,6 +137,16 @@ static const struct cmn_pll_fixed_output_clk ipq8074_output_clks[] = {
{ /* Sentinel */ }
};
+static const struct cmn_pll_fixed_output_clk ipq5332_output_clks[] = {
+ CLK_PLL_OUTPUT(IPQ5332_XO_24MHZ_CLK, "xo-24mhz", 24000000UL),
+ CLK_PLL_OUTPUT(IPQ5332_SLEEP_32KHZ_CLK, "sleep-32khz", 32000UL),
+ CLK_PLL_OUTPUT(IPQ5332_PCS_31P25MHZ_CLK, "pcs-31p25mhz", 31250000UL),
+ CLK_PLL_OUTPUT(IPQ5332_NSS_300MHZ_CLK, "nss-300mhz", 300000000UL),
+ CLK_PLL_OUTPUT(IPQ5332_PPE_200MHZ_CLK, "ppe-200mhz", 200000000UL),
+ CLK_PLL_OUTPUT(IPQ5332_ETH_50MHZ_CLK, "eth-50mhz", 50000000UL),
+ { /* Sentinel */ }
+};
+
static const struct cmn_pll_fixed_output_clk ipq5424_output_clks[] = {
CLK_PLL_OUTPUT(IPQ5424_XO_24MHZ_CLK, "xo-24mhz", 24000000UL),
CLK_PLL_OUTPUT(IPQ5424_SLEEP_32KHZ_CLK, "sleep-32khz", 32000UL),
@@ -199,7 +215,7 @@ static unsigned long clk_cmn_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_cmn_pll *cmn_pll = to_clk_cmn_pll(hw);
- u32 val, factor;
+ u32 val, factor, ref_div;
/*
* The value of CMN_PLL_DIVIDER_CTRL_FACTOR is automatically adjusted
@@ -207,8 +223,15 @@ static unsigned long clk_cmn_pll_recalc_rate(struct clk_hw *hw,
*/
regmap_read(cmn_pll->regmap, CMN_PLL_DIVIDER_CTRL, &val);
factor = FIELD_GET(CMN_PLL_DIVIDER_CTRL_FACTOR, val);
+ if (WARN_ON(factor == 0))
+ factor = 1;
+
+ regmap_read(cmn_pll->regmap, CMN_PLL_REFCLK_CONFIG, &val);
+ ref_div = FIELD_GET(CMN_PLL_REFCLK_DIV, val);
+ if (WARN_ON(ref_div == 0))
+ ref_div = 1;
- return parent_rate * 2 * factor;
+ return div_u64((u64)parent_rate * 2 * factor, ref_div);
}
static int clk_cmn_pll_determine_rate(struct clk_hw *hw,
@@ -461,6 +484,7 @@ static const struct dev_pm_ops ipq_cmn_pll_pm_ops = {
static const struct of_device_id ipq_cmn_pll_clk_ids[] = {
{ .compatible = "qcom,ipq5018-cmn-pll", .data = &ipq5018_output_clks },
+ { .compatible = "qcom,ipq5332-cmn-pll", .data = &ipq5332_output_clks },
{ .compatible = "qcom,ipq5424-cmn-pll", .data = &ipq5424_output_clks },
{ .compatible = "qcom,ipq6018-cmn-pll", .data = &ipq6018_output_clks },
{ .compatible = "qcom,ipq8074-cmn-pll", .data = &ipq8074_output_clks },
diff --git a/drivers/clk/qcom/negcc-nord.c b/drivers/clk/qcom/negcc-nord.c
index 1aa24e2784e5..2e653ef0fe0e 100644
--- a/drivers/clk/qcom/negcc-nord.c
+++ b/drivers/clk/qcom/negcc-nord.c
@@ -1918,6 +1918,7 @@ static const struct qcom_reset_map ne_gcc_nord_resets[] = {
[NE_GCC_USB3_PHY_SEC_BCR] = { 0x2d000 },
[NE_GCC_USB3PHY_PHY_PRIM_BCR] = { 0x2b004 },
[NE_GCC_USB3PHY_PHY_SEC_BCR] = { 0x2d004 },
+ [NE_GCC_QUSB2PHY_PRIM_BCR] = { 0x2e000 },
};
static const struct clk_rcg_dfs_data ne_gcc_nord_dfs_clocks[] = {
@@ -1945,7 +1946,7 @@ static void clk_nord_regs_configure(struct device *dev, struct regmap *regmap)
qcom_branch_set_force_mem_core(regmap, ne_gcc_ufs_phy_axi_clk, true);
}
-static struct qcom_cc_driver_data ne_gcc_nord_driver_data = {
+static const struct qcom_cc_driver_data ne_gcc_nord_driver_data = {
.dfs_rcgs = ne_gcc_nord_dfs_clocks,
.num_dfs_rcgs = ARRAY_SIZE(ne_gcc_nord_dfs_clocks),
.clk_regs_configure = clk_nord_regs_configure,
diff --git a/drivers/clk/qcom/nwgcc-nord.c b/drivers/clk/qcom/nwgcc-nord.c
index 163ab63c872b..961cae47ff7c 100644
--- a/drivers/clk/qcom/nwgcc-nord.c
+++ b/drivers/clk/qcom/nwgcc-nord.c
@@ -626,7 +626,7 @@ static const struct qcom_reset_map nw_gcc_nord_resets[] = {
[NW_GCC_VIDEO_BCR] = { 0x1a000 },
};
-static u32 nw_gcc_nord_critical_cbcrs[] = {
+static const u32 nw_gcc_nord_critical_cbcrs[] = {
0x16004, /* NW_GCC_CAMERA_AHB_CLK */
0x16030, /* NW_GCC_CAMERA_XO_CLK */
0x18004, /* NW_GCC_DISP_0_AHB_CLK */
@@ -641,7 +641,7 @@ static u32 nw_gcc_nord_critical_cbcrs[] = {
0x1a044, /* NW_GCC_VIDEO_XO_CLK */
};
-static struct qcom_cc_driver_data nw_gcc_nord_driver_data = {
+static const struct qcom_cc_driver_data nw_gcc_nord_driver_data = {
.clk_cbcrs = nw_gcc_nord_critical_cbcrs,
.num_clk_cbcrs = ARRAY_SIZE(nw_gcc_nord_critical_cbcrs),
};
diff --git a/drivers/clk/qcom/segcc-nord.c b/drivers/clk/qcom/segcc-nord.c
index 1aab0999de4d..c82a56d97154 100644
--- a/drivers/clk/qcom/segcc-nord.c
+++ b/drivers/clk/qcom/segcc-nord.c
@@ -1568,7 +1568,7 @@ static const struct regmap_config se_gcc_nord_regmap_config = {
.fast_io = true,
};
-static struct qcom_cc_driver_data se_gcc_nord_driver_data = {
+static const struct qcom_cc_driver_data se_gcc_nord_driver_data = {
.dfs_rcgs = se_gcc_nord_dfs_clocks,
.num_dfs_rcgs = ARRAY_SIZE(se_gcc_nord_dfs_clocks),
};
diff --git a/drivers/clk/qcom/tcsrcc-hawi.c b/drivers/clk/qcom/tcsrcc-hawi.c
new file mode 100644
index 000000000000..c942b0c8e09f
--- /dev/null
+++ b/drivers/clk/qcom/tcsrcc-hawi.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,hawi-tcsrcc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+#include "common.h"
+#include "reset.h"
+
+enum {
+ DT_BI_TCXO_PAD,
+};
+
+static struct clk_branch tcsr_pcie_0_clkref_en = {
+ .halt_reg = 0x4c,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x4c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "tcsr_pcie_0_clkref_en",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO_PAD,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch tcsr_pcie_1_clkref_en = {
+ .halt_reg = 0x0,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "tcsr_pcie_1_clkref_en",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO_PAD,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch tcsr_ufs_clkref_en = {
+ .halt_reg = 0x10,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x10,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "tcsr_ufs_clkref_en",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO_PAD,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch tcsr_usb2_clkref_en = {
+ .halt_reg = 0x18,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x18,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "tcsr_usb2_clkref_en",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO_PAD,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch tcsr_usb3_clkref_en = {
+ .halt_reg = 0x8,
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "tcsr_usb3_clkref_en",
+ .parent_data = &(const struct clk_parent_data){
+ .index = DT_BI_TCXO_PAD,
+ },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_regmap *tcsr_cc_hawi_clocks[] = {
+ [TCSR_PCIE_0_CLKREF_EN] = &tcsr_pcie_0_clkref_en.clkr,
+ [TCSR_PCIE_1_CLKREF_EN] = &tcsr_pcie_1_clkref_en.clkr,
+ [TCSR_UFS_CLKREF_EN] = &tcsr_ufs_clkref_en.clkr,
+ [TCSR_USB2_CLKREF_EN] = &tcsr_usb2_clkref_en.clkr,
+ [TCSR_USB3_CLKREF_EN] = &tcsr_usb3_clkref_en.clkr,
+};
+
+static const struct regmap_config tcsr_cc_hawi_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x4c,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc tcsr_cc_hawi_desc = {
+ .config = &tcsr_cc_hawi_regmap_config,
+ .clks = tcsr_cc_hawi_clocks,
+ .num_clks = ARRAY_SIZE(tcsr_cc_hawi_clocks),
+};
+
+static const struct of_device_id tcsr_cc_hawi_match_table[] = {
+ { .compatible = "qcom,hawi-tcsrcc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, tcsr_cc_hawi_match_table);
+
+static int tcsr_cc_hawi_probe(struct platform_device *pdev)
+{
+ return qcom_cc_probe(pdev, &tcsr_cc_hawi_desc);
+}
+
+static struct platform_driver tcsr_cc_hawi_driver = {
+ .probe = tcsr_cc_hawi_probe,
+ .driver = {
+ .name = "tcsrcc-hawi",
+ .of_match_table = tcsr_cc_hawi_match_table,
+ },
+};
+
+module_platform_driver(tcsr_cc_hawi_driver);
+
+MODULE_DESCRIPTION("QTI TCSRCC HAWI Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/qcom/videocc-x1p42100.c b/drivers/clk/qcom/videocc-x1p42100.c
new file mode 100644
index 000000000000..2bb40ac6fcc5
--- /dev/null
+++ b/drivers/clk/qcom/videocc-x1p42100.c
@@ -0,0 +1,585 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,x1p42100-videocc.h>
+
+#include "clk-alpha-pll.h"
+#include "clk-branch.h"
+#include "clk-rcg.h"
+#include "clk-regmap.h"
+#include "clk-regmap-divider.h"
+#include "common.h"
+#include "gdsc.h"
+#include "reset.h"
+
+enum {
+ DT_BI_TCXO,
+};
+
+enum {
+ P_BI_TCXO,
+ P_VIDEO_CC_PLL0_OUT_MAIN,
+ P_VIDEO_CC_PLL1_OUT_MAIN,
+};
+
+static const struct pll_vco lucid_ole_vco[] = {
+ { 249600000, 2300000000, 0 },
+};
+
+/* 420.0 MHz Configuration */
+static const struct alpha_pll_config video_cc_pll0_config = {
+ .l = 0x15,
+ .alpha = 0xe000,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00000000,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll video_cc_pll0 = {
+ .offset = 0x0,
+ .config = &video_cc_pll0_config,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_pll0",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_evo_ops,
+ },
+ },
+};
+
+/* 1050.0 MHz Configuration */
+static const struct alpha_pll_config video_cc_pll1_config = {
+ .l = 0x36,
+ .alpha = 0xb000,
+ .config_ctl_val = 0x20485699,
+ .config_ctl_hi_val = 0x00182261,
+ .config_ctl_hi1_val = 0x82aa299c,
+ .test_ctl_val = 0x00000000,
+ .test_ctl_hi_val = 0x00000003,
+ .test_ctl_hi1_val = 0x00009000,
+ .test_ctl_hi2_val = 0x00000034,
+ .user_ctl_val = 0x00000000,
+ .user_ctl_hi_val = 0x00000005,
+};
+
+static struct clk_alpha_pll video_cc_pll1 = {
+ .offset = 0x1000,
+ .config = &video_cc_pll1_config,
+ .vco_table = lucid_ole_vco,
+ .num_vco = ARRAY_SIZE(lucid_ole_vco),
+ .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_LUCID_OLE],
+ .clkr = {
+ .hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_pll1",
+ .parent_data = &(const struct clk_parent_data) {
+ .index = DT_BI_TCXO,
+ },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_lucid_evo_ops,
+ },
+ },
+};
+
+static const struct parent_map video_cc_parent_map_0[] = {
+ { P_BI_TCXO, 0 },
+};
+
+static const struct clk_parent_data video_cc_parent_data_0[] = {
+ { .index = DT_BI_TCXO },
+};
+
+static const struct parent_map video_cc_parent_map_1[] = {
+ { P_BI_TCXO, 0 },
+ { P_VIDEO_CC_PLL0_OUT_MAIN, 1 },
+};
+
+static const struct clk_parent_data video_cc_parent_data_1[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &video_cc_pll0.clkr.hw },
+};
+
+static const struct parent_map video_cc_parent_map_2[] = {
+ { P_BI_TCXO, 0 },
+ { P_VIDEO_CC_PLL1_OUT_MAIN, 1 },
+};
+
+static const struct clk_parent_data video_cc_parent_data_2[] = {
+ { .index = DT_BI_TCXO },
+ { .hw = &video_cc_pll1.clkr.hw },
+};
+
+static const struct freq_tbl ftbl_video_cc_mvs0_bse_clk_src[] = {
+ F(420000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
+ F(600000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
+ F(670000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
+ F(848000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
+ F(920000000, P_VIDEO_CC_PLL0_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 video_cc_mvs0_bse_clk_src = {
+ .cmd_rcgr = 0x8154,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = video_cc_parent_map_1,
+ .freq_tbl = ftbl_video_cc_mvs0_bse_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs0_bse_clk_src",
+ .parent_data = video_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(video_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_video_cc_mvs0_clk_src[] = {
+ F(210000000, P_VIDEO_CC_PLL0_OUT_MAIN, 2, 0, 0),
+ F(300000000, P_VIDEO_CC_PLL0_OUT_MAIN, 2, 0, 0),
+ F(335000000, P_VIDEO_CC_PLL0_OUT_MAIN, 2, 0, 0),
+ F(424000000, P_VIDEO_CC_PLL0_OUT_MAIN, 2, 0, 0),
+ F(460000000, P_VIDEO_CC_PLL0_OUT_MAIN, 2, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 video_cc_mvs0_clk_src = {
+ .cmd_rcgr = 0x8000,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = video_cc_parent_map_1,
+ .freq_tbl = ftbl_video_cc_mvs0_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs0_clk_src",
+ .parent_data = video_cc_parent_data_1,
+ .num_parents = ARRAY_SIZE(video_cc_parent_data_1),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_video_cc_mvs1_clk_src[] = {
+ F(1050000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0),
+ F(1350000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0),
+ F(1650000000, P_VIDEO_CC_PLL1_OUT_MAIN, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 video_cc_mvs1_clk_src = {
+ .cmd_rcgr = 0x8018,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = video_cc_parent_map_2,
+ .freq_tbl = ftbl_video_cc_mvs1_clk_src,
+ .hw_clk_ctrl = true,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs1_clk_src",
+ .parent_data = video_cc_parent_data_2,
+ .num_parents = ARRAY_SIZE(video_cc_parent_data_2),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static const struct freq_tbl ftbl_video_cc_xo_clk_src[] = {
+ F(19200000, P_BI_TCXO, 1, 0, 0),
+ { }
+};
+
+static struct clk_rcg2 video_cc_xo_clk_src = {
+ .cmd_rcgr = 0x810c,
+ .mnd_width = 0,
+ .hid_width = 5,
+ .parent_map = video_cc_parent_map_0,
+ .freq_tbl = ftbl_video_cc_xo_clk_src,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_xo_clk_src",
+ .parent_data = video_cc_parent_data_0,
+ .num_parents = ARRAY_SIZE(video_cc_parent_data_0),
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_rcg2_shared_ops,
+ },
+};
+
+static struct clk_regmap_div video_cc_mvs0_bse_div4_div_clk_src = {
+ .reg = 0x817c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs0_bse_div4_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &video_cc_mvs0_bse_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div video_cc_mvs1_div_clk_src = {
+ .reg = 0x80ec,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs1_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &video_cc_mvs1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_regmap_div video_cc_mvs1c_div2_div_clk_src = {
+ .reg = 0x809c,
+ .shift = 0,
+ .width = 4,
+ .clkr.hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs1c_div2_div_clk_src",
+ .parent_hws = (const struct clk_hw*[]) {
+ &video_cc_mvs1_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_regmap_div_ro_ops,
+ },
+};
+
+static struct clk_branch video_cc_mvs0_bse_clk = {
+ .halt_reg = 0x8170,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8170,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs0_bse_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &video_cc_mvs0_bse_div4_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch video_cc_mvs0_clk = {
+ .halt_reg = 0x80b8,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x80b8,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x80b8,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs0_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &video_cc_mvs0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch video_cc_mvs0_shift_clk = {
+ .halt_reg = 0x8128,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x8128,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs0_shift_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &video_cc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch video_cc_mvs0c_clk = {
+ .halt_reg = 0x8064,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8064,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs0c_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &video_cc_mvs0_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch video_cc_mvs0c_shift_clk = {
+ .halt_reg = 0x812c,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x812c,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs0c_shift_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &video_cc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch video_cc_mvs1_clk = {
+ .halt_reg = 0x80e0,
+ .halt_check = BRANCH_HALT_VOTED,
+ .hwcg_reg = 0x80e0,
+ .hwcg_bit = 1,
+ .clkr = {
+ .enable_reg = 0x80e0,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs1_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &video_cc_mvs1_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch video_cc_mvs1_shift_clk = {
+ .halt_reg = 0x8130,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x8130,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs1_shift_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &video_cc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch video_cc_mvs1c_clk = {
+ .halt_reg = 0x8090,
+ .halt_check = BRANCH_HALT,
+ .clkr = {
+ .enable_reg = 0x8090,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs1c_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &video_cc_mvs1c_div2_div_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch video_cc_mvs1c_shift_clk = {
+ .halt_reg = 0x8134,
+ .halt_check = BRANCH_HALT_VOTED,
+ .clkr = {
+ .enable_reg = 0x8134,
+ .enable_mask = BIT(0),
+ .hw.init = &(const struct clk_init_data) {
+ .name = "video_cc_mvs1c_shift_clk",
+ .parent_hws = (const struct clk_hw*[]) {
+ &video_cc_xo_clk_src.clkr.hw,
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct gdsc video_cc_mvs0c_gdsc = {
+ .gdscr = 0x804c,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x6,
+ .pd = {
+ .name = "video_cc_mvs0c_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc video_cc_mvs0_gdsc = {
+ .gdscr = 0x80a4,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0x6,
+ .pd = {
+ .name = "video_cc_mvs0_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .parent = &video_cc_mvs0c_gdsc.pd,
+ .flags = HW_CTRL_TRIGGER | POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc video_cc_mvs1c_gdsc = {
+ .gdscr = 0x8078,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "video_cc_mvs1c_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct gdsc video_cc_mvs1_gdsc = {
+ .gdscr = 0x80cc,
+ .en_rest_wait_val = 0x2,
+ .en_few_wait_val = 0x2,
+ .clk_dis_wait_val = 0xf,
+ .pd = {
+ .name = "video_cc_mvs1_gdsc",
+ },
+ .pwrsts = PWRSTS_OFF_ON,
+ .parent = &video_cc_mvs1c_gdsc.pd,
+ .flags = HW_CTRL_TRIGGER | POLL_CFG_GDSCR | RETAIN_FF_ENABLE,
+};
+
+static struct clk_regmap *video_cc_x1p42100_clocks[] = {
+ [VIDEO_CC_MVS0_BSE_CLK] = &video_cc_mvs0_bse_clk.clkr,
+ [VIDEO_CC_MVS0_BSE_CLK_SRC] = &video_cc_mvs0_bse_clk_src.clkr,
+ [VIDEO_CC_MVS0_BSE_DIV4_DIV_CLK_SRC] = &video_cc_mvs0_bse_div4_div_clk_src.clkr,
+ [VIDEO_CC_MVS0_CLK] = &video_cc_mvs0_clk.clkr,
+ [VIDEO_CC_MVS0_CLK_SRC] = &video_cc_mvs0_clk_src.clkr,
+ [VIDEO_CC_MVS0_SHIFT_CLK] = &video_cc_mvs0_shift_clk.clkr,
+ [VIDEO_CC_MVS0C_CLK] = &video_cc_mvs0c_clk.clkr,
+ [VIDEO_CC_MVS0C_SHIFT_CLK] = &video_cc_mvs0c_shift_clk.clkr,
+ [VIDEO_CC_MVS1_CLK] = &video_cc_mvs1_clk.clkr,
+ [VIDEO_CC_MVS1_CLK_SRC] = &video_cc_mvs1_clk_src.clkr,
+ [VIDEO_CC_MVS1_DIV_CLK_SRC] = &video_cc_mvs1_div_clk_src.clkr,
+ [VIDEO_CC_MVS1_SHIFT_CLK] = &video_cc_mvs1_shift_clk.clkr,
+ [VIDEO_CC_MVS1C_CLK] = &video_cc_mvs1c_clk.clkr,
+ [VIDEO_CC_MVS1C_DIV2_DIV_CLK_SRC] = &video_cc_mvs1c_div2_div_clk_src.clkr,
+ [VIDEO_CC_MVS1C_SHIFT_CLK] = &video_cc_mvs1c_shift_clk.clkr,
+ [VIDEO_CC_PLL0] = &video_cc_pll0.clkr,
+ [VIDEO_CC_PLL1] = &video_cc_pll1.clkr,
+ [VIDEO_CC_XO_CLK_SRC] = &video_cc_xo_clk_src.clkr,
+};
+
+static struct gdsc *video_cc_x1p42100_gdscs[] = {
+ [VIDEO_CC_MVS0_GDSC] = &video_cc_mvs0_gdsc,
+ [VIDEO_CC_MVS0C_GDSC] = &video_cc_mvs0c_gdsc,
+ [VIDEO_CC_MVS1_GDSC] = &video_cc_mvs1_gdsc,
+ [VIDEO_CC_MVS1C_GDSC] = &video_cc_mvs1c_gdsc,
+};
+
+static const struct qcom_reset_map video_cc_x1p42100_resets[] = {
+ [CVP_VIDEO_CC_INTERFACE_BCR] = { 0x80f0 },
+ [CVP_VIDEO_CC_MVS0_BCR] = { 0x80a0 },
+ [CVP_VIDEO_CC_MVS0C_BCR] = { 0x8048 },
+ [CVP_VIDEO_CC_MVS1_BCR] = { 0x80c8 },
+ [CVP_VIDEO_CC_MVS1C_BCR] = { 0x8074 },
+ [VIDEO_CC_MVS0_BSE_BCR] = { 0x816c },
+ [VIDEO_CC_MVS0C_CLK_ARES] = { 0x8064, 2 },
+ [VIDEO_CC_MVS1C_CLK_ARES] = { 0x8090, 2 },
+ [VIDEO_CC_XO_CLK_ARES] = { 0x8124, 2 },
+};
+
+static struct clk_alpha_pll *video_cc_x1p42100_plls[] = {
+ &video_cc_pll0,
+ &video_cc_pll1,
+};
+
+static u32 video_cc_x1p42100_critical_cbcrs[] = {
+ 0x80f4, /* VIDEO_CC_AHB_CLK */
+ 0x8150, /* VIDEO_CC_SLEEP_CLK */
+ 0x8124, /* VIDEO_CC_XO_CLK */
+};
+
+static const struct regmap_config video_cc_x1p42100_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x9f54,
+ .fast_io = true,
+};
+
+static struct qcom_cc_driver_data video_cc_x1p42100_driver_data = {
+ .alpha_plls = video_cc_x1p42100_plls,
+ .num_alpha_plls = ARRAY_SIZE(video_cc_x1p42100_plls),
+ .clk_cbcrs = video_cc_x1p42100_critical_cbcrs,
+ .num_clk_cbcrs = ARRAY_SIZE(video_cc_x1p42100_critical_cbcrs),
+};
+
+static const struct qcom_cc_desc video_cc_x1p42100_desc = {
+ .config = &video_cc_x1p42100_regmap_config,
+ .clks = video_cc_x1p42100_clocks,
+ .num_clks = ARRAY_SIZE(video_cc_x1p42100_clocks),
+ .resets = video_cc_x1p42100_resets,
+ .num_resets = ARRAY_SIZE(video_cc_x1p42100_resets),
+ .gdscs = video_cc_x1p42100_gdscs,
+ .num_gdscs = ARRAY_SIZE(video_cc_x1p42100_gdscs),
+ .use_rpm = true,
+ .driver_data = &video_cc_x1p42100_driver_data,
+};
+
+static const struct of_device_id video_cc_x1p42100_match_table[] = {
+ { .compatible = "qcom,x1p42100-videocc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, video_cc_x1p42100_match_table);
+
+static int video_cc_x1p42100_probe(struct platform_device *pdev)
+{
+ return qcom_cc_probe(pdev, &video_cc_x1p42100_desc);
+}
+
+static struct platform_driver video_cc_x1p42100_driver = {
+ .probe = video_cc_x1p42100_probe,
+ .driver = {
+ .name = "videocc-x1p42100",
+ .of_match_table = video_cc_x1p42100_match_table,
+ },
+};
+
+module_platform_driver(video_cc_x1p42100_driver);
+
+MODULE_DESCRIPTION("QTI VIDEOCC X1P42100 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/renesas/clk-r8a73a4.c b/drivers/clk/renesas/clk-r8a73a4.c
index 7f47644396e6..1a2bbc5e9299 100644
--- a/drivers/clk/renesas/clk-r8a73a4.c
+++ b/drivers/clk/renesas/clk-r8a73a4.c
@@ -42,6 +42,8 @@ static struct div4_clk div4_clks[] = {
{ "b", CPG_FRQCRA, 8 },
{ "m1", CPG_FRQCRA, 4 },
{ "m2", CPG_FRQCRA, 0 },
+ { "ztr", CPG_FRQCRB, 20 },
+ { "zt", CPG_FRQCRB, 16 },
{ "zx", CPG_FRQCRB, 12 },
{ "zs", CPG_FRQCRB, 8 },
{ "hp", CPG_FRQCRB, 4 },
diff --git a/drivers/clk/renesas/clk-r8a7740.c b/drivers/clk/renesas/clk-r8a7740.c
index 635d59ead499..31a79674583e 100644
--- a/drivers/clk/renesas/clk-r8a7740.c
+++ b/drivers/clk/renesas/clk-r8a7740.c
@@ -37,6 +37,8 @@ static struct div4_clk div4_clks[] = {
{ "zg", CPG_FRQCRA, 16 },
{ "b", CPG_FRQCRA, 8 },
{ "m1", CPG_FRQCRA, 4 },
+ { "ztr", CPG_FRQCRB, 20 },
+ { "zt", CPG_FRQCRB, 16 },
{ "hp", CPG_FRQCRB, 4 },
{ "hpp", CPG_FRQCRC, 20 },
{ "usbp", CPG_FRQCRC, 16 },
diff --git a/drivers/clk/renesas/r8a779g0-cpg-mssr.c b/drivers/clk/renesas/r8a779g0-cpg-mssr.c
index 015b9773cc55..54ba76ff5ab0 100644
--- a/drivers/clk/renesas/r8a779g0-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a779g0-cpg-mssr.c
@@ -245,6 +245,7 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = {
DEF_MOD("fcpvx0", 1100, R8A779G0_CLK_S0D1_VIO),
DEF_MOD("fcpvx1", 1101, R8A779G0_CLK_S0D1_VIO),
DEF_MOD("tsn", 2723, R8A779G0_CLK_S0D4_HSC),
+ DEF_MOD("dsc", 2819, R8A779G0_CLK_VIOBUSD2),
DEF_MOD("ssiu", 2926, R8A779G0_CLK_S0D6_PER),
DEF_MOD("ssi", 2927, R8A779G0_CLK_S0D6_PER),
};
diff --git a/drivers/clk/renesas/r9a07g043-cpg.c b/drivers/clk/renesas/r9a07g043-cpg.c
index 70944ef8c5b8..59d6ee2e888f 100644
--- a/drivers/clk/renesas/r9a07g043-cpg.c
+++ b/drivers/clk/renesas/r9a07g043-cpg.c
@@ -103,7 +103,7 @@ static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = {
/* Internal Core Clocks */
DEF_FIXED(".osc", R9A07G043_OSCCLK, CLK_EXTAL, 1, 1),
DEF_FIXED(".osc_div1000", CLK_OSC_DIV1000, CLK_EXTAL, 1, 1000),
- DEF_SAMPLL(".pll1", CLK_PLL1, CLK_EXTAL, PLL146_CONF(0)),
+ DEF_SAMPLL(".pll1", CLK_PLL1, CLK_EXTAL, CPG_SAM_PLL_CONF(0)),
DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 200, 3),
DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 1, 2),
DEF_FIXED(".clk_800", CLK_PLL2_800, CLK_PLL2, 1, 2),
diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c
index 2d3487203bf5..913cca6dd46f 100644
--- a/drivers/clk/renesas/r9a07g044-cpg.c
+++ b/drivers/clk/renesas/r9a07g044-cpg.c
@@ -159,7 +159,7 @@ static const struct {
/* Internal Core Clocks */
DEF_FIXED(".osc", R9A07G044_OSCCLK, CLK_EXTAL, 1, 1),
DEF_FIXED(".osc_div1000", CLK_OSC_DIV1000, CLK_EXTAL, 1, 1000),
- DEF_SAMPLL(".pll1", CLK_PLL1, CLK_EXTAL, PLL146_CONF(0)),
+ DEF_SAMPLL(".pll1", CLK_PLL1, CLK_EXTAL, CPG_SAM_PLL_CONF(0)),
DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 200, 3),
DEF_FIXED(".pll2_533", CLK_PLL2_533, CLK_PLL2, 1, 3),
DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 200, 3),
diff --git a/drivers/clk/renesas/r9a08g045-cpg.c b/drivers/clk/renesas/r9a08g045-cpg.c
index 1232fec913eb..624fc5e6fb24 100644
--- a/drivers/clk/renesas/r9a08g045-cpg.c
+++ b/drivers/clk/renesas/r9a08g045-cpg.c
@@ -9,7 +9,6 @@
#include <linux/device.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/pm_domain.h>
#include <dt-bindings/clock/r9a08g045-cpg.h>
@@ -50,16 +49,6 @@
#define G3S_SEL_SDHI1 SEL_PLL_PACK(G3S_CPG_SDHI_DSEL, 4, 2)
#define G3S_SEL_SDHI2 SEL_PLL_PACK(G3S_CPG_SDHI_DSEL, 8, 2)
-/* PLL 1/4/6 configuration registers macro. */
-#define G3S_PLL146_CONF(clk1, clk2, setting) ((clk1) << 22 | (clk2) << 12 | (setting))
-
-#define DEF_G3S_MUX(_name, _id, _conf, _parent_names, _mux_flags, _clk_flags) \
- DEF_TYPE(_name, _id, CLK_TYPE_MUX, .conf = (_conf), \
- .parent_names = (_parent_names), \
- .num_parents = ARRAY_SIZE((_parent_names)), \
- .mux_flags = CLK_MUX_HIWORD_MASK | (_mux_flags), \
- .flag = (_clk_flags))
-
enum clk_ids {
/* Core Clock Outputs exported to DT */
LAST_DT_CORE_CLK = R9A08G045_SWD,
@@ -134,7 +123,7 @@ static const struct cpg_core_clk r9a08g045_core_clks[] __initconst = {
/* Internal Core Clocks */
DEF_FIXED(".osc_div1000", CLK_OSC_DIV1000, CLK_EXTAL, 1, 1000),
- DEF_G3S_PLL(".pll1", CLK_PLL1, CLK_EXTAL, G3S_PLL146_CONF(0x4, 0x8, 0x100),
+ DEF_G3S_PLL(".pll1", CLK_PLL1, CLK_EXTAL, CPG_PLL_CONF(0, 0x100),
1100000000UL),
DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 200, 3),
DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 200, 3),
diff --git a/drivers/clk/renesas/r9a08g046-cpg.c b/drivers/clk/renesas/r9a08g046-cpg.c
index 6759957980f2..a57638734ce7 100644
--- a/drivers/clk/renesas/r9a08g046-cpg.c
+++ b/drivers/clk/renesas/r9a08g046-cpg.c
@@ -17,17 +17,69 @@
/* RZ/G3L Specific registers. */
#define G3L_CPG_PL2_DDIV (0x204)
#define G3L_CPG_PL3_DDIV (0x208)
+#define G3L_CPG_CA55CORE_DDIV (0x234)
+#define G3L_CPG_RSCI_DDIV (0x238)
+#define G3L_CPG_RSPI_DDIV (0x23c)
#define G3L_CLKDIVSTATUS (0x280)
+#define G3L_CPG_ETH_SSEL (0x410)
+#define G3L_CPG_RSCI_SSEL (0x414)
+#define G3L_CPG_RSPI_SSEL (0x418)
+#define G3L_CPG_ETH_SDIV (0x434)
/* RZ/G3L Specific division configuration. */
#define G3L_DIVPL2A DDIV_PACK(G3L_CPG_PL2_DDIV, 0, 2)
#define G3L_DIVPL2B DDIV_PACK(G3L_CPG_PL2_DDIV, 4, 2)
#define G3L_DIVPL3A DDIV_PACK(G3L_CPG_PL3_DDIV, 0, 2)
+#define G3L_DIV_CA55_CORE0 DDIV_PACK(G3L_CPG_CA55CORE_DDIV, 0, 3)
+#define G3L_DIV_CA55_CORE1 DDIV_PACK(G3L_CPG_CA55CORE_DDIV, 4, 3)
+#define G3L_DIV_CA55_CORE2 DDIV_PACK(G3L_CPG_CA55CORE_DDIV, 8, 3)
+#define G3L_DIV_CA55_CORE3 DDIV_PACK(G3L_CPG_CA55CORE_DDIV, 12, 3)
+#define G3L_DIV_RSCI0 DDIV_PACK(G3L_CPG_RSCI_DDIV, 0, 2)
+#define G3L_DIV_RSCI1 DDIV_PACK(G3L_CPG_RSCI_DDIV, 2, 2)
+#define G3L_DIV_RSCI2 DDIV_PACK(G3L_CPG_RSCI_DDIV, 4, 2)
+#define G3L_DIV_RSCI3 DDIV_PACK(G3L_CPG_RSCI_DDIV, 6, 2)
+#define G3L_DIV_RSPI0 DDIV_PACK(G3L_CPG_RSPI_DDIV, 0, 2)
+#define G3L_DIV_RSPI1 DDIV_PACK(G3L_CPG_RSPI_DDIV, 2, 2)
+#define G3L_DIV_RSPI2 DDIV_PACK(G3L_CPG_RSPI_DDIV, 4, 2)
+#define G3L_SDIV_ETH_A DDIV_PACK(G3L_CPG_ETH_SDIV, 0, 2)
+#define G3L_SDIV_ETH_B DDIV_PACK(G3L_CPG_ETH_SDIV, 4, 1)
+#define G3L_SDIV_ETH_C DDIV_PACK(G3L_CPG_ETH_SDIV, 8, 2)
+#define G3L_SDIV_ETH_D DDIV_PACK(G3L_CPG_ETH_SDIV, 12, 1)
/* RZ/G3L Clock status configuration. */
#define G3L_DIVPL2A_STS DDIV_PACK(G3L_CLKDIVSTATUS, 4, 1)
#define G3L_DIVPL2B_STS DDIV_PACK(G3L_CLKDIVSTATUS, 5, 1)
#define G3L_DIVPL3A_STS DDIV_PACK(G3L_CLKDIVSTATUS, 8, 1)
+#define G3L_DIV_CA55_CORE0_STS DDIV_PACK(G3L_CLKDIVSTATUS, 12, 1)
+#define G3L_DIV_CA55_CORE1_STS DDIV_PACK(G3L_CLKDIVSTATUS, 13, 1)
+#define G3L_DIV_CA55_CORE2_STS DDIV_PACK(G3L_CLKDIVSTATUS, 14, 1)
+#define G3L_DIV_CA55_CORE3_STS DDIV_PACK(G3L_CLKDIVSTATUS, 15, 1)
+#define G3L_DIV_RSCI0_STS DDIV_PACK(G3L_CLKDIVSTATUS, 16, 1)
+#define G3L_DIV_RSCI1_STS DDIV_PACK(G3L_CLKDIVSTATUS, 17, 1)
+#define G3L_DIV_RSCI2_STS DDIV_PACK(G3L_CLKDIVSTATUS, 18, 1)
+#define G3L_DIV_RSCI3_STS DDIV_PACK(G3L_CLKDIVSTATUS, 19, 1)
+#define G3L_DIV_RSPI0_STS DDIV_PACK(G3L_CLKDIVSTATUS, 20, 1)
+#define G3L_DIV_RSPI1_STS DDIV_PACK(G3L_CLKDIVSTATUS, 21, 1)
+#define G3L_DIV_RSPI2_STS DDIV_PACK(G3L_CLKDIVSTATUS, 22, 1)
+
+/* RZ/G3L Specific clocks select. */
+#define G3L_SEL_ETH0_TX SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 0, 1)
+#define G3L_SEL_ETH0_RX SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 1, 1)
+#define G3L_SEL_ETH0_RM SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 2, 1)
+#define G3L_SEL_ETH0_CLK_TX_I SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 3, 1)
+#define G3L_SEL_ETH0_CLK_RX_I SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 4, 1)
+#define G3L_SEL_ETH1_TX SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 8, 1)
+#define G3L_SEL_ETH1_RX SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 9, 1)
+#define G3L_SEL_ETH1_RM SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 10, 1)
+#define G3L_SEL_ETH1_CLK_TX_I SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 11, 1)
+#define G3L_SEL_ETH1_CLK_RX_I SEL_PLL_PACK(G3L_CPG_ETH_SSEL, 12, 1)
+#define G3L_SEL_RSCI0 SEL_PLL_PACK(G3L_CPG_RSCI_SSEL, 0, 2)
+#define G3L_SEL_RSCI1 SEL_PLL_PACK(G3L_CPG_RSCI_SSEL, 2, 2)
+#define G3L_SEL_RSCI2 SEL_PLL_PACK(G3L_CPG_RSCI_SSEL, 4, 2)
+#define G3L_SEL_RSCI3 SEL_PLL_PACK(G3L_CPG_RSCI_SSEL, 6, 2)
+#define G3L_SEL_RSPI0 SEL_PLL_PACK(G3L_CPG_RSPI_SSEL, 0, 2)
+#define G3L_SEL_RSPI1 SEL_PLL_PACK(G3L_CPG_RSPI_SSEL, 2, 2)
+#define G3L_SEL_RSPI2 SEL_PLL_PACK(G3L_CPG_RSPI_SSEL, 4, 2)
enum clk_ids {
/* Core Clock Outputs exported to DT */
@@ -41,16 +93,72 @@ enum clk_ids {
CLK_ETH1_RXC_RX_CLK_IN,
/* Internal Core Clocks */
+ CLK_PLL1,
CLK_PLL2,
CLK_PLL2_DIV2,
+ CLK_PLL2_DIV2_4,
+ CLK_PLL2_DIV5,
+ CLK_PLL2_DIV6,
+ CLK_PLL2_DIV7,
CLK_PLL3,
CLK_PLL3_DIV2,
+ CLK_PLL6,
+ CLK_PLL6_DIV10,
+ CLK_SEL_ETH0_TX,
+ CLK_SEL_ETH0_RX,
+ CLK_SEL_ETH0_RM,
+ CLK_SEL_ETH1_TX,
+ CLK_SEL_ETH1_RX,
+ CLK_SEL_ETH1_RM,
+ CLK_SEL_RSCI0,
+ CLK_SEL_RSCI1,
+ CLK_SEL_RSCI2,
+ CLK_SEL_RSCI3,
+ CLK_SEL_RSPI0,
+ CLK_SEL_RSPI1,
+ CLK_SEL_RSPI2,
+ CLK_ETH0_TR,
+ CLK_ETH0_RM,
+ CLK_ETH1_TR,
+ CLK_ETH1_RM,
/* Module Clocks */
MOD_CLK_BASE,
};
/* Divider tables */
+static const struct clk_div_table dtable_1_8[] = {
+ { 0, 1 },
+ { 1, 2 },
+ { 2, 4 },
+ { 3, 8 },
+ { 0, 0 },
+};
+
+static const struct clk_div_table dtable_1_32[] = {
+ { 0, 1 },
+ { 1, 2 },
+ { 2, 4 },
+ { 3, 8 },
+ { 4, 16 },
+ { 5, 32 },
+ { 0, 0 },
+};
+
+static const struct clk_div_table dtable_2_20[] = {
+ { 0, 2 },
+ { 1, 20 },
+ { 0, 0 },
+};
+
+static const struct clk_div_table dtable_2_16[] = {
+ { 0, 2 },
+ { 1, 4 },
+ { 2, 8 },
+ { 3, 16 },
+ { 0, 0 },
+};
+
static const struct clk_div_table dtable_4_128[] = {
{ 0, 4 },
{ 1, 8 },
@@ -59,6 +167,13 @@ static const struct clk_div_table dtable_4_128[] = {
{ 0, 0 },
};
+static const struct clk_div_table dtable_4_200[] = {
+ { 0, 4 },
+ { 1, 20 },
+ { 2, 200 },
+ { 0, 0 },
+};
+
static const struct clk_div_table dtable_8_256[] = {
{ 0, 8 },
{ 1, 16 },
@@ -67,6 +182,19 @@ static const struct clk_div_table dtable_8_256[] = {
{ 0, 0 },
};
+/* Mux clock names tables. */
+static const char * const sel_eth0_tx[] = { ".div_eth0_tr", "eth0_txc_tx_clk" };
+static const char * const sel_eth0_rx[] = { ".div_eth0_tr", "eth0_rxc_rx_clk" };
+static const char * const sel_eth0_rm[] = { ".pll6_div10", "eth0_rxc_rx_clk" };
+static const char * const sel_eth1_tx[] = { ".div_eth1_tr", "eth1_txc_tx_clk" };
+static const char * const sel_eth1_rx[] = { ".div_eth1_tr", "eth1_rxc_rx_clk" };
+static const char * const sel_eth1_rm[] = { ".pll6_div10", "eth1_rxc_rx_clk" };
+static const char * const sel_rsci_rspi[] = { ".pll2_div5", ".pll2_div6", ".pll2_div7", ".pll2_div2_4" };
+static const char * const sel_eth0_clk_tx_i[] = { ".sel_eth0_tx", ".div_eth0_rm" };
+static const char * const sel_eth0_clk_rx_i[] = { ".sel_eth0_rx", ".div_eth0_rm" };
+static const char * const sel_eth1_clk_tx_i[] = { ".sel_eth1_tx", ".div_eth1_rm" };
+static const char * const sel_eth1_clk_rx_i[] = { ".sel_eth1_rx", ".div_eth1_rm" };
+
static const struct cpg_core_clk r9a08g046_core_clks[] __initconst = {
/* External Clock Inputs */
DEF_INPUT("extal", CLK_EXTAL),
@@ -76,18 +204,82 @@ static const struct cpg_core_clk r9a08g046_core_clks[] __initconst = {
DEF_INPUT("eth1_rxc_rx_clk", CLK_ETH1_RXC_RX_CLK_IN),
/* Internal Core Clocks */
+ DEF_G3L_PLL(".pll1", CLK_PLL1, CLK_EXTAL, CPG_PLL_CONF(0, 0x100),
+ 1200000000UL),
DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 200, 3),
DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 200, 3),
+ DEF_G3L_PLL(".pll6", CLK_PLL6, CLK_EXTAL, CPG_PLL_CONF(0x50, 0),
+ 500000000UL),
DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 1, 2),
+ DEF_FIXED(".pll2_div2_4", CLK_PLL2_DIV2_4, CLK_PLL2_DIV2, 1, 4),
+ DEF_FIXED(".pll2_div5", CLK_PLL2_DIV5, CLK_PLL2, 1, 5),
+ DEF_FIXED(".pll2_div6", CLK_PLL2_DIV6, CLK_PLL2, 1, 6),
+ DEF_FIXED(".pll2_div7", CLK_PLL2_DIV7, CLK_PLL2, 1, 7),
DEF_FIXED(".pll3_div2", CLK_PLL3_DIV2, CLK_PLL3, 1, 2),
+ DEF_FIXED(".pll6_div10", CLK_PLL6_DIV10, CLK_PLL6, 1, 10),
+ DEF_MUX(".sel_rsci0", CLK_SEL_RSCI0, G3L_SEL_RSCI0, sel_rsci_rspi),
+ DEF_MUX(".sel_rsci1", CLK_SEL_RSCI1, G3L_SEL_RSCI1, sel_rsci_rspi),
+ DEF_MUX(".sel_rsci2", CLK_SEL_RSCI2, G3L_SEL_RSCI2, sel_rsci_rspi),
+ DEF_MUX(".sel_rsci3", CLK_SEL_RSCI3, G3L_SEL_RSCI3, sel_rsci_rspi),
+ DEF_MUX(".sel_rspi0", CLK_SEL_RSPI0, G3L_SEL_RSPI0, sel_rsci_rspi),
+ DEF_MUX(".sel_rspi1", CLK_SEL_RSPI1, G3L_SEL_RSPI1, sel_rsci_rspi),
+ DEF_MUX(".sel_rspi2", CLK_SEL_RSPI2, G3L_SEL_RSPI2, sel_rsci_rspi),
+ DEF_MUX(".sel_eth0_tx", CLK_SEL_ETH0_TX, G3L_SEL_ETH0_TX, sel_eth0_tx),
+ DEF_MUX(".sel_eth0_rx", CLK_SEL_ETH0_RX, G3L_SEL_ETH0_RX, sel_eth0_rx),
+ DEF_MUX(".sel_eth0_rm", CLK_SEL_ETH0_RM, G3L_SEL_ETH0_RM, sel_eth0_rm),
+ DEF_MUX(".sel_eth1_tx", CLK_SEL_ETH1_TX, G3L_SEL_ETH1_TX, sel_eth1_tx),
+ DEF_MUX(".sel_eth1_rx", CLK_SEL_ETH1_RX, G3L_SEL_ETH1_RX, sel_eth1_rx),
+ DEF_MUX(".sel_eth1_rm", CLK_SEL_ETH1_RM, G3L_SEL_ETH1_RM, sel_eth1_rm),
+ DEF_DIV(".div_eth0_tr", CLK_ETH0_TR, CLK_PLL6, G3L_SDIV_ETH_A, dtable_4_200),
+ DEF_DIV(".div_eth1_tr", CLK_ETH1_TR, CLK_PLL6, G3L_SDIV_ETH_C, dtable_4_200),
+ DEF_DIV(".div_eth0_rm", CLK_ETH0_RM, CLK_SEL_ETH0_RM, G3L_SDIV_ETH_B, dtable_2_20),
+ DEF_DIV(".div_eth1_rm", CLK_ETH1_RM, CLK_SEL_ETH1_RM, G3L_SDIV_ETH_D, dtable_2_20),
/* Core output clk */
+ DEF_G3S_DIV("IC0", R9A08G046_CLK_IC0, CLK_PLL1, G3L_DIV_CA55_CORE0, G3L_DIV_CA55_CORE0_STS,
+ dtable_1_32, 0, 0, 0, NULL),
+ DEF_G3S_DIV("IC1", R9A08G046_CLK_IC1, CLK_PLL1, G3L_DIV_CA55_CORE1, G3L_DIV_CA55_CORE1_STS,
+ dtable_1_32, 0, 0, 0, NULL),
+ DEF_G3S_DIV("IC2", R9A08G046_CLK_IC2, CLK_PLL1, G3L_DIV_CA55_CORE2, G3L_DIV_CA55_CORE2_STS,
+ dtable_1_32, 0, 0, 0, NULL),
+ DEF_G3S_DIV("IC3", R9A08G046_CLK_IC3, CLK_PLL1, G3L_DIV_CA55_CORE3, G3L_DIV_CA55_CORE3_STS,
+ dtable_1_32, 0, 0, 0, NULL),
DEF_G3S_DIV("P0", R9A08G046_CLK_P0, CLK_PLL2_DIV2, G3L_DIVPL2B, G3L_DIVPL2B_STS,
dtable_8_256, 0, 0, 0, NULL),
DEF_G3S_DIV("P1", R9A08G046_CLK_P1, CLK_PLL3_DIV2, G3L_DIVPL3A, G3L_DIVPL3A_STS,
dtable_4_128, 0, 0, 0, NULL),
DEF_G3S_DIV("P3", R9A08G046_CLK_P3, CLK_PLL2_DIV2, G3L_DIVPL2A, G3L_DIVPL2A_STS,
dtable_4_128, 0, 0, 0, NULL),
+ DEF_G3S_DIV("P13", R9A08G046_CLK_P13, CLK_SEL_RSCI0, G3L_DIV_RSCI0, G3L_DIV_RSCI0_STS,
+ dtable_2_16, 0, 100000000UL, 0, NULL),
+ DEF_G3S_DIV("P14", R9A08G046_CLK_P14, CLK_SEL_RSCI1, G3L_DIV_RSCI1, G3L_DIV_RSCI1_STS,
+ dtable_2_16, 0, 100000000UL, 0, NULL),
+ DEF_G3S_DIV("P15", R9A08G046_CLK_P15, CLK_SEL_RSCI2, G3L_DIV_RSCI2, G3L_DIV_RSCI2_STS,
+ dtable_2_16, 0, 100000000UL, 0, NULL),
+ DEF_G3S_DIV("P16", R9A08G046_CLK_P16, CLK_SEL_RSCI3, G3L_DIV_RSCI3, G3L_DIV_RSCI3_STS,
+ dtable_2_16, 0, 100000000UL, 0, NULL),
+ DEF_G3S_DIV("P17", R9A08G046_CLK_P17, CLK_SEL_RSPI0, G3L_DIV_RSPI0, G3L_DIV_RSPI0_STS,
+ dtable_1_8, 0, 200000000UL, 0, NULL),
+ DEF_G3S_DIV("P18", R9A08G046_CLK_P18, CLK_SEL_RSPI1, G3L_DIV_RSPI1, G3L_DIV_RSPI1_STS,
+ dtable_1_8, 0, 200000000UL, 0, NULL),
+ DEF_G3S_DIV("P19", R9A08G046_CLK_P19, CLK_SEL_RSPI2, G3L_DIV_RSPI2, G3L_DIV_RSPI2_STS,
+ dtable_1_8, 0, 200000000UL, 0, NULL),
+ DEF_FIXED("HP", R9A08G046_CLK_HP, CLK_PLL6_DIV10, 1, 1),
+ DEF_MUX_FLAGS("ETHTX01", R9A08G046_CLK_ETHTX01, G3L_SEL_ETH0_CLK_TX_I, sel_eth0_clk_tx_i,
+ CLK_SET_RATE_PARENT),
+ DEF_MUX_FLAGS("ETHRX01", R9A08G046_CLK_ETHRX01, G3L_SEL_ETH0_CLK_RX_I, sel_eth0_clk_rx_i,
+ CLK_SET_RATE_PARENT),
+ DEF_MUX_FLAGS("ETHTX11", R9A08G046_CLK_ETHTX11, G3L_SEL_ETH1_CLK_TX_I, sel_eth1_clk_tx_i,
+ CLK_SET_RATE_PARENT),
+ DEF_MUX_FLAGS("ETHRX11", R9A08G046_CLK_ETHRX11, G3L_SEL_ETH1_CLK_RX_I, sel_eth1_clk_rx_i,
+ CLK_SET_RATE_PARENT),
+ DEF_FIXED("ETHRM0", R9A08G046_CLK_ETHRM0, CLK_SEL_ETH0_RM, 1, 1),
+ DEF_FIXED("ETHTX02", R9A08G046_CLK_ETHTX02, CLK_SEL_ETH0_TX, 1, 1),
+ DEF_FIXED("ETHRX02", R9A08G046_CLK_ETHRX02, CLK_SEL_ETH0_RX, 1, 1),
+ DEF_FIXED("ETHRM1", R9A08G046_CLK_ETHRM1, CLK_SEL_ETH1_RM, 1, 1),
+ DEF_FIXED("ETHTX12", R9A08G046_CLK_ETHTX12, CLK_SEL_ETH1_TX, 1, 1),
+ DEF_FIXED("ETHRX12", R9A08G046_CLK_ETHRX12, CLK_SEL_ETH1_RX, 1, 1),
+ DEF_FIXED("OSCCLK", R9A08G046_OSCCLK, CLK_EXTAL, 1, 1),
};
static const struct rzg2l_mod_clk r9a08g046_mod_clks[] = {
@@ -101,8 +293,116 @@ static const struct rzg2l_mod_clk r9a08g046_mod_clks[] = {
MSTOP(BUS_REG1, BIT(2))),
DEF_MOD("dmac_pclk", R9A08G046_DMAC_PCLK, R9A08G046_CLK_P3, 0x52c, 1,
MSTOP(BUS_REG1, BIT(3))),
+ DEF_MOD("wdt0_pclk", R9A08G046_WDT0_PCLK, R9A08G046_CLK_P0, 0x548, 0,
+ MSTOP(BUS_REG0, BIT(0))),
+ DEF_MOD("wdt0_clk", R9A08G046_WDT0_CLK, R9A08G046_OSCCLK, 0x548, 1,
+ MSTOP(BUS_REG0, BIT(0))),
+ DEF_MOD("ssi0_pclk2", R9A08G046_SSI0_PCLK2, R9A08G046_CLK_P0, 0x570, 0,
+ MSTOP(BUS_MCPU1, BIT(10))),
+ DEF_MOD("ssi0_pclk_sfr", R9A08G046_SSI0_PCLK_SFR, R9A08G046_CLK_P0, 0x570, 1,
+ MSTOP(BUS_MCPU1, BIT(10))),
+ DEF_MOD("ssi1_pclk2", R9A08G046_SSI1_PCLK2, R9A08G046_CLK_P0, 0x570, 2,
+ MSTOP(BUS_MCPU1, BIT(11))),
+ DEF_MOD("ssi1_pclk_sfr", R9A08G046_SSI1_PCLK_SFR, R9A08G046_CLK_P0, 0x570, 3,
+ MSTOP(BUS_MCPU1, BIT(11))),
+ DEF_MOD("ssi2_pclk2", R9A08G046_SSI2_PCLK2, R9A08G046_CLK_P0, 0x570, 4,
+ MSTOP(BUS_MCPU1, BIT(12))),
+ DEF_MOD("ssi2_pclk_sfr", R9A08G046_SSI2_PCLK_SFR, R9A08G046_CLK_P0, 0x570, 5,
+ MSTOP(BUS_MCPU1, BIT(12))),
+ DEF_MOD("ssi3_pclk2", R9A08G046_SSI3_PCLK2, R9A08G046_CLK_P0, 0x570, 6,
+ MSTOP(BUS_MCPU1, BIT(13))),
+ DEF_MOD("ssi3_pclk_sfr", R9A08G046_SSI3_PCLK_SFR, R9A08G046_CLK_P0, 0x570, 7,
+ MSTOP(BUS_MCPU1, BIT(13))),
+ DEF_MOD("eth0_clk_axi", R9A08G046_ETH0_CLK_AXI, R9A08G046_CLK_P1, 0x57c, 0,
+ MSTOP(BUS_PERI_COM, BIT(2))),
+ DEF_MOD("eth1_clk_axi", R9A08G046_ETH1_CLK_AXI, R9A08G046_CLK_P1, 0x57c, 1,
+ MSTOP(BUS_PERI_COM, BIT(3))),
+ DEF_MOD("eth0_clk_chi", R9A08G046_ETH0_CLK_CHI, R9A08G046_CLK_P1, 0x57c, 2,
+ MSTOP(BUS_PERI_COM, BIT(2))),
+ DEF_MOD("eth1_clk_chi", R9A08G046_ETH1_CLK_CHI, R9A08G046_CLK_P1, 0x57c, 3,
+ MSTOP(BUS_PERI_COM, BIT(3))),
+ DEF_COUPLED("eth0_tx_i", R9A08G046_ETH0_CLK_TX_I, R9A08G046_CLK_ETHTX01, 0x57c, 4,
+ MSTOP(BUS_PERI_COM, BIT(2))),
+ DEF_COUPLED("eth0_tx_180_i", R9A08G046_ETH0_CLK_TX_180_I, R9A08G046_CLK_ETHTX02, 0x57c, 4,
+ MSTOP(BUS_PERI_COM, BIT(2))),
+ DEF_COUPLED("eth1_tx_i", R9A08G046_ETH1_CLK_TX_I, R9A08G046_CLK_ETHTX11, 0x57c, 5,
+ MSTOP(BUS_PERI_COM, BIT(3))),
+ DEF_COUPLED("eth1_tx_180_i", R9A08G046_ETH1_CLK_TX_180_I, R9A08G046_CLK_ETHTX12, 0x57c, 5,
+ MSTOP(BUS_PERI_COM, BIT(3))),
+ DEF_COUPLED("eth0_rx_i", R9A08G046_ETH0_CLK_RX_I, R9A08G046_CLK_ETHRX01, 0x57c, 6,
+ MSTOP(BUS_PERI_COM, BIT(2))),
+ DEF_COUPLED("eth0_rx_180_i", R9A08G046_ETH0_CLK_RX_180_I, R9A08G046_CLK_ETHRX02, 0x57c, 6,
+ MSTOP(BUS_PERI_COM, BIT(2))),
+ DEF_COUPLED("eth1_rx_i", R9A08G046_ETH1_CLK_RX_I, R9A08G046_CLK_ETHRX11, 0x57c, 7,
+ MSTOP(BUS_PERI_COM, BIT(3))),
+ DEF_COUPLED("eth1_rx_180_i", R9A08G046_ETH1_CLK_RX_180_I, R9A08G046_CLK_ETHRX12, 0x57c, 7,
+ MSTOP(BUS_PERI_COM, BIT(3))),
+ DEF_MOD("eth0_ptp_ref_i", R9A08G046_ETH0_CLK_PTP_REF_I, R9A08G046_CLK_HP, 0x57c, 8,
+ MSTOP(BUS_PERI_COM, BIT(2))),
+ DEF_MOD("eth1_ptp_ref_i", R9A08G046_ETH1_CLK_PTP_REF_I, R9A08G046_CLK_HP, 0x57c, 9,
+ MSTOP(BUS_PERI_COM, BIT(3))),
+ DEF_MOD("eth0_rmii_i", R9A08G046_ETH0_CLK_RMII_I, R9A08G046_CLK_ETHRM0, 0x57c, 10,
+ MSTOP(BUS_PERI_COM, BIT(2))),
+ DEF_MOD("eth1_rmii_i", R9A08G046_ETH1_CLK_RMII_I, R9A08G046_CLK_ETHRM1, 0x57c, 11,
+ MSTOP(BUS_PERI_COM, BIT(3))),
+ DEF_COUPLED("eth0_tx_i_rmii", R9A08G046_ETH0_CLK_TX_I_RMII, R9A08G046_CLK_ETHTX01, 0x57c, 12,
+ MSTOP(BUS_PERI_COM, BIT(2))),
+ DEF_COUPLED("eth0_rx_i_rmii", R9A08G046_ETH0_CLK_RX_I_RMII, R9A08G046_CLK_ETHRX01, 0x57c, 12,
+ MSTOP(BUS_PERI_COM, BIT(2))),
+ DEF_COUPLED("eth1_tx_i_rmii", R9A08G046_ETH1_CLK_TX_I_RMII, R9A08G046_CLK_ETHTX11, 0x57c, 13,
+ MSTOP(BUS_PERI_COM, BIT(3))),
+ DEF_COUPLED("eth1_rx_i_rmii", R9A08G046_ETH1_CLK_RX_I_RMII, R9A08G046_CLK_ETHRX11, 0x57c, 13,
+ MSTOP(BUS_PERI_COM, BIT(3))),
+ DEF_MOD("i2c0_pclk", R9A08G046_I2C0_PCLK, R9A08G046_CLK_P0, 0x580, 0,
+ MSTOP(BUS_MCPU2, BIT(10))),
+ DEF_MOD("i2c1_pclk", R9A08G046_I2C1_PCLK, R9A08G046_CLK_P0, 0x580, 1,
+ MSTOP(BUS_MCPU2, BIT(11))),
+ DEF_MOD("i2c2_pclk", R9A08G046_I2C2_PCLK, R9A08G046_CLK_P0, 0x580, 2,
+ MSTOP(BUS_MCPU2, BIT(12))),
+ DEF_MOD("i2c3_pclk", R9A08G046_I2C3_PCLK, R9A08G046_CLK_P0, 0x580, 3,
+ MSTOP(BUS_MCPU2, BIT(13))),
DEF_MOD("scif0_clk_pck", R9A08G046_SCIF0_CLK_PCK, R9A08G046_CLK_P0, 0x584, 0,
MSTOP(BUS_MCPU2, BIT(1))),
+ DEF_MOD("scif1_clk_pck", R9A08G046_SCIF1_CLK_PCK, R9A08G046_CLK_P0, 0x584, 1,
+ MSTOP(BUS_MCPU2, BIT(2))),
+ DEF_MOD("scif2_clk_pck", R9A08G046_SCIF2_CLK_PCK, R9A08G046_CLK_P0, 0x584, 2,
+ MSTOP(BUS_MCPU2, BIT(3))),
+ DEF_MOD("scif3_clk_pck", R9A08G046_SCIF3_CLK_PCK, R9A08G046_CLK_P0, 0x584, 3,
+ MSTOP(BUS_MCPU2, BIT(4))),
+ DEF_MOD("scif4_clk_pck", R9A08G046_SCIF4_CLK_PCK, R9A08G046_CLK_P0, 0x584, 4,
+ MSTOP(BUS_MCPU2, BIT(5))),
+ DEF_MOD("scif5_clk_pck", R9A08G046_SCIF5_CLK_PCK, R9A08G046_CLK_P0, 0x584, 5,
+ MSTOP(BUS_MCPU3, BIT(4))),
+ DEF_MOD("rspi0_pclk", R9A08G046_RSPI0_PCLK, R9A08G046_CLK_P3, 0x590, 0,
+ MSTOP(BUS_MCPU1, BIT(14))),
+ DEF_MOD("rspi1_pclk", R9A08G046_RSPI1_PCLK, R9A08G046_CLK_P3, 0x590, 1,
+ MSTOP(BUS_MCPU1, BIT(15))),
+ DEF_MOD("rspi2_pclk", R9A08G046_RSPI2_PCLK, R9A08G046_CLK_P3, 0x590, 2,
+ MSTOP(BUS_MCPU2, BIT(0))),
+ DEF_MOD("rspi0_tclk", R9A08G046_RSPI0_TCLK, R9A08G046_CLK_P17, 0x590, 8,
+ MSTOP(BUS_MCPU1, BIT(14))),
+ DEF_MOD("rspi1_tclk", R9A08G046_RSPI1_TCLK, R9A08G046_CLK_P18, 0x590, 9,
+ MSTOP(BUS_MCPU1, BIT(15))),
+ DEF_MOD("rspi2_tclk", R9A08G046_RSPI2_TCLK, R9A08G046_CLK_P19, 0x590, 10,
+ MSTOP(BUS_MCPU2, BIT(0))),
+ DEF_MOD("gpio_hclk", R9A08G046_GPIO_HCLK, R9A08G046_OSCCLK, 0x598, 0,
+ MSTOP(BUS_PERI_CPU, BIT(6))),
+ DEF_MOD("rsci0_pclk", R9A08G046_RSCI0_PCLK, R9A08G046_CLK_P0, 0x618, 0,
+ MSTOP(BUS_MCPU2, BIT(7))),
+ DEF_MOD("rsci1_pclk", R9A08G046_RSCI1_PCLK, R9A08G046_CLK_P0, 0x618, 1,
+ MSTOP(BUS_MCPU2, BIT(8))),
+ DEF_MOD("rsci2_pclk", R9A08G046_RSCI2_PCLK, R9A08G046_CLK_P0, 0x618, 2,
+ MSTOP(BUS_MCPU3, BIT(11))),
+ DEF_MOD("rsci3_pclk", R9A08G046_RSCI3_PCLK, R9A08G046_CLK_P0, 0x618, 3,
+ MSTOP(BUS_MCPU3, BIT(12))),
+ DEF_MOD("rsci0_tclk", R9A08G046_RSCI0_TCLK, R9A08G046_CLK_P13, 0x618, 8,
+ MSTOP(BUS_MCPU2, BIT(7))),
+ DEF_MOD("rsci1_tclk", R9A08G046_RSCI1_TCLK, R9A08G046_CLK_P14, 0x618, 9,
+ MSTOP(BUS_MCPU2, BIT(8))),
+ DEF_MOD("rsci2_tclk", R9A08G046_RSCI2_TCLK, R9A08G046_CLK_P15, 0x618, 10,
+ MSTOP(BUS_MCPU3, BIT(11))),
+ DEF_MOD("rsci3_tclk", R9A08G046_RSCI3_TCLK, R9A08G046_CLK_P16, 0x618, 11,
+ MSTOP(BUS_MCPU3, BIT(12))),
};
static const struct rzg2l_reset r9a08g046_resets[] = {
@@ -111,11 +411,45 @@ static const struct rzg2l_reset r9a08g046_resets[] = {
DEF_RST(R9A08G046_IA55_RESETN, 0x818, 0),
DEF_RST(R9A08G046_DMAC_ARESETN, 0x82c, 0),
DEF_RST(R9A08G046_DMAC_RST_ASYNC, 0x82c, 1),
+ DEF_RST(R9A08G046_WDT0_PRESETN, 0x848, 0),
+ DEF_RST(R9A08G046_SSI0_RST_M2_REG, 0x870, 0),
+ DEF_RST(R9A08G046_SSI1_RST_M2_REG, 0x870, 1),
+ DEF_RST(R9A08G046_SSI2_RST_M2_REG, 0x870, 2),
+ DEF_RST(R9A08G046_SSI3_RST_M2_REG, 0x870, 3),
+ DEF_RST(R9A08G046_ETH0_ARESET_N, 0x87c, 0),
+ DEF_RST(R9A08G046_ETH1_ARESET_N, 0x87c, 1),
+ DEF_RST(R9A08G046_I2C0_MRST, 0x880, 0),
+ DEF_RST(R9A08G046_I2C1_MRST, 0x880, 1),
+ DEF_RST(R9A08G046_I2C2_MRST, 0x880, 2),
+ DEF_RST(R9A08G046_I2C3_MRST, 0x880, 3),
DEF_RST(R9A08G046_SCIF0_RST_SYSTEM_N, 0x884, 0),
+ DEF_RST(R9A08G046_SCIF1_RST_SYSTEM_N, 0x884, 1),
+ DEF_RST(R9A08G046_SCIF2_RST_SYSTEM_N, 0x884, 2),
+ DEF_RST(R9A08G046_SCIF3_RST_SYSTEM_N, 0x884, 3),
+ DEF_RST(R9A08G046_SCIF4_RST_SYSTEM_N, 0x884, 4),
+ DEF_RST(R9A08G046_SCIF5_RST_SYSTEM_N, 0x884, 5),
+ DEF_RST(R9A08G046_RSPI0_PRESETN, 0x890, 0),
+ DEF_RST(R9A08G046_RSPI1_PRESETN, 0x890, 1),
+ DEF_RST(R9A08G046_RSPI2_PRESETN, 0x890, 2),
+ DEF_RST(R9A08G046_RSPI0_TRESETN, 0x890, 8),
+ DEF_RST(R9A08G046_RSPI1_TRESETN, 0x890, 9),
+ DEF_RST(R9A08G046_RSPI2_TRESETN, 0x890, 10),
+ DEF_RST(R9A08G046_GPIO_RSTN, 0x898, 0),
+ DEF_RST(R9A08G046_GPIO_PORT_RESETN, 0x898, 1),
+ DEF_RST(R9A08G046_GPIO_SPARE_RESETN, 0x898, 2),
+ DEF_RST(R9A08G046_RSCI0_PRESETN, 0x918, 0),
+ DEF_RST(R9A08G046_RSCI1_PRESETN, 0x918, 1),
+ DEF_RST(R9A08G046_RSCI2_PRESETN, 0x918, 2),
+ DEF_RST(R9A08G046_RSCI3_PRESETN, 0x918, 3),
+ DEF_RST(R9A08G046_RSCI0_TRESETN, 0x918, 8),
+ DEF_RST(R9A08G046_RSCI1_TRESETN, 0x918, 9),
+ DEF_RST(R9A08G046_RSCI2_TRESETN, 0x918, 10),
+ DEF_RST(R9A08G046_RSCI3_TRESETN, 0x918, 11),
};
static const unsigned int r9a08g046_crit_mod_clks[] __initconst = {
MOD_CLK_BASE + R9A08G046_GIC600_GICCLK,
+ MOD_CLK_BASE + R9A08G046_IA55_PCLK,
MOD_CLK_BASE + R9A08G046_IA55_CLK,
MOD_CLK_BASE + R9A08G046_DMAC_ACLK,
};
@@ -125,6 +459,23 @@ static const unsigned int r9a08g046_crit_resets[] = {
R9A08G046_DMAC_RST_ASYNC,
};
+static const unsigned int r9a08g046_no_pm_mod_clks[] = {
+ MOD_CLK_BASE + R9A08G046_ETH0_CLK_TX_I,
+ MOD_CLK_BASE + R9A08G046_ETH0_CLK_TX_180_I,
+ MOD_CLK_BASE + R9A08G046_ETH0_CLK_RX_I,
+ MOD_CLK_BASE + R9A08G046_ETH0_CLK_RX_180_I,
+ MOD_CLK_BASE + R9A08G046_ETH0_CLK_RMII_I,
+ MOD_CLK_BASE + R9A08G046_ETH0_CLK_TX_I_RMII,
+ MOD_CLK_BASE + R9A08G046_ETH0_CLK_RX_I_RMII,
+ MOD_CLK_BASE + R9A08G046_ETH1_CLK_TX_I,
+ MOD_CLK_BASE + R9A08G046_ETH1_CLK_TX_180_I,
+ MOD_CLK_BASE + R9A08G046_ETH1_CLK_RX_I,
+ MOD_CLK_BASE + R9A08G046_ETH1_CLK_RX_180_I,
+ MOD_CLK_BASE + R9A08G046_ETH1_CLK_RMII_I,
+ MOD_CLK_BASE + R9A08G046_ETH1_CLK_TX_I_RMII,
+ MOD_CLK_BASE + R9A08G046_ETH1_CLK_RX_I_RMII,
+};
+
const struct rzg2l_cpg_info r9a08g046_cpg_info = {
/* Core Clocks */
.core_clks = r9a08g046_core_clks,
@@ -141,6 +492,10 @@ const struct rzg2l_cpg_info r9a08g046_cpg_info = {
.num_mod_clks = ARRAY_SIZE(r9a08g046_mod_clks),
.num_hw_mod_clks = R9A08G046_BSC_X_BCK_BSC + 1,
+ /* No PM modules Clocks */
+ .no_pm_mod_clks = r9a08g046_no_pm_mod_clks,
+ .num_no_pm_mod_clks = ARRAY_SIZE(r9a08g046_no_pm_mod_clks),
+
/* Resets */
.resets = r9a08g046_resets,
.num_resets = R9A08G046_BSC_X_PRESET_BSC + 1, /* Last reset ID + 1 */
diff --git a/drivers/clk/renesas/r9a09g011-cpg.c b/drivers/clk/renesas/r9a09g011-cpg.c
index ba25429c244d..a99ab1375f07 100644
--- a/drivers/clk/renesas/r9a09g011-cpg.c
+++ b/drivers/clk/renesas/r9a09g011-cpg.c
@@ -16,11 +16,6 @@
#include "rzg2l-cpg.h"
-#define RZV2M_SAMPLL4_CLK1 0x104
-#define RZV2M_SAMPLL4_CLK2 0x108
-
-#define PLL4_CONF (RZV2M_SAMPLL4_CLK1 << 22 | RZV2M_SAMPLL4_CLK2 << 12)
-
#define DIV_A DDIV_PACK(0x200, 0, 3)
#define DIV_B DDIV_PACK(0x204, 0, 2)
#define DIV_D DDIV_PACK(0x204, 4, 2)
@@ -131,7 +126,7 @@ static const struct cpg_core_clk r9a09g011_core_clks[] __initconst = {
DEF_FIXED(".pll2_400", CLK_PLL2_400, CLK_PLL2_800, 1, 2),
DEF_FIXED(".pll2_200", CLK_PLL2_200, CLK_PLL2_800, 1, 4),
DEF_FIXED(".pll2_100", CLK_PLL2_100, CLK_PLL2_800, 1, 8),
- DEF_SAMPLL(".pll4", CLK_PLL4, CLK_MAIN_2, PLL4_CONF),
+ DEF_SAMPLL(".pll4", CLK_PLL4, CLK_MAIN_2, CPG_SAM_PLL_CONF(0x100)),
DEF_DIV_RO(".diva", CLK_DIV_A, CLK_PLL1, DIV_A, dtable_diva),
DEF_DIV_RO(".divb", CLK_DIV_B, CLK_PLL2_400, DIV_B, dtable_divb),
diff --git a/drivers/clk/renesas/r9a09g047-cpg.c b/drivers/clk/renesas/r9a09g047-cpg.c
index e59ac4a05a7f..94158b6834e6 100644
--- a/drivers/clk/renesas/r9a09g047-cpg.c
+++ b/drivers/clk/renesas/r9a09g047-cpg.c
@@ -6,6 +6,7 @@
*/
#include <linux/clk-provider.h>
+#include <linux/clk/renesas.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -30,6 +31,8 @@ enum clk_ids {
CLK_PLLCA55,
CLK_PLLVDO,
CLK_PLLETH,
+ CLK_PLLDSI0,
+ CLK_PLLDSI1,
/* Internal Core Clocks */
CLK_PLLCM33_DIV3,
@@ -57,6 +60,8 @@ enum clk_ids {
CLK_PLLETH_DIV_125_FIX,
CLK_CSDIV_PLLETH_GBE0,
CLK_CSDIV_PLLETH_GBE1,
+ CLK_SMUX2_DSI0_CLK,
+ CLK_SMUX2_DSI1_CLK,
CLK_SMUX2_GBE0_TXCLK,
CLK_SMUX2_GBE0_RXCLK,
CLK_SMUX2_GBE1_TXCLK,
@@ -64,6 +69,12 @@ enum clk_ids {
CLK_PLLDTY_DIV16,
CLK_PLLVDO_CRU0,
CLK_PLLVDO_GPU,
+ CLK_PLLETH_DIV4_LPCLK,
+ CLK_PLLETH_LPCLK,
+ CLK_PLLDSI0_DIV7,
+ CLK_PLLDSI1_DIV7,
+ CLK_PLLDSI0_CSDIV,
+ CLK_PLLDSI1_CSDIV,
/* Module Clocks */
MOD_CLK_BASE,
@@ -91,6 +102,18 @@ static const struct clk_div_table dtable_2_16[] = {
{0, 0},
};
+static const struct clk_div_table dtable_2_16_plldsi[] = {
+ {0, 2},
+ {1, 4},
+ {2, 6},
+ {3, 8},
+ {4, 10},
+ {5, 12},
+ {6, 14},
+ {7, 16},
+ {0, 0},
+};
+
static const struct clk_div_table dtable_2_64[] = {
{0, 2},
{1, 4},
@@ -107,7 +130,23 @@ static const struct clk_div_table dtable_2_100[] = {
{0, 0},
};
+static const struct clk_div_table dtable_16_128[] = {
+ {0, 16},
+ {1, 32},
+ {2, 64},
+ {3, 128},
+ {0, 0},
+};
+
+RZG3E_CPG_PLL_DSI0_LIMITS(rzg3e_cpg_pll_dsi0_limits);
+RZG3E_CPG_PLL_DSI1_LIMITS(rzg3e_cpg_pll_dsi1_limits);
+
+#define PLLDSI0 PLL_PACK_LIMITS(0xc0, 1, 0, &rzg3e_cpg_pll_dsi0_limits)
+#define PLLDSI1 PLL_PACK_LIMITS(0x160, 1, 1, &rzg3e_cpg_pll_dsi1_limits)
+
/* Mux clock tables */
+static const char * const smux2_dsi0_clk[] = { ".plldsi0_div7", ".plldsi0_csdiv" };
+static const char * const smux2_dsi1_clk[] = { ".plldsi1_div7", ".plldsi1_csdiv" };
static const char * const smux2_gbe0_rxclk[] = { ".plleth_gbe0", "et0_rxclk" };
static const char * const smux2_gbe0_txclk[] = { ".plleth_gbe0", "et0_txclk" };
static const char * const smux2_gbe1_rxclk[] = { ".plleth_gbe1", "et1_rxclk" };
@@ -128,6 +167,8 @@ static const struct cpg_core_clk r9a09g047_core_clks[] __initconst = {
DEF_PLL(".pllca55", CLK_PLLCA55, CLK_QEXTAL, PLLCA55),
DEF_FIXED(".plleth", CLK_PLLETH, CLK_QEXTAL, 125, 3),
DEF_FIXED(".pllvdo", CLK_PLLVDO, CLK_QEXTAL, 105, 2),
+ DEF_PLLDSI(".plldsi0", CLK_PLLDSI0, CLK_QEXTAL, PLLDSI0),
+ DEF_PLLDSI(".plldsi1", CLK_PLLDSI1, CLK_QEXTAL, PLLDSI1),
/* Internal Core Clocks */
DEF_FIXED(".pllcm33_div3", CLK_PLLCM33_DIV3, CLK_PLLCM33, 1, 3),
@@ -171,6 +212,21 @@ static const struct cpg_core_clk r9a09g047_core_clks[] __initconst = {
DEF_DDIV(".pllvdo_cru0", CLK_PLLVDO_CRU0, CLK_PLLVDO, CDDIV3_DIVCTL3, dtable_2_4),
DEF_DDIV(".pllvdo_gpu", CLK_PLLVDO_GPU, CLK_PLLVDO, CDDIV3_DIVCTL1, dtable_2_64),
+ DEF_FIXED(".plleth_div4_lpclk", CLK_PLLETH_DIV4_LPCLK, CLK_PLLETH, 1, 4),
+ DEF_CSDIV(".plleth_lpclk", CLK_PLLETH_LPCLK, CLK_PLLETH_DIV4_LPCLK,
+ CSDIV0_DIVCTL2, dtable_16_128),
+
+ DEF_PLLDSI_DIV(".plldsi0_csdiv", CLK_PLLDSI0_CSDIV, CLK_PLLDSI0,
+ CSDIV1_DIVCTL2, dtable_2_16_plldsi),
+ DEF_PLLDSI_DIV(".plldsi1_csdiv", CLK_PLLDSI1_CSDIV, CLK_PLLDSI1,
+ CSDIV1_DIVCTL3, dtable_2_16_plldsi),
+ DEF_FIXED(".plldsi0_div7", CLK_PLLDSI0_DIV7, CLK_PLLDSI0, 1, 7),
+ DEF_FIXED(".plldsi1_div7", CLK_PLLDSI1_DIV7, CLK_PLLDSI1, 1, 7),
+ DEF_PLLDSI_SMUX(".smux2_dsi0_clk", CLK_SMUX2_DSI0_CLK,
+ SSEL3_SELCTL0, smux2_dsi0_clk),
+ DEF_PLLDSI_SMUX(".smux2_dsi1_clk", CLK_SMUX2_DSI1_CLK,
+ SSEL3_SELCTL1, smux2_dsi1_clk),
+
/* Core Clocks */
DEF_FIXED("sys_0_pclk", R9A09G047_SYS_0_PCLK, CLK_QEXTAL, 1, 1),
DEF_DDIV("ca55_0_coreclk0", R9A09G047_CA55_0_CORECLK0, CLK_PLLCA55,
@@ -452,6 +508,22 @@ static const struct rzv2h_mod_clk r9a09g047_mod_clks[] __initconst = {
BUS_MSTOP(9, BIT(4))),
DEF_MOD("cru_0_pclk", CLK_PLLDTY_DIV16, 13, 4, 6, 20,
BUS_MSTOP(9, BIT(4))),
+ DEF_MOD("dsi_0_pclk", CLK_PLLDTY_DIV16, 14, 8, 7, 8,
+ BUS_MSTOP(9, BIT(15) | BIT(14))),
+ DEF_MOD("dsi_0_aclk", CLK_PLLDTY_ACPU_DIV2, 14, 9, 7, 9,
+ BUS_MSTOP(9, BIT(15) | BIT(14))),
+ DEF_MOD("dsi_0_vclk1", CLK_SMUX2_DSI0_CLK, 14, 10, 7, 10,
+ BUS_MSTOP(9, BIT(15) | BIT(14))),
+ DEF_MOD("dsi_0_lpclk", CLK_PLLETH_LPCLK, 14, 11, 7, 11,
+ BUS_MSTOP(9, BIT(15) | BIT(14))),
+ DEF_MOD("dsi_0_pllref_clk", CLK_QEXTAL, 14, 12, 7, 12,
+ BUS_MSTOP(9, BIT(15) | BIT(14))),
+ DEF_MOD("lcdc_0_clk_a", CLK_PLLDTY_ACPU_DIV2, 14, 13, 7, 13,
+ BUS_MSTOP(10, BIT(3) | BIT(2) | BIT(1))),
+ DEF_MOD("lcdc_0_clk_p", CLK_PLLDTY_DIV16, 14, 14, 7, 14,
+ BUS_MSTOP(10, BIT(3) | BIT(2) | BIT(1))),
+ DEF_MOD("lcdc_0_clk_d", CLK_SMUX2_DSI0_CLK, 14, 15, 7, 15,
+ BUS_MSTOP(10, BIT(3) | BIT(2) | BIT(1))),
DEF_MOD("ge3d_clk", CLK_PLLVDO_GPU, 15, 0, 7, 16,
BUS_MSTOP(3, BIT(4))),
DEF_MOD("ge3d_axi_clk", CLK_PLLDTY_ACPU_DIV2, 15, 1, 7, 17,
@@ -460,6 +532,14 @@ static const struct rzv2h_mod_clk r9a09g047_mod_clks[] __initconst = {
BUS_MSTOP(3, BIT(4))),
DEF_MOD("tsu_1_pclk", CLK_QEXTAL, 16, 10, 8, 10,
BUS_MSTOP(2, BIT(15))),
+ DEF_MOD("dsi_0_vclk2", CLK_SMUX2_DSI1_CLK, 25, 0, 10, 21,
+ BUS_MSTOP(9, BIT(15) | BIT(14))),
+ DEF_MOD("lcdc_1_clk_a", CLK_PLLDTY_ACPU_DIV2, 26, 8, 10, 30,
+ BUS_MSTOP(13, BIT(5) | BIT(4) | BIT(3))),
+ DEF_MOD("lcdc_1_clk_p", CLK_PLLDTY_DIV16, 26, 9, 10, 31,
+ BUS_MSTOP(13, BIT(5) | BIT(4) | BIT(3))),
+ DEF_MOD("lcdc_1_clk_d", CLK_SMUX2_DSI1_CLK, 26, 10, 11, 0,
+ BUS_MSTOP(13, BIT(5) | BIT(4) | BIT(3))),
};
static const struct rzv2h_reset r9a09g047_resets[] __initconst = {
@@ -535,10 +615,14 @@ static const struct rzv2h_reset r9a09g047_resets[] __initconst = {
DEF_RST(12, 5, 5, 22), /* CRU_0_PRESETN */
DEF_RST(12, 6, 5, 23), /* CRU_0_ARESETN */
DEF_RST(12, 7, 5, 24), /* CRU_0_S_RESETN */
+ DEF_RST(13, 7, 6, 8), /* DSI_0_PRESETN */
+ DEF_RST(13, 8, 6, 9), /* DSI_0_ARESETN */
+ DEF_RST(13, 12, 6, 13), /* LCDC_0_RESET_N */
DEF_RST(13, 13, 6, 14), /* GE3D_RESETN */
DEF_RST(13, 14, 6, 15), /* GE3D_AXI_RESETN */
DEF_RST(13, 15, 6, 16), /* GE3D_ACE_RESETN */
DEF_RST(15, 8, 7, 9), /* TSU_1_PRESETN */
+ DEF_RST(17, 14, 8, 15), /* LCDC_1_RESET_N */
};
const struct rzv2h_cpg_info r9a09g047_cpg_info __initconst = {
diff --git a/drivers/clk/renesas/r9a09g077-cpg.c b/drivers/clk/renesas/r9a09g077-cpg.c
index 93b15e06a19b..f777601a23b9 100644
--- a/drivers/clk/renesas/r9a09g077-cpg.c
+++ b/drivers/clk/renesas/r9a09g077-cpg.c
@@ -257,6 +257,7 @@ static const struct mssr_mod_clk r9a09g077_mod_clks[] __initconst = {
DEF_MOD("spi0", 104, CLK_SPI0ASYNC),
DEF_MOD("spi1", 105, CLK_SPI1ASYNC),
DEF_MOD("spi2", 106, CLK_SPI2ASYNC),
+ DEF_MOD("mtu3", 200, R9A09G077_CLK_PCLKH),
DEF_MOD("adc0", 206, R9A09G077_CLK_PCLKH),
DEF_MOD("adc1", 207, R9A09G077_CLK_PCLKH),
DEF_MOD("adc2", 225, R9A09G077_CLK_PCLKM),
diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c
index 26ea85cfaa02..5b84cbee030b 100644
--- a/drivers/clk/renesas/renesas-cpg-mssr.c
+++ b/drivers/clk/renesas/renesas-cpg-mssr.c
@@ -370,6 +370,9 @@ struct clk *cpg_mssr_clk_src_twocell_get(struct of_phandle_args *clkspec,
struct clk *clk;
int range_check;
+ if (clkspec->args_count != 2)
+ return ERR_PTR(-EINVAL);
+
switch (clkspec->args[0]) {
case CPG_CORE:
type = "core";
diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c
index abfd8634d2be..51c9e19e1575 100644
--- a/drivers/clk/renesas/rzg2l-cpg.c
+++ b/drivers/clk/renesas/rzg2l-cpg.c
@@ -58,15 +58,22 @@
#define RZG3S_DIV_NF GENMASK(12, 1)
#define RZG3S_SEL_PLL BIT(0)
+#define CPG_PLL1_SETTING_OFFSET(conf) FIELD_GET(GENMASK(11, 0), (conf))
+#define CPG_PLL_STBY_OFFSET(conf) FIELD_GET(GENMASK(23, 12), (conf))
+#define CPG_PLL_STBY_RESETB_WEN BIT(16)
+#define CPG_PLL_STBY_RESETB BIT(0)
+#define CPG_PLL_CLK1_OFFSET(x) (CPG_PLL_STBY_OFFSET(x) + 0x4)
+#define CPG_PLL_CLK2_OFFSET(x) (CPG_PLL_STBY_OFFSET(x) + 0x8)
+#define CPG_PLL_MON_OFFSET(x) (CPG_PLL_STBY_OFFSET(x) + 0xc)
+#define CPG_PLL_MON_LOCK BIT(4)
+#define CPG_PLL_MON_RESETB BIT(0)
+
#define CLK_ON_R(reg) (reg)
#define CLK_MON_R(reg) (0x180 + (reg))
#define CLK_RST_R(reg) (reg)
#define CLK_MRST_R(reg) (0x180 + (reg))
#define GET_REG_OFFSET(val) ((val >> 20) & 0xfff)
-#define GET_REG_SAMPLL_CLK1(val) ((val >> 22) & 0xfff)
-#define GET_REG_SAMPLL_CLK2(val) ((val >> 12) & 0xfff)
-#define GET_REG_SAMPLL_SETTING(val) ((val) & 0xfff)
#define CPG_WEN_BIT BIT(16)
@@ -1086,8 +1093,8 @@ static unsigned long rzg2l_cpg_pll_clk_recalc_rate(struct clk_hw *hw,
if (pll_clk->type != CLK_TYPE_SAM_PLL)
return parent_rate;
- val1 = readl(priv->base + GET_REG_SAMPLL_CLK1(pll_clk->conf));
- val2 = readl(priv->base + GET_REG_SAMPLL_CLK2(pll_clk->conf));
+ val1 = readl(priv->base + CPG_PLL_CLK1_OFFSET(pll_clk->conf));
+ val2 = readl(priv->base + CPG_PLL_CLK2_OFFSET(pll_clk->conf));
rate = mul_u64_u32_shr(parent_rate, (MDIV(val1) << 16) + KDIV(val1),
16 + SDIV(val2));
@@ -1107,17 +1114,14 @@ static unsigned long rzg3s_cpg_pll_clk_recalc_rate(struct clk_hw *hw,
u32 nir, nfr, mr, pr, val, setting;
u64 rate;
- if (pll_clk->type != CLK_TYPE_G3S_PLL)
- return parent_rate;
-
- setting = GET_REG_SAMPLL_SETTING(pll_clk->conf);
+ setting = CPG_PLL1_SETTING_OFFSET(pll_clk->conf);
if (setting) {
val = readl(priv->base + setting);
if (val & RZG3S_SEL_PLL)
return pll_clk->default_rate;
}
- val = readl(priv->base + GET_REG_SAMPLL_CLK1(pll_clk->conf));
+ val = readl(priv->base + CPG_PLL_CLK1_OFFSET(pll_clk->conf));
pr = 1 << FIELD_GET(RZG3S_DIV_P, val);
/* Hardware interprets values higher than 8 as p = 16. */
@@ -1178,6 +1182,61 @@ rzg2l_cpg_pll_clk_register(const struct cpg_core_clk *core,
return pll_clk->hw.clk;
}
+static int rzg3l_cpg_pll_clk_is_enabled(struct clk_hw *hw)
+{
+ struct pll_clk *pll_clk = to_pll(hw);
+ struct rzg2l_cpg_priv *priv = pll_clk->priv;
+ u32 val = readl(priv->base + CPG_PLL_MON_OFFSET(pll_clk->conf));
+ u32 mon_val = CPG_PLL_MON_RESETB | CPG_PLL_MON_LOCK;
+
+ /* Ensure both RESETB and LOCK bits are set */
+ return (mon_val == (val & mon_val));
+}
+
+static int rzg3l_cpg_pll_clk_endisable(struct clk_hw *hw, bool enable)
+{
+ struct pll_clk *pll_clk = to_pll(hw);
+ struct rzg2l_cpg_priv *priv = pll_clk->priv;
+ u32 mon_mask = CPG_PLL_MON_RESETB | CPG_PLL_MON_LOCK;
+ u32 val = CPG_PLL_STBY_RESETB_WEN;
+ u32 stby_offset, mon_offset;
+ u32 mon_val = 0;
+ int ret;
+
+ stby_offset = CPG_PLL_STBY_OFFSET(pll_clk->conf);
+ mon_offset = CPG_PLL_MON_OFFSET(pll_clk->conf);
+
+ if (enable) {
+ val |= CPG_PLL_STBY_RESETB;
+ mon_val = mon_mask;
+ }
+
+ writel(val, priv->base + stby_offset);
+
+ /* ensure PLL is in normal/standby mode */
+ ret = readl_poll_timeout_atomic(priv->base + mon_offset, val,
+ mon_val == (val & mon_mask), 10, 100);
+ if (ret)
+ dev_err(priv->dev, "Failed to %s PLL 0x%x/%pC\n", enable ?
+ "enable" : "disable", stby_offset, hw->clk);
+
+ return ret;
+}
+
+static int rzg3l_cpg_pll_clk_enable(struct clk_hw *hw)
+{
+ if (rzg3l_cpg_pll_clk_is_enabled(hw))
+ return 0;
+
+ return rzg3l_cpg_pll_clk_endisable(hw, true);
+}
+
+static const struct clk_ops rzg3l_cpg_pll_ops = {
+ .is_enabled = rzg3l_cpg_pll_clk_is_enabled,
+ .enable = rzg3l_cpg_pll_clk_enable,
+ .recalc_rate = rzg3s_cpg_pll_clk_recalc_rate,
+};
+
static struct clk
*rzg2l_cpg_clk_src_twocell_get(struct of_phandle_args *clkspec,
void *data)
@@ -1261,6 +1320,9 @@ rzg2l_cpg_register_core_clk(const struct cpg_core_clk *core,
case CLK_TYPE_SAM_PLL:
clk = rzg2l_cpg_pll_clk_register(core, priv, &rzg2l_cpg_pll_ops);
break;
+ case CLK_TYPE_G3L_PLL:
+ clk = rzg2l_cpg_pll_clk_register(core, priv, &rzg3l_cpg_pll_ops);
+ break;
case CLK_TYPE_G3S_PLL:
clk = rzg2l_cpg_pll_clk_register(core, priv, &rzg3s_cpg_pll_ops);
break;
@@ -1340,10 +1402,10 @@ struct mod_clock {
#define to_mod_clock(_hw) container_of(_hw, struct mod_clock, hw)
#define for_each_mod_clock(mod_clock, hw, priv) \
- for (unsigned int i = 0; (priv) && i < (priv)->num_mod_clks; i++) \
- if ((priv)->clks[(priv)->num_core_clks + i] == ERR_PTR(-ENOENT)) \
+ for (unsigned int __i = 0; (priv) && __i < (priv)->num_mod_clks; __i++) \
+ if ((priv)->clks[(priv)->num_core_clks + __i] == ERR_PTR(-ENOENT)) \
continue; \
- else if (((hw) = __clk_get_hw((priv)->clks[(priv)->num_core_clks + i])) && \
+ else if (((hw) = __clk_get_hw((priv)->clks[(priv)->num_core_clks + __i])) && \
((mod_clock) = to_mod_clock(hw)))
/* Need to be called with a lock held to avoid concurrent access to mstop->usecnt. */
diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h
index 10baf9e71a6e..bd6169f62538 100644
--- a/drivers/clk/renesas/rzg2l-cpg.h
+++ b/drivers/clk/renesas/rzg2l-cpg.h
@@ -58,11 +58,8 @@
#define CPG_CLKSTATUS_SELSDHI0_STS BIT(28)
#define CPG_CLKSTATUS_SELSDHI1_STS BIT(29)
-/* n = 0/1/2 for PLL1/4/6 */
-#define CPG_SAMPLL_CLK1(n) (0x04 + (16 * n))
-#define CPG_SAMPLL_CLK2(n) (0x08 + (16 * n))
-
-#define PLL146_CONF(n) (CPG_SAMPLL_CLK1(n) << 22 | CPG_SAMPLL_CLK2(n) << 12)
+#define CPG_SAM_PLL_CONF(stby) ((stby) << 12)
+#define CPG_PLL_CONF(stby, setting) ((stby) << 12 | (setting))
#define DDIV_PACK(offset, bitpos, size) \
(((offset) << 20) | ((bitpos) << 12) | ((size) << 8))
@@ -123,6 +120,7 @@ enum clk_types {
CLK_TYPE_IN, /* External Clock Input */
CLK_TYPE_FF, /* Fixed Factor Clock */
CLK_TYPE_SAM_PLL,
+ CLK_TYPE_G3L_PLL,
CLK_TYPE_G3S_PLL,
/* Clock with divider */
@@ -152,6 +150,9 @@ enum clk_types {
DEF_TYPE(_name, _id, _type, .parent = _parent)
#define DEF_SAMPLL(_name, _id, _parent, _conf) \
DEF_TYPE(_name, _id, CLK_TYPE_SAM_PLL, .parent = _parent, .conf = _conf)
+#define DEF_G3L_PLL(_name, _id, _parent, _conf, _default_rate) \
+ DEF_TYPE(_name, _id, CLK_TYPE_G3L_PLL, .parent = _parent, .conf = _conf, \
+ .default_rate = _default_rate)
#define DEF_G3S_PLL(_name, _id, _parent, _conf, _default_rate) \
DEF_TYPE(_name, _id, CLK_TYPE_G3S_PLL, .parent = _parent, .conf = _conf, \
.default_rate = _default_rate)
@@ -174,11 +175,14 @@ enum clk_types {
.invalid_rate = _invalid_rate, \
.max_rate = _max_rate, .flag = (_clk_flags), \
.notifier = _notif)
-#define DEF_MUX(_name, _id, _conf, _parent_names) \
+#define DEF_MUX_FLAGS(_name, _id, _conf, _parent_names, _flag) \
DEF_TYPE(_name, _id, CLK_TYPE_MUX, .conf = _conf, \
.parent_names = _parent_names, \
.num_parents = ARRAY_SIZE(_parent_names), \
- .mux_flags = CLK_MUX_HIWORD_MASK)
+ .mux_flags = CLK_MUX_HIWORD_MASK, \
+ .flag = _flag)
+#define DEF_MUX(_name, _id, _conf, _parent_names) \
+ DEF_MUX_FLAGS(_name, _id, _conf, _parent_names, 0)
#define DEF_MUX_RO(_name, _id, _conf, _parent_names) \
DEF_TYPE(_name, _id, CLK_TYPE_MUX, .conf = _conf, \
.parent_names = _parent_names, \
diff --git a/drivers/clk/renesas/rzv2h-cpg.c b/drivers/clk/renesas/rzv2h-cpg.c
index f6c47fb89bca..e271c04cee34 100644
--- a/drivers/clk/renesas/rzv2h-cpg.c
+++ b/drivers/clk/renesas/rzv2h-cpg.c
@@ -76,6 +76,11 @@
/* On RZ/G3E SoC we have two DSI PLLs */
#define MAX_CPG_DSI_PLL 2
+#define CPG_PLLDSI_SMUX_LVDS_DUTY_NUM 4
+#define CPG_PLLDSI_SMUX_LVDS_DUTY_DEN 7
+#define CPG_PLLDSI_SMUX_DSI_RGB_DUTY_NUM 1
+#define CPG_PLLDSI_SMUX_DSI_RGB_DUTY_DEN 2
+
/**
* struct rzv2h_pll_dsi_info - PLL DSI information, holds the limits and parameters
*
@@ -418,6 +423,20 @@ bool rzv2h_get_pll_divs_pars(const struct rzv2h_pll_limits *limits,
}
EXPORT_SYMBOL_NS_GPL(rzv2h_get_pll_divs_pars, "RZV2H_CPG");
+/**
+ * struct rzv2h_plldsi_mux_clk - PLL DSI MUX clock
+ *
+ * @priv: CPG private data
+ * @mux: mux clk
+ */
+struct rzv2h_plldsi_mux_clk {
+ struct rzv2h_cpg_priv *priv;
+ struct clk_mux mux;
+};
+
+#define to_plldsi_clk_mux(_mux) \
+ container_of(_mux, struct rzv2h_plldsi_mux_clk, mux)
+
static unsigned long rzv2h_cpg_plldsi_div_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
@@ -649,6 +668,165 @@ static int rzv2h_cpg_plldsi_set_rate(struct clk_hw *hw, unsigned long rate,
return rzv2h_cpg_pll_set_rate(pll_clk, &dsi_info->pll_dsi_parameters.pll, true);
}
+static u8 rzv2h_cpg_plldsi_smux_get_parent(struct clk_hw *hw)
+{
+ return clk_mux_ops.get_parent(hw);
+}
+
+static int rzv2h_cpg_plldsi_smux_set_parent(struct clk_hw *hw, u8 index)
+{
+ return clk_mux_ops.set_parent(hw, index);
+}
+
+static int rzv2h_cpg_plldsi_smux_lvds_determine_rate(struct rzv2h_cpg_priv *priv,
+ struct pll_clk *pll_clk,
+ struct clk_rate_request *req)
+{
+ struct rzv2h_pll_div_pars *dsi_params;
+ struct rzv2h_pll_dsi_info *dsi_info;
+ u8 lvds_table[] = { 7 };
+ u64 rate_millihz;
+
+ dsi_info = &priv->pll_dsi_info[pll_clk->pll.instance];
+ dsi_params = &dsi_info->pll_dsi_parameters;
+
+ rate_millihz = mul_u32_u32(req->rate, MILLI);
+ if (!rzv2h_get_pll_divs_pars(dsi_info->pll_dsi_limits, dsi_params,
+ lvds_table, ARRAY_SIZE(lvds_table), rate_millihz)) {
+ dev_err(priv->dev, "failed to determine rate for req->rate: %lu\n",
+ req->rate);
+ return -EINVAL;
+ }
+
+ req->rate = DIV_ROUND_CLOSEST_ULL(dsi_params->div.freq_millihz, MILLI);
+ req->best_parent_rate = req->rate;
+ dsi_info->req_pll_dsi_rate = req->best_parent_rate * dsi_params->div.divider_value;
+
+ return 0;
+}
+
+static int rzv2h_cpg_plldsi_smux_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct clk_mux *mux = to_clk_mux(hw);
+ struct rzv2h_plldsi_mux_clk *dsi_mux = to_plldsi_clk_mux(mux);
+ struct pll_clk *pll_clk = to_pll(clk_hw_get_parent(hw));
+ struct rzv2h_cpg_priv *priv = dsi_mux->priv;
+
+ /*
+ * For LVDS output (parent index 0), calculate PLL parameters with
+ * fixed divider value of 7. For DSI/RGB output (parent index 1) skip
+ * PLL calculation here as it's handled by determine_rate of the
+ * divider (up one level).
+ */
+ if (!clk_mux_ops.get_parent(hw))
+ return rzv2h_cpg_plldsi_smux_lvds_determine_rate(priv, pll_clk, req);
+
+ req->best_parent_rate = req->rate;
+ return 0;
+}
+
+static int rzv2h_cpg_plldsi_smux_get_duty_cycle(struct clk_hw *hw,
+ struct clk_duty *duty)
+{
+ u8 parent = clk_mux_ops.get_parent(hw);
+
+ /*
+ * CDIV7_DSIx_CLK - LVDS path (div7) - duty 4/7.
+ * CSDIV_DSIx - DSI/RGB path (csdiv) - duty 1/2.
+ */
+ if (parent == 0) {
+ duty->num = CPG_PLLDSI_SMUX_LVDS_DUTY_NUM;
+ duty->den = CPG_PLLDSI_SMUX_LVDS_DUTY_DEN;
+ } else {
+ duty->num = CPG_PLLDSI_SMUX_DSI_RGB_DUTY_NUM;
+ duty->den = CPG_PLLDSI_SMUX_DSI_RGB_DUTY_DEN;
+ }
+
+ return 0;
+}
+
+static int rzv2h_cpg_plldsi_smux_set_duty_cycle(struct clk_hw *hw,
+ struct clk_duty *duty)
+{
+ struct clk_hw *parent_hw;
+ u8 parent_idx;
+
+ /*
+ * Select parent based on requested duty cycle:
+ * - If duty > 50% (num/den > 1/2), select LVDS path (parent 0)
+ * - Otherwise, select DSI/RGB path (parent 1)
+ */
+ if (duty->num * CPG_PLLDSI_SMUX_DSI_RGB_DUTY_DEN >
+ duty->den * CPG_PLLDSI_SMUX_DSI_RGB_DUTY_NUM)
+ parent_idx = 0;
+ else
+ parent_idx = 1;
+
+ if (parent_idx >= clk_hw_get_num_parents(hw))
+ return -EINVAL;
+
+ parent_hw = clk_hw_get_parent_by_index(hw, parent_idx);
+ if (!parent_hw)
+ return -EINVAL;
+
+ return clk_hw_set_parent(hw, parent_hw);
+}
+
+static const struct clk_ops rzv2h_cpg_plldsi_smux_ops = {
+ .determine_rate = rzv2h_cpg_plldsi_smux_determine_rate,
+ .get_parent = rzv2h_cpg_plldsi_smux_get_parent,
+ .set_parent = rzv2h_cpg_plldsi_smux_set_parent,
+ .get_duty_cycle = rzv2h_cpg_plldsi_smux_get_duty_cycle,
+ .set_duty_cycle = rzv2h_cpg_plldsi_smux_set_duty_cycle,
+};
+
+static struct clk * __init
+rzv2h_cpg_plldsi_smux_clk_register(const struct cpg_core_clk *core,
+ struct rzv2h_cpg_priv *priv)
+{
+ struct rzv2h_plldsi_mux_clk *clk_hw_data;
+ struct clk_init_data init;
+ struct clk_hw *clk_hw;
+ struct smuxed smux;
+ int ret;
+
+ smux = core->cfg.smux;
+
+ if (smux.shift + smux.width > 16) {
+ dev_err(priv->dev, "mux value exceeds LOWORD field\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ clk_hw_data = devm_kzalloc(priv->dev, sizeof(*clk_hw_data), GFP_KERNEL);
+ if (!clk_hw_data)
+ return ERR_PTR(-ENOMEM);
+
+ clk_hw_data->priv = priv;
+
+ init.name = core->name;
+ init.ops = &rzv2h_cpg_plldsi_smux_ops;
+ init.flags = core->flag;
+ init.parent_names = core->parent_names;
+ init.num_parents = core->num_parents;
+
+ clk_hw_data->mux.reg = priv->base + smux.offset;
+
+ clk_hw_data->mux.shift = smux.shift;
+ clk_hw_data->mux.mask = clk_div_mask(smux.width);
+ clk_hw_data->mux.flags = core->mux_flags;
+ clk_hw_data->mux.lock = &priv->rmw_lock;
+
+ clk_hw = &clk_hw_data->mux.hw;
+ clk_hw->init = &init;
+
+ ret = devm_clk_hw_register(priv->dev, clk_hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return clk_hw->clk;
+}
+
static int rzv2h_cpg_pll_clk_is_enabled(struct clk_hw *hw)
{
struct pll_clk *pll_clk = to_pll(hw);
@@ -1085,6 +1263,9 @@ rzv2h_cpg_register_core_clk(const struct cpg_core_clk *core,
case CLK_TYPE_PLLDSI_DIV:
clk = rzv2h_cpg_plldsi_div_clk_register(core, priv);
break;
+ case CLK_TYPE_PLLDSI_SMUX:
+ clk = rzv2h_cpg_plldsi_smux_clk_register(core, priv);
+ break;
default:
goto fail;
}
diff --git a/drivers/clk/renesas/rzv2h-cpg.h b/drivers/clk/renesas/rzv2h-cpg.h
index dc957bdaf5e9..dec0f7b621d6 100644
--- a/drivers/clk/renesas/rzv2h-cpg.h
+++ b/drivers/clk/renesas/rzv2h-cpg.h
@@ -121,6 +121,7 @@ struct fixed_mod_conf {
#define CPG_SSEL0 (0x300)
#define CPG_SSEL1 (0x304)
+#define CPG_SSEL3 (0x30C)
#define CPG_CDDIV0 (0x400)
#define CPG_CDDIV1 (0x404)
#define CPG_CDDIV2 (0x408)
@@ -148,6 +149,7 @@ struct fixed_mod_conf {
#define CSDIV0_DIVCTL2 DDIV_PACK(CPG_CSDIV0, 8, 2, CSDIV_NO_MON)
#define CSDIV0_DIVCTL3 DDIV_PACK_NO_RMW(CPG_CSDIV0, 12, 2, CSDIV_NO_MON)
#define CSDIV1_DIVCTL2 DDIV_PACK(CPG_CSDIV1, 8, 4, CSDIV_NO_MON)
+#define CSDIV1_DIVCTL3 DDIV_PACK(CPG_CSDIV1, 12, 4, CSDIV_NO_MON)
#define SSEL0_SELCTL2 SMUX_PACK(CPG_SSEL0, 8, 1)
#define SSEL0_SELCTL3 SMUX_PACK(CPG_SSEL0, 12, 1)
@@ -155,6 +157,8 @@ struct fixed_mod_conf {
#define SSEL1_SELCTL1 SMUX_PACK(CPG_SSEL1, 4, 1)
#define SSEL1_SELCTL2 SMUX_PACK(CPG_SSEL1, 8, 1)
#define SSEL1_SELCTL3 SMUX_PACK(CPG_SSEL1, 12, 1)
+#define SSEL3_SELCTL0 SMUX_PACK(CPG_SSEL3, 0, 1)
+#define SSEL3_SELCTL1 SMUX_PACK(CPG_SSEL3, 4, 1)
#define BUS_MSTOP_IDX_MASK GENMASK(31, 16)
#define BUS_MSTOP_BITS_MASK GENMASK(15, 0)
@@ -203,6 +207,7 @@ enum clk_types {
CLK_TYPE_SMUX, /* Static Mux */
CLK_TYPE_PLLDSI, /* PLLDSI */
CLK_TYPE_PLLDSI_DIV, /* PLLDSI divider */
+ CLK_TYPE_PLLDSI_SMUX, /* PLLDSI Static Mux */
};
#define DEF_TYPE(_name, _id, _type...) \
@@ -241,6 +246,13 @@ enum clk_types {
.dtable = _dtable, \
.parent = _parent, \
.flag = CLK_SET_RATE_PARENT)
+#define DEF_PLLDSI_SMUX(_name, _id, _smux_packed, _parent_names) \
+ DEF_TYPE(_name, _id, CLK_TYPE_PLLDSI_SMUX, \
+ .cfg.smux = _smux_packed, \
+ .parent_names = _parent_names, \
+ .num_parents = ARRAY_SIZE(_parent_names), \
+ .flag = CLK_SET_RATE_PARENT, \
+ .mux_flags = CLK_MUX_HIWORD_MASK)
/**
* struct rzv2h_mod_clk - Module Clocks definitions
diff --git a/drivers/clk/rockchip/Kconfig b/drivers/clk/rockchip/Kconfig
index 7e1433502061..85133498f013 100644
--- a/drivers/clk/rockchip/Kconfig
+++ b/drivers/clk/rockchip/Kconfig
@@ -3,7 +3,7 @@
config COMMON_CLK_ROCKCHIP
bool "Rockchip clock controller common support"
- depends on ARCH_ROCKCHIP
+ depends on ARCH_ROCKCHIP || COMPILE_TEST
default ARCH_ROCKCHIP
help
Say y here to enable common clock controller for Rockchip platforms.
diff --git a/drivers/clk/rockchip/clk-rk3588.c b/drivers/clk/rockchip/clk-rk3588.c
index 1694223f4f84..2ba9976654cf 100644
--- a/drivers/clk/rockchip/clk-rk3588.c
+++ b/drivers/clk/rockchip/clk-rk3588.c
@@ -5,11 +5,13 @@
*/
#include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/syscore_ops.h>
#include <dt-bindings/clock/rockchip,rk3588-cru.h>
+#include <soc/rockchip/rk3588_grf.h>
#include "clk.h"
#define RK3588_GRF_SOC_STATUS0 0x600
@@ -892,6 +894,8 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
RK3588_CLKGATE_CON(8), 0, GFLAGS),
MUX(I2S2_2CH_MCLKOUT, "i2s2_2ch_mclkout", i2s2_2ch_mclkout_p, CLK_SET_RATE_PARENT,
RK3588_CLKSEL_CON(30), 2, 1, MFLAGS),
+ GATE_GRF(I2S2_2CH_MCLKOUT_TO_IO, "i2s2_2ch_mclkout_to_io", "i2s2_2ch_mclkout",
+ 0, RK3588_SYSGRF_SOC_CON6, 2, GFLAGS, grf_type_sys),
COMPOSITE(CLK_I2S3_2CH_SRC, "clk_i2s3_2ch_src", gpll_aupll_p, 0,
RK3588_CLKSEL_CON(30), 8, 1, MFLAGS, 3, 5, DFLAGS,
@@ -907,6 +911,8 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
RK3588_CLKGATE_CON(8), 4, GFLAGS),
MUX(I2S3_2CH_MCLKOUT, "i2s3_2ch_mclkout", i2s3_2ch_mclkout_p, CLK_SET_RATE_PARENT,
RK3588_CLKSEL_CON(32), 2, 1, MFLAGS),
+ GATE_GRF(I2S3_2CH_MCLKOUT_TO_IO, "i2s3_2ch_mclkout_to_io", "i2s3_2ch_mclkout",
+ 0, RK3588_SYSGRF_SOC_CON6, 7, GFLAGS, grf_type_sys),
GATE(PCLK_ACDCDIG, "pclk_acdcdig", "pclk_audio_root", 0,
RK3588_CLKGATE_CON(7), 11, GFLAGS),
GATE(HCLK_I2S0_8CH, "hclk_i2s0_8ch", "hclk_audio_root", 0,
@@ -935,6 +941,8 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
RK3588_CLKGATE_CON(7), 10, GFLAGS),
MUX(I2S0_8CH_MCLKOUT, "i2s0_8ch_mclkout", i2s0_8ch_mclkout_p, CLK_SET_RATE_PARENT,
RK3588_CLKSEL_CON(28), 2, 2, MFLAGS),
+ GATE_GRF(I2S0_8CH_MCLKOUT_TO_IO, "i2s0_8ch_mclkout_to_io", "i2s0_8ch_mclkout",
+ 0, RK3588_SYSGRF_SOC_CON6, 0, GFLAGS, grf_type_sys),
GATE(HCLK_PDM1, "hclk_pdm1", "hclk_audio_root", 0,
RK3588_CLKGATE_CON(9), 6, GFLAGS),
@@ -2220,6 +2228,8 @@ static struct rockchip_clk_branch rk3588_early_clk_branches[] __initdata = {
RK3588_PMU_CLKGATE_CON(2), 13, GFLAGS),
MUX(I2S1_8CH_MCLKOUT, "i2s1_8ch_mclkout", i2s1_8ch_mclkout_p, CLK_SET_RATE_PARENT,
RK3588_PMU_CLKSEL_CON(9), 2, 2, MFLAGS),
+ GATE_GRF(I2S1_8CH_MCLKOUT_TO_IO, "i2s1_8ch_mclkout_to_io", "i2s1_8ch_mclkout",
+ 0, RK3588_SYSGRF_SOC_CON6, 1, GFLAGS, grf_type_sys),
GATE(PCLK_PMU1, "pclk_pmu1", "pclk_pmu0_root", CLK_IS_CRITICAL,
RK3588_PMU_CLKGATE_CON(1), 0, GFLAGS),
GATE(CLK_DDR_FAIL_SAFE, "clk_ddr_fail_safe", "clk_pmu0", CLK_IGNORE_UNUSED,
@@ -2439,6 +2449,7 @@ static struct rockchip_clk_branch rk3588_clk_branches[] = {
static void __init rk3588_clk_early_init(struct device_node *np)
{
struct rockchip_clk_provider *ctx;
+ struct regmap *sys_grf;
unsigned long clk_nr_clks, max_clk_id1, max_clk_id2;
void __iomem *reg_base;
@@ -2479,6 +2490,11 @@ static void __init rk3588_clk_early_init(struct device_node *np)
&rk3588_cpub1clk_data, rk3588_cpub1clk_rates,
ARRAY_SIZE(rk3588_cpub1clk_rates));
+ /* Register SYS_GRF for I2S MCLK output to IO gate clocks */
+ sys_grf = syscon_regmap_lookup_by_compatible("rockchip,rk3588-sys-grf");
+ if (!IS_ERR(sys_grf))
+ rockchip_clk_add_grf(ctx, sys_grf, grf_type_sys);
+
rockchip_clk_register_branches(ctx, rk3588_early_clk_branches,
ARRAY_SIZE(rk3588_early_clk_branches));
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
index e8b3b0b9a4f8..ee8c79b938d3 100644
--- a/drivers/clk/rockchip/clk.c
+++ b/drivers/clk/rockchip/clk.c
@@ -429,6 +429,24 @@ void rockchip_clk_of_add_provider(struct device_node *np,
}
EXPORT_SYMBOL_GPL(rockchip_clk_of_add_provider);
+int rockchip_clk_add_grf(struct rockchip_clk_provider *ctx,
+ struct regmap *grf,
+ enum rockchip_grf_type type)
+{
+ struct rockchip_aux_grf *aux_grf;
+
+ aux_grf = kzalloc_obj(*aux_grf);
+ if (!aux_grf)
+ return -ENOMEM;
+
+ aux_grf->grf = grf;
+ aux_grf->type = type;
+ hash_add(ctx->aux_grf_table, &aux_grf->node, type);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rockchip_clk_add_grf);
+
void rockchip_clk_register_plls(struct rockchip_clk_provider *ctx,
struct rockchip_pll_clock *list,
unsigned int nr_pll, int grf_lock_offset)
@@ -509,10 +527,9 @@ void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx,
clk = NULL;
/* for GRF-dependent branches, choose the right grf first */
- if ((list->branch_type == branch_grf_mux ||
- list->branch_type == branch_grf_gate ||
- list->branch_type == branch_grf_mmc) &&
- list->grf_type != grf_type_sys) {
+ if (list->branch_type == branch_grf_mux ||
+ list->branch_type == branch_grf_gate ||
+ list->branch_type == branch_grf_mmc) {
hash_for_each_possible(ctx->aux_grf_table, agrf, node, list->grf_type) {
if (agrf->type == list->grf_type) {
grf = agrf->grf;
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index cf0f5f11c34b..9e3503e2ffc2 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -1329,6 +1329,9 @@ struct rockchip_clk_provider *rockchip_clk_init_early(struct device_node *np,
void rockchip_clk_finalize(struct rockchip_clk_provider *ctx);
void rockchip_clk_of_add_provider(struct device_node *np,
struct rockchip_clk_provider *ctx);
+int rockchip_clk_add_grf(struct rockchip_clk_provider *ctx,
+ struct regmap *grf,
+ enum rockchip_grf_type type);
unsigned long rockchip_clk_find_max_clk_id(struct rockchip_clk_branch *list,
unsigned int nr_clk);
void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx,
diff --git a/drivers/clk/samsung/clk-exynos850.c b/drivers/clk/samsung/clk-exynos850.c
index eb9c80b60225..b143a42293f5 100644
--- a/drivers/clk/samsung/clk-exynos850.c
+++ b/drivers/clk/samsung/clk-exynos850.c
@@ -686,10 +686,11 @@ static const struct samsung_gate_clock apm_gate_clks[] __initconst = {
CLK_CON_GAT_GOUT_APM_APBIF_RTC_PCLK, 21, 0, 0),
GATE(CLK_GOUT_TOP_RTC_PCLK, "gout_top_rtc_pclk", "dout_apm_bus",
CLK_CON_GAT_GOUT_APM_APBIF_TOP_RTC_PCLK, 21, 0, 0),
+ /* TODO: Should be dealt with or enabled in PMIC ACPM driver */
GATE(CLK_GOUT_I3C_PCLK, "gout_i3c_pclk", "dout_apm_bus",
- CLK_CON_GAT_GOUT_APM_I3C_APM_PMIC_I_PCLK, 21, 0, 0),
+ CLK_CON_GAT_GOUT_APM_I3C_APM_PMIC_I_PCLK, 21, CLK_IS_CRITICAL, 0),
GATE(CLK_GOUT_I3C_SCLK, "gout_i3c_sclk", "mout_apm_i3c",
- CLK_CON_GAT_GOUT_APM_I3C_APM_PMIC_I_SCLK, 21, 0, 0),
+ CLK_CON_GAT_GOUT_APM_I3C_APM_PMIC_I_SCLK, 21, CLK_IS_CRITICAL, 0),
GATE(CLK_GOUT_SPEEDY_PCLK, "gout_speedy_pclk", "dout_apm_bus",
CLK_CON_GAT_GOUT_APM_SPEEDY_APM_PCLK, 21, 0, 0),
/* TODO: Should be enabled in GPIO driver (or made CLK_IS_CRITICAL) */
diff --git a/drivers/clk/samsung/clk-exynos990.c b/drivers/clk/samsung/clk-exynos990.c
index 6277dd557fab..4385c3b76dd6 100644
--- a/drivers/clk/samsung/clk-exynos990.c
+++ b/drivers/clk/samsung/clk-exynos990.c
@@ -1546,54 +1546,44 @@ static const unsigned long peric0_clk_regs[] __initconst = {
/* Parent clock list for CMU_PERIC0 muxes */
PNAME(mout_peric0_bus_user_p) = { "oscclk", "dout_cmu_peric0_bus" };
-PNAME(mout_peric0_uart_dbg_p) = { "oscclk", "dout_cmu_peric0_ip" };
-PNAME(mout_peric0_usi00_user_p) = { "oscclk", "dout_cmu_peric0_ip" };
-PNAME(mout_peric0_usi01_user_p) = { "oscclk", "dout_cmu_peric0_ip" };
-PNAME(mout_peric0_usi02_user_p) = { "oscclk", "dout_cmu_peric0_ip" };
-PNAME(mout_peric0_usi03_user_p) = { "oscclk", "dout_cmu_peric0_ip" };
-PNAME(mout_peric0_usi04_user_p) = { "oscclk", "dout_cmu_peric0_ip" };
-PNAME(mout_peric0_usi05_user_p) = { "oscclk", "dout_cmu_peric0_ip" };
-PNAME(mout_peric0_usi13_user_p) = { "oscclk", "dout_cmu_peric0_ip" };
-PNAME(mout_peric0_usi14_user_p) = { "oscclk", "dout_cmu_peric0_ip" };
-PNAME(mout_peric0_usi15_user_p) = { "oscclk", "dout_cmu_peric0_ip" };
-PNAME(mout_peric0_usi_i2c_user_p) = { "oscclk", "dout_cmu_peric0_ip" };
+PNAME(mout_peric0_nonbususer_p) = { "oscclk", "dout_cmu_peric0_ip" };
static const struct samsung_mux_clock peric0_mux_clks[] __initconst = {
MUX(CLK_MOUT_PERIC0_BUS_USER, "mout_peric0_bus_user",
mout_peric0_bus_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_BUS_USER,
4, 1),
- MUX(CLK_MOUT_PERIC0_UART_DBG, "mout_peric0_uart_dbg",
- mout_peric0_uart_dbg_p, PLL_CON0_MUX_CLKCMU_PERIC0_UART_DBG,
- 4, 1),
- MUX(CLK_MOUT_PERIC0_USI00_USI_USER, "mout_peric0_usi00_usi_user",
- mout_peric0_usi00_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI00_USI_USER,
- 4, 1),
- MUX(CLK_MOUT_PERIC0_USI01_USI_USER, "mout_peric0_usi01_usi_user",
- mout_peric0_usi01_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI01_USI_USER,
- 4, 1),
- MUX(CLK_MOUT_PERIC0_USI02_USI_USER, "mout_peric0_usi02_usi_user",
- mout_peric0_usi02_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI02_USI_USER,
- 4, 1),
- MUX(CLK_MOUT_PERIC0_USI03_USI_USER, "mout_peric0_usi03_usi_user",
- mout_peric0_usi03_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI03_USI_USER,
- 4, 1),
- MUX(CLK_MOUT_PERIC0_USI04_USI_USER, "mout_peric0_usi04_usi_user",
- mout_peric0_usi04_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI04_USI_USER,
- 4, 1),
- MUX(CLK_MOUT_PERIC0_USI05_USI_USER, "mout_peric0_usi05_usi_user",
- mout_peric0_usi05_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI05_USI_USER,
- 4, 1),
- MUX(CLK_MOUT_PERIC0_USI13_USI_USER, "mout_peric0_usi13_usi_user",
- mout_peric0_usi13_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI13_USI_USER,
- 4, 1),
- MUX(CLK_MOUT_PERIC0_USI14_USI_USER, "mout_peric0_usi14_usi_user",
- mout_peric0_usi14_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI14_USI_USER,
- 4, 1),
- MUX(CLK_MOUT_PERIC0_USI15_USI_USER, "mout_peric0_usi15_usi_user",
- mout_peric0_usi15_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI15_USI_USER,
- 4, 1),
+ nMUX(CLK_MOUT_PERIC0_UART_DBG, "mout_peric0_uart_dbg",
+ mout_peric0_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC0_UART_DBG,
+ 4, 1),
+ nMUX(CLK_MOUT_PERIC0_USI00_USI_USER, "mout_peric0_usi00_usi_user",
+ mout_peric0_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI00_USI_USER,
+ 4, 1),
+ nMUX(CLK_MOUT_PERIC0_USI01_USI_USER, "mout_peric0_usi01_usi_user",
+ mout_peric0_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI01_USI_USER,
+ 4, 1),
+ nMUX(CLK_MOUT_PERIC0_USI02_USI_USER, "mout_peric0_usi02_usi_user",
+ mout_peric0_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI02_USI_USER,
+ 4, 1),
+ nMUX(CLK_MOUT_PERIC0_USI03_USI_USER, "mout_peric0_usi03_usi_user",
+ mout_peric0_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI03_USI_USER,
+ 4, 1),
+ nMUX(CLK_MOUT_PERIC0_USI04_USI_USER, "mout_peric0_usi04_usi_user",
+ mout_peric0_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI04_USI_USER,
+ 4, 1),
+ nMUX(CLK_MOUT_PERIC0_USI05_USI_USER, "mout_peric0_usi05_usi_user",
+ mout_peric0_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI05_USI_USER,
+ 4, 1),
+ nMUX(CLK_MOUT_PERIC0_USI13_USI_USER, "mout_peric0_usi13_usi_user",
+ mout_peric0_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI13_USI_USER,
+ 4, 1),
+ nMUX(CLK_MOUT_PERIC0_USI14_USI_USER, "mout_peric0_usi14_usi_user",
+ mout_peric0_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI14_USI_USER,
+ 4, 1),
+ nMUX(CLK_MOUT_PERIC0_USI15_USI_USER, "mout_peric0_usi15_usi_user",
+ mout_peric0_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI15_USI_USER,
+ 4, 1),
MUX(CLK_MOUT_PERIC0_USI_I2C_USER, "mout_peric0_usi_i2c_user",
- mout_peric0_usi_i2c_user_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI_I2C_USER,
+ mout_peric0_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC0_USI_I2C_USER,
4, 1),
};
@@ -1602,42 +1592,42 @@ static const struct samsung_div_clock peric0_div_clks[] __initconst = {
"mout_peric0_uart_dbg",
CLK_CON_DIV_DIV_CLK_PERIC0_UART_DBG,
0, 4),
- DIV(CLK_DOUT_PERIC0_USI00_USI, "dout_peric0_usi00_usi",
- "mout_peric0_usi00_usi_user",
- CLK_CON_DIV_DIV_CLK_PERIC0_USI00_USI,
- 0, 4),
- DIV(CLK_DOUT_PERIC0_USI01_USI, "dout_peric0_usi01_usi",
- "mout_peric0_usi01_usi_user",
- CLK_CON_DIV_DIV_CLK_PERIC0_USI01_USI,
- 0, 4),
- DIV(CLK_DOUT_PERIC0_USI02_USI, "dout_peric0_usi02_usi",
- "mout_peric0_usi02_usi_user",
- CLK_CON_DIV_DIV_CLK_PERIC0_USI02_USI,
- 0, 4),
- DIV(CLK_DOUT_PERIC0_USI03_USI, "dout_peric0_usi03_usi",
- "mout_peric0_usi03_usi_user",
- CLK_CON_DIV_DIV_CLK_PERIC0_USI03_USI,
- 0, 4),
- DIV(CLK_DOUT_PERIC0_USI04_USI, "dout_peric0_usi04_usi",
- "mout_peric0_usi04_usi_user",
- CLK_CON_DIV_DIV_CLK_PERIC0_USI04_USI,
- 0, 4),
- DIV(CLK_DOUT_PERIC0_USI05_USI, "dout_peric0_usi05_usi",
- "mout_peric0_usi05_usi_user",
- CLK_CON_DIV_DIV_CLK_PERIC0_USI05_USI,
- 0, 4),
- DIV(CLK_DOUT_PERIC0_USI13_USI, "dout_peric0_usi13_usi",
- "mout_peric0_usi13_usi_user",
- CLK_CON_DIV_DIV_CLK_PERIC0_USI13_USI,
- 0, 4),
- DIV(CLK_DOUT_PERIC0_USI14_USI, "dout_peric0_usi14_usi",
- "mout_peric0_usi14_usi_user",
- CLK_CON_DIV_DIV_CLK_PERIC0_USI14_USI,
- 0, 4),
- DIV(CLK_DOUT_PERIC0_USI15_USI, "dout_peric0_usi15_usi",
- "mout_peric0_usi15_usi_user",
- CLK_CON_DIV_DIV_CLK_PERIC0_USI15_USI,
- 0, 4),
+ DIV_F(CLK_DOUT_PERIC0_USI00_USI, "dout_peric0_usi00_usi",
+ "mout_peric0_usi00_usi_user",
+ CLK_CON_DIV_DIV_CLK_PERIC0_USI00_USI, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(CLK_DOUT_PERIC0_USI01_USI, "dout_peric0_usi01_usi",
+ "mout_peric0_usi01_usi_user",
+ CLK_CON_DIV_DIV_CLK_PERIC0_USI01_USI, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(CLK_DOUT_PERIC0_USI02_USI, "dout_peric0_usi02_usi",
+ "mout_peric0_usi02_usi_user",
+ CLK_CON_DIV_DIV_CLK_PERIC0_USI02_USI, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(CLK_DOUT_PERIC0_USI03_USI, "dout_peric0_usi03_usi",
+ "mout_peric0_usi03_usi_user",
+ CLK_CON_DIV_DIV_CLK_PERIC0_USI03_USI, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(CLK_DOUT_PERIC0_USI04_USI, "dout_peric0_usi04_usi",
+ "mout_peric0_usi04_usi_user",
+ CLK_CON_DIV_DIV_CLK_PERIC0_USI04_USI, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(CLK_DOUT_PERIC0_USI05_USI, "dout_peric0_usi05_usi",
+ "mout_peric0_usi05_usi_user",
+ CLK_CON_DIV_DIV_CLK_PERIC0_USI05_USI, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(CLK_DOUT_PERIC0_USI13_USI, "dout_peric0_usi13_usi",
+ "mout_peric0_usi13_usi_user",
+ CLK_CON_DIV_DIV_CLK_PERIC0_USI13_USI, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(CLK_DOUT_PERIC0_USI14_USI, "dout_peric0_usi14_usi",
+ "mout_peric0_usi14_usi_user",
+ CLK_CON_DIV_DIV_CLK_PERIC0_USI14_USI, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(CLK_DOUT_PERIC0_USI15_USI, "dout_peric0_usi15_usi",
+ "mout_peric0_usi15_usi_user",
+ CLK_CON_DIV_DIV_CLK_PERIC0_USI15_USI, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
DIV(CLK_DOUT_PERIC0_USI_I2C, "dout_peric0_usi_i2c",
"mout_peric0_usi_i2c_user",
CLK_CON_DIV_DIV_CLK_PERIC0_USI_I2C,
@@ -2107,58 +2097,47 @@ static const unsigned long peric1_clk_regs[] __initconst = {
/* Parent clock list for CMU_PERIC1 muxes */
PNAME(mout_peric1_bus_user_p) = { "oscclk", "dout_cmu_peric1_bus" };
-PNAME(mout_peric1_uart_bt_user_p) = { "oscclk", "dout_cmu_peric1_ip" };
-PNAME(mout_peric1_usi06_user_p) = { "oscclk", "dout_cmu_peric1_ip" };
-PNAME(mout_peric1_usi07_user_p) = { "oscclk", "dout_cmu_peric1_ip" };
-PNAME(mout_peric1_usi08_user_p) = { "oscclk", "dout_cmu_peric1_ip" };
-PNAME(mout_peric1_usi09_user_p) = { "oscclk", "dout_cmu_peric1_ip" };
-PNAME(mout_peric1_usi10_user_p) = { "oscclk", "dout_cmu_peric1_ip" };
-PNAME(mout_peric1_usi11_user_p) = { "oscclk", "dout_cmu_peric1_ip" };
-PNAME(mout_peric1_usi12_user_p) = { "oscclk", "dout_cmu_peric1_ip" };
-PNAME(mout_peric1_usi18_user_p) = { "oscclk", "dout_cmu_peric1_ip" };
-PNAME(mout_peric1_usi16_user_p) = { "oscclk", "dout_cmu_peric1_ip" };
-PNAME(mout_peric1_usi17_user_p) = { "oscclk", "dout_cmu_peric1_ip" };
-PNAME(mout_peric1_usi_i2c_user_p) = { "oscclk", "dout_cmu_peric1_ip" };
+PNAME(mout_peric1_nonbususer_p) = { "oscclk", "dout_cmu_peric1_ip" };
static const struct samsung_mux_clock peric1_mux_clks[] __initconst = {
MUX(CLK_MOUT_PERIC1_BUS_USER, "mout_peric1_bus_user",
mout_peric1_bus_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_BUS_USER,
4, 1),
- MUX(CLK_MOUT_PERIC1_UART_BT_USER, "mout_peric1_uart_bt_user",
- mout_peric1_uart_bt_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_UART_BT_USER,
- 4, 1),
- MUX(CLK_MOUT_PERIC1_USI06_USI_USER, "mout_peric1_usi06_usi_user",
- mout_peric1_usi06_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI06_USI_USER,
- 4, 1),
- MUX(CLK_MOUT_PERIC1_USI07_USI_USER, "mout_peric1_usi07_usi_user",
- mout_peric1_usi07_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI07_USI_USER,
- 4, 1),
- MUX(CLK_MOUT_PERIC1_USI08_USI_USER, "mout_peric1_usi08_usi_user",
- mout_peric1_usi08_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI08_USI_USER,
- 4, 1),
- MUX(CLK_MOUT_PERIC1_USI09_USI_USER, "mout_peric1_usi09_usi_user",
- mout_peric1_usi09_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI09_USI_USER,
- 4, 1),
- MUX(CLK_MOUT_PERIC1_USI10_USI_USER, "mout_peric1_usi10_usi_user",
- mout_peric1_usi10_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI10_USI_USER,
- 4, 1),
- MUX(CLK_MOUT_PERIC1_USI11_USI_USER, "mout_peric1_usi11_usi_user",
- mout_peric1_usi11_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI11_USI_USER,
- 4, 1),
- MUX(CLK_MOUT_PERIC1_USI12_USI_USER, "mout_peric1_usi12_usi_user",
- mout_peric1_usi12_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI12_USI_USER,
- 4, 1),
- MUX(CLK_MOUT_PERIC1_USI18_USI_USER, "mout_peric1_usi18_usi_user",
- mout_peric1_usi18_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI18_USI_USER,
- 4, 1),
- MUX(CLK_MOUT_PERIC1_USI16_USI_USER, "mout_peric1_usi16_usi_user",
- mout_peric1_usi16_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI16_USI_USER,
- 4, 1),
- MUX(CLK_MOUT_PERIC1_USI17_USI_USER, "mout_peric1_usi17_usi_user",
- mout_peric1_usi17_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI17_USI_USER,
- 4, 1),
+ nMUX(CLK_MOUT_PERIC1_UART_BT_USER, "mout_peric1_uart_bt_user",
+ mout_peric1_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC1_UART_BT_USER,
+ 4, 1),
+ nMUX(CLK_MOUT_PERIC1_USI06_USI_USER, "mout_peric1_usi06_usi_user",
+ mout_peric1_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI06_USI_USER,
+ 4, 1),
+ nMUX(CLK_MOUT_PERIC1_USI07_USI_USER, "mout_peric1_usi07_usi_user",
+ mout_peric1_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI07_USI_USER,
+ 4, 1),
+ nMUX(CLK_MOUT_PERIC1_USI08_USI_USER, "mout_peric1_usi08_usi_user",
+ mout_peric1_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI08_USI_USER,
+ 4, 1),
+ nMUX(CLK_MOUT_PERIC1_USI09_USI_USER, "mout_peric1_usi09_usi_user",
+ mout_peric1_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI09_USI_USER,
+ 4, 1),
+ nMUX(CLK_MOUT_PERIC1_USI10_USI_USER, "mout_peric1_usi10_usi_user",
+ mout_peric1_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI10_USI_USER,
+ 4, 1),
+ nMUX(CLK_MOUT_PERIC1_USI11_USI_USER, "mout_peric1_usi11_usi_user",
+ mout_peric1_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI11_USI_USER,
+ 4, 1),
+ nMUX(CLK_MOUT_PERIC1_USI12_USI_USER, "mout_peric1_usi12_usi_user",
+ mout_peric1_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI12_USI_USER,
+ 4, 1),
+ nMUX(CLK_MOUT_PERIC1_USI18_USI_USER, "mout_peric1_usi18_usi_user",
+ mout_peric1_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI18_USI_USER,
+ 4, 1),
+ nMUX(CLK_MOUT_PERIC1_USI16_USI_USER, "mout_peric1_usi16_usi_user",
+ mout_peric1_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI16_USI_USER,
+ 4, 1),
+ nMUX(CLK_MOUT_PERIC1_USI17_USI_USER, "mout_peric1_usi17_usi_user",
+ mout_peric1_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI17_USI_USER,
+ 4, 1),
MUX(CLK_MOUT_PERIC1_USI_I2C_USER, "mout_peric1_usi_i2c_user",
- mout_peric1_usi_i2c_user_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI_I2C_USER,
+ mout_peric1_nonbususer_p, PLL_CON0_MUX_CLKCMU_PERIC1_USI_I2C_USER,
4, 1),
};
@@ -2167,46 +2146,46 @@ static const struct samsung_div_clock peric1_div_clks[] __initconst = {
"mout_peric1_uart_bt_user",
CLK_CON_DIV_DIV_CLK_PERIC1_UART_BT,
0, 4),
- DIV(CLK_DOUT_PERIC1_USI06_USI, "dout_peric1_usi06_usi",
- "mout_peric1_usi06_usi_user",
- CLK_CON_DIV_DIV_CLK_PERIC1_USI06_USI,
- 0, 4),
- DIV(CLK_DOUT_PERIC1_USI07_USI, "dout_peric1_usi07_usi",
- "mout_peric1_usi07_usi_user",
- CLK_CON_DIV_DIV_CLK_PERIC1_USI07_USI,
- 0, 4),
- DIV(CLK_DOUT_PERIC1_USI08_USI, "dout_peric1_usi08_usi",
- "mout_peric1_usi08_usi_user",
- CLK_CON_DIV_DIV_CLK_PERIC1_USI08_USI,
- 0, 4),
- DIV(CLK_DOUT_PERIC1_USI18_USI, "dout_peric1_usi18_usi",
- "mout_peric1_usi18_usi_user",
- CLK_CON_DIV_DIV_CLK_PERIC1_USI18_USI,
- 0, 4),
- DIV(CLK_DOUT_PERIC1_USI12_USI, "dout_peric1_usi12_usi",
- "mout_peric1_usi12_usi_user",
- CLK_CON_DIV_DIV_CLK_PERIC1_USI12_USI,
- 0, 4),
- DIV(CLK_DOUT_PERIC1_USI09_USI, "dout_peric1_usi09_usi",
- "mout_peric1_usi09_usi_user",
- CLK_CON_DIV_DIV_CLK_PERIC1_USI09_USI,
- 0, 4),
- DIV(CLK_DOUT_PERIC1_USI10_USI, "dout_peric1_usi10_usi",
- "mout_peric1_usi10_usi_user",
- CLK_CON_DIV_DIV_CLK_PERIC1_USI10_USI,
- 0, 4),
- DIV(CLK_DOUT_PERIC1_USI11_USI, "dout_peric1_usi11_usi",
- "mout_peric1_usi11_usi_user",
- CLK_CON_DIV_DIV_CLK_PERIC1_USI11_USI,
- 0, 4),
- DIV(CLK_DOUT_PERIC1_USI16_USI, "dout_peric1_usi16_usi",
- "mout_peric1_usi16_usi_user",
- CLK_CON_DIV_DIV_CLK_PERIC1_USI16_USI,
- 0, 4),
- DIV(CLK_DOUT_PERIC1_USI17_USI, "dout_peric1_usi17_usi",
- "mout_peric1_usi17_usi_user",
- CLK_CON_DIV_DIV_CLK_PERIC1_USI17_USI,
- 0, 4),
+ DIV_F(CLK_DOUT_PERIC1_USI06_USI, "dout_peric1_usi06_usi",
+ "mout_peric1_usi06_usi_user",
+ CLK_CON_DIV_DIV_CLK_PERIC1_USI06_USI, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(CLK_DOUT_PERIC1_USI07_USI, "dout_peric1_usi07_usi",
+ "mout_peric1_usi07_usi_user",
+ CLK_CON_DIV_DIV_CLK_PERIC1_USI07_USI, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(CLK_DOUT_PERIC1_USI08_USI, "dout_peric1_usi08_usi",
+ "mout_peric1_usi08_usi_user",
+ CLK_CON_DIV_DIV_CLK_PERIC1_USI08_USI, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(CLK_DOUT_PERIC1_USI18_USI, "dout_peric1_usi18_usi",
+ "mout_peric1_usi18_usi_user",
+ CLK_CON_DIV_DIV_CLK_PERIC1_USI18_USI, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(CLK_DOUT_PERIC1_USI12_USI, "dout_peric1_usi12_usi",
+ "mout_peric1_usi12_usi_user",
+ CLK_CON_DIV_DIV_CLK_PERIC1_USI12_USI, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(CLK_DOUT_PERIC1_USI09_USI, "dout_peric1_usi09_usi",
+ "mout_peric1_usi09_usi_user",
+ CLK_CON_DIV_DIV_CLK_PERIC1_USI09_USI, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(CLK_DOUT_PERIC1_USI10_USI, "dout_peric1_usi10_usi",
+ "mout_peric1_usi10_usi_user",
+ CLK_CON_DIV_DIV_CLK_PERIC1_USI10_USI, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(CLK_DOUT_PERIC1_USI11_USI, "dout_peric1_usi11_usi",
+ "mout_peric1_usi11_usi_user",
+ CLK_CON_DIV_DIV_CLK_PERIC1_USI11_USI, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(CLK_DOUT_PERIC1_USI16_USI, "dout_peric1_usi16_usi",
+ "mout_peric1_usi16_usi_user",
+ CLK_CON_DIV_DIV_CLK_PERIC1_USI16_USI, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
+ DIV_F(CLK_DOUT_PERIC1_USI17_USI, "dout_peric1_usi17_usi",
+ "mout_peric1_usi17_usi_user",
+ CLK_CON_DIV_DIV_CLK_PERIC1_USI17_USI, 0, 4,
+ CLK_SET_RATE_PARENT, 0),
DIV(CLK_DOUT_PERIC1_USI_I2C, "dout_peric1_usi_i2c",
"mout_peric1_usi_i2c_user",
CLK_CON_DIV_DIV_CLK_PERIC1_USI_I2C,
diff --git a/drivers/clk/socfpga/clk-agilex.c b/drivers/clk/socfpga/clk-agilex.c
index 8dd94f64756b..2bdea1997b5e 100644
--- a/drivers/clk/socfpga/clk-agilex.c
+++ b/drivers/clk/socfpga/clk-agilex.c
@@ -259,6 +259,8 @@ static const struct stratix10_perip_cnt_clock agilex_main_perip_cnt_clks[] = {
0, 0x3C, 0, 0, 0},
{ AGILEX_NOC_FREE_CLK, "noc_free_clk", NULL, noc_free_mux, ARRAY_SIZE(noc_free_mux),
0, 0x40, 0, 0, 0},
+ { AGILEX_L3_MAIN_FREE_CLK, "l3_main_free_clk", "noc_free_clk", NULL,
+ 1, 0, 0, 1, 0, 0},
{ AGILEX_L4_SYS_FREE_CLK, "l4_sys_free_clk", NULL, noc_mux, ARRAY_SIZE(noc_mux), 0,
0, 4, 0x30, 1},
{ AGILEX_EMAC_A_FREE_CLK, "emaca_free_clk", NULL, emaca_free_mux, ARRAY_SIZE(emaca_free_mux),
diff --git a/drivers/clk/spacemit/ccu-k3.c b/drivers/clk/spacemit/ccu-k3.c
index bb8b75bdbdb3..cb0c4277f72a 100644
--- a/drivers/clk/spacemit/ccu-k3.c
+++ b/drivers/clk/spacemit/ccu-k3.c
@@ -947,16 +947,21 @@ static const struct clk_parent_data edp1_pclk_parents[] = {
};
CCU_MUX_GATE_DEFINE(edp1_pxclk, edp1_pclk_parents, APMU_LCD_EDP_CTRL, 18, 1, BIT(17), 0);
-CCU_GATE_DEFINE(pciea_mstr_clk, CCU_PARENT_HW(axi_clk), APMU_PCIE_CLK_RES_CTRL_A, BIT(2), 0);
-CCU_GATE_DEFINE(pciea_slv_clk, CCU_PARENT_HW(axi_clk), APMU_PCIE_CLK_RES_CTRL_A, BIT(1), 0);
-CCU_GATE_DEFINE(pcieb_mstr_clk, CCU_PARENT_HW(axi_clk), APMU_PCIE_CLK_RES_CTRL_B, BIT(2), 0);
-CCU_GATE_DEFINE(pcieb_slv_clk, CCU_PARENT_HW(axi_clk), APMU_PCIE_CLK_RES_CTRL_B, BIT(1), 0);
-CCU_GATE_DEFINE(pciec_mstr_clk, CCU_PARENT_HW(axi_clk), APMU_PCIE_CLK_RES_CTRL_C, BIT(2), 0);
-CCU_GATE_DEFINE(pciec_slv_clk, CCU_PARENT_HW(axi_clk), APMU_PCIE_CLK_RES_CTRL_C, BIT(1), 0);
-CCU_GATE_DEFINE(pcied_mstr_clk, CCU_PARENT_HW(axi_clk), APMU_PCIE_CLK_RES_CTRL_D, BIT(2), 0);
-CCU_GATE_DEFINE(pcied_slv_clk, CCU_PARENT_HW(axi_clk), APMU_PCIE_CLK_RES_CTRL_D, BIT(1), 0);
-CCU_GATE_DEFINE(pciee_mstr_clk, CCU_PARENT_HW(axi_clk), APMU_PCIE_CLK_RES_CTRL_E, BIT(2), 0);
-CCU_GATE_DEFINE(pciee_slv_clk, CCU_PARENT_HW(axi_clk), APMU_PCIE_CLK_RES_CTRL_E, BIT(1), 0);
+CCU_GATE_DEFINE(pciea_mstr_clk, CCU_PARENT_HW(pll2_d6), APMU_PCIE_CLK_RES_CTRL_A, BIT(2), 0);
+CCU_GATE_DEFINE(pciea_slv_clk, CCU_PARENT_HW(pll2_d6), APMU_PCIE_CLK_RES_CTRL_A, BIT(1), 0);
+CCU_GATE_DEFINE(pciea_dbi_clk, CCU_PARENT_HW(axi_clk), APMU_PCIE_CLK_RES_CTRL_A, BIT(0), 0);
+CCU_GATE_DEFINE(pcieb_mstr_clk, CCU_PARENT_HW(pll2_d6), APMU_PCIE_CLK_RES_CTRL_B, BIT(2), 0);
+CCU_GATE_DEFINE(pcieb_slv_clk, CCU_PARENT_HW(pll2_d6), APMU_PCIE_CLK_RES_CTRL_B, BIT(1), 0);
+CCU_GATE_DEFINE(pcieb_dbi_clk, CCU_PARENT_HW(axi_clk), APMU_PCIE_CLK_RES_CTRL_B, BIT(0), 0);
+CCU_GATE_DEFINE(pciec_mstr_clk, CCU_PARENT_HW(pll2_d6), APMU_PCIE_CLK_RES_CTRL_C, BIT(2), 0);
+CCU_GATE_DEFINE(pciec_slv_clk, CCU_PARENT_HW(pll2_d6), APMU_PCIE_CLK_RES_CTRL_C, BIT(1), 0);
+CCU_GATE_DEFINE(pciec_dbi_clk, CCU_PARENT_HW(axi_clk), APMU_PCIE_CLK_RES_CTRL_C, BIT(0), 0);
+CCU_GATE_DEFINE(pcied_mstr_clk, CCU_PARENT_HW(pll2_d6), APMU_PCIE_CLK_RES_CTRL_D, BIT(2), 0);
+CCU_GATE_DEFINE(pcied_slv_clk, CCU_PARENT_HW(pll2_d6), APMU_PCIE_CLK_RES_CTRL_D, BIT(1), 0);
+CCU_GATE_DEFINE(pcied_dbi_clk, CCU_PARENT_HW(axi_clk), APMU_PCIE_CLK_RES_CTRL_D, BIT(0), 0);
+CCU_GATE_DEFINE(pciee_mstr_clk, CCU_PARENT_HW(pll2_d6), APMU_PCIE_CLK_RES_CTRL_E, BIT(2), 0);
+CCU_GATE_DEFINE(pciee_slv_clk, CCU_PARENT_HW(pll2_d6), APMU_PCIE_CLK_RES_CTRL_E, BIT(1), 0);
+CCU_GATE_DEFINE(pciee_dbi_clk, CCU_PARENT_HW(axi_clk), APMU_PCIE_CLK_RES_CTRL_E, BIT(0), 0);
static const struct clk_parent_data emac_1588_parents[] = {
CCU_PARENT_NAME(vctcxo_24m),
@@ -1391,14 +1396,19 @@ static struct clk_hw *k3_ccu_apmu_hws[] = {
[CLK_APMU_EDP1_PXCLK] = &edp1_pxclk.common.hw,
[CLK_APMU_PCIE_PORTA_MSTE] = &pciea_mstr_clk.common.hw,
[CLK_APMU_PCIE_PORTA_SLV] = &pciea_slv_clk.common.hw,
+ [CLK_APMU_PCIE_PORTA_DBI] = &pciea_dbi_clk.common.hw,
[CLK_APMU_PCIE_PORTB_MSTE] = &pcieb_mstr_clk.common.hw,
[CLK_APMU_PCIE_PORTB_SLV] = &pcieb_slv_clk.common.hw,
+ [CLK_APMU_PCIE_PORTB_DBI] = &pcieb_dbi_clk.common.hw,
[CLK_APMU_PCIE_PORTC_MSTE] = &pciec_mstr_clk.common.hw,
[CLK_APMU_PCIE_PORTC_SLV] = &pciec_slv_clk.common.hw,
+ [CLK_APMU_PCIE_PORTC_DBI] = &pciec_dbi_clk.common.hw,
[CLK_APMU_PCIE_PORTD_MSTE] = &pcied_mstr_clk.common.hw,
[CLK_APMU_PCIE_PORTD_SLV] = &pcied_slv_clk.common.hw,
+ [CLK_APMU_PCIE_PORTD_DBI] = &pcied_dbi_clk.common.hw,
[CLK_APMU_PCIE_PORTE_MSTE] = &pciee_mstr_clk.common.hw,
[CLK_APMU_PCIE_PORTE_SLV] = &pciee_slv_clk.common.hw,
+ [CLK_APMU_PCIE_PORTE_DBI] = &pciee_dbi_clk.common.hw,
[CLK_APMU_EMAC0_BUS] = &emac0_bus_clk.common.hw,
[CLK_APMU_EMAC0_REF] = &emac0_ref_clk.common.hw,
[CLK_APMU_EMAC0_1588] = &emac0_1588_clk.common.hw,
diff --git a/drivers/clk/visconti/pll.c b/drivers/clk/visconti/pll.c
index 805b95481281..3ce1a906fb0c 100644
--- a/drivers/clk/visconti/pll.c
+++ b/drivers/clk/visconti/pll.c
@@ -21,9 +21,9 @@ struct visconti_pll {
void __iomem *pll_base;
spinlock_t *lock;
unsigned long flags;
- const struct visconti_pll_rate_table *rate_table;
size_t rate_count;
struct visconti_pll_provider *ctx;
+ struct visconti_pll_rate_table rate_table[] __counted_by(rate_count);
};
#define PLL_CONF_REG 0x0000
@@ -255,10 +255,6 @@ static struct clk_hw *visconti_register_pll(struct visconti_pll_provider *ctx,
size_t len;
int ret;
- pll = kzalloc_obj(*pll);
- if (!pll)
- return ERR_PTR(-ENOMEM);
-
init.name = name;
init.flags = CLK_IGNORE_UNUSED;
init.parent_names = &parent_name;
@@ -266,11 +262,13 @@ static struct clk_hw *visconti_register_pll(struct visconti_pll_provider *ctx,
for (len = 0; rate_table[len].rate != 0; )
len++;
+
+ pll = kzalloc_flex(*pll, rate_table, len);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
pll->rate_count = len;
- pll->rate_table = kmemdup_array(rate_table,
- pll->rate_count, sizeof(*pll->rate_table),
- GFP_KERNEL);
- WARN(!pll->rate_table, "%s: could not allocate rate table for %s\n", __func__, name);
+ memcpy(pll->rate_table, rate_table, len * sizeof(*pll->rate_table));
init.ops = &visconti_pll_ops;
pll->hw.init = &init;
@@ -282,7 +280,6 @@ static struct clk_hw *visconti_register_pll(struct visconti_pll_provider *ctx,
ret = clk_hw_register(NULL, &pll->hw);
if (ret) {
pr_err("failed to register pll clock %s : %d\n", name, ret);
- kfree(pll->rate_table);
kfree(pll);
pll_hw_clk = ERR_PTR(ret);
}
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
index 370664c47e65..e355b42043cf 100644
--- a/drivers/cpuidle/driver.c
+++ b/drivers/cpuidle/driver.c
@@ -195,14 +195,6 @@ static void __cpuidle_driver_init(struct cpuidle_driver *drv)
s->exit_latency_ns = 0;
else
s->exit_latency = div_u64(s->exit_latency_ns, NSEC_PER_USEC);
-
- /*
- * Warn if the exit latency of a CPU idle state exceeds its
- * target residency which is assumed to never happen in cpuidle
- * in multiple places.
- */
- if (s->exit_latency_ns > s->target_residency_ns)
- pr_warn("Idle state %d target residency too low\n", i);
}
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
index 9783a3cefb04..da325863ad76 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
@@ -558,7 +558,7 @@ uint32_t amdgpu_amdkfd_get_max_engine_clock_in_mhz(struct amdgpu_device *adev)
int amdgpu_amdkfd_get_dmabuf_info(struct amdgpu_device *adev, int dma_buf_fd,
struct amdgpu_device **dmabuf_adev,
- uint64_t *bo_size, void *metadata_buffer,
+ uint64_t *bo_size, void **metadata_buffer,
size_t buffer_size, uint32_t *metadata_size,
uint32_t *flags, int8_t *xcp_id)
{
@@ -593,9 +593,24 @@ int amdgpu_amdkfd_get_dmabuf_info(struct amdgpu_device *adev, int dma_buf_fd,
*dmabuf_adev = adev;
if (bo_size)
*bo_size = amdgpu_bo_size(bo);
- if (metadata_buffer)
- r = amdgpu_bo_get_metadata(bo, metadata_buffer, buffer_size,
- metadata_size, &metadata_flags);
+ if (metadata_buffer) {
+ /* first get metadata_size by buffer = NULL */
+ r = amdgpu_bo_get_metadata(bo, NULL, 0,
+ metadata_size, NULL);
+
+ /* user buf_size is bigger than bo metadata_size
+ * allocate a buf at kernel space and copy */
+ if (*metadata_size <= buffer_size) {
+ *metadata_buffer = kzalloc(*metadata_size, GFP_KERNEL);
+
+ if (!*metadata_buffer)
+ return -ENOMEM;
+
+ r = amdgpu_bo_get_metadata(bo, *metadata_buffer, *metadata_size,
+ NULL, &metadata_flags);
+ } else
+ r = -EINVAL;
+ }
if (flags) {
*flags = (bo->preferred_domains & AMDGPU_GEM_DOMAIN_VRAM) ?
KFD_IOC_ALLOC_MEM_FLAGS_VRAM
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
index 5333e052d56d..e443a7277299 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
@@ -262,7 +262,7 @@ uint64_t amdgpu_amdkfd_get_gpu_clock_counter(struct amdgpu_device *adev);
uint32_t amdgpu_amdkfd_get_max_engine_clock_in_mhz(struct amdgpu_device *adev);
int amdgpu_amdkfd_get_dmabuf_info(struct amdgpu_device *adev, int dma_buf_fd,
struct amdgpu_device **dmabuf_adev,
- uint64_t *bo_size, void *metadata_buffer,
+ uint64_t *bo_size, void **metadata_buffer,
size_t buffer_size, uint32_t *metadata_size,
uint32_t *flags, int8_t *xcp_id);
int amdgpu_amdkfd_get_pcie_bandwidth_mbytes(struct amdgpu_device *adev, bool is_min);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
index d54794e5b18b..35fe2c974699 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
@@ -1914,13 +1914,6 @@ int amdgpu_amdkfd_gpuvm_free_memory_of_gpu(
mutex_lock(&mem->lock);
- /* Unpin MMIO/DOORBELL BO's that were pinned during allocation */
- if (mem->alloc_flags &
- (KFD_IOC_ALLOC_MEM_FLAGS_DOORBELL |
- KFD_IOC_ALLOC_MEM_FLAGS_MMIO_REMAP)) {
- amdgpu_amdkfd_gpuvm_unpin_bo(mem->bo);
- }
-
mapped_to_gpu_memory = mem->mapped_to_gpu_memory;
is_imported = mem->is_imported;
mutex_unlock(&mem->lock);
@@ -1934,6 +1927,15 @@ int amdgpu_amdkfd_gpuvm_free_memory_of_gpu(
return -EBUSY;
}
+ /* At this point the BO is guaranteed to be freed, so unpin the
+ * MMIO/DOORBELL BOs that were pinned during allocation.
+ */
+ if (mem->alloc_flags &
+ (KFD_IOC_ALLOC_MEM_FLAGS_DOORBELL |
+ KFD_IOC_ALLOC_MEM_FLAGS_MMIO_REMAP)) {
+ amdgpu_amdkfd_gpuvm_unpin_bo(mem->bo);
+ }
+
/* Make sure restore workers don't access the BO any more */
mutex_lock(&process_info->lock);
if (!list_empty(&mem->validate_list))
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index 115b134b4cd1..c2e6495a28bc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -247,13 +247,17 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p,
goto free_partial_kdata;
break;
+ case AMDGPU_CHUNK_ID_CP_GFX_SHADOW:
+ if (size < sizeof(struct drm_amdgpu_cs_chunk_cp_gfx_shadow))
+ goto free_partial_kdata;
+ break;
+
case AMDGPU_CHUNK_ID_DEPENDENCIES:
case AMDGPU_CHUNK_ID_SYNCOBJ_IN:
case AMDGPU_CHUNK_ID_SYNCOBJ_OUT:
case AMDGPU_CHUNK_ID_SCHEDULED_DEPENDENCIES:
case AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_WAIT:
case AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_SIGNAL:
- case AMDGPU_CHUNK_ID_CP_GFX_SHADOW:
break;
default:
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
index 0d7f6cd74f79..ce35b415093d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
@@ -326,7 +326,6 @@ static int amdgpu_ctx_init(struct amdgpu_ctx_mgr *mgr, int32_t priority,
struct drm_file *filp, struct amdgpu_ctx *ctx)
{
struct amdgpu_fpriv *fpriv = filp->driver_priv;
- u32 current_stable_pstate;
int r;
r = amdgpu_ctx_priority_permit(filp, priority);
@@ -344,36 +343,21 @@ static int amdgpu_ctx_init(struct amdgpu_ctx_mgr *mgr, int32_t priority,
ctx->generation = amdgpu_vm_generation(mgr->adev, &fpriv->vm);
ctx->init_priority = priority;
ctx->override_priority = AMDGPU_CTX_PRIORITY_UNSET;
-
- r = amdgpu_ctx_get_stable_pstate(ctx, &current_stable_pstate);
- if (r)
- return r;
-
- if (mgr->adev->pm.stable_pstate_ctx)
- ctx->stable_pstate = mgr->adev->pm.stable_pstate_ctx->stable_pstate;
- else
- ctx->stable_pstate = current_stable_pstate;
+ ctx->stable_pstate = AMDGPU_CTX_STABLE_PSTATE_NONE;
return 0;
}
-static int amdgpu_ctx_set_stable_pstate(struct amdgpu_ctx *ctx,
- u32 stable_pstate)
+static int __amdgpu_ctx_set_stable_pstate(struct amdgpu_ctx *ctx,
+ u32 stable_pstate)
{
struct amdgpu_device *adev = ctx->mgr->adev;
enum amd_dpm_forced_level level;
+ struct amdgpu_ctx *current_ctx;
u32 current_stable_pstate;
- int r;
+ int r = 0;
- mutex_lock(&adev->pm.stable_pstate_ctx_lock);
- if (adev->pm.stable_pstate_ctx && adev->pm.stable_pstate_ctx != ctx) {
- r = -EBUSY;
- goto done;
- }
-
- r = amdgpu_ctx_get_stable_pstate(ctx, &current_stable_pstate);
- if (r || (stable_pstate == current_stable_pstate))
- goto done;
+ lockdep_assert_held(&adev->pm.stable_pstate_ctx_lock);
switch (stable_pstate) {
case AMDGPU_CTX_STABLE_PSTATE_NONE:
@@ -392,17 +376,41 @@ static int amdgpu_ctx_set_stable_pstate(struct amdgpu_ctx *ctx,
level = AMD_DPM_FORCED_LEVEL_PROFILE_PEAK;
break;
default:
- r = -EINVAL;
- goto done;
+ return -EINVAL;
}
+ current_ctx = adev->pm.stable_pstate_ctx;
+ if (current_ctx && current_ctx != ctx)
+ return -EBUSY;
+
+ r = amdgpu_ctx_get_stable_pstate(ctx, &current_stable_pstate);
+ if (r || current_stable_pstate == stable_pstate)
+ return r;
+
r = amdgpu_dpm_force_performance_level(adev, level);
+ if (r)
+ return r;
- if (level == AMD_DPM_FORCED_LEVEL_AUTO)
- adev->pm.stable_pstate_ctx = NULL;
- else
+ if (!current_ctx) {
adev->pm.stable_pstate_ctx = ctx;
-done:
+ /*
+ * Serialized by context taking ownership for the first time
+ * while holding adev->pm.stable_pstate_ctx_lock).
+ */
+ WRITE_ONCE(ctx->stable_pstate, current_stable_pstate);
+ }
+
+ return 0;
+}
+
+static int amdgpu_ctx_set_stable_pstate(struct amdgpu_ctx *ctx,
+ u32 stable_pstate)
+{
+ struct amdgpu_device *adev = ctx->mgr->adev;
+ int r;
+
+ mutex_lock(&adev->pm.stable_pstate_ctx_lock);
+ r = __amdgpu_ctx_set_stable_pstate(ctx, stable_pstate);
mutex_unlock(&adev->pm.stable_pstate_ctx_lock);
return r;
@@ -428,7 +436,12 @@ static void amdgpu_ctx_fini(struct kref *ref)
}
if (drm_dev_enter(adev_to_drm(adev), &idx)) {
- amdgpu_ctx_set_stable_pstate(ctx, ctx->stable_pstate);
+ mutex_lock(&adev->pm.stable_pstate_ctx_lock);
+ if (adev->pm.stable_pstate_ctx == ctx) {
+ __amdgpu_ctx_set_stable_pstate(ctx, ctx->stable_pstate);
+ adev->pm.stable_pstate_ctx = NULL;
+ }
+ mutex_unlock(&adev->pm.stable_pstate_ctx_lock);
drm_dev_exit(idx);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
index 27830518a230..e77db76b48b8 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c
@@ -22,8 +22,9 @@
*
*/
-#include <generated/utsrelease.h>
#include <linux/devcoredump.h>
+#include <linux/utsname.h>
+#include <drm/drm_exec.h>
#include "amdgpu_dev_coredump.h"
#include "atom.h"
@@ -207,28 +208,143 @@ static void amdgpu_devcoredump_fw_info(struct amdgpu_device *adev,
}
}
+static void
+amdgpu_devcoredump_print_ibs(struct drm_printer *p,
+ struct amdgpu_coredump_info *coredump,
+ bool sizing_pass)
+{
+ struct amdgpu_device *adev = coredump->adev;
+ struct amdgpu_bo_va_mapping *mapping;
+ struct amdgpu_bo *abo;
+ struct drm_exec exec;
+ struct amdgpu_vm *vm;
+ u32 *ib_content;
+ u64 va_start, offset;
+ u8 *kptr;
+ u32 off;
+ int r;
+
+ /*
+ * On the sizing pass there is no VM to look up and no BO to lock; the
+ * size estimate doesn't depend on whether the IB BOs are reachable.
+ * Just emit the per-IB headers (the content is not written anywhere).
+ */
+ if (sizing_pass) {
+ for (int i = 0; i < coredump->num_ibs; i++) {
+ drm_printf(p, "\nIB #%d 0x%llx %d dw\n", i,
+ coredump->ibs[i].gpu_addr,
+ coredump->ibs[i].ib_size_dw);
+ }
+ return;
+ }
+
+ /*
+ * Lock the VM root PD and every IB BO together in a single drm_exec
+ * ticket. Reserving the IB BOs one by one while the root PD is held
+ * would be a recursive reservation_ww_class_mutex acquire without a
+ * ww_acquire_ctx, which trips lockdep and self-deadlocks for IB BOs
+ * that share their dma_resv with the root PD (always-valid BOs).
+ */
+ drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES, 1 + coredump->num_ibs);
+ drm_exec_until_all_locked(&exec) {
+ vm = amdgpu_vm_lock_by_pasid(adev, coredump->pasid, &exec);
+ if (!vm)
+ goto unlock;
+
+ for (int i = 0; i < coredump->num_ibs; i++) {
+ u64 pfn = (coredump->ibs[i].gpu_addr &
+ AMDGPU_GMC_HOLE_MASK) / AMDGPU_GPU_PAGE_SIZE;
+
+ mapping = amdgpu_vm_bo_lookup_mapping(vm, pfn);
+ if (!mapping)
+ continue;
+
+ abo = mapping->bo_va->base.bo;
+ r = drm_exec_lock_obj(&exec, &abo->tbo.base);
+ drm_exec_retry_on_contention(&exec);
+ if (r)
+ goto unlock;
+ }
+ }
+
+ for (int i = 0; i < coredump->num_ibs; i++) {
+ bool emit_content = false;
+
+ ib_content = kvmalloc_array(coredump->ibs[i].ib_size_dw, 4,
+ GFP_KERNEL);
+ if (!ib_content)
+ continue;
+
+ va_start = coredump->ibs[i].gpu_addr & AMDGPU_GMC_HOLE_MASK;
+ mapping = amdgpu_vm_bo_lookup_mapping(vm,
+ va_start / AMDGPU_GPU_PAGE_SIZE);
+ if (!mapping)
+ goto output_ib_content;
+
+ abo = mapping->bo_va->base.bo;
+ offset = va_start - mapping->start * AMDGPU_GPU_PAGE_SIZE;
+
+ if (abo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) {
+ struct amdgpu_res_cursor cursor;
+
+ off = 0;
+
+ if (abo->tbo.resource->mem_type != TTM_PL_VRAM)
+ goto output_ib_content;
+
+ amdgpu_res_first(abo->tbo.resource, offset,
+ coredump->ibs[i].ib_size_dw * 4, &cursor);
+ while (cursor.remaining) {
+ amdgpu_device_mm_access(adev, cursor.start / 4,
+ &ib_content[off], cursor.size / 4,
+ false);
+ off += cursor.size;
+ amdgpu_res_next(&cursor, cursor.size);
+ }
+ emit_content = true;
+ } else {
+ r = ttm_bo_kmap(&abo->tbo, 0, PFN_UP(abo->tbo.base.size),
+ &abo->kmap);
+ if (r)
+ goto output_ib_content;
+
+ kptr = amdgpu_bo_kptr(abo);
+ kptr += offset;
+ memcpy(ib_content, kptr, coredump->ibs[i].ib_size_dw * 4);
+
+ amdgpu_bo_kunmap(abo);
+ emit_content = true;
+ }
+
+output_ib_content:
+ drm_printf(p, "\nIB #%d 0x%llx %d dw\n", i,
+ coredump->ibs[i].gpu_addr, coredump->ibs[i].ib_size_dw);
+ if (emit_content) {
+ for (int j = 0; j < coredump->ibs[i].ib_size_dw; j++)
+ drm_printf(p, "0x%08x\n", ib_content[j]);
+ }
+ kvfree(ib_content);
+ }
+
+unlock:
+ drm_exec_fini(&exec);
+}
+
static ssize_t
amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_info *coredump)
{
- struct amdgpu_device *adev = coredump->adev;
struct drm_printer p;
struct drm_print_iterator iter;
struct amdgpu_vm_fault_info *fault_info;
- struct amdgpu_bo_va_mapping *mapping;
struct amdgpu_ip_block *ip_block;
- struct amdgpu_res_cursor cursor;
- struct amdgpu_bo *abo, *root;
- uint64_t va_start, offset;
struct amdgpu_ring *ring;
- struct amdgpu_vm *vm;
- u32 *ib_content;
- uint8_t *kptr;
- int ver, i, j, r;
+ int ver, i, j;
u32 ring_idx, off;
bool sizing_pass;
sizing_pass = buffer == NULL;
iter.data = buffer;
+ iter.start = 0;
iter.offset = 0;
iter.remain = count;
@@ -236,7 +352,7 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf
drm_printf(&p, "**** AMDGPU Device Coredump ****\n");
drm_printf(&p, "version: " AMDGPU_COREDUMP_VERSION "\n");
- drm_printf(&p, "kernel: " UTS_RELEASE "\n");
+ drm_printf(&p, "kernel: %s\n", init_utsname()->release);
drm_printf(&p, "module: " KBUILD_MODNAME "\n");
drm_printf(&p, "time: %ptSp\n", &coredump->reset_time);
@@ -342,86 +458,8 @@ amdgpu_devcoredump_format(char *buffer, size_t count, struct amdgpu_coredump_inf
else if (coredump->reset_vram_lost)
drm_printf(&p, "VRAM is lost due to GPU reset!\n");
- if (coredump->num_ibs) {
- /* Don't try to lookup the VM or map the BOs when calculating the
- * size required to store the devcoredump.
- */
- if (sizing_pass)
- vm = NULL;
- else
- vm = amdgpu_vm_lock_by_pasid(adev, &root, coredump->pasid);
-
- for (int i = 0; i < coredump->num_ibs && (sizing_pass || vm); i++) {
- ib_content = kvmalloc_array(coredump->ibs[i].ib_size_dw, 4,
- GFP_KERNEL);
- if (!ib_content)
- continue;
-
- /* vm=NULL can only happen when 'sizing_pass' is true. Skip to the
- * drm_printf() calls (ib_content doesn't need to be initialized
- * as its content won't be written anywhere).
- */
- if (!vm)
- goto output_ib_content;
-
- va_start = coredump->ibs[i].gpu_addr & AMDGPU_GMC_HOLE_MASK;
- mapping = amdgpu_vm_bo_lookup_mapping(vm, va_start / AMDGPU_GPU_PAGE_SIZE);
- if (!mapping)
- goto free_ib_content;
-
- offset = va_start - (mapping->start * AMDGPU_GPU_PAGE_SIZE);
- abo = amdgpu_bo_ref(mapping->bo_va->base.bo);
- r = amdgpu_bo_reserve(abo, false);
- if (r)
- goto free_ib_content;
-
- if (abo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) {
- off = 0;
-
- if (abo->tbo.resource->mem_type != TTM_PL_VRAM)
- goto unreserve_abo;
-
- amdgpu_res_first(abo->tbo.resource, offset,
- coredump->ibs[i].ib_size_dw * 4,
- &cursor);
- while (cursor.remaining) {
- amdgpu_device_mm_access(adev, cursor.start / 4,
- &ib_content[off], cursor.size / 4,
- false);
- off += cursor.size;
- amdgpu_res_next(&cursor, cursor.size);
- }
- } else {
- r = ttm_bo_kmap(&abo->tbo, 0,
- PFN_UP(abo->tbo.base.size),
- &abo->kmap);
- if (r)
- goto unreserve_abo;
-
- kptr = amdgpu_bo_kptr(abo);
- kptr += offset;
- memcpy(ib_content, kptr,
- coredump->ibs[i].ib_size_dw * 4);
-
- amdgpu_bo_kunmap(abo);
- }
-
-output_ib_content:
- drm_printf(&p, "\nIB #%d 0x%llx %d dw\n",
- i, coredump->ibs[i].gpu_addr, coredump->ibs[i].ib_size_dw);
- for (int j = 0; j < coredump->ibs[i].ib_size_dw; j++)
- drm_printf(&p, "0x%08x\n", ib_content[j]);
-unreserve_abo:
- if (vm)
- amdgpu_bo_unreserve(abo);
-free_ib_content:
- kvfree(ib_content);
- }
- if (vm) {
- amdgpu_bo_unreserve(root);
- amdgpu_bo_unref(&root);
- }
- }
+ if (coredump->num_ibs)
+ amdgpu_devcoredump_print_ibs(&p, coredump, sizing_pass);
return count - iter.remain;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index 942f0251c748..211d30f03d25 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -3043,7 +3043,7 @@ static int amdgpu_device_ip_suspend_phase2(struct amdgpu_device *adev)
amdgpu_dpm_gfx_state_change(adev, sGpuChangeState_D3Entry);
for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
- if (!adev->ip_blocks[i].status.valid)
+ if (!adev->ip_blocks[i].status.valid || !adev->ip_blocks[i].status.hw)
continue;
/* displays are handled in phase1 */
if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE)
@@ -3771,6 +3771,8 @@ int amdgpu_device_init(struct amdgpu_device *adev,
mutex_init(&adev->gfx.workload_profile_mutex);
mutex_init(&adev->vcn.workload_profile_mutex);
+ spin_lock_init(&adev->irq.lock);
+
amdgpu_device_init_apu_flags(adev);
r = amdgpu_device_check_arguments(adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
index 212c14d99f6b..76da3f932f24 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -1094,6 +1094,11 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data,
* If that number is larger than the size of the array, the ioctl must
* be retried.
*/
+ if (!bo_va) {
+ r = -ENOENT;
+ goto out_exec;
+ }
+
if (args->num_entries > INT_MAX / sizeof(*vm_entries)) {
r = -EINVAL;
goto out_exec;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
index 1e190fb54a97..85372af1216d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
@@ -1664,12 +1664,13 @@ static int amdgpu_gfx_run_cleaner_shader_job(struct amdgpu_ring *ring)
struct amdgpu_device *adev = ring->adev;
struct drm_gpu_scheduler *sched = &ring->sched;
struct drm_sched_entity entity;
+ unsigned int ib_size_dw = 16;
static atomic_t counter;
struct dma_fence *f;
struct amdgpu_job *job;
struct amdgpu_ib *ib;
void *owner;
- int i, r;
+ int r;
/* Initialize the scheduler entity */
r = drm_sched_entity_init(&entity, DRM_SCHED_PRIORITY_NORMAL,
@@ -1687,7 +1688,7 @@ static int amdgpu_gfx_run_cleaner_shader_job(struct amdgpu_ring *ring)
owner = (void *)(unsigned long)atomic_inc_return(&counter);
r = amdgpu_job_alloc_with_ib(ring->adev, &entity, owner,
- 64, 0, &job,
+ ib_size_dw * sizeof(uint32_t), 0, &job,
AMDGPU_KERNEL_JOB_ID_CLEANER_SHADER);
if (r)
goto err;
@@ -1697,9 +1698,8 @@ static int amdgpu_gfx_run_cleaner_shader_job(struct amdgpu_ring *ring)
job->run_cleaner_shader = true;
ib = &job->ibs[0];
- for (i = 0; i <= ring->funcs->align_mask; ++i)
- ib->ptr[i] = ring->funcs->nop;
- ib->length_dw = ring->funcs->align_mask + 1;
+ memset32(ib->ptr, ring->funcs->nop, ib_size_dw);
+ ib->length_dw = ib_size_dw;
f = amdgpu_job_submit(job);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
index d23a91d029aa..0ea32561c4bc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
@@ -272,7 +272,20 @@ static bool amdgpu_gtt_mgr_intersects(struct ttm_resource_manager *man,
const struct ttm_place *place,
size_t size)
{
- return !place->lpfn || amdgpu_gtt_mgr_has_gart_addr(res);
+ const struct drm_mm_node *const node = &to_ttm_range_mgr_node(res)->mm_nodes[0];
+ const u32 num_pages = PFN_UP(size);
+
+ if (!place->lpfn)
+ return true;
+
+ if (!amdgpu_gtt_mgr_has_gart_addr(res))
+ return false;
+
+ if (place->fpfn >= (node->start + num_pages) ||
+ (place->lpfn && place->lpfn <= node->start))
+ return false;
+
+ return true;
}
/**
@@ -290,7 +303,20 @@ static bool amdgpu_gtt_mgr_compatible(struct ttm_resource_manager *man,
const struct ttm_place *place,
size_t size)
{
- return !place->lpfn || amdgpu_gtt_mgr_has_gart_addr(res);
+ const struct drm_mm_node *const node = &to_ttm_range_mgr_node(res)->mm_nodes[0];
+ const u32 num_pages = PFN_UP(size);
+
+ if (!place->lpfn)
+ return true;
+
+ if (!amdgpu_gtt_mgr_has_gart_addr(res))
+ return false;
+
+ if (node->start < place->fpfn ||
+ (place->lpfn && (node->start + num_pages) > place->lpfn))
+ return false;
+
+ return true;
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
index 254a4e983f40..53be764968e4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
@@ -309,8 +309,6 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
unsigned int irq, flags;
int r;
- spin_lock_init(&adev->irq.lock);
-
/* Enable MSI if not disabled by module parameter */
adev->irq.msi_enabled = false;
@@ -547,7 +545,7 @@ void amdgpu_irq_delegate(struct amdgpu_device *adev,
unsigned int num_dw)
{
amdgpu_ih_ring_write(adev, &adev->irq.ih_soft, entry->iv_entry, num_dw);
- schedule_work(&adev->irq.ih_soft_work);
+ queue_work(system_unbound_wq, &adev->irq.ih_soft_work);
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_lockdep.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_lockdep.c
index d5d71fd7c70d..61450af539a6 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_lockdep.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_lockdep.c
@@ -16,6 +16,17 @@
#ifdef CONFIG_LOCKDEP
+struct amdgpu_lockdep_dummy_locks {
+ struct mutex reset_lock;
+ struct mutex userq_sch_mutex;
+ struct mutex userq_mutex;
+ struct mutex notifier_lock;
+ struct mutex vram_lock;
+ struct mutex srbm_mutex;
+ struct mutex grbm_idx_mutex;
+ spinlock_t mmio_idx_lock;
+};
+
/* Lock class keys for associating with real driver locks */
static struct lock_class_key amdgpu_userq_sch_mutex_key;
static struct lock_class_key amdgpu_userq_mutex_key;
@@ -84,72 +95,65 @@ void amdgpu_lockdep_set_class(struct amdgpu_device *adev)
int amdgpu_lockdep_init(void)
{
struct amdgpu_reset_domain *reset_domain = NULL;
- struct amdgpu_reset_control reset_ctl;
- struct mutex userq_sch_mutex;
- struct mutex userq_mutex;
- struct mutex notifier_lock;
- struct mutex vram_lock;
- struct mutex srbm_mutex;
- struct mutex grbm_idx_mutex;
- spinlock_t mmio_idx_lock;
+ struct amdgpu_lockdep_dummy_locks *locks;
unsigned long flags;
+ locks = kzalloc(sizeof(*locks), GFP_KERNEL);
+ if (!locks)
+ return -ENOMEM;
+
/*
* Initialize dummy reset domain
*/
reset_domain = amdgpu_reset_create_reset_domain(SINGLE_DEVICE,
"lockdep_test");
- if (!reset_domain)
+ if (!reset_domain) {
+ kfree(locks);
return -ENOMEM;
-
+ }
/* Initialize dummy locks */
- mutex_init(&userq_sch_mutex);
- mutex_init(&userq_mutex);
- mutex_init(&notifier_lock);
- mutex_init(&vram_lock);
- mutex_init(&reset_ctl.reset_lock);
- mutex_init(&srbm_mutex);
- mutex_init(&grbm_idx_mutex);
- spin_lock_init(&mmio_idx_lock);
+ mutex_init(&locks->userq_sch_mutex);
+ mutex_init(&locks->userq_mutex);
+ mutex_init(&locks->notifier_lock);
+ mutex_init(&locks->vram_lock);
+ mutex_init(&locks->reset_lock);
+ mutex_init(&locks->srbm_mutex);
+ mutex_init(&locks->grbm_idx_mutex);
+ spin_lock_init(&locks->mmio_idx_lock);
/*
* Associate dummy locks with the same class keys used for real
* driver locks. This ensures lockdep connects the ordering learned
* here with the actual locks used at runtime.
*/
- lockdep_set_class(&userq_sch_mutex, &amdgpu_userq_sch_mutex_key);
- lockdep_set_class(&userq_mutex, &amdgpu_userq_mutex_key);
- lockdep_set_class(&notifier_lock, &amdgpu_notifier_lock_key);
- lockdep_set_class(&vram_lock, &amdgpu_vram_lock_key);
+ lockdep_set_class(&locks->userq_sch_mutex, &amdgpu_userq_sch_mutex_key);
+ lockdep_set_class(&locks->userq_mutex, &amdgpu_userq_mutex_key);
+ lockdep_set_class(&locks->notifier_lock, &amdgpu_notifier_lock_key);
+ lockdep_set_class(&locks->vram_lock, &amdgpu_vram_lock_key);
lockdep_set_class(&reset_domain->sem, &amdgpu_reset_sem_key);
- lockdep_set_class(&reset_ctl.reset_lock, &amdgpu_reset_lock_key);
- lockdep_set_class(&srbm_mutex, &amdgpu_srbm_lock_key);
- lockdep_set_class(&grbm_idx_mutex, &amdgpu_grbm_lock_key);
- lockdep_set_class(&mmio_idx_lock, &amdgpu_mmio_lock_key);
-
+ lockdep_set_class(&locks->reset_lock, &amdgpu_reset_lock_key);
+ lockdep_set_class(&locks->srbm_mutex, &amdgpu_srbm_lock_key);
+ lockdep_set_class(&locks->grbm_idx_mutex, &amdgpu_grbm_lock_key);
+ lockdep_set_class(&locks->mmio_idx_lock, &amdgpu_mmio_lock_key);
/*
* Take locks in the correct order to train lockdep.
* This establishes the dependency chain.
*/
/* Level 1: Global userq scheduler mutex (outermost) */
- mutex_lock(&userq_sch_mutex);
+ mutex_lock(&locks->userq_sch_mutex);
/* Level 2: Per-context userq mutex */
- mutex_lock(&userq_mutex);
-
+ mutex_lock(&locks->userq_mutex);
/* Level 3: MMU notifier lock */
- mutex_lock(&notifier_lock);
-
+ mutex_lock(&locks->notifier_lock);
/* Level 4: VRAM allocator lock */
- mutex_lock(&vram_lock);
-
+ mutex_lock(&locks->vram_lock);
/* Level 5: Reset domain semaphore */
down_read(&reset_domain->sem);
/* Level 6: Reset control lock */
- mutex_lock(&reset_ctl.reset_lock);
-
+ mutex_lock(&locks->reset_lock);
/*
* Mark potential memory reclaim boundary.
* GPU operations might trigger memory allocation/reclaim.
@@ -157,36 +161,35 @@ int amdgpu_lockdep_init(void)
fs_reclaim_acquire(GFP_KERNEL);
/* Level 7: SRBM register access */
- mutex_lock(&srbm_mutex);
-
+ mutex_lock(&locks->srbm_mutex);
/* Level 8: GRBM index access */
- mutex_lock(&grbm_idx_mutex);
+ mutex_lock(&locks->grbm_idx_mutex);
/* Level 9: MMIO index access (innermost lock, spinlock) */
- spin_lock_irqsave(&mmio_idx_lock, flags);
-
+ spin_lock_irqsave(&locks->mmio_idx_lock, flags);
/*
* All locks acquired in order.
* Lockdep has now learned the valid dependency chain.
*/
/* Release in reverse order */
- spin_unlock_irqrestore(&mmio_idx_lock, flags);
- mutex_unlock(&grbm_idx_mutex);
- mutex_unlock(&srbm_mutex);
-
+ spin_unlock_irqrestore(&locks->mmio_idx_lock, flags);
+ mutex_unlock(&locks->grbm_idx_mutex);
+ mutex_unlock(&locks->srbm_mutex);
fs_reclaim_release(GFP_KERNEL);
- mutex_unlock(&reset_ctl.reset_lock);
+ mutex_unlock(&locks->reset_lock);
up_read(&reset_domain->sem);
- mutex_unlock(&vram_lock);
- mutex_unlock(&notifier_lock);
- mutex_unlock(&userq_mutex);
- mutex_unlock(&userq_sch_mutex);
+
+ mutex_unlock(&locks->vram_lock);
+ mutex_unlock(&locks->notifier_lock);
+ mutex_unlock(&locks->userq_mutex);
+ mutex_unlock(&locks->userq_sch_mutex);
/* Cleanup */
amdgpu_reset_put_reset_domain(reset_domain);
+ kfree(locks);
pr_info("AMDGPU: Lockdep annotations initialized (9 lock levels)\n");
return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index 2740de94e93c..16c060badaee 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -515,6 +515,15 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
if (new_mem->mem_type == TTM_PL_TT ||
new_mem->mem_type == AMDGPU_PL_PREEMPT) {
+ if (old_mem && (old_mem->mem_type == TTM_PL_TT ||
+ old_mem->mem_type == AMDGPU_PL_PREEMPT)) {
+ r = ttm_bo_wait_ctx(bo, ctx);
+ if (r)
+ return r;
+
+ amdgpu_ttm_backend_unbind(bo->bdev, bo->ttm);
+ }
+
r = amdgpu_ttm_backend_bind(bo->bdev, bo->ttm, new_mem);
if (r)
return r;
@@ -549,6 +558,15 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
ttm_bo_assign_mem(bo, new_mem);
return 0;
}
+ if ((old_mem->mem_type == TTM_PL_TT ||
+ old_mem->mem_type == AMDGPU_PL_PREEMPT) &&
+ (new_mem->mem_type == TTM_PL_TT ||
+ new_mem->mem_type == AMDGPU_PL_PREEMPT)) {
+ amdgpu_bo_move_notify(bo, evict, new_mem);
+ ttm_resource_free(bo, &bo->resource);
+ ttm_bo_assign_mem(bo, new_mem);
+ return 0;
+ }
if (old_mem->mem_type == AMDGPU_PL_GDS ||
old_mem->mem_type == AMDGPU_PL_GWS ||
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
index 3a3bc0d370fa..480bf88def46 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
@@ -135,7 +135,7 @@ MODULE_FIRMWARE(FIRMWARE_VEGA12);
MODULE_FIRMWARE(FIRMWARE_VEGA20);
static void amdgpu_uvd_idle_work_handler(struct work_struct *work);
-static void amdgpu_uvd_force_into_uvd_segment(struct amdgpu_bo *abo);
+static void amdgpu_uvd_force_into_vcpu_segment(struct amdgpu_bo *abo);
static int amdgpu_uvd_create_msg_bo_helper(struct amdgpu_device *adev,
uint32_t size,
@@ -158,7 +158,7 @@ static int amdgpu_uvd_create_msg_bo_helper(struct amdgpu_device *adev,
amdgpu_bo_kunmap(bo);
amdgpu_bo_unpin(bo);
amdgpu_bo_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_VRAM);
- amdgpu_uvd_force_into_uvd_segment(bo);
+ amdgpu_uvd_force_into_vcpu_segment(bo);
r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
if (r)
goto err;
@@ -188,6 +188,7 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
const struct common_firmware_header *hdr;
unsigned int family_id;
int i, j, r;
+ u32 vcpu_bo_domain;
INIT_DELAYED_WORK(&adev->uvd.idle_work, amdgpu_uvd_idle_work_handler);
@@ -319,12 +320,20 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
bo_size += AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8);
+ /* UVD 5.0 and newer HW can use 64 bit addressing. */
+ adev->uvd.address_64_bit =
+ !amdgpu_device_ip_block_version_cmp(adev, AMD_IP_BLOCK_TYPE_UVD, 5, 0);
+
+ vcpu_bo_domain = AMDGPU_GEM_DOMAIN_VRAM;
+ if (adev->uvd.address_64_bit)
+ vcpu_bo_domain |= AMDGPU_GEM_DOMAIN_GTT;
+
for (j = 0; j < adev->uvd.num_uvd_inst; j++) {
if (adev->uvd.harvest_config & (1 << j))
continue;
+
r = amdgpu_bo_create_kernel(adev, bo_size, PAGE_SIZE,
- AMDGPU_GEM_DOMAIN_VRAM |
- AMDGPU_GEM_DOMAIN_GTT,
+ vcpu_bo_domain,
&adev->uvd.inst[j].vcpu_bo,
&adev->uvd.inst[j].gpu_addr,
&adev->uvd.inst[j].cpu_addr);
@@ -339,10 +348,6 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
adev->uvd.filp[i] = NULL;
}
- /* from uvd v5.0 HW addressing capacity increased to 64 bits */
- if (!amdgpu_device_ip_block_version_cmp(adev, AMD_IP_BLOCK_TYPE_UVD, 5, 0))
- adev->uvd.address_64_bit = true;
-
r = amdgpu_uvd_create_msg_bo_helper(adev, 128 << 10, &adev->uvd.ib_bo);
if (r)
return r;
@@ -545,6 +550,24 @@ void amdgpu_uvd_free_handles(struct amdgpu_device *adev, struct drm_file *filp)
}
}
+static void amdgpu_uvd_force_into_vcpu_segment(struct amdgpu_bo *bo)
+{
+ struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
+ struct amdgpu_bo *vcpu_bo = adev->uvd.inst[0].vcpu_bo;
+ struct amdgpu_res_cursor vcpu_cur;
+
+ amdgpu_res_first(vcpu_bo->tbo.resource, 0,
+ amdgpu_bo_size(vcpu_bo), &vcpu_cur);
+
+ bo->placement.num_placement = 1;
+ bo->placement.placement = &bo->placements[0];
+ bo->placements[0].fpfn = ALIGN_DOWN(vcpu_cur.start, SZ_256M) >> PAGE_SHIFT;
+ bo->placements[0].lpfn = bo->placements[0].fpfn + (SZ_256M >> PAGE_SHIFT);
+ bo->placements[0].mem_type = vcpu_bo->tbo.resource->mem_type;
+ if (bo->placements[0].mem_type == TTM_PL_VRAM)
+ bo->placements[0].flags |= TTM_PL_FLAG_CONTIGUOUS;
+}
+
static void amdgpu_uvd_force_into_uvd_segment(struct amdgpu_bo *abo)
{
int i;
@@ -595,13 +618,10 @@ static int amdgpu_uvd_cs_pass1(struct amdgpu_uvd_cs_ctx *ctx)
if (!ctx->parser->adev->uvd.address_64_bit) {
/* check if it's a message or feedback command */
cmd = amdgpu_ib_get_value(ctx->ib, ctx->idx) >> 1;
- if (cmd == 0x0 || cmd == 0x3) {
- /* yes, force it into VRAM */
- uint32_t domain = AMDGPU_GEM_DOMAIN_VRAM;
-
- amdgpu_bo_placement_from_domain(bo, domain);
- }
- amdgpu_uvd_force_into_uvd_segment(bo);
+ if (cmd == 0x0 || cmd == 0x3)
+ amdgpu_uvd_force_into_vcpu_segment(bo);
+ else
+ amdgpu_uvd_force_into_uvd_segment(bo);
r = ttm_bo_validate(&bo->tbo, &bo->placement, &tctx);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index 7d51880b4860..fee4c94c2585 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -2920,47 +2920,56 @@ int amdgpu_vm_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
}
/**
- * amdgpu_vm_lock_by_pasid - return an amdgpu_vm and its root bo from a pasid, if possible.
+ * amdgpu_vm_lock_by_pasid - look up a VM by PASID and lock its root PD
* @adev: amdgpu device pointer
- * @root: root BO of the VM
* @pasid: PASID of the VM
- * The caller needs to unreserve and unref the root bo on success.
+ * @exec: drm_exec context to lock the root PD in
+ *
+ * Must be called from within a drm_exec_until_all_locked() loop; the caller
+ * runs drm_exec_retry_on_contention() afterwards. The drm_exec context holds
+ * a reference on the root BO until it is finalised.
+ *
+ * Return: the VM on success, or NULL if the PASID has no VM, the VM is being
+ * torn down, or locking the root PD failed.
*/
struct amdgpu_vm *amdgpu_vm_lock_by_pasid(struct amdgpu_device *adev,
- struct amdgpu_bo **root, u32 pasid)
+ u32 pasid, struct drm_exec *exec)
{
unsigned long irqflags;
+ struct amdgpu_bo *root;
struct amdgpu_vm *vm;
int r;
xa_lock_irqsave(&adev->vm_manager.pasids, irqflags);
vm = xa_load(&adev->vm_manager.pasids, pasid);
- *root = vm ? amdgpu_bo_ref(vm->root.bo) : NULL;
+ root = vm ? amdgpu_bo_ref(vm->root.bo) : NULL;
xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags);
- if (!*root)
+ if (!root)
return NULL;
- r = amdgpu_bo_reserve(*root, true);
- if (r)
- goto error_unref;
+ r = drm_exec_lock_obj(exec, &root->tbo.base);
+ if (r) {
+ amdgpu_bo_unref(&root);
+ return NULL;
+ }
/* Double check that the VM still exists */
xa_lock_irqsave(&adev->vm_manager.pasids, irqflags);
vm = xa_load(&adev->vm_manager.pasids, pasid);
- if (vm && vm->root.bo != *root)
+ if (vm && vm->root.bo != root)
vm = NULL;
xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags);
- if (!vm)
- goto error_unlock;
+ if (!vm) {
+ drm_exec_unlock_obj(exec, &root->tbo.base);
+ amdgpu_bo_unref(&root);
+ return NULL;
+ }
- return vm;
-error_unlock:
- amdgpu_bo_unreserve(*root);
+ /* The drm_exec context holds its own reference on the root BO. */
+ amdgpu_bo_unref(&root);
-error_unref:
- amdgpu_bo_unref(root);
- return NULL;
+ return vm;
}
/**
@@ -2982,33 +2991,49 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
uint64_t ts, bool write_fault)
{
bool is_compute_context = false;
- struct amdgpu_bo *root;
+ struct drm_exec exec;
uint64_t value, flags;
struct amdgpu_vm *vm;
int r;
- vm = amdgpu_vm_lock_by_pasid(adev, &root, pasid);
- if (!vm)
+ drm_exec_init(&exec, 0, 1);
+ drm_exec_until_all_locked(&exec) {
+ vm = amdgpu_vm_lock_by_pasid(adev, pasid, &exec);
+ drm_exec_retry_on_contention(&exec);
+ if (!vm)
+ break;
+ }
+ if (!vm) {
+ drm_exec_fini(&exec);
return false;
+ }
is_compute_context = vm->is_compute_context;
if (is_compute_context) {
- /* Unreserve root since svm_range_restore_pages might try to reserve it. */
- /* TODO: rework svm_range_restore_pages so that this isn't necessary. */
- amdgpu_bo_unreserve(root);
+ /* Release the root PD lock since svm_range_restore_pages
+ * might try to take it.
+ * TODO: rework svm_range_restore_pages so that this isn't
+ * necessary.
+ */
+ drm_exec_fini(&exec);
if (!svm_range_restore_pages(adev, pasid, vmid,
- node_id, addr >> PAGE_SHIFT, ts, write_fault)) {
- amdgpu_bo_unref(&root);
+ node_id, addr >> PAGE_SHIFT, ts, write_fault))
return true;
- }
- amdgpu_bo_unref(&root);
/* Re-acquire the VM lock, could be that the VM was freed in between. */
- vm = amdgpu_vm_lock_by_pasid(adev, &root, pasid);
- if (!vm)
+ drm_exec_init(&exec, 0, 1);
+ drm_exec_until_all_locked(&exec) {
+ vm = amdgpu_vm_lock_by_pasid(adev, pasid, &exec);
+ drm_exec_retry_on_contention(&exec);
+ if (!vm)
+ break;
+ }
+ if (!vm) {
+ drm_exec_fini(&exec);
return false;
+ }
}
addr /= AMDGPU_GPU_PAGE_SIZE;
@@ -3032,7 +3057,7 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
value = 0;
}
- r = dma_resv_reserve_fences(root->tbo.base.resv, 1);
+ r = dma_resv_reserve_fences(vm->root.bo->tbo.base.resv, 1);
if (r) {
pr_debug("failed %d to reserve fence slot\n", r);
goto error_unlock;
@@ -3046,12 +3071,10 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
r = amdgpu_vm_update_pdes(adev, vm, true);
error_unlock:
- amdgpu_bo_unreserve(root);
+ drm_exec_fini(&exec);
if (r < 0)
dev_err(adev->dev, "Can't handle page fault (%d)\n", r);
- amdgpu_bo_unref(&root);
-
return false;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
index 3695299f1a03..b32f51a78cd8 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h
@@ -592,7 +592,7 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid,
bool write_fault);
struct amdgpu_vm *amdgpu_vm_lock_by_pasid(struct amdgpu_device *adev,
- struct amdgpu_bo **root, u32 pasid);
+ u32 pasid, struct drm_exec *exec);
void amdgpu_vm_set_task_info(struct amdgpu_vm *vm);
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
index 47721d0c3781..81a759a98725 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
@@ -4071,6 +4071,41 @@ err_priv_inst:
return r;
}
+static void gfx_v9_0_deactivate_kcq_hqd(struct amdgpu_device *adev)
+{
+ amdgpu_gfx_rlc_enter_safe_mode(adev, 0);
+ for (int i = 0; i < adev->gfx.num_compute_rings; i++) {
+ u32 tmp;
+ struct amdgpu_ring *ring = &adev->gfx.compute_ring[i];
+
+ mutex_lock(&adev->srbm_mutex);
+ soc15_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0, 0);
+ tmp = RREG32_SOC15(GC, 0, mmCP_HQD_ACTIVE);
+ /* disable the queue if it's active */
+ if (tmp & CP_HQD_ACTIVE__ACTIVE_MASK) {
+ int j;
+
+ WREG32_SOC15(GC, 0, mmCP_HQD_DEQUEUE_REQUEST, 1);
+ for (j = 0; j < adev->usec_timeout; j++) {
+ tmp = RREG32_SOC15(GC, 0, mmCP_HQD_ACTIVE);
+ if (!(tmp & CP_HQD_ACTIVE__ACTIVE_MASK))
+ break;
+ udelay(1);
+ }
+ if (j == AMDGPU_MAX_USEC_TIMEOUT) {
+ DRM_DEBUG("comp_%u_%u_%u dequeue request failed.\n",
+ ring->me, ring->pipe, ring->queue);
+ /* Manual disable if dequeue request times out */
+ WREG32_SOC15(GC, 0, mmCP_HQD_ACTIVE, 0);
+ }
+ WREG32_SOC15(GC, 0, mmCP_HQD_DEQUEUE_REQUEST, 0);
+ }
+ soc15_grbm_select(adev, 0, 0, 0, 0, 0);
+ mutex_unlock(&adev->srbm_mutex);
+ }
+ amdgpu_gfx_rlc_exit_safe_mode(adev, 0);
+}
+
static int gfx_v9_0_hw_fini(struct amdgpu_ip_block *ip_block)
{
struct amdgpu_device *adev = ip_block->adev;
@@ -4095,6 +4130,10 @@ static int gfx_v9_0_hw_fini(struct amdgpu_ip_block *ip_block)
return 0;
}
+ if ((adev->flags & AMD_IS_APU) && amdgpu_in_reset(adev) &&
+ amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_MODE2)
+ gfx_v9_0_deactivate_kcq_hqd(adev);
+
/* Use deinitialize sequence from CAIL when unbinding device from driver,
* otherwise KIQ is hanging when binding back
*/
diff --git a/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c b/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c
index 95b3f4e55ec3..699c274d357e 100644
--- a/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c
+++ b/drivers/gpu/drm/amd/amdgpu/ih_v6_1.c
@@ -790,7 +790,7 @@ static void ih_v6_1_set_interrupt_funcs(struct amdgpu_device *adev)
const struct amdgpu_ip_block_version ih_v6_1_ip_block = {
.type = AMD_IP_BLOCK_TYPE_IH,
.major = 6,
- .minor = 0,
+ .minor = 1,
.rev = 0,
.funcs = &ih_v6_1_ip_funcs,
};
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index a2b100d14425..531e20748198 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -1299,18 +1299,11 @@ static int kfd_ioctl_map_memory_to_gpu(struct file *filep,
return -EINVAL;
}
- devices_arr = kmalloc_array(args->n_devices, sizeof(*devices_arr),
- GFP_KERNEL);
- if (!devices_arr)
- return -ENOMEM;
+ devices_arr = memdup_array_user((void *)args->device_ids_array_ptr,
+ args->n_devices, sizeof(*devices_arr));
- err = copy_from_user(devices_arr,
- (void __user *)args->device_ids_array_ptr,
- args->n_devices * sizeof(*devices_arr));
- if (err != 0) {
- err = -EFAULT;
- goto copy_from_user_failed;
- }
+ if (IS_ERR(devices_arr))
+ return PTR_ERR(devices_arr);
mutex_lock(&p->mutex);
pdd = kfd_process_device_data_by_id(p, GET_GPU_ID(args->handle));
@@ -1391,7 +1384,6 @@ get_mem_obj_from_handle_failed:
map_memory_to_gpu_failed:
sync_memory_failed:
mutex_unlock(&p->mutex);
-copy_from_user_failed:
kfree(devices_arr);
return err;
@@ -1416,18 +1408,11 @@ static int kfd_ioctl_unmap_memory_from_gpu(struct file *filep,
return -EINVAL;
}
- devices_arr = kmalloc_array(args->n_devices, sizeof(*devices_arr),
- GFP_KERNEL);
- if (!devices_arr)
- return -ENOMEM;
+ devices_arr = memdup_array_user((void *)args->device_ids_array_ptr,
+ args->n_devices, sizeof(*devices_arr));
- err = copy_from_user(devices_arr,
- (void __user *)args->device_ids_array_ptr,
- args->n_devices * sizeof(*devices_arr));
- if (err != 0) {
- err = -EFAULT;
- goto copy_from_user_failed;
- }
+ if (IS_ERR(devices_arr))
+ return PTR_ERR(devices_arr);
mutex_lock(&p->mutex);
pdd = kfd_process_device_data_by_id(p, GET_GPU_ID(args->handle));
@@ -1493,7 +1478,6 @@ get_mem_obj_from_handle_failed:
unmap_memory_from_gpu_failed:
sync_memory_failed:
mutex_unlock(&p->mutex);
-copy_from_user_failed:
kfree(devices_arr);
return err;
}
@@ -1562,16 +1546,10 @@ static int kfd_ioctl_get_dmabuf_info(struct file *filep,
if (!dev)
return -EINVAL;
- if (args->metadata_ptr) {
- metadata_buffer = kzalloc(args->metadata_size, GFP_KERNEL);
- if (!metadata_buffer)
- return -ENOMEM;
- }
-
/* Get dmabuf info from KGD */
r = amdgpu_amdkfd_get_dmabuf_info(dev->adev, args->dmabuf_fd,
&dmabuf_adev, &args->size,
- metadata_buffer, args->metadata_size,
+ &metadata_buffer, args->metadata_size,
&args->metadata_size, &flags, &xcp_id);
if (r)
goto exit;
@@ -1583,7 +1561,7 @@ static int kfd_ioctl_get_dmabuf_info(struct file *filep,
args->flags = flags;
/* Copy metadata buffer to user mode */
- if (metadata_buffer) {
+ if (metadata_buffer && args->metadata_ptr) {
r = copy_to_user((void __user *)args->metadata_ptr,
metadata_buffer, args->metadata_size);
if (r != 0)
@@ -2359,17 +2337,11 @@ static int criu_restore_devices(struct kfd_process *p,
if (*priv_offset + (args->num_devices * sizeof(*device_privs)) > max_priv_data_size)
return -EINVAL;
- device_buckets = kmalloc_objs(*device_buckets, args->num_devices);
- if (!device_buckets)
- return -ENOMEM;
+ device_buckets = memdup_array_user((void *)args->devices,
+ args->num_devices, sizeof(*device_buckets));
- ret = copy_from_user(device_buckets, (void __user *)args->devices,
- args->num_devices * sizeof(*device_buckets));
- if (ret) {
- pr_err("Failed to copy devices buckets from user\n");
- ret = -EFAULT;
- goto exit;
- }
+ if (IS_ERR(device_buckets))
+ return PTR_ERR(device_buckets);
for (i = 0; i < args->num_devices; i++) {
struct kfd_node *dev;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
index 05c74887fd6f..fdcf7f2d1b5b 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
@@ -153,14 +153,16 @@ void __iomem *kfd_get_kernel_doorbell(struct kfd_dev *kfd,
u32 inx;
mutex_lock(&kfd->doorbell_mutex);
+
inx = find_first_zero_bit(kfd->doorbell_bitmap, PAGE_SIZE / sizeof(u32));
+ if (inx >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS) {
+ mutex_unlock(&kfd->doorbell_mutex);
+ return NULL;
+ }
__set_bit(inx, kfd->doorbell_bitmap);
mutex_unlock(&kfd->doorbell_mutex);
- if (inx >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)
- return NULL;
-
*doorbell_off = amdgpu_doorbell_index_on_bar(kfd->adev,
kfd->doorbells,
inx,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
index 28dc6886c1ff..226e76ae0be7 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c
@@ -424,7 +424,7 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange,
migrate.dst = migrate.src + npages;
scratch = (dma_addr_t *)(migrate.dst + npages);
- kfd_smi_event_migration_start(node, p->lead_thread->pid,
+ kfd_smi_event_migration_start(node, p->lead_thread,
start >> PAGE_SHIFT, end >> PAGE_SHIFT,
0, node->id, prange->prefetch_loc,
prange->preferred_loc, trigger);
@@ -462,7 +462,7 @@ svm_migrate_vma_to_vram(struct kfd_node *node, struct svm_range *prange,
out_free:
kvfree(buf);
- kfd_smi_event_migration_end(node, p->lead_thread->pid,
+ kfd_smi_event_migration_end(node, p->lead_thread,
start >> PAGE_SHIFT, end >> PAGE_SHIFT,
0, node->id, trigger, r);
out:
@@ -727,7 +727,7 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange,
migrate.fault_page = fault_page;
scratch = (dma_addr_t *)(migrate.dst + npages);
- kfd_smi_event_migration_start(node, p->lead_thread->pid,
+ kfd_smi_event_migration_start(node, p->lead_thread,
start >> PAGE_SHIFT, end >> PAGE_SHIFT,
node->id, 0, prange->prefetch_loc,
prange->preferred_loc, trigger);
@@ -766,7 +766,7 @@ svm_migrate_vma_to_ram(struct kfd_node *node, struct svm_range *prange,
out_free:
kvfree(buf);
- kfd_smi_event_migration_end(node, p->lead_thread->pid,
+ kfd_smi_event_migration_end(node, p->lead_thread,
start >> PAGE_SHIFT, end >> PAGE_SHIFT,
node->id, 0, trigger, r);
out:
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
index 368283d53077..ca71fa726e32 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
@@ -1175,10 +1175,12 @@ static void kfd_process_remove_sysfs(struct kfd_process *p)
if (!p->kobj)
return;
- sysfs_remove_file(p->kobj, &p->attr_pasid);
- kobject_del(p->kobj_queues);
- kobject_put(p->kobj_queues);
- p->kobj_queues = NULL;
+ if (p->kobj_queues) {
+ sysfs_remove_file(p->kobj, &p->attr_pasid);
+ kobject_del(p->kobj_queues);
+ kobject_put(p->kobj_queues);
+ p->kobj_queues = NULL;
+ }
for (i = 0; i < p->n_pdds; i++) {
pdd = p->pdds[i];
@@ -1186,17 +1188,21 @@ static void kfd_process_remove_sysfs(struct kfd_process *p)
sysfs_remove_file(p->kobj, &pdd->attr_vram);
sysfs_remove_file(p->kobj, &pdd->attr_sdma);
- sysfs_remove_file(pdd->kobj_stats, &pdd->attr_evict);
- if (pdd->dev->kfd2kgd->get_cu_occupancy)
- sysfs_remove_file(pdd->kobj_stats,
- &pdd->attr_cu_occupancy);
- kobject_del(pdd->kobj_stats);
- kobject_put(pdd->kobj_stats);
- pdd->kobj_stats = NULL;
+ if (pdd->kobj_stats) {
+ sysfs_remove_file(pdd->kobj_stats, &pdd->attr_evict);
+ if (pdd->dev->kfd2kgd->get_cu_occupancy)
+ sysfs_remove_file(pdd->kobj_stats,
+ &pdd->attr_cu_occupancy);
+ kobject_del(pdd->kobj_stats);
+ kobject_put(pdd->kobj_stats);
+ pdd->kobj_stats = NULL;
+ }
}
for_each_set_bit(i, p->svms.bitmap_supported, p->n_pdds) {
pdd = p->pdds[i];
+ if (!pdd->kobj_counters)
+ continue;
sysfs_remove_file(pdd->kobj_counters, &pdd->attr_faults);
sysfs_remove_file(pdd->kobj_counters, &pdd->attr_page_in);
@@ -1254,6 +1260,13 @@ static void kfd_process_wq_release(struct work_struct *work)
kfd_debugfs_remove_process(p);
+ /*
+ * Remove the proc/sysfs entries before destroying PDDs. The removal path
+ * walks the PDD array and sysfs callbacks dereference PDD fields, so the
+ * backing data must remain valid until sysfs removal has completed.
+ */
+ kfd_process_remove_sysfs(p);
+
kfd_process_kunmap_signal_bo(p);
kfd_process_free_outstanding_kfd_bos(p);
svm_range_list_fini(p);
@@ -1267,11 +1280,6 @@ static void kfd_process_wq_release(struct work_struct *work)
put_task_struct(p->lead_thread);
- /* the last step is removing process entries under /sys
- * to indicate the process has been terminated.
- */
- kfd_process_remove_sysfs(p);
-
kfree(p);
}
@@ -1969,7 +1977,7 @@ int kfd_process_evict_queues(struct kfd_process *p, uint32_t trigger)
struct kfd_process_device *pdd = p->pdds[i];
struct device *dev = pdd->dev->adev->dev;
- kfd_smi_event_queue_eviction(pdd->dev, p->lead_thread->pid,
+ kfd_smi_event_queue_eviction(pdd->dev, p->lead_thread,
trigger);
r = pdd->dev->dqm->ops.evict_process_queues(pdd->dev->dqm,
@@ -1999,7 +2007,7 @@ fail:
if (n_evicted == 0)
break;
- kfd_smi_event_queue_restore(pdd->dev, p->lead_thread->pid);
+ kfd_smi_event_queue_restore(pdd->dev, p->lead_thread);
if (pdd->dev->dqm->ops.restore_process_queues(pdd->dev->dqm,
&pdd->qpd))
@@ -2022,7 +2030,7 @@ int kfd_process_restore_queues(struct kfd_process *p)
struct kfd_process_device *pdd = p->pdds[i];
struct device *dev = pdd->dev->adev->dev;
- kfd_smi_event_queue_restore(pdd->dev, p->lead_thread->pid);
+ kfd_smi_event_queue_restore(pdd->dev, p->lead_thread);
r = pdd->dev->dqm->ops.restore_process_queues(pdd->dev->dqm,
&pdd->qpd);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
index 44e39ce222b7..0ac35789b239 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
@@ -962,8 +962,8 @@ static void set_queue_properties_from_criu(struct queue_properties *qp,
qp->priority = q_data->priority;
qp->queue_address = q_data->q_address;
qp->queue_size = q_data->q_size;
- qp->read_ptr = (uint32_t *) q_data->read_ptr_addr;
- qp->write_ptr = (uint32_t *) q_data->write_ptr_addr;
+ qp->read_ptr = (void __user *)q_data->read_ptr_addr;
+ qp->write_ptr = (void __user *)q_data->write_ptr_addr;
qp->eop_ring_buffer_address = q_data->eop_ring_buffer_address;
qp->eop_ring_buffer_size = q_data->eop_ring_buffer_size;
qp->ctx_save_restore_area_address = q_data->ctx_save_restore_area_address;
@@ -1042,10 +1042,18 @@ int kfd_criu_restore_queue(struct kfd_process *p,
memset(&qp, 0, sizeof(qp));
set_queue_properties_from_criu(&qp, q_data, NUM_XCC(pdd->dev->adev->gfx.xcc_mask));
+ ret = kfd_queue_acquire_buffers(pdd, &qp);
+ if (ret) {
+ pr_debug("failed to acquire user queue buffers for CRIU\n");
+ goto exit;
+ }
+
print_queue_properties(&qp);
ret = pqm_create_queue(&p->pqm, pdd->dev, &qp, &queue_id, q_data, mqd, ctl_stack, NULL);
if (ret) {
+ kfd_queue_unref_bo_vas(pdd, &qp);
+ kfd_queue_release_buffers(pdd, &qp);
pr_err("Failed to create new queue err:%d\n", ret);
goto exit;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c
index dfbde5a571f6..e659cd50eb0b 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c
@@ -195,17 +195,35 @@ static void add_event_to_kfifo(pid_t pid, struct kfd_node *dev,
rcu_read_unlock();
}
+/**
+ * kfd_smi_task_to_pid - Convert task to namespace-aware PID
+ * @task: task_struct pointer (typically p->lead_thread)
+ *
+ * Returns the PID as it appears in the task's own PID namespace.
+ * For containerized processes, this returns the container-local PID
+ * (what getpid() returns), not the global host PID.
+ *
+ * Returns 0 if task is NULL.
+ */
+static inline pid_t kfd_smi_task_to_pid(struct task_struct *task)
+{
+ return task ? task_tgid_nr_ns(task, task_active_pid_ns(task)) : 0;
+}
+
__printf(4, 5)
-static void kfd_smi_event_add(pid_t pid, struct kfd_node *dev,
+static void kfd_smi_event_add(struct task_struct *task, struct kfd_node *dev,
unsigned int event, char *fmt, ...)
{
char fifo_in[KFD_SMI_EVENT_MSG_SIZE];
int len;
va_list args;
+ pid_t pid;
if (list_empty(&dev->smi_clients))
return;
+ pid = kfd_smi_task_to_pid(task);
+
len = snprintf(fifo_in, sizeof(fifo_in), "%x ", event);
va_start(args, fmt);
@@ -234,14 +252,15 @@ void kfd_smi_event_update_gpu_reset(struct kfd_node *dev, bool post_reset,
amdgpu_reset_get_desc(reset_context, reset_cause,
sizeof(reset_cause));
- kfd_smi_event_add(0, dev, event, KFD_EVENT_FMT_UPDATE_GPU_RESET(
+ kfd_smi_event_add(NULL, dev, event, KFD_EVENT_FMT_UPDATE_GPU_RESET(
dev->reset_seq_num, reset_cause));
}
void kfd_smi_event_update_thermal_throttling(struct kfd_node *dev,
uint64_t throttle_bitmask)
{
- kfd_smi_event_add(0, dev, KFD_SMI_EVENT_THERMAL_THROTTLE, KFD_EVENT_FMT_THERMAL_THROTTLING(
+ kfd_smi_event_add(NULL, dev, KFD_SMI_EVENT_THERMAL_THROTTLE,
+ KFD_EVENT_FMT_THERMAL_THROTTLING(
throttle_bitmask,
amdgpu_dpm_get_thermal_throttling_counter(dev->adev)));
}
@@ -254,67 +273,67 @@ void kfd_smi_event_update_vmfault(struct kfd_node *dev, uint16_t pasid)
if (task_info) {
/* Report VM faults from user applications, not retry from kernel */
if (task_info->task.pid)
- kfd_smi_event_add(task_info->tgid, dev,
- KFD_SMI_EVENT_VMFAULT,
- KFD_EVENT_FMT_VMFAULT(task_info->task.pid,
- task_info->task.comm));
+ kfd_smi_event_add(NULL, dev, KFD_SMI_EVENT_VMFAULT, KFD_EVENT_FMT_VMFAULT(
+ task_info->task.pid, task_info->task.comm));
amdgpu_vm_put_task_info(task_info);
}
}
-void kfd_smi_event_page_fault_start(struct kfd_node *node, pid_t pid,
+void kfd_smi_event_page_fault_start(struct kfd_node *node, struct task_struct *task,
unsigned long address, bool write_fault,
ktime_t ts)
{
- kfd_smi_event_add(pid, node, KFD_SMI_EVENT_PAGE_FAULT_START,
- KFD_EVENT_FMT_PAGEFAULT_START(ktime_to_ns(ts), pid,
- address, node->id, write_fault ? 'W' : 'R'));
+ kfd_smi_event_add(task, node, KFD_SMI_EVENT_PAGE_FAULT_START,
+ KFD_EVENT_FMT_PAGEFAULT_START(ktime_to_ns(ts),
+ kfd_smi_task_to_pid(task), address, node->id,
+ write_fault ? 'W' : 'R'));
}
-void kfd_smi_event_page_fault_end(struct kfd_node *node, pid_t pid,
+void kfd_smi_event_page_fault_end(struct kfd_node *node, struct task_struct *task,
unsigned long address, bool migration)
{
- kfd_smi_event_add(pid, node, KFD_SMI_EVENT_PAGE_FAULT_END,
+ kfd_smi_event_add(task, node, KFD_SMI_EVENT_PAGE_FAULT_END,
KFD_EVENT_FMT_PAGEFAULT_END(ktime_get_boottime_ns(),
- pid, address, node->id, migration ? 'M' : 'U'));
+ kfd_smi_task_to_pid(task), address, node->id,
+ migration ? 'M' : 'U'));
}
-void kfd_smi_event_migration_start(struct kfd_node *node, pid_t pid,
+void kfd_smi_event_migration_start(struct kfd_node *node, struct task_struct *task,
unsigned long start, unsigned long end,
uint32_t from, uint32_t to,
uint32_t prefetch_loc, uint32_t preferred_loc,
uint32_t trigger)
{
- kfd_smi_event_add(pid, node, KFD_SMI_EVENT_MIGRATE_START,
- KFD_EVENT_FMT_MIGRATE_START(
- ktime_get_boottime_ns(), pid, start, end - start,
- from, to, prefetch_loc, preferred_loc, trigger));
+ kfd_smi_event_add(task, node, KFD_SMI_EVENT_MIGRATE_START,
+ KFD_EVENT_FMT_MIGRATE_START(ktime_get_boottime_ns(),
+ kfd_smi_task_to_pid(task), start, end - start, from,
+ to, prefetch_loc, preferred_loc, trigger));
}
-void kfd_smi_event_migration_end(struct kfd_node *node, pid_t pid,
+void kfd_smi_event_migration_end(struct kfd_node *node, struct task_struct *task,
unsigned long start, unsigned long end,
uint32_t from, uint32_t to, uint32_t trigger,
int error_code)
{
- kfd_smi_event_add(pid, node, KFD_SMI_EVENT_MIGRATE_END,
- KFD_EVENT_FMT_MIGRATE_END(
- ktime_get_boottime_ns(), pid, start, end - start,
- from, to, trigger, error_code));
+ kfd_smi_event_add(task, node, KFD_SMI_EVENT_MIGRATE_END,
+ KFD_EVENT_FMT_MIGRATE_END(ktime_get_boottime_ns(),
+ kfd_smi_task_to_pid(task), start, end - start, from,
+ to, trigger, error_code));
}
-void kfd_smi_event_queue_eviction(struct kfd_node *node, pid_t pid,
+void kfd_smi_event_queue_eviction(struct kfd_node *node, struct task_struct *task,
uint32_t trigger)
{
- kfd_smi_event_add(pid, node, KFD_SMI_EVENT_QUEUE_EVICTION,
- KFD_EVENT_FMT_QUEUE_EVICTION(ktime_get_boottime_ns(), pid,
- node->id, trigger));
+ kfd_smi_event_add(task, node, KFD_SMI_EVENT_QUEUE_EVICTION,
+ KFD_EVENT_FMT_QUEUE_EVICTION(ktime_get_boottime_ns(),
+ kfd_smi_task_to_pid(task), node->id, trigger));
}
-void kfd_smi_event_queue_restore(struct kfd_node *node, pid_t pid)
+void kfd_smi_event_queue_restore(struct kfd_node *node, struct task_struct *task)
{
- kfd_smi_event_add(pid, node, KFD_SMI_EVENT_QUEUE_RESTORE,
- KFD_EVENT_FMT_QUEUE_RESTORE(ktime_get_boottime_ns(), pid,
- node->id, '0'));
+ kfd_smi_event_add(task, node, KFD_SMI_EVENT_QUEUE_RESTORE,
+ KFD_EVENT_FMT_QUEUE_RESTORE(ktime_get_boottime_ns(),
+ kfd_smi_task_to_pid(task), node->id, '0'));
}
void kfd_smi_event_queue_restore_rescheduled(struct mm_struct *mm)
@@ -329,21 +348,23 @@ void kfd_smi_event_queue_restore_rescheduled(struct mm_struct *mm)
for (i = 0; i < p->n_pdds; i++) {
struct kfd_process_device *pdd = p->pdds[i];
- kfd_smi_event_add(p->lead_thread->pid, pdd->dev,
+ kfd_smi_event_add(p->lead_thread, pdd->dev,
KFD_SMI_EVENT_QUEUE_RESTORE,
KFD_EVENT_FMT_QUEUE_RESTORE(ktime_get_boottime_ns(),
- p->lead_thread->pid, pdd->dev->id, 'R'));
+ kfd_smi_task_to_pid(p->lead_thread),
+ pdd->dev->id, 'R'));
}
kfd_unref_process(p);
}
-void kfd_smi_event_unmap_from_gpu(struct kfd_node *node, pid_t pid,
+void kfd_smi_event_unmap_from_gpu(struct kfd_node *node, struct task_struct *task,
unsigned long address, unsigned long last,
uint32_t trigger)
{
- kfd_smi_event_add(pid, node, KFD_SMI_EVENT_UNMAP_FROM_GPU,
+ kfd_smi_event_add(task, node, KFD_SMI_EVENT_UNMAP_FROM_GPU,
KFD_EVENT_FMT_UNMAP_FROM_GPU(ktime_get_boottime_ns(),
- pid, address, last - address + 1, node->id, trigger));
+ kfd_smi_task_to_pid(task), address,
+ last - address + 1, node->id, trigger));
}
void kfd_smi_event_process(struct kfd_process_device *pdd, bool start)
@@ -358,7 +379,7 @@ void kfd_smi_event_process(struct kfd_process_device *pdd, bool start)
task_info = amdgpu_vm_get_task_info_vm(avm);
if (task_info) {
- kfd_smi_event_add(task_info->tgid, pdd->dev,
+ kfd_smi_event_add(NULL, pdd->dev,
start ? KFD_SMI_EVENT_PROCESS_START :
KFD_SMI_EVENT_PROCESS_END,
KFD_EVENT_FMT_PROCESS(task_info->task.pid,
@@ -387,7 +408,7 @@ int kfd_smi_event_open(struct kfd_node *dev, uint32_t *fd)
spin_lock_init(&client->lock);
client->events = 0;
client->dev = dev;
- client->pid = current->tgid;
+ client->pid = kfd_smi_task_to_pid(current);
client->suser = capable(CAP_SYS_ADMIN);
spin_lock(&dev->smi_lock);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.h b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.h
index bb4d72b57387..afa93d7cfa7f 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.h
@@ -32,25 +32,25 @@ void kfd_smi_event_update_thermal_throttling(struct kfd_node *dev,
uint64_t throttle_bitmask);
void kfd_smi_event_update_gpu_reset(struct kfd_node *dev, bool post_reset,
struct amdgpu_reset_context *reset_context);
-void kfd_smi_event_page_fault_start(struct kfd_node *node, pid_t pid,
+void kfd_smi_event_page_fault_start(struct kfd_node *node, struct task_struct *task,
unsigned long address, bool write_fault,
ktime_t ts);
-void kfd_smi_event_page_fault_end(struct kfd_node *node, pid_t pid,
+void kfd_smi_event_page_fault_end(struct kfd_node *node, struct task_struct *task,
unsigned long address, bool migration);
-void kfd_smi_event_migration_start(struct kfd_node *node, pid_t pid,
+void kfd_smi_event_migration_start(struct kfd_node *node, struct task_struct *task,
unsigned long start, unsigned long end,
uint32_t from, uint32_t to,
uint32_t prefetch_loc, uint32_t preferred_loc,
uint32_t trigger);
-void kfd_smi_event_migration_end(struct kfd_node *node, pid_t pid,
+void kfd_smi_event_migration_end(struct kfd_node *node, struct task_struct *task,
unsigned long start, unsigned long end,
uint32_t from, uint32_t to, uint32_t trigger,
int error_code);
-void kfd_smi_event_queue_eviction(struct kfd_node *node, pid_t pid,
+void kfd_smi_event_queue_eviction(struct kfd_node *node, struct task_struct *task,
uint32_t trigger);
-void kfd_smi_event_queue_restore(struct kfd_node *node, pid_t pid);
+void kfd_smi_event_queue_restore(struct kfd_node *node, struct task_struct *task);
void kfd_smi_event_queue_restore_rescheduled(struct mm_struct *mm);
-void kfd_smi_event_unmap_from_gpu(struct kfd_node *node, pid_t pid,
+void kfd_smi_event_unmap_from_gpu(struct kfd_node *node, struct task_struct *task,
unsigned long address, unsigned long last,
uint32_t trigger);
void kfd_smi_event_process(struct kfd_process_device *pdd, bool start);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
index 3841943da5ec..0900bb23349e 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c
@@ -1144,7 +1144,7 @@ static int
svm_range_split_tail(struct svm_range *prange, uint64_t new_last,
struct list_head *insert_list, struct list_head *remap_list)
{
- unsigned long last_align_down = ALIGN_DOWN(prange->last, 512);
+ unsigned long last_align_down = ALIGN_DOWN(prange->last + 1, 512);
unsigned long start_align = ALIGN(prange->start, 512);
bool huge_page_mapping = last_align_down > start_align;
struct svm_range *tail = NULL;
@@ -1168,7 +1168,7 @@ static int
svm_range_split_head(struct svm_range *prange, uint64_t new_start,
struct list_head *insert_list, struct list_head *remap_list)
{
- unsigned long last_align_down = ALIGN_DOWN(prange->last, 512);
+ unsigned long last_align_down = ALIGN_DOWN(prange->last + 1, 512);
unsigned long start_align = ALIGN(prange->start, 512);
bool huge_page_mapping = last_align_down > start_align;
struct svm_range *head = NULL;
@@ -1181,8 +1181,8 @@ svm_range_split_head(struct svm_range *prange, uint64_t new_start,
list_add(&head->list, insert_list);
- if (huge_page_mapping && head->last + 1 > start_align &&
- head->last + 1 < last_align_down && (!IS_ALIGNED(head->last, 512)))
+ if (huge_page_mapping && new_start > start_align &&
+ new_start < last_align_down && !IS_ALIGNED(new_start, 512))
list_add(&head->update_list, remap_list);
return 0;
@@ -1408,7 +1408,7 @@ svm_range_unmap_from_gpus(struct svm_range *prange, unsigned long start,
return -EINVAL;
}
- kfd_smi_event_unmap_from_gpu(pdd->dev, p->lead_thread->pid,
+ kfd_smi_event_unmap_from_gpu(pdd->dev, p->lead_thread,
start, last, trigger);
r = svm_range_unmap_from_gpu(pdd->dev->adev,
@@ -3205,7 +3205,7 @@ retry_write_locked:
svms, prange->start, prange->last, best_loc,
prange->actual_loc);
- kfd_smi_event_page_fault_start(node, p->lead_thread->pid, addr,
+ kfd_smi_event_page_fault_start(node, p->lead_thread, addr,
write_fault, timestamp);
/* Align migration range start and size to granularity size */
@@ -3248,7 +3248,7 @@ retry_write_locked:
r, svms, start, last);
out_migrate_fail:
- kfd_smi_event_page_fault_end(node, p->lead_thread->pid, addr,
+ kfd_smi_event_page_fault_end(node, p->lead_thread, addr,
migration);
out_unlock_range:
@@ -4115,6 +4115,7 @@ exit:
list_for_each_entry_safe(criu_svm_md, next, &svms->criu_svm_metadata_list, list) {
pr_debug("freeing criu_svm_md[]\n\tstart: 0x%llx\n",
criu_svm_md->data.start_addr);
+ list_del(&criu_svm_md->list);
kfree(criu_svm_md);
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 97ab1e83b318..d3a8d681227a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -12942,13 +12942,11 @@ static bool amdgpu_dm_crtc_mem_type_changed(struct drm_device *dev,
struct drm_plane_state *new_plane_state, *old_plane_state;
drm_for_each_plane_mask(plane, dev, crtc_state->plane_mask) {
- new_plane_state = drm_atomic_get_plane_state(state, plane);
- old_plane_state = drm_atomic_get_plane_state(state, plane);
+ new_plane_state = drm_atomic_get_new_plane_state(state, plane);
+ old_plane_state = drm_atomic_get_old_plane_state(state, plane);
- if (IS_ERR(new_plane_state) || IS_ERR(old_plane_state)) {
- drm_err(dev, "Failed to get plane state for plane %s\n", plane->name);
- return false;
- }
+ if (!old_plane_state || !new_plane_state)
+ continue;
if (old_plane_state->fb && new_plane_state->fb &&
get_mem_type(old_plane_state->fb) != get_mem_type(new_plane_state->fb))
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index f257ea91a34d..c6f94eb71ffa 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -95,8 +95,11 @@ static u32 edid_extract_panel_id(struct edid *edid)
(u32)EDID_PRODUCT_ID(edid);
}
-static void apply_edid_quirks(struct drm_device *dev, struct edid *edid, struct dc_edid_caps *edid_caps)
+static void apply_edid_quirks(struct dc_link *link, struct edid *edid,
+ struct dc_edid_caps *edid_caps)
{
+ struct amdgpu_dm_connector *aconnector = link->priv;
+ struct drm_device *dev = aconnector->base.dev;
uint32_t panel_id = edid_extract_panel_id(edid);
switch (panel_id) {
@@ -126,6 +129,11 @@ static void apply_edid_quirks(struct drm_device *dev, struct edid *edid, struct
drm_dbg_driver(dev, "Disabling VSC on monitor with panel id %X\n", panel_id);
edid_caps->panel_patch.disable_colorimetry = true;
break;
+ /* Workaround for monitors that get corrupted by the PHY SSC reduction */
+ case drm_edid_encode_panel_id('D', 'E', 'L', 0x4147):
+ drm_dbg_driver(dev, "Skip PHY SSC reduction on panel id %X\n", panel_id);
+ link->wa_flags.skip_phy_ssc_reduction = true;
+ break;
default:
return;
}
@@ -147,7 +155,6 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
{
struct amdgpu_dm_connector *aconnector = link->priv;
struct drm_connector *connector = &aconnector->base;
- struct drm_device *dev = connector->dev;
struct edid *edid_buf = edid ? (struct edid *) edid->raw_edid : NULL;
struct cea_sad *sads;
int sad_count = -1;
@@ -188,7 +195,7 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
edid_caps->frl_dsc_max_frl_rate, edid_caps->frl_dsc_total_chunk_kbytes);
}
- apply_edid_quirks(dev, edid_buf, edid_caps);
+ apply_edid_quirks(link, edid_buf, edid_caps);
sad_count = drm_edid_to_sad((struct edid *) edid->raw_edid, &sads);
if (sad_count <= 0)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index e957657b06c7..c7f8e08feaf4 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -1859,6 +1859,7 @@ static const struct drm_plane_funcs dm_plane_funcs = {
.atomic_duplicate_state = amdgpu_dm_plane_drm_plane_duplicate_state,
.atomic_destroy_state = amdgpu_dm_plane_drm_plane_destroy_state,
.format_mod_supported = amdgpu_dm_plane_format_mod_supported,
+ .format_mod_supported_async = amdgpu_dm_plane_format_mod_supported,
#ifdef AMD_PRIVATE_COLOR
.atomic_set_property = dm_atomic_plane_set_property,
.atomic_get_property = dm_atomic_plane_get_property,
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
index 00c4be7c3aa4..ff47af3854b6 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
@@ -158,7 +158,6 @@ void dcn31_update_clocks(struct clk_mgr *clk_mgr_base,
if (new_clocks->zstate_support != DCN_ZSTATE_SUPPORT_DISALLOW &&
new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {
dcn31_smu_set_zstate_support(clk_mgr, new_clocks->zstate_support);
- dm_helpers_enable_periodic_detection(clk_mgr_base->ctx, true);
clk_mgr_base->clks.zstate_support = new_clocks->zstate_support;
}
@@ -184,7 +183,6 @@ void dcn31_update_clocks(struct clk_mgr *clk_mgr_base,
if (new_clocks->zstate_support == DCN_ZSTATE_SUPPORT_DISALLOW &&
new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {
dcn31_smu_set_zstate_support(clk_mgr, DCN_ZSTATE_SUPPORT_DISALLOW);
- dm_helpers_enable_periodic_detection(clk_mgr_base->ctx, false);
clk_mgr_base->clks.zstate_support = new_clocks->zstate_support;
}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c
index dd6f11ecb9c9..24f6304011ae 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn314/dcn314_clk_mgr.c
@@ -230,7 +230,6 @@ void dcn314_update_clocks(struct clk_mgr *clk_mgr_base,
if (new_clocks->zstate_support != DCN_ZSTATE_SUPPORT_DISALLOW &&
new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {
dcn314_smu_set_zstate_support(clk_mgr, new_clocks->zstate_support);
- dm_helpers_enable_periodic_detection(clk_mgr_base->ctx, true);
clk_mgr_base->clks.zstate_support = new_clocks->zstate_support;
}
@@ -255,7 +254,6 @@ void dcn314_update_clocks(struct clk_mgr *clk_mgr_base,
if (new_clocks->zstate_support == DCN_ZSTATE_SUPPORT_DISALLOW &&
new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {
dcn314_smu_set_zstate_support(clk_mgr, DCN_ZSTATE_SUPPORT_DISALLOW);
- dm_helpers_enable_periodic_detection(clk_mgr_base->ctx, false);
clk_mgr_base->clks.zstate_support = new_clocks->zstate_support;
}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
index 103013e2a0de..a69824e1eb26 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c
@@ -419,6 +419,7 @@ void dcn35_update_clocks(struct clk_mgr *clk_mgr_base,
if (new_clocks->zstate_support != DCN_ZSTATE_SUPPORT_DISALLOW &&
new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {
dcn35_smu_set_zstate_support(clk_mgr, new_clocks->zstate_support);
+ dm_helpers_enable_periodic_detection(clk_mgr_base->ctx, true);
clk_mgr_base->clks.zstate_support = new_clocks->zstate_support;
}
@@ -438,6 +439,7 @@ void dcn35_update_clocks(struct clk_mgr *clk_mgr_base,
if (new_clocks->zstate_support == DCN_ZSTATE_SUPPORT_DISALLOW &&
new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {
dcn35_smu_set_zstate_support(clk_mgr, DCN_ZSTATE_SUPPORT_DISALLOW);
+ dm_helpers_enable_periodic_detection(clk_mgr_base->ctx, false);
clk_mgr_base->clks.zstate_support = new_clocks->zstate_support;
}
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c
index fb1145691410..a214ddbd4c86 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0_0_ppt.c
@@ -227,9 +227,14 @@ static int smu_v15_0_0_system_features_control(struct smu_context *smu, bool en)
struct amdgpu_device *adev = smu->adev;
int ret = 0;
- if (!en && !adev->in_s0ix)
+ if (!en && !adev->in_s0ix) {
ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, NULL);
+ /* SMU resets BIF_FB_EN to zero, re-enable MC access on APUs with SMU V15 */
+ if (!ret && adev->nbio.funcs && adev->nbio.funcs->mc_access_enable)
+ adev->nbio.funcs->mc_access_enable(adev, true);
+ }
+
return ret;
}
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 3fa4d2082cd7..11646453aaac 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -3571,7 +3571,7 @@ EXPORT_SYMBOL(drm_mode_put_tile_group);
/**
* drm_mode_get_tile_group - get a reference to an existing tile group
* @dev: DRM device
- * @topology: 8-bytes unique per monitor.
+ * @topology_id: 9-byte unique ID per monitor.
*
* Use the unique bytes to get a reference to an existing tile group.
*
@@ -3579,14 +3579,14 @@ EXPORT_SYMBOL(drm_mode_put_tile_group);
* tile group or NULL if not found.
*/
struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
- const char topology[8])
+ const char topology_id[9])
{
struct drm_tile_group *tg;
int id;
mutex_lock(&dev->mode_config.idr_mutex);
idr_for_each_entry(&dev->mode_config.tile_idr, tg, id) {
- if (!memcmp(tg->group_data, topology, 8)) {
+ if (!memcmp(tg->group_data, topology_id, sizeof(tg->group_data))) {
if (!kref_get_unless_zero(&tg->refcount))
tg = NULL;
mutex_unlock(&dev->mode_config.idr_mutex);
@@ -3601,7 +3601,7 @@ EXPORT_SYMBOL(drm_mode_get_tile_group);
/**
* drm_mode_create_tile_group - create a tile group from a displayid description
* @dev: DRM device
- * @topology: 8-bytes unique per monitor.
+ * @topology_id: 9-byte unique ID per monitor.
*
* Create a tile group for the unique monitor, and get a unique
* identifier for the tile group.
@@ -3610,7 +3610,7 @@ EXPORT_SYMBOL(drm_mode_get_tile_group);
* new tile group or NULL.
*/
struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
- const char topology[8])
+ const char topology_id[9])
{
struct drm_tile_group *tg;
int ret;
@@ -3620,7 +3620,7 @@ struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
return NULL;
kref_init(&tg->refcount);
- memcpy(tg->group_data, topology, 8);
+ memcpy(tg->group_data, topology_id, sizeof(tg->group_data));
tg->dev = dev;
mutex_lock(&dev->mode_config.idr_mutex);
diff --git a/drivers/gpu/drm/drm_displayid_internal.h b/drivers/gpu/drm/drm_displayid_internal.h
index 5b1b32f73516..4590d6a3d821 100644
--- a/drivers/gpu/drm/drm_displayid_internal.h
+++ b/drivers/gpu/drm/drm_displayid_internal.h
@@ -109,7 +109,7 @@ struct displayid_tiled_block {
u8 topo[3];
u8 tile_size[4];
u8 tile_pixel_bezel[5];
- u8 topology_id[8];
+ u8 topology_id[9];
} __packed;
struct displayid_detailed_timings_1 {
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 404208bf23a6..df3c25bac761 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -7575,6 +7575,14 @@ static void drm_parse_tiled_block(struct drm_connector *connector,
u8 num_v_tile, num_h_tile;
struct drm_tile_group *tg;
+ /* tiled block payload per spec: cap 1 + topo 3 + size 4 + bezel 5 + id 9 = 22 */
+ if (block->num_bytes < 22) {
+ drm_dbg_kms(connector->dev,
+ "[CONNECTOR:%d:%s] Unexpected tiled block size %u\n",
+ connector->base.id, connector->name, block->num_bytes);
+ return;
+ }
+
w = tile->tile_size[0] | tile->tile_size[1] << 8;
h = tile->tile_size[2] | tile->tile_size[3] << 8;
diff --git a/drivers/gpu/drm/i915/display/intel_atomic.c b/drivers/gpu/drm/i915/display/intel_atomic.c
index 0e4f0678c53c..9d0d47c79dd1 100644
--- a/drivers/gpu/drm/i915/display/intel_atomic.c
+++ b/drivers/gpu/drm/i915/display/intel_atomic.c
@@ -288,6 +288,12 @@ static void intel_crtc_put_color_blobs(struct intel_crtc_state *crtc_state)
drm_property_blob_put(crtc_state->pre_csc_lut);
drm_property_blob_put(crtc_state->post_csc_lut);
+
+ crtc_state->hw.degamma_lut = NULL;
+ crtc_state->hw.gamma_lut = NULL;
+ crtc_state->hw.ctm = NULL;
+ crtc_state->pre_csc_lut = NULL;
+ crtc_state->post_csc_lut = NULL;
}
void intel_crtc_free_hw_state(struct intel_crtc_state *crtc_state)
diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c
index 189ae2d3cfc9..7bc9b956554b 100644
--- a/drivers/gpu/drm/i915/display/intel_cdclk.c
+++ b/drivers/gpu/drm/i915/display/intel_cdclk.c
@@ -1256,9 +1256,22 @@ static void skl_sanitize_cdclk(struct intel_display *display)
cdctl = intel_de_read(display, CDCLK_CTL);
expected = (cdctl & CDCLK_FREQ_SEL_MASK) |
skl_cdclk_decimal(display->cdclk.hw.cdclk);
- if (cdctl == expected)
- /* All well; nothing to sanitize */
- return;
+
+ if (cdctl != expected) {
+ cdctl &= ~CDCLK_FREQ_DECIMAL_MASK;
+ cdctl |= expected & CDCLK_FREQ_DECIMAL_MASK;
+
+ if (cdctl != expected)
+ goto sanitize;
+
+ drm_dbg_kms(display->drm, "Sanitizing CDCLK decimal divider (CDCLK_CTL 0x%x, expected 0x%x)\n",
+ intel_de_read(display, CDCLK_CTL), expected);
+
+ intel_de_write(display, CDCLK_CTL, expected);
+ }
+
+ /* All well; nothing to sanitize */
+ return;
sanitize:
drm_dbg_kms(display->drm, "Sanitizing cdclk programmed by pre-os\n");
@@ -2354,11 +2367,25 @@ static void bxt_sanitize_cdclk(struct intel_display *display)
* (PIPE_NONE).
*/
cdctl &= ~bxt_cdclk_cd2x_pipe(display, INVALID_PIPE);
- expected &= ~bxt_cdclk_cd2x_pipe(display, INVALID_PIPE);
+ cdctl |= bxt_cdclk_cd2x_pipe(display, INVALID_PIPE);
- if (cdctl == expected)
- /* All well; nothing to sanitize */
- return;
+ if (cdctl != expected) {
+ if (DISPLAY_VER(display) < 20) {
+ cdctl &= ~CDCLK_FREQ_DECIMAL_MASK;
+ cdctl |= expected & CDCLK_FREQ_DECIMAL_MASK;
+ }
+
+ if (cdctl != expected)
+ goto sanitize;
+
+ drm_dbg_kms(display->drm, "Sanitizing CDCLK decimal divider (CDCLK_CTL 0x%x, expected 0x%x)\n",
+ intel_de_read(display, CDCLK_CTL), expected);
+
+ intel_de_write(display, CDCLK_CTL, expected);
+ }
+
+ /* All well; nothing to sanitize */
+ return;
sanitize:
drm_dbg_kms(display->drm, "Sanitizing cdclk programmed by pre-os\n");
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 205978c9feb6..6296635c4e79 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -2652,9 +2652,6 @@ static void mtl_ddi_pre_enable_dp(struct intel_atomic_state *state,
/* 3. Select Thunderbolt */
mtl_port_buf_ctl_io_selection(encoder);
- /* 4. Enable Panel Power if PPS is required */
- intel_pps_on(intel_dp);
-
/* 5. Enable the port PLL */
intel_ddi_enable_clock(encoder, crtc_state);
@@ -3708,6 +3705,14 @@ intel_ddi_pre_pll_enable(struct intel_atomic_state *state,
else if (display->platform.geminilake || display->platform.broxton)
bxt_dpio_phy_set_lane_optim_mask(encoder,
crtc_state->lane_lat_optim_mask);
+
+ /*
+ * There is no direct connection between the PLL and PPS, however
+ * enabling PPS before PLL is required to avoid PLL/DDI BUF timeouts
+ * during system resume. Do that matching the Bspec order as well.
+ */
+ if (DISPLAY_VER(display) >= 14)
+ intel_pps_on(&dig_port->dp);
}
static void adlp_tbt_to_dp_alt_switch_wa(struct intel_encoder *encoder)
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index bcdc50491347..0aa3e6b4c781 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -726,6 +726,10 @@ static int mst_stream_compute_config(struct intel_encoder *encoder,
if (ret)
return ret;
+ ret = intel_pfit_compute_config(pipe_config, conn_state);
+ if (ret)
+ return ret;
+
for_each_joiner_candidate(connector, adjusted_mode, num_joined_pipes) {
if (num_joined_pipes > 1)
pipe_config->joiner_pipes = GENMASK(crtc->pipe + num_joined_pipes - 1,
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
index 6ac0f23570f3..aeafe1742d30 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
@@ -613,6 +613,7 @@ set_proto_ctx_engines_parallel_submit(struct i915_user_extension __user *base,
return -EINVAL;
}
+ slot = array_index_nospec(slot, set->num_engines);
if (set->engines[slot].type != I915_GEM_ENGINE_TYPE_INVALID) {
drm_dbg(&i915->drm,
"Invalid placement[%d], already occupied\n", slot);
diff --git a/drivers/gpu/drm/nouveau/nouveau_exec.c b/drivers/gpu/drm/nouveau/nouveau_exec.c
index c01a01aee32b..a08ab1cfea9b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_exec.c
+++ b/drivers/gpu/drm/nouveau/nouveau_exec.c
@@ -331,10 +331,10 @@ nouveau_exec_ucopy(struct nouveau_exec_job_args *args,
return 0;
-err_free_pushs:
- u_free(args->push.s);
err_free_ins:
u_free(args->in_sync.s);
+err_free_pushs:
+ u_free(args->push.s);
return ret;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c
index 36445915aa58..f5e4756b4de4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c
@@ -1779,10 +1779,10 @@ nouveau_uvmm_vm_bind_ucopy(struct nouveau_uvmm_bind_job_args *args,
return 0;
-err_free_ops:
- u_free(args->op.s);
err_free_ins:
u_free(args->in_sync.s);
+err_free_ops:
+ u_free(args->op.s);
return ret;
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c
index 4c7745cd6ae5..7fd967a2554f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c
@@ -315,6 +315,7 @@ nvkm_acr_oneinit(struct nvkm_subdev *subdev)
i, us, fw);
}
}
+ nvkm_done(acr->wpr);
return -EINVAL;
}
nvkm_done(acr->wpr);
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 3ac1a79b6f13..533215d6e9cb 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -906,6 +906,7 @@ struct radeon_fence *r100_copy_blit(struct radeon_device *rdev,
{
struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
struct radeon_fence *fence;
+ uint64_t cur_src_offset, cur_dst_offset;
uint32_t cur_pages;
uint32_t stride_bytes = RADEON_GPU_PAGE_SIZE;
uint32_t pitch;
@@ -934,6 +935,10 @@ struct radeon_fence *r100_copy_blit(struct radeon_device *rdev,
cur_pages = 8191;
}
num_gpu_pages -= cur_pages;
+ cur_src_offset = src_offset +
+ (uint64_t)num_gpu_pages * RADEON_GPU_PAGE_SIZE;
+ cur_dst_offset = dst_offset +
+ (uint64_t)num_gpu_pages * RADEON_GPU_PAGE_SIZE;
/* pages are in Y direction - height
page width in X direction - width */
@@ -950,13 +955,13 @@ struct radeon_fence *r100_copy_blit(struct radeon_device *rdev,
RADEON_DP_SRC_SOURCE_MEMORY |
RADEON_GMC_CLR_CMP_CNTL_DIS |
RADEON_GMC_WR_MSK_DIS);
- radeon_ring_write(ring, (pitch << 22) | (src_offset >> 10));
- radeon_ring_write(ring, (pitch << 22) | (dst_offset >> 10));
+ radeon_ring_write(ring, (pitch << 22) | (cur_src_offset >> 10));
+ radeon_ring_write(ring, (pitch << 22) | (cur_dst_offset >> 10));
radeon_ring_write(ring, (0x1fff) | (0x1fff << 16));
radeon_ring_write(ring, 0);
radeon_ring_write(ring, (0x1fff) | (0x1fff << 16));
- radeon_ring_write(ring, num_gpu_pages);
- radeon_ring_write(ring, num_gpu_pages);
+ radeon_ring_write(ring, 0);
+ radeon_ring_write(ring, 0);
radeon_ring_write(ring, cur_pages | (stride_pixels << 16));
}
radeon_ring_write(ring, PACKET0(RADEON_DSTCACHE_CTLSTAT, 0));
diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
index 2a2b553366fb..547f2327af5e 100644
--- a/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
+++ b/drivers/gpu/drm/sysfb/drm_sysfb_helper.h
@@ -50,7 +50,7 @@ struct resource *drm_sysfb_get_memory_si(struct drm_device *dev,
int drm_sysfb_get_stride_si(struct drm_device *dev, const struct screen_info *si,
const struct drm_format_info *format,
unsigned int width, unsigned int height, u64 size);
-u64 drm_sysfb_get_visible_size_si(struct drm_device *dev, const struct screen_info *si,
+s64 drm_sysfb_get_visible_size_si(struct drm_device *dev, const struct screen_info *si,
unsigned int height, unsigned int stride, u64 size);
#endif
diff --git a/drivers/gpu/drm/sysfb/drm_sysfb_screen_info.c b/drivers/gpu/drm/sysfb/drm_sysfb_screen_info.c
index 749290196c6a..1c479ce0e503 100644
--- a/drivers/gpu/drm/sysfb/drm_sysfb_screen_info.c
+++ b/drivers/gpu/drm/sysfb/drm_sysfb_screen_info.c
@@ -2,6 +2,7 @@
#include <linux/export.h>
#include <linux/limits.h>
+#include <linux/math64.h>
#include <linux/minmax.h>
#include <linux/screen_info.h>
@@ -56,18 +57,24 @@ int drm_sysfb_get_stride_si(struct drm_device *dev, const struct screen_info *si
unsigned int width, unsigned int height, u64 size)
{
u64 lfb_linelength = si->lfb_linelength;
+ s64 stride;
if (!lfb_linelength)
lfb_linelength = drm_format_info_min_pitch(format, 0, width);
- return drm_sysfb_get_validated_int0(dev, "stride", lfb_linelength, div64_u64(size, height));
+ stride = drm_sysfb_get_validated_size0(dev, "stride", lfb_linelength,
+ div64_u64(size, height));
+ if (stride < INT_MIN || stride > INT_MAX)
+ return -EINVAL;
+
+ return (int)stride; /* stride or negative errno code */
}
EXPORT_SYMBOL(drm_sysfb_get_stride_si);
-u64 drm_sysfb_get_visible_size_si(struct drm_device *dev, const struct screen_info *si,
+s64 drm_sysfb_get_visible_size_si(struct drm_device *dev, const struct screen_info *si,
unsigned int height, unsigned int stride, u64 size)
{
- u64 vsize = PAGE_ALIGN(height * stride);
+ u64 vsize = mul_u32_u32(height, stride);
return drm_sysfb_get_validated_size0(dev, "visible size", vsize, size);
}
diff --git a/drivers/gpu/drm/sysfb/efidrm.c b/drivers/gpu/drm/sysfb/efidrm.c
index 1a1e36700976..3f9cd5d03efb 100644
--- a/drivers/gpu/drm/sysfb/efidrm.c
+++ b/drivers/gpu/drm/sysfb/efidrm.c
@@ -152,7 +152,8 @@ static struct efidrm_device *efidrm_device_create(struct drm_driver *drv,
const struct screen_info *si;
const struct drm_format_info *format;
int width, height, stride;
- u64 vsize, mem_flags;
+ s64 vsize;
+ u64 mem_flags;
struct resource resbuf;
struct resource *res;
struct efidrm_device *efi;
@@ -206,8 +207,8 @@ static struct efidrm_device *efidrm_device_create(struct drm_driver *drv,
if (stride < 0)
return ERR_PTR(stride);
vsize = drm_sysfb_get_visible_size_si(dev, si, height, stride, resource_size(res));
- if (!vsize)
- return ERR_PTR(-EINVAL);
+ if (vsize < 0)
+ return ERR_PTR(vsize);
drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d bytes\n",
&format->format, width, height, stride);
diff --git a/drivers/gpu/drm/sysfb/vesadrm.c b/drivers/gpu/drm/sysfb/vesadrm.c
index dbc317778d54..6a67b2d2e451 100644
--- a/drivers/gpu/drm/sysfb/vesadrm.c
+++ b/drivers/gpu/drm/sysfb/vesadrm.c
@@ -402,7 +402,7 @@ static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv,
const struct screen_info *si;
const struct drm_format_info *format;
int width, height, stride;
- u64 vsize;
+ s64 vsize;
struct resource resbuf;
struct resource *res;
struct vesadrm_device *vesa;
@@ -457,8 +457,8 @@ static struct vesadrm_device *vesadrm_device_create(struct drm_driver *drv,
if (stride < 0)
return ERR_PTR(stride);
vsize = drm_sysfb_get_visible_size_si(dev, si, height, stride, resource_size(res));
- if (!vsize)
- return ERR_PTR(-EINVAL);
+ if (vsize < 0)
+ return ERR_PTR(vsize);
drm_dbg(dev, "framebuffer format=%p4cc, size=%dx%d, stride=%d bytes\n",
&format->format, width, height, stride);
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 09661f079d03..8e7b146880f4 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -16,14 +16,14 @@ subdir-ccflags-y += -I$(obj) -I$(src)
hostprogs := xe_gen_wa_oob
generated_oob := $(obj)/generated/xe_wa_oob.c $(obj)/generated/xe_wa_oob.h
quiet_cmd_wa_oob = GEN $(notdir $(generated_oob))
- cmd_wa_oob = mkdir -p $(@D); $^ $(generated_oob)
+ cmd_wa_oob = mkdir -p $(@D); $(obj)/xe_gen_wa_oob $(src)/xe_wa_oob.rules $(generated_oob)
$(obj)/generated/%_wa_oob.c $(obj)/generated/%_wa_oob.h: $(obj)/xe_gen_wa_oob \
$(src)/xe_wa_oob.rules
$(call cmd,wa_oob)
generated_device_oob := $(obj)/generated/xe_device_wa_oob.c $(obj)/generated/xe_device_wa_oob.h
quiet_cmd_device_wa_oob = GEN $(notdir $(generated_device_oob))
- cmd_device_wa_oob = mkdir -p $(@D); $^ $(generated_device_oob)
+ cmd_device_wa_oob = mkdir -p $(@D); $(obj)/xe_gen_wa_oob $(src)/xe_device_wa_oob.rules $(generated_device_oob)
$(obj)/generated/%_device_wa_oob.c $(obj)/generated/%_device_wa_oob.h: $(obj)/xe_gen_wa_oob \
$(src)/xe_device_wa_oob.rules
$(call cmd,device_wa_oob)
diff --git a/drivers/gpu/drm/xe/regs/xe_gtt_defs.h b/drivers/gpu/drm/xe/regs/xe_gtt_defs.h
index 4d83461e538b..d6bc19ef277b 100644
--- a/drivers/gpu/drm/xe/regs/xe_gtt_defs.h
+++ b/drivers/gpu/drm/xe/regs/xe_gtt_defs.h
@@ -9,7 +9,11 @@
#define XELPG_GGTT_PTE_PAT0 BIT_ULL(52)
#define XELPG_GGTT_PTE_PAT1 BIT_ULL(53)
-#define XE_PTE_ADDR_MASK GENMASK_ULL(51, 12)
+/*
+ * Mask for PTE address bits [51:shift].
+ * shift is the lower address boundary of page.
+ */
+#define XE_PAGE_ADDR_MASK(shift) GENMASK_ULL(51, (shift))
#define GGTT_PTE_VFID GENMASK_ULL(11, 2)
#define GUC_GGTT_TOP 0xFEE00000
diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
index d224861b6f6f..abe25aedeead 100644
--- a/drivers/gpu/drm/xe/xe_device.c
+++ b/drivers/gpu/drm/xe/xe_device.c
@@ -526,7 +526,8 @@ int xe_device_init_early(struct xe_device *xe)
err = ttm_device_init(&xe->ttm, &xe_ttm_funcs, xe->drm.dev,
xe->drm.anon_inode->i_mapping,
- xe->drm.vma_offset_manager, 0);
+ xe->drm.vma_offset_manager,
+ TTM_ALLOCATION_POOL_BENEFICIAL_ORDER(get_order(SZ_2M)));
if (err)
return err;
diff --git a/drivers/gpu/drm/xe/xe_guc_capture.c b/drivers/gpu/drm/xe/xe_guc_capture.c
index 21f7caf9ea08..1a019137ddf4 100644
--- a/drivers/gpu/drm/xe/xe_guc_capture.c
+++ b/drivers/gpu/drm/xe/xe_guc_capture.c
@@ -461,8 +461,14 @@ static void guc_capture_alloc_steered_lists(struct xe_guc *guc)
if (!list || guc->capture->extlists)
return;
- total = bitmap_weight(gt->fuse_topo.g_dss_mask, sizeof(gt->fuse_topo.g_dss_mask) * 8) *
- guc_capture_get_steer_reg_num(guc_to_xe(guc));
+ {
+ xe_dss_mask_t all_dss;
+
+ total = bitmap_weighted_or(all_dss, gt->fuse_topo.g_dss_mask,
+ gt->fuse_topo.c_dss_mask,
+ XE_MAX_DSS_FUSE_BITS) *
+ guc_capture_get_steer_reg_num(guc_to_xe(guc));
+ }
if (!total)
return;
diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c
index 2669ff5ee747..18a98667c0e6 100644
--- a/drivers/gpu/drm/xe/xe_pt.c
+++ b/drivers/gpu/drm/xe/xe_pt.c
@@ -1602,23 +1602,21 @@ static bool xe_pt_check_kill(u64 addr, u64 next, unsigned int level,
return false;
}
-/* page_size = 2^(reclamation_size + XE_PTE_SHIFT) */
-#define COMPUTE_RECLAIM_ADDRESS_MASK(page_size) \
-({ \
- BUILD_BUG_ON(!__builtin_constant_p(page_size)); \
- ilog2(page_size) - XE_PTE_SHIFT; \
-})
-
static int generate_reclaim_entry(struct xe_tile *tile,
struct xe_page_reclaim_list *prl,
u64 pte, struct xe_pt *xe_child)
{
struct xe_gt *gt = tile->primary_gt;
struct xe_guc_page_reclaim_entry *reclaim_entries = prl->entries;
- u64 phys_addr = pte & XE_PTE_ADDR_MASK;
+ bool is_2m = xe_child->level == 1 && (pte & XE_PDE_PS_2M);
+ bool is_64k = xe_child->level == 0 && ((pte & XE_PTE_PS64) || xe_child->is_compact);
+ u32 page_shift = is_2m ? ilog2(SZ_2M) : is_64k ? ilog2(SZ_64K) : ilog2(SZ_4K);
+ /* Physical address bits start at page shift: 2M->[51:21], 64K->[51:16], 4K->[51:12] */
+ u64 phys_addr = pte & XE_PAGE_ADDR_MASK(page_shift);
+ /* Page address is relative to 4K page regardless of entry level */
u64 phys_page = phys_addr >> XE_PTE_SHIFT;
int num_entries = prl->num_entries;
- u32 reclamation_size;
+ u32 reclamation_size = page_shift - XE_PTE_SHIFT;
xe_tile_assert(tile, xe_child->level <= MAX_HUGEPTE_LEVEL);
xe_tile_assert(tile, reclaim_entries);
@@ -1633,18 +1631,12 @@ static int generate_reclaim_entry(struct xe_tile *tile,
* Page size is computed as 2^(reclamation_size + XE_PTE_SHIFT) bytes.
* Only 4K, 64K (level 0), and 2M pages are supported by hardware for page reclaim
*/
- if (xe_child->level == 0 && !(pte & XE_PTE_PS64)) {
- xe_gt_stats_incr(gt, XE_GT_STATS_ID_PRL_4K_ENTRY_COUNT, 1);
- reclamation_size = COMPUTE_RECLAIM_ADDRESS_MASK(SZ_4K); /* reclamation_size = 0 */
- xe_tile_assert(tile, phys_addr % SZ_4K == 0);
- } else if (xe_child->level == 0) {
- xe_gt_stats_incr(gt, XE_GT_STATS_ID_PRL_64K_ENTRY_COUNT, 1);
- reclamation_size = COMPUTE_RECLAIM_ADDRESS_MASK(SZ_64K); /* reclamation_size = 4 */
- xe_tile_assert(tile, phys_addr % SZ_64K == 0);
- } else if (xe_child->level == 1 && pte & XE_PDE_PS_2M) {
+ if (is_2m) {
xe_gt_stats_incr(gt, XE_GT_STATS_ID_PRL_2M_ENTRY_COUNT, 1);
- reclamation_size = COMPUTE_RECLAIM_ADDRESS_MASK(SZ_2M); /* reclamation_size = 9 */
- xe_tile_assert(tile, phys_addr % SZ_2M == 0);
+ } else if (is_64k) {
+ xe_gt_stats_incr(gt, XE_GT_STATS_ID_PRL_64K_ENTRY_COUNT, 1);
+ } else if (xe_child->level == 0) {
+ xe_gt_stats_incr(gt, XE_GT_STATS_ID_PRL_4K_ENTRY_COUNT, 1);
} else {
xe_page_reclaim_list_abort(tile->primary_gt, prl,
"unsupported PTE level=%u pte=%#llx",
@@ -1665,6 +1657,48 @@ static int generate_reclaim_entry(struct xe_tile *tile,
return 0;
}
+static int add_pte_to_prl(struct xe_tile *tile, struct xe_page_reclaim_list *prl,
+ struct xe_pt *xe_child, u64 pte, u64 addr)
+{
+ /*
+ * In rare scenarios, pte may not be written yet due to racy conditions.
+ * In such cases, invalidate the PRL and fallback to full PPC invalidation.
+ */
+ if (!pte) {
+ xe_page_reclaim_list_abort(tile->primary_gt, prl,
+ "found zero pte at addr=%#llx", addr);
+ return -EINVAL;
+ }
+
+ /* Ensure it is a defined page */
+ xe_tile_assert(tile, xe_child->level == 0 ||
+ (pte & (XE_PDE_PS_2M | XE_PDPE_PS_1G)));
+
+ /* Account for NULL terminated entry on end (-1) */
+ if (prl->num_entries >= XE_PAGE_RECLAIM_MAX_ENTRIES - 1) {
+ xe_page_reclaim_list_abort(tile->primary_gt, prl,
+ "overflow while adding pte=%#llx", pte);
+ return -ENOSPC;
+ }
+
+ return generate_reclaim_entry(tile, prl, pte, xe_child);
+}
+
+static bool add_compact_pt_prl(struct xe_tile *tile, struct xe_page_reclaim_list *prl,
+ struct xe_device *xe, struct xe_pt *compact_pt, u64 addr)
+{
+ struct iosys_map *map = &compact_pt->bo->vmap;
+
+ for (pgoff_t i = 0; i < SZ_2M / SZ_64K && xe_page_reclaim_list_valid(prl); i++) {
+ u64 pte = xe_map_rd(xe, map, i * sizeof(u64), u64);
+
+ if (add_pte_to_prl(tile, prl, compact_pt, pte, addr + i * SZ_64K))
+ break;
+ }
+
+ return xe_page_reclaim_list_valid(prl);
+}
+
static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset,
unsigned int level, u64 addr, u64 next,
struct xe_ptw **child,
@@ -1674,21 +1708,22 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset,
struct xe_pt *xe_child = container_of(*child, typeof(*xe_child), base);
struct xe_pt_stage_unbind_walk *xe_walk =
container_of(walk, typeof(*xe_walk), base);
- struct xe_device *xe = tile_to_xe(xe_walk->tile);
+ struct xe_page_reclaim_list *prl = xe_walk->prl;
+ struct xe_tile *tile = xe_walk->tile;
+ struct xe_device *xe = tile_to_xe(tile);
pgoff_t first = xe_pt_offset(addr, xe_child->level, walk);
bool killed;
XE_WARN_ON(!*child);
XE_WARN_ON(!level);
/* Check for leaf node */
- if (xe_walk->prl && xe_page_reclaim_list_valid(xe_walk->prl) &&
+ if (prl && xe_page_reclaim_list_valid(prl) &&
xe_child->level <= MAX_HUGEPTE_LEVEL) {
struct iosys_map *leaf_map = &xe_child->bo->vmap;
pgoff_t count = xe_pt_num_entries(addr, next, xe_child->level, walk);
for (pgoff_t i = 0; i < count; i++) {
u64 pte;
- int ret;
/*
* If not a leaf pt, skip unless non-leaf pt is interleaved between
@@ -1698,10 +1733,23 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset,
u64 pt_size = 1ULL << walk->shifts[xe_child->level];
bool edge_pt = (i == 0 && !IS_ALIGNED(addr, pt_size)) ||
(i == count - 1 && !IS_ALIGNED(next, pt_size));
-
- if (!edge_pt) {
- xe_page_reclaim_list_abort(xe_walk->tile->primary_gt,
- xe_walk->prl,
+ struct xe_pt *child_pt =
+ container_of(xe_child->base.children[first + i],
+ struct xe_pt, base);
+
+ /* Compact PTs always fill a full 2M-aligned slot, never an edge. */
+ XE_WARN_ON(child_pt->is_compact && edge_pt);
+ if (edge_pt)
+ continue;
+
+ /* Walker never descends into compact PTs, descend now */
+ if (child_pt->is_compact) {
+ if (!add_compact_pt_prl(tile, prl, xe, child_pt,
+ addr + (u64)i * pt_size))
+ break;
+ } else {
+ xe_page_reclaim_list_abort(tile->primary_gt,
+ prl,
"PT is skipped by walk at level=%u offset=%lu",
xe_child->level, first + i);
break;
@@ -1711,37 +1759,12 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset,
pte = xe_map_rd(xe, leaf_map, (first + i) * sizeof(u64), u64);
- /*
- * In rare scenarios, pte may not be written yet due to racy conditions.
- * In such cases, invalidate the PRL and fallback to full PPC invalidation.
- */
- if (!pte) {
- xe_page_reclaim_list_abort(xe_walk->tile->primary_gt, xe_walk->prl,
- "found zero pte at addr=%#llx", addr);
+ if (add_pte_to_prl(tile, prl, xe_child, pte, addr))
break;
- }
-
- /* Ensure it is a defined page */
- xe_tile_assert(xe_walk->tile, xe_child->level == 0 ||
- (pte & (XE_PDE_PS_2M | XE_PDPE_PS_1G)));
/* An entry should be added for 64KB but contigious 4K have XE_PTE_PS64 */
if (pte & XE_PTE_PS64)
i += 15; /* Skip other 15 consecutive 4K pages in the 64K page */
-
- /* Account for NULL terminated entry on end (-1) */
- if (xe_walk->prl->num_entries < XE_PAGE_RECLAIM_MAX_ENTRIES - 1) {
- ret = generate_reclaim_entry(xe_walk->tile, xe_walk->prl,
- pte, xe_child);
- if (ret)
- break;
- } else {
- /* overflow, mark as invalid */
- xe_page_reclaim_list_abort(xe_walk->tile->primary_gt, xe_walk->prl,
- "overflow while adding pte=%#llx",
- pte);
- break;
- }
}
}
@@ -1751,7 +1774,7 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset,
* Verify if any PTE are potentially dropped at non-leaf levels, either from being
* killed or the page walk covers the region.
*/
- if (xe_walk->prl && xe_page_reclaim_list_valid(xe_walk->prl) &&
+ if (prl && xe_page_reclaim_list_valid(prl) &&
xe_child->level > MAX_HUGEPTE_LEVEL && xe_child->num_live) {
bool covered = xe_pt_covers(addr, next, xe_child->level, &xe_walk->base);
@@ -1760,7 +1783,7 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset,
* we need to invalidate the PRL.
*/
if (killed || covered)
- xe_page_reclaim_list_abort(xe_walk->tile->primary_gt, xe_walk->prl,
+ xe_page_reclaim_list_abort(tile->primary_gt, prl,
"kill at level=%u addr=%#llx next=%#llx num_live=%u",
level, addr, next, xe_child->num_live);
}
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 5c2d3ff5fce8..2bfbcc033d59 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1098,6 +1098,7 @@ config SENSORS_LTC2992
tristate "Linear Technology LTC2992"
depends on I2C
depends on GPIOLIB
+ select REGMAP_I2C
help
If you say yes here you get support for Linear Technology LTC2992
I2C System Monitor. The LTC2992 measures current, voltage, and
@@ -1248,6 +1249,7 @@ config SENSORS_MAX16065
config SENSORS_MAX1619
tristate "Maxim MAX1619 sensor chip"
depends on I2C
+ select REGMAP
help
If you say yes here you get support for MAX1619 sensor chip.
@@ -1366,6 +1368,7 @@ config SENSORS_MAX6650
config SENSORS_MAX6697
tristate "Maxim MAX6697 and compatibles"
depends on I2C
+ select REGMAP_I2C
help
If you say yes here you get support for MAX6581, MAX6602, MAX6622,
MAX6636, MAX6689, MAX6693, MAX6694, MAX6697, MAX6698, and MAX6699
diff --git a/drivers/hwmon/aspeed-g6-pwm-tach.c b/drivers/hwmon/aspeed-g6-pwm-tach.c
index 4f6e6d440dd4..5d611a8e5269 100644
--- a/drivers/hwmon/aspeed-g6-pwm-tach.c
+++ b/drivers/hwmon/aspeed-g6-pwm-tach.c
@@ -293,7 +293,10 @@ static int aspeed_tach_val_to_rpm(struct aspeed_pwm_tach_data *priv, u32 tach_va
priv->clk_rate, tach_val, tach_div);
rpm = (u64)priv->clk_rate * 60;
- do_div(rpm, tach_div);
+ if (tach_div)
+ do_div(rpm, tach_div);
+ else
+ rpm = 0;
return (int)rpm;
}
diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c
index 109318b0434d..92afb64c09df 100644
--- a/drivers/hwmon/asus_atk0110.c
+++ b/drivers/hwmon/asus_atk0110.c
@@ -1037,6 +1037,9 @@ static int atk_ec_present(struct atk_data *data)
if (obj->type != ACPI_TYPE_PACKAGE)
continue;
+ if (!obj->package.count)
+ continue;
+
id = &obj->package.elements[0];
if (id->type != ACPI_TYPE_INTEGER)
continue;
diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c
index 42cc6068bb08..e18e80e832fd 100644
--- a/drivers/hwmon/occ/common.c
+++ b/drivers/hwmon/occ/common.c
@@ -214,6 +214,11 @@ int occ_update_response(struct occ *occ)
if (rc)
return rc;
+ if (!occ->active) {
+ rc = -ENODEV;
+ goto unlock;
+ }
+
/* limit the maximum rate of polling the OCC */
if (time_after(jiffies, occ->next_update)) {
rc = occ_poll(occ);
@@ -222,6 +227,7 @@ int occ_update_response(struct occ *occ)
rc = occ->last_error;
}
+unlock:
mutex_unlock(&occ->lock);
return rc;
}
@@ -1105,11 +1111,16 @@ static void occ_parse_poll_response(struct occ *occ)
int occ_active(struct occ *occ, bool active)
{
- int rc = mutex_lock_interruptible(&occ->lock);
+ struct device *hwmon = NULL;
+ int rc = mutex_lock_interruptible(&occ->hwmon_lock);
if (rc)
return rc;
+ rc = mutex_lock_interruptible(&occ->lock);
+ if (rc)
+ goto unlock_hwmon;
+
if (active) {
if (occ->active) {
rc = -EALREADY;
@@ -1154,14 +1165,17 @@ int occ_active(struct occ *occ, bool active)
goto unlock;
}
- if (occ->hwmon)
- hwmon_device_unregister(occ->hwmon);
+ hwmon = occ->hwmon;
occ->active = false;
occ->hwmon = NULL;
}
unlock:
mutex_unlock(&occ->lock);
+ if (hwmon)
+ hwmon_device_unregister(hwmon);
+unlock_hwmon:
+ mutex_unlock(&occ->hwmon_lock);
return rc;
}
@@ -1170,6 +1184,7 @@ int occ_setup(struct occ *occ)
int rc;
mutex_init(&occ->lock);
+ mutex_init(&occ->hwmon_lock);
occ->groups[0] = &occ->group;
rc = occ_setup_sysfs(occ);
@@ -1190,15 +1205,22 @@ EXPORT_SYMBOL_GPL(occ_setup);
void occ_shutdown(struct occ *occ)
{
- mutex_lock(&occ->lock);
+ struct device *hwmon;
occ_shutdown_sysfs(occ);
- if (occ->hwmon)
- hwmon_device_unregister(occ->hwmon);
+ mutex_lock(&occ->hwmon_lock);
+ mutex_lock(&occ->lock);
+
+ hwmon = occ->hwmon;
+ occ->active = false;
occ->hwmon = NULL;
mutex_unlock(&occ->lock);
+
+ if (hwmon)
+ hwmon_device_unregister(hwmon);
+ mutex_unlock(&occ->hwmon_lock);
}
EXPORT_SYMBOL_GPL(occ_shutdown);
diff --git a/drivers/hwmon/occ/common.h b/drivers/hwmon/occ/common.h
index 7ac4b2febce6..82f600093c7f 100644
--- a/drivers/hwmon/occ/common.h
+++ b/drivers/hwmon/occ/common.h
@@ -101,6 +101,7 @@ struct occ {
unsigned long next_update;
struct mutex lock; /* lock OCC access */
+ struct mutex hwmon_lock; /* serialize hwmon registration/removal */
struct device *hwmon;
struct occ_attribute *attrs;
diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c
index 2e5963fb1e12..d3c3ff85dba3 100644
--- a/drivers/hwmon/pmbus/adm1275.c
+++ b/drivers/hwmon/pmbus/adm1275.c
@@ -512,7 +512,7 @@ static int adm1275_enable_vout_temp(struct adm1275_data *data,
static int adm1275_probe(struct i2c_client *client)
{
s32 (*config_read_fn)(const struct i2c_client *client, u8 reg);
- u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
+ u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1] = {0};
int config, device_config;
int ret;
struct pmbus_driver_info *info;
@@ -839,15 +839,25 @@ static int adm1275_probe(struct i2c_client *client)
info->R[PSC_VOLTAGE_OUT] = coefficients[voindex].R;
}
if (cindex >= 0) {
+ u32 m;
+
/* Scale current with sense resistor value */
- info->m[PSC_CURRENT_OUT] =
- coefficients[cindex].m * shunt / 1000;
+ if (unlikely(check_mul_overflow(coefficients[cindex].m, shunt, &m))) {
+ dev_err(&client->dev, "Current coefficient overflow\n");
+ return -EOVERFLOW;
+ }
+ info->m[PSC_CURRENT_OUT] = m / 1000;
info->b[PSC_CURRENT_OUT] = coefficients[cindex].b;
info->R[PSC_CURRENT_OUT] = coefficients[cindex].R;
}
if (pindex >= 0) {
- info->m[PSC_POWER] =
- coefficients[pindex].m * shunt / 1000;
+ u32 m;
+
+ if (unlikely(check_mul_overflow(coefficients[pindex].m, shunt, &m))) {
+ dev_err(&client->dev, "Power coefficient overflow\n");
+ return -EOVERFLOW;
+ }
+ info->m[PSC_POWER] = m / 1000;
info->b[PSC_POWER] = coefficients[pindex].b;
info->R[PSC_POWER] = coefficients[pindex].R;
}
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index e8fdd799c71c..3143b9e0316c 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -1095,9 +1095,27 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data,
static u16 pmbus_data2reg_vid(struct pmbus_data *data,
struct pmbus_sensor *sensor, s64 val)
{
- val = clamp_val(val, 500, 1600);
-
- return 2 + DIV_ROUND_CLOSEST_ULL((1600LL - val) * 100LL, 625);
+ switch (data->info->vrm_version[sensor->page]) {
+ case vr12:
+ val = clamp_val(val, 250, 1520);
+ return 1 + DIV_ROUND_CLOSEST_ULL(val - 250, 5);
+ case vr13:
+ val = clamp_val(val, 500, 3040);
+ return 1 + DIV_ROUND_CLOSEST_ULL(val - 500, 10);
+ case imvp9:
+ val = clamp_val(val, 200, 2740);
+ return 1 + DIV_ROUND_CLOSEST_ULL(val - 200, 10);
+ case amd625mv:
+ val = clamp_val(val, 200, 1550);
+ return DIV_ROUND_CLOSEST_ULL((1550LL - val) * 100LL, 625);
+ case nvidia195mv:
+ val = clamp_val(val, 195, 1465);
+ return 1 + DIV_ROUND_CLOSEST_ULL(val - 195, 5);
+ case vr11:
+ default:
+ val = clamp_val(val, 500, 1600);
+ return 2 + DIV_ROUND_CLOSEST_ULL((1600LL - val) * 100LL, 625);
+ }
}
static u16 pmbus_data2reg(struct pmbus_data *data,
@@ -3329,18 +3347,23 @@ static void pmbus_regulator_notify_worker(struct work_struct *work)
int i, j;
for (i = 0; i < data->info->pages; i++) {
- int event;
+ unsigned int event;
event = atomic_xchg(&data->regulator_events[i], 0);
if (!event)
continue;
for (j = 0; j < data->info->num_regulators; j++) {
- if (i == rdev_get_id(data->rdevs[j])) {
+ if (i != rdev_get_id(data->rdevs[j]))
+ continue;
+ while (event) {
+ unsigned int _event = BIT(__ffs(event));
+
regulator_notifier_call_chain(data->rdevs[j],
- event, NULL);
- break;
+ _event, NULL);
+ event &= ~_event;
}
+ break;
}
}
}
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 95115d7b863e..bb993bb09f40 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -1823,6 +1823,8 @@ static int w83627hf_probe(struct platform_device *pdev)
return 0;
error:
+ device_remove_file(dev, &dev_attr_vrm);
+ device_remove_file(dev, &dev_attr_cpu0_vid);
sysfs_remove_group(&dev->kobj, &w83627hf_group);
sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
return err;
@@ -1834,6 +1836,8 @@ static void w83627hf_remove(struct platform_device *pdev)
hwmon_device_unregister(data->hwmon_dev);
+ device_remove_file(&pdev->dev, &dev_attr_vrm);
+ device_remove_file(&pdev->dev, &dev_attr_cpu0_vid);
sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
}
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index b1f906f06ab4..a548586369e1 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -1917,6 +1917,7 @@ exit_remove:
for (i = 0; i < ARRAY_SIZE(w83793_vid); i++)
device_remove_file(dev, &w83793_vid[i].dev_attr);
+ device_remove_file(dev, &dev_attr_vrm);
for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++)
device_remove_file(dev, &w83793_left_fan[i].dev_attr);
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 32a3cef02c7b..b29c99ed3883 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -931,13 +931,13 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
*/
if (hwpec)
iowrite8(ioread8(SMBAUXCTL(priv)) & ~SMBAUXCTL_CRC, SMBAUXCTL(priv));
-out:
/*
* Unlock the SMBus device for use by BIOS/ACPI,
* and clear status flags if not done already.
*/
iowrite8(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv));
+out:
pm_runtime_put_autosuspend(&priv->pci_dev->dev);
mutex_unlock(&priv->acpi_lock);
return ret;
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 28c5c5c1fb7a..a21fa45bd64c 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -844,7 +844,7 @@ static int fsl_i2c_probe(struct platform_device *op)
"fsl,timeout", &mpc_ops.timeout);
if (!result) {
- mpc_ops.timeout *= HZ / 1000000;
+ mpc_ops.timeout = mpc_ops.timeout * HZ / 1000000;
if (mpc_ops.timeout < 5)
mpc_ops.timeout = 5;
} else {
diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index 49a59da6a841..5d49a9021c7d 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -616,8 +616,8 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr,
unsigned int presence_offset;
unsigned int map_offset;
unsigned int offset;
+ unsigned int num_registers;
unsigned int reg;
- int i;
int b;
int ret;
@@ -643,7 +643,7 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr,
ret = rmi_read_block(d, addr, buf, size_presence_reg);
if (ret)
return ret;
- addr += size_presence_reg;
+ ++addr;
if (buf[0] == 0) {
if (size_presence_reg < 3)
@@ -657,7 +657,7 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr,
memset(presence_map, 0, sizeof(presence_map));
map_offset = 0;
- for (i = presence_offset; i < size_presence_reg; i++) {
+ for (int i = presence_offset; i < size_presence_reg; i++) {
for (b = 0; b < 8; b++) {
if (buf[i] & BIT(b)) {
if (map_offset >= RMI_REG_DESC_PRESENCE_BITS)
@@ -697,28 +697,41 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr,
if (ret)
return ret;
- reg = find_first_bit(presence_map, RMI_REG_DESC_PRESENCE_BITS);
offset = 0;
- for (i = 0; i < rdesc->num_registers; i++) {
- struct rmi_register_desc_item *item = &rdesc->registers[i];
+ num_registers = 0;
+ for_each_set_bit(reg, presence_map, RMI_REG_DESC_PRESENCE_BITS) {
+ struct rmi_register_desc_item *item = &rdesc->registers[num_registers];
int item_size;
+ if (offset >= rdesc->struct_size)
+ break;
+
item_size = rmi_parse_register_desc_item(item,
&struct_buf[offset],
rdesc->struct_size - offset);
- if (item_size < 0)
- return item_size;
+ if (item_size < 0) {
+ dev_warn(&d->dev,
+ "%s: Failed to parse register %d descriptor, ignoring it\n",
+ __func__, reg);
+ break;
+ }
item->reg = reg;
offset += item_size;
- rmi_dbg(RMI_DEBUG_CORE, &d->dev,
- "%s: reg: %d reg size: %u subpackets: %d\n", __func__,
- item->reg, item->reg_size, item->num_subpackets);
+ if (item->reg_size == 0) {
+ dev_warn(&d->dev,
+ "%s: Register %d has 0 size, ignoring it\n",
+ __func__, item->reg);
+ } else {
+ rmi_dbg(RMI_DEBUG_CORE, &d->dev,
+ "%s: reg: %d reg size: %u subpackets: %d\n", __func__,
+ item->reg, item->reg_size, item->num_subpackets);
- reg = find_next_bit(presence_map,
- RMI_REG_DESC_PRESENCE_BITS, reg + 1);
+ num_registers++;
+ }
}
+ rdesc->num_registers = num_registers;
return 0;
}
diff --git a/drivers/input/rmi4/rmi_f30.c b/drivers/input/rmi4/rmi_f30.c
index 35045f161dc2..b2155c8e20e7 100644
--- a/drivers/input/rmi4/rmi_f30.c
+++ b/drivers/input/rmi4/rmi_f30.c
@@ -233,7 +233,7 @@ static int rmi_f30_map_gpios(struct rmi_function *fn,
int button_count = min_t(u8, f30->gpioled_count, TRACKSTICK_RANGE_END);
f30->gpioled_key_map = devm_kcalloc(&fn->dev,
- button_count,
+ f30->gpioled_count,
sizeof(f30->gpioled_key_map[0]),
GFP_KERNEL);
if (!f30->gpioled_key_map) {
diff --git a/drivers/input/rmi4/rmi_f3a.c b/drivers/input/rmi4/rmi_f3a.c
index 0e8baed84dbb..a0777644eef0 100644
--- a/drivers/input/rmi4/rmi_f3a.c
+++ b/drivers/input/rmi4/rmi_f3a.c
@@ -132,7 +132,7 @@ static int rmi_f3a_map_gpios(struct rmi_function *fn, struct f3a_data *f3a,
int button_count = min_t(u8, f3a->gpio_count, TRACKSTICK_RANGE_END);
f3a->gpio_key_map = devm_kcalloc(&fn->dev,
- button_count,
+ f3a->gpio_count,
sizeof(f3a->gpio_key_map[0]),
GFP_KERNEL);
if (!f3a->gpio_key_map) {
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
index 22b2f57fd91f..bf9b993f5733 100644
--- a/drivers/input/serio/gscps2.c
+++ b/drivers/input/serio/gscps2.c
@@ -219,6 +219,7 @@ static void gscps2_read_data(struct gscps2port *ps2port)
ps2port->buffer[ps2port->append].str = status;
ps2port->buffer[ps2port->append].data =
gscps2_readb_input(ps2port->addr);
+ ps2port->append = (ps2port->append + 1) & BUFFER_SIZE;
} while (true);
}
diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c
index ce572c62f58f..73a9db2c7537 100644
--- a/drivers/interconnect/core.c
+++ b/drivers/interconnect/core.c
@@ -443,6 +443,26 @@ struct icc_path *devm_of_icc_get(struct device *dev, const char *name)
}
EXPORT_SYMBOL_GPL(devm_of_icc_get);
+struct icc_path *devm_of_icc_get_by_index(struct device *dev, int idx)
+{
+ struct icc_path **ptr, *path;
+
+ ptr = devres_alloc(devm_icc_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ path = of_icc_get_by_index(dev, idx);
+ if (!IS_ERR(path)) {
+ *ptr = path;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return path;
+}
+EXPORT_SYMBOL_GPL(devm_of_icc_get_by_index);
+
/**
* of_icc_get_by_index() - get a path handle from a DT node based on index
* @dev: device pointer for the consumer device
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 932b3a3df2e5..59001fd4b6f7 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -178,10 +178,15 @@ static void airoha_fe_maccr_init(struct airoha_eth *eth)
{
int p;
- for (p = 1; p <= ARRAY_SIZE(eth->ports); p++)
+ for (p = 1; p <= ARRAY_SIZE(eth->ports); p++) {
airoha_fe_set(eth, REG_GDM_FWD_CFG(p),
GDM_TCP_CKSUM_MASK | GDM_UDP_CKSUM_MASK |
GDM_IP4_CKSUM_MASK | GDM_DROP_CRC_ERR_MASK);
+ airoha_fe_rmw(eth, REG_GDM_LEN_CFG(p),
+ GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK,
+ FIELD_PREP(GDM_SHORT_LEN_MASK, 60) |
+ FIELD_PREP(GDM_LONG_LEN_MASK, AIROHA_MAX_RX_SIZE));
+ }
airoha_fe_rmw(eth, REG_CDM_VLAN_CTRL(1), CDM_VLAN_MASK,
FIELD_PREP(CDM_VLAN_MASK, 0x8100));
@@ -944,6 +949,25 @@ static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q)
q->txq_stopped = false;
}
+static void airoha_unmap_xmit_buf(struct airoha_eth *eth,
+ struct airoha_queue_entry *e)
+{
+ switch (e->dma_type) {
+ case AIROHA_DMA_MAP_PAGE:
+ dma_unmap_page(eth->dev, e->dma_addr, e->dma_len,
+ DMA_TO_DEVICE);
+ break;
+ case AIROHA_DMA_MAP_SINGLE:
+ dma_unmap_single(eth->dev, e->dma_addr, e->dma_len,
+ DMA_TO_DEVICE);
+ break;
+ case AIROHA_DMA_UNMAPPED:
+ default:
+ break;
+ }
+ e->dma_type = AIROHA_DMA_UNMAPPED;
+}
+
static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
{
struct airoha_tx_irq_queue *irq_q;
@@ -1006,9 +1030,7 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
skb = e->skb;
e->skb = NULL;
- dma_unmap_single(eth->dev, e->dma_addr, e->dma_len,
- DMA_TO_DEVICE);
- e->dma_addr = 0;
+ airoha_unmap_xmit_buf(eth, e);
list_add_tail(&e->list, &q->tx_list);
WRITE_ONCE(desc->msg0, 0);
@@ -1177,12 +1199,10 @@ static void airoha_qdma_tx_cleanup(struct airoha_qdma *qdma)
struct airoha_qdma_desc *desc = &q->desc[j];
struct sk_buff *skb = e->skb;
- if (!e->dma_addr)
+ if (e->dma_type == AIROHA_DMA_UNMAPPED)
continue;
- dma_unmap_single(qdma->eth->dev, e->dma_addr,
- e->dma_len, DMA_TO_DEVICE);
- e->dma_addr = 0;
+ airoha_unmap_xmit_buf(qdma->eth, e);
list_add_tail(&e->list, &q->tx_list);
WRITE_ONCE(desc->ctrl, 0);
@@ -1831,13 +1851,24 @@ static void airoha_update_hw_stats(struct airoha_gdm_dev *dev)
spin_unlock(&port->stats_lock);
}
+static void airoha_dev_set_xmit_frame_size(struct net_device *netdev)
+{
+ struct airoha_gdm_dev *dev = netdev_priv(netdev);
+
+ airoha_ppe_set_xmit_frame_size(dev);
+ if (!airoha_is_lan_gdm_dev(dev))
+ airoha_fe_rmw(dev->eth, REG_WAN_MTU0, WAN_MTU0_MASK,
+ FIELD_PREP(WAN_MTU0_MASK,
+ VLAN_ETH_HLEN + netdev->mtu));
+}
+
static int airoha_dev_open(struct net_device *netdev)
{
- int err, len = ETH_HLEN + netdev->mtu + ETH_FCS_LEN;
struct airoha_gdm_dev *dev = netdev_priv(netdev);
struct airoha_gdm_port *port = dev->port;
- u32 cur_len, pse_port = FE_PSE_PORT_PPE1;
struct airoha_qdma *qdma = dev->qdma;
+ u32 pse_port = FE_PSE_PORT_PPE1;
+ int err;
netif_tx_start_all_queues(netdev);
err = airoha_set_vip_for_gdm_port(dev, true);
@@ -1851,19 +1882,7 @@ static int airoha_dev_open(struct net_device *netdev)
airoha_fe_clear(qdma->eth, REG_GDM_INGRESS_CFG(port->id),
GDM_STAG_EN_MASK);
- cur_len = airoha_fe_get(qdma->eth, REG_GDM_LEN_CFG(port->id),
- GDM_LONG_LEN_MASK);
- if (!port->users || len > cur_len) {
- /* Opening a sibling net_device with a larger MTU updates the
- * MTU of already running devices. This is required to allow
- * multiple net_devices with different MTUs to share the same
- * GDM port.
- */
- airoha_fe_rmw(qdma->eth, REG_GDM_LEN_CFG(port->id),
- GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK,
- FIELD_PREP(GDM_SHORT_LEN_MASK, 60) |
- FIELD_PREP(GDM_LONG_LEN_MASK, len));
- }
+ airoha_dev_set_xmit_frame_size(netdev);
port->users++;
if (!airoha_is_lan_gdm_dev(dev) &&
@@ -1875,30 +1894,6 @@ static int airoha_dev_open(struct net_device *netdev)
return 0;
}
-static void airoha_set_port_mtu(struct airoha_eth *eth,
- struct airoha_gdm_port *port)
-{
- u32 len = 0;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(port->devs); i++) {
- struct airoha_gdm_dev *dev = port->devs[i];
- struct net_device *netdev;
-
- if (!dev)
- continue;
-
- netdev = netdev_from_priv(dev);
- if (netif_running(netdev))
- len = max_t(u32, len, netdev->mtu);
- }
- len += ETH_HLEN + ETH_FCS_LEN;
-
- airoha_fe_rmw(eth, REG_GDM_LEN_CFG(port->id),
- GDM_LONG_LEN_MASK,
- FIELD_PREP(GDM_LONG_LEN_MASK, len));
-}
-
static int airoha_dev_stop(struct net_device *netdev)
{
struct airoha_gdm_dev *dev = netdev_priv(netdev);
@@ -1909,7 +1904,7 @@ static int airoha_dev_stop(struct net_device *netdev)
airoha_set_vip_for_gdm_port(dev, false);
if (--port->users)
- airoha_set_port_mtu(dev->eth, port);
+ airoha_ppe_set_xmit_frame_size(dev);
else
airoha_set_gdm_port_fwd_cfg(qdma->eth,
REG_GDM_FWD_CFG(port->id),
@@ -1962,10 +1957,6 @@ static int airoha_enable_gdm2_loopback(struct airoha_gdm_dev *dev)
FIELD_PREP(LPBK_CHAN_MASK, chan) |
LBK_GAP_MODE_MASK | LBK_LEN_MODE_MASK |
LBK_CHAN_MODE_MASK | LPBK_EN_MASK);
- airoha_fe_rmw(eth, REG_GDM_LEN_CFG(AIROHA_GDM2_IDX),
- GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK,
- FIELD_PREP(GDM_SHORT_LEN_MASK, 60) |
- FIELD_PREP(GDM_LONG_LEN_MASK, AIROHA_MAX_MTU));
/* Forward the traffic to the proper GDM port */
pse_port = port->id == AIROHA_GDM3_IDX ? FE_PSE_PORT_GDM3
: FE_PSE_PORT_GDM4;
@@ -2098,7 +2089,7 @@ static int airoha_dev_change_mtu(struct net_device *netdev, int mtu)
WRITE_ONCE(netdev->mtu, mtu);
if (port->users)
- airoha_set_port_mtu(dev->eth, port);
+ airoha_dev_set_xmit_frame_size(netdev);
return 0;
}
@@ -2193,8 +2184,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
struct netdev_queue *txq;
struct airoha_queue *q;
LIST_HEAD(tx_list);
+ dma_addr_t addr;
int i = 0, qid;
- void *data;
u16 index;
u8 fport;
@@ -2250,24 +2241,22 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
return NETDEV_TX_BUSY;
}
- len = skb_headlen(skb);
- data = skb->data;
-
e = list_first_entry(&q->tx_list, struct airoha_queue_entry,
list);
+ len = skb_headlen(skb);
+ addr = dma_map_single(netdev->dev.parent, skb->data, len,
+ DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(netdev->dev.parent, addr)))
+ goto error_unlock;
+
+ e->dma_type = AIROHA_DMA_MAP_SINGLE;
index = e - q->entry;
while (true) {
struct airoha_qdma_desc *desc = &q->desc[index];
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- dma_addr_t addr;
u32 val;
- addr = dma_map_single(netdev->dev.parent, data, len,
- DMA_TO_DEVICE);
- if (unlikely(dma_mapping_error(netdev->dev.parent, addr)))
- goto error_unmap;
-
list_move_tail(&e->list, &tx_list);
e->skb = i == nr_frags - 1 ? skb : NULL;
e->dma_addr = addr;
@@ -2291,8 +2280,13 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
if (++i == nr_frags)
break;
- data = skb_frag_address(frag);
len = skb_frag_size(frag);
+ addr = skb_frag_dma_map(netdev->dev.parent, frag, 0, len,
+ DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(netdev->dev.parent, addr)))
+ goto error_unmap;
+
+ e->dma_type = AIROHA_DMA_MAP_PAGE;
}
q->queued += i;
@@ -2313,11 +2307,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
error_unmap:
- list_for_each_entry(e, &tx_list, list) {
- dma_unmap_single(netdev->dev.parent, e->dma_addr, e->dma_len,
- DMA_TO_DEVICE);
- e->dma_addr = 0;
- }
+ list_for_each_entry(e, &tx_list, list)
+ airoha_unmap_xmit_buf(dev->eth, e);
list_splice(&tx_list, &q->tx_list);
error_unlock:
spin_unlock_bh(&q->lock);
diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
index d7ff8c5200e2..f6d01a8e8da1 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
@@ -23,6 +23,7 @@
#define AIROHA_MAX_DSA_PORTS 7
#define AIROHA_MAX_NUM_RSTS 3
#define AIROHA_MAX_MTU 9220
+#define AIROHA_MAX_RX_SIZE 16128
#define AIROHA_MAX_PACKET_SIZE 2048
#define AIROHA_NUM_QOS_CHANNELS 4
#define AIROHA_NUM_QOS_QUEUES 8
@@ -170,12 +171,19 @@ enum trtcm_param {
#define TRTCM_TOKEN_RATE_MASK GENMASK(23, 6)
#define TRTCM_TOKEN_RATE_FRACTION_MASK GENMASK(5, 0)
+enum airoha_dma_map_type {
+ AIROHA_DMA_UNMAPPED,
+ AIROHA_DMA_MAP_SINGLE,
+ AIROHA_DMA_MAP_PAGE,
+};
+
struct airoha_queue_entry {
union {
void *buf;
struct {
struct list_head list;
struct sk_buff *skb;
+ enum airoha_dma_map_type dma_type;
};
};
dma_addr_t dma_addr;
@@ -676,6 +684,7 @@ int airoha_get_fe_port(struct airoha_gdm_dev *dev);
bool airoha_is_valid_gdm_dev(struct airoha_eth *eth,
struct airoha_gdm_dev *dev);
+void airoha_ppe_set_xmit_frame_size(struct airoha_gdm_dev *dev);
void airoha_ppe_set_cpu_port(struct airoha_gdm_dev *dev, u8 ppe_id, u8 fport);
bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index);
void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb,
diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c
index 42f4b0f21d17..e7c78293002a 100644
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
@@ -97,6 +97,33 @@ void airoha_ppe_set_cpu_port(struct airoha_gdm_dev *dev, u8 ppe_id, u8 fport)
__field_prep(DFT_CPORT_MASK(fport), fe_cpu_port));
}
+void airoha_ppe_set_xmit_frame_size(struct airoha_gdm_dev *dev)
+{
+ struct airoha_gdm_port *port = dev->port;
+ struct airoha_eth *eth = dev->eth;
+ int i, ppe_id, index;
+ u32 len = 0;
+
+ for (i = 0; i < ARRAY_SIZE(port->devs); i++) {
+ struct airoha_gdm_dev *d = port->devs[i];
+ struct net_device *netdev;
+
+ if (!d)
+ continue;
+
+ netdev = netdev_from_priv(d);
+ if (netif_running(netdev))
+ len = max_t(u32, len, netdev->mtu);
+ }
+ len += VLAN_ETH_HLEN;
+
+ ppe_id = !airoha_is_lan_gdm_dev(dev) && airoha_ppe_is_enabled(eth, 1);
+ index = port->id == AIROHA_GDM4_IDX ? 7 : port->id;
+ airoha_fe_rmw(eth, REG_PPE_MTU(ppe_id, index),
+ FP_EGRESS_MTU_MASK(index),
+ __field_prep(FP_EGRESS_MTU_MASK(index), len));
+}
+
static void airoha_ppe_hw_init(struct airoha_ppe *ppe)
{
u32 sram_ppe_num_data_entries = PPE_SRAM_NUM_ENTRIES, sram_num_entries;
@@ -115,8 +142,6 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe)
PPE_RAM_NUM_ENTRIES_SHIFT(sram_ppe_num_data_entries);
for (i = 0; i < eth->soc->num_ppe; i++) {
- int p;
-
airoha_fe_wr(eth, REG_PPE_TB_BASE(i),
ppe->foe_dma + sram_tb_size);
@@ -166,15 +191,6 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe)
airoha_fe_wr(eth, REG_PPE_HASH_SEED(i), PPE_HASH_SEED);
airoha_fe_clear(eth, REG_PPE_PPE_FLOW_CFG(i),
PPE_FLOW_CFG_IP6_6RD_MASK);
-
- for (p = 0; p < ARRAY_SIZE(eth->ports); p++)
- airoha_fe_rmw(eth, REG_PPE_MTU(i, p),
- FP0_EGRESS_MTU_MASK |
- FP1_EGRESS_MTU_MASK,
- FIELD_PREP(FP0_EGRESS_MTU_MASK,
- AIROHA_MAX_MTU) |
- FIELD_PREP(FP1_EGRESS_MTU_MASK,
- AIROHA_MAX_MTU));
}
for (i = 0; i < ARRAY_SIZE(eth->ports); i++) {
@@ -196,6 +212,7 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe)
airoha_ppe_is_enabled(eth, 1);
fport = airoha_get_fe_port(dev);
airoha_ppe_set_cpu_port(dev, ppe_id, fport);
+ airoha_ppe_set_xmit_frame_size(dev);
}
}
}
diff --git a/drivers/net/ethernet/airoha/airoha_regs.h b/drivers/net/ethernet/airoha/airoha_regs.h
index 436f3c8779c1..6fed63d013b4 100644
--- a/drivers/net/ethernet/airoha/airoha_regs.h
+++ b/drivers/net/ethernet/airoha/airoha_regs.h
@@ -327,9 +327,8 @@
#define PPE_SRAM_TABLE_EN_MASK BIT(0)
#define REG_PPE_MTU_BASE(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x304)
-#define REG_PPE_MTU(_m, _n) (REG_PPE_MTU_BASE(_m) + ((_n) << 2))
-#define FP1_EGRESS_MTU_MASK GENMASK(29, 16)
-#define FP0_EGRESS_MTU_MASK GENMASK(13, 0)
+#define REG_PPE_MTU(_m, _n) (REG_PPE_MTU_BASE(_m) + (((_n) / 2) << 2))
+#define FP_EGRESS_MTU_MASK(_n) GENMASK(13 + (((_n) % 2) << 4), ((_n) % 2) << 4)
#define REG_PPE_RAM_CTRL(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x31c)
#define PPE_SRAM_CTRL_ACK_MASK BIT(31)
@@ -377,6 +376,10 @@
#define REG_SRC_PORT_FC_MAP6 0x2298
#define FC_ID_OF_SRC_PORT_MASK(_n) GENMASK(4 + ((_n) << 3), ((_n) << 3))
+#define REG_WAN_MTU0 0x2300
+#define WAN_MTU1_MASK GENMASK(29, 16)
+#define WAN_MTU0_MASK GENMASK(13, 0)
+
#define REG_CDM5_RX_OQ1_DROP_CNT 0x29d4
/* QDMA */
diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c
index 75f22f74774c..06b4424e778e 100644
--- a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c
+++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c
@@ -1163,18 +1163,14 @@ int setup_cn23xx_octeon_pf_device(struct octeon_device *oct)
if (octeon_map_pci_barx(oct, 1, MAX_BAR1_IOREMAP_SIZE)) {
dev_err(&oct->pci_dev->dev, "%s CN23XX BAR1 map failed\n",
__func__);
- octeon_unmap_pci_barx(oct, 0);
- return 1;
+ goto err_unmap_bar0;
}
if (cn23xx_get_pf_num(oct) != 0)
- return 1;
+ goto err_unmap_bar1;
- if (cn23xx_sriov_config(oct)) {
- octeon_unmap_pci_barx(oct, 0);
- octeon_unmap_pci_barx(oct, 1);
- return 1;
- }
+ if (cn23xx_sriov_config(oct))
+ goto err_unmap_bar1;
octeon_write_csr64(oct, CN23XX_SLI_MAC_CREDIT_CNT, 0x3F802080802080ULL);
@@ -1205,6 +1201,12 @@ int setup_cn23xx_octeon_pf_device(struct octeon_device *oct)
oct->coproc_clock_rate = 1000000ULL * cn23xx_coprocessor_clock(oct);
return 0;
+
+err_unmap_bar1:
+ octeon_unmap_pci_barx(oct, 1);
+err_unmap_bar0:
+ octeon_unmap_pci_barx(oct, 0);
+ return 1;
}
EXPORT_SYMBOL_GPL(setup_cn23xx_octeon_pf_device);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index 171750fad44f..6871127427fa 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -6737,14 +6737,6 @@ void t4_sge_decode_idma_state(struct adapter *adapter, int state)
return;
}
- if (is_t4(adapter->params.chip)) {
- sge_idma_decode = (const char **)t4_decode;
- sge_idma_decode_nstates = ARRAY_SIZE(t4_decode);
- } else {
- sge_idma_decode = (const char **)t5_decode;
- sge_idma_decode_nstates = ARRAY_SIZE(t5_decode);
- }
-
if (state < sge_idma_decode_nstates)
CH_WARN(adapter, "idma state %s\n", sge_idma_decode[state]);
else
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index aa8a87124b10..8e3f345dd9aa 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -1783,6 +1783,7 @@ int enetc_xdp_xmit(struct net_device *ndev, int num_frames,
{
struct enetc_tx_swbd xdp_redirect_arr[ENETC_MAX_SKB_FRAGS] = {0};
struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct skb_shared_info *shinfo;
struct enetc_bdr *tx_ring;
int xdp_tx_bd_cnt, i, k;
int xdp_tx_frm_cnt = 0;
@@ -1798,6 +1799,12 @@ int enetc_xdp_xmit(struct net_device *ndev, int num_frames,
prefetchw(ENETC_TXBD(*tx_ring, tx_ring->next_to_use));
for (k = 0; k < num_frames; k++) {
+ if (xdp_frame_has_frags(frames[k])) {
+ shinfo = xdp_get_shared_info_from_frame(frames[k]);
+ if (unlikely((shinfo->nr_frags + 1) > ENETC_MAX_SKB_FRAGS))
+ break;
+ }
+
xdp_tx_bd_cnt = enetc_xdp_frame_to_xdp_tx_swbd(tx_ring,
xdp_redirect_arr,
frames[k]);
diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c
index 013273a2de32..299bab043175 100644
--- a/drivers/net/ethernet/freescale/fman/fman.c
+++ b/drivers/net/ethernet/freescale/fman/fman.c
@@ -1995,8 +1995,10 @@ static int fman_init(struct fman *fman)
/* Init KeyGen */
fman->keygen = keygen_init(fman->kg_regs);
- if (!fman->keygen)
+ if (!fman->keygen) {
+ free_init_resources(fman);
return -EINVAL;
+ }
err = enable(fman, cfg);
if (err != 0)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
index 71b3a059c964..daff53ba7d09 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c
@@ -714,34 +714,43 @@ static int mlx5e_macsec_add_rxsc(struct macsec_context *ctx)
}
sc_xarray_element->rx_sc = rx_sc;
- err = xa_alloc(&macsec->sc_xarray, &sc_xarray_element->fs_id, sc_xarray_element,
- XA_LIMIT(1, MLX5_MACEC_RX_FS_ID_MAX), GFP_KERNEL);
- if (err) {
- if (err == -EBUSY)
- netdev_err(ctx->netdev,
- "MACsec offload: unable to create entry for RX SC (%d Rx SCs already allocated)\n",
- MLX5_MACEC_RX_FS_ID_MAX);
- goto destroy_sc_xarray_elemenet;
- }
rx_sc->md_dst = metadata_dst_alloc(0, METADATA_MACSEC, GFP_KERNEL);
if (!rx_sc->md_dst) {
err = -ENOMEM;
- goto erase_xa_alloc;
+ goto destroy_sc_xarray_elemenet;
}
rx_sc->sci = ctx_rx_sc->sci;
rx_sc->active = ctx_rx_sc->active;
- list_add_rcu(&rx_sc->rx_sc_list_element, rx_sc_list);
-
rx_sc->sc_xarray_element = sc_xarray_element;
rx_sc->md_dst->u.macsec_info.sci = rx_sc->sci;
+
+ /*
+ * Publish the fully-initialised SC last: xa_alloc() makes
+ * sc_xarray_element->rx_sc (and rx_sc->md_dst) reachable from the RX
+ * datapath via xa_load(). Doing it only after md_dst is allocated and
+ * initialised pairs with the rcu_read_lock()/xa_load() in
+ * mlx5e_macsec_offload_handle_rx_skb(), so a reader can never observe
+ * a non-NULL md_dst with uninitialised contents.
+ */
+ err = xa_alloc(&macsec->sc_xarray, &sc_xarray_element->fs_id, sc_xarray_element,
+ XA_LIMIT(1, MLX5_MACEC_RX_FS_ID_MAX), GFP_KERNEL);
+ if (err) {
+ if (err == -EBUSY)
+ netdev_err(ctx->netdev,
+ "MACsec offload: unable to create entry for RX SC (%d Rx SCs already allocated)\n",
+ MLX5_MACEC_RX_FS_ID_MAX);
+ goto destroy_md_dst;
+ }
+
+ list_add_rcu(&rx_sc->rx_sc_list_element, rx_sc_list);
mutex_unlock(&macsec->lock);
return 0;
-erase_xa_alloc:
- xa_erase(&macsec->sc_xarray, sc_xarray_element->fs_id);
+destroy_md_dst:
+ dst_release(&rx_sc->md_dst->dst);
destroy_sc_xarray_elemenet:
kfree(sc_xarray_element);
destroy_rx_sc:
@@ -829,7 +838,7 @@ static void macsec_del_rxsc_ctx(struct mlx5e_macsec *macsec, struct mlx5e_macsec
*/
list_del_rcu(&rx_sc->rx_sc_list_element);
xa_erase(&macsec->sc_xarray, rx_sc->sc_xarray_element->fs_id);
- metadata_dst_free(rx_sc->md_dst);
+ dst_release(&rx_sc->md_dst->dst);
kfree(rx_sc->sc_xarray_element);
kfree_rcu_mightsleep(rx_sc);
}
@@ -1695,10 +1704,10 @@ void mlx5e_macsec_offload_handle_rx_skb(struct net_device *netdev,
rcu_read_lock();
sc_xarray_element = xa_load(&macsec->sc_xarray, fs_id);
- rx_sc = sc_xarray_element->rx_sc;
- if (rx_sc) {
- dst_hold(&rx_sc->md_dst->dst);
- skb_dst_set(skb, &rx_sc->md_dst->dst);
+ rx_sc = sc_xarray_element ? sc_xarray_element->rx_sc : NULL;
+ if (rx_sc && rx_sc->md_dst) {
+ if (dst_hold_safe(&rx_sc->md_dst->dst))
+ skb_dst_set(skb, &rx_sc->md_dst->dst);
}
rcu_read_unlock();
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c
index eae02bc74221..3bcf412a08c4 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c
@@ -205,6 +205,7 @@ static int hws_bwc_matcher_move(struct mlx5hws_bwc_matcher *bwc_matcher)
ret = mlx5hws_matcher_resize_set_target(old_matcher, new_matcher);
if (ret) {
mlx5hws_err(ctx, "Rehash error: failed setting resize target\n");
+ mlx5hws_matcher_destroy(new_matcher);
return ret;
}
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
index 9cd85a0d0c3a..401f8b8ae1ca 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
@@ -194,16 +194,18 @@ static bool fbnic_tx_tstamp(struct sk_buff *skb)
static bool
fbnic_tx_lso(struct fbnic_ring *ring, struct sk_buff *skb,
- struct skb_shared_info *shinfo, __le64 *meta,
- unsigned int *l2len, unsigned int *i3len)
+ __le64 *meta, unsigned int *l2len, unsigned int *i3len)
{
unsigned int l3_type, l4_type, l4len, hdrlen;
+ struct skb_shared_info *shinfo;
unsigned char *l4hdr;
__be16 payload_len;
if (unlikely(skb_cow_head(skb, 0)))
return true;
+ shinfo = skb_shinfo(skb);
+
if (shinfo->gso_type & SKB_GSO_PARTIAL) {
l3_type = FBNIC_TWD_L3_TYPE_OTHER;
} else if (!skb->encapsulation) {
@@ -258,7 +260,6 @@ fbnic_tx_lso(struct fbnic_ring *ring, struct sk_buff *skb,
static bool
fbnic_tx_offloads(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta)
{
- struct skb_shared_info *shinfo = skb_shinfo(skb);
unsigned int l2len, i3len;
if (fbnic_tx_tstamp(skb))
@@ -273,8 +274,8 @@ fbnic_tx_offloads(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta)
*meta |= cpu_to_le64(FIELD_PREP(FBNIC_TWD_CSUM_OFFSET_MASK,
skb->csum_offset / 2));
- if (shinfo->gso_size) {
- if (fbnic_tx_lso(ring, skb, shinfo, meta, &l2len, &i3len))
+ if (skb_is_gso(skb)) {
+ if (fbnic_tx_lso(ring, skb, meta, &l2len, &i3len))
return true;
} else {
*meta |= cpu_to_le64(FBNIC_TWD_FLAG_REQ_CSO);
diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c
index 1cdce35e1423..e759171bfd76 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -3541,8 +3541,8 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter,
adapter->max_tx_channels = PCI11X1X_MAX_TX_CHANNELS;
adapter->used_tx_channels = PCI11X1X_USED_TX_CHANNELS;
adapter->max_vector_count = PCI11X1X_MAX_VECTOR_COUNT;
- pci11x1x_strap_get_status(adapter);
spin_lock_init(&adapter->eth_syslock_spinlock);
+ pci11x1x_strap_get_status(adapter);
mutex_init(&adapter->sgmii_rw_lock);
pci11x1x_set_rfe_rd_fifo_threshold(adapter);
sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL);
diff --git a/drivers/net/ethernet/qlogic/qede/qede_fp.c b/drivers/net/ethernet/qlogic/qede/qede_fp.c
index e338bfc8b7b2..33e18bb69774 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_fp.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_fp.c
@@ -961,7 +961,7 @@ static inline void qede_tpa_cont(struct qede_dev *edev,
{
int i;
- for (i = 0; cqe->len_list[i] && i < ARRAY_SIZE(cqe->len_list); i++)
+ for (i = 0; i < ARRAY_SIZE(cqe->len_list) && cqe->len_list[i]; i++)
qede_fill_frag_skb(edev, rxq, cqe->tpa_agg_index,
le16_to_cpu(cqe->len_list[i]));
@@ -986,7 +986,7 @@ static int qede_tpa_end(struct qede_dev *edev,
dma_unmap_page(rxq->dev, tpa_info->buffer.mapping,
PAGE_SIZE, rxq->data_direction);
- for (i = 0; cqe->len_list[i] && i < ARRAY_SIZE(cqe->len_list); i++)
+ for (i = 0; i < ARRAY_SIZE(cqe->len_list) && cqe->len_list[i]; i++)
qede_fill_frag_skb(edev, rxq, cqe->tpa_agg_index,
le16_to_cpu(cqe->len_list[i]));
if (unlikely(i > 1))
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
index d042567b8128..814d88d2aee4 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c
@@ -1802,6 +1802,7 @@ static bool wx_set_vmdq_queues(struct wx *wx)
rss_i = 4;
}
} else {
+ vmdq_m = WX_VMDQ_1Q_MASK;
/* double check we are limited to maximum pools */
vmdq_i = min_t(u16, 8, vmdq_i);
diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
index c7befe4cdfe9..65e3e55db1cf 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -486,6 +486,7 @@ enum WX_MSCA_CMD_value {
#define WX_VMDQ_4Q_MASK 0x7C
#define WX_VMDQ_2Q_MASK 0x7E
+#define WX_VMDQ_1Q_MASK 0x7F
/****************** Manageablility Host Interface defines ********************/
#define WX_HI_MAX_BLOCK_BYTE_LENGTH 256 /* Num of bytes in range */
diff --git a/drivers/net/ipa/ipa_smp2p.c b/drivers/net/ipa/ipa_smp2p.c
index 2f0ccdd937cc..331c00ad02c0 100644
--- a/drivers/net/ipa/ipa_smp2p.c
+++ b/drivers/net/ipa/ipa_smp2p.c
@@ -232,19 +232,27 @@ ipa_smp2p_init(struct ipa *ipa, struct platform_device *pdev, bool modem_init)
&valid_bit);
if (IS_ERR(valid_state))
return PTR_ERR(valid_state);
- if (valid_bit >= 32) /* BITS_PER_U32 */
- return -EINVAL;
+ if (valid_bit >= 32) { /* BITS_PER_U32 */
+ ret = -EINVAL;
+ goto err_valid_state_put;
+ }
enabled_state = qcom_smem_state_get(dev, "ipa-clock-enabled",
&enabled_bit);
- if (IS_ERR(enabled_state))
- return PTR_ERR(enabled_state);
- if (enabled_bit >= 32) /* BITS_PER_U32 */
- return -EINVAL;
+ if (IS_ERR(enabled_state)) {
+ ret = PTR_ERR(enabled_state);
+ goto err_valid_state_put;
+ }
+ if (enabled_bit >= 32) { /* BITS_PER_U32 */
+ ret = -EINVAL;
+ goto err_enabled_state_put;
+ }
smp2p = kzalloc_obj(*smp2p);
- if (!smp2p)
- return -ENOMEM;
+ if (!smp2p) {
+ ret = -ENOMEM;
+ goto err_enabled_state_put;
+ }
smp2p->ipa = ipa;
@@ -289,6 +297,10 @@ err_null_smp2p:
ipa->smp2p = NULL;
mutex_destroy(&smp2p->mutex);
kfree(smp2p);
+err_enabled_state_put:
+ qcom_smem_state_put(enabled_state);
+err_valid_state_put:
+ qcom_smem_state_put(valid_state);
return ret;
}
@@ -305,6 +317,8 @@ void ipa_smp2p_exit(struct ipa *ipa)
ipa_smp2p_power_release(ipa);
ipa->smp2p = NULL;
mutex_destroy(&smp2p->mutex);
+ qcom_smem_state_put(smp2p->enabled_state);
+ qcom_smem_state_put(smp2p->valid_state);
kfree(smp2p);
}
diff --git a/drivers/net/mdio/mdio-i2c.c b/drivers/net/mdio/mdio-i2c.c
index b88f63234b4e..ed20352a589a 100644
--- a/drivers/net/mdio/mdio-i2c.c
+++ b/drivers/net/mdio/mdio-i2c.c
@@ -419,50 +419,6 @@ static int i2c_mii_write_rollball(struct mii_bus *bus, int phy_id, int devad,
return 0;
}
-static int i2c_mii_probe_rollball(struct i2c_adapter *i2c)
-{
- u8 data_buf[] = { ROLLBALL_DATA_ADDR, 0x01, 0x00, 0x00 };
- u8 cmd_buf[] = { ROLLBALL_CMD_ADDR, ROLLBALL_CMD_READ };
- u8 cmd_addr = ROLLBALL_CMD_ADDR;
- struct i2c_msg msgs[2];
- u8 result;
- int ret;
- int i;
-
- msgs[0].addr = ROLLBALL_PHY_I2C_ADDR;
- msgs[0].flags = 0;
- msgs[0].len = sizeof(data_buf);
- msgs[0].buf = data_buf;
- msgs[1].addr = ROLLBALL_PHY_I2C_ADDR;
- msgs[1].flags = 0;
- msgs[1].len = sizeof(cmd_buf);
- msgs[1].buf = cmd_buf;
-
- ret = i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs));
- if (ret < 0)
- return -ENODEV;
-
- msgs[0].addr = ROLLBALL_PHY_I2C_ADDR;
- msgs[0].flags = 0;
- msgs[0].len = 1;
- msgs[0].buf = &cmd_addr;
- msgs[1].addr = ROLLBALL_PHY_I2C_ADDR;
- msgs[1].flags = I2C_M_RD;
- msgs[1].len = 1;
- msgs[1].buf = &result;
-
- for (i = 0; i < 10; i++) {
- msleep(20);
- ret = i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs));
- if (ret < 0)
- return -ENODEV;
- if (result == ROLLBALL_CMD_DONE)
- return 0;
- }
-
- return -ENODEV;
-}
-
static int i2c_mii_init_rollball(struct i2c_adapter *i2c)
{
struct i2c_msg msg;
@@ -482,11 +438,11 @@ static int i2c_mii_init_rollball(struct i2c_adapter *i2c)
ret = i2c_transfer(i2c, &msg, 1);
if (ret < 0)
- return -ENODEV;
- if (ret != 1)
+ return ret;
+ else if (ret != 1)
return -EIO;
-
- return i2c_mii_probe_rollball(i2c);
+ else
+ return 0;
}
static bool mdio_i2c_check_functionality(struct i2c_adapter *i2c,
@@ -531,10 +487,9 @@ struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c,
case MDIO_I2C_ROLLBALL:
ret = i2c_mii_init_rollball(i2c);
if (ret < 0) {
- if (ret != -ENODEV)
- dev_err(parent,
- "Cannot initialize RollBall MDIO I2C protocol: %d\n",
- ret);
+ dev_err(parent,
+ "Cannot initialize RollBall MDIO I2C protocol: %d\n",
+ ret);
mdiobus_free(mii);
return ERR_PTR(ret);
}
diff --git a/drivers/net/netdevsim/ethtool.c b/drivers/net/netdevsim/ethtool.c
index 9350ba48eb81..025ea79879f3 100644
--- a/drivers/net/netdevsim/ethtool.c
+++ b/drivers/net/netdevsim/ethtool.c
@@ -252,6 +252,7 @@ void nsim_ethtool_init(struct netdevsim *ns)
ns->ethtool.channels = ns->nsim_bus_dev->num_queues;
ethtool = debugfs_create_dir("ethtool", ns->nsim_dev_port->ddir);
+ ns->ethtool_ddir = ethtool;
debugfs_create_u32("get_err", 0600, ethtool, &ns->ethtool.get_err);
debugfs_create_u32("set_err", 0600, ethtool, &ns->ethtool.set_err);
@@ -272,3 +273,8 @@ void nsim_ethtool_init(struct netdevsim *ns)
debugfs_create_u32("tx_max_pending", 0600, dir,
&ns->ethtool.ring.tx_max_pending);
}
+
+void nsim_ethtool_fini(struct netdevsim *ns)
+{
+ debugfs_remove(ns->ethtool_ddir);
+}
diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c
index 27e5f109f933..4e9d7e10b527 100644
--- a/drivers/net/netdevsim/netdev.c
+++ b/drivers/net/netdevsim/netdev.c
@@ -1165,6 +1165,7 @@ struct netdevsim *nsim_create(struct nsim_dev *nsim_dev,
return ns;
err_free_netdev:
+ nsim_ethtool_fini(ns);
free_netdev(dev);
return ERR_PTR(err);
}
@@ -1178,6 +1179,7 @@ void nsim_destroy(struct netdevsim *ns)
debugfs_remove(ns->vlan_dfs);
debugfs_remove(ns->qr_dfs);
debugfs_remove(ns->pp_dfs);
+ nsim_ethtool_fini(ns);
if (ns->nb.notifier_call)
unregister_netdevice_notifier_dev_net(ns->netdev, &ns->nb,
diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h
index 4c9cc96dcec3..64f77f93d937 100644
--- a/drivers/net/netdevsim/netdevsim.h
+++ b/drivers/net/netdevsim/netdevsim.h
@@ -154,6 +154,7 @@ struct netdevsim {
struct dentry *pp_dfs;
struct dentry *qr_dfs;
struct dentry *vlan_dfs;
+ struct dentry *ethtool_ddir;
struct nsim_ethtool ethtool;
struct netdevsim __rcu *peer;
@@ -169,6 +170,7 @@ void nsim_destroy(struct netdevsim *ns);
bool netdev_is_nsim(struct net_device *dev);
void nsim_ethtool_init(struct netdevsim *ns);
+void nsim_ethtool_fini(struct netdevsim *ns);
void nsim_udp_tunnels_debugfs_create(struct nsim_dev *nsim_dev);
int nsim_udp_tunnels_info_create(struct nsim_dev *nsim_dev,
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index 03bfd8640db9..f520206734da 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -597,7 +597,6 @@ static const struct sfp_quirk sfp_quirks[] = {
// OEM SFP-GE-T is a 1000Base-T module with broken TX_FAULT indicator
SFP_QUIRK_F("OEM", "SFP-GE-T", sfp_fixup_ignore_tx_fault),
- SFP_QUIRK_F("OEM", "SFP-10G-T-I", sfp_fixup_rollball),
SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc),
SFP_QUIRK_S("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g),
SFP_QUIRK_S("OEM", "SFP-2.5G-BX10-D", sfp_quirk_2500basex),
@@ -963,6 +962,7 @@ static int sfp_i2c_mdiobus_create(struct sfp *sfp)
static void sfp_i2c_mdiobus_destroy(struct sfp *sfp)
{
mdiobus_unregister(sfp->i2c_mii);
+ mdiobus_free(sfp->i2c_mii);
sfp->i2c_mii = NULL;
}
@@ -2173,17 +2173,10 @@ static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn)
static int sfp_sm_add_mdio_bus(struct sfp *sfp)
{
- int ret;
-
- if (sfp->mdio_protocol == MDIO_I2C_NONE)
- return 0;
+ if (sfp->mdio_protocol != MDIO_I2C_NONE)
+ return sfp_i2c_mdiobus_create(sfp);
- ret = sfp_i2c_mdiobus_create(sfp);
- if (ret == -ENODEV) {
- sfp->mdio_protocol = MDIO_I2C_NONE;
- return 0;
- }
- return ret;
+ return 0;
}
/* Probe a SFP for a PHY device if the module supports copper - the PHY
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 69dbdbde9d71..a5e6d7b26b9f 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -1367,7 +1367,7 @@ static void __pse_control_release(struct kref *kref)
if (psec->pcdev->pi[psec->id].admin_state_enabled)
regulator_disable(psec->ps);
- devm_regulator_put(psec->ps);
+ regulator_put(psec->ps);
module_put(psec->pcdev->owner);
@@ -1436,8 +1436,8 @@ pse_control_get_internal(struct pse_controller_dev *pcdev, unsigned int index,
goto free_psec;
pcdev->pi[index].admin_state_enabled = ret;
- psec->ps = devm_regulator_get_exclusive(pcdev->dev,
- rdev_get_name(pcdev->pi[index].rdev));
+ psec->ps = regulator_get_exclusive(pcdev->dev,
+ rdev_get_name(pcdev->pi[index].rdev));
if (IS_ERR(psec->ps)) {
ret = PTR_ERR(psec->ps);
goto put_module;
diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c
index 0bfa37c14059..09afd137b64e 100644
--- a/drivers/net/usb/gl620a.c
+++ b/drivers/net/usb/gl620a.c
@@ -104,6 +104,9 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
return 0;
}
+ if (!skb_pull(skb, size + 4))
+ return 0;
+
// allocate the skb for the individual packet
gl_skb = alloc_skb(size, GFP_ATOMIC);
if (gl_skb) {
@@ -116,9 +119,6 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
// advance to the next packet
packet = (struct gl_packet *)&packet->packet_data[size];
count--;
-
- // shift the data pointer to the next gl_packet
- skb_pull(skb, size + 4);
}
// skip the packet length field 4 bytes
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 26afa6341d16..3e2a5876c6c8 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -3011,6 +3011,9 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
unsigned int xdp_xmit = 0;
bool napi_complete;
+ if (budget)
+ virtqueue_disable_cb(rq->vq);
+
virtnet_poll_cleantx(rq, budget);
received = virtnet_receive(rq, budget, &xdp_xmit);
diff --git a/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c b/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c
index bff46f7ca59f..0bbd41263cc2 100644
--- a/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c
+++ b/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c
@@ -553,19 +553,21 @@ static int mux_dl_process_dg(struct iosm_mux *ipc_mux, struct mux_adbh *adbh,
u32 packet_offset, i, rc, dg_len;
for (i = 0; i < nr_of_dg; i++, dg++) {
- if (le32_to_cpu(dg->datagram_index)
- < sizeof(struct mux_adbh))
+ u32 dg_index = le32_to_cpu(dg->datagram_index);
+
+ dg_len = le16_to_cpu(dg->datagram_length);
+
+ if (dg_index < sizeof(struct mux_adbh))
goto dg_error;
- /* Is the packet inside of the ADB */
- if (le32_to_cpu(dg->datagram_index) >=
- le32_to_cpu(adbh->block_length)) {
+ /* Is the packet inside of the ADB and the received skb ? */
+ if (dg_index >= le32_to_cpu(adbh->block_length) ||
+ dg_index >= skb->len ||
+ dg_len > skb->len - dg_index ||
+ dl_head_pad_len >= dg_len) {
goto dg_error;
} else {
- packet_offset =
- le32_to_cpu(dg->datagram_index) +
- dl_head_pad_len;
- dg_len = le16_to_cpu(dg->datagram_length);
+ packet_offset = dg_index + dl_head_pad_len;
/* Pass the packet to the netif layer. */
rc = ipc_mux_net_receive(ipc_mux, if_id, ipc_mux->wwan,
packet_offset,
@@ -589,12 +591,16 @@ static void mux_dl_adb_decode(struct iosm_mux *ipc_mux,
struct mux_adbh *adbh;
struct mux_adth *adth;
int nr_of_dg, if_id;
- u32 adth_index;
+ u32 adth_index, prev_index = 0;
u8 *block;
block = skb->data;
adbh = (struct mux_adbh *)block;
+ /* The block header itself must fit in the received skb. */
+ if (skb->len < sizeof(struct mux_adbh))
+ goto adb_decode_err;
+
/* Process the aggregated datagram tables. */
adth_index = le32_to_cpu(adbh->first_table_index);
@@ -606,6 +612,16 @@ static void mux_dl_adb_decode(struct iosm_mux *ipc_mux,
/* Loop through mixed session tables. */
while (adth_index) {
+ /* The table header must lie within the received skb, and the
+ * chain must move forward so a modem cannot make the loop
+ * cycle between two tables.
+ */
+ if (adth_index <= prev_index ||
+ adth_index < sizeof(struct mux_adbh) ||
+ adth_index > skb->len - sizeof(struct mux_adth))
+ goto adb_decode_err;
+ prev_index = adth_index;
+
/* Get the reference to the table header. */
adth = (struct mux_adth *)(block + adth_index);
@@ -629,6 +645,10 @@ static void mux_dl_adb_decode(struct iosm_mux *ipc_mux,
if (le16_to_cpu(adth->table_length) < sizeof(struct mux_adth))
goto adb_decode_err;
+ /* The whole datagram table must fit in the received skb. */
+ if (le16_to_cpu(adth->table_length) > skb->len - adth_index)
+ goto adb_decode_err;
+
/* Calculate the number of datagrams. */
nr_of_dg = (le16_to_cpu(adth->table_length) -
sizeof(struct mux_adth)) /
diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c
index 1a163596ddf5..36bee0d8ac6c 100644
--- a/drivers/ntb/hw/amd/ntb_hw_amd.c
+++ b/drivers/ntb/hw/amd/ntb_hw_amd.c
@@ -376,7 +376,7 @@ static int amd_ntb_link_disable(struct ntb_dev *ntb)
if (ndev->ntb.topo == NTB_TOPO_SEC)
return -EINVAL;
- dev_dbg(&ntb->pdev->dev, "Enabling Link.\n");
+ dev_dbg(&ntb->pdev->dev, "Disabling Link.\n");
return 0;
}
@@ -1328,15 +1328,15 @@ static const struct ntb_dev_data dev_data[] = {
};
static const struct pci_device_id amd_ntb_pci_tbl[] = {
- { PCI_VDEVICE(AMD, 0x145b), (kernel_ulong_t)&dev_data[0] },
- { PCI_VDEVICE(AMD, 0x148b), (kernel_ulong_t)&dev_data[1] },
- { PCI_VDEVICE(AMD, 0x14c0), (kernel_ulong_t)&dev_data[1] },
- { PCI_VDEVICE(AMD, 0x14c3), (kernel_ulong_t)&dev_data[1] },
- { PCI_VDEVICE(AMD, 0x155a), (kernel_ulong_t)&dev_data[1] },
- { PCI_VDEVICE(AMD, 0x17d4), (kernel_ulong_t)&dev_data[1] },
- { PCI_VDEVICE(AMD, 0x17d7), (kernel_ulong_t)&dev_data[2] },
- { PCI_VDEVICE(HYGON, 0x145b), (kernel_ulong_t)&dev_data[0] },
- { 0, }
+ { PCI_VDEVICE(AMD, 0x145b), .driver_data = (kernel_ulong_t)&dev_data[0] },
+ { PCI_VDEVICE(AMD, 0x148b), .driver_data = (kernel_ulong_t)&dev_data[1] },
+ { PCI_VDEVICE(AMD, 0x14c0), .driver_data = (kernel_ulong_t)&dev_data[1] },
+ { PCI_VDEVICE(AMD, 0x14c3), .driver_data = (kernel_ulong_t)&dev_data[1] },
+ { PCI_VDEVICE(AMD, 0x155a), .driver_data = (kernel_ulong_t)&dev_data[1] },
+ { PCI_VDEVICE(AMD, 0x17d4), .driver_data = (kernel_ulong_t)&dev_data[1] },
+ { PCI_VDEVICE(AMD, 0x17d7), .driver_data = (kernel_ulong_t)&dev_data[2] },
+ { PCI_VDEVICE(HYGON, 0x145b), .driver_data = (kernel_ulong_t)&dev_data[0] },
+ { }
};
MODULE_DEVICE_TABLE(pci, amd_ntb_pci_tbl);
diff --git a/drivers/ntb/hw/epf/ntb_hw_epf.c b/drivers/ntb/hw/epf/ntb_hw_epf.c
index af5755472842..c47607d4f8a7 100644
--- a/drivers/ntb/hw/epf/ntb_hw_epf.c
+++ b/drivers/ntb/hw/epf/ntb_hw_epf.c
@@ -729,7 +729,8 @@ static void ntb_epf_deinit_pci(struct ntb_epf_dev *ndev)
struct pci_dev *pdev = ndev->ntb.pdev;
pci_iounmap(pdev, ndev->ctrl_reg);
- pci_iounmap(pdev, ndev->peer_spad_reg);
+ if (ndev->barno_map[BAR_PEER_SPAD] != ndev->barno_map[BAR_CONFIG])
+ pci_iounmap(pdev, ndev->peer_spad_reg);
pci_iounmap(pdev, ndev->db_reg);
pci_release_regions(pdev);
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 7cb0d7e88247..6e7a42dedad3 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -2160,7 +2160,7 @@ static bool of_check_bad_map(const __be32 *map, int len)
* @map_mask_name: optional property name of the mask to use.
* @filter_np: pointer to an optional filter node, or NULL to allow bypass.
* If non-NULL, the map property must exist (-ENODEV if absent). If
- * *filter_np is also non-NULL, only entries targeting that node match.
+ * ``*filter_np`` is also non-NULL, only entries targeting that node match.
* @arg: pointer to a &struct of_phandle_args for the result. On success,
* @arg->args_count will be set to the number of output specifier cells
* as defined by @cells_name in the target node, and
@@ -2350,7 +2350,7 @@ EXPORT_SYMBOL_GPL(of_map_iommu_id);
* stream/device ID) used as the lookup key in the msi-map table.
* @filter_np: pointer to an optional filter node, or NULL to allow bypass.
* If non-NULL, the map property must exist (-ENODEV if absent). If
- * *filter_np is also non-NULL, only entries targeting that node match.
+ * ``*filter_np`` is also non-NULL, only entries targeting that node match.
* @arg: pointer to a &struct of_phandle_args for the result. On success,
* @arg->args_count will be set to the number of output specifier cells
* and @arg->args[0..args_count-1] will contain the translated output
diff --git a/drivers/of/property.c b/drivers/of/property.c
index b276d1de3222..72cf12907de0 100644
--- a/drivers/of/property.c
+++ b/drivers/of/property.c
@@ -1172,6 +1172,14 @@ of_fwnode_get_reference_args(const struct fwnode_handle *fwnode,
unsigned int i;
int ret;
+ /*
+ * This function should return -ENOENT for out of bound indexes,
+ * but the OF API uses signed indexes and consider negative indexes
+ * as invalid. Catch them here to correctly implement the fwnode API.
+ */
+ if ((int)index < 0)
+ return -ENOENT;
+
if (nargs_prop)
ret = of_parse_phandle_with_args(to_of_node(fwnode), prop,
nargs_prop, index, &of_args);
diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c
index b2eb9909f6a4..d50ea62fa2f3 100644
--- a/drivers/platform/x86/amd/pmc/pmc.c
+++ b/drivers/platform/x86/amd/pmc/pmc.c
@@ -645,9 +645,12 @@ static int amd_pmc_verify_czn_rtc(struct amd_pmc_dev *pdev, u32 *arg)
rtc_device = rtc_class_open("rtc0");
if (!rtc_device)
return 0;
- rc = rtc_read_alarm(rtc_device, &alarm);
- if (rc)
- return rc;
+ rc = rtc_read_next_alarm(rtc_device, &alarm);
+ if (rc) {
+ if (rc == -ENOENT)
+ dev_dbg(pdev->dev, "no alarm pending\n");
+ return rc == -ENOENT ? 0 : rc;
+ }
if (!alarm.enabled) {
dev_dbg(pdev->dev, "alarm not enabled\n");
return 0;
diff --git a/drivers/pwm/pwm-rzg2l-gpt.c b/drivers/pwm/pwm-rzg2l-gpt.c
index 4856af080e8e..dfa1d11a48a8 100644
--- a/drivers/pwm/pwm-rzg2l-gpt.c
+++ b/drivers/pwm/pwm-rzg2l-gpt.c
@@ -81,7 +81,7 @@ struct rzg2l_gpt_chip {
void __iomem *mmio;
struct mutex lock; /* lock to protect shared channel resources */
unsigned long rate_khz;
- u32 period_ticks[RZG2L_MAX_HW_CHANNELS];
+ u64 period_ticks[RZG2L_MAX_HW_CHANNELS];
u32 channel_request_count[RZG2L_MAX_HW_CHANNELS];
u32 channel_enable_count[RZG2L_MAX_HW_CHANNELS];
};
@@ -408,14 +408,14 @@ static int rzg2l_gpt_probe(struct platform_device *pdev)
rate = clk_get_rate(clk);
if (!rate)
- return dev_err_probe(dev, -EINVAL, "The gpt clk rate is 0");
+ return dev_err_probe(dev, -EINVAL, "The gpt clk rate is 0\n");
/*
* Refuse clk rates > 1 GHz to prevent overflow later for computing
* period and duty cycle.
*/
if (rate > NSEC_PER_SEC)
- return dev_err_probe(dev, -EINVAL, "The gpt clk rate is > 1GHz");
+ return dev_err_probe(dev, -EINVAL, "The gpt clk rate is > 1GHz\n");
/*
* Rate is in MHz and is always integer for peripheral clk
@@ -424,7 +424,7 @@ static int rzg2l_gpt_probe(struct platform_device *pdev)
*/
rzg2l_gpt->rate_khz = rate / KILO;
if (rzg2l_gpt->rate_khz * KILO != rate)
- return dev_err_probe(dev, -EINVAL, "Rate is not multiple of 1000");
+ return dev_err_probe(dev, -EINVAL, "Rate is not multiple of 1000\n");
mutex_init(&rzg2l_gpt->lock);
diff --git a/drivers/regulator/da9121-regulator.c b/drivers/regulator/da9121-regulator.c
index 2b150bb4d471..36a52f707602 100644
--- a/drivers/regulator/da9121-regulator.c
+++ b/drivers/regulator/da9121-regulator.c
@@ -1195,15 +1195,15 @@ static void da9121_i2c_remove(struct i2c_client *i2c)
}
static const struct i2c_device_id da9121_i2c_id[] = {
- {"da9121", DA9121_TYPE_DA9121_DA9130},
- {"da9130", DA9121_TYPE_DA9121_DA9130},
- {"da9217", DA9121_TYPE_DA9217},
- {"da9122", DA9121_TYPE_DA9122_DA9131},
- {"da9131", DA9121_TYPE_DA9122_DA9131},
- {"da9220", DA9121_TYPE_DA9220_DA9132},
- {"da9132", DA9121_TYPE_DA9220_DA9132},
- {"da9141", DA9121_TYPE_DA9141},
- {"da9142", DA9121_TYPE_DA9142},
+ {"da9121", DA9121_SUBTYPE_DA9121},
+ {"da9130", DA9121_SUBTYPE_DA9130},
+ {"da9217", DA9121_SUBTYPE_DA9217},
+ {"da9122", DA9121_SUBTYPE_DA9122},
+ {"da9131", DA9121_SUBTYPE_DA9131},
+ {"da9220", DA9121_SUBTYPE_DA9220},
+ {"da9132", DA9121_SUBTYPE_DA9132},
+ {"da9141", DA9121_SUBTYPE_DA9141},
+ {"da9142", DA9121_SUBTYPE_DA9142},
{},
};
MODULE_DEVICE_TABLE(i2c, da9121_i2c_id);
diff --git a/drivers/regulator/pca9450-regulator.c b/drivers/regulator/pca9450-regulator.c
index 45d7dc44c2cd..c41db70fa052 100644
--- a/drivers/regulator/pca9450-regulator.c
+++ b/drivers/regulator/pca9450-regulator.c
@@ -44,6 +44,7 @@ struct pca9450 {
unsigned int rcnt;
int irq;
bool sd_vsel_fixed_low;
+ int default_t_off_deb;
};
static const struct regmap_range pca9450_status_range = {
@@ -1209,7 +1210,7 @@ static int pca9450_of_init(struct pca9450 *pca9450)
ret = of_property_read_u32(i2c->dev.of_node, "nxp,pmic-on-req-off-debounce-us", &val);
if (ret == -EINVAL)
- t_off_deb = T_OFF_DEB_120US;
+ t_off_deb = pca9450->default_t_off_deb;
else if (ret)
return ret;
else {
@@ -1304,21 +1305,25 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
case PCA9450_TYPE_PCA9450A:
regulator_desc = pca9450a_regulators;
pca9450->rcnt = ARRAY_SIZE(pca9450a_regulators);
+ pca9450->default_t_off_deb = T_OFF_DEB_120US;
type_name = "pca9450a";
break;
case PCA9450_TYPE_PCA9450BC:
regulator_desc = pca9450bc_regulators;
pca9450->rcnt = ARRAY_SIZE(pca9450bc_regulators);
+ pca9450->default_t_off_deb = T_OFF_DEB_120US;
type_name = "pca9450bc";
break;
case PCA9450_TYPE_PCA9451A:
regulator_desc = pca9451a_regulators;
pca9450->rcnt = ARRAY_SIZE(pca9451a_regulators);
+ pca9450->default_t_off_deb = T_OFF_DEB_2MS;
type_name = "pca9451a";
break;
case PCA9450_TYPE_PCA9452:
regulator_desc = pca9451a_regulators;
pca9450->rcnt = ARRAY_SIZE(pca9451a_regulators);
+ pca9450->default_t_off_deb = T_OFF_DEB_2MS;
type_name = "pca9452";
break;
default:
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 364afc73f8ab..01def8231873 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1763,13 +1763,6 @@ config RTC_DRV_STMP
This driver can also be built as a module. If so, the module
will be called rtc-stmp3xxx.
-config RTC_DRV_PCAP
- tristate "PCAP RTC"
- depends on EZX_PCAP
- help
- If you say Y here you will get support for the RTC found on
- the PCAP2 ASIC used on some Motorola phones.
-
config RTC_DRV_MC13XXX
depends on MFD_MC13XXX
tristate "Freescale MC13xxx RTC"
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 6cf7e066314e..0347645b021f 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -128,7 +128,6 @@ obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o
obj-$(CONFIG_RTC_DRV_OPTEE) += rtc-optee.o
obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o
-obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o
obj-$(CONFIG_RTC_DRV_PCF2123) += rtc-pcf2123.o
obj-$(CONFIG_RTC_DRV_PCF2127) += rtc-pcf2127.o
obj-$(CONFIG_RTC_DRV_PCF85063) += rtc-pcf85063.o
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 1906f4884a83..96626f8068f9 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -384,6 +384,46 @@ done:
return err;
}
+/**
+ * rtc_read_next_alarm - read the next expiring alarm
+ * @rtc: RTC device
+ * @alarm: storage for the alarm information
+ *
+ * Read the next expiring alarm from the RTC timerqueue. This returns
+ * the alarm that will actually fire next, which may be different from
+ * rtc_read_alarm() if multiple timers are queued (e.g., alarmtimer
+ * and wakealarm sysfs both active).
+ *
+ * Returns: 0 on success, -ENOENT if no alarm is pending, or other error.
+ */
+int rtc_read_next_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
+{
+ struct timerqueue_node *next;
+ int err;
+
+ if (!rtc || !alarm)
+ return -EINVAL;
+
+ err = mutex_lock_interruptible(&rtc->ops_lock);
+ if (err)
+ return err;
+
+ next = timerqueue_getnext(&rtc->timerqueue);
+ if (!next) {
+ err = -ENOENT;
+ goto unlock;
+ }
+
+ memset(alarm, 0, sizeof(struct rtc_wkalrm));
+ alarm->time = rtc_ktime_to_tm(next->expires);
+ alarm->enabled = 1;
+
+unlock:
+ mutex_unlock(&rtc->ops_lock);
+ return err;
+}
+EXPORT_SYMBOL_GPL(rtc_read_next_alarm);
+
int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
{
int err;
@@ -635,8 +675,8 @@ EXPORT_SYMBOL_GPL(rtc_update_irq_enable);
/**
* rtc_handle_legacy_irq - AIE, UIE and PIE event hook
* @rtc: pointer to the rtc device
- * @num: number of occurence of the event
- * @mode: type of the event, RTC_AF, RTC_UF of RTC_PF
+ * @num: number of occurrence of the event
+ * @mode: type of the event, RTC_AF, RTC_UF or RTC_PF
*
* This function is called when an AIE, UIE or PIE mode interrupt
* has occurred (or been emulated).
diff --git a/drivers/rtc/rtc-88pm886.c b/drivers/rtc/rtc-88pm886.c
index 57e9b0a66eed..13aa3ae82239 100644
--- a/drivers/rtc/rtc-88pm886.c
+++ b/drivers/rtc/rtc-88pm886.c
@@ -78,7 +78,7 @@ static int pm886_rtc_probe(struct platform_device *pdev)
}
static const struct platform_device_id pm886_rtc_id_table[] = {
- { "88pm886-rtc", },
+ { .name = "88pm886-rtc" },
{ }
};
MODULE_DEVICE_TABLE(platform, pm886_rtc_id_table);
diff --git a/drivers/rtc/rtc-ab-b5ze-s3.c b/drivers/rtc/rtc-ab-b5ze-s3.c
index 684f9898d768..6439ca427c32 100644
--- a/drivers/rtc/rtc-ab-b5ze-s3.c
+++ b/drivers/rtc/rtc-ab-b5ze-s3.c
@@ -933,7 +933,7 @@ MODULE_DEVICE_TABLE(of, abb5zes3_dt_match);
#endif
static const struct i2c_device_id abb5zes3_id[] = {
- { "abb5zes3" },
+ { .name = "abb5zes3" },
{ }
};
MODULE_DEVICE_TABLE(i2c, abb5zes3_id);
diff --git a/drivers/rtc/rtc-ab-eoz9.c b/drivers/rtc/rtc-ab-eoz9.c
index de002f7a39bf..b75f4f665076 100644
--- a/drivers/rtc/rtc-ab-eoz9.c
+++ b/drivers/rtc/rtc-ab-eoz9.c
@@ -546,7 +546,7 @@ MODULE_DEVICE_TABLE(of, abeoz9_dt_match);
#endif
static const struct i2c_device_id abeoz9_id[] = {
- { "abeoz9" },
+ { .name = "abeoz9" },
{ }
};
diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c
index ed2b6b8bb3bf..0978bd0a3393 100644
--- a/drivers/rtc/rtc-ab8500.c
+++ b/drivers/rtc/rtc-ab8500.c
@@ -284,11 +284,10 @@ static ssize_t ab8500_sysfs_show_rtc_calibration(struct device *dev,
retval = ab8500_rtc_get_calibration(dev, &calibration);
if (retval < 0) {
dev_err(dev, "Failed to read RTC calibration attribute\n");
- sprintf(buf, "0\n");
return retval;
}
- return sprintf(buf, "%d\n", calibration);
+ return sysfs_emit(buf, "%d\n", calibration);
}
static DEVICE_ATTR(rtc_calibration, S_IRUGO | S_IWUSR,
@@ -324,14 +323,13 @@ static const struct rtc_class_ops ab8500_rtc_ops = {
};
static const struct platform_device_id ab85xx_rtc_ids[] = {
- { "ab8500-rtc", (kernel_ulong_t)&ab8500_rtc_ops, },
+ { .name = "ab8500-rtc" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, ab85xx_rtc_ids);
static int ab8500_rtc_probe(struct platform_device *pdev)
{
- const struct platform_device_id *platid = platform_get_device_id(pdev);
int err;
struct rtc_device *rtc;
u8 rtc_ctrl;
@@ -367,7 +365,7 @@ static int ab8500_rtc_probe(struct platform_device *pdev)
if (IS_ERR(rtc))
return PTR_ERR(rtc);
- rtc->ops = (struct rtc_class_ops *)platid->driver_data;
+ rtc->ops = &ab8500_rtc_ops;
err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
rtc_alarm_handler, IRQF_ONESHOT,
diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c
index 00d7de64ed3e..5486d9d0b1e5 100644
--- a/drivers/rtc/rtc-abx80x.c
+++ b/drivers/rtc/rtc-abx80x.c
@@ -545,7 +545,8 @@ static int abx80x_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
status &= ~ABX8XX_STATUS_BLF;
- tmp = i2c_smbus_write_byte_data(client, ABX8XX_REG_STATUS, 0);
+ tmp = i2c_smbus_write_byte_data(client, ABX8XX_REG_STATUS,
+ status);
if (tmp < 0)
return tmp;
@@ -752,16 +753,16 @@ static int abx80x_setup_nvmem(struct abx80x_priv *priv)
}
static const struct i2c_device_id abx80x_id[] = {
- { "abx80x", ABX80X },
- { "ab0801", AB0801 },
- { "ab0803", AB0803 },
- { "ab0804", AB0804 },
- { "ab0805", AB0805 },
- { "ab1801", AB1801 },
- { "ab1803", AB1803 },
- { "ab1804", AB1804 },
- { "ab1805", AB1805 },
- { "rv1805", RV1805 },
+ { .name = "abx80x", .driver_data = ABX80X },
+ { .name = "ab0801", .driver_data = AB0801 },
+ { .name = "ab0803", .driver_data = AB0803 },
+ { .name = "ab0804", .driver_data = AB0804 },
+ { .name = "ab0805", .driver_data = AB0805 },
+ { .name = "ab1801", .driver_data = AB1801 },
+ { .name = "ab1803", .driver_data = AB1803 },
+ { .name = "ab1804", .driver_data = AB1804 },
+ { .name = "ab1805", .driver_data = AB1805 },
+ { .name = "rv1805", .driver_data = RV1805 },
{ }
};
MODULE_DEVICE_TABLE(i2c, abx80x_id);
diff --git a/drivers/rtc/rtc-aspeed.c b/drivers/rtc/rtc-aspeed.c
index 0d0053b52f9b..8f5b440f8c0a 100644
--- a/drivers/rtc/rtc-aspeed.c
+++ b/drivers/rtc/rtc-aspeed.c
@@ -111,6 +111,7 @@ static const struct of_device_id aspeed_rtc_match[] = {
{ .compatible = "aspeed,ast2400-rtc", },
{ .compatible = "aspeed,ast2500-rtc", },
{ .compatible = "aspeed,ast2600-rtc", },
+ { .compatible = "aspeed,ast2700-rtc", },
{}
};
MODULE_DEVICE_TABLE(of, aspeed_rtc_match);
diff --git a/drivers/rtc/rtc-bd70528.c b/drivers/rtc/rtc-bd70528.c
index 4c8599761b2e..482810b61495 100644
--- a/drivers/rtc/rtc-bd70528.c
+++ b/drivers/rtc/rtc-bd70528.c
@@ -341,10 +341,10 @@ static int bd70528_probe(struct platform_device *pdev)
}
static const struct platform_device_id bd718x7_rtc_id[] = {
- { "bd71828-rtc", ROHM_CHIP_TYPE_BD71828 },
- { "bd71815-rtc", ROHM_CHIP_TYPE_BD71815 },
- { "bd72720-rtc", ROHM_CHIP_TYPE_BD72720 },
- { },
+ { .name = "bd71828-rtc", .driver_data = ROHM_CHIP_TYPE_BD71828 },
+ { .name = "bd71815-rtc", .driver_data = ROHM_CHIP_TYPE_BD71815 },
+ { .name = "bd72720-rtc", .driver_data = ROHM_CHIP_TYPE_BD72720 },
+ { }
};
MODULE_DEVICE_TABLE(platform, bd718x7_rtc_id);
diff --git a/drivers/rtc/rtc-bq32k.c b/drivers/rtc/rtc-bq32k.c
index 7ad34539be4d..573231613e52 100644
--- a/drivers/rtc/rtc-bq32k.c
+++ b/drivers/rtc/rtc-bq32k.c
@@ -16,6 +16,7 @@
#include <linux/kstrtox.h>
#include <linux/errno.h>
#include <linux/bcd.h>
+#include <linux/delay.h>
#define BQ32K_SECONDS 0x00 /* Seconds register address */
#define BQ32K_SECONDS_MASK 0x7F /* Mask over seconds value */
@@ -89,9 +90,17 @@ static int bq32k_write(struct device *dev, void *data, uint8_t off, uint8_t len)
static int bq32k_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct bq32k_regs regs;
int error;
+ /*
+ * When the device doesn't have the interrupt connected, prevent
+ * userpace from polling the RTC registers too frequently.
+ */
+ if (client->irq <= 0)
+ usleep_range(2000, 2500);
+
error = bq32k_read(dev, &regs, 0, sizeof(regs));
if (error)
return error;
@@ -304,7 +313,7 @@ static void bq32k_remove(struct i2c_client *client)
}
static const struct i2c_device_id bq32k_id[] = {
- { "bq32000" },
+ { .name = "bq32000" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bq32k_id);
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index f89ab58f5048..fa04ece151b8 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -934,6 +934,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
unsigned char rtc_control;
unsigned address_space;
u32 flags = 0;
+ bool hpet_registered = false;
struct nvmem_config nvmem_cfg = {
.name = "cmos_nvram",
.word_size = 1,
@@ -1091,6 +1092,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
" failed in rtc_init().");
goto cleanup1;
}
+ hpet_registered = true;
} else
rtc_cmos_int_handler = cmos_interrupt;
@@ -1140,6 +1142,10 @@ cleanup2:
if (is_valid_irq(rtc_irq))
free_irq(rtc_irq, cmos_rtc.rtc);
cleanup1:
+ if (hpet_registered) {
+ hpet_mask_rtc_irq_bit(RTC_IRQMASK);
+ hpet_unregister_irq_handler(cmos_interrupt);
+ }
cmos_rtc.dev = NULL;
cleanup0:
if (RTC_IOMAPPED)
diff --git a/drivers/rtc/rtc-cros-ec.c b/drivers/rtc/rtc-cros-ec.c
index e956505a06fb..f3ecd017e2f7 100644
--- a/drivers/rtc/rtc-cros-ec.c
+++ b/drivers/rtc/rtc-cros-ec.c
@@ -388,8 +388,8 @@ static void cros_ec_rtc_remove(struct platform_device *pdev)
}
static const struct platform_device_id cros_ec_rtc_id[] = {
- { DRV_NAME, 0 },
- {}
+ { .name = DRV_NAME },
+ { }
};
MODULE_DEVICE_TABLE(platform, cros_ec_rtc_id);
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 7205c59ff729..0707ded5368b 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -269,6 +269,16 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
if (tmp & DS1338_BIT_OSF)
return -EINVAL;
break;
+ case ds_1337:
+ case ds_1339:
+ case ds_1341:
+ case ds_3231:
+ ret = regmap_read(ds1307->regmap, DS1337_REG_STATUS, &tmp);
+ if (ret)
+ return ret;
+ if (tmp & DS1337_BIT_OSF)
+ return -EINVAL;
+ break;
case ds_1340:
if (tmp & DS1340_BIT_nEOSC)
return -EINVAL;
@@ -279,13 +289,6 @@ 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)
@@ -308,7 +311,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
t->tm_hour = bcd2bin(tmp);
/* rx8130 is bit position, not BCD */
if (ds1307->type == rx_8130)
- t->tm_wday = fls(regs[DS1307_REG_WDAY] & 0x7f);
+ t->tm_wday = fls(regs[DS1307_REG_WDAY] & 0x7f) - 1;
else
t->tm_wday = bcd2bin(regs[DS1307_REG_WDAY] & 0x07) - 1;
t->tm_mday = bcd2bin(regs[DS1307_REG_MDAY] & 0x3f);
@@ -380,14 +383,17 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
regmap_update_bits(ds1307->regmap, DS1307_REG_CONTROL,
DS1338_BIT_OSF, 0);
break;
- case ds_1340:
- regmap_update_bits(ds1307->regmap, DS1340_REG_FLAG,
- DS1340_BIT_OSF, 0);
- break;
+ case ds_1337:
+ case ds_1339:
case ds_1341:
+ case ds_3231:
regmap_update_bits(ds1307->regmap, DS1337_REG_STATUS,
DS1337_BIT_OSF, 0);
break;
+ case ds_1340:
+ regmap_update_bits(ds1307->regmap, DS1340_REG_FLAG,
+ DS1340_BIT_OSF, 0);
+ break;
case ds_1388:
regmap_update_bits(ds1307->regmap, DS1388_REG_FLAG,
DS1388_BIT_OSF, 0);
@@ -1063,24 +1069,24 @@ static const struct chip_desc chips[last_ds_type] = {
};
static const struct i2c_device_id ds1307_id[] = {
- { "ds1307", ds_1307 },
- { "ds1308", ds_1308 },
- { "ds1337", ds_1337 },
- { "ds1338", ds_1338 },
- { "ds1339", ds_1339 },
- { "ds1388", ds_1388 },
- { "ds1340", ds_1340 },
- { "ds1341", ds_1341 },
- { "ds3231", ds_3231 },
- { "m41t0", m41t0 },
- { "m41t00", m41t00 },
- { "m41t11", m41t11 },
- { "mcp7940x", mcp794xx },
- { "mcp7941x", mcp794xx },
- { "pt7c4338", ds_1307 },
- { "rx8025", rx_8025 },
- { "isl12057", ds_1337 },
- { "rx8130", rx_8130 },
+ { .name = "ds1307", .driver_data = ds_1307 },
+ { .name = "ds1308", .driver_data = ds_1308 },
+ { .name = "ds1337", .driver_data = ds_1337 },
+ { .name = "ds1338", .driver_data = ds_1338 },
+ { .name = "ds1339", .driver_data = ds_1339 },
+ { .name = "ds1388", .driver_data = ds_1388 },
+ { .name = "ds1340", .driver_data = ds_1340 },
+ { .name = "ds1341", .driver_data = ds_1341 },
+ { .name = "ds3231", .driver_data = ds_3231 },
+ { .name = "m41t0", .driver_data = m41t0 },
+ { .name = "m41t00", .driver_data = m41t00 },
+ { .name = "m41t11", .driver_data = m41t11 },
+ { .name = "mcp7940x", .driver_data = mcp794xx },
+ { .name = "mcp7941x", .driver_data = mcp794xx },
+ { .name = "pt7c4338", .driver_data = ds_1307 },
+ { .name = "rx8025", .driver_data = rx_8025 },
+ { .name = "isl12057", .driver_data = ds_1337 },
+ { .name = "rx8130", .driver_data = rx_8130 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ds1307_id);
@@ -1409,7 +1415,7 @@ static void ds1307_hwmon_register(struct ds1307 *ds1307)
{
}
-#endif /* CONFIG_RTC_DRV_DS1307_HWMON */
+#endif /* IS_REACHABLE(CONFIG_HWMON) */
/*----------------------------------------------------------------------*/
@@ -1658,18 +1664,153 @@ static int ds3231_clks_register(struct ds1307 *ds1307)
return 0;
}
+/* ds1307 RTC clock output support */
+static unsigned long ds1307_clk_rates[] = {
+ 1,
+ 4096,
+ 8192,
+ 32768,
+};
+
+static unsigned long ds1307_clk_sqw_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ int ret;
+ unsigned int rate_id;
+ struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
+
+ ret = regmap_read(ds1307->regmap, DS1307_REG_CONTROL, &rate_id);
+ if (ret)
+ return ret;
+
+ rate_id &= (DS1307_BIT_RS1 | DS1307_BIT_RS0);
+
+ return ds1307_clk_rates[rate_id];
+}
+
+static int ds1307_clk_sqw_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ds1307_clk_rates); i++) {
+ if (req->rate <= ds1307_clk_rates[i]) {
+ req->rate = ds1307_clk_rates[i];
+ return 0;
+ }
+ }
+
+ /* Default rate 1Hz */
+ req->rate = ds1307_clk_rates[0];
+
+ return 0;
+}
+
+static int ds1307_clk_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ int id, ret;
+ struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
+
+ for (id = 0; id < ARRAY_SIZE(ds1307_clk_rates); id++) {
+ if (ds1307_clk_rates[id] == rate)
+ break;
+ }
+
+ if (id >= ARRAY_SIZE(ds1307_clk_rates))
+ return -EINVAL;
+
+ ret = regmap_update_bits(ds1307->regmap, DS1307_REG_CONTROL,
+ DS1307_BIT_RS0 | DS1307_BIT_RS1, id);
+
+ return ret;
+}
+
+static int ds1307_clk_sqw_prepare(struct clk_hw *hw)
+{
+ int ret;
+ struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
+
+ ret = regmap_update_bits(ds1307->regmap, DS1307_REG_CONTROL,
+ DS1307_BIT_SQWE, DS1307_BIT_SQWE);
+
+ return ret;
+}
+
+static void ds1307_clk_sqw_unprepare(struct clk_hw *hw)
+{
+ struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
+
+ regmap_update_bits(ds1307->regmap, DS1307_REG_CONTROL,
+ DS1307_BIT_SQWE, ~DS1307_BIT_SQWE);
+}
+
+static int ds1307_clk_sqw_is_prepared(struct clk_hw *hw)
+{
+ int ret;
+ struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
+ unsigned int status;
+
+ ret = regmap_read(ds1307->regmap, DS1307_REG_CONTROL, &status);
+ if (ret)
+ return ret;
+
+ return !!(status & DS1307_BIT_SQWE);
+}
+
+static const struct clk_ops ds1307_clk_sqw_ops = {
+ .prepare = ds1307_clk_sqw_prepare,
+ .unprepare = ds1307_clk_sqw_unprepare,
+ .is_prepared = ds1307_clk_sqw_is_prepared,
+ .recalc_rate = ds1307_clk_sqw_recalc_rate,
+ .set_rate = ds1307_clk_sqw_set_rate,
+ .determine_rate = ds1307_clk_sqw_determine_rate,
+};
+
+static int rtc_ds1307_clks_register(struct ds1307 *ds1307)
+{
+ struct device_node *node = ds1307->dev->of_node;
+ struct clk *clk;
+ struct clk_init_data init = {0};
+
+ init.name = "ds1307_clk_sqw";
+ init.ops = &ds1307_clk_sqw_ops;
+
+ ds1307->clks[0].init = &init;
+
+ /* Register the clock with CCF */
+ clk = devm_clk_register(ds1307->dev, &ds1307->clks[0]);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ if (node)
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+ return 0;
+}
+
static void ds1307_clks_register(struct ds1307 *ds1307)
{
int ret;
- if (ds1307->type != ds_3231)
+ switch (ds1307->type) {
+ case ds_3231:
+ ret = ds3231_clks_register(ds1307);
+ break;
+
+ case ds_1307:
+ ret = rtc_ds1307_clks_register(ds1307);
+ break;
+
+ default:
return;
+ }
- ret = ds3231_clks_register(ds1307);
if (ret) {
dev_warn(ds1307->dev, "unable to register clock device %d\n",
ret);
}
+
}
#else
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c
index c2359eb86bc9..8c247215d611 100644
--- a/drivers/rtc/rtc-ds1374.c
+++ b/drivers/rtc/rtc-ds1374.c
@@ -52,7 +52,7 @@
#define DS1374_REG_TCR 0x09 /* Trickle Charge */
static const struct i2c_device_id ds1374_id[] = {
- { "ds1374" },
+ { .name = "ds1374" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ds1374_id);
diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
index 6e5314215d00..c610beb55bb5 100644
--- a/drivers/rtc/rtc-ds1672.c
+++ b/drivers/rtc/rtc-ds1672.c
@@ -133,7 +133,7 @@ static int ds1672_probe(struct i2c_client *client)
}
static const struct i2c_device_id ds1672_id[] = {
- { "ds1672" },
+ { .name = "ds1672" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ds1672_id);
diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c
index 18f35823b4b5..d1ef9e0dad34 100644
--- a/drivers/rtc/rtc-ds3232.c
+++ b/drivers/rtc/rtc-ds3232.c
@@ -566,7 +566,7 @@ static int ds3232_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id ds3232_id[] = {
- { "ds3232" },
+ { .name = "ds3232" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ds3232_id);
diff --git a/drivers/rtc/rtc-em3027.c b/drivers/rtc/rtc-em3027.c
index dc1ccbc65dcb..d555e5d59881 100644
--- a/drivers/rtc/rtc-em3027.c
+++ b/drivers/rtc/rtc-em3027.c
@@ -129,7 +129,7 @@ static int em3027_probe(struct i2c_client *client)
}
static const struct i2c_device_id em3027_id[] = {
- { "em3027" },
+ { .name = "em3027" },
{ }
};
MODULE_DEVICE_TABLE(i2c, em3027_id);
diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c
index f82728ebac0c..28bb6d3f644e 100644
--- a/drivers/rtc/rtc-fm3130.c
+++ b/drivers/rtc/rtc-fm3130.c
@@ -53,7 +53,7 @@ struct fm3130 {
int data_valid;
};
static const struct i2c_device_id fm3130_id[] = {
- { "fm3130" },
+ { .name = "fm3130" },
{ }
};
MODULE_DEVICE_TABLE(i2c, fm3130_id);
diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c
index 7a170c0f9710..3156aa5f2d9f 100644
--- a/drivers/rtc/rtc-hym8563.c
+++ b/drivers/rtc/rtc-hym8563.c
@@ -564,8 +564,8 @@ static int hym8563_probe(struct i2c_client *client)
}
static const struct i2c_device_id hym8563_id[] = {
- { "hym8563" },
- {}
+ { .name = "hym8563" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, hym8563_id);
diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c
index 5fc52dc64213..bc36288854ee 100644
--- a/drivers/rtc/rtc-isl12022.c
+++ b/drivers/rtc/rtc-isl12022.c
@@ -604,7 +604,7 @@ static const struct of_device_id isl12022_dt_match[] = {
MODULE_DEVICE_TABLE(of, isl12022_dt_match);
static const struct i2c_device_id isl12022_id[] = {
- { "isl12022" },
+ { .name = "isl12022" },
{ }
};
MODULE_DEVICE_TABLE(i2c, isl12022_id);
diff --git a/drivers/rtc/rtc-isl12026.c b/drivers/rtc/rtc-isl12026.c
index 45a2c9f676c5..b86a325d8a23 100644
--- a/drivers/rtc/rtc-isl12026.c
+++ b/drivers/rtc/rtc-isl12026.c
@@ -485,8 +485,8 @@ static const struct of_device_id isl12026_dt_match[] = {
MODULE_DEVICE_TABLE(of, isl12026_dt_match);
static const struct i2c_device_id isl12026_id[] = {
- { "isl12026" },
- { },
+ { .name = "isl12026" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, isl12026_id);
diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
index f71a6bb77b2a..9bdd5d121571 100644
--- a/drivers/rtc/rtc-isl1208.c
+++ b/drivers/rtc/rtc-isl1208.c
@@ -110,11 +110,11 @@ static const struct isl1208_config config_raa215300_a0 = {
};
static const struct i2c_device_id isl1208_id[] = {
- { "isl1208", .driver_data = (kernel_ulong_t)&config_isl1208 },
- { "isl1209", .driver_data = (kernel_ulong_t)&config_isl1209 },
- { "isl1218", .driver_data = (kernel_ulong_t)&config_isl1218 },
- { "isl1219", .driver_data = (kernel_ulong_t)&config_isl1219 },
- { "raa215300_a0", .driver_data = (kernel_ulong_t)&config_raa215300_a0 },
+ { .name = "isl1208", .driver_data = (kernel_ulong_t)&config_isl1208 },
+ { .name = "isl1209", .driver_data = (kernel_ulong_t)&config_isl1209 },
+ { .name = "isl1218", .driver_data = (kernel_ulong_t)&config_isl1218 },
+ { .name = "isl1219", .driver_data = (kernel_ulong_t)&config_isl1219 },
+ { .name = "raa215300_a0", .driver_data = (kernel_ulong_t)&config_raa215300_a0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, isl1208_id);
@@ -822,6 +822,11 @@ static const struct nvmem_config isl1208_nvmem_config = {
.reg_write = isl1208_nvmem_write,
};
+static void isl1208_disable_irq_wake_action(void *data)
+{
+ disable_irq_wake((unsigned long)data);
+}
+
static int isl1208_setup_irq(struct i2c_client *client, int irq)
{
int rc = devm_request_threaded_irq(&client->dev, irq, NULL,
@@ -831,7 +836,15 @@ static int isl1208_setup_irq(struct i2c_client *client, int irq)
client);
if (!rc) {
device_init_wakeup(&client->dev, true);
- enable_irq_wake(irq);
+ rc = enable_irq_wake(irq);
+ if (rc)
+ return rc;
+
+ rc = devm_add_action_or_reset(&client->dev,
+ isl1208_disable_irq_wake_action,
+ (void *)(unsigned long)irq);
+ if (rc)
+ return rc;
} else {
dev_err(&client->dev,
"Unable to request irq %d, no alarm support\n",
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index b26afef37d9c..3c8c379392c1 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -71,17 +71,17 @@
#define M41T80_FEATURE_SQ_ALT BIT(4) /* RSx bits are in reg 4 */
static const struct i2c_device_id m41t80_id[] = {
- { "m41t62", M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT },
- { "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 },
- { "m41t82", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
- { "m41t83", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
- { "m41st84", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
- { "m41st85", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
- { "m41st87", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
- { "rv4162", M41T80_FEATURE_SQ | M41T80_FEATURE_WD | M41T80_FEATURE_SQ_ALT },
+ { .name = "m41t62", .driver_data = M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT },
+ { .name = "m41t65", .driver_data = M41T80_FEATURE_WD },
+ { .name = "m41t80", .driver_data = M41T80_FEATURE_SQ },
+ { .name = "m41t81", .driver_data = M41T80_FEATURE_HT | M41T80_FEATURE_SQ},
+ { .name = "m41t81s", .driver_data = M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
+ { .name = "m41t82", .driver_data = M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
+ { .name = "m41t83", .driver_data = M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
+ { .name = "m41st84", .driver_data = M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
+ { .name = "m41st85", .driver_data = M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
+ { .name = "m41st87", .driver_data = M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
+ { .name = "rv4162", .driver_data = M41T80_FEATURE_SQ | M41T80_FEATURE_WD | M41T80_FEATURE_SQ_ALT },
{ }
};
MODULE_DEVICE_TABLE(i2c, m41t80_id);
diff --git a/drivers/rtc/rtc-m41t93.c b/drivers/rtc/rtc-m41t93.c
index 9444cb5f5190..fa7a4b5f848d 100644
--- a/drivers/rtc/rtc-m41t93.c
+++ b/drivers/rtc/rtc-m41t93.c
@@ -12,6 +12,9 @@
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+#include <linux/clk-provider.h>
+#include <linux/watchdog.h>
#define M41T93_REG_SSEC 0
#define M41T93_REG_ST_SEC 1
@@ -21,7 +24,23 @@
#define M41T93_REG_DAY 5
#define M41T93_REG_MON 6
#define M41T93_REG_YEAR 7
-
+#define M41T93_REG_AL1_MONTH 0xa
+#define M41T93_REG_AL1_DATE 0xb
+#define M41T93_REG_AL1_HOUR 0xc
+#define M41T93_REG_AL1_MIN 0xd
+#define M41T93_REG_AL1_SEC 0xe
+#define M41T93_BIT_A1IE BIT(7)
+#define M41T93_BIT_ABE BIT(5)
+#define M41T93_FLAG_AF1 BIT(6)
+#define M41T93_SRAM_BASE 0x19
+#define M41T93_REG_SQW 0x13
+#define M41T93_SQW_RS_MASK 0xf0
+#define M41T93_SQW_RS_SHIFT 4
+#define M41T93_BIT_SQWE BIT(6)
+#define M41T93_REG_WATCHDOG 0x9
+#define M41T93_WDT_RB_MASK 0x3
+#define M41T93_WDT_BMB_MASK 0x7c
+#define M41T93_WDT_BMB_SHIFT 2
#define M41T93_REG_ALM_HOUR_HT 0xc
#define M41T93_REG_FLAGS 0xf
@@ -31,23 +50,23 @@
#define M41T93_FLAG_BL (1 << 4)
#define M41T93_FLAG_HT (1 << 6)
-static inline int m41t93_set_reg(struct spi_device *spi, u8 addr, u8 data)
-{
- u8 buf[2];
-
- /* MSB must be '1' to write */
- buf[0] = addr | 0x80;
- buf[1] = data;
-
- return spi_write(spi, buf, sizeof(buf));
-}
+struct m41t93_data {
+ struct rtc_device *rtc;
+ struct regmap *regmap;
+#ifdef CONFIG_COMMON_CLK
+ struct clk_hw clks;
+#endif
+#ifdef CONFIG_WATCHDOG
+ struct watchdog_device wdd;
+#endif
+};
static int m41t93_set_time(struct device *dev, struct rtc_time *tm)
{
- struct spi_device *spi = to_spi_device(dev);
- int tmp;
- u8 buf[9] = {0x80}; /* write cmd + 8 data bytes */
- u8 * const data = &buf[1]; /* ptr to first data byte */
+ struct m41t93_data *m41t93 = dev_get_drvdata(dev);
+ int tmp, ret;
+ u8 buf[8] = {0}; /* 8 data bytes */
+ u8 * const data = &buf[0]; /* ptr to first data byte */
dev_dbg(dev, "%s secs=%d, mins=%d, "
"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -56,31 +75,31 @@ static int m41t93_set_time(struct device *dev, struct rtc_time *tm)
tm->tm_mon, tm->tm_year, tm->tm_wday);
if (tm->tm_year < 100) {
- dev_warn(&spi->dev, "unsupported date (before 2000-01-01).\n");
+ dev_warn(dev, "unsupported date (before 2000-01-01).\n");
return -EINVAL;
}
- tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
- if (tmp < 0)
- return tmp;
+ ret = regmap_read(m41t93->regmap, M41T93_REG_FLAGS, &tmp);
+ if (ret < 0)
+ return ret;
if (tmp & M41T93_FLAG_OF) {
- dev_warn(&spi->dev, "OF bit is set, resetting.\n");
- m41t93_set_reg(spi, M41T93_REG_FLAGS, tmp & ~M41T93_FLAG_OF);
+ dev_warn(dev, "OF bit is set, resetting.\n");
+ regmap_write(m41t93->regmap, M41T93_REG_FLAGS, tmp & ~M41T93_FLAG_OF);
- tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
- if (tmp < 0) {
- return tmp;
+ ret = regmap_read(m41t93->regmap, M41T93_REG_FLAGS, &tmp);
+ if (ret < 0) {
+ return ret;
} else if (tmp & M41T93_FLAG_OF) {
/* OF cannot be immediately reset: oscillator has to be
* restarted. */
u8 reset_osc = buf[M41T93_REG_ST_SEC] | M41T93_FLAG_ST;
- dev_warn(&spi->dev,
+ dev_warn(dev,
"OF bit is still set, kickstarting clock.\n");
- m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc);
+ regmap_write(m41t93->regmap, M41T93_REG_ST_SEC, reset_osc);
reset_osc &= ~M41T93_FLAG_ST;
- m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc);
+ regmap_write(m41t93->regmap, M41T93_REG_ST_SEC, reset_osc);
}
}
@@ -94,14 +113,13 @@ static int m41t93_set_time(struct device *dev, struct rtc_time *tm)
data[M41T93_REG_MON] = bin2bcd(tm->tm_mon + 1);
data[M41T93_REG_YEAR] = bin2bcd(tm->tm_year % 100);
- return spi_write(spi, buf, sizeof(buf));
+ return regmap_bulk_write(m41t93->regmap, M41T93_REG_SSEC, buf, sizeof(buf));
}
static int m41t93_get_time(struct device *dev, struct rtc_time *tm)
{
- struct spi_device *spi = to_spi_device(dev);
- const u8 start_addr = 0;
+ struct m41t93_data *m41t93 = dev_get_drvdata(dev);
u8 buf[8];
int century_after_1900;
int tmp;
@@ -113,32 +131,32 @@ static int m41t93_get_time(struct device *dev, struct rtc_time *tm)
case after poweron. Time is valid after resetting HT bit.
2. oscillator fail bit (OF) is set: time is invalid.
*/
- tmp = spi_w8r8(spi, M41T93_REG_ALM_HOUR_HT);
- if (tmp < 0)
- return tmp;
+ ret = regmap_read(m41t93->regmap, M41T93_REG_ALM_HOUR_HT, &tmp);
+ if (ret < 0)
+ return ret;
if (tmp & M41T93_FLAG_HT) {
- dev_dbg(&spi->dev, "HT bit is set, reenable clock update.\n");
- m41t93_set_reg(spi, M41T93_REG_ALM_HOUR_HT,
- tmp & ~M41T93_FLAG_HT);
+ dev_dbg(dev, "HT bit is set, reenable clock update.\n");
+ regmap_write(m41t93->regmap, M41T93_REG_ALM_HOUR_HT,
+ tmp & ~M41T93_FLAG_HT);
}
- tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
- if (tmp < 0)
- return tmp;
+ ret = regmap_read(m41t93->regmap, M41T93_REG_FLAGS, &tmp);
+ if (ret < 0)
+ return ret;
if (tmp & M41T93_FLAG_OF) {
ret = -EINVAL;
- dev_warn(&spi->dev, "OF bit is set, write time to restart.\n");
+ dev_warn(dev, "OF bit is set, write time to restart.\n");
}
if (tmp & M41T93_FLAG_BL)
- dev_warn(&spi->dev, "BL bit is set, replace battery.\n");
+ dev_warn(dev, "BL bit is set, replace battery.\n");
/* read actual time/date */
- tmp = spi_write_then_read(spi, &start_addr, 1, buf, sizeof(buf));
- if (tmp < 0)
- return tmp;
+ ret = regmap_bulk_read(m41t93->regmap, M41T93_REG_SSEC, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
tm->tm_sec = bcd2bin(buf[M41T93_REG_ST_SEC]);
tm->tm_min = bcd2bin(buf[M41T93_REG_MIN]);
@@ -159,41 +177,407 @@ static int m41t93_get_time(struct device *dev, struct rtc_time *tm)
return ret;
}
+static int m41t93_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct m41t93_data *m41t93 = dev_get_drvdata(dev);
+ int ret;
+ unsigned int val;
+ u8 alarm_vals[5] = {0};
+
+ ret = regmap_bulk_write(m41t93->regmap, M41T93_REG_AL1_DATE, alarm_vals, 4);
+ if (ret)
+ return ret;
+
+ /* Set alarm values */
+ alarm_vals[0] = bin2bcd(alrm->time.tm_mon + 1) & 0x1f;
+ alarm_vals[1] = bin2bcd(alrm->time.tm_mday) & 0x3f;
+ alarm_vals[2] = bin2bcd(alrm->time.tm_hour) & 0x3f;
+ alarm_vals[3] = bin2bcd(alrm->time.tm_min) & 0x7f;
+ alarm_vals[4] = bin2bcd(alrm->time.tm_sec) & 0x7f;
+
+ if (alrm->enabled) {
+ /* Enable alarm IRQ generation */
+ alarm_vals[0] |= M41T93_BIT_A1IE | M41T93_BIT_ABE;
+ }
+
+ /* Preserve SQWE bit */
+ ret = regmap_read(m41t93->regmap, M41T93_REG_AL1_MONTH, &val);
+ if (ret)
+ return ret;
+
+ alarm_vals[0] |= val & 0x40;
+
+ ret = regmap_bulk_write(m41t93->regmap, M41T93_REG_AL1_MONTH,
+ alarm_vals, sizeof(alarm_vals));
+ if (ret)
+ return ret;
+
+ /* Device address pointer is now at FLAG register, move it to other location
+ * to finish setting alarm, as recommended by the datasheet.
+ * We do read of AL1_MONTH register to achieve this.
+ */
+ ret = regmap_read(m41t93->regmap, M41T93_REG_AL1_MONTH, &val);
+ if (ret)
+ return ret;
+
+ if (bcd2bin(val & 0x1f) == (alrm->time.tm_mon & 0x1f))
+ dev_notice(dev, "Alarm set successfully\n");
+
+ return 0;
+}
+
+static int m41t93_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct m41t93_data *m41t93 = dev_get_drvdata(dev);
+ int ret;
+ unsigned int val;
+ u8 alarm_vals[5] = {0};
+
+ ret = regmap_bulk_read(m41t93->regmap, M41T93_REG_AL1_MONTH,
+ alarm_vals, sizeof(alarm_vals));
+ if (ret)
+ return ret;
+
+ alrm->time.tm_mon = bcd2bin(alarm_vals[0] & 0x1f) - 1;
+ alrm->time.tm_mday = bcd2bin(alarm_vals[1] & 0x3f);
+ alrm->time.tm_hour = bcd2bin(alarm_vals[2] & 0x3f);
+ alrm->time.tm_min = bcd2bin(alarm_vals[3] & 0x7f);
+ alrm->time.tm_sec = bcd2bin(alarm_vals[4] & 0x7f);
+
+ alrm->enabled = !!(alarm_vals[0] & M41T93_BIT_A1IE);
+
+ ret = regmap_read(m41t93->regmap, M41T93_REG_FLAGS, &val);
+ if (ret)
+ return ret;
+
+ alrm->pending = (val & M41T93_FLAG_AF1) && alrm->enabled;
+
+ return 0;
+}
+
+static int m41t93_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct m41t93_data *m41t93 = dev_get_drvdata(dev);
+ unsigned int val;
+ int ret;
+
+ val = enabled ? M41T93_BIT_A1IE | M41T93_BIT_ABE : 0;
+
+ ret = regmap_update_bits(m41t93->regmap, M41T93_REG_AL1_MONTH,
+ M41T93_BIT_A1IE | M41T93_BIT_ABE, val);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static const struct rtc_class_ops m41t93_rtc_ops = {
.read_time = m41t93_get_time,
.set_time = m41t93_set_time,
+ .set_alarm = m41t93_set_alarm,
+ .read_alarm = m41t93_get_alarm,
+ .alarm_irq_enable = m41t93_alarm_irq_enable,
+};
+
+#ifdef CONFIG_COMMON_CLK
+#define clk_sqw_to_m41t93_data(clk) \
+ container_of(clk, struct m41t93_data, clks)
+
+/* m41t93 RTC clock output support */
+static unsigned long m41t93_clk_rates[] = {
+ 0,
+ 32768, /* RS3:RS0 = 0b0001 */
+ 8192,
+ 4096,
+ 2048,
+ 1024,
+ 512,
+ 256,
+ 128,
+ 64,
+ 32,
+ 16,
+ 8,
+ 4,
+ 2,
+ 1, /* RS3:RS0 = 0b1111 */
+};
+
+static unsigned long m41t93_clk_sqw_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ int ret;
+ unsigned int rate_id;
+ struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
+
+ ret = regmap_read(m41t93->regmap, M41T93_REG_SQW, &rate_id);
+ if (ret)
+ return ret;
+
+ rate_id &= M41T93_SQW_RS_MASK;
+ rate_id >>= M41T93_SQW_RS_SHIFT;
+
+ return m41t93_clk_rates[rate_id];
+}
+
+static int m41t93_clk_sqw_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ int i;
+
+ for (i = 1; i < ARRAY_SIZE(m41t93_clk_rates); i++) {
+ if (req->rate >= m41t93_clk_rates[i]) {
+ req->rate = m41t93_clk_rates[i];
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static int m41t93_clk_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ int id, ret;
+ struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
+
+ for (id = 0; id < ARRAY_SIZE(m41t93_clk_rates); id++) {
+ if (m41t93_clk_rates[id] == rate)
+ break;
+ }
+
+ if (id >= ARRAY_SIZE(m41t93_clk_rates))
+ return -EINVAL;
+
+ ret = regmap_update_bits(m41t93->regmap, M41T93_REG_SQW,
+ M41T93_SQW_RS_MASK, id << M41T93_SQW_RS_SHIFT);
+
+ return ret;
+}
+
+static int m41t93_clk_sqw_prepare(struct clk_hw *hw)
+{
+ int ret;
+ struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
+
+ ret = regmap_update_bits(m41t93->regmap, M41T93_REG_AL1_MONTH,
+ M41T93_BIT_SQWE, M41T93_BIT_SQWE);
+
+ return ret;
+}
+
+static void m41t93_clk_sqw_unprepare(struct clk_hw *hw)
+{
+ struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
+
+ regmap_update_bits(m41t93->regmap, M41T93_REG_AL1_MONTH,
+ M41T93_BIT_SQWE, 0);
+}
+
+static int m41t93_clk_sqw_is_prepared(struct clk_hw *hw)
+{
+ int ret;
+ struct m41t93_data *m41t93 = clk_sqw_to_m41t93_data(hw);
+ unsigned int status;
+
+ ret = regmap_read(m41t93->regmap, M41T93_REG_AL1_MONTH, &status);
+ if (ret)
+ return ret;
+
+ return !!(status & M41T93_BIT_SQWE);
+}
+
+static const struct clk_ops m41t93_clk_sqw_ops = {
+ .prepare = m41t93_clk_sqw_prepare,
+ .unprepare = m41t93_clk_sqw_unprepare,
+ .is_prepared = m41t93_clk_sqw_is_prepared,
+ .recalc_rate = m41t93_clk_sqw_recalc_rate,
+ .set_rate = m41t93_clk_sqw_set_rate,
+ .determine_rate = m41t93_clk_sqw_determine_rate,
+};
+
+static int rtc_m41t93_clks_register(struct device *dev, struct m41t93_data *m41t93)
+{
+ struct device_node *node = dev->of_node;
+ struct clk *clk;
+ struct clk_init_data init = {0};
+
+ init.name = "m41t93_clk_sqw";
+ init.ops = &m41t93_clk_sqw_ops;
+
+ m41t93->clks.init = &init;
+
+ /* Register the clock with CCF */
+ clk = devm_clk_register(dev, &m41t93->clks);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ if (node)
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_WATCHDOG
+static int m41t93_wdt_ping(struct watchdog_device *wdd)
+{
+ u8 resolution, mult;
+ u8 val = 0;
+ int ret;
+ struct m41t93_data *m41t93 = watchdog_get_drvdata(wdd);
+
+ /* Resolution supported by hardware
+ * 0b00 : 1/16 seconds
+ * 0b01 : 1/4 second
+ * 0b10 : 1 second
+ * 0b11 : 4 seconds
+ */
+ resolution = 0x2; /* hardcode resolution to 1s */
+ mult = wdd->timeout;
+ val = resolution | (mult << M41T93_WDT_BMB_SHIFT & M41T93_WDT_BMB_MASK);
+
+ ret = regmap_write_bits(m41t93->regmap, M41T93_REG_WATCHDOG,
+ M41T93_WDT_RB_MASK | M41T93_WDT_BMB_MASK, val);
+
+ return ret;
+}
+
+static int m41t93_wdt_start(struct watchdog_device *wdd)
+{
+ return m41t93_wdt_ping(wdd);
+}
+
+static int m41t93_wdt_stop(struct watchdog_device *wdd)
+{
+ struct m41t93_data *m41t93 = watchdog_get_drvdata(wdd);
+
+ /* Write 0 to watchdog register */
+ return regmap_write_bits(m41t93->regmap, M41T93_REG_WATCHDOG,
+ M41T93_WDT_RB_MASK | M41T93_WDT_BMB_MASK, 0);
+}
+
+static int m41t93_wdt_set_timeout(struct watchdog_device *wdd,
+ unsigned int new_timeout)
+{
+ wdd->timeout = new_timeout;
+
+ return 0;
+}
+
+static const struct watchdog_info m41t93_wdt_info = {
+ .identity = "m41t93 rtc Watchdog",
+ .options = WDIOF_ALARMONLY | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+};
+
+static const struct watchdog_ops m41t93_watchdog_ops = {
+ .owner = THIS_MODULE,
+ .start = m41t93_wdt_start,
+ .stop = m41t93_wdt_stop,
+ .ping = m41t93_wdt_ping,
+ .set_timeout = m41t93_wdt_set_timeout,
};
+static int m41t93_watchdog_register(struct device *dev, struct m41t93_data *m41t93)
+{
+ int ret;
+
+ m41t93->wdd.parent = dev;
+ m41t93->wdd.info = &m41t93_wdt_info;
+ m41t93->wdd.ops = &m41t93_watchdog_ops;
+ m41t93->wdd.min_timeout = 0;
+ m41t93->wdd.max_timeout = 10;
+ m41t93->wdd.timeout = 3; /* Default timeout is 3 sec */
+ m41t93->wdd.status = WATCHDOG_NOWAYOUT_INIT_STATUS;
+
+ watchdog_set_drvdata(&m41t93->wdd, m41t93);
+
+ ret = devm_watchdog_register_device(dev, &m41t93->wdd);
+ if (ret) {
+ dev_warn(dev, "Failed to register watchdog\n");
+ return ret;
+ }
+
+ /* Disable watchdog at start */
+ ret = m41t93_wdt_stop(&m41t93->wdd);
+
+ return ret;
+}
+#endif
+
static struct spi_driver m41t93_driver;
+static const struct regmap_config regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .read_flag_mask = 0x00,
+ .write_flag_mask = 0x80,
+ .zero_flag_mask = true,
+};
+
static int m41t93_probe(struct spi_device *spi)
{
- struct rtc_device *rtc;
- int res;
+ int res, ret;
+ struct m41t93_data *m41t93;
spi->bits_per_word = 8;
spi_setup(spi);
- res = spi_w8r8(spi, M41T93_REG_WDAY);
+ m41t93 = devm_kzalloc(&spi->dev, sizeof(struct m41t93_data), GFP_KERNEL);
+
+ if (!m41t93)
+ return -ENOMEM;
+
+ /* Set up regmap to access device registers*/
+ m41t93->regmap = devm_regmap_init_spi(spi, &regmap_config);
+ if (IS_ERR(m41t93->regmap)) {
+ dev_err(&spi->dev, "regmap init failure\n");
+ return PTR_ERR(m41t93->regmap);
+ }
+
+ ret = regmap_read(m41t93->regmap, M41T93_REG_WDAY, &res);
+ if (ret < 0) {
+ dev_err(&spi->dev, "IO error\n");
+ return -EIO;
+ }
+
if (res < 0 || (res & 0xf8) != 0) {
dev_err(&spi->dev, "not found 0x%x.\n", res);
return -ENODEV;
}
- rtc = devm_rtc_device_register(&spi->dev, m41t93_driver.driver.name,
- &m41t93_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc))
- return PTR_ERR(rtc);
+ spi_set_drvdata(spi, m41t93);
+
+ m41t93->rtc = devm_rtc_device_register(&spi->dev, m41t93_driver.driver.name,
+ &m41t93_rtc_ops, THIS_MODULE);
+ if (IS_ERR(m41t93->rtc))
+ return PTR_ERR(m41t93->rtc);
- spi_set_drvdata(spi, rtc);
+#ifdef CONFIG_COMMON_CLK
+ ret = rtc_m41t93_clks_register(&spi->dev, m41t93);
+ if (ret)
+ dev_warn(&spi->dev, "Unable to register clock\n");
+#endif
+#ifdef CONFIG_WATCHDOG
+ ret = m41t93_watchdog_register(&spi->dev, m41t93);
+ if (ret)
+ dev_warn(&spi->dev, "Unable to register watchdog\n");
+#endif
return 0;
}
+static const struct of_device_id m41t93_dt_match[] = {
+ { .compatible = "st,m41t93" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, m41t93_dt_match);
+
static struct spi_driver m41t93_driver = {
.driver = {
.name = "rtc-m41t93",
+ .of_match_table = m41t93_dt_match,
},
.probe = m41t93_probe,
};
diff --git a/drivers/rtc/rtc-max31335.c b/drivers/rtc/rtc-max31335.c
index 952b455071d6..595816973851 100644
--- a/drivers/rtc/rtc-max31335.c
+++ b/drivers/rtc/rtc-max31335.c
@@ -745,8 +745,8 @@ static int max31335_probe(struct i2c_client *client)
}
static const struct i2c_device_id max31335_id[] = {
- { "max31331", (kernel_ulong_t)&chip[ID_MAX31331] },
- { "max31335", (kernel_ulong_t)&chip[ID_MAX31335] },
+ { .name = "max31331", .driver_data = (kernel_ulong_t)&chip[ID_MAX31331] },
+ { .name = "max31335", .driver_data = (kernel_ulong_t)&chip[ID_MAX31335] },
{ }
};
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c
index 7be31fce5bc7..8ef6d0fcd032 100644
--- a/drivers/rtc/rtc-max6900.c
+++ b/drivers/rtc/rtc-max6900.c
@@ -215,7 +215,7 @@ static int max6900_probe(struct i2c_client *client)
}
static const struct i2c_device_id max6900_id[] = {
- { "max6900" },
+ { .name = "max6900" },
{ }
};
MODULE_DEVICE_TABLE(i2c, max6900_id);
diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c
index 3cdfd78a07cc..375565a3bddf 100644
--- a/drivers/rtc/rtc-max77686.c
+++ b/drivers/rtc/rtc-max77686.c
@@ -866,11 +866,11 @@ static SIMPLE_DEV_PM_OPS(max77686_rtc_pm_ops,
max77686_rtc_suspend, max77686_rtc_resume);
static const struct platform_device_id rtc_id[] = {
- { "max77686-rtc", .driver_data = (kernel_ulong_t)&max77686_drv_data, },
- { "max77802-rtc", .driver_data = (kernel_ulong_t)&max77802_drv_data, },
- { "max77620-rtc", .driver_data = (kernel_ulong_t)&max77620_drv_data, },
- { "max77714-rtc", .driver_data = (kernel_ulong_t)&max77714_drv_data, },
- {},
+ { .name = "max77686-rtc", .driver_data = (kernel_ulong_t)&max77686_drv_data },
+ { .name = "max77802-rtc", .driver_data = (kernel_ulong_t)&max77802_drv_data },
+ { .name = "max77620-rtc", .driver_data = (kernel_ulong_t)&max77620_drv_data },
+ { .name = "max77714-rtc", .driver_data = (kernel_ulong_t)&max77714_drv_data },
+ { }
};
MODULE_DEVICE_TABLE(platform, rtc_id);
diff --git a/drivers/rtc/rtc-max8997.c b/drivers/rtc/rtc-max8997.c
index e7618d715bd8..89203c92e2cd 100644
--- a/drivers/rtc/rtc-max8997.c
+++ b/drivers/rtc/rtc-max8997.c
@@ -512,8 +512,8 @@ static void max8997_rtc_shutdown(struct platform_device *pdev)
}
static const struct platform_device_id rtc_id[] = {
- { "max8997-rtc", 0 },
- {},
+ { .name = "max8997-rtc" },
+ { }
};
MODULE_DEVICE_TABLE(platform, rtc_id);
diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c
index c873b4509b3c..a2c946edcd1a 100644
--- a/drivers/rtc/rtc-max8998.c
+++ b/drivers/rtc/rtc-max8998.c
@@ -299,8 +299,8 @@ no_irq:
}
static const struct platform_device_id max8998_rtc_id[] = {
- { "max8998-rtc", TYPE_MAX8998 },
- { "lp3974-rtc", TYPE_LP3974 },
+ { .name = "max8998-rtc", .driver_data = TYPE_MAX8998 },
+ { .name = "lp3974-rtc", .driver_data = TYPE_LP3974 },
{ }
};
MODULE_DEVICE_TABLE(platform, max8998_rtc_id);
diff --git a/drivers/rtc/rtc-mpfs.c b/drivers/rtc/rtc-mpfs.c
index 6aa3eae575d2..ece6de4a6adb 100644
--- a/drivers/rtc/rtc-mpfs.c
+++ b/drivers/rtc/rtc-mpfs.c
@@ -112,7 +112,7 @@ static int mpfs_rtc_settime(struct device *dev, struct rtc_time *tm)
ctrl |= CONTROL_UPLOAD_BIT;
writel(ctrl, rtcdev->base + CONTROL_REG);
- ret = read_poll_timeout(readl, prog, prog & CONTROL_UPLOAD_BIT, 0, UPLOAD_TIMEOUT_US,
+ ret = read_poll_timeout(readl, prog, !(prog & CONTROL_UPLOAD_BIT), 0, UPLOAD_TIMEOUT_US,
false, rtcdev->base + CONTROL_REG);
if (ret) {
dev_err(dev, "timed out uploading time to rtc");
diff --git a/drivers/rtc/rtc-msc313.c b/drivers/rtc/rtc-msc313.c
index 8d7737e0e2e0..6ef9c4efd7c9 100644
--- a/drivers/rtc/rtc-msc313.c
+++ b/drivers/rtc/rtc-msc313.c
@@ -160,7 +160,7 @@ static const struct rtc_class_ops msc313_rtc_ops = {
static irqreturn_t msc313_rtc_interrupt(s32 irq, void *dev_id)
{
- struct msc313_rtc *priv = dev_get_drvdata(dev_id);
+ struct msc313_rtc *priv = dev_id;
u16 reg;
reg = readw(priv->rtc_base + REG_RTC_STATUS_INT);
@@ -206,7 +206,7 @@ static int msc313_rtc_probe(struct platform_device *pdev)
priv->rtc_dev->range_max = U32_MAX;
ret = devm_request_irq(dev, irq, msc313_rtc_interrupt, IRQF_SHARED,
- dev_name(&pdev->dev), &pdev->dev);
+ dev_name(&pdev->dev), priv);
if (ret) {
dev_err(dev, "Could not request IRQ\n");
return ret;
diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c
index c27ad626d09f..f88976fd6d5d 100644
--- a/drivers/rtc/rtc-mv.c
+++ b/drivers/rtc/rtc-mv.c
@@ -301,6 +301,28 @@ static const struct of_device_id rtc_mv_of_match_table[] = {
MODULE_DEVICE_TABLE(of, rtc_mv_of_match_table);
#endif
+#ifdef CONFIG_PM_SLEEP
+static int mv_rtc_suspend(struct device *dev)
+{
+ struct rtc_plat_data *pdata = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev) && pdata->irq >= 0)
+ enable_irq_wake(pdata->irq);
+ return 0;
+}
+
+static int mv_rtc_resume(struct device *dev)
+{
+ struct rtc_plat_data *pdata = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev) && pdata->irq >= 0)
+ disable_irq_wake(pdata->irq);
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(mv_rtc_pm_ops, mv_rtc_suspend, mv_rtc_resume);
+
/*
* mv_rtc_remove() lives in .exit.text. For drivers registered via
* module_platform_driver_probe() this is ok because they cannot get unbound at
@@ -312,6 +334,7 @@ static struct platform_driver mv_rtc_driver __refdata = {
.driver = {
.name = "rtc-mv",
.of_match_table = of_match_ptr(rtc_mv_of_match_table),
+ .pm = &mv_rtc_pm_ops,
},
};
diff --git a/drivers/rtc/rtc-nct3018y.c b/drivers/rtc/rtc-nct3018y.c
index cd4b1db902e9..700a395fad3a 100644
--- a/drivers/rtc/rtc-nct3018y.c
+++ b/drivers/rtc/rtc-nct3018y.c
@@ -572,7 +572,7 @@ static int nct3018y_probe(struct i2c_client *client)
}
static const struct i2c_device_id nct3018y_id[] = {
- { "nct3018y" },
+ { .name = "nct3018y" },
{ }
};
MODULE_DEVICE_TABLE(i2c, nct3018y_id);
diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c
deleted file mode 100644
index d6651611a0c6..000000000000
--- a/drivers/rtc/rtc-pcap.c
+++ /dev/null
@@ -1,179 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * pcap rtc code for Motorola EZX phones
- *
- * Copyright (c) 2008 guiming zhuo <gmzhuo@gmail.com>
- * Copyright (c) 2009 Daniel Ribeiro <drwyrm@gmail.com>
- *
- * Based on Motorola's rtc.c Copyright (c) 2003-2005 Motorola
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/mfd/ezx-pcap.h>
-#include <linux/rtc.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-
-struct pcap_rtc {
- struct pcap_chip *pcap;
- struct rtc_device *rtc;
-};
-
-static irqreturn_t pcap_rtc_irq(int irq, void *_pcap_rtc)
-{
- struct pcap_rtc *pcap_rtc = _pcap_rtc;
- unsigned long rtc_events;
-
- if (irq == pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_1HZ))
- rtc_events = RTC_IRQF | RTC_UF;
- else if (irq == pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_TODA))
- rtc_events = RTC_IRQF | RTC_AF;
- else
- rtc_events = 0;
-
- rtc_update_irq(pcap_rtc->rtc, 1, rtc_events);
- return IRQ_HANDLED;
-}
-
-static int pcap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
-{
- struct pcap_rtc *pcap_rtc = dev_get_drvdata(dev);
- struct rtc_time *tm = &alrm->time;
- unsigned long secs;
- u32 tod; /* time of day, seconds since midnight */
- u32 days; /* days since 1/1/1970 */
-
- ezx_pcap_read(pcap_rtc->pcap, PCAP_REG_RTC_TODA, &tod);
- secs = tod & PCAP_RTC_TOD_MASK;
-
- ezx_pcap_read(pcap_rtc->pcap, PCAP_REG_RTC_DAYA, &days);
- secs += (days & PCAP_RTC_DAY_MASK) * SEC_PER_DAY;
-
- rtc_time64_to_tm(secs, tm);
-
- return 0;
-}
-
-static int pcap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
-{
- struct pcap_rtc *pcap_rtc = dev_get_drvdata(dev);
- unsigned long secs = rtc_tm_to_time64(&alrm->time);
- u32 tod, days;
-
- tod = secs % SEC_PER_DAY;
- ezx_pcap_write(pcap_rtc->pcap, PCAP_REG_RTC_TODA, tod);
-
- days = secs / SEC_PER_DAY;
- ezx_pcap_write(pcap_rtc->pcap, PCAP_REG_RTC_DAYA, days);
-
- return 0;
-}
-
-static int pcap_rtc_read_time(struct device *dev, struct rtc_time *tm)
-{
- struct pcap_rtc *pcap_rtc = dev_get_drvdata(dev);
- unsigned long secs;
- u32 tod, days;
-
- ezx_pcap_read(pcap_rtc->pcap, PCAP_REG_RTC_TOD, &tod);
- secs = tod & PCAP_RTC_TOD_MASK;
-
- ezx_pcap_read(pcap_rtc->pcap, PCAP_REG_RTC_DAY, &days);
- secs += (days & PCAP_RTC_DAY_MASK) * SEC_PER_DAY;
-
- rtc_time64_to_tm(secs, tm);
-
- return 0;
-}
-
-static int pcap_rtc_set_time(struct device *dev, struct rtc_time *tm)
-{
- struct pcap_rtc *pcap_rtc = dev_get_drvdata(dev);
- unsigned long secs = rtc_tm_to_time64(tm);
- u32 tod, days;
-
- tod = secs % SEC_PER_DAY;
- ezx_pcap_write(pcap_rtc->pcap, PCAP_REG_RTC_TOD, tod);
-
- days = secs / SEC_PER_DAY;
- ezx_pcap_write(pcap_rtc->pcap, PCAP_REG_RTC_DAY, days);
-
- return 0;
-}
-
-static int pcap_rtc_irq_enable(struct device *dev, int pirq, unsigned int en)
-{
- struct pcap_rtc *pcap_rtc = dev_get_drvdata(dev);
-
- if (en)
- enable_irq(pcap_to_irq(pcap_rtc->pcap, pirq));
- else
- disable_irq(pcap_to_irq(pcap_rtc->pcap, pirq));
-
- return 0;
-}
-
-static int pcap_rtc_alarm_irq_enable(struct device *dev, unsigned int en)
-{
- return pcap_rtc_irq_enable(dev, PCAP_IRQ_TODA, en);
-}
-
-static const struct rtc_class_ops pcap_rtc_ops = {
- .read_time = pcap_rtc_read_time,
- .set_time = pcap_rtc_set_time,
- .read_alarm = pcap_rtc_read_alarm,
- .set_alarm = pcap_rtc_set_alarm,
- .alarm_irq_enable = pcap_rtc_alarm_irq_enable,
-};
-
-static int __init pcap_rtc_probe(struct platform_device *pdev)
-{
- struct pcap_rtc *pcap_rtc;
- int timer_irq, alarm_irq;
- int err = -ENOMEM;
-
- pcap_rtc = devm_kzalloc(&pdev->dev, sizeof(struct pcap_rtc),
- GFP_KERNEL);
- if (!pcap_rtc)
- return err;
-
- pcap_rtc->pcap = dev_get_drvdata(pdev->dev.parent);
-
- platform_set_drvdata(pdev, pcap_rtc);
-
- pcap_rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
- if (IS_ERR(pcap_rtc->rtc))
- return PTR_ERR(pcap_rtc->rtc);
-
- pcap_rtc->rtc->ops = &pcap_rtc_ops;
- pcap_rtc->rtc->range_max = (1 << 14) * 86400ULL - 1;
-
- timer_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_1HZ);
- alarm_irq = pcap_to_irq(pcap_rtc->pcap, PCAP_IRQ_TODA);
-
- err = devm_request_irq(&pdev->dev, timer_irq, pcap_rtc_irq, 0,
- "RTC Timer", pcap_rtc);
- if (err)
- return err;
-
- err = devm_request_irq(&pdev->dev, alarm_irq, pcap_rtc_irq, 0,
- "RTC Alarm", pcap_rtc);
- if (err)
- return err;
-
- return devm_rtc_register_device(pcap_rtc->rtc);
-}
-
-static struct platform_driver pcap_rtc_driver = {
- .driver = {
- .name = "pcap-rtc",
- },
-};
-
-module_platform_driver_probe(pcap_rtc_driver, pcap_rtc_probe);
-
-MODULE_DESCRIPTION("Motorola pcap rtc driver");
-MODULE_AUTHOR("guiming zhuo <gmzhuo@gmail.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c
index e4785c5a55d0..1995e9f2756d 100644
--- a/drivers/rtc/rtc-pcf2127.c
+++ b/drivers/rtc/rtc-pcf2127.c
@@ -1449,10 +1449,10 @@ static const struct regmap_bus pcf2127_i2c_regmap = {
static struct i2c_driver pcf2127_i2c_driver;
static const struct i2c_device_id pcf2127_i2c_id[] = {
- { "pcf2127", (kernel_ulong_t)&pcf21xx_cfg[PCF2127] },
- { "pcf2129", (kernel_ulong_t)&pcf21xx_cfg[PCF2129] },
- { "pca2129", (kernel_ulong_t)&pcf21xx_cfg[PCF2129] },
- { "pcf2131", (kernel_ulong_t)&pcf21xx_cfg[PCF2131] },
+ { .name = "pcf2127", .driver_data = (kernel_ulong_t)&pcf21xx_cfg[PCF2127] },
+ { .name = "pcf2129", .driver_data = (kernel_ulong_t)&pcf21xx_cfg[PCF2129] },
+ { .name = "pca2129", .driver_data = (kernel_ulong_t)&pcf21xx_cfg[PCF2129] },
+ { .name = "pcf2131", .driver_data = (kernel_ulong_t)&pcf21xx_cfg[PCF2131] },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf2127_i2c_id);
diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c
index f643e0bd7351..01e209d88f5f 100644
--- a/drivers/rtc/rtc-pcf85063.c
+++ b/drivers/rtc/rtc-pcf85063.c
@@ -665,12 +665,12 @@ static const struct pcf85063_config config_rv8263 = {
};
static const struct i2c_device_id pcf85063_ids[] = {
- { "pca85073a", .driver_data = (kernel_ulong_t)&config_pcf85063a },
- { "pcf85063", .driver_data = (kernel_ulong_t)&config_pcf85063 },
- { "pcf85063tp", .driver_data = (kernel_ulong_t)&config_pcf85063tp },
- { "pcf85063a", .driver_data = (kernel_ulong_t)&config_pcf85063a },
- { "rv8263", .driver_data = (kernel_ulong_t)&config_rv8263 },
- {}
+ { .name = "pca85073a", .driver_data = (kernel_ulong_t)&config_pcf85063a },
+ { .name = "pcf85063", .driver_data = (kernel_ulong_t)&config_pcf85063 },
+ { .name = "pcf85063tp", .driver_data = (kernel_ulong_t)&config_pcf85063tp },
+ { .name = "pcf85063a", .driver_data = (kernel_ulong_t)&config_pcf85063a },
+ { .name = "rv8263", .driver_data = (kernel_ulong_t)&config_rv8263 },
+ { }
};
MODULE_DEVICE_TABLE(i2c, pcf85063_ids);
diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c
index 2c63c0ffd05a..e8354953836c 100644
--- a/drivers/rtc/rtc-pcf8523.c
+++ b/drivers/rtc/rtc-pcf8523.c
@@ -495,7 +495,7 @@ static int pcf8523_probe(struct i2c_client *client)
}
static const struct i2c_device_id pcf8523_id[] = {
- { "pcf8523" },
+ { .name = "pcf8523" },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf8523_id);
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index b281e9489df1..81d13733b1e9 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -557,9 +557,9 @@ static int pcf8563_probe(struct i2c_client *client)
}
static const struct i2c_device_id pcf8563_id[] = {
- { "pcf8563" },
- { "rtc8564" },
- { "pca8565" },
+ { .name = "pcf8563" },
+ { .name = "rtc8564" },
+ { .name = "pca8565" },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf8563_id);
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
index 652b9dfa7566..df5e20cbc26c 100644
--- a/drivers/rtc/rtc-pcf8583.c
+++ b/drivers/rtc/rtc-pcf8583.c
@@ -297,7 +297,7 @@ static int pcf8583_probe(struct i2c_client *client)
}
static const struct i2c_device_id pcf8583_id[] = {
- { "pcf8583" },
+ { .name = "pcf8583" },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf8583_id);
diff --git a/drivers/rtc/rtc-renesas-rtca3.c b/drivers/rtc/rtc-renesas-rtca3.c
index cbabaa4dc96a..b3875d041de5 100644
--- a/drivers/rtc/rtc-renesas-rtca3.c
+++ b/drivers/rtc/rtc-renesas-rtca3.c
@@ -103,7 +103,7 @@ enum rtca3_alrm_set_step {
/**
* struct rtca3_ppb_per_cycle - PPB per cycle
- * @ten_sec: PPB per cycle in 10 seconds adjutment mode
+ * @ten_sec: PPB per cycle in 10 seconds adjustment mode
* @sixty_sec: PPB per cycle in 60 seconds adjustment mode
*/
struct rtca3_ppb_per_cycle {
@@ -228,12 +228,19 @@ static void rtca3_prepare_cntalrm_regs_for_read(struct rtca3_priv *priv, bool cn
}
}
+static u32 rtca3_decode_year(u8 mask, u16 year)
+{
+ u8 y = FIELD_GET(mask, year);
+ u32 century = bcd2bin((y == 0x99) ? 0x19 : 0x20);
+
+ return (century * 100 + bcd2bin(y)) - 1900;
+}
+
static int rtca3_read_time(struct device *dev, struct rtc_time *tm)
{
struct rtca3_priv *priv = dev_get_drvdata(dev);
u8 sec, min, hour, wday, mday, month, tmp;
u8 trials = 0;
- u32 year100;
u16 year;
guard(spinlock_irqsave)(&priv->lock);
@@ -274,9 +281,7 @@ static int rtca3_read_time(struct device *dev, struct rtc_time *tm)
tm->tm_wday = bcd2bin(FIELD_GET(RTCA3_RWKCNT_WK, wday));
tm->tm_mday = bcd2bin(FIELD_GET(RTCA3_RDAYCNT_DAY, mday));
tm->tm_mon = bcd2bin(FIELD_GET(RTCA3_RMONCNT_MONTH, month)) - 1;
- year = FIELD_GET(RTCA3_RYRCNT_YEAR, year);
- year100 = bcd2bin((year == 0x99) ? 0x19 : 0x20);
- tm->tm_year = (year100 * 100 + bcd2bin(year)) - 1900;
+ tm->tm_year = rtca3_decode_year(RTCA3_RYRCNT_YEAR, year);
return 0;
}
@@ -354,7 +359,6 @@ static int rtca3_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
struct rtca3_priv *priv = dev_get_drvdata(dev);
u8 sec, min, hour, wday, mday, month;
struct rtc_time *tm = &wkalrm->time;
- u32 year100;
u16 year;
guard(spinlock_irqsave)(&priv->lock);
@@ -373,9 +377,7 @@ static int rtca3_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
tm->tm_wday = bcd2bin(FIELD_GET(RTCA3_RWKAR_DAYW, wday));
tm->tm_mday = bcd2bin(FIELD_GET(RTCA3_RDAYAR_DATE, mday));
tm->tm_mon = bcd2bin(FIELD_GET(RTCA3_RMONAR_MON, month)) - 1;
- year = FIELD_GET(RTCA3_RYRAR_YR, year);
- year100 = bcd2bin((year == 0x99) ? 0x19 : 0x20);
- tm->tm_year = (year100 * 100 + bcd2bin(year)) - 1900;
+ tm->tm_year = rtca3_decode_year(RTCA3_RYRAR_YR, year);
wkalrm->enabled = !!(readb(priv->base + RTCA3_RCR1) & RTCA3_RCR1_AIE);
@@ -455,7 +457,7 @@ setup_failed:
* specified timeout for setup.
*/
writeb(rcr1 & ~RTCA3_RCR1_PIE, priv->base + RTCA3_RCR1);
- readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp, !(tmp & ~RTCA3_RCR1_PIE),
+ readb_poll_timeout_atomic(priv->base + RTCA3_RCR1, tmp, !(tmp & RTCA3_RCR1_PIE),
10, RTCA3_DEFAULT_TIMEOUT_US);
atomic_set(&priv->alrm_sstep, RTCA3_ALRM_SSTEP_DONE);
}
@@ -634,6 +636,8 @@ static int rtca3_initial_setup(struct clk *clk, struct rtca3_priv *priv)
writeb(0, priv->base + RTCA3_RADJ);
ret = readb_poll_timeout(priv->base + RTCA3_RADJ, tmp, !tmp, 10,
RTCA3_DEFAULT_TIMEOUT_US);
+ if (ret)
+ return ret;
/* Start the RTC and enable automatic time error adjustment. */
mask = RTCA3_RCR2_START | RTCA3_RCR2_AADJE;
@@ -700,7 +704,7 @@ static void rtca3_action(void *data)
ret = reset_control_assert(priv->rstc);
if (ret)
- dev_err(dev, "Failed to de-assert reset!");
+ dev_err(dev, "Failed to assert reset!");
ret = pm_runtime_put_sync(dev);
if (ret < 0)
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index 936f4f05c8c7..24bd795d9d95 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -75,12 +75,12 @@ enum rtc_type {
};
static const struct i2c_device_id rs5c372_id[] = {
- { "r2025sd", rtc_r2025sd },
- { "r2221tl", rtc_r2221tl },
- { "rs5c372a", rtc_rs5c372a },
- { "rs5c372b", rtc_rs5c372b },
- { "rv5c386", rtc_rv5c386 },
- { "rv5c387a", rtc_rv5c387a },
+ { .name = "r2025sd", .driver_data = rtc_r2025sd },
+ { .name = "r2221tl", .driver_data = rtc_r2221tl },
+ { .name = "rs5c372a", .driver_data = rtc_rs5c372a },
+ { .name = "rs5c372b", .driver_data = rtc_rs5c372b },
+ { .name = "rv5c386", .driver_data = rtc_rv5c386 },
+ { .name = "rv5c387a", .driver_data = rtc_rv5c387a },
{ }
};
MODULE_DEVICE_TABLE(i2c, rs5c372_id);
diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c
index 83331d1fcab0..98953af2a24a 100644
--- a/drivers/rtc/rtc-rv3029c2.c
+++ b/drivers/rtc/rtc-rv3029c2.c
@@ -807,8 +807,8 @@ static int rv3029_i2c_probe(struct i2c_client *client)
}
static const struct i2c_device_id rv3029_id[] = {
- { "rv3029" },
- { "rv3029c2" },
+ { .name = "rv3029" },
+ { .name = "rv3029c2" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rv3029_id);
diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c
index 2bf988a89fd7..b9b5fee16ee4 100644
--- a/drivers/rtc/rtc-rv8803.c
+++ b/drivers/rtc/rtc-rv8803.c
@@ -631,10 +631,10 @@ static int rv8803_suspend(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(rv8803_pm_ops, rv8803_suspend, rv8803_resume);
static const struct i2c_device_id rv8803_id[] = {
- { "rv8803", rv_8803 },
- { "rv8804", rx_8804 },
- { "rx8803", rx_8803 },
- { "rx8900", rx_8900 },
+ { .name = "rv8803", .driver_data = rv_8803 },
+ { .name = "rv8804", .driver_data = rx_8804 },
+ { .name = "rx8803", .driver_data = rx_8803 },
+ { .name = "rx8900", .driver_data = rx_8900 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rv8803_id);
diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c
index 07bf35ac8d79..1eacd470a27c 100644
--- a/drivers/rtc/rtc-rx6110.c
+++ b/drivers/rtc/rtc-rx6110.c
@@ -449,7 +449,7 @@ static const struct acpi_device_id rx6110_i2c_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, rx6110_i2c_acpi_match);
static const struct i2c_device_id rx6110_i2c_id[] = {
- { "rx6110" },
+ { .name = "rx6110" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rx6110_i2c_id);
diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c
index 171240e50f48..ce3954132336 100644
--- a/drivers/rtc/rtc-rx8010.c
+++ b/drivers/rtc/rtc-rx8010.c
@@ -50,7 +50,7 @@
#define RX8010_ALARM_AE BIT(7)
static const struct i2c_device_id rx8010_id[] = {
- { "rx8010" },
+ { .name = "rx8010" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rx8010_id);
diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c
index c57081f9e02b..5eeaa929f3ef 100644
--- a/drivers/rtc/rtc-rx8025.c
+++ b/drivers/rtc/rtc-rx8025.c
@@ -71,8 +71,8 @@ enum rx_model {
};
static const struct i2c_device_id rx8025_id[] = {
- { "rx8025", model_rx_8025 },
- { "rx8035", model_rx_8035 },
+ { .name = "rx8025", .driver_data = model_rx_8025 },
+ { .name = "rx8035", .driver_data = model_rx_8035 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rx8025_id);
diff --git a/drivers/rtc/rtc-rx8581.c b/drivers/rtc/rtc-rx8581.c
index 20c2dff01bae..cf4dab94c337 100644
--- a/drivers/rtc/rtc-rx8581.c
+++ b/drivers/rtc/rtc-rx8581.c
@@ -294,7 +294,7 @@ static int rx8581_probe(struct i2c_client *client)
}
static const struct i2c_device_id rx8581_id[] = {
- { "rx8581" },
+ { .name = "rx8581" },
{ }
};
MODULE_DEVICE_TABLE(i2c, rx8581_id);
diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c
index a4678d7c6cf6..b72eef4fb099 100644
--- a/drivers/rtc/rtc-s35390a.c
+++ b/drivers/rtc/rtc-s35390a.c
@@ -51,7 +51,7 @@
#define S35390A_INT2_MODE_PMIN (BIT(3) | BIT(2)) /* INT2FE | INT2ME */
static const struct i2c_device_id s35390a_id[] = {
- { "s35390a" },
+ { .name = "s35390a" },
{ }
};
MODULE_DEVICE_TABLE(i2c, s35390a_id);
@@ -297,7 +297,7 @@ static int s35390a_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
else
sts = S35390A_INT2_MODE_NOINTR;
- /* set interupt mode*/
+ /* set interrupt mode*/
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
if (err < 0)
return err;
diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c
index c6ed5a4ca8a0..aa706074ec3e 100644
--- a/drivers/rtc/rtc-s5m.c
+++ b/drivers/rtc/rtc-s5m.c
@@ -807,12 +807,12 @@ static int s5m_rtc_suspend(struct device *dev)
static SIMPLE_DEV_PM_OPS(s5m_rtc_pm_ops, s5m_rtc_suspend, s5m_rtc_resume);
static const struct platform_device_id s5m_rtc_id[] = {
- { "s5m-rtc", S5M8767X },
- { "s2mpg10-rtc", S2MPG10 },
- { "s2mps13-rtc", S2MPS13X },
- { "s2mps14-rtc", S2MPS14X },
- { "s2mps15-rtc", S2MPS15X },
- { },
+ { .name = "s5m-rtc", .driver_data = S5M8767X },
+ { .name = "s2mpg10-rtc", .driver_data = S2MPG10 },
+ { .name = "s2mps13-rtc", .driver_data = S2MPS13X },
+ { .name = "s2mps14-rtc", .driver_data = S2MPS14X },
+ { .name = "s2mps15-rtc", .driver_data = S2MPS15X },
+ { }
};
MODULE_DEVICE_TABLE(platform, s5m_rtc_id);
diff --git a/drivers/rtc/rtc-sd2405al.c b/drivers/rtc/rtc-sd2405al.c
index 708ea5d964de..7982a910a537 100644
--- a/drivers/rtc/rtc-sd2405al.c
+++ b/drivers/rtc/rtc-sd2405al.c
@@ -202,7 +202,7 @@ static int sd2405al_probe(struct i2c_client *client)
}
static const struct i2c_device_id sd2405al_id[] = {
- { "sd2405al" },
+ { .name = "sd2405al" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, sd2405al_id);
diff --git a/drivers/rtc/rtc-sd3078.c b/drivers/rtc/rtc-sd3078.c
index 10cc1dcfc774..2c61f0e204a4 100644
--- a/drivers/rtc/rtc-sd3078.c
+++ b/drivers/rtc/rtc-sd3078.c
@@ -186,7 +186,7 @@ static int sd3078_probe(struct i2c_client *client)
}
static const struct i2c_device_id sd3078_id[] = {
- { "sd3078" },
+ { .name = "sd3078" },
{ }
};
MODULE_DEVICE_TABLE(i2c, sd3078_id);
diff --git a/drivers/rtc/rtc-tps6594.c b/drivers/rtc/rtc-tps6594.c
index 7c6246e3f029..2cebd54c2dbf 100644
--- a/drivers/rtc/rtc-tps6594.c
+++ b/drivers/rtc/rtc-tps6594.c
@@ -485,8 +485,8 @@ static int tps6594_rtc_suspend(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(tps6594_rtc_pm_ops, tps6594_rtc_suspend, tps6594_rtc_resume);
static const struct platform_device_id tps6594_rtc_id_table[] = {
- { "tps6594-rtc", },
- {}
+ { .name = "tps6594-rtc" },
+ { }
};
MODULE_DEVICE_TABLE(platform, tps6594_rtc_id_table);
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index b8a0fccef14e..bb1a5c86f621 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -663,7 +663,7 @@ static void x1205_remove(struct i2c_client *client)
}
static const struct i2c_device_id x1205_id[] = {
- { "x1205" },
+ { .name = "x1205" },
{ }
};
MODULE_DEVICE_TABLE(i2c, x1205_id);
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index f38a0f7d0f27..0490777fa406 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -1372,34 +1372,6 @@ int sdw_slave_get_current_bank(struct sdw_slave *slave)
}
EXPORT_SYMBOL_GPL(sdw_slave_get_current_bank);
-/**
- * sdw_slave_wait_for_init - Wait for device initialisation
- * @slave: Pointer to the SoundWire peripheral.
- * @timeout_ms: Timeout in milliseconds.
- *
- * Wait for a peripheral device to enumerate and be initialised by the
- * SoundWire core.
- *
- * Return: Zero on success, and a negative error code on failure.
- */
-int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms)
-{
- unsigned long time;
-
- time = wait_for_completion_timeout(&slave->initialization_complete,
- msecs_to_jiffies(timeout_ms));
- if (!time) {
- dev_err(&slave->dev, "Initialization not complete\n");
- sdw_show_ping_status(slave->bus, true);
- return -ETIMEDOUT;
- }
-
- slave->unattach_request = 0;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(sdw_slave_wait_for_init);
-
static int sdw_slave_set_frequency(struct sdw_slave *slave)
{
int scale_index;
diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c
index 4fc864d38cff..603e81a92c57 100644
--- a/drivers/spi/spi-dw-mmio.c
+++ b/drivers/spi/spi-dw-mmio.c
@@ -438,6 +438,7 @@ static const struct of_device_id dw_spi_mmio_of_match[] = {
{ .compatible = "amazon,alpine-dw-apb-ssi", .data = dw_spi_alpine_init},
{ .compatible = "renesas,rzn1-spi", .data = dw_spi_pssi_init},
{ .compatible = "snps,dwc-ssi-1.01a", .data = dw_spi_hssi_init},
+ { .compatible = "snps,dwc-ssi-2.00a", .data = dw_spi_hssi_init},
{ .compatible = "intel,keembay-ssi", .data = dw_spi_hssi_no_dma_init},
{
.compatible = "intel,mountevans-imc-ssi",
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 9cc79c566a70..2f2debc64e73 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -282,6 +282,7 @@ static inline void dw_spi_shutdown_chip(struct dw_spi *dws)
{
dw_spi_enable_chip(dws, 0);
dw_spi_set_clk(dws, 0);
+ dws->current_freq = 0;
}
extern void dw_spi_set_cs(struct spi_device *spi, bool enable);
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index ae9912905c67..79a6c1a60b0a 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -2152,7 +2152,8 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
if (spi_imx->usedma) {
ret = spi_imx_dma_transfer(spi_imx, transfer);
if (transfer->error & SPI_TRANS_FAIL_NO_START) {
- spi_imx->usedma = false;
+ controller->fallback = true;
+ spi_imx_setupxfer(spi, transfer);
if (spi_imx->target_mode)
return spi_imx_pio_transfer_target(spi, transfer);
else
diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c
index 1ef7bd91b3b3..b63c7856e758 100644
--- a/drivers/spi/spi-rpc-if.c
+++ b/drivers/spi/spi-rpc-if.c
@@ -206,8 +206,12 @@ static int rpcif_spi_suspend(struct device *dev)
static int rpcif_spi_resume(struct device *dev)
{
struct spi_controller *ctlr = dev_get_drvdata(dev);
+ struct rpcif *rpc = spi_controller_get_devdata(ctlr);
+ int ret;
- rpcif_hw_init(dev, false);
+ ret = rpcif_hw_init(rpc->dev, false);
+ if (ret)
+ return ret;
return spi_controller_resume(ctlr);
}
diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c
index cc20fd11f03f..86fce9a571da 100644
--- a/drivers/spi/spi-uniphier.c
+++ b/drivers/spi/spi-uniphier.c
@@ -656,6 +656,8 @@ static int uniphier_spi_probe(struct platform_device *pdev)
priv->host = host;
priv->is_save_param = false;
+ init_completion(&priv->xfer_done);
+
priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
@@ -679,8 +681,6 @@ static int uniphier_spi_probe(struct platform_device *pdev)
return ret;
}
- init_completion(&priv->xfer_done);
-
clk_rate = clk_get_rate(priv->clk);
host->max_speed_hz = DIV_ROUND_UP(clk_rate, SSI_MIN_CLK_DIVIDER);
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 76e3563c523f..f897789a44d1 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -355,12 +355,16 @@ EXPORT_SYMBOL_GPL(spi_get_device_id);
const void *spi_get_device_match_data(const struct spi_device *sdev)
{
const void *match;
+ const struct spi_device_id *id;
match = device_get_match_data(&sdev->dev);
if (match)
return match;
- return (const void *)spi_get_device_id(sdev)->driver_data;
+ id = spi_get_device_id(sdev);
+ if (!id)
+ return NULL;
+ return (const void *)id->driver_data;
}
EXPORT_SYMBOL_GPL(spi_get_device_match_data);
@@ -2975,12 +2979,12 @@ struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr,
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list,
acpi_spi_add_resource, &lookup);
- acpi_dev_free_resource_list(&resource_list);
-
if (ret < 0)
/* Found SPI in _CRS but it points to another controller */
return ERR_PTR(ret);
+ acpi_dev_free_resource_list(&resource_list);
+
if (!lookup.max_speed_hz &&
ACPI_SUCCESS(acpi_get_parent(adev->handle, &parent_handle)) &&
device_match_acpi_handle(lookup.ctlr->dev.parent, parent_handle)) {
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index 69f8d456324a..2e2cb4774103 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -28,6 +28,7 @@
#define PMIC_ARB_VERSION_V5_MIN 0x50000000
#define PMIC_ARB_VERSION_V7_MIN 0x70000000
#define PMIC_ARB_VERSION_V8_MIN 0x80000000
+#define PMIC_ARB_VERSION_V8P5_MIN 0x80050000
#define PMIC_ARB_INT_EN 0x0004
#define PMIC_ARB_FEATURES 0x0004
@@ -62,14 +63,6 @@
/* Ownership Table */
#define SPMI_OWNERSHIP_PERIPH2OWNER(X) ((X) & 0x7)
-/* Channel Status fields */
-enum pmic_arb_chnl_status {
- PMIC_ARB_STATUS_DONE = BIT(0),
- PMIC_ARB_STATUS_FAILURE = BIT(1),
- PMIC_ARB_STATUS_DENIED = BIT(2),
- PMIC_ARB_STATUS_DROPPED = BIT(3),
-};
-
/* Command register fields */
#define PMIC_ARB_CMD_MAX_BYTE_COUNT 8
@@ -239,6 +232,7 @@ struct spmi_pmic_arb {
* on v2 address of SPMI_PIC_IRQ_CLEARn.
* @apid_map_offset: offset of PMIC_ARB_REG_CHNLn
* @apid_owner: on v2 and later address of SPMI_PERIPHn_2OWNER_TABLE_REG
+ * @check_chnl_status: checks channel status and returns error code if any
*/
struct pmic_arb_ver_ops {
const char *ver_str;
@@ -261,6 +255,8 @@ struct pmic_arb_ver_ops {
void __iomem *(*irq_clear)(struct spmi_pmic_arb_bus *bus, u16 n);
u32 (*apid_map_offset)(u16 n);
void __iomem *(*apid_owner)(struct spmi_pmic_arb_bus *bus, u16 n);
+ int (*check_chnl_status)(struct spmi_controller *ctrl, u32 status,
+ u8 sid, u16 addr, u32 offset);
};
static inline void pmic_arb_base_write(struct spmi_pmic_arb *pmic_arb,
@@ -306,6 +302,84 @@ static void pmic_arb_write_data(struct spmi_pmic_arb *pmic_arb, const u8 *buf,
__raw_writel(data, pmic_arb->wr_base + reg);
}
+static int pmic_arb_check_chnl_status_v1(struct spmi_controller *ctrl,
+ u32 status, u8 sid, u16 addr,
+ u32 offset)
+{
+ /* Check if DONE bit is set */
+ if (!(status & BIT(0)))
+ return -EAGAIN;
+
+ if (status & BIT(1)) {
+ dev_err(&ctrl->dev, "%s: %#x %#x: transaction failed (%#x) reg: 0x%x\n",
+ __func__, sid, addr, status, offset);
+ WARN_ON(1);
+ return -EIO;
+ }
+
+ if (status & BIT(2)) {
+ dev_err(&ctrl->dev, "%s: %#x %#x: transaction denied (%#x)\n",
+ __func__, sid, addr, status);
+ return -EPERM;
+ }
+
+ if (status & BIT(3)) {
+ dev_err(&ctrl->dev, "%s: %#x %#x: transaction dropped (%#x)\n",
+ __func__, sid, addr, status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int pmic_arb_check_chnl_status_v8p5(struct spmi_controller *ctrl,
+ u32 status, u8 sid, u16 addr,
+ u32 offset)
+{
+ /* Check if DONE bit is set */
+ if (!(status & BIT(0)))
+ return -EAGAIN;
+
+ if (status & BIT(1)) {
+ dev_err(&ctrl->dev, "%s: %#x %#x: transaction failed (%#x) reg: 0x%x\n",
+ __func__, sid, addr, status, offset);
+ WARN_ON(1);
+ return -EIO;
+ }
+
+ if (status & BIT(2)) {
+ dev_err(&ctrl->dev, "%s: %#x %#x: CRC error (%#x)\n",
+ __func__, sid, addr, status);
+ return -EIO;
+ }
+
+ if (status & BIT(3)) {
+ dev_err(&ctrl->dev, "%s: %#x %#x: parity error (%#x)\n",
+ __func__, sid, addr, status);
+ return -EIO;
+ }
+
+ if (status & BIT(4)) {
+ dev_err(&ctrl->dev, "%s: %#x %#x: NACK error (%#x)\n",
+ __func__, sid, addr, status);
+ return -EIO;
+ }
+
+ if (status & BIT(5)) {
+ dev_err(&ctrl->dev, "%s: %#x %#x: transaction denied (%#x)\n",
+ __func__, sid, addr, status);
+ return -EPERM;
+ }
+
+ if (status & BIT(6)) {
+ dev_err(&ctrl->dev, "%s: %#x %#x: transaction dropped (%#x)\n",
+ __func__, sid, addr, status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
void __iomem *base, u8 sid, u16 addr,
enum pmic_arb_channel ch_type)
@@ -327,28 +401,10 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
while (timeout--) {
status = readl_relaxed(base + offset);
- if (status & PMIC_ARB_STATUS_DONE) {
- if (status & PMIC_ARB_STATUS_DENIED) {
- dev_err(&ctrl->dev, "%s: %#x %#x: transaction denied (%#x)\n",
- __func__, sid, addr, status);
- return -EPERM;
- }
+ rc = pmic_arb->ver_ops->check_chnl_status(ctrl, status, sid, addr, offset);
+ if (rc != -EAGAIN)
+ return rc;
- if (status & PMIC_ARB_STATUS_FAILURE) {
- dev_err(&ctrl->dev, "%s: %#x %#x: transaction failed (%#x) reg: 0x%x\n",
- __func__, sid, addr, status, offset);
- WARN_ON(1);
- return -EIO;
- }
-
- if (status & PMIC_ARB_STATUS_DROPPED) {
- dev_err(&ctrl->dev, "%s: %#x %#x: transaction dropped (%#x)\n",
- __func__, sid, addr, status);
- return -EIO;
- }
-
- return 0;
- }
udelay(1);
}
@@ -1768,6 +1824,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v1 = {
.irq_clear = pmic_arb_irq_clear_v1,
.apid_map_offset = pmic_arb_apid_map_offset_v2,
.apid_owner = pmic_arb_apid_owner_v2,
+ .check_chnl_status = pmic_arb_check_chnl_status_v1,
};
static const struct pmic_arb_ver_ops pmic_arb_v2 = {
@@ -1784,6 +1841,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v2 = {
.irq_clear = pmic_arb_irq_clear_v2,
.apid_map_offset = pmic_arb_apid_map_offset_v2,
.apid_owner = pmic_arb_apid_owner_v2,
+ .check_chnl_status = pmic_arb_check_chnl_status_v1,
};
static const struct pmic_arb_ver_ops pmic_arb_v3 = {
@@ -1800,6 +1858,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v3 = {
.irq_clear = pmic_arb_irq_clear_v2,
.apid_map_offset = pmic_arb_apid_map_offset_v2,
.apid_owner = pmic_arb_apid_owner_v2,
+ .check_chnl_status = pmic_arb_check_chnl_status_v1,
};
static const struct pmic_arb_ver_ops pmic_arb_v5 = {
@@ -1816,6 +1875,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v5 = {
.irq_clear = pmic_arb_irq_clear_v5,
.apid_map_offset = pmic_arb_apid_map_offset_v5,
.apid_owner = pmic_arb_apid_owner_v2,
+ .check_chnl_status = pmic_arb_check_chnl_status_v1,
};
static const struct pmic_arb_ver_ops pmic_arb_v7 = {
@@ -1832,6 +1892,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v7 = {
.irq_clear = pmic_arb_irq_clear_v7,
.apid_map_offset = pmic_arb_apid_map_offset_v7,
.apid_owner = pmic_arb_apid_owner_v7,
+ .check_chnl_status = pmic_arb_check_chnl_status_v1,
};
static const struct pmic_arb_ver_ops pmic_arb_v8 = {
@@ -1849,6 +1910,25 @@ static const struct pmic_arb_ver_ops pmic_arb_v8 = {
.irq_clear = pmic_arb_irq_clear_v8,
.apid_map_offset = pmic_arb_apid_map_offset_v8,
.apid_owner = pmic_arb_apid_owner_v8,
+ .check_chnl_status = pmic_arb_check_chnl_status_v1,
+};
+
+static const struct pmic_arb_ver_ops pmic_arb_v8p5 = {
+ .ver_str = "v8.5",
+ .get_core_resources = pmic_arb_get_core_resources_v8,
+ .get_bus_resources = pmic_arb_get_bus_resources_v8,
+ .init_apid = pmic_arb_init_apid_v8,
+ .ppid_to_apid = pmic_arb_ppid_to_apid_v5,
+ .non_data_cmd = pmic_arb_non_data_cmd_v2,
+ .offset = pmic_arb_offset_v8,
+ .fmt_cmd = pmic_arb_fmt_cmd_v2,
+ .owner_acc_status = pmic_arb_owner_acc_status_v7,
+ .acc_enable = pmic_arb_acc_enable_v8,
+ .irq_status = pmic_arb_irq_status_v8,
+ .irq_clear = pmic_arb_irq_clear_v8,
+ .apid_map_offset = pmic_arb_apid_map_offset_v8,
+ .apid_owner = pmic_arb_apid_owner_v8,
+ .check_chnl_status = pmic_arb_check_chnl_status_v8p5,
};
static const struct irq_domain_ops pmic_arb_irq_domain_ops = {
@@ -2030,8 +2110,10 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
pmic_arb->ver_ops = &pmic_arb_v5;
else if (hw_ver < PMIC_ARB_VERSION_V8_MIN)
pmic_arb->ver_ops = &pmic_arb_v7;
- else
+ else if (hw_ver < PMIC_ARB_VERSION_V8P5_MIN)
pmic_arb->ver_ops = &pmic_arb_v8;
+ else
+ pmic_arb->ver_ops = &pmic_arb_v8p5;
err = pmic_arb->ver_ops->get_core_resources(pdev, core);
if (err)
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index e889b129f3ac..57b7c0cb4240 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -450,7 +450,7 @@ struct spmi_controller *spmi_controller_alloc(struct device *parent,
if (WARN_ON(!parent))
return ERR_PTR(-EINVAL);
- ctrl = kzalloc(sizeof(*ctrl) + size, GFP_KERNEL);
+ ctrl = kzalloc_flex(*ctrl, priv, size);
if (!ctrl)
return ERR_PTR(-ENOMEM);
@@ -459,7 +459,7 @@ struct spmi_controller *spmi_controller_alloc(struct device *parent,
ctrl->dev.bus = &spmi_bus_type;
ctrl->dev.parent = parent;
ctrl->dev.of_node = parent->of_node;
- spmi_controller_set_drvdata(ctrl, &ctrl[1]);
+ spmi_controller_set_drvdata(ctrl, ctrl->priv);
id = ida_alloc(&ctrl_ida, GFP_KERNEL);
if (id < 0) {
diff --git a/drivers/thermal/intel/therm_throt.c b/drivers/thermal/intel/therm_throt.c
index 44fa4dd15dd1..45a8ef4a608b 100644
--- a/drivers/thermal/intel/therm_throt.c
+++ b/drivers/thermal/intel/therm_throt.c
@@ -529,8 +529,13 @@ static int thermal_throttle_online(unsigned int cpu)
{
struct thermal_state *state = &per_cpu(thermal_state, cpu);
struct device *dev = get_cpu_device(cpu);
+ int err;
u32 l;
+ err = thermal_throttle_add_dev(dev, cpu);
+ if (err)
+ return err;
+
state->package_throttle.level = PACKAGE_LEVEL;
state->core_throttle.level = CORE_LEVEL;
@@ -548,7 +553,7 @@ static int thermal_throttle_online(unsigned int cpu)
l = apic_read(APIC_LVTTHMR);
apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
- return thermal_throttle_add_dev(dev, cpu);
+ return err;
}
static int thermal_throttle_offline(unsigned int cpu)
diff --git a/drivers/thermal/testing/command.c b/drivers/thermal/testing/command.c
index fbf7ab9729b5..90e06c593327 100644
--- a/drivers/thermal/testing/command.c
+++ b/drivers/thermal/testing/command.c
@@ -86,7 +86,10 @@
#include "thermal_testing.h"
-struct dentry *d_testing;
+struct workqueue_struct *tt_wq __ro_after_init;
+
+struct dentry *d_testing __ro_after_init;
+static struct dentry *d_command __ro_after_init;
#define TT_COMMAND_SIZE 16
@@ -203,17 +206,42 @@ static const struct file_operations tt_command_fops = {
static int __init thermal_testing_init(void)
{
+ int error;
+
+ tt_wq = alloc_workqueue("thermal_testing", WQ_UNBOUND, 0);
+ if (!tt_wq)
+ return -ENOMEM;
+
d_testing = debugfs_create_dir("thermal-testing", NULL);
- if (!IS_ERR(d_testing))
- debugfs_create_file("command", 0200, d_testing, NULL,
- &tt_command_fops);
+ if (IS_ERR(d_testing)) {
+ error = PTR_ERR(d_testing);
+ goto destroy_wq;
+ }
+
+ d_command = debugfs_create_file("command", 0200, d_testing, NULL, &tt_command_fops);
+ if (IS_ERR(d_command)) {
+ error = PTR_ERR(d_command);
+ goto remove_d_testing;
+ }
return 0;
+
+remove_d_testing:
+ debugfs_remove(d_testing);
+destroy_wq:
+ destroy_workqueue(tt_wq);
+ return error;
}
module_init(thermal_testing_init);
static void __exit thermal_testing_exit(void)
{
+ /* First, prevent new commands from being entered. */
+ debugfs_remove(d_command);
+ /* Flush commands in progress (if any). */
+ flush_workqueue(tt_wq);
+ destroy_workqueue(tt_wq);
+ /* Remove the directory structure and clean up. */
debugfs_remove(d_testing);
tt_zone_cleanup();
}
diff --git a/drivers/thermal/testing/thermal_testing.h b/drivers/thermal/testing/thermal_testing.h
index c790a32aae4e..5880c9a63dba 100644
--- a/drivers/thermal/testing/thermal_testing.h
+++ b/drivers/thermal/testing/thermal_testing.h
@@ -1,4 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/workqueue.h>
+
+extern struct workqueue_struct *tt_wq;
+
+static inline void tt_queue_work(struct work_struct *work)
+{
+ queue_work(tt_wq, work);
+}
extern struct dentry *d_testing;
diff --git a/drivers/thermal/testing/zone.c b/drivers/thermal/testing/zone.c
index f7f9ca2f1f2c..6db26276dd41 100644
--- a/drivers/thermal/testing/zone.c
+++ b/drivers/thermal/testing/zone.c
@@ -13,7 +13,6 @@
#include <linux/idr.h>
#include <linux/list.h>
#include <linux/thermal.h>
-#include <linux/workqueue.h>
#include "thermal_testing.h"
@@ -207,7 +206,7 @@ int tt_add_tz(void)
INIT_WORK(&tt_work->work, tt_add_tz_work_fn);
tt_work->tt_zone = no_free_ptr(tt_zone);
- schedule_work(&(no_free_ptr(tt_work)->work));
+ tt_queue_work(&(no_free_ptr(tt_work)->work));
return 0;
}
@@ -269,7 +268,7 @@ int tt_del_tz(const char *arg)
INIT_WORK(&tt_work->work, tt_del_tz_work_fn);
tt_work->tt_zone = tt_zone;
- schedule_work(&(no_free_ptr(tt_work)->work));
+ tt_queue_work(&(no_free_ptr(tt_work)->work));
return 0;
}
@@ -358,7 +357,7 @@ int tt_zone_add_trip(const char *arg)
INIT_WORK(&tt_work->work, tt_zone_add_trip_work_fn);
tt_work->tt_zone = no_free_ptr(tt_zone);
tt_work->tt_trip = no_free_ptr(tt_trip);
- schedule_work(&(no_free_ptr(tt_work)->work));
+ tt_queue_work(&(no_free_ptr(tt_work)->work));
return 0;
}
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 9077d3b99357..9f5c4c101581 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -1273,6 +1273,7 @@ static void fbcon_deinit(struct vc_data *vc)
int idx;
fbcon_free_font(p);
+ p->mode = NULL;
idx = con2fb_map[vc->vc_num];
if (idx == -1)
@@ -1443,14 +1444,14 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
p = &fb_display[unit];
- if (var_to_display(p, var, info))
- return;
-
vc = vc_cons[unit].d;
if (!vc)
return;
+ if (var_to_display(p, var, info))
+ return;
+
default_mode = vc->vc_display_fg;
svc = *default_mode;
t = &fb_display[svc->vc_num];
@@ -2405,6 +2406,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
int resize, ret, old_width, old_height, old_charcount;
font_data_t *old_fontdata = p->fontdata;
const u8 *old_data = vc->vc_font.data;
+ unsigned short old_hi_font_mask = vc->vc_hi_font_mask;
font_data_get(data);
@@ -2451,6 +2453,12 @@ err_out:
vc->vc_font.height = old_height;
vc->vc_font.charcount = old_charcount;
+ /* Restore the hi_font state and screen buffer */
+ if (old_hi_font_mask && !vc->vc_hi_font_mask)
+ set_vc_hi_font(vc, true);
+ else if (!old_hi_font_mask && vc->vc_hi_font_mask)
+ set_vc_hi_font(vc, false);
+
font_data_put(data);
return ret;
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index e5221653ec2b..2f1c56e5a7a2 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -767,6 +767,18 @@ int fb_new_modelist(struct fb_info *info)
if (list_empty(&info->modelist))
return 1;
+ /*
+ * The new modelist may not contain the current mode (info->var), and
+ * fbcon_new_modelist() below only re-points consoles mapped to this
+ * framebuffer. Add the current mode here so info->var keeps a match
+ * even when fbcon is unbound.
+ */
+ if (!fb_match_mode(&info->var, &info->modelist)) {
+ fb_var_to_videomode(&mode, &info->var);
+ if (fb_add_videomode(&mode, &info->modelist))
+ return 1;
+ }
+
fbcon_new_modelist(info);
return 0;
diff --git a/drivers/video/fbdev/core/fbsysfs.c b/drivers/video/fbdev/core/fbsysfs.c
index d9743ef35355..ea196603c7a8 100644
--- a/drivers/video/fbdev/core/fbsysfs.c
+++ b/drivers/video/fbdev/core/fbsysfs.c
@@ -10,6 +10,7 @@
#include <linux/major.h>
#include "fb_internal.h"
+#include "fbcon.h"
static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var)
{
@@ -108,8 +109,15 @@ static ssize_t store_modes(struct device *device,
if (fb_new_modelist(fb_info)) {
fb_destroy_modelist(&fb_info->modelist);
list_splice(&old_list, &fb_info->modelist);
- } else
+ } else {
+ /*
+ * fb_display[i].mode and fb_info->mode both point into the old
+ * list. Clear them before it is freed.
+ */
+ fbcon_delete_modelist(&old_list);
+ fb_info->mode = NULL;
fb_destroy_modelist(&old_list);
+ }
unlock_fb_info(fb_info);
console_unlock();
diff --git a/drivers/video/fbdev/goldfishfb.c b/drivers/video/fbdev/goldfishfb.c
index c9871281bc1d..e5d79886ea66 100644
--- a/drivers/video/fbdev/goldfishfb.c
+++ b/drivers/video/fbdev/goldfishfb.c
@@ -138,10 +138,12 @@ static int goldfish_fb_pan_display(struct fb_var_screeninfo *var,
writel(fb->fb.fix.smem_start + fb->fb.var.xres * 2 * var->yoffset,
fb->reg_base + FB_SET_BASE);
spin_unlock_irqrestore(&fb->lock, irq_flags);
- wait_event_timeout(fb->wait,
- fb->base_update_count != base_update_count, HZ / 15);
- if (fb->base_update_count == base_update_count)
+ if (!wait_event_timeout(fb->wait,
+ fb->base_update_count != base_update_count,
+ HZ / 15)) {
pr_err("%s: timeout waiting for base update\n", __func__);
+ return -ETIMEDOUT;
+ }
return 0;
}
@@ -251,7 +253,9 @@ static int goldfish_fb_probe(struct platform_device *pdev)
goto err_request_irq_failed;
writel(FB_INT_BASE_UPDATE_DONE, fb->reg_base + FB_INT_ENABLE);
- goldfish_fb_pan_display(&fb->fb.var, &fb->fb); /* updates base */
+ ret = goldfish_fb_pan_display(&fb->fb.var, &fb->fb); /* updates base */
+ if (ret)
+ goto err_pan_display_failed;
ret = register_framebuffer(&fb->fb);
if (ret)
@@ -259,6 +263,7 @@ static int goldfish_fb_probe(struct platform_device *pdev)
return 0;
err_register_framebuffer_failed:
+err_pan_display_failed:
free_irq(fb->irq, fb);
err_request_irq_failed:
err_fb_set_var_failed:
diff --git a/drivers/video/fbdev/pm2fb.c b/drivers/video/fbdev/pm2fb.c
index 412ff249b5c7..058075a34c5d 100644
--- a/drivers/video/fbdev/pm2fb.c
+++ b/drivers/video/fbdev/pm2fb.c
@@ -1711,6 +1711,7 @@ static int pm2fb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
err_exit_both:
kfree(info->pixmap.addr);
err_exit_pixmap:
+ arch_phys_wc_del(default_par->wc_cookie);
iounmap(info->screen_base);
release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
err_exit_mmio:
diff --git a/drivers/video/fbdev/vga16fb.c b/drivers/video/fbdev/vga16fb.c
index 22085d3668e8..cdd6b8de0ceb 100644
--- a/drivers/video/fbdev/vga16fb.c
+++ b/drivers/video/fbdev/vga16fb.c
@@ -1421,8 +1421,8 @@ static void vga16fb_remove(struct platform_device *dev)
}
static const struct platform_device_id vga16fb_driver_id_table[] = {
- {"ega-framebuffer", 0},
- {"vga-framebuffer", 0},
+ { .name = "ega-framebuffer" },
+ { .name = "vga-framebuffer" },
{ }
};
MODULE_DEVICE_TABLE(platform, vga16fb_driver_id_table);
diff --git a/drivers/video/fbdev/via/via-core.c b/drivers/video/fbdev/via/via-core.c
index a8d4a3e2c65e..1632a669941a 100644
--- a/drivers/video/fbdev/via/via-core.c
+++ b/drivers/video/fbdev/via/via-core.c
@@ -234,6 +234,7 @@ int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg)
dma_addr_t descr_handle;
unsigned long flags;
int i;
+ int ret = 0;
struct scatterlist *sgentry;
dma_addr_t nextdesc;
@@ -290,8 +291,10 @@ int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg)
*/
wait_for_completion_timeout(&viafb_dma_completion, 1);
msleep(1);
- if ((viafb_mmio_read(VDMA_CSR0)&VDMA_C_DONE) == 0)
+ if ((viafb_mmio_read(VDMA_CSR0) & VDMA_C_DONE) == 0) {
printk(KERN_ERR "VIA DMA timeout!\n");
+ ret = -ETIMEDOUT;
+ }
/*
* Clean up and we're done.
*/
@@ -301,7 +304,7 @@ int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg)
dma_free_coherent(&global_dev.pdev->dev,
nsg*sizeof(struct viafb_vx855_dma_descr), descrpages,
descr_handle);
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(viafb_dma_copy_out_sg);
#endif /* CONFIG_VIDEO_VIA_CAMERA */
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 0a86f672cc09..61bd6d92ff25 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -2561,7 +2561,8 @@ int ceph_pool_perm_check(struct inode *inode, int need)
struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_string *pool_ns;
s64 pool;
- int ret, flags;
+ int ret;
+ unsigned long flags;
/* Only need to do this for regular files */
if (!S_ISREG(inode->i_mode))
@@ -2603,20 +2604,19 @@ check:
if (ret < 0)
return ret;
- flags = CEPH_I_POOL_PERM;
- if (ret & POOL_READ)
- flags |= CEPH_I_POOL_RD;
- if (ret & POOL_WRITE)
- flags |= CEPH_I_POOL_WR;
-
spin_lock(&ci->i_ceph_lock);
if (pool == ci->i_layout.pool_id &&
pool_ns == rcu_dereference_raw(ci->i_layout.pool_ns)) {
- ci->i_ceph_flags |= flags;
- } else {
+ set_bit(CEPH_I_POOL_PERM_BIT, &ci->i_ceph_flags);
+ if (ret & POOL_READ)
+ set_bit(CEPH_I_POOL_RD_BIT, &ci->i_ceph_flags);
+ if (ret & POOL_WRITE)
+ set_bit(CEPH_I_POOL_WR_BIT, &ci->i_ceph_flags);
+ } else {
pool = ci->i_layout.pool_id;
- flags = ci->i_ceph_flags;
}
+ /* Re-read flags under the lock so check: sees the updated bits. */
+ flags = ci->i_ceph_flags;
spin_unlock(&ci->i_ceph_lock);
goto check;
}
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index d51454e995a8..4b37d9ffdf7f 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -549,7 +549,7 @@ static void __cap_delay_requeue_front(struct ceph_mds_client *mdsc,
doutc(mdsc->fsc->client, "%p %llx.%llx\n", inode, ceph_vinop(inode));
spin_lock(&mdsc->cap_delay_lock);
- ci->i_ceph_flags |= CEPH_I_FLUSH;
+ set_bit(CEPH_I_FLUSH_BIT, &ci->i_ceph_flags);
if (!list_empty(&ci->i_cap_delay_list))
list_del_init(&ci->i_cap_delay_list);
list_add(&ci->i_cap_delay_list, &mdsc->cap_delay_list);
@@ -1409,7 +1409,7 @@ static void __prep_cap(struct cap_msg_args *arg, struct ceph_cap *cap,
ceph_cap_string(revoking));
BUG_ON((retain & CEPH_CAP_PIN) == 0);
- ci->i_ceph_flags &= ~CEPH_I_FLUSH;
+ clear_bit(CEPH_I_FLUSH_BIT, &ci->i_ceph_flags);
cap->issued &= retain; /* drop bits we don't want */
/*
@@ -1648,6 +1648,7 @@ static void __ceph_flush_snaps(struct ceph_inode_info *ci,
spin_lock(&mdsc->cap_dirty_lock);
capsnap->cap_flush.tid = ++mdsc->last_cap_flush_tid;
+ capsnap->cap_flush.ci = ci;
list_add_tail(&capsnap->cap_flush.g_list,
&mdsc->cap_flush_list);
if (oldest_flush_tid == 0)
@@ -1666,7 +1667,7 @@ static void __ceph_flush_snaps(struct ceph_inode_info *ci,
last_tid = capsnap->cap_flush.tid;
}
- ci->i_ceph_flags &= ~CEPH_I_FLUSH_SNAPS;
+ clear_bit(CEPH_I_FLUSH_SNAPS_BIT, &ci->i_ceph_flags);
while (first_tid <= last_tid) {
struct ceph_cap *cap = ci->i_auth_cap;
@@ -1846,6 +1847,7 @@ struct ceph_cap_flush *ceph_alloc_cap_flush(void)
return NULL;
cf->is_capsnap = false;
+ cf->ci = NULL;
return cf;
}
@@ -1931,6 +1933,7 @@ static u64 __mark_caps_flushing(struct inode *inode,
doutc(cl, "%p %llx.%llx now !dirty\n", inode, ceph_vinop(inode));
swap(cf, ci->i_prealloc_cap_flush);
+ cf->ci = ci;
cf->caps = flushing;
cf->wake = wake;
@@ -2026,7 +2029,7 @@ void ceph_check_caps(struct ceph_inode_info *ci, int flags)
spin_lock(&ci->i_ceph_lock);
if (ci->i_ceph_flags & CEPH_I_ASYNC_CREATE) {
- ci->i_ceph_flags |= CEPH_I_ASYNC_CHECK_CAPS;
+ set_bit(CEPH_I_ASYNC_CHECK_CAPS_BIT, &ci->i_ceph_flags);
/* Don't send messages until we get async create reply */
spin_unlock(&ci->i_ceph_lock);
@@ -2577,7 +2580,7 @@ static void __kick_flushing_caps(struct ceph_mds_client *mdsc,
if (ci->i_ceph_flags & CEPH_I_ASYNC_CREATE)
return;
- ci->i_ceph_flags &= ~CEPH_I_KICK_FLUSH;
+ clear_bit(CEPH_I_KICK_FLUSH_BIT, &ci->i_ceph_flags);
list_for_each_entry_reverse(cf, &ci->i_cap_flush_list, i_list) {
if (cf->is_capsnap) {
@@ -2686,7 +2689,7 @@ void ceph_early_kick_flushing_caps(struct ceph_mds_client *mdsc,
__kick_flushing_caps(mdsc, session, ci,
oldest_flush_tid);
} else {
- ci->i_ceph_flags |= CEPH_I_KICK_FLUSH;
+ set_bit(CEPH_I_KICK_FLUSH_BIT, &ci->i_ceph_flags);
}
spin_unlock(&ci->i_ceph_lock);
@@ -2829,7 +2832,7 @@ again:
spin_lock(&ci->i_ceph_lock);
if ((flags & CHECK_FILELOCK) &&
- (ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK)) {
+ test_bit(CEPH_I_ERROR_FILELOCK_BIT, &ci->i_ceph_flags)) {
doutc(cl, "%p %llx.%llx error filelock\n", inode,
ceph_vinop(inode));
ret = -EIO;
@@ -3207,7 +3210,7 @@ static int ceph_try_drop_cap_snap(struct ceph_inode_info *ci,
BUG_ON(capsnap->cap_flush.tid > 0);
ceph_put_snap_context(capsnap->context);
if (!list_is_last(&capsnap->ci_item, &ci->i_cap_snaps))
- ci->i_ceph_flags |= CEPH_I_FLUSH_SNAPS;
+ set_bit(CEPH_I_FLUSH_SNAPS_BIT, &ci->i_ceph_flags);
list_del(&capsnap->ci_item);
ceph_put_cap_snap(capsnap);
@@ -3396,7 +3399,7 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr,
if (ceph_try_drop_cap_snap(ci, capsnap)) {
put++;
} else {
- ci->i_ceph_flags |= CEPH_I_FLUSH_SNAPS;
+ set_bit(CEPH_I_FLUSH_SNAPS_BIT, &ci->i_ceph_flags);
flush_snaps = true;
}
}
@@ -3648,7 +3651,7 @@ static void handle_cap_grant(struct inode *inode,
if (ci->i_layout.pool_id != old_pool ||
extra_info->pool_ns != old_ns)
- ci->i_ceph_flags &= ~CEPH_I_POOL_PERM;
+ clear_bit(CEPH_I_POOL_PERM_BIT, &ci->i_ceph_flags);
extra_info->pool_ns = old_ns;
@@ -3826,6 +3829,13 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid,
bool wake_ci = false;
bool wake_mdsc = false;
+ /*
+ * Flush tids are monotonically increasing and acks arrive in
+ * order under i_ceph_lock, so this is always the latest tid.
+ * Diagnostic readers use READ_ONCE() without holding the lock.
+ */
+ WRITE_ONCE(ci->i_last_cap_flush_ack, flush_tid);
+
list_for_each_entry_safe(cf, tmp_cf, &ci->i_cap_flush_list, i_list) {
/* Is this the one that was flushed? */
if (cf->tid == flush_tid)
@@ -4815,7 +4825,7 @@ int ceph_drop_caps_for_unlink(struct inode *inode)
doutc(mdsc->fsc->client, "%p %llx.%llx\n", inode,
ceph_vinop(inode));
spin_lock(&mdsc->cap_delay_lock);
- ci->i_ceph_flags |= CEPH_I_FLUSH;
+ set_bit(CEPH_I_FLUSH_BIT, &ci->i_ceph_flags);
if (!list_empty(&ci->i_cap_delay_list))
list_del_init(&ci->i_cap_delay_list);
list_add_tail(&ci->i_cap_delay_list,
@@ -5080,7 +5090,7 @@ int ceph_purge_inode_cap(struct inode *inode, struct ceph_cap *cap, bool *invali
if (atomic_read(&ci->i_filelock_ref) > 0) {
/* make further file lock syscall return -EIO */
- ci->i_ceph_flags |= CEPH_I_ERROR_FILELOCK;
+ set_bit(CEPH_I_ERROR_FILELOCK_BIT, &ci->i_ceph_flags);
pr_warn_ratelimited_client(cl,
" dropping file locks for %p %llx.%llx\n",
inode, ceph_vinop(inode));
diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c
index e2463f93cf6b..18eb5da03411 100644
--- a/fs/ceph/debugfs.c
+++ b/fs/ceph/debugfs.c
@@ -9,6 +9,7 @@
#include <linux/seq_file.h>
#include <linux/math64.h>
#include <linux/ktime.h>
+#include <linux/uaccess.h>
#include <linux/atomic.h>
#include <linux/ceph/libceph.h>
@@ -392,6 +393,90 @@ static int status_show(struct seq_file *s, void *p)
return 0;
}
+static int reset_status_show(struct seq_file *s, void *p)
+{
+ struct ceph_fs_client *fsc = s->private;
+ struct ceph_mds_client *mdsc = fsc->mdsc;
+ struct ceph_client_reset_state *st;
+ u64 trigger = 0, success = 0, failure = 0;
+ unsigned long last_start = 0, last_finish = 0;
+ int last_errno = 0;
+ enum ceph_client_reset_phase phase = CEPH_CLIENT_RESET_IDLE;
+ bool drain_timed_out = false;
+ int sessions_reset = 0;
+ int blocked_requests = 0;
+ char reason[CEPH_CLIENT_RESET_REASON_LEN];
+
+ if (!mdsc)
+ return 0;
+
+ st = &mdsc->reset_state;
+
+ spin_lock(&st->lock);
+ trigger = st->trigger_count;
+ success = st->success_count;
+ failure = st->failure_count;
+ last_start = st->last_start;
+ last_finish = st->last_finish;
+ last_errno = st->last_errno;
+ phase = st->phase;
+ drain_timed_out = st->drain_timed_out;
+ sessions_reset = st->sessions_reset;
+ strscpy(reason, st->last_reason, sizeof(reason));
+ spin_unlock(&st->lock);
+
+ blocked_requests = atomic_read(&st->blocked_requests);
+
+ seq_printf(s, "phase: %s\n", ceph_reset_phase_name(phase));
+ seq_printf(s, "trigger_count: %llu\n", trigger);
+ seq_printf(s, "success_count: %llu\n", success);
+ seq_printf(s, "failure_count: %llu\n", failure);
+ if (last_start)
+ seq_printf(s, "last_start_ms_ago: %u\n",
+ jiffies_to_msecs(jiffies - last_start));
+ else
+ seq_puts(s, "last_start_ms_ago: (never)\n");
+ if (last_finish)
+ seq_printf(s, "last_finish_ms_ago: %u\n",
+ jiffies_to_msecs(jiffies - last_finish));
+ else
+ seq_puts(s, "last_finish_ms_ago: (never)\n");
+ seq_printf(s, "last_errno: %d\n", last_errno);
+ seq_printf(s, "last_reason: %s\n",
+ reason[0] ? reason : "(none)");
+ seq_printf(s, "drain_timed_out: %s\n",
+ drain_timed_out ? "yes" : "no");
+ seq_printf(s, "sessions_reset: %d\n", sessions_reset);
+ seq_printf(s, "blocked_requests: %d\n", blocked_requests);
+
+ return 0;
+}
+
+static ssize_t reset_trigger_write(struct file *file, const char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ struct ceph_fs_client *fsc = file->private_data;
+ struct ceph_mds_client *mdsc = fsc->mdsc;
+ char reason[CEPH_CLIENT_RESET_REASON_LEN];
+ size_t copy;
+ int ret;
+
+ if (!mdsc)
+ return -ENODEV;
+
+ copy = min_t(size_t, len, sizeof(reason) - 1);
+ if (copy && copy_from_user(reason, buf, copy))
+ return -EFAULT;
+ reason[copy] = '\0';
+ strim(reason);
+
+ ret = ceph_mdsc_schedule_reset(mdsc, reason);
+ if (ret)
+ return ret;
+
+ return len;
+}
+
static int subvolume_metrics_show(struct seq_file *s, void *p)
{
struct ceph_fs_client *fsc = s->private;
@@ -450,6 +535,7 @@ DEFINE_SHOW_ATTRIBUTE(mdsc);
DEFINE_SHOW_ATTRIBUTE(caps);
DEFINE_SHOW_ATTRIBUTE(mds_sessions);
DEFINE_SHOW_ATTRIBUTE(status);
+DEFINE_SHOW_ATTRIBUTE(reset_status);
DEFINE_SHOW_ATTRIBUTE(metrics_file);
DEFINE_SHOW_ATTRIBUTE(metrics_latency);
DEFINE_SHOW_ATTRIBUTE(metrics_size);
@@ -521,6 +607,13 @@ static int metric_features_show(struct seq_file *s, void *p)
DEFINE_SHOW_ATTRIBUTE(metric_features);
+static const struct file_operations ceph_reset_trigger_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .write = reset_trigger_write,
+ .llseek = noop_llseek,
+};
+
/*
* debugfs
*/
@@ -554,6 +647,7 @@ void ceph_fs_debugfs_cleanup(struct ceph_fs_client *fsc)
debugfs_remove(fsc->debugfs_caps);
debugfs_remove(fsc->debugfs_status);
debugfs_remove(fsc->debugfs_mdsc);
+ debugfs_remove_recursive(fsc->debugfs_reset_dir);
debugfs_remove(fsc->debugfs_subvolume_metrics);
debugfs_remove_recursive(fsc->debugfs_metrics_dir);
doutc(fsc->client, "done\n");
@@ -602,6 +696,15 @@ void ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
fsc,
&caps_fops);
+ fsc->debugfs_reset_dir = debugfs_create_dir("reset",
+ fsc->client->debugfs_dir);
+ debugfs_create_file("trigger", 0200,
+ fsc->debugfs_reset_dir, fsc,
+ &ceph_reset_trigger_fops);
+ debugfs_create_file("status", 0400,
+ fsc->debugfs_reset_dir, fsc,
+ &reset_status_fops);
+
fsc->debugfs_status = debugfs_create_file("status",
0400,
fsc->client->debugfs_dir,
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index 0ad42e1cc305..71161f2b2151 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -598,12 +598,12 @@ static void wake_async_create_waiters(struct inode *inode,
spin_lock(&ci->i_ceph_lock);
if (ci->i_ceph_flags & CEPH_I_ASYNC_CREATE) {
- clear_and_wake_up_bit(CEPH_ASYNC_CREATE_BIT, &ci->i_ceph_flags);
+ /* Serialized by i_ceph_lock; the two ops touch different bits. */
+ clear_and_wake_up_bit(CEPH_I_ASYNC_CREATE_BIT, &ci->i_ceph_flags);
- if (ci->i_ceph_flags & CEPH_I_ASYNC_CHECK_CAPS) {
- ci->i_ceph_flags &= ~CEPH_I_ASYNC_CHECK_CAPS;
+ if (test_and_clear_bit(CEPH_I_ASYNC_CHECK_CAPS_BIT,
+ &ci->i_ceph_flags))
check_cap = true;
- }
}
ceph_kick_flushing_inode_caps(session, ci);
spin_unlock(&ci->i_ceph_lock);
@@ -766,7 +766,8 @@ static int ceph_finish_async_create(struct inode *dir, struct inode *inode,
* that point and don't worry about setting
* CEPH_I_ASYNC_CREATE.
*/
- ceph_inode(inode)->i_ceph_flags = CEPH_I_ASYNC_CREATE;
+ set_bit(CEPH_I_ASYNC_CREATE_BIT,
+ &ceph_inode(inode)->i_ceph_flags);
unlock_new_inode(inode);
}
if (d_in_lookup(dentry) || d_really_is_negative(dentry)) {
@@ -2486,7 +2487,7 @@ retry_snap:
if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 ||
(iocb->ki_flags & IOCB_DIRECT) || (fi->flags & CEPH_F_SYNC) ||
- (ci->i_ceph_flags & CEPH_I_ERROR_WRITE)) {
+ test_bit(CEPH_I_ERROR_WRITE_BIT, &ci->i_ceph_flags)) {
struct ceph_snap_context *snapc;
struct iov_iter data;
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 22c7da1ea61c..61d7c0b8161f 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -671,6 +671,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
INIT_LIST_HEAD(&ci->i_cap_snaps);
ci->i_head_snapc = NULL;
ci->i_snap_caps = 0;
+ ci->i_last_cap_flush_ack = 0;
ci->i_last_rd = ci->i_last_wr = jiffies - 3600 * HZ;
for (i = 0; i < CEPH_FILE_MODE_BITS; i++)
@@ -1180,7 +1181,7 @@ int ceph_fill_inode(struct inode *inode, struct page *locked_page,
rcu_assign_pointer(ci->i_layout.pool_ns, pool_ns);
if (ci->i_layout.pool_id != old_pool || pool_ns != old_ns)
- ci->i_ceph_flags &= ~CEPH_I_POOL_PERM;
+ clear_bit(CEPH_I_POOL_PERM_BIT, &ci->i_ceph_flags);
pool_ns = old_ns;
@@ -3240,7 +3241,7 @@ void ceph_inode_shutdown(struct inode *inode)
bool invalidate = false;
spin_lock(&ci->i_ceph_lock);
- ci->i_ceph_flags |= CEPH_I_SHUTDOWN;
+ set_bit(CEPH_I_SHUTDOWN_BIT, &ci->i_ceph_flags);
p = rb_first(&ci->i_caps);
while (p) {
struct ceph_cap *cap = rb_entry(p, struct ceph_cap, ci_node);
diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c
index dd764f9c64b9..677221bd64e0 100644
--- a/fs/ceph/locks.c
+++ b/fs/ceph/locks.c
@@ -57,9 +57,7 @@ static void ceph_fl_release_lock(struct file_lock *fl)
ci = ceph_inode(inode);
if (atomic_dec_and_test(&ci->i_filelock_ref)) {
/* clear error when all locks are released */
- spin_lock(&ci->i_ceph_lock);
- ci->i_ceph_flags &= ~CEPH_I_ERROR_FILELOCK;
- spin_unlock(&ci->i_ceph_lock);
+ clear_bit(CEPH_I_ERROR_FILELOCK_BIT, &ci->i_ceph_flags);
}
fl->fl_u.ceph.inode = NULL;
iput(inode);
@@ -251,6 +249,7 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
{
struct inode *inode = file_inode(file);
struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(inode->i_sb);
struct ceph_client *cl = ceph_inode_to_client(inode);
int err = 0;
u16 op = CEPH_MDS_OP_SETFILELOCK;
@@ -271,15 +270,17 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
else if (IS_SETLKW(cmd))
wait = 1;
- spin_lock(&ci->i_ceph_lock);
- if (ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) {
- err = -EIO;
- }
- spin_unlock(&ci->i_ceph_lock);
- if (err < 0) {
+ if (test_bit(CEPH_I_ERROR_FILELOCK_BIT, &ci->i_ceph_flags)) {
if (op == CEPH_MDS_OP_SETFILELOCK && lock_is_unlock(fl))
posix_lock_file(file, fl, NULL);
- return err;
+ return -EIO;
+ }
+
+ /* Wait for reset to complete before acquiring new locks */
+ if (op == CEPH_MDS_OP_SETFILELOCK && !lock_is_unlock(fl)) {
+ err = ceph_mdsc_wait_for_reset(mdsc);
+ if (err)
+ return err;
}
if (lock_is_read(fl))
@@ -318,6 +319,7 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
{
struct inode *inode = file_inode(file);
struct ceph_inode_info *ci = ceph_inode(inode);
+ struct ceph_mds_client *mdsc = ceph_sb_to_mdsc(inode->i_sb);
struct ceph_client *cl = ceph_inode_to_client(inode);
int err = 0;
u8 wait = 0;
@@ -331,15 +333,17 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
doutc(cl, "fl_file: %p\n", fl->c.flc_file);
- spin_lock(&ci->i_ceph_lock);
- if (ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) {
- err = -EIO;
- }
- spin_unlock(&ci->i_ceph_lock);
- if (err < 0) {
+ if (test_bit(CEPH_I_ERROR_FILELOCK_BIT, &ci->i_ceph_flags)) {
if (lock_is_unlock(fl))
locks_lock_file_wait(file, fl);
- return err;
+ return -EIO;
+ }
+
+ /* Wait for reset to complete before acquiring new locks */
+ if (!lock_is_unlock(fl)) {
+ err = ceph_mdsc_wait_for_reset(mdsc);
+ if (err)
+ return err;
}
if (IS_SETLKW(cmd))
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 0edb6a251501..853bf698b356 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -6,6 +6,7 @@
#include <linux/slab.h>
#include <linux/gfp.h>
#include <linux/sched.h>
+#include <linux/delay.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/ratelimit.h>
@@ -65,6 +66,7 @@ static void __wake_requests(struct ceph_mds_client *mdsc,
struct list_head *head);
static void ceph_cap_release_work(struct work_struct *work);
static void ceph_cap_reclaim_work(struct work_struct *work);
+static void ceph_mdsc_reset_workfn(struct work_struct *work);
static const struct ceph_connection_operations mds_con_ops;
@@ -2330,19 +2332,112 @@ static int check_caps_flush(struct ceph_mds_client *mdsc,
}
/*
- * flush all dirty inode data to disk.
+ * Snapshot of a single cap_flush entry for diagnostic dump.
+ * Collected under cap_dirty_lock, printed after releasing it.
+ */
+struct flush_dump_entry {
+ u64 ino; /* inode number */
+ u64 snap; /* snap id */
+ int caps; /* dirty cap bits */
+ u64 tid; /* flush transaction id */
+ u64 last_ack; /* most recent ack tid for this inode */
+ bool wake; /* whether completion was requested */
+ bool is_capsnap; /* true if this is a cap snap flush */
+ bool ci_null; /* true if cf->ci was unexpectedly NULL */
+};
+
+/*
+ * Dump pending cap flushes for diagnostic purposes.
*
- * returns true if we've flushed through want_flush_tid
+ * cf->ci is safe to dereference here: cap_flush entries hold a
+ * reference on the inode (via the cap), and entries are removed from
+ * cap_flush_list under cap_dirty_lock before the cap (and thus the
+ * inode reference) is released. Holding cap_dirty_lock therefore
+ * guarantees the inode remains valid for the lifetime of the scan.
+ */
+
+static void dump_cap_flushes(struct ceph_mds_client *mdsc, u64 want_tid)
+{
+ struct ceph_client *cl = mdsc->fsc->client;
+ struct flush_dump_entry entries[CEPH_CAP_FLUSH_MAX_DUMP_ENTRIES];
+ struct ceph_cap_flush *cf;
+ int n = 0, remaining = 0;
+ int i;
+
+ spin_lock(&mdsc->cap_dirty_lock);
+ list_for_each_entry(cf, &mdsc->cap_flush_list, g_list) {
+ if (cf->tid > want_tid)
+ break;
+ if (n < CEPH_CAP_FLUSH_MAX_DUMP_ENTRIES) {
+ struct flush_dump_entry *e = &entries[n++];
+
+ e->ci_null = WARN_ON_ONCE(!cf->ci);
+ if (!e->ci_null) {
+ e->ino = ceph_ino(&cf->ci->netfs.inode);
+ e->snap = ceph_snap(&cf->ci->netfs.inode);
+ e->last_ack = READ_ONCE(cf->ci->i_last_cap_flush_ack);
+ }
+ e->caps = cf->caps;
+ e->tid = cf->tid;
+ e->wake = cf->wake;
+ e->is_capsnap = cf->is_capsnap;
+ } else {
+ remaining++;
+ }
+ }
+ spin_unlock(&mdsc->cap_dirty_lock);
+
+ pr_info_client(cl, "still waiting for cap flushes through %llu:\n",
+ want_tid);
+ for (i = 0; i < n; i++) {
+ struct flush_dump_entry *e = &entries[i];
+
+ if (e->ci_null)
+ pr_info_client(cl,
+ " (null ci) %s tid=%llu wake=%d%s\n",
+ ceph_cap_string(e->caps), e->tid,
+ e->wake,
+ e->is_capsnap ? " is_capsnap" : "");
+ else
+ pr_info_client(cl,
+ " %llx.%llx %s tid=%llu last_ack=%llu wake=%d%s\n",
+ e->ino, e->snap,
+ ceph_cap_string(e->caps), e->tid,
+ e->last_ack, e->wake,
+ e->is_capsnap ? " is_capsnap" : "");
+ }
+ if (remaining)
+ pr_info_client(cl, " ... and %d more pending flushes\n",
+ remaining);
+}
+
+/*
+ * Wait for all cap flushes through @want_flush_tid to complete.
+ * Periodically dumps pending cap flush state for diagnostics.
*/
static void wait_caps_flush(struct ceph_mds_client *mdsc,
u64 want_flush_tid)
{
struct ceph_client *cl = mdsc->fsc->client;
+ int i = 0;
+ long ret;
doutc(cl, "want %llu\n", want_flush_tid);
- wait_event(mdsc->cap_flushing_wq,
- check_caps_flush(mdsc, want_flush_tid));
+ do {
+ /* 60 * HZ fits in a long on all supported architectures. */
+ ret = wait_event_timeout(mdsc->cap_flushing_wq,
+ check_caps_flush(mdsc, want_flush_tid),
+ CEPH_CAP_FLUSH_WAIT_TIMEOUT_SEC * HZ);
+ if (ret == 0) {
+ if (i < CEPH_CAP_FLUSH_MAX_DUMP_ITERS)
+ dump_cap_flushes(mdsc, want_flush_tid);
+ else if (i == CEPH_CAP_FLUSH_MAX_DUMP_ITERS)
+ pr_info_client(cl,
+ "still waiting for cap flushes; suppressing further dumps\n");
+ i++;
+ }
+ } while (ret == 0);
doutc(cl, "ok, flushed thru %llu\n", want_flush_tid);
}
@@ -3657,7 +3752,8 @@ static void __do_request(struct ceph_mds_client *mdsc,
spin_lock(&ci->i_ceph_lock);
cap = ci->i_auth_cap;
- if (ci->i_ceph_flags & CEPH_I_ASYNC_CREATE && mds != cap->mds) {
+ if (test_bit(CEPH_I_ASYNC_CREATE_BIT, &ci->i_ceph_flags) &&
+ mds != cap->mds) {
doutc(cl, "session changed for auth cap %d -> %d\n",
cap->session->s_mds, session->s_mds);
@@ -3751,6 +3847,22 @@ int ceph_mdsc_submit_request(struct ceph_mds_client *mdsc, struct inode *dir,
struct ceph_client *cl = mdsc->fsc->client;
int err = 0;
+ /*
+ * If a reset is in progress, wait for it to complete.
+ *
+ * This is best-effort: a request can pass this check just
+ * before the phase leaves IDLE and proceed concurrently with
+ * reset. That is acceptable because (a) such requests will
+ * either complete normally or fail and be retried by the
+ * caller, and (b) adding lock serialization here would
+ * penalize every request for a rare manual operation.
+ */
+ err = ceph_mdsc_wait_for_reset(mdsc);
+ if (err) {
+ doutc(cl, "wait_for_reset failed: %d\n", err);
+ return err;
+ }
+
/* take CAP_PIN refs for r_inode, r_parent, r_old_dentry */
if (req->r_inode)
ceph_get_cap_refs(ceph_inode(req->r_inode), CEPH_CAP_PIN);
@@ -4469,9 +4581,14 @@ skip_cap_auths:
break;
case CEPH_SESSION_REJECT:
- WARN_ON(session->s_state != CEPH_MDS_SESSION_OPENING);
- pr_info_client(cl, "mds%d rejected session\n",
- session->s_mds);
+ WARN_ON(session->s_state != CEPH_MDS_SESSION_OPENING &&
+ session->s_state != CEPH_MDS_SESSION_RECONNECTING);
+ if (session->s_state == CEPH_MDS_SESSION_RECONNECTING)
+ pr_info_client(cl, "mds%d reconnect rejected\n",
+ session->s_mds);
+ else
+ pr_info_client(cl, "mds%d rejected session\n",
+ session->s_mds);
session->s_state = CEPH_MDS_SESSION_REJECTED;
cleanup_session_requests(mdsc, session);
remove_session_caps(session);
@@ -4731,6 +4848,14 @@ static int reconnect_caps_cb(struct inode *inode, int mds, void *arg)
cap->mseq = 0; /* and migrate_seq */
cap->cap_gen = atomic_read(&cap->session->s_cap_gen);
+ /*
+ * Note: CEPH_I_ERROR_FILELOCK is not set during reconnect.
+ * Instead, locks are submitted for best-effort MDS reclaim
+ * via the flock_len field below. If reclaim fails (e.g.,
+ * another client grabbed a conflicting lock), future lock
+ * operations will fail and set the error flag at that point.
+ */
+
/* These are lost when the session goes away */
if (S_ISDIR(inode->i_mode)) {
if (cap->issued & CEPH_CAP_DIR_CREATE) {
@@ -4746,8 +4871,9 @@ static int reconnect_caps_cb(struct inode *inode, int mds, void *arg)
rec.v2.issued = cpu_to_le32(cap->issued);
rec.v2.snaprealm = cpu_to_le64(ci->i_snap_realm->ino);
rec.v2.pathbase = cpu_to_le64(path_info.vino.ino);
- rec.v2.flock_len = (__force __le32)
- ((ci->i_ceph_flags & CEPH_I_ERROR_FILELOCK) ? 0 : 1);
+ rec.v2.flock_len = cpu_to_le32(
+ test_bit(CEPH_I_ERROR_FILELOCK_BIT,
+ &ci->i_ceph_flags) ? 0 : 1);
} else {
struct timespec64 ts;
@@ -4944,20 +5070,19 @@ fail:
*
* This is a relatively heavyweight operation, but it's rare.
*/
-static void send_mds_reconnect(struct ceph_mds_client *mdsc,
- struct ceph_mds_session *session)
+static int send_mds_reconnect(struct ceph_mds_client *mdsc,
+ struct ceph_mds_session *session)
{
struct ceph_client *cl = mdsc->fsc->client;
struct ceph_msg *reply;
int mds = session->s_mds;
int err = -ENOMEM;
+ int old_state;
struct ceph_reconnect_state recon_state = {
.session = session,
};
LIST_HEAD(dispose);
- pr_info_client(cl, "mds%d reconnect start\n", mds);
-
recon_state.pagelist = ceph_pagelist_alloc(GFP_NOFS);
if (!recon_state.pagelist)
goto fail_nopagelist;
@@ -4966,9 +5091,37 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc,
if (!reply)
goto fail_nomsg;
+ mutex_lock(&session->s_mutex);
+
+ /* Serialized by s_mutex against concurrent ceph_get_deleg_ino(). */
xa_destroy(&session->s_delegated_inos);
+ if (session->s_state == CEPH_MDS_SESSION_CLOSED ||
+ session->s_state == CEPH_MDS_SESSION_REJECTED) {
+ pr_info_client(cl, "mds%d skipping reconnect, session %s\n",
+ mds,
+ ceph_session_state_name(session->s_state));
+ mutex_unlock(&session->s_mutex);
+ ceph_msg_put(reply);
+ err = -ESTALE;
+ goto fail_return;
+ }
- mutex_lock(&session->s_mutex);
+ /* s_mutex -> mdsc->mutex matches cleanup_session_requests() order. */
+ mutex_lock(&mdsc->mutex);
+ if (mds >= mdsc->max_sessions || mdsc->sessions[mds] != session) {
+ mutex_unlock(&mdsc->mutex);
+ pr_info_client(cl,
+ "mds%d skipping reconnect, session unregistered\n",
+ mds);
+ mutex_unlock(&session->s_mutex);
+ ceph_msg_put(reply);
+ err = -ENOENT;
+ goto fail_return;
+ }
+ mutex_unlock(&mdsc->mutex);
+
+ pr_info_client(cl, "mds%d reconnect start\n", mds);
+ old_state = session->s_state;
session->s_state = CEPH_MDS_SESSION_RECONNECTING;
session->s_seq = 0;
@@ -5098,7 +5251,7 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc,
up_read(&mdsc->snap_rwsem);
ceph_pagelist_release(recon_state.pagelist);
- return;
+ return 0;
fail_clear_cap_reconnect:
spin_lock(&session->s_cap_lock);
@@ -5107,13 +5260,504 @@ fail_clear_cap_reconnect:
fail:
ceph_msg_put(reply);
up_read(&mdsc->snap_rwsem);
+ /*
+ * Restore prior session state so map-driven reconnect logic
+ * (check_new_map) can retry. Without this, a transient build
+ * failure strands the session in RECONNECTING indefinitely.
+ */
+ session->s_state = old_state;
mutex_unlock(&session->s_mutex);
fail_nomsg:
ceph_pagelist_release(recon_state.pagelist);
fail_nopagelist:
pr_err_client(cl, "error %d preparing reconnect for mds%d\n",
err, mds);
+ return err;
+
+fail_return:
+ /*
+ * Early-exit path for expected concurrent-teardown races
+ * (-ESTALE for closed/rejected sessions, -ENOENT for
+ * unregistered sessions). Skip the pr_err_client diagnostic
+ * since these are not genuine reconnect build failures.
+ */
+ ceph_pagelist_release(recon_state.pagelist);
+ return err;
+}
+
+const char *ceph_reset_phase_name(enum ceph_client_reset_phase phase)
+{
+ switch (phase) {
+ case CEPH_CLIENT_RESET_IDLE: return "idle";
+ case CEPH_CLIENT_RESET_QUIESCING: return "quiescing";
+ case CEPH_CLIENT_RESET_DRAINING: return "draining";
+ case CEPH_CLIENT_RESET_TEARDOWN: return "teardown";
+ default: return "unknown";
+ }
+}
+
+/**
+ * ceph_mdsc_wait_for_reset - wait for an active reset to complete
+ * @mdsc: MDS client
+ *
+ * Returns 0 if reset completed successfully or no reset was active.
+ * Returns -EAGAIN if reset completed with an error, signalling the
+ * caller to retry. The internal error (e.g. -ENOMEM) is not propagated
+ * because callers like open() or flock() have no way to act on
+ * work-function internals. The detailed error is available via debugfs
+ * reset/status and tracepoints.
+ * Returns -ETIMEDOUT if we timed out waiting.
+ * Returns -ERESTARTSYS if interrupted by signal.
+ */
+int ceph_mdsc_wait_for_reset(struct ceph_mds_client *mdsc)
+{
+ struct ceph_client_reset_state *st = &mdsc->reset_state;
+ struct ceph_client *cl = mdsc->fsc->client;
+ unsigned long deadline = jiffies + CEPH_CLIENT_RESET_WAIT_TIMEOUT_SEC * HZ;
+ int blocked_count;
+ long remaining;
+ long wait_ret;
+ int ret;
+
+ if (ceph_reset_is_idle(st))
+ return 0;
+
+ blocked_count = atomic_inc_return(&st->blocked_requests);
+ doutc(cl, "request blocked during reset, %d total blocked\n",
+ blocked_count);
+ trace_ceph_client_reset_blocked(mdsc, blocked_count);
+
+retry:
+ remaining = max_t(long, deadline - jiffies, 1);
+ wait_ret = wait_event_interruptible_timeout(st->blocked_wq,
+ ceph_reset_is_idle(st),
+ remaining);
+
+ if (wait_ret == 0) {
+ atomic_dec(&st->blocked_requests);
+ pr_warn_client(cl, "timed out waiting for reset to complete\n");
+ trace_ceph_client_reset_unblocked(mdsc, -ETIMEDOUT);
+ return -ETIMEDOUT;
+ }
+ if (wait_ret < 0) {
+ atomic_dec(&st->blocked_requests);
+ trace_ceph_client_reset_unblocked(mdsc, (int)wait_ret);
+ return (int)wait_ret; /* -ERESTARTSYS */
+ }
+
+ /*
+ * Verify phase is still IDLE under the lock. If another reset
+ * was scheduled between the wake-up and this check, loop back
+ * and wait for it to finish rather than returning a stale result.
+ */
+ spin_lock(&st->lock);
+ if (st->phase != CEPH_CLIENT_RESET_IDLE) {
+ spin_unlock(&st->lock);
+ if (time_before(jiffies, deadline))
+ goto retry;
+ atomic_dec(&st->blocked_requests);
+ trace_ceph_client_reset_unblocked(mdsc, -ETIMEDOUT);
+ return -ETIMEDOUT;
+ }
+ ret = st->last_errno;
+ spin_unlock(&st->lock);
+
+ atomic_dec(&st->blocked_requests);
+ trace_ceph_client_reset_unblocked(mdsc, ret);
+ return ret ? -EAGAIN : 0;
+}
+
+static void ceph_mdsc_reset_complete(struct ceph_mds_client *mdsc, int ret)
+{
+ struct ceph_client_reset_state *st = &mdsc->reset_state;
+
+ spin_lock(&st->lock);
+ /*
+ * If destroy already marked us as shut down, it owns the
+ * final bookkeeping and waiter wakeup. Just bail so we
+ * don't overwrite its state.
+ */
+ if (st->shutdown) {
+ spin_unlock(&st->lock);
+ return;
+ }
+ st->last_finish = jiffies;
+ st->last_errno = ret;
+ st->phase = CEPH_CLIENT_RESET_IDLE;
+ if (ret)
+ st->failure_count++;
+ else
+ st->success_count++;
+ spin_unlock(&st->lock);
+
+ /* Wake up all requests that were blocked waiting for reset */
+ wake_up_all(&st->blocked_wq);
+
+ trace_ceph_client_reset_complete(mdsc, ret);
+}
+
+static void ceph_mdsc_reset_workfn(struct work_struct *work)
+{
+ struct ceph_mds_client *mdsc =
+ container_of(work, struct ceph_mds_client, reset_work);
+ struct ceph_client_reset_state *st = &mdsc->reset_state;
+ struct ceph_client *cl = mdsc->fsc->client;
+ struct ceph_mds_session **sessions = NULL;
+ char reason[CEPH_CLIENT_RESET_REASON_LEN];
+ unsigned long drain_deadline;
+ int max_sessions, i, n = 0, torn_down = 0;
+ int ret = 0;
+
+ spin_lock(&st->lock);
+ strscpy(reason, st->last_reason, sizeof(reason));
+ spin_unlock(&st->lock);
+
+ mutex_lock(&mdsc->mutex);
+ max_sessions = mdsc->max_sessions;
+ if (max_sessions <= 0) {
+ mutex_unlock(&mdsc->mutex);
+ goto out_complete;
+ }
+
+ sessions = kcalloc(max_sessions, sizeof(*sessions), GFP_KERNEL);
+ if (!sessions) {
+ mutex_unlock(&mdsc->mutex);
+ ret = -ENOMEM;
+ pr_err_client(cl,
+ "manual session reset failed to allocate session array\n");
+ ceph_mdsc_reset_complete(mdsc, ret);
+ return;
+ }
+
+ for (i = 0; i < max_sessions; i++) {
+ struct ceph_mds_session *session = mdsc->sessions[i];
+
+ if (!session)
+ continue;
+
+ /*
+ * Read session state without s_mutex to avoid nesting
+ * mdsc->mutex -> s_mutex, which would invert the
+ * s_mutex -> mdsc->mutex order used by
+ * cleanup_session_requests(). s_state is an int
+ * so loads are atomic; the teardown loop below
+ * handles races with concurrent state transitions.
+ */
+ switch (READ_ONCE(session->s_state)) {
+ case CEPH_MDS_SESSION_OPEN:
+ case CEPH_MDS_SESSION_HUNG:
+ case CEPH_MDS_SESSION_OPENING:
+ case CEPH_MDS_SESSION_RESTARTING:
+ case CEPH_MDS_SESSION_RECONNECTING:
+ case CEPH_MDS_SESSION_CLOSING:
+ sessions[n++] = ceph_get_mds_session(session);
+ break;
+ default:
+ pr_info_client(cl,
+ "mds%d in state %s, skipping reset\n",
+ session->s_mds,
+ ceph_session_state_name(session->s_state));
+ break;
+ }
+ }
+ mutex_unlock(&mdsc->mutex);
+
+ pr_info_client(cl,
+ "manual session reset executing (sessions=%d, reason=\"%s\")\n",
+ n, reason);
+
+ if (n == 0) {
+ kfree(sessions);
+ goto out_complete;
+ }
+
+ spin_lock(&st->lock);
+ if (st->shutdown) {
+ spin_unlock(&st->lock);
+ goto out_sessions;
+ }
+ st->phase = CEPH_CLIENT_RESET_DRAINING;
+ spin_unlock(&st->lock);
+
+ /*
+ * Best-effort drain: flush dirty state while sessions are still
+ * alive. New requests are blocked while phase != IDLE.
+ * The sessions are functional, so non-stuck state drains normally.
+ * Stuck state (the cause of the stalemate the operator is trying
+ * to break) will not drain -- that is expected, and we proceed to
+ * forced teardown after the timeout.
+ *
+ * Four things are drained:
+ * 1. MDS journal -- send_flush_mdlog asks each MDS to journal
+ * pending unsafe operations (creates, renames, setattrs).
+ * 2. Unsafe requests -- bounded wait for each unsafe write
+ * request to reach safe status via r_safe_completion.
+ * 3. Dirty caps -- ceph_flush_dirty_caps triggers cap flush on
+ * all sessions. Non-stuck caps flush in milliseconds.
+ * 4. Cap releases -- push pending cap release messages.
+ *
+ * The unsafe-request wait and cap-flush wait below provide
+ * the bounded drain window during which all categories can
+ * make progress.
+ */
+ for (i = 0; i < n; i++)
+ send_flush_mdlog(sessions[i]);
+
+ /*
+ * Both drain legs (unsafe requests and cap flushes) share a
+ * single deadline so the total drain time is bounded at
+ * CEPH_CLIENT_RESET_DRAIN_SEC.
+ */
+ drain_deadline = jiffies + CEPH_CLIENT_RESET_DRAIN_SEC * HZ;
+
+ /*
+ * Wait for unsafe write requests (creates, renames, setattrs)
+ * to reach safe status. Uses the same pattern as
+ * flush_mdlog_and_wait_mdsc_unsafe_requests() but bounded by
+ * the shared drain deadline. Requests that do not complete within
+ * the window are force-dropped during teardown.
+ */
+ {
+ struct ceph_mds_request *req;
+ struct rb_node *rn;
+ u64 last_tid;
+
+ mutex_lock(&mdsc->mutex);
+ last_tid = mdsc->last_tid;
+ mutex_unlock(&mdsc->mutex);
+
+ mutex_lock(&mdsc->mutex);
+ rn = rb_first(&mdsc->request_tree);
+ while (rn) {
+ req = rb_entry(rn, struct ceph_mds_request, r_node);
+ if (req->r_tid > last_tid)
+ break;
+ if (req->r_op == CEPH_MDS_OP_SETFILELOCK ||
+ !(req->r_op & CEPH_MDS_OP_WRITE)) {
+ rn = rb_next(rn);
+ continue;
+ }
+ ceph_mdsc_get_request(req);
+ mutex_unlock(&mdsc->mutex);
+
+ wait_for_completion_timeout(&req->r_safe_completion,
+ max_t(long, drain_deadline - jiffies, 1));
+
+ mutex_lock(&mdsc->mutex);
+ ceph_mdsc_put_request(req);
+ if (time_after(jiffies, drain_deadline))
+ break;
+ rn = rb_first(&mdsc->request_tree);
+ }
+ mutex_unlock(&mdsc->mutex);
+
+ if (time_after_eq(jiffies, drain_deadline))
+ WRITE_ONCE(st->drain_timed_out, true);
+ }
+
+ ceph_flush_dirty_caps(mdsc);
+ ceph_flush_cap_releases(mdsc);
+
+ spin_lock(&mdsc->cap_dirty_lock);
+ if (!list_empty(&mdsc->cap_flush_list)) {
+ struct ceph_cap_flush *cf =
+ list_last_entry(&mdsc->cap_flush_list,
+ struct ceph_cap_flush, g_list);
+ u64 want_flush = mdsc->last_cap_flush_tid;
+ long drain_ret;
+
+ /*
+ * Setting wake on the last entry is sufficient: flush
+ * entries complete in order, so when this entry finishes
+ * all earlier ones are already done.
+ */
+ cf->wake = true;
+ spin_unlock(&mdsc->cap_dirty_lock);
+ pr_info_client(cl,
+ "draining (want_flush=%llu, %d sessions)\n",
+ want_flush, n);
+ drain_ret = wait_event_timeout(mdsc->cap_flushing_wq,
+ check_caps_flush(mdsc,
+ want_flush),
+ max_t(long,
+ drain_deadline - jiffies,
+ 1));
+ if (drain_ret == 0) {
+ pr_info_client(cl,
+ "drain timed out, proceeding with forced teardown\n");
+ WRITE_ONCE(st->drain_timed_out, true);
+ } else {
+ pr_info_client(cl, "drain completed successfully\n");
+ }
+ } else {
+ spin_unlock(&mdsc->cap_dirty_lock);
+ }
+
+ spin_lock(&st->lock);
+ if (st->shutdown) {
+ spin_unlock(&st->lock);
+ goto out_sessions;
+ }
+ st->phase = CEPH_CLIENT_RESET_TEARDOWN;
+ spin_unlock(&st->lock);
+
+ /*
+ * Ask each MDS to close the session before we tear it down
+ * locally. Without this the MDS sees only a connection drop and
+ * waits for the client to reconnect (up to session_autoclose
+ * seconds) before evicting the session and releasing locks.
+ *
+ * Reuse the normal close machinery so the session state/sequence
+ * snapshot is serialized under s_mutex and a racing s_seq bump
+ * retransmits REQUEST_CLOSE while the session remains CLOSING.
+ * We send all close requests first, then yield briefly to let the
+ * network stack transmit them before __unregister_session()
+ * closes the connections.
+ */
+ for (i = 0; i < n; i++) {
+ int err;
+
+ mutex_lock(&sessions[i]->s_mutex);
+ err = __close_session(mdsc, sessions[i]);
+ mutex_unlock(&sessions[i]->s_mutex);
+ if (err < 0)
+ pr_warn_client(cl,
+ "mds%d failed to queue close request before reset: %d\n",
+ sessions[i]->s_mds, err);
+ }
+ /*
+ * Best-effort grace period: yield briefly so the network stack
+ * can transmit the queued REQUEST_CLOSE messages before we tear
+ * down connections. Not a correctness requirement -- the MDS
+ * will still evict via session_autoclose if it never receives
+ * the close request.
+ *
+ * Event-based waiting is not viable here: there is no completion
+ * event for "message left the NIC," and waiting for the MDS
+ * SESSION_CLOSE response would re-create the stalemate that the
+ * reset is meant to break.
+ */
+ if (n > 0)
+ msleep(CEPH_CLIENT_RESET_CLOSE_GRACE_MS);
+
+ /*
+ * Tear down each session: close the connection, remove all
+ * caps, clean up requests, then kick pending requests so they
+ * re-open a fresh session on the next attempt.
+ *
+ * This is modeled on the check_new_map() forced-close path
+ * for stopped MDS ranks - a proven pattern for hard session
+ * teardown. We do NOT attempt send_mds_reconnect() because
+ * the MDS only accepts reconnects during its own RECONNECT
+ * phase (after MDS restart), not from an active client.
+ *
+ * Any state that did not drain (caps that didn't flush, unsafe
+ * requests that the MDS didn't journal) is force-dropped here.
+ * This is intentional: that state is stuck and is the reason
+ * the operator triggered the reset.
+ */
+ for (i = 0; i < n; i++) {
+ int mds = sessions[i]->s_mds;
+
+ pr_info_client(cl, "mds%d resetting session\n", mds);
+
+ mutex_lock(&mdsc->mutex);
+ if (mds >= mdsc->max_sessions ||
+ mdsc->sessions[mds] != sessions[i]) {
+ pr_info_client(cl,
+ "mds%d session already torn down, skipping\n",
+ mds);
+ mutex_unlock(&mdsc->mutex);
+ ceph_put_mds_session(sessions[i]);
+ sessions[i] = NULL;
+ continue;
+ }
+ sessions[i]->s_state = CEPH_MDS_SESSION_CLOSED;
+ __unregister_session(mdsc, sessions[i]);
+ __wake_requests(mdsc, &sessions[i]->s_waiting);
+ mutex_unlock(&mdsc->mutex);
+
+ mutex_lock(&sessions[i]->s_mutex);
+ cleanup_session_requests(mdsc, sessions[i]);
+ remove_session_caps(sessions[i]);
+ mutex_unlock(&sessions[i]->s_mutex);
+
+ wake_up_all(&mdsc->session_close_wq);
+
+ ceph_put_mds_session(sessions[i]);
+
+ mutex_lock(&mdsc->mutex);
+ kick_requests(mdsc, mds);
+ mutex_unlock(&mdsc->mutex);
+
+ torn_down++;
+ pr_info_client(cl, "mds%d session reset complete\n", mds);
+ }
+
+ kfree(sessions);
+
+ spin_lock(&st->lock);
+ st->sessions_reset = torn_down;
+ spin_unlock(&st->lock);
+
+out_complete:
+ ceph_mdsc_reset_complete(mdsc, ret);
return;
+
+out_sessions:
+ /* shutdown == true: ceph_mdsc_destroy() owns the final transition. */
+ for (i = 0; i < n; i++)
+ ceph_put_mds_session(sessions[i]);
+ kfree(sessions);
+}
+
+int ceph_mdsc_schedule_reset(struct ceph_mds_client *mdsc,
+ const char *reason)
+{
+ struct ceph_client_reset_state *st = &mdsc->reset_state;
+ struct ceph_fs_client *fsc = mdsc->fsc;
+ const char *msg = (reason && reason[0]) ? reason : "manual";
+ int mount_state;
+
+ mount_state = READ_ONCE(fsc->mount_state);
+ if (mount_state != CEPH_MOUNT_MOUNTED) {
+ pr_warn_client(fsc->client,
+ "reset rejected: mount_state=%d (not mounted)\n",
+ mount_state);
+ return -EINVAL;
+ }
+
+ spin_lock(&st->lock);
+ if (st->phase != CEPH_CLIENT_RESET_IDLE) {
+ spin_unlock(&st->lock);
+ return -EBUSY;
+ }
+
+ st->phase = CEPH_CLIENT_RESET_QUIESCING;
+ st->last_start = jiffies;
+ st->last_errno = 0;
+ st->drain_timed_out = false;
+ st->sessions_reset = 0;
+ st->trigger_count++;
+ strscpy(st->last_reason, msg, sizeof(st->last_reason));
+ spin_unlock(&st->lock);
+
+ if (WARN_ON_ONCE(!queue_work(system_unbound_wq, &mdsc->reset_work))) {
+ spin_lock(&st->lock);
+ st->phase = CEPH_CLIENT_RESET_IDLE;
+ st->last_errno = -EALREADY;
+ st->last_finish = jiffies;
+ st->failure_count++;
+ spin_unlock(&st->lock);
+ wake_up_all(&st->blocked_wq);
+ return -EALREADY;
+ }
+
+ pr_info_client(mdsc->fsc->client,
+ "manual session reset scheduled (reason=\"%s\")\n",
+ msg);
+ trace_ceph_client_reset_schedule(mdsc, msg);
+ return 0;
}
@@ -5194,9 +5838,15 @@ static void check_new_map(struct ceph_mds_client *mdsc,
*/
if (s->s_state == CEPH_MDS_SESSION_RESTARTING &&
newstate >= CEPH_MDS_STATE_RECONNECT) {
+ int rc;
+
mutex_unlock(&mdsc->mutex);
clear_bit(i, targets);
- send_mds_reconnect(mdsc, s);
+ rc = send_mds_reconnect(mdsc, s);
+ if (rc)
+ pr_warn_client(cl,
+ "mds%d reconnect failed: %d\n",
+ i, rc);
mutex_lock(&mdsc->mutex);
}
@@ -5260,7 +5910,11 @@ static void check_new_map(struct ceph_mds_client *mdsc,
}
doutc(cl, "send reconnect to export target mds.%d\n", i);
mutex_unlock(&mdsc->mutex);
- send_mds_reconnect(mdsc, s);
+ err = send_mds_reconnect(mdsc, s);
+ if (err)
+ pr_warn_client(cl,
+ "mds%d export target reconnect failed: %d\n",
+ i, err);
ceph_put_mds_session(s);
mutex_lock(&mdsc->mutex);
}
@@ -5651,6 +6305,11 @@ int ceph_mdsc_init(struct ceph_fs_client *fsc)
INIT_LIST_HEAD(&mdsc->dentry_leases);
INIT_LIST_HEAD(&mdsc->dentry_dir_leases);
+ spin_lock_init(&mdsc->reset_state.lock);
+ init_waitqueue_head(&mdsc->reset_state.blocked_wq);
+ atomic_set(&mdsc->reset_state.blocked_requests, 0);
+ INIT_WORK(&mdsc->reset_work, ceph_mdsc_reset_workfn);
+
ceph_caps_init(mdsc);
ceph_adjust_caps_max_min(mdsc, fsc->mount_options);
@@ -6176,6 +6835,23 @@ void ceph_mdsc_destroy(struct ceph_fs_client *fsc)
/* flush out any connection work with references to us */
ceph_msgr_flush();
+ /*
+ * Mark reset as failed and wake any blocked waiters before
+ * cancelling, so unmount doesn't stall on blocked_wq timeout
+ * if cancel_work_sync() prevents the work from running.
+ */
+ spin_lock(&mdsc->reset_state.lock);
+ mdsc->reset_state.shutdown = true;
+ if (mdsc->reset_state.phase != CEPH_CLIENT_RESET_IDLE) {
+ mdsc->reset_state.phase = CEPH_CLIENT_RESET_IDLE;
+ mdsc->reset_state.last_errno = -ESHUTDOWN;
+ mdsc->reset_state.last_finish = jiffies;
+ mdsc->reset_state.failure_count++;
+ }
+ spin_unlock(&mdsc->reset_state.lock);
+ wake_up_all(&mdsc->reset_state.blocked_wq);
+
+ cancel_work_sync(&mdsc->reset_work);
ceph_mdsc_stop(mdsc);
ceph_metric_destroy(&mdsc->metric);
@@ -6348,12 +7024,92 @@ static void mds_peer_reset(struct ceph_connection *con)
{
struct ceph_mds_session *s = con->private;
struct ceph_mds_client *mdsc = s->s_mdsc;
+ int session_state;
pr_warn_client(mdsc->fsc->client, "mds%d closed our session\n",
s->s_mds);
- if (READ_ONCE(mdsc->fsc->mount_state) != CEPH_MOUNT_FENCE_IO &&
- ceph_mdsmap_get_state(mdsc->mdsmap, s->s_mds) >= CEPH_MDS_STATE_RECONNECT)
- send_mds_reconnect(mdsc, s);
+
+ if (READ_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_FENCE_IO ||
+ ceph_mdsmap_get_state(mdsc->mdsmap, s->s_mds) < CEPH_MDS_STATE_RECONNECT)
+ return;
+
+ /*
+ * Only reconnect if MDS is in its RECONNECT phase. An MDS past
+ * RECONNECT (REJOIN, CLIENTREPLAY, ACTIVE) will reject reconnect
+ * attempts, so those states fall through to session teardown below.
+ */
+ if (ceph_mdsmap_get_state(mdsc->mdsmap, s->s_mds) == CEPH_MDS_STATE_RECONNECT) {
+ int rc = send_mds_reconnect(mdsc, s);
+
+ if (rc)
+ pr_warn_client(mdsc->fsc->client,
+ "mds%d reconnect failed: %d\n",
+ s->s_mds, rc);
+ return;
+ }
+
+ /*
+ * MDS is active (past RECONNECT). It will not accept a
+ * CLIENT_RECONNECT from us, so tear the session down locally
+ * and let new requests re-open a fresh session.
+ *
+ * Snapshot session state with READ_ONCE, then revalidate under
+ * mdsc->mutex before acting. The subsequent mdsc->mutex
+ * section rechecks s_state to catch concurrent transitions, so
+ * the lockless snapshot here is safe. s->s_mutex is taken
+ * separately for cleanup after unregistration, which avoids
+ * introducing a new s->s_mutex + mdsc->mutex nesting.
+ */
+ session_state = READ_ONCE(s->s_state);
+
+ switch (session_state) {
+ case CEPH_MDS_SESSION_RESTARTING:
+ case CEPH_MDS_SESSION_RECONNECTING:
+ case CEPH_MDS_SESSION_CLOSING:
+ case CEPH_MDS_SESSION_OPEN:
+ case CEPH_MDS_SESSION_HUNG:
+ case CEPH_MDS_SESSION_OPENING:
+ mutex_lock(&mdsc->mutex);
+ if (s->s_mds >= mdsc->max_sessions ||
+ mdsc->sessions[s->s_mds] != s ||
+ s->s_state != session_state) {
+ pr_info_client(mdsc->fsc->client,
+ "mds%d state changed to %s during peer reset\n",
+ s->s_mds,
+ ceph_session_state_name(s->s_state));
+ mutex_unlock(&mdsc->mutex);
+ return;
+ }
+
+ ceph_get_mds_session(s);
+ s->s_state = CEPH_MDS_SESSION_CLOSED;
+ __unregister_session(mdsc, s);
+ __wake_requests(mdsc, &s->s_waiting);
+ mutex_unlock(&mdsc->mutex);
+
+ mutex_lock(&s->s_mutex);
+ cleanup_session_requests(mdsc, s);
+ remove_session_caps(s);
+ mutex_unlock(&s->s_mutex);
+
+ wake_up_all(&mdsc->session_close_wq);
+
+ mutex_lock(&mdsc->mutex);
+ kick_requests(mdsc, s->s_mds);
+ mutex_unlock(&mdsc->mutex);
+
+ ceph_put_mds_session(s);
+ break;
+ case CEPH_MDS_SESSION_CLOSED:
+ case CEPH_MDS_SESSION_REJECTED:
+ break;
+ default:
+ pr_warn_client(mdsc->fsc->client,
+ "mds%d peer reset in unexpected state %s\n",
+ s->s_mds,
+ ceph_session_state_name(session_state));
+ break;
+ }
}
static void mds_dispatch(struct ceph_connection *con, struct ceph_msg *msg)
@@ -6365,6 +7121,8 @@ static void mds_dispatch(struct ceph_connection *con, struct ceph_msg *msg)
mutex_lock(&mdsc->mutex);
if (__verify_registered_session(mdsc, s) < 0) {
+ doutc(cl, "dropping tid %llu from unregistered session %d\n",
+ le64_to_cpu(msg->hdr.tid), s->s_mds);
mutex_unlock(&mdsc->mutex);
goto out;
}
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h
index 4e6c87f8414c..731d6ad04956 100644
--- a/fs/ceph/mds_client.h
+++ b/fs/ceph/mds_client.h
@@ -77,6 +77,50 @@ struct ceph_fs_client;
struct ceph_cap;
#define MDS_AUTH_UID_ANY -1
+#define CEPH_CAP_FLUSH_WAIT_TIMEOUT_SEC 60
+#define CEPH_CAP_FLUSH_MAX_DUMP_ENTRIES 5
+#define CEPH_CAP_FLUSH_MAX_DUMP_ITERS 5
+#define CEPH_CLIENT_RESET_REASON_LEN 64
+#define CEPH_CLIENT_RESET_DRAIN_SEC 30
+#define CEPH_CLIENT_RESET_CLOSE_GRACE_MS 100
+#define CEPH_CLIENT_RESET_WAIT_TIMEOUT_SEC 120
+
+enum ceph_client_reset_phase {
+ CEPH_CLIENT_RESET_IDLE = 0,
+ /*
+ * QUIESCING is set synchronously by schedule_reset() before the
+ * workqueue item is dispatched. It gates new requests (any
+ * phase != IDLE blocks callers) during the window between
+ * scheduling and the work function's transition to DRAINING.
+ */
+ CEPH_CLIENT_RESET_QUIESCING,
+ CEPH_CLIENT_RESET_DRAINING,
+ CEPH_CLIENT_RESET_TEARDOWN,
+};
+
+struct ceph_client_reset_state {
+ spinlock_t lock; /* protects all fields below */
+ u64 trigger_count; /* number of resets triggered */
+ u64 success_count; /* number of successful resets */
+ u64 failure_count; /* number of failed resets */
+ unsigned long last_start; /* jiffies when last reset started */
+ unsigned long last_finish; /* jiffies when last reset finished */
+ int last_errno; /* result of most recent reset */
+ enum ceph_client_reset_phase phase; /* current reset phase */
+ bool drain_timed_out; /* drain exceeded timeout */
+ bool shutdown; /* destroy in progress */
+ int sessions_reset; /* sessions torn down in last reset */
+ char last_reason[CEPH_CLIENT_RESET_REASON_LEN]; /* operator-supplied reason */
+
+ /* Request blocking during reset */
+ wait_queue_head_t blocked_wq; /* waitqueue for blocked callers */
+ atomic_t blocked_requests; /* count of blocked callers */
+};
+
+static inline bool ceph_reset_is_idle(struct ceph_client_reset_state *st)
+{
+ return READ_ONCE(st->phase) == CEPH_CLIENT_RESET_IDLE;
+}
struct ceph_mds_cap_match {
s64 uid; /* default to MDS_AUTH_UID_ANY */
@@ -540,6 +584,8 @@ struct ceph_mds_client {
struct list_head dentry_dir_leases; /* lru list */
struct ceph_client_metric metric;
+ struct work_struct reset_work;
+ struct ceph_client_reset_state reset_state;
struct ceph_subvolume_metrics_tracker subvol_metrics;
/* Subvolume metrics send tracking */
@@ -571,10 +617,14 @@ extern struct ceph_mds_session *
__ceph_lookup_mds_session(struct ceph_mds_client *, int mds);
extern const char *ceph_session_state_name(int s);
+extern const char *ceph_reset_phase_name(enum ceph_client_reset_phase phase);
extern struct ceph_mds_session *
ceph_get_mds_session(struct ceph_mds_session *s);
extern void ceph_put_mds_session(struct ceph_mds_session *s);
+int ceph_mdsc_schedule_reset(struct ceph_mds_client *mdsc,
+ const char *reason);
+int ceph_mdsc_wait_for_reset(struct ceph_mds_client *mdsc);
extern int ceph_mdsc_init(struct ceph_fs_client *fsc);
extern void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc);
@@ -670,7 +720,7 @@ static inline int ceph_wait_on_async_create(struct inode *inode)
{
struct ceph_inode_info *ci = ceph_inode(inode);
- return wait_on_bit(&ci->i_ceph_flags, CEPH_ASYNC_CREATE_BIT,
+ return wait_on_bit(&ci->i_ceph_flags, CEPH_I_ASYNC_CREATE_BIT,
TASK_KILLABLE);
}
diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c
index 52b4c2684f92..9b79a5eaca93 100644
--- a/fs/ceph/snap.c
+++ b/fs/ceph/snap.c
@@ -700,7 +700,7 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
return 0;
}
- ci->i_ceph_flags |= CEPH_I_FLUSH_SNAPS;
+ set_bit(CEPH_I_FLUSH_SNAPS_BIT, &ci->i_ceph_flags);
doutc(cl, "%p %llx.%llx cap_snap %p snapc %p %llu %s s=%llu\n",
inode, ceph_vinop(inode), capsnap, capsnap->context,
capsnap->context->seq, ceph_cap_string(capsnap->dirty),
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index afc89ce91804..1d6aab060780 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -179,6 +179,7 @@ struct ceph_fs_client {
struct dentry *debugfs_status;
struct dentry *debugfs_mds_sessions;
struct dentry *debugfs_metrics_dir;
+ struct dentry *debugfs_reset_dir;
struct dentry *debugfs_subvolume_metrics;
#endif
@@ -239,6 +240,7 @@ struct ceph_cap_flush {
bool is_capsnap; /* true means capsnap */
struct list_head g_list; // global
struct list_head i_list; // per inode
+ struct ceph_inode_info *ci;
};
/*
@@ -453,6 +455,11 @@ struct ceph_inode_info {
struct ceph_snap_context *i_head_snapc; /* set if wr_buffer_head > 0 or
dirty|flushing caps */
unsigned i_snap_caps; /* cap bits for snapped files */
+ /*
+ * Written under i_ceph_lock, read via READ_ONCE()
+ * from diagnostic paths.
+ */
+ u64 i_last_cap_flush_ack;
unsigned long i_last_rd;
unsigned long i_last_wr;
@@ -665,23 +672,33 @@ static inline struct inode *ceph_find_inode(struct super_block *sb,
/*
* Ceph inode.
*/
-#define CEPH_I_DIR_ORDERED (1 << 0) /* dentries in dir are ordered */
-#define CEPH_I_FLUSH (1 << 2) /* do not delay flush of dirty metadata */
-#define CEPH_I_POOL_PERM (1 << 3) /* pool rd/wr bits are valid */
-#define CEPH_I_POOL_RD (1 << 4) /* can read from pool */
-#define CEPH_I_POOL_WR (1 << 5) /* can write to pool */
-#define CEPH_I_SEC_INITED (1 << 6) /* security initialized */
-#define CEPH_I_KICK_FLUSH (1 << 7) /* kick flushing caps */
-#define CEPH_I_FLUSH_SNAPS (1 << 8) /* need flush snapss */
-#define CEPH_I_ERROR_WRITE (1 << 9) /* have seen write errors */
-#define CEPH_I_ERROR_FILELOCK (1 << 10) /* have seen file lock errors */
-#define CEPH_I_ODIRECT_BIT (11) /* inode in direct I/O mode */
-#define CEPH_I_ODIRECT (1 << CEPH_I_ODIRECT_BIT)
-#define CEPH_ASYNC_CREATE_BIT (12) /* async create in flight for this */
-#define CEPH_I_ASYNC_CREATE (1 << CEPH_ASYNC_CREATE_BIT)
-#define CEPH_I_SHUTDOWN (1 << 13) /* inode is no longer usable */
-#define CEPH_I_ASYNC_CHECK_CAPS (1 << 14) /* check caps immediately after async
- creating finishes */
+#define CEPH_I_DIR_ORDERED_BIT (0) /* dentries in dir are ordered */
+ /* bit 1 historically unused */
+#define CEPH_I_FLUSH_BIT (2) /* do not delay flush of dirty metadata */
+#define CEPH_I_POOL_PERM_BIT (3) /* pool rd/wr bits are valid */
+#define CEPH_I_POOL_RD_BIT (4) /* can read from pool */
+#define CEPH_I_POOL_WR_BIT (5) /* can write to pool */
+#define CEPH_I_SEC_INITED_BIT (6) /* security initialized */
+#define CEPH_I_KICK_FLUSH_BIT (7) /* kick flushing caps */
+#define CEPH_I_FLUSH_SNAPS_BIT (8) /* need flush snaps */
+#define CEPH_I_ERROR_WRITE_BIT (9) /* have seen write errors */
+#define CEPH_I_ERROR_FILELOCK_BIT (10) /* have seen file lock errors */
+#define CEPH_I_ODIRECT_BIT (11) /* inode in direct I/O mode */
+#define CEPH_I_ASYNC_CREATE_BIT (12) /* async create in flight for this */
+#define CEPH_I_SHUTDOWN_BIT (13) /* inode is no longer usable */
+#define CEPH_I_ASYNC_CHECK_CAPS_BIT (14) /* check caps after async creating finishes */
+
+#define CEPH_I_DIR_ORDERED (1 << CEPH_I_DIR_ORDERED_BIT)
+#define CEPH_I_FLUSH (1 << CEPH_I_FLUSH_BIT)
+#define CEPH_I_POOL_PERM (1 << CEPH_I_POOL_PERM_BIT)
+#define CEPH_I_POOL_RD (1 << CEPH_I_POOL_RD_BIT)
+#define CEPH_I_POOL_WR (1 << CEPH_I_POOL_WR_BIT)
+#define CEPH_I_SEC_INITED (1 << CEPH_I_SEC_INITED_BIT)
+#define CEPH_I_KICK_FLUSH (1 << CEPH_I_KICK_FLUSH_BIT)
+#define CEPH_I_FLUSH_SNAPS (1 << CEPH_I_FLUSH_SNAPS_BIT)
+#define CEPH_I_ODIRECT (1 << CEPH_I_ODIRECT_BIT)
+#define CEPH_I_ASYNC_CREATE (1 << CEPH_I_ASYNC_CREATE_BIT)
+#define CEPH_I_SHUTDOWN (1 << CEPH_I_SHUTDOWN_BIT)
/*
* Masks of ceph inode work.
@@ -694,27 +711,18 @@ static inline struct inode *ceph_find_inode(struct super_block *sb,
/*
* We set the ERROR_WRITE bit when we start seeing write errors on an inode
- * and then clear it when they start succeeding. Note that we do a lockless
- * check first, and only take the lock if it looks like it needs to be changed.
- * The write submission code just takes this as a hint, so we're not too
- * worried if a few slip through in either direction.
+ * and then clear it when they start succeeding. The write submission code
+ * just takes this as a hint, so we're not too worried if a few slip through
+ * in either direction.
*/
static inline void ceph_set_error_write(struct ceph_inode_info *ci)
{
- if (!(READ_ONCE(ci->i_ceph_flags) & CEPH_I_ERROR_WRITE)) {
- spin_lock(&ci->i_ceph_lock);
- ci->i_ceph_flags |= CEPH_I_ERROR_WRITE;
- spin_unlock(&ci->i_ceph_lock);
- }
+ set_bit(CEPH_I_ERROR_WRITE_BIT, &ci->i_ceph_flags);
}
static inline void ceph_clear_error_write(struct ceph_inode_info *ci)
{
- if (READ_ONCE(ci->i_ceph_flags) & CEPH_I_ERROR_WRITE) {
- spin_lock(&ci->i_ceph_lock);
- ci->i_ceph_flags &= ~CEPH_I_ERROR_WRITE;
- spin_unlock(&ci->i_ceph_lock);
- }
+ clear_bit(CEPH_I_ERROR_WRITE_BIT, &ci->i_ceph_flags);
}
static inline void __ceph_dir_set_complete(struct ceph_inode_info *ci,
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c
index e773be07f767..860fc8e1867d 100644
--- a/fs/ceph/xattr.c
+++ b/fs/ceph/xattr.c
@@ -1054,7 +1054,7 @@ handle_non_vxattrs:
if (current->journal_info &&
!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) &&
security_ismaclabel(name + XATTR_SECURITY_PREFIX_LEN))
- ci->i_ceph_flags |= CEPH_I_SEC_INITED;
+ set_bit(CEPH_I_SEC_INITED_BIT, &ci->i_ceph_flags);
out:
spin_unlock(&ci->i_ceph_lock);
return err;
diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
index 8d3c278a7591..0053b5c45412 100644
--- a/fs/crypto/fscrypt_private.h
+++ b/fs/crypto/fscrypt_private.h
@@ -236,7 +236,7 @@ struct fscrypt_symlink_data {
* @tfm: crypto API transform object
* @blk_key: key for blk-crypto
*
- * Normally only one of the fields will be non-NULL.
+ * Only one of the fields is non-NULL.
*/
struct fscrypt_prepared_key {
struct crypto_sync_skcipher *tfm;
@@ -245,6 +245,15 @@ struct fscrypt_prepared_key {
#endif
};
+/* An entry in the linked list ->mk_mode_keys */
+struct fscrypt_mode_key {
+ struct fscrypt_prepared_key key;
+ struct list_head link;
+ u8 hkdf_context;
+ u8 mode_num;
+ u8 data_unit_bits;
+};
+
/*
* fscrypt_inode_info - the "encryption key" for an inode
*
@@ -430,20 +439,12 @@ int fscrypt_derive_sw_secret(struct super_block *sb,
* @prep_key, depending on which encryption implementation the file will use.
*/
static inline bool
-fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
+fscrypt_is_key_prepared(const struct fscrypt_prepared_key *prep_key,
const struct fscrypt_inode_info *ci)
{
- /*
- * The two smp_load_acquire()'s here pair with the smp_store_release()'s
- * in fscrypt_prepare_inline_crypt_key() and fscrypt_prepare_key().
- * I.e., in some cases (namely, if this prep_key is a per-mode
- * encryption key) another task can publish blk_key or tfm concurrently,
- * executing a RELEASE barrier. We need to use smp_load_acquire() here
- * to safely ACQUIRE the memory the other task published.
- */
if (fscrypt_using_inline_encryption(ci))
- return smp_load_acquire(&prep_key->blk_key) != NULL;
- return smp_load_acquire(&prep_key->tfm) != NULL;
+ return prep_key->blk_key != NULL;
+ return prep_key->tfm != NULL;
}
#else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
@@ -486,16 +487,29 @@ fscrypt_derive_sw_secret(struct super_block *sb,
}
static inline bool
-fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
+fscrypt_is_key_prepared(const struct fscrypt_prepared_key *prep_key,
const struct fscrypt_inode_info *ci)
{
- return smp_load_acquire(&prep_key->tfm) != NULL;
+ return prep_key->tfm != NULL;
}
#endif /* !CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
/* keyring.c */
/*
+ * fscrypt_master_key_user - a user's claim to a master key
+ */
+struct fscrypt_master_key_user {
+ struct list_head link;
+ kuid_t uid;
+ /*
+ * This 'struct key' contains no secret. It exists solely to charge the
+ * appropriate user's key quota.
+ */
+ struct key *quota_key;
+};
+
+/*
* fscrypt_master_key_secret - secret key material of an in-use master key
*/
struct fscrypt_master_key_secret {
@@ -577,8 +591,8 @@ struct fscrypt_master_key {
/*
* Active and structural reference counts. An active ref guarantees
* that the struct continues to exist, continues to be in the keyring
- * ->s_master_keys, and that any embedded subkeys (e.g.
- * ->mk_direct_keys) that have been prepared continue to exist.
+ * ->s_master_keys, and that any non-file-scoped subkeys (e.g.
+ * ->mk_mode_keys) that have been prepared continue to exist.
* A structural ref only guarantees that the struct continues to exist.
*
* There is one active ref associated with ->mk_present being true, and
@@ -610,19 +624,18 @@ struct fscrypt_master_key {
struct fscrypt_key_specifier mk_spec;
/*
- * Keyring which contains a key of type 'key_type_fscrypt_user' for each
- * user who has added this key. Normally each key will be added by just
- * one user, but it's possible that multiple users share a key, and in
- * that case we need to keep track of those users so that one user can't
- * remove the key before the others want it removed too.
+ * List of user claims to this key (struct fscrypt_master_key_user).
+ * Normally each key will be added by just one user, but it's possible
+ * that multiple users share a key, and in that case we need to keep
+ * track of those users so that one user can't remove the key before the
+ * others want it removed too.
*
- * This is NULL for v1 policy keys; those can only be added by root.
+ * Used only for v2 policy keys. v1 policy keys can be added only by
+ * root, so user tracking doesn't apply to them.
*
- * Locking: protected by ->mk_sem. (We don't just rely on the keyrings
- * subsystem semaphore ->mk_users->sem, as we need support for atomic
- * search+insert along with proper synchronization with other fields.)
+ * Locking: protected by ->mk_sem.
*/
- struct key *mk_users;
+ struct list_head mk_users;
/*
* List of inodes that were unlocked using this key. This allows the
@@ -632,12 +645,21 @@ struct fscrypt_master_key {
spinlock_t mk_decrypted_inodes_lock;
/*
- * Per-mode encryption keys for the various types of encryption policies
- * that use them. Allocated and derived on-demand.
+ * A list of 'struct fscrypt_mode_key' for the (hkdf_context, mode_num,
+ * data_unit_bits, inlinecrypt) combinations that are in use for this
+ * master key, for hkdf_context in [HKDF_CONTEXT_DIRECT_KEY,
+ * HKDF_CONTEXT_IV_INO_LBLK_32_KEY, HKDF_CONTEXT_IV_INO_LBLK_64_KEY].
+ *
+ * This is a linked list and not a hash table because in practice
+ * there's just a single encryption policy per master key, using
+ * _at most_ 2 nodes in this list. Per-file keys don't use this at all.
+ *
+ * This list is append-only until the master key is fully removed, at
+ * which time the list is cleared. Before then,
+ * fscrypt_mode_key_setup_mutex synchronizes appends, and searches use
+ * the RCU read lock together with ->mk_sem held for read.
*/
- struct fscrypt_prepared_key mk_direct_keys[FSCRYPT_MODE_MAX + 1];
- struct fscrypt_prepared_key mk_iv_ino_lblk_64_keys[FSCRYPT_MODE_MAX + 1];
- struct fscrypt_prepared_key mk_iv_ino_lblk_32_keys[FSCRYPT_MODE_MAX + 1];
+ struct list_head mk_mode_keys;
/* Hash key for inode numbers. Initialized only when needed. */
siphash_key_t mk_ino_hash_key;
diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
index 37d42d357925..47324062fee5 100644
--- a/fs/crypto/inline_crypt.c
+++ b/fs/crypto/inline_crypt.c
@@ -198,13 +198,7 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
goto fail;
}
- /*
- * Pairs with the smp_load_acquire() in fscrypt_is_key_prepared().
- * I.e., here we publish ->blk_key with a RELEASE barrier so that
- * concurrent tasks can ACQUIRE it. Note that this concurrency is only
- * possible for per-mode keys, not for per-file keys.
- */
- smp_store_release(&prep_key->blk_key, blk_key);
+ prep_key->blk_key = blk_key;
return 0;
fail:
diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c
index be8e6e8011f2..38b73e703073 100644
--- a/fs/crypto/keyring.c
+++ b/fs/crypto/keyring.c
@@ -65,36 +65,33 @@ static void fscrypt_free_master_key(struct rcu_head *head)
kfree_sensitive(mk);
}
+static void clear_mk_users(struct fscrypt_master_key *mk);
+
void fscrypt_put_master_key(struct fscrypt_master_key *mk)
{
if (!refcount_dec_and_test(&mk->mk_struct_refs))
return;
/*
- * No structural references left, so free ->mk_users, and also free the
+ * No structural references left, so clear ->mk_users, and also free the
* fscrypt_master_key struct itself after an RCU grace period ensures
* that concurrent keyring lookups can no longer find it.
*/
WARN_ON_ONCE(refcount_read(&mk->mk_active_refs) != 0);
- if (mk->mk_users) {
- /* Clear the keyring so the quota gets released right away. */
- keyring_clear(mk->mk_users);
- key_put(mk->mk_users);
- mk->mk_users = NULL;
- }
+ clear_mk_users(mk);
call_rcu(&mk->mk_rcu_head, fscrypt_free_master_key);
}
void fscrypt_put_master_key_activeref(struct super_block *sb,
struct fscrypt_master_key *mk)
{
- size_t i;
+ struct fscrypt_mode_key *node, *tmp;
if (!refcount_dec_and_test(&mk->mk_active_refs))
return;
/*
* No active references left, so complete the full removal of this
* fscrypt_master_key struct by removing it from the keyring and
- * destroying any subkeys embedded in it.
+ * destroying any non-file-scoped subkeys.
*/
if (WARN_ON_ONCE(!sb->s_master_keys))
@@ -110,13 +107,16 @@ void fscrypt_put_master_key_activeref(struct super_block *sb,
WARN_ON_ONCE(mk->mk_present);
WARN_ON_ONCE(!list_empty(&mk->mk_decrypted_inodes));
- for (i = 0; i <= FSCRYPT_MODE_MAX; i++) {
- fscrypt_destroy_prepared_key(
- sb, &mk->mk_direct_keys[i]);
- fscrypt_destroy_prepared_key(
- sb, &mk->mk_iv_ino_lblk_64_keys[i]);
- fscrypt_destroy_prepared_key(
- sb, &mk->mk_iv_ino_lblk_32_keys[i]);
+ /*
+ * Destroy any non-file-scoped subkeys. Since ->mk_active_refs == 0,
+ * they're no longer referenced by any inodes. Nor can key setup run
+ * and use them again. So they're no longer needed. (This implies no
+ * concurrent readers, so we don't need list_del_rcu() for example.)
+ */
+ list_for_each_entry_safe(node, tmp, &mk->mk_mode_keys, link) {
+ fscrypt_destroy_prepared_key(sb, &node->key);
+ list_del(&node->link);
+ kfree(node);
}
memzero_explicit(&mk->mk_ino_hash_key,
sizeof(mk->mk_ino_hash_key));
@@ -162,8 +162,8 @@ static void fscrypt_user_key_describe(const struct key *key, struct seq_file *m)
}
/*
- * Type of key in ->mk_users. Each key of this type represents a particular
- * user who has added a particular master key.
+ * Type of fscrypt_master_key_user::quota_key. This contains no secret; it
+ * exists solely to charge a user's key quota.
*
* Note that the name of this key type really should be something like
* ".fscrypt-user" instead of simply ".fscrypt". But the shorter name is chosen
@@ -177,30 +177,9 @@ static struct key_type key_type_fscrypt_user = {
.describe = fscrypt_user_key_describe,
};
-#define FSCRYPT_MK_USERS_DESCRIPTION_SIZE \
- (CONST_STRLEN("fscrypt-") + 2 * FSCRYPT_KEY_IDENTIFIER_SIZE + \
- CONST_STRLEN("-users") + 1)
-
#define FSCRYPT_MK_USER_DESCRIPTION_SIZE \
(2 * FSCRYPT_KEY_IDENTIFIER_SIZE + CONST_STRLEN(".uid.") + 10 + 1)
-static void format_mk_users_keyring_description(
- char description[FSCRYPT_MK_USERS_DESCRIPTION_SIZE],
- const u8 mk_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE])
-{
- sprintf(description, "fscrypt-%*phN-users",
- FSCRYPT_KEY_IDENTIFIER_SIZE, mk_identifier);
-}
-
-static void format_mk_user_description(
- char description[FSCRYPT_MK_USER_DESCRIPTION_SIZE],
- const u8 mk_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE])
-{
-
- sprintf(description, "%*phN.uid.%u", FSCRYPT_KEY_IDENTIFIER_SIZE,
- mk_identifier, __kuid_val(current_fsuid()));
-}
-
/* Create ->s_master_keys if needed. Synchronized by fscrypt_add_key_mutex. */
static int allocate_filesystem_keyring(struct super_block *sb)
{
@@ -335,91 +314,94 @@ out:
return mk;
}
-static int allocate_master_key_users_keyring(struct fscrypt_master_key *mk)
-{
- char description[FSCRYPT_MK_USERS_DESCRIPTION_SIZE];
- struct key *keyring;
-
- format_mk_users_keyring_description(description,
- mk->mk_spec.u.identifier);
- keyring = keyring_alloc(description, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
- current_cred(), KEY_POS_SEARCH |
- KEY_USR_SEARCH | KEY_USR_READ | KEY_USR_VIEW,
- KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
- if (IS_ERR(keyring))
- return PTR_ERR(keyring);
-
- mk->mk_users = keyring;
- return 0;
-}
-
-/*
- * Find the current user's "key" in the master key's ->mk_users.
- * Returns ERR_PTR(-ENOKEY) if not found.
- */
-static struct key *find_master_key_user(struct fscrypt_master_key *mk)
+/* Find the current user's claim in ->mk_users. ->mk_sem must be held. */
+static struct fscrypt_master_key_user *
+find_master_key_user(struct fscrypt_master_key *mk)
{
- char description[FSCRYPT_MK_USER_DESCRIPTION_SIZE];
- key_ref_t keyref;
-
- format_mk_user_description(description, mk->mk_spec.u.identifier);
+ struct fscrypt_master_key_user *mk_user;
+ kuid_t uid = current_fsuid();
- /*
- * We need to mark the keyring reference as "possessed" so that we
- * acquire permission to search it, via the KEY_POS_SEARCH permission.
- */
- keyref = keyring_search(make_key_ref(mk->mk_users, true /*possessed*/),
- &key_type_fscrypt_user, description, false);
- if (IS_ERR(keyref)) {
- if (PTR_ERR(keyref) == -EAGAIN || /* not found */
- PTR_ERR(keyref) == -EKEYREVOKED) /* recently invalidated */
- keyref = ERR_PTR(-ENOKEY);
- return ERR_CAST(keyref);
+ list_for_each_entry(mk_user, &mk->mk_users, link) {
+ if (uid_eq(mk_user->uid, uid))
+ return mk_user;
}
- return key_ref_to_ptr(keyref);
+ return NULL;
}
/*
- * Give the current user a "key" in ->mk_users. This charges the user's quota
+ * Give the current user a claim in ->mk_users. This charges the user's quota
* and marks the master key as added by the current user, so that it cannot be
* removed by another user with the key. Either ->mk_sem must be held for
* write, or the master key must be still undergoing initialization.
*/
static int add_master_key_user(struct fscrypt_master_key *mk)
{
+ kuid_t uid = current_fsuid();
char description[FSCRYPT_MK_USER_DESCRIPTION_SIZE];
- struct key *mk_user;
+ struct key *quota_key;
+ struct fscrypt_master_key_user *mk_user;
int err;
- format_mk_user_description(description, mk->mk_spec.u.identifier);
- mk_user = key_alloc(&key_type_fscrypt_user, description,
- current_fsuid(), current_gid(), current_cred(),
- KEY_POS_SEARCH | KEY_USR_VIEW, 0, NULL);
- if (IS_ERR(mk_user))
- return PTR_ERR(mk_user);
+ snprintf(description, sizeof(description), "%*phN.uid.%u",
+ FSCRYPT_KEY_IDENTIFIER_SIZE, mk->mk_spec.u.identifier,
+ __kuid_val(uid));
+ quota_key = key_alloc(&key_type_fscrypt_user, description, uid,
+ current_gid(), current_cred(),
+ KEY_POS_SEARCH | KEY_USR_VIEW, 0, NULL);
+ if (IS_ERR(quota_key))
+ return PTR_ERR(quota_key);
+
+ err = key_instantiate_and_link(quota_key, NULL, 0, NULL, NULL);
+ if (err) {
+ key_put(quota_key);
+ return err;
+ }
- err = key_instantiate_and_link(mk_user, NULL, 0, mk->mk_users, NULL);
- key_put(mk_user);
- return err;
+ mk_user = kzalloc_obj(*mk_user);
+ if (!mk_user) {
+ key_put(quota_key);
+ return -ENOMEM;
+ }
+ mk_user->uid = uid;
+ mk_user->quota_key = quota_key;
+ list_add(&mk_user->link, &mk->mk_users);
+ return 0;
+}
+
+static void unlink_and_free_mk_user(struct fscrypt_master_key_user *mk_user)
+{
+ list_del(&mk_user->link);
+ key_put(mk_user->quota_key);
+ kfree(mk_user);
}
/*
- * Remove the current user's "key" from ->mk_users.
+ * Remove the current user's claim from ->mk_users.
* ->mk_sem must be held for write.
*
- * Returns 0 if removed, -ENOKEY if not found, or another -errno code.
+ * Returns 0 if removed or -ENOKEY if not found.
*/
static int remove_master_key_user(struct fscrypt_master_key *mk)
{
- struct key *mk_user;
- int err;
+ struct fscrypt_master_key_user *mk_user;
mk_user = find_master_key_user(mk);
- if (IS_ERR(mk_user))
- return PTR_ERR(mk_user);
- err = key_unlink(mk->mk_users, mk_user);
- key_put(mk_user);
- return err;
+ if (!mk_user)
+ return -ENOKEY;
+ unlink_and_free_mk_user(mk_user);
+ return 0;
+}
+
+/*
+ * Clear ->mk_users. Either ->mk_sem must be held for write, or 'mk' must have
+ * no structural references left.
+ */
+static void clear_mk_users(struct fscrypt_master_key *mk)
+{
+ struct fscrypt_master_key_user *mk_user, *tmp;
+
+ list_for_each_entry_safe(mk_user, tmp, &mk->mk_users, link)
+ unlink_and_free_mk_user(mk_user);
}
/*
@@ -442,13 +424,14 @@ static int add_new_master_key(struct super_block *sb,
refcount_set(&mk->mk_struct_refs, 1);
mk->mk_spec = *mk_spec;
+ INIT_LIST_HEAD(&mk->mk_users);
+
INIT_LIST_HEAD(&mk->mk_decrypted_inodes);
spin_lock_init(&mk->mk_decrypted_inodes_lock);
+ INIT_LIST_HEAD(&mk->mk_mode_keys);
+
if (mk_spec->type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
- err = allocate_master_key_users_keyring(mk);
- if (err)
- goto out_put;
err = add_master_key_user(mk);
if (err)
goto out_put;
@@ -477,19 +460,13 @@ static int add_existing_master_key(struct fscrypt_master_key *mk,
int err;
/*
- * If the current user is already in ->mk_users, then there's nothing to
- * do. Otherwise, we need to add the user to ->mk_users. (Neither is
- * applicable for v1 policy keys, which have NULL ->mk_users.)
+ * For v2 policy keys (FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER): If the current
+ * user is already in ->mk_users, then there's nothing to do.
+ * Otherwise, add the user to ->mk_users.
*/
- if (mk->mk_users) {
- struct key *mk_user = find_master_key_user(mk);
-
- if (mk_user != ERR_PTR(-ENOKEY)) {
- if (IS_ERR(mk_user))
- return PTR_ERR(mk_user);
- key_put(mk_user);
+ if (mk->mk_spec.type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
+ if (find_master_key_user(mk) != NULL)
return 0;
- }
err = add_master_key_user(mk);
if (err)
return err;
@@ -888,7 +865,6 @@ int fscrypt_verify_key_added(struct super_block *sb,
{
struct fscrypt_key_specifier mk_spec;
struct fscrypt_master_key *mk;
- struct key *mk_user;
int err;
mk_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
@@ -900,13 +876,10 @@ int fscrypt_verify_key_added(struct super_block *sb,
goto out;
}
down_read(&mk->mk_sem);
- mk_user = find_master_key_user(mk);
- if (IS_ERR(mk_user)) {
- err = PTR_ERR(mk_user);
- } else {
- key_put(mk_user);
+ if (find_master_key_user(mk) != NULL)
err = 0;
- }
+ else
+ err = -ENOKEY;
up_read(&mk->mk_sem);
fscrypt_put_master_key(mk);
out:
@@ -1098,16 +1071,18 @@ static int do_remove_key(struct file *filp, void __user *_uarg, bool all_users)
down_write(&mk->mk_sem);
/* If relevant, remove current user's (or all users) claim to the key */
- if (mk->mk_users && mk->mk_users->keys.nr_leaves_on_tree != 0) {
- if (all_users)
- err = keyring_clear(mk->mk_users);
- else
+ if (!list_empty(&mk->mk_users)) {
+ if (all_users) {
+ clear_mk_users(mk);
+ err = 0;
+ } else {
err = remove_master_key_user(mk);
+ }
if (err) {
up_write(&mk->mk_sem);
goto out_put_key;
}
- if (mk->mk_users->keys.nr_leaves_on_tree != 0) {
+ if (!list_empty(&mk->mk_users)) {
/*
* Other users have still added the key too. We removed
* the current user's claim to the key, but we still
@@ -1193,6 +1168,8 @@ int fscrypt_ioctl_get_key_status(struct file *filp, void __user *uarg)
struct super_block *sb = file_inode(filp)->i_sb;
struct fscrypt_get_key_status_arg arg;
struct fscrypt_master_key *mk;
+ kuid_t uid;
+ const struct fscrypt_master_key_user *mk_user;
int err;
if (copy_from_user(&arg, uarg, sizeof(arg)))
@@ -1225,19 +1202,13 @@ int fscrypt_ioctl_get_key_status(struct file *filp, void __user *uarg)
}
arg.status = FSCRYPT_KEY_STATUS_PRESENT;
- if (mk->mk_users) {
- struct key *mk_user;
- arg.user_count = mk->mk_users->keys.nr_leaves_on_tree;
- mk_user = find_master_key_user(mk);
- if (!IS_ERR(mk_user)) {
+ uid = current_fsuid();
+ list_for_each_entry(mk_user, &mk->mk_users, link) {
+ arg.user_count++;
+ if (uid_eq(mk_user->uid, uid))
arg.status_flags |=
FSCRYPT_KEY_STATUS_FLAG_ADDED_BY_SELF;
- key_put(mk_user);
- } else if (mk_user != ERR_PTR(-ENOKEY)) {
- err = PTR_ERR(mk_user);
- goto out_release_key;
- }
}
err = 0;
out_release_key:
diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c
index ce327bfdada4..f905f9f94bdd 100644
--- a/fs/crypto/keysetup.c
+++ b/fs/crypto/keysetup.c
@@ -163,13 +163,7 @@ int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key,
tfm = fscrypt_allocate_skcipher(ci->ci_mode, raw_key, ci->ci_inode);
if (IS_ERR(tfm))
return PTR_ERR(tfm);
- /*
- * Pairs with the smp_load_acquire() in fscrypt_is_key_prepared().
- * I.e., here we publish ->tfm with a RELEASE barrier so that
- * concurrent tasks can ACQUIRE it. Note that this concurrency is only
- * possible for per-mode keys, not for per-file keys.
- */
- smp_store_release(&prep_key->tfm, tfm);
+ prep_key->tfm = tfm;
return 0;
}
@@ -190,9 +184,37 @@ int fscrypt_set_per_file_enc_key(struct fscrypt_inode_info *ci,
return fscrypt_prepare_key(&ci->ci_enc_key, raw_key, ci);
}
+/*
+ * Find the fscrypt_prepared_key (if any) for a particular (mk, hkdf_context,
+ * mode_num, data_unit_bits, inlinecrypt) combination.
+ *
+ * The caller must hold ->mk_sem for reading and ->mk_present must be true,
+ * ensuring that ->mk_mode_keys is still append-only.
+ */
+static struct fscrypt_prepared_key *
+fscrypt_find_mode_key(struct fscrypt_master_key *mk, u8 hkdf_context,
+ u8 mode_num, const struct fscrypt_inode_info *ci)
+{
+ struct fscrypt_mode_key *node;
+
+ /*
+ * The RCU read lock here is used only to synchronize with concurrent
+ * list_add_tail_rcu(). Concurrent deletions are impossible here, so
+ * returning a pointer to a node without taking any refcount is safe.
+ */
+ guard(rcu)();
+ list_for_each_entry_rcu(node, &mk->mk_mode_keys, link) {
+ if (node->hkdf_context == hkdf_context &&
+ node->mode_num == mode_num &&
+ node->data_unit_bits == ci->ci_data_unit_bits &&
+ fscrypt_is_key_prepared(&node->key, ci))
+ return &node->key;
+ }
+ return NULL;
+}
+
static int setup_per_mode_enc_key(struct fscrypt_inode_info *ci,
struct fscrypt_master_key *mk,
- struct fscrypt_prepared_key *keys,
u8 hkdf_context, bool include_fs_uuid)
{
const struct inode *inode = ci->ci_inode;
@@ -200,7 +222,8 @@ static int setup_per_mode_enc_key(struct fscrypt_inode_info *ci,
struct fscrypt_mode *mode = ci->ci_mode;
const u8 mode_num = mode - fscrypt_modes;
struct fscrypt_prepared_key *prep_key;
- u8 mode_key[FSCRYPT_MAX_RAW_KEY_SIZE];
+ struct fscrypt_mode_key *new_node;
+ u8 raw_mode_key[FSCRYPT_MAX_RAW_KEY_SIZE];
u8 hkdf_info[sizeof(mode_num) + sizeof(sb->s_uuid)];
unsigned int hkdf_infolen = 0;
bool use_hw_wrapped_key = false;
@@ -223,48 +246,56 @@ static int setup_per_mode_enc_key(struct fscrypt_inode_info *ci,
use_hw_wrapped_key = true;
}
- prep_key = &keys[mode_num];
- if (fscrypt_is_key_prepared(prep_key, ci)) {
+ prep_key = fscrypt_find_mode_key(mk, hkdf_context, mode_num, ci);
+ if (prep_key) {
ci->ci_enc_key = *prep_key;
return 0;
}
- mutex_lock(&fscrypt_mode_key_setup_mutex);
+ guard(mutex)(&fscrypt_mode_key_setup_mutex);
- if (fscrypt_is_key_prepared(prep_key, ci))
- goto done_unlock;
+ prep_key = fscrypt_find_mode_key(mk, hkdf_context, mode_num, ci);
+ if (prep_key) {
+ ci->ci_enc_key = *prep_key;
+ return 0;
+ }
+
+ new_node = kzalloc_obj(*new_node);
+ if (!new_node)
+ return -ENOMEM;
+ new_node->hkdf_context = hkdf_context;
+ new_node->mode_num = mode_num;
+ new_node->data_unit_bits = ci->ci_data_unit_bits;
+ prep_key = &new_node->key;
if (use_hw_wrapped_key) {
err = fscrypt_prepare_inline_crypt_key(prep_key,
mk->mk_secret.bytes,
mk->mk_secret.size, true,
ci);
- if (err)
- goto out_unlock;
- goto done_unlock;
+ } else {
+ static_assert(sizeof(mode_num) == 1);
+ static_assert(sizeof(sb->s_uuid) == 16);
+ static_assert(sizeof(hkdf_info) == 17);
+ hkdf_info[hkdf_infolen++] = mode_num;
+ if (include_fs_uuid) {
+ memcpy(&hkdf_info[hkdf_infolen], &sb->s_uuid,
+ sizeof(sb->s_uuid));
+ hkdf_infolen += sizeof(sb->s_uuid);
+ }
+ fscrypt_hkdf_expand(&mk->mk_secret.hkdf, hkdf_context,
+ hkdf_info, hkdf_infolen, raw_mode_key,
+ mode->keysize);
+ err = fscrypt_prepare_key(prep_key, raw_mode_key, ci);
+ memzero_explicit(raw_mode_key, mode->keysize);
}
-
- BUILD_BUG_ON(sizeof(mode_num) != 1);
- BUILD_BUG_ON(sizeof(sb->s_uuid) != 16);
- BUILD_BUG_ON(sizeof(hkdf_info) != 17);
- hkdf_info[hkdf_infolen++] = mode_num;
- if (include_fs_uuid) {
- memcpy(&hkdf_info[hkdf_infolen], &sb->s_uuid,
- sizeof(sb->s_uuid));
- hkdf_infolen += sizeof(sb->s_uuid);
+ if (err) {
+ kfree(new_node);
+ return err;
}
- fscrypt_hkdf_expand(&mk->mk_secret.hkdf, hkdf_context, hkdf_info,
- hkdf_infolen, mode_key, mode->keysize);
- err = fscrypt_prepare_key(prep_key, mode_key, ci);
- memzero_explicit(mode_key, mode->keysize);
- if (err)
- goto out_unlock;
-done_unlock:
+ list_add_tail_rcu(&new_node->link, &mk->mk_mode_keys);
ci->ci_enc_key = *prep_key;
- err = 0;
-out_unlock:
- mutex_unlock(&fscrypt_mode_key_setup_mutex);
- return err;
+ return 0;
}
/*
@@ -311,8 +342,8 @@ static int fscrypt_setup_iv_ino_lblk_32_key(struct fscrypt_inode_info *ci,
{
int err;
- err = setup_per_mode_enc_key(ci, mk, mk->mk_iv_ino_lblk_32_keys,
- HKDF_CONTEXT_IV_INO_LBLK_32_KEY, true);
+ err = setup_per_mode_enc_key(ci, mk, HKDF_CONTEXT_IV_INO_LBLK_32_KEY,
+ true);
if (err)
return err;
@@ -364,8 +395,8 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_inode_info *ci,
* encryption key. This ensures that the master key is
* consistently used only for HKDF, avoiding key reuse issues.
*/
- err = setup_per_mode_enc_key(ci, mk, mk->mk_direct_keys,
- HKDF_CONTEXT_DIRECT_KEY, false);
+ err = setup_per_mode_enc_key(ci, mk, HKDF_CONTEXT_DIRECT_KEY,
+ false);
} else if (ci->ci_policy.v2.flags &
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) {
/*
@@ -374,9 +405,8 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_inode_info *ci,
* the IVs. This format is optimized for use with inline
* encryption hardware compliant with the UFS standard.
*/
- err = setup_per_mode_enc_key(ci, mk, mk->mk_iv_ino_lblk_64_keys,
- HKDF_CONTEXT_IV_INO_LBLK_64_KEY,
- true);
+ err = setup_per_mode_enc_key(
+ ci, mk, HKDF_CONTEXT_IV_INO_LBLK_64_KEY, true);
} else if (ci->ci_policy.v2.flags &
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) {
err = fscrypt_setup_iv_ino_lblk_32_key(ci, mk);
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 5ef67b2674ee..74b02b55e3f6 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -49,25 +49,15 @@ void ecryptfs_from_hex(char *dst, char *src, int dst_size)
}
static int ecryptfs_crypto_api_algify_cipher_name(char **algified_name,
- char *cipher_name,
- char *chaining_modifier)
+ const char *cipher_name,
+ const char *chaining_modifier)
{
- int cipher_name_len = strlen(cipher_name);
- int chaining_modifier_len = strlen(chaining_modifier);
- int algified_name_len;
- int rc;
+ (*algified_name) = kasprintf(GFP_KERNEL, "%s(%s)", chaining_modifier,
+ cipher_name);
+ if (!(*algified_name))
+ return -ENOMEM;
- algified_name_len = (chaining_modifier_len + cipher_name_len + 3);
- (*algified_name) = kmalloc(algified_name_len, GFP_KERNEL);
- if (!(*algified_name)) {
- rc = -ENOMEM;
- goto out;
- }
- snprintf((*algified_name), algified_name_len, "%s(%s)",
- chaining_modifier, cipher_name);
- rc = 0;
-out:
- return rc;
+ return 0;
}
/**
diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
index 0be746493e56..ebebc9551f1f 100644
--- a/fs/ecryptfs/keystore.c
+++ b/fs/ecryptfs/keystore.c
@@ -1718,7 +1718,6 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
struct dentry *ecryptfs_dentry)
{
size_t i = 0;
- size_t found_auth_tok;
size_t next_packet_is_auth_tok_packet;
LIST_HEAD(auth_tok_list);
struct ecryptfs_auth_tok *matching_auth_tok;
@@ -1822,7 +1821,6 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
* the metadata. There may be several potential matches, but
* just one will be sufficient to decrypt to get the FEK. */
find_next_matching_auth_tok:
- found_auth_tok = 0;
list_for_each_entry(auth_tok_list_item, &auth_tok_list, list) {
candidate_auth_tok = &auth_tok_list_item->auth_tok;
if (unlikely(ecryptfs_verbosity > 0)) {
@@ -1843,17 +1841,13 @@ find_next_matching_auth_tok:
&matching_auth_tok,
crypt_stat->mount_crypt_stat,
candidate_auth_tok_sig);
- if (!rc) {
- found_auth_tok = 1;
+ if (!rc)
goto found_matching_auth_tok;
- }
- }
- if (!found_auth_tok) {
- ecryptfs_printk(KERN_ERR, "Could not find a usable "
- "authentication token\n");
- rc = -EIO;
- goto out_wipe_list;
}
+ ecryptfs_printk(KERN_ERR,
+ "Could not find a usable authentication token\n");
+ rc = -EIO;
+ goto out_wipe_list;
found_matching_auth_tok:
if (candidate_auth_tok->token_type == ECRYPTFS_PRIVATE_KEY) {
memcpy(&(candidate_auth_tok->token.private_key),
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index d158c4b7413d..51ac1fd44f78 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -1322,6 +1322,19 @@ static int gfs2_block_zero_range(struct inode *inode, loff_t from, loff_t length
&gfs2_iomap_write_ops, NULL);
}
+int gfs2_clear_beyond_eof(struct inode *inode, loff_t end)
+{
+ loff_t isize = i_size_read(inode);
+ unsigned int len = isize & ~PAGE_MASK;
+
+ if (!len || isize >= end)
+ return 0;
+ len = PAGE_SIZE - len;
+ if (end - isize < len)
+ len = end - isize;
+ return gfs2_block_zero_range(inode, isize, len);
+}
+
#define GFS2_JTRUNC_REVOKES 8192
/**
@@ -2097,6 +2110,12 @@ static int do_grow(struct inode *inode, u64 size)
unstuff = 1;
}
+ if (!unstuff) {
+ error = gfs2_clear_beyond_eof(inode, size);
+ if (error)
+ goto do_grow_qunlock;
+ }
+
error = gfs2_trans_begin(sdp, RES_DINODE + RES_STATFS + RES_RG_BIT +
(unstuff &&
gfs2_is_jdata(ip) ? RES_JDATA : 0) +
diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h
index 6cdc72dd55a3..e3d6efdfd890 100644
--- a/fs/gfs2/bmap.h
+++ b/fs/gfs2/bmap.h
@@ -58,6 +58,7 @@ int gfs2_get_extent(struct inode *inode, u64 lblock, u64 *dblock,
unsigned int *extlen);
int gfs2_alloc_extent(struct inode *inode, u64 lblock, u64 *dblock,
unsigned *extlen, bool *new);
+int gfs2_clear_beyond_eof(struct inode *inode, loff_t end);
int gfs2_setattr_size(struct inode *inode, u64 size);
int gfs2_truncatei_resume(struct gfs2_inode *ip);
int gfs2_file_dealloc(struct gfs2_inode *ip);
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index 9704f1ef6ad1..b8c10de113ba 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -1057,6 +1057,10 @@ retry:
goto out_unlock;
}
+ ret = gfs2_clear_beyond_eof(inode, iocb->ki_pos);
+ if (ret)
+ goto out_unlock;
+
pagefault_disable();
ret = iomap_file_buffered_write(iocb, from, &gfs2_iomap_ops,
&gfs2_iomap_write_ops, NULL);
@@ -1173,8 +1177,7 @@ out_unlock:
return ret;
}
-static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
- int mode)
+static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len)
{
struct super_block *sb = inode->i_sb;
struct gfs2_inode *ip = GFS2_I(inode);
@@ -1266,6 +1269,12 @@ static long __gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t
next = (next + 1) << sdp->sd_sb.sb_bsize_shift;
+ if (!(mode & FALLOC_FL_KEEP_SIZE)) {
+ error = gfs2_clear_beyond_eof(inode, offset + len);
+ if (error)
+ return error;
+ }
+
offset &= bsize_mask;
len = next - offset;
@@ -1336,7 +1345,7 @@ static long __gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t
if (error)
goto out_trans_fail;
- error = fallocate_chunk(inode, offset, max_bytes, mode);
+ error = fallocate_chunk(inode, offset, max_bytes);
gfs2_trans_end(sdp);
if (error)
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index 5290865f27f1..91e9975d25e8 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -254,9 +254,13 @@ fail:
return NULL;
}
-static struct gfs2_quota_data *gfs2_qd_search_bucket(unsigned int hash,
- const struct gfs2_sbd *sdp,
- struct kqid qid)
+/*
+ * Lookup variant for callers which already hold qd_lock + bucket lock.
+ */
+static struct gfs2_quota_data *
+gfs2_qd_search_bucket_noref(unsigned int hash,
+ const struct gfs2_sbd *sdp,
+ struct kqid qid)
{
struct gfs2_quota_data *qd;
struct hlist_bl_node *h;
@@ -264,12 +268,22 @@ static struct gfs2_quota_data *gfs2_qd_search_bucket(unsigned int hash,
hlist_bl_for_each_entry_rcu(qd, h, &qd_hash_table[hash], qd_hlist) {
if (!qid_eq(qd->qd_id, qid))
continue;
- if (qd->qd_sbd != sdp)
- continue;
- if (lockref_get_not_dead(&qd->qd_lockref)) {
- list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru);
+ if (qd->qd_sbd == sdp)
return qd;
- }
+ }
+
+ return NULL;
+}
+
+static struct gfs2_quota_data *
+gfs2_qd_search_bucket(unsigned int hash, const struct gfs2_sbd *sdp, struct kqid qid)
+{
+ struct gfs2_quota_data *qd;
+
+ qd = gfs2_qd_search_bucket_noref(hash, sdp, qid);
+ if (qd && lockref_get_not_dead(&qd->qd_lockref)) {
+ list_lru_del_obj(&gfs2_qd_lru, &qd->qd_lru);
+ return qd;
}
return NULL;
@@ -1433,7 +1447,7 @@ int gfs2_quota_init(struct gfs2_sbd *sdp)
qc = (struct gfs2_quota_change *)(bh->b_data + sizeof(struct gfs2_meta_header));
for (y = 0; y < sdp->sd_qc_per_block && slot < sdp->sd_quota_slots;
- y++, slot++) {
+ y++, slot++, qc++) {
struct gfs2_quota_data *old_qd, *qd;
s64 qc_change = be64_to_cpu(qc->qc_change);
u32 qc_flags = be32_to_cpu(qc->qc_flags);
@@ -1441,7 +1455,6 @@ int gfs2_quota_init(struct gfs2_sbd *sdp)
USRQUOTA : GRPQUOTA;
struct kqid qc_id = make_kqid(&init_user_ns, qtype,
be32_to_cpu(qc->qc_id));
- qc++;
if (!qc_change)
continue;
@@ -1458,7 +1471,7 @@ int gfs2_quota_init(struct gfs2_sbd *sdp)
spin_lock(&qd_lock);
spin_lock_bucket(hash);
- old_qd = gfs2_qd_search_bucket(hash, sdp, qc_id);
+ old_qd = gfs2_qd_search_bucket_noref(hash, sdp, qc_id);
if (old_qd) {
fs_err(sdp, "Corruption found in quota_change%u"
"file: duplicate identifier in "
@@ -1467,7 +1480,6 @@ int gfs2_quota_init(struct gfs2_sbd *sdp)
spin_unlock_bucket(hash);
spin_unlock(&qd_lock);
- qd_put(old_qd);
gfs2_glock_put(qd->qd_gl);
kmem_cache_free(gfs2_quotad_cachep, qd);
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index a2ea121331f1..4d854556b529 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -643,6 +643,7 @@ restart:
gfs2_delete_debugfs_file(sdp);
gfs2_sys_fs_del(sdp);
+ rcu_barrier();
free_sbd(sdp);
}
diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c
index 42a3115359da..07cf0e578233 100644
--- a/fs/smb/client/cifsacl.c
+++ b/fs/smb/client/cifsacl.c
@@ -1185,7 +1185,8 @@ set_size:
static __u16 replace_sids_and_copy_aces(struct smb_acl *pdacl, struct smb_acl *pndacl,
struct smb_sid *pownersid, struct smb_sid *pgrpsid,
- struct smb_sid *pnownersid, struct smb_sid *pngrpsid)
+ struct smb_sid *pnownersid, struct smb_sid *pngrpsid,
+ int *aclflag)
{
int i;
u16 size = 0;
@@ -1209,12 +1210,15 @@ static __u16 replace_sids_and_copy_aces(struct smb_acl *pdacl, struct smb_acl *p
pntace = (struct smb_ace *) (acl_base + size);
pnntace = (struct smb_ace *) (nacl_base + nsize);
- if (pnownersid && compare_sids(&pntace->sid, pownersid) == 0)
+ if (pnownersid && compare_sids(&pntace->sid, pownersid) == 0) {
ace_size = cifs_copy_ace(pnntace, pntace, pnownersid);
- else if (pngrpsid && compare_sids(&pntace->sid, pgrpsid) == 0)
+ *aclflag |= CIFS_ACL_DACL;
+ } else if (pngrpsid && compare_sids(&pntace->sid, pgrpsid) == 0) {
ace_size = cifs_copy_ace(pnntace, pntace, pngrpsid);
- else
+ *aclflag |= CIFS_ACL_DACL;
+ } else {
ace_size = cifs_copy_ace(pnntace, pntace, NULL);
+ }
size += le16_to_cpu(pntace->size);
nsize += ace_size;
@@ -1521,7 +1525,8 @@ static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
/* Replace ACEs for old owner with new one */
size = replace_sids_and_copy_aces(dacl_ptr, ndacl_ptr,
owner_sid_ptr, group_sid_ptr,
- nowner_sid_ptr, ngroup_sid_ptr);
+ nowner_sid_ptr, ngroup_sid_ptr,
+ aclflag);
ndacl_ptr->size = cpu_to_le16(size);
}
@@ -1738,7 +1743,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
kuid_t uid, kgid_t gid)
{
int rc = 0;
- int aclflag = CIFS_ACL_DACL; /* default flag to set */
+ int aclflag = 0;
__u32 secdesclen = 0;
__u32 nsecdesclen = 0;
__u32 dacloffset = 0;
@@ -1834,14 +1839,23 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
- if (ops->set_acl == NULL)
- rc = -EOPNOTSUPP;
+ if (rc != 0)
+ goto id_mode_to_cifs_acl_exit;
- if (!rc) {
- /* Set the security descriptor */
- rc = ops->set_acl(pnntsd, nsecdesclen, inode, path, aclflag);
- cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
+ if (aclflag == 0) {
+ cifs_dbg(FYI, "set_cifs_acl aclflag=0, no change mapped\n");
+ goto id_mode_to_cifs_acl_exit;
}
+
+ if (ops->set_acl == NULL) {
+ rc = -EOPNOTSUPP;
+ goto id_mode_to_cifs_acl_exit;
+ }
+
+ /* Set the security descriptor */
+ rc = ops->set_acl(pnntsd, nsecdesclen, inode, path, aclflag);
+ cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
+
id_mode_to_cifs_acl_exit:
cifs_put_tlink(tlink);
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index befc5eecb55c..99f9e6dca62b 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -1393,6 +1393,7 @@ struct cifs_search_info {
bool emptyDir:1;
bool unicode:1;
bool smallBuf:1; /* so we know which buf_release function to call */
+ bool is_dynamic_buf:1; /* dynamically allocated buffer - can be variable size */
};
#define ACL_NO_MODE ((umode_t)(-1))
@@ -1906,6 +1907,7 @@ enum cifs_find_flags {
#define CIFS_NO_BUFFER 0 /* Response buffer not returned */
#define CIFS_SMALL_BUFFER 1
#define CIFS_LARGE_BUFFER 2
+#define CIFS_DYNAMIC_BUFFER 3 /* Dynamically allocated buffer */
#define CIFS_IOVEC 4 /* array of response buffers */
/* Type of Request to SendReceive2 */
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index 74197766471c..85aec302c89e 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -457,8 +457,8 @@ static int __reconnect_target_locked(struct TCP_Server_Info *server,
server->hostname = hostname;
spin_unlock(&server->srv_lock);
} else {
- cifs_dbg(FYI, "%s: couldn't extract hostname or address from dfs target: %ld\n",
- __func__, PTR_ERR(hostname));
+ cifs_dbg(FYI, "%s: couldn't extract hostname or address from dfs target: %pe\n",
+ __func__, hostname);
cifs_dbg(FYI, "%s: default to last target server: %s\n", __func__,
server->hostname);
}
diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c
index 58430ba51b10..8b25d6c9ec5e 100644
--- a/fs/smb/client/file.c
+++ b/fs/smb/client/file.c
@@ -1563,6 +1563,8 @@ int cifs_closedir(struct inode *inode, struct file *file)
cfile->srch_inf.ntwrk_buf_start = NULL;
if (cfile->srch_inf.smallBuf)
cifs_small_buf_release(buf);
+ else if (cfile->srch_inf.is_dynamic_buf)
+ kfree(buf);
else
cifs_buf_release(buf);
}
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index 51fb7c418d52..1dbcfd163ff0 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -3038,13 +3038,20 @@ int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start,
void cifs_setsize(struct inode *inode, loff_t offset)
{
+ loff_t old_size;
+ u64 blocks = CIFS_INO_BLOCKS(offset);
+
spin_lock(&inode->i_lock);
+ old_size = i_size_read(inode);
i_size_write(inode, offset);
+
/*
- * Until we can query the server for actual allocation size,
- * this is best estimate we have for blocks allocated for a file.
+ * Extending EOF does not allocate the intervening range. Only clamp
+ * i_blocks on shrink; allocation growth comes from writes or from the
+ * server-reported AllocationSize.
*/
- inode->i_blocks = CIFS_INO_BLOCKS(offset);
+ if (offset < old_size && (u64)inode->i_blocks > blocks)
+ inode->i_blocks = blocks;
spin_unlock(&inode->i_lock);
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
truncate_pagecache(inode, offset);
@@ -3376,7 +3383,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
if (attrs->ia_valid & ATTR_GID)
gid = attrs->ia_gid;
- if (sbflags & (CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_MODE_FROM_SID)) {
+ if ((sbflags & (CIFS_MOUNT_CIFS_ACL | CIFS_MOUNT_MODE_FROM_SID)) ||
+ cifs_sb_master_tcon(cifs_sb)->posix_extensions) {
if (uid_valid(uid) || gid_valid(gid)) {
mode = NO_CHANGE_64;
rc = id_mode_to_cifs_acl(inode, full_path, &mode,
diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c
index 1ff77f3d1de0..a50c86bbe60f 100644
--- a/fs/smb/client/readdir.c
+++ b/fs/smb/client/readdir.c
@@ -732,6 +732,8 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
if (cfile->srch_inf.smallBuf)
cifs_small_buf_release(cfile->srch_inf.
ntwrk_buf_start);
+ else if (cfile->srch_inf.is_dynamic_buf)
+ kfree(cfile->srch_inf.ntwrk_buf_start);
else
cifs_buf_release(cfile->srch_inf.
ntwrk_buf_start);
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index a8f8feeeccb5..06e9322a762a 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -2117,8 +2117,9 @@ smb2_sync_write(const unsigned int xid, struct cifs_fid *pfid,
}
/* Set or clear the SPARSE_FILE attribute based on value passed in setsparse */
-static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon,
- struct cifsFileInfo *cfile, struct inode *inode, __u8 setsparse)
+static int smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon,
+ struct cifsFileInfo *cfile, struct inode *inode,
+ __u8 setsparse)
{
struct cifsInodeInfo *cifsi;
int rc;
@@ -2127,31 +2128,31 @@ static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon,
/* if file already sparse don't bother setting sparse again */
if ((cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) && setsparse)
- return true; /* already sparse */
+ return 0; /* already sparse */
if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) && !setsparse)
- return true; /* already not sparse */
+ return 0; /* already not sparse */
/*
* Can't check for sparse support on share the usual way via the
* FS attribute info (FILE_SUPPORTS_SPARSE_FILES) on the share
* since Samba server doesn't set the flag on the share, yet
* supports the set sparse FSCTL and returns sparse correctly
- * in the file attributes. If we fail setting sparse though we
- * mark that server does not support sparse files for this share
- * to avoid repeatedly sending the unsupported fsctl to server
- * if the file is repeatedly extended.
+ * in the file attributes. If the server returns EOPNOTSUPP, mark
+ * that sparse files are not supported on this share to avoid
+ * repeatedly sending the unsupported FSCTL.
*/
if (tcon->broken_sparse_sup)
- return false;
+ return -EOPNOTSUPP;
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
cfile->fid.volatile_fid, FSCTL_SET_SPARSE,
&setsparse, 1, CIFSMaxBufSize, NULL, NULL);
if (rc) {
- tcon->broken_sparse_sup = true;
+ if (rc == -EOPNOTSUPP)
+ tcon->broken_sparse_sup = true;
cifs_dbg(FYI, "set sparse rc = %d\n", rc);
- return false;
+ return rc;
}
if (setsparse)
@@ -2159,7 +2160,7 @@ static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon,
else
cifsi->cifsAttrs &= (~FILE_ATTRIBUTE_SPARSE_FILE);
- return true;
+ return 0;
}
static int
@@ -3483,10 +3484,9 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
/* Need to make file sparse, if not already, before freeing range. */
/* Consider adding equivalent for compressed since it could also work */
- if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse)) {
- rc = -EOPNOTSUPP;
+ rc = smb2_set_sparse(xid, tcon, cfile, inode, set_sparse);
+ if (rc)
goto out;
- }
filemap_invalidate_lock(inode->i_mapping);
/*
@@ -4071,7 +4071,7 @@ static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode,
return smb3_collapse_range(file, tcon, off, len);
else if (mode == FALLOC_FL_INSERT_RANGE)
return smb3_insert_range(file, tcon, off, len);
- else if (mode == 0)
+ else if (mode == FALLOC_FL_ALLOCATE_RANGE)
return smb3_simple_falloc(file, tcon, off, len, false);
return -EOPNOTSUPP;
@@ -5111,6 +5111,12 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
one_more:
shdr = (struct smb2_hdr *)buf;
next_cmd = le32_to_cpu(shdr->NextCommand);
+
+ if (*num_mids >= MAX_COMPOUND) {
+ cifs_server_dbg(VFS, "too many PDUs in compound\n");
+ return -1;
+ }
+
if (next_cmd) {
if (WARN_ON_ONCE(next_cmd > pdu_length))
return -1;
@@ -5134,10 +5140,6 @@ one_more:
mid_entry->resp_buf_size = server->pdu_size;
}
- if (*num_mids >= MAX_COMPOUND) {
- cifs_server_dbg(VFS, "too many PDUs in compound\n");
- return -1;
- }
bufs[*num_mids] = buf;
mids[(*num_mids)++] = mid_entry;
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 3c7691b39377..d058584b8f05 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -3305,6 +3305,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
replay_again:
/* reinitialize for possible replay */
+ resp_buftype = CIFS_NO_BUFFER;
+ memset(&rsp_iov, 0, sizeof(rsp_iov));
flags = 0;
server = cifs_pick_channel(ses);
oparms->replay = !!(retries);
@@ -3530,6 +3532,8 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
replay_again:
/* reinitialize for possible replay */
+ resp_buftype = CIFS_NO_BUFFER;
+ memset(&rsp_iov, 0, sizeof(rsp_iov));
flags = 0;
server = cifs_pick_channel(ses);
@@ -3724,6 +3728,8 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
replay_again:
/* reinitialize for possible replay */
+ resp_buftype = CIFS_NO_BUFFER;
+ memset(&rsp_iov, 0, sizeof(rsp_iov));
flags = 0;
query_attrs = false;
server = cifs_pick_channel(ses);
@@ -3936,6 +3942,8 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
replay_again:
/* reinitialize for possible replay */
+ resp_buftype = CIFS_NO_BUFFER;
+ memset(&rsp_iov, 0, sizeof(rsp_iov));
flags = 0;
allocated = false;
server = cifs_pick_channel(ses);
@@ -4108,6 +4116,8 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
replay_again:
/* reinitialize for possible replay */
+ resp_buftype = CIFS_NO_BUFFER;
+ memset(&rsp_iov, 0, sizeof(rsp_iov));
flags = 0;
server = cifs_pick_channel(ses);
@@ -4450,6 +4460,8 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
replay_again:
/* reinitialize for possible replay */
+ resp_buftype = CIFS_NO_BUFFER;
+ memset(&rsp_iov, 0, sizeof(rsp_iov));
flags = 0;
server = cifs_pick_channel(ses);
@@ -5661,6 +5673,8 @@ smb2_parse_query_directory(struct cifs_tcon *tcon,
if (srch_inf->ntwrk_buf_start) {
if (srch_inf->smallBuf)
cifs_small_buf_release(srch_inf->ntwrk_buf_start);
+ else if (srch_inf->is_dynamic_buf)
+ kfree(srch_inf->ntwrk_buf_start);
else
cifs_buf_release(srch_inf->ntwrk_buf_start);
}
@@ -5680,12 +5694,18 @@ smb2_parse_query_directory(struct cifs_tcon *tcon,
cifs_dbg(FYI, "num entries %d last_index %lld srch start %p srch end %p\n",
srch_inf->entries_in_buffer, srch_inf->index_of_last_entry,
srch_inf->srch_entries_start, srch_inf->last_entry);
- if (resp_buftype == CIFS_LARGE_BUFFER)
+ if (resp_buftype == CIFS_LARGE_BUFFER) {
srch_inf->smallBuf = false;
- else if (resp_buftype == CIFS_SMALL_BUFFER)
+ srch_inf->is_dynamic_buf = false;
+ } else if (resp_buftype == CIFS_SMALL_BUFFER) {
srch_inf->smallBuf = true;
- else
+ srch_inf->is_dynamic_buf = false;
+ } else if (resp_buftype == CIFS_DYNAMIC_BUFFER) {
+ srch_inf->smallBuf = false;
+ srch_inf->is_dynamic_buf = true;
+ } else {
cifs_tcon_dbg(VFS, "Invalid search buffer type\n");
+ }
return 0;
}
@@ -5708,6 +5728,8 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
replay_again:
/* reinitialize for possible replay */
+ resp_buftype = CIFS_NO_BUFFER;
+ memset(&rsp_iov, 0, sizeof(rsp_iov));
flags = 0;
server = cifs_pick_channel(ses);
diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h
index 325ff83b12fe..e7ff52b8aba5 100644
--- a/fs/smb/common/smb2pdu.h
+++ b/fs/smb/common/smb2pdu.h
@@ -1244,6 +1244,30 @@ struct create_mxac_req {
} __packed;
/*
+ * AAPL flags. See Samba libcli/smb/smb2_create_ctx.h
+ */
+
+/* "AAPL" Context Command Codes */
+#define SMB2_CRTCTX_AAPL_SERVER_QUERY 1
+#define SMB2_CRTCTX_AAPL_RESOLVE_ID 2
+
+/* "AAPL" Server Query request/response bitmap */
+#define SMB2_CRTCTX_AAPL_SERVER_CAPS 1
+#define SMB2_CRTCTX_AAPL_VOLUME_CAPS 2
+#define SMB2_CRTCTX_AAPL_MODEL_INFO 4
+
+/* "AAPL" Client/Server Capabilities bitmap */
+#define SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR 1
+#define SMB2_CRTCTX_AAPL_SUPPORTS_OSX_COPYFILE 2
+#define SMB2_CRTCTX_AAPL_UNIX_BASED 4
+#define SMB2_CRTCTX_AAPL_SUPPORTS_NFS_ACE 8
+
+/* "AAPL" Volume Capabilities bitmap */
+#define SMB2_CRTCTX_AAPL_SUPPORT_RESOLVE_ID 1
+#define SMB2_CRTCTX_AAPL_CASE_SENSITIVE 2
+#define SMB2_CRTCTX_AAPL_FULL_SYNC 4
+
+/*
* Flags
* See MS-SMB2 2.2.13.2.11
* MS-SMB2 2.2.13.2.12
diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c
index e99409fa721c..86f521e849d5 100644
--- a/fs/smb/server/auth.c
+++ b/fs/smb/server/auth.c
@@ -142,6 +142,7 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
{
char ntlmv2_hash[CIFS_ENCPWD_SIZE];
char ntlmv2_rsp[CIFS_HMAC_MD5_HASH_SIZE];
+ char sess_key[SMB2_NTLMV2_SESSKEY_SIZE];
struct hmac_md5_ctx ctx;
int rc;
@@ -164,12 +165,21 @@ int ksmbd_auth_ntlmv2(struct ksmbd_conn *conn, struct ksmbd_session *sess,
/* Generate the session key */
hmac_md5_usingrawkey(ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE,
ntlmv2_rsp, CIFS_HMAC_MD5_HASH_SIZE,
- sess->sess_key);
+ sess_key);
if (crypto_memneq(ntlmv2->ntlmv2_hash, ntlmv2_rsp,
- CIFS_HMAC_MD5_HASH_SIZE))
- return -EINVAL;
- return 0;
+ CIFS_HMAC_MD5_HASH_SIZE)) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ memcpy(sess->sess_key, sess_key, sizeof(sess_key));
+ rc = 0;
+out:
+ memzero_explicit(ntlmv2_hash, sizeof(ntlmv2_hash));
+ memzero_explicit(ntlmv2_rsp, sizeof(ntlmv2_rsp));
+ memzero_explicit(sess_key, sizeof(sess_key));
+ return rc;
}
/**
@@ -226,6 +236,8 @@ int ksmbd_decode_ntlmssp_auth_blob(struct authenticate_message *authblob,
nt_len - CIFS_ENCPWD_SIZE,
domain_name, conn->ntlmssp.cryptkey);
kfree(domain_name);
+ if (ret)
+ return ret;
/* The recovered secondary session key */
if (conn->ntlmssp.client_flags & NTLMSSP_NEGOTIATE_KEY_XCH) {
diff --git a/fs/smb/server/ksmbd_work.c b/fs/smb/server/ksmbd_work.c
index a5ab6799a65c..e2c2f45264be 100644
--- a/fs/smb/server/ksmbd_work.c
+++ b/fs/smb/server/ksmbd_work.c
@@ -16,6 +16,36 @@
static struct kmem_cache *work_cache;
static struct workqueue_struct *ksmbd_wq;
+static int ksmbd_reserve_iov(struct ksmbd_work *work, int need_iov_cnt)
+{
+ struct kvec *new;
+ int new_alloc_cnt = work->iov_alloc_cnt;
+
+ if (work->iov_alloc_cnt >= work->iov_cnt + need_iov_cnt)
+ return 0;
+
+ do {
+ new_alloc_cnt += KSMBD_WORK_INLINE_IOVS;
+ } while (new_alloc_cnt < work->iov_cnt + need_iov_cnt);
+
+ if (work->iov == work->iov_inline) {
+ new = kcalloc(new_alloc_cnt, sizeof(*new), KSMBD_DEFAULT_GFP);
+ if (!new)
+ return -ENOMEM;
+
+ memcpy(new, work->iov_inline, sizeof(work->iov_inline));
+ } else {
+ new = krealloc(work->iov, sizeof(*new) * new_alloc_cnt,
+ KSMBD_DEFAULT_GFP | __GFP_ZERO);
+ if (!new)
+ return -ENOMEM;
+ }
+
+ work->iov = new;
+ work->iov_alloc_cnt = new_alloc_cnt;
+ return 0;
+}
+
struct ksmbd_work *ksmbd_alloc_work_struct(void)
{
struct ksmbd_work *work = kmem_cache_zalloc(work_cache, KSMBD_DEFAULT_GFP);
@@ -27,13 +57,8 @@ struct ksmbd_work *ksmbd_alloc_work_struct(void)
INIT_LIST_HEAD(&work->async_request_entry);
INIT_LIST_HEAD(&work->fp_entry);
INIT_LIST_HEAD(&work->aux_read_list);
- work->iov_alloc_cnt = 4;
- work->iov = kzalloc_objs(struct kvec, work->iov_alloc_cnt,
- KSMBD_DEFAULT_GFP);
- if (!work->iov) {
- kmem_cache_free(work_cache, work);
- work = NULL;
- }
+ work->iov_alloc_cnt = ARRAY_SIZE(work->iov_inline);
+ work->iov = work->iov_inline;
}
return work;
}
@@ -55,7 +80,8 @@ void ksmbd_free_work_struct(struct ksmbd_work *work)
kfree(work->tr_buf);
kvfree(work->compress_buf);
kvfree(work->request_buf);
- kfree(work->iov);
+ if (work->iov != work->iov_inline)
+ kfree(work->iov);
if (work->async_id)
ksmbd_release_id(&work->conn->async_ida, work->async_id);
@@ -117,19 +143,9 @@ static int __ksmbd_iov_pin_rsp(struct ksmbd_work *work, void *ib, int len,
return -ENOMEM;
}
- if (work->iov_alloc_cnt < work->iov_cnt + need_iov_cnt) {
- struct kvec *new;
-
- work->iov_alloc_cnt += 4;
- new = krealloc(work->iov,
- sizeof(struct kvec) * work->iov_alloc_cnt,
- KSMBD_DEFAULT_GFP | __GFP_ZERO);
- if (!new) {
- kfree(ar);
- work->iov_alloc_cnt -= 4;
- return -ENOMEM;
- }
- work->iov = new;
+ if (ksmbd_reserve_iov(work, need_iov_cnt)) {
+ kfree(ar);
+ return -ENOMEM;
}
/* Plus rfc_length size on first iov */
diff --git a/fs/smb/server/ksmbd_work.h b/fs/smb/server/ksmbd_work.h
index 0da8cc0972d6..df0554a2c50d 100644
--- a/fs/smb/server/ksmbd_work.h
+++ b/fs/smb/server/ksmbd_work.h
@@ -13,6 +13,8 @@ struct ksmbd_conn;
struct ksmbd_session;
struct ksmbd_tree_connect;
+#define KSMBD_WORK_INLINE_IOVS 4
+
enum {
KSMBD_WORK_ACTIVE = 0,
KSMBD_WORK_CANCELLED,
@@ -42,6 +44,7 @@ struct ksmbd_work {
int iov_alloc_cnt;
int iov_cnt;
int iov_idx;
+ struct kvec iov_inline[KSMBD_WORK_INLINE_IOVS];
/* Next cmd hdr in compound req buf*/
int next_smb2_rcv_hdr_off;
@@ -57,6 +60,7 @@ struct ksmbd_work {
u64 compound_fid;
u64 compound_pfid;
u64 compound_sid;
+ __le32 compound_status;
const struct cred *saved_cred;
diff --git a/fs/smb/server/misc.c b/fs/smb/server/misc.c
index 966004c414a8..2dd91c9e956a 100644
--- a/fs/smb/server/misc.c
+++ b/fs/smb/server/misc.c
@@ -121,7 +121,9 @@ int parse_stream_name(char *filename, char **stream_name, int *s_type)
char *stream_type;
char *s_name;
int rc = 0;
+ bool has_stream_type = false;
+ *stream_name = NULL;
s_name = filename;
filename = strsep(&s_name, ":");
ksmbd_debug(SMB, "filename : %s, streams : %s\n", filename, s_name);
@@ -137,14 +139,20 @@ int parse_stream_name(char *filename, char **stream_name, int *s_type)
ksmbd_debug(SMB, "stream name : %s, stream type : %s\n", s_name,
stream_type);
- if (!strncasecmp("$data", stream_type, 5))
+ if (!strncasecmp("$data", stream_type, 5)) {
*s_type = DATA_STREAM;
- else if (!strncasecmp("$index_allocation", stream_type, 17))
+ has_stream_type = true;
+ } else if (!strncasecmp("$index_allocation", stream_type, 17)) {
*s_type = DIR_STREAM;
- else
+ has_stream_type = true;
+ } else {
rc = -ENOENT;
+ }
}
+ if (has_stream_type && !s_name[0] && *s_type == DATA_STREAM)
+ goto out;
+
*stream_name = s_name;
out:
return rc;
diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
index 60e7e821c245..31dd9f3479b2 100644
--- a/fs/smb/server/oplock.c
+++ b/fs/smb/server/oplock.c
@@ -5,6 +5,7 @@
*/
#include <linux/moduleparam.h>
+#include <linux/err.h>
#include "glob.h"
#include "oplock.h"
@@ -19,6 +20,53 @@
static LIST_HEAD(lease_table_list);
static DEFINE_RWLOCK(lease_list_lock);
+#define SMB2_LEASE_STATE_MASK_LE (SMB2_LEASE_READ_CACHING_LE | \
+ SMB2_LEASE_HANDLE_CACHING_LE | \
+ SMB2_LEASE_WRITE_CACHING_LE)
+
+static bool lease_state_valid(__le32 state)
+{
+ return !(state & ~SMB2_LEASE_STATE_MASK_LE);
+}
+
+static __le32 lease_state_grantable(__le32 state)
+{
+ if (state == SMB2_LEASE_READ_CACHING_LE ||
+ state == (SMB2_LEASE_READ_CACHING_LE | SMB2_LEASE_HANDLE_CACHING_LE) ||
+ state == (SMB2_LEASE_READ_CACHING_LE | SMB2_LEASE_WRITE_CACHING_LE) ||
+ state == SMB2_LEASE_STATE_MASK_LE)
+ return state;
+
+ return 0;
+}
+
+static bool lease_v2_flags_valid(__le32 flags)
+{
+ return !(flags & ~SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE);
+}
+
+static bool lease_has_parent_key(struct lease *lease)
+{
+ return lease->flags & SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE;
+}
+
+static bool lease_break_in_progress(struct lease *lease)
+{
+ struct oplock_info *opinfo;
+ bool ret = false;
+
+ spin_lock(&lease->lock);
+ list_for_each_entry(opinfo, &lease->open_list, lease_entry) {
+ if (opinfo->op_state == OPLOCK_ACK_WAIT) {
+ ret = true;
+ break;
+ }
+ }
+ spin_unlock(&lease->lock);
+
+ return ret;
+}
+
/**
* alloc_opinfo() - allocate a new opinfo object for oplock info
* @work: smb work
@@ -45,6 +93,7 @@ static struct oplock_info *alloc_opinfo(struct ksmbd_work *work,
opinfo->fid = id;
opinfo->Tid = Tid;
INIT_LIST_HEAD(&opinfo->op_entry);
+ INIT_LIST_HEAD(&opinfo->lease_entry);
init_waitqueue_head(&opinfo->oplock_q);
init_waitqueue_head(&opinfo->oplock_brk);
atomic_set(&opinfo->refcount, 1);
@@ -53,31 +102,44 @@ static struct oplock_info *alloc_opinfo(struct ksmbd_work *work,
return opinfo;
}
-static void lease_add_list(struct oplock_info *opinfo)
+static void lease_get(struct lease *lease)
{
- struct lease_table *lb = opinfo->o_lease->l_lb;
+ atomic_inc(&lease->refcount);
+}
+static void lease_put(struct lease *lease)
+{
+ if (lease && atomic_dec_and_test(&lease->refcount))
+ kfree(lease);
+}
+
+static void lease_add_table(struct lease *lease, struct lease_table *lb)
+{
+ lease_get(lease);
+ lease->l_lb = lb;
spin_lock(&lb->lb_lock);
- list_add_rcu(&opinfo->lease_entry, &lb->lease_list);
+ list_add_rcu(&lease->l_entry, &lb->lease_list);
spin_unlock(&lb->lb_lock);
}
-static void lease_del_list(struct oplock_info *opinfo)
+static void lease_del_table(struct lease *lease)
{
- struct lease_table *lb = opinfo->o_lease->l_lb;
+ struct lease_table *lb = lease->l_lb;
if (!lb)
return;
spin_lock(&lb->lb_lock);
- if (list_empty(&opinfo->lease_entry)) {
+ if (list_empty(&lease->l_entry)) {
spin_unlock(&lb->lb_lock);
return;
}
- list_del_init(&opinfo->lease_entry);
- opinfo->o_lease->l_lb = NULL;
+ list_del_init(&lease->l_entry);
+ lease->l_lb = NULL;
spin_unlock(&lb->lb_lock);
+
+ lease_put(lease);
}
static struct lease_table *alloc_lease_table(struct oplock_info *opinfo)
@@ -90,18 +152,29 @@ static struct lease_table *alloc_lease_table(struct oplock_info *opinfo)
memcpy(lb->client_guid, opinfo->conn->ClientGUID,
SMB2_CLIENT_GUID_SIZE);
+ lb->conn = ksmbd_conn_get(opinfo->conn);
INIT_LIST_HEAD(&lb->lease_list);
spin_lock_init(&lb->lb_lock);
return lb;
}
-static int alloc_lease(struct oplock_info *opinfo, struct lease_ctx_info *lctx)
+static void free_lease_table(struct lease_table *lb)
+{
+ if (!lb)
+ return;
+
+ ksmbd_conn_put(lb->conn);
+ kfree(lb);
+}
+
+static struct lease *alloc_lease(struct lease_ctx_info *lctx,
+ struct ksmbd_inode *ci)
{
struct lease *lease;
lease = kmalloc_obj(struct lease, KSMBD_DEFAULT_GFP);
if (!lease)
- return -ENOMEM;
+ return NULL;
memcpy(lease->lease_key, lctx->lease_key, SMB2_LEASE_KEY_SIZE);
lease->state = lctx->req_state;
@@ -111,19 +184,50 @@ static int alloc_lease(struct oplock_info *opinfo, struct lease_ctx_info *lctx)
lease->is_dir = lctx->is_dir;
memcpy(lease->parent_lease_key, lctx->parent_lease_key, SMB2_LEASE_KEY_SIZE);
lease->version = lctx->version;
- lease->epoch = le16_to_cpu(lctx->epoch) + 1;
- INIT_LIST_HEAD(&opinfo->lease_entry);
- opinfo->o_lease = lease;
+ lease->epoch = lctx->version == 2 ? le16_to_cpu(lctx->epoch) + 1 : 0;
+ lease->ci = ci;
+ lease->reuse_epoch = false;
+ lease->l_lb = NULL;
+ INIT_LIST_HEAD(&lease->l_entry);
+ INIT_LIST_HEAD(&lease->open_list);
+ spin_lock_init(&lease->lock);
+ atomic_set(&lease->refcount, 1);
+
+ return lease;
+}
- return 0;
+static void lease_add_open(struct lease *lease, struct oplock_info *opinfo)
+{
+ spin_lock(&lease->lock);
+ list_add(&opinfo->lease_entry, &lease->open_list);
+ spin_unlock(&lease->lock);
}
-static void free_lease(struct oplock_info *opinfo)
+static void lease_del_open(struct oplock_info *opinfo)
{
- struct lease *lease;
+ struct lease *lease = opinfo->o_lease;
+ bool remove_table = false;
- lease = opinfo->o_lease;
- kfree(lease);
+ if (!lease)
+ return;
+
+ spin_lock(&lease->lock);
+ if (!list_empty(&opinfo->lease_entry)) {
+ list_del_init(&opinfo->lease_entry);
+ remove_table = list_empty(&lease->open_list);
+ }
+ spin_unlock(&lease->lock);
+
+ if (remove_table) {
+ write_lock(&lease_list_lock);
+ lease_del_table(lease);
+ write_unlock(&lease_list_lock);
+ }
+}
+
+static void free_lease(struct oplock_info *opinfo)
+{
+ lease_put(opinfo->o_lease);
}
static void __free_opinfo(struct oplock_info *opinfo)
@@ -146,6 +250,21 @@ static void free_opinfo(struct oplock_info *opinfo)
call_rcu(&opinfo->rcu, free_opinfo_rcu);
}
+void lease_update_oplock_levels(struct lease *lease)
+{
+ struct oplock_info *opinfo;
+ __u8 level;
+
+ if (!lease)
+ return;
+
+ level = smb2_map_lease_to_oplock(lease->state);
+ spin_lock(&lease->lock);
+ list_for_each_entry(opinfo, &lease->open_list, lease_entry)
+ opinfo->level = level;
+ spin_unlock(&lease->lock);
+}
+
struct oplock_info *opinfo_get(struct ksmbd_file *fp)
{
struct oplock_info *opinfo;
@@ -193,6 +312,18 @@ void opinfo_put(struct oplock_info *opinfo)
free_opinfo(opinfo);
}
+static bool ksmbd_inode_has_lease(struct ksmbd_inode *ci)
+{
+ struct oplock_info *opinfo = opinfo_get_list(ci);
+ bool is_lease;
+
+ if (!opinfo)
+ return false;
+ is_lease = opinfo->is_lease;
+ opinfo_put(opinfo);
+ return is_lease;
+}
+
static void opinfo_add(struct oplock_info *opinfo, struct ksmbd_file *fp)
{
struct ksmbd_inode *ci = fp->f_ci;
@@ -206,11 +337,9 @@ static void opinfo_del(struct oplock_info *opinfo)
{
struct ksmbd_inode *ci = opinfo->o_fp->f_ci;
- if (opinfo->is_lease) {
- write_lock(&lease_list_lock);
- lease_del_list(opinfo);
- write_unlock(&lease_list_lock);
- }
+ if (opinfo->is_lease)
+ lease_del_open(opinfo);
+
down_write(&ci->m_lock);
list_del(&opinfo->op_entry);
up_write(&ci->m_lock);
@@ -259,8 +388,10 @@ int opinfo_write_to_read(struct oplock_info *opinfo)
}
opinfo->level = SMB2_OPLOCK_LEVEL_II;
- if (opinfo->is_lease)
+ if (opinfo->is_lease) {
lease->state = lease->new_state;
+ lease_update_oplock_levels(lease);
+ }
return 0;
}
@@ -275,7 +406,7 @@ int opinfo_read_handle_to_read(struct oplock_info *opinfo)
struct lease *lease = opinfo->o_lease;
lease->state = lease->new_state;
- opinfo->level = SMB2_OPLOCK_LEVEL_II;
+ lease_update_oplock_levels(lease);
return 0;
}
@@ -297,8 +428,10 @@ int opinfo_write_to_none(struct oplock_info *opinfo)
return -EINVAL;
}
opinfo->level = SMB2_OPLOCK_LEVEL_NONE;
- if (opinfo->is_lease)
+ if (opinfo->is_lease) {
lease->state = lease->new_state;
+ lease_update_oplock_levels(lease);
+ }
return 0;
}
@@ -319,8 +452,10 @@ int opinfo_read_to_none(struct oplock_info *opinfo)
return -EINVAL;
}
opinfo->level = SMB2_OPLOCK_LEVEL_NONE;
- if (opinfo->is_lease)
+ if (opinfo->is_lease) {
lease->state = lease->new_state;
+ lease_update_oplock_levels(lease);
+ }
return 0;
}
@@ -341,10 +476,7 @@ int lease_read_to_write(struct oplock_info *opinfo)
lease->new_state = SMB2_LEASE_NONE_LE;
lease->state |= SMB2_LEASE_WRITE_CACHING_LE;
- if (lease->state & SMB2_LEASE_HANDLE_CACHING_LE)
- opinfo->level = SMB2_OPLOCK_LEVEL_BATCH;
- else
- opinfo->level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+ lease_update_oplock_levels(lease);
return 0;
}
@@ -366,15 +498,7 @@ static int lease_none_upgrade(struct oplock_info *opinfo, __le32 new_state)
lease->new_state = SMB2_LEASE_NONE_LE;
lease->state = new_state;
- if (lease->state & SMB2_LEASE_HANDLE_CACHING_LE)
- if (lease->state & SMB2_LEASE_WRITE_CACHING_LE)
- opinfo->level = SMB2_OPLOCK_LEVEL_BATCH;
- else
- opinfo->level = SMB2_OPLOCK_LEVEL_II;
- else if (lease->state & SMB2_LEASE_WRITE_CACHING_LE)
- opinfo->level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
- else if (lease->state & SMB2_LEASE_READ_CACHING_LE)
- opinfo->level = SMB2_OPLOCK_LEVEL_II;
+ lease_update_oplock_levels(lease);
return 0;
}
@@ -505,7 +629,7 @@ static inline int compare_guid_key(struct oplock_info *opinfo,
* Return: oplock(lease) object on success, otherwise NULL
*/
static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci,
- char *client_guid,
+ const char *client_guid,
struct lease_ctx_info *lctx)
{
int ret;
@@ -555,8 +679,11 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci,
if (lctx->req_state ==
(SMB2_LEASE_READ_CACHING_LE |
SMB2_LEASE_HANDLE_CACHING_LE)) {
- lease->epoch++;
- lease->state = lctx->req_state;
+ if (lease->state != lctx->req_state) {
+ lease->epoch++;
+ lease->state = lctx->req_state;
+ lease_update_oplock_levels(lease);
+ }
}
}
@@ -572,7 +699,7 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci,
return m_opinfo;
}
-static void wait_for_break_ack(struct oplock_info *opinfo)
+static bool wait_for_break_ack(struct oplock_info *opinfo)
{
int rc = 0;
@@ -583,11 +710,16 @@ static void wait_for_break_ack(struct oplock_info *opinfo)
/* is this a timeout ? */
if (!rc) {
- if (opinfo->is_lease)
+ if (opinfo->is_lease) {
opinfo->o_lease->state = SMB2_LEASE_NONE_LE;
+ lease_update_oplock_levels(opinfo->o_lease);
+ }
opinfo->level = SMB2_OPLOCK_LEVEL_NONE;
opinfo->op_state = OPLOCK_STATE_NONE;
+ return true;
}
+
+ return false;
}
static void wake_up_oplock_break(struct oplock_info *opinfo)
@@ -601,6 +733,9 @@ static void wake_up_oplock_break(struct oplock_info *opinfo)
static int oplock_break_pending(struct oplock_info *opinfo, int req_op_level)
{
while (test_and_set_bit(0, &opinfo->pending_break)) {
+ if (opinfo->is_lease)
+ opinfo->o_lease->reuse_epoch = true;
+
wait_on_bit(&opinfo->pending_break, 0, TASK_UNINTERRUPTIBLE);
/* Not immediately break to none. */
@@ -634,6 +769,17 @@ static int oplock_break_pending(struct oplock_info *opinfo, int req_op_level)
return 0;
}
+static bool lease_break_needed(struct oplock_info *opinfo, int req_op_level,
+ bool open_trunc)
+{
+ struct lease *lease = opinfo->o_lease;
+
+ if (open_trunc)
+ return lease->state != SMB2_LEASE_NONE_LE;
+
+ return opinfo->level > req_op_level;
+}
+
/**
* __smb2_oplock_break_noti() - send smb2 oplock break cmd from conn
* to client
@@ -723,7 +869,7 @@ static int smb2_oplock_break_noti(struct oplock_info *opinfo)
conn = READ_ONCE(opinfo->conn);
if (!conn)
- return 0;
+ return ksmbd_invalidate_durable_fd(opinfo->fid);
work = ksmbd_alloc_work_struct();
if (!work)
@@ -748,7 +894,8 @@ static int smb2_oplock_break_noti(struct oplock_info *opinfo)
INIT_WORK(&work->work, __smb2_oplock_break_noti);
ksmbd_queue_work(work);
- wait_for_break_ack(opinfo);
+ if (wait_for_break_ack(opinfo))
+ ret = ksmbd_invalidate_durable_fd(opinfo->fid);
} else {
__smb2_oplock_break_noti(&work->work);
if (opinfo->level == SMB2_OPLOCK_LEVEL_II)
@@ -820,19 +967,26 @@ out:
* smb2_lease_break_noti() - break lease when a new client request
* write lease
* @opinfo: contains lease state information
+ * @wait_ack: wait for lease break acknowledgment from the client
+ * @inc_epoch: increment the lease epoch before sending the break
*
* Return: 0 on success, otherwise error
*/
-static int smb2_lease_break_noti(struct oplock_info *opinfo)
+static int smb2_lease_break_noti(struct oplock_info *opinfo, bool wait_ack,
+ bool inc_epoch)
{
struct ksmbd_conn *conn;
struct ksmbd_work *work;
struct lease_break_info *br_info;
struct lease *lease = opinfo->o_lease;
+ int ret = 0;
conn = READ_ONCE(opinfo->conn);
+ if (lease->version == 2 && lease->l_lb && lease->l_lb->conn &&
+ !ksmbd_conn_releasing(lease->l_lb->conn))
+ conn = lease->l_lb->conn;
if (!conn)
- return 0;
+ return ksmbd_invalidate_durable_fd(opinfo->fid);
work = ksmbd_alloc_work_struct();
if (!work)
@@ -846,10 +1000,13 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo)
br_info->curr_state = lease->state;
br_info->new_state = lease->new_state;
- if (lease->version == 2)
- br_info->epoch = cpu_to_le16(++lease->epoch);
- else
+ if (lease->version == 2) {
+ if (inc_epoch)
+ lease->epoch++;
+ br_info->epoch = cpu_to_le16(lease->epoch);
+ } else {
br_info->epoch = 0;
+ }
memcpy(br_info->lease_key, lease->lease_key, SMB2_LEASE_KEY_SIZE);
work->request_buf = (char *)br_info;
@@ -860,15 +1017,18 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo)
if (opinfo->op_state == OPLOCK_ACK_WAIT) {
INIT_WORK(&work->work, __smb2_lease_break_noti);
ksmbd_queue_work(work);
- wait_for_break_ack(opinfo);
+ if (wait_ack) {
+ if (wait_for_break_ack(opinfo))
+ ret = ksmbd_invalidate_durable_fd(opinfo->fid);
+ }
} else {
__smb2_lease_break_noti(&work->work);
if (opinfo->o_lease->new_state == SMB2_LEASE_NONE_LE) {
- opinfo->level = SMB2_OPLOCK_LEVEL_NONE;
opinfo->o_lease->state = SMB2_LEASE_NONE_LE;
+ lease_update_oplock_levels(opinfo->o_lease);
}
}
- return 0;
+ return ret;
}
static void wait_lease_breaking(struct oplock_info *opinfo)
@@ -889,9 +1049,10 @@ static void wait_lease_breaking(struct oplock_info *opinfo)
}
static int oplock_break(struct oplock_info *brk_opinfo, int req_op_level,
- struct ksmbd_work *in_work)
+ struct ksmbd_work *in_work, bool share_break)
{
int err = 0;
+ bool sent_interim = false;
/* Need to break exclusive/batch oplock, write lease or overwrite_if */
ksmbd_debug(OPLOCK,
@@ -900,18 +1061,36 @@ static int oplock_break(struct oplock_info *brk_opinfo, int req_op_level,
if (brk_opinfo->is_lease) {
struct lease *lease = brk_opinfo->o_lease;
+ bool open_trunc = brk_opinfo->open_trunc;
+ bool was_pending = test_bit(0, &brk_opinfo->pending_break);
+ bool wait_ack;
+ bool inc_epoch = true;
+
+ if (in_work && was_pending) {
+ setup_async_work(in_work, NULL, NULL);
+ smb2_send_interim_resp(in_work, STATUS_PENDING);
+ release_async_work(in_work);
+ sent_interim = true;
+ }
- atomic_inc(&brk_opinfo->breaking_cnt);
err = oplock_break_pending(brk_opinfo, req_op_level);
if (err)
return err < 0 ? err : 0;
+ if (was_pending)
+ open_trunc = brk_opinfo->open_trunc;
- if (brk_opinfo->open_trunc) {
+again:
+ atomic_inc(&brk_opinfo->breaking_cnt);
+ if (open_trunc) {
/*
* Create overwrite break trigger the lease break to
* none.
*/
lease->new_state = SMB2_LEASE_NONE_LE;
+ } else if (share_break &&
+ lease->state & SMB2_LEASE_HANDLE_CACHING_LE) {
+ lease->new_state =
+ lease->state & ~SMB2_LEASE_HANDLE_CACHING_LE;
} else {
if (lease->state & SMB2_LEASE_WRITE_CACHING_LE) {
if (lease->state & SMB2_LEASE_HANDLE_CACHING_LE)
@@ -931,17 +1110,56 @@ static int oplock_break(struct oplock_info *brk_opinfo, int req_op_level,
}
}
+ if (in_work && !sent_interim) {
+ setup_async_work(in_work, NULL, NULL);
+ smb2_send_interim_resp(in_work, STATUS_PENDING);
+ release_async_work(in_work);
+ sent_interim = true;
+ }
+
if (lease->state & (SMB2_LEASE_WRITE_CACHING_LE |
SMB2_LEASE_HANDLE_CACHING_LE)) {
- if (in_work) {
- setup_async_work(in_work, NULL, NULL);
- smb2_send_interim_resp(in_work, STATUS_PENDING);
- release_async_work(in_work);
- }
-
brk_opinfo->op_state = OPLOCK_ACK_WAIT;
} else
atomic_dec(&brk_opinfo->breaking_cnt);
+
+ wait_ack = !(open_trunc &&
+ lease->state == (SMB2_LEASE_READ_CACHING_LE |
+ SMB2_LEASE_HANDLE_CACHING_LE));
+ if (lease->reuse_epoch) {
+ inc_epoch = false;
+ lease->reuse_epoch = false;
+ }
+ err = smb2_lease_break_noti(brk_opinfo, wait_ack, inc_epoch);
+ inc_epoch = false;
+
+ ksmbd_debug(OPLOCK, "oplock granted = %d\n", brk_opinfo->level);
+ if (brk_opinfo->op_state == OPLOCK_CLOSING)
+ err = -ENOENT;
+
+ if (wait_ack)
+ wait_lease_breaking(brk_opinfo);
+ /*
+ * A share-mode conflict break only drops the conflicting
+ * caching bit; the triggering open fails with a sharing
+ * violation, so keep it to a single break.
+ *
+ * Otherwise chain another break while the lease is still
+ * incompatible with this open (req_op_level), or while a
+ * truncating waiter that arrived during the break still needs
+ * the lease dropped to none. open_trunc snapshotted for this
+ * break stays cleared, so the next state is computed from the
+ * lease state and the cascade steps down (e.g. RH->R->none)
+ * instead of collapsing straight to none.
+ */
+ if (wait_ack && !err && !share_break &&
+ (lease_break_needed(brk_opinfo, req_op_level, open_trunc) ||
+ (brk_opinfo->open_trunc &&
+ lease->state != SMB2_LEASE_NONE_LE)))
+ goto again;
+
+ wake_up_oplock_break(brk_opinfo);
+ return err;
} else {
err = oplock_break_pending(brk_opinfo, req_op_level);
if (err)
@@ -952,25 +1170,20 @@ static int oplock_break(struct oplock_info *brk_opinfo, int req_op_level,
brk_opinfo->op_state = OPLOCK_ACK_WAIT;
}
- if (brk_opinfo->is_lease)
- err = smb2_lease_break_noti(brk_opinfo);
- else
- err = smb2_oplock_break_noti(brk_opinfo);
+ err = smb2_oplock_break_noti(brk_opinfo);
ksmbd_debug(OPLOCK, "oplock granted = %d\n", brk_opinfo->level);
if (brk_opinfo->op_state == OPLOCK_CLOSING)
- err = -ENOENT;
+ err = -EAGAIN;
wake_up_oplock_break(brk_opinfo);
- wait_lease_breaking(brk_opinfo);
-
return err;
}
void destroy_lease_table(struct ksmbd_conn *conn)
{
struct lease_table *lb, *lbtmp;
- struct oplock_info *opinfo;
+ struct lease *lease, *ltmp;
write_lock(&lease_list_lock);
if (list_empty(&lease_table_list)) {
@@ -982,25 +1195,18 @@ void destroy_lease_table(struct ksmbd_conn *conn)
if (conn && memcmp(lb->client_guid, conn->ClientGUID,
SMB2_CLIENT_GUID_SIZE))
continue;
-again:
- rcu_read_lock();
- list_for_each_entry_rcu(opinfo, &lb->lease_list,
- lease_entry) {
- rcu_read_unlock();
- lease_del_list(opinfo);
- goto again;
- }
- rcu_read_unlock();
+ list_for_each_entry_safe(lease, ltmp, &lb->lease_list, l_entry)
+ lease_del_table(lease);
list_del(&lb->l_entry);
- kfree(lb);
+ free_lease_table(lb);
}
write_unlock(&lease_list_lock);
}
-int find_same_lease_key(struct ksmbd_session *sess, struct ksmbd_inode *ci,
+int find_same_lease_key(struct ksmbd_conn *conn, struct ksmbd_inode *ci,
struct lease_ctx_info *lctx)
{
- struct oplock_info *opinfo;
+ struct lease *lease;
int err = 0;
struct lease_table *lb;
@@ -1014,7 +1220,7 @@ int find_same_lease_key(struct ksmbd_session *sess, struct ksmbd_inode *ci,
}
list_for_each_entry(lb, &lease_table_list, l_entry) {
- if (!memcmp(lb->client_guid, sess->ClientGUID,
+ if (!memcmp(lb->client_guid, conn->ClientGUID,
SMB2_CLIENT_GUID_SIZE))
goto found;
}
@@ -1023,67 +1229,40 @@ int find_same_lease_key(struct ksmbd_session *sess, struct ksmbd_inode *ci,
return 0;
found:
- rcu_read_lock();
- list_for_each_entry_rcu(opinfo, &lb->lease_list, lease_entry) {
- if (!atomic_inc_not_zero(&opinfo->refcount))
+ list_for_each_entry(lease, &lb->lease_list, l_entry) {
+ if (lease->ci == ci)
continue;
- rcu_read_unlock();
- if (opinfo->o_fp->f_ci == ci)
- goto op_next;
- err = compare_guid_key(opinfo, sess->ClientGUID,
- lctx->lease_key);
- if (err) {
+ if (!memcmp(lease->lease_key, lctx->lease_key,
+ SMB2_LEASE_KEY_SIZE)) {
err = -EINVAL;
ksmbd_debug(OPLOCK,
"found same lease key is already used in other files\n");
- opinfo_put(opinfo);
goto out;
}
-op_next:
- opinfo_put(opinfo);
- rcu_read_lock();
}
- rcu_read_unlock();
out:
read_unlock(&lease_list_lock);
return err;
}
-static void copy_lease(struct oplock_info *op1, struct oplock_info *op2)
-{
- struct lease *lease1 = op1->o_lease;
- struct lease *lease2 = op2->o_lease;
-
- op2->level = op1->level;
- lease2->state = lease1->state;
- memcpy(lease2->lease_key, lease1->lease_key,
- SMB2_LEASE_KEY_SIZE);
- lease2->duration = lease1->duration;
- lease2->flags = lease1->flags;
- lease2->epoch = lease1->epoch;
- lease2->version = lease1->version;
-}
-
-static void add_lease_global_list(struct oplock_info *opinfo,
+static void add_lease_global_list(struct lease *lease, struct ksmbd_conn *conn,
struct lease_table *new_lb)
{
struct lease_table *lb;
write_lock(&lease_list_lock);
list_for_each_entry(lb, &lease_table_list, l_entry) {
- if (!memcmp(lb->client_guid, opinfo->conn->ClientGUID,
+ if (!memcmp(lb->client_guid, conn->ClientGUID,
SMB2_CLIENT_GUID_SIZE)) {
- opinfo->o_lease->l_lb = lb;
- lease_add_list(opinfo);
+ lease_add_table(lease, lb);
write_unlock(&lease_list_lock);
- kfree(new_lb);
+ free_lease_table(new_lb);
return;
}
}
- opinfo->o_lease->l_lb = new_lb;
- lease_add_list(opinfo);
+ lease_add_table(lease, new_lb);
list_add(&new_lb->l_entry, &lease_table_list);
write_unlock(&lease_list_lock);
}
@@ -1135,7 +1314,7 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
continue;
}
- oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE, NULL);
+ oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE, NULL, false);
opinfo_put(opinfo);
}
}
@@ -1176,7 +1355,7 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp)
continue;
}
- oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE, NULL);
+ oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE, NULL, false);
opinfo_put(opinfo);
}
}
@@ -1201,19 +1380,21 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
struct ksmbd_file *fp, __u16 tid,
struct lease_ctx_info *lctx, int share_ret)
{
- struct ksmbd_session *sess = work->sess;
int err = 0;
+ int break_level = SMB2_OPLOCK_LEVEL_II;
struct oplock_info *opinfo = NULL, *prev_opinfo = NULL;
struct ksmbd_inode *ci = fp->f_ci;
struct lease_table *new_lb = NULL;
bool prev_op_has_lease;
+ bool prev_durable_open = false;
+ bool prev_durable_detached = false;
+ unsigned long long prev_fid = KSMBD_NO_FID;
+ bool new_lease = false;
__le32 prev_op_state = 0;
/* Only v2 leases handle the directory */
if (S_ISDIR(file_inode(fp->filp)->i_mode)) {
- if (!lctx || lctx->version != 2 ||
- (lctx->flags != SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE &&
- !lctx->epoch))
+ if (!lctx || lctx->version != 2)
return 0;
}
@@ -1222,20 +1403,35 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
return -ENOMEM;
if (lctx) {
- err = alloc_lease(opinfo, lctx);
- if (err)
+ opinfo->o_lease = alloc_lease(lctx, ci);
+ if (!opinfo->o_lease) {
+ err = -ENOMEM;
goto err_out;
+ }
opinfo->is_lease = 1;
+ new_lease = true;
}
/* ci does not have any oplock */
if (!opinfo_count(fp))
goto set_lev;
- /* grant none-oplock if second open is trunc */
- if (fp->attrib_only && fp->cdoption != FILE_OVERWRITE_IF_LE &&
+ /*
+ * A stat open that only requests metadata access must not break the
+ * existing caching state. READ_CONTROL (reading the security
+ * descriptor) does not conflict with a lease, but it does conflict
+ * with an oplock, so only treat a read-control-only open as a stat
+ * open when the existing holder is a lease.
+ */
+ if (fp->cdoption != FILE_OVERWRITE_IF_LE &&
fp->cdoption != FILE_OVERWRITE_LE &&
- fp->cdoption != FILE_SUPERSEDE_LE) {
+ fp->cdoption != FILE_SUPERSEDE_LE &&
+ (fp->attrib_only ||
+ (!(fp->daccess & ~(FILE_READ_ATTRIBUTES_LE |
+ FILE_WRITE_ATTRIBUTES_LE |
+ FILE_SYNCHRONIZE_LE |
+ FILE_READ_CONTROL_LE)) &&
+ ksmbd_inode_has_lease(ci)))) {
req_op_level = SMB2_OPLOCK_LEVEL_NONE;
goto set_lev;
}
@@ -1244,13 +1440,14 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
struct oplock_info *m_opinfo;
/* is lease already granted ? */
- m_opinfo = same_client_has_lease(ci, sess->ClientGUID,
+ m_opinfo = same_client_has_lease(ci, work->conn->ClientGUID,
lctx);
if (m_opinfo) {
- copy_lease(m_opinfo, opinfo);
- if (atomic_read(&m_opinfo->breaking_cnt))
- opinfo->o_lease->flags =
- SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE;
+ lease_put(opinfo->o_lease);
+ lease_get(m_opinfo->o_lease);
+ opinfo->o_lease = m_opinfo->o_lease;
+ opinfo->level = m_opinfo->level;
+ new_lease = false;
opinfo_put(m_opinfo);
goto out;
}
@@ -1264,7 +1461,6 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
prev_op_has_lease = prev_opinfo->is_lease;
if (prev_op_has_lease)
prev_op_state = prev_opinfo->o_lease->state;
-
if (share_ret < 0 &&
prev_opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
err = share_ret;
@@ -1278,10 +1474,32 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
goto op_break_not_needed;
}
- err = oplock_break(prev_opinfo, SMB2_OPLOCK_LEVEL_II, work);
+ if (prev_opinfo->o_fp && prev_opinfo->o_fp != fp &&
+ prev_opinfo->o_fp->is_durable) {
+ prev_durable_open = true;
+ prev_durable_detached = !prev_opinfo->o_fp->conn ||
+ !prev_opinfo->o_fp->tcon;
+ prev_fid = prev_opinfo->fid;
+ }
+
+ err = oplock_break(prev_opinfo, break_level, work,
+ share_ret < 0 && prev_opinfo->is_lease);
+ if (prev_durable_detached || (prev_durable_open && err == -ENOENT))
+ ksmbd_invalidate_durable_fd(prev_fid);
opinfo_put(prev_opinfo);
- if (err == -ENOENT)
+ if (err == -EAGAIN) {
+ share_ret = ksmbd_smb_check_shared_mode(fp->filp, fp);
+ if (share_ret < 0) {
+ err = share_ret;
+ goto err_out;
+ }
+ goto set_lev;
+ }
+ if (err == -ENOENT) {
+ if (req_op_level != SMB2_OPLOCK_LEVEL_NONE)
+ req_op_level = SMB2_OPLOCK_LEVEL_II;
goto set_lev;
+ }
/* Check all oplock was freed by close */
else if (err < 0)
goto err_out;
@@ -1310,17 +1528,13 @@ set_lev:
out:
/*
- * Set o_fp before any publication so that concurrent readers
- * (e.g. find_same_lease_key() on the lease list) that
- * dereference opinfo->o_fp don't hit a NULL pointer.
- *
* Keep the original publication order so concurrent opens can
* still observe the in-flight grant via ci->m_op_list, but make
* everything after opinfo_add() no-fail by preallocating any new
* lease_table first.
*/
opinfo->o_fp = fp;
- if (opinfo->is_lease) {
+ if (new_lease) {
new_lb = alloc_lease_table(opinfo);
if (!new_lb) {
err = -ENOMEM;
@@ -1331,8 +1545,10 @@ out:
opinfo_count_inc(fp);
opinfo_add(opinfo, fp);
+ if (new_lease)
+ add_lease_global_list(opinfo->o_lease, opinfo->conn, new_lb);
if (opinfo->is_lease)
- add_lease_global_list(opinfo, new_lb);
+ lease_add_open(opinfo->o_lease, opinfo);
rcu_assign_pointer(fp->f_opinfo, opinfo);
@@ -1349,38 +1565,46 @@ err_out:
* @fp: ksmbd file pointer
* @is_trunc: truncate on open
*/
-static void smb_break_all_write_oplock(struct ksmbd_work *work,
+static bool smb_break_all_write_oplock(struct ksmbd_work *work,
struct ksmbd_file *fp, int is_trunc)
{
struct oplock_info *brk_opinfo;
+ bool sent_break = false;
brk_opinfo = opinfo_get_list(fp->f_ci);
if (!brk_opinfo)
- return;
+ return false;
if (brk_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH &&
brk_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
opinfo_put(brk_opinfo);
- return;
+ return false;
}
brk_opinfo->open_trunc = is_trunc;
- oplock_break(brk_opinfo, SMB2_OPLOCK_LEVEL_II, work);
+ oplock_break(brk_opinfo, SMB2_OPLOCK_LEVEL_II, work, false);
+ sent_break = true;
opinfo_put(brk_opinfo);
+
+ return sent_break;
}
/**
- * smb_break_all_levII_oplock() - send level2 oplock or read lease break command
+ * __smb_break_all_levII_oplock() - send level2 oplock or read lease break command
* from server to client
- * @work: smb work
- * @fp: ksmbd file pointer
- * @is_trunc: truncate on open
+ * @work: smb work
+ * @fp: ksmbd file pointer
+ * @is_trunc: truncate on open
+ * @send_interim: send interim response to the client
+ * @send_oplock_break: send oplock break notification to the client
*/
-void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
- int is_trunc)
+static void __smb_break_all_levII_oplock(struct ksmbd_work *work,
+ struct ksmbd_file *fp, int is_trunc,
+ bool send_interim, bool send_oplock_break)
{
struct oplock_info *op, *brk_op;
struct ksmbd_inode *ci;
struct ksmbd_conn *conn = work->conn;
+ bool sent_interim = false;
if (!test_share_config_flag(work->tcon->share_conf,
KSMBD_SHARE_FLAG_OPLOCKS))
@@ -1402,14 +1626,8 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
continue;
}
- if (brk_op->is_lease && (brk_op->o_lease->state &
- (~(SMB2_LEASE_READ_CACHING_LE |
- SMB2_LEASE_HANDLE_CACHING_LE)))) {
- ksmbd_debug(OPLOCK, "unexpected lease state(0x%x)\n",
- brk_op->o_lease->state);
- goto next;
- } else if (brk_op->level !=
- SMB2_OPLOCK_LEVEL_II) {
+ if (!brk_op->is_lease &&
+ brk_op->level != SMB2_OPLOCK_LEVEL_II) {
ksmbd_debug(OPLOCK, "unexpected oplock(0x%x)\n",
brk_op->level);
goto next;
@@ -1428,7 +1646,17 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
SMB2_LEASE_KEY_SIZE))
goto next;
brk_op->open_trunc = is_trunc;
- oplock_break(brk_op, SMB2_OPLOCK_LEVEL_NONE, NULL);
+ if (!brk_op->is_lease && !send_oplock_break) {
+ brk_op->level = SMB2_OPLOCK_LEVEL_NONE;
+ brk_op->op_state = OPLOCK_STATE_NONE;
+ } else {
+ oplock_break(brk_op,
+ brk_op->is_lease && !is_trunc ?
+ SMB2_OPLOCK_LEVEL_II : SMB2_OPLOCK_LEVEL_NONE,
+ send_interim && !sent_interim ? work : NULL,
+ false);
+ }
+ sent_interim = true;
next:
opinfo_put(brk_op);
}
@@ -1438,6 +1666,24 @@ next:
opinfo_put(op);
}
+void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
+ int is_trunc)
+{
+ __smb_break_all_levII_oplock(work, fp, is_trunc, true, true);
+}
+
+void smb_break_all_levII_oplock_no_interim(struct ksmbd_work *work,
+ struct ksmbd_file *fp, int is_trunc)
+{
+ __smb_break_all_levII_oplock(work, fp, is_trunc, false, true);
+}
+
+void smb_break_all_levII_oplock_for_delete(struct ksmbd_work *work,
+ struct ksmbd_file *fp)
+{
+ __smb_break_all_levII_oplock(work, fp, 0, false, false);
+}
+
/**
* smb_break_all_oplock() - break both batch/exclusive and level2 oplock
* @work: smb work
@@ -1445,12 +1691,14 @@ next:
*/
void smb_break_all_oplock(struct ksmbd_work *work, struct ksmbd_file *fp)
{
+ bool sent_break;
+
if (!test_share_config_flag(work->tcon->share_conf,
KSMBD_SHARE_FLAG_OPLOCKS))
return;
- smb_break_all_write_oplock(work, fp, 1);
- smb_break_all_levII_oplock(work, fp, 1);
+ sent_break = smb_break_all_write_oplock(work, fp, 1);
+ __smb_break_all_levII_oplock(work, fp, 1, !sent_break, true);
}
/**
@@ -1461,15 +1709,13 @@ void smb_break_all_oplock(struct ksmbd_work *work, struct ksmbd_file *fp)
*/
__u8 smb2_map_lease_to_oplock(__le32 lease_state)
{
- if (lease_state == (SMB2_LEASE_HANDLE_CACHING_LE |
- SMB2_LEASE_READ_CACHING_LE |
- SMB2_LEASE_WRITE_CACHING_LE)) {
+ if ((lease_state & SMB2_LEASE_WRITE_CACHING_LE) &&
+ (lease_state & SMB2_LEASE_HANDLE_CACHING_LE)) {
return SMB2_OPLOCK_LEVEL_BATCH;
- } else if (lease_state != SMB2_LEASE_WRITE_CACHING_LE &&
- lease_state & SMB2_LEASE_WRITE_CACHING_LE) {
- if (!(lease_state & SMB2_LEASE_HANDLE_CACHING_LE))
- return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
- } else if (lease_state & SMB2_LEASE_READ_CACHING_LE) {
+ } else if (lease_state & SMB2_LEASE_WRITE_CACHING_LE) {
+ return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+ } else if (lease_state & (SMB2_LEASE_READ_CACHING_LE |
+ SMB2_LEASE_HANDLE_CACHING_LE)) {
return SMB2_OPLOCK_LEVEL_II;
}
return 0;
@@ -1484,14 +1730,19 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
{
if (lease->version == 2) {
struct create_lease_v2 *buf = (struct create_lease_v2 *)rbuf;
+ __le32 flags = 0;
memset(buf, 0, sizeof(struct create_lease_v2));
memcpy(buf->lcontext.LeaseKey, lease->lease_key,
SMB2_LEASE_KEY_SIZE);
- buf->lcontext.LeaseFlags = lease->flags;
+ if (lease_has_parent_key(lease))
+ flags |= SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE;
+ if (lease_break_in_progress(lease))
+ flags |= SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE;
+ buf->lcontext.LeaseFlags = flags;
buf->lcontext.Epoch = cpu_to_le16(lease->epoch);
buf->lcontext.LeaseState = lease->state;
- if (lease->flags == SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE)
+ if (lease_has_parent_key(lease))
memcpy(buf->lcontext.ParentLeaseKey, lease->parent_lease_key,
SMB2_LEASE_KEY_SIZE);
buf->ccontext.DataOffset = cpu_to_le16(offsetof
@@ -1509,7 +1760,9 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
memset(buf, 0, sizeof(struct create_lease));
memcpy(buf->lcontext.LeaseKey, lease->lease_key, SMB2_LEASE_KEY_SIZE);
- buf->lcontext.LeaseFlags = lease->flags;
+ if (lease_break_in_progress(lease))
+ buf->lcontext.LeaseFlags =
+ SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE;
buf->lcontext.LeaseState = lease->state;
buf->ccontext.DataOffset = cpu_to_le16(offsetof
(struct create_lease, lcontext));
@@ -1537,12 +1790,14 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
struct lease_ctx_info *lreq;
cc = smb2_find_context_vals(req, SMB2_CREATE_REQUEST_LEASE, 4);
- if (IS_ERR_OR_NULL(cc))
+ if (IS_ERR(cc))
+ return ERR_CAST(cc);
+ if (!cc)
return NULL;
lreq = kzalloc_obj(struct lease_ctx_info, KSMBD_DEFAULT_GFP);
if (!lreq)
- return NULL;
+ return ERR_PTR(-ENOMEM);
if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) {
struct create_lease_v2 *lc = (struct create_lease_v2 *)cc;
@@ -1556,11 +1811,15 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
lreq->flags = lc->lcontext.LeaseFlags;
lreq->epoch = lc->lcontext.Epoch;
lreq->duration = lc->lcontext.LeaseDuration;
+ if (!lease_state_valid(lreq->req_state) ||
+ !lease_v2_flags_valid(lreq->flags))
+ goto err_out;
+ lreq->req_state = lease_state_grantable(lreq->req_state);
if (lreq->flags == SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE)
memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey,
SMB2_LEASE_KEY_SIZE);
lreq->version = 2;
- } else {
+ } else if (sizeof(struct lease_context) == le32_to_cpu(cc->DataLength)) {
struct create_lease *lc = (struct create_lease *)cc;
if (le16_to_cpu(cc->DataOffset) + le32_to_cpu(cc->DataLength) <
@@ -1569,14 +1828,18 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
lreq->req_state = lc->lcontext.LeaseState;
- lreq->flags = lc->lcontext.LeaseFlags;
+ lreq->flags = 0;
lreq->duration = lc->lcontext.LeaseDuration;
+ if (!lease_state_valid(lreq->req_state))
+ goto err_out;
+ lreq->req_state = lease_state_grantable(lreq->req_state);
lreq->version = 1;
- }
+ } else
+ goto err_out;
return lreq;
err_out:
kfree(lreq);
- return NULL;
+ return ERR_PTR(-EINVAL);
}
/**
@@ -1601,6 +1864,9 @@ struct create_context *smb2_find_context_vals(void *open_req, const char *tag, i
* CreateContextsOffset and CreateContextsLength are guaranteed to
* be valid because of ksmbd_smb2_check_message().
*/
+ if (!req->CreateContextsOffset || !req->CreateContextsLength)
+ return NULL;
+
cc = (struct create_context *)((char *)req +
le32_to_cpu(req->CreateContextsOffset));
remain_len = le32_to_cpu(req->CreateContextsLength);
@@ -1810,8 +2076,8 @@ struct oplock_info *lookup_lease_in_table(struct ksmbd_conn *conn,
char *lease_key)
{
struct oplock_info *opinfo = NULL, *ret_op = NULL;
+ struct lease *lease;
struct lease_table *lt;
- int ret;
read_lock(&lease_list_lock);
list_for_each_entry(lt, &lease_table_list, l_entry) {
@@ -1824,29 +2090,30 @@ struct oplock_info *lookup_lease_in_table(struct ksmbd_conn *conn,
return NULL;
found:
- rcu_read_lock();
- list_for_each_entry_rcu(opinfo, &lt->lease_list, lease_entry) {
- if (!atomic_inc_not_zero(&opinfo->refcount))
+ list_for_each_entry(lease, &lt->lease_list, l_entry) {
+ if (memcmp(lease->lease_key, lease_key, SMB2_LEASE_KEY_SIZE))
continue;
- rcu_read_unlock();
- if (!opinfo->op_state || opinfo->op_state == OPLOCK_CLOSING)
- goto op_next;
- if (!(opinfo->o_lease->state &
- (SMB2_LEASE_HANDLE_CACHING_LE |
- SMB2_LEASE_WRITE_CACHING_LE)))
- goto op_next;
- ret = compare_guid_key(opinfo, conn->ClientGUID,
- lease_key);
- if (ret) {
- ksmbd_debug(OPLOCK, "found opinfo\n");
+ if (!(lease->state & (SMB2_LEASE_HANDLE_CACHING_LE |
+ SMB2_LEASE_WRITE_CACHING_LE)))
+ break;
+
+ spin_lock(&lease->lock);
+ list_for_each_entry(opinfo, &lease->open_list, lease_entry) {
+ if (!opinfo->op_state ||
+ opinfo->op_state == OPLOCK_CLOSING)
+ continue;
+ if (!atomic_inc_not_zero(&opinfo->refcount))
+ continue;
ret_op = opinfo;
+ break;
+ }
+ spin_unlock(&lease->lock);
+ if (ret_op) {
+ ksmbd_debug(OPLOCK, "found opinfo\n");
goto out;
}
-op_next:
- opinfo_put(opinfo);
- rcu_read_lock();
+ break;
}
- rcu_read_unlock();
out:
read_unlock(&lease_list_lock);
@@ -1866,6 +2133,12 @@ int smb2_check_durable_oplock(struct ksmbd_conn *conn,
if (!opinfo)
return 0;
+ if (ksmbd_has_other_active_fd(fp)) {
+ ksmbd_debug(SMB, "Durable handle reconnect failed: competing open\n");
+ ret = -EBADF;
+ goto out;
+ }
+
if (ksmbd_vfs_compare_durable_owner(fp, user) == false) {
ksmbd_debug(SMB, "Durable handle reconnect failed: owner mismatch\n");
ret = -EBADF;
diff --git a/fs/smb/server/oplock.h b/fs/smb/server/oplock.h
index d91a8266e065..3f581d22bb67 100644
--- a/fs/smb/server/oplock.h
+++ b/fs/smb/server/oplock.h
@@ -34,6 +34,7 @@ struct lease_ctx_info {
struct lease_table {
char client_guid[SMB2_CLIENT_GUID_SIZE];
+ struct ksmbd_conn *conn;
struct list_head lease_list;
struct list_head l_entry;
spinlock_t lb_lock;
@@ -49,7 +50,13 @@ struct lease {
int version;
unsigned short epoch;
bool is_dir;
+ bool reuse_epoch;
+ struct ksmbd_inode *ci;
struct lease_table *l_lb;
+ struct list_head l_entry;
+ struct list_head open_list;
+ spinlock_t lock;
+ atomic_t refcount;
};
struct oplock_info {
@@ -92,6 +99,10 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level,
struct lease_ctx_info *lctx, int share_ret);
void smb_break_all_levII_oplock(struct ksmbd_work *work,
struct ksmbd_file *fp, int is_trunc);
+void smb_break_all_levII_oplock_no_interim(struct ksmbd_work *work,
+ struct ksmbd_file *fp, int is_trunc);
+void smb_break_all_levII_oplock_for_delete(struct ksmbd_work *work,
+ struct ksmbd_file *fp);
int opinfo_write_to_read(struct oplock_info *opinfo);
int opinfo_read_handle_to_read(struct oplock_info *opinfo);
int opinfo_write_to_none(struct oplock_info *opinfo);
@@ -105,6 +116,7 @@ void opinfo_put(struct oplock_info *opinfo);
void create_lease_buf(u8 *rbuf, struct lease *lease);
struct lease_ctx_info *parse_lease_state(void *open_req);
__u8 smb2_map_lease_to_oplock(__le32 lease_state);
+void lease_update_oplock_levels(struct lease *lease);
int lease_read_to_write(struct oplock_info *opinfo);
/* Durable related functions */
@@ -116,7 +128,7 @@ void create_posix_rsp_buf(char *cc, struct ksmbd_file *fp);
struct create_context *smb2_find_context_vals(void *open_req, const char *tag, int tag_len);
struct oplock_info *lookup_lease_in_table(struct ksmbd_conn *conn,
char *lease_key);
-int find_same_lease_key(struct ksmbd_session *sess, struct ksmbd_inode *ci,
+int find_same_lease_key(struct ksmbd_conn *conn, struct ksmbd_inode *ci,
struct lease_ctx_info *lctx);
void destroy_lease_table(struct ksmbd_conn *conn);
void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index c1c6c1a64f60..5859fa68bb84 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -57,6 +57,10 @@ static void __wbuf(struct ksmbd_work *work, void **req, void **rsp)
#define WORK_BUFFERS(w, rq, rs) __wbuf((w), (void **)&(rq), (void **)&(rs))
+#define SMB2_CREATE_FILE_ATTRIBUTE_MASK \
+ (FILE_ATTRIBUTE_MASK & ~(FILE_ATTRIBUTE_INTEGRITY_STREAM | \
+ FILE_ATTRIBUTE_NO_SCRUB_DATA))
+
/**
* check_session_id() - check for valid session id in smb header
* @conn: connection instance
@@ -246,6 +250,13 @@ void set_smb2_rsp_status(struct ksmbd_work *work, __le32 err)
{
struct smb2_hdr *rsp_hdr;
+ if (work->next_smb2_rcv_hdr_off) {
+ rsp_hdr = ksmbd_resp_buf_next(work);
+ rsp_hdr->Status = err;
+ smb2_set_err_rsp(work);
+ return;
+ }
+
rsp_hdr = smb_get_msg(work->response_buf);
rsp_hdr->Status = err;
@@ -405,6 +416,59 @@ static void init_chained_smb2_rsp(struct ksmbd_work *work)
work->compound_fid = ((struct smb2_create_rsp *)rsp)->VolatileFileId;
work->compound_pfid = ((struct smb2_create_rsp *)rsp)->PersistentFileId;
work->compound_sid = le64_to_cpu(rsp->SessionId);
+ work->compound_status = STATUS_SUCCESS;
+ } else if ((req->Command == SMB2_FLUSH ||
+ req->Command == SMB2_READ ||
+ req->Command == SMB2_WRITE) &&
+ rsp->Status == STATUS_SUCCESS) {
+ u64 volatile_id = KSMBD_NO_FID;
+ u64 persistent_id = KSMBD_NO_FID;
+
+ if (req->Command == SMB2_FLUSH) {
+ struct smb2_flush_req *flush_req =
+ (struct smb2_flush_req *)req;
+
+ volatile_id = flush_req->VolatileFileId;
+ persistent_id = flush_req->PersistentFileId;
+ } else if (req->Command == SMB2_READ) {
+ struct smb2_read_req *read_req =
+ (struct smb2_read_req *)req;
+
+ volatile_id = read_req->VolatileFileId;
+ persistent_id = read_req->PersistentFileId;
+ } else {
+ struct smb2_write_req *write_req =
+ (struct smb2_write_req *)req;
+
+ volatile_id = write_req->VolatileFileId;
+ persistent_id = write_req->PersistentFileId;
+ }
+
+ if (has_file_id(volatile_id)) {
+ work->compound_fid = volatile_id;
+ work->compound_pfid = persistent_id;
+ work->compound_sid = le64_to_cpu(rsp->SessionId);
+ work->compound_status = STATUS_SUCCESS;
+ }
+ } else if (req->Command == SMB2_CREATE) {
+ work->compound_fid = KSMBD_NO_FID;
+ work->compound_pfid = KSMBD_NO_FID;
+ work->compound_sid = le64_to_cpu(rsp->SessionId);
+ work->compound_status = rsp->Status;
+ } else if (rsp->Status != STATUS_SUCCESS) {
+ work->compound_sid = le64_to_cpu(rsp->SessionId);
+ /*
+ * Only carry the failed status forward when the failing command
+ * was itself part of the related chain. An unrelated command
+ * that fails (e.g. a standalone request with a bad session id)
+ * must not seed the status for a following related command,
+ * which has to be evaluated on its own (and may legitimately
+ * fail with a different status such as INVALID_PARAMETER). The
+ * compound session id is still tracked so a following related
+ * command can validate it.
+ */
+ if (req->Flags & SMB2_FLAGS_RELATED_OPERATIONS)
+ work->compound_status = rsp->Status;
}
len = get_rfc1002_len(work->response_buf) - work->next_smb2_rsp_hdr_off;
@@ -430,6 +494,7 @@ static void init_chained_smb2_rsp(struct ksmbd_work *work)
ksmbd_debug(SMB, "related flag should be set\n");
work->compound_fid = KSMBD_NO_FID;
work->compound_pfid = KSMBD_NO_FID;
+ work->compound_status = STATUS_SUCCESS;
}
memset((char *)rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;
@@ -449,6 +514,19 @@ static void init_chained_smb2_rsp(struct ksmbd_work *work)
memcpy(rsp_hdr->Signature, rcv_hdr->Signature, 16);
}
+static bool smb2_compound_has_failed(struct ksmbd_work *work,
+ struct smb2_hdr *rsp)
+{
+ if (!work->next_smb2_rcv_hdr_off ||
+ has_file_id(work->compound_fid) ||
+ work->compound_status == STATUS_SUCCESS)
+ return false;
+
+ rsp->Status = work->compound_status;
+ smb2_set_err_rsp(work);
+ return true;
+}
+
/**
* is_chained_smb2_message() - check for chained command
* @work: smb work containing smb request buffer
@@ -1016,6 +1094,7 @@ static __le32 decode_compress_ctxt(struct ksmbd_conn *conn,
int ctxt_len)
{
int alg_cnt, algs_size, i;
+ __le16 *algs;
if (sizeof(struct smb2_neg_context) + 10 > ctxt_len) {
pr_err("Invalid SMB2_COMPRESSION_CAPABILITIES context length\n");
@@ -1040,8 +1119,15 @@ static __le32 decode_compress_ctxt(struct ksmbd_conn *conn,
return STATUS_INVALID_PARAMETER;
}
+ /*
+ * CompressionAlgorithms[] is declared as a fixed 4-element array, but
+ * the actual element count is variable (clients such as Windows may
+ * advertise more). The on-wire length was validated above, so walk the
+ * algorithms through a pointer to avoid a fixed-array bounds check.
+ */
+ algs = pneg_ctxt->CompressionAlgorithms;
for (i = 0; i < alg_cnt; i++) {
- __le16 alg = pneg_ctxt->CompressionAlgorithms[i];
+ __le16 alg = algs[i];
/*
* LZ77 is the required general-purpose codec. Pattern_V1 is an
@@ -2807,8 +2893,10 @@ struct durable_info {
unsigned short int type;
bool persistent;
bool reconnected;
+ bool app_instance_id;
unsigned int timeout;
char *CreateGuid;
+ char AppInstanceId[SMB2_CREATE_GUID_SIZE];
};
static int parse_durable_handle_context(struct ksmbd_work *work,
@@ -2845,9 +2933,8 @@ static int parse_durable_handle_context(struct ksmbd_work *work,
goto out;
}
- if (le16_to_cpu(context->DataOffset) +
- le32_to_cpu(context->DataLength) <
- sizeof(struct create_durable_handle_reconnect_v2)) {
+ if (le32_to_cpu(context->DataLength) <
+ sizeof(recon_v2->dcontext)) {
err = -EINVAL;
goto out;
}
@@ -2861,6 +2948,13 @@ static int parse_durable_handle_context(struct ksmbd_work *work,
goto out;
}
+ if (dh_info->fp->durable_volatile_id !=
+ recon_v2->dcontext.Fid.VolatileFileId) {
+ err = -EBADF;
+ ksmbd_put_durable_fd(dh_info->fp);
+ goto out;
+ }
+
if (memcmp(dh_info->fp->create_guid, recon_v2->dcontext.CreateGuid,
SMB2_CREATE_GUID_SIZE)) {
err = -EBADF;
@@ -2885,9 +2979,8 @@ static int parse_durable_handle_context(struct ksmbd_work *work,
goto out;
}
- if (le16_to_cpu(context->DataOffset) +
- le32_to_cpu(context->DataLength) <
- sizeof(create_durable_reconn_t)) {
+ if (le32_to_cpu(context->DataLength) <
+ sizeof(recon->Data)) {
err = -EINVAL;
goto out;
}
@@ -2901,6 +2994,13 @@ static int parse_durable_handle_context(struct ksmbd_work *work,
goto out;
}
+ if (dh_info->fp->durable_volatile_id !=
+ recon->Data.Fid.VolatileFileId) {
+ err = -EBADF;
+ ksmbd_put_durable_fd(dh_info->fp);
+ goto out;
+ }
+
dh_info->type = dh_idx;
dh_info->reconnected = true;
ksmbd_debug(SMB, "reconnect Persistent-id from reconnect = %llu\n",
@@ -2917,9 +3017,8 @@ static int parse_durable_handle_context(struct ksmbd_work *work,
goto out;
}
- if (le16_to_cpu(context->DataOffset) +
- le32_to_cpu(context->DataLength) <
- sizeof(struct create_durable_req_v2)) {
+ if (le32_to_cpu(context->DataLength) <
+ sizeof(durable_v2_blob->dcontext)) {
err = -EINVAL;
goto out;
}
@@ -2982,6 +3081,31 @@ out:
return err;
}
+static int parse_app_instance_id(struct smb2_create_req *req,
+ struct durable_info *dh_info)
+{
+ struct create_context *context;
+ char *data;
+
+ context = smb2_find_context_vals(req, SMB2_CREATE_APP_INSTANCE_ID,
+ SMB2_CREATE_GUID_SIZE);
+ if (IS_ERR(context))
+ return PTR_ERR(context);
+ if (!context)
+ return 0;
+
+ if (le32_to_cpu(context->DataLength) < 20)
+ return -EINVAL;
+
+ data = (char *)context + le16_to_cpu(context->DataOffset);
+ if (data[0] != 20 || data[1])
+ return -EINVAL;
+
+ memcpy(dh_info->AppInstanceId, data + 4, SMB2_CREATE_GUID_SIZE);
+ dh_info->app_instance_id = true;
+ return 0;
+}
+
/**
* smb2_open() - handler for smb file open request
* @work: smb work containing request buffer
@@ -3017,7 +3141,7 @@ int smb2_open(struct ksmbd_work *work)
char *stream_name = NULL;
bool file_present = false, created = false, already_permitted = false;
int share_ret, need_truncate = 0;
- u64 time;
+ u64 time, alloc_size = 0;
umode_t posix_mode = 0;
__le32 daccess, maximal_access = 0;
int iov_len = 0;
@@ -3108,11 +3232,25 @@ int smb2_open(struct ksmbd_work *work)
if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE &&
req->CreateContextsOffset) {
lc = parse_lease_state(req);
+ if (IS_ERR(lc)) {
+ rc = PTR_ERR(lc);
+ lc = NULL;
+ goto err_out2;
+ }
+ if (lc && lc->version == 2 && conn->dialect < SMB30_PROT_ID) {
+ kfree(lc);
+ lc = NULL;
+ if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE)
+ req_op_level = SMB2_OPLOCK_LEVEL_NONE;
+ }
rc = parse_durable_handle_context(work, req, lc, &dh_info);
if (rc) {
ksmbd_debug(SMB, "error parsing durable handle context\n");
goto err_out2;
}
+ rc = parse_app_instance_id(req, &dh_info);
+ if (rc)
+ goto err_out2;
if (dh_info.reconnected == true) {
rc = smb2_check_durable_oplock(conn, share, dh_info.fp,
@@ -3139,8 +3277,22 @@ int smb2_open(struct ksmbd_work *work)
goto reconnected_fp;
}
- } else if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE)
+
+ if (dh_info.type == DURABLE_REQ_V2 && dh_info.app_instance_id)
+ ksmbd_close_fd_app_instance_id(dh_info.AppInstanceId);
+ } else if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) {
lc = parse_lease_state(req);
+ if (IS_ERR(lc)) {
+ rc = PTR_ERR(lc);
+ lc = NULL;
+ goto err_out2;
+ }
+ if (lc && lc->version == 2 && conn->dialect < SMB30_PROT_ID) {
+ kfree(lc);
+ lc = NULL;
+ req_op_level = SMB2_OPLOCK_LEVEL_NONE;
+ }
+ }
if (le32_to_cpu(req->ImpersonationLevel) > le32_to_cpu(IL_DELEGATE)) {
pr_err("Invalid impersonationlevel : 0x%x\n",
@@ -3192,7 +3344,15 @@ int smb2_open(struct ksmbd_work *work)
goto err_out2;
}
- if (req->FileAttributes && !(req->FileAttributes & FILE_ATTRIBUTE_MASK_LE)) {
+ if (req->DesiredAccess == FILE_SYNCHRONIZE_LE &&
+ req->CreateDisposition == FILE_OPEN_IF_LE &&
+ !req->FileAttributes) {
+ rc = -EACCES;
+ goto err_out2;
+ }
+
+ if (req->FileAttributes &&
+ (req->FileAttributes & ~cpu_to_le32(SMB2_CREATE_FILE_ATTRIBUTE_MASK))) {
pr_err("Invalid file attribute : 0x%x\n",
le32_to_cpu(req->FileAttributes));
rc = -EINVAL;
@@ -3250,6 +3410,23 @@ int smb2_open(struct ksmbd_work *work)
rc = ksmbd_vfs_kern_path(work, name, LOOKUP_NO_SYMLINKS,
&path, 1);
+
+ /*
+ * A durable handle opened with delete-on-close is preserved across a
+ * disconnect so it can be reclaimed by a durable reconnect. When a new
+ * delete-on-close open for the same name arrives instead, the
+ * disconnected handle must give way: close it so its delete-on-close
+ * removes the file, then re-resolve so this open can create a fresh one.
+ */
+ if (!rc && (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE) &&
+ (req->CreateDisposition == FILE_OVERWRITE_IF_LE ||
+ req->CreateDisposition == FILE_OPEN_IF_LE) &&
+ ksmbd_close_disconnected_durable_delete_on_close(path.dentry)) {
+ path_put(&path);
+ rc = ksmbd_vfs_kern_path(work, name, LOOKUP_NO_SYMLINKS,
+ &path, 1);
+ }
+
if (!rc) {
file_present = true;
@@ -3284,7 +3461,14 @@ int smb2_open(struct ksmbd_work *work)
rc = 0;
}
- if (stream_name) {
+ /*
+ * An explicit ::$DATA suffix names the unnamed data stream and is
+ * canonicalized to a NULL stream name (base file), but the request
+ * still has to be validated against the data-stream type, e.g. opening
+ * <dir>::$DATA with FILE_DIRECTORY_FILE must fail with
+ * STATUS_NOT_A_DIRECTORY.
+ */
+ if (stream_name || s_type == DATA_STREAM) {
if (req->CreateOptions & FILE_DIRECTORY_FILE_LE) {
if (s_type == DATA_STREAM) {
rc = -EIO;
@@ -3482,14 +3666,16 @@ int smb2_open(struct ksmbd_work *work)
if (posix_acl_rc)
ksmbd_debug(SMB, "inherit posix acl failed : %d\n", posix_acl_rc);
- if (test_share_config_flag(work->tcon->share_conf,
- KSMBD_SHARE_FLAG_ACL_XATTR)) {
- rc = smb_inherit_dacl(conn, &path, sess->user->uid,
- sess->user->gid);
- }
+ rc = smb2_create_sd_buffer(work, req, &path);
+ if (rc && rc != -ENOENT)
+ goto err_out;
- if (rc) {
- rc = smb2_create_sd_buffer(work, req, &path);
+ if (rc == -ENOENT) {
+ if (test_share_config_flag(work->tcon->share_conf,
+ KSMBD_SHARE_FLAG_ACL_XATTR)) {
+ rc = smb_inherit_dacl(conn, &path, sess->user->uid,
+ sess->user->gid);
+ }
if (rc) {
if (posix_acl_rc)
ksmbd_vfs_set_init_posix_acl(idmap,
@@ -3580,6 +3766,12 @@ int smb2_open(struct ksmbd_work *work)
goto err_out;
}
+ if (!stream_name && daccess & FILE_DELETE_LE &&
+ ksmbd_has_stream_without_delete_share(fp)) {
+ rc = -EPERM;
+ goto err_out;
+ }
+
if (file_present || created)
path_put(&path);
@@ -3615,7 +3807,7 @@ int smb2_open(struct ksmbd_work *work)
ksmbd_debug(SMB,
"lease req for(%s) req oplock state 0x%x, lease state 0x%x\n",
name, req_op_level, lc->req_state);
- rc = find_same_lease_key(sess, fp->f_ci, lc);
+ rc = find_same_lease_key(conn, fp->f_ci, lc);
if (rc)
goto err_out1;
} else if (open_flags == O_RDONLY &&
@@ -3631,8 +3823,10 @@ int smb2_open(struct ksmbd_work *work)
goto err_out1;
}
- if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)
+ if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE) {
+ smb_break_all_levII_oplock_for_delete(work, fp);
ksmbd_fd_set_delete_on_close(fp, file_info);
+ }
if (need_truncate) {
rc = smb2_create_truncate(&fp->filp->f_path);
@@ -3649,7 +3843,6 @@ int smb2_open(struct ksmbd_work *work)
rc = PTR_ERR(az_req);
goto err_out1;
} else if (az_req) {
- loff_t alloc_size;
int err;
if (le16_to_cpu(az_req->ccontext.DataOffset) +
@@ -3698,6 +3891,9 @@ int smb2_open(struct ksmbd_work *work)
fp->create_time = ksmbd_UnixTimeToNT(stat.btime);
else
fp->create_time = ksmbd_UnixTimeToNT(stat.ctime);
+ fp->change_time = ksmbd_UnixTimeToNT(stat.ctime);
+ fp->allocation_size = S_ISDIR(stat.mode) ? 0 :
+ (alloc_size ?: stat.blocks << 9);
if (req->FileAttributes || fp->f_ci->m_fattr == 0)
fp->f_ci->m_fattr =
cpu_to_le32(smb2_get_dos_mode(&stat, le32_to_cpu(req->FileAttributes)));
@@ -3723,6 +3919,10 @@ int smb2_open(struct ksmbd_work *work)
if (dh_info.type == DURABLE_REQ_V2) {
memcpy(fp->create_guid, dh_info.CreateGuid,
SMB2_CREATE_GUID_SIZE);
+ if (dh_info.app_instance_id)
+ memcpy(fp->app_instance_id,
+ dh_info.AppInstanceId,
+ SMB2_CREATE_GUID_SIZE);
if (dh_info.timeout)
fp->durable_timeout =
min_t(unsigned int, dh_info.timeout,
@@ -3743,10 +3943,20 @@ reconnected_fp:
rsp->LastAccessTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.mtime);
rsp->LastWriteTime = cpu_to_le64(time);
- time = ksmbd_UnixTimeToNT(stat.ctime);
- rsp->ChangeTime = cpu_to_le64(time);
- rsp->AllocationSize = S_ISDIR(stat.mode) ? 0 :
- cpu_to_le64(stat.blocks << 9);
+ rsp->ChangeTime = cpu_to_le64(fp->change_time);
+ /*
+ * The cached allocation size hides filesystem rounding for the
+ * requested allocation, but it can go stale when the file grows past
+ * it via writes (e.g. across a durable reconnect). Refresh it once the
+ * file exceeds the cached value, rounding the end of file up to the
+ * volume allocation unit (the filesystem block size, matching the
+ * SectorsPerAllocationUnit/BytesPerSector ksmbd advertises) rather than
+ * using the raw on-disk block count, which can include filesystem
+ * preallocation and metadata rounding.
+ */
+ if (!S_ISDIR(stat.mode) && stat.size > fp->allocation_size)
+ fp->allocation_size = round_up(stat.size, stat.blksize);
+ rsp->AllocationSize = cpu_to_le64(fp->allocation_size);
rsp->EndofFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
rsp->FileAttributes = fp->f_ci->m_fattr;
@@ -4519,11 +4729,28 @@ int smb2_query_dir(struct ksmbd_work *work)
unsigned char srch_flag;
int buffer_sz;
struct smb2_query_dir_private query_dir_private = {NULL, };
+ unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
ksmbd_debug(SMB, "Received smb2 query directory request\n");
WORK_BUFFERS(work, req, rsp);
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
+
+ if (work->next_smb2_rcv_hdr_off &&
+ !has_file_id(req->VolatileFileId)) {
+ ksmbd_debug(SMB, "Compound request set FID = %llu\n",
+ work->compound_fid);
+ id = work->compound_fid;
+ pid = work->compound_pfid;
+ }
+
+ if (!has_file_id(id)) {
+ id = req->VolatileFileId;
+ pid = req->PersistentFileId;
+ }
+
if (ksmbd_override_fsids(work)) {
rsp->hdr.Status = STATUS_NO_MEMORY;
smb2_set_err_rsp(work);
@@ -4536,7 +4763,7 @@ int smb2_query_dir(struct ksmbd_work *work)
goto err_out2;
}
- dir_fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId);
+ dir_fp = ksmbd_lookup_fd_slow(work, id, pid);
if (!dir_fp) {
rc = -EBADF;
goto err_out2;
@@ -5013,8 +5240,7 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp,
basic_info->LastAccessTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.mtime);
basic_info->LastWriteTime = cpu_to_le64(time);
- time = ksmbd_UnixTimeToNT(stat.ctime);
- basic_info->ChangeTime = cpu_to_le64(time);
+ basic_info->ChangeTime = cpu_to_le64(fp->change_time);
basic_info->Attributes = fp->f_ci->m_fattr;
basic_info->Pad = 0;
rsp->OutputBufferLength =
@@ -5039,7 +5265,7 @@ static int get_file_standard_info(struct smb2_query_info_rsp *rsp,
delete_pending = ksmbd_inode_pending_delete(fp);
if (ksmbd_stream_fd(fp) == false) {
- sinfo->AllocationSize = cpu_to_le64(stat.blocks << 9);
+ sinfo->AllocationSize = cpu_to_le64(fp->allocation_size);
sinfo->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
} else {
sinfo->AllocationSize = cpu_to_le64(fp->stream.size);
@@ -5116,13 +5342,11 @@ static int get_file_all_info(struct ksmbd_work *work,
file_info->LastAccessTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.mtime);
file_info->LastWriteTime = cpu_to_le64(time);
- time = ksmbd_UnixTimeToNT(stat.ctime);
- file_info->ChangeTime = cpu_to_le64(time);
+ file_info->ChangeTime = cpu_to_le64(fp->change_time);
file_info->Attributes = fp->f_ci->m_fattr;
file_info->Pad1 = 0;
if (ksmbd_stream_fd(fp) == false) {
- file_info->AllocationSize =
- cpu_to_le64(stat.blocks << 9);
+ file_info->AllocationSize = cpu_to_le64(fp->allocation_size);
file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
} else {
file_info->AllocationSize = cpu_to_le64(fp->stream.size);
@@ -5326,11 +5550,10 @@ static int get_file_network_open_info(struct smb2_query_info_rsp *rsp,
file_info->LastAccessTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.mtime);
file_info->LastWriteTime = cpu_to_le64(time);
- time = ksmbd_UnixTimeToNT(stat.ctime);
- file_info->ChangeTime = cpu_to_le64(time);
+ file_info->ChangeTime = cpu_to_le64(fp->change_time);
file_info->Attributes = fp->f_ci->m_fattr;
if (ksmbd_stream_fd(fp) == false) {
- file_info->AllocationSize = cpu_to_le64(stat.blocks << 9);
+ file_info->AllocationSize = cpu_to_le64(fp->allocation_size);
file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
} else {
file_info->AllocationSize = cpu_to_le64(fp->stream.size);
@@ -5458,13 +5681,12 @@ static int find_file_posix_info(struct smb2_query_info_rsp *rsp,
file_info->LastAccessTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.mtime);
file_info->LastWriteTime = cpu_to_le64(time);
- time = ksmbd_UnixTimeToNT(stat.ctime);
- file_info->ChangeTime = cpu_to_le64(time);
+ file_info->ChangeTime = cpu_to_le64(fp->change_time);
file_info->DosAttributes = fp->f_ci->m_fattr;
file_info->Inode = cpu_to_le64(stat.ino);
if (ksmbd_stream_fd(fp) == false) {
file_info->EndOfFile = cpu_to_le64(stat.size);
- file_info->AllocationSize = cpu_to_le64(stat.blocks << 9);
+ file_info->AllocationSize = cpu_to_le64(fp->allocation_size);
} else {
file_info->EndOfFile = cpu_to_le64(fp->stream.size);
file_info->AllocationSize = cpu_to_le64(fp->stream.size);
@@ -6003,6 +6225,9 @@ int smb2_query_info(struct ksmbd_work *work)
WORK_BUFFERS(work, req, rsp);
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
+
if (ksmbd_override_fsids(work)) {
rc = -ENOMEM;
goto err_out;
@@ -6107,6 +6332,9 @@ int smb2_close(struct ksmbd_work *work)
WORK_BUFFERS(work, req, rsp);
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
+
if (test_share_config_flag(work->tcon->share_conf,
KSMBD_SHARE_FLAG_PIPE)) {
ksmbd_debug(SMB, "IPC pipe close request\n");
@@ -6173,8 +6401,7 @@ int smb2_close(struct ksmbd_work *work)
}
rsp->Flags = SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB;
- rsp->AllocationSize = S_ISDIR(stat.mode) ? 0 :
- cpu_to_le64(stat.blocks << 9);
+ rsp->AllocationSize = cpu_to_le64(fp->allocation_size);
rsp->EndOfFile = cpu_to_le64(stat.size);
rsp->Attributes = fp->f_ci->m_fattr;
rsp->CreationTime = cpu_to_le64(fp->create_time);
@@ -6182,8 +6409,7 @@ int smb2_close(struct ksmbd_work *work)
rsp->LastAccessTime = cpu_to_le64(time);
time = ksmbd_UnixTimeToNT(stat.mtime);
rsp->LastWriteTime = cpu_to_le64(time);
- time = ksmbd_UnixTimeToNT(stat.ctime);
- rsp->ChangeTime = cpu_to_le64(time);
+ rsp->ChangeTime = cpu_to_le64(fp->change_time);
ksmbd_fd_put(work, fp);
} else {
rsp->Flags = 0;
@@ -6396,9 +6622,11 @@ static int set_file_basic_info(struct ksmbd_file *fp,
attrs.ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET);
}
- if (file_info->ChangeTime)
+ if (file_info->ChangeTime) {
+ fp->change_time = le64_to_cpu(file_info->ChangeTime);
inode_set_ctime_to_ts(inode,
ksmbd_NTtimeToUnix(file_info->ChangeTime));
+ }
if (file_info->LastWriteTime) {
attrs.ia_mtime = ksmbd_NTtimeToUnix(file_info->LastWriteTime);
@@ -6506,6 +6734,8 @@ static int set_file_allocation_info(struct ksmbd_work *work,
if (size < alloc_blks * 512)
i_size_write(inode, size);
}
+
+ fp->allocation_size = le64_to_cpu(file_alloc_info->AllocationSize);
return 0;
}
@@ -6562,7 +6792,8 @@ static int set_rename_info(struct ksmbd_work *work, struct ksmbd_file *fp,
return smb2_rename(work, fp, rename_info, work->conn->local_nls);
}
-static int set_file_disposition_info(struct ksmbd_file *fp,
+static int set_file_disposition_info(struct ksmbd_work *work,
+ struct ksmbd_file *fp,
struct smb2_file_disposition_info *file_info)
{
struct inode *inode;
@@ -6574,9 +6805,13 @@ static int set_file_disposition_info(struct ksmbd_file *fp,
inode = file_inode(fp->filp);
if (file_info->DeletePending) {
+ if (ksmbd_has_stream_without_delete_share(fp))
+ return -ESHARE;
+
if (S_ISDIR(inode->i_mode) &&
ksmbd_vfs_empty_dir(fp) == -ENOTEMPTY)
return -EBUSY;
+ smb_break_all_levII_oplock_for_delete(work, fp);
ksmbd_set_inode_pending_delete(fp);
} else {
ksmbd_clear_inode_pending_delete(fp);
@@ -6703,7 +6938,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
if (buf_len < sizeof(struct smb2_file_disposition_info))
return -EMSGSIZE;
- return set_file_disposition_info(fp,
+ return set_file_disposition_info(work, fp,
(struct smb2_file_disposition_info *)buffer);
}
case FILE_FULL_EA_INFORMATION:
@@ -6774,6 +7009,8 @@ int smb2_set_info(struct ksmbd_work *work)
if (work->next_smb2_rcv_hdr_off) {
req = ksmbd_req_buf_next(work);
rsp = ksmbd_resp_buf_next(work);
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
if (!has_file_id(req->VolatileFileId)) {
ksmbd_debug(SMB, "Compound request set FID = %llu\n",
work->compound_fid);
@@ -6989,7 +7226,7 @@ int smb2_read(struct ksmbd_work *work)
size_t length, mincount;
ssize_t nbytes = 0, remain_bytes = 0;
int err = 0;
- bool is_rdma_channel = false;
+ bool is_rdma_channel = false, async_interim = false;
unsigned int max_read_size = conn->vals->max_read_size;
unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
void *aux_payload_buf;
@@ -7005,6 +7242,8 @@ int smb2_read(struct ksmbd_work *work)
if (work->next_smb2_rcv_hdr_off) {
req = ksmbd_req_buf_next(work);
rsp = ksmbd_resp_buf_next(work);
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
if (!has_file_id(req->VolatileFileId)) {
ksmbd_debug(SMB, "Compound request set FID = %llu\n",
work->compound_fid);
@@ -7059,6 +7298,14 @@ int smb2_read(struct ksmbd_work *work)
goto out;
}
+ if (work->next_smb2_rcv_hdr_off && !req->hdr.NextCommand) {
+ err = setup_async_work(work, NULL, NULL);
+ if (err)
+ goto out;
+ smb2_send_interim_resp(work, STATUS_PENDING);
+ async_interim = true;
+ }
+
offset = le64_to_cpu(req->Offset);
if (offset < 0) {
err = -EINVAL;
@@ -7094,6 +7341,8 @@ int smb2_read(struct ksmbd_work *work)
kvfree(aux_payload_buf);
rsp->hdr.Status = STATUS_END_OF_FILE;
smb2_set_err_rsp(work);
+ if (async_interim)
+ release_async_work(work);
ksmbd_fd_put(work, fp);
return -ENODATA;
}
@@ -7128,6 +7377,8 @@ int smb2_read(struct ksmbd_work *work)
kvfree(aux_payload_buf);
goto out;
}
+ if (async_interim)
+ release_async_work(work);
/*
* RDMA responses are transferred through channel buffers and encrypted
* responses use the encryption transform, so only normal SMB transport
@@ -7141,6 +7392,8 @@ int smb2_read(struct ksmbd_work *work)
return 0;
out:
+ if (async_interim)
+ release_async_work(work);
if (err) {
if (err == -EISDIR)
rsp->hdr.Status = STATUS_INVALID_DEVICE_REQUEST;
@@ -7276,13 +7529,31 @@ int smb2_write(struct ksmbd_work *work)
ssize_t nbytes;
char *data_buf;
bool writethrough = false, is_rdma_channel = false;
+ bool async_interim = false;
int err = 0;
unsigned int max_write_size = work->conn->vals->max_write_size;
+ unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
ksmbd_debug(SMB, "Received smb2 write request\n");
WORK_BUFFERS(work, req, rsp);
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
+
+ if (work->next_smb2_rcv_hdr_off &&
+ !has_file_id(req->VolatileFileId)) {
+ ksmbd_debug(SMB, "Compound request set FID = %llu\n",
+ work->compound_fid);
+ id = work->compound_fid;
+ pid = work->compound_pfid;
+ }
+
+ if (!has_file_id(id)) {
+ id = req->VolatileFileId;
+ pid = req->PersistentFileId;
+ }
+
if (test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_PIPE)) {
ksmbd_debug(SMB, "IPC pipe write request\n");
return smb2_write_pipe(work);
@@ -7327,7 +7598,7 @@ int smb2_write(struct ksmbd_work *work)
goto out;
}
- fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId);
+ fp = ksmbd_lookup_fd_slow(work, id, pid);
if (!fp) {
err = -ENOENT;
goto out;
@@ -7339,6 +7610,14 @@ int smb2_write(struct ksmbd_work *work)
goto out;
}
+ if (work->next_smb2_rcv_hdr_off && !req->hdr.NextCommand) {
+ err = setup_async_work(work, NULL, NULL);
+ if (err)
+ goto out;
+ smb2_send_interim_resp(work, STATUS_PENDING);
+ async_interim = true;
+ }
+
if (length > max_write_size) {
ksmbd_debug(SMB, "limiting write size to max size(%u)\n",
max_write_size);
@@ -7387,10 +7666,15 @@ int smb2_write(struct ksmbd_work *work)
err = ksmbd_iov_pin_rsp(work, rsp, offsetof(struct smb2_write_rsp, Buffer));
if (err)
goto out;
+ if (async_interim)
+ release_async_work(work);
ksmbd_fd_put(work, fp);
return 0;
out:
+ if (async_interim)
+ release_async_work(work);
+
if (err == -EAGAIN)
rsp->hdr.Status = STATUS_FILE_LOCK_CONFLICT;
else if (err == -ENOSPC || err == -EFBIG)
@@ -7421,13 +7705,30 @@ int smb2_flush(struct ksmbd_work *work)
{
struct smb2_flush_req *req;
struct smb2_flush_rsp *rsp;
+ u64 id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
int err;
WORK_BUFFERS(work, req, rsp);
ksmbd_debug(SMB, "Received smb2 flush request(fid : %llu)\n", req->VolatileFileId);
- err = ksmbd_vfs_fsync(work, req->VolatileFileId, req->PersistentFileId);
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
+
+ if (work->next_smb2_rcv_hdr_off &&
+ !has_file_id(req->VolatileFileId)) {
+ ksmbd_debug(SMB, "Compound request set FID = %llu\n",
+ work->compound_fid);
+ id = work->compound_fid;
+ pid = work->compound_pfid;
+ }
+
+ if (!has_file_id(id)) {
+ id = req->VolatileFileId;
+ pid = req->PersistentFileId;
+ }
+
+ err = ksmbd_vfs_fsync(work, id, pid);
if (err)
goto out;
@@ -7459,7 +7760,8 @@ int smb2_cancel(struct ksmbd_work *work)
hdr = ksmbd_resp_buf_next(work);
ksmbd_debug(SMB, "smb2 cancel called on mid %llu, async flags 0x%x\n",
- hdr->MessageId, hdr->Flags);
+ le64_to_cpu(hdr->MessageId),
+ le32_to_cpu(hdr->Flags));
if (hdr->Flags & SMB2_FLAGS_ASYNC_COMMAND) {
command_list = &conn->async_requests;
@@ -7645,11 +7947,29 @@ int smb2_lock(struct ksmbd_work *work)
LIST_HEAD(lock_list);
LIST_HEAD(rollback_list);
int prior_lock = 0, bkt;
+ unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
WORK_BUFFERS(work, req, rsp);
ksmbd_debug(SMB, "Received smb2 lock request\n");
- fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId);
+
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
+
+ if (work->next_smb2_rcv_hdr_off &&
+ !has_file_id(req->VolatileFileId)) {
+ ksmbd_debug(SMB, "Compound request set FID = %llu\n",
+ work->compound_fid);
+ id = work->compound_fid;
+ pid = work->compound_pfid;
+ }
+
+ if (!has_file_id(id)) {
+ id = req->VolatileFileId;
+ pid = req->PersistentFileId;
+ }
+
+ fp = ksmbd_lookup_fd_slow(work, id, pid);
if (!fp) {
ksmbd_debug(SMB, "Invalid file id for lock : %llu\n", req->VolatileFileId);
err = -ENOENT;
@@ -7774,9 +8094,11 @@ int smb2_lock(struct ksmbd_work *work)
nolock = 0;
list_del(&cmp_lock->flist);
list_del(&cmp_lock->clist);
+ cmp_lock->conn = NULL;
spin_unlock(&conn->llist_lock);
up_read(&conn_list_lock);
+ ksmbd_conn_put(conn);
locks_free_lock(cmp_lock->fl);
kfree(cmp_lock);
goto out_check_cl;
@@ -7911,6 +8233,7 @@ skip:
goto out2;
} else if (!rc) {
list_add(&smb_lock->llist, &rollback_list);
+ smb_lock->conn = ksmbd_conn_get(work->conn);
spin_lock(&work->conn->llist_lock);
list_add_tail(&smb_lock->clist,
&work->conn->lock_list);
@@ -7965,11 +8288,14 @@ out:
}
list_del(&smb_lock->llist);
- spin_lock(&work->conn->llist_lock);
+ conn = smb_lock->conn;
+ spin_lock(&conn->llist_lock);
if (!list_empty(&smb_lock->flist))
list_del(&smb_lock->flist);
list_del(&smb_lock->clist);
- spin_unlock(&work->conn->llist_lock);
+ smb_lock->conn = NULL;
+ spin_unlock(&conn->llist_lock);
+ ksmbd_conn_put(conn);
locks_free_lock(smb_lock->fl);
if (rlock)
@@ -8449,6 +8775,8 @@ int smb2_ioctl(struct ksmbd_work *work)
if (work->next_smb2_rcv_hdr_off) {
req = ksmbd_req_buf_next(work);
rsp = ksmbd_resp_buf_next(work);
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
if (!has_file_id(req->VolatileFileId)) {
ksmbd_debug(SMB, "Compound request set FID = %llu\n",
work->compound_fid);
@@ -8546,6 +8874,15 @@ int smb2_ioctl(struct ksmbd_work *work)
case FSCTL_CREATE_OR_GET_OBJECT_ID:
{
struct file_object_buf_type1_ioctl_rsp *obj_buf;
+ struct ksmbd_file *fp;
+
+ fp = ksmbd_lookup_fd_fast(work, id);
+ if (!fp) {
+ ret = -EBADF;
+ rsp->hdr.Status = STATUS_FILE_CLOSED;
+ goto out2;
+ }
+ ksmbd_fd_put(work, fp);
nbytes = sizeof(struct file_object_buf_type1_ioctl_rsp);
obj_buf = (struct file_object_buf_type1_ioctl_rsp *)
@@ -8871,11 +9208,10 @@ static void smb20_oplock_break_ack(struct ksmbd_work *work)
struct smb2_oplock_break *rsp;
struct ksmbd_file *fp;
struct oplock_info *opinfo = NULL;
- __le32 err = 0;
- int ret = 0;
+ __le32 status = STATUS_SUCCESS;
+ int ret;
u64 volatile_id, persistent_id;
char req_oplevel = 0, rsp_oplevel = 0;
- unsigned int oplock_change_type;
WORK_BUFFERS(work, req, rsp);
@@ -8901,71 +9237,58 @@ static void smb20_oplock_break_ack(struct ksmbd_work *work)
return;
}
- if (opinfo->level == SMB2_OPLOCK_LEVEL_NONE) {
- rsp->hdr.Status = STATUS_INVALID_OPLOCK_PROTOCOL;
+ if (opinfo->op_state != OPLOCK_ACK_WAIT) {
+ ksmbd_debug(SMB, "unexpected oplock state 0x%x\n",
+ opinfo->op_state);
+ if (opinfo->level == SMB2_OPLOCK_LEVEL_NONE)
+ status = STATUS_INVALID_OPLOCK_PROTOCOL;
+ else
+ status = STATUS_INVALID_DEVICE_STATE;
goto err_out;
}
- if (opinfo->op_state == OPLOCK_STATE_NONE) {
- ksmbd_debug(SMB, "unexpected oplock state 0x%x\n", opinfo->op_state);
- rsp->hdr.Status = STATUS_UNSUCCESSFUL;
+ if (req_oplevel == SMB2_OPLOCK_LEVEL_LEASE) {
+ opinfo->level = SMB2_OPLOCK_LEVEL_NONE;
+ status = STATUS_INVALID_PARAMETER;
goto err_out;
}
- if ((opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE ||
- opinfo->level == SMB2_OPLOCK_LEVEL_BATCH) &&
- (req_oplevel != SMB2_OPLOCK_LEVEL_II &&
- req_oplevel != SMB2_OPLOCK_LEVEL_NONE)) {
- err = STATUS_INVALID_OPLOCK_PROTOCOL;
- oplock_change_type = OPLOCK_WRITE_TO_NONE;
- } else if (opinfo->level == SMB2_OPLOCK_LEVEL_II &&
- req_oplevel != SMB2_OPLOCK_LEVEL_NONE) {
- err = STATUS_INVALID_OPLOCK_PROTOCOL;
- oplock_change_type = OPLOCK_READ_TO_NONE;
- } else if (req_oplevel == SMB2_OPLOCK_LEVEL_II ||
- req_oplevel == SMB2_OPLOCK_LEVEL_NONE) {
- err = STATUS_INVALID_DEVICE_STATE;
- if ((opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE ||
- opinfo->level == SMB2_OPLOCK_LEVEL_BATCH) &&
- req_oplevel == SMB2_OPLOCK_LEVEL_II) {
- oplock_change_type = OPLOCK_WRITE_TO_READ;
- } else if ((opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE ||
- opinfo->level == SMB2_OPLOCK_LEVEL_BATCH) &&
- req_oplevel == SMB2_OPLOCK_LEVEL_NONE) {
- oplock_change_type = OPLOCK_WRITE_TO_NONE;
- } else if (opinfo->level == SMB2_OPLOCK_LEVEL_II &&
- req_oplevel == SMB2_OPLOCK_LEVEL_NONE) {
- oplock_change_type = OPLOCK_READ_TO_NONE;
- } else {
- oplock_change_type = 0;
- }
- } else {
- oplock_change_type = 0;
+ if (opinfo->level == SMB2_OPLOCK_LEVEL_NONE) {
+ status = STATUS_INVALID_OPLOCK_PROTOCOL;
+ goto err_out;
}
- switch (oplock_change_type) {
- case OPLOCK_WRITE_TO_READ:
- ret = opinfo_write_to_read(opinfo);
- rsp_oplevel = SMB2_OPLOCK_LEVEL_II;
- break;
- case OPLOCK_WRITE_TO_NONE:
- ret = opinfo_write_to_none(opinfo);
- rsp_oplevel = SMB2_OPLOCK_LEVEL_NONE;
- break;
- case OPLOCK_READ_TO_NONE:
- ret = opinfo_read_to_none(opinfo);
- rsp_oplevel = SMB2_OPLOCK_LEVEL_NONE;
- break;
- default:
- pr_err("unknown oplock change 0x%x -> 0x%x\n",
- opinfo->level, rsp_oplevel);
+ if (opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE &&
+ req_oplevel != SMB2_OPLOCK_LEVEL_II &&
+ req_oplevel != SMB2_OPLOCK_LEVEL_NONE) {
+ opinfo->level = SMB2_OPLOCK_LEVEL_NONE;
+ status = STATUS_INVALID_OPLOCK_PROTOCOL;
+ goto err_out;
}
- if (ret < 0) {
- rsp->hdr.Status = err;
+ if (opinfo->level == SMB2_OPLOCK_LEVEL_BATCH &&
+ req_oplevel != SMB2_OPLOCK_LEVEL_II &&
+ req_oplevel != SMB2_OPLOCK_LEVEL_NONE &&
+ req_oplevel != SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
+ opinfo->level = SMB2_OPLOCK_LEVEL_NONE;
+ status = STATUS_INVALID_OPLOCK_PROTOCOL;
goto err_out;
}
+ if (opinfo->level == SMB2_OPLOCK_LEVEL_II &&
+ req_oplevel != SMB2_OPLOCK_LEVEL_NONE) {
+ opinfo->level = SMB2_OPLOCK_LEVEL_NONE;
+ status = STATUS_INVALID_OPLOCK_PROTOCOL;
+ goto err_out;
+ }
+
+ if (req_oplevel == SMB2_OPLOCK_LEVEL_EXCLUSIVE)
+ rsp_oplevel = SMB2_OPLOCK_LEVEL_NONE;
+ else
+ rsp_oplevel = req_oplevel;
+
+ opinfo->level = rsp_oplevel;
+
rsp->StructureSize = cpu_to_le16(24);
rsp->OplockLevel = rsp_oplevel;
rsp->Reserved = 0;
@@ -8973,27 +9296,33 @@ static void smb20_oplock_break_ack(struct ksmbd_work *work)
rsp->VolatileFid = volatile_id;
rsp->PersistentFid = persistent_id;
ret = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_oplock_break));
- if (ret) {
+ if (ret)
+ ksmbd_debug(SMB, "failed to pin oplock break response: %d\n",
+ ret);
+ goto out;
+
err_out:
- smb2_set_err_rsp(work);
- }
+ rsp->hdr.Status = status;
+ smb2_set_err_rsp(work);
+out:
opinfo->op_state = OPLOCK_STATE_NONE;
wake_up_interruptible_all(&opinfo->oplock_q);
opinfo_put(opinfo);
ksmbd_fd_put(work, fp);
}
-static int check_lease_state(struct lease *lease, __le32 req_state)
+static bool smb2_lease_state_valid(__le32 state)
{
- if ((lease->new_state ==
- (SMB2_LEASE_READ_CACHING_LE | SMB2_LEASE_HANDLE_CACHING_LE)) &&
- !(req_state & SMB2_LEASE_WRITE_CACHING_LE)) {
- lease->new_state = req_state;
- return 0;
- }
+ return !(state & ~(SMB2_LEASE_READ_CACHING_LE |
+ SMB2_LEASE_HANDLE_CACHING_LE |
+ SMB2_LEASE_WRITE_CACHING_LE));
+}
- if (lease->new_state == req_state)
+static int check_lease_state(struct lease *lease, __le32 req_state)
+{
+ if (smb2_lease_state_valid(req_state) &&
+ !(req_state & ~lease->new_state))
return 0;
return 1;
@@ -9011,9 +9340,7 @@ static void smb21_lease_break_ack(struct ksmbd_work *work)
struct smb2_lease_ack *req;
struct smb2_lease_ack *rsp;
struct oplock_info *opinfo;
- __le32 err = 0;
int ret = 0;
- unsigned int lease_change_type;
__le32 lease_state;
struct lease *lease;
@@ -9037,80 +9364,23 @@ static void smb21_lease_break_ack(struct ksmbd_work *work)
goto err_out;
}
- if (check_lease_state(lease, req->LeaseState)) {
- rsp->hdr.Status = STATUS_REQUEST_NOT_ACCEPTED;
- ksmbd_debug(OPLOCK,
- "req lease state: 0x%x, expected state: 0x%x\n",
- req->LeaseState, lease->new_state);
- goto err_out;
- }
-
if (!atomic_read(&opinfo->breaking_cnt)) {
rsp->hdr.Status = STATUS_UNSUCCESSFUL;
goto err_out;
}
- /* check for bad lease state */
- if (req->LeaseState &
- (~(SMB2_LEASE_READ_CACHING_LE | SMB2_LEASE_HANDLE_CACHING_LE))) {
- err = STATUS_INVALID_OPLOCK_PROTOCOL;
- if (lease->state & SMB2_LEASE_WRITE_CACHING_LE)
- lease_change_type = OPLOCK_WRITE_TO_NONE;
- else
- lease_change_type = OPLOCK_READ_TO_NONE;
- ksmbd_debug(OPLOCK, "handle bad lease state 0x%x -> 0x%x\n",
- le32_to_cpu(lease->state),
- le32_to_cpu(req->LeaseState));
- } else if (lease->state == SMB2_LEASE_READ_CACHING_LE &&
- req->LeaseState != SMB2_LEASE_NONE_LE) {
- err = STATUS_INVALID_OPLOCK_PROTOCOL;
- lease_change_type = OPLOCK_READ_TO_NONE;
- ksmbd_debug(OPLOCK, "handle bad lease state 0x%x -> 0x%x\n",
- le32_to_cpu(lease->state),
- le32_to_cpu(req->LeaseState));
- } else {
- /* valid lease state changes */
- err = STATUS_INVALID_DEVICE_STATE;
- if (req->LeaseState == SMB2_LEASE_NONE_LE) {
- if (lease->state & SMB2_LEASE_WRITE_CACHING_LE)
- lease_change_type = OPLOCK_WRITE_TO_NONE;
- else
- lease_change_type = OPLOCK_READ_TO_NONE;
- } else if (req->LeaseState & SMB2_LEASE_READ_CACHING_LE) {
- if (lease->state & SMB2_LEASE_WRITE_CACHING_LE)
- lease_change_type = OPLOCK_WRITE_TO_READ;
- else
- lease_change_type = OPLOCK_READ_HANDLE_TO_READ;
- } else {
- lease_change_type = 0;
- }
- }
-
- switch (lease_change_type) {
- case OPLOCK_WRITE_TO_READ:
- ret = opinfo_write_to_read(opinfo);
- break;
- case OPLOCK_READ_HANDLE_TO_READ:
- ret = opinfo_read_handle_to_read(opinfo);
- break;
- case OPLOCK_WRITE_TO_NONE:
- ret = opinfo_write_to_none(opinfo);
- break;
- case OPLOCK_READ_TO_NONE:
- ret = opinfo_read_to_none(opinfo);
- break;
- default:
- ksmbd_debug(OPLOCK, "unknown lease change 0x%x -> 0x%x\n",
- le32_to_cpu(lease->state),
- le32_to_cpu(req->LeaseState));
- }
-
- if (ret < 0) {
- rsp->hdr.Status = err;
+ if (check_lease_state(lease, req->LeaseState)) {
+ rsp->hdr.Status = STATUS_REQUEST_NOT_ACCEPTED;
+ ksmbd_debug(OPLOCK,
+ "req lease state: 0x%x, expected state: 0x%x\n",
+ req->LeaseState, lease->new_state);
goto err_out;
}
- lease_state = lease->state;
+ lease_state = req->LeaseState;
+ lease->state = lease_state;
+ lease->new_state = SMB2_LEASE_NONE_LE;
+ lease_update_oplock_levels(lease);
rsp->StructureSize = cpu_to_le16(36);
rsp->Reserved = 0;
@@ -9119,16 +9389,20 @@ static void smb21_lease_break_ack(struct ksmbd_work *work)
rsp->LeaseState = lease_state;
rsp->LeaseDuration = 0;
ret = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_lease_ack));
- if (ret) {
-err_out:
- smb2_set_err_rsp(work);
- }
+ if (ret)
+ goto err_out;
opinfo->op_state = OPLOCK_STATE_NONE;
wake_up_interruptible_all(&opinfo->oplock_q);
atomic_dec(&opinfo->breaking_cnt);
wake_up_interruptible_all(&opinfo->oplock_brk);
opinfo_put(opinfo);
+ return;
+
+err_out:
+ smb2_set_err_rsp(work);
+ opinfo_put(opinfo);
+ return;
}
/**
@@ -9179,6 +9453,9 @@ int smb2_notify(struct ksmbd_work *work)
WORK_BUFFERS(work, req, rsp);
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
+
if (work->next_smb2_rcv_hdr_off && req->hdr.NextCommand) {
rsp->hdr.Status = STATUS_INTERNAL_ERROR;
smb2_set_err_rsp(work);
@@ -9401,10 +9678,13 @@ void smb3_preauth_hash_rsp(struct ksmbd_work *work)
WORK_BUFFERS(work, req, rsp);
- if (le16_to_cpu(req->Command) == SMB2_NEGOTIATE_HE &&
- conn->preauth_info)
- ksmbd_gen_preauth_integrity_hash(conn, work->response_buf,
- conn->preauth_info->Preauth_HashValue);
+ if (le16_to_cpu(req->Command) == SMB2_NEGOTIATE_HE) {
+ ksmbd_conn_lock(conn);
+ if (conn->preauth_info)
+ ksmbd_gen_preauth_integrity_hash(conn, work->response_buf,
+ conn->preauth_info->Preauth_HashValue);
+ ksmbd_conn_unlock(conn);
+ }
if (le16_to_cpu(rsp->Command) == SMB2_SESSION_SETUP_HE && sess) {
__u8 *hash_value;
diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h
index 3bed676bb5ad..c2512dbcdec8 100644
--- a/fs/smb/server/smb2pdu.h
+++ b/fs/smb/server/smb2pdu.h
@@ -23,7 +23,7 @@
#define MAX_SMB2_HDR_SIZE 0x78 /* 4 len + 64 hdr + (2*24 wct) + 2 bct + 2 pad */
#define SMB21_DEFAULT_IOSIZE (1024 * 1024)
-#define SMB3_DEFAULT_TRANS_SIZE (1024 * 1024)
+#define SMB3_DEFAULT_TRANS_SIZE (4 * 1024 * 1024)
#define SMB3_MIN_IOSIZE (64 * 1024)
#define SMB3_MAX_IOSIZE (8 * 1024 * 1024)
#define SMB3_MAX_MSGSIZE (4 * 4096)
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index 74b0307cb100..f5fa22d87603 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -700,10 +700,18 @@ retry:
if (err)
goto out_drop_write;
+ if (!work->tcon->posix_extensions && d_is_dir(old_child) &&
+ ksmbd_has_open_files(old_child)) {
+ err = -EACCES;
+ goto out3;
+ }
+
parent_fp = ksmbd_lookup_fd_inode(old_child->d_parent);
if (parent_fp) {
- if (parent_fp->daccess & FILE_DELETE_LE) {
- pr_err("parent dir is opened with delete access\n");
+ if ((parent_fp->daccess & FILE_DELETE_LE) ||
+ (!parent_fp->attrib_only &&
+ !(parent_fp->saccess & FILE_SHARE_DELETE_LE))) {
+ pr_err("parent dir blocks delete sharing\n");
err = -ESHARE;
ksmbd_fd_put(work, parent_fp);
goto out3;
diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c
index 8c556e46cc10..fde22742d193 100644
--- a/fs/smb/server/vfs_cache.c
+++ b/fs/smb/server/vfs_cache.c
@@ -10,6 +10,7 @@
#include <linux/vmalloc.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
+#include <linux/dcache.h>
#include "glob.h"
#include "vfs_cache.h"
@@ -37,6 +38,8 @@ static struct ksmbd_file_table global_ft;
static atomic_long_t fd_limit;
static struct kmem_cache *filp_cache;
+static int ksmbd_mark_fp_closed(struct ksmbd_file *fp);
+
#define OPLOCK_NONE 0
#define OPLOCK_EXCLUSIVE 1
#define OPLOCK_BATCH 2
@@ -251,6 +254,33 @@ void ksmbd_clear_inode_pending_delete(struct ksmbd_file *fp)
up_write(&ci->m_lock);
}
+bool ksmbd_has_stream_without_delete_share(struct ksmbd_file *fp)
+{
+ struct ksmbd_file *prev_fp;
+ struct ksmbd_inode *ci = fp->f_ci;
+ bool ret = false;
+
+ if (ksmbd_stream_fd(fp))
+ return false;
+
+ down_read(&ci->m_lock);
+ list_for_each_entry(prev_fp, &ci->m_fp_list, node) {
+ if (prev_fp == fp || !ksmbd_stream_fd(prev_fp))
+ continue;
+
+ if (file_inode(fp->filp) != file_inode(prev_fp->filp))
+ continue;
+
+ if (!(prev_fp->saccess & FILE_SHARE_DELETE_LE)) {
+ ret = true;
+ break;
+ }
+ }
+ up_read(&ci->m_lock);
+
+ return ret;
+}
+
void ksmbd_fd_set_delete_on_close(struct ksmbd_file *fp,
int file_info)
{
@@ -484,10 +514,14 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
* there are not accesses to fp->lock_list.
*/
list_for_each_entry_safe(smb_lock, tmp_lock, &fp->lock_list, flist) {
- if (!list_empty(&smb_lock->clist) && fp->conn) {
- spin_lock(&fp->conn->llist_lock);
- list_del(&smb_lock->clist);
- spin_unlock(&fp->conn->llist_lock);
+ struct ksmbd_conn *conn = smb_lock->conn;
+
+ if (conn) {
+ spin_lock(&conn->llist_lock);
+ list_del_init(&smb_lock->clist);
+ smb_lock->conn = NULL;
+ spin_unlock(&conn->llist_lock);
+ ksmbd_conn_put(conn);
}
list_del(&smb_lock->flist);
@@ -513,6 +547,63 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
kmem_cache_free(filp_cache, fp);
}
+/**
+ * ksmbd_close_disconnected_durable_delete_on_close() - drop a delete-on-close
+ * file kept present only by disconnected durable handles
+ * @dentry: dentry of the file being opened
+ *
+ * A durable handle opened with delete-on-close is preserved across a
+ * disconnect so it can be reclaimed by a durable reconnect. When a new
+ * (non-reconnect) open arrives for the same name instead, the disconnected
+ * handle has to give way. Close such handles so their delete-on-close is
+ * applied and the file is removed once the last handle is gone, letting the
+ * new open create a fresh file.
+ *
+ * The caller's inode reference is dropped before closing so that the final
+ * close can promote S_DEL_ON_CLS to S_DEL_PENDING and unlink the file.
+ *
+ * Return: true if a disconnected durable handle was closed.
+ */
+bool ksmbd_close_disconnected_durable_delete_on_close(struct dentry *dentry)
+{
+ struct ksmbd_inode *ci;
+ struct ksmbd_file *fp, *tmp;
+ LIST_HEAD(dispose);
+ bool closed = false;
+
+ ci = ksmbd_inode_lookup_lock(dentry);
+ if (!ci)
+ return false;
+
+ down_write(&ci->m_lock);
+ if (ci->m_flags & (S_DEL_ON_CLS | S_DEL_ON_CLS_STREAM | S_DEL_PENDING)) {
+ list_for_each_entry_safe(fp, tmp, &ci->m_fp_list, node) {
+ if (fp->conn || !fp->is_durable ||
+ fp->f_state != FP_INITED)
+ continue;
+ list_move_tail(&fp->node, &dispose);
+ }
+ }
+ up_write(&ci->m_lock);
+
+ /*
+ * Drop our lookup reference before closing so the last __ksmbd_close_fd()
+ * can drop m_count to zero and unlink the delete-on-close file. The
+ * collected handles still hold references, so ci stays valid until they
+ * are closed below.
+ */
+ ksmbd_inode_put(ci);
+
+ while (!list_empty(&dispose)) {
+ fp = list_first_entry(&dispose, struct ksmbd_file, node);
+ list_del_init(&fp->node);
+ __ksmbd_close_fd(NULL, fp);
+ closed = true;
+ }
+
+ return closed;
+}
+
static struct ksmbd_file *ksmbd_fp_get(struct ksmbd_file *fp)
{
if (fp->f_state != FP_INITED)
@@ -576,6 +667,7 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id)
{
struct ksmbd_file *fp;
struct ksmbd_file_table *ft;
+ bool closed = false;
if (!has_file_id(id))
return 0;
@@ -590,6 +682,7 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id)
fp = NULL;
else {
fp->f_state = FP_CLOSED;
+ closed = true;
if (!atomic_dec_and_test(&fp->refcount))
fp = NULL;
}
@@ -597,7 +690,7 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id)
write_unlock(&ft->lock);
if (!fp)
- return -EINVAL;
+ return closed ? 0 : -EINVAL;
__put_fd_final(work, fp);
return 0;
@@ -670,7 +763,8 @@ struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id)
struct ksmbd_file *fp;
fp = __ksmbd_lookup_fd(&global_ft, id);
- if (fp && (fp->conn ||
+ if (fp && (fp->durable_reconnect_disabled ||
+ fp->conn ||
(fp->durable_scavenger_timeout &&
(fp->durable_scavenger_timeout <
jiffies_to_msecs(jiffies))))) {
@@ -689,6 +783,122 @@ void ksmbd_put_durable_fd(struct ksmbd_file *fp)
__ksmbd_close_fd(NULL, fp);
}
+bool ksmbd_has_other_active_fd(struct ksmbd_file *fp)
+{
+ struct ksmbd_file *lfp;
+ struct ksmbd_inode *ci = fp->f_ci;
+ bool ret = false;
+
+ down_read(&ci->m_lock);
+ list_for_each_entry(lfp, &ci->m_fp_list, node) {
+ if (lfp == fp)
+ continue;
+
+ if (lfp->f_state == FP_INITED &&
+ (READ_ONCE(lfp->conn) || READ_ONCE(lfp->tcon))) {
+ ret = true;
+ break;
+ }
+ }
+ up_read(&ci->m_lock);
+
+ return ret;
+}
+
+static struct ksmbd_file *ksmbd_lookup_fd_app_instance_id(char *app_instance_id)
+{
+ struct ksmbd_file *fp = NULL;
+ unsigned int id;
+
+ if (!memchr_inv(app_instance_id, 0, SMB2_CREATE_GUID_SIZE))
+ return NULL;
+
+ read_lock(&global_ft.lock);
+ idr_for_each_entry(global_ft.idr, fp, id) {
+ if (!memcmp(fp->app_instance_id, app_instance_id,
+ SMB2_CREATE_GUID_SIZE)) {
+ fp = ksmbd_fp_get(fp);
+ break;
+ }
+ }
+ read_unlock(&global_ft.lock);
+
+ return fp;
+}
+
+int ksmbd_close_fd_app_instance_id(char *app_instance_id)
+{
+ struct ksmbd_file_table *ft;
+ struct ksmbd_file *fp;
+ struct oplock_info *opinfo;
+ int n_to_drop = 0;
+
+ fp = ksmbd_lookup_fd_app_instance_id(app_instance_id);
+ if (!fp)
+ return 0;
+
+ opinfo = opinfo_get(fp);
+ if (!opinfo || !opinfo->sess)
+ goto out;
+
+ ft = &opinfo->sess->file_table;
+ write_lock(&ft->lock);
+ if (fp->f_state == FP_INITED) {
+ if (has_file_id(fp->volatile_id)) {
+ idr_remove(ft->idr, fp->volatile_id);
+ fp->volatile_id = KSMBD_NO_FID;
+ }
+ n_to_drop = ksmbd_mark_fp_closed(fp);
+ }
+ write_unlock(&ft->lock);
+ opinfo_put(opinfo);
+ opinfo = NULL;
+
+ if (!n_to_drop)
+ goto out;
+
+ down_write(&fp->f_ci->m_lock);
+ list_del_init(&fp->node);
+ up_write(&fp->f_ci->m_lock);
+
+ if (atomic_sub_and_test(n_to_drop, &fp->refcount)) {
+ if (fp->conn)
+ atomic_dec(&fp->conn->stats.open_files_count);
+ __ksmbd_close_fd(NULL, fp);
+ }
+ return 0;
+
+out:
+ if (opinfo)
+ opinfo_put(opinfo);
+ ksmbd_put_durable_fd(fp);
+ return 0;
+}
+
+int ksmbd_invalidate_durable_fd(unsigned long long id)
+{
+ struct ksmbd_file *fp;
+
+ fp = ksmbd_lookup_global_fd(id);
+ if (!fp)
+ return -ENOENT;
+
+ fp->durable_reconnect_disabled = true;
+
+ if (fp->conn) {
+ ksmbd_put_durable_fd(fp);
+ return -ENOENT;
+ }
+
+ fp->durable_timeout = 1;
+ fp->durable_scavenger_timeout = jiffies_to_msecs(jiffies);
+ ksmbd_put_durable_fd(fp);
+ if (waitqueue_active(&dh_wq))
+ wake_up(&dh_wq);
+
+ return -ENOENT;
+}
+
struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid)
{
struct ksmbd_file *fp = NULL;
@@ -734,6 +944,30 @@ struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry)
return NULL;
}
+bool ksmbd_has_open_files(struct dentry *dentry)
+{
+ struct ksmbd_file *fp;
+ unsigned int id;
+ bool ret = false;
+
+ read_lock(&global_ft.lock);
+ idr_for_each_entry(global_ft.idr, fp, id) {
+ struct dentry *fp_dentry = fp->filp->f_path.dentry;
+
+ if (fp->f_state != FP_INITED)
+ continue;
+ if (fp_dentry == dentry)
+ continue;
+ if (is_subdir(fp_dentry, dentry)) {
+ ret = true;
+ break;
+ }
+ }
+ read_unlock(&global_ft.lock);
+
+ return ret;
+}
+
#define OPEN_ID_TYPE_VOLATILE_ID (0)
#define OPEN_ID_TYPE_PERSISTENT_ID (1)
@@ -758,7 +992,8 @@ static int __open_id(struct ksmbd_file_table *ft, struct ksmbd_file *fp,
idr_preload(KSMBD_DEFAULT_GFP);
write_lock(&ft->lock);
- ret = idr_alloc_cyclic(ft->idr, fp, 0, INT_MAX - 1, GFP_NOWAIT);
+ ret = idr_alloc_cyclic(ft->idr, fp, KSMBD_START_FID, INT_MAX - 1,
+ GFP_NOWAIT);
if (ret >= 0) {
id = ret;
ret = 0;
@@ -929,6 +1164,7 @@ __close_file_table_ids(struct ksmbd_session *sess,
* global_ft.
*/
idr_remove(ft->idr, id);
+ fp->durable_volatile_id = fp->volatile_id;
fp->volatile_id = KSMBD_NO_FID;
write_unlock(&ft->lock);
@@ -1108,10 +1344,10 @@ static int ksmbd_durable_scavenger(void *dummy)
if (try_to_freeze())
continue;
- remaining_jiffies = wait_event_timeout(dh_wq,
+ remaining_jiffies = wait_event_interruptible_timeout(dh_wq,
ksmbd_durable_scavenger_alive() == false,
__msecs_to_jiffies(min_timeout));
- if (remaining_jiffies)
+ if ((long)remaining_jiffies > 0)
min_timeout = jiffies_to_msecs(remaining_jiffies);
else
min_timeout = DURABLE_HANDLE_MAX_TIMEOUT;
@@ -1303,9 +1539,15 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon,
up_write(&ci->m_lock);
list_for_each_entry_safe(smb_lock, tmp_lock, &fp->lock_list, flist) {
- spin_lock(&conn->llist_lock);
+ struct ksmbd_conn *lock_conn = smb_lock->conn;
+
+ if (!lock_conn)
+ continue;
+ spin_lock(&lock_conn->llist_lock);
list_del_init(&smb_lock->clist);
- spin_unlock(&conn->llist_lock);
+ smb_lock->conn = NULL;
+ spin_unlock(&lock_conn->llist_lock);
+ ksmbd_conn_put(lock_conn);
}
fp->conn = NULL;
@@ -1435,6 +1677,7 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
}
list_for_each_entry(smb_lock, &fp->lock_list, flist) {
+ smb_lock->conn = ksmbd_conn_get(conn);
spin_lock(&conn->llist_lock);
list_add_tail(&smb_lock->clist, &conn->lock_list);
spin_unlock(&conn->llist_lock);
diff --git a/fs/smb/server/vfs_cache.h b/fs/smb/server/vfs_cache.h
index 7d547e1a74f7..287f3e675cd3 100644
--- a/fs/smb/server/vfs_cache.h
+++ b/fs/smb/server/vfs_cache.h
@@ -23,7 +23,12 @@
#define FILE_GENERIC_WRITE 0x120116
#define FILE_GENERIC_EXECUTE 0X1200a0
-#define KSMBD_START_FID 0
+/*
+ * Start volatile/persistent file id allocation at 1. A file id of 0 yields an
+ * SMB2 FileId of {0, 0}, which clients (e.g. Windows, Samba) treat as a null
+ * handle and never close, leaking the open on the server.
+ */
+#define KSMBD_START_FID 1
#define KSMBD_NO_FID (INT_MAX)
#define SMB2_NO_FID (0xFFFFFFFFFFFFFFFFULL)
@@ -32,6 +37,7 @@ struct ksmbd_session;
struct ksmbd_lock {
struct file_lock *fl;
+ struct ksmbd_conn *conn;
struct list_head clist;
struct list_head flist;
struct list_head llist;
@@ -80,6 +86,7 @@ struct ksmbd_file {
struct file *filp;
u64 persistent_id;
u64 volatile_id;
+ u64 durable_volatile_id;
spinlock_t f_lock;
@@ -95,6 +102,8 @@ struct ksmbd_file {
__le32 coption;
__le32 cdoption;
__u64 create_time;
+ __u64 change_time;
+ __u64 allocation_size;
__u64 itime;
bool is_nt_open;
@@ -121,6 +130,7 @@ struct ksmbd_file {
bool is_durable;
bool is_persistent;
bool is_resilient;
+ bool durable_reconnect_disabled;
bool is_posix_ctxt;
struct durable_owner owner;
@@ -159,11 +169,17 @@ struct ksmbd_file *ksmbd_lookup_fd_slow(struct ksmbd_work *work, u64 id,
void ksmbd_fd_put(struct ksmbd_work *work, struct ksmbd_file *fp);
struct ksmbd_inode *ksmbd_inode_lookup_lock(struct dentry *d);
void ksmbd_inode_put(struct ksmbd_inode *ci);
+bool ksmbd_close_disconnected_durable_delete_on_close(struct dentry *dentry);
struct ksmbd_file *ksmbd_lookup_global_fd(unsigned long long id);
struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id);
void ksmbd_put_durable_fd(struct ksmbd_file *fp);
+int ksmbd_invalidate_durable_fd(unsigned long long id);
+bool ksmbd_has_other_active_fd(struct ksmbd_file *fp);
+bool ksmbd_has_stream_without_delete_share(struct ksmbd_file *fp);
+int ksmbd_close_fd_app_instance_id(char *app_instance_id);
struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid);
struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry);
+bool ksmbd_has_open_files(struct dentry *dentry);
unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp);
struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp);
void ksmbd_launch_ksmbd_durable_scavenger(void);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 5ad62c207d00..5f5ca023cd65 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -2608,13 +2608,13 @@ struct drm_tile_group {
struct kref refcount;
struct drm_device *dev;
int id;
- u8 group_data[8];
+ u8 group_data[9];
};
struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
- const char topology[8]);
+ const char topology_id[9]);
struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
- const char topology[8]);
+ const char topology_id[9]);
void drm_mode_put_tile_group(struct drm_device *dev,
struct drm_tile_group *tg);
diff --git a/include/dt-bindings/clock/canaan,k230-clk.h b/include/dt-bindings/clock/canaan,k230-clk.h
new file mode 100644
index 000000000000..3b916678cc5b
--- /dev/null
+++ b/include/dt-bindings/clock/canaan,k230-clk.h
@@ -0,0 +1,220 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Kendryte Canaan K230 Clock Drivers
+ *
+ * Author: Xukai Wang <kingxukai@zohomail.com>
+ */
+
+#ifndef __DT_BINDINGS_CANAAN_K230_CLOCK_H__
+#define __DT_BINDINGS_CANAAN_K230_CLOCK_H__
+
+#define K230_CPU0_SRC_GATE 0
+#define K230_CPU0_PLIC_GATE 1
+#define K230_CPU0_NOC_DDRCP4_GATE 2
+#define K230_CPU0_APB_GATE 3
+#define K230_CPU0_SRC_RATE 4
+#define K230_CPU0_AXI_RATE 5
+#define K230_CPU0_PLIC_RATE 6
+#define K230_CPU0_APB_RATE 7
+#define K230_HS_SSI0_MUX 8
+#define K230_HS_USB_REF_MUX 9
+#define K230_HS_HCLK_HIGH_GATE 10
+#define K230_HS_HCLK_GATE 11
+#define K230_HS_SD0_AHB_GATE 12
+#define K230_HS_SD1_AHB_GATE 13
+#define K230_HS_SSI1_AHB_GATE 14
+#define K230_HS_SSI2_AHB_GATE 15
+#define K230_HS_USB0_AHB_GATE 16
+#define K230_HS_USB1_AHB_GATE 17
+#define K230_HS_SSI0_AXI_GATE 18
+#define K230_HS_SSI1_GATE 19
+#define K230_HS_SSI2_GATE 20
+#define K230_HS_QSPI_AXI_SRC_GATE 21
+#define K230_HS_SSI1_AXI_GATE 22
+#define K230_HS_SSI2_AXI_GATE 23
+#define K230_HS_SD_CARD_SRC_GATE 24
+#define K230_HS_SD0_CARD_GATE 25
+#define K230_HS_SD1_CARD_GATE 26
+#define K230_HS_SD_AXI_SRC_GATE 27
+#define K230_HS_SD0_AXI_GATE 28
+#define K230_HS_SD1_AXI_GATE 29
+#define K230_HS_SD0_BASE_GATE 30
+#define K230_HS_SD1_BASE_GATE 31
+#define K230_HS_SSI0_GATE 32
+#define K230_HS_SD_TIMER_SRC_GATE 33
+#define K230_HS_SD0_TIMER_GATE 34
+#define K230_HS_SD1_TIMER_GATE 35
+#define K230_HS_USB0_REF_GATE 36
+#define K230_HS_USB1_REF_GATE 37
+#define K230_HS_HCLK_HIGH_RATE 38
+#define K230_HS_HCLK_RATE 39
+#define K230_HS_SSI0_AXI_RATE 40
+#define K230_HS_SSI1_RATE 41
+#define K230_HS_SSI2_RATE 42
+#define K230_HS_QSPI_AXI_SRC_RATE 43
+#define K230_HS_SD_CARD_SRC_RATE 44
+#define K230_HS_SD_AXI_SRC_RATE 45
+#define K230_HS_USB_REF_50M_RATE 46
+#define K230_HS_SD_TIMER_SRC_RATE 47
+#define K230_TIMER0_MUX 48
+#define K230_TIMER1_MUX 49
+#define K230_TIMER2_MUX 50
+#define K230_TIMER3_MUX 51
+#define K230_TIMER4_MUX 52
+#define K230_TIMER5_MUX 53
+#define K230_SHRM_SRAM_MUX 54
+#define K230_DDRC_SRC_MUX 55
+#define K230_AI_SRC_MUX 56
+#define K230_CAMERA0_MUX 57
+#define K230_CAMERA1_MUX 58
+#define K230_CAMERA2_MUX 59
+#define K230_CPU1_SRC_MUX 60
+#define K230_CPU1_SRC_GATE 61
+#define K230_CPU1_PLIC_GATE 62
+#define K230_CPU1_APB_GATE 63
+#define K230_CPU1_SRC_RATE 64
+#define K230_CPU1_AXI_RATE 65
+#define K230_CPU1_PLIC_RATE 66
+#define K230_PMU_APB_GATE 67
+#define K230_LS_APB_SRC_GATE 68
+#define K230_LS_UART0_APB_GATE 69
+#define K230_LS_UART1_APB_GATE 70
+#define K230_LS_UART2_APB_GATE 71
+#define K230_LS_UART3_APB_GATE 72
+#define K230_LS_UART4_APB_GATE 73
+#define K230_LS_I2C0_APB_GATE 74
+#define K230_LS_I2C1_APB_GATE 75
+#define K230_LS_I2C2_APB_GATE 76
+#define K230_LS_I2C3_APB_GATE 77
+#define K230_LS_I2C4_APB_GATE 78
+#define K230_LS_GPIO_APB_GATE 79
+#define K230_LS_PWM_APB_GATE 80
+#define K230_LS_JAMLINK0_APB_GATE 81
+#define K230_LS_JAMLINK1_APB_GATE 82
+#define K230_LS_JAMLINK2_APB_GATE 83
+#define K230_LS_JAMLINK3_APB_GATE 84
+#define K230_LS_AUDIO_APB_GATE 85
+#define K230_LS_ADC_APB_GATE 86
+#define K230_LS_CODEC_APB_GATE 87
+#define K230_LS_I2C0_GATE 88
+#define K230_LS_I2C1_GATE 89
+#define K230_LS_I2C2_GATE 90
+#define K230_LS_I2C3_GATE 91
+#define K230_LS_I2C4_GATE 92
+#define K230_LS_CODEC_ADC_GATE 93
+#define K230_LS_CODEC_DAC_GATE 94
+#define K230_LS_AUDIO_DEV_GATE 95
+#define K230_LS_PDM_GATE 96
+#define K230_LS_ADC_GATE 97
+#define K230_LS_UART0_GATE 98
+#define K230_LS_UART1_GATE 99
+#define K230_LS_UART2_GATE 100
+#define K230_LS_UART3_GATE 101
+#define K230_LS_UART4_GATE 102
+#define K230_LS_JAMLINK0CO_GATE 103
+#define K230_LS_JAMLINK1CO_GATE 104
+#define K230_LS_JAMLINK2CO_GATE 105
+#define K230_LS_JAMLINK3CO_GATE 106
+#define K230_LS_GPIO_DEBOUNCE_GATE 107
+#define K230_SYSCTL_WDT0_APB_GATE 108
+#define K230_SYSCTL_WDT1_APB_GATE 109
+#define K230_SYSCTL_TIMER_APB_GATE 110
+#define K230_SYSCTL_IOMUX_APB_GATE 111
+#define K230_SYSCTL_MAILBOX_APB_GATE 112
+#define K230_SYSCTL_HDI_GATE 113
+#define K230_SYSCTL_TIME_STAMP_GATE 114
+#define K230_SYSCTL_WDT0_GATE 115
+#define K230_SYSCTL_WDT1_GATE 116
+#define K230_TIMER0_GATE 117
+#define K230_TIMER1_GATE 118
+#define K230_TIMER2_GATE 119
+#define K230_TIMER3_GATE 120
+#define K230_TIMER4_GATE 121
+#define K230_TIMER5_GATE 122
+#define K230_SHRM_APB_GATE 123
+#define K230_SHRM_AXI_GATE 124
+#define K230_SHRM_AXI_SLAVE_GATE 125
+#define K230_SHRM_NONAI2D_AXI_GATE 126
+#define K230_SHRM_SRAM_GATE 127
+#define K230_SHRM_DECOMPRESS_AXI_GATE 128
+#define K230_SHRM_SDMA_AXI_GATE 129
+#define K230_SHRM_PDMA_AXI_GATE 130
+#define K230_DDRC_SRC_GATE 131
+#define K230_DDRC_BYPASS_GATE 132
+#define K230_DDRC_APB_GATE 133
+#define K230_DISPLAY_AHB_GATE 134
+#define K230_DISPLAY_AXI_GATE 135
+#define K230_DISPLAY_GPU_GATE 136
+#define K230_DISPLAY_DPIP_GATE 137
+#define K230_DISPLAY_CFG_GATE 138
+#define K230_DISPLAY_REF_GATE 139
+#define K230_USB_480M_GATE 140
+#define K230_USB_100M_GATE 141
+#define K230_DPHY_DFT_GATE 142
+#define K230_SPI2AXI_GATE 143
+#define K230_AI_SRC_GATE 144
+#define K230_AI_AXI_GATE 145
+#define K230_AI_SRC_RATE 146
+#define K230_CAMERA0_GATE 147
+#define K230_CAMERA1_GATE 148
+#define K230_CAMERA2_GATE 149
+#define K230_LS_APB_SRC_RATE 150
+#define K230_LS_I2C0_RATE 151
+#define K230_LS_I2C1_RATE 152
+#define K230_LS_I2C2_RATE 153
+#define K230_LS_I2C3_RATE 154
+#define K230_LS_I2C4_RATE 155
+#define K230_LS_CODEC_ADC_RATE 156
+#define K230_LS_CODEC_DAC_RATE 157
+#define K230_LS_AUDIO_DEV_RATE 158
+#define K230_LS_PDM_RATE 159
+#define K230_LS_ADC_RATE 160
+#define K230_LS_UART0_RATE 161
+#define K230_LS_UART1_RATE 162
+#define K230_LS_UART2_RATE 163
+#define K230_LS_UART3_RATE 164
+#define K230_LS_UART4_RATE 165
+#define K230_LS_JAMLINKCO_SRC_RATE 166
+#define K230_LS_GPIO_DEBOUNCE_RATE 167
+#define K230_SYSCTL_HDI_RATE 168
+#define K230_SYSCTL_TIME_STAMP_RATE 169
+#define K230_SYSCTL_TEMP_SENSOR_RATE 170
+#define K230_SYSCTL_WDT0_RATE 171
+#define K230_SYSCTL_WDT1_RATE 172
+#define K230_TIMER0_SRC_RATE 173
+#define K230_TIMER1_SRC_RATE 174
+#define K230_TIMER2_SRC_RATE 175
+#define K230_TIMER3_SRC_RATE 176
+#define K230_TIMER4_SRC_RATE 177
+#define K230_TIMER5_SRC_RATE 178
+#define K230_SHRM_APB_RATE 179
+#define K230_DDRC_SRC_RATE 180
+#define K230_DDRC_APB_RATE 181
+#define K230_DISPLAY_AHB_RATE 182
+#define K230_DISPLAY_CLKEXT_RATE 183
+#define K230_DISPLAY_GPU_RATE 184
+#define K230_DISPLAY_DPIP_RATE 185
+#define K230_DISPLAY_CFG_RATE 186
+#define K230_VPU_SRC_GATE 187
+#define K230_VPU_AXI_GATE 188
+#define K230_VPU_DDRCP2_GATE 189
+#define K230_VPU_CFG_GATE 190
+#define K230_VPU_SRC_RATE 191
+#define K230_VPU_AXI_SRC_RATE 192
+#define K230_VPU_CFG_RATE 193
+#define K230_SEC_APB_GATE 194
+#define K230_SEC_FIX_GATE 195
+#define K230_SEC_AXI_GATE 196
+#define K230_SEC_APB_RATE 197
+#define K230_SEC_FIX_RATE 198
+#define K230_SEC_AXI_RATE 199
+#define K230_USB_480M_RATE 200
+#define K230_USB_100M_RATE 201
+#define K230_DPHY_DFT_RATE 202
+#define K230_SPI2AXI_RATE 203
+#define K230_CAMERA0_RATE 204
+#define K230_CAMERA1_RATE 205
+#define K230_CAMERA2_RATE 206
+#define K230_SHRM_SRAM_DIV2 207
+
+#endif /* __DT_BINDINGS_CANAAN_K230_CLOCK_H__ */
diff --git a/include/dt-bindings/clock/qcom,hawi-gcc.h b/include/dt-bindings/clock/qcom,hawi-gcc.h
new file mode 100644
index 000000000000..6cd7fa0884f5
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,hawi-gcc.h
@@ -0,0 +1,253 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_GCC_HAWI_H
+#define _DT_BINDINGS_CLK_QCOM_GCC_HAWI_H
+
+/* GCC clocks */
+#define GCC_AGGRE_NOC_PCIE_AXI_CLK 0
+#define GCC_AGGRE_STARDUSTNOC_USB3_PRIM_AXI_CLK 1
+#define GCC_AGGRE_UFS_PHY_AXI_CLK 2
+#define GCC_BOOT_ROM_AHB_CLK 3
+#define GCC_CAM_BIST_MCLK_AHB_CLK 4
+#define GCC_CAMERA_AHB_CLK 5
+#define GCC_CAMERA_HF_AXI_CLK 6
+#define GCC_CAMERA_RSC_CORE_CLK 7
+#define GCC_CAMERA_SF_AXI_CLK 8
+#define GCC_CAMERA_XO_CLK 9
+#define GCC_CFG_NOC_PCIE_ANOC_AHB_CLK 10
+#define GCC_CFG_NOC_USB3_PRIM_AXI_CLK 11
+#define GCC_CNOC_PCIE_SF_AXI_CLK 12
+#define GCC_EVA_AHB_CLK 13
+#define GCC_EVA_AXI0_CLK 14
+#define GCC_EVA_AXI0C_CLK 15
+#define GCC_EVA_XO_CLK 16
+#define GCC_GP1_CLK 17
+#define GCC_GP1_CLK_SRC 18
+#define GCC_GP2_CLK 19
+#define GCC_GP2_CLK_SRC 20
+#define GCC_GP3_CLK 21
+#define GCC_GP3_CLK_SRC 22
+#define GCC_GPLL0 23
+#define GCC_GPLL0_OUT_EVEN 24
+#define GCC_GPLL4 25
+#define GCC_GPLL5 26
+#define GCC_GPLL7 27
+#define GCC_GPLL9 28
+#define GCC_GPU_CFG_AHB_CLK 29
+#define GCC_GPU_GEMNOC_GFX_CLK 30
+#define GCC_GPU_GPLL0_CLK_SRC 31
+#define GCC_GPU_GPLL0_DIV_CLK_SRC 32
+#define GCC_GPU_RSC_CORE_CLK 33
+#define GCC_GPU_SMMU_VOTE_CLK 34
+#define GCC_MMU_TCU_VOTE_CLK 35
+#define GCC_PCIE_0_AUX_CLK 36
+#define GCC_PCIE_0_AUX_CLK_SRC 37
+#define GCC_PCIE_0_CFG_AHB_CLK 38
+#define GCC_PCIE_0_MSTR_AXI_CLK 39
+#define GCC_PCIE_0_PHY_AUX_CLK 40
+#define GCC_PCIE_0_PHY_AUX_CLK_SRC 41
+#define GCC_PCIE_0_PHY_RCHNG_CLK 42
+#define GCC_PCIE_0_PHY_RCHNG_CLK_SRC 43
+#define GCC_PCIE_0_PIPE_CLK 44
+#define GCC_PCIE_0_PIPE_CLK_SRC 45
+#define GCC_PCIE_0_PIPE_DIV2_CLK 46
+#define GCC_PCIE_0_PIPE_DIV_CLK_SRC 47
+#define GCC_PCIE_0_SLV_AXI_CLK 48
+#define GCC_PCIE_0_SLV_Q2A_AXI_CLK 49
+#define GCC_PCIE_1_AUX_CLK 50
+#define GCC_PCIE_1_AUX_CLK_SRC 51
+#define GCC_PCIE_1_CFG_AHB_CLK 52
+#define GCC_PCIE_1_MSTR_AXI_CLK 53
+#define GCC_PCIE_1_PHY_AUX_CLK 54
+#define GCC_PCIE_1_PHY_AUX_CLK_SRC 55
+#define GCC_PCIE_1_PHY_RCHNG_CLK 56
+#define GCC_PCIE_1_PHY_RCHNG_CLK_SRC 57
+#define GCC_PCIE_1_PIPE_CLK 58
+#define GCC_PCIE_1_PIPE_CLK_SRC 59
+#define GCC_PCIE_1_PIPE_DIV2_CLK 60
+#define GCC_PCIE_1_PIPE_DIV_CLK_SRC 61
+#define GCC_PCIE_1_RSC_CORE_CLK 62
+#define GCC_PCIE_1_SLV_AXI_CLK 63
+#define GCC_PCIE_1_SLV_Q2A_AXI_CLK 64
+#define GCC_PCIE_RSC_CORE_CLK 65
+#define GCC_PCIE_RSCC_CFG_AHB_CLK 66
+#define GCC_PCIE_RSCC_XO_CLK 67
+#define GCC_PDM2_CLK 68
+#define GCC_PDM2_CLK_SRC 69
+#define GCC_PDM_AHB_CLK 70
+#define GCC_PDM_XO4_CLK 71
+#define GCC_QUPV3_I2C_CORE_CLK 72
+#define GCC_QUPV3_I2C_S0_CLK 73
+#define GCC_QUPV3_I2C_S0_CLK_SRC 74
+#define GCC_QUPV3_I2C_S1_CLK 75
+#define GCC_QUPV3_I2C_S1_CLK_SRC 76
+#define GCC_QUPV3_I2C_S2_CLK 77
+#define GCC_QUPV3_I2C_S2_CLK_SRC 78
+#define GCC_QUPV3_I2C_S3_CLK 79
+#define GCC_QUPV3_I2C_S3_CLK_SRC 80
+#define GCC_QUPV3_I2C_S4_CLK 81
+#define GCC_QUPV3_I2C_S4_CLK_SRC 82
+#define GCC_QUPV3_I2C_S_AHB_CLK 83
+#define GCC_QUPV3_WRAP1_CORE_2X_CLK 84
+#define GCC_QUPV3_WRAP1_CORE_CLK 85
+#define GCC_QUPV3_WRAP1_QSPI_REF_CLK 86
+#define GCC_QUPV3_WRAP1_QSPI_REF_CLK_SRC 87
+#define GCC_QUPV3_WRAP1_S0_CLK 88
+#define GCC_QUPV3_WRAP1_S0_CLK_SRC 89
+#define GCC_QUPV3_WRAP1_S1_CLK 90
+#define GCC_QUPV3_WRAP1_S1_CLK_SRC 91
+#define GCC_QUPV3_WRAP1_S2_CLK 92
+#define GCC_QUPV3_WRAP1_S2_CLK_SRC 93
+#define GCC_QUPV3_WRAP1_S3_CLK 94
+#define GCC_QUPV3_WRAP1_S3_CLK_SRC 95
+#define GCC_QUPV3_WRAP1_S4_CLK 96
+#define GCC_QUPV3_WRAP1_S4_CLK_SRC 97
+#define GCC_QUPV3_WRAP1_S5_CLK 98
+#define GCC_QUPV3_WRAP1_S5_CLK_SRC 99
+#define GCC_QUPV3_WRAP1_S6_CLK 100
+#define GCC_QUPV3_WRAP1_S6_CLK_SRC 101
+#define GCC_QUPV3_WRAP1_S7_CLK 102
+#define GCC_QUPV3_WRAP1_S7_CLK_SRC 103
+#define GCC_QUPV3_WRAP2_CORE_2X_CLK 104
+#define GCC_QUPV3_WRAP2_CORE_CLK 105
+#define GCC_QUPV3_WRAP2_S0_CLK 106
+#define GCC_QUPV3_WRAP2_S0_CLK_SRC 107
+#define GCC_QUPV3_WRAP2_S1_CLK 108
+#define GCC_QUPV3_WRAP2_S1_CLK_SRC 109
+#define GCC_QUPV3_WRAP2_S2_CLK 110
+#define GCC_QUPV3_WRAP2_S2_CLK_SRC 111
+#define GCC_QUPV3_WRAP2_S3_CLK 112
+#define GCC_QUPV3_WRAP2_S3_CLK_SRC 113
+#define GCC_QUPV3_WRAP2_S4_CLK 114
+#define GCC_QUPV3_WRAP2_S4_CLK_SRC 115
+#define GCC_QUPV3_WRAP3_CORE_2X_CLK 116
+#define GCC_QUPV3_WRAP3_CORE_CLK 117
+#define GCC_QUPV3_WRAP3_QSPI_REF_CLK 118
+#define GCC_QUPV3_WRAP3_QSPI_REF_CLK_SRC 119
+#define GCC_QUPV3_WRAP3_S0_CLK 120
+#define GCC_QUPV3_WRAP3_S0_CLK_SRC 121
+#define GCC_QUPV3_WRAP3_S1_CLK 122
+#define GCC_QUPV3_WRAP3_S1_CLK_SRC 123
+#define GCC_QUPV3_WRAP3_S2_CLK 124
+#define GCC_QUPV3_WRAP3_S2_CLK_SRC 125
+#define GCC_QUPV3_WRAP3_S3_CLK 126
+#define GCC_QUPV3_WRAP3_S3_CLK_SRC 127
+#define GCC_QUPV3_WRAP3_S4_CLK 128
+#define GCC_QUPV3_WRAP3_S4_CLK_SRC 129
+#define GCC_QUPV3_WRAP3_S5_CLK 130
+#define GCC_QUPV3_WRAP3_S5_CLK_SRC 131
+#define GCC_QUPV3_WRAP4_CORE_2X_CLK 132
+#define GCC_QUPV3_WRAP4_CORE_CLK 133
+#define GCC_QUPV3_WRAP4_S0_CLK 134
+#define GCC_QUPV3_WRAP4_S0_CLK_SRC 135
+#define GCC_QUPV3_WRAP4_S1_CLK 136
+#define GCC_QUPV3_WRAP4_S1_CLK_SRC 137
+#define GCC_QUPV3_WRAP4_S2_CLK 138
+#define GCC_QUPV3_WRAP4_S2_CLK_SRC 139
+#define GCC_QUPV3_WRAP4_S3_CLK 140
+#define GCC_QUPV3_WRAP4_S3_CLK_SRC 141
+#define GCC_QUPV3_WRAP4_S4_CLK 142
+#define GCC_QUPV3_WRAP4_S4_CLK_SRC 143
+#define GCC_QUPV3_WRAP_1_M_AXI_CLK 144
+#define GCC_QUPV3_WRAP_1_S_AHB_CLK 145
+#define GCC_QUPV3_WRAP_2_M_AHB_CLK 146
+#define GCC_QUPV3_WRAP_2_S_AHB_CLK 147
+#define GCC_QUPV3_WRAP_3_M_AHB_CLK 148
+#define GCC_QUPV3_WRAP_3_S_AHB_CLK 149
+#define GCC_QUPV3_WRAP_4_M_AHB_CLK 150
+#define GCC_QUPV3_WRAP_4_S_AHB_CLK 151
+#define GCC_SDCC2_AHB_CLK 152
+#define GCC_SDCC2_APPS_CLK 153
+#define GCC_SDCC2_APPS_CLK_SRC 154
+#define GCC_SDCC4_AHB_CLK 155
+#define GCC_SDCC4_APPS_CLK 156
+#define GCC_SDCC4_APPS_CLK_SRC 157
+#define GCC_UFS_PHY_AHB_CLK 158
+#define GCC_UFS_PHY_AXI_CLK 159
+#define GCC_UFS_PHY_AXI_CLK_SRC 160
+#define GCC_UFS_PHY_ICE_CORE_CLK 161
+#define GCC_UFS_PHY_ICE_CORE_CLK_SRC 162
+#define GCC_UFS_PHY_PHY_AUX_CLK 163
+#define GCC_UFS_PHY_PHY_AUX_CLK_SRC 164
+#define GCC_UFS_PHY_RX_SYMBOL_0_CLK 165
+#define GCC_UFS_PHY_RX_SYMBOL_0_CLK_SRC 166
+#define GCC_UFS_PHY_RX_SYMBOL_1_CLK 167
+#define GCC_UFS_PHY_RX_SYMBOL_1_CLK_SRC 168
+#define GCC_UFS_PHY_TX_SYMBOL_0_CLK 169
+#define GCC_UFS_PHY_TX_SYMBOL_0_CLK_SRC 170
+#define GCC_UFS_PHY_UNIPRO_5_CORE_CLK 171
+#define GCC_UFS_PHY_UNIPRO_5_CORE_CLK_SRC 172
+#define GCC_USB30_PRIM_MASTER_CLK 173
+#define GCC_USB30_PRIM_MASTER_CLK_SRC 174
+#define GCC_USB30_PRIM_MOCK_UTMI_CLK 175
+#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC 176
+#define GCC_USB30_PRIM_MOCK_UTMI_POSTDIV_CLK_SRC 177
+#define GCC_USB30_PRIM_SLEEP_CLK 178
+#define GCC_USB3_PRIM_PHY_AUX_CLK 179
+#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC 180
+#define GCC_USB3_PRIM_PHY_COM_AUX_CLK 181
+#define GCC_USB3_PRIM_PHY_PIPE_CLK 182
+#define GCC_USB3_PRIM_PHY_PIPE_CLK_SRC 183
+#define GCC_VIDEO_AHB_CLK 184
+#define GCC_VIDEO_AXI0_CLK 185
+#define GCC_VIDEO_AXI0C_CLK 186
+#define GCC_VIDEO_XO_CLK 187
+
+/* GCC power domains */
+#define GCC_PCIE_0_GDSC 0
+#define GCC_PCIE_0_PHY_GDSC 1
+#define GCC_PCIE_1_GDSC 2
+#define GCC_PCIE_1_PHY_GDSC 3
+#define GCC_UFS_MEM_PHY_GDSC 4
+#define GCC_UFS_PHY_GDSC 5
+#define GCC_USB30_PRIM_GDSC 6
+#define GCC_USB3_PHY_GDSC 7
+
+/* GCC resets */
+#define GCC_CAMERA_BCR 0
+#define GCC_EVA_AXI0_CLK_ARES 1
+#define GCC_EVA_AXI0C_CLK_ARES 2
+#define GCC_EVA_BCR 3
+#define GCC_GPU_BCR 4
+#define GCC_PCIE_0_BCR 5
+#define GCC_PCIE_0_LINK_DOWN_BCR 6
+#define GCC_PCIE_0_NOCSR_COM_PHY_BCR 7
+#define GCC_PCIE_0_PHY_BCR 8
+#define GCC_PCIE_0_PHY_NOCSR_COM_PHY_BCR 9
+#define GCC_PCIE_1_BCR 10
+#define GCC_PCIE_1_LINK_DOWN_BCR 11
+#define GCC_PCIE_1_NOCSR_COM_PHY_BCR 12
+#define GCC_PCIE_1_PHY_BCR 13
+#define GCC_PCIE_1_PHY_NOCSR_COM_PHY_BCR 14
+#define GCC_PCIE_PHY_BCR 15
+#define GCC_PCIE_PHY_CFG_AHB_BCR 16
+#define GCC_PCIE_PHY_COM_BCR 17
+#define GCC_PCIE_RSCC_BCR 18
+#define GCC_PDM_BCR 19
+#define GCC_QUPV3_WRAPPER_1_BCR 20
+#define GCC_QUPV3_WRAPPER_2_BCR 21
+#define GCC_QUPV3_WRAPPER_3_BCR 22
+#define GCC_QUPV3_WRAPPER_4_BCR 23
+#define GCC_QUPV3_WRAPPER_I2C_BCR 24
+#define GCC_QUSB2PHY_PRIM_BCR 25
+#define GCC_QUSB2PHY_SEC_BCR 26
+#define GCC_SDCC2_BCR 27
+#define GCC_SDCC4_BCR 28
+#define GCC_TCSR_PCIE_BCR 29
+#define GCC_UFS_PHY_BCR 30
+#define GCC_USB30_PRIM_BCR 31
+#define GCC_USB3_DP_PHY_PRIM_BCR 32
+#define GCC_USB3_DP_PHY_SEC_BCR 33
+#define GCC_USB3_PHY_PRIM_BCR 34
+#define GCC_USB3_PHY_SEC_BCR 35
+#define GCC_USB3PHY_PHY_PRIM_BCR 36
+#define GCC_USB3PHY_PHY_SEC_BCR 37
+#define GCC_VIDEO_AXI0_CLK_ARES 38
+#define GCC_VIDEO_AXI0C_CLK_ARES 39
+#define GCC_VIDEO_BCR 40
+#define GCC_VIDEO_XO_CLK_ARES 41
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,hawi-tcsrcc.h b/include/dt-bindings/clock/qcom,hawi-tcsrcc.h
new file mode 100644
index 000000000000..957bc5f75bb7
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,hawi-tcsrcc.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_TCSR_CC_HAWI_H
+#define _DT_BINDINGS_CLK_QCOM_TCSR_CC_HAWI_H
+
+/* TCSR_CC clocks */
+#define TCSR_PCIE_0_CLKREF_EN 0
+#define TCSR_PCIE_1_CLKREF_EN 1
+#define TCSR_UFS_CLKREF_EN 2
+#define TCSR_USB2_CLKREF_EN 3
+#define TCSR_USB3_CLKREF_EN 4
+
+#endif
diff --git a/include/dt-bindings/clock/qcom,ipq5332-cmn-pll.h b/include/dt-bindings/clock/qcom,ipq5332-cmn-pll.h
new file mode 100644
index 000000000000..172330e43669
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,ipq5332-cmn-pll.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_IPQ5332_CMN_PLL_H
+#define _DT_BINDINGS_CLK_QCOM_IPQ5332_CMN_PLL_H
+
+/* CMN PLL core clock. */
+#define IPQ5332_CMN_PLL_CLK 0
+
+/* The output clocks from CMN PLL of IPQ5332. */
+#define IPQ5332_XO_24MHZ_CLK 1
+#define IPQ5332_SLEEP_32KHZ_CLK 2
+#define IPQ5332_PCS_31P25MHZ_CLK 3
+#define IPQ5332_NSS_300MHZ_CLK 4
+#define IPQ5332_PPE_200MHZ_CLK 5
+#define IPQ5332_ETH_50MHZ_CLK 6
+#endif
diff --git a/include/dt-bindings/clock/qcom,nord-negcc.h b/include/dt-bindings/clock/qcom,nord-negcc.h
index 95f333d8e1aa..a7024317e90b 100644
--- a/include/dt-bindings/clock/qcom,nord-negcc.h
+++ b/include/dt-bindings/clock/qcom,nord-negcc.h
@@ -120,5 +120,6 @@
#define NE_GCC_USB3_PHY_SEC_BCR 10
#define NE_GCC_USB3PHY_PHY_PRIM_BCR 11
#define NE_GCC_USB3PHY_PHY_SEC_BCR 12
+#define NE_GCC_QUSB2PHY_PRIM_BCR 13
#endif
diff --git a/include/dt-bindings/clock/qcom,rpmh.h b/include/dt-bindings/clock/qcom,rpmh.h
index 0a7d1be0d124..2d62d5d0b08d 100644
--- a/include/dt-bindings/clock/qcom,rpmh.h
+++ b/include/dt-bindings/clock/qcom,rpmh.h
@@ -33,5 +33,7 @@
#define RPMH_HWKM_CLK 24
#define RPMH_QLINK_CLK 25
#define RPMH_QLINK_CLK_A 26
+#define RPMH_LN_BB_CLK4 27
+#define RPMH_LN_BB_CLK4_A 28
#endif
diff --git a/include/dt-bindings/clock/qcom,x1e80100-camcc.h b/include/dt-bindings/clock/qcom,x1e80100-camcc.h
index d72fdfb06a7c..06c316022fb0 100644
--- a/include/dt-bindings/clock/qcom,x1e80100-camcc.h
+++ b/include/dt-bindings/clock/qcom,x1e80100-camcc.h
@@ -115,6 +115,9 @@
#define CAM_CC_SLEEP_CLK_SRC 105
#define CAM_CC_SLOW_AHB_CLK_SRC 106
#define CAM_CC_XO_CLK_SRC 107
+#define CAM_CC_QDSS_DEBUG_CLK 108
+#define CAM_CC_QDSS_DEBUG_CLK_SRC 109
+#define CAM_CC_QDSS_DEBUG_XO_CLK 110
/* CAM_CC power domains */
#define CAM_CC_BPS_GDSC 0
diff --git a/include/dt-bindings/clock/qcom,x1p42100-videocc.h b/include/dt-bindings/clock/qcom,x1p42100-videocc.h
new file mode 100644
index 000000000000..996408d1a0c3
--- /dev/null
+++ b/include/dt-bindings/clock/qcom,x1p42100-videocc.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef _DT_BINDINGS_CLK_QCOM_VIDEO_CC_X1P42100_H
+#define _DT_BINDINGS_CLK_QCOM_VIDEO_CC_X1P42100_H
+
+/* VIDEO_CC clocks */
+#define VIDEO_CC_MVS0_CLK 0
+#define VIDEO_CC_MVS0_CLK_SRC 1
+#define VIDEO_CC_MVS0_DIV_CLK_SRC 2
+#define VIDEO_CC_MVS0C_CLK 3
+#define VIDEO_CC_MVS0C_DIV2_DIV_CLK_SRC 4
+#define VIDEO_CC_MVS1_CLK 5
+#define VIDEO_CC_MVS1_CLK_SRC 6
+#define VIDEO_CC_MVS1_DIV_CLK_SRC 7
+#define VIDEO_CC_MVS1C_CLK 8
+#define VIDEO_CC_MVS1C_DIV2_DIV_CLK_SRC 9
+#define VIDEO_CC_PLL0 10
+#define VIDEO_CC_PLL1 11
+#define VIDEO_CC_MVS0_SHIFT_CLK 12
+#define VIDEO_CC_MVS0C_SHIFT_CLK 13
+#define VIDEO_CC_MVS1_SHIFT_CLK 14
+#define VIDEO_CC_MVS1C_SHIFT_CLK 15
+#define VIDEO_CC_XO_CLK_SRC 16
+#define VIDEO_CC_MVS0_BSE_CLK 17
+#define VIDEO_CC_MVS0_BSE_CLK_SRC 18
+#define VIDEO_CC_MVS0_BSE_DIV4_DIV_CLK_SRC 19
+
+/* VIDEO_CC power domains */
+#define VIDEO_CC_MVS0C_GDSC 0
+#define VIDEO_CC_MVS0_GDSC 1
+#define VIDEO_CC_MVS1C_GDSC 2
+#define VIDEO_CC_MVS1_GDSC 3
+
+/* VIDEO_CC resets */
+#define CVP_VIDEO_CC_INTERFACE_BCR 0
+#define CVP_VIDEO_CC_MVS0_BCR 1
+#define CVP_VIDEO_CC_MVS0C_BCR 2
+#define CVP_VIDEO_CC_MVS1_BCR 3
+#define CVP_VIDEO_CC_MVS1C_BCR 4
+#define VIDEO_CC_MVS0C_CLK_ARES 5
+#define VIDEO_CC_MVS1C_CLK_ARES 6
+#define VIDEO_CC_XO_CLK_ARES 7
+#define VIDEO_CC_MVS0_BSE_BCR 8
+
+#endif
diff --git a/include/dt-bindings/clock/rockchip,rk3588-cru.h b/include/dt-bindings/clock/rockchip,rk3588-cru.h
index 0c7d3ca2d5bc..7528034cff56 100644
--- a/include/dt-bindings/clock/rockchip,rk3588-cru.h
+++ b/include/dt-bindings/clock/rockchip,rk3588-cru.h
@@ -734,6 +734,10 @@
#define PCLK_AV1_PRE 719
#define HCLK_SDIO_PRE 720
#define PCLK_VO1GRF 721
+#define I2S0_8CH_MCLKOUT_TO_IO 722
+#define I2S1_8CH_MCLKOUT_TO_IO 723
+#define I2S2_2CH_MCLKOUT_TO_IO 724
+#define I2S3_2CH_MCLKOUT_TO_IO 725
/* scmi-clocks indices */
diff --git a/include/dt-bindings/clock/spacemit,k3-clocks.h b/include/dt-bindings/clock/spacemit,k3-clocks.h
index b22336f3ae40..dfae52547cda 100644
--- a/include/dt-bindings/clock/spacemit,k3-clocks.h
+++ b/include/dt-bindings/clock/spacemit,k3-clocks.h
@@ -380,6 +380,11 @@
#define CLK_APMU_ISIM_VCLK1 86
#define CLK_APMU_ISIM_VCLK2 87
#define CLK_APMU_ISIM_VCLK3 88
+#define CLK_APMU_PCIE_PORTA_DBI 89
+#define CLK_APMU_PCIE_PORTB_DBI 90
+#define CLK_APMU_PCIE_PORTC_DBI 91
+#define CLK_APMU_PCIE_PORTD_DBI 92
+#define CLK_APMU_PCIE_PORTE_DBI 93
/* DCIU clocks */
#define CLK_DCIU_HDMA 0
diff --git a/include/linux/adi-axi-common.h b/include/linux/adi-axi-common.h
index 37962ba530df..e7ba393061ee 100644
--- a/include/linux/adi-axi-common.h
+++ b/include/linux/adi-axi-common.h
@@ -51,6 +51,7 @@ enum adi_axi_fpga_technology {
ADI_AXI_FPGA_TECH_SERIES7,
ADI_AXI_FPGA_TECH_ULTRASCALE,
ADI_AXI_FPGA_TECH_ULTRASCALE_PLUS,
+ ADI_AXI_FPGA_TECH_VERSAL,
};
enum adi_axi_fpga_family {
@@ -71,6 +72,7 @@ enum adi_axi_fpga_speed_grade {
ADI_AXI_FPGA_SPEED_2 = 20,
ADI_AXI_FPGA_SPEED_2L = 21,
ADI_AXI_FPGA_SPEED_2LV = 22,
+ ADI_AXI_FPGA_SPEED_2MP = 23,
ADI_AXI_FPGA_SPEED_3 = 30,
};
diff --git a/include/linux/clk/renesas.h b/include/linux/clk/renesas.h
index c360df9fa735..0949400f44de 100644
--- a/include/linux/clk/renesas.h
+++ b/include/linux/clk/renesas.h
@@ -164,6 +164,26 @@ struct rzv2h_pll_div_pars {
.k = { .min = -32768, .max = 32767 }, \
} \
+#define RZG3E_CPG_PLL_DSI0_LIMITS(name) \
+ static const struct rzv2h_pll_limits (name) = { \
+ .fout = { .min = 25 * MEGA, .max = 1218 * MEGA }, \
+ .fvco = { .min = 1600 * MEGA, .max = 3200 * MEGA }, \
+ .m = { .min = 64, .max = 533 }, \
+ .p = { .min = 1, .max = 4 }, \
+ .s = { .min = 0, .max = 6 }, \
+ .k = { .min = -32768, .max = 32767 }, \
+ } \
+
+#define RZG3E_CPG_PLL_DSI1_LIMITS(name) \
+ static const struct rzv2h_pll_limits (name) = { \
+ .fout = { .min = 25 * MEGA, .max = 609 * MEGA }, \
+ .fvco = { .min = 1600 * MEGA, .max = 3200 * MEGA }, \
+ .m = { .min = 64, .max = 533 }, \
+ .p = { .min = 1, .max = 4 }, \
+ .s = { .min = 0, .max = 6 }, \
+ .k = { .min = -32768, .max = 32767 }, \
+ } \
+
#ifdef CONFIG_CLK_RZV2H
bool rzv2h_get_pll_pars(const struct rzv2h_pll_limits *limits,
struct rzv2h_pll_pars *pars, u64 freq_millihz);
diff --git a/include/linux/interconnect.h b/include/linux/interconnect.h
index 4b12821528a6..75a32ad0482e 100644
--- a/include/linux/interconnect.h
+++ b/include/linux/interconnect.h
@@ -47,6 +47,7 @@ struct icc_path *of_icc_get(struct device *dev, const char *name);
struct icc_path *devm_of_icc_get(struct device *dev, const char *name);
int devm_of_icc_bulk_get(struct device *dev, int num_paths, struct icc_bulk_data *paths);
struct icc_path *of_icc_get_by_index(struct device *dev, int idx);
+struct icc_path *devm_of_icc_get_by_index(struct device *dev, int idx);
void icc_put(struct icc_path *path);
int icc_enable(struct icc_path *path);
int icc_disable(struct icc_path *path);
@@ -79,6 +80,11 @@ static inline struct icc_path *of_icc_get_by_index(struct device *dev, int idx)
return NULL;
}
+static inline struct icc_path *devm_of_icc_get_by_index(struct device *dev, int idx)
+{
+ return NULL;
+}
+
static inline void icc_put(struct icc_path *path)
{
}
diff --git a/include/linux/ntb.h b/include/linux/ntb.h
index 879c3e89e026..ae72caa03859 100644
--- a/include/linux/ntb.h
+++ b/include/linux/ntb.h
@@ -567,7 +567,7 @@ void ntb_msg_event(struct ntb_dev *ntb);
int ntb_default_port_number(struct ntb_dev *ntb);
/**
- * ntb_default_port_count() - get the default number of peer device ports
+ * ntb_default_peer_port_count() - get the default number of peer device ports
* @ntb: NTB device context.
*
* By default hardware driver supports just one peer device.
@@ -582,7 +582,7 @@ int ntb_default_peer_port_count(struct ntb_dev *ntb);
/**
* ntb_default_peer_port_number() - get the default peer port by given index
* @ntb: NTB device context.
- * @idx: Peer port index (should not differ from zero).
+ * @pidx: Peer port index (should not differ from zero).
*
* By default hardware driver supports just one peer device, so this method
* shall return the corresponding value from enum ntb_default_port.
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index 95da051fb155..c09fc22819d0 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -190,6 +190,8 @@ extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm);
int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm);
extern int rtc_read_alarm(struct rtc_device *rtc,
struct rtc_wkalrm *alrm);
+extern int rtc_read_next_alarm(struct rtc_device *rtc,
+ struct rtc_wkalrm *alrm);
extern int rtc_set_alarm(struct rtc_device *rtc,
struct rtc_wkalrm *alrm);
extern int rtc_initialize_alarm(struct rtc_device *rtc,
diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index a46cbaec5949..b484784e2690 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -11,6 +11,7 @@
#include <linux/idr.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
+#include <linux/jiffies.h>
#include <linux/lockdep_types.h>
#include <linux/mod_devicetable.h>
#include <linux/mutex.h>
@@ -1093,8 +1094,6 @@ int sdw_slave_get_current_bank(struct sdw_slave *sdev);
int sdw_slave_get_scale_index(struct sdw_slave *slave, u8 *base);
-int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms);
-
/* messaging and data APIs */
int sdw_read(struct sdw_slave *slave, u32 addr);
int sdw_write(struct sdw_slave *slave, u32 addr, u8 value);
@@ -1138,12 +1137,6 @@ static inline int sdw_slave_get_current_bank(struct sdw_slave *sdev)
return -EINVAL;
}
-static inline int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms)
-{
- WARN_ONCE(1, "SoundWire API is disabled");
- return -EINVAL;
-}
-
/* messaging and data APIs */
static inline int sdw_read(struct sdw_slave *slave, u32 addr)
{
@@ -1207,4 +1200,33 @@ static inline int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u
#endif /* CONFIG_SOUNDWIRE */
+/**
+ * sdw_slave_wait_for_init - Wait for device initialisation
+ * @slave: Pointer to the SoundWire peripheral.
+ * @timeout_ms: Timeout in milliseconds.
+ *
+ * Wait for a peripheral device to enumerate and be initialised by the
+ * SoundWire core.
+ *
+ * Return: Zero on success, and a negative error code on failure.
+ */
+static inline int sdw_slave_wait_for_init(struct sdw_slave *slave, int timeout_ms)
+{
+ unsigned long time;
+
+ if (!slave)
+ return 0;
+
+ time = wait_for_completion_timeout(&slave->initialization_complete,
+ msecs_to_jiffies(timeout_ms));
+ if (!time) {
+ dev_err(&slave->dev, "Initialization not complete\n");
+ return -ETIMEDOUT;
+ }
+
+ slave->unattach_request = 0;
+
+ return 0;
+}
+
#endif /* __SOUNDWIRE_H */
diff --git a/include/linux/spmi.h b/include/linux/spmi.h
index 28e8c8bd3944..4eb9564a7fb3 100644
--- a/include/linux/spmi.h
+++ b/include/linux/spmi.h
@@ -76,6 +76,7 @@ void spmi_device_remove(struct spmi_device *sdev);
* @cmd: sends a non-data command sequence on the SPMI bus.
* @read_cmd: sends a register read command sequence on the SPMI bus.
* @write_cmd: sends a register write command sequence on the SPMI bus.
+ * @priv: array of private data.
*/
struct spmi_controller {
struct device dev;
@@ -85,6 +86,7 @@ struct spmi_controller {
u8 sid, u16 addr, u8 *buf, size_t len);
int (*write_cmd)(struct spmi_controller *ctrl, u8 opcode,
u8 sid, u16 addr, const u8 *buf, size_t len);
+ u8 priv[];
};
static inline struct spmi_controller *to_spmi_controller(struct device *d)
@@ -109,7 +111,7 @@ struct spmi_controller *spmi_controller_alloc(struct device *parent,
/**
* spmi_controller_put() - decrement controller refcount
- * @ctrl SPMI controller.
+ * @ctrl: SPMI controller.
*/
static inline void spmi_controller_put(struct spmi_controller *ctrl)
{
@@ -129,6 +131,7 @@ int devm_spmi_controller_add(struct device *parent, struct spmi_controller *ctrl
* this structure.
* @probe: binds this driver to a SPMI device.
* @remove: unbinds this driver from the SPMI device.
+ * @shutdown: shuts down this driver.
*
* If PM runtime support is desired for a slave, a device driver can call
* pm_runtime_put() from their probe() routine (and a balancing
diff --git a/include/net/tcp_ao.h b/include/net/tcp_ao.h
index 29fd7b735afa..9a2333e62e99 100644
--- a/include/net/tcp_ao.h
+++ b/include/net/tcp_ao.h
@@ -145,6 +145,7 @@ struct tcp_ao_info {
u32 snd_sne;
u32 rcv_sne;
refcount_t refcnt; /* Protects twsk destruction */
+ struct rcu_head rcu;
};
#ifdef CONFIG_TCP_MD5SIG
diff --git a/include/soc/rockchip/rk3588_grf.h b/include/soc/rockchip/rk3588_grf.h
index 02a7b2432d99..db0092fc66ad 100644
--- a/include/soc/rockchip/rk3588_grf.h
+++ b/include/soc/rockchip/rk3588_grf.h
@@ -19,4 +19,6 @@
/* Whether the LPDDR5 is in 2:1 (= 0) or 4:1 (= 1) CKR a.k.a. DQS mode */
#define RK3588_PMUGRF_OS_REG6_LP5_CKR BIT(0)
+#define RK3588_SYSGRF_SOC_CON6 0x0318
+
#endif /* __SOC_RK3588_GRF_H */
diff --git a/include/soc/spacemit/k3-syscon.h b/include/soc/spacemit/k3-syscon.h
index 0299bea065a0..a68255dd641f 100644
--- a/include/soc/spacemit/k3-syscon.h
+++ b/include/soc/spacemit/k3-syscon.h
@@ -168,8 +168,8 @@
#define APMU_CPU_C2_CLK_CTRL 0x394
#define APMU_CPU_C3_CLK_CTRL 0x208
#define APMU_PCIE_CLK_RES_CTRL_A 0x1f0
-#define APMU_PCIE_CLK_RES_CTRL_B 0x1c8
-#define APMU_PCIE_CLK_RES_CTRL_C 0x1d0
+#define APMU_PCIE_CLK_RES_CTRL_B 0x1d0
+#define APMU_PCIE_CLK_RES_CTRL_C 0x1c8
#define APMU_PCIE_CLK_RES_CTRL_D 0x1e0
#define APMU_PCIE_CLK_RES_CTRL_E 0x1e8
#define APMU_EMAC0_CLK_RES_CTRL 0x3e4
diff --git a/include/sound/soc-component.h b/include/sound/soc-component.h
index 11bc9527653f..aa423865dbe7 100644
--- a/include/sound/soc-component.h
+++ b/include/sound/soc-component.h
@@ -10,6 +10,8 @@
#include <sound/soc.h>
+struct device_link;
+
/*
* Component probe and remove ordering levels for components with runtime
* dependencies.
@@ -216,6 +218,8 @@ struct snd_soc_component {
struct list_head card_aux_list; /* for auxiliary bound components */
struct list_head card_list;
+ struct device_link *card_device_link;
+
const struct snd_soc_component_driver *driver;
struct list_head dai_list;
diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h
index d45f805b5d18..b763da613769 100644
--- a/include/sound/tas2781.h
+++ b/include/sound/tas2781.h
@@ -59,9 +59,9 @@
#define TASDEVICE_CHECKSUM_REG TASDEVICE_REG(0x0, 0x0, 0x7e)
/* XM_340 */
-#define TASDEVICE_XM_A1_REG TASDEVICE_REG(0x64, 0x63, 0x3c)
+#define TASDEVICE_XM_A1_REG TASDEVICE_REG(0x64, 0x02, 0x4c)
/* XM_341 */
-#define TASDEVICE_XM_A2_REG TASDEVICE_REG(0x64, 0x63, 0x38)
+#define TASDEVICE_XM_A2_REG TASDEVICE_REG(0x64, 0x02, 0x64)
/* Volume control */
#define TAS2563_DVC_LVL TASDEVICE_REG(0x00, 0x02, 0x0c)
diff --git a/include/trace/events/ceph.h b/include/trace/events/ceph.h
index 08cb0659fbfc..1b990632f62b 100644
--- a/include/trace/events/ceph.h
+++ b/include/trace/events/ceph.h
@@ -226,6 +226,73 @@ TRACE_EVENT(ceph_handle_caps,
__entry->mseq)
);
+/*
+ * Client reset tracepoints - identify the client by its monitor-
+ * assigned global_id so traces remain meaningful when kernel pointer
+ * hashing is enabled.
+ */
+TRACE_EVENT(ceph_client_reset_schedule,
+ TP_PROTO(const struct ceph_mds_client *mdsc, const char *reason),
+ TP_ARGS(mdsc, reason),
+ TP_STRUCT__entry(
+ __field(u64, client_id)
+ __string(reason, reason ? reason : "")
+ ),
+ TP_fast_assign(
+ __entry->client_id = mdsc->fsc->client->monc.auth ?
+ mdsc->fsc->client->monc.auth->global_id : 0;
+ __assign_str(reason);
+ ),
+ TP_printk("client_id=%llu reason=%s",
+ __entry->client_id, __get_str(reason))
+);
+
+TRACE_EVENT(ceph_client_reset_complete,
+ TP_PROTO(const struct ceph_mds_client *mdsc, int ret),
+ TP_ARGS(mdsc, ret),
+ TP_STRUCT__entry(
+ __field(u64, client_id)
+ __field(int, ret)
+ ),
+ TP_fast_assign(
+ __entry->client_id = mdsc->fsc->client->monc.auth ?
+ mdsc->fsc->client->monc.auth->global_id : 0;
+ __entry->ret = ret;
+ ),
+ TP_printk("client_id=%llu ret=%d", __entry->client_id, __entry->ret)
+);
+
+TRACE_EVENT(ceph_client_reset_blocked,
+ TP_PROTO(const struct ceph_mds_client *mdsc, int blocked_count),
+ TP_ARGS(mdsc, blocked_count),
+ TP_STRUCT__entry(
+ __field(u64, client_id)
+ __field(int, blocked_count)
+ ),
+ TP_fast_assign(
+ __entry->client_id = mdsc->fsc->client->monc.auth ?
+ mdsc->fsc->client->monc.auth->global_id : 0;
+ __entry->blocked_count = blocked_count;
+ ),
+ TP_printk("client_id=%llu blocked_count=%d", __entry->client_id,
+ __entry->blocked_count)
+);
+
+TRACE_EVENT(ceph_client_reset_unblocked,
+ TP_PROTO(const struct ceph_mds_client *mdsc, int ret),
+ TP_ARGS(mdsc, ret),
+ TP_STRUCT__entry(
+ __field(u64, client_id)
+ __field(int, ret)
+ ),
+ TP_fast_assign(
+ __entry->client_id = mdsc->fsc->client->monc.auth ?
+ mdsc->fsc->client->monc.auth->global_id : 0;
+ __entry->ret = ret;
+ ),
+ TP_printk("client_id=%llu ret=%d", __entry->client_id, __entry->ret)
+);
+
#undef EM
#undef E_
#endif /* _TRACE_CEPH_H */
diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
index 564071a92d7d..1433809bb166 100644
--- a/kernel/bpf/bpf_lsm.c
+++ b/kernel/bpf/bpf_lsm.c
@@ -51,6 +51,9 @@ BTF_ID(func, bpf_lsm_key_getsecurity)
#ifdef CONFIG_AUDIT
BTF_ID(func, bpf_lsm_audit_rule_match)
#endif
+#ifdef CONFIG_SECURITY_NETWORK_XFRM
+BTF_ID(func, bpf_lsm_xfrm_decode_session)
+#endif
BTF_ID(func, bpf_lsm_ismaclabel)
BTF_ID(func, bpf_lsm_file_alloc_security)
BTF_SET_END(bpf_lsm_disabled_hooks)
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 15ae7c43f594..64572f85edc8 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -28,6 +28,7 @@
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/overflow.h>
+#include <linux/bitops.h>
#include <net/netfilter/nf_bpf_link.h>
@@ -3472,12 +3473,69 @@ static int btf_find_struct(const struct btf *btf, const struct btf_type *t,
return BTF_FIELD_FOUND;
}
+struct btf_type_tag_match {
+ const char *name;
+ u32 flag;
+};
+
+struct btf_type_tag_walk_ctx {
+ const struct btf_type *t; /* Input/Output */
+ u32 id; /* Output */
+ u32 res; /* Output */
+};
+
+static int btf_type_tag_walk(const struct btf *btf,
+ struct btf_type_tag_walk_ctx *ctx,
+ const struct btf_type_tag_match *matches,
+ u32 match_cnt)
+{
+ const struct btf_type *t = ctx->t;
+ u32 res = 0;
+ const char *tag;
+ u32 id, i;
+
+ do {
+ id = t->type;
+ t = btf_type_by_id(btf, id);
+
+ if (!btf_type_is_modifier(t))
+ break;
+
+ if (!btf_type_is_type_tag(t) || btf_type_kflag(t))
+ continue;
+
+ tag = __btf_name_by_offset(btf, t->name_off);
+ for (i = 0; i < match_cnt; i++) {
+ if (strcmp(tag, matches[i].name))
+ continue;
+ res |= matches[i].flag;
+ break;
+ }
+ } while (true);
+
+ /* We only support a single tag. */
+ if (hweight32(res) > 1)
+ return -EINVAL;
+
+ ctx->t = t;
+ ctx->id = id;
+ ctx->res = res;
+
+ return 0;
+}
+
static int btf_find_kptr(const struct btf *btf, const struct btf_type *t,
u32 off, int sz, struct btf_field_info *info, u32 field_mask)
{
- enum btf_field_type type;
- const char *tag_value;
- bool is_type_tag;
+ static const struct btf_type_tag_match kptr_type_tags[] = {
+ { "kptr_untrusted", BPF_KPTR_UNREF },
+ { "kptr", BPF_KPTR_REF },
+ { "percpu_kptr", BPF_KPTR_PERCPU },
+ { "uptr", BPF_UPTR },
+ };
+ struct btf_type_tag_walk_ctx ctx;
+ enum btf_field_type type = 0;
+ int err;
u32 res_id;
/* Permit modifiers on the pointer itself */
@@ -3486,30 +3544,20 @@ static int btf_find_kptr(const struct btf *btf, const struct btf_type *t,
/* For PTR, sz is always == 8 */
if (!btf_type_is_ptr(t))
return BTF_FIELD_IGNORE;
- t = btf_type_by_id(btf, t->type);
- is_type_tag = btf_type_is_type_tag(t) && !btf_type_kflag(t);
- if (!is_type_tag)
- return BTF_FIELD_IGNORE;
- /* Reject extra tags */
- if (btf_type_is_type_tag(btf_type_by_id(btf, t->type)))
- return -EINVAL;
- tag_value = __btf_name_by_offset(btf, t->name_off);
- if (!strcmp("kptr_untrusted", tag_value))
- type = BPF_KPTR_UNREF;
- else if (!strcmp("kptr", tag_value))
- type = BPF_KPTR_REF;
- else if (!strcmp("percpu_kptr", tag_value))
- type = BPF_KPTR_PERCPU;
- else if (!strcmp("uptr", tag_value))
- type = BPF_UPTR;
- else
- return -EINVAL;
+
+ ctx.t = t;
+ err = btf_type_tag_walk(btf, &ctx, kptr_type_tags,
+ ARRAY_SIZE(kptr_type_tags));
+ if (err)
+ return err;
+
+ t = ctx.t;
+ res_id = ctx.id;
+ type = ctx.res;
if (!(type & field_mask))
return BTF_FIELD_IGNORE;
- /* Get the base type */
- t = btf_type_skip_modifiers(btf, t->type, &res_id);
/* Only pointer to struct is allowed */
if (!__btf_type_is_struct(t))
return -EINVAL;
@@ -5859,11 +5907,10 @@ struct btf_struct_meta *btf_find_struct_meta(const struct btf *btf, u32 btf_id)
return bsearch(&btf_id, tab->types, tab->cnt, sizeof(tab->types[0]), btf_id_cmp_func);
}
-static int btf_check_type_tags(struct btf_verifier_env *env,
- struct btf *btf, int start_id)
+static int btf_check_modifier_chain_length(struct btf_verifier_env *env,
+ struct btf *btf, int start_id)
{
int i, n, good_id = start_id - 1;
- bool in_tags;
n = btf_nr_types(btf);
for (i = start_id; i < n; i++) {
@@ -5879,20 +5926,12 @@ static int btf_check_type_tags(struct btf_verifier_env *env,
cond_resched();
- in_tags = btf_type_is_type_tag(t);
while (btf_type_is_modifier(t)) {
if (!chain_limit--) {
btf_verifier_log(env, "Max chain length or cycle detected");
return -ELOOP;
}
- if (btf_type_is_type_tag(t)) {
- if (!in_tags) {
- btf_verifier_log(env, "Type tags don't precede modifiers");
- return -EINVAL;
- }
- } else if (in_tags) {
- in_tags = false;
- }
+
if (cur_id <= good_id)
break;
/* Move to next type */
@@ -5970,7 +6009,7 @@ static struct btf *btf_parse(const union bpf_attr *attr, bpfptr_t uattr,
if (err)
goto errout;
- err = btf_check_type_tags(env, btf, 1);
+ err = btf_check_modifier_chain_length(env, btf, 1);
if (err)
goto errout;
@@ -6378,7 +6417,7 @@ static struct btf *btf_parse_base(struct btf_verifier_env *env, const char *name
if (err)
goto errout;
- err = btf_check_type_tags(env, btf, 1);
+ err = btf_check_modifier_chain_length(env, btf, 1);
if (err)
goto errout;
@@ -6504,7 +6543,7 @@ static struct btf *btf_parse_module(const char *module_name, const void *data,
if (err)
goto errout;
- err = btf_check_type_tags(env, btf, btf_nr_types(base_btf));
+ err = btf_check_modifier_chain_length(env, btf, btf_nr_types(base_btf));
if (err)
goto errout;
@@ -6810,14 +6849,18 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
const struct bpf_prog *prog,
struct bpf_insn_access_aux *info)
{
+ static const struct btf_type_tag_match ctx_type_tags[] = {
+ { "user", MEM_USER },
+ { "percpu", MEM_PERCPU },
+ };
const struct btf_type *t = prog->aux->attach_func_proto;
struct bpf_prog *tgt_prog = prog->aux->dst_prog;
struct btf *btf = bpf_prog_get_target_btf(prog);
const char *tname = prog->aux->attach_func_name;
struct bpf_verifier_log *log = info->log;
+ struct btf_type_tag_walk_ctx ctx;
const struct btf_param *args;
bool ptr_err_raw_tp = false;
- const char *tag_value;
u32 nr_args, arg;
int i, ret;
@@ -7020,22 +7063,18 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
}
info->btf = btf;
- info->btf_id = t->type;
- t = btf_type_by_id(btf, t->type);
-
- if (btf_type_is_type_tag(t) && !btf_type_kflag(t)) {
- tag_value = __btf_name_by_offset(btf, t->name_off);
- if (strcmp(tag_value, "user") == 0)
- info->reg_type |= MEM_USER;
- if (strcmp(tag_value, "percpu") == 0)
- info->reg_type |= MEM_PERCPU;
+ ctx.t = t;
+ ret = btf_type_tag_walk(btf, &ctx, ctx_type_tags,
+ ARRAY_SIZE(ctx_type_tags));
+ if (ret) {
+ bpf_log(log, "func '%s' arg%d type %s has multiple type tags\n",
+ tname, arg, btf_type_str(t));
+ return false;
}
+ info->reg_type |= ctx.res;
+ info->btf_id = ctx.id;
+ t = ctx.t;
- /* skip modifiers */
- while (btf_type_is_modifier(t)) {
- info->btf_id = t->type;
- t = btf_type_by_id(btf, t->type);
- }
if (!btf_type_is_struct(t)) {
bpf_log(log,
"func '%s' arg%d type %s is not a struct\n",
@@ -7074,7 +7113,7 @@ static int btf_struct_walk(struct bpf_verifier_log *log, const struct btf *btf,
u32 i, moff, mtrue_end, msize = 0, total_nelems = 0;
const struct btf_type *mtype, *elem_type = NULL;
const struct btf_member *member;
- const char *tname, *mname, *tag_value;
+ const char *tname, *mname;
u32 vlen, elem_id, mid;
again:
@@ -7270,8 +7309,15 @@ error:
}
if (btf_type_is_ptr(mtype)) {
- const struct btf_type *stype, *t;
+ static const struct btf_type_tag_match walk_type_tags[] = {
+ { "user", MEM_USER },
+ { "percpu", MEM_PERCPU },
+ { "rcu", MEM_RCU },
+ };
enum bpf_type_flag tmp_flag = 0;
+ struct btf_type_tag_walk_ctx ctx = { .t = mtype };
+ const struct btf_type *stype;
+ int err;
u32 id;
if (msize != size || off != moff) {
@@ -7281,22 +7327,17 @@ error:
return -EACCES;
}
- /* check type tag */
- t = btf_type_by_id(btf, mtype->type);
- if (btf_type_is_type_tag(t) && !btf_type_kflag(t)) {
- tag_value = __btf_name_by_offset(btf, t->name_off);
- /* check __user tag */
- if (strcmp(tag_value, "user") == 0)
- tmp_flag = MEM_USER;
- /* check __percpu tag */
- if (strcmp(tag_value, "percpu") == 0)
- tmp_flag = MEM_PERCPU;
- /* check __rcu tag */
- if (strcmp(tag_value, "rcu") == 0)
- tmp_flag = MEM_RCU;
+ err = btf_type_tag_walk(btf, &ctx, walk_type_tags,
+ ARRAY_SIZE(walk_type_tags));
+ if (err) {
+ bpf_log(log, "type '%s' has multiple type tags\n",
+ btf_type_str(mtype));
+ return err;
}
+ tmp_flag = ctx.res;
+ id = ctx.id;
+ stype = ctx.t;
- stype = btf_type_skip_modifiers(btf, mtype->type, &id);
if (btf_type_is_struct(stype)) {
*next_btf_id = id;
*flag |= tmp_flag;
@@ -7867,7 +7908,12 @@ static int btf_scan_type_tags(struct bpf_verifier_env *env,
const struct btf *btf, u32 type_id,
u32 *tags)
{
+ static const struct btf_type_tag_match func_type_tags[] = {
+ { "arena", ARG_TAG_ARENA },
+ };
+ struct btf_type_tag_walk_ctx ctx;
const struct btf_type *t;
+ int err;
/* Find the first pointer type in the chain. */
t = btf_type_skip_modifiers(btf, type_id, NULL);
@@ -7879,24 +7925,15 @@ static int btf_scan_type_tags(struct bpf_verifier_env *env,
if (!t || !btf_type_is_ptr(t))
return 0;
- /* We got a pointer, get all associated type tags. */
- for (t = btf_type_by_id(btf, t->type); t && btf_type_is_modifier(t);
- t = btf_type_by_id(btf, t->type)) {
-
- /* Skip non-type tag modifiers. */
- if (!btf_type_is_type_tag(t))
- continue;
-
- const char *tag = __btf_name_by_offset(btf, t->name_off);
-
- if (strcmp(tag, "arena") == 0) {
- *tags |= ARG_TAG_ARENA;
- } else {
- bpf_log(&env->log, "function signature member has unsupported type tag '%s'\n",
- tag);
- return -EOPNOTSUPP;
- }
+ ctx.t = t;
+ err = btf_type_tag_walk(btf, &ctx, func_type_tags,
+ ARRAY_SIZE(func_type_tags));
+ if (err) {
+ bpf_log(&env->log,
+ "function signature member has multiple type tags\n");
+ return err;
}
+ *tags |= ctx.res;
return 0;
}
diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c
index 83ce66296ac1..4355ccb78a9c 100644
--- a/kernel/bpf/cgroup.c
+++ b/kernel/bpf/cgroup.c
@@ -939,19 +939,65 @@ static int cgroup_bpf_attach(struct cgroup *cgrp,
return ret;
}
+static int effective_prog_pos(struct cgroup *cgrp,
+ enum cgroup_bpf_attach_type atype,
+ struct bpf_prog_list *target_pl)
+{
+ int cnt = 0, preorder_cnt = 0, fstart, bstart, init_bstart, pos = -1;
+ struct bpf_prog_list *pl;
+ struct cgroup *p = cgrp;
+
+ /* count effective programs to find where the preorder region ends */
+ do {
+ if (cnt == 0 || (p->bpf.flags[atype] & BPF_F_ALLOW_MULTI))
+ cnt += prog_list_length(&p->bpf.progs[atype], &preorder_cnt);
+ p = cgroup_parent(p);
+ } while (p);
+
+ /* replay compute_effective_progs() placement and record target's slot */
+ cnt = 0;
+ p = cgrp;
+ fstart = preorder_cnt;
+ bstart = preorder_cnt - 1;
+ do {
+ if (cnt > 0 && !(p->bpf.flags[atype] & BPF_F_ALLOW_MULTI))
+ continue;
+
+ init_bstart = bstart;
+ hlist_for_each_entry(pl, &p->bpf.progs[atype], node) {
+ if (!prog_list_prog(pl))
+ continue;
+
+ if (pl->flags & BPF_F_PREORDER) {
+ if (pl == target_pl)
+ pos = bstart;
+ bstart--;
+ } else {
+ if (pl == target_pl)
+ pos = fstart;
+ fstart++;
+ }
+ cnt++;
+ }
+
+ /* reverse pre-ordering progs at this cgroup level */
+ if (pos >= bstart + 1 && pos <= init_bstart)
+ pos = bstart + 1 + init_bstart - pos;
+ } while ((p = cgroup_parent(p)));
+
+ return pos;
+}
+
/* Swap updated BPF program for given link in effective program arrays across
* all descendant cgroups. This function is guaranteed to succeed.
*/
static void replace_effective_prog(struct cgroup *cgrp,
enum cgroup_bpf_attach_type atype,
- struct bpf_cgroup_link *link)
+ struct bpf_prog_list *pl)
{
struct bpf_prog_array_item *item;
struct cgroup_subsys_state *css;
struct bpf_prog_array *progs;
- struct bpf_prog_list *pl;
- struct hlist_head *head;
- struct cgroup *cg;
int pos;
css_for_each_descendant_pre(css, &cgrp->self) {
@@ -960,27 +1006,15 @@ static void replace_effective_prog(struct cgroup *cgrp,
if (percpu_ref_is_zero(&desc->bpf.refcnt))
continue;
- /* find position of link in effective progs array */
- for (pos = 0, cg = desc; cg; cg = cgroup_parent(cg)) {
- if (pos && !(cg->bpf.flags[atype] & BPF_F_ALLOW_MULTI))
- continue;
+ pos = effective_prog_pos(desc, atype, pl);
+ if (WARN_ON_ONCE(pos < 0))
+ continue;
- head = &cg->bpf.progs[atype];
- hlist_for_each_entry(pl, head, node) {
- if (!prog_list_prog(pl))
- continue;
- if (pl->link == link)
- goto found;
- pos++;
- }
- }
-found:
- BUG_ON(!cg);
progs = rcu_dereference_protected(
desc->bpf.effective[atype],
lockdep_is_held(&cgroup_mutex));
item = &progs->items[pos];
- WRITE_ONCE(item->prog, link->link.prog);
+ WRITE_ONCE(item->prog, pl->link->link.prog);
}
}
@@ -1024,7 +1058,7 @@ static int __cgroup_bpf_replace(struct cgroup *cgrp,
cgrp->bpf.revisions[atype] += 1;
old_prog = xchg(&link->link.prog, new_prog);
- replace_effective_prog(cgrp, atype, link);
+ replace_effective_prog(cgrp, atype, pl);
bpf_prog_put(old_prog);
return 0;
}
@@ -1091,19 +1125,14 @@ static struct bpf_prog_list *find_detach_entry(struct hlist_head *progs,
* recomputing the array in place.
*
* @cgrp: The cgroup which descendants to travers
- * @prog: A program to detach or NULL
- * @link: A link to detach or NULL
+ * @pl: The prog_list entry being detached
* @atype: Type of detach operation
*/
-static void purge_effective_progs(struct cgroup *cgrp, struct bpf_prog *prog,
- struct bpf_cgroup_link *link,
+static void purge_effective_progs(struct cgroup *cgrp, struct bpf_prog_list *pl,
enum cgroup_bpf_attach_type atype)
{
struct cgroup_subsys_state *css;
struct bpf_prog_array *progs;
- struct bpf_prog_list *pl;
- struct hlist_head *head;
- struct cgroup *cg;
int pos;
/* recompute effective prog array in place */
@@ -1113,24 +1142,11 @@ static void purge_effective_progs(struct cgroup *cgrp, struct bpf_prog *prog,
if (percpu_ref_is_zero(&desc->bpf.refcnt))
continue;
- /* find position of link or prog in effective progs array */
- for (pos = 0, cg = desc; cg; cg = cgroup_parent(cg)) {
- if (pos && !(cg->bpf.flags[atype] & BPF_F_ALLOW_MULTI))
- continue;
-
- head = &cg->bpf.progs[atype];
- hlist_for_each_entry(pl, head, node) {
- if (!prog_list_prog(pl))
- continue;
- if (pl->prog == prog && pl->link == link)
- goto found;
- pos++;
- }
- }
-
+ pos = effective_prog_pos(desc, atype, pl);
/* no link or prog match, skip the cgroup of this layer */
- continue;
-found:
+ if (pos < 0)
+ continue;
+
progs = rcu_dereference_protected(
desc->bpf.effective[atype],
lockdep_is_held(&cgroup_mutex));
@@ -1196,7 +1212,7 @@ static int __cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
/* if update effective array failed replace the prog with a dummy prog*/
pl->prog = old_prog;
pl->link = link;
- purge_effective_progs(cgrp, old_prog, link, atype);
+ purge_effective_progs(cgrp, pl, atype);
}
/* now can actually delete it from this cgroup list */
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c
index 77ba03216c09..41fe87d7302f 100644
--- a/kernel/bpf/stackmap.c
+++ b/kernel/bpf/stackmap.c
@@ -175,6 +175,95 @@ static inline void stack_map_build_id_set_valid(struct bpf_stack_build_id *id,
memcpy(id->build_id, build_id, BUILD_ID_SIZE_MAX);
}
+/*
+ * A cached VMA lookup result. The range [vm_start, vm_end) is always set.
+ * vm_pgoff, file, build_id are set only when the build ID was resolved.
+ * Zero vm_end marks the slot empty. build_id aliases the id_offs[] entry.
+ */
+struct stack_map_cached_vma {
+ unsigned long vm_start;
+ unsigned long vm_end;
+ unsigned long vm_pgoff;
+ struct file *file; /* pinned in the sleepable path; NULL otherwise */
+ const unsigned char *build_id;
+};
+
+/*
+ * Per stack_map_get_build_id_offset() call cache of the last VMA with a build ID
+ * resolved and the last VMA with no usable build ID. Adjacent stack frames tend
+ * to land in the same VMA or the same backing file, so caching the last result
+ * of each kind lets us skip unnecessary VMA lookups and build ID parse calls.
+ * Keeping the two slots independent means a build-ID-less VMA doesn't evict the
+ * last resolved build ID.
+ */
+struct stack_map_build_id_cache {
+ struct stack_map_cached_vma resolved;
+ struct stack_map_cached_vma unresolved;
+};
+
+/*
+ * Fill @id from a cached range covering @ip. On a hit this writes @id (resolved
+ * range -> build ID + offset, unresolved range -> raw ip) and returns 0; on a
+ * miss it leaves @id untouched and returns -ENOENT.
+ */
+static int stack_map_build_id_set_from_cache(struct stack_map_build_id_cache *cache,
+ struct bpf_stack_build_id *id, u64 ip)
+{
+ unsigned long vm_start, vm_end, vm_pgoff;
+ u64 offset;
+
+ vm_start = cache->resolved.vm_start;
+ vm_end = cache->resolved.vm_end;
+ if (vm_end && ip >= vm_start && ip < vm_end) {
+ vm_pgoff = cache->resolved.vm_pgoff;
+ offset = stack_map_build_id_offset(vm_pgoff, vm_start, ip);
+ stack_map_build_id_set_valid(id, offset, cache->resolved.build_id);
+ return 0;
+ }
+
+ vm_start = cache->unresolved.vm_start;
+ vm_end = cache->unresolved.vm_end;
+ if (vm_end && ip >= vm_start && ip < vm_end) {
+ stack_map_build_id_set_ip(id);
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
+/*
+ * Record @vma's build ID as the last resolved one. @file is the pinned backing
+ * file in the sleepable path (released when evicted), or NULL otherwise.
+ */
+static void stack_map_build_id_cache_set_resolved(struct stack_map_build_id_cache *cache,
+ struct file *file,
+ const unsigned char *build_id,
+ unsigned long vm_start,
+ unsigned long vm_end,
+ unsigned long vm_pgoff)
+{
+ if (cache->resolved.file)
+ fput(cache->resolved.file);
+ cache->resolved = (struct stack_map_cached_vma){
+ .vm_start = vm_start,
+ .vm_end = vm_end,
+ .vm_pgoff = vm_pgoff,
+ .file = file,
+ .build_id = build_id,
+ };
+}
+
+/* Record [vm_start, vm_end) as a range with no usable build ID. */
+static void stack_map_build_id_cache_set_unresolved(struct stack_map_build_id_cache *cache,
+ unsigned long vm_start,
+ unsigned long vm_end)
+{
+ cache->unresolved = (struct stack_map_cached_vma){
+ .vm_start = vm_start,
+ .vm_end = vm_end,
+ };
+}
+
struct stack_map_vma_lock {
struct vm_area_struct *vma;
struct mm_struct *mm;
@@ -244,15 +333,9 @@ static void stack_map_unlock_vma(struct stack_map_vma_lock *lock)
static void stack_map_get_build_id_offset_sleepable(struct bpf_stack_build_id *id_offs,
u32 trace_nr)
{
- struct mm_struct *mm = current->mm;
- struct stack_map_vma_lock lock = { .mm = mm };
- struct {
- struct file *file;
- const unsigned char *build_id;
- unsigned long vm_start;
- unsigned long vm_end;
- unsigned long vm_pgoff;
- } cache = {};
+ struct stack_map_vma_lock lock = { .mm = current->mm };
+ struct stack_map_build_id_cache cache = {};
+ struct stack_map_cached_vma *res = &cache.resolved;
unsigned long vm_pgoff, vm_start, vm_end;
struct vm_area_struct *vma;
struct file *file;
@@ -262,44 +345,39 @@ static void stack_map_get_build_id_offset_sleepable(struct bpf_stack_build_id *i
for (u32 i = 0; i < trace_nr; i++) {
ip = READ_ONCE(id_offs[i].ip);
- /*
- * Range cache fast path: if ip falls within the previously
- * resolved VMA range, reuse the cache build_id without
- * re-acquiring the VMA lock.
- */
- if (cache.build_id && ip >= cache.vm_start && ip < cache.vm_end) {
- offset = stack_map_build_id_offset(cache.vm_pgoff, cache.vm_start, ip);
- stack_map_build_id_set_valid(&id_offs[i], offset, cache.build_id);
+ if (!stack_map_build_id_set_from_cache(&cache, &id_offs[i], ip))
continue;
- }
vma = stack_map_lock_vma(&lock, ip);
if (!vma) {
stack_map_build_id_set_ip(&id_offs[i]);
continue;
}
+
+ vm_pgoff = vma->vm_pgoff;
+ vm_start = vma->vm_start;
+ vm_end = vma->vm_end;
+
if (vma_is_anonymous(vma) || !vma->vm_file) {
- stack_map_build_id_set_ip(&id_offs[i]);
stack_map_unlock_vma(&lock);
+ stack_map_build_id_set_ip(&id_offs[i]);
+ stack_map_build_id_cache_set_unresolved(&cache, vm_start, vm_end);
continue;
}
file = vma->vm_file;
- vm_pgoff = vma->vm_pgoff;
- vm_start = vma->vm_start;
- vm_end = vma->vm_end;
offset = stack_map_build_id_offset(vm_pgoff, vm_start, ip);
/*
- * Same backing file as previous (e.g. different VMAs
- * of the same ELF binary). Reuse the cache build_id.
+ * Same backing file as the last resolved VMA (another mapping
+ * of the same ELF binary): reuse its build_id without re-parsing.
*/
- if (file == cache.file) {
+ if (file == res->file) {
stack_map_unlock_vma(&lock);
- stack_map_build_id_set_valid(&id_offs[i], offset, cache.build_id);
- cache.vm_start = vm_start;
- cache.vm_end = vm_end;
- cache.vm_pgoff = vm_pgoff;
+ stack_map_build_id_set_valid(&id_offs[i], offset, res->build_id);
+ res->vm_start = vm_start;
+ res->vm_end = vm_end;
+ res->vm_pgoff = vm_pgoff;
continue;
}
@@ -310,21 +388,17 @@ static void stack_map_get_build_id_offset_sleepable(struct bpf_stack_build_id *i
if (build_id_parse_file(file, id_offs[i].build_id, NULL)) {
stack_map_build_id_set_ip(&id_offs[i]);
fput(file);
+ stack_map_build_id_cache_set_unresolved(&cache, vm_start, vm_end);
continue;
}
stack_map_build_id_set_valid(&id_offs[i], offset, id_offs[i].build_id);
- if (cache.file)
- fput(cache.file);
- cache.file = file;
- cache.build_id = id_offs[i].build_id;
- cache.vm_start = vm_start;
- cache.vm_end = vm_end;
- cache.vm_pgoff = vm_pgoff;
+ stack_map_build_id_cache_set_resolved(&cache, file, id_offs[i].build_id,
+ vm_start, vm_end, vm_pgoff);
}
- if (cache.file)
- fput(cache.file);
+ if (res->file)
+ fput(res->file);
}
/*
@@ -343,8 +417,8 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
struct mmap_unlock_irq_work *work = NULL;
bool irq_work_busy = bpf_mmap_unlock_get_irq_work(&work);
bool has_user_ctx = user && current && current->mm;
- struct vm_area_struct *vma, *prev_vma = NULL;
- const unsigned char *prev_build_id = NULL;
+ struct stack_map_build_id_cache cache = {};
+ struct vm_area_struct *vma;
int i;
if (may_fault && has_user_ctx) {
@@ -365,27 +439,30 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
for (i = 0; i < trace_nr; i++) {
u64 ip = READ_ONCE(id_offs[i].ip);
- u64 offset;
- if (prev_build_id && range_in_vma(prev_vma, ip, ip)) {
- vma = prev_vma;
- offset = stack_map_build_id_offset(vma->vm_pgoff, vma->vm_start, ip);
- stack_map_build_id_set_valid(&id_offs[i], offset, prev_build_id);
+ if (!stack_map_build_id_set_from_cache(&cache, &id_offs[i], ip))
continue;
- }
+
vma = find_vma(current->mm, ip);
if (!vma || vma_is_anonymous(vma) ||
fetch_build_id(vma, id_offs[i].build_id, may_fault)) {
- /* per entry fall back to ips */
+ /* per entry fall back to ips; cache build-ID-less range */
stack_map_build_id_set_ip(&id_offs[i]);
- prev_vma = vma;
- prev_build_id = NULL;
+ if (vma)
+ stack_map_build_id_cache_set_unresolved(&cache,
+ vma->vm_start, vma->vm_end);
continue;
}
- offset = stack_map_build_id_offset(vma->vm_pgoff, vma->vm_start, ip);
- stack_map_build_id_set_valid(&id_offs[i], offset, id_offs[i].build_id);
- prev_vma = vma;
- prev_build_id = id_offs[i].build_id;
+ /*
+ * mmap_lock is held for the whole loop, so the cached VMA
+ * fields stay valid; no file pinning is needed here.
+ */
+ stack_map_build_id_set_valid(&id_offs[i],
+ stack_map_build_id_offset(vma->vm_pgoff, vma->vm_start, ip),
+ id_offs[i].build_id);
+ stack_map_build_id_cache_set_resolved(&cache, NULL, id_offs[i].build_id,
+ vma->vm_start, vma->vm_end,
+ vma->vm_pgoff);
}
bpf_mmap_unlock_mm(work, current->mm);
}
diff --git a/kernel/bpf/states.c b/kernel/bpf/states.c
index 32f346ce3ffc..ea2153cf28d0 100644
--- a/kernel/bpf/states.c
+++ b/kernel/bpf/states.c
@@ -436,12 +436,10 @@ static void __clean_func_state(struct bpf_verifier_env *env,
continue;
/*
- * Only destroy spilled_ptr when hi half is dead.
- * If hi half is still live with STACK_SPILL, the
- * spilled_ptr metadata is needed for correct state
- * comparison in stacksafe().
- * is_spilled_reg() is using slot_type[7], but
- * is_spilled_scalar_after() check either slot_type[0] or [4]
+ * Only scalar spills can be degraded to raw stack bytes
+ * when their high half is dead. Pointer spills need the
+ * saved spilled_ptr metadata so partial fills keep
+ * rejecting as non-scalar register fills.
*/
if (!hi_live) {
struct bpf_reg_state *spill = &st->stack[i].spilled_ptr;
@@ -449,6 +447,9 @@ static void __clean_func_state(struct bpf_verifier_env *env,
if (lo_live && stype == STACK_SPILL) {
u8 val = STACK_MISC;
+ if (spill->type != SCALAR_VALUE)
+ continue;
+
/*
* 8 byte spill of scalar 0 where half slot is dead
* should become STACK_ZERO in lo 4 bytes.
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index b44106c8ea75..6db306d23b47 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -6308,7 +6308,7 @@ static int prog_stream_read(union bpf_attr *attr)
return ret;
}
-#define BPF_PROG_ASSOC_STRUCT_OPS_LAST_FIELD prog_assoc_struct_ops.prog_fd
+#define BPF_PROG_ASSOC_STRUCT_OPS_LAST_FIELD prog_assoc_struct_ops.flags
static int prog_assoc_struct_ops(union bpf_attr *attr)
{
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 2abc79dbf281..21a365d436a5 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -3479,7 +3479,8 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
bool sanitize = reg && is_spillable_regtype(reg->type);
for (i = 0; i < size; i++) {
- u8 type = state->stack[spi].slot_type[i];
+ u8 type = state->stack[spi].slot_type[(slot - i) %
+ BPF_REG_SIZE];
if (type != STACK_MISC && type != STACK_ZERO) {
sanitize = true;
@@ -5786,6 +5787,10 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
return -EFAULT;
}
ret = env->ops->btf_struct_access(&env->log, reg, off, size);
+ if (ret < 0)
+ verbose(env,
+ "%s cannot write into ptr_%s at off=%d size=%d\n",
+ reg_arg_name(env, argno), tname, off, size);
} else {
/* Writes are permitted with default btf_struct_access for
* program allocated objects (which always have id > 0),
@@ -6196,6 +6201,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, struct b
*/
if (info.reg_type == SCALAR_VALUE) {
if (info.is_retval && get_func_retval_range(env->prog, &range)) {
+ mark_reg_unknown(env, regs, value_regno);
err = __mark_reg_s32_range(env, regs, value_regno,
range.minval, range.maxval);
if (err)
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c
index ae9fd211cec1..a4e689eefdfb 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -486,6 +486,7 @@ static void sugov_update_single_perf(struct update_util_data *hook, u64 time,
cpufreq_driver_adjust_perf(sg_policy->policy, sg_cpu->bw_min,
sg_cpu->util, max_cap);
+ sg_policy->need_freq_update = false;
sg_policy->last_freq_update_time = time;
}
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 82f8feea6931..75495a5c3507 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -2376,9 +2376,12 @@ static int copy_user_syms(struct user_syms *us, unsigned long __user *usyms, u32
int err = -ENOMEM;
unsigned int i;
+ if (!access_ok(usyms, cnt * sizeof(*usyms)))
+ return -EFAULT;
+
syms = kvmalloc_array(cnt, sizeof(*syms), GFP_KERNEL);
if (!syms)
- goto error;
+ return -ENOMEM;
buf = kvmalloc_array(cnt, KSYM_NAME_LEN, GFP_KERNEL);
if (!buf)
@@ -2403,10 +2406,8 @@ static int copy_user_syms(struct user_syms *us, unsigned long __user *usyms, u32
return 0;
error:
- if (err) {
- kvfree(syms);
- kvfree(buf);
- }
+ kvfree(syms);
+ kvfree(buf);
return err;
}
diff --git a/kernel/trace/fprobe.c b/kernel/trace/fprobe.c
index f378613ad120..f215990b9061 100644
--- a/kernel/trace/fprobe.c
+++ b/kernel/trace/fprobe.c
@@ -613,6 +613,16 @@ static int fprobe_fgraph_entry(struct ftrace_graph_ent *trace, struct fgraph_ops
continue;
data_size = fp->entry_data_size;
+ /*
+ * The list may have grown since it was sized, so this node
+ * may not fit. Skip it as missed rather than overrun the
+ * reservation.
+ */
+ if (fp->exit_handler &&
+ used + FPROBE_HEADER_SIZE_IN_LONG + SIZE_IN_LONG(data_size) > reserved_words) {
+ fp->nmissed++;
+ continue;
+ }
if (data_size && fp->exit_handler)
data = fgraph_data + used + FPROBE_HEADER_SIZE_IN_LONG;
else
diff --git a/kernel/trace/trace_eprobe.c b/kernel/trace/trace_eprobe.c
index b66d6196338d..50518b071414 100644
--- a/kernel/trace/trace_eprobe.c
+++ b/kernel/trace/trace_eprobe.c
@@ -315,7 +315,7 @@ get_event_field(struct fetch_insn *code, void *rec)
val = (unsigned long)addr;
break;
case FILTER_PTR_STRING:
- val = (unsigned long)(*(char *)addr);
+ val = *(unsigned long *)addr;
break;
default:
WARN_ON_ONCE(1);
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index fd1caa1f9723..d17cfee77d9c 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -342,10 +342,6 @@ static int parse_trace_event(char *arg, struct fetch_insn *code,
ret = parse_trace_event_arg(arg, code, ctx);
if (!ret)
return 0;
- if (strcmp(arg, "comm") == 0 || strcmp(arg, "COMM") == 0) {
- code->op = FETCH_OP_COMM;
- return 0;
- }
return -EINVAL;
}
@@ -678,7 +674,7 @@ static int parse_btf_arg(char *varname,
int i, is_ptr, ret;
u32 tid;
- if (WARN_ON_ONCE(!ctx->funcname && !(ctx->flags & TPARG_FL_TEVENT)))
+ if (!ctx->funcname && !(ctx->flags & TPARG_FL_TEVENT))
return -EINVAL;
is_ptr = split_next_field(varname, &field, ctx);
@@ -1068,8 +1064,14 @@ static int parse_probe_vars(char *orig_arg, const struct fetch_type *t,
int len;
if (ctx->flags & TPARG_FL_TEVENT) {
- if (parse_trace_event(arg, code, ctx) < 0)
+ if (parse_trace_event(arg, code, ctx) < 0) {
+ /* 'comm' should be checked after field parsing. */
+ if (strcmp(arg, "comm") == 0 || strcmp(arg, "COMM") == 0) {
+ code->op = FETCH_OP_COMM;
+ return 0;
+ }
goto inval;
+ }
return 0;
}
@@ -1241,6 +1243,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type,
code->op = FETCH_OP_FOFFS;
code->immediate = (unsigned long)offset; // imm64?
+ offset = 0;
} else {
/* uprobes don't support symbols */
if (!(ctx->flags & TPARG_FL_KERNEL)) {
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 15758cc11fc6..0f09f7aaf93f 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -511,7 +511,7 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
C(NO_RETVAL, "This function returns 'void' type"), \
C(BAD_STACK_NUM, "Invalid stack number"), \
C(BAD_ARG_NUM, "Invalid argument number"), \
- C(BAD_VAR, "Invalid $-valiable specified"), \
+ C(BAD_VAR, "Invalid $-variable specified"), \
C(BAD_REG_NAME, "Invalid register name"), \
C(BAD_MEM_ADDR, "Invalid memory address"), \
C(BAD_IMM, "Invalid immediate value"), \
diff --git a/lib/bootconfig.c b/lib/bootconfig.c
index f445b7703fdd..2ed9ee3dc81c 100644
--- a/lib/bootconfig.c
+++ b/lib/bootconfig.c
@@ -427,10 +427,18 @@ static char xbc_namebuf[XBC_KEYLEN_MAX] __initdata;
int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
{
struct xbc_node *knode, *vnode;
- char *end = buf + size;
const char *val, *q;
+ size_t len = 0;
int ret;
+ /*
+ * Track the running written length rather than advancing @buf, so we
+ * never form "buf + size" or "buf += ret" while @buf is NULL (the
+ * size-probe call passes buf=NULL, size=0). NULL pointer arithmetic
+ * is undefined behavior and trips host UBSan / FORTIFY_SOURCE when
+ * this renderer runs at kernel build time. snprintf(NULL, 0, ...)
+ * itself is well defined and returns the would-be length.
+ */
xbc_node_for_each_key_value(root, knode, val) {
ret = xbc_node_compose_key_after(root, knode,
xbc_namebuf, XBC_KEYLEN_MAX);
@@ -439,10 +447,11 @@ int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
vnode = xbc_node_get_child(knode);
if (!vnode) {
- ret = snprintf(buf, rest(buf, end), "%s ", xbc_namebuf);
+ ret = snprintf(buf ? buf + len : NULL, rest(len, size),
+ "%s ", xbc_namebuf);
if (ret < 0)
return ret;
- buf += ret;
+ len += ret;
continue;
}
xbc_array_for_each_value(vnode, val) {
@@ -452,15 +461,15 @@ int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
* whitespace.
*/
q = strpbrk(val, " \t\r\n") ? "\"" : "";
- ret = snprintf(buf, rest(buf, end), "%s=%s%s%s ",
- xbc_namebuf, q, val, q);
+ ret = snprintf(buf ? buf + len : NULL, rest(len, size),
+ "%s=%s%s%s ", xbc_namebuf, q, val, q);
if (ret < 0)
return ret;
- buf += ret;
+ len += ret;
}
}
- return buf - (end - size);
+ return len;
}
#undef rest
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c
index ae39ceaa2e29..c40c9e02391b 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -1066,6 +1066,9 @@ out:
* @skb: the buffer containing the packet to extract the VID from
* @hdr_size: the size of the batman-adv header encapsulating the packet
*
+ * The caller must ensure that at least @hdr_size + ETH_HLEN bytes are
+ * accessible after skb->data.
+ *
* Return: If the packet embedded in the skb is vlan tagged this function
* returns the VID with the BATADV_VLAN_HAS_TAG flag. Otherwise BATADV_NO_FLAGS
* is returned.
@@ -1148,6 +1151,10 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
if (!READ_ONCE(bat_priv->distributed_arp_table))
goto out;
+ /* first, find out the vid. */
+ if (!pskb_may_pull(skb, hdr_size + ETH_HLEN))
+ goto out;
+
vid = batadv_dat_get_vid(skb, &hdr_size);
type = batadv_arp_get_type(bat_priv, skb, hdr_size);
@@ -1243,6 +1250,10 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
if (!READ_ONCE(bat_priv->distributed_arp_table))
goto out;
+ /* first, find out the vid. */
+ if (!pskb_may_pull(skb, hdr_size + ETH_HLEN))
+ goto out;
+
vid = batadv_dat_get_vid(skb, &hdr_size);
type = batadv_arp_get_type(bat_priv, skb, hdr_size);
@@ -1305,6 +1316,10 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
if (!READ_ONCE(bat_priv->distributed_arp_table))
return;
+ /* first, find out the vid. */
+ if (!pskb_may_pull(skb, hdr_size + ETH_HLEN))
+ return;
+
vid = batadv_dat_get_vid(skb, &hdr_size);
type = batadv_arp_get_type(bat_priv, skb, hdr_size);
@@ -1353,6 +1368,10 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
if (!READ_ONCE(bat_priv->distributed_arp_table))
goto out;
+ /* first, find out the vid. */
+ if (!pskb_may_pull(skb, hdr_size + ETH_HLEN))
+ goto out;
+
vid = batadv_dat_get_vid(skb, &hdr_size);
type = batadv_arp_get_type(bat_priv, skb, hdr_size);
@@ -1747,6 +1766,7 @@ void batadv_dat_snoop_incoming_dhcp_ack(struct batadv_priv *bat_priv,
struct ethhdr *ethhdr;
__be32 ip_src, yiaddr;
unsigned short vid;
+ int hdr_size_tmp;
__be16 proto;
u8 *hw_src;
@@ -1763,8 +1783,10 @@ void batadv_dat_snoop_incoming_dhcp_ack(struct batadv_priv *bat_priv,
if (!batadv_dat_check_dhcp_ack(skb, proto, &ip_src, chaddr, &yiaddr))
return;
+ hdr_size_tmp = hdr_size;
+ vid = batadv_dat_get_vid(skb, &hdr_size_tmp);
+ ethhdr = (struct ethhdr *)(skb->data + hdr_size);
hw_src = ethhdr->h_source;
- vid = batadv_dat_get_vid(skb, &hdr_size);
batadv_dat_entry_add(bat_priv, yiaddr, chaddr, vid);
batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
@@ -1804,6 +1826,10 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv,
if (batadv_forw_packet_is_rebroadcast(forw_packet))
goto out;
+ /* first, find out the vid. */
+ if (!pskb_may_pull(forw_packet->skb, hdr_size + ETH_HLEN))
+ goto out;
+
vid = batadv_dat_get_vid(forw_packet->skb, &hdr_size);
type = batadv_arp_get_type(bat_priv, forw_packet->skb, hdr_size);
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 305488a74a25..a5ac82eabd25 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -684,12 +684,13 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
struct batadv_gw_node *gw_node = NULL;
struct batadv_gw_node *curr_gw = NULL;
struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo;
- struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
+ struct ethhdr *ethhdr;
bool out_of_range = false;
u8 curr_tq_avg;
unsigned short vid;
vid = batadv_get_vid(skb, 0);
+ ethhdr = (struct ethhdr *)skb->data;
if (is_multicast_ether_addr(ethhdr->h_dest))
goto out;
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 04bb030ef299..fb2b0e35e349 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -571,6 +571,9 @@ void batadv_recv_handler_unregister(u8 packet_type)
* @skb: the buffer containing the packet
* @header_len: length of the batman header preceding the ethernet header
*
+ * The caller must ensure that at least @header_len + ETH_HLEN bytes are
+ * accessible after skb->data.
+ *
* Return: VID with the BATADV_VLAN_HAS_TAG flag when the packet embedded in the
* skb is vlan tagged. Otherwise BATADV_NO_FLAGS.
*/
diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c
index a37368c1f5b5..5cc72bbc4570 100644
--- a/net/batman-adv/mesh-interface.c
+++ b/net/batman-adv/mesh-interface.c
@@ -434,6 +434,7 @@ void batadv_interface_rx(struct net_device *mesh_iface,
if (!pskb_may_pull(skb, VLAN_ETH_HLEN))
goto dropped;
+ ethhdr = eth_hdr(skb);
vhdr = skb_vlan_eth_hdr(skb);
/* drop batman-in-batman packets to prevent loops */
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index c05fcc9241ad..bbd40fe3a8e5 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -855,8 +855,8 @@ static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
if (skb_cow(skb, sizeof(*unicast_packet)) < 0)
return false;
- unicast_packet = (struct batadv_unicast_packet *)skb->data;
vid = batadv_get_vid(skb, hdr_len);
+ unicast_packet = (struct batadv_unicast_packet *)skb->data;
ethhdr = (struct ethhdr *)(skb->data + hdr_len);
/* do not reroute multicast frames in a unicast header */
@@ -1029,6 +1029,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
hdr_size);
batadv_orig_node_put(orig_node_gw);
if (is_gw) {
+ orig_addr_gw = eth_hdr(skb)->h_source;
batadv_dbg(BATADV_DBG_BLA, bat_priv,
"%s(): Dropped unicast pkt received from another backbone gw %pM.\n",
__func__, orig_addr_gw);
diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c
index 7fdee8f52ee2..5d51f6cb7d15 100644
--- a/net/bpf/test_run.c
+++ b/net/bpf/test_run.c
@@ -452,12 +452,8 @@ static int bpf_test_finish(const union bpf_attr *kattr,
}
if (data_out) {
- int len = sinfo ? copy_size - frag_size : copy_size;
-
- if (len < 0) {
- err = -ENOSPC;
- goto out;
- }
+ u32 head_len = size - frag_size;
+ u32 len = min(copy_size, head_len);
if (copy_to_user(data_out, data, len))
goto out;
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 7ed19aa8ae59..c52613431f88 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -392,6 +392,9 @@ void br_dev_delete(struct net_device *dev, struct list_head *head)
br_fdb_delete_by_port(br, NULL, 0, 1);
+ timer_shutdown_sync(&br->hello_timer);
+ timer_shutdown_sync(&br->topology_change_timer);
+ timer_shutdown_sync(&br->tcn_timer);
cancel_delayed_work_sync(&br->gc_work);
br_sysfs_delbr(br->dev);
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index 46919d73d42f..c7e7e924f155 100644
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -382,7 +382,8 @@ void br_topology_change_detection(struct net_bridge *br)
{
int isroot = br_is_root_bridge(br);
- if (br->stp_enabled != BR_KERNEL_STP)
+ if (br->stp_enabled != BR_KERNEL_STP ||
+ !(br->dev->flags & IFF_UP))
return;
br_info(br, "topology change detected, %s\n",
diff --git a/net/core/filter.c b/net/core/filter.c
index 69ec1a4c0f9d..b446aa8be5c3 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -6221,7 +6221,7 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
struct in_device *in_dev;
struct net_device *dev;
struct fib_result res;
- struct flowi4 fl4;
+ struct flowi4 fl4 = {};
u32 mtu = 0;
int err;
@@ -6361,7 +6361,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
struct neighbour *neigh;
struct net_device *dev;
struct inet6_dev *idev;
- struct flowi6 fl6;
+ struct flowi6 fl6 = {};
int strict = 0;
int oif, err;
u32 mtu = 0;
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 85aa51350881..aed415d3cd74 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -633,14 +633,6 @@ static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
container_of(rcu_head, struct netpoll_info, rcu);
skb_queue_purge(&npinfo->txq);
-
- /* we can't call cancel_delayed_work_sync here, as we are in softirq */
- cancel_delayed_work(&npinfo->tx_work);
-
- /* clean after last, unfinished work */
- __skb_queue_purge(&npinfo->txq);
- /* now cancel it again */
- cancel_delayed_work(&npinfo->tx_work);
kfree(npinfo);
}
@@ -664,6 +656,7 @@ static void __netpoll_cleanup(struct netpoll *np)
ops->ndo_netpoll_cleanup(np->dev);
RCU_INIT_POINTER(np->dev->npinfo, NULL);
+ disable_delayed_work_sync(&npinfo->tx_work);
call_rcu(&npinfo->rcu, rcu_cleanup_netpoll_info);
}
diff --git a/net/dsa/tag.c b/net/dsa/tag.c
index 79ad105902d9..991732d6eae2 100644
--- a/net/dsa/tag.c
+++ b/net/dsa/tag.c
@@ -79,15 +79,16 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
if (likely(skb->dev)) {
dsa_default_offload_fwd_mark(skb);
nskb = skb;
+ } else {
+ /* Just drop the skb if we can't find the user */
+ kfree_skb(skb);
}
} else {
nskb = cpu_dp->rcv(skb, dev);
}
- if (!nskb) {
- kfree_skb(skb);
+ if (!nskb)
return 0;
- }
skb = nskb;
skb_push(skb, ETH_HLEN);
@@ -107,11 +108,10 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
if (unlikely(cpu_dp->ds->untag_bridge_pvid ||
cpu_dp->ds->untag_vlan_aware_bridge_pvid)) {
+ /* dsa_software_vlan_untag() drops skb on failure */
nskb = dsa_software_vlan_untag(skb);
- if (!nskb) {
- kfree_skb(skb);
+ if (!nskb)
return 0;
- }
skb = nskb;
}
diff --git a/net/dsa/tag_ar9331.c b/net/dsa/tag_ar9331.c
index cbb588ca73aa..2e2388143b02 100644
--- a/net/dsa/tag_ar9331.c
+++ b/net/dsa/tag_ar9331.c
@@ -51,8 +51,10 @@ static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb,
u8 ver, port;
u16 hdr;
- if (unlikely(!pskb_may_pull(skb, AR9331_HDR_LEN)))
+ if (unlikely(!pskb_may_pull(skb, AR9331_HDR_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
hdr = le16_to_cpu(*(__le16 *)skb_mac_header(skb));
@@ -60,12 +62,14 @@ static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb,
if (unlikely(ver != AR9331_HDR_VERSION)) {
netdev_warn_once(ndev, "%s:%i wrong header version 0x%2x\n",
__func__, __LINE__, hdr);
+ kfree_skb(skb);
return NULL;
}
if (unlikely(hdr & AR9331_HDR_FROM_CPU)) {
netdev_warn_once(ndev, "%s:%i packet should not be from cpu 0x%2x\n",
__func__, __LINE__, hdr);
+ kfree_skb(skb);
return NULL;
}
@@ -75,8 +79,10 @@ static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb,
port = FIELD_GET(AR9331_HDR_PORT_NUM_MASK, hdr);
skb->dev = dsa_conduit_find_user(ndev, 0, port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
return skb;
}
diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
index cf9420439054..411e3b57d16a 100644
--- a/net/dsa/tag_brcm.c
+++ b/net/dsa/tag_brcm.c
@@ -102,9 +102,9 @@ static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb,
* (including FCS and tag) because the length verification is done after
* the Broadcom tag is stripped off the ingress packet.
*
- * Let dsa_user_xmit() free the SKB
+ * Free the SKB on error.
*/
- if (__skb_put_padto(skb, ETH_ZLEN + BRCM_TAG_LEN, false))
+ if (skb_put_padto(skb, ETH_ZLEN + BRCM_TAG_LEN))
return NULL;
skb_push(skb, BRCM_TAG_LEN);
@@ -151,27 +151,35 @@ static struct sk_buff *brcm_tag_rcv_ll(struct sk_buff *skb,
int source_port;
u8 *brcm_tag;
- if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN)))
+ if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
brcm_tag = skb->data - offset;
/* The opcode should never be different than 0b000 */
- if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK))
+ if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK)) {
+ kfree_skb(skb);
return NULL;
+ }
/* We should never see a reserved reason code without knowing how to
* handle it
*/
- if (unlikely(brcm_tag[2] & BRCM_EG_RC_RSVD))
+ if (unlikely(brcm_tag[2] & BRCM_EG_RC_RSVD)) {
+ kfree_skb(skb);
return NULL;
+ }
/* Locate which port this is coming from */
source_port = brcm_tag[3] & BRCM_EG_PID_MASK;
skb->dev = dsa_conduit_find_user(dev, 0, source_port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
/* Remove Broadcom tag and update checksum */
skb_pull_rcsum(skb, BRCM_TAG_LEN);
@@ -228,8 +236,10 @@ static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
__be16 *proto;
u8 *brcm_tag;
- if (unlikely(!pskb_may_pull(skb, BRCM_LEG_TAG_LEN + VLAN_HLEN)))
+ if (unlikely(!pskb_may_pull(skb, BRCM_LEG_TAG_LEN + VLAN_HLEN))) {
+ kfree_skb(skb);
return NULL;
+ }
brcm_tag = dsa_etype_header_pos_rx(skb);
proto = (__be16 *)(brcm_tag + BRCM_LEG_TAG_LEN);
@@ -237,8 +247,10 @@ static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb,
source_port = brcm_tag[5] & BRCM_LEG_PORT_ID;
skb->dev = dsa_conduit_find_user(dev, 0, source_port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
/* The internal switch in BCM63XX SoCs always tags on egress on the CPU
* port. We use VID 0 internally for untagged traffic, so strip the tag
@@ -273,10 +285,8 @@ static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb,
* need to make sure that packets are at least 70 bytes
* (including FCS and tag) because the length verification is done after
* the Broadcom tag is stripped off the ingress packet.
- *
- * Let dsa_user_xmit() free the SKB
*/
- if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false))
+ if (skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN))
return NULL;
skb_push(skb, BRCM_LEG_TAG_LEN);
@@ -325,10 +335,8 @@ static struct sk_buff *brcm_leg_fcs_tag_xmit(struct sk_buff *skb,
* need to make sure that packets are at least 70 bytes (including FCS
* and tag) because the length verification is done after the Broadcom
* tag is stripped off the ingress packet.
- *
- * Let dsa_user_xmit() free the SKB.
*/
- if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false))
+ if (skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN))
return NULL;
fcs_len = skb->len;
@@ -351,8 +359,9 @@ static struct sk_buff *brcm_leg_fcs_tag_xmit(struct sk_buff *skb,
brcm_tag[5] = dp->index & BRCM_LEG_PORT_ID;
/* Original FCS value */
- if (__skb_pad(skb, ETH_FCS_LEN, false))
+ if (skb_pad(skb, ETH_FCS_LEN))
return NULL;
+
skb_put_data(skb, &fcs_val, ETH_FCS_LEN);
return skb;
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index 2a2c4fb61a65..d5ffee35fbb5 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -224,6 +224,7 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
/* Remote management is not implemented yet,
* drop.
*/
+ kfree_skb(skb);
return NULL;
case DSA_CODE_ARP_MIRROR:
case DSA_CODE_POLICY_MIRROR:
@@ -244,12 +245,14 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
/* Reserved code, this could be anything. Drop
* seems like the safest option.
*/
+ kfree_skb(skb);
return NULL;
}
break;
default:
+ kfree_skb(skb);
return NULL;
}
@@ -271,8 +274,10 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev,
source_port);
}
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
/* When using LAG offload, skb->dev is not a DSA user interface,
* so we cannot call dsa_default_offload_fwd_mark and we need to
@@ -335,8 +340,10 @@ static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct net_device *dev)
static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev)
{
- if (unlikely(!pskb_may_pull(skb, DSA_HLEN)))
+ if (unlikely(!pskb_may_pull(skb, DSA_HLEN))) {
+ kfree_skb(skb);
return NULL;
+ }
return dsa_rcv_ll(skb, dev, 0);
}
@@ -375,8 +382,10 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct net_device *dev)
static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev)
{
- if (unlikely(!pskb_may_pull(skb, EDSA_HLEN)))
+ if (unlikely(!pskb_may_pull(skb, EDSA_HLEN))) {
+ kfree_skb(skb);
return NULL;
+ }
skb_pull_rcsum(skb, EDSA_HLEN - DSA_HLEN);
diff --git a/net/dsa/tag_gswip.c b/net/dsa/tag_gswip.c
index 5fa436121087..5c407d448c9f 100644
--- a/net/dsa/tag_gswip.c
+++ b/net/dsa/tag_gswip.c
@@ -80,16 +80,20 @@ static struct sk_buff *gswip_tag_rcv(struct sk_buff *skb,
int port;
u8 *gswip_tag;
- if (unlikely(!pskb_may_pull(skb, GSWIP_RX_HEADER_LEN)))
+ if (unlikely(!pskb_may_pull(skb, GSWIP_RX_HEADER_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
gswip_tag = skb->data - ETH_HLEN;
/* Get source port information */
port = (gswip_tag[7] & GSWIP_RX_SPPID_MASK) >> GSWIP_RX_SPPID_SHIFT;
skb->dev = dsa_conduit_find_user(dev, 0, port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
/* remove GSWIP tag */
skb_pull_rcsum(skb, GSWIP_RX_HEADER_LEN);
diff --git a/net/dsa/tag_hellcreek.c b/net/dsa/tag_hellcreek.c
index 544ab15685a2..dd9f328f3182 100644
--- a/net/dsa/tag_hellcreek.c
+++ b/net/dsa/tag_hellcreek.c
@@ -27,8 +27,10 @@ static struct sk_buff *hellcreek_xmit(struct sk_buff *skb,
* checksums after the switch strips the tag.
*/
if (skb->ip_summed == CHECKSUM_PARTIAL &&
- skb_checksum_help(skb))
+ skb_checksum_help(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
/* Tag encoding */
tag = skb_put(skb, HELLCREEK_TAG_LEN);
@@ -47,11 +49,14 @@ static struct sk_buff *hellcreek_rcv(struct sk_buff *skb,
skb->dev = dsa_conduit_find_user(dev, 0, port);
if (!skb->dev) {
netdev_warn_once(dev, "Failed to get source port: %d\n", port);
+ kfree_skb(skb);
return NULL;
}
- if (pskb_trim_rcsum(skb, skb->len - HELLCREEK_TAG_LEN))
+ if (pskb_trim_rcsum(skb, skb->len - HELLCREEK_TAG_LEN)) {
+ kfree_skb(skb);
return NULL;
+ }
dsa_default_offload_fwd_mark(skb);
diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c
index d2475c3bbb7d..67fa89f102e0 100644
--- a/net/dsa/tag_ksz.c
+++ b/net/dsa/tag_ksz.c
@@ -88,11 +88,15 @@ static struct sk_buff *ksz_common_rcv(struct sk_buff *skb,
unsigned int port, unsigned int len)
{
skb->dev = dsa_conduit_find_user(dev, 0, port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
- if (pskb_trim_rcsum(skb, skb->len - len))
+ if (pskb_trim_rcsum(skb, skb->len - len)) {
+ kfree_skb(skb);
return NULL;
+ }
dsa_default_offload_fwd_mark(skb);
@@ -123,8 +127,10 @@ static struct sk_buff *ksz8795_xmit(struct sk_buff *skb, struct net_device *dev)
struct ethhdr *hdr;
u8 *tag;
- if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
+ if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
/* Tag encoding */
tag = skb_put(skb, KSZ_INGRESS_TAG_LEN);
@@ -141,8 +147,10 @@ static struct sk_buff *ksz8795_rcv(struct sk_buff *skb, struct net_device *dev)
{
u8 *tag;
- if (skb_linearize(skb))
+ if (skb_linearize(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN;
@@ -255,22 +263,24 @@ static struct sk_buff *ksz_defer_xmit(struct dsa_port *dp, struct sk_buff *skb)
xmit_work_fn = tagger_data->xmit_work_fn;
xmit_worker = priv->xmit_worker;
- if (!xmit_work_fn || !xmit_worker)
+ if (!xmit_work_fn || !xmit_worker) {
+ kfree_skb(skb);
return NULL;
+ }
xmit_work = kzalloc_obj(*xmit_work, GFP_ATOMIC);
- if (!xmit_work)
+ if (!xmit_work) {
+ kfree_skb(skb);
return NULL;
+ }
kthread_init_work(&xmit_work->work, xmit_work_fn);
- /* Increase refcount so the kfree_skb in dsa_user_xmit
- * won't really free the packet.
- */
xmit_work->dp = dp;
xmit_work->skb = skb_get(skb);
kthread_queue_work(xmit_worker, &xmit_work->work);
+ kfree_skb(skb);
return NULL;
}
@@ -284,8 +294,10 @@ static struct sk_buff *ksz9477_xmit(struct sk_buff *skb,
__be16 *tag;
u16 val;
- if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
+ if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
/* Tag encoding */
ksz_xmit_timestamp(dp, skb);
@@ -310,8 +322,10 @@ static struct sk_buff *ksz9477_rcv(struct sk_buff *skb, struct net_device *dev)
unsigned int port;
u8 *tag;
- if (skb_linearize(skb))
+ if (skb_linearize(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
/* Tag decoding */
tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN;
@@ -352,8 +366,10 @@ static struct sk_buff *ksz9893_xmit(struct sk_buff *skb,
struct ethhdr *hdr;
u8 *tag;
- if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
+ if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
/* Tag encoding */
ksz_xmit_timestamp(dp, skb);
@@ -418,8 +434,10 @@ static struct sk_buff *lan937x_xmit(struct sk_buff *skb,
__be16 *tag;
u16 val;
- if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
+ if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
ksz_xmit_timestamp(dp, skb);
diff --git a/net/dsa/tag_lan9303.c b/net/dsa/tag_lan9303.c
index 258e5d7dc5ef..d1194696499a 100644
--- a/net/dsa/tag_lan9303.c
+++ b/net/dsa/tag_lan9303.c
@@ -85,6 +85,7 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev)
if (unlikely(!pskb_may_pull(skb, LAN9303_TAG_LEN))) {
dev_warn_ratelimited(&dev->dev,
"Dropping packet, cannot pull\n");
+ kfree_skb(skb);
return NULL;
}
@@ -102,6 +103,7 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev)
skb->dev = dsa_conduit_find_user(dev, 0, source_port);
if (!skb->dev) {
dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid source port\n");
+ kfree_skb(skb);
return NULL;
}
diff --git a/net/dsa/tag_mtk.c b/net/dsa/tag_mtk.c
index dea3eecaf093..c7dc7731675e 100644
--- a/net/dsa/tag_mtk.c
+++ b/net/dsa/tag_mtk.c
@@ -72,8 +72,10 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev)
int port;
__be16 *phdr;
- if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN)))
+ if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
phdr = dsa_etype_header_pos_rx(skb);
hdr = ntohs(*phdr);
@@ -87,8 +89,10 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev)
port = (hdr & MTK_HDR_RECV_SOURCE_PORT_MASK);
skb->dev = dsa_conduit_find_user(dev, 0, port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
dsa_default_offload_fwd_mark(skb);
diff --git a/net/dsa/tag_mxl-gsw1xx.c b/net/dsa/tag_mxl-gsw1xx.c
index 60f7c445e656..4b1b6ef94196 100644
--- a/net/dsa/tag_mxl-gsw1xx.c
+++ b/net/dsa/tag_mxl-gsw1xx.c
@@ -73,6 +73,7 @@ static struct sk_buff *gsw1xx_tag_rcv(struct sk_buff *skb,
if (unlikely(!pskb_may_pull(skb, GSW1XX_HEADER_LEN))) {
dev_warn_ratelimited(&dev->dev, "Dropping packet, cannot pull SKB\n");
+ kfree_skb(skb);
return NULL;
}
@@ -81,6 +82,7 @@ static struct sk_buff *gsw1xx_tag_rcv(struct sk_buff *skb,
if (unlikely(ntohs(gsw1xx_tag[0]) != ETH_P_MXLGSW)) {
dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid special tag\n");
dev_warn_ratelimited(&dev->dev, "Tag: %8ph\n", gsw1xx_tag);
+ kfree_skb(skb);
return NULL;
}
@@ -90,6 +92,7 @@ static struct sk_buff *gsw1xx_tag_rcv(struct sk_buff *skb,
if (!skb->dev) {
dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid source port\n");
dev_warn_ratelimited(&dev->dev, "Tag: %8ph\n", gsw1xx_tag);
+ kfree_skb(skb);
return NULL;
}
diff --git a/net/dsa/tag_mxl862xx.c b/net/dsa/tag_mxl862xx.c
index 8daefeb8d49d..87b80ddf0946 100644
--- a/net/dsa/tag_mxl862xx.c
+++ b/net/dsa/tag_mxl862xx.c
@@ -64,6 +64,7 @@ static struct sk_buff *mxl862_tag_rcv(struct sk_buff *skb,
if (unlikely(!pskb_may_pull(skb, MXL862_HEADER_LEN))) {
dev_warn_ratelimited(&dev->dev, "Cannot pull SKB, packet dropped\n");
+ kfree_skb(skb);
return NULL;
}
@@ -73,6 +74,7 @@ static struct sk_buff *mxl862_tag_rcv(struct sk_buff *skb,
dev_warn_ratelimited(&dev->dev,
"Invalid special tag marker, packet dropped, tag: %8ph\n",
mxl862_tag);
+ kfree_skb(skb);
return NULL;
}
@@ -83,6 +85,7 @@ static struct sk_buff *mxl862_tag_rcv(struct sk_buff *skb,
dev_warn_ratelimited(&dev->dev,
"Invalid source port, packet dropped, tag: %8ph\n",
mxl862_tag);
+ kfree_skb(skb);
return NULL;
}
diff --git a/net/dsa/tag_netc.c b/net/dsa/tag_netc.c
index ccedfe3a80b6..df72a61796ad 100644
--- a/net/dsa/tag_netc.c
+++ b/net/dsa/tag_netc.c
@@ -131,14 +131,13 @@ static struct sk_buff *netc_rcv(struct sk_buff *skb,
int type, subtype;
if (unlikely(!pskb_may_pull(skb, NETC_TAG_MAX_LEN)))
- return NULL;
+ goto err_free_skb;
tag_cmn = dsa_etype_header_pos_rx(skb);
if (ntohs(tag_cmn->tpid) != ETH_P_NXP_NETC) {
dev_warn_ratelimited(&ndev->dev, "Unknown TPID 0x%04x\n",
ntohs(tag_cmn->tpid));
-
- return NULL;
+ goto err_free_skb;
}
if (tag_cmn->qos & NETC_TAG_QV)
@@ -149,14 +148,13 @@ static struct sk_buff *netc_rcv(struct sk_buff *skb,
if (!sw_id) {
dev_warn_ratelimited(&ndev->dev,
"VEPA switch ID is not supported yet\n");
-
- return NULL;
+ goto err_free_skb;
}
port = FIELD_GET(NETC_TAG_PORT, tag_cmn->switch_port);
skb->dev = dsa_conduit_find_user(ndev, sw_id, port);
if (!skb->dev)
- return NULL;
+ goto err_free_skb;
type = FIELD_GET(NETC_TAG_TYPE, tag_cmn->type);
subtype = FIELD_GET(NETC_TAG_SUBTYPE, tag_cmn->type);
@@ -165,11 +163,11 @@ static struct sk_buff *netc_rcv(struct sk_buff *skb,
} else if (type == NETC_TAG_TO_HOST) {
/* Currently only subtype0 supported */
if (subtype != NETC_TAG_TH_SUBTYPE0)
- return NULL;
+ goto err_free_skb;
} else {
dev_warn_ratelimited(&ndev->dev,
"Unexpected tag type %d\n", type);
- return NULL;
+ goto err_free_skb;
}
/* Remove Switch tag from the frame */
@@ -178,6 +176,10 @@ static struct sk_buff *netc_rcv(struct sk_buff *skb,
dsa_strip_etype_header(skb, tag_len);
return skb;
+
+err_free_skb:
+ kfree_skb(skb);
+ return NULL;
}
static void netc_flow_dissect(const struct sk_buff *skb, __be16 *proto,
diff --git a/net/dsa/tag_ocelot.c b/net/dsa/tag_ocelot.c
index 3405def79c2d..d208c7322cd6 100644
--- a/net/dsa/tag_ocelot.c
+++ b/net/dsa/tag_ocelot.c
@@ -107,14 +107,16 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
ocelot_xfh_get_rew_val(extraction, &rew_val);
skb->dev = dsa_conduit_find_user(netdev, 0, src_port);
- if (!skb->dev)
+ if (!skb->dev) {
/* The switch will reflect back some frames sent through
* sockets opened on the bare DSA conduit. These will come back
* with src_port equal to the index of the CPU port, for which
* there is no user registered. So don't print any error
* message here (ignore and drop those frames).
*/
+ kfree_skb(skb);
return NULL;
+ }
dsa_default_offload_fwd_mark(skb);
skb->priority = qos_class;
diff --git a/net/dsa/tag_ocelot_8021q.c b/net/dsa/tag_ocelot_8021q.c
index e89d9254e90a..f50f1cd83f16 100644
--- a/net/dsa/tag_ocelot_8021q.c
+++ b/net/dsa/tag_ocelot_8021q.c
@@ -33,30 +33,34 @@ static struct sk_buff *ocelot_defer_xmit(struct dsa_port *dp,
xmit_work_fn = data->xmit_work_fn;
xmit_worker = priv->xmit_worker;
- if (!xmit_work_fn || !xmit_worker)
+ if (!xmit_work_fn || !xmit_worker) {
+ kfree_skb(skb);
return NULL;
+ }
/* PTP over IP packets need UDP checksumming. We may have inherited
* NETIF_F_HW_CSUM from the DSA conduit, but these packets are not sent
* through the DSA conduit, so calculate the checksum here.
*/
- if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
+ if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
xmit_work = kzalloc_obj(*xmit_work, GFP_ATOMIC);
- if (!xmit_work)
+ if (!xmit_work) {
+ kfree_skb(skb);
return NULL;
+ }
/* Calls felix_port_deferred_xmit in felix.c */
kthread_init_work(&xmit_work->work, xmit_work_fn);
- /* Increase refcount so the kfree_skb in dsa_user_xmit
- * won't really free the packet.
- */
xmit_work->dp = dp;
xmit_work->skb = skb_get(skb);
kthread_queue_work(xmit_worker, &xmit_work->work);
+ kfree_skb(skb);
return NULL;
}
@@ -84,8 +88,10 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
dsa_8021q_rcv(skb, &src_port, &switch_id, NULL, NULL);
skb->dev = dsa_conduit_find_user(netdev, switch_id, src_port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
dsa_default_offload_fwd_mark(skb);
diff --git a/net/dsa/tag_qca.c b/net/dsa/tag_qca.c
index 9e3b429e8b36..510792fbfa92 100644
--- a/net/dsa/tag_qca.c
+++ b/net/dsa/tag_qca.c
@@ -46,16 +46,20 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
tagger_data = ds->tagger_data;
- if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN)))
+ if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
phdr = dsa_etype_header_pos_rx(skb);
hdr = ntohs(*phdr);
/* Make sure the version is correct */
ver = FIELD_GET(QCA_HDR_RECV_VERSION, hdr);
- if (unlikely(ver != QCA_HDR_VERSION))
+ if (unlikely(ver != QCA_HDR_VERSION)) {
+ kfree_skb(skb);
return NULL;
+ }
/* Get pk type */
pk_type = FIELD_GET(QCA_HDR_RECV_TYPE, hdr);
@@ -64,6 +68,7 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK) {
if (likely(tagger_data->rw_reg_ack_handler))
tagger_data->rw_reg_ack_handler(ds, skb);
+ kfree_skb(skb);
return NULL;
}
@@ -71,6 +76,7 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
if (pk_type == QCA_HDR_RECV_TYPE_MIB) {
if (likely(tagger_data->mib_autocast_handler))
tagger_data->mib_autocast_handler(ds, skb);
+ kfree_skb(skb);
return NULL;
}
@@ -78,8 +84,10 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev)
port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, hdr);
skb->dev = dsa_conduit_find_user(dev, 0, port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
/* Remove QCA tag and recalculate checksum */
skb_pull_rcsum(skb, QCA_HDR_LEN);
diff --git a/net/dsa/tag_rtl4_a.c b/net/dsa/tag_rtl4_a.c
index 3cc63eacfa03..590ea3b921c9 100644
--- a/net/dsa/tag_rtl4_a.c
+++ b/net/dsa/tag_rtl4_a.c
@@ -41,7 +41,7 @@ static struct sk_buff *rtl4a_tag_xmit(struct sk_buff *skb,
u16 out;
/* Pad out to at least 60 bytes */
- if (unlikely(__skb_put_padto(skb, ETH_ZLEN, false)))
+ if (unlikely(eth_skb_pad(skb)))
return NULL;
netdev_dbg(dev, "add realtek tag to package to port %d\n",
@@ -75,8 +75,10 @@ static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb,
u8 prot;
u8 port;
- if (unlikely(!pskb_may_pull(skb, RTL4_A_HDR_LEN)))
+ if (unlikely(!pskb_may_pull(skb, RTL4_A_HDR_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
tag = dsa_etype_header_pos_rx(skb);
p = (__be16 *)tag;
@@ -92,6 +94,7 @@ static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb,
prot = (protport >> RTL4_A_PROTOCOL_SHIFT) & 0x0f;
if (prot != RTL4_A_PROTOCOL_RTL8366RB) {
netdev_err(dev, "unknown realtek protocol 0x%01x\n", prot);
+ kfree_skb(skb);
return NULL;
}
port = protport & 0xff;
@@ -99,6 +102,7 @@ static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb,
skb->dev = dsa_conduit_find_user(dev, 0, port);
if (!skb->dev) {
netdev_dbg(dev, "could not find user for port %d\n", port);
+ kfree_skb(skb);
return NULL;
}
diff --git a/net/dsa/tag_rtl8_4.c b/net/dsa/tag_rtl8_4.c
index 852c6b88079a..4da3beebef75 100644
--- a/net/dsa/tag_rtl8_4.c
+++ b/net/dsa/tag_rtl8_4.c
@@ -143,8 +143,10 @@ static struct sk_buff *rtl8_4t_tag_xmit(struct sk_buff *skb,
/* Calculate the checksum here if not done yet as trailing tags will
* break either software or hardware based checksum
*/
- if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
+ if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
rtl8_4_write_tag(skb, dev, skb_put(skb, RTL8_4_TAG_LEN));
@@ -201,11 +203,15 @@ static int rtl8_4_read_tag(struct sk_buff *skb, struct net_device *dev,
static struct sk_buff *rtl8_4_tag_rcv(struct sk_buff *skb,
struct net_device *dev)
{
- if (unlikely(!pskb_may_pull(skb, RTL8_4_TAG_LEN)))
+ if (unlikely(!pskb_may_pull(skb, RTL8_4_TAG_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
- if (unlikely(rtl8_4_read_tag(skb, dev, dsa_etype_header_pos_rx(skb))))
+ if (unlikely(rtl8_4_read_tag(skb, dev, dsa_etype_header_pos_rx(skb)))) {
+ kfree_skb(skb);
return NULL;
+ }
/* Remove tag and recalculate checksum */
skb_pull_rcsum(skb, RTL8_4_TAG_LEN);
@@ -218,14 +224,20 @@ static struct sk_buff *rtl8_4_tag_rcv(struct sk_buff *skb,
static struct sk_buff *rtl8_4t_tag_rcv(struct sk_buff *skb,
struct net_device *dev)
{
- if (skb_linearize(skb))
+ if (skb_linearize(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
- if (unlikely(rtl8_4_read_tag(skb, dev, skb_tail_pointer(skb) - RTL8_4_TAG_LEN)))
+ if (unlikely(rtl8_4_read_tag(skb, dev, skb_tail_pointer(skb) - RTL8_4_TAG_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
- if (pskb_trim_rcsum(skb, skb->len - RTL8_4_TAG_LEN))
+ if (pskb_trim_rcsum(skb, skb->len - RTL8_4_TAG_LEN)) {
+ kfree_skb(skb);
return NULL;
+ }
return skb;
}
diff --git a/net/dsa/tag_rzn1_a5psw.c b/net/dsa/tag_rzn1_a5psw.c
index 10994b3470f6..734910156dc3 100644
--- a/net/dsa/tag_rzn1_a5psw.c
+++ b/net/dsa/tag_rzn1_a5psw.c
@@ -48,7 +48,7 @@ static struct sk_buff *a5psw_tag_xmit(struct sk_buff *skb, struct net_device *de
* least 60 bytes otherwise they will be discarded when they enter the
* switch port logic.
*/
- if (__skb_put_padto(skb, ETH_ZLEN, false))
+ if (eth_skb_pad(skb))
return NULL;
/* provide 'A5PSW_TAG_LEN' bytes additional space */
@@ -77,6 +77,7 @@ static struct sk_buff *a5psw_tag_rcv(struct sk_buff *skb,
if (unlikely(!pskb_may_pull(skb, A5PSW_TAG_LEN))) {
dev_warn_ratelimited(&dev->dev,
"Dropping packet, cannot pull\n");
+ kfree_skb(skb);
return NULL;
}
@@ -84,14 +85,17 @@ static struct sk_buff *a5psw_tag_rcv(struct sk_buff *skb,
if (tag->ctrl_tag != htons(ETH_P_DSA_A5PSW)) {
dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid TAG marker\n");
+ kfree_skb(skb);
return NULL;
}
port = FIELD_GET(A5PSW_CTRL_DATA_PORT, ntohs(tag->ctrl_data));
skb->dev = dsa_conduit_find_user(dev, 0, port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
skb_pull_rcsum(skb, A5PSW_TAG_LEN);
dsa_strip_etype_header(skb, A5PSW_TAG_LEN);
diff --git a/net/dsa/tag_sja1105.c b/net/dsa/tag_sja1105.c
index de6d4ce8668b..bfe1f746f55b 100644
--- a/net/dsa/tag_sja1105.c
+++ b/net/dsa/tag_sja1105.c
@@ -149,19 +149,20 @@ static struct sk_buff *sja1105_defer_xmit(struct dsa_port *dp,
xmit_work_fn = tagger_data->xmit_work_fn;
xmit_worker = priv->xmit_worker;
- if (!xmit_work_fn || !xmit_worker)
+ if (!xmit_work_fn || !xmit_worker) {
+ kfree_skb(skb);
return NULL;
+ }
xmit_work = kzalloc_obj(*xmit_work, GFP_ATOMIC);
- if (!xmit_work)
+ if (!xmit_work) {
+ kfree_skb(skb);
return NULL;
+ }
kthread_init_work(&xmit_work->work, xmit_work_fn);
- /* Increase refcount so the kfree_skb in dsa_user_xmit
- * won't really free the packet.
- */
xmit_work->dp = dp;
- xmit_work->skb = skb_get(skb);
+ xmit_work->skb = skb;
kthread_queue_work(xmit_worker, &xmit_work->work);
@@ -401,10 +402,7 @@ static struct sk_buff
kfree_skb(priv->stampable_skb);
}
- /* Hold a reference to avoid dsa_switch_rcv
- * from freeing the skb.
- */
- priv->stampable_skb = skb_get(skb);
+ priv->stampable_skb = skb;
spin_unlock(&priv->meta_lock);
/* Tell DSA we got nothing */
@@ -436,6 +434,7 @@ static struct sk_buff
dev_err_ratelimited(ds->dev,
"Unexpected meta frame\n");
spin_unlock(&priv->meta_lock);
+ kfree_skb(skb);
return NULL;
}
@@ -443,6 +442,7 @@ static struct sk_buff
dev_err_ratelimited(ds->dev,
"Meta frame on wrong port\n");
spin_unlock(&priv->meta_lock);
+ kfree_skb(skb);
return NULL;
}
@@ -501,18 +501,21 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
/* Normal data plane traffic and link-local frames are tagged with
* a tag_8021q VLAN which we have to strip
*/
- if (sja1105_skb_has_tag_8021q(skb))
+ if (sja1105_skb_has_tag_8021q(skb)) {
dsa_8021q_rcv(skb, &source_port, &switch_id, &vbid, &vid);
- else if (source_port == -1 && switch_id == -1)
+ } else if (source_port == -1 && switch_id == -1) {
/* Packets with no source information have no chance of
* getting accepted, drop them straight away.
*/
+ kfree_skb(skb);
return NULL;
+ }
skb->dev = dsa_tag_8021q_find_user(netdev, source_port, switch_id,
vid, vbid);
if (!skb->dev) {
netdev_warn(netdev, "Couldn't decode source port\n");
+ kfree_skb(skb);
return NULL;
}
@@ -539,12 +542,15 @@ static struct sk_buff *sja1110_rcv_meta(struct sk_buff *skb, u16 rx_header)
if (!ds) {
net_err_ratelimited("%s: cannot find switch id %d\n",
conduit->name, switch_id);
+ kfree_skb(skb);
return NULL;
}
tagger_data = sja1105_tagger_data(ds);
- if (!tagger_data->meta_tstamp_handler)
+ if (!tagger_data->meta_tstamp_handler) {
+ kfree_skb(skb);
return NULL;
+ }
for (i = 0; i <= n_ts; i++) {
u8 ts_id, source_port, dir;
@@ -562,6 +568,7 @@ static struct sk_buff *sja1110_rcv_meta(struct sk_buff *skb, u16 rx_header)
}
/* Discard the meta frame, we've consumed the timestamps it contained */
+ kfree_skb(skb);
return NULL;
}
@@ -572,8 +579,10 @@ static struct sk_buff *sja1110_rcv_inband_control_extension(struct sk_buff *skb,
{
u16 rx_header;
- if (unlikely(!pskb_may_pull(skb, SJA1110_HEADER_LEN)))
+ if (unlikely(!pskb_may_pull(skb, SJA1110_HEADER_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
/* skb->data points to skb_mac_header(skb) + ETH_HLEN, which is exactly
* what we need because the caller has checked the EtherType (which is
@@ -609,8 +618,10 @@ static struct sk_buff *sja1110_rcv_inband_control_extension(struct sk_buff *skb,
* padding and trailer we need to account for the fact that
* skb->data points to skb_mac_header(skb) + ETH_HLEN.
*/
- if (pskb_trim_rcsum(skb, start_of_padding - ETH_HLEN))
+ if (pskb_trim_rcsum(skb, start_of_padding - ETH_HLEN)) {
+ kfree_skb(skb);
return NULL;
+ }
/* Trap-to-host frame, no timestamp trailer */
} else {
*source_port = SJA1110_RX_HEADER_SRC_PORT(rx_header);
@@ -653,6 +664,7 @@ static struct sk_buff *sja1110_rcv(struct sk_buff *skb,
if (!skb->dev) {
netdev_warn(netdev, "Couldn't decode source port\n");
+ kfree_skb(skb);
return NULL;
}
diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c
index 4dce24cfe6a7..49c802c10ca6 100644
--- a/net/dsa/tag_trailer.c
+++ b/net/dsa/tag_trailer.c
@@ -30,22 +30,30 @@ static struct sk_buff *trailer_rcv(struct sk_buff *skb, struct net_device *dev)
u8 *trailer;
int source_port;
- if (skb_linearize(skb))
+ if (skb_linearize(skb)) {
+ kfree_skb(skb);
return NULL;
+ }
trailer = skb_tail_pointer(skb) - 4;
if (trailer[0] != 0x80 || (trailer[1] & 0xf8) != 0x00 ||
- (trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00)
+ (trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00) {
+ kfree_skb(skb);
return NULL;
+ }
source_port = trailer[1] & 7;
skb->dev = dsa_conduit_find_user(dev, 0, source_port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
- if (pskb_trim_rcsum(skb, skb->len - 4))
+ if (pskb_trim_rcsum(skb, skb->len - 4)) {
+ kfree_skb(skb);
return NULL;
+ }
return skb;
}
diff --git a/net/dsa/tag_vsc73xx_8021q.c b/net/dsa/tag_vsc73xx_8021q.c
index af121a9aff7f..f4736a1a7a0f 100644
--- a/net/dsa/tag_vsc73xx_8021q.c
+++ b/net/dsa/tag_vsc73xx_8021q.c
@@ -44,6 +44,7 @@ vsc73xx_rcv(struct sk_buff *skb, struct net_device *netdev)
if (!skb->dev) {
dev_warn_ratelimited(&netdev->dev,
"Couldn't decode source port\n");
+ kfree_skb(skb);
return NULL;
}
diff --git a/net/dsa/tag_xrs700x.c b/net/dsa/tag_xrs700x.c
index a05219f702c6..bb268020ee86 100644
--- a/net/dsa/tag_xrs700x.c
+++ b/net/dsa/tag_xrs700x.c
@@ -30,15 +30,21 @@ static struct sk_buff *xrs700x_rcv(struct sk_buff *skb, struct net_device *dev)
source_port = ffs((int)trailer[0]) - 1;
- if (source_port < 0)
+ if (source_port < 0) {
+ kfree_skb(skb);
return NULL;
+ }
skb->dev = dsa_conduit_find_user(dev, 0, source_port);
- if (!skb->dev)
+ if (!skb->dev) {
+ kfree_skb(skb);
return NULL;
+ }
- if (pskb_trim_rcsum(skb, skb->len - 1))
+ if (pskb_trim_rcsum(skb, skb->len - 1)) {
+ kfree_skb(skb);
return NULL;
+ }
/* Frame is forwarded by hardware, don't forward in software. */
dsa_default_offload_fwd_mark(skb);
diff --git a/net/dsa/tag_yt921x.c b/net/dsa/tag_yt921x.c
index f3ced99b1c85..294784ab6694 100644
--- a/net/dsa/tag_yt921x.c
+++ b/net/dsa/tag_yt921x.c
@@ -87,8 +87,10 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev)
__be16 *tag;
u16 rx;
- if (unlikely(!pskb_may_pull(skb, YT921X_TAG_LEN)))
+ if (unlikely(!pskb_may_pull(skb, YT921X_TAG_LEN))) {
+ kfree_skb(skb);
return NULL;
+ }
tag = dsa_etype_header_pos_rx(skb);
@@ -96,6 +98,7 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev)
dev_warn_ratelimited(&netdev->dev,
"Unexpected EtherType 0x%04x\n",
ntohs(tag[0]));
+ kfree_skb(skb);
return NULL;
}
@@ -104,6 +107,7 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev)
if (unlikely((rx & YT921X_TAG_PORT_EN) == 0)) {
dev_warn_ratelimited(&netdev->dev,
"Unexpected rx tag 0x%04x\n", rx);
+ kfree_skb(skb);
return NULL;
}
@@ -112,6 +116,7 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev)
if (unlikely(!skb->dev)) {
dev_warn_ratelimited(&netdev->dev,
"Couldn't decode source port %u\n", port);
+ kfree_skb(skb);
return NULL;
}
diff --git a/net/dsa/user.c b/net/dsa/user.c
index 8704c1a3a5b7..072fa76972cc 100644
--- a/net/dsa/user.c
+++ b/net/dsa/user.c
@@ -935,13 +935,12 @@ static netdev_tx_t dsa_user_xmit(struct sk_buff *skb, struct net_device *dev)
eth_skb_pad(skb);
/* Transmit function may have to reallocate the original SKB,
- * in which case it must have freed it. Only free it here on error.
+ * in which case it must have freed it. Taggers will drop the
+ * passed skb on error.
*/
nskb = p->xmit(skb, dev);
- if (!nskb) {
- kfree_skb(skb);
+ if (!nskb)
return NETDEV_TX_OK;
- }
return dsa_enqueue_skb(nskb, dev);
}
diff --git a/net/ipv4/tcp_ao.c b/net/ipv4/tcp_ao.c
index a56bb79e15e0..e4ec60a33496 100644
--- a/net/ipv4/tcp_ao.c
+++ b/net/ipv4/tcp_ao.c
@@ -371,8 +371,9 @@ static void tcp_ao_key_free_rcu(struct rcu_head *head)
kfree_sensitive(key);
}
-static void tcp_ao_info_free(struct tcp_ao_info *ao)
+static void tcp_ao_info_free_rcu(struct rcu_head *head)
{
+ struct tcp_ao_info *ao = container_of(head, struct tcp_ao_info, rcu);
struct tcp_ao_key *key;
struct hlist_node *n;
@@ -411,7 +412,7 @@ void tcp_ao_destroy_sock(struct sock *sk, bool twsk)
if (!twsk)
tcp_ao_sk_omem_free(sk, ao);
- tcp_ao_info_free(ao);
+ call_rcu(&ao->rcu, tcp_ao_info_free_rcu);
}
void tcp_ao_time_wait(struct tcp_timewait_sock *tcptw, struct tcp_sock *tp)
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index ec09f97cc9e6..209ef7522508 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1467,9 +1467,9 @@ void tcp_clear_md5_list(struct sock *sk)
md5sig = rcu_dereference_protected(tp->md5sig_info, 1);
hlist_for_each_entry_safe(key, n, &md5sig->head, node) {
- hlist_del(&key->node);
+ hlist_del_rcu(&key->node);
atomic_sub(sizeof(*key), &sk->sk_omem_alloc);
- kfree(key);
+ kfree_rcu(key, rcu);
}
}
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 00ec4b5900f2..d7c1444b5e30 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -4329,9 +4329,13 @@ int tcp_connect(struct sock *sk)
if (needs_md5) {
tcp_ao_destroy_sock(sk, false);
} else if (needs_ao) {
+ struct tcp_md5sig_info *md5sig;
+
tcp_clear_md5_list(sk);
- kfree(rcu_replace_pointer(tp->md5sig_info, NULL,
- lockdep_sock_is_held(sk)));
+ md5sig = rcu_replace_pointer(tp->md5sig_info, NULL,
+ lockdep_sock_is_held(sk));
+ kfree_rcu(md5sig, rcu);
+ static_branch_slow_dec_deferred(&tcp_md5_needed);
}
}
#endif
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index fc95738ded76..a130cdfaebfb 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -636,12 +636,12 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
};
const struct nlmsghdr *nlh = cb->nlh;
struct net *net = sock_net(skb->sk);
- unsigned int e = 0, s_e;
struct hlist_head *head;
struct fib6_walker *w;
struct fib6_table *tb;
unsigned int h, s_h;
int err = 0;
+ u32 s_id;
rcu_read_lock();
if (cb->strict_check) {
@@ -701,23 +701,22 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
}
s_h = cb->args[0];
- s_e = cb->args[1];
+ s_id = cb->args[1];
- for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) {
- e = 0;
+ for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_id = 0) {
head = &net->ipv6.fib_table_hash[h];
hlist_for_each_entry_rcu(tb, head, tb6_hlist) {
- if (e < s_e)
- goto next;
+ if (s_id && tb->tb6_id != s_id)
+ continue;
+
+ s_id = 0;
+ cb->args[1] = tb->tb6_id;
err = fib6_dump_table(tb, skb, cb);
if (err != 0)
goto out;
-next:
- e++;
}
}
out:
- cb->args[1] = e;
cb->args[0] = h;
unlock:
diff --git a/net/ipv6/seg6.c b/net/ipv6/seg6.c
index 1c3ad25700c4..62a7eb779202 100644
--- a/net/ipv6/seg6.c
+++ b/net/ipv6/seg6.c
@@ -29,6 +29,9 @@ bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len, bool reduced)
int max_last_entry;
int trailing;
+ if (len < sizeof(*srh))
+ return false;
+
if (srh->type != IPV6_SRCRT_TYPE_4)
return false;
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
index a531b654b8d9..6cfad152d7d1 100644
--- a/net/netfilter/ipset/ip_set_core.c
+++ b/net/netfilter/ipset/ip_set_core.c
@@ -1480,7 +1480,11 @@ ip_set_dump_done(struct netlink_callback *cb)
struct ip_set_net *inst =
(struct ip_set_net *)cb->args[IPSET_CB_NET];
ip_set_id_t index = (ip_set_id_t)cb->args[IPSET_CB_INDEX];
- struct ip_set *set = ip_set_ref_netlink(inst, index);
+ struct ip_set *set;
+
+ rcu_read_lock();
+ set = ip_set_ref_netlink(inst, index);
+ rcu_read_unlock();
if (set->variant->uref)
set->variant->uref(set, cb, false);
@@ -1686,7 +1690,9 @@ next_set:
release_refcount:
/* If there was an error or set is done, release set */
if (ret || !cb->args[IPSET_CB_ARG0]) {
+ rcu_read_lock();
set = ip_set_ref_netlink(inst, index);
+ rcu_read_unlock();
if (set->variant->uref)
set->variant->uref(set, cb, false);
pr_debug("release set %s\n", set->name);
diff --git a/net/netfilter/nf_conntrack_bpf.c b/net/netfilter/nf_conntrack_bpf.c
index 40c261cd0af3..f98d1d4b42c3 100644
--- a/net/netfilter/nf_conntrack_bpf.c
+++ b/net/netfilter/nf_conntrack_bpf.c
@@ -65,6 +65,15 @@ enum {
NF_BPF_CT_OPTS_SZ = 16,
};
+static void *bpf_ct_opts_result(struct bpf_ct_opts *opts, u32 opts__sz, void *ret)
+{
+ if (!IS_ERR(ret))
+ return ret;
+ if (opts__sz >= offsetofend(struct bpf_ct_opts, error))
+ opts->error = PTR_ERR(ret);
+ return NULL;
+}
+
static int bpf_nf_ct_tuple_parse(struct bpf_sock_tuple *bpf_tuple,
u32 tuple_len, u8 protonum, u8 dir,
struct nf_conntrack_tuple *tuple)
@@ -297,12 +306,7 @@ bpf_xdp_ct_alloc(struct xdp_md *xdp_ctx, struct bpf_sock_tuple *bpf_tuple,
nfct = __bpf_nf_ct_alloc_entry(dev_net(ctx->rxq->dev), bpf_tuple, tuple__sz,
opts, opts__sz, 10);
- if (IS_ERR(nfct)) {
- opts->error = PTR_ERR(nfct);
- return NULL;
- }
-
- return (struct nf_conn___init *)nfct;
+ return (struct nf_conn___init *)bpf_ct_opts_result(opts, opts__sz, nfct);
}
/* bpf_xdp_ct_lookup - Lookup CT entry for the given tuple, and acquire a
@@ -331,11 +335,7 @@ bpf_xdp_ct_lookup(struct xdp_md *xdp_ctx, struct bpf_sock_tuple *bpf_tuple,
caller_net = dev_net(ctx->rxq->dev);
nfct = __bpf_nf_ct_lookup(caller_net, bpf_tuple, tuple__sz, opts, opts__sz);
- if (IS_ERR(nfct)) {
- opts->error = PTR_ERR(nfct);
- return NULL;
- }
- return nfct;
+ return bpf_ct_opts_result(opts, opts__sz, nfct);
}
/* bpf_skb_ct_alloc - Allocate a new CT entry
@@ -363,12 +363,7 @@ bpf_skb_ct_alloc(struct __sk_buff *skb_ctx, struct bpf_sock_tuple *bpf_tuple,
net = skb->dev ? dev_net(skb->dev) : sock_net(skb->sk);
nfct = __bpf_nf_ct_alloc_entry(net, bpf_tuple, tuple__sz, opts, opts__sz, 10);
- if (IS_ERR(nfct)) {
- opts->error = PTR_ERR(nfct);
- return NULL;
- }
-
- return (struct nf_conn___init *)nfct;
+ return (struct nf_conn___init *)bpf_ct_opts_result(opts, opts__sz, nfct);
}
/* bpf_skb_ct_lookup - Lookup CT entry for the given tuple, and acquire a
@@ -397,11 +392,7 @@ bpf_skb_ct_lookup(struct __sk_buff *skb_ctx, struct bpf_sock_tuple *bpf_tuple,
caller_net = skb->dev ? dev_net(skb->dev) : sock_net(skb->sk);
nfct = __bpf_nf_ct_lookup(caller_net, bpf_tuple, tuple__sz, opts, opts__sz);
- if (IS_ERR(nfct)) {
- opts->error = PTR_ERR(nfct);
- return NULL;
- }
- return nfct;
+ return bpf_ct_opts_result(opts, opts__sz, nfct);
}
/* bpf_ct_insert_entry - Add the provided entry into a CT map
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 38630c5e006f..7ae68d60586a 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -306,7 +306,7 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
{
struct nf_conntrack_expect *new;
- new = kmem_cache_alloc(nf_ct_expect_cachep, GFP_ATOMIC);
+ new = kmem_cache_zalloc(nf_ct_expect_cachep, GFP_ATOMIC);
if (!new)
return NULL;
@@ -391,6 +391,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
#if IS_ENABLED(CONFIG_NF_NAT)
memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
+ exp->dir = 0;
#endif
}
EXPORT_SYMBOL_GPL(nf_ct_expect_init);
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 4217715d42dc..31cbb1b55b9e 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -3549,8 +3549,6 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
if (cda[CTA_EXPECT_FLAGS]) {
exp->flags = ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS]));
exp->flags &= ~NF_CT_EXPECT_USERSPACE;
- } else {
- exp->flags = 0;
}
if (cda[CTA_EXPECT_FN]) {
const char *name = nla_data(cda[CTA_EXPECT_FN]);
@@ -3562,8 +3560,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
goto err_out;
}
exp->expectfn = expfn->expectfn;
- } else
- exp->expectfn = NULL;
+ }
exp->class = class;
exp->master = ct;
@@ -3583,12 +3580,6 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
exp, nf_ct_l3num(ct));
if (err < 0)
goto err_out;
-#if IS_ENABLED(CONFIG_NF_NAT)
- } else {
- memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
- memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
- exp->dir = 0;
-#endif
}
return exp;
err_out:
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 5ec3a4a4bbd7..f3f90a866338 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -956,7 +956,6 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
return NF_ACCEPT;
saddr = &ct->tuplehash[!dir].tuple.src.u3;
} else if (sip_external_media) {
- struct net_device *dev = skb_dst(skb)->dev;
struct dst_entry *dst = NULL;
struct flowi fl;
@@ -978,7 +977,11 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
* through the same interface as the signalling peer.
*/
if (dst) {
- bool external_media = (dst->dev == dev);
+ const struct dst_entry *this_dst = skb_dst(skb);
+ bool external_media = false;
+
+ if (this_dst && dst->dev == this_dst->dev)
+ external_media = true;
dst_release(dst);
if (external_media)
diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c
index f1460b683d7a..2cbcca9110db 100644
--- a/net/netfilter/nfnetlink_cthelper.c
+++ b/net/netfilter/nfnetlink_cthelper.c
@@ -163,6 +163,8 @@ nfnl_cthelper_expect_policy(struct nf_conntrack_expect_policy *expect_policy,
tb[NFCTH_POLICY_NAME], NF_CT_HELPER_NAME_LEN);
expect_policy->max_expected =
ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX]));
+ if (!expect_policy->max_expected)
+ expect_policy->max_expected = NF_CT_EXPECT_MAX_CNT;
if (expect_policy->max_expected > NF_CT_EXPECT_MAX_CNT)
return -EINVAL;
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 80ca077b81bd..35d4c6c628ff 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -1184,6 +1184,173 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
return err;
}
+static bool nfqnl_validate_ipopts(const struct iphdr *iph_new,
+ const struct nf_queue_entry *e)
+{
+ const struct iphdr *iph_orig = ip_hdr(e->skb);
+ unsigned int ihl = iph_new->ihl * 4;
+
+ if (iph_new->ihl != iph_orig->ihl)
+ return false;
+ if (ihl == sizeof(*iph_orig))
+ return true;
+
+ return memcmp(iph_new + 1, ip_hdr(e->skb) + 1, ihl - sizeof(*iph_orig)) == 0;
+}
+
+static bool nfqnl_validate_ip4(const struct iphdr *iph, unsigned int data_len,
+ const struct nf_queue_entry *e)
+{
+ unsigned int ihl;
+
+ if (data_len < sizeof(*iph))
+ return false;
+
+ ihl = iph->ihl * 4u;
+ if (ihl < sizeof(*iph) || data_len < ihl)
+ return false;
+
+ if (iph->version != 4 ||
+ ((iph->frag_off ^ ip_hdr(e->skb)->frag_off) & ~htons(IP_DF)) != 0)
+ return false;
+
+ /* BIG TCP won't work; netlink attr len is u16 */
+ if (ntohs(iph->tot_len) != data_len)
+ return false;
+
+ /* support for ipopts mangling would require
+ * recompile + skb transport header update.
+ */
+ return nfqnl_validate_ipopts(iph, e);
+}
+
+static bool nfqnl_validate_one_exthdr(const u8 *data,
+ unsigned int data_len,
+ const struct nf_queue_entry *e,
+ int start, int hdrlen)
+{
+ u16 octets;
+
+ if (data_len < hdrlen || hdrlen < 2)
+ return false;
+
+ while (hdrlen > 0) {
+ if (data_len < sizeof(octets))
+ return false;
+ data_len -= sizeof(octets);
+
+ if (skb_copy_bits(e->skb, start, &octets, sizeof(octets)))
+ return false;
+
+ if (hdrlen < sizeof(octets))
+ return false;
+
+ hdrlen -= sizeof(octets);
+ if (memcmp(data, &octets, sizeof(octets)))
+ return false;
+
+ start += sizeof(octets);
+ data += sizeof(octets);
+ }
+
+ return true;
+}
+
+static bool nfqnl_validate_exthdr(const struct ipv6hdr *ip6_new,
+ unsigned int data_len,
+ const struct nf_queue_entry *e)
+{
+ const struct ipv6hdr *ip6_orig = ipv6_hdr(e->skb);
+ int exthdr_cnt = 0, start = sizeof(*ip6_orig);
+ const u8 *data = (const u8 *)ip6_new;
+ u8 orig_nexthdr = ip6_orig->nexthdr;
+ u8 new_nexthdr = ip6_new->nexthdr;
+
+ if (new_nexthdr != orig_nexthdr)
+ return false;
+
+ data += sizeof(*ip6_new);
+ data_len -= sizeof(*ip6_new);
+
+ while (ipv6_ext_hdr(orig_nexthdr)) {
+ const struct ipv6_opt_hdr *hp;
+ struct ipv6_opt_hdr _hdr;
+ int hdrlen;
+
+ if (orig_nexthdr == NEXTHDR_NONE)
+ return true;
+
+ if (unlikely(exthdr_cnt++ >= IP6_MAX_EXT_HDRS_CNT))
+ return false;
+
+ hp = skb_header_pointer(e->skb, start, sizeof(_hdr), &_hdr);
+ if (!hp)
+ return false;
+
+ switch (orig_nexthdr) {
+ case NEXTHDR_FRAGMENT:
+ hdrlen = sizeof(struct frag_hdr);
+ break;
+ case NEXTHDR_AUTH:
+ hdrlen = ipv6_authlen(hp);
+ break;
+ default:
+ hdrlen = ipv6_optlen(hp);
+ break;
+ }
+
+ if (!nfqnl_validate_one_exthdr(data, data_len, e,
+ start, hdrlen))
+ return false;
+
+ orig_nexthdr = hp->nexthdr;
+ hp = (const void *)data;
+ new_nexthdr = hp->nexthdr;
+
+ if (new_nexthdr != orig_nexthdr)
+ return false;
+
+ data_len -= hdrlen;
+ start += hdrlen;
+ data += hdrlen;
+ }
+
+ return true;
+}
+
+static bool nfqnl_validate_ip6(const struct ipv6hdr *ip6, unsigned int data_len,
+ const struct nf_queue_entry *e)
+{
+ if (data_len < sizeof(*ip6))
+ return false;
+
+ /* BIG TCP/jumbograms won't work; netlink attr len is u16 */
+ if (ntohs(ip6->payload_len) != data_len - sizeof(*ip6))
+ return false;
+
+ if (ip6->version != 6)
+ return false;
+
+ return nfqnl_validate_exthdr(ip6, data_len, e);
+}
+
+static bool nfqnl_validate_write(const void *data, unsigned int data_len,
+ const struct nf_queue_entry *e)
+{
+ switch (e->state.pf) {
+ case NFPROTO_IPV4:
+ return nfqnl_validate_ip4(data, data_len, e);
+ case NFPROTO_IPV6:
+ return nfqnl_validate_ip6(data, data_len, e) &&
+ !(IP6CB(e->skb)->flags & IP6SKB_JUMBOGRAM);
+ case NFPROTO_BRIDGE:
+ /* No write support. Bridge is dubious: userspace doesn't even see L2 header */
+ return false;
+ }
+
+ return false;
+}
+
static int
nfqnl_mangle(void *data, unsigned int data_len, struct nf_queue_entry *e, int diff)
{
@@ -1192,6 +1359,9 @@ nfqnl_mangle(void *data, unsigned int data_len, struct nf_queue_entry *e, int di
if (e->state.net->user_ns != &init_user_ns)
return -EPERM;
+ if (!nfqnl_validate_write(data, data_len, e))
+ return -EINVAL;
+
if (diff < 0) {
unsigned int min_len = skb_transport_offset(e->skb);
diff --git a/net/netfilter/nft_fib.c b/net/netfilter/nft_fib.c
index e048f05694cd..89555380f1c5 100644
--- a/net/netfilter/nft_fib.c
+++ b/net/netfilter/nft_fib.c
@@ -31,6 +31,15 @@ int nft_fib_validate(const struct nft_ctx *ctx, const struct nft_expr *expr)
const struct nft_fib *priv = nft_expr_priv(expr);
unsigned int hooks;
+ switch (ctx->family) {
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ case NFPROTO_INET:
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
switch (priv->result) {
case NFT_FIB_RESULT_OIF:
case NFT_FIB_RESULT_OIFNAME:
diff --git a/net/netfilter/nft_fib_netdev.c b/net/netfilter/nft_fib_netdev.c
index 3f3478abd845..5774a7544027 100644
--- a/net/netfilter/nft_fib_netdev.c
+++ b/net/netfilter/nft_fib_netdev.c
@@ -50,6 +50,33 @@ static void nft_fib_netdev_eval(const struct nft_expr *expr,
regs->verdict.code = NFT_BREAK;
}
+static int nft_fib_netdev_validate(const struct nft_ctx *ctx,
+ const struct nft_expr *expr)
+{
+ const struct nft_fib *priv = nft_expr_priv(expr);
+ unsigned int hooks;
+
+ switch (priv->result) {
+ case NFT_FIB_RESULT_OIF:
+ case NFT_FIB_RESULT_OIFNAME:
+ hooks = (1 << NF_NETDEV_INGRESS);
+ break;
+ case NFT_FIB_RESULT_ADDRTYPE:
+ if (priv->flags & NFTA_FIB_F_IIF)
+ hooks = (1 << NF_NETDEV_INGRESS);
+ else if (priv->flags & NFTA_FIB_F_OIF)
+ hooks = (1 << NF_NETDEV_EGRESS);
+ else
+ hooks = (1 << NF_NETDEV_INGRESS) |
+ (1 << NF_NETDEV_EGRESS);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return nft_chain_validate_hooks(ctx->chain, hooks);
+}
+
static struct nft_expr_type nft_fib_netdev_type;
static const struct nft_expr_ops nft_fib_netdev_ops = {
.type = &nft_fib_netdev_type,
@@ -57,7 +84,7 @@ static const struct nft_expr_ops nft_fib_netdev_ops = {
.eval = nft_fib_netdev_eval,
.init = nft_fib_init,
.dump = nft_fib_dump,
- .validate = nft_fib_validate,
+ .validate = nft_fib_netdev_validate,
};
static struct nft_expr_type nft_fib_netdev_type __read_mostly = {
diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
index 345eff140d56..391539a1ceaa 100644
--- a/net/netfilter/nft_payload.c
+++ b/net/netfilter/nft_payload.c
@@ -834,6 +834,249 @@ nft_payload_set_vlan(const u32 *src, struct sk_buff *skb, u16 offset, u8 len,
return true;
}
+/* Ingress is very early, before l3 protocol handlers.
+ * There should be no in-tree code that trusts l3/l4 headers
+ * between ingress and NF_INET_PRE_ROUTING hooks.
+ */
+static bool nft_in_ingress(const struct nf_hook_state *s)
+{
+ return s->pf == NFPROTO_NETDEV && s->hook == NF_NETDEV_INGRESS;
+}
+
+static bool nft_nh_write_ok_ip4(const struct nft_pktinfo *pkt,
+ const struct nft_payload_set *priv,
+ const u32 *src)
+{
+ unsigned int offset = priv->offset + skb_network_offset(pkt->skb);
+ const u8 *new_octets = (const u8 *)src;
+ u8 old_octet;
+
+ switch (priv->offset) {
+ case 0: /* csum fixups does expand dscp/tos store to 2 bytes.
+ * make sure ihl/version remain unchanged.
+ */
+ if (skb_copy_bits(pkt->skb, offset, &old_octet, sizeof(old_octet)))
+ return false;
+
+ return priv->len == 2 &&
+ *new_octets == old_octet;
+ case offsetof(struct iphdr, tos):
+ return priv->len == 1;
+ case offsetof(struct iphdr, id):
+ return priv->len == 2;
+ case offsetof(struct iphdr, ttl):
+ if (priv->len == 1)
+ return true;
+
+ if (priv->len != 2)
+ return false;
+
+ /* same, csum fixup does expand ttl store to two bytes.
+ * check protocol is not altered.
+ */
+ if (skb_copy_bits(pkt->skb, offset + 1, &old_octet, sizeof(old_octet)))
+ return false;
+
+ return new_octets[1] == old_octet;
+ case offsetof(struct iphdr, check):
+ return priv->len <= 2 + 4 + 4;
+ case offsetof(struct iphdr, saddr):
+ return priv->len <= 4 + 4;
+ case offsetof(struct iphdr, daddr):
+ return priv->len <= 4;
+ }
+
+ return false;
+}
+
+static bool nft_nh_write_ok_ip6(const struct nft_pktinfo *pkt,
+ const struct nft_payload_set *priv,
+ const u32 *src)
+{
+ const struct ipv6hdr *ih = (const void *)src;
+
+ switch (priv->offset) {
+ case 0: /* store to dscp must not alter ip6 version */
+ return priv->len <= 4 && ih->version == 6;
+ case 2:
+ return priv->len <= 2;
+ case offsetof(struct ipv6hdr, hop_limit):
+ return priv->len == 1;
+ case offsetof(struct ipv6hdr, saddr):
+ return priv->len <= 16 + 16;
+ case offsetof(struct ipv6hdr, daddr):
+ return priv->len <= 16;
+ }
+
+ return false;
+}
+
+static bool nft_nh_write_ok_arp(const struct nft_payload_set *priv)
+{
+ /* Variable size for standard ethernet arp */
+ const unsigned int eth_ip = 2 * (ETH_ALEN + 4);
+ unsigned int offset = priv->offset;
+
+ switch (offset) {
+ case offsetof(struct arphdr, ar_op):
+ return priv->len == 2;
+ default:
+ break;
+ }
+
+ /* permit writes post fixed arp header size. offset + len are
+ * checked vs skb size via skb_ensure_writable.
+ */
+ return offset >= sizeof(struct arphdr) && priv->len <= eth_ip;
+}
+
+static bool nft_nh_write_ok_netdev(const struct nft_pktinfo *pkt,
+ const struct nft_payload_set *priv,
+ const u32 *src)
+{
+#ifdef CONFIG_NF_TABLES_NETDEV
+ switch (pkt->skb->protocol) {
+ case htons(ETH_P_ARP):
+ return nft_nh_write_ok_arp(priv);
+ case htons(ETH_P_IP):
+ return nft_nh_write_ok_ip4(pkt, priv, src);
+ case htons(ETH_P_IPV6):
+ return nft_nh_write_ok_ip6(pkt, priv, src);
+ }
+#endif
+ /* default to false for now, relax later in case we have
+ * use-cases that need inner header manipulation for
+ * encapsulated traffic like vlan or PPPoE.
+ */
+ return false;
+}
+
+static bool nft_nh_write_ok_bridge(const struct nft_pktinfo *pkt,
+ const struct nft_payload_set *priv,
+ const u32 *src)
+{
+#if IS_ENABLED(CONFIG_NF_TABLES_BRIDGE)
+ switch (pkt->ethertype) {
+ case htons(ETH_P_ARP):
+ return nft_nh_write_ok_arp(priv);
+ case htons(ETH_P_IP):
+ return nft_nh_write_ok_ip4(pkt, priv, src);
+ case htons(ETH_P_IPV6):
+ return nft_nh_write_ok_ip6(pkt, priv, src);
+ }
+#endif
+ /* see nft_nh_write_ok_netdev: default to false */
+ return false;
+}
+
+static bool nft_nh_write_ok(const struct nft_pktinfo *pkt,
+ const struct nft_payload_set *priv,
+ const u32 *src)
+{
+ switch (pkt->state->pf) {
+ case NFPROTO_ARP:
+ return nft_nh_write_ok_arp(priv);
+ case NFPROTO_BRIDGE:
+ return nft_nh_write_ok_bridge(pkt, priv, src);
+ case NFPROTO_IPV4:
+ return nft_nh_write_ok_ip4(pkt, priv, src);
+ case NFPROTO_IPV6:
+ return nft_nh_write_ok_ip6(pkt, priv, src);
+ case NFPROTO_NETDEV:
+ if (pkt->state->hook == NF_NETDEV_INGRESS)
+ return true;
+ return nft_nh_write_ok_netdev(pkt, priv, src);
+ }
+
+ return false;
+}
+
+/* check linklayer modifications don't spill into network header. */
+static bool nft_ll_write_ok(const struct nft_pktinfo *pkt, int offset)
+{
+ if (nft_in_ingress(pkt->state))
+ return true;
+
+ return offset <= skb_network_offset(pkt->skb);
+}
+
+static bool nft_payload_validate_inet_csum_offset(const struct nft_ctx *ctx,
+ const struct nft_payload_set *priv)
+{
+ switch (priv->base) {
+ case NFT_PAYLOAD_LL_HEADER:
+ break;
+ case NFT_PAYLOAD_NETWORK_HEADER:
+ if (ctx->family == NFPROTO_IPV4) {
+ if (offsetof(struct iphdr, check) == priv->csum_offset)
+ return true;
+
+ return false;
+ }
+ return true; /* run time validation required */
+ case NFT_PAYLOAD_TRANSPORT_HEADER:
+ if (priv->csum_flags) /* makes no sense, asks for "re-update" of L4 checksum */
+ return false;
+
+ /* no further check here; offset can't be negative so bogus
+ * offsets can corrupt L4 or payload but not l3 headers.
+ * We already allow arbitrary l4/inner payload writes.
+ */
+ return true;
+ case NFT_PAYLOAD_INNER_HEADER:
+ return true;
+ case NFT_PAYLOAD_TUN_HEADER:
+ break;
+ }
+
+ return false;
+}
+
+/* do not allow arbitrary network header mangling via bogus csum_off.
+ * We only support ipv4. Only NFPROTO_IPV4 can be checked from control
+ * plane.
+ */
+static bool nft_payload_csum_nh_write_ok(const struct nft_payload_set *priv,
+ const struct nft_pktinfo *pkt)
+{
+ switch (pkt->state->pf) {
+ case NFPROTO_IPV4:
+ /* Warning: NFPROTO_INET was not checked; we can't return true here. */
+ return priv->csum_offset == offsetof(struct iphdr, check);
+ case NFPROTO_IPV6:
+ return false;
+ case NFPROTO_BRIDGE:
+ return pkt->ethertype == htons(ETH_P_IP) &&
+ priv->csum_offset == offsetof(struct iphdr, check);
+ case NFPROTO_NETDEV:
+ return pkt->skb->protocol == htons(ETH_P_IP) &&
+ priv->csum_offset == offsetof(struct iphdr, check);
+ }
+
+ return false;
+}
+
+static bool nft_payload_csum_write_ok(const struct nft_pktinfo *pkt,
+ const struct nft_payload_set *priv)
+{
+ switch (priv->base) {
+ case NFT_PAYLOAD_LL_HEADER:
+ break;
+ case NFT_PAYLOAD_NETWORK_HEADER:
+ return nft_payload_csum_nh_write_ok(priv, pkt);
+ case NFT_PAYLOAD_TRANSPORT_HEADER:
+ case NFT_PAYLOAD_INNER_HEADER:
+ /* neither offsets are validated, offsets cannot be
+ * negative so real l3 headers cannot be mangled.
+ */
+ return true;
+ case NFT_PAYLOAD_TUN_HEADER:
+ break;
+ }
+
+ return false;
+}
+
static void nft_payload_set_eval(const struct nft_expr *expr,
struct nft_regs *regs,
const struct nft_pktinfo *pkt)
@@ -861,8 +1104,12 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
}
offset = skb_mac_header(skb) - skb->data - vlan_hlen;
+ if (!nft_ll_write_ok(pkt, priv->len + priv->offset + offset))
+ goto err;
break;
case NFT_PAYLOAD_NETWORK_HEADER:
+ if (!nft_nh_write_ok(pkt, priv, src))
+ goto err;
offset = skb_network_offset(skb);
break;
case NFT_PAYLOAD_TRANSPORT_HEADER:
@@ -894,6 +1141,7 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
tsum = csum_partial(src, priv->len, 0);
if (priv->csum_type == NFT_PAYLOAD_CSUM_INET &&
+ nft_payload_csum_write_ok(pkt, priv) &&
nft_payload_csum_inet(skb, src, fsum, tsum, csum_offset))
goto err;
@@ -960,7 +1208,26 @@ static int nft_payload_set_init(const struct nft_ctx *ctx,
switch (csum_type) {
case NFT_PAYLOAD_CSUM_NONE:
+ if (priv->csum_offset) /* nonsensical */
+ return -EINVAL;
+
+ if (priv->csum_flags == 0)
+ break;
+
+ /* Userspace requests L4 checksum update, e.g.:
+ * - IPv6 stateless NAT (no l3 csum)
+ * - transport header mangling
+ * - inner data mangling
+ */
+ if (priv->base == NFT_PAYLOAD_NETWORK_HEADER ||
+ priv->base == NFT_PAYLOAD_TRANSPORT_HEADER ||
+ priv->base == NFT_PAYLOAD_INNER_HEADER)
+ break;
+
+ return -EINVAL;
case NFT_PAYLOAD_CSUM_INET:
+ if (!nft_payload_validate_inet_csum_offset(ctx, priv))
+ return -EINVAL;
break;
case NFT_PAYLOAD_CSUM_SCTP:
if (priv->base != NFT_PAYLOAD_TRANSPORT_HEADER)
@@ -968,6 +1235,9 @@ static int nft_payload_set_init(const struct nft_ctx *ctx,
if (priv->csum_offset != offsetof(struct sctphdr, checksum))
return -EINVAL;
+
+ if (priv->csum_flags)
+ return -EINVAL;
break;
default:
return -EOPNOTSUPP;
diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c
index 706c78853f24..978bb0c01106 100644
--- a/net/netfilter/nft_set_pipapo.c
+++ b/net/netfilter/nft_set_pipapo.c
@@ -342,6 +342,8 @@
#include "nft_set_pipapo_avx2.h"
#include "nft_set_pipapo.h"
+static void nft_pipapo_abort(const struct nft_set *set);
+
/**
* pipapo_refill() - For each set bit, set bits from selected mapping table item
* @map: Bitmap to be scanned for set bits
@@ -1296,7 +1298,7 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
const u8 *start_p, *end_p;
int i, bsize_max, err = 0;
- if (!m)
+ if (!m || m->state == NFT_PIPAPO_CLONE_ERR)
return -ENOMEM;
if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END))
@@ -1367,8 +1369,10 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
else
ret = pipapo_expand(f, start, end, f->groups * f->bb);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ err = ret;
+ goto abort;
+ }
if (f->bsize > bsize_max)
bsize_max = f->bsize;
@@ -1384,7 +1388,7 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
err = pipapo_realloc_scratch(m, bsize_max);
if (err)
- return err;
+ goto abort;
m->bsize_max = bsize_max;
} else {
@@ -1396,7 +1400,26 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
pipapo_map(m, rulemap, e);
+ m->state = NFT_PIPAPO_CLONE_MOD;
return 0;
+abort:
+ DEBUG_NET_WARN_ON_ONCE(m->state == NFT_PIPAPO_CLONE_ERR);
+
+ /* Two rollback cases:
+ * 1) no previous changes. nft_pipapo_abort is not
+ * guaranteed to be invoked (there might be no further
+ * add/delete requests coming after this).
+ *
+ * 2) we had previous changes: there are transaction
+ * records pointing to this set. Leave the rollback to
+ * the transaction handling.
+ */
+ if (m->state == NFT_PIPAPO_CLONE_NEW)
+ nft_pipapo_abort(set); /* releases m */
+ else
+ m->state = NFT_PIPAPO_CLONE_ERR;
+
+ return err;
}
/**
@@ -1473,6 +1496,7 @@ static struct nft_pipapo_match *pipapo_clone(struct nft_pipapo_match *old)
dst++;
}
+ new->state = NFT_PIPAPO_CLONE_NEW;
return new;
out_mt:
@@ -1896,7 +1920,7 @@ nft_pipapo_deactivate(const struct net *net, const struct nft_set *set,
/* removal must occur on priv->clone, if we are low on memory
* we have no choice and must fail the removal request.
*/
- if (!m)
+ if (!m || m->state == NFT_PIPAPO_CLONE_ERR)
return NULL;
e = pipapo_get(m, (const u8 *)elem->key.val.data,
diff --git a/net/netfilter/nft_set_pipapo.h b/net/netfilter/nft_set_pipapo.h
index b82abb03576e..a19e980d06ef 100644
--- a/net/netfilter/nft_set_pipapo.h
+++ b/net/netfilter/nft_set_pipapo.h
@@ -131,9 +131,16 @@ struct nft_pipapo_scratch {
unsigned long __map[];
};
+enum nft_pipapo_clone_state {
+ NFT_PIPAPO_CLONE_NEW,
+ NFT_PIPAPO_CLONE_MOD,
+ NFT_PIPAPO_CLONE_ERR,
+};
+
/**
* struct nft_pipapo_match - Data used for lookup and matching
* @field_count: Amount of fields in set
+ * @state: add/delete state; used from control plane
* @bsize_max: Maximum lookup table bucket size of all fields, in longs
* @scratch: Preallocated per-CPU maps for partial matching results
* @rcu: Matching data is swapped on commits
@@ -141,6 +148,7 @@ struct nft_pipapo_scratch {
*/
struct nft_pipapo_match {
u8 field_count;
+ enum nft_pipapo_clone_state state:8;
unsigned int bsize_max;
struct nft_pipapo_scratch * __percpu *scratch;
struct rcu_head rcu;
diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c
index 58a074651176..09d46e195e33 100644
--- a/net/sched/act_bpf.c
+++ b/net/sched/act_bpf.c
@@ -44,7 +44,7 @@ TC_INDIRECT_SCOPE int tcf_bpf_act(struct sk_buff *skb,
tcf_lastuse_update(&prog->tcf_tm);
bstats_update(this_cpu_ptr(prog->common.cpu_bstats), skb);
- filter = rcu_dereference(prog->filter);
+ filter = rcu_dereference_bh(prog->filter);
if (at_ingress) {
__skb_push(skb, skb->mac_len);
filter_res = bpf_prog_run_data_pointers(filter, skb);
diff --git a/net/sched/sch_dualpi2.c b/net/sched/sch_dualpi2.c
index 5434df6ca8ef..27088760eff4 100644
--- a/net/sched/sch_dualpi2.c
+++ b/net/sched/sch_dualpi2.c
@@ -346,6 +346,8 @@ static int dualpi2_skb_classify(struct dualpi2_sched_data *q,
struct tcf_proto *fl;
int result;
+ cb->classified = DUALPI2_C_CLASSIC;
+
dualpi2_read_ect(skb);
if (cb->ect & q->ecn_mask) {
cb->classified = DUALPI2_C_L4S;
@@ -359,10 +361,8 @@ static int dualpi2_skb_classify(struct dualpi2_sched_data *q,
}
fl = rcu_dereference_bh(q->tcf_filters);
- if (!fl) {
- cb->classified = DUALPI2_C_CLASSIC;
+ if (!fl)
return NET_XMIT_SUCCESS;
- }
result = tcf_classify(skb, NULL, fl, &res, false);
if (result >= 0) {
diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c
index 1e25b75daae2..d85cb0263b67 100644
--- a/net/sched/sch_hhf.c
+++ b/net/sched/sch_hhf.c
@@ -462,12 +462,39 @@ begin:
return skb;
}
+static void hhf_reset_classifier(struct hhf_sched_data *q)
+{
+ int i;
+
+ if (!q->hh_flows)
+ return;
+
+ for (i = 0; i < HH_FLOWS_CNT; i++) {
+ struct hh_flow_state *flow, *next;
+ struct list_head *head = &q->hh_flows[i];
+
+ list_for_each_entry_safe(flow, next, head, flowchain) {
+ list_del(&flow->flowchain);
+ kfree(flow);
+ }
+ }
+ WRITE_ONCE(q->hh_flows_current_cnt, 0);
+
+ for (i = 0; i < HHF_ARRAYS_CNT; i++) {
+ if (q->hhf_valid_bits[i])
+ bitmap_zero(q->hhf_valid_bits[i], HHF_ARRAYS_LEN);
+ }
+ q->hhf_arrays_reset_timestamp = hhf_time_stamp();
+}
+
static void hhf_reset(struct Qdisc *sch)
{
+ struct hhf_sched_data *q = qdisc_priv(sch);
struct sk_buff *skb;
while ((skb = hhf_dequeue(sch)) != NULL)
rtnl_kfree_skbs(skb, skb);
+ hhf_reset_classifier(q);
}
static void hhf_destroy(struct Qdisc *sch)
diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c
index 4e465d11e3d7..a467dd122369 100644
--- a/net/sched/sch_multiq.c
+++ b/net/sched/sch_multiq.c
@@ -103,7 +103,7 @@ static struct sk_buff *multiq_dequeue(struct Qdisc *sch)
if (!netif_xmit_stopped(
netdev_get_tx_queue(qdisc_dev(sch), q->curband))) {
qdisc = q->queues[q->curband];
- skb = qdisc->dequeue(qdisc);
+ skb = qdisc_dequeue_peeked(qdisc);
if (skb) {
qdisc_bstats_update(sch, skb);
qdisc_qlen_dec(sch);
diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c
index 558987d9b977..299234a5f0fe 100644
--- a/net/sched/sch_taprio.c
+++ b/net/sched/sch_taprio.c
@@ -749,7 +749,7 @@ static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq,
return NULL;
skip_peek_checks:
- skb = child->ops->dequeue(child);
+ skb = qdisc_dequeue_peeked(child);
if (unlikely(!skb))
return NULL;
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index e7bbc9e5174d..24ba31f8c828 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -52,7 +52,8 @@
struct teql_master {
struct Qdisc_ops qops;
struct net_device *dev;
- struct Qdisc *slaves;
+ struct Qdisc __rcu *slaves;
+ spinlock_t slaves_lock; /* serializes writes to ->slaves */
struct list_head master_list;
unsigned long tx_bytes;
unsigned long tx_packets;
@@ -61,7 +62,7 @@ struct teql_master {
};
struct teql_sched_data {
- struct Qdisc *next;
+ struct Qdisc __rcu *next;
struct teql_master *m;
struct sk_buff_head q;
};
@@ -101,7 +102,9 @@ teql_dequeue(struct Qdisc *sch)
if (skb == NULL) {
struct net_device *m = qdisc_dev(q);
if (m) {
- dat->m->slaves = sch;
+ spin_lock_bh(&dat->m->slaves_lock);
+ rcu_assign_pointer(dat->m->slaves, sch);
+ spin_unlock_bh(&dat->m->slaves_lock);
netif_wake_queue(m);
}
} else {
@@ -132,34 +135,49 @@ teql_destroy(struct Qdisc *sch)
struct Qdisc *q, *prev;
struct teql_sched_data *dat = qdisc_priv(sch);
struct teql_master *master = dat->m;
+ struct netdev_queue *txq = NULL;
+ bool reset_master_queue = false;
if (!master)
return;
- prev = master->slaves;
+ spin_lock_bh(&master->slaves_lock);
+ prev = rcu_dereference_protected(master->slaves,
+ lockdep_is_held(&master->slaves_lock));
if (prev) {
do {
- q = NEXT_SLAVE(prev);
- if (q == sch) {
- NEXT_SLAVE(prev) = NEXT_SLAVE(q);
- if (q == master->slaves) {
- master->slaves = NEXT_SLAVE(q);
- if (q == master->slaves) {
- struct netdev_queue *txq;
-
- txq = netdev_get_tx_queue(master->dev, 0);
- master->slaves = NULL;
-
- dev_reset_queue(master->dev,
- txq, NULL);
- }
- }
- skb_queue_purge(&dat->q);
- break;
+ struct Qdisc *head, *next;
+
+ q = rcu_dereference_protected(NEXT_SLAVE(prev),
+ lockdep_is_held(&master->slaves_lock));
+ if (q != sch) {
+ prev = q;
+ continue;
}
- } while ((prev = q) != master->slaves);
+ next = rcu_dereference_protected(NEXT_SLAVE(q),
+ lockdep_is_held(&master->slaves_lock));
+ rcu_assign_pointer(NEXT_SLAVE(prev), next);
+
+ head = rcu_dereference_protected(master->slaves,
+ lockdep_is_held(&master->slaves_lock));
+ if (q == head) {
+ rcu_assign_pointer(master->slaves, next);
+ if (q == next) {
+ txq = netdev_get_tx_queue(master->dev, 0);
+ rcu_assign_pointer(master->slaves, NULL);
+ reset_master_queue = true;
+ }
+ }
+ skb_queue_purge(&dat->q);
+ break;
+ } while (prev != rcu_dereference_protected(master->slaves,
+ lockdep_is_held(&master->slaves_lock)));
}
+ spin_unlock_bh(&master->slaves_lock);
+
+ if (reset_master_queue)
+ dev_reset_queue(master->dev, txq, NULL);
}
static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,
@@ -168,6 +186,7 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,
struct net_device *dev = qdisc_dev(sch);
struct teql_master *m = (struct teql_master *)sch->ops;
struct teql_sched_data *q = qdisc_priv(sch);
+ struct Qdisc *first;
if (dev->hard_header_len > m->dev->hard_header_len)
return -EINVAL;
@@ -184,7 +203,9 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,
skb_queue_head_init(&q->q);
- if (m->slaves) {
+ spin_lock_bh(&m->slaves_lock);
+ first = rcu_dereference_protected(m->slaves, lockdep_is_held(&m->slaves_lock));
+ if (first) {
if (m->dev->flags & IFF_UP) {
if ((m->dev->flags & IFF_POINTOPOINT &&
!(dev->flags & IFF_POINTOPOINT)) ||
@@ -192,8 +213,10 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,
!(dev->flags & IFF_BROADCAST)) ||
(m->dev->flags & IFF_MULTICAST &&
!(dev->flags & IFF_MULTICAST)) ||
- dev->mtu < m->dev->mtu)
+ dev->mtu < m->dev->mtu) {
+ spin_unlock_bh(&m->slaves_lock);
return -EINVAL;
+ }
} else {
if (!(dev->flags&IFF_POINTOPOINT))
m->dev->flags &= ~IFF_POINTOPOINT;
@@ -204,14 +227,17 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,
if (dev->mtu < m->dev->mtu)
m->dev->mtu = dev->mtu;
}
- q->next = NEXT_SLAVE(m->slaves);
- NEXT_SLAVE(m->slaves) = sch;
+ rcu_assign_pointer(q->next,
+ rcu_dereference_protected(NEXT_SLAVE(first),
+ lockdep_is_held(&m->slaves_lock)));
+ rcu_assign_pointer(NEXT_SLAVE(first), sch);
} else {
- q->next = sch;
- m->slaves = sch;
+ rcu_assign_pointer(q->next, sch);
+ rcu_assign_pointer(m->slaves, sch);
m->dev->mtu = dev->mtu;
m->dev->flags = (m->dev->flags&~FMASK)|(dev->flags&FMASK);
}
+ spin_unlock_bh(&m->slaves_lock);
return 0;
}
@@ -285,7 +311,9 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
int subq = skb_get_queue_mapping(skb);
struct sk_buff *skb_res = NULL;
- start = master->slaves;
+ rcu_read_lock_bh();
+
+ start = rcu_dereference_bh(master->slaves);
restart:
nores = 0;
@@ -317,10 +345,17 @@ restart:
netdev_start_xmit(skb, slave, slave_txq, false) ==
NETDEV_TX_OK) {
__netif_tx_unlock(slave_txq);
- master->slaves = NEXT_SLAVE(q);
+ spin_lock_bh(&master->slaves_lock);
+ if (rcu_dereference_protected(master->slaves,
+ lockdep_is_held(&master->slaves_lock)) == q)
+ rcu_assign_pointer(master->slaves,
+ rcu_dereference_protected(NEXT_SLAVE(q),
+ lockdep_is_held(&master->slaves_lock)));
+ spin_unlock_bh(&master->slaves_lock);
netif_wake_queue(dev);
master->tx_packets++;
master->tx_bytes += length;
+ rcu_read_unlock_bh();
return NETDEV_TX_OK;
}
__netif_tx_unlock(slave_txq);
@@ -329,14 +364,21 @@ restart:
busy = 1;
break;
case 1:
- master->slaves = NEXT_SLAVE(q);
+ spin_lock_bh(&master->slaves_lock);
+ if (rcu_dereference_protected(master->slaves,
+ lockdep_is_held(&master->slaves_lock)) == q)
+ rcu_assign_pointer(master->slaves,
+ rcu_dereference_protected(NEXT_SLAVE(q),
+ lockdep_is_held(&master->slaves_lock)));
+ spin_unlock_bh(&master->slaves_lock);
+ rcu_read_unlock_bh();
return NETDEV_TX_OK;
default:
nores = 1;
break;
}
__skb_pull(skb, skb_network_offset(skb));
- } while ((q = NEXT_SLAVE(q)) != start);
+ } while ((q = rcu_dereference_bh(NEXT_SLAVE(q))) != start);
if (nores && skb_res == NULL) {
skb_res = skb;
@@ -345,29 +387,32 @@ restart:
if (busy) {
netif_stop_queue(dev);
+ rcu_read_unlock_bh();
return NETDEV_TX_BUSY;
}
master->tx_errors++;
drop:
master->tx_dropped++;
+ rcu_read_unlock_bh();
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
static int teql_master_open(struct net_device *dev)
{
- struct Qdisc *q;
+ struct Qdisc *q, *first;
struct teql_master *m = netdev_priv(dev);
int mtu = 0xFFFE;
unsigned int flags = IFF_NOARP | IFF_MULTICAST;
- if (m->slaves == NULL)
+ first = rtnl_dereference(m->slaves);
+ if (!first)
return -EUNATCH;
flags = FMASK;
- q = m->slaves;
+ q = first;
do {
struct net_device *slave = qdisc_dev(q);
@@ -389,7 +434,7 @@ static int teql_master_open(struct net_device *dev)
flags &= ~IFF_BROADCAST;
if (!(slave->flags&IFF_MULTICAST))
flags &= ~IFF_MULTICAST;
- } while ((q = NEXT_SLAVE(q)) != m->slaves);
+ } while ((q = rtnl_dereference(NEXT_SLAVE(q))) != first);
m->dev->mtu = mtu;
m->dev->flags = (m->dev->flags&~FMASK) | flags;
@@ -417,14 +462,15 @@ static void teql_master_stats64(struct net_device *dev,
static int teql_master_mtu(struct net_device *dev, int new_mtu)
{
struct teql_master *m = netdev_priv(dev);
- struct Qdisc *q;
+ struct Qdisc *q, *first;
- q = m->slaves;
+ first = rtnl_dereference(m->slaves);
+ q = first;
if (q) {
do {
if (new_mtu > qdisc_dev(q)->mtu)
return -EINVAL;
- } while ((q = NEXT_SLAVE(q)) != m->slaves);
+ } while ((q = rtnl_dereference(NEXT_SLAVE(q))) != first);
}
WRITE_ONCE(dev->mtu, new_mtu);
@@ -444,6 +490,7 @@ static __init void teql_master_setup(struct net_device *dev)
struct teql_master *master = netdev_priv(dev);
struct Qdisc_ops *ops = &master->qops;
+ spin_lock_init(&master->slaves_lock);
master->dev = dev;
ops->priv_size = sizeof(struct teql_sched_data);
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 587b0017a67d..cf335494bffe 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -663,8 +663,9 @@ static void sctp_free_addr_wq(struct net *net)
struct sctp_sockaddr_entry *addrw;
struct sctp_sockaddr_entry *temp;
+ timer_shutdown_sync(&net->sctp.addr_wq_timer);
+
spin_lock_bh(&net->sctp.addr_wq_lock);
- timer_delete(&net->sctp.addr_wq_timer);
list_for_each_entry_safe(addrw, temp, &net->sctp.addr_waitq, list) {
list_del(&addrw->list);
kfree(addrw);
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 41958b8e59fd..8adac9e0cd66 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1761,6 +1761,8 @@ struct sctp_association *sctp_unpack_cookie(
bear_cookie = &cookie->c;
ch = (struct sctp_chunkhdr *)(bear_cookie + 1);
+ if (ch->type != SCTP_CID_INIT)
+ goto malformed;
chlen = ntohs(ch->length);
if (chlen < sizeof(struct sctp_init_chunk))
goto malformed;
@@ -2298,7 +2300,8 @@ int sctp_verify_init(struct net *net, const struct sctp_endpoint *ep,
* VIOLATION error. We build the ERROR chunk here and let the normal
* error handling code build and send the packet.
*/
- if (param.v != (void *)chunk->chunk_end)
+ if (param.v != (void *)peer_init +
+ SCTP_PAD4(ntohs(peer_init->chunk_hdr.length)))
return sctp_process_inv_paramlength(asoc, param.p, chunk, errp);
/* The only missing mandatory param possible today is
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 8e920cef0858..d23d935e128e 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -707,11 +707,12 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net,
struct sctp_cmd_seq *commands)
{
struct sctp_ulpevent *ev, *ai_ev = NULL, *auth_ev = NULL;
+ struct sctp_chunk *err_chk_p = NULL;
struct sctp_association *new_asoc;
struct sctp_init_chunk *peer_init;
struct sctp_chunk *chunk = arg;
- struct sctp_chunk *err_chk_p;
struct sctp_chunk *repl;
+ enum sctp_cid cid;
struct sock *sk;
int error = 0;
@@ -785,6 +786,19 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net,
}
}
+ peer_init = (struct sctp_init_chunk *)(chunk->subh.cookie_hdr + 1);
+ cid = peer_init->chunk_hdr.type;
+ if (!sctp_sk(sk)->cookie_auth_enable &&
+ !sctp_verify_init(net, ep, asoc, cid, peer_init, chunk,
+ &err_chk_p)) {
+ sctp_association_free(new_asoc);
+ if (err_chk_p)
+ sctp_chunk_free(err_chk_p);
+ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+ }
+ if (err_chk_p)
+ sctp_chunk_free(err_chk_p);
+
if (security_sctp_assoc_request(new_asoc, chunk->head_skb ?: chunk->skb)) {
sctp_association_free(new_asoc);
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
@@ -798,7 +812,6 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net,
/* This is a brand-new association, so these are not yet side
* effects--it is safe to run them here.
*/
- peer_init = (struct sctp_init_chunk *)(chunk->subh.cookie_hdr + 1);
if (!sctp_process_init(new_asoc, chunk,
&chunk->subh.cookie_hdr->c.peer_addr,
peer_init, GFP_ATOMIC))
@@ -2215,10 +2228,12 @@ enum sctp_disposition sctp_sf_do_5_2_4_dupcook(
void *arg,
struct sctp_cmd_seq *commands)
{
+ struct sctp_chunk *err_chk_p = NULL;
struct sctp_association *new_asoc;
+ struct sctp_init_chunk *peer_init;
struct sctp_chunk *chunk = arg;
enum sctp_disposition retval;
- struct sctp_chunk *err_chk_p;
+ enum sctp_cid cid;
int error = 0;
char action;
@@ -2287,6 +2302,21 @@ enum sctp_disposition sctp_sf_do_5_2_4_dupcook(
switch (action) {
case 'A': /* Association restart. */
case 'B': /* Collision case B. */
+ peer_init = (struct sctp_init_chunk *)
+ (chunk->subh.cookie_hdr + 1);
+ cid = peer_init->chunk_hdr.type;
+ if (!sctp_sk(ep->base.sk)->cookie_auth_enable &&
+ !sctp_verify_init(net, ep, asoc, cid, peer_init, chunk,
+ &err_chk_p)) {
+ sctp_association_free(new_asoc);
+ if (err_chk_p)
+ sctp_chunk_free(err_chk_p);
+ return sctp_sf_pdiscard(net, ep, asoc, type, arg,
+ commands);
+ }
+ if (err_chk_p)
+ sctp_chunk_free(err_chk_p);
+ fallthrough;
case 'D': /* Collision case D. */
/* Update socket peer label if first association. */
if (security_sctp_assoc_request((struct sctp_association *)asoc,
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index c8481461f7d8..c7b9e325ec1c 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -4111,8 +4111,9 @@ static int sctp_setsockopt_reset_streams(struct sock *sk,
if (optlen < sizeof(*params))
return -EINVAL;
/* srs_number_streams is u16, so optlen can't be bigger than this. */
- optlen = min_t(unsigned int, optlen, USHRT_MAX +
- sizeof(__u16) * sizeof(*params));
+ optlen = min_t(unsigned int, optlen,
+ struct_size_t(struct sctp_reset_streams, srs_stream_list,
+ USHRT_MAX));
if (params->srs_number_streams * sizeof(__u16) >
optlen - sizeof(*params))
@@ -4598,8 +4599,8 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
if (optlen > 0) {
/* Trim it to the biggest size sctp sockopt may need if necessary */
optlen = min_t(unsigned int, optlen,
- PAGE_ALIGN(USHRT_MAX +
- sizeof(__u16) * sizeof(struct sctp_reset_streams)));
+ PAGE_ALIGN(struct_size_t(struct sctp_reset_streams,
+ srs_stream_list, USHRT_MAX)));
kopt = memdup_sockptr(optval, optlen);
if (IS_ERR(kopt))
return PTR_ERR(kopt);
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index 76a1585d3f6b..10d1ec593084 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -497,12 +497,13 @@ void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l,
*/
int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l,
struct tipc_msg *hdr,
- struct sk_buff_head *retrq)
+ struct sk_buff_head *retrq, bool *valid)
{
struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq;
struct tipc_gap_ack_blks *ga;
struct sk_buff_head xmitq;
int rc = 0;
+ u16 glen;
__skb_queue_head_init(&xmitq);
@@ -510,13 +511,18 @@ int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l,
if (msg_type(hdr) != STATE_MSG) {
tipc_link_bc_init_rcv(l, hdr);
} else if (!msg_bc_ack_invalid(hdr)) {
- tipc_get_gap_ack_blks(&ga, l, hdr, false);
- if (!sysctl_tipc_bc_retruni)
- retrq = &xmitq;
- rc = tipc_link_bc_ack_rcv(l, msg_bcast_ack(hdr),
- msg_bc_gap(hdr), ga, &xmitq,
- retrq);
- rc |= tipc_link_bc_sync_rcv(l, hdr, &xmitq);
+ glen = tipc_get_gap_ack_blks(&ga, l, hdr, false);
+ if (glen > msg_data_sz(hdr)) {
+ /* Malformed Gap ACK blocks; caller drops the msg */
+ *valid = false;
+ } else {
+ if (!sysctl_tipc_bc_retruni)
+ retrq = &xmitq;
+ rc = tipc_link_bc_ack_rcv(l, msg_bcast_ack(hdr),
+ msg_bc_gap(hdr), ga, &xmitq,
+ retrq);
+ rc |= tipc_link_bc_sync_rcv(l, hdr, &xmitq);
+ }
}
tipc_bcast_unlock(net);
diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h
index 2d9352dc7b0e..55d17b5413e1 100644
--- a/net/tipc/bcast.h
+++ b/net/tipc/bcast.h
@@ -97,7 +97,7 @@ void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l,
struct tipc_msg *hdr);
int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l,
struct tipc_msg *hdr,
- struct sk_buff_head *retrq);
+ struct sk_buff_head *retrq, bool *valid);
int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg,
struct tipc_link *bcl);
int tipc_nl_bc_link_set(struct net *net, struct nlattr *attrs[]);
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 97aa970a0d83..8e4ef2630ae4 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -1831,12 +1831,15 @@ static void tipc_node_mcast_rcv(struct tipc_node *n)
}
static void tipc_node_bc_sync_rcv(struct tipc_node *n, struct tipc_msg *hdr,
- int bearer_id, struct sk_buff_head *xmitq)
+ int bearer_id, struct sk_buff_head *xmitq,
+ bool *valid)
{
struct tipc_link *ucl;
int rc;
- rc = tipc_bcast_sync_rcv(n->net, n->bc_entry.link, hdr, xmitq);
+ rc = tipc_bcast_sync_rcv(n->net, n->bc_entry.link, hdr, xmitq, valid);
+ if (!*valid)
+ return;
if (rc & TIPC_LINK_DOWN_EVT) {
tipc_node_reset_links(n);
@@ -2140,12 +2143,18 @@ rcv:
/* Ensure broadcast reception is in synch with peer's send state */
if (unlikely(usr == LINK_PROTOCOL)) {
+ bool valid = true;
+
if (unlikely(skb_linearize(skb))) {
tipc_node_put(n);
goto discard;
}
hdr = buf_msg(skb);
- tipc_node_bc_sync_rcv(n, hdr, bearer_id, &xmitq);
+ tipc_node_bc_sync_rcv(n, hdr, bearer_id, &xmitq, &valid);
+ if (!valid) {
+ tipc_node_put(n);
+ goto discard;
+ }
} else if (unlikely(tipc_link_acked(n->bc_entry.link) != bc_ack)) {
tipc_bcast_ack_rcv(net, n->bc_entry.link, hdr);
}
diff --git a/samples/trace_events/trace-events-sample.c b/samples/trace_events/trace-events-sample.c
index ecc7db237f2e..0b7a6efdb247 100644
--- a/samples/trace_events/trace-events-sample.c
+++ b/samples/trace_events/trace-events-sample.c
@@ -107,6 +107,10 @@ int foo_bar_reg(void)
* for consistency sake, we still take the thread_mutex.
*/
simple_tsk_fn = kthread_run(simple_thread_fn, NULL, "event-sample-fn");
+ if (IS_ERR_OR_NULL(simple_tsk_fn)) {
+ pr_err("Failed to create simple_thread_fn\n");
+ simple_tsk_fn = NULL;
+ }
out:
mutex_unlock(&thread_mutex);
return 0;
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index fd63d219bf86..ea699491f0c3 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -1083,15 +1083,18 @@ static int snd_compr_task_new(struct snd_compr_stream *stream, struct snd_compr_
file descriptors are allocated before fd_install() */
if (!task->input || !task->input->file || !task->output || !task->output->file) {
retval = -EINVAL;
- goto cleanup;
+ goto free_driver_task;
}
fd_i = get_unused_fd_flags(O_WRONLY|O_CLOEXEC);
- if (fd_i < 0)
- goto cleanup;
+ if (fd_i < 0) {
+ retval = fd_i;
+ goto free_driver_task;
+ }
fd_o = get_unused_fd_flags(O_RDONLY|O_CLOEXEC);
if (fd_o < 0) {
+ retval = fd_o;
put_unused_fd(fd_i);
- goto cleanup;
+ goto free_driver_task;
}
/* keep dmabuf reference until freed with task free ioctl */
get_dma_buf(task->input);
@@ -1103,6 +1106,8 @@ static int snd_compr_task_new(struct snd_compr_stream *stream, struct snd_compr_
list_add_tail(&task->list, &stream->runtime->tasks);
stream->runtime->total_tasks++;
return 0;
+free_driver_task:
+ stream->ops->task_free(stream, task);
cleanup:
snd_compr_task_free(task);
return retval;
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index fe597f7d522d..4d665b4148d7 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -545,7 +545,7 @@ void snd_pcm_set_sync_per_card(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
const unsigned char *id, unsigned int len)
{
- *(__u32 *)params->sync = cpu_to_le32(substream->pcm->card->number);
+ *(__le32 *)params->sync = cpu_to_le32(substream->pcm->card->number);
len = min(12, len);
memcpy(params->sync + 4, id, len);
memset(params->sync + 4 + len, 0, 12 - len);
diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
index ca9f6db0022c..209b08c2a940 100644
--- a/sound/core/seq/seq_memory.c
+++ b/sound/core/seq/seq_memory.c
@@ -364,7 +364,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
size = snd_seq_event_packet_size(event);
memcpy(&cell->ump, event, size);
#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
- if (size < sizeof(cell->event))
+ if (size < sizeof(cell->ump))
cell->ump.raw.extra = 0;
#endif
diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c
index 2b7f071d593b..33c9dd48b3b0 100644
--- a/sound/firewire/isight.c
+++ b/sound/firewire/isight.c
@@ -179,7 +179,8 @@ static void isight_packet(struct fw_iso_context *context, u32 cycle,
if (likely(length >= 16 &&
payload->signature == cpu_to_be32(0x73676874/*"sght"*/))) {
count = be32_to_cpu(payload->sample_count);
- if (likely(count <= (length - 16) / 4)) {
+ if (likely(count <= (length - 16) / 4 &&
+ count <= MAX_FRAMES_PER_PACKET)) {
total = be32_to_cpu(payload->sample_total);
if (unlikely(total != isight->total_samples)) {
if (!isight->first_packet)
diff --git a/sound/hda/codecs/conexant.c b/sound/hda/codecs/conexant.c
index e3b6aaabe3a9..3d92262763f6 100644
--- a/sound/hda/codecs/conexant.c
+++ b/sound/hda/codecs/conexant.c
@@ -291,6 +291,7 @@ enum {
CXT_FIXUP_HEADSET_MIC,
CXT_FIXUP_HP_MIC_NO_PRESENCE,
CXT_PINCFG_SWS_JS201D,
+ CXT_PINCFG_LENOVO_IDEAPAD_SLIM5_16AKP10,
CXT_PINCFG_TOP_SPEAKER,
CXT_FIXUP_HP_A_U,
CXT_FIXUP_ACER_SWIFT_HP,
@@ -826,6 +827,12 @@ static const struct hda_pintbl cxt_pincfg_lemote[] = {
{}
};
+/* Lenovo IdeaPad Slim 5 16AKP10 with SN6140 */
+static const struct hda_pintbl cxt_pincfg_lenovo_ideapad_slim5_16akp10[] = {
+ { 0x1a, 0x95a60130 }, /* Internal mic, fixed/always-connected */
+ {}
+};
+
/* SuoWoSi/South-holding JS201D with sn6140 */
static const struct hda_pintbl cxt_pincfg_sws_js201d[] = {
{ 0x16, 0x03211040 }, /* hp out */
@@ -1006,6 +1013,10 @@ static const struct hda_fixup cxt_fixups[] = {
.type = HDA_FIXUP_PINS,
.v.pins = cxt_pincfg_sws_js201d,
},
+ [CXT_PINCFG_LENOVO_IDEAPAD_SLIM5_16AKP10] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = cxt_pincfg_lenovo_ideapad_slim5_16akp10,
+ },
[CXT_PINCFG_TOP_SPEAKER] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -1114,6 +1125,7 @@ static const struct hda_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410),
SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410),
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo IdeaPad Z560", CXT_FIXUP_MUTE_LED_EAPD),
+ SND_PCI_QUIRK(0x17aa, 0x38b6, "Lenovo IdeaPad Slim 5 16AKP10", CXT_PINCFG_LENOVO_IDEAPAD_SLIM5_16AKP10),
SND_PCI_QUIRK(0x17aa, 0x3905, "Lenovo G50-30", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c
index 5d09baa6d32e..d9e2384fc0ba 100644
--- a/sound/hda/codecs/realtek/alc269.c
+++ b/sound/hda/codecs/realtek/alc269.c
@@ -6807,11 +6807,13 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC287_FIXUP_ACER_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x1597, "Acer Nitro 5 AN517-55", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x160e, "Acer PT316-51S", ALC2XX_FIXUP_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1025, 0x161f, "Acer S40-54", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1025, 0x1640, "Acer Aspire A315-44P", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x1679, "Acer Nitro 16 AN16-41", ALC2XX_FIXUP_HEADSET_MIC),
SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x171e, "Acer Nitro ANV15-51", ALC245_FIXUP_ACER_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x173a, "Acer Swift SFG14-73", ALC245_FIXUP_ACER_MICMUTE_LED),
+ SND_PCI_QUIRK(0x1025, 0x1758, "Acer Nitro ANV15-41", ALC245_FIXUP_ACER_MICMUTE_LED),
SND_PCI_QUIRK(0x1025, 0x1826, "Acer Helios ZPC", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1025, 0x182c, "Acer Helios ZPD", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1025, 0x1844, "Acer Helios ZPS", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
@@ -6986,6 +6988,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8537, "HP ProBook 440 G6", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8548, "HP EliteBook x360 830 G6", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x854a, "HP EliteBook 830 G6", ALC285_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x854d, "HP EliteBook 840 G6", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x856a, "HP Pavilion 15-cs1xxx", ALC295_FIXUP_HP_PAVILION_MUTE_LED_1B),
SND_PCI_QUIRK(0x103c, 0x85c6, "HP Pavilion x360 Convertible 14-dy1xxx", ALC295_FIXUP_HP_MUTE_LED_COEFBIT11),
SND_PCI_QUIRK(0x103c, 0x85de, "HP Envy x360 13-ar0xxx", ALC285_FIXUP_HP_ENVY_X360),
@@ -7326,6 +7329,10 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8f0e, "HP ZBook X G2i 16W", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8f2d, "HP Auster 14", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8f2e, "HP Auster 14", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8f37, "HP EliteBook 6 G2i", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8f38, "HP EliteBook 6 G2i", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8f39, "HP EliteBook 6 G2i", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8f3a, "HP EliteBook 6 G2i", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8f3c, "HP EliteBook 6 G2a", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8f3d, "HP EliteBook 6 G2a", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8f40, "HP ZBook 8 G2a 14", ALC245_FIXUP_HP_TAS2781_I2C_MUTE_LED),
@@ -7597,6 +7604,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1558, 0x51b3, "Clevo NS70AU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x5630, "Clevo NP50RNJS", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x5700, "Clevo X560WN[RST]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1558, 0x6480, "Clevo V6xxAW", ALC245_FIXUP_CLEVO_NOISY_MIC),
SND_PCI_QUIRK(0x1558, 0x70a1, "Clevo NB70T[HJK]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x70b3, "Clevo NK70SB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1558, 0x70f2, "Clevo NH79EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
@@ -7753,11 +7761,13 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x3865, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x3866, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
+ HDA_CODEC_QUIRK(0x17aa, 0x386a, "Lenovo Yoga 7 16IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
HDA_CODEC_QUIRK(0x17aa, 0x386e, "Legion Y9000X 2022 IAH7", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x386e, "Yoga Pro 7 14ARP8", ALC285_FIXUP_SPEAKER2_TO_DAC1),
HDA_CODEC_QUIRK(0x17aa, 0x38a8, "Legion Pro 7 16ARX8H", ALC287_FIXUP_TAS2781_I2C), /* this must match before PCI SSID 17aa:386f below */
SND_PCI_QUIRK(0x17aa, 0x386f, "Legion Pro 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x3870, "Lenovo Yoga 7 14ARB7", ALC287_FIXUP_YOGA7_14ARB7_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x3874, "Legion 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x3877, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x3878, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x387d, "Yoga S780-16 pro Quad AAC", ALC287_FIXUP_TAS2781_I2C),
diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda_property.c b/sound/hda/codecs/side-codecs/cs35l41_hda_property.c
index 732ae534db36..416d7bf3e289 100644
--- a/sound/hda/codecs/side-codecs/cs35l41_hda_property.c
+++ b/sound/hda/codecs/side-codecs/cs35l41_hda_property.c
@@ -128,6 +128,7 @@ static const struct cs35l41_config cs35l41_config_table[] = {
{ "17AA3866", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
{ "17AA386E", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
{ "17AA386F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+ { "17AA3874", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
{ "17AA3877", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
{ "17AA3878", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
{ "17AA38A9", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
@@ -554,6 +555,7 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
{ "CSC3551", "17AA3866", generic_dsd_config },
{ "CSC3551", "17AA386E", generic_dsd_config },
{ "CSC3551", "17AA386F", generic_dsd_config },
+ { "CSC3551", "17AA3874", generic_dsd_config },
{ "CSC3551", "17AA3877", generic_dsd_config },
{ "CSC3551", "17AA3878", generic_dsd_config },
{ "CSC3551", "17AA38A9", generic_dsd_config },
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index 9023f3444d20..b8749e0131ad 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -1181,19 +1181,17 @@ static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream)
runtime->private_free = snd_emu10k1_pcm_free_substream;
runtime->hw = snd_emu10k1_playback;
err = snd_emu10k1_playback_set_constraints(runtime);
- if (err < 0) {
- kfree(epcm);
- return err;
- }
+ if (err < 0)
+ goto free_epcm;
+
if (emu->card_capabilities->emu_model)
sample_rate = emu->emu1010.word_clock;
else
sample_rate = 48000;
err = snd_pcm_hw_rule_noresample(runtime, sample_rate);
- if (err < 0) {
- kfree(epcm);
- return err;
- }
+ if (err < 0)
+ goto free_epcm;
+
mix = &emu->pcm_mixer[substream->number];
for (i = 0; i < 8; i++)
mix->send_routing[0][i] = mix->send_routing[1][i] = mix->send_routing[2][i] = i;
@@ -1204,6 +1202,10 @@ static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream)
mix->epcm = epcm;
snd_emu10k1_pcm_mixer_notify(emu, substream->number, 1);
return 0;
+
+free_epcm:
+ kfree(epcm);
+ return err;
}
static int snd_emu10k1_playback_close(struct snd_pcm_substream *substream)
diff --git a/sound/sh/aica.c b/sound/sh/aica.c
index 9438c3a68ee9..8196e1bf0416 100644
--- a/sound/sh/aica.c
+++ b/sound/sh/aica.c
@@ -564,10 +564,9 @@ static int snd_aica_probe(struct platform_device *devptr)
return -ENOMEM;
err = snd_card_new(&devptr->dev, index, SND_AICA_DRIVER,
THIS_MODULE, 0, &dreamcastcard->card);
- if (unlikely(err < 0)) {
- kfree(dreamcastcard);
- return err;
- }
+ if (unlikely(err < 0))
+ goto free_card;
+
strscpy(dreamcastcard->card->driver, "snd_aica");
strscpy(dreamcastcard->card->shortname, SND_AICA_DRIVER);
strscpy(dreamcastcard->card->longname,
@@ -593,6 +592,7 @@ static int snd_aica_probe(struct platform_device *devptr)
return 0;
freedreamcast:
snd_card_free(dreamcastcard->card);
+free_card:
kfree(dreamcastcard);
return err;
}
diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c
index 18b5ff75feec..2c7e33135911 100644
--- a/sound/soc/codecs/cs530x.c
+++ b/sound/soc/codecs/cs530x.c
@@ -1093,6 +1093,29 @@ static int cs530x_component_probe(struct snd_soc_component *component)
return 0;
}
+static bool cs530x_mclk_freq_is_valid(struct cs530x_priv *cs530x,
+ unsigned int freq)
+{
+ /*
+ * All these chips support 48 kHz- and 44.1 kHz-related sample rates,
+ * but they differ in what MCLK frequency is required for achieving
+ * the sample rate.
+ */
+ switch (cs530x->devtype) {
+ case CS4282:
+ case CS4302:
+ case CS4304:
+ case CS4308:
+ return freq == 49152000 || freq == 45158400;
+ case CS5302:
+ case CS5304:
+ case CS5308:
+ return freq == 24576000 || freq == 22579200;
+ }
+
+ return false;
+}
+
static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id,
int source, unsigned int freq, int dir)
{
@@ -1101,11 +1124,7 @@ static int cs530x_set_sysclk(struct snd_soc_component *component, int clk_id,
switch (source) {
case CS530X_SYSCLK_SRC_MCLK:
- switch (freq) {
- case CS530X_SYSCLK_REF_45_1MHZ:
- case CS530X_SYSCLK_REF_49_1MHZ:
- break;
- default:
+ if (!cs530x_mclk_freq_is_valid(cs530x, freq)) {
dev_err(component->dev, "Invalid MCLK source rate %d\n", freq);
return -EINVAL;
}
diff --git a/sound/soc/codecs/cs530x.h b/sound/soc/codecs/cs530x.h
index 1e2f6a7a589c..18aa4dfd0c86 100644
--- a/sound/soc/codecs/cs530x.h
+++ b/sound/soc/codecs/cs530x.h
@@ -200,12 +200,6 @@
/* IN_VOL_CTL5 and OUT_VOL_CTL5 */
#define CS530X_INOUT_VU BIT(0)
-/* MCLK Reference Source Frequency */
-/* 41KHz related */
-#define CS530X_SYSCLK_REF_45_1MHZ 45158400
-/* 48KHz related */
-#define CS530X_SYSCLK_REF_49_1MHZ 49152000
-
/* System Clock Source */
#define CS530X_SYSCLK_SRC_MCLK 0
#define CS530X_SYSCLK_SRC_PLL 1
diff --git a/sound/soc/codecs/es9356.c b/sound/soc/codecs/es9356.c
index 670e918b56a4..8db81d574624 100644
--- a/sound/soc/codecs/es9356.c
+++ b/sound/soc/codecs/es9356.c
@@ -1111,8 +1111,10 @@ static int es9356_sdca_dev_resume(struct device *dev)
es9356->disable_irq = false;
ret = sdw_slave_wait_for_init(slave, es9356_PROBE_TIMEOUT);
- if (ret)
+ if (ret) {
+ sdw_show_ping_status(slave->bus, true);
return ret;
+ }
regcache_cache_only(es9356->regmap, false);
regcache_sync(es9356->regmap);
diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c
index 6829fa07c9ec..7a42052dc051 100644
--- a/sound/soc/codecs/max98373-sdw.c
+++ b/sound/soc/codecs/max98373-sdw.c
@@ -272,8 +272,10 @@ static int max98373_resume(struct device *dev)
return 0;
ret = sdw_slave_wait_for_init(slave, MAX98373_PROBE_TIMEOUT);
- if (ret)
+ if (ret) {
+ sdw_show_ping_status(slave->bus, true);
return ret;
+ }
regcache_cache_only(max98373->regmap, false);
regcache_sync(max98373->regmap);
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index fdef98ce52f1..fe3b5011fa16 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -633,7 +633,7 @@ static int pcm512x_dai_startup_slave(struct snd_pcm_substream *substream,
struct regmap *regmap = pcm512x->regmap;
if (IS_ERR(pcm512x->sclk)) {
- dev_info(dev, "No SCLK, using BCLK: %ld\n",
+ dev_info_once(dev, "No SCLK, using BCLK: %ld\n",
PTR_ERR(pcm512x->sclk));
/* Disable reporting of missing SCLK as an error */
diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c
index d62e8a253676..91d3d43cd998 100644
--- a/sound/soc/codecs/rt1017-sdca-sdw.c
+++ b/sound/soc/codecs/rt1017-sdca-sdw.c
@@ -779,8 +779,10 @@ static int rt1017_sdca_dev_resume(struct device *dev)
return 0;
ret = sdw_slave_wait_for_init(slave, RT1017_PROBE_TIMEOUT);
- if (ret)
+ if (ret) {
+ sdw_show_ping_status(slave->bus, true);
return ret;
+ }
regcache_cache_only(rt1017->regmap, false);
regcache_sync(rt1017->regmap);
diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c
index 39e06a3a7560..60e5040b6dd9 100644
--- a/sound/soc/codecs/rt1308-sdw.c
+++ b/sound/soc/codecs/rt1308-sdw.c
@@ -774,8 +774,10 @@ static int rt1308_dev_resume(struct device *dev)
return 0;
ret = sdw_slave_wait_for_init(slave, RT1308_PROBE_TIMEOUT);
- if (ret)
+ if (ret) {
+ sdw_show_ping_status(slave->bus, true);
return ret;
+ }
regcache_cache_only(rt1308->regmap, false);
regcache_sync_region(rt1308->regmap, 0xc000, 0xcfff);
diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c
index 1828fd9d5af6..5e8eda6a5f7f 100644
--- a/sound/soc/codecs/rt1316-sdw.c
+++ b/sound/soc/codecs/rt1316-sdw.c
@@ -751,8 +751,10 @@ static int rt1316_dev_resume(struct device *dev)
return 0;
ret = sdw_slave_wait_for_init(slave, RT1316_PROBE_TIMEOUT);
- if (ret)
+ if (ret) {
+ sdw_show_ping_status(slave->bus, true);
return ret;
+ }
regcache_cache_only(rt1316->regmap, false);
regcache_sync(rt1316->regmap);
diff --git a/sound/soc/codecs/rt5575-spi.c b/sound/soc/codecs/rt5575-spi.c
index 9a349965435b..d5b3a57c8866 100644
--- a/sound/soc/codecs/rt5575-spi.c
+++ b/sound/soc/codecs/rt5575-spi.c
@@ -17,7 +17,7 @@
struct rt5575_spi_burst_write {
u8 cmd;
- u32 addr;
+ __le32 addr;
u8 data[RT5575_SPI_BUF_LEN];
u8 dummy;
} __packed;
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 8a9af260e5f7..e9819653b30d 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -83,6 +83,8 @@ static const struct reg_sequence rt5650_init_list[] = {
{RT5645_PWR_ANLG1, 0x02},
{RT5645_IL_CMD3, 0x6728},
{RT5645_PR_BASE + 0x3a, 0x0000},
+ {RT5645_CLSD_OUT_CTRL1, 0x4059},
+ {RT5645_GEN_CTRL3, 0x0200},
};
static const struct reg_default rt5645_reg[] = {
@@ -1855,13 +1857,9 @@ static int rt5645_spk_event(struct snd_soc_dapm_widget *w,
RT5645_PWR_CLS_D_L,
RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
RT5645_PWR_CLS_D_L);
- snd_soc_component_update_bits(component, RT5645_GEN_CTRL3,
- RT5645_DET_CLK_MASK, RT5645_DET_CLK_MODE1);
break;
case SND_SOC_DAPM_PRE_PMD:
- snd_soc_component_update_bits(component, RT5645_GEN_CTRL3,
- RT5645_DET_CLK_MASK, RT5645_DET_CLK_DIS);
snd_soc_component_write(component, RT5645_EQ_CTRL2, 0);
snd_soc_component_update_bits(component, RT5645_PWR_DIG1,
RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h
index bef74b29fd54..a5bfe9861b8b 100644
--- a/sound/soc/codecs/rt5645.h
+++ b/sound/soc/codecs/rt5645.h
@@ -118,6 +118,7 @@
#define RT5645_A_JD_CTRL1 0x94
#define RT5645_VAD_CTRL4 0x9d
#define RT5645_CLSD_OUT_CTRL 0xa0
+#define RT5645_CLSD_OUT_CTRL1 0xa1
/* Function - Digital */
#define RT5645_ADC_EQ_CTRL1 0xae
#define RT5645_ADC_EQ_CTRL2 0xaf
diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c
index ec2a35a0cacd..dec8c2147d68 100644
--- a/sound/soc/codecs/rt5682-sdw.c
+++ b/sound/soc/codecs/rt5682-sdw.c
@@ -769,8 +769,10 @@ static int rt5682_dev_resume(struct device *dev)
}
ret = sdw_slave_wait_for_init(slave, RT5682_PROBE_TIMEOUT);
- if (ret)
+ if (ret) {
+ sdw_show_ping_status(slave->bus, true);
return ret;
+ }
regcache_cache_only(rt5682->sdw_regmap, false);
regcache_cache_only(rt5682->regmap, false);
diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c
index 30fcca210f05..6bc636c86f42 100644
--- a/sound/soc/codecs/rt700-sdw.c
+++ b/sound/soc/codecs/rt700-sdw.c
@@ -528,8 +528,10 @@ static int rt700_dev_resume(struct device *dev)
return 0;
ret = sdw_slave_wait_for_init(slave, RT700_PROBE_TIMEOUT);
- if (ret)
+ if (ret) {
+ sdw_show_ping_status(slave->bus, true);
return ret;
+ }
regcache_cache_only(rt700->regmap, false);
regcache_sync_region(rt700->regmap, 0x3000, 0x8fff);
diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c
index a8164fc3979a..461315844ba9 100644
--- a/sound/soc/codecs/rt711-sdca-sdw.c
+++ b/sound/soc/codecs/rt711-sdca-sdw.c
@@ -454,8 +454,10 @@ static int rt711_sdca_dev_resume(struct device *dev)
}
ret = sdw_slave_wait_for_init(slave, RT711_PROBE_TIMEOUT);
- if (ret)
+ if (ret) {
+ sdw_show_ping_status(slave->bus, true);
return ret;
+ }
regcache_cache_only(rt711->regmap, false);
regcache_sync(rt711->regmap);
diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c
index 4c5c2f5ba5ed..8b7d50a80ff9 100644
--- a/sound/soc/codecs/rt712-sdca-dmic.c
+++ b/sound/soc/codecs/rt712-sdca-dmic.c
@@ -911,8 +911,10 @@ static int rt712_sdca_dmic_dev_resume(struct device *dev)
return 0;
ret = sdw_slave_wait_for_init(slave, RT712_PROBE_TIMEOUT);
- if (ret)
+ if (ret) {
+ sdw_show_ping_status(slave->bus, true);
return ret;
+ }
regcache_cache_only(rt712->regmap, false);
regcache_sync(rt712->regmap);
diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c
index 581732180473..2787524c796e 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.c
+++ b/sound/soc/codecs/rt712-sdca-sdw.c
@@ -467,8 +467,10 @@ static int rt712_sdca_dev_resume(struct device *dev)
}
ret = sdw_slave_wait_for_init(slave, RT712_PROBE_TIMEOUT);
- if (ret)
+ if (ret) {
+ sdw_show_ping_status(slave->bus, true);
return ret;
+ }
regcache_cache_only(rt712->regmap, false);
regcache_sync(rt712->regmap);
diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c
index 4b9815b5628d..fabd21bbbe5b 100644
--- a/sound/soc/codecs/rt715-sdca-sdw.c
+++ b/sound/soc/codecs/rt715-sdca-sdw.c
@@ -230,8 +230,10 @@ static int rt715_dev_resume(struct device *dev)
return 0;
ret = sdw_slave_wait_for_init(slave, RT715_PROBE_TIMEOUT);
- if (ret)
+ if (ret) {
+ sdw_show_ping_status(slave->bus, true);
return ret;
+ }
regcache_cache_only(rt715->regmap, false);
regcache_sync_region(rt715->regmap,
diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c
index 7f83a8f1a06e..a4a3945522e8 100644
--- a/sound/soc/codecs/rt715-sdw.c
+++ b/sound/soc/codecs/rt715-sdw.c
@@ -507,8 +507,10 @@ static int rt715_dev_resume(struct device *dev)
return 0;
ret = sdw_slave_wait_for_init(slave, RT715_PROBE_TIMEOUT);
- if (ret)
+ if (ret) {
+ sdw_show_ping_status(slave->bus, true);
return ret;
+ }
regcache_cache_only(rt715->regmap, false);
regcache_sync_region(rt715->regmap, 0x3000, 0x8fff);
diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c
index 58606209316a..02df04a0ddad 100644
--- a/sound/soc/codecs/rt721-sdca-sdw.c
+++ b/sound/soc/codecs/rt721-sdca-sdw.c
@@ -505,8 +505,10 @@ static int rt721_sdca_dev_resume(struct device *dev)
}
ret = sdw_slave_wait_for_init(slave, RT721_PROBE_TIMEOUT);
- if (ret)
+ if (ret) {
+ sdw_show_ping_status(slave->bus, true);
return ret;
+ }
regcache_cache_only(rt721->regmap, false);
regcache_sync(rt721->regmap);
diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c
index 0f76492ff915..284900933ebf 100644
--- a/sound/soc/codecs/rt722-sdca-sdw.c
+++ b/sound/soc/codecs/rt722-sdca-sdw.c
@@ -552,8 +552,10 @@ static int rt722_sdca_dev_resume(struct device *dev)
}
ret = sdw_slave_wait_for_init(slave, RT722_PROBE_TIMEOUT);
- if (ret)
+ if (ret) {
+ sdw_show_ping_status(slave->bus, true);
return ret;
+ }
regcache_cache_only(rt722->regmap, false);
regcache_sync(rt722->regmap);
diff --git a/sound/soc/codecs/tac5xx2-sdw.c b/sound/soc/codecs/tac5xx2-sdw.c
index bb12cfb6da12..ace06f5ab58c 100644
--- a/sound/soc/codecs/tac5xx2-sdw.c
+++ b/sound/soc/codecs/tac5xx2-sdw.c
@@ -1445,8 +1445,10 @@ static s32 tac5xx2_sdca_dev_resume(struct device *dev)
}
ret = sdw_slave_wait_for_init(slave, TAC5XX2_PROBE_TIMEOUT_MS);
- if (ret)
+ if (ret) {
+ sdw_show_ping_status(slave->bus, true);
return ret;
+ }
regcache_cache_only(tac_dev->regmap, false);
regcache_mark_dirty(tac_dev->regmap);
diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c
index 7d70e7e3f24f..3d0b116544cc 100644
--- a/sound/soc/codecs/tas2783-sdw.c
+++ b/sound/soc/codecs/tas2783-sdw.c
@@ -100,6 +100,8 @@ struct tas2783_prv {
wait_queue_head_t fw_wait;
bool fw_dl_task_done;
bool fw_dl_success;
+ /* use fallback fw name */
+ bool fw_use_fallback;
};
static const struct reg_default tas2783_reg_default[] = {
@@ -740,11 +742,19 @@ static void tas2783_fw_ready(const struct firmware *fmw, void *context)
goto out;
}
+ /* firmware binary not found*/
if (!fmw || !fmw->data) {
- /* firmware binary not found*/
- dev_err(tas_dev->dev,
- "Failed to read fw binary %s\n",
- tas_dev->rca_binaryname);
+ if (!tas_dev->fw_use_fallback) {
+ tas_dev->fw_use_fallback = true;
+ dev_info(tas_dev->dev,
+ "Failed to read preferred fw binary: %s, attempting fallback binary load\n",
+ tas_dev->rca_binaryname);
+ } else {
+ dev_err(tas_dev->dev,
+ "Failed to read fallback fw binary %s\n",
+ tas_dev->rca_binaryname);
+ }
+
ret = -EINVAL;
goto out;
}
@@ -1083,8 +1093,10 @@ static s32 tas2783_sdca_dev_resume(struct device *dev)
int ret;
ret = sdw_slave_wait_for_init(slave, TAS2783_PROBE_TIMEOUT);
- if (ret)
+ if (ret) {
+ sdw_show_ping_status(slave->bus, true);
return ret;
+ }
regcache_cache_only(tas_dev->regmap, false);
regcache_sync(tas_dev->regmap);
@@ -1103,13 +1115,16 @@ static void tas_generate_fw_name(struct sdw_slave *slave, char *name, size_t siz
bool pci_found = false;
#if IS_ENABLED(CONFIG_PCI)
struct device *dev = &slave->dev;
+ struct tas2783_prv *tas_dev = dev_get_drvdata(&slave->dev);
struct pci_dev *pci = NULL;
+ const char *fw_uid_prefix = tas_dev->fw_use_fallback ? "" : "0x";
for (; dev; dev = dev->parent) {
if (dev->bus == &pci_bus_type) {
pci = to_pci_dev(dev);
- scnprintf(name, size, "%04X-%1X-%1X.bin",
- pci->subsystem_device, bus->link_id, unique_id);
+ scnprintf(name, size, "%04X-%1X-%s%1X.bin",
+ pci->subsystem_device, bus->link_id,
+ fw_uid_prefix, unique_id);
pci_found = true;
break;
}
@@ -1121,28 +1136,15 @@ static void tas_generate_fw_name(struct sdw_slave *slave, char *name, size_t siz
bus->link_id, unique_id);
}
-static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
+static s32 tas_fw_load(struct tas2783_prv *tas_dev, struct sdw_slave *slave)
{
- struct tas2783_prv *tas_dev = dev_get_drvdata(dev);
s32 ret;
u8 unique_id = tas_dev->sdw_peripheral->id.unique_id;
- if (tas_dev->hw_init)
- return 0;
-
- tas_dev->fw_dl_task_done = false;
- tas_dev->fw_dl_success = false;
-
- ret = regmap_write(tas_dev->regmap, TAS2783_SW_RESET, 0x1);
- if (ret) {
- dev_err(dev, "sw reset failed, err=%d", ret);
- return ret;
- }
- usleep_range(2000, 2200);
-
tas_generate_fw_name(slave, tas_dev->rca_binaryname,
sizeof(tas_dev->rca_binaryname));
+ tas_dev->fw_dl_task_done = false;
ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
tas_dev->rca_binaryname, tas_dev->dev,
GFP_KERNEL, tas_dev, tas2783_fw_ready);
@@ -1157,8 +1159,35 @@ static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
msecs_to_jiffies(TIMEOUT_FW_DL_MS));
if (!ret) {
dev_err(tas_dev->dev, "fw request, wait_event timeout\n");
- ret = -EAGAIN;
- } else {
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
+{
+ struct tas2783_prv *tas_dev = dev_get_drvdata(dev);
+ s32 ret;
+
+ if (tas_dev->hw_init)
+ return 0;
+
+ tas_dev->fw_dl_success = false;
+
+ ret = regmap_write(tas_dev->regmap, TAS2783_SW_RESET, 0x1);
+ if (ret) {
+ dev_err(dev, "sw reset failed, err=%d", ret);
+ return ret;
+ }
+ usleep_range(2000, 2200);
+
+ tas_dev->fw_use_fallback = false;
+ ret = tas_fw_load(tas_dev, slave);
+ if (!ret && tas_dev->fw_use_fallback)
+ ret = tas_fw_load(tas_dev, slave);
+
+ if (!ret) {
if (tas_dev->sa_func_data)
ret = sdca_regmap_write_init(dev, tas_dev->regmap,
tas_dev->sa_func_data);
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index b12c1952823b..b38393a8130f 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -1049,11 +1049,13 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
+ static const u8 dual_rate_q[] = {4, 8, 9, 12, 16};
struct snd_soc_component *component = dai->component;
struct aic3x_priv *aic3x = snd_soc_component_get_drvdata(component);
int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
u16 d, pll_d = 1;
+ bool dual_rate;
int clk;
int width = aic3x->slot_width;
@@ -1079,14 +1081,25 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
/* Fsref can be 44100 or 48000 */
fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000;
+ dual_rate = params_rate(params) >= 64000;
/* Try to find a value for Q which allows us to bypass the PLL and
* generate CODEC_CLK directly. */
- for (pll_q = 2; pll_q < 18; pll_q++)
- if (aic3x->sysclk / (128 * pll_q) == fsref) {
- bypass_pll = 1;
- break;
+ if (dual_rate) {
+ for (int i = 0; i < ARRAY_SIZE(dual_rate_q); i++) {
+ pll_q = dual_rate_q[i];
+ if (aic3x->sysclk / (128 * pll_q) == fsref) {
+ bypass_pll = 1;
+ break;
+ }
}
+ } else {
+ for (pll_q = 2; pll_q < 18; pll_q++)
+ if (aic3x->sysclk / (128 * pll_q) == fsref) {
+ bypass_pll = 1;
+ break;
+ }
+ }
if (bypass_pll) {
pll_q &= 0xf;
@@ -1106,13 +1119,13 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
* right DAC to right channel input */
data = (LDAC2LCH | RDAC2RCH);
data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000;
- if (params_rate(params) >= 64000)
+ if (dual_rate)
data |= DUAL_RATE_MODE;
snd_soc_component_write(component, AIC3X_CODEC_DATAPATH_REG, data);
/* codec sample rate select */
data = (fsref * 20) / params_rate(params);
- if (params_rate(params) < 64000)
+ if (!dual_rate)
data /= 2;
data /= 5;
data -= 2;
diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c
index 5aa96af994c4..38f2b7c63133 100644
--- a/sound/soc/fsl/fsl_asrc_dma.c
+++ b/sound/soc/fsl/fsl_asrc_dma.c
@@ -288,6 +288,26 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component,
config_be.dst_addr_width = buswidth;
config_be.dst_maxburst = dma_params_be->maxburst;
+ /*
+ * For eDMA, the back-end may report a maxburst size that is not evenly
+ * divisible by the channel count. This causes the DMA transfer length
+ * to misalign with the FIFO boundary, resulting in wrong data and
+ * audible noise. Align maxburst to the nearest valid boundary:
+ * - If maxburst >= channel count, override to the channel count so
+ * each transfer equals exactly one audio frame.
+ * - If maxburst < channel count, override to 1 to avoid partial-frame
+ * transfers.
+ */
+ if (asrc->use_edma && (dma_params_be->maxburst % params_channels(params))) {
+ if (dma_params_be->maxburst >= params_channels(params)) {
+ config_be.src_maxburst = params_channels(params);
+ config_be.dst_maxburst = params_channels(params);
+ } else {
+ config_be.src_maxburst = 1;
+ config_be.dst_maxburst = 1;
+ }
+ }
+
memset(&audio_config, 0, sizeof(audio_config));
config_be.peripheral_config = &audio_config;
config_be.peripheral_size = sizeof(audio_config);
diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c
index 6894bb936cfd..0202ed0ee78e 100644
--- a/sound/soc/generic/audio-graph-card2.c
+++ b/sound/soc/generic/audio-graph-card2.c
@@ -778,18 +778,6 @@ static void graph_link_init(struct simple_util_priv *priv,
graph_parse_daifmt(ports_cpu, &daifmt);
graph_parse_daifmt(ports_codec, &daifmt);
graph_parse_daifmt(lnk, &daifmt);
- if (daifmt) {
- struct device *dev = simple_priv_to_dev(priv);
-
- /*
- * Recommend to use Auto Select by using .auto_selectable_formats.
- * linux/sound/soc/renesas/rcar/core.c can be good sample for it.
- *
- * One note is that Audio Graph Card2 still keeps compatible to set
- * DAI format via DT.
- */
- dev_warn_once(dev, "use .auto_selectable_formats on each corresponding CPU/Codec driver");
- }
graph_util_parse_link_direction(lnk, &playback_only, &capture_only);
graph_util_parse_link_direction(ports_cpu, &playback_only, &capture_only);
diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c
index 2e5b25b8d00f..641d6d243229 100644
--- a/sound/soc/qcom/qdsp6/q6apm.c
+++ b/sound/soc/qcom/qdsp6/q6apm.c
@@ -587,6 +587,10 @@ static int graph_callback(const struct gpr_resp_pkt *data, void *priv, int op)
token = hdr->token & APM_WRITE_TOKEN_MASK;
done = data->payload;
+ if (!graph->rx_data.buf) {
+ mutex_unlock(&graph->lock);
+ break;
+ }
phys = graph->rx_data.buf[token].phys;
mutex_unlock(&graph->lock);
/* token numbering starts at 0 */
@@ -609,6 +613,10 @@ static int graph_callback(const struct gpr_resp_pkt *data, void *priv, int op)
client_event = APM_CLIENT_EVENT_DATA_READ_DONE;
mutex_lock(&graph->lock);
rd_done = data->payload;
+ if (!graph->tx_data.buf) {
+ mutex_unlock(&graph->lock);
+ break;
+ }
phys = graph->tx_data.buf[hdr->token].phys;
mutex_unlock(&graph->lock);
/* token numbering starts at 0 */
diff --git a/sound/soc/rockchip/rockchip_sai.c b/sound/soc/rockchip/rockchip_sai.c
index a195e96fed0a..585e89f61f0d 100644
--- a/sound/soc/rockchip/rockchip_sai.c
+++ b/sound/soc/rockchip/rockchip_sai.c
@@ -11,6 +11,7 @@
#include <linux/delay.h>
#include <linux/of_device.h>
#include <linux/clk.h>
+#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/reset.h>
@@ -18,6 +19,7 @@
#include <sound/pcm_params.h>
#include <sound/dmaengine_pcm.h>
#include <sound/tlv.h>
+
#include "rockchip_sai.h"
#define DRV_NAME "rockchip-sai"
@@ -215,12 +217,14 @@ wait_for_idle:
static int rockchip_sai_runtime_suspend(struct device *dev)
{
struct rk_sai_dev *sai = dev_get_drvdata(dev);
+ unsigned long flags;
rockchip_sai_fsync_lost_detect(sai, 0);
rockchip_sai_fsync_err_detect(sai, 0);
- scoped_guard(spinlock_irqsave, &sai->xfer_lock)
- rockchip_sai_xfer_clk_stop_and_wait(sai, NULL);
+ spin_lock_irqsave(&sai->xfer_lock, flags);
+ rockchip_sai_xfer_clk_stop_and_wait(sai, NULL);
+ spin_unlock_irqrestore(&sai->xfer_lock, flags);
regcache_cache_only(sai->regmap, true);
/*
@@ -480,6 +484,7 @@ static int rockchip_sai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
unsigned int mask = 0, val = 0;
unsigned int clk_gates;
+ unsigned long flags;
int ret = 0;
pm_runtime_get_sync(dai->dev);
@@ -495,56 +500,56 @@ static int rockchip_sai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
sai->is_master_mode = false;
break;
default:
- pm_runtime_put(dai->dev);
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_pm_put;
}
- scoped_guard(spinlock_irqsave, &sai->xfer_lock) {
- rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
- if (sai->initialized) {
- if (sai->has_capture && sai->has_playback)
- rockchip_sai_xfer_stop(sai, -1);
- else if (sai->has_capture)
- rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_CAPTURE);
- else
- rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_PLAYBACK);
- } else {
- rockchip_sai_clear(sai, 0);
- sai->initialized = true;
- }
+ spin_lock_irqsave(&sai->xfer_lock, flags);
+ rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
+ if (sai->initialized) {
+ if (sai->has_capture && sai->has_playback)
+ rockchip_sai_xfer_stop(sai, -1);
+ else if (sai->has_capture)
+ rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_CAPTURE);
+ else
+ rockchip_sai_xfer_stop(sai, SNDRV_PCM_STREAM_PLAYBACK);
+ } else {
+ rockchip_sai_clear(sai, 0);
+ sai->initialized = true;
+ }
- regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
-
- mask = SAI_CKR_CKP_MASK | SAI_CKR_FSP_MASK;
- switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
- case SND_SOC_DAIFMT_NB_NF:
- val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_NORMAL;
- break;
- case SND_SOC_DAIFMT_NB_IF:
- val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_INVERTED;
- break;
- case SND_SOC_DAIFMT_IB_NF:
- val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_NORMAL;
- break;
- case SND_SOC_DAIFMT_IB_IF:
- val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_INVERTED;
- break;
- default:
- ret = -EINVAL;
- break;
- }
+ regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
- if (ret == 0) {
- regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
- rockchip_sai_fmt_create(sai, fmt);
- }
-
- if (clk_gates)
- regmap_update_bits(sai->regmap, SAI_XFER,
- SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
- clk_gates);
+ mask = SAI_CKR_CKP_MASK | SAI_CKR_FSP_MASK;
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_NORMAL;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ val = SAI_CKR_CKP_NORMAL | SAI_CKR_FSP_INVERTED;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_NORMAL;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ val = SAI_CKR_CKP_INVERTED | SAI_CKR_FSP_INVERTED;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err_xfer_unlock;
}
+ regmap_update_bits(sai->regmap, SAI_CKR, mask, val);
+
+ rockchip_sai_fmt_create(sai, fmt);
+
+err_xfer_unlock:
+ if (clk_gates)
+ regmap_update_bits(sai->regmap, SAI_XFER,
+ SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
+ clk_gates);
+ spin_unlock_irqrestore(&sai->xfer_lock, flags);
+err_pm_put:
pm_runtime_put(dai->dev);
return ret;
@@ -560,6 +565,7 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
unsigned int ch_per_lane, slot_width;
unsigned int val, fscr, reg;
unsigned int lanes, req_lanes;
+ unsigned long flags;
int ret = 0;
if (!rockchip_sai_stream_valid(substream, dai))
@@ -586,8 +592,8 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
dev_err(sai->dev, "not enough lanes (%d) for requested number of %s channels (%d)\n",
lanes, reg == SAI_TXCR ? "playback" : "capture",
params_channels(params));
- pm_runtime_put(sai->dev);
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_pm_put;
} else {
lanes = req_lanes;
}
@@ -613,88 +619,84 @@ static int rockchip_sai_hw_params(struct snd_pcm_substream *substream,
val = SAI_XCR_VDW(32);
break;
default:
- pm_runtime_put(sai->dev);
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_pm_put;
}
val |= SAI_XCR_CSR(lanes);
- scoped_guard(spinlock_irqsave, &sai->xfer_lock) {
+ spin_lock_irqsave(&sai->xfer_lock, flags);
+
+ regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK | SAI_XCR_CSR_MASK, val);
- regmap_update_bits(sai->regmap, reg, SAI_XCR_VDW_MASK | SAI_XCR_CSR_MASK, val);
+ if (!sai->is_tdm)
+ regmap_update_bits(sai->regmap, reg, SAI_XCR_SBW_MASK,
+ SAI_XCR_SBW(params_physical_width(params)));
- if (!sai->is_tdm)
- regmap_update_bits(sai->regmap, reg, SAI_XCR_SBW_MASK,
- SAI_XCR_SBW(params_physical_width(params)));
+ regmap_read(sai->regmap, reg, &val);
- regmap_read(sai->regmap, reg, &val);
+ slot_width = SAI_XCR_SBW_V(val);
+ ch_per_lane = params_channels(params) / lanes;
- slot_width = SAI_XCR_SBW_V(val);
- ch_per_lane = params_channels(params) / lanes;
+ regmap_update_bits(sai->regmap, reg, SAI_XCR_SNB_MASK,
+ SAI_XCR_SNB(ch_per_lane));
- regmap_update_bits(sai->regmap, reg, SAI_XCR_SNB_MASK,
- SAI_XCR_SNB(ch_per_lane));
+ fscr = SAI_FSCR_FW(sai->fw_ratio * slot_width * ch_per_lane);
- fscr = SAI_FSCR_FW(sai->fw_ratio * slot_width * ch_per_lane);
+ switch (sai->fpw) {
+ case FPW_ONE_BCLK_WIDTH:
+ fscr |= SAI_FSCR_FPW(1);
+ break;
+ case FPW_ONE_SLOT_WIDTH:
+ fscr |= SAI_FSCR_FPW(slot_width);
+ break;
+ case FPW_HALF_FRAME_WIDTH:
+ fscr |= SAI_FSCR_FPW(sai->fw_ratio * slot_width * ch_per_lane / 2);
+ break;
+ default:
+ dev_err(sai->dev, "Invalid Frame Pulse Width %d\n", sai->fpw);
+ ret = -EINVAL;
+ goto err_xfer_unlock;
+ }
- switch (sai->fpw) {
- case FPW_ONE_BCLK_WIDTH:
- fscr |= SAI_FSCR_FPW(1);
- break;
- case FPW_ONE_SLOT_WIDTH:
- fscr |= SAI_FSCR_FPW(slot_width);
- break;
- case FPW_HALF_FRAME_WIDTH:
- fscr |= SAI_FSCR_FPW(sai->fw_ratio * slot_width * ch_per_lane / 2);
- break;
- default:
- dev_err(sai->dev, "Invalid Frame Pulse Width %d\n", sai->fpw);
+ regmap_update_bits(sai->regmap, SAI_FSCR,
+ SAI_FSCR_FW_MASK | SAI_FSCR_FPW_MASK, fscr);
+
+ if (sai->is_master_mode) {
+ bclk_rate = sai->fw_ratio * slot_width * ch_per_lane * params_rate(params);
+ ret = clk_set_rate(sai->mclk, sai->mclk_rate);
+ if (ret) {
+ dev_err(sai->dev, "Failed to set mclk to %u: %pe\n",
+ sai->mclk_rate, ERR_PTR(ret));
+ goto err_xfer_unlock;
+ }
+
+ mclk_rate = clk_get_rate(sai->mclk);
+ if (mclk_rate < bclk_rate) {
+ dev_err(sai->dev, "Mismatch mclk: %u, at least %u\n",
+ mclk_rate, bclk_rate);
ret = -EINVAL;
- break;
+ goto err_xfer_unlock;
}
- if (ret == 0) {
- regmap_update_bits(sai->regmap, SAI_FSCR,
- SAI_FSCR_FW_MASK | SAI_FSCR_FPW_MASK, fscr);
-
- if (sai->is_master_mode) {
- bclk_rate = sai->fw_ratio * slot_width *
- ch_per_lane * params_rate(params);
- ret = clk_set_rate(sai->mclk, sai->mclk_rate);
- if (ret)
- dev_err(sai->dev, "Failed to set mclk to %u: %pe\n",
- sai->mclk_rate, ERR_PTR(ret));
- else {
- mclk_rate = clk_get_rate(sai->mclk);
- if (mclk_rate < bclk_rate) {
- dev_err(sai->dev, "Mismatch mclk: %u, at least %u\n",
- mclk_rate, bclk_rate);
- ret = -EINVAL;
- } else {
-
- div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
- mclk_req_rate = bclk_rate * div_bclk;
-
- if (mclk_rate <
- mclk_req_rate - CLK_SHIFT_RATE_HZ_MAX ||
- mclk_rate >
- mclk_req_rate + CLK_SHIFT_RATE_HZ_MAX) {
- dev_err(sai->dev,
- "Mismatch mclk: %u, expected %u (+/- %dHz)\n",
- mclk_rate, mclk_req_rate,
- CLK_SHIFT_RATE_HZ_MAX);
- ret = -EINVAL;
- } else
- regmap_update_bits(sai->regmap,
- SAI_CKR,
- SAI_CKR_MDIV_MASK,
- SAI_CKR_MDIV(div_bclk));
- }
- }
- }
+ div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
+ mclk_req_rate = bclk_rate * div_bclk;
+
+ if (mclk_rate < mclk_req_rate - CLK_SHIFT_RATE_HZ_MAX ||
+ mclk_rate > mclk_req_rate + CLK_SHIFT_RATE_HZ_MAX) {
+ dev_err(sai->dev, "Mismatch mclk: %u, expected %u (+/- %dHz)\n",
+ mclk_rate, mclk_req_rate, CLK_SHIFT_RATE_HZ_MAX);
+ ret = -EINVAL;
+ goto err_xfer_unlock;
}
+
+ regmap_update_bits(sai->regmap, SAI_CKR, SAI_CKR_MDIV_MASK,
+ SAI_CKR_MDIV(div_bclk));
}
+err_xfer_unlock:
+ spin_unlock_irqrestore(&sai->xfer_lock, flags);
+err_pm_put:
pm_runtime_put(sai->dev);
return ret;
@@ -704,6 +706,7 @@ static int rockchip_sai_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
+ unsigned long flags;
if (!rockchip_sai_stream_valid(substream, dai))
return 0;
@@ -724,12 +727,13 @@ static int rockchip_sai_prepare(struct snd_pcm_substream *substream,
* udelay falls short.
*/
udelay(20);
- scoped_guard(spinlock_irqsave, &sai->xfer_lock)
- regmap_update_bits(sai->regmap, SAI_XFER,
- SAI_XFER_CLK_MASK |
- SAI_XFER_FSS_MASK,
- SAI_XFER_CLK_EN |
- SAI_XFER_FSS_EN);
+ spin_lock_irqsave(&sai->xfer_lock, flags);
+ regmap_update_bits(sai->regmap, SAI_XFER,
+ SAI_XFER_CLK_MASK |
+ SAI_XFER_FSS_MASK,
+ SAI_XFER_CLK_EN |
+ SAI_XFER_FSS_EN);
+ spin_unlock_irqrestore(&sai->xfer_lock, flags);
}
rockchip_sai_fsync_lost_detect(sai, 1);
@@ -912,6 +916,7 @@ static int rockchip_sai_set_tdm_slot(struct snd_soc_dai *dai,
int slots, int slot_width)
{
struct rk_sai_dev *sai = snd_soc_dai_get_drvdata(dai);
+ unsigned long flags;
unsigned int clk_gates;
int sw = slot_width;
@@ -927,16 +932,16 @@ static int rockchip_sai_set_tdm_slot(struct snd_soc_dai *dai,
return -EINVAL;
pm_runtime_get_sync(dai->dev);
- scoped_guard(spinlock_irqsave, &sai->xfer_lock) {
- rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
- regmap_update_bits(sai->regmap, SAI_TXCR, SAI_XCR_SBW_MASK,
- SAI_XCR_SBW(sw));
- regmap_update_bits(sai->regmap, SAI_RXCR, SAI_XCR_SBW_MASK,
- SAI_XCR_SBW(sw));
- regmap_update_bits(sai->regmap, SAI_XFER,
- SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
- clk_gates);
- }
+ spin_lock_irqsave(&sai->xfer_lock, flags);
+ rockchip_sai_xfer_clk_stop_and_wait(sai, &clk_gates);
+ regmap_update_bits(sai->regmap, SAI_TXCR, SAI_XCR_SBW_MASK,
+ SAI_XCR_SBW(sw));
+ regmap_update_bits(sai->regmap, SAI_RXCR, SAI_XCR_SBW_MASK,
+ SAI_XCR_SBW(sw));
+ regmap_update_bits(sai->regmap, SAI_XFER,
+ SAI_XFER_CLK_MASK | SAI_XFER_FSS_MASK,
+ clk_gates);
+ spin_unlock_irqrestore(&sai->xfer_lock, flags);
pm_runtime_put(dai->dev);
return 0;
diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c
index e76afa396b0a..b4dedba719dc 100644
--- a/sound/soc/sdca/sdca_asoc.c
+++ b/sound/soc/sdca/sdca_asoc.c
@@ -160,6 +160,9 @@ static int ge_put_enum_double(struct snd_kcontrol *kcontrol,
unsigned int reg = e->reg;
int ret;
+ if (item[0] >= e->items)
+ return -EINVAL;
+
reg &= ~SDW_SDCA_CTL_CSEL(0x3F);
reg |= SDW_SDCA_CTL_CSEL(SDCA_CTL_GE_DETECTED_MODE);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 86b6c752a56b..7817beea5b3b 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1980,19 +1980,15 @@ static void soc_cleanup_card_resources(struct snd_soc_card *card)
}
}
-static void snd_soc_remove_device_links(struct snd_soc_card *card,
- struct snd_soc_component *stop_at)
+static void snd_soc_remove_device_links(struct snd_soc_card *card)
{
struct snd_soc_component *component;
for_each_card_components(card, component) {
- if (card->dev == component->dev)
- continue;
-
- device_link_remove(card->dev, component->dev);
-
- if (component == stop_at)
- return;
+ if (component->card_device_link) {
+ device_link_del(component->card_device_link);
+ component->card_device_link = NULL;
+ }
}
}
@@ -2001,7 +1997,7 @@ static void snd_soc_unbind_card(struct snd_soc_card *card)
if (snd_soc_card_is_instantiated(card)) {
card->instantiated = false;
- snd_soc_remove_device_links(card, NULL);
+ snd_soc_remove_device_links(card);
soc_cleanup_card_resources(card);
}
@@ -2012,7 +2008,6 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
struct snd_soc_pcm_runtime *rtd;
struct snd_soc_component *component;
struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card);
- struct snd_soc_component *last_devlinked_component = NULL;
int ret;
snd_soc_card_mutex_lock_root(card);
@@ -2141,19 +2136,21 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
* Add device_link from card to component so that system_suspend
* will be done in the correct order. The card must suspend first
* to stop audio activity before the components suspend.
+ *
+ * If a driver pair already have a link in the opposite direction
+ * they must manage their own suspend order.
*/
for_each_card_components(card, component) {
if (card->dev == component->dev)
continue;
- if (!device_link_add(card->dev, component->dev, DL_FLAG_STATELESS)) {
- dev_warn(card->dev, "Failed to create device link to %s\n",
+ component->card_device_link = device_link_add(card->dev,
+ component->dev,
+ DL_FLAG_STATELESS);
+ if (!component->card_device_link) {
+ dev_warn(card->dev, "Could not create device link to %s\n",
dev_name(component->dev));
- ret = -EINVAL;
- goto probe_end;
}
-
- last_devlinked_component = component;
}
ret = snd_soc_card_late_probe(card);
@@ -2185,9 +2182,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card)
probe_end:
if (ret < 0) {
- if (last_devlinked_component)
- snd_soc_remove_device_links(card, last_devlinked_component);
-
+ snd_soc_remove_device_links(card);
soc_cleanup_card_resources(card);
}
diff --git a/sound/usb/caiaq/input.c b/sound/usb/caiaq/input.c
index 5c70fdf61cc1..eabbf41fdfb2 100644
--- a/sound/usb/caiaq/input.c
+++ b/sound/usb/caiaq/input.c
@@ -237,12 +237,16 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *cdev,
switch (cdev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
+ if (len < 2)
+ return;
i = decode_erp(buf[0], buf[1]);
input_report_abs(input_dev, ABS_X, i);
input_sync(input_dev);
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
+ if (len < 16)
+ return;
i = decode_erp(buf[7], buf[5]);
input_report_abs(input_dev, ABS_HAT0X, i);
i = decode_erp(buf[12], buf[14]);
@@ -263,6 +267,8 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *cdev,
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER):
+ if (len < 22)
+ return;
/* 4 under the left screen */
input_report_abs(input_dev, ABS_HAT0X, decode_erp(buf[21], buf[20]));
input_report_abs(input_dev, ABS_HAT0Y, decode_erp(buf[15], buf[14]));
@@ -308,9 +314,13 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *cdev,
switch (cdev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
+ if (len < 5)
+ return;
input_report_abs(cdev->input_dev, ABS_MISC, 255 - buf[4]);
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
+ if (len < 7)
+ return;
/* rotary encoders */
input_report_abs(cdev->input_dev, ABS_X, buf[5] & 0xf);
input_report_abs(cdev->input_dev, ABS_Y, buf[5] >> 4);
@@ -330,7 +340,7 @@ static void snd_usb_caiaq_tks4_dispatch(struct snd_usb_caiaqdev *cdev,
{
struct device *dev = caiaqdev_to_dev(cdev);
- while (len) {
+ while (len >= TKS4_MSGBLOCK_SIZE) {
unsigned int i, block_id = (buf[0] << 8) | buf[1];
switch (block_id) {
diff --git a/sound/usb/fcp.c b/sound/usb/fcp.c
index ea746bdb36ff..6f5dcd35e1d4 100644
--- a/sound/usb/fcp.c
+++ b/sound/usb/fcp.c
@@ -1083,6 +1083,8 @@ static int fcp_find_fc_interface(struct usb_mixer_interface *mixer)
if (desc->bInterfaceClass != 255)
continue;
+ if (desc->bNumEndpoints < 1)
+ continue;
epd = get_endpoint(intf->altsetting, 0);
private->bInterfaceNumber = desc->bInterfaceNumber;
diff --git a/sound/usb/midi2.c b/sound/usb/midi2.c
index 04aeb9052f13..3ec633291772 100644
--- a/sound/usb/midi2.c
+++ b/sound/usb/midi2.c
@@ -470,6 +470,11 @@ static int create_midi2_endpoint(struct snd_usb_midi2_interface *umidi,
static void free_midi2_endpoint(struct snd_usb_midi2_endpoint *ep)
{
list_del(&ep->list);
+ if (!ep->disconnected) {
+ ep->disconnected = 1;
+ kill_midi_urbs(ep, false);
+ drain_urb_queue(ep);
+ }
free_midi_urbs(ep);
kfree(ep);
}
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 628f841b04aa..10792d26fa94 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -577,46 +577,30 @@ static bool snd_dualsense_ih_match(struct input_handler *handler,
{
struct dualsense_mixer_elem_info *mei;
struct usb_device *snd_dev;
- char *input_dev_path, *usb_dev_path;
- size_t usb_dev_path_len;
- bool match = false;
+ struct device *parent;
mei = container_of(handler, struct dualsense_mixer_elem_info, ih);
snd_dev = mei->info.head.mixer->chip->dev;
- input_dev_path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
- if (!input_dev_path) {
- dev_warn(&snd_dev->dev, "Failed to get input dev path\n");
- return false;
- }
-
- usb_dev_path = kobject_get_path(&snd_dev->dev.kobj, GFP_KERNEL);
- if (!usb_dev_path) {
- dev_warn(&snd_dev->dev, "Failed to get USB dev path\n");
- goto free_paths;
- }
-
/*
* Ensure the VID:PID matched input device supposedly owned by the
* hid-playstation driver belongs to the actual hardware handled by
- * the current USB audio device, which implies input_dev_path being
- * a subpath of usb_dev_path.
+ * the current USB audio device.
*
* This verification is necessary when there is more than one identical
* controller attached to the host system.
+ *
+ * The input device is registered below the HID device, USB interface and
+ * USB device, so compare the parent chain directly instead of building
+ * kobject path strings. This avoids dereferencing kobject names while the
+ * USB device hierarchy is being torn down during disconnect.
*/
- usb_dev_path_len = strlen(usb_dev_path);
- if (usb_dev_path_len >= strlen(input_dev_path))
- goto free_paths;
-
- usb_dev_path[usb_dev_path_len] = '/';
- match = !memcmp(input_dev_path, usb_dev_path, usb_dev_path_len + 1);
-
-free_paths:
- kfree(input_dev_path);
- kfree(usb_dev_path);
+ for (parent = dev->dev.parent; parent; parent = parent->parent) {
+ if (parent == &snd_dev->dev)
+ return true;
+ }
- return match;
+ return false;
}
static int snd_dualsense_ih_connect(struct input_handler *handler,
@@ -4526,6 +4510,7 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
case USB_ID(0x1235, 0x821b): /* Focusrite Scarlett 16i16 4th Gen */
case USB_ID(0x1235, 0x821c): /* Focusrite Scarlett 18i16 4th Gen */
case USB_ID(0x1235, 0x821d): /* Focusrite Scarlett 18i20 4th Gen */
+ case USB_ID(0x1235, 0x821e): /* Focusrite ISA C8X */
err = snd_fcp_init(mixer);
break;
diff --git a/sound/usb/qcom/qc_audio_offload.c b/sound/usb/qcom/qc_audio_offload.c
index a3f90cc7c6ca..e4bfd43a2488 100644
--- a/sound/usb/qcom/qc_audio_offload.c
+++ b/sound/usb/qcom/qc_audio_offload.c
@@ -1160,6 +1160,7 @@ uaudio_endpoint_setup(struct snd_usb_substream *subs,
tr_pa = page_to_phys(pg);
mem_info->dma = sg_dma_address(sgt->sgl);
sg_free_table(sgt);
+ kfree(sgt);
/* data transfer ring */
iova = uaudio_iommu_map_pa(MEM_XFER_RING, dma_coherent, tr_pa,
@@ -1229,6 +1230,7 @@ static int uaudio_event_ring_setup(struct snd_usb_substream *subs,
er_pa = page_to_phys(pg);
mem_info->dma = sg_dma_address(sgt->sgl);
sg_free_table(sgt);
+ kfree(sgt);
iova = uaudio_iommu_map_pa(MEM_EVENT_RING, dma_coherent, er_pa,
PAGE_SIZE);
@@ -1618,8 +1620,13 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle,
if (req_msg->service_interval_valid) {
ret = get_data_interval_from_si(subs,
req_msg->service_interval);
- if (ret == -EINVAL)
+ if (ret == -EINVAL) {
+ if (req_msg->enable) {
+ guard(mutex)(&chip->mutex);
+ subs->opened = 0;
+ }
goto response;
+ }
datainterval = ret;
}
@@ -1640,6 +1647,11 @@ static void handle_uaudio_stream_req(struct qmi_handle *handle,
subs->opened = 0;
}
} else {
+ if (info_idx < 0) {
+ ret = -EINVAL;
+ goto response;
+ }
+
info = &uadev[pcm_card_num].info[info_idx];
if (info->data_ep_pipe) {
ep = usb_pipe_endpoint(uadev[pcm_card_num].udev,
@@ -1976,6 +1988,7 @@ static int qc_usb_audio_probe(struct auxiliary_device *auxdev,
release_qmi:
qc_usb_audio_cleanup_qmi_dev();
qmi_handle_release(svc->uaudio_svc_hdl);
+ kfree(svc->uaudio_svc_hdl);
free_svc:
kfree(svc);
@@ -2000,6 +2013,7 @@ static void qc_usb_audio_remove(struct auxiliary_device *auxdev)
qc_usb_audio_cleanup_qmi_dev();
qmi_handle_release(svc->uaudio_svc_hdl);
+ kfree(svc->uaudio_svc_hdl);
kfree(svc);
uaudio_svc = NULL;
}
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 97f28c53d201..71444c2898b4 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -391,6 +391,20 @@ YAMAHA_DEVICE(0x105d, NULL),
}
},
{
+ USB_DEVICE(0x0499, 0x150d),
+ QUIRK_DRIVER_INFO {
+ /* .vendor_name = "Yamaha", */
+ /* .product_name = "CDS3000", */
+ QUIRK_DATA_COMPOSITE {
+ { QUIRK_DATA_STANDARD_AUDIO(1) },
+ { QUIRK_DATA_STANDARD_AUDIO(2) },
+ { QUIRK_DATA_MIDI_YAMAHA(3) },
+ { QUIRK_DATA_IGNORE(4) },
+ QUIRK_COMPOSITE_END
+ }
+ }
+},
+{
USB_DEVICE(0x0499, 0x1718),
QUIRK_DRIVER_INFO {
/* .vendor_name = "Yamaha", */
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 30f6d572e4d1..1cb588691e16 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -2413,6 +2413,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16),
DEVICE_FLG(0x1bcf, 0x2283, /* NexiGo N930AF FHD Webcam */
QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIC_RES_16),
+ DEVICE_FLG(0x1ff7, 0x0f81, /* SC13A Webcam */
+ QUIRK_FLAG_GET_SAMPLE_RATE),
DEVICE_FLG(0x2040, 0x7200, /* Hauppauge HVR-950Q */
QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
DEVICE_FLG(0x2040, 0x7201, /* Hauppauge HVR-950Q-MXL */
diff --git a/tools/bpf/bpftool/cgroup.c b/tools/bpf/bpftool/cgroup.c
index ec356deb27c9..ce69d1e5468e 100644
--- a/tools/bpf/bpftool/cgroup.c
+++ b/tools/bpf/bpftool/cgroup.c
@@ -78,6 +78,13 @@ static unsigned int query_flags;
static struct btf *btf_vmlinux;
static __u32 btf_vmlinux_id;
+static void free_btf_vmlinux(void)
+{
+ btf__free(btf_vmlinux);
+ btf_vmlinux = NULL;
+ btf_vmlinux_id = 0;
+}
+
static enum bpf_attach_type parse_attach_type(const char *str)
{
const char *attach_type_str;
@@ -388,6 +395,8 @@ static int do_show(int argc, char **argv)
if (json_output)
jsonw_end_array(json_wtr);
+ free_btf_vmlinux();
+
exit_cgroup:
close(cgroup_fd);
exit:
@@ -437,7 +446,9 @@ static int do_show_tree_fn(const char *fpath, const struct stat *sb,
printf("%s\n", fpath);
}
- btf_vmlinux = libbpf_find_kernel_btf();
+ if (!btf_vmlinux)
+ btf_vmlinux = libbpf_find_kernel_btf();
+
for (i = 0; i < ARRAY_SIZE(cgroup_attach_types); i++)
show_bpf_progs(cgroup_fd, cgroup_attach_types[i], ftw->level);
@@ -540,6 +551,7 @@ static int do_show_tree(int argc, char **argv)
if (json_output)
jsonw_end_array(json_wtr);
+ free_btf_vmlinux();
free(cgroup_alloced);
return ret;
diff --git a/tools/testing/selftests/bpf/bpf_experimental.h b/tools/testing/selftests/bpf/bpf_experimental.h
index d1db355e872b..67ff7882299e 100644
--- a/tools/testing/selftests/bpf/bpf_experimental.h
+++ b/tools/testing/selftests/bpf/bpf_experimental.h
@@ -423,6 +423,8 @@ static inline int get_preempt_count(void)
return bpf_get_current_task_btf()->thread_info.preempt_count;
#elif defined(bpf_target_s390)
return bpf_get_lowcore()->preempt_count;
+#elif defined(bpf_target_loongarch)
+ return bpf_get_current_task_btf()->thread_info.preempt_count;
#endif
return 0;
}
@@ -433,6 +435,7 @@ static inline int get_preempt_count(void)
* * arm64
* * powerpc64
* * s390x
+ * * loongarch
*/
static inline int bpf_in_interrupt(void)
{
@@ -454,6 +457,7 @@ static inline int bpf_in_interrupt(void)
* * arm64
* * powerpc64
* * s390x
+ * * loongarch
*/
static inline int bpf_in_nmi(void)
{
@@ -466,6 +470,7 @@ static inline int bpf_in_nmi(void)
* * arm64
* * powerpc64
* * s390x
+ * * loongarch
*/
static inline int bpf_in_hardirq(void)
{
@@ -478,6 +483,7 @@ static inline int bpf_in_hardirq(void)
* * arm64
* * powerpc64
* * s390x
+ * * loongarch
*/
static inline int bpf_in_serving_softirq(void)
{
@@ -498,6 +504,7 @@ static inline int bpf_in_serving_softirq(void)
* * arm64
* * powerpc64
* * s390x
+ * * loongarch
*/
static inline int bpf_in_task(void)
{
diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_nf.c b/tools/testing/selftests/bpf/prog_tests/bpf_nf.c
index b33dba4b126e..14d4c1793aed 100644
--- a/tools/testing/selftests/bpf/prog_tests/bpf_nf.c
+++ b/tools/testing/selftests/bpf/prog_tests/bpf_nf.c
@@ -5,6 +5,8 @@
#include "test_bpf_nf.skel.h"
#include "test_bpf_nf_fail.skel.h"
+#define CT_OPTS_ERROR_GUARD 0x12345678
+
static char log_buf[1024 * 1024];
struct {
@@ -119,6 +121,10 @@ static void test_bpf_nf_ct(int mode)
ASSERT_EQ(skel->bss->test_einval_reserved_new, -EINVAL, "Test EINVAL for reserved in new struct not set to 0");
ASSERT_EQ(skel->bss->test_einval_netns_id, -EINVAL, "Test EINVAL for netns_id < -1");
ASSERT_EQ(skel->bss->test_einval_len_opts, -EINVAL, "Test EINVAL for len__opts != NF_BPF_CT_OPTS_SZ");
+ ASSERT_EQ(skel->bss->test_einval_len_opts_small_lookup, CT_OPTS_ERROR_GUARD,
+ "Test no error write for lookup opts__sz before error field");
+ ASSERT_EQ(skel->bss->test_einval_len_opts_small_alloc, CT_OPTS_ERROR_GUARD,
+ "Test no error write for alloc opts__sz before error field");
ASSERT_EQ(skel->bss->test_eproto_l4proto, -EPROTO, "Test EPROTO for l4proto != TCP or UDP");
ASSERT_EQ(skel->bss->test_enonet_netns_id, -ENONET, "Test ENONET for bad but valid netns_id");
ASSERT_EQ(skel->bss->test_enoent_lookup, -ENOENT, "Test ENOENT for failed lookup");
diff --git a/tools/testing/selftests/bpf/prog_tests/btf.c b/tools/testing/selftests/bpf/prog_tests/btf.c
index 96f719a0cec9..66855cbd6b73 100644
--- a/tools/testing/selftests/bpf/prog_tests/btf.c
+++ b/tools/testing/selftests/bpf/prog_tests/btf.c
@@ -4121,8 +4121,6 @@ static struct btf_raw_test raw_tests[] = {
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 1,
- .btf_load_err = true,
- .err_str = "Type tags don't precede modifiers",
},
{
.descr = "type_tag test #3, type tag order",
@@ -4141,8 +4139,6 @@ static struct btf_raw_test raw_tests[] = {
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 1,
- .btf_load_err = true,
- .err_str = "Type tags don't precede modifiers",
},
{
.descr = "type_tag test #4, type tag order",
@@ -4161,8 +4157,6 @@ static struct btf_raw_test raw_tests[] = {
.key_type_id = 1,
.value_type_id = 1,
.max_entries = 1,
- .btf_load_err = true,
- .err_str = "Type tags don't precede modifiers",
},
{
.descr = "type_tag test #5, type tag order",
@@ -4198,11 +4192,9 @@ static struct btf_raw_test raw_tests[] = {
.map_name = "tag_type_check_btf",
.key_size = sizeof(int),
.value_size = 4,
- .key_type_id = 1,
- .value_type_id = 1,
+ .key_type_id = 4,
+ .value_type_id = 4,
.max_entries = 1,
- .btf_load_err = true,
- .err_str = "Type tags don't precede modifiers",
},
{
.descr = "type_tag test #7, tag with kflag",
diff --git a/tools/testing/selftests/bpf/prog_tests/cgroup_preorder.c b/tools/testing/selftests/bpf/prog_tests/cgroup_preorder.c
index d4d583872fa2..d2ccf409dfe3 100644
--- a/tools/testing/selftests/bpf/prog_tests/cgroup_preorder.c
+++ b/tools/testing/selftests/bpf/prog_tests/cgroup_preorder.c
@@ -102,6 +102,82 @@ close_skel:
return err;
}
+/*
+ * Replacing a link's program (bpf_link_update) must target the correct slot in
+ * the effective array even when a BPF_F_PREORDER program is attached to the
+ * same cgroup. All programs here are attached to a single cgroup; "parent" is
+ * reused only as a third distinct program.
+ *
+ * Attach child(1) normally and child_2(2) with BPF_F_PREORDER, so the effective
+ * order is [2, 1]. Then replace child(1)'s program with parent(3): only the
+ * non-preorder slot changes, giving [2, 3].
+ */
+static int run_link_replace_test(int cgroup_fd, int sock_fd)
+{
+ LIBBPF_OPTS(bpf_link_create_opts, create_opts);
+ int err = 0, normal_link = -1, preorder_link = -1;
+ struct cgroup_preorder *skel = NULL;
+ enum bpf_attach_type atype;
+ __u8 *result, buf = 0x00;
+ socklen_t optlen = 1;
+
+ skel = cgroup_preorder__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "cgroup_preorder__open_and_load"))
+ return -1;
+
+ err = setsockopt(sock_fd, SOL_IP, IP_TOS, &buf, 1);
+ if (!ASSERT_OK(err, "setsockopt"))
+ goto close_skel;
+
+ atype = bpf_program__expected_attach_type(skel->progs.child);
+
+ create_opts.flags = 0;
+ normal_link = bpf_link_create(bpf_program__fd(skel->progs.child),
+ cgroup_fd, atype, &create_opts);
+ if (!ASSERT_GE(normal_link, 0, "create_normal_link")) {
+ err = normal_link;
+ goto close_skel;
+ }
+
+ create_opts.flags = BPF_F_PREORDER;
+ preorder_link = bpf_link_create(bpf_program__fd(skel->progs.child_2),
+ cgroup_fd, atype, &create_opts);
+ if (!ASSERT_GE(preorder_link, 0, "create_preorder_link")) {
+ err = preorder_link;
+ goto close_links;
+ }
+
+ result = skel->bss->result;
+ skel->bss->idx = 0;
+ memset(result, 0, 4);
+
+ err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
+ if (!ASSERT_OK(err, "getsockopt-before"))
+ goto close_links;
+ ASSERT_TRUE(result[0] == 2 && result[1] == 1, "order before update");
+
+ /* Replace the normal link's program child(1) -> parent(3). */
+ err = bpf_link_update(normal_link, bpf_program__fd(skel->progs.parent), NULL);
+ if (!ASSERT_OK(err, "bpf_link_update"))
+ goto close_links;
+
+ skel->bss->idx = 0;
+ memset(result, 0, 4);
+
+ err = getsockopt(sock_fd, SOL_IP, IP_TOS, &buf, &optlen);
+ if (!ASSERT_OK(err, "getsockopt-after"))
+ goto close_links;
+ ASSERT_TRUE(result[0] == 2 && result[1] == 3, "order after update");
+
+close_links:
+ if (preorder_link >= 0)
+ close(preorder_link);
+ close(normal_link);
+close_skel:
+ cgroup_preorder__destroy(skel);
+ return err;
+}
+
void test_cgroup_preorder(void)
{
int cg_parent = -1, cg_child = -1, sock_fd = -1;
@@ -120,6 +196,7 @@ void test_cgroup_preorder(void)
ASSERT_OK(run_getsockopt_test(cg_parent, cg_child, sock_fd, false), "getsockopt_test_1");
ASSERT_OK(run_getsockopt_test(cg_parent, cg_child, sock_fd, true), "getsockopt_test_2");
+ ASSERT_OK(run_link_replace_test(cg_child, sock_fd), "link_replace_test");
out:
close(sock_fd);
diff --git a/tools/testing/selftests/bpf/progs/bpf_misc.h b/tools/testing/selftests/bpf/progs/bpf_misc.h
index 9eeb5b0b63d6..b0c441384f20 100644
--- a/tools/testing/selftests/bpf/progs/bpf_misc.h
+++ b/tools/testing/selftests/bpf/progs/bpf_misc.h
@@ -158,6 +158,7 @@
#define __arch_arm64 __arch("ARM64")
#define __arch_riscv64 __arch("RISCV64")
#define __arch_s390x __arch("s390x")
+#define __arch_loongarch __arch("LOONGARCH")
#define __caps_unpriv(caps) __test_tag("test_caps_unpriv=" EXPAND_QUOTE(caps))
#define __load_if_JITed() __test_tag("load_mode=jited")
#define __load_if_no_JITed() __test_tag("load_mode=no_jited")
diff --git a/tools/testing/selftests/bpf/progs/test_bpf_nf.c b/tools/testing/selftests/bpf/progs/test_bpf_nf.c
index 076fbf03a126..df43649ecb78 100644
--- a/tools/testing/selftests/bpf/progs/test_bpf_nf.c
+++ b/tools/testing/selftests/bpf/progs/test_bpf_nf.c
@@ -10,6 +10,8 @@
#define EINVAL 22
#define ENOENT 2
+#define CT_OPTS_ERROR_GUARD 0x12345678
+
#define NF_CT_ZONE_DIR_ORIG (1 << IP_CT_DIR_ORIGINAL)
#define NF_CT_ZONE_DIR_REPL (1 << IP_CT_DIR_REPLY)
@@ -19,6 +21,8 @@ int test_einval_reserved = 0;
int test_einval_reserved_new = 0;
int test_einval_netns_id = 0;
int test_einval_len_opts = 0;
+int test_einval_len_opts_small_lookup = 0;
+int test_einval_len_opts_small_alloc = 0;
int test_eproto_l4proto = 0;
int test_enonet_netns_id = 0;
int test_enoent_lookup = 0;
@@ -124,6 +128,28 @@ nf_ct_test(struct nf_conn *(*lookup_fn)(void *, struct bpf_sock_tuple *, u32,
else
test_einval_len_opts = opts_def.error;
+ opts_def.error = CT_OPTS_ERROR_GUARD;
+ ct = lookup_fn(ctx, &bpf_tuple, sizeof(bpf_tuple.ipv4), &opts_def,
+ sizeof(opts_def.netns_id));
+ if (ct) {
+ bpf_ct_release(ct);
+ test_einval_len_opts_small_lookup = -EINVAL;
+ } else {
+ test_einval_len_opts_small_lookup = opts_def.error;
+ }
+
+ opts_def.error = CT_OPTS_ERROR_GUARD;
+ ct = alloc_fn(ctx, &bpf_tuple, sizeof(bpf_tuple.ipv4), &opts_def,
+ sizeof(opts_def.netns_id));
+ if (ct) {
+ ct = bpf_ct_insert_entry(ct);
+ if (ct)
+ bpf_ct_release(ct);
+ test_einval_len_opts_small_alloc = -EINVAL;
+ } else {
+ test_einval_len_opts_small_alloc = opts_def.error;
+ }
+
opts_def.l4proto = IPPROTO_ICMP;
ct = lookup_fn(ctx, &bpf_tuple, sizeof(bpf_tuple.ipv4), &opts_def,
sizeof(opts_def));
diff --git a/tools/testing/selftests/bpf/progs/verifier_jit_inline.c b/tools/testing/selftests/bpf/progs/verifier_jit_inline.c
index 76d80605ec7f..02e562f56f9d 100644
--- a/tools/testing/selftests/bpf/progs/verifier_jit_inline.c
+++ b/tools/testing/selftests/bpf/progs/verifier_jit_inline.c
@@ -12,6 +12,8 @@ __arch_arm64
__jited(" mrs x8, SP_EL0")
__arch_riscv64
__jited(" mv a5, tp")
+__arch_loongarch
+__jited(" move $a5, $tp")
int inline_bpf_get_current_task(void)
{
bpf_get_current_task();
@@ -19,4 +21,15 @@ int inline_bpf_get_current_task(void)
return 0;
}
+SEC("fentry/bpf_fentry_test2")
+__success __retval(0)
+__arch_loongarch
+__jited(" ld.wu $a5, $tp, 16")
+int inline_bpf_get_smp_processor_id(void)
+{
+ bpf_get_smp_processor_id();
+
+ return 0;
+}
+
char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/verifier_lsm.c b/tools/testing/selftests/bpf/progs/verifier_lsm.c
index 2f8103bfa14e..c724bf389f5c 100644
--- a/tools/testing/selftests/bpf/progs/verifier_lsm.c
+++ b/tools/testing/selftests/bpf/progs/verifier_lsm.c
@@ -197,4 +197,19 @@ int BPF_PROG(sleepable_lsm_cgroup)
return 0;
}
+SEC("lsm/file_mprotect")
+__description("lsm retval load must reset stale register bounds")
+__failure __msg("div by zero")
+__naked int retval_load_resets_bounds(void *ctx)
+{
+ asm volatile (
+ "r6 = 0;"
+ "r6 = *(u64 *)(r1 + 24);"
+ "if r6 == 0 goto +1;"
+ "r6 /= 0;"
+ "r0 = 0;"
+ "exit;"
+ ::: __clobber_all);
+}
+
char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c
index 6bc721accbae..0174887e28f5 100644
--- a/tools/testing/selftests/bpf/progs/verifier_spill_fill.c
+++ b/tools/testing/selftests/bpf/progs/verifier_spill_fill.c
@@ -1359,4 +1359,22 @@ __naked void var_off_write_over_scalar_spill(void)
: __clobber_all);
}
+SEC("socket")
+__description("partial fill from cleaned pointer spill")
+__failure
+__log_level(2)
+__msg("1: (05) goto pc+0")
+__msg("2: (61) r0 = *(u32 *)(r10 -4)")
+__msg("invalid size of register fill")
+__flag(BPF_F_TEST_STATE_FREQ)
+__naked void partial_fill_from_cleaned_pointer_spill(void)
+{
+ /* Spill R1(ctx), then force a checkpoint and half-slot cleanup. */
+ asm volatile ("*(u64 *)(r10 - 8) = r1;"
+ "goto +0;"
+ "r0 = *(u32 *)(r10 - 4);"
+ "exit;"
+ ::: __clobber_all);
+}
+
char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/verifier_unpriv.c b/tools/testing/selftests/bpf/progs/verifier_unpriv.c
index c16f8382cf17..49f7bd05edad 100644
--- a/tools/testing/selftests/bpf/progs/verifier_unpriv.c
+++ b/tools/testing/selftests/bpf/progs/verifier_unpriv.c
@@ -976,4 +976,26 @@ l0_%=: exit; \
: __clobber_all);
}
+SEC("socket")
+__description("unpriv: Spectre v4 stack write slot index")
+__success __success_unpriv
+__retval(0)
+#ifdef SPEC_V4
+__xlated_unpriv("r0 = 0")
+__xlated_unpriv("*(u32 *)(r10 -4) = r0")
+__xlated_unpriv("nospec")
+__xlated_unpriv("*(u32 *)(r10 -8) = r0")
+__xlated_unpriv("nospec")
+__xlated_unpriv("exit")
+#endif
+__naked void stack_write_nospec_slot_index(void)
+{
+ asm volatile (" \
+ r0 = 0; \
+ *(u32 *)(r10 - 4) = r0; \
+ *(u32 *)(r10 - 8) = r0; \
+ exit; \
+" ::: __clobber_all);
+}
+
char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/test_loader.c b/tools/testing/selftests/bpf/test_loader.c
index abdb9e6e3713..3ce32d134e2c 100644
--- a/tools/testing/selftests/bpf/test_loader.c
+++ b/tools/testing/selftests/bpf/test_loader.c
@@ -377,6 +377,7 @@ enum arch {
ARCH_ARM64 = 0x4,
ARCH_RISCV64 = 0x8,
ARCH_S390X = 0x10,
+ ARCH_LOONGARCH = 0x20,
};
static int get_current_arch(void)
@@ -389,6 +390,8 @@ static int get_current_arch(void)
return ARCH_RISCV64;
#elif defined(__s390x__)
return ARCH_S390X;
+#elif defined(__loongarch__)
+ return ARCH_LOONGARCH;
#endif
return ARCH_UNKNOWN;
}
@@ -580,6 +583,8 @@ static int parse_test_spec(struct test_loader *tester,
arch = ARCH_RISCV64;
} else if (strcmp(val, "s390x") == 0) {
arch = ARCH_S390X;
+ } else if (strcmp(val, "LOONGARCH") == 0) {
+ arch = ARCH_LOONGARCH;
} else {
PRINT_FAIL("bad arch spec: '%s'\n", val);
err = -EINVAL;
diff --git a/tools/testing/selftests/drivers/net/hw/tso.py b/tools/testing/selftests/drivers/net/hw/tso.py
index 1b789fea8929..802bb4868046 100755
--- a/tools/testing/selftests/drivers/net/hw/tso.py
+++ b/tools/testing/selftests/drivers/net/hw/tso.py
@@ -187,28 +187,24 @@ def query_nic_features(cfg) -> None:
cfg.wanted_features.add(f["name"])
cfg.hw_features = set()
- hw_all_features_cmd = ""
for f in features["hw"]["bits"]["bit"]:
if f.get("value", False):
- feature = f["name"]
- cfg.hw_features.add(feature)
- hw_all_features_cmd += f" {feature} on"
- try:
- ethtool(f"-K {cfg.ifname} {hw_all_features_cmd}")
- except Exception as e:
- ksft_pr(f"WARNING: failure enabling all hw features: {e}")
- ksft_pr("partial gso feature detection may be impacted")
+ cfg.hw_features.add(f["name"])
# Check which features are supported via GSO partial
cfg.partial_features = set()
if 'tx-gso-partial' in cfg.hw_features:
+ seg_features = {f for f in cfg.hw_features if "segmentation" in f}
+ ethtool(f"-K {cfg.ifname} " +
+ " ".join(f"{f} on" for f in seg_features))
+
ethtool(f"-K {cfg.ifname} tx-gso-partial off")
no_partial = set()
features = cfg.ethnl.features_get({"header": {"dev-index": cfg.ifindex}})
for f in features["active"]["bits"]["bit"]:
no_partial.add(f["name"])
- cfg.partial_features = cfg.hw_features - no_partial
+ cfg.partial_features = seg_features - no_partial
ethtool(f"-K {cfg.ifname} tx-gso-partial on")
restore_wanted_features(cfg)
diff --git a/tools/testing/selftests/net/lib/py/utils.py b/tools/testing/selftests/net/lib/py/utils.py
index 87eae79d01c1..184bb04343f6 100644
--- a/tools/testing/selftests/net/lib/py/utils.py
+++ b/tools/testing/selftests/net/lib/py/utils.py
@@ -44,7 +44,7 @@ class cmd:
Use bkg() instead to run a command in the background.
"""
def __init__(self, comm, shell=None, fail=True, expect_fail=False, ns=None,
- background=False, host=None, timeout=5, ksft_ready=None,
+ background=False, host=None, timeout=20, ksft_ready=None,
ksft_wait=None):
if ns:
if hasattr(ns, 'user_ns_path'):
@@ -113,7 +113,7 @@ class cmd:
return stdout, stderr
- def process(self, terminate=True, fail=None, expect_fail=False, timeout=5):
+ def process(self, terminate=True, fail=None, expect_fail=False, timeout=20):
if fail is None:
fail = not terminate
diff --git a/tools/tracing/rtla/.gitignore b/tools/tracing/rtla/.gitignore
index c7b4bf1c8ba9..2a1c99ddd1bf 100644
--- a/tools/tracing/rtla/.gitignore
+++ b/tools/tracing/rtla/.gitignore
@@ -1,14 +1,9 @@
# SPDX-License-Identifier: GPL-2.0-only
-rtla
-rtla-static
-unit_tests
+/rtla
+/rtla-static
+/unit_tests
fixdep
feature
FEATURE-DUMP
*.skel.h
-custom_filename.txt
-osnoise_irq_noise_hist.txt
-osnoise_trace.txt
-timerlat_trace.txt
-libsubcmd/
-lib/
+/libsubcmd/
diff --git a/tools/tracing/rtla/tests/scripts/lib/get_workload_pids.sh b/tools/tracing/rtla/tests/scripts/lib/get_workload_pids.sh
index 8aff98cd2c1f..d10a4e3b321d 100644
--- a/tools/tracing/rtla/tests/scripts/lib/get_workload_pids.sh
+++ b/tools/tracing/rtla/tests/scripts/lib/get_workload_pids.sh
@@ -5,7 +5,7 @@ get_workload_pids() {
local rtla_pid=$(ps -o ppid= $shell_pid)
# kernel threads
- pgrep -P $(pgrep ^kthreadd$) -f '^(osnoise|timerlat)/[0-9]+$'
+ pgrep -P $(pgrep ^kthreadd$) -f '^\[?(osnoise|timerlat)/[0-9]+\]?$'
# user threads
pgrep -P $rtla_pid | grep -v "^$shell_pid$"
}