Files
bengris32 dc38585c87 Merge branch 'android-4.19-stable' of https://android.googlesource.com/kernel/common into lineage-21
* 'android-4.19-stable' of https://android.googlesource.com/kernel/common:
  Revert "UPSTREAM: unicode: Don't special case ignorable code points"
  Reapply "UPSTREAM: unicode: Don't special case ignorable code points"
  Revert "UPSTREAM: unicode: Don't special case ignorable code points"
  Linux 4.19.325
  sh: intc: Fix use-after-free bug in register_intc_controller()
  modpost: remove incorrect code in do_eisa_entry()
  9p/xen: fix release of IRQ
  9p/xen: fix init sequence
  block: return unsigned int from bdev_io_min
  jffs2: fix use of uninitialized variable
  ubi: fastmap: Fix duplicate slab cache names while attaching
  ubifs: Correct the total block count by deducting journal reservation
  rtc: check if __rtc_read_time was successful in rtc_timer_do_work()
  NFSv4.0: Fix a use-after-free problem in the asynchronous open()
  um: Fix the return value of elf_core_copy_task_fpregs
  rpmsg: glink: Propagate TX failures in intentless mode as well
  NFSD: Prevent a potential integer overflow
  lib: string_helpers: silence snprintf() output truncation warning
  usb: dwc3: gadget: Fix checking for number of TRBs left
  media: wl128x: Fix atomicity violation in fmc_send_cmd()
  HID: wacom: Interpret tilt data from Intuos Pro BT as signed values
  block: fix ordering between checking BLK_MQ_S_STOPPED request adding
  arm64: tls: Fix context-switching of tpidrro_el0 when kpti is enabled
  sh: cpuinfo: Fix a warning for CONFIG_CPUMASK_OFFSTACK
  um: vector: Do not use drvdata in release
  serial: 8250: omap: Move pm_runtime_get_sync
  um: net: Do not use drvdata in release
  um: ubd: Do not use drvdata in release
  ubi: wl: Put source PEB into correct list if trying locking LEB failed
  spi: Fix acpi deferred irq probe
  netfilter: ipset: add missing range check in bitmap_ip_uadt
  Revert "serial: sh-sci: Clean sci_ports[0] after at earlycon exit"
  serial: sh-sci: Clean sci_ports[0] after at earlycon exit
  Revert "usb: gadget: composite: fix OS descriptors w_value logic"
  ALSA: usb-audio: Fix potential out-of-bound accesses for Extigy and Mbox devices
  Bluetooth: Fix type of len in rfcomm_sock_getsockopt{,_old}()
  tty: ldsic: fix tty_ldisc_autoload sysctl's proc_handler
  PCI: Fix use-after-free of slot->bus on hot remove
  ASoC: codecs: Fix atomicity violation in snd_soc_component_get_drvdata()
  jfs: xattr: check invalid xattr size more strictly
  ext4: fix FS_IOC_GETFSMAP handling
  ext4: supress data-race warnings in ext4_free_inodes_{count,set}()
  usb: ehci-spear: fix call balance of sehci clk handling routines
  apparmor: fix 'Do simple duplicate message elimination'
  misc: apds990x: Fix missing pm_runtime_disable()
  USB: chaoskey: Fix possible deadlock chaoskey_list_lock
  USB: chaoskey: fail open after removal
  usb: using mutex lock and supporting O_NONBLOCK flag in iowarrior_read()
  net: stmmac: dwmac-socfpga: Set RX watchdog interrupt as broken
  marvell: pxa168_eth: fix call balance of pep->clk handling routines
  net: usb: lan78xx: Fix refcounting and autosuspend on invalid WoL configuration
  tg3: Set coherent DMA mask bits to 31 for BCM57766 chipsets
  net: usb: lan78xx: Fix memory leak on device unplug by freeing PHY device
  power: supply: core: Remove might_sleep() from power_supply_put()
  vfio/pci: Properly hide first-in-list PCIe extended capability
  NFSD: Cap the number of bytes copied by nfs4_reset_recoverydir()
  NFSD: Prevent NULL dereference in nfsd4_process_cb_update()
  rpmsg: glink: use only lower 16-bits of param2 for CMD_OPEN name length
  rpmsg: glink: Fix GLINK command prefix
  rpmsg: glink: Send READ_NOTIFY command in FIFO full case
  rpmsg: glink: Add TX_DATA_CONT command while sending
  m68k: coldfire/device.c: only build FEC when HW macros are defined
  m68k: mcfgpio: Fix incorrect register offset for CONFIG_M5441x
  PCI: cpqphp: Fix PCIBIOS_* return value confusion
  PCI: cpqphp: Use PCI_POSSIBLE_ERROR() to check config reads
  perf probe: Correct demangled symbols in C++ program
  clk: clk-axi-clkgen: make sure to enable the AXI bus clock
  clk: axi-clkgen: use devm_platform_ioremap_resource() short-hand
  dt-bindings: clock: axi-clkgen: include AXI clk
  dt-bindings: clock: adi,axi-clkgen: convert old binding to yaml format
  fbdev: sh7760fb: Fix a possible memory leak in sh7760fb_alloc_mem()
  fbdev/sh7760fb: Alloc DMA memory from hardware device
  powerpc/sstep: make emulate_vsx_load and emulate_vsx_store static
  ocfs2: fix uninitialized value in ocfs2_file_read_iter()
  scsi: qedi: Fix a possible memory leak in qedi_alloc_and_init_sb()
  scsi: fusion: Remove unused variable 'rc'
  scsi: bfa: Fix use-after-free in bfad_im_module_exit()
  mfd: rt5033: Fix missing regmap_del_irq_chip()
  RDMA/bnxt_re: Check cqe flags to know imm_data vs inv_irkey
  mtd: rawnand: atmel: Fix possible memory leak
  cpufreq: loongson2: Unregister platform_driver on failure
  mfd: da9052-spi: Change read-mask to write-mask
  powerpc/vdso: Flag VDSO64 entry points as functions
  trace/trace_event_perf: remove duplicate samples on the first tracepoint event
  netpoll: Use rcu_access_pointer() in netpoll_poll_lock
  ALSA: 6fire: Release resources at card release
  ALSA: caiaq: Use snd_card_free_when_closed() at disconnection
  ALSA: us122l: Use snd_card_free_when_closed() at disconnection
  net: rfkill: gpio: Add check for clk_enable()
  drm/etnaviv: hold GPU lock across perfmon sampling
  drm/etnaviv: fix power register offset on GC300
  drm/etnaviv: dump: fix sparse warnings
  drm/etnaviv: consolidate hardware fence handling in etnaviv_gpu
  wifi: mwifiex: Fix memcpy() field-spanning write warning in mwifiex_config_scan()
  bpf: Fix the xdp_adjust_tail sample prog issue
  drm/omap: Fix locking in omap_gem_new_dmabuf()
  wifi: ath9k: add range check for conn_rsp_epid in htc_connect_service()
  drm/mm: Mark drm_mm_interval_tree*() functions with __maybe_unused
  firmware: arm_scpi: Check the DVFS OPP count returned by the firmware
  regmap: irq: Set lockdep class for hierarchical IRQ domains
  ARM: dts: cubieboard4: Fix DCDC5 regulator constraints
  mmc: mmc_spi: drop buggy snprintf()
  soc: qcom: geni-se: fix array underflow in geni_se_clk_tbl_get()
  time: Fix references to _msecs_to_jiffies() handling of values
  crypto: cavium - Fix an error handling path in cpt_ucode_load_fw()
  crypto: bcm - add error check in the ahash_hmac_init function
  crypto: cavium - Fix the if condition to exit loop after timeout
  crypto: pcrypt - Call crypto layer directly when padata_do_parallel() return -EBUSY
  EDAC/fsl_ddr: Fix bad bit shift operations
  hfsplus: don't query the device logical block size multiple times
  s390/syscalls: Avoid creation of arch/arch/ directory
  acpi/arm64: Adjust error handling procedure in gtdt_parse_timer_block()
  m68k: mvme147: Reinstate early console
  m68k: mvme16x: Add and use "mvme16x.h"
  m68k: mvme147: Fix SCSI controller IRQ numbers
  initramfs: avoid filename buffer overrun
  nvme: fix metadata handling in nvme-passthrough
  proc/softirqs: replace seq_printf with seq_put_decimal_ull_width
  net: usb: qmi_wwan: add Quectel RG650V
  x86/amd_nb: Fix compile-testing without CONFIG_AMD_NB
  selftests/watchdog-test: Fix system accidentally reset after watchdog-test
  mac80211: fix user-power when emulating chanctx
  ASoC: Intel: bytcr_rt5640: Add DMI quirk for Vexia Edu Atla 10 tablet
  mm: revert "mm: shmem: fix data-race in shmem_getattr()"
  kbuild: Use uname for LINUX_COMPILE_HOST detection
  media: dvbdev: fix the logic when DVB_DYNAMIC_MINORS is not set
  Revert "mmc: dw_mmc: Fix IDMAC operation with pages bigger than 4K"
  nilfs2: fix null-ptr-deref in block_dirty_buffer tracepoint
  ocfs2: fix UBSAN warning in ocfs2_verify_volume()
  nilfs2: fix null-ptr-deref in block_touch_buffer tracepoint
  ocfs2: uncache inode which has failed entering the group
  netlink: terminate outstanding dump on socket close
  Linux 4.19.324
  9p: fix slab cache name creation for real
  net: usb: qmi_wwan: add Fibocom FG132 0x0112 composition
  fs: Fix uninitialized value issue in from_kuid and from_kgid
  powerpc/powernv: Free name on error in opal_event_init()
  sound: Make CONFIG_SND depend on INDIRECT_IOMEM instead of UML
  bpf: use kvzmalloc to allocate BPF verifier environment
  HID: multitouch: Add quirk for HONOR MagicBook Art 14 touchpad
  9p: Avoid creating multiple slab caches with the same name
  ALSA: usb-audio: Add endianness annotations
  vsock/virtio: Initialization of the dangling pointer occurring in vsk->trans
  hv_sock: Initializing vsk->trans to NULL to prevent a dangling pointer
  ALSA: usb-audio: Add quirks for Dell WD19 dock
  ALSA: usb-audio: Support jack detection on Dell dock
  ALSA: usb-audio: Add custom mixer status quirks for RME CC devices
  ALSA: pcm: Return 0 when size < start_threshold in capture
  ocfs2: remove entry once instead of null-ptr-dereference in ocfs2_xa_remove()
  irqchip/gic-v3: Force propagation of the active state with a read-back
  USB: serial: option: add Quectel RG650V
  USB: serial: option: add Fibocom FG132 0x0112 composition
  USB: serial: qcserial: add support for Sierra Wireless EM86xx
  USB: serial: io_edgeport: fix use after free in debug printk
  usb: musb: sunxi: Fix accessing an released usb phy
  fs/proc: fix compile warning about variable 'vmcore_mmap_ops'
  media: uvcvideo: Skip parsing frames of type UVC_VS_UNDEFINED in uvc_parse_format
  net: bridge: xmit: make sure we have at least eth header len bytes
  bonding (gcc13): synchronize bond_{a,t}lb_xmit() types
  btrfs: reinitialize delayed ref list after deleting it from the list
  nfs: Fix KMSAN warning in decode_getfattr_attrs()
  dm-unstriped: cast an operand to sector_t to prevent potential uint32_t overflow
  dm cache: fix potential out-of-bounds access on the first resume
  dm cache: optimize dirty bit checking with find_next_bit when resizing
  dm cache: fix out-of-bounds access to the dirty bitset when resizing
  dm cache: correct the number of origin blocks to match the target length
  drm/amdgpu: prevent NULL pointer dereference if ATIF is not supported
  drm/amdgpu: add missing size check in amdgpu_debugfs_gprwave_read()
  media: v4l2-tpg: prevent the risk of a division by zero
  media: cx24116: prevent overflows on SNR calculus
  media: s5p-jpeg: prevent buffer overflows
  ALSA: firewire-lib: fix return value on fail in amdtp_tscm_init()
  media: adv7604: prevent underflow condition when reporting colorspace
  media: dvb_frontend: don't play tricks with underflow values
  media: dvbdev: prevent the risk of out of memory access
  media: stb0899_algo: initialize cfr before using it
  net: hns3: fix kernel crash when uninstalling driver
  can: c_can: fix {rx,tx}_errors statistics
  sctp: properly validate chunk size in sctp_sf_ootb()
  security/keys: fix slab-out-of-bounds in key_task_permission
  HID: core: zero-initialize the report buffer
  ARM: dts: rockchip: Fix the realtek audio codec on rk3036-kylin
  ARM: dts: rockchip: drop grf reference from rk3036 hdmi
  ARM: dts: rockchip: fix rk3036 acodec node
  arm64: dts: rockchip: Fix rt5651 compatible value on rk3399-sapphire-excavator
  Linux 4.19.323
  vt: prevent kernel-infoleak in con_font_get()
  mm: shmem: fix data-race in shmem_getattr()
  nilfs2: fix kernel bug due to missing clearing of checked flag
  ocfs2: pass u64 to ocfs2_truncate_inline maybe overflow
  nilfs2: fix potential deadlock with newly created symlinks
  wifi: iwlegacy: Clear stale interrupts before resuming device
  wifi: ath10k: Fix memory leak in management tx
  wifi: mac80211: do not pass a stopped vif to the driver in .get_txpower
  Revert "driver core: Fix uevent_show() vs driver detach race"
  xhci: Fix Link TRB DMA in command ring stopped completion event
  usb: phy: Fix API devm_usb_put_phy() can not release the phy
  usbip: tools: Fix detach_port() invalid port error path
  misc: sgi-gru: Don't disable preemption in GRU driver
  net: amd: mvme147: Fix probe banner message
  firmware: arm_sdei: Fix the input parameter of cpuhp_remove_state()
  netfilter: nft_payload: sanitize offset and length before calling skb_checksum()
  net: skip offload for NETIF_F_IPV6_CSUM if ipv6 header contains extension
  net: support ip generic csum processing in skb_csum_hwoffload_help
  bpf: Fix out-of-bounds write in trie_get_next_key()
  net/sched: stop qdisc_tree_reduce_backlog on TC_H_ROOT
  gtp: allow -1 to be specified as file description from userspace
  gtp: simplify error handling code in 'gtp_encap_enable()'
  wifi: mac80211: skip non-uploaded keys in ieee80211_iter_keys
  cgroup: Fix potential overflow issue when checking max_depth
  usb: dwc3: core: Stop processing of pending events if controller is halted
  usb: dwc3: Add splitdisable quirk for Hisilicon Kirin Soc
  usb: dwc3: remove generic PHY calibrate() calls
  xfrm: validate new SA's prefixlen using SA family when sel.family is unset
  arm64/uprobes: change the uprobe_opcode_t typedef to fix the sparse warning
  selinux: improve error checking in sel_write_load()
  hv_netvsc: Fix VF namespace also in synthetic NIC NETDEV_REGISTER event
  nilfs2: fix kernel bug due to missing clearing of buffer delay flag
  ACPI: button: Add DMI quirk for Samsung Galaxy Book2 to fix initial lid detection issue
  drm/amd: Guard against bad data for ATIF ACPI method
  ALSA: hda/realtek: Update default depop procedure
  posix-clock: posix-clock: Fix unbalanced locking in pc_clock_settime()
  net: usb: usbnet: fix name regression
  be2net: fix potential memory leak in be_xmit()
  net/sun3_82586: fix potential memory leak in sun3_82586_send_packet()
  jfs: Fix sanity check in dbMount
  udf: fix uninit-value use in udf_get_fileshortad
  KVM: s390: gaccess: Check if guest address is in memslot
  KVM: s390: gaccess: Cleanup access to guest pages
  KVM: s390: gaccess: Refactor access address range check
  KVM: s390: gaccess: Refactor gpa and length calculation
  arm64: probes: Fix uprobes for big-endian kernels
  arm64:uprobe fix the uprobe SWBP_INSN in big-endian
  Bluetooth: bnep: fix wild-memory-access in proto_unregister
  usb: typec: altmode should keep reference to parent
  net: systemport: fix potential memory leak in bcm_sysport_xmit()
  net: ethernet: aeroflex: fix potential memory leak in greth_start_xmit_gbit()
  macsec: don't increment counters for an unrelated SA
  drm/msm/dsi: fix 32-bit signed integer extension in pclk_rate calculation
  RDMA/bnxt_re: Return more meaningful error
  RDMA/cxgb4: Fix RDMA_CM_EVENT_UNREACHABLE error for iWARP
  RDMA/bnxt_re: Fix incorrect AVID type in WQE structure
  clk: Fix slab-out-of-bounds error in devm_clk_release()
  clk: Fix pointer casting to prevent oops in devm_clk_release()
  nilfs2: propagate directory read errors from nilfs_find_entry()
  x86/apic: Always explicitly disarm TSC-deadline timer
  parport: Proper fix for array out-of-bounds access
  USB: serial: option: add Telit FN920C04 MBIM compositions
  USB: serial: option: add support for Quectel EG916Q-GL
  xhci: Fix incorrect stream context type macro
  Bluetooth: btusb: Fix regression with fake CSR controllers 0a12:0001
  Bluetooth: Remove debugfs directory on module init failure
  iio: light: opt3001: add missing full-scale range value
  iio: hid-sensors: Fix an error handling path in _hid_sensor_set_report_latency()
  iio: adc: ti-ads8688: add missing select IIO_(TRIGGERED_)BUFFER in Kconfig
  iio: dac: stm32-dac-core: add missing select REGMAP_MMIO in Kconfig
  drm/vmwgfx: Handle surface check failure correctly
  x86/cpufeatures: Define X86_FEATURE_AMD_IBPB_RET
  KVM: s390: Change virtual to physical address access in diag 0x258 handler
  s390/sclp_vt220: Convert newlines to CRLF instead of LFCR
  net: dsa: mv88e6xxx: Fix out-of-bound access
  KVM: Fix a data race on last_boosted_vcpu in kvm_vcpu_on_spin()
  fat: fix uninitialized variable
  PCI: Add function 0 DMA alias quirk for Glenfly Arise chip
  arm64: probes: Fix simulate_ldr*_literal()
  arm64: probes: Remove broken LDR (literal) uprobe support
  posix-clock: Fix missing timespec64 check in pc_clock_settime()
  net: Fix an unsafe loop on the list
  usb: storage: ignore bogus device raised by JieLi BR21 USB sound chip
  usb: xhci: Fix problem with xhci resume from suspend
  Revert "usb: yurex: Replace snprintf() with the safer scnprintf() variant"
  HID: plantronics: Workaround for an unexcepted opposite volume key
  CDC-NCM: avoid overflow in sanity checking
  net: ipv6: ensure we call ipv6_mc_down() at most once
  ppp: fix ppp_async_encode() illegal access
  net: ibm: emac: mal: fix wrong goto
  igb: Do not bring the device up after non-fatal error
  gpio: aspeed: Use devm_clk api to manage clock source
  clk: Provide new devm_clk helpers for prepared and enabled clocks
  clk: generalize devm_clk_get() a bit
  clk: Add (devm_)clk_get_optional() functions
  gpio: aspeed: Add the flush write to ensure the write complete.
  Bluetooth: RFCOMM: FIX possible deadlock in rfcomm_sk_state_change
  netfilter: br_netfilter: fix panic with metadata_dst skb
  tcp: fix tcp_enter_recovery() to zero retrans_stamp when it's safe
  SUNRPC: Fix integer overflow in decode_rc_list()
  NFS: Remove print_overflow_msg()
  fbdev: sisfb: Fix strbuf array overflow
  driver core: bus: Return -EIO instead of 0 when show/store invalid bus attribute
  tools/iio: Add memory allocation failure check for trigger_name
  usb: chipidea: udc: enable suspend interrupt after usb reset
  media: videobuf2-core: clear memory related fields in __vb2_plane_dmabuf_put()
  PCI: Mark Creative Labs EMU20k2 INTx masking as broken
  i2c: i801: Use a different adapter-name for IDF adapters
  clk: bcm: bcm53573: fix OF node leak in init
  ktest.pl: Avoid false positives with grub2 skip regex
  s390/cpum_sf: Remove WARN_ON_ONCE statements
  ext4: nested locking for xattr inode
  s390/mm: Add cond_resched() to cmm_alloc/free_pages()
  s390/facility: Disable compile time optimization for decompressor code
  bpf: Check percpu map value size first
  Input: synaptics-rmi4 - fix UAF of IRQ domain on driver removal
  virtio_console: fix misc probe bugs
  drm/crtc: fix uninitialized variable use even harder
  drm: Move drm_mode_setcrtc() local re-init to failure path
  tracing: Remove precision vsnprintf() check from print event
  net: ethernet: cortina: Drop TSO support
  ext4: fix inode tree inconsistency caused by ENOMEM
  ACPI: battery: Fix possible crash when unregistering a battery hook
  ACPI: battery: Simplify battery hook locking
  rtc: at91sam9: fix OF node leak in probe() error path
  rtc: at91sam9: drop platform_data support
  nfsd: fix delegation_blocked() to block correctly for at least 30 seconds
  nfsd: use ktime_get_seconds() for timestamps
  uprobes: fix kernel info leak via "[uprobes]" vma
  arm64: errata: Expand speculative SSBS workaround once more
  arm64: cputype: Add Neoverse-N3 definitions
  arm64: Add Cortex-715 CPU part definition
  ext4: update orig_path in ext4_find_extent()
  ext4: fix slab-use-after-free in ext4_split_extent_at()
  ext4: avoid ext4_error()'s caused by ENOMEM in the truncate path
  gpio: davinci: fix lazy disable
  btrfs: wait for fixup workers before stopping cleaner kthread during umount
  Input: adp5589-keys - fix adp5589_gpio_get_value()
  tomoyo: fallback to realpath if symlink's pathname does not exist
  iio: magnetometer: ak8975: Fix reading for ak099xx sensors
  media: venus: fix use after free bug in venus_remove due to race condition
  media: uapi/linux/cec.h: cec_msg_set_reply_to: zero flags
  clk: rockchip: fix error for unknown clocks
  aoe: fix the potential use-after-free problem in more places
  riscv: define ILLEGAL_POINTER_VALUE for 64bit
  ocfs2: fix possible null-ptr-deref in ocfs2_set_buffer_uptodate
  ocfs2: fix null-ptr-deref when journal load failed.
  ocfs2: remove unreasonable unlock in ocfs2_read_blocks
  ocfs2: cancel dqi_sync_work before freeing oinfo
  ocfs2: reserve space for inline xattr before attaching reflink tree
  ocfs2: fix uninit-value in ocfs2_get_block()
  ocfs2: fix the la space leak when unmounting an ocfs2 volume
  jbd2: stop waiting for space when jbd2_cleanup_journal_tail() returns error
  of/irq: Support #msi-cells=<0> in of_msi_get_domain
  parisc: Fix 64-bit userspace syscall path
  ext4: fix incorrect tid assumption in ext4_wait_for_tail_page_commit()
  ext4: fix double brelse() the buffer of the extents path
  ext4: aovid use-after-free in ext4_ext_insert_extent()
  ext4: fix incorrect tid assumption in __jbd2_log_wait_for_space()
  ext4: propagate errors from ext4_find_extent() in ext4_insert_range()
  ext4: no need to continue when the number of entries is 1
  ALSA: core: add isascii() check to card ID generator
  parisc: Fix itlb miss handler for 64-bit programs
  perf/core: Fix small negative period being ignored
  spi: bcm63xx: Fix module autoloading
  i2c: xiic: Wait for TX empty to avoid missed TX NAKs
  selftests: vDSO: fix vDSO symbols lookup for powerpc64
  selftests: breakpoints: use remaining time to check if suspend succeed
  spi: s3c64xx: fix timeout counters in flush_fifo
  ext4: fix i_data_sem unlock order in ext4_ind_migrate()
  ext4: ext4_search_dir should return a proper error
  of/irq: Refer to actual buffer size in of_irq_parse_one()
  drm/radeon/r100: Handle unknown family in r100_cp_init_microcode()
  scsi: aacraid: Rearrange order of struct aac_srb_unit
  drm/printer: Allow NULL data in devcoredump printer
  drm/amd/display: Fix index out of bounds in degamma hardware format translation
  drm/amd/display: Check stream before comparing them
  jfs: Fix uninit-value access of new_ea in ea_buffer
  jfs: check if leafidx greater than num leaves per dmap tree
  jfs: Fix uaf in dbFreeBits
  jfs: UBSAN: shift-out-of-bounds in dbFindBits
  ata: sata_sil: Rename sil_blacklist to sil_quirks
  power: reset: brcmstb: Do not go into infinite loop if reset fails
  fbdev: pxafb: Fix possible use after free in pxafb_task()
  ALSA: hdsp: Break infinite MIDI input flush loop
  ALSA: asihpi: Fix potential OOB array access
  signal: Replace BUG_ON()s
  wifi: mwifiex: Fix memcpy() field-spanning write warning in mwifiex_cmd_802_11_scan_ext()
  ACPICA: iasl: handle empty connection_node
  tcp: avoid reusing FIN_WAIT2 when trying to find port in connect() process
  ipv4: Mask upper DSCP bits and ECN bits in NETLINK_FIB_LOOKUP family
  ipv4: Check !in_dev earlier for ioctl(SIOCSIFADDR).
  net: mvpp2: Increase size of queue_name buffer
  tipc: guard against string buffer overrun
  ACPICA: check null return of ACPI_ALLOCATE_ZEROED() in acpi_db_convert_to_package()
  ACPI: EC: Do not release locks during operation region accesses
  ACPICA: Fix memory leak if acpi_ps_get_next_field() fails
  ACPICA: Fix memory leak if acpi_ps_get_next_namepath() fails
  net: hisilicon: hns_mdio: fix OF node leak in probe()
  net: hisilicon: hns_dsaf_mac: fix OF node leak in hns_mac_get_info()
  net: hisilicon: hip04: fix OF node leak in probe()
  wifi: ath9k_htc: Use __skb_set_length() for resetting urb before resubmit
  wifi: ath9k: fix possible integer overflow in ath9k_get_et_stats()
  f2fs: Require FMODE_WRITE for atomic write ioctls
  ALSA: hda/conexant: Fix conflicting quirk for System76 Pangolin
  ALSA: hda/generic: Unconditionally prefer preferred_dacs pairs
  sctp: set sk_state back to CLOSED if autobind fails in sctp_listen_start
  ipv4: ip_gre: Fix drops of small packets in ipgre_xmit
  net: add more sanity checks to qdisc_pkt_len_init()
  net: avoid potential underflow in qdisc_pkt_len_init() with UFO
  net: ethernet: lantiq_etop: fix memory disclosure
  r8152: Factor out OOB link list waits
  netfilter: nf_tables: prevent nf_skb_duplicated corruption
  netfilter: uapi: NFTA_FLOWTABLE_HOOK is NLA_NESTED
  ceph: remove the incorrect Fw reference check when dirtying pages
  mailbox: bcm2835: Fix timeout during suspend mode
  mailbox: rockchip: fix a typo in module autoloading
  usb: yurex: Fix inconsistent locking bug in yurex_read()
  i2c: isch: Add missed 'else'
  i2c: aspeed: Update the stop sw state when the bus recovery occurs
  pps: add an error check in parport_attach
  pps: remove usage of the deprecated ida_simple_xx() API
  USB: misc: yurex: fix race between read and write
  usb: yurex: Replace snprintf() with the safer scnprintf() variant
  soc: versatile: realview: fix soc_dev leak during device remove
  soc: versatile: realview: fix memory leak during device remove
  PCI: xilinx-nwl: Fix off-by-one in INTx IRQ handler
  PCI: xilinx-nwl: Use irq_data_get_irq_chip_data()
  nfs: fix memory leak in error path of nfs4_do_reclaim
  fs: Fix file_set_fowner LSM hook inconsistencies
  vfs: fix race between evice_inodes() and find_inode()&iput()
  f2fs: avoid potential int overflow in sanity_check_area_boundary()
  f2fs: prevent possible int overflow in dir_block_index()
  ACPI: sysfs: validate return type of _STR method
  drbd: Add NULL check for net_conf to prevent dereference in state validation
  drbd: Fix atomicity violation in drbd_uuid_set_bm()
  tty: rp2: Fix reset with non forgiving PCIe host bridges
  firmware_loader: Block path traversal
  USB: misc: cypress_cy7c63: check for short transfer
  USB: appledisplay: close race between probe and completion handler
  soc: versatile: integrator: fix OF node leak in probe() error path
  Remove *.orig pattern from .gitignore
  crypto: aead,cipher - zeroize key buffer after use
  netfilter: ctnetlink: compile ctnetlink_label_size with CONFIG_NF_CONNTRACK_EVENTS
  net: qrtr: Update packets cloning when broadcasting
  tcp: check skb is non-NULL in tcp_rto_delta_us()
  tcp: introduce tcp_skb_timestamp_us() helper
  net: seeq: Fix use after free vulnerability in ether3 Driver Due to Race Condition
  netfilter: nf_reject_ipv6: fix nf_reject_ip6_tcphdr_put()
  coresight: tmc: sg: Do not leak sg_table
  f2fs: reduce expensive checkpoint trigger frequency
  f2fs: remove unneeded check condition in __f2fs_setxattr()
  f2fs: fix to update i_ctime in __f2fs_setxattr()
  f2fs: fix typo
  f2fs: enhance to update i_mode and acl atomically in f2fs_setattr()
  nfsd: call cache_put if xdr_reserve_space returns NULL
  ntb: intel: Fix the NULL vs IS_ERR() bug for debugfs_create_dir()
  RDMA/cxgb4: Added NULL check for lookup_atid
  pinctrl: mvebu: Fix devinit_dove_pinctrl_probe function
  clk: ti: dra7-atl: Fix leak of of_nodes
  pinctrl: single: fix missing error code in pcs_probe()
  RDMA/iwcm: Fix WARNING:at_kernel/workqueue.c:#check_flush_dependency
  PCI: xilinx-nwl: Fix register misspelling
  drivers: media: dvb-frontends/rtl2830: fix an out-of-bounds write error
  drivers: media: dvb-frontends/rtl2832: fix an out-of-bounds write error
  clk: rockchip: Set parent rate for DCLK_VOP clock on RK3228
  perf time-utils: Fix 32-bit nsec parsing
  perf sched timehist: Fixed timestamp error when unable to confirm event sched_in time
  perf sched timehist: Fix missing free of session in perf_sched__timehist()
  nilfs2: fix potential oob read in nilfs_btree_check_delete()
  nilfs2: determine empty node blocks as corrupted
  nilfs2: fix potential null-ptr-deref in nilfs_btree_insert()
  ext4: avoid OOB when system.data xattr changes underneath the filesystem
  ext4: return error on ext4_find_inline_entry
  ext4: avoid negative min_clusters in find_group_orlov()
  smackfs: Use rcu_assign_pointer() to ensure safe assignment in smk_set_cipso
  ext4: clear EXT4_GROUP_INFO_WAS_TRIMMED_BIT even mount with discard
  jbd2: introduce/export functions jbd2_journal_submit|finish_inode_data_buffers()
  kthread: fix task state in kthread worker if being frozen
  kthread: add kthread_work tracepoints
  xz: cleanup CRC32 edits from 2018
  selftests/bpf: Fix error compiling test_lru_map.c
  xen/swiotlb: add alignment check for dma buffers
  xen/swiotlb: simplify range_straddles_page_boundary()
  xen: use correct end address of kernel for conflict checking
  drm/msm: fix %s null argument error
  ipmi: docs: don't advertise deprecated sysfs entries
  drm/msm/a5xx: fix races in preemption evaluation stage
  drm/msm/a5xx: properly clear preemption records on resume
  jfs: fix out-of-bounds in dbNextAG() and diAlloc()
  drm/radeon/evergreen_cs: fix int overflow errors in cs track offsets
  drm/rockchip: vop: Allow 4096px width scaling
  drm/radeon: properly handle vbios fake edid sizing
  drm/radeon: Replace one-element array with flexible-array member
  drm/amdgpu: properly handle vbios fake edid sizing
  drm/amdgpu: Replace one-element array with flexible-array member
  drm/amd: fix typo
  drm/stm: Fix an error handling path in stm_drm_platform_probe()
  fbdev: hpfb: Fix an error handling path in hpfb_dio_probe()
  power: supply: max17042_battery: Fix SOC threshold calc w/ no current sense
  hwmon: (ntc_thermistor) fix module autoloading
  mtd: slram: insert break after errors in parsing the map
  hwmon: (max16065) Fix overflows seen when writing limits
  clocksource/drivers/qcom: Add missing iounmap() on errors in msm_dt_timer_init()
  reset: berlin: fix OF node leak in probe() error path
  ARM: versatile: fix OF node leak in CPUs prepare
  spi: ppc4xx: Avoid returning 0 when failed to parse and map IRQ
  spi: ppc4xx: handle irq_of_parse_and_map() errors
  block, bfq: don't break merge chain in bfq_split_bfqq()
  block, bfq: choose the last bfqq from merge chain in bfq_setup_cooperator()
  block, bfq: fix possible UAF for bfqq->bic with merge chain
  Bluetooth: btusb: Fix not handling ZPL/short-transfer
  can: bcm: Clear bo->bcm_proc_read after remove_proc_entry().
  wifi: mac80211: use two-phase skb reclamation in ieee80211_do_stop()
  wifi: cfg80211: fix two more possible UBSAN-detected off-by-one errors
  wifi: cfg80211: fix UBSAN noise in cfg80211_wext_siwscan()
  netfilter: nf_tables: elements with timeout below CONFIG_HZ never expire
  wifi: ath9k: Remove error checks when creating debugfs entries
  wifi: ath9k: fix parameter check in ath9k_init_debug()
  ACPI: PMIC: Remove unneeded check in tps68470_pmic_opregion_probe()
  USB: serial: pl2303: add device id for Macrosilicon MS3020
  gpio: prevent potential speculation leaks in gpio_device_get_desc()
  ocfs2: strict bound check before memcmp in ocfs2_xattr_find_entry()
  ocfs2: add bounds checking to ocfs2_xattr_find_entry()
  x86/hyperv: Set X86_FEATURE_TSC_KNOWN_FREQ when Hyper-V provides frequency
  spi: bcm63xx: Enable module autoloading
  ASoC: tda7419: fix module autoloading
  wifi: iwlwifi: mvm: don't wait for tx queues if firmware is dead
  wifi: iwlwifi: mvm: fix iwl_mvm_max_scan_ie_fw_cmd_room()
  net: ftgmac100: Ensure tx descriptor updates are visible
  microblaze: don't treat zero reserved memory regions as error
  pinctrl: at91: make it work with current gpiolib
  ASoC: allow module autoloading for table db1200_pids
  selftests/kcmp: remove call to ksft_set_plan()
  selftests/vm: remove call to ksft_set_plan()
  soundwire: stream: Revert "soundwire: stream: fix programming slave ports for non-continous port maps"
  net: dpaa: Pad packets to ETH_ZLEN
  net: ftgmac100: Enable TX interrupt to avoid TX timeout
  net/mlx5: Update the list of the PCI supported devices
  arm64: dts: rockchip: override BIOS_DISABLE signal via GPIO hog on RK3399 Puma
  scripts: kconfig: merge_config: config files: add a trailing newline
  net: phy: vitesse: repair vsc73xx autonegotiation
  net: ethernet: use ip_hdrlen() instead of bit shift
  usbnet: ipheth: fix carrier detection in modes 1 and 4
  staging: iio: frequency: ad9834: Validate frequency parameter value
  staging: iio: frequency: ad9833: Load clock using clock framework
  staging: iio: frequency: ad9833: Get frequency value statically

Change-Id: Id96e4bf331d59a5f3f52791887390bc747dc31cb
Signed-off-by: bengris32 <bengris32@protonmail.ch>
2024-12-17 21:41:20 +00:00

1125 lines
27 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>
#define CREATE_TRACE_POINTS
#include <trace/events/rtc.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 void rtc_add_offset(struct rtc_device *rtc, struct rtc_time *tm)
{
time64_t secs;
if (!rtc->offset_secs)
return;
secs = rtc_tm_to_time64(tm);
/*
* Since the reading time values from RTC device are always in the RTC
* original valid range, but we need to skip the overlapped region
* between expanded range and original range, which is no need to add
* the offset.
*/
if ((rtc->start_secs > rtc->range_min && secs >= rtc->start_secs) ||
(rtc->start_secs < rtc->range_min &&
secs <= (rtc->start_secs + rtc->range_max - rtc->range_min)))
return;
rtc_time64_to_tm(secs + rtc->offset_secs, tm);
}
static void rtc_subtract_offset(struct rtc_device *rtc, struct rtc_time *tm)
{
time64_t secs;
if (!rtc->offset_secs)
return;
secs = rtc_tm_to_time64(tm);
/*
* If the setting time values are in the valid range of RTC hardware
* device, then no need to subtract the offset when setting time to RTC
* device. Otherwise we need to subtract the offset to make the time
* values are valid for RTC hardware device.
*/
if (secs >= rtc->range_min && secs <= rtc->range_max)
return;
rtc_time64_to_tm(secs - rtc->offset_secs, tm);
}
static int rtc_valid_range(struct rtc_device *rtc, struct rtc_time *tm)
{
if (rtc->range_min != rtc->range_max) {
time64_t time = rtc_tm_to_time64(tm);
time64_t range_min = rtc->set_start_time ? rtc->start_secs :
rtc->range_min;
time64_t range_max = rtc->set_start_time ?
(rtc->start_secs + rtc->range_max - rtc->range_min) :
rtc->range_max;
if (time < range_min || time > range_max)
return -ERANGE;
}
return 0;
}
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;
}
rtc_add_offset(rtc, tm);
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);
trace_rtc_read_time(rtc_tm_to_time64(tm), err);
return err;
}
EXPORT_SYMBOL_GPL(rtc_read_time);
int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
{
int err, uie;
err = rtc_valid_tm(tm);
if (err != 0)
return err;
err = rtc_valid_range(rtc, tm);
if (err)
return err;
rtc_subtract_offset(rtc, tm);
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
uie = rtc->uie_rtctimer.enabled || rtc->uie_irq_active;
#else
uie = rtc->uie_rtctimer.enabled;
#endif
if (uie) {
err = rtc_update_irq_enable(rtc, 0);
if (err)
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);
if (uie) {
err = rtc_update_irq_enable(rtc, 1);
if (err)
return err;
}
trace_rtc_set_time(rtc_tm_to_time64(tm), err);
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);
trace_rtc_read_alarm(rtc_tm_to_time64(&alarm->time), err);
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) {
rtc_add_offset(rtc, &alarm->time);
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);
trace_rtc_read_alarm(rtc_tm_to_time64(&alarm->time), err);
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.
*/
rtc_subtract_offset(rtc, &alarm->time);
if (!rtc->ops)
err = -ENODEV;
else if (!rtc->ops->set_alarm)
err = -EINVAL;
else
err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
trace_rtc_set_alarm(rtc_tm_to_time64(&alarm->time), err);
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 = rtc_valid_range(rtc, &alarm->time);
if (err)
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);
int rtc_set_alarm_poweron(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
{
int err;
err = rtc_valid_tm(&alarm->time);
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_alarm)
err = -EINVAL;
else
err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
mutex_unlock(&rtc->ops_lock);
return err;
}
EXPORT_SYMBOL_GPL(rtc_set_alarm_poweron);
/* 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);
trace_rtc_timer_enqueue(&rtc->aie_timer);
}
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);
trace_rtc_alarm_irq_enable(enabled, err);
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);
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);
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.
*/
int rtc_irq_set_state(struct rtc_device *rtc, int enabled)
{
int err = 0;
while (rtc_update_hrtimer(rtc, enabled) < 0)
cpu_relax();
rtc->pie_enabled = enabled;
trace_rtc_irq_set_state(enabled, err);
return err;
}
/**
* 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
* 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, int freq)
{
int err = 0;
if (freq <= 0 || freq > RTC_MAX_FREQ)
return -EINVAL;
rtc->irq_freq = freq;
while (rtc->pie_enabled && rtc_update_hrtimer(rtc, 1) < 0)
cpu_relax();
trace_rtc_irq_set_freq(freq, err);
return err;
}
/**
* 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);
trace_rtc_timer_enqueue(timer);
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);
trace_rtc_timer_dequeue(timer);
timer->enabled = 0;
return err;
}
}
return 0;
}
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);
trace_rtc_alarm_irq_enable(0, 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);
trace_rtc_timer_dequeue(timer);
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;
int err;
struct rtc_device *rtc =
container_of(work, struct rtc_device, irqwork);
mutex_lock(&rtc->ops_lock);
again:
err = __rtc_read_time(rtc, &tm);
if (err) {
mutex_unlock(&rtc->ops_lock);
return;
}
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);
trace_rtc_timer_dequeue(timer);
timer->enabled = 0;
if (timer->func)
timer->func(timer->private_data);
trace_rtc_timer_fired(timer);
/* 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);
trace_rtc_timer_enqueue(timer);
}
}
/* 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);
trace_rtc_timer_dequeue(timer);
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->func = f;
timer->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);
trace_rtc_read_offset(*offset, ret);
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.
*
* The adjustment applied is as follows:
* t = t0 * (1 + offset * 1e-9)
* where t0 is the measured length of 1 RTC second with offset = 0
*
* 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);
trace_rtc_set_offset(offset, ret);
return ret;
}