* remotes/origin/tmp-b7e55e8:
Linux 4.14.61
scsi: sg: fix minor memory leak in error path
drm/vc4: Reset ->{x, y}_scaling[1] when dealing with uniplanar formats
crypto: padlock-aes - Fix Nano workaround data corruption
RDMA/uverbs: Expand primary and alt AV port checks
iwlwifi: add more card IDs for 9000 series
userfaultfd: remove uffd flags from vma->vm_flags if UFFD_EVENT_FORK fails
audit: fix potential null dereference 'context->module.name'
kvm: x86: vmx: fix vpid leak
x86/entry/64: Remove %ebx handling from error_entry/exit
x86/apic: Future-proof the TSC_DEADLINE quirk for SKX
virtio_balloon: fix another race between migration and ballooning
net: socket: fix potential spectre v1 gadget in socketcall
can: ems_usb: Fix memory leak on ems_usb_disconnect()
squashfs: more metadata hardenings
squashfs: more metadata hardening
net/mlx5e: E-Switch, Initialize eswitch only if eswitch manager
rxrpc: Fix user call ID check in rxrpc_service_prealloc_one
net: stmmac: Fix WoL for PCI-based setups
netlink: Fix spectre v1 gadget in netlink_create()
net: dsa: Do not suspend/resume closed slave_dev
ipv4: frags: handle possible skb truesize change
inet: frag: enforce memory limits earlier
bonding: avoid lockdep confusion in bond_get_stats()
Linux 4.14.60
tcp: add one more quick ack after after ECN events
tcp: refactor tcp_ecn_check_ce to remove sk type cast
tcp: do not aggressively quick ack after ECN events
tcp: add max_quickacks param to tcp_incr_quickack and tcp_enter_quickack_mode
tcp: do not force quickack when receiving out-of-order packets
netlink: Don't shift with UB on nlk->ngroups
netlink: Do not subscribe to non-existent groups
xen-netfront: wait xenbus state change when load module manually
tcp_bbr: fix bw probing to raise in-flight data for very small BDPs
NET: stmmac: align DMA stuff to largest cache line length
net: mdio-mux: bcm-iproc: fix wrong getter and setter pair
net: lan78xx: fix rx handling before first packet is send
net: fix amd-xgbe flow-control issue
net: ena: Fix use of uninitialized DMA address bits field
ipv4: remove BUG_ON() from fib_compute_spec_dst
net: dsa: qca8k: Allow overwriting CPU port setting
net: dsa: qca8k: Add QCA8334 binding documentation
net: dsa: qca8k: Enable RXMAC when bringing up a port
net: dsa: qca8k: Force CPU port to its highest bandwidth
RDMA/uverbs: Protect from attempts to create flows on unsupported QP
usb: gadget: udc: renesas_usb3: should remove debugfs
ovl: Sync upper dirty data when syncing overlayfs
PCI: xgene: Remove leftover pci_scan_child_bus() call
PCI: pciehp: Assume NoCompl+ for Thunderbolt ports
ext4: fix check to prevent initializing reserved inodes
ext4: check for allocation block validity with block group locked
ext4: fix inline data updates with checksums enabled
squashfs: be more careful about metadata corruption
random: mix rdrand with entropy sent in from userspace
block: reset bi_iter.bi_done after splitting bio
blkdev: __blkdev_direct_IO_simple: fix leak in error case
block: bio_iov_iter_get_pages: fix size of last iovec
drm/dp/mst: Fix off-by-one typo when dump payload table
drm/atomic-helper: Drop plane->fb references only for drm_atomic_helper_shutdown()
drm: Add DP PSR2 sink enable bit
ASoC: topology: Add missing clock gating parameter when parsing hw_configs
ASoC: topology: Fix bclk and fsync inversion in set_link_hw_format()
media: si470x: fix __be16 annotations
media: atomisp: compat32: fix __user annotations
scsi: cxlflash: Avoid clobbering context control register value
scsi: cxlflash: Synchronize reset and remove ops
scsi: megaraid_sas: Increase timeout by 1 sec for non-RAID fastpath IOs
scsi: scsi_dh: replace too broad "TP9" string with the exact models
regulator: Don't return or expect -errno from of_map_mode()
media: omap3isp: fix unbalanced dma_iommu_mapping
crypto: authenc - don't leak pointers to authenc keys
crypto: authencesn - don't leak pointers to authenc keys
usb: hub: Don't wait for connect state at resume for powered-off ports
microblaze: Fix simpleImage format generation
soc: imx: gpcv2: Do not pass static memory as platform data
serial: core: Make sure compiler barfs for 16-byte earlycon names
staging: lustre: ldlm: free resource when ldlm_lock_create() fails.
staging: lustre: llite: correct removexattr detection
staging: vchiq_core: Fix missing semaphore release in error case
audit: allow not equal op for audit by executable
rsi: fix nommu_map_sg overflow kernel panic
rsi: Fix 'invalid vdd' warning in mmc
ipconfig: Correctly initialise ic_nameservers
drm/gma500: fix psb_intel_lvds_mode_valid()'s return type
igb: Fix queue selection on MAC filters on i210
arm64: defconfig: Enable Rockchip io-domain driver
nvme: lightnvm: add granby support
memory: tegra: Apply interrupts mask per SoC
memory: tegra: Do not handle spurious interrupts
delayacct: Use raw_spinlocks
stop_machine: Use raw spinlocks
backlight: pwm_bl: Don't use GPIOF_* with gpiod_get_direction
dt-bindings: net: meson-dwmac: new compatible name for AXG SoC
net: hns3: Fixes the out of bounds access in hclge_map_tqp
spi: meson-spicc: Fix error handling in meson_spicc_probe()
dt-bindings: pinctrl: meson: add support for the Meson8m2 SoC
mmc: pwrseq: Use kmalloc_array instead of stack VLA
mmc: dw_mmc: update actual clock for mmc debugfs
ALSA: hda/ca0132: fix build failure when a local macro is defined
drm/atomic: Handling the case when setting old crtc for plane
media: siano: get rid of __le32/__le16 cast warnings
f2fs: avoid fsync() failure caused by EAGAIN in writepage()
bpf: fix references to free_bpf_prog_info() in comments
thermal: exynos: fix setting rising_threshold for Exynos5433
staging: lustre: o2iblnd: Fix FastReg map/unmap for MLX5
staging: lustre: o2iblnd: fix race at kiblnd_connect_peer
scsi: qedf: Set the UNLOADING flag when removing a vport
scsi: hisi_sas: config ATA de-reset as an constrained command for v3 hw
scsi: megaraid: silence a static checker bug
scsi: 3w-xxxx: fix a missing-check bug
scsi: 3w-9xxx: fix a missing-check bug
bnxt_en: Check unsupported speeds in bnxt_update_link() on PF only.
perf: fix invalid bit in diagnostic entry
s390/cpum_sf: Add data entry sizes to sampling trailer entry
brcmfmac: Add support for bcm43364 wireless chipset
mtd: rawnand: fsl_ifc: fix FSL NAND driver to read all ONFI parameter pages
media: saa7164: Fix driver name in debug output
media: media-device: fix ioctl function types
ACPI / LPSS: Only call pwm_add_table() for Bay Trail PWM if PMIC HRV is 2
libata: Fix command retry decision
media: rcar_jpu: Add missing clk_disable_unprepare() on error in jpu_open()
net: phy: phylink: Release link GPIO
dma-iommu: Fix compilation when !CONFIG_IOMMU_DMA
tty: Fix data race in tty_insert_flip_string_fixed_flag
i40e: free the skb after clearing the bitlock
nvmem: properly handle returned value nvmem_reg_read
ARM: dts: sh73a0: Add missing interrupt-affinity to PMU node
ARM: dts: emev2: Add missing interrupt-affinity to PMU node
ARM: dts: stih407-pinctrl: Fix complain about IRQ_TYPE_NONE usage
EDAC, altera: Fix ARM64 build warning
HID: i2c-hid: check if device is there before really probing
powerpc/embedded6xx/hlwd-pic: Prevent interrupts from being handled by Starlet
drm/amdgpu: Remove VRAM from shared bo domains.
drm/radeon: fix mode_valid's return type
arm64: dts: renesas: salvator-common: use audio-graph-card for Sound
HID: hid-plantronics: Re-resend Update to map button for PTT products
arm64: cmpwait: Clear event register before arming exclusive monitor
media: atomisp: ov2680: don't declare unused vars
ALSA: usb-audio: Apply rate limit to warning messages in URB complete callback
net: ethernet: ti: cpsw-phy-sel: check bus_find_device() ret value
media: smiapp: fix timeout checking in smiapp_read_nvm
ixgbevf: fix MAC address changes through ixgbevf_set_mac()
md: fix NULL dereference of mddev->pers in remove_and_add_spares()
md/raid1: add error handling of read error from FailFast device
regulator: pfuze100: add .is_enable() for pfuze100_swb_regulator_ops
ALSA: emu10k1: Rate-limit error messages about page errors
rtc: tps65910: fix possible race condition
rtc: vr41xx: fix possible race condition
rtc: tps6586x: fix possible race condition
Bluetooth: btusb: add ID for LiteOn 04ca:301a
drm/nouveau/fifo/gk104-: poll for runlist update completion
scsi: zfcp: assert that the ERP lock is held when tracing a recovery trigger
scsi: ufs: fix exception event handling
scsi: ufs: ufshcd: fix possible unclocked register access
fscrypt: use unbound workqueue for decryption
net: hns3: Fix the missing client list node initialization
spi: Add missing pm_runtime_put_noidle() after failed get
drivers/perf: arm-ccn: don't log to dmesg in event_init
ima: based on policy verify firmware signatures (pre-allocated buffer)
mwifiex: correct histogram data with appropriate index
net: dsa: qca8k: Add support for QCA8334 switch
PCI: pciehp: Request control of native hotplug only if supported
bpf: powerpc64: pad function address loads with NOPs
pinctrl: at91-pio4: add missing of_node_put
powerpc/8xx: fix invalid register expression in head_8xx.S
spi: sh-msiof: Fix setting SIRMDR1.SYNCAC to match SITMDR1.SYNCAC
powerpc: Add __printf verification to prom_printf
powerpc/powermac: Mark variable x as unused
powerpc/powermac: Add missing prototype for note_bootable_part()
powerpc/chrp/time: Make some functions static, add missing header include
powerpc/32: Add a missing include header
ath: Add regulatory mapping for Bahamas
ath: Add regulatory mapping for Bermuda
ath: Add regulatory mapping for Serbia
ath: Add regulatory mapping for Tanzania
ath: Add regulatory mapping for Uganda
ath: Add regulatory mapping for APL2_FCCA
ath: Add regulatory mapping for APL13_WORLD
ath: Add regulatory mapping for ETSI8_WORLD
ath: Add regulatory mapping for FCC3_ETSIC
nvme-pci: Fix AER reset handling
nvme-rdma: stop admin queue before freeing it
PCI: Prevent sysfs disable of device while driver is attached
PM / wakeup: Make s2idle_lock a RAW_SPINLOCK
x86/microcode: Make the late update update_lock a raw lock for RT
btrfs: qgroup: Finish rescan when hit the last leaf of extent tree
btrfs: add barriers to btrfs_sync_log before log_commit_wait wakeups
Btrfs: don't BUG_ON() in btrfs_truncate_inode_items()
Btrfs: don't return ino to ino cache if inode item removal fails
media: videobuf2-core: don't call memop 'finish' when queueing
media: tw686x: Fix incorrect vb2_mem_ops GFP flags
net: hns3: Fixes the init of the VALID BD info in the descriptor
wlcore: sdio: check for valid platform device data before suspend
mwifiex: handle race during mwifiex_usb_disconnect
mfd: cros_ec: Fail early if we cannot identify the EC
ASoC: dpcm: fix BE dai not hw_free and shutdown
Bluetooth: btusb: Add a new Realtek 8723DE ID 2ff8:b011
Bluetooth: hci_qca: Fix "Sleep inside atomic section" warning
iwlwifi: pcie: fix race in Rx buffer allocator
btrfs: balance dirty metadata pages in btrfs_finish_ordered_io
PCI: Fix devm_pci_alloc_host_bridge() memory leak
selftests: intel_pstate: return Kselftest Skip code for skipped tests
selftests: memfd: return Kselftest Skip code for skipped tests
selftests/intel_pstate: Improve test, minor fixes
perf/x86/intel/uncore: Correct fixed counter index check for NHM
perf/x86/intel/uncore: Correct fixed counter index check in generic code
usbip: dynamically allocate idev by nports found in sysfs
usbip: usbip_detach: Fix memory, udev context and udev leak
block, bfq: remove wrong lock in bfq_requests_merged
f2fs: fix race in between GC and atomic open
f2fs: fix to detect failure of dquot_initialize
f2fs: Fix deadlock in shutdown ioctl
f2fs: fix to wait page writeback during revoking atomic write
f2fs: fix to don't trigger writeback during recovery
f2fs: fix error path of move_data_page
disable loading f2fs module on PAGE_SIZE > 4KB
pnfs: Don't release the sequence slot until we've processed layoutget on open
netfilter: nf_tables: check msg_type before nft_trans_set(trans)
lightnvm: pblk: warn in case of corrupted write buffer
RDMA/mad: Convert BUG_ONs to error flows
powerpc/64s: Fix compiler store ordering to SLB shadow area
hvc_opal: don't set tb_ticks_per_usec in udbg_init_opal_common()
powerpc/eeh: Fix use-after-release of EEH driver
powerpc/64s: Add barrier_nospec
powerpc/lib: Adjust .balign inside string functions for PPC32
infiniband: fix a possible use-after-free bug
e1000e: Ignore TSYNCRXCTL when getting I219 clock attributes
ceph: fix alignment of rasize
bpf, arm32: fix inconsistent naming about emit_a32_lsr_{r64,i64}
printk: drop in_nmi check from printk_safe_flush_on_panic()
watchdog: da9063: Fix updating timeout value
irqchip/ls-scfg-msi: Map MSIs in the iommu
netfilter: ipset: List timing out entries with "timeout 1" instead of zero
netfilter: ipset: forbid family for hash:mac sets
perf tools: Fix pmu events parsing rule
rtc: ensure rtc_set_alarm fails when alarms are not supported
mm/slub.c: add __printf verification to slab_err()
mm: vmalloc: avoid racy handling of debugobjects in vunmap
mm: /proc/pid/pagemap: hide swap entries from unprivileged users
kernel/hung_task.c: show all hung tasks before panic
vfio/type1: Fix task tracking for QEMU vCPU hotplug
vfio/mdev: Check globally for duplicate devices
vfio: platform: Fix reset module leak in error path
nfsd: fix potential use-after-free in nfsd4_decode_getdeviceinfo
NFSv4.1: Fix the client behaviour on NFS4ERR_SEQ_FALSE_RETRY
ALSA: fm801: add error handling for snd_ctl_add
ALSA: emu10k1: add error handling for snd_ctl_add
skip LAYOUTRETURN if layout is invalid
hv_netvsc: fix network namespace issues with VF support
xen/netfront: raise max number of slots in xennet_get_responses()
kcov: ensure irq code sees a valid area
mlxsw: spectrum_switchdev: Fix port_vlan refcounting
arm64: fix vmemmap BUILD_BUG_ON() triggering on !vmemmap setups
tracing: Quiet gcc warning about maybe unused link variable
tracing/kprobes: Fix trace_probe flags on enable_trace_kprobe() failure
kthread, tracing: Don't expose half-written comm when creating kthreads
tracing: Fix possible double free in event_enable_trigger_func()
tracing: Fix double free of event_trigger_data
delayacct: fix crash in delayacct_blkio_end() after delayacct init failure
kvm, mm: account shadow page tables to kmemcg
Input: elan_i2c - add another ACPI ID for Lenovo Ideapad 330-15AST
Input: i8042 - add Lenovo LaVie Z to the i8042 reset list
Input: elan_i2c - add ACPI ID for lenovo ideapad 330
spi: spi-s3c64xx: Fix system resume support
drivers/infiniband/ulp/srpt/ib_srpt.c: fix build with gcc-4.4.4
IB/srpt: Fix an out-of-bounds stack access in srpt_zerolength_write()
drivers/infiniband/core/verbs.c: fix build with gcc-4.4.4
RDMA/core: Avoid that ib_drain_qp() triggers an out-of-bounds stack access
i2c: core: decrease reference count of device node in i2c_unregister_device
fork: unconditionally clear stack on fork
Linux 4.14.59
turn off -Wattribute-alias
can: m_can.c: fix setup of CCCR register: clear CCCR NISO bit before checking can.ctrlmode
can: peak_canfd: fix firmware < v3.3.0: limit allocation to 32-bit DMA addr only
can: xilinx_can: fix RX overflow interrupt not being enabled
can: xilinx_can: fix incorrect clear of non-processed interrupts
can: xilinx_can: keep only 1-2 frames in TX FIFO to fix TX accounting
can: xilinx_can: fix device dropping off bus on RX overrun
can: xilinx_can: fix recovery from error states not being propagated
can: xilinx_can: fix power management handling
can: xilinx_can: fix RX loop if RXNEMP is asserted without RXOK
driver core: Partially revert "driver core: correct device's shutdown order"
usb: gadget: f_fs: Only return delayed status when len is 0
usb: dwc2: Fix DMA alignment to start at allocated boundary
usb: core: handle hub C_PORT_OVER_CURRENT condition
usb: cdc_acm: Add quirk for Castles VEGA3000
staging: speakup: fix wraparound in uaccess length check
tcp: add tcp_ooo_try_coalesce() helper
tcp: call tcp_drop() from tcp_data_queue_ofo()
tcp: detect malicious patterns in tcp_collapse_ofo_queue()
tcp: avoid collapses in tcp_prune_queue() if possible
tcp: free batches of packets in tcp_prune_ofo_queue()
tcp: do not delay ACK in DCTCP upon CE status change
tcp: do not cancel delay-AcK on DCTCP special ACK
tcp: helpers to send special DCTCP ack
tcp: fix dctcp delayed ACK schedule
vxlan: fix default fdb entry netlink notify ordering during netdev create
vxlan: make netlink notify in vxlan_fdb_destroy optional
vxlan: add new fdb alloc and create helpers
rtnetlink: add rtnl_link_state check in rtnl_configure_link
sock: fix sg page frag coalescing in sk_alloc_sg
net: phy: consider PHY_IGNORE_INTERRUPT in phy_start_aneg_priv
multicast: do not restore deleted record source filter mode to new one
net/ipv6: Fix linklocal to global address with VRF
net/mlx5e: Fix quota counting in aRFS expire flow
net/mlx5e: Don't allow aRFS for encapsulated packets
net/mlx5: Adjust clock overflow work period
net: skb_segment() should not return NULL
net/mlx4_core: Save the qpn from the input modifier in RST2INIT wrapper
ip: in cmsg IP(V6)_ORIGDSTADDR call pskb_may_pull
ip: hash fragments consistently
bonding: set default miimon value for non-arp modes if not set
drm/nouveau: Set DRIVER_ATOMIC cap earlier to fix debugfs
drm/nouveau/drm/nouveau: Fix runtime PM leak in nv50_disp_atomic_commit()
KVM: PPC: Check if IOMMU page is contained in the pinned physical page
xen/PVH: Set up GS segment for stack canary
MIPS: Fix off-by-one in pci_resource_to_user()
MIPS: ath79: fix register address in ath79_ddr_wb_flush()
Revert "cifs: Fix slab-out-of-bounds in send_set_info() on SMB2 ACE setting"
ANDROID: verity: really fix android-verity Kconfig
tcp: add tcp_ooo_try_coalesce() helper
tcp: call tcp_drop() from tcp_data_queue_ofo()
tcp: detect malicious patterns in tcp_collapse_ofo_queue()
tcp: avoid collapses in tcp_prune_queue() if possible
tcp: free batches of packets in tcp_prune_ofo_queue()
x86_64_cuttlefish_defconfig: Enable android-verity
x86_64_cuttlefish_defconfig: enable verity cert
ANDROID: android-verity: Fix broken parameter handling.
ANDROID: android-verity: Make it work with newer kernels
ANDROID: android-verity: Add API to verify signature with builtin keys.
ANDROID: verity: fix android-verity Kconfig dependencies
Linux 4.14.58
xhci: Fix perceived dead host due to runtime suspend race with event handler
powerpc/powernv: Fix save/restore of SPRG3 on entry/exit from stop (idle)
cxl_getfile(): fix double-iput() on alloc_file() failures
alpha: fix osf_wait4() breakage
net: usb: asix: replace mii_nway_restart in resume path
ipv6: make DAD fail with enhanced DAD when nonce length differs
net: systemport: Fix CRC forwarding check for SYSTEMPORT Lite
net/mlx4_en: Don't reuse RX page when XDP is set
hv_netvsc: Fix napi reschedule while receive completion is busy
tg3: Add higher cpu clock for 5762.
qmi_wwan: add support for Quectel EG91
ptp: fix missing break in switch
net: phy: fix flag masking in __set_phy_supported
net/ipv4: Set oif in fib_compute_spec_dst
skbuff: Unconditionally copy pfmemalloc in __skb_clone()
net: Don't copy pfmemalloc flag in __copy_skb_header()
net: diag: Don't double-free TCP_NEW_SYN_RECV sockets in tcp_abort
lib/rhashtable: consider param->min_size when setting initial table size
ipv6: ila: select CONFIG_DST_CACHE
ipv6: fix useless rol32 call on hash
ipv4: Return EINVAL when ping_group_range sysctl doesn't map to user ns
gen_stats: Fix netlink stats dumping in the presence of padding
drm/nouveau: Avoid looping through fake MST connectors
drm/nouveau: Use drm_connector_list_iter_* for iterating connectors
drm/i915: Fix hotplug irq ack on i965/g4x
stop_machine: Disable preemption when waking two stopper threads
vfio/spapr: Use IOMMU pageshift rather than pagesize
vfio/pci: Fix potential Spectre v1
cpufreq: intel_pstate: Register when ACPI PCCH is present
mm/huge_memory.c: fix data loss when splitting a file pmd
mm: memcg: fix use after free in mem_cgroup_iter()
ARC: mm: allow mprotect to make stack mappings executable
ARC: configs: Remove CONFIG_INITRAMFS_SOURCE from defconfigs
ARC: Fix CONFIG_SWAP
ARCv2: [plat-hsdk]: Save accl reg pair by default
ALSA: hda: add mute led support for HP ProBook 455 G5
ALSA: hda/realtek - Add Panasonic CF-SZ6 headset jack quirk
ALSA: rawmidi: Change resized buffers atomically
fat: fix memory allocation failure handling of match_strdup()
x86/MCE: Remove min interval polling limitation
x86/events/intel/ds: Fix bts_interrupt_threshold alignment
x86/apm: Don't access __preempt_count with zeroed fs
KVM/Eventfd: Avoid crash when assign and deassign specific eventfd in parallel.
scsi: sd_zbc: Fix variable type and bogus comment
ANDROID: uid_sys_stats: Replace tasklist lock with RCU in uid_cputime_show
Linux 4.14.57
string: drop __must_check from strscpy() and restore strscpy() usages in cgroup
arm64: KVM: Add ARCH_WORKAROUND_2 discovery through ARCH_FEATURES_FUNC_ID
arm64: KVM: Handle guest's ARCH_WORKAROUND_2 requests
arm64: KVM: Add ARCH_WORKAROUND_2 support for guests
arm64: KVM: Add HYP per-cpu accessors
arm64: ssbd: Add prctl interface for per-thread mitigation
arm64: ssbd: Introduce thread flag to control userspace mitigation
arm64: ssbd: Restore mitigation status on CPU resume
arm64: ssbd: Skip apply_ssbd if not using dynamic mitigation
arm64: ssbd: Add global mitigation state accessor
arm64: Add 'ssbd' command-line option
arm64: Add ARCH_WORKAROUND_2 probing
arm64: Add per-cpu infrastructure to call ARCH_WORKAROUND_2
arm64: Call ARCH_WORKAROUND_2 on transitions between EL0 and EL1
arm/arm64: smccc: Add SMCCC-specific return codes
KVM: arm64: Avoid storing the vcpu pointer on the stack
KVM: arm/arm64: Do not use kern_hyp_va() with kvm_vgic_global_state
arm64: alternatives: Add dynamic patching feature
KVM: arm64: Stop save/restoring host tpidr_el1 on VHE
arm64: alternatives: use tpidr_el2 on VHE hosts
KVM: arm64: Change hyp_panic()s dependency on tpidr_el2
KVM: arm/arm64: Convert kvm_host_cpu_state to a static per-cpu allocation
KVM: arm64: Store vcpu on the stack during __guest_enter()
net/nfc: Avoid stalls when nfc_alloc_send_skb() returned NULL.
rds: avoid unenecessary cong_update in loop transport
bdi: Fix another oops in wb_workfn()
netfilter: ipv6: nf_defrag: drop skb dst before queueing
nsh: set mac len based on inner packet
autofs: fix slab out of bounds read in getname_kernel()
tls: Stricter error checking in zerocopy sendmsg path
KEYS: DNS: fix parsing multiple options
reiserfs: fix buffer overflow with long warning messages
netfilter: ebtables: reject non-bridge targets
PCI: hv: Disable/enable IRQs rather than BH in hv_compose_msi_msg()
block: do not use interruptible wait anywhere
mtd: rawnand: denali_dt: set clk_x_rate to 200 MHz unconditionally
crypto: af_alg - Initialize sg_num_bytes in error code path
clocksource: Initialize cs->wd_list
media: rc: oops in ir_timer_keyup after device unplug
xhci: Fix USB3 NULL pointer dereference at logical disconnect.
net: lan78xx: Fix race in tx pending skb size calculation
rtlwifi: rtl8821ae: fix firmware is not ready to run
rtlwifi: Fix kernel Oops "Fw download fail!!"
net: cxgb3_main: fix potential Spectre v1
VSOCK: fix loopback on big-endian systems
vhost_net: validate sock before trying to put its fd
tcp: prevent bogus FRTO undos with non-SACK flows
tcp: fix Fast Open key endianness
strparser: Remove early eaten to fix full tcp receive buffer stall
stmmac: fix DMA channel hang in half-duplex mode
r8152: napi hangup fix after disconnect
qmi_wwan: add support for the Dell Wireless 5821e module
qed: Limit msix vectors in kdump kernel to the minimum required count.
qed: Fix use of incorrect size in memcpy call.
qed: Fix setting of incorrect eswitch mode.
qede: Adverstise software timestamp caps when PHC is not available.
net/tcp: Fix socket lookups with SO_BINDTODEVICE
net: sungem: fix rx checksum support
net_sched: blackhole: tell upper qdisc about dropped packets
net/packet: fix use-after-free
net: mvneta: fix the Rx desc DMA address in the Rx path
net/mlx5: Fix wrong size allocation for QoS ETC TC regitster
net/mlx5: Fix required capability for manipulating MPFS
net/mlx5: Fix incorrect raw command length parsing
net/mlx5: Fix command interface race in polling mode
net/mlx5: E-Switch, Avoid setup attempt if not being e-switch manager
net/mlx5e: Don't attempt to dereference the ppriv struct if not being eswitch manager
net/mlx5e: Avoid dealing with vport representors if not being e-switch manager
net: macb: Fix ptp time adjustment for large negative delta
net: fix use-after-free in GRO with ESP
net: dccp: switch rx_tstamp_last_feedback to monotonic clock
net: dccp: avoid crash in ccid3_hc_rx_send_feedback()
ixgbe: split XDP_TX tail and XDP_REDIRECT map flushing
ipvlan: fix IFLA_MTU ignored on NEWLINK
ipv6: sr: fix passing wrong flags to crypto_alloc_shash()
hv_netvsc: split sub-channel setup into async and sync
atm: zatm: Fix potential Spectre v1
atm: Preserve value of skb->truesize when accounting to vcc
alx: take rtnl before calling __alx_open from resume
crypto: crypto4xx - fix crypto4xx_build_pdr, crypto4xx_build_sdr leak
crypto: crypto4xx - remove bad list_del
PCI: exynos: Fix a potential init_clk_resources NULL pointer dereference
bcm63xx_enet: do not write to random DMA channel on BCM6345
bcm63xx_enet: correct clock usage
ocfs2: ip_alloc_sem should be taken in ocfs2_get_block()
ocfs2: subsystem.su_mutex is required while accessing the item->ci_parent
xprtrdma: Fix corner cases when handling device removal
cpufreq / CPPC: Set platform specific transition_delay_us
Btrfs: fix duplicate extents after fsync of file with prealloc extents
x86/paravirt: Make native_save_fl() extern inline
x86/asm: Add _ASM_ARG* constants for argument registers to <asm/asm.h>
compiler-gcc.h: Add __attribute__((gnu_inline)) to all inline declarations
ANDROID: Add hold functionality to schedtune CPU boost
ANDROID: sched/rt: Add schedtune accounting to rt task enqueue/dequeue
UPSTREAM: cpuidle: menu: Avoid selecting shallow states with stopped tick
UPSTREAM: cpuidle: menu: Refine idle state selection for running tick
UPSTREAM: sched: idle: Select idle state before stopping the tick
BACKPORT: time: hrtimer: Introduce hrtimer_next_event_without()
BACKPORT: time: tick-sched: Split tick_nohz_stop_sched_tick()
UPSTREAM: cpuidle: Return nohz hint from cpuidle_select()
UPSTREAM: jiffies: Introduce USER_TICK_USEC and redefine TICK_USEC
UPSTREAM: sched: idle: Do not stop the tick before cpuidle_idle_call()
BACKPORT: sched: idle: Do not stop the tick upfront in the idle loop
BACKPORT: time: tick-sched: Reorganize idle tick management code
ANDROID: sched/fair: fix a warning
ANDROID: sched/walt: Fix compilation issue for x86_64
ANDROID: mnt: Fix next_descendent
ANDROID: sched/events: Introduce util_est trace events
ANDROID: sched/fair: schedtune: update before schedutil
FROMLIST: sched/fair: add support to tune PELT ramp/decay timings
BACKPORT: sched/fair: Update util_est before updating schedutil
BACKPORT: sched/fair: Update util_est only on util_avg updates
BACKPORT: sched/fair: Use util_est in LB and WU paths
BACKPORT: sched/fair: Add util_est on top of PELT
ANDROID: sched/fair: Cleanup cpu_util{_wake}()
ANDROID: sched: Update max cpu capacity in case of max frequency constraints
ANDROID: arm: enable max frequency capping
ANDROID: arm64: enable max frequency capping
ANDROID: implement max frequency capping
ANDROID: sched/fair: add arch scaling function for max frequency capping
ANDROID: trace: Add WALT util signal to trace event sched_load_cfs_rq
ANDROID: sched, trace: Remove trace event sched_load_avg_cpu
ANDROID: Rename and move include/linux/sched_energy.h
ANDROID: Adjust juno energy model
ANDROID: Check equality of max cap state cap and cpu scale
ANDROID: Move energy model init call into arch_topology driver
ANDROID: Streamline sched_domain_energy_f functions
ANDROID: Separate cpu_scale and energy model setup
ANDROID: update_group_capacity for single cpu in cluster
ANDROID: sched/fair: return idle CPU immediately for prefer_idle
ANDROID: sched/fair: add idle state filter to prefer_idle case
ANDROID: sched/fair: remove order from CPU selection
ANDROID: sched/fair: unify spare capacity calculation
ANDROID:sched/fair: prefer energy efficient CPUs for !prefer_idle tasks
ANDROID: sched/fair: fix CPU selection for non latency sensitive tasks
ANDROID: sched/fair: Also do misfit in overloaded groups
ANDROID: sched/fair: Don't balance misfits if it would overload local group
ANDROID: sched/fair: Attempt to improve throughput for asym cap systems
FROMLIST: sched/fair: Don't move tasks to lower capacity cpus unless necessary
FROMLIST: sched/core: Disable SD_PREFER_SIBLING on asymmetric cpu capacity domains
FROMLIST: sched/core: Disable SD_ASYM_CPUCAPACITY for root_domains without asymmetry
FROMLIST: sched/fair: Set rq->rd->overload when misfit
FROMLIST: sched: Wrap rq->rd->overload accesses with READ/WRITE_ONCE
FROMLIST: sched: Change root_domain->overload type to int
FROMLIST: sched/fair: Change prefer_sibling type to bool
FROMLIST: sched/fair: Consider misfit tasks when load-balancing
FROMLIST: sched: Add sched_group per-cpu max capacity
FROMLIST: sched/fair: Add group_misfit_task load-balance type
FROMLIST: sched: Add static_key for asymmetric cpu capacity optimizations
UPSTREAM: ANDROID: binder: change down_write to down_read
UPSTREAM: ANDROID: binder: correct the cmd print for BINDER_WORK_RETURN_ERROR
UPSTREAM: ANDROID: binder: remove 32-bit binder interface.
UPSTREAM: android: binder: Use true and false for boolean values
UPSTREAM: android: binder: Use octal permissions
UPSTREAM: android: binder: Prefer __func__ to using hardcoded function name
UPSTREAM: ANDROID: binder: make binder_alloc_new_buf_locked static and indent its arguments
UPSTREAM: android: binder: Check for errors in binder_alloc_shrinker_init().
Conflicts:
arch/arm64/Kconfig
arch/arm64/include/asm/cpucaps.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/thread_info.h
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/entry.S
arch/arm64/kernel/ssbd.c
drivers/base/arch_topology.c
drivers/md/Kconfig
drivers/scsi/ufs/ufshcd.c
drivers/usb/gadget/function/f_fs.c
include/trace/events/sched.h
kernel/sched/cpufreq_schedutil.c
kernel/sched/energy.c
kernel/sched/fair.c
kernel/sched/features.h
kernel/sched/sched.h
kernel/sched/topology.c
kernel/sched/tune.c
kernel/sched/walt.c
kernel/sched/walt.h
kernel/stop_machine.c
kernel/time/tick-sched.c
net/socket.c
sound/core/rawmidi.c
Change-Id: Ia246711317930ecd55bb42565a04e6b4fdfc26d2
Signed-off-by: Isaac J. Manjarres <isaacm@codeaurora.org>
1035 lines
26 KiB
C
1035 lines
26 KiB
C
/*
|
|
* RTC subsystem, interface functions
|
|
*
|
|
* Copyright (C) 2005 Tower Technologies
|
|
* Author: Alessandro Zummo <a.zummo@towertech.it>
|
|
*
|
|
* based on arch/arm/common/rtctime.c
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <linux/rtc.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/module.h>
|
|
#include <linux/log2.h>
|
|
#include <linux/workqueue.h>
|
|
|
|
static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer);
|
|
static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer);
|
|
|
|
static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
|
|
{
|
|
int err;
|
|
if (!rtc->ops)
|
|
err = -ENODEV;
|
|
else if (!rtc->ops->read_time)
|
|
err = -EINVAL;
|
|
else {
|
|
memset(tm, 0, sizeof(struct rtc_time));
|
|
err = rtc->ops->read_time(rtc->dev.parent, tm);
|
|
if (err < 0) {
|
|
dev_dbg(&rtc->dev, "read_time: fail to read: %d\n",
|
|
err);
|
|
return err;
|
|
}
|
|
|
|
err = rtc_valid_tm(tm);
|
|
if (err < 0)
|
|
dev_dbg(&rtc->dev, "read_time: rtc_time isn't valid\n");
|
|
}
|
|
return err;
|
|
}
|
|
|
|
int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
|
|
{
|
|
int err;
|
|
|
|
err = mutex_lock_interruptible(&rtc->ops_lock);
|
|
if (err)
|
|
return err;
|
|
|
|
err = __rtc_read_time(rtc, tm);
|
|
mutex_unlock(&rtc->ops_lock);
|
|
return err;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rtc_read_time);
|
|
|
|
int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
|
|
{
|
|
int err;
|
|
|
|
err = rtc_valid_tm(tm);
|
|
if (err != 0)
|
|
return err;
|
|
|
|
err = mutex_lock_interruptible(&rtc->ops_lock);
|
|
if (err)
|
|
return err;
|
|
|
|
if (!rtc->ops)
|
|
err = -ENODEV;
|
|
else if (rtc->ops->set_time)
|
|
err = rtc->ops->set_time(rtc->dev.parent, tm);
|
|
else if (rtc->ops->set_mmss64) {
|
|
time64_t secs64 = rtc_tm_to_time64(tm);
|
|
|
|
err = rtc->ops->set_mmss64(rtc->dev.parent, secs64);
|
|
} else if (rtc->ops->set_mmss) {
|
|
time64_t secs64 = rtc_tm_to_time64(tm);
|
|
err = rtc->ops->set_mmss(rtc->dev.parent, secs64);
|
|
} else
|
|
err = -EINVAL;
|
|
|
|
pm_stay_awake(rtc->dev.parent);
|
|
mutex_unlock(&rtc->ops_lock);
|
|
/* A timer might have just expired */
|
|
schedule_work(&rtc->irqwork);
|
|
return err;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rtc_set_time);
|
|
|
|
static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
|
{
|
|
int err;
|
|
|
|
err = mutex_lock_interruptible(&rtc->ops_lock);
|
|
if (err)
|
|
return err;
|
|
|
|
if (rtc->ops == NULL)
|
|
err = -ENODEV;
|
|
else if (!rtc->ops->read_alarm)
|
|
err = -EINVAL;
|
|
else {
|
|
alarm->enabled = 0;
|
|
alarm->pending = 0;
|
|
alarm->time.tm_sec = -1;
|
|
alarm->time.tm_min = -1;
|
|
alarm->time.tm_hour = -1;
|
|
alarm->time.tm_mday = -1;
|
|
alarm->time.tm_mon = -1;
|
|
alarm->time.tm_year = -1;
|
|
alarm->time.tm_wday = -1;
|
|
alarm->time.tm_yday = -1;
|
|
alarm->time.tm_isdst = -1;
|
|
err = rtc->ops->read_alarm(rtc->dev.parent, alarm);
|
|
}
|
|
|
|
mutex_unlock(&rtc->ops_lock);
|
|
return err;
|
|
}
|
|
|
|
int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
|
{
|
|
int err;
|
|
struct rtc_time before, now;
|
|
int first_time = 1;
|
|
time64_t t_now, t_alm;
|
|
enum { none, day, month, year } missing = none;
|
|
unsigned days;
|
|
|
|
/* The lower level RTC driver may return -1 in some fields,
|
|
* creating invalid alarm->time values, for reasons like:
|
|
*
|
|
* - The hardware may not be capable of filling them in;
|
|
* many alarms match only on time-of-day fields, not
|
|
* day/month/year calendar data.
|
|
*
|
|
* - Some hardware uses illegal values as "wildcard" match
|
|
* values, which non-Linux firmware (like a BIOS) may try
|
|
* to set up as e.g. "alarm 15 minutes after each hour".
|
|
* Linux uses only oneshot alarms.
|
|
*
|
|
* When we see that here, we deal with it by using values from
|
|
* a current RTC timestamp for any missing (-1) values. The
|
|
* RTC driver prevents "periodic alarm" modes.
|
|
*
|
|
* But this can be racey, because some fields of the RTC timestamp
|
|
* may have wrapped in the interval since we read the RTC alarm,
|
|
* which would lead to us inserting inconsistent values in place
|
|
* of the -1 fields.
|
|
*
|
|
* Reading the alarm and timestamp in the reverse sequence
|
|
* would have the same race condition, and not solve the issue.
|
|
*
|
|
* So, we must first read the RTC timestamp,
|
|
* then read the RTC alarm value,
|
|
* and then read a second RTC timestamp.
|
|
*
|
|
* If any fields of the second timestamp have changed
|
|
* when compared with the first timestamp, then we know
|
|
* our timestamp may be inconsistent with that used by
|
|
* the low-level rtc_read_alarm_internal() function.
|
|
*
|
|
* So, when the two timestamps disagree, we just loop and do
|
|
* the process again to get a fully consistent set of values.
|
|
*
|
|
* This could all instead be done in the lower level driver,
|
|
* but since more than one lower level RTC implementation needs it,
|
|
* then it's probably best best to do it here instead of there..
|
|
*/
|
|
|
|
/* Get the "before" timestamp */
|
|
err = rtc_read_time(rtc, &before);
|
|
if (err < 0)
|
|
return err;
|
|
do {
|
|
if (!first_time)
|
|
memcpy(&before, &now, sizeof(struct rtc_time));
|
|
first_time = 0;
|
|
|
|
/* get the RTC alarm values, which may be incomplete */
|
|
err = rtc_read_alarm_internal(rtc, alarm);
|
|
if (err)
|
|
return err;
|
|
|
|
/* full-function RTCs won't have such missing fields */
|
|
if (rtc_valid_tm(&alarm->time) == 0)
|
|
return 0;
|
|
|
|
/* get the "after" timestamp, to detect wrapped fields */
|
|
err = rtc_read_time(rtc, &now);
|
|
if (err < 0)
|
|
return err;
|
|
|
|
/* note that tm_sec is a "don't care" value here: */
|
|
} while ( before.tm_min != now.tm_min
|
|
|| before.tm_hour != now.tm_hour
|
|
|| before.tm_mon != now.tm_mon
|
|
|| before.tm_year != now.tm_year);
|
|
|
|
/* Fill in the missing alarm fields using the timestamp; we
|
|
* know there's at least one since alarm->time is invalid.
|
|
*/
|
|
if (alarm->time.tm_sec == -1)
|
|
alarm->time.tm_sec = now.tm_sec;
|
|
if (alarm->time.tm_min == -1)
|
|
alarm->time.tm_min = now.tm_min;
|
|
if (alarm->time.tm_hour == -1)
|
|
alarm->time.tm_hour = now.tm_hour;
|
|
|
|
/* For simplicity, only support date rollover for now */
|
|
if (alarm->time.tm_mday < 1 || alarm->time.tm_mday > 31) {
|
|
alarm->time.tm_mday = now.tm_mday;
|
|
missing = day;
|
|
}
|
|
if ((unsigned)alarm->time.tm_mon >= 12) {
|
|
alarm->time.tm_mon = now.tm_mon;
|
|
if (missing == none)
|
|
missing = month;
|
|
}
|
|
if (alarm->time.tm_year == -1) {
|
|
alarm->time.tm_year = now.tm_year;
|
|
if (missing == none)
|
|
missing = year;
|
|
}
|
|
|
|
/* Can't proceed if alarm is still invalid after replacing
|
|
* missing fields.
|
|
*/
|
|
err = rtc_valid_tm(&alarm->time);
|
|
if (err)
|
|
goto done;
|
|
|
|
/* with luck, no rollover is needed */
|
|
t_now = rtc_tm_to_time64(&now);
|
|
t_alm = rtc_tm_to_time64(&alarm->time);
|
|
if (t_now < t_alm)
|
|
goto done;
|
|
|
|
switch (missing) {
|
|
|
|
/* 24 hour rollover ... if it's now 10am Monday, an alarm that
|
|
* that will trigger at 5am will do so at 5am Tuesday, which
|
|
* could also be in the next month or year. This is a common
|
|
* case, especially for PCs.
|
|
*/
|
|
case day:
|
|
dev_dbg(&rtc->dev, "alarm rollover: %s\n", "day");
|
|
t_alm += 24 * 60 * 60;
|
|
rtc_time64_to_tm(t_alm, &alarm->time);
|
|
break;
|
|
|
|
/* Month rollover ... if it's the 31th, an alarm on the 3rd will
|
|
* be next month. An alarm matching on the 30th, 29th, or 28th
|
|
* may end up in the month after that! Many newer PCs support
|
|
* this type of alarm.
|
|
*/
|
|
case month:
|
|
dev_dbg(&rtc->dev, "alarm rollover: %s\n", "month");
|
|
do {
|
|
if (alarm->time.tm_mon < 11)
|
|
alarm->time.tm_mon++;
|
|
else {
|
|
alarm->time.tm_mon = 0;
|
|
alarm->time.tm_year++;
|
|
}
|
|
days = rtc_month_days(alarm->time.tm_mon,
|
|
alarm->time.tm_year);
|
|
} while (days < alarm->time.tm_mday);
|
|
break;
|
|
|
|
/* Year rollover ... easy except for leap years! */
|
|
case year:
|
|
dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year");
|
|
do {
|
|
alarm->time.tm_year++;
|
|
} while (!is_leap_year(alarm->time.tm_year + 1900)
|
|
&& rtc_valid_tm(&alarm->time) != 0);
|
|
break;
|
|
|
|
default:
|
|
dev_warn(&rtc->dev, "alarm rollover not handled\n");
|
|
}
|
|
|
|
err = rtc_valid_tm(&alarm->time);
|
|
|
|
done:
|
|
if (err) {
|
|
dev_warn(&rtc->dev, "invalid alarm value: %d-%d-%d %d:%d:%d\n",
|
|
alarm->time.tm_year + 1900, alarm->time.tm_mon + 1,
|
|
alarm->time.tm_mday, alarm->time.tm_hour, alarm->time.tm_min,
|
|
alarm->time.tm_sec);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
|
{
|
|
int err;
|
|
|
|
err = mutex_lock_interruptible(&rtc->ops_lock);
|
|
if (err)
|
|
return err;
|
|
if (rtc->ops == NULL)
|
|
err = -ENODEV;
|
|
else if (!rtc->ops->read_alarm)
|
|
err = -EINVAL;
|
|
else {
|
|
memset(alarm, 0, sizeof(struct rtc_wkalrm));
|
|
alarm->enabled = rtc->aie_timer.enabled;
|
|
alarm->time = rtc_ktime_to_tm(rtc->aie_timer.node.expires);
|
|
}
|
|
mutex_unlock(&rtc->ops_lock);
|
|
|
|
return err;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rtc_read_alarm);
|
|
|
|
static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
|
{
|
|
struct rtc_time tm;
|
|
time64_t now, scheduled;
|
|
int err;
|
|
|
|
err = rtc_valid_tm(&alarm->time);
|
|
if (err)
|
|
return err;
|
|
scheduled = rtc_tm_to_time64(&alarm->time);
|
|
|
|
/* Make sure we're not setting alarms in the past */
|
|
err = __rtc_read_time(rtc, &tm);
|
|
if (err)
|
|
return err;
|
|
now = rtc_tm_to_time64(&tm);
|
|
if (scheduled <= now)
|
|
return -ETIME;
|
|
/*
|
|
* XXX - We just checked to make sure the alarm time is not
|
|
* in the past, but there is still a race window where if
|
|
* the is alarm set for the next second and the second ticks
|
|
* over right here, before we set the alarm.
|
|
*/
|
|
|
|
if (!rtc->ops)
|
|
err = -ENODEV;
|
|
else if (!rtc->ops->set_alarm)
|
|
err = -EINVAL;
|
|
else
|
|
err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
|
|
|
|
return err;
|
|
}
|
|
|
|
int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
|
{
|
|
int err;
|
|
|
|
if (!rtc->ops)
|
|
return -ENODEV;
|
|
else if (!rtc->ops->set_alarm)
|
|
return -EINVAL;
|
|
|
|
err = rtc_valid_tm(&alarm->time);
|
|
if (err != 0)
|
|
return err;
|
|
|
|
err = mutex_lock_interruptible(&rtc->ops_lock);
|
|
if (err)
|
|
return err;
|
|
if (rtc->aie_timer.enabled)
|
|
rtc_timer_remove(rtc, &rtc->aie_timer);
|
|
|
|
rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
|
|
rtc->aie_timer.period = 0;
|
|
if (alarm->enabled)
|
|
err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
|
|
|
|
mutex_unlock(&rtc->ops_lock);
|
|
return err;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rtc_set_alarm);
|
|
|
|
static void rtc_alarm_disable(struct rtc_device *rtc)
|
|
{
|
|
if (!rtc->ops || !rtc->ops->alarm_irq_enable)
|
|
return;
|
|
|
|
rtc->ops->alarm_irq_enable(rtc->dev.parent, false);
|
|
}
|
|
|
|
/* Called once per device from rtc_device_register */
|
|
int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
|
{
|
|
int err;
|
|
struct rtc_time now;
|
|
|
|
err = rtc_valid_tm(&alarm->time);
|
|
if (err != 0)
|
|
return err;
|
|
|
|
err = rtc_read_time(rtc, &now);
|
|
if (err)
|
|
return err;
|
|
|
|
err = mutex_lock_interruptible(&rtc->ops_lock);
|
|
if (err)
|
|
return err;
|
|
|
|
rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
|
|
rtc->aie_timer.period = 0;
|
|
|
|
/* Alarm has to be enabled & in the future for us to enqueue it */
|
|
if (alarm->enabled && (rtc_tm_to_ktime(now) <
|
|
rtc->aie_timer.node.expires)) {
|
|
|
|
rtc->aie_timer.enabled = 1;
|
|
timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node);
|
|
} else if (alarm->enabled && (rtc_tm_to_ktime(now) >=
|
|
rtc->aie_timer.node.expires)){
|
|
rtc_alarm_disable(rtc);
|
|
}
|
|
|
|
mutex_unlock(&rtc->ops_lock);
|
|
return err;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rtc_initialize_alarm);
|
|
|
|
int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
|
|
{
|
|
int err = mutex_lock_interruptible(&rtc->ops_lock);
|
|
if (err)
|
|
return err;
|
|
|
|
if (rtc->aie_timer.enabled != enabled) {
|
|
if (enabled)
|
|
err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
|
|
else
|
|
rtc_timer_remove(rtc, &rtc->aie_timer);
|
|
}
|
|
|
|
if (err)
|
|
/* nothing */;
|
|
else if (!rtc->ops)
|
|
err = -ENODEV;
|
|
else if (!rtc->ops->alarm_irq_enable)
|
|
err = -EINVAL;
|
|
else
|
|
err = rtc->ops->alarm_irq_enable(rtc->dev.parent, enabled);
|
|
|
|
mutex_unlock(&rtc->ops_lock);
|
|
return err;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rtc_alarm_irq_enable);
|
|
|
|
int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
|
|
{
|
|
int err = mutex_lock_interruptible(&rtc->ops_lock);
|
|
if (err)
|
|
return err;
|
|
|
|
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
|
|
if (enabled == 0 && rtc->uie_irq_active) {
|
|
mutex_unlock(&rtc->ops_lock);
|
|
return rtc_dev_update_irq_enable_emul(rtc, 0);
|
|
}
|
|
#endif
|
|
/* make sure we're changing state */
|
|
if (rtc->uie_rtctimer.enabled == enabled)
|
|
goto out;
|
|
|
|
if (rtc->uie_unsupported) {
|
|
err = -EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
if (enabled) {
|
|
struct rtc_time tm;
|
|
ktime_t now, onesec;
|
|
|
|
__rtc_read_time(rtc, &tm);
|
|
onesec = ktime_set(1, 0);
|
|
now = rtc_tm_to_ktime(tm);
|
|
rtc->uie_rtctimer.node.expires = ktime_add(now, onesec);
|
|
rtc->uie_rtctimer.period = ktime_set(1, 0);
|
|
err = rtc_timer_enqueue(rtc, &rtc->uie_rtctimer);
|
|
} else
|
|
rtc_timer_remove(rtc, &rtc->uie_rtctimer);
|
|
|
|
out:
|
|
mutex_unlock(&rtc->ops_lock);
|
|
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
|
|
/*
|
|
* Enable emulation if the driver did not provide
|
|
* the update_irq_enable function pointer or if returned
|
|
* -EINVAL to signal that it has been configured without
|
|
* interrupts or that are not available at the moment.
|
|
*/
|
|
if (err == -EINVAL)
|
|
err = rtc_dev_update_irq_enable_emul(rtc, enabled);
|
|
#endif
|
|
return err;
|
|
|
|
}
|
|
EXPORT_SYMBOL_GPL(rtc_update_irq_enable);
|
|
|
|
|
|
/**
|
|
* rtc_handle_legacy_irq - AIE, UIE and PIE event hook
|
|
* @rtc: pointer to the rtc device
|
|
*
|
|
* This function is called when an AIE, UIE or PIE mode interrupt
|
|
* has occurred (or been emulated).
|
|
*
|
|
* Triggers the registered irq_task function callback.
|
|
*/
|
|
void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode)
|
|
{
|
|
unsigned long flags;
|
|
|
|
/* mark one irq of the appropriate mode */
|
|
spin_lock_irqsave(&rtc->irq_lock, flags);
|
|
rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF|mode);
|
|
spin_unlock_irqrestore(&rtc->irq_lock, flags);
|
|
|
|
/* call the task func */
|
|
spin_lock_irqsave(&rtc->irq_task_lock, flags);
|
|
if (rtc->irq_task)
|
|
rtc->irq_task->func(rtc->irq_task->private_data);
|
|
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
|
|
|
|
wake_up_interruptible(&rtc->irq_queue);
|
|
kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
|
|
}
|
|
|
|
|
|
/**
|
|
* rtc_aie_update_irq - AIE mode rtctimer hook
|
|
* @private: pointer to the rtc_device
|
|
*
|
|
* This functions is called when the aie_timer expires.
|
|
*/
|
|
void rtc_aie_update_irq(void *private)
|
|
{
|
|
struct rtc_device *rtc = (struct rtc_device *)private;
|
|
rtc_handle_legacy_irq(rtc, 1, RTC_AF);
|
|
}
|
|
|
|
|
|
/**
|
|
* rtc_uie_update_irq - UIE mode rtctimer hook
|
|
* @private: pointer to the rtc_device
|
|
*
|
|
* This functions is called when the uie_timer expires.
|
|
*/
|
|
void rtc_uie_update_irq(void *private)
|
|
{
|
|
struct rtc_device *rtc = (struct rtc_device *)private;
|
|
rtc_handle_legacy_irq(rtc, 1, RTC_UF);
|
|
}
|
|
|
|
|
|
/**
|
|
* rtc_pie_update_irq - PIE mode hrtimer hook
|
|
* @timer: pointer to the pie mode hrtimer
|
|
*
|
|
* This function is used to emulate PIE mode interrupts
|
|
* using an hrtimer. This function is called when the periodic
|
|
* hrtimer expires.
|
|
*/
|
|
enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer)
|
|
{
|
|
struct rtc_device *rtc;
|
|
ktime_t period;
|
|
int count;
|
|
rtc = container_of(timer, struct rtc_device, pie_timer);
|
|
|
|
period = NSEC_PER_SEC / rtc->irq_freq;
|
|
count = hrtimer_forward_now(timer, period);
|
|
|
|
rtc_handle_legacy_irq(rtc, count, RTC_PF);
|
|
|
|
return HRTIMER_RESTART;
|
|
}
|
|
|
|
/**
|
|
* rtc_update_irq - Triggered when a RTC interrupt occurs.
|
|
* @rtc: the rtc device
|
|
* @num: how many irqs are being reported (usually one)
|
|
* @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF
|
|
* Context: any
|
|
*/
|
|
void rtc_update_irq(struct rtc_device *rtc,
|
|
unsigned long num, unsigned long events)
|
|
{
|
|
if (IS_ERR_OR_NULL(rtc))
|
|
return;
|
|
|
|
pm_stay_awake(rtc->dev.parent);
|
|
schedule_work(&rtc->irqwork);
|
|
}
|
|
EXPORT_SYMBOL_GPL(rtc_update_irq);
|
|
|
|
static int __rtc_match(struct device *dev, const void *data)
|
|
{
|
|
const char *name = data;
|
|
|
|
if (strcmp(dev_name(dev), name) == 0)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
struct rtc_device *rtc_class_open(const char *name)
|
|
{
|
|
struct device *dev;
|
|
struct rtc_device *rtc = NULL;
|
|
|
|
dev = class_find_device(rtc_class, NULL, name, __rtc_match);
|
|
if (dev)
|
|
rtc = to_rtc_device(dev);
|
|
|
|
if (rtc) {
|
|
if (!try_module_get(rtc->owner)) {
|
|
put_device(dev);
|
|
rtc = NULL;
|
|
}
|
|
}
|
|
|
|
return rtc;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rtc_class_open);
|
|
|
|
void rtc_class_close(struct rtc_device *rtc)
|
|
{
|
|
module_put(rtc->owner);
|
|
put_device(&rtc->dev);
|
|
}
|
|
EXPORT_SYMBOL_GPL(rtc_class_close);
|
|
|
|
int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task)
|
|
{
|
|
int retval = -EBUSY;
|
|
|
|
if (task == NULL || task->func == NULL)
|
|
return -EINVAL;
|
|
|
|
/* Cannot register while the char dev is in use */
|
|
if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags))
|
|
return -EBUSY;
|
|
|
|
spin_lock_irq(&rtc->irq_task_lock);
|
|
if (rtc->irq_task == NULL) {
|
|
rtc->irq_task = task;
|
|
retval = 0;
|
|
}
|
|
spin_unlock_irq(&rtc->irq_task_lock);
|
|
|
|
clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
|
|
|
|
return retval;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rtc_irq_register);
|
|
|
|
void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task)
|
|
{
|
|
spin_lock_irq(&rtc->irq_task_lock);
|
|
if (rtc->irq_task == task)
|
|
rtc->irq_task = NULL;
|
|
spin_unlock_irq(&rtc->irq_task_lock);
|
|
}
|
|
EXPORT_SYMBOL_GPL(rtc_irq_unregister);
|
|
|
|
static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled)
|
|
{
|
|
/*
|
|
* We always cancel the timer here first, because otherwise
|
|
* we could run into BUG_ON(timer->state != HRTIMER_STATE_CALLBACK);
|
|
* when we manage to start the timer before the callback
|
|
* returns HRTIMER_RESTART.
|
|
*
|
|
* We cannot use hrtimer_cancel() here as a running callback
|
|
* could be blocked on rtc->irq_task_lock and hrtimer_cancel()
|
|
* would spin forever.
|
|
*/
|
|
if (hrtimer_try_to_cancel(&rtc->pie_timer) < 0)
|
|
return -1;
|
|
|
|
if (enabled) {
|
|
ktime_t period = NSEC_PER_SEC / rtc->irq_freq;
|
|
|
|
hrtimer_start(&rtc->pie_timer, period, HRTIMER_MODE_REL);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rtc_irq_set_state - enable/disable 2^N Hz periodic IRQs
|
|
* @rtc: the rtc device
|
|
* @task: currently registered with rtc_irq_register()
|
|
* @enabled: true to enable periodic IRQs
|
|
* Context: any
|
|
*
|
|
* Note that rtc_irq_set_freq() should previously have been used to
|
|
* specify the desired frequency of periodic IRQ task->func() callbacks.
|
|
*/
|
|
int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled)
|
|
{
|
|
int err = 0;
|
|
unsigned long flags;
|
|
|
|
retry:
|
|
spin_lock_irqsave(&rtc->irq_task_lock, flags);
|
|
if (rtc->irq_task != NULL && task == NULL)
|
|
err = -EBUSY;
|
|
else if (rtc->irq_task != task)
|
|
err = -EACCES;
|
|
else {
|
|
if (rtc_update_hrtimer(rtc, enabled) < 0) {
|
|
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
|
|
cpu_relax();
|
|
goto retry;
|
|
}
|
|
rtc->pie_enabled = enabled;
|
|
}
|
|
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
|
|
return err;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rtc_irq_set_state);
|
|
|
|
/**
|
|
* rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ
|
|
* @rtc: the rtc device
|
|
* @task: currently registered with rtc_irq_register()
|
|
* @freq: positive frequency with which task->func() will be called
|
|
* Context: any
|
|
*
|
|
* Note that rtc_irq_set_state() is used to enable or disable the
|
|
* periodic IRQs.
|
|
*/
|
|
int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
|
|
{
|
|
int err = 0;
|
|
unsigned long flags;
|
|
|
|
if (freq <= 0 || freq > RTC_MAX_FREQ)
|
|
return -EINVAL;
|
|
retry:
|
|
spin_lock_irqsave(&rtc->irq_task_lock, flags);
|
|
if (rtc->irq_task != NULL && task == NULL)
|
|
err = -EBUSY;
|
|
else if (rtc->irq_task != task)
|
|
err = -EACCES;
|
|
else {
|
|
rtc->irq_freq = freq;
|
|
if (rtc->pie_enabled && rtc_update_hrtimer(rtc, 1) < 0) {
|
|
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
|
|
cpu_relax();
|
|
goto retry;
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
|
|
return err;
|
|
}
|
|
EXPORT_SYMBOL_GPL(rtc_irq_set_freq);
|
|
|
|
/**
|
|
* rtc_timer_enqueue - Adds a rtc_timer to the rtc_device timerqueue
|
|
* @rtc rtc device
|
|
* @timer timer being added.
|
|
*
|
|
* Enqueues a timer onto the rtc devices timerqueue and sets
|
|
* the next alarm event appropriately.
|
|
*
|
|
* Sets the enabled bit on the added timer.
|
|
*
|
|
* Must hold ops_lock for proper serialization of timerqueue
|
|
*/
|
|
static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
|
|
{
|
|
struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue);
|
|
struct rtc_time tm;
|
|
ktime_t now;
|
|
|
|
timer->enabled = 1;
|
|
__rtc_read_time(rtc, &tm);
|
|
now = rtc_tm_to_ktime(tm);
|
|
|
|
/* Skip over expired timers */
|
|
while (next) {
|
|
if (next->expires >= now)
|
|
break;
|
|
next = timerqueue_iterate_next(next);
|
|
}
|
|
|
|
timerqueue_add(&rtc->timerqueue, &timer->node);
|
|
if (!next || ktime_before(timer->node.expires, next->expires)) {
|
|
struct rtc_wkalrm alarm;
|
|
int err;
|
|
alarm.time = rtc_ktime_to_tm(timer->node.expires);
|
|
alarm.enabled = 1;
|
|
err = __rtc_set_alarm(rtc, &alarm);
|
|
if (err == -ETIME) {
|
|
pm_stay_awake(rtc->dev.parent);
|
|
schedule_work(&rtc->irqwork);
|
|
} else if (err) {
|
|
timerqueue_del(&rtc->timerqueue, &timer->node);
|
|
timer->enabled = 0;
|
|
return err;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue
|
|
* @rtc rtc device
|
|
* @timer timer being removed.
|
|
*
|
|
* Removes a timer onto the rtc devices timerqueue and sets
|
|
* the next alarm event appropriately.
|
|
*
|
|
* Clears the enabled bit on the removed timer.
|
|
*
|
|
* Must hold ops_lock for proper serialization of timerqueue
|
|
*/
|
|
static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer)
|
|
{
|
|
struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue);
|
|
timerqueue_del(&rtc->timerqueue, &timer->node);
|
|
timer->enabled = 0;
|
|
if (next == &timer->node) {
|
|
struct rtc_wkalrm alarm;
|
|
int err;
|
|
next = timerqueue_getnext(&rtc->timerqueue);
|
|
if (!next) {
|
|
rtc_alarm_disable(rtc);
|
|
return;
|
|
}
|
|
alarm.time = rtc_ktime_to_tm(next->expires);
|
|
alarm.enabled = 1;
|
|
err = __rtc_set_alarm(rtc, &alarm);
|
|
if (err == -ETIME) {
|
|
pm_stay_awake(rtc->dev.parent);
|
|
schedule_work(&rtc->irqwork);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* rtc_timer_do_work - Expires rtc timers
|
|
* @rtc rtc device
|
|
* @timer timer being removed.
|
|
*
|
|
* Expires rtc timers. Reprograms next alarm event if needed.
|
|
* Called via worktask.
|
|
*
|
|
* Serializes access to timerqueue via ops_lock mutex
|
|
*/
|
|
void rtc_timer_do_work(struct work_struct *work)
|
|
{
|
|
struct rtc_timer *timer;
|
|
struct timerqueue_node *next;
|
|
ktime_t now;
|
|
struct rtc_time tm;
|
|
|
|
struct rtc_device *rtc =
|
|
container_of(work, struct rtc_device, irqwork);
|
|
|
|
mutex_lock(&rtc->ops_lock);
|
|
again:
|
|
__rtc_read_time(rtc, &tm);
|
|
now = rtc_tm_to_ktime(tm);
|
|
while ((next = timerqueue_getnext(&rtc->timerqueue))) {
|
|
if (next->expires > now)
|
|
break;
|
|
|
|
/* expire timer */
|
|
timer = container_of(next, struct rtc_timer, node);
|
|
timerqueue_del(&rtc->timerqueue, &timer->node);
|
|
timer->enabled = 0;
|
|
if (timer->task.func)
|
|
timer->task.func(timer->task.private_data);
|
|
|
|
/* Re-add/fwd periodic timers */
|
|
if (ktime_to_ns(timer->period)) {
|
|
timer->node.expires = ktime_add(timer->node.expires,
|
|
timer->period);
|
|
timer->enabled = 1;
|
|
timerqueue_add(&rtc->timerqueue, &timer->node);
|
|
}
|
|
}
|
|
|
|
/* Set next alarm */
|
|
if (next) {
|
|
struct rtc_wkalrm alarm;
|
|
int err;
|
|
int retry = 3;
|
|
|
|
alarm.time = rtc_ktime_to_tm(next->expires);
|
|
alarm.enabled = 1;
|
|
reprogram:
|
|
err = __rtc_set_alarm(rtc, &alarm);
|
|
if (err == -ETIME)
|
|
goto again;
|
|
else if (err) {
|
|
if (retry-- > 0)
|
|
goto reprogram;
|
|
|
|
timer = container_of(next, struct rtc_timer, node);
|
|
timerqueue_del(&rtc->timerqueue, &timer->node);
|
|
timer->enabled = 0;
|
|
dev_err(&rtc->dev, "__rtc_set_alarm: err=%d\n", err);
|
|
goto again;
|
|
}
|
|
} else
|
|
rtc_alarm_disable(rtc);
|
|
|
|
pm_relax(rtc->dev.parent);
|
|
mutex_unlock(&rtc->ops_lock);
|
|
}
|
|
|
|
|
|
/* rtc_timer_init - Initializes an rtc_timer
|
|
* @timer: timer to be intiialized
|
|
* @f: function pointer to be called when timer fires
|
|
* @data: private data passed to function pointer
|
|
*
|
|
* Kernel interface to initializing an rtc_timer.
|
|
*/
|
|
void rtc_timer_init(struct rtc_timer *timer, void (*f)(void *p), void *data)
|
|
{
|
|
timerqueue_init(&timer->node);
|
|
timer->enabled = 0;
|
|
timer->task.func = f;
|
|
timer->task.private_data = data;
|
|
}
|
|
|
|
/* rtc_timer_start - Sets an rtc_timer to fire in the future
|
|
* @ rtc: rtc device to be used
|
|
* @ timer: timer being set
|
|
* @ expires: time at which to expire the timer
|
|
* @ period: period that the timer will recur
|
|
*
|
|
* Kernel interface to set an rtc_timer
|
|
*/
|
|
int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer,
|
|
ktime_t expires, ktime_t period)
|
|
{
|
|
int ret = 0;
|
|
mutex_lock(&rtc->ops_lock);
|
|
if (timer->enabled)
|
|
rtc_timer_remove(rtc, timer);
|
|
|
|
timer->node.expires = expires;
|
|
timer->period = period;
|
|
|
|
ret = rtc_timer_enqueue(rtc, timer);
|
|
|
|
mutex_unlock(&rtc->ops_lock);
|
|
return ret;
|
|
}
|
|
|
|
/* rtc_timer_cancel - Stops an rtc_timer
|
|
* @ rtc: rtc device to be used
|
|
* @ timer: timer being set
|
|
*
|
|
* Kernel interface to cancel an rtc_timer
|
|
*/
|
|
void rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer)
|
|
{
|
|
mutex_lock(&rtc->ops_lock);
|
|
if (timer->enabled)
|
|
rtc_timer_remove(rtc, timer);
|
|
mutex_unlock(&rtc->ops_lock);
|
|
}
|
|
|
|
/**
|
|
* rtc_read_offset - Read the amount of rtc offset in parts per billion
|
|
* @ rtc: rtc device to be used
|
|
* @ offset: the offset in parts per billion
|
|
*
|
|
* see below for details.
|
|
*
|
|
* Kernel interface to read rtc clock offset
|
|
* Returns 0 on success, or a negative number on error.
|
|
* If read_offset() is not implemented for the rtc, return -EINVAL
|
|
*/
|
|
int rtc_read_offset(struct rtc_device *rtc, long *offset)
|
|
{
|
|
int ret;
|
|
|
|
if (!rtc->ops)
|
|
return -ENODEV;
|
|
|
|
if (!rtc->ops->read_offset)
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&rtc->ops_lock);
|
|
ret = rtc->ops->read_offset(rtc->dev.parent, offset);
|
|
mutex_unlock(&rtc->ops_lock);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* rtc_set_offset - Adjusts the duration of the average second
|
|
* @ rtc: rtc device to be used
|
|
* @ offset: the offset in parts per billion
|
|
*
|
|
* Some rtc's allow an adjustment to the average duration of a second
|
|
* to compensate for differences in the actual clock rate due to temperature,
|
|
* the crystal, capacitor, etc.
|
|
*
|
|
* Kernel interface to adjust an rtc clock offset.
|
|
* Return 0 on success, or a negative number on error.
|
|
* If the rtc offset is not setable (or not implemented), return -EINVAL
|
|
*/
|
|
int rtc_set_offset(struct rtc_device *rtc, long offset)
|
|
{
|
|
int ret;
|
|
|
|
if (!rtc->ops)
|
|
return -ENODEV;
|
|
|
|
if (!rtc->ops->set_offset)
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&rtc->ops_lock);
|
|
ret = rtc->ops->set_offset(rtc->dev.parent, offset);
|
|
mutex_unlock(&rtc->ops_lock);
|
|
return ret;
|
|
}
|