
Changes in 5.10.209 f2fs: explicitly null-terminate the xattr list pinctrl: lochnagar: Don't build on MIPS ALSA: hda - Fix speaker and headset mic pin config for CHUWI CoreBook XPro mptcp: fix uninit-value in mptcp_incoming_options debugfs: fix automount d_fsdata usage drm/amdgpu: Fix cat debugfs amdgpu_regs_didt causes kernel null pointer nvme-core: check for too small lba shift ASoC: wm8974: Correct boost mixer inputs ASoC: Intel: Skylake: Fix mem leak in few functions ASoC: nau8822: Fix incorrect type in assignment and cast to restricted __be16 ASoC: Intel: Skylake: mem leak in skl register function ASoC: cs43130: Fix the position of const qualifier ASoC: cs43130: Fix incorrect frame delay configuration ASoC: rt5650: add mutex to avoid the jack detection failure nouveau/tu102: flush all pdbs on vmm flush net/tg3: fix race condition in tg3_reset_task() ASoC: da7219: Support low DC impedance headset nvme: introduce helper function to get ctrl state drm/exynos: fix a potential error pointer dereference drm/exynos: fix a wrong error checking clk: rockchip: rk3128: Fix HCLK_OTG gate register jbd2: correct the printing of write_flags in jbd2_write_superblock() drm/crtc: Fix uninit-value bug in drm_mode_setcrtc neighbour: Don't let neigh_forced_gc() disable preemption for long jbd2: fix soft lockup in journal_finish_inode_data_buffers() tracing: Have large events show up as '[LINE TOO BIG]' instead of nothing tracing: Add size check when printing trace_marker output ring-buffer: Do not record in NMI if the arch does not support cmpxchg in NMI reset: hisilicon: hi6220: fix Wvoid-pointer-to-enum-cast warning Input: atkbd - skip ATKBD_CMD_GETID in translated mode Input: i8042 - add nomux quirk for Acer P459-G2-M s390/scm: fix virtual vs physical address confusion ARC: fix spare error Input: xpad - add Razer Wolverine V2 support i2c: rk3x: fix potential spinlock recursion on poll ida: Fix crash in ida_free when the bitmap is empty net: qrtr: ns: Return 0 if server port is not present ARM: sun9i: smp: fix return code check of of_property_match_string drm/crtc: fix uninitialized variable use ACPI: resource: Add another DMI match for the TongFang GMxXGxx binder: use EPOLLERR from eventpoll.h binder: fix trivial typo of binder_free_buf_locked() binder: fix comment on binder_alloc_new_buf() return value uio: Fix use-after-free in uio_open parport: parport_serial: Add Brainboxes BAR details parport: parport_serial: Add Brainboxes device IDs and geometry PCI: Add ACS quirk for more Zhaoxin Root Ports coresight: etm4x: Fix width of CCITMIN field x86/lib: Fix overflow when counting digits EDAC/thunderx: Fix possible out-of-bounds string access powerpc: add crtsavres.o to always-y instead of extra-y powerpc: Remove in_kernel_text() powerpc/44x: select I2C for CURRITUCK powerpc/pseries/memhotplug: Quieten some DLPAR operations powerpc/pseries/memhp: Fix access beyond end of drmem array selftests/powerpc: Fix error handling in FPU/VMX preemption tests powerpc/powernv: Add a null pointer check to scom_debug_init_one() powerpc/powernv: Add a null pointer check in opal_event_init() powerpc/powernv: Add a null pointer check in opal_powercap_init() powerpc/imc-pmu: Add a null pointer check in update_events_in_group() spi: spi-zynqmp-gqspi: fix driver kconfig dependencies mtd: rawnand: Increment IFC_TIMEOUT_MSECS for nand controller response ACPI: video: check for error while searching for backlight device parent ACPI: LPIT: Avoid u32 multiplication overflow of: property: define of_property_read_u{8,16,32,64}_array() unconditionally of: Add of_property_present() helper cpufreq: Use of_property_present() for testing DT property presence cpufreq: scmi: process the result of devm_of_clk_add_hw_provider() net: netlabel: Fix kerneldoc warnings netlabel: remove unused parameter in netlbl_netlink_auditinfo() calipso: fix memory leak in netlbl_calipso_add_pass() efivarfs: force RO when remounting if SetVariable is not supported spi: sh-msiof: Enforce fixed DTDL for R-Car H3 ACPI: extlog: Clear Extended Error Log status when RAS_CEC handled the error mtd: Fix gluebi NULL pointer dereference caused by ftl notifier selinux: Fix error priority for bind with AF_UNSPEC on PF_INET6 socket virtio_crypto: Introduce VIRTIO_CRYPTO_NOSPC virtio-crypto: introduce akcipher service virtio-crypto: implement RSA algorithm virtio-crypto: change code style virtio-crypto: use private buffer for control request virtio-crypto: wait ctrl queue instead of busy polling crypto: virtio - Handle dataq logic with tasklet crypto: sa2ul - Return crypto_aead_setkey to transfer the error crypto: ccp - fix memleak in ccp_init_dm_workarea crypto: af_alg - Disallow multiple in-flight AIO requests crypto: sahara - remove FLAGS_NEW_KEY logic crypto: sahara - fix cbc selftest failure crypto: sahara - fix ahash selftest failure crypto: sahara - fix processing requests with cryptlen < sg->length crypto: sahara - fix error handling in sahara_hw_descriptor_create() pstore: ram_core: fix possible overflow in persistent_ram_init_ecc() fs: indicate request originates from old mount API Revert "gfs2: Don't reject a supposedly full bitmap if we have blocks reserved" gfs2: Also reflect single-block allocations in rgd->rd_extfail_pt gfs2: Fix kernel NULL pointer dereference in gfs2_rgrp_dump crypto: virtio - Wait for tasklet to complete on device remove crypto: sahara - avoid skcipher fallback code duplication crypto: sahara - handle zero-length aes requests crypto: sahara - fix ahash reqsize crypto: sahara - fix wait_for_completion_timeout() error handling crypto: sahara - improve error handling in sahara_sha_process() crypto: sahara - fix processing hash requests with req->nbytes < sg->length crypto: sahara - do not resize req->src when doing hash operations crypto: scomp - fix req->dst buffer overflow blocklayoutdriver: Fix reference leak of pnfs_device_node NFSv4.1/pnfs: Ensure we handle the error NFS4ERR_RETURNCONFLICT wifi: rtw88: fix RX filter in FIF_ALLMULTI flag bpf, lpm: Fix check prefixlen before walking trie bpf: Add crosstask check to __bpf_get_stack wifi: ath11k: Defer on rproc_get failure wifi: libertas: stop selecting wext ARM: dts: qcom: apq8064: correct XOADC register address ncsi: internal.h: Fix a spello net/ncsi: Fix netlink major/minor version numbers firmware: ti_sci: Fix an off-by-one in ti_sci_debugfs_create() firmware: meson_sm: populate platform devices from sm device tree data wifi: rtlwifi: rtl8821ae: phy: fix an undefined bitwise shift behavior arm64: dts: ti: k3-am65-main: Fix DSS irq trigger type bpf: fix check for attempt to corrupt spilled pointer scsi: fnic: Return error if vmalloc() failed arm64: dts: qcom: qrb5165-rb5: correct LED panic indicator arm64: dts: qcom: sdm845-db845c: correct LED panic indicator bpf: Fix verification of indirect var-off stack access scsi: hisi_sas: Replace with standard error code return value selftests/net: fix grep checking for fib_nexthop_multiprefix virtio/vsock: fix logic which reduces credit update messages dma-mapping: Add dma_release_coherent_memory to DMA API dma-mapping: clear dev->dma_mem to NULL after freeing it wifi: rtlwifi: add calculate_bit_shift() wifi: rtlwifi: rtl8188ee: phy: using calculate_bit_shift() wifi: rtlwifi: rtl8192c: using calculate_bit_shift() wifi: rtlwifi: rtl8192cu: using calculate_bit_shift() wifi: rtlwifi: rtl8192ce: using calculate_bit_shift() rtlwifi: rtl8192de: make arrays static const, makes object smaller wifi: rtlwifi: rtl8192de: using calculate_bit_shift() wifi: rtlwifi: rtl8192ee: using calculate_bit_shift() wifi: rtlwifi: rtl8192se: using calculate_bit_shift() netfilter: nf_tables: mark newset as dead on transaction abort Bluetooth: Fix bogus check for re-auth no supported with non-ssp Bluetooth: btmtkuart: fix recv_buf() return value ip6_tunnel: fix NEXTHDR_FRAGMENT handling in ip6_tnl_parse_tlv_enc_lim() ARM: davinci: always select CONFIG_CPU_ARM926T RDMA/usnic: Silence uninitialized symbol smatch warnings drm/panel-elida-kd35t133: hold panel in reset for unprepare rcu: Create an unrcu_pointer() to remove __rcu from a pointer drm/nouveau/fence:: fix warning directly dereferencing a rcu pointer drm/bridge: tpd12s015: Drop buggy __exit annotation for remove function media: pvrusb2: fix use after free on context disconnection drm/bridge: Fix typo in post_disable() description f2fs: fix to avoid dirent corruption drm/radeon/r600_cs: Fix possible int overflows in r600_cs_check_reg() drm/radeon/r100: Fix integer overflow issues in r100_cs_track_check() drm/radeon: check return value of radeon_ring_lock() ASoC: cs35l33: Fix GPIO name and drop legacy include ASoC: cs35l34: Fix GPIO name and drop legacy include drm/msm/mdp4: flush vblank event on disable drm/msm/dsi: Use pm_runtime_resume_and_get to prevent refcnt leaks drm/drv: propagate errors from drm_modeset_register_all() drm/radeon: check the alloc_workqueue return value in radeon_crtc_init() drm/radeon/dpm: fix a memleak in sumo_parse_power_table drm/radeon/trinity_dpm: fix a memleak in trinity_parse_power_table drm/bridge: tc358767: Fix return value on error case media: cx231xx: fix a memleak in cx231xx_init_isoc clk: qcom: gpucc-sm8150: Update the gpu_cc_pll1 config media: rkisp1: Disable runtime PM in probe error path f2fs: fix to check compress file in f2fs_move_file_range() f2fs: fix to update iostat correctly in f2fs_filemap_fault() media: dvbdev: drop refcount on error path in dvb_device_open() media: dvb-frontends: m88ds3103: Fix a memory leak in an error handling path of m88ds3103_probe() drm/amdgpu/debugfs: fix error code when smc register accessors are NULL drm/amd/pm: fix a double-free in si_dpm_init drivers/amd/pm: fix a use-after-free in kv_parse_power_table gpu/drm/radeon: fix two memleaks in radeon_vm_init dt-bindings: clock: Update the videocc resets for sm8150 clk: qcom: videocc-sm8150: Update the videocc resets clk: qcom: videocc-sm8150: Add missing PLL config property drivers: clk: zynqmp: calculate closest mux rate clk: zynqmp: make bestdiv unsigned clk: zynqmp: Add a check for NULL pointer drivers: clk: zynqmp: update divider round rate logic watchdog: set cdev owner before adding watchdog/hpwdt: Only claim UNKNOWN NMI if from iLO watchdog: bcm2835_wdt: Fix WDIOC_SETTIMEOUT handling watchdog: rti_wdt: Drop runtime pm reference count when watchdog is unused clk: si5341: fix an error code problem in si5341_output_clk_set_rate clk: fixed-rate: add devm_clk_hw_register_fixed_rate clk: fixed-rate: fix clk_hw_register_fixed_rate_with_accuracy_parent_hw pwm: stm32: Use regmap_clear_bits and regmap_set_bits where applicable pwm: stm32: Use hweight32 in stm32_pwm_detect_channels pwm: stm32: Fix enable count for clk in .probe() mmc: sdhci_am654: Fix TI SoC dependencies mmc: sdhci_omap: Fix TI SoC dependencies IB/iser: Prevent invalidating wrong MR of: Fix double free in of_parse_phandle_with_args_map of: unittest: Fix of_count_phandle_with_args() expected value message keys, dns: Fix size check of V1 server-list header binder: fix async space check for 0-sized buffers binder: fix unused alloc->free_async_space binder: fix use-after-free in shinker's callback Input: atkbd - use ab83 as id when skipping the getid command dma-mapping: Fix build error unused-value virtio-crypto: fix memory-leak virtio-crypto: fix memory leak in virtio_crypto_alg_skcipher_close_session() Revert "ASoC: atmel: Remove system clock tree configuration for at91sam9g20ek" kprobes: Fix to handle forcibly unoptimized kprobes on freeing_list net: ethernet: mtk_eth_soc: remove duplicate if statements xen-netback: don't produce zero-size SKB frags binder: fix race between mmput() and do_exit() tick-sched: Fix idle and iowait sleeptime accounting vs CPU hotplug usb: phy: mxs: remove CONFIG_USB_OTG condition for mxs_phy_is_otg_host() usb: dwc: ep0: Update request status in dwc3_ep0_stall_restart Revert "usb: dwc3: Soft reset phy on probe for host" Revert "usb: dwc3: don't reset device side if dwc3 was configured as host-only" usb: chipidea: wait controller resume finished for wakeup irq Revert "usb: typec: class: fix typec_altmode_put_partner to put plugs" usb: typec: class: fix typec_altmode_put_partner to put plugs usb: mon: Fix atomicity violation in mon_bin_vma_fault serial: imx: Ensure that imx_uart_rs485_config() is called with enabled clock ALSA: oxygen: Fix right channel of capture volume mixer ALSA: hda/relatek: Enable Mute LED on HP Laptop 15s-fq2xxx fbdev: flush deferred work in fb_deferred_io_fsync() pwm: jz4740: Don't use dev_err_probe() in .request() io_uring/rw: ensure io->bytes_done is always initialized rootfs: Fix support for rootfstype= when root= is given Bluetooth: Fix atomicity violation in {min,max}_key_size_set iommu/arm-smmu-qcom: Add missing GMU entry to match table wifi: rtlwifi: Remove bogus and dangerous ASPM disable/enable code wifi: rtlwifi: Convert LNKCTL change to PCIe cap RMW accessors wifi: mwifiex: configure BSSID consistently when starting AP x86/kvm: Do not try to disable kvmclock if it was not enabled KVM: arm64: vgic-v4: Restore pending state on host userspace write KVM: arm64: vgic-its: Avoid potential UAF in LPI translation cache iio: adc: ad7091r: Pass iio_dev to event handler HID: wacom: Correct behavior when processing some confidence == false touches mfd: syscon: Fix null pointer dereference in of_syscon_register() leds: aw2013: Select missing dependency REGMAP_I2C mips: dmi: Fix early remap on MIPS32 mips: Fix incorrect max_low_pfn adjustment MIPS: Alchemy: Fix an out-of-bound access in db1200_dev_setup() MIPS: Alchemy: Fix an out-of-bound access in db1550_dev_setup() power: supply: cw2015: correct time_to_empty units in sysfs serial: 8250: omap: Don't skip resource freeing if pm_runtime_resume_and_get() failed libapi: Add missing linux/types.h header to get the __u64 type on io.h acpi: property: Let args be NULL in __acpi_node_get_property_reference software node: Let args be NULL in software_node_get_reference_args serial: imx: fix tx statemachine deadlock iio: adc: ad9467: Benefit from devm_clk_get_enabled() to simplify iio: adc: ad9467: fix reset gpio handling iio: adc: ad9467: don't ignore error codes iio: adc: ad9467: fix scale setting perf genelf: Set ELF program header addresses properly tty: change tty_write_lock()'s ndelay parameter to bool tty: early return from send_break() on TTY_DRIVER_HARDWARE_BREAK tty: don't check for signal_pending() in send_break() tty: use 'if' in send_break() instead of 'goto' usb: cdc-acm: return correct error code on unsupported break nvmet-tcp: Fix a kernel panic when host sends an invalid H2C PDU length nvmet-tcp: fix a crash in nvmet_req_complete() perf env: Avoid recursively taking env->bpf_progs.lock apparmor: avoid crash when parsed profile name is empty serial: imx: Correct clock error message in function probe() nvmet-tcp: Fix the H2C expected PDU len calculation PCI: keystone: Fix race condition when initializing PHYs s390/pci: fix max size calculation in zpci_memcpy_toio() net: qualcomm: rmnet: fix global oob in rmnet_policy net: ethernet: ti: am65-cpsw: Fix max mtu to fit ethernet frames net: phy: micrel: populate .soft_reset for KSZ9131 net: ravb: Fix dma_addr_t truncation in error case net: dsa: vsc73xx: Add null pointer check to vsc73xx_gpio_probe netfilter: nf_tables: do not allow mismatch field size and set key length netfilter: nf_tables: skip dead set elements in netlink dump netfilter: nf_tables: reject NFT_SET_CONCAT with not field length description ipvs: avoid stat macros calls from preemptible context kdb: Fix a potential buffer overflow in kdb_local() ethtool: netlink: Add missing ethnl_ops_begin/complete mlxsw: spectrum_acl_erp: Fix error flow of pool allocation failure mlxsw: spectrum: Use 'bitmap_zalloc()' when applicable mlxsw: spectrum_acl_tcam: Add missing mutex_destroy() mlxsw: spectrum_acl_tcam: Make fini symmetric to init mlxsw: spectrum_acl_tcam: Reorder functions to avoid forward declarations mlxsw: spectrum_acl_tcam: Fix stack corruption selftests: mlxsw: qos_pfc: Convert to iproute2 dcb selftests: mlxsw: qos_pfc: Adjust the test to support 8 lanes i2c: s3c24xx: fix read transfers in polling mode i2c: s3c24xx: fix transferring more than one message in polling mode arm64: dts: armada-3720-turris-mox: set irq type for RTC Linux 5.10.209 Change-Id: I86438e299a811ccb08c5a27b2259c33cd482ff00 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
285 lines
6.7 KiB
C
285 lines
6.7 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* System Control and Power Interface (SCMI) based CPUFreq Interface driver
|
|
*
|
|
* Copyright (C) 2018 ARM Ltd.
|
|
* Sudeep Holla <sudeep.holla@arm.com>
|
|
*/
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
#include <linux/clk-provider.h>
|
|
#include <linux/cpu.h>
|
|
#include <linux/cpufreq.h>
|
|
#include <linux/cpumask.h>
|
|
#include <linux/energy_model.h>
|
|
#include <linux/export.h>
|
|
#include <linux/module.h>
|
|
#include <linux/pm_opp.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/scmi_protocol.h>
|
|
#include <linux/types.h>
|
|
|
|
struct scmi_data {
|
|
int domain_id;
|
|
struct device *cpu_dev;
|
|
};
|
|
|
|
static struct scmi_protocol_handle *ph;
|
|
static const struct scmi_perf_proto_ops *perf_ops;
|
|
|
|
static unsigned int scmi_cpufreq_get_rate(unsigned int cpu)
|
|
{
|
|
struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
|
|
struct scmi_data *priv = policy->driver_data;
|
|
unsigned long rate;
|
|
int ret;
|
|
|
|
ret = perf_ops->freq_get(ph, priv->domain_id, &rate, false);
|
|
if (ret)
|
|
return 0;
|
|
return rate / 1000;
|
|
}
|
|
|
|
/*
|
|
* perf_ops->freq_set is not a synchronous, the actual OPP change will
|
|
* happen asynchronously and can get notified if the events are
|
|
* subscribed for by the SCMI firmware
|
|
*/
|
|
static int
|
|
scmi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index)
|
|
{
|
|
struct scmi_data *priv = policy->driver_data;
|
|
u64 freq = policy->freq_table[index].frequency;
|
|
|
|
return perf_ops->freq_set(ph, priv->domain_id, freq * 1000, false);
|
|
}
|
|
|
|
static unsigned int scmi_cpufreq_fast_switch(struct cpufreq_policy *policy,
|
|
unsigned int target_freq)
|
|
{
|
|
struct scmi_data *priv = policy->driver_data;
|
|
|
|
if (!perf_ops->freq_set(ph, priv->domain_id,
|
|
target_freq * 1000, true))
|
|
return target_freq;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
scmi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
|
|
{
|
|
int cpu, domain, tdomain;
|
|
struct device *tcpu_dev;
|
|
|
|
domain = perf_ops->device_domain_id(cpu_dev);
|
|
if (domain < 0)
|
|
return domain;
|
|
|
|
for_each_possible_cpu(cpu) {
|
|
if (cpu == cpu_dev->id)
|
|
continue;
|
|
|
|
tcpu_dev = get_cpu_device(cpu);
|
|
if (!tcpu_dev)
|
|
continue;
|
|
|
|
tdomain = perf_ops->device_domain_id(tcpu_dev);
|
|
if (tdomain == domain)
|
|
cpumask_set_cpu(cpu, cpumask);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __maybe_unused
|
|
scmi_get_cpu_power(unsigned long *power, unsigned long *KHz,
|
|
struct device *cpu_dev)
|
|
{
|
|
unsigned long Hz;
|
|
int ret, domain;
|
|
|
|
domain = perf_ops->device_domain_id(cpu_dev);
|
|
if (domain < 0)
|
|
return domain;
|
|
|
|
/* Get the power cost of the performance domain. */
|
|
Hz = *KHz * 1000;
|
|
ret = perf_ops->est_power_get(ph, domain, &Hz, power);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* The EM framework specifies the frequency in KHz. */
|
|
*KHz = Hz / 1000;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int scmi_cpufreq_init(struct cpufreq_policy *policy)
|
|
{
|
|
int ret, nr_opp;
|
|
unsigned int latency;
|
|
struct device *cpu_dev;
|
|
struct scmi_data *priv;
|
|
struct cpufreq_frequency_table *freq_table;
|
|
struct em_data_callback em_cb = EM_DATA_CB(scmi_get_cpu_power);
|
|
bool power_scale_mw;
|
|
|
|
cpu_dev = get_cpu_device(policy->cpu);
|
|
if (!cpu_dev) {
|
|
pr_err("failed to get cpu%d device\n", policy->cpu);
|
|
return -ENODEV;
|
|
}
|
|
|
|
ret = perf_ops->device_opps_add(ph, cpu_dev);
|
|
if (ret) {
|
|
dev_warn(cpu_dev, "failed to add opps to the device\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = scmi_get_sharing_cpus(cpu_dev, policy->cpus);
|
|
if (ret) {
|
|
dev_warn(cpu_dev, "failed to get sharing cpumask\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus);
|
|
if (ret) {
|
|
dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n",
|
|
__func__, ret);
|
|
return ret;
|
|
}
|
|
|
|
nr_opp = dev_pm_opp_get_opp_count(cpu_dev);
|
|
if (nr_opp <= 0) {
|
|
dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n");
|
|
ret = -EPROBE_DEFER;
|
|
goto out_free_opp;
|
|
}
|
|
|
|
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
|
if (!priv) {
|
|
ret = -ENOMEM;
|
|
goto out_free_opp;
|
|
}
|
|
|
|
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
|
|
if (ret) {
|
|
dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
|
|
goto out_free_priv;
|
|
}
|
|
|
|
priv->cpu_dev = cpu_dev;
|
|
priv->domain_id = perf_ops->device_domain_id(cpu_dev);
|
|
|
|
policy->driver_data = priv;
|
|
policy->freq_table = freq_table;
|
|
|
|
/* SCMI allows DVFS request for any domain from any CPU */
|
|
policy->dvfs_possible_from_any_cpu = true;
|
|
|
|
latency = perf_ops->transition_latency_get(ph, cpu_dev);
|
|
if (!latency)
|
|
latency = CPUFREQ_ETERNAL;
|
|
|
|
policy->cpuinfo.transition_latency = latency;
|
|
|
|
policy->fast_switch_possible =
|
|
perf_ops->fast_switch_possible(ph, cpu_dev);
|
|
|
|
power_scale_mw = perf_ops->power_scale_mw_get(ph);
|
|
em_dev_register_perf_domain(cpu_dev, nr_opp, &em_cb, policy->cpus,
|
|
power_scale_mw);
|
|
|
|
return 0;
|
|
|
|
out_free_priv:
|
|
kfree(priv);
|
|
out_free_opp:
|
|
dev_pm_opp_remove_all_dynamic(cpu_dev);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int scmi_cpufreq_exit(struct cpufreq_policy *policy)
|
|
{
|
|
struct scmi_data *priv = policy->driver_data;
|
|
|
|
dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
|
|
dev_pm_opp_remove_all_dynamic(priv->cpu_dev);
|
|
kfree(priv);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct cpufreq_driver scmi_cpufreq_driver = {
|
|
.name = "scmi",
|
|
.flags = CPUFREQ_STICKY | CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
|
|
CPUFREQ_NEED_INITIAL_FREQ_CHECK |
|
|
CPUFREQ_IS_COOLING_DEV,
|
|
.verify = cpufreq_generic_frequency_table_verify,
|
|
.attr = cpufreq_generic_attr,
|
|
.target_index = scmi_cpufreq_set_target,
|
|
.fast_switch = scmi_cpufreq_fast_switch,
|
|
.get = scmi_cpufreq_get_rate,
|
|
.init = scmi_cpufreq_init,
|
|
.exit = scmi_cpufreq_exit,
|
|
};
|
|
|
|
static int scmi_cpufreq_probe(struct scmi_device *sdev)
|
|
{
|
|
int ret;
|
|
struct device *dev = &sdev->dev;
|
|
const struct scmi_handle *handle;
|
|
|
|
handle = sdev->handle;
|
|
|
|
if (!handle)
|
|
return -ENODEV;
|
|
|
|
perf_ops = handle->devm_get_protocol(sdev, SCMI_PROTOCOL_PERF, &ph);
|
|
if (IS_ERR(perf_ops))
|
|
return PTR_ERR(perf_ops);
|
|
|
|
#ifdef CONFIG_COMMON_CLK
|
|
/* dummy clock provider as needed by OPP if clocks property is used */
|
|
if (of_property_present(dev->of_node, "#clock-cells")) {
|
|
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, NULL);
|
|
if (ret)
|
|
return dev_err_probe(dev, ret, "%s: registering clock provider failed\n", __func__);
|
|
}
|
|
#endif
|
|
|
|
ret = cpufreq_register_driver(&scmi_cpufreq_driver);
|
|
if (ret) {
|
|
dev_err(dev, "%s: registering cpufreq failed, err: %d\n",
|
|
__func__, ret);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void scmi_cpufreq_remove(struct scmi_device *sdev)
|
|
{
|
|
cpufreq_unregister_driver(&scmi_cpufreq_driver);
|
|
}
|
|
|
|
static const struct scmi_device_id scmi_id_table[] = {
|
|
{ SCMI_PROTOCOL_PERF, "cpufreq" },
|
|
{ },
|
|
};
|
|
MODULE_DEVICE_TABLE(scmi, scmi_id_table);
|
|
|
|
static struct scmi_driver scmi_cpufreq_drv = {
|
|
.name = "scmi-cpufreq",
|
|
.probe = scmi_cpufreq_probe,
|
|
.remove = scmi_cpufreq_remove,
|
|
.id_table = scmi_id_table,
|
|
};
|
|
module_scmi_driver(scmi_cpufreq_drv);
|
|
|
|
MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
|
|
MODULE_DESCRIPTION("ARM SCMI CPUFreq interface driver");
|
|
MODULE_LICENSE("GPL v2");
|