71c433299b
https://source.android.com/security/bulletin/2021-09-01 CVE-2021-0695 * tag 'ASB-2021-09-05_4.19-stable' of https://github.com/aosp-mirror/kernel_common: Linux 4.19.206 net: don't unconditionally copy_from_user a struct ifreq for socket ioctls Revert "floppy: reintroduce O_NDELAY fix" KVM: x86/mmu: Treat NX as used (not reserved) for all !TDP shadow MMUs fbmem: add margin check to fb_check_caps() vt_kdsetmode: extend console locking net/rds: dma_map_sg is entitled to merge entries drm/nouveau/disp: power down unused DP links during init drm: Copy drm_wait_vblank to user before returning qed: Fix null-pointer dereference in qed_rdma_create_qp() qed: qed ll2 race condition fixes vringh: Use wiov->used to check for read/write desc order virtio_pci: Support surprise removal of virtio pci device virtio: Improve vq->broken access to avoid any compiler optimization opp: remove WARN when no valid OPPs remain usb: gadget: u_audio: fix race condition on endpoint stop net: hns3: fix get wrong pfc_en when query PFC configuration net: marvell: fix MVNETA_TX_IN_PRGRS bit number xgene-v2: Fix a resource leak in the error handling path of 'xge_probe()' ip_gre: add validation for csum_start e1000e: Fix the max snoop/no-snoop latency for 10M IB/hfi1: Fix possible null-pointer dereference in _extend_sdma_tx_descs() usb: dwc3: gadget: Stop EP0 transfers during pullup disable usb: dwc3: gadget: Fix dwc3_calc_trbs_left() USB: serial: option: add new VID/PID to support Fibocom FG150 Revert "USB: serial: ch341: fix character loss at high transfer rates" can: usb: esd_usb2: esd_usb2_rx_event(): fix the interchange of the CAN RX and TX error counters once: Fix panic when module unload netfilter: conntrack: collect all entries in one cycle ARC: Fix CONFIG_STACKDEPOT bpf: Fix truncation handling for mod32 dst reg wrt zero bpf: Fix 32 bit src register truncation on div/mod bpf: Do not use ax register in interpreter on div/mod net: qrtr: fix another OOB Read in qrtr_endpoint_post Revert "net: igmp: fix data-race in igmp_ifc_timer_expire()" Revert "net: igmp: increase size of mr_ifc_count" Revert "PCI/MSI: Protect msi_desc::masked for multi-MSI" ANDROID: update ABI representation Linux 4.19.205 netfilter: nft_exthdr: fix endianness of tcp option cast fs: warn about impending deprecation of mandatory locks locks: print a warning when mount fails due to lack of "mand" support ASoC: intel: atom: Fix breakage for PCM buffer address setup PCI: Increase D3 delay for AMD Renoir/Cezanne XHCI btrfs: prevent rename2 from exchanging a subvol with a directory from different parents ipack: tpci200: fix memory leak in the tpci200_register ipack: tpci200: fix many double free issues in tpci200_pci_probe slimbus: ngd: reset dma setup during runtime pm slimbus: messaging: check for valid transaction id slimbus: messaging: start transaction ids from 1 instead of zero tracing / histogram: Fix NULL pointer dereference on strcmp() on NULL event name ALSA: hda - fix the 'Capture Switch' value change notifications mmc: dw_mmc: Fix hang on data CRC error net: mdio-mux: Handle -EPROBE_DEFER correctly net: mdio-mux: Don't ignore memory allocation errors net: qlcnic: add missed unlock in qlcnic_83xx_flash_read32 ptp_pch: Restore dependency on PCI net: 6pack: fix slab-out-of-bounds in decode_data bnxt: disable napi before canceling DIM bnxt: don't lock the tx queue from napi poll vhost: Fix the calculation in vhost_overflow() dccp: add do-while-0 stubs for dccp_pr_debug macros cpufreq: armada-37xx: forbid cpufreq for 1.2 GHz variant Bluetooth: hidp: use correct wait queue when removing ctrl_wait net: usb: lan78xx: don't modify phy_device state concurrently ARM: dts: nomadik: Fix up interrupt controller node names scsi: core: Avoid printing an error if target_alloc() returns -ENXIO scsi: scsi_dh_rdac: Avoid crash during rdac_bus_attach() scsi: megaraid_mm: Fix end of loop tests for list_for_each_entry() dmaengine: of-dma: router_xlate to return -EPROBE_DEFER if controller is not yet available ARM: dts: am43x-epos-evm: Reduce i2c0 bus speed for tps65218 dmaengine: usb-dmac: Fix PM reference leak in usb_dmac_probe() dmaengine: xilinx_dma: Fix read-after-free bug when terminating transfers ath9k: Postpone key cache entry deletion for TXQ frames reference it ath: Modify ath_key_delete() to not need full key entry ath: Export ath_hw_keysetmac() ath9k: Clear key cache explicitly on disabling hardware ath: Use safer key clearing with key cache entries x86/fpu: Make init_fpstate correct with optimized XSAVE KVM: nSVM: avoid picking up unsupported bits from L2 in int_ctl (CVE-2021-3653) KVM: nSVM: always intercept VMLOAD/VMSAVE when nested (CVE-2021-3656) mac80211: drop data frames without key on encrypted links iommu/vt-d: Fix agaw for a supported 48 bit guest address width vmlinux.lds.h: Handle clang's module.{c,d}tor sections PCI/MSI: Enforce MSI[X] entry updates to be visible PCI/MSI: Enforce that MSI-X table entry is masked for update PCI/MSI: Mask all unused MSI-X entries PCI/MSI: Protect msi_desc::masked for multi-MSI PCI/MSI: Use msi_mask_irq() in pci_msi_shutdown() PCI/MSI: Correct misleading comments PCI/MSI: Do not set invalid bits in MSI mask PCI/MSI: Enable and mask MSI-X early genirq/msi: Ensure deactivation on teardown x86/resctrl: Fix default monitoring groups reporting x86/ioapic: Force affinity setup before startup x86/msi: Force affinity setup before startup genirq: Provide IRQCHIP_AFFINITY_PRE_STARTUP x86/tools: Fix objdump version check again powerpc/kprobes: Fix kprobe Oops happens in booke vsock/virtio: avoid potential deadlock when vsock device remove xen/events: Fix race in set_evtchn_to_irq net: igmp: increase size of mr_ifc_count tcp_bbr: fix u32 wrap bug in round logic if bbr_init() called after 2B packets net: bridge: fix memleak in br_add_if() net: dsa: lan9303: fix broken backpressure in .port_fdb_dump net: igmp: fix data-race in igmp_ifc_timer_expire() net: Fix memory leak in ieee802154_raw_deliver psample: Add a fwd declaration for skbuff ppp: Fix generating ifname when empty IFLA_IFNAME is specified net: dsa: mt7530: add the missing RxUnicast MIB counter ASoC: cs42l42: Fix LRCLK frame start edge ASoC: cs42l42: Remove duplicate control for WNF filter frequency ASoC: cs42l42: Fix inversion of ADC Notch Switch control ASoC: cs42l42: Don't allow SND_SOC_DAIFMT_LEFT_J ASoC: cs42l42: Correct definition of ADC Volume control ieee802154: hwsim: fix GPF in hwsim_new_edge_nl ieee802154: hwsim: fix GPF in hwsim_set_edge_lqi ACPI: NFIT: Fix support for virtual SPA ranges i2c: dev: zero out array used for i2c reads from userspace ASoC: intel: atom: Fix reference to PCM buffer address iio: adc: Fix incorrect exit of for-loop iio: humidity: hdc100x: Add margin to the conversion time ANDROID: xt_quota2: set usersize in xt_match registration object ANDROID: xt_quota2: clear quota2_log message before sending ANDROID: xt_quota2: remove trailing junk which might have a digit in it Linux 4.19.204 net: xilinx_emaclite: Do not print real IOMEM pointer ovl: prevent private clone if bind mount is not allowed ppp: Fix generating ppp unit id when ifname is not specified USB:ehci:fix Kunpeng920 ehci hardware problem KVM: X86: MMU: Use the correct inherited permissions to get shadow page bpf, selftests: Adjust few selftest outcomes wrt unreachable code bpf: Fix leakage under speculation on mispredicted branches bpf: Do not mark insn as seen under speculative path verification bpf: Inherit expanded/patched seen count from old aux data tracing: Reject string operand in the histogram expression KVM: SVM: Fix off-by-one indexing when nullifying last used SEV VMCB Linux 4.19.203 ARM: imx: add mmdc ipg clock operation for mmdc net/qla3xxx: fix schedule while atomic in ql_wait_for_drvr_lock and ql_adapter_reset alpha: Send stop IPI to send to online CPUs reiserfs: check directory items on read from disk reiserfs: add check for root_inode in reiserfs_fill_super libata: fix ata_pio_sector for CONFIG_HIGHMEM qmi_wwan: add network device usage statistics for qmimux devices perf/x86/amd: Don't touch the AMD64_EVENTSEL_HOSTONLY bit inside the guest spi: meson-spicc: fix memory leak in meson_spicc_remove KVM: x86/mmu: Fix per-cpu counter corruption on 32-bit builds KVM: x86: accept userspace interrupt only if no event is injected pcmcia: i82092: fix a null pointer dereference bug MIPS: Malta: Do not byte-swap accesses to the CBUS UART serial: 8250: Mask out floating 16/32-bit bus bits ext4: fix potential htree corruption when growing large_dir directories pipe: increase minimum default pipe size to 2 pages media: rtl28xxu: fix zero-length control request staging: rtl8723bs: Fix a resource leak in sd_int_dpc optee: Clear stale cache entries during initialization tracing/histogram: Rename "cpu" to "common_cpu" tracing / histogram: Give calculation hist_fields a size scripts/tracing: fix the bug that can't parse raw_trace_func usb: otg-fsm: Fix hrtimer list corruption usb: gadget: f_hid: idle uses the highest byte for duration usb: gadget: f_hid: fixed NULL pointer dereference usb: gadget: f_hid: added GET_IDLE and SET_IDLE handlers ALSA: usb-audio: Add registration quirk for JBL Quantum 600 firmware_loader: fix use-after-free in firmware_fallback_sysfs firmware_loader: use -ETIMEDOUT instead of -EAGAIN in fw_load_sysfs_fallback USB: serial: ftdi_sio: add device ID for Auto-M3 OP-COM v2 USB: serial: ch341: fix character loss at high transfer rates USB: serial: option: add Telit FD980 composition 0x1056 USB: usbtmc: Fix RCU stall warning Bluetooth: defer cleanup of resources in hci_unregister_dev() blk-iolatency: error out if blk_get_queue() failed in iolatency_set_limit() net: vxge: fix use-after-free in vxge_device_unregister net: fec: fix use-after-free in fec_drv_remove net: pegasus: fix uninit-value in get_interrupt_interval bnx2x: fix an error code in bnx2x_nic_load() mips: Fix non-POSIX regexp net: ipv6: fix returned variable type in ip6_skb_dst_mtu nfp: update ethtool reporting of pauseframe control sctp: move the active_key update after sh_keys is added net: natsemi: Fix missing pci_disable_device() in probe and remove media: videobuf2-core: dequeue if start_streaming fails scsi: sr: Return correct event when media event code is 3 omap5-board-common: remove not physically existing vdds_1v8_main fixed-regulator clk: stm32f4: fix post divisor setup for I2S/SAI PLLs ALSA: usb-audio: fix incorrect clock source setting ARM: dts: colibri-imx6ull: limit SDIO clock to 25MHz ARM: imx: add missing iounmap() ALSA: seq: Fix racy deletion of subscriber Revert "ACPICA: Fix memory leak caused by _CID repair function" Revert "bdi: add a ->dev_name field to struct backing_dev_info" Revert "padata: validate cpumask without removed CPU during offline" Revert "padata: add separate cpuhp node for CPUHP_PADATA_DEAD" Linux 4.19.202 spi: mediatek: Fix fifo transfer padata: add separate cpuhp node for CPUHP_PADATA_DEAD padata: validate cpumask without removed CPU during offline Revert "watchdog: iTCO_wdt: Account for rebooting on second timeout" firmware: arm_scmi: Ensure drivers provide a probe function drm/i915: Ensure intel_engine_init_execlist() builds with Clang Revert "Bluetooth: Shutdown controller after workqueues are flushed or cancelled" bdi: add a ->dev_name field to struct backing_dev_info bdi: use bdi_dev_name() to get device name bdi: move bdi_dev_name out of line net: Fix zero-copy head len calculation. qed: fix possible unpaired spin_{un}lock_bh in _qed_mcp_cmd_and_union() r8152: Fix potential PM refcount imbalance ASoC: tlv320aic31xx: fix reversed bclk/wclk master bits regulator: rt5033: Fix n_voltages settings for BUCK and LDO btrfs: mark compressed range uptodate only if all bio succeed Linux 4.19.201 i40e: Add additional info to PHY type error Revert "perf map: Fix dso->nsinfo refcounting" powerpc/pseries: Fix regression while building external modules can: hi311x: fix a signedness bug in hi3110_cmd() sis900: Fix missing pci_disable_device() in probe and remove tulip: windbond-840: Fix missing pci_disable_device() in probe and remove sctp: fix return value check in __sctp_rcv_asconf_lookup net/mlx5: Fix flow table chaining net: llc: fix skb_over_panic mlx4: Fix missing error code in mlx4_load_one() tipc: fix sleeping in tipc accept routine i40e: Fix log TC creation failure when max num of queues is exceeded i40e: Fix logic of disabling queues netfilter: nft_nat: allow to specify layer 4 protocol NAT only netfilter: conntrack: adjust stop timestamp to real expiry value cfg80211: Fix possible memory leak in function cfg80211_bss_update nfc: nfcsim: fix use after free during module unload NIU: fix incorrect error return, missed in previous revert can: esd_usb2: fix memory leak can: ems_usb: fix memory leak can: usb_8dev: fix memory leak can: mcba_usb_start(): add missing urb->transfer_dma initialization can: raw: raw_setsockopt(): fix raw_rcv panic for sock UAF ocfs2: issue zeroout to EOF blocks ocfs2: fix zero out valid data x86/kvm: fix vcpu-id indexed array sizes btrfs: fix rw device counting in __btrfs_free_extra_devids x86/asm: Ensure asm/proto.h can be included stand-alone gro: ensure frag0 meets IP header alignment virtio_net: Do not pull payload in skb->head Change-Id: Ib9cbb4d2a34913231716321681a1b6c488a5dfe4 Signed-off-by: UtsavBalar1231 <utsavbalar1231@gmail.com> Conflicts: drivers/slimbus/messaging.c drivers/slimbus/qcom-ngd-ctrl.c drivers/usb/dwc3/gadget.c drivers/usb/gadget/function/f_hid.c net/qrtr/qrtr.c
887 lines
23 KiB
C
887 lines
23 KiB
C
/*
|
|
* Devices PM QoS constraints management
|
|
*
|
|
* Copyright (C) 2011 Texas Instruments, Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
*
|
|
* This module exposes the interface to kernel space for specifying
|
|
* per-device PM QoS dependencies. It provides infrastructure for registration
|
|
* of:
|
|
*
|
|
* Dependents on a QoS value : register requests
|
|
* Watchers of QoS value : get notified when target QoS value changes
|
|
*
|
|
* This QoS design is best effort based. Dependents register their QoS needs.
|
|
* Watchers register to keep track of the current QoS needs of the system.
|
|
* Watchers can register a per-device notification callback using the
|
|
* dev_pm_qos_*_notifier API. The notification chain data is stored in the
|
|
* per-device constraint data struct.
|
|
*
|
|
* Note about the per-device constraint data struct allocation:
|
|
* . The per-device constraints data struct ptr is tored into the device
|
|
* dev_pm_info.
|
|
* . To minimize the data usage by the per-device constraints, the data struct
|
|
* is only allocated at the first call to dev_pm_qos_add_request.
|
|
* . The data is later free'd when the device is removed from the system.
|
|
* . A global mutex protects the constraints users from the data being
|
|
* allocated and free'd.
|
|
*/
|
|
|
|
#include <linux/pm_qos.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/device.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/export.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/err.h>
|
|
#include <trace/events/power.h>
|
|
|
|
#include "power.h"
|
|
|
|
static DEFINE_MUTEX(dev_pm_qos_mtx);
|
|
static DEFINE_MUTEX(dev_pm_qos_sysfs_mtx);
|
|
|
|
/**
|
|
* __dev_pm_qos_flags - Check PM QoS flags for a given device.
|
|
* @dev: Device to check the PM QoS flags for.
|
|
* @mask: Flags to check against.
|
|
*
|
|
* This routine must be called with dev->power.lock held.
|
|
*/
|
|
enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask)
|
|
{
|
|
struct dev_pm_qos *qos = dev->power.qos;
|
|
struct pm_qos_flags *pqf;
|
|
s32 val;
|
|
|
|
lockdep_assert_held(&dev->power.lock);
|
|
|
|
if (IS_ERR_OR_NULL(qos))
|
|
return PM_QOS_FLAGS_UNDEFINED;
|
|
|
|
pqf = &qos->flags;
|
|
if (list_empty(&pqf->list))
|
|
return PM_QOS_FLAGS_UNDEFINED;
|
|
|
|
val = pqf->effective_flags & mask;
|
|
if (val)
|
|
return (val == mask) ? PM_QOS_FLAGS_ALL : PM_QOS_FLAGS_SOME;
|
|
|
|
return PM_QOS_FLAGS_NONE;
|
|
}
|
|
|
|
/**
|
|
* dev_pm_qos_flags - Check PM QoS flags for a given device (locked).
|
|
* @dev: Device to check the PM QoS flags for.
|
|
* @mask: Flags to check against.
|
|
*/
|
|
enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask)
|
|
{
|
|
unsigned long irqflags;
|
|
enum pm_qos_flags_status ret;
|
|
|
|
spin_lock_irqsave(&dev->power.lock, irqflags);
|
|
ret = __dev_pm_qos_flags(dev, mask);
|
|
spin_unlock_irqrestore(&dev->power.lock, irqflags);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(dev_pm_qos_flags);
|
|
|
|
/**
|
|
* __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
|
|
* @dev: Device to get the PM QoS constraint value for.
|
|
*
|
|
* This routine must be called with dev->power.lock held.
|
|
*/
|
|
s32 __dev_pm_qos_read_value(struct device *dev)
|
|
{
|
|
lockdep_assert_held(&dev->power.lock);
|
|
|
|
return dev_pm_qos_raw_read_value(dev);
|
|
}
|
|
|
|
/**
|
|
* dev_pm_qos_read_value - Get PM QoS constraint for a given device (locked).
|
|
* @dev: Device to get the PM QoS constraint value for.
|
|
*/
|
|
s32 dev_pm_qos_read_value(struct device *dev)
|
|
{
|
|
unsigned long flags;
|
|
s32 ret;
|
|
|
|
spin_lock_irqsave(&dev->power.lock, flags);
|
|
ret = __dev_pm_qos_read_value(dev);
|
|
spin_unlock_irqrestore(&dev->power.lock, flags);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* apply_constraint - Add/modify/remove device PM QoS request.
|
|
* @req: Constraint request to apply
|
|
* @action: Action to perform (add/update/remove).
|
|
* @value: Value to assign to the QoS request.
|
|
*
|
|
* Internal function to update the constraints list using the PM QoS core
|
|
* code and if needed call the per-device callbacks.
|
|
*/
|
|
static int apply_constraint(struct dev_pm_qos_request *req,
|
|
enum pm_qos_req_action action, s32 value)
|
|
{
|
|
struct dev_pm_qos *qos = req->dev->power.qos;
|
|
int ret;
|
|
|
|
switch(req->type) {
|
|
case DEV_PM_QOS_RESUME_LATENCY:
|
|
if (WARN_ON(action != PM_QOS_REMOVE_REQ && value < 0))
|
|
value = 0;
|
|
|
|
ret = pm_qos_update_target(&qos->resume_latency,
|
|
&req->data.pnode, action, value);
|
|
break;
|
|
case DEV_PM_QOS_LATENCY_TOLERANCE:
|
|
ret = pm_qos_update_target(&qos->latency_tolerance,
|
|
&req->data.pnode, action, value);
|
|
if (ret) {
|
|
value = pm_qos_read_value(&qos->latency_tolerance);
|
|
req->dev->power.set_latency_tolerance(req->dev, value);
|
|
}
|
|
break;
|
|
case DEV_PM_QOS_FLAGS:
|
|
ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
|
|
action, value);
|
|
break;
|
|
default:
|
|
ret = -EINVAL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* dev_pm_qos_constraints_allocate
|
|
* @dev: device to allocate data for
|
|
*
|
|
* Called at the first call to add_request, for constraint data allocation
|
|
* Must be called with the dev_pm_qos_mtx mutex held
|
|
*/
|
|
static int dev_pm_qos_constraints_allocate(struct device *dev)
|
|
{
|
|
struct dev_pm_qos *qos;
|
|
struct pm_qos_constraints *c;
|
|
struct blocking_notifier_head *n;
|
|
|
|
qos = kzalloc(sizeof(*qos), GFP_KERNEL);
|
|
if (!qos)
|
|
return -ENOMEM;
|
|
|
|
n = kzalloc(sizeof(*n), GFP_KERNEL);
|
|
if (!n) {
|
|
kfree(qos);
|
|
return -ENOMEM;
|
|
}
|
|
BLOCKING_INIT_NOTIFIER_HEAD(n);
|
|
|
|
c = &qos->resume_latency;
|
|
plist_head_init(&c->list);
|
|
c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
|
|
c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
|
|
c->no_constraint_value = PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
|
|
c->type = PM_QOS_MIN;
|
|
c->notifiers = n;
|
|
|
|
c = &qos->latency_tolerance;
|
|
plist_head_init(&c->list);
|
|
c->target_value = PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE;
|
|
c->default_value = PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE;
|
|
c->no_constraint_value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
|
|
c->type = PM_QOS_MIN;
|
|
|
|
INIT_LIST_HEAD(&qos->flags.list);
|
|
|
|
spin_lock_irq(&dev->power.lock);
|
|
dev->power.qos = qos;
|
|
spin_unlock_irq(&dev->power.lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void __dev_pm_qos_hide_latency_limit(struct device *dev);
|
|
static void __dev_pm_qos_hide_flags(struct device *dev);
|
|
|
|
/**
|
|
* dev_pm_qos_constraints_destroy
|
|
* @dev: target device
|
|
*
|
|
* Called from the device PM subsystem on device removal under device_pm_lock().
|
|
*/
|
|
void dev_pm_qos_constraints_destroy(struct device *dev)
|
|
{
|
|
struct dev_pm_qos *qos;
|
|
struct dev_pm_qos_request *req, *tmp;
|
|
struct pm_qos_constraints *c;
|
|
struct pm_qos_flags *f;
|
|
|
|
mutex_lock(&dev_pm_qos_sysfs_mtx);
|
|
|
|
/*
|
|
* If the device's PM QoS resume latency limit or PM QoS flags have been
|
|
* exposed to user space, they have to be hidden at this point.
|
|
*/
|
|
pm_qos_sysfs_remove_resume_latency(dev);
|
|
pm_qos_sysfs_remove_flags(dev);
|
|
|
|
mutex_lock(&dev_pm_qos_mtx);
|
|
|
|
__dev_pm_qos_hide_latency_limit(dev);
|
|
__dev_pm_qos_hide_flags(dev);
|
|
|
|
qos = dev->power.qos;
|
|
if (!qos)
|
|
goto out;
|
|
|
|
/* Flush the constraints lists for the device. */
|
|
c = &qos->resume_latency;
|
|
plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
|
|
/*
|
|
* Update constraints list and call the notification
|
|
* callbacks if needed
|
|
*/
|
|
apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
|
|
memset(req, 0, sizeof(*req));
|
|
}
|
|
c = &qos->latency_tolerance;
|
|
plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) {
|
|
apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
|
|
memset(req, 0, sizeof(*req));
|
|
}
|
|
f = &qos->flags;
|
|
list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) {
|
|
apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
|
|
memset(req, 0, sizeof(*req));
|
|
}
|
|
|
|
spin_lock_irq(&dev->power.lock);
|
|
dev->power.qos = ERR_PTR(-ENODEV);
|
|
spin_unlock_irq(&dev->power.lock);
|
|
|
|
kfree(qos->resume_latency.notifiers);
|
|
kfree(qos);
|
|
|
|
out:
|
|
mutex_unlock(&dev_pm_qos_mtx);
|
|
|
|
mutex_unlock(&dev_pm_qos_sysfs_mtx);
|
|
}
|
|
|
|
static bool dev_pm_qos_invalid_req_type(struct device *dev,
|
|
enum dev_pm_qos_req_type type)
|
|
{
|
|
return type == DEV_PM_QOS_LATENCY_TOLERANCE &&
|
|
!dev->power.set_latency_tolerance;
|
|
}
|
|
|
|
static int __dev_pm_qos_add_request(struct device *dev,
|
|
struct dev_pm_qos_request *req,
|
|
enum dev_pm_qos_req_type type, s32 value)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (!dev || !req || dev_pm_qos_invalid_req_type(dev, type))
|
|
return -EINVAL;
|
|
|
|
if (WARN(dev_pm_qos_request_active(req),
|
|
"%s() called for already added request\n", __func__))
|
|
return -EINVAL;
|
|
|
|
if (IS_ERR(dev->power.qos))
|
|
ret = -ENODEV;
|
|
else if (!dev->power.qos)
|
|
ret = dev_pm_qos_constraints_allocate(dev);
|
|
|
|
trace_dev_pm_qos_add_request(dev_name(dev), type, value);
|
|
if (!ret) {
|
|
req->dev = dev;
|
|
req->type = type;
|
|
ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* dev_pm_qos_add_request - inserts new qos request into the list
|
|
* @dev: target device for the constraint
|
|
* @req: pointer to a preallocated handle
|
|
* @type: type of the request
|
|
* @value: defines the qos request
|
|
*
|
|
* This function inserts a new entry in the device constraints list of
|
|
* requested qos performance characteristics. It recomputes the aggregate
|
|
* QoS expectations of parameters and initializes the dev_pm_qos_request
|
|
* handle. Caller needs to save this handle for later use in updates and
|
|
* removal.
|
|
*
|
|
* Returns 1 if the aggregated constraint value has changed,
|
|
* 0 if the aggregated constraint value has not changed,
|
|
* -EINVAL in case of wrong parameters, -ENOMEM if there's not enough memory
|
|
* to allocate for data structures, -ENODEV if the device has just been removed
|
|
* from the system.
|
|
*
|
|
* Callers should ensure that the target device is not RPM_SUSPENDED before
|
|
* using this function for requests of type DEV_PM_QOS_FLAGS.
|
|
*/
|
|
int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
|
|
enum dev_pm_qos_req_type type, s32 value)
|
|
{
|
|
int ret;
|
|
|
|
mutex_lock(&dev_pm_qos_mtx);
|
|
ret = __dev_pm_qos_add_request(dev, req, type, value);
|
|
mutex_unlock(&dev_pm_qos_mtx);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(dev_pm_qos_add_request);
|
|
|
|
/**
|
|
* __dev_pm_qos_update_request - Modify an existing device PM QoS request.
|
|
* @req : PM QoS request to modify.
|
|
* @new_value: New value to request.
|
|
*/
|
|
static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
|
|
s32 new_value)
|
|
{
|
|
s32 curr_value;
|
|
int ret = 0;
|
|
|
|
if (!req) /*guard against callers passing in null */
|
|
return -EINVAL;
|
|
|
|
if (WARN(!dev_pm_qos_request_active(req),
|
|
"%s() called for unknown object\n", __func__))
|
|
return -EINVAL;
|
|
|
|
if (IS_ERR_OR_NULL(req->dev->power.qos))
|
|
return -ENODEV;
|
|
|
|
switch(req->type) {
|
|
case DEV_PM_QOS_RESUME_LATENCY:
|
|
case DEV_PM_QOS_LATENCY_TOLERANCE:
|
|
curr_value = req->data.pnode.prio;
|
|
break;
|
|
case DEV_PM_QOS_FLAGS:
|
|
curr_value = req->data.flr.flags;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
trace_dev_pm_qos_update_request(dev_name(req->dev), req->type,
|
|
new_value);
|
|
if (curr_value != new_value)
|
|
ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* dev_pm_qos_update_request - modifies an existing qos request
|
|
* @req : handle to list element holding a dev_pm_qos request to use
|
|
* @new_value: defines the qos request
|
|
*
|
|
* Updates an existing dev PM qos request along with updating the
|
|
* target value.
|
|
*
|
|
* Attempts are made to make this code callable on hot code paths.
|
|
*
|
|
* Returns 1 if the aggregated constraint value has changed,
|
|
* 0 if the aggregated constraint value has not changed,
|
|
* -EINVAL in case of wrong parameters, -ENODEV if the device has been
|
|
* removed from the system
|
|
*
|
|
* Callers should ensure that the target device is not RPM_SUSPENDED before
|
|
* using this function for requests of type DEV_PM_QOS_FLAGS.
|
|
*/
|
|
int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value)
|
|
{
|
|
int ret;
|
|
|
|
mutex_lock(&dev_pm_qos_mtx);
|
|
ret = __dev_pm_qos_update_request(req, new_value);
|
|
mutex_unlock(&dev_pm_qos_mtx);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(dev_pm_qos_update_request);
|
|
|
|
static int __dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
|
|
{
|
|
int ret;
|
|
|
|
if (!req) /*guard against callers passing in null */
|
|
return -EINVAL;
|
|
|
|
if (WARN(!dev_pm_qos_request_active(req),
|
|
"%s() called for unknown object\n", __func__))
|
|
return -EINVAL;
|
|
|
|
if (IS_ERR_OR_NULL(req->dev->power.qos))
|
|
return -ENODEV;
|
|
|
|
trace_dev_pm_qos_remove_request(dev_name(req->dev), req->type,
|
|
PM_QOS_DEFAULT_VALUE);
|
|
ret = apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
|
|
memset(req, 0, sizeof(*req));
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* dev_pm_qos_remove_request - modifies an existing qos request
|
|
* @req: handle to request list element
|
|
*
|
|
* Will remove pm qos request from the list of constraints and
|
|
* recompute the current target value. Call this on slow code paths.
|
|
*
|
|
* Returns 1 if the aggregated constraint value has changed,
|
|
* 0 if the aggregated constraint value has not changed,
|
|
* -EINVAL in case of wrong parameters, -ENODEV if the device has been
|
|
* removed from the system
|
|
*
|
|
* Callers should ensure that the target device is not RPM_SUSPENDED before
|
|
* using this function for requests of type DEV_PM_QOS_FLAGS.
|
|
*/
|
|
int dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
|
|
{
|
|
int ret;
|
|
|
|
mutex_lock(&dev_pm_qos_mtx);
|
|
ret = __dev_pm_qos_remove_request(req);
|
|
mutex_unlock(&dev_pm_qos_mtx);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
|
|
|
|
/**
|
|
* dev_pm_qos_add_notifier - sets notification entry for changes to target value
|
|
* of per-device PM QoS constraints
|
|
*
|
|
* @dev: target device for the constraint
|
|
* @notifier: notifier block managed by caller.
|
|
*
|
|
* Will register the notifier into a notification chain that gets called
|
|
* upon changes to the target value for the device.
|
|
*
|
|
* If the device's constraints object doesn't exist when this routine is called,
|
|
* it will be created (or error code will be returned if that fails).
|
|
*/
|
|
int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
|
|
{
|
|
int ret = 0;
|
|
|
|
mutex_lock(&dev_pm_qos_mtx);
|
|
|
|
if (IS_ERR(dev->power.qos))
|
|
ret = -ENODEV;
|
|
else if (!dev->power.qos)
|
|
ret = dev_pm_qos_constraints_allocate(dev);
|
|
|
|
if (!ret)
|
|
ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers,
|
|
notifier);
|
|
|
|
mutex_unlock(&dev_pm_qos_mtx);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
|
|
|
|
/**
|
|
* dev_pm_qos_remove_notifier - deletes notification for changes to target value
|
|
* of per-device PM QoS constraints
|
|
*
|
|
* @dev: target device for the constraint
|
|
* @notifier: notifier block to be removed.
|
|
*
|
|
* Will remove the notifier from the notification chain that gets called
|
|
* upon changes to the target value.
|
|
*/
|
|
int dev_pm_qos_remove_notifier(struct device *dev,
|
|
struct notifier_block *notifier)
|
|
{
|
|
int retval = 0;
|
|
|
|
mutex_lock(&dev_pm_qos_mtx);
|
|
|
|
/* Silently return if the constraints object is not present. */
|
|
if (!IS_ERR_OR_NULL(dev->power.qos))
|
|
retval = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
|
|
notifier);
|
|
|
|
mutex_unlock(&dev_pm_qos_mtx);
|
|
return retval;
|
|
}
|
|
EXPORT_SYMBOL_GPL(dev_pm_qos_remove_notifier);
|
|
|
|
/**
|
|
* dev_pm_qos_add_ancestor_request - Add PM QoS request for device's ancestor.
|
|
* @dev: Device whose ancestor to add the request for.
|
|
* @req: Pointer to the preallocated handle.
|
|
* @type: Type of the request.
|
|
* @value: Constraint latency value.
|
|
*/
|
|
int dev_pm_qos_add_ancestor_request(struct device *dev,
|
|
struct dev_pm_qos_request *req,
|
|
enum dev_pm_qos_req_type type, s32 value)
|
|
{
|
|
struct device *ancestor = dev->parent;
|
|
int ret = -ENODEV;
|
|
|
|
switch (type) {
|
|
case DEV_PM_QOS_RESUME_LATENCY:
|
|
while (ancestor && !ancestor->power.ignore_children)
|
|
ancestor = ancestor->parent;
|
|
|
|
break;
|
|
case DEV_PM_QOS_LATENCY_TOLERANCE:
|
|
while (ancestor && !ancestor->power.set_latency_tolerance)
|
|
ancestor = ancestor->parent;
|
|
|
|
break;
|
|
default:
|
|
ancestor = NULL;
|
|
}
|
|
if (ancestor)
|
|
ret = dev_pm_qos_add_request(ancestor, req, type, value);
|
|
|
|
if (ret < 0)
|
|
req->dev = NULL;
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request);
|
|
|
|
static void __dev_pm_qos_drop_user_request(struct device *dev,
|
|
enum dev_pm_qos_req_type type)
|
|
{
|
|
struct dev_pm_qos_request *req = NULL;
|
|
|
|
switch(type) {
|
|
case DEV_PM_QOS_RESUME_LATENCY:
|
|
req = dev->power.qos->resume_latency_req;
|
|
dev->power.qos->resume_latency_req = NULL;
|
|
break;
|
|
case DEV_PM_QOS_LATENCY_TOLERANCE:
|
|
req = dev->power.qos->latency_tolerance_req;
|
|
dev->power.qos->latency_tolerance_req = NULL;
|
|
break;
|
|
case DEV_PM_QOS_FLAGS:
|
|
req = dev->power.qos->flags_req;
|
|
dev->power.qos->flags_req = NULL;
|
|
break;
|
|
}
|
|
__dev_pm_qos_remove_request(req);
|
|
kfree(req);
|
|
}
|
|
|
|
static void dev_pm_qos_drop_user_request(struct device *dev,
|
|
enum dev_pm_qos_req_type type)
|
|
{
|
|
mutex_lock(&dev_pm_qos_mtx);
|
|
__dev_pm_qos_drop_user_request(dev, type);
|
|
mutex_unlock(&dev_pm_qos_mtx);
|
|
}
|
|
|
|
/**
|
|
* dev_pm_qos_expose_latency_limit - Expose PM QoS latency limit to user space.
|
|
* @dev: Device whose PM QoS latency limit is to be exposed to user space.
|
|
* @value: Initial value of the latency limit.
|
|
*/
|
|
int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
|
|
{
|
|
struct dev_pm_qos_request *req;
|
|
int ret;
|
|
|
|
if (!device_is_registered(dev) || value < 0)
|
|
return -EINVAL;
|
|
|
|
req = kzalloc(sizeof(*req), GFP_KERNEL);
|
|
if (!req)
|
|
return -ENOMEM;
|
|
|
|
ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_RESUME_LATENCY, value);
|
|
if (ret < 0) {
|
|
kfree(req);
|
|
return ret;
|
|
}
|
|
|
|
mutex_lock(&dev_pm_qos_sysfs_mtx);
|
|
|
|
mutex_lock(&dev_pm_qos_mtx);
|
|
|
|
if (IS_ERR_OR_NULL(dev->power.qos))
|
|
ret = -ENODEV;
|
|
else if (dev->power.qos->resume_latency_req)
|
|
ret = -EEXIST;
|
|
|
|
if (ret < 0) {
|
|
__dev_pm_qos_remove_request(req);
|
|
kfree(req);
|
|
mutex_unlock(&dev_pm_qos_mtx);
|
|
goto out;
|
|
}
|
|
dev->power.qos->resume_latency_req = req;
|
|
|
|
mutex_unlock(&dev_pm_qos_mtx);
|
|
|
|
ret = pm_qos_sysfs_add_resume_latency(dev);
|
|
if (ret)
|
|
dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_RESUME_LATENCY);
|
|
|
|
out:
|
|
mutex_unlock(&dev_pm_qos_sysfs_mtx);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit);
|
|
|
|
static void __dev_pm_qos_hide_latency_limit(struct device *dev)
|
|
{
|
|
if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->resume_latency_req)
|
|
__dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_RESUME_LATENCY);
|
|
}
|
|
|
|
/**
|
|
* dev_pm_qos_hide_latency_limit - Hide PM QoS latency limit from user space.
|
|
* @dev: Device whose PM QoS latency limit is to be hidden from user space.
|
|
*/
|
|
void dev_pm_qos_hide_latency_limit(struct device *dev)
|
|
{
|
|
mutex_lock(&dev_pm_qos_sysfs_mtx);
|
|
|
|
pm_qos_sysfs_remove_resume_latency(dev);
|
|
|
|
mutex_lock(&dev_pm_qos_mtx);
|
|
__dev_pm_qos_hide_latency_limit(dev);
|
|
mutex_unlock(&dev_pm_qos_mtx);
|
|
|
|
mutex_unlock(&dev_pm_qos_sysfs_mtx);
|
|
}
|
|
EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit);
|
|
|
|
/**
|
|
* dev_pm_qos_expose_flags - Expose PM QoS flags of a device to user space.
|
|
* @dev: Device whose PM QoS flags are to be exposed to user space.
|
|
* @val: Initial values of the flags.
|
|
*/
|
|
int dev_pm_qos_expose_flags(struct device *dev, s32 val)
|
|
{
|
|
struct dev_pm_qos_request *req;
|
|
int ret;
|
|
|
|
if (!device_is_registered(dev))
|
|
return -EINVAL;
|
|
|
|
req = kzalloc(sizeof(*req), GFP_KERNEL);
|
|
if (!req)
|
|
return -ENOMEM;
|
|
|
|
ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_FLAGS, val);
|
|
if (ret < 0) {
|
|
kfree(req);
|
|
return ret;
|
|
}
|
|
|
|
pm_runtime_get_sync(dev);
|
|
mutex_lock(&dev_pm_qos_sysfs_mtx);
|
|
|
|
mutex_lock(&dev_pm_qos_mtx);
|
|
|
|
if (IS_ERR_OR_NULL(dev->power.qos))
|
|
ret = -ENODEV;
|
|
else if (dev->power.qos->flags_req)
|
|
ret = -EEXIST;
|
|
|
|
if (ret < 0) {
|
|
__dev_pm_qos_remove_request(req);
|
|
kfree(req);
|
|
mutex_unlock(&dev_pm_qos_mtx);
|
|
goto out;
|
|
}
|
|
dev->power.qos->flags_req = req;
|
|
|
|
mutex_unlock(&dev_pm_qos_mtx);
|
|
|
|
ret = pm_qos_sysfs_add_flags(dev);
|
|
if (ret)
|
|
dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
|
|
|
|
out:
|
|
mutex_unlock(&dev_pm_qos_sysfs_mtx);
|
|
pm_runtime_put(dev);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(dev_pm_qos_expose_flags);
|
|
|
|
static void __dev_pm_qos_hide_flags(struct device *dev)
|
|
{
|
|
if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->flags_req)
|
|
__dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
|
|
}
|
|
|
|
/**
|
|
* dev_pm_qos_hide_flags - Hide PM QoS flags of a device from user space.
|
|
* @dev: Device whose PM QoS flags are to be hidden from user space.
|
|
*/
|
|
void dev_pm_qos_hide_flags(struct device *dev)
|
|
{
|
|
pm_runtime_get_sync(dev);
|
|
mutex_lock(&dev_pm_qos_sysfs_mtx);
|
|
|
|
pm_qos_sysfs_remove_flags(dev);
|
|
|
|
mutex_lock(&dev_pm_qos_mtx);
|
|
__dev_pm_qos_hide_flags(dev);
|
|
mutex_unlock(&dev_pm_qos_mtx);
|
|
|
|
mutex_unlock(&dev_pm_qos_sysfs_mtx);
|
|
pm_runtime_put(dev);
|
|
}
|
|
EXPORT_SYMBOL_GPL(dev_pm_qos_hide_flags);
|
|
|
|
/**
|
|
* dev_pm_qos_update_flags - Update PM QoS flags request owned by user space.
|
|
* @dev: Device to update the PM QoS flags request for.
|
|
* @mask: Flags to set/clear.
|
|
* @set: Whether to set or clear the flags (true means set).
|
|
*/
|
|
int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set)
|
|
{
|
|
s32 value;
|
|
int ret;
|
|
|
|
pm_runtime_get_sync(dev);
|
|
mutex_lock(&dev_pm_qos_mtx);
|
|
|
|
if (IS_ERR_OR_NULL(dev->power.qos) || !dev->power.qos->flags_req) {
|
|
ret = -EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
value = dev_pm_qos_requested_flags(dev);
|
|
if (set)
|
|
value |= mask;
|
|
else
|
|
value &= ~mask;
|
|
|
|
ret = __dev_pm_qos_update_request(dev->power.qos->flags_req, value);
|
|
|
|
out:
|
|
mutex_unlock(&dev_pm_qos_mtx);
|
|
pm_runtime_put(dev);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* dev_pm_qos_get_user_latency_tolerance - Get user space latency tolerance.
|
|
* @dev: Device to obtain the user space latency tolerance for.
|
|
*/
|
|
s32 dev_pm_qos_get_user_latency_tolerance(struct device *dev)
|
|
{
|
|
s32 ret;
|
|
|
|
mutex_lock(&dev_pm_qos_mtx);
|
|
ret = IS_ERR_OR_NULL(dev->power.qos)
|
|
|| !dev->power.qos->latency_tolerance_req ?
|
|
PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT :
|
|
dev->power.qos->latency_tolerance_req->data.pnode.prio;
|
|
mutex_unlock(&dev_pm_qos_mtx);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* dev_pm_qos_update_user_latency_tolerance - Update user space latency tolerance.
|
|
* @dev: Device to update the user space latency tolerance for.
|
|
* @val: New user space latency tolerance for @dev (negative values disable).
|
|
*/
|
|
int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val)
|
|
{
|
|
int ret;
|
|
|
|
mutex_lock(&dev_pm_qos_mtx);
|
|
|
|
if (IS_ERR_OR_NULL(dev->power.qos)
|
|
|| !dev->power.qos->latency_tolerance_req) {
|
|
struct dev_pm_qos_request *req;
|
|
|
|
if (val < 0) {
|
|
if (val == PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT)
|
|
ret = 0;
|
|
else
|
|
ret = -EINVAL;
|
|
goto out;
|
|
}
|
|
req = kzalloc(sizeof(*req), GFP_KERNEL);
|
|
if (!req) {
|
|
ret = -ENOMEM;
|
|
goto out;
|
|
}
|
|
ret = __dev_pm_qos_add_request(dev, req, DEV_PM_QOS_LATENCY_TOLERANCE, val);
|
|
if (ret < 0) {
|
|
kfree(req);
|
|
goto out;
|
|
}
|
|
dev->power.qos->latency_tolerance_req = req;
|
|
} else {
|
|
if (val < 0) {
|
|
__dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY_TOLERANCE);
|
|
ret = 0;
|
|
} else {
|
|
ret = __dev_pm_qos_update_request(dev->power.qos->latency_tolerance_req, val);
|
|
}
|
|
}
|
|
|
|
out:
|
|
mutex_unlock(&dev_pm_qos_mtx);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(dev_pm_qos_update_user_latency_tolerance);
|
|
|
|
/**
|
|
* dev_pm_qos_expose_latency_tolerance - Expose latency tolerance to userspace
|
|
* @dev: Device whose latency tolerance to expose
|
|
*/
|
|
int dev_pm_qos_expose_latency_tolerance(struct device *dev)
|
|
{
|
|
int ret;
|
|
|
|
if (!dev->power.set_latency_tolerance)
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&dev_pm_qos_sysfs_mtx);
|
|
ret = pm_qos_sysfs_add_latency_tolerance(dev);
|
|
mutex_unlock(&dev_pm_qos_sysfs_mtx);
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_tolerance);
|
|
|
|
/**
|
|
* dev_pm_qos_hide_latency_tolerance - Hide latency tolerance from userspace
|
|
* @dev: Device whose latency tolerance to hide
|
|
*/
|
|
void dev_pm_qos_hide_latency_tolerance(struct device *dev)
|
|
{
|
|
mutex_lock(&dev_pm_qos_sysfs_mtx);
|
|
pm_qos_sysfs_remove_latency_tolerance(dev);
|
|
mutex_unlock(&dev_pm_qos_sysfs_mtx);
|
|
|
|
/* Remove the request from user space now */
|
|
pm_runtime_get_sync(dev);
|
|
dev_pm_qos_update_user_latency_tolerance(dev,
|
|
PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT);
|
|
pm_runtime_put(dev);
|
|
}
|
|
EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_tolerance);
|