Files
bengris32 2162cb9481 Merge branch 'linux-4.19.y-cip' of https://git.kernel.org/pub/scm/linux/kernel/git/cip/linux-cip into lineage-22.1
* 'linux-4.19.y-cip' of https://git.kernel.org/pub/scm/linux/kernel/git/cip/linux-cip:
  CIP: Bump version suffix to -cip120 after merge from cip/linux-4.19.y-st tree
  Update localversion-st, tree is up-to-date with 5.4.292.
  net: dsa: mv88e6xxx: propperly shutdown PPU re-enable timer on destroy
  jfs: add index corruption check to DT_GETPAGE()
  jfs: fix slab-out-of-bounds read in ea_get()
  tracing: Fix use-after-free in print_graph_function_flags during tracer switching
  mmc: sdhci-pxav3: set NEED_RSP_BUSY capability
  x86/tsc: Always save/restore TSC sched_clock() on suspend/resume
  ntb_perf: Delete duplicate dmaengine_unmap_put() call in perf_copy_chunk()
  arcnet: Add NULL check in com20020pci_probe()
  ipv6: fix omitted netlink attributes when using RTEXT_FILTER_SKIP_STATS
  vsock: avoid timeout during connect() if the socket is closing
  net_sched: skbprio: Remove overly strict queue assertions
  netlabel: Fix NULL pointer exception caused by CALIPSO on IPv4 sockets
  ntb: intel: Fix using link status DB's
  ntb_hw_switchtec: Fix shift-out-of-bounds in switchtec_ntb_mw_set_trans
  spufs: fix a leak in spufs_create_context()
  spufs: fix a leak on spufs_new_file() failure
  hwmon: (nct6775-core) Fix out of bounds access for NCT679{8,9}
  sched/deadline: Use online cpus for validating runtime
  affs: don't write overlarge OFS data block size fields
  affs: generate OFS sequence numbers starting at 1
  wifi: iwlwifi: fw: allocate chained SG tables for dump
  sched/smt: Always inline sched_smt_active()
  ring-buffer: Fix bytes_dropped calculation issue
  objtool, media: dib8000: Prevent divide-by-zero in dib8000_set_dds()
  fs/procfs: fix the comment above proc_pid_wchan()
  perf python: Check if there is space to copy all the event
  perf python: Decrement the refcount of just created event on failure
  perf python: Fixup description of sample.id event member
  ocfs2: validate l_tree_depth to avoid out-of-bounds access
  perf units: Fix insufficient array space
  iio: accel: mma8452: Ensure error return on failure to matching oversampling ratio
  coresight: catu: Fix number of pages while using 64k pages
  isofs: fix KMSAN uninit-value bug in do_isofs_readdir()
  x86/dumpstack: Fix inaccurate unwinding from exception stacks due to misplaced assignment
  mfd: sm501: Switch to BIT() to mitigate integer overflows
  RDMA/mlx5: Fix mlx5_poll_one() cur_qp update flow
  power: supply: max77693: Fix wrong conversion of charge input threshold value
  x86/entry: Fix ORC unwinder for PUSH_REGS with save_ret=1
  IB/mad: Check available slots before posting receive WRs
  clk: rockchip: rk3328: fix wrong clk_ref_usb3otg parent
  lib: 842: Improve error handling in sw842_compress()
  clk: amlogic: gxbb: drop incorrect flag on 32k clock
  fbdev: sm501fb: Add some geometry checks.
  mdacon: rework dependency list
  fbdev: au1100fb: Move a variable assignment behind a null pointer check
  PCI/portdrv: Only disable pciehp interrupts early when needed
  ALSA: hda/realtek: Always honor no_shutup_pins
  perf/ring_buffer: Allow the EPOLLRDNORM flag for poll
  lockdep: Don't disable interrupts on RT in disable_irq_nosync_lockdep.*()
  thermal: int340x: Add NULL check for adev
  EDAC/ie31200: Fix the error path order of ie31200_init()
  EDAC/ie31200: Fix the DIMM size mask for several SoCs
  x86/fpu: Avoid copying dynamic FP state from init_task in arch_dup_task_struct()
  cpufreq: governor: Fix negative 'idle_time' handling in dbs_update()
  net: usb: usbnet: restore usb%d name exception for local mac addresses
  net: usb: qmi_wwan: add Telit Cinterion FE990B composition
  net: usb: qmi_wwan: add Telit Cinterion FN990B composition
  tty: serial: 8250: Add some more device IDs
  netfilter: socket: Lookup orig tuple for IPv6 SNAT
  ARM: 9351/1: fault: Add "cut here" line for prefetch aborts
  ARM: 9350/1: fault: Implement copy_from_kernel_nofault_allowed()
  atm: Fix NULL pointer dereference
  ALSA: usb-audio: Add quirk for Plantronics headsets to fix control names
  drm/radeon: fix uninitialized size issue in radeon_vce_cs_parse()
  batman-adv: Ignore own maximum aggregation size during RX
  ARM: shmobile: smp: Enforce shmobile_smp_* alignment
  mmc: atmel-mci: Add missing clk_disable_unprepare()
  net/neighbor: add missing policy for NDTPA_QUEUE_LENBYTES
  net: atm: fix use after free in lec_send()
  Bluetooth: Fix error code in chan_alloc_skb_cb()
  RDMA/hns: Fix wrong value of max_sge_rd
  RDMA/bnxt_re: Avoid clearing VLAN_ID mask in modify qp path
  xfrm_output: Force software GSO only in tunnel mode
  i2c: sis630: Fix an error handling path in sis630_probe()
  i2c: ali15x3: Fix an error handling path in ali15x3_probe()
  i2c: ali1535: Fix an error handling path in ali1535_probe()
  ASoC: codecs: wm0010: Fix error handling path in wm0010_spi_probe()
  drm/gma500: Add NULL check for pci_gfx_root in mid_get_vbt_data()
  qlcnic: fix memory leak issues in qlcnic_sriov_common.c
  drm/amd/display: Assign normalized_pix_clk when color depth = 14
  x86/microcode/AMD: Fix out-of-bounds on systems with CPU-less NUMA nodes
  USB: serial: option: match on interface class for Telit FN990B
  USB: serial: option: fix Telit Cinterion FE990A name
  USB: serial: option: add Telit Cinterion FE990B compositions
  USB: serial: ftdi_sio: add support for Altera USB Blaster 3
  block: fix 'kmem_cache of name 'bio-108' already exists'
  drm/nouveau: Do not override forced connector status
  x86/irq: Define trace events conditionally
  nvme: only allow entering LIVE from CONNECTING state
  sctp: Fix undefined behavior in left shift operation
  nvmet-rdma: recheck queue state is LIVE in state lock in recv done
  s390/cio: Fix CHPID "configure" attribute caching
  HID: ignore non-functional sensor in HP 5MP Camera
  iscsi_ibft: Fix UBSAN shift-out-of-bounds warning in ibft_attr_show_nic()
  powercap: call put_device() on an error path in powercap_register_control_type()
  nvme-fc: go straight to connecting state when initializing
  net_sched: Prevent creation of classes with TC_H_ROOT
  ipvs: prevent integer overflow in do_ip_vs_get_ctl()
  netfilter: nf_conncount: Fully initialize struct nf_conncount_tuple in insert_tree()
  Drivers: hv: vmbus: Don't release fb_mmio resource in vmbus_free_mmio()
  drivers/hv: Replace binary semaphore with mutex
  netpoll: hold rcu read lock in __netpoll_send_skb()
  netpoll: netpoll_send_skb() returns transmit status
  netpoll: move netpoll_send_skb() out of line
  netpoll: remove dev argument from netpoll_send_skb_on_dev()
  netpoll: Fix use correct return type for ndo_start_xmit()
  pinctrl: bcm281xx: Fix incorrect regmap max_registers value
  sctp: sysctl: auth_enable: avoid using current->nsproxy
  sctp: sysctl: cookie_hmac_alg: avoid using current->nsproxy
  Revert "sctp: sysctl: auth_enable: avoid using current->nsproxy"
  Revert "sctp: sysctl: cookie_hmac_alg: avoid using current->nsproxy"
  sched/isolation: Prevent boot crash when the boot CPU is nohz_full
  CIP: Bump version suffix to -cip119 after merge from cip/linux-4.19.y-st tree
  watchdog: renesas_wdt: support handover from bootloader
  Update localversion-st, tree is up-to-date with 5.4.291.
  gtp: Suppress list corruption splat in gtp_net_exit_batch_rtnl().
  gtp: Destroy device along with udp socket's netns dismantle.
  net: gso: fix ownership in __udp_gso_segment
  vlan: fix memory leak in vlan_newlink()
  batman-adv: Drop unmanaged ELP metric worker
  tee: optee: Fix supplicant wait loop
  pps: Fix a use-after-free
  net: rose: lock the socket in rose_bind()
  btrfs: fix use-after-free when attempting to join an aborted transaction
  media: lmedm04: Handle errors for lme2510_int_read
  wifi: rtlwifi: rtl8192se: rise completion of firmware loading as last step
  eeprom: digsy_mtc: Make GPIO lookup table match the device
  slimbus: messaging: Free transaction ID in delayed interrupt scenario
  intel_th: pci: Add Panther Lake-P/U support
  intel_th: pci: Add Panther Lake-H support
  intel_th: pci: Add Arrow Lake support
  Squashfs: check the inode number is not the invalid value of zero
  xhci: pci: Fix indentation in the PCI device ID definitions
  usb: gadget: Check bmAttributes only if configuration is valid
  usb: gadget: Fix setting self-powered state on suspend
  usb: gadget: Set self-powered based on MaxPower and bmAttributes
  usb: typec: tcpci_rt1711h: Unmask alert interrupts to fix functionality
  usb: typec: ucsi: increase timeout for PPM reset operations
  usb: atm: cxacru: fix a flaw in existing endpoint checks
  usb: quirks: Add DELAY_INIT and NO_LPM for Prolific Mass Storage Card Reader
  usb: renesas_usbhs: Use devm_usb_get_phy()
  Revert "drivers/card_reader/rtsx_usb: Restore interrupt based detection"
  net: ipv6: fix missing dst ref drop in ila lwtunnel
  net: ipv6: fix dst ref loop in ila lwtunnel
  net-timestamp: support TCP GSO case for a few missing flags
  vlan: enforce underlying device type
  ppp: Fix KMSAN uninit-value warning with bpf
  be2net: fix sleeping while atomic bugs in be_ndo_bridge_getlink
  hwmon: fix a NULL vs IS_ERR_OR_NULL() check in xgene_hwmon_probe()
  llc: do not use skb_get() before dev_queue_xmit()
  hwmon: (ad7314) Validate leading zero bits and return error
  hwmon: (ntc_thermistor) Fix the ncpXXxh103 sensor table
  hwmon: (pmbus) Initialise page count in pmbus_identify()
  caif_virtio: fix wrong pointer check in cfv_probe()
  HID: intel-ish-hid: Fix use-after-free issue in ishtp_hid_remove()
  mm/page_alloc: fix uninitialized variable
  rapidio: fix an API misues when rio_add_net() fails
  rapidio: add check for rio_add_net() in rio_scan_alloc_net()
  wifi: nl80211: reject cooked mode if it is set along with other flags
  wifi: cfg80211: regulatory: improve invalid hints checking
  x86/cpu: Properly parse CPUID leaf 0x2 TLB descriptor 0x63
  x86/cpu: Validate CPUID leaf 0x2 EDX output
  x86/cacheinfo: Validate CPUID leaf 0x2 EDX output
  platform/x86: thinkpad_acpi: Add battery quirk for ThinkPad X131e
  drm/radeon: Fix rs400_gpu_init for ATI mobility radeon Xpress 200M
  ALSA: hda/realtek: update ALC222 depop optimize
  ALSA: hda: intel: Add Dell ALC3271 to power_save denylist
  HID: appleir: Fix potential NULL dereference at raw event handle
  Revert "of: reserved-memory: Fix using wrong number of cells to get property 'alignment'"
  drm/amdgpu: disable BAR resize on Dell G5 SE
  drm/amdgpu: Check extended configuration space register when system uses large bar
  drm/amdgpu: skip BAR resizing if the bios already did it
  acct: perform last write from workqueue
  kernel/acct.c: use dedicated helper to access rlimit values
  kernel/acct.c: use #elif instead of #end and #elif
  pfifo_tail_enqueue: Drop new packet when sch->limit == 0
  sched/core: Prevent rescheduling when interrupts are disabled
  phy: exynos5-usbdrd: fix MPLL_MULTIPLIER and SSC_REFCLKSEL masks in refclk
  usbnet: gl620a: fix endpoint checking in genelink_bind()
  perf/core: Fix low freq setting via IOC_PERIOD
  ftrace: Avoid potential division by zero in function_stat_show()
  x86/CPU: Fix warm boot hang regression on AMD SC1100 SoC systems
  ipvs: Always clear ipvs_property flag in skb_scrub_packet()
  ASoC: es8328: fix route from DAC to output
  net: cadence: macb: Synchronize stats calculations
  sunrpc: suppress warnings for unused procfs functions
  batman-adv: Ignore neighbor throughput metrics in error case
  acct: block access to kernel internal filesystems
  ALSA: hda/conexant: Add quirk for HP ProBook 450 G4 mute LED
  nfp: bpf: Add check for nfp_app_ctrl_msg_alloc()
  power: supply: da9150-fg: fix potential overflow
  geneve: Suppress list corruption splat in geneve_destroy_tunnels().
  geneve: Fix use-after-free in geneve_find_dev().
  powerpc/code-patching: Fix KASAN hit by not flagging text patching area as VM_ALLOC
  ALSA: hda/realtek - Add type for ALC287
  powerpc/64s: Rewrite __real_pte() and __rpte_to_hidx() as static inline
  powerpc/64s/mm: Move __real_pte stubs into hash-4k.h
  USB: gadget: f_midi: f_midi_complete to call queue_work
  usb/gadget: f_midi: Replace tasklet with work
  usb/gadget: f_midi: convert tasklets to use new tasklet_setup() API
  usb: dwc3: Fix timeout issue during controller enter/exit from halt state
  mm: update mark_victim tracepoints fields
  crypto: testmgr - some more fixes to RSA test vectors
  crypto: testmgr - populate RSA CRT parameters in RSA test vectors
  crypto: testmgr - fix version number of RSA tests
  crypto: testmgr - Fix wrong test case of RSA
  crypto: testmgr - fix wrong key length for pkcs1pad
  driver core: bus: Fix double free in driver API bus_register()
  scsi: storvsc: Set correct data length for sending SCSI command without payload
  vlan: move dev_put into vlan_dev_uninit
  vlan: introduce vlan_dev_free_egress_priority
  Revert "btrfs: avoid monopolizing a core when activating a swap file"
  parport_pc: add support for ASIX AX99100
  can: ems_pci: move ASIX AX99100 ids to pci_ids.h
  nilfs2: protect access to buffers with no active references
  nilfs2: do not force clear folio if buffer is referenced
  nilfs2: do not output warnings when clearing dirty buffers
  alpha: replace hardcoded stack offsets with autogenerated ones
  ndisc: extend RCU protection in ndisc_send_skb()
  openvswitch: use RCU protection in ovs_vport_cmd_fill_info()
  arp: use RCU protection in arp_xmit()
  neighbour: use RCU protection in __neigh_notify()
  neighbour: delete redundant judgment statements
  ndisc: use RCU protection in ndisc_alloc_skb()
  ipv6: use RCU protection in ip6_default_advmss()
  ipv4: use RCU protection in inet_select_addr()
  ipv4: use RCU protection in rt_is_expired()
  net: add dev_net_rcu() helper
  net: treat possible_net_t net pointer as an RCU one and add read_pnet_rcu()
  partitions: mac: fix handling of bogus partition table
  gpio: stmpe: Check return value of stmpe_reg_read in stmpe_gpio_irq_sync_unlock
  alpha: align stack for page fault and user unaligned trap handlers
  alpha: make stack 16-byte aligned (most cases)
  can: c_can: fix unbalanced runtime PM disable in error path
  USB: serial: option: drop MeiG Smart defines
  USB: serial: option: fix Telit Cinterion FN990A name
  USB: serial: option: add Telit Cinterion FN990B compositions
  USB: serial: option: add MeiG Smart SLM828
  usb: cdc-acm: Fix handling of oversized fragments
  usb: cdc-acm: Check control transfer buffer size before access
  USB: cdc-acm: Fill in Renesas R-Car D3 USB Download mode quirk
  USB: hub: Ignore non-compliant devices with too many configs or interfaces
  usb: gadget: f_midi: fix MIDI Streaming descriptor lengths
  USB: Add USB_QUIRK_NO_LPM quirk for sony xperia xz1 smartphone
  USB: quirks: add USB_QUIRK_NO_LPM quirk for Teclast dist
  USB: pci-quirks: Fix HCCPARAMS register error for LS7A EHCI
  usb: dwc2: gadget: remove of_node reference upon udc_stop
  usb: gadget: udc: renesas_usb3: Fix compiler warning
  usb: roles: set switch registered flag early on
  batman-adv: fix panic during interface removal
  ASoC: Intel: bytcr_rt5640: Add DMI quirk for Vexia Edu Atla 10 tablet 5V
  orangefs: fix a oob in orangefs_debug_write
  Grab mm lock before grabbing pt lock
  vfio/pci: Enable iowrite64 and ioread64 for vfio pci
  media: cxd2841er: fix 64-bit division on gcc-9
  xen: remove a confusing comment on auto-translated guest I/O
  gpio: bcm-kona: Add missing newline to dev_err format string
  gpio: bcm-kona: Fix GPIO lock/unlock for banks above bank 0
  arm64: cacheinfo: Avoid out-of-bounds write to cacheinfo array
  team: better TEAM_OPTION_TYPE_STRING validation
  vrf: use RCU protection in l3mdev_l3_out()
  ndisc: ndisc_send_redirect() must use dev_get_by_index_rcu()
  HID: multitouch: Add NULL check in mt_input_configured
  ocfs2: check dir i_size in ocfs2_find_entry
  MIPS: ftrace: Declare ftrace_get_parent_ra_addr() as static
  ptp: Ensure info->enable callback is always set
  mtd: onenand: Fix uninitialized retlen in do_otp_read()
  NFC: nci: Add bounds checking in nci_hci_create_pipe()
  nilfs2: fix possible int overflows in nilfs_fiemap()
  ocfs2: handle a symlink read error correctly
  ocfs2: fix incorrect CPU endianness conversion causing mount failure
  nvmem: core: improve range check for nvmem_cell_write()
  crypto: qce - fix goto jump in error path
  media: uvcvideo: Remove redundant NULL assignment
  media: uvcvideo: Fix event flags in uvc_ctrl_send_events
  media: ov5640: fix get_light_freq on auto
  soc: qcom: smem_state: fix missing of_node_put in error path
  powerpc/pseries/eeh: Fix get PE state translation
  serial: sh-sci: Do not probe the serial port if its slot in sci_ports[] is in use
  serial: sh-sci: Drop __initdata macro for port_cfg
  usb: gadget: f_tcm: Don't prepare BOT write request twice
  usb: gadget: f_tcm: ep_autoconfig with fullspeed endpoint
  usb: gadget: f_tcm: Decrement command ref count on cleanup
  usb: gadget: f_tcm: Translate error to sense
  wifi: brcmfmac: fix NULL pointer dereference in brcmf_txfinalize()
  HID: hid-sensor-hub: don't use stale platform-data on remove
  of: reserved-memory: Fix using wrong number of cells to get property 'alignment'
  of: Fix of_find_node_opts_by_path() handling of alias+path+options
  of: Correct child specifier used as input of the 2nd nexus node
  clk: qcom: clk-alpha-pll: fix alpha mode configuration
  Bluetooth: L2CAP: handle NULL sock pointer in l2cap_sock_alloc
  KVM: s390: vsie: fix some corner-cases when grabbing vsie pages
  KVM: Explicitly verify target vCPU is online in kvm_get_vcpu()
  arm64: dts: rockchip: increase gmac rx_delay on rk3399-puma
  binfmt_flat: Fix integer overflow bug on 32 bit systems
  m68k: vga: Fix I/O defines
  s390/futex: Fix FUTEX_OP_ANDN implementation
  leds: lp8860: Write full EEPROM, not only half of it
  cpufreq: s3c64xx: Fix compilation warning
  tun: revert fix group permission check
  netem: Update sch->q.qlen before qdisc_tree_reduce_backlog()
  udp: gso: do not drop small packets when PMTU reduces
  tg3: Disable tg3 PCIe AER on system reboot
  firmware: iscsi_ibft: fix ISCSI_IBFT Kconfig entry
  nvme: handle connectivity loss in nvme_set_queue_count
  usb: xhci: Fix NULL pointer dereference on certain command aborts
  usb: xhci: Add timeout argument in address_device USB HCD callback
  media: uvcvideo: Remove dangling pointers
  media: uvcvideo: Only save async fh if success
  nilfs2: handle errors that nilfs_prepare_chunk() may return
  nilfs2: eliminate staggered calls to kunmap in nilfs_rename
  nilfs2: move page release outside of nilfs_delete_entry and nilfs_set_link
  x86/mm: Don't disable PCID when INVLPG has been fixed by microcode
  HID: Wacom: Add PCI Wacom device support
  mfd: lpc_ich: Add another Gemini Lake ISA bridge PCI device-id
  wifi: brcmsmac: add gain range check to wlc_phy_iqcal_gainparams_nphy()
  mmc: core: Respect quirk_max_rate for non-UHS SDIO card
  tun: fix group permission check
  printk: Fix signed integer overflow when defining LOG_BUF_LEN_MAX
  sched: Don't try to catch up excess steal time.
  btrfs: convert BUG_ON in btrfs_reloc_cow_block() to proper error handling
  btrfs: output the reason for open_ctree() failure
  usb: gadget: f_tcm: Don't free command immediately
  media: uvcvideo: Fix double free in error path
  usb: typec: tcpm: set SRC_SEND_CAPABILITIES timeout to PD_T_SENDER_RESPONSE
  drivers/card_reader/rtsx_usb: Restore interrupt based detection
  ktest.pl: Check kernelrelease return in get_version
  NFSD: Reset cb_seq_status after NFS4ERR_DELAY
  hexagon: Fix unbalanced spinlock in die()
  hexagon: fix using plain integer as NULL pointer warning in cmpxchg
  genksyms: fix memory leak when the same symbol is read from *.symref file
  genksyms: fix memory leak when the same symbol is added from source
  net: sh_eth: Fix missing rtnl lock in suspend/resume path
  vsock: Allow retrying on connect() failure
  net: davicom: fix UAF in dm9000_drv_remove
  net: rose: fix timer races against user threads
  PM: hibernate: Add error handling for syscore_suspend()
  net: fec: implement TSO descriptor cleanup
  ubifs: skip dumping tnc tree when zroot is null
  dmaengine: ti: edma: fix OF node reference leaks in edma_driver
  module: Extend the preempt disabled section in dereference_symbol_descriptor().
  ocfs2: mark dquot as inactive if failed to start trans while releasing dquot
  scsi: mpt3sas: Set ioc->manu_pg11.EEDPTagMode directly to 1
  media: camif-core: Add check for clk_enable()
  media: mipi-csis: Add check for clk_enable()
  PCI: endpoint: Destroy the EPC device in devm_pci_epc_destroy()
  media: rc: iguanair: handle timeouts
  fbdev: omapfb: Fix an OF node leak in dss_of_port_get_parent_device()
  ARM: dts: mediatek: mt7623: fix IR nodename
  arm64: dts: mediatek: mt8173-evb: Fix MT6397 PMIC sub-node names
  arm64: dts: mediatek: mt8173-evb: Drop regulator-compatible property
  rdma/cxgb4: Prevent potential integer overflow on 32bit
  RDMA/mlx4: Avoid false error about access to uninitialized gids array
  perf report: Fix misleading help message about --demangle
  perf top: Don't complain about lack of vmlinux when not resolving some kernel samples
  padata: fix sysfs store callback check
  ktest.pl: Remove unused declarations in run_bisect_test function
  net: sched: Disallow replacing of child qdisc from one parent to another
  net/mlxfw: Drop hard coded max FW flash image size
  selftests: harness: fix printing of mismatch values in __EXPECT()
  selftests/harness: Display signed values correctly
  wifi: wlcore: fix unbalanced pm_runtime calls
  regulator: of: Implement the unwind path of of_regulator_match()
  team: prevent adding a device which is already a team device lower
  cpupower: fix TSC MHz calculation
  wifi: rtlwifi: pci: wait for firmware loading before releasing memory
  wifi: rtlwifi: fix memory leaks and invalid access at probe error path
  wifi: rtlwifi: remove unused dualmac control leftovers
  rtlwifi: replace usage of found with dedicated list iterator variable
  wifi: rtlwifi: usb: fix workqueue leak when probe fails
  wifi: rtlwifi: do not complete firmware loading needlessly
  drm/amdgpu: Fix potential NULL pointer dereference in atomctrl_get_smc_sclk_range_table
  drm/etnaviv: Fix page property being used for non writecombine buffers
  afs: Fix directory format encoding struct
  overflow: Allow mixed type arguments
  overflow: Correct check_shl_overflow() comment
  overflow: Add __must_check attribute to check_*() helpers
  udf: Fix use of check_add_overflow() with mixed type arguments

Change-Id: Ia7c26633509cfe8ec59d7dd0d6efd602629c87f4
Signed-off-by: bengris32 <bengris32@protonmail.ch>
2025-06-01 18:10:49 +01:00

2148 lines
54 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Procedures for creating, accessing and interpreting the device tree.
*
* Paul Mackerras August 1996.
* Copyright (C) 1996-2005 Paul Mackerras.
*
* Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
* {engebret|bergner}@us.ibm.com
*
* Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net
*
* Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell and
* Grant Likely.
*/
#define pr_fmt(fmt) "OF: " fmt
#include <linux/console.h>
#include <linux/ctype.h>
#include <linux/cpu.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/proc_fs.h>
#include "of_private.h"
LIST_HEAD(aliases_lookup);
struct device_node *of_root;
EXPORT_SYMBOL(of_root);
struct device_node *of_chosen;
struct device_node *of_aliases;
struct device_node *of_stdout;
static const char *of_stdout_options;
struct kset *of_kset;
/*
* Used to protect the of_aliases, to hold off addition of nodes to sysfs.
* This mutex must be held whenever modifications are being made to the
* device tree. The of_{attach,detach}_node() and
* of_{add,remove,update}_property() helpers make sure this happens.
*/
DEFINE_MUTEX(of_mutex);
/* use when traversing tree through the child, sibling,
* or parent members of struct device_node.
*/
DEFINE_RAW_SPINLOCK(devtree_lock);
bool of_node_name_eq(const struct device_node *np, const char *name)
{
const char *node_name;
size_t len;
if (!np)
return false;
node_name = kbasename(np->full_name);
len = strchrnul(node_name, '@') - node_name;
return (strlen(name) == len) && (strncmp(node_name, name, len) == 0);
}
EXPORT_SYMBOL(of_node_name_eq);
bool of_node_name_prefix(const struct device_node *np, const char *prefix)
{
if (!np)
return false;
return strncmp(kbasename(np->full_name), prefix, strlen(prefix)) == 0;
}
EXPORT_SYMBOL(of_node_name_prefix);
int of_n_addr_cells(struct device_node *np)
{
u32 cells;
do {
if (np->parent)
np = np->parent;
if (!of_property_read_u32(np, "#address-cells", &cells))
return cells;
} while (np->parent);
/* No #address-cells property for the root node */
return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
}
EXPORT_SYMBOL(of_n_addr_cells);
int of_n_size_cells(struct device_node *np)
{
u32 cells;
do {
if (np->parent)
np = np->parent;
if (!of_property_read_u32(np, "#size-cells", &cells))
return cells;
} while (np->parent);
/* No #size-cells property for the root node */
return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
}
EXPORT_SYMBOL(of_n_size_cells);
#ifdef CONFIG_NUMA
int __weak of_node_to_nid(struct device_node *np)
{
return NUMA_NO_NODE;
}
#endif
/*
* Assumptions behind phandle_cache implementation:
* - phandle property values are in a contiguous range of 1..n
*
* If the assumptions do not hold, then
* - the phandle lookup overhead reduction provided by the cache
* will likely be less
*/
static struct device_node **phandle_cache;
static u32 phandle_cache_mask;
/*
* Caller must hold devtree_lock.
*/
static void __of_free_phandle_cache(void)
{
u32 cache_entries = phandle_cache_mask + 1;
u32 k;
if (!phandle_cache)
return;
for (k = 0; k < cache_entries; k++)
of_node_put(phandle_cache[k]);
kfree(phandle_cache);
phandle_cache = NULL;
}
int of_free_phandle_cache(void)
{
unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
__of_free_phandle_cache();
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return 0;
}
#if !defined(CONFIG_MODULES)
late_initcall_sync(of_free_phandle_cache);
#endif
/*
* Caller must hold devtree_lock.
*/
void __of_free_phandle_cache_entry(phandle handle)
{
phandle masked_handle;
struct device_node *np;
if (!handle)
return;
masked_handle = handle & phandle_cache_mask;
if (phandle_cache) {
np = phandle_cache[masked_handle];
if (np && handle == np->phandle) {
of_node_put(np);
phandle_cache[masked_handle] = NULL;
}
}
}
void of_populate_phandle_cache(void)
{
unsigned long flags;
u32 cache_entries;
struct device_node *np;
u32 phandles = 0;
raw_spin_lock_irqsave(&devtree_lock, flags);
__of_free_phandle_cache();
for_each_of_allnodes(np)
if (np->phandle && np->phandle != OF_PHANDLE_ILLEGAL)
phandles++;
if (!phandles)
goto out;
cache_entries = roundup_pow_of_two(phandles);
phandle_cache_mask = cache_entries - 1;
phandle_cache = kcalloc(cache_entries, sizeof(*phandle_cache),
GFP_ATOMIC);
if (!phandle_cache)
goto out;
for_each_of_allnodes(np)
if (np->phandle && np->phandle != OF_PHANDLE_ILLEGAL) {
of_node_get(np);
phandle_cache[np->phandle & phandle_cache_mask] = np;
}
out:
raw_spin_unlock_irqrestore(&devtree_lock, flags);
}
void __init of_core_init(void)
{
struct device_node *np;
of_populate_phandle_cache();
/* Create the kset, and register existing nodes */
mutex_lock(&of_mutex);
of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj);
if (!of_kset) {
mutex_unlock(&of_mutex);
pr_err("failed to register existing nodes\n");
return;
}
for_each_of_allnodes(np)
__of_attach_node_sysfs(np);
mutex_unlock(&of_mutex);
/* Symlink in /proc as required by userspace ABI */
if (of_root)
proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base");
}
static struct property *__of_find_property(const struct device_node *np,
const char *name, int *lenp)
{
struct property *pp;
if (!np)
return NULL;
for (pp = np->properties; pp; pp = pp->next) {
if (of_prop_cmp(pp->name, name) == 0) {
if (lenp)
*lenp = pp->length;
break;
}
}
return pp;
}
struct property *of_find_property(const struct device_node *np,
const char *name,
int *lenp)
{
struct property *pp;
unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
pp = __of_find_property(np, name, lenp);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return pp;
}
EXPORT_SYMBOL(of_find_property);
struct device_node *__of_find_all_nodes(struct device_node *prev)
{
struct device_node *np;
if (!prev) {
np = of_root;
} else if (prev->child) {
np = prev->child;
} else {
/* Walk back up looking for a sibling, or the end of the structure */
np = prev;
while (np->parent && !np->sibling)
np = np->parent;
np = np->sibling; /* Might be null at the end of the tree */
}
return np;
}
/**
* of_find_all_nodes - Get next node in global list
* @prev: Previous node or NULL to start iteration
* of_node_put() will be called on it
*
* Returns a node pointer with refcount incremented, use
* of_node_put() on it when done.
*/
struct device_node *of_find_all_nodes(struct device_node *prev)
{
struct device_node *np;
unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
np = __of_find_all_nodes(prev);
of_node_get(np);
of_node_put(prev);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
}
EXPORT_SYMBOL(of_find_all_nodes);
/*
* Find a property with a given name for a given node
* and return the value.
*/
const void *__of_get_property(const struct device_node *np,
const char *name, int *lenp)
{
struct property *pp = __of_find_property(np, name, lenp);
return pp ? pp->value : NULL;
}
/*
* Find a property with a given name for a given node
* and return the value.
*/
const void *of_get_property(const struct device_node *np, const char *name,
int *lenp)
{
struct property *pp = of_find_property(np, name, lenp);
return pp ? pp->value : NULL;
}
EXPORT_SYMBOL(of_get_property);
/*
* arch_match_cpu_phys_id - Match the given logical CPU and physical id
*
* @cpu: logical cpu index of a core/thread
* @phys_id: physical identifier of a core/thread
*
* CPU logical to physical index mapping is architecture specific.
* However this __weak function provides a default match of physical
* id to logical cpu index. phys_id provided here is usually values read
* from the device tree which must match the hardware internal registers.
*
* Returns true if the physical identifier and the logical cpu index
* correspond to the same core/thread, false otherwise.
*/
bool __weak arch_match_cpu_phys_id(int cpu, u64 phys_id)
{
return (u32)phys_id == cpu;
}
/**
* Checks if the given "prop_name" property holds the physical id of the
* core/thread corresponding to the logical cpu 'cpu'. If 'thread' is not
* NULL, local thread number within the core is returned in it.
*/
static bool __of_find_n_match_cpu_property(struct device_node *cpun,
const char *prop_name, int cpu, unsigned int *thread)
{
const __be32 *cell;
int ac, prop_len, tid;
u64 hwid;
ac = of_n_addr_cells(cpun);
cell = of_get_property(cpun, prop_name, &prop_len);
if (!cell || !ac)
return false;
prop_len /= sizeof(*cell) * ac;
for (tid = 0; tid < prop_len; tid++) {
hwid = of_read_number(cell, ac);
if (arch_match_cpu_phys_id(cpu, hwid)) {
if (thread)
*thread = tid;
return true;
}
cell += ac;
}
return false;
}
/*
* arch_find_n_match_cpu_physical_id - See if the given device node is
* for the cpu corresponding to logical cpu 'cpu'. Return true if so,
* else false. If 'thread' is non-NULL, the local thread number within the
* core is returned in it.
*/
bool __weak arch_find_n_match_cpu_physical_id(struct device_node *cpun,
int cpu, unsigned int *thread)
{
/* Check for non-standard "ibm,ppc-interrupt-server#s" property
* for thread ids on PowerPC. If it doesn't exist fallback to
* standard "reg" property.
*/
if (IS_ENABLED(CONFIG_PPC) &&
__of_find_n_match_cpu_property(cpun,
"ibm,ppc-interrupt-server#s",
cpu, thread))
return true;
return __of_find_n_match_cpu_property(cpun, "reg", cpu, thread);
}
/**
* of_get_cpu_node - Get device node associated with the given logical CPU
*
* @cpu: CPU number(logical index) for which device node is required
* @thread: if not NULL, local thread number within the physical core is
* returned
*
* The main purpose of this function is to retrieve the device node for the
* given logical CPU index. It should be used to initialize the of_node in
* cpu device. Once of_node in cpu device is populated, all the further
* references can use that instead.
*
* CPU logical to physical index mapping is architecture specific and is built
* before booting secondary cores. This function uses arch_match_cpu_phys_id
* which can be overridden by architecture specific implementation.
*
* Returns a node pointer for the logical cpu with refcount incremented, use
* of_node_put() on it when done. Returns NULL if not found.
*/
struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
{
struct device_node *cpun;
for_each_node_by_type(cpun, "cpu") {
if (arch_find_n_match_cpu_physical_id(cpun, cpu, thread))
return cpun;
}
return NULL;
}
EXPORT_SYMBOL(of_get_cpu_node);
/**
* of_cpu_node_to_id: Get the logical CPU number for a given device_node
*
* @cpu_node: Pointer to the device_node for CPU.
*
* Returns the logical CPU number of the given CPU device_node.
* Returns -ENODEV if the CPU is not found.
*/
int of_cpu_node_to_id(struct device_node *cpu_node)
{
int cpu;
bool found = false;
struct device_node *np;
for_each_possible_cpu(cpu) {
np = of_cpu_device_node_get(cpu);
found = (cpu_node == np);
of_node_put(np);
if (found)
return cpu;
}
return -ENODEV;
}
EXPORT_SYMBOL(of_cpu_node_to_id);
/**
* __of_device_is_compatible() - Check if the node matches given constraints
* @device: pointer to node
* @compat: required compatible string, NULL or "" for any match
* @type: required device_type value, NULL or "" for any match
* @name: required node name, NULL or "" for any match
*
* Checks if the given @compat, @type and @name strings match the
* properties of the given @device. A constraints can be skipped by
* passing NULL or an empty string as the constraint.
*
* Returns 0 for no match, and a positive integer on match. The return
* value is a relative score with larger values indicating better
* matches. The score is weighted for the most specific compatible value
* to get the highest score. Matching type is next, followed by matching
* name. Practically speaking, this results in the following priority
* order for matches:
*
* 1. specific compatible && type && name
* 2. specific compatible && type
* 3. specific compatible && name
* 4. specific compatible
* 5. general compatible && type && name
* 6. general compatible && type
* 7. general compatible && name
* 8. general compatible
* 9. type && name
* 10. type
* 11. name
*/
static int __of_device_is_compatible(const struct device_node *device,
const char *compat, const char *type, const char *name)
{
struct property *prop;
const char *cp;
int index = 0, score = 0;
/* Compatible match has highest priority */
if (compat && compat[0]) {
prop = __of_find_property(device, "compatible", NULL);
for (cp = of_prop_next_string(prop, NULL); cp;
cp = of_prop_next_string(prop, cp), index++) {
if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {
score = INT_MAX/2 - (index << 2);
break;
}
}
if (!score)
return 0;
}
/* Matching type is better than matching name */
if (type && type[0]) {
if (!device->type || of_node_cmp(type, device->type))
return 0;
score += 2;
}
/* Matching name is a bit better than not */
if (name && name[0]) {
if (!device->name || of_node_cmp(name, device->name))
return 0;
score++;
}
return score;
}
/** Checks if the given "compat" string matches one of the strings in
* the device's "compatible" property
*/
int of_device_is_compatible(const struct device_node *device,
const char *compat)
{
unsigned long flags;
int res;
raw_spin_lock_irqsave(&devtree_lock, flags);
res = __of_device_is_compatible(device, compat, NULL, NULL);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return res;
}
EXPORT_SYMBOL(of_device_is_compatible);
/** Checks if the device is compatible with any of the entries in
* a NULL terminated array of strings. Returns the best match
* score or 0.
*/
int of_device_compatible_match(struct device_node *device,
const char *const *compat)
{
unsigned int tmp, score = 0;
if (!compat)
return 0;
while (*compat) {
tmp = of_device_is_compatible(device, *compat);
if (tmp > score)
score = tmp;
compat++;
}
return score;
}
/**
* of_machine_is_compatible - Test root of device tree for a given compatible value
* @compat: compatible string to look for in root node's compatible property.
*
* Returns a positive integer if the root node has the given value in its
* compatible property.
*/
int of_machine_is_compatible(const char *compat)
{
struct device_node *root;
int rc = 0;
root = of_find_node_by_path("/");
if (root) {
rc = of_device_is_compatible(root, compat);
of_node_put(root);
}
return rc;
}
EXPORT_SYMBOL(of_machine_is_compatible);
/**
* __of_device_is_available - check if a device is available for use
*
* @device: Node to check for availability, with locks already held
*
* Returns true if the status property is absent or set to "okay" or "ok",
* false otherwise
*/
static bool __of_device_is_available(const struct device_node *device)
{
const char *status;
int statlen;
if (!device)
return false;
status = __of_get_property(device, "status", &statlen);
if (status == NULL)
return true;
if (statlen > 0) {
if (!strcmp(status, "okay") || !strcmp(status, "ok"))
return true;
}
return false;
}
/**
* of_device_is_available - check if a device is available for use
*
* @device: Node to check for availability
*
* Returns true if the status property is absent or set to "okay" or "ok",
* false otherwise
*/
bool of_device_is_available(const struct device_node *device)
{
unsigned long flags;
bool res;
raw_spin_lock_irqsave(&devtree_lock, flags);
res = __of_device_is_available(device);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return res;
}
EXPORT_SYMBOL(of_device_is_available);
/**
* of_device_is_big_endian - check if a device has BE registers
*
* @device: Node to check for endianness
*
* Returns true if the device has a "big-endian" property, or if the kernel
* was compiled for BE *and* the device has a "native-endian" property.
* Returns false otherwise.
*
* Callers would nominally use ioread32be/iowrite32be if
* of_device_is_big_endian() == true, or readl/writel otherwise.
*/
bool of_device_is_big_endian(const struct device_node *device)
{
if (of_property_read_bool(device, "big-endian"))
return true;
if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) &&
of_property_read_bool(device, "native-endian"))
return true;
return false;
}
EXPORT_SYMBOL(of_device_is_big_endian);
/**
* of_get_parent - Get a node's parent if any
* @node: Node to get parent
*
* Returns a node pointer with refcount incremented, use
* of_node_put() on it when done.
*/
struct device_node *of_get_parent(const struct device_node *node)
{
struct device_node *np;
unsigned long flags;
if (!node)
return NULL;
raw_spin_lock_irqsave(&devtree_lock, flags);
np = of_node_get(node->parent);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
}
EXPORT_SYMBOL(of_get_parent);
/**
* of_get_next_parent - Iterate to a node's parent
* @node: Node to get parent of
*
* This is like of_get_parent() except that it drops the
* refcount on the passed node, making it suitable for iterating
* through a node's parents.
*
* Returns a node pointer with refcount incremented, use
* of_node_put() on it when done.
*/
struct device_node *of_get_next_parent(struct device_node *node)
{
struct device_node *parent;
unsigned long flags;
if (!node)
return NULL;
raw_spin_lock_irqsave(&devtree_lock, flags);
parent = of_node_get(node->parent);
of_node_put(node);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return parent;
}
EXPORT_SYMBOL(of_get_next_parent);
static struct device_node *__of_get_next_child(const struct device_node *node,
struct device_node *prev)
{
struct device_node *next;
if (!node)
return NULL;
next = prev ? prev->sibling : node->child;
for (; next; next = next->sibling)
if (of_node_get(next))
break;
of_node_put(prev);
return next;
}
#define __for_each_child_of_node(parent, child) \
for (child = __of_get_next_child(parent, NULL); child != NULL; \
child = __of_get_next_child(parent, child))
/**
* of_get_next_child - Iterate a node childs
* @node: parent node
* @prev: previous child of the parent node, or NULL to get first
*
* Returns a node pointer with refcount incremented, use of_node_put() on
* it when done. Returns NULL when prev is the last child. Decrements the
* refcount of prev.
*/
struct device_node *of_get_next_child(const struct device_node *node,
struct device_node *prev)
{
struct device_node *next;
unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
next = __of_get_next_child(node, prev);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return next;
}
EXPORT_SYMBOL(of_get_next_child);
/**
* of_get_next_available_child - Find the next available child node
* @node: parent node
* @prev: previous child of the parent node, or NULL to get first
*
* This function is like of_get_next_child(), except that it
* automatically skips any disabled nodes (i.e. status = "disabled").
*/
struct device_node *of_get_next_available_child(const struct device_node *node,
struct device_node *prev)
{
struct device_node *next;
unsigned long flags;
if (!node)
return NULL;
raw_spin_lock_irqsave(&devtree_lock, flags);
next = prev ? prev->sibling : node->child;
for (; next; next = next->sibling) {
if (!__of_device_is_available(next))
continue;
if (of_node_get(next))
break;
}
of_node_put(prev);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return next;
}
EXPORT_SYMBOL(of_get_next_available_child);
/**
* of_get_compatible_child - Find compatible child node
* @parent: parent node
* @compatible: compatible string
*
* Lookup child node whose compatible property contains the given compatible
* string.
*
* Returns a node pointer with refcount incremented, use of_node_put() on it
* when done; or NULL if not found.
*/
struct device_node *of_get_compatible_child(const struct device_node *parent,
const char *compatible)
{
struct device_node *child;
for_each_child_of_node(parent, child) {
if (of_device_is_compatible(child, compatible))
break;
}
return child;
}
EXPORT_SYMBOL(of_get_compatible_child);
/**
* of_get_child_by_name - Find the child node by name for a given parent
* @node: parent node
* @name: child name to look for.
*
* This function looks for child node for given matching name
*
* Returns a node pointer if found, with refcount incremented, use
* of_node_put() on it when done.
* Returns NULL if node is not found.
*/
struct device_node *of_get_child_by_name(const struct device_node *node,
const char *name)
{
struct device_node *child;
for_each_child_of_node(node, child)
if (child->name && (of_node_cmp(child->name, name) == 0))
break;
return child;
}
EXPORT_SYMBOL(of_get_child_by_name);
struct device_node *__of_find_node_by_path(struct device_node *parent,
const char *path)
{
struct device_node *child;
int len;
len = strcspn(path, "/:");
if (!len)
return NULL;
__for_each_child_of_node(parent, child) {
const char *name = kbasename(child->full_name);
if (strncmp(path, name, len) == 0 && (strlen(name) == len))
return child;
}
return NULL;
}
struct device_node *__of_find_node_by_full_path(struct device_node *node,
const char *path)
{
const char *separator = strchr(path, ':');
while (node && *path == '/') {
struct device_node *tmp = node;
path++; /* Increment past '/' delimiter */
node = __of_find_node_by_path(node, path);
of_node_put(tmp);
path = strchrnul(path, '/');
if (separator && separator < path)
break;
}
return node;
}
/**
* of_find_node_opts_by_path - Find a node matching a full OF path
* @path: Either the full path to match, or if the path does not
* start with '/', the name of a property of the /aliases
* node (an alias). In the case of an alias, the node
* matching the alias' value will be returned.
* @opts: Address of a pointer into which to store the start of
* an options string appended to the end of the path with
* a ':' separator.
*
* Valid paths:
* /foo/bar Full path
* foo Valid alias
* foo/bar Valid alias + relative path
*
* Returns a node pointer with refcount incremented, use
* of_node_put() on it when done.
*/
struct device_node *of_find_node_opts_by_path(const char *path, const char **opts)
{
struct device_node *np = NULL;
struct property *pp;
unsigned long flags;
const char *separator = strchr(path, ':');
if (opts)
*opts = separator ? separator + 1 : NULL;
if (strcmp(path, "/") == 0)
return of_node_get(of_root);
/* The path could begin with an alias */
if (*path != '/') {
int len;
const char *p = strchrnul(path, '/');
if (separator && separator < p)
p = separator;
len = p - path;
/* of_aliases must not be NULL */
if (!of_aliases)
return NULL;
for_each_property_of_node(of_aliases, pp) {
if (strlen(pp->name) == len && !strncmp(pp->name, path, len)) {
np = of_find_node_by_path(pp->value);
break;
}
}
if (!np)
return NULL;
path = p;
}
/* Step down the tree matching path components */
raw_spin_lock_irqsave(&devtree_lock, flags);
if (!np)
np = of_node_get(of_root);
np = __of_find_node_by_full_path(np, path);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
}
EXPORT_SYMBOL(of_find_node_opts_by_path);
/**
* of_find_node_by_name - Find a node by its "name" property
* @from: The node to start searching from or NULL; the node
* you pass will not be searched, only the next one
* will. Typically, you pass what the previous call
* returned. of_node_put() will be called on @from.
* @name: The name string to match against
*
* Returns a node pointer with refcount incremented, use
* of_node_put() on it when done.
*/
struct device_node *of_find_node_by_name(struct device_node *from,
const char *name)
{
struct device_node *np;
unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
for_each_of_allnodes_from(from, np)
if (np->name && (of_node_cmp(np->name, name) == 0)
&& of_node_get(np))
break;
of_node_put(from);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
}
EXPORT_SYMBOL(of_find_node_by_name);
/**
* of_find_node_by_type - Find a node by its "device_type" property
* @from: The node to start searching from, or NULL to start searching
* the entire device tree. The node you pass will not be
* searched, only the next one will; typically, you pass
* what the previous call returned. of_node_put() will be
* called on from for you.
* @type: The type string to match against
*
* Returns a node pointer with refcount incremented, use
* of_node_put() on it when done.
*/
struct device_node *of_find_node_by_type(struct device_node *from,
const char *type)
{
struct device_node *np;
unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
for_each_of_allnodes_from(from, np)
if (np->type && (of_node_cmp(np->type, type) == 0)
&& of_node_get(np))
break;
of_node_put(from);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
}
EXPORT_SYMBOL(of_find_node_by_type);
/**
* of_find_compatible_node - Find a node based on type and one of the
* tokens in its "compatible" property
* @from: The node to start searching from or NULL, the node
* you pass will not be searched, only the next one
* will; typically, you pass what the previous call
* returned. of_node_put() will be called on it
* @type: The type string to match "device_type" or NULL to ignore
* @compatible: The string to match to one of the tokens in the device
* "compatible" list.
*
* Returns a node pointer with refcount incremented, use
* of_node_put() on it when done.
*/
struct device_node *of_find_compatible_node(struct device_node *from,
const char *type, const char *compatible)
{
struct device_node *np;
unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
for_each_of_allnodes_from(from, np)
if (__of_device_is_compatible(np, compatible, type, NULL) &&
of_node_get(np))
break;
of_node_put(from);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
}
EXPORT_SYMBOL(of_find_compatible_node);
/**
* of_find_node_with_property - Find a node which has a property with
* the given name.
* @from: The node to start searching from or NULL, the node
* you pass will not be searched, only the next one
* will; typically, you pass what the previous call
* returned. of_node_put() will be called on it
* @prop_name: The name of the property to look for.
*
* Returns a node pointer with refcount incremented, use
* of_node_put() on it when done.
*/
struct device_node *of_find_node_with_property(struct device_node *from,
const char *prop_name)
{
struct device_node *np;
struct property *pp;
unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
for_each_of_allnodes_from(from, np) {
for (pp = np->properties; pp; pp = pp->next) {
if (of_prop_cmp(pp->name, prop_name) == 0) {
of_node_get(np);
goto out;
}
}
}
out:
of_node_put(from);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
}
EXPORT_SYMBOL(of_find_node_with_property);
static
const struct of_device_id *__of_match_node(const struct of_device_id *matches,
const struct device_node *node)
{
const struct of_device_id *best_match = NULL;
int score, best_score = 0;
if (!matches)
return NULL;
for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) {
score = __of_device_is_compatible(node, matches->compatible,
matches->type, matches->name);
if (score > best_score) {
best_match = matches;
best_score = score;
}
}
return best_match;
}
/**
* of_match_node - Tell if a device_node has a matching of_match structure
* @matches: array of of device match structures to search in
* @node: the of device structure to match against
*
* Low level utility function used by device matching.
*/
const struct of_device_id *of_match_node(const struct of_device_id *matches,
const struct device_node *node)
{
const struct of_device_id *match;
unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
match = __of_match_node(matches, node);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return match;
}
EXPORT_SYMBOL(of_match_node);
/**
* of_find_matching_node_and_match - Find a node based on an of_device_id
* match table.
* @from: The node to start searching from or NULL, the node
* you pass will not be searched, only the next one
* will; typically, you pass what the previous call
* returned. of_node_put() will be called on it
* @matches: array of of device match structures to search in
* @match Updated to point at the matches entry which matched
*
* Returns a node pointer with refcount incremented, use
* of_node_put() on it when done.
*/
struct device_node *of_find_matching_node_and_match(struct device_node *from,
const struct of_device_id *matches,
const struct of_device_id **match)
{
struct device_node *np;
const struct of_device_id *m;
unsigned long flags;
if (match)
*match = NULL;
raw_spin_lock_irqsave(&devtree_lock, flags);
for_each_of_allnodes_from(from, np) {
m = __of_match_node(matches, np);
if (m && of_node_get(np)) {
if (match)
*match = m;
break;
}
}
of_node_put(from);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
}
EXPORT_SYMBOL(of_find_matching_node_and_match);
/**
* of_modalias_node - Lookup appropriate modalias for a device node
* @node: pointer to a device tree node
* @modalias: Pointer to buffer that modalias value will be copied into
* @len: Length of modalias value
*
* Based on the value of the compatible property, this routine will attempt
* to choose an appropriate modalias value for a particular device tree node.
* It does this by stripping the manufacturer prefix (as delimited by a ',')
* from the first entry in the compatible list property.
*
* This routine returns 0 on success, <0 on failure.
*/
int of_modalias_node(struct device_node *node, char *modalias, int len)
{
const char *compatible, *p;
int cplen;
compatible = of_get_property(node, "compatible", &cplen);
if (!compatible || strlen(compatible) > cplen)
return -ENODEV;
p = strchr(compatible, ',');
strlcpy(modalias, p ? p + 1 : compatible, len);
return 0;
}
EXPORT_SYMBOL_GPL(of_modalias_node);
/**
* of_find_node_by_phandle - Find a node given a phandle
* @handle: phandle of the node to find
*
* Returns a node pointer with refcount incremented, use
* of_node_put() on it when done.
*/
struct device_node *of_find_node_by_phandle(phandle handle)
{
struct device_node *np = NULL;
unsigned long flags;
phandle masked_handle;
if (!handle)
return NULL;
raw_spin_lock_irqsave(&devtree_lock, flags);
masked_handle = handle & phandle_cache_mask;
if (phandle_cache) {
if (phandle_cache[masked_handle] &&
handle == phandle_cache[masked_handle]->phandle)
np = phandle_cache[masked_handle];
if (np && of_node_check_flag(np, OF_DETACHED)) {
WARN_ON(1); /* did not uncache np on node removal */
of_node_put(np);
phandle_cache[masked_handle] = NULL;
np = NULL;
}
}
if (!np) {
for_each_of_allnodes(np)
if (np->phandle == handle &&
!of_node_check_flag(np, OF_DETACHED)) {
if (phandle_cache) {
/* will put when removed from cache */
of_node_get(np);
phandle_cache[masked_handle] = np;
}
break;
}
}
of_node_get(np);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
}
EXPORT_SYMBOL(of_find_node_by_phandle);
void of_print_phandle_args(const char *msg, const struct of_phandle_args *args)
{
int i;
printk("%s %pOF", msg, args->np);
for (i = 0; i < args->args_count; i++) {
const char delim = i ? ',' : ':';
pr_cont("%c%08x", delim, args->args[i]);
}
pr_cont("\n");
}
int of_phandle_iterator_init(struct of_phandle_iterator *it,
const struct device_node *np,
const char *list_name,
const char *cells_name,
int cell_count)
{
const __be32 *list;
int size;
memset(it, 0, sizeof(*it));
/*
* one of cell_count or cells_name must be provided to determine the
* argument length.
*/
if (cell_count < 0 && !cells_name)
return -EINVAL;
list = of_get_property(np, list_name, &size);
if (!list)
return -ENOENT;
it->cells_name = cells_name;
it->cell_count = cell_count;
it->parent = np;
it->list_end = list + size / sizeof(*list);
it->phandle_end = list;
it->cur = list;
return 0;
}
EXPORT_SYMBOL_GPL(of_phandle_iterator_init);
int of_phandle_iterator_next(struct of_phandle_iterator *it)
{
uint32_t count = 0;
if (it->node) {
of_node_put(it->node);
it->node = NULL;
}
if (!it->cur || it->phandle_end >= it->list_end)
return -ENOENT;
it->cur = it->phandle_end;
/* If phandle is 0, then it is an empty entry with no arguments. */
it->phandle = be32_to_cpup(it->cur++);
if (it->phandle) {
/*
* Find the provider node and parse the #*-cells property to
* determine the argument length.
*/
it->node = of_find_node_by_phandle(it->phandle);
if (it->cells_name) {
if (!it->node) {
pr_err("%pOF: could not find phandle\n",
it->parent);
goto err;
}
if (of_property_read_u32(it->node, it->cells_name,
&count)) {
/*
* If both cell_count and cells_name is given,
* fall back to cell_count in absence
* of the cells_name property
*/
if (it->cell_count >= 0) {
count = it->cell_count;
} else {
pr_err("%pOF: could not get %s for %pOF\n",
it->parent,
it->cells_name,
it->node);
goto err;
}
}
} else {
count = it->cell_count;
}
/*
* Make sure that the arguments actually fit in the remaining
* property data length
*/
if (it->cur + count > it->list_end) {
pr_err("%pOF: arguments longer than property\n",
it->parent);
goto err;
}
}
it->phandle_end = it->cur + count;
it->cur_count = count;
return 0;
err:
if (it->node) {
of_node_put(it->node);
it->node = NULL;
}
return -EINVAL;
}
EXPORT_SYMBOL_GPL(of_phandle_iterator_next);
int of_phandle_iterator_args(struct of_phandle_iterator *it,
uint32_t *args,
int size)
{
int i, count;
count = it->cur_count;
if (WARN_ON(size < count))
count = size;
for (i = 0; i < count; i++)
args[i] = be32_to_cpup(it->cur++);
return count;
}
EXPORT_SYMBOL_GPL(of_phandle_iterator_args);
static int __of_parse_phandle_with_args(const struct device_node *np,
const char *list_name,
const char *cells_name,
int cell_count, int index,
struct of_phandle_args *out_args)
{
struct of_phandle_iterator it;
int rc, cur_index = 0;
/* Loop over the phandles until all the requested entry is found */
of_for_each_phandle(&it, rc, np, list_name, cells_name, cell_count) {
/*
* All of the error cases bail out of the loop, so at
* this point, the parsing is successful. If the requested
* index matches, then fill the out_args structure and return,
* or return -ENOENT for an empty entry.
*/
rc = -ENOENT;
if (cur_index == index) {
if (!it.phandle)
goto err;
if (out_args) {
int c;
c = of_phandle_iterator_args(&it,
out_args->args,
MAX_PHANDLE_ARGS);
out_args->np = it.node;
out_args->args_count = c;
} else {
of_node_put(it.node);
}
/* Found it! return success */
return 0;
}
cur_index++;
}
/*
* Unlock node before returning result; will be one of:
* -ENOENT : index is for empty phandle
* -EINVAL : parsing error on data
*/
err:
of_node_put(it.node);
return rc;
}
/**
* of_parse_phandle - Resolve a phandle property to a device_node pointer
* @np: Pointer to device node holding phandle property
* @phandle_name: Name of property holding a phandle value
* @index: For properties holding a table of phandles, this is the index into
* the table
*
* Returns the device_node pointer with refcount incremented. Use
* of_node_put() on it when done.
*/
struct device_node *of_parse_phandle(const struct device_node *np,
const char *phandle_name, int index)
{
struct of_phandle_args args;
if (index < 0)
return NULL;
if (__of_parse_phandle_with_args(np, phandle_name, NULL, 0,
index, &args))
return NULL;
return args.np;
}
EXPORT_SYMBOL(of_parse_phandle);
/**
* of_parse_phandle_with_args() - Find a node pointed by phandle in a list
* @np: pointer to a device tree node containing a list
* @list_name: property name that contains a list
* @cells_name: property name that specifies phandles' arguments count
* @index: index of a phandle to parse out
* @out_args: optional pointer to output arguments structure (will be filled)
*
* This function is useful to parse lists of phandles and their arguments.
* Returns 0 on success and fills out_args, on error returns appropriate
* errno value.
*
* Caller is responsible to call of_node_put() on the returned out_args->np
* pointer.
*
* Example:
*
* phandle1: node1 {
* #list-cells = <2>;
* }
*
* phandle2: node2 {
* #list-cells = <1>;
* }
*
* node3 {
* list = <&phandle1 1 2 &phandle2 3>;
* }
*
* To get a device_node of the `node2' node you may call this:
* of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args);
*/
int of_parse_phandle_with_args(const struct device_node *np, const char *list_name,
const char *cells_name, int index,
struct of_phandle_args *out_args)
{
int cell_count = -1;
if (index < 0)
return -EINVAL;
/* If cells_name is NULL we assume a cell count of 0 */
if (!cells_name)
cell_count = 0;
return __of_parse_phandle_with_args(np, list_name, cells_name,
cell_count, index, out_args);
}
EXPORT_SYMBOL(of_parse_phandle_with_args);
/**
* of_parse_phandle_with_args_map() - Find a node pointed by phandle in a list and remap it
* @np: pointer to a device tree node containing a list
* @list_name: property name that contains a list
* @stem_name: stem of property names that specify phandles' arguments count
* @index: index of a phandle to parse out
* @out_args: optional pointer to output arguments structure (will be filled)
*
* This function is useful to parse lists of phandles and their arguments.
* Returns 0 on success and fills out_args, on error returns appropriate errno
* value. The difference between this function and of_parse_phandle_with_args()
* is that this API remaps a phandle if the node the phandle points to has
* a <@stem_name>-map property.
*
* Caller is responsible to call of_node_put() on the returned out_args->np
* pointer.
*
* Example:
*
* phandle1: node1 {
* #list-cells = <2>;
* }
*
* phandle2: node2 {
* #list-cells = <1>;
* }
*
* phandle3: node3 {
* #list-cells = <1>;
* list-map = <0 &phandle2 3>,
* <1 &phandle2 2>,
* <2 &phandle1 5 1>;
* list-map-mask = <0x3>;
* };
*
* node4 {
* list = <&phandle1 1 2 &phandle3 0>;
* }
*
* To get a device_node of the `node2' node you may call this:
* of_parse_phandle_with_args(node4, "list", "list", 1, &args);
*/
int of_parse_phandle_with_args_map(const struct device_node *np,
const char *list_name,
const char *stem_name,
int index, struct of_phandle_args *out_args)
{
char *cells_name, *map_name = NULL, *mask_name = NULL;
char *pass_name = NULL;
struct device_node *cur, *new = NULL;
const __be32 *map, *mask, *pass;
static const __be32 dummy_mask[] = { [0 ... MAX_PHANDLE_ARGS] = ~0 };
static const __be32 dummy_pass[] = { [0 ... MAX_PHANDLE_ARGS] = 0 };
__be32 initial_match_array[MAX_PHANDLE_ARGS];
const __be32 *match_array = initial_match_array;
int i, ret, map_len, match;
u32 list_size, new_size;
if (index < 0)
return -EINVAL;
cells_name = kasprintf(GFP_KERNEL, "#%s-cells", stem_name);
if (!cells_name)
return -ENOMEM;
ret = -ENOMEM;
map_name = kasprintf(GFP_KERNEL, "%s-map", stem_name);
if (!map_name)
goto free;
mask_name = kasprintf(GFP_KERNEL, "%s-map-mask", stem_name);
if (!mask_name)
goto free;
pass_name = kasprintf(GFP_KERNEL, "%s-map-pass-thru", stem_name);
if (!pass_name)
goto free;
ret = __of_parse_phandle_with_args(np, list_name, cells_name, -1, index,
out_args);
if (ret)
goto free;
/* Get the #<list>-cells property */
cur = out_args->np;
ret = of_property_read_u32(cur, cells_name, &list_size);
if (ret < 0)
goto put;
/* Precalculate the match array - this simplifies match loop */
for (i = 0; i < list_size; i++)
initial_match_array[i] = cpu_to_be32(out_args->args[i]);
ret = -EINVAL;
while (cur) {
/* Get the <list>-map property */
map = of_get_property(cur, map_name, &map_len);
if (!map) {
ret = 0;
goto free;
}
map_len /= sizeof(u32);
/* Get the <list>-map-mask property (optional) */
mask = of_get_property(cur, mask_name, NULL);
if (!mask)
mask = dummy_mask;
/* Iterate through <list>-map property */
match = 0;
while (map_len > (list_size + 1) && !match) {
/* Compare specifiers */
match = 1;
for (i = 0; i < list_size; i++, map_len--)
match &= !((match_array[i] ^ *map++) & mask[i]);
of_node_put(new);
new = of_find_node_by_phandle(be32_to_cpup(map));
map++;
map_len--;
/* Check if not found */
if (!new) {
ret = -EINVAL;
goto put;
}
if (!of_device_is_available(new))
match = 0;
ret = of_property_read_u32(new, cells_name, &new_size);
if (ret)
goto put;
/* Check for malformed properties */
if (WARN_ON(new_size > MAX_PHANDLE_ARGS) ||
map_len < new_size) {
ret = -EINVAL;
goto put;
}
/* Move forward by new node's #<list>-cells amount */
map += new_size;
map_len -= new_size;
}
if (!match) {
ret = -ENOENT;
goto put;
}
/* Get the <list>-map-pass-thru property (optional) */
pass = of_get_property(cur, pass_name, NULL);
if (!pass)
pass = dummy_pass;
/*
* Successfully parsed a <list>-map translation; copy new
* specifier into the out_args structure, keeping the
* bits specified in <list>-map-pass-thru.
*/
for (i = 0; i < new_size; i++) {
__be32 val = *(map - new_size + i);
if (i < list_size) {
val &= ~pass[i];
val |= cpu_to_be32(out_args->args[i]) & pass[i];
}
initial_match_array[i] = val;
out_args->args[i] = be32_to_cpu(val);
}
out_args->args_count = list_size = new_size;
/* Iterate again with new provider */
out_args->np = new;
of_node_put(cur);
cur = new;
new = NULL;
}
put:
of_node_put(cur);
of_node_put(new);
free:
kfree(mask_name);
kfree(map_name);
kfree(cells_name);
kfree(pass_name);
return ret;
}
EXPORT_SYMBOL(of_parse_phandle_with_args_map);
/**
* of_parse_phandle_with_fixed_args() - Find a node pointed by phandle in a list
* @np: pointer to a device tree node containing a list
* @list_name: property name that contains a list
* @cell_count: number of argument cells following the phandle
* @index: index of a phandle to parse out
* @out_args: optional pointer to output arguments structure (will be filled)
*
* This function is useful to parse lists of phandles and their arguments.
* Returns 0 on success and fills out_args, on error returns appropriate
* errno value.
*
* Caller is responsible to call of_node_put() on the returned out_args->np
* pointer.
*
* Example:
*
* phandle1: node1 {
* }
*
* phandle2: node2 {
* }
*
* node3 {
* list = <&phandle1 0 2 &phandle2 2 3>;
* }
*
* To get a device_node of the `node2' node you may call this:
* of_parse_phandle_with_fixed_args(node3, "list", 2, 1, &args);
*/
int of_parse_phandle_with_fixed_args(const struct device_node *np,
const char *list_name, int cell_count,
int index, struct of_phandle_args *out_args)
{
if (index < 0)
return -EINVAL;
return __of_parse_phandle_with_args(np, list_name, NULL, cell_count,
index, out_args);
}
EXPORT_SYMBOL(of_parse_phandle_with_fixed_args);
/**
* of_count_phandle_with_args() - Find the number of phandles references in a property
* @np: pointer to a device tree node containing a list
* @list_name: property name that contains a list
* @cells_name: property name that specifies phandles' arguments count
*
* Returns the number of phandle + argument tuples within a property. It
* is a typical pattern to encode a list of phandle and variable
* arguments into a single property. The number of arguments is encoded
* by a property in the phandle-target node. For example, a gpios
* property would contain a list of GPIO specifies consisting of a
* phandle and 1 or more arguments. The number of arguments are
* determined by the #gpio-cells property in the node pointed to by the
* phandle.
*/
int of_count_phandle_with_args(const struct device_node *np, const char *list_name,
const char *cells_name)
{
struct of_phandle_iterator it;
int rc, cur_index = 0;
/*
* If cells_name is NULL we assume a cell count of 0. This makes
* counting the phandles trivial as each 32bit word in the list is a
* phandle and no arguments are to consider. So we don't iterate through
* the list but just use the length to determine the phandle count.
*/
if (!cells_name) {
const __be32 *list;
int size;
list = of_get_property(np, list_name, &size);
if (!list)
return -ENOENT;
return size / sizeof(*list);
}
rc = of_phandle_iterator_init(&it, np, list_name, cells_name, -1);
if (rc)
return rc;
while ((rc = of_phandle_iterator_next(&it)) == 0)
cur_index += 1;
if (rc != -ENOENT)
return rc;
return cur_index;
}
EXPORT_SYMBOL(of_count_phandle_with_args);
/**
* __of_add_property - Add a property to a node without lock operations
*/
int __of_add_property(struct device_node *np, struct property *prop)
{
struct property **next;
prop->next = NULL;
next = &np->properties;
while (*next) {
if (strcmp(prop->name, (*next)->name) == 0)
/* duplicate ! don't insert it */
return -EEXIST;
next = &(*next)->next;
}
*next = prop;
return 0;
}
/**
* of_add_property - Add a property to a node
*/
int of_add_property(struct device_node *np, struct property *prop)
{
unsigned long flags;
int rc;
mutex_lock(&of_mutex);
raw_spin_lock_irqsave(&devtree_lock, flags);
rc = __of_add_property(np, prop);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
if (!rc)
__of_add_property_sysfs(np, prop);
mutex_unlock(&of_mutex);
if (!rc)
of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop, NULL);
return rc;
}
int __of_remove_property(struct device_node *np, struct property *prop)
{
struct property **next;
for (next = &np->properties; *next; next = &(*next)->next) {
if (*next == prop)
break;
}
if (*next == NULL)
return -ENODEV;
/* found the node */
*next = prop->next;
prop->next = np->deadprops;
np->deadprops = prop;
return 0;
}
/**
* of_remove_property - Remove a property from a node.
*
* Note that we don't actually remove it, since we have given out
* who-knows-how-many pointers to the data using get-property.
* Instead we just move the property to the "dead properties"
* list, so it won't be found any more.
*/
int of_remove_property(struct device_node *np, struct property *prop)
{
unsigned long flags;
int rc;
if (!prop)
return -ENODEV;
mutex_lock(&of_mutex);
raw_spin_lock_irqsave(&devtree_lock, flags);
rc = __of_remove_property(np, prop);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
if (!rc)
__of_remove_property_sysfs(np, prop);
mutex_unlock(&of_mutex);
if (!rc)
of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop, NULL);
return rc;
}
int __of_update_property(struct device_node *np, struct property *newprop,
struct property **oldpropp)
{
struct property **next, *oldprop;
for (next = &np->properties; *next; next = &(*next)->next) {
if (of_prop_cmp((*next)->name, newprop->name) == 0)
break;
}
*oldpropp = oldprop = *next;
if (oldprop) {
/* replace the node */
newprop->next = oldprop->next;
*next = newprop;
oldprop->next = np->deadprops;
np->deadprops = oldprop;
} else {
/* new node */
newprop->next = NULL;
*next = newprop;
}
return 0;
}
/*
* of_update_property - Update a property in a node, if the property does
* not exist, add it.
*
* Note that we don't actually remove it, since we have given out
* who-knows-how-many pointers to the data using get-property.
* Instead we just move the property to the "dead properties" list,
* and add the new property to the property list
*/
int of_update_property(struct device_node *np, struct property *newprop)
{
struct property *oldprop;
unsigned long flags;
int rc;
if (!newprop->name)
return -EINVAL;
mutex_lock(&of_mutex);
raw_spin_lock_irqsave(&devtree_lock, flags);
rc = __of_update_property(np, newprop, &oldprop);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
if (!rc)
__of_update_property_sysfs(np, newprop, oldprop);
mutex_unlock(&of_mutex);
if (!rc)
of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop, oldprop);
return rc;
}
static void of_alias_add(struct alias_prop *ap, struct device_node *np,
int id, const char *stem, int stem_len)
{
ap->np = np;
ap->id = id;
strncpy(ap->stem, stem, stem_len);
ap->stem[stem_len] = 0;
list_add_tail(&ap->link, &aliases_lookup);
pr_debug("adding DT alias:%s: stem=%s id=%i node=%pOF\n",
ap->alias, ap->stem, ap->id, np);
}
/**
* of_alias_scan - Scan all properties of the 'aliases' node
*
* The function scans all the properties of the 'aliases' node and populates
* the global lookup table with the properties. It returns the
* number of alias properties found, or an error code in case of failure.
*
* @dt_alloc: An allocator that provides a virtual address to memory
* for storing the resulting tree
*/
void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
{
struct property *pp;
of_aliases = of_find_node_by_path("/aliases");
of_chosen = of_find_node_by_path("/chosen");
if (of_chosen == NULL)
of_chosen = of_find_node_by_path("/chosen@0");
if (of_chosen) {
/* linux,stdout-path and /aliases/stdout are for legacy compatibility */
const char *name = NULL;
if (of_property_read_string(of_chosen, "stdout-path", &name))
of_property_read_string(of_chosen, "linux,stdout-path",
&name);
if (IS_ENABLED(CONFIG_PPC) && !name)
of_property_read_string(of_aliases, "stdout", &name);
if (name)
of_stdout = of_find_node_opts_by_path(name, &of_stdout_options);
}
if (!of_aliases)
return;
for_each_property_of_node(of_aliases, pp) {
const char *start = pp->name;
const char *end = start + strlen(start);
struct device_node *np;
struct alias_prop *ap;
int id, len;
/* Skip those we do not want to proceed */
if (!strcmp(pp->name, "name") ||
!strcmp(pp->name, "phandle") ||
!strcmp(pp->name, "linux,phandle"))
continue;
np = of_find_node_by_path(pp->value);
if (!np)
continue;
/* walk the alias backwards to extract the id and work out
* the 'stem' string */
while (isdigit(*(end-1)) && end > start)
end--;
len = end - start;
if (kstrtoint(end, 10, &id) < 0)
continue;
/* Allocate an alias_prop with enough space for the stem */
ap = dt_alloc(sizeof(*ap) + len + 1, __alignof__(*ap));
if (!ap)
continue;
memset(ap, 0, sizeof(*ap) + len + 1);
ap->alias = start;
of_alias_add(ap, np, id, start, len);
}
}
/**
* of_alias_get_id - Get alias id for the given device_node
* @np: Pointer to the given device_node
* @stem: Alias stem of the given device_node
*
* The function travels the lookup table to get the alias id for the given
* device_node and alias stem. It returns the alias id if found.
*/
int of_alias_get_id(struct device_node *np, const char *stem)
{
struct alias_prop *app;
int id = -ENODEV;
mutex_lock(&of_mutex);
list_for_each_entry(app, &aliases_lookup, link) {
if (strcmp(app->stem, stem) != 0)
continue;
if (np == app->np) {
id = app->id;
break;
}
}
mutex_unlock(&of_mutex);
return id;
}
EXPORT_SYMBOL_GPL(of_alias_get_id);
/**
* of_alias_get_highest_id - Get highest alias id for the given stem
* @stem: Alias stem to be examined
*
* The function travels the lookup table to get the highest alias id for the
* given alias stem. It returns the alias id if found.
*/
int of_alias_get_highest_id(const char *stem)
{
struct alias_prop *app;
int id = -ENODEV;
mutex_lock(&of_mutex);
list_for_each_entry(app, &aliases_lookup, link) {
if (strcmp(app->stem, stem) != 0)
continue;
if (app->id > id)
id = app->id;
}
mutex_unlock(&of_mutex);
return id;
}
EXPORT_SYMBOL_GPL(of_alias_get_highest_id);
/**
* of_console_check() - Test and setup console for DT setup
* @dn - Pointer to device node
* @name - Name to use for preferred console without index. ex. "ttyS"
* @index - Index to use for preferred console.
*
* Check if the given device node matches the stdout-path property in the
* /chosen node. If it does then register it as the preferred console and return
* TRUE. Otherwise return FALSE.
*/
bool of_console_check(struct device_node *dn, char *name, int index)
{
if (!dn || dn != of_stdout || console_set_on_cmdline)
return false;
/*
* XXX: cast `options' to char pointer to suppress complication
* warnings: printk, UART and console drivers expect char pointer.
*/
return !add_preferred_console(name, index, (char *)of_stdout_options);
}
EXPORT_SYMBOL_GPL(of_console_check);
/**
* of_find_next_cache_node - Find a node's subsidiary cache
* @np: node of type "cpu" or "cache"
*
* Returns a node pointer with refcount incremented, use
* of_node_put() on it when done. Caller should hold a reference
* to np.
*/
struct device_node *of_find_next_cache_node(const struct device_node *np)
{
struct device_node *child, *cache_node;
cache_node = of_parse_phandle(np, "l2-cache", 0);
if (!cache_node)
cache_node = of_parse_phandle(np, "next-level-cache", 0);
if (cache_node)
return cache_node;
/* OF on pmac has nodes instead of properties named "l2-cache"
* beneath CPU nodes.
*/
if (IS_ENABLED(CONFIG_PPC_PMAC) && !strcmp(np->type, "cpu"))
for_each_child_of_node(np, child)
if (!strcmp(child->type, "cache"))
return child;
return NULL;
}
/**
* of_find_last_cache_level - Find the level at which the last cache is
* present for the given logical cpu
*
* @cpu: cpu number(logical index) for which the last cache level is needed
*
* Returns the the level at which the last cache is present. It is exactly
* same as the total number of cache levels for the given logical cpu.
*/
int of_find_last_cache_level(unsigned int cpu)
{
u32 cache_level = 0;
struct device_node *prev = NULL, *np = of_cpu_device_node_get(cpu);
while (np) {
prev = np;
of_node_put(np);
np = of_find_next_cache_node(np);
}
of_property_read_u32(prev, "cache-level", &cache_level);
return cache_level;
}