From 5b7c4cabbb65f5c469464da6c5f614cbd7f730f2 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 21 Feb 2023 18:24:12 -0800 Subject: Merge tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next Pull networking updates from Jakub Kicinski: "Core: - Add dedicated kmem_cache for typical/small skb->head, avoid having to access struct page at kfree time, and improve memory use. - Introduce sysctl to set default RPS configuration for new netdevs. - Define Netlink protocol specification format which can be used to describe messages used by each family and auto-generate parsers. Add tools for generating kernel data structures and uAPI headers. - Expose all net/core sysctls inside netns. - Remove 4s sleep in netpoll if carrier is instantly detected on boot. - Add configurable limit of MDB entries per port, and port-vlan. - Continue populating drop reasons throughout the stack. - Retire a handful of legacy Qdiscs and classifiers. Protocols: - Support IPv4 big TCP (TSO frames larger than 64kB). - Add IP_LOCAL_PORT_RANGE socket option, to control local port range on socket by socket basis. - Track and report in procfs number of MPTCP sockets used. - Support mixing IPv4 and IPv6 flows in the in-kernel MPTCP path manager. - IPv6: don't check net.ipv6.route.max_size and rely on garbage collection to free memory (similarly to IPv4). - Support Penultimate Segment Pop (PSP) flavor in SRv6 (RFC8986). - ICMP: add per-rate limit counters. - Add support for user scanning requests in ieee802154. - Remove static WEP support. - Support minimal Wi-Fi 7 Extremely High Throughput (EHT) rate reporting. - WiFi 7 EHT channel puncturing support (client & AP). BPF: - Add a rbtree data structure following the "next-gen data structure" precedent set by recently added linked list, that is, by using kfunc + kptr instead of adding a new BPF map type. - Expose XDP hints via kfuncs with initial support for RX hash and timestamp metadata. - Add BPF_F_NO_TUNNEL_KEY extension to bpf_skb_set_tunnel_key to better support decap on GRE tunnel devices not operating in collect metadata. - Improve x86 JIT's codegen for PROBE_MEM runtime error checks. - Remove the need for trace_printk_lock for bpf_trace_printk and bpf_trace_vprintk helpers. - Extend libbpf's bpf_tracing.h support for tracing arguments of kprobes/uprobes and syscall as a special case. - Significantly reduce the search time for module symbols by livepatch and BPF. - Enable cpumasks to be used as kptrs, which is useful for tracing programs tracking which tasks end up running on which CPUs in different time intervals. - Add support for BPF trampoline on s390x and riscv64. - Add capability to export the XDP features supported by the NIC. - Add __bpf_kfunc tag for marking kernel functions as kfuncs. - Add cgroup.memory=nobpf kernel parameter option to disable BPF memory accounting for container environments. Netfilter: - Remove the CLUSTERIP target. It has been marked as obsolete for years, and we still have WARN splats wrt races of the out-of-band /proc interface installed by this target. - Add 'destroy' commands to nf_tables. They are identical to the existing 'delete' commands, but do not return an error if the referenced object (set, chain, rule...) did not exist. Driver API: - Improve cpumask_local_spread() locality to help NICs set the right IRQ affinity on AMD platforms. - Separate C22 and C45 MDIO bus transactions more clearly. - Introduce new DCB table to control DSCP rewrite on egress. - Support configuration of Physical Layer Collision Avoidance (PLCA) Reconciliation Sublayer (RS) (802.3cg-2019). Modern version of shared medium Ethernet. - Support for MAC Merge layer (IEEE 802.3-2018 clause 99). Allowing preemption of low priority frames by high priority frames. - Add support for controlling MACSec offload using netlink SET. - Rework devlink instance refcounts to allow registration and de-registration under the instance lock. Split the code into multiple files, drop some of the unnecessarily granular locks and factor out common parts of netlink operation handling. - Add TX frame aggregation parameters (for USB drivers). - Add a new attr TCA_EXT_WARN_MSG to report TC (offload) warning messages with notifications for debug. - Allow offloading of UDP NEW connections via act_ct. - Add support for per action HW stats in TC. - Support hardware miss to TC action (continue processing in SW from a specific point in the action chain). - Warn if old Wireless Extension user space interface is used with modern cfg80211/mac80211 drivers. Do not support Wireless Extensions for Wi-Fi 7 devices at all. Everyone should switch to using nl80211 interface instead. - Improve the CAN bit timing configuration. Use extack to return error messages directly to user space, update the SJW handling, including the definition of a new default value that will benefit CAN-FD controllers, by increasing their oscillator tolerance. New hardware / drivers: - Ethernet: - nVidia BlueField-3 support (control traffic driver) - Ethernet support for imx93 SoCs - Motorcomm yt8531 gigabit Ethernet PHY - onsemi NCN26000 10BASE-T1S PHY (with support for PLCA) - Microchip LAN8841 PHY (incl. cable diagnostics and PTP) - Amlogic gxl MDIO mux - WiFi: - RealTek RTL8188EU (rtl8xxxu) - Qualcomm Wi-Fi 7 devices (ath12k) - CAN: - Renesas R-Car V4H Drivers: - Bluetooth: - Set Per Platform Antenna Gain (PPAG) for Intel controllers. - Ethernet NICs: - Intel (1G, igc): - support TSN / Qbv / packet scheduling features of i226 model - Intel (100G, ice): - use GNSS subsystem instead of TTY - multi-buffer XDP support - extend support for GPIO pins to E823 devices - nVidia/Mellanox: - update the shared buffer configuration on PFC commands - implement PTP adjphase function for HW offset control - TC support for Geneve and GRE with VF tunnel offload - more efficient crypto key management method - multi-port eswitch support - Netronome/Corigine: - add DCB IEEE support - support IPsec offloading for NFP3800 - Freescale/NXP (enetc): - support XDP_REDIRECT for XDP non-linear buffers - improve reconfig, avoid link flap and waiting for idle - support MAC Merge layer - Other NICs: - sfc/ef100: add basic devlink support for ef100 - ionic: rx_push mode operation (writing descriptors via MMIO) - bnxt: use the auxiliary bus abstraction for RDMA - r8169: disable ASPM and reset bus in case of tx timeout - cpsw: support QSGMII mode for J721e CPSW9G - cpts: support pulse-per-second output - ngbe: add an mdio bus driver - usbnet: optimize usbnet_bh() by avoiding unnecessary queuing - r8152: handle devices with FW with NCM support - amd-xgbe: support 10Mbps, 2.5GbE speeds and rx-adaptation - virtio-net: support multi buffer XDP - virtio/vsock: replace virtio_vsock_pkt with sk_buff - tsnep: XDP support - Ethernet high-speed switches: - nVidia/Mellanox (mlxsw): - add support for latency TLV (in FW control messages) - Microchip (sparx5): - separate explicit and implicit traffic forwarding rules, make the implicit rules always active - add support for egress DSCP rewrite - IS0 VCAP support (Ingress Classification) - IS2 VCAP filters (protos, L3 addrs, L4 ports, flags, ToS etc.) - ES2 VCAP support (Egress Access Control) - support for Per-Stream Filtering and Policing (802.1Q, 8.6.5.1) - Ethernet embedded switches: - Marvell (mv88e6xxx): - add MAB (port auth) offload support - enable PTP receive for mv88e6390 - NXP (ocelot): - support MAC Merge layer - support for the the vsc7512 internal copper phys - Microchip: - lan9303: convert to PHYLINK - lan966x: support TC flower filter statistics - lan937x: PTP support for KSZ9563/KSZ8563 and LAN937x - lan937x: support Credit Based Shaper configuration - ksz9477: support Energy Efficient Ethernet - other: - qca8k: convert to regmap read/write API, use bulk operations - rswitch: Improve TX timestamp accuracy - Intel WiFi (iwlwifi): - EHT (Wi-Fi 7) rate reporting - STEP equalizer support: transfer some STEP (connection to radio on platforms with integrated wifi) related parameters from the BIOS to the firmware. - Qualcomm 802.11ax WiFi (ath11k): - IPQ5018 support - Fine Timing Measurement (FTM) responder role support - channel 177 support - MediaTek WiFi (mt76): - per-PHY LED support - mt7996: EHT (Wi-Fi 7) support - Wireless Ethernet Dispatch (WED) reset support - switch to using page pool allocator - RealTek WiFi (rtw89): - support new version of Bluetooth co-existance - Mobile: - rmnet: support TX aggregation" * tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1872 commits) page_pool: add a comment explaining the fragment counter usage net: ethtool: fix __ethtool_dev_mm_supported() implementation ethtool: pse-pd: Fix double word in comments xsk: add linux/vmalloc.h to xsk.c sefltests: netdevsim: wait for devlink instance after netns removal selftest: fib_tests: Always cleanup before exit net/mlx5e: Align IPsec ASO result memory to be as required by hardware net/mlx5e: TC, Set CT miss to the specific ct action instance net/mlx5e: Rename CHAIN_TO_REG to MAPPED_OBJ_TO_REG net/mlx5: Refactor tc miss handling to a single function net/mlx5: Kconfig: Make tc offload depend on tc skb extension net/sched: flower: Support hardware miss to tc action net/sched: flower: Move filter handle initialization earlier net/sched: cls_api: Support hardware miss to tc action net/sched: Rename user cookie and act cookie sfc: fix builds without CONFIG_RTC_LIB sfc: clean up some inconsistent indentings net/mlx4_en: Introduce flexible array to silence overflow warning net: lan966x: Fix possible deadlock inside PTP net/ulp: Remove redundant ->clone() test in inet_clone_ulp(). ... --- scripts/dtc/dt_to_config | 1212 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1212 insertions(+) create mode 100755 scripts/dtc/dt_to_config (limited to 'scripts/dtc/dt_to_config') diff --git a/scripts/dtc/dt_to_config b/scripts/dtc/dt_to_config new file mode 100755 index 000000000..299d1c2b2 --- /dev/null +++ b/scripts/dtc/dt_to_config @@ -0,0 +1,1212 @@ +#!/usr/bin/env perl +# SPDX-License-Identifier: GPL-2.0-only + +# Copyright 2016 by Frank Rowand +# Copyright 2016 by Gaurav Minocha +# + +use strict 'refs'; +use strict subs; + +use Getopt::Long; + +$VUFX = "160610a"; + +$script_name = $0; +$script_name =~ s|^.*/||; + + +# ----- constants for print_flags() + +# Position in string $pr_flags. Range of 0..($num_pr_flags - 1). +$pr_flag_pos_mcompatible = 0; +$pr_flag_pos_driver = 1; +$pr_flag_pos_mdriver = 2; +$pr_flag_pos_config = 3; +$pr_flag_pos_mconfig = 4; +$pr_flag_pos_node_not_enabled = 5; +$pr_flag_pos_white_list = 6; +$pr_flag_pos_hard_coded = 7; +$pr_flag_pos_config_hard_coded = 8; +$pr_flag_pos_config_none = 9; +$pr_flag_pos_config_m = 10; +$pr_flag_pos_config_y = 11; +$pr_flag_pos_config_test_fail = 12; + +$num_pr_flags = $pr_flag_pos_config_test_fail + 1; + +# flags in @pr_flag_value must be unique values to allow simple regular +# expessions to work for --include_flags and --exclude_flags. +# Convention: use upper case letters for potential issues or problems. + +@pr_flag_value = ('M', 'd', 'D', 'c', 'C', 'E', 'W', 'H', 'x', 'n', 'm', 'y', 'F'); + +@pr_flag_help = ( + "multiple compatibles found for this node", + "driver found for this compatible", + "multiple drivers found for this compatible", + "kernel config found for this driver", + "multiple config options found for this driver", + "node is not enabled", + "compatible is white listed", + "matching driver and/or kernel config is hard coded", + "kernel config hard coded in Makefile", + "one or more kernel config file options is not set", + "one or more kernel config file options is set to 'm'", + "one or more kernel config file options is set to 'y'", + "one of more kernel config file options fails to have correct value" +); + + +# ----- + +%driver_config = (); # driver config array, indexed by driver source file +%driver_count = (); # driver_cnt, indexed by compatible +%compat_driver = (); # compatible driver array, indexed by compatible +%existing_config = (); # existing config symbols present in given config file + # expected values are: "y", "m", a decimal number, a + # hex number, or a string + +# ----- magic compatibles, do not have a driver +# +# Will not search for drivers for these compatibles. + +%compat_white_list = ( + 'none' => '1', + 'pci' => '1', + 'simple-bus' => '1', +); + +# Will not search for drivers for these compatibles. +# +# These compatibles have a very large number of false positives. +# +# 'hardcoded_no_driver' is a magic value. Other code knows this +# magic value. Do not use 'no_driver' here! +# +# Revisit each 'hardcoded_no_driver' to see how the compatible +# is used. Are there drivers that can be provided? + +%driver_hard_code_list = ( + 'cache' => ['hardcoded_no_driver'], + 'eeprom' => ['hardcoded_no_driver'], + 'gpio' => ['hardcoded_no_driver'], + 'gpio-keys' => ['drivers/input/keyboard/gpio_keys.c'], + 'i2c-gpio' => ['drivers/i2c/busses/i2c-gpio.c'], + 'isa' => ['arch/mips/mti-malta/malta-dt.c', + 'arch/x86/kernel/devicetree.c'], + 'led' => ['hardcoded_no_driver'], + 'm25p32' => ['hardcoded_no_driver'], + 'm25p64' => ['hardcoded_no_driver'], + 'm25p80' => ['hardcoded_no_driver'], + 'mtd-ram' => ['drivers/mtd/maps/physmap_of.c'], + 'pwm-backlight' => ['drivers/video/backlight/pwm_bl.c'], + 'spidev' => ['hardcoded_no_driver'], + 'syscon' => ['drivers/mfd/syscon.c'], + 'tlv320aic23' => ['hardcoded_no_driver'], + 'wm8731' => ['hardcoded_no_driver'], +); + +# Use these config options instead of searching makefiles + +%driver_config_hard_code_list = ( + + # this one needed even if %driver_hard_code_list is empty + 'no_driver' => ['no_config'], + 'hardcoded_no_driver' => ['no_config'], + + # drivers/usb/host/ehci-ppc-of.c + # drivers/usb/host/ehci-xilinx-of.c + # are included from: + # drivers/usb/host/ehci-hcd.c + # thus the search of Makefile for the included .c files is incorrect + # ehci-hcd.c wraps the includes with ifdef CONFIG_USB_EHCI_HCD_..._OF + # + # similar model for ohci-hcd.c (but no ohci-xilinx-of.c) + # + # similarly, uhci-hcd.c includes uhci-platform.c + + 'drivers/usb/host/ehci-ppc-of.c' => ['CONFIG_USB_EHCI_HCD', + 'CONFIG_USB_EHCI_HCD_PPC_OF'], + 'drivers/usb/host/ohci-ppc-of.c' => ['CONFIG_USB_OHCI_HCD', + 'CONFIG_USB_OHCI_HCD_PPC_OF'], + + 'drivers/usb/host/ehci-xilinx-of.c' => ['CONFIG_USB_EHCI_HCD', + 'CONFIG_USB_EHCI_HCD_XILINX'], + + 'drivers/usb/host/uhci-platform.c' => ['CONFIG_USB_UHCI_HCD', + 'CONFIG_USB_UHCI_PLATFORM'], + + # scan_makefile will find only one of these config options: + # ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),) + 'arch/arm/mach-imx/platsmp.c' => ['CONFIG_SOC_IMX6 && CONFIG_SMP', + 'CONFIG_SOC_LS1021A && CONFIG_SMP'], +); + + +# 'virt/kvm/arm/.*' are controlled by makefiles in other directories, +# using relative paths, such as 'KVM := ../../../virt/kvm'. Do not +# add complexity to find_kconfig() to deal with this. There is a long +# term intent to change the kvm related makefiles to the normal kernel +# style. After that is done, this entry can be removed from the +# black_list_driver. + +@black_list_driver = ( + # kvm no longer a problem after commit 503a62862e8f in 4.7-rc1 + # 'virt/kvm/arm/.*', +); + + +sub usage() +{ + print +" +Usage: $script_name [options] device-tree... + + device_tree is: dts_file | dtb_file | proc_device-tree + + +Valid options: + -c FILE Read kernel config options from FILE + --config FILE synonym for 'c' + --config-format config file friendly output format + --exclude-flag FLAG exclude entries with a matching flag + -h Display this message and exit + --help synonym for 'h' + --black-list-driver use driver black list + --white-list-config use config white list + --white-list-driver use driver white list + --include-flag FLAG include only entries with a matching flag + --include-suspect include only entries with an uppercase flag + --short-name do not show the path portion of the node name + --show-lists report of white and black lists + --version Display program version and exit + + + Report driver source files that match the compatibles in the device + tree file and the kernel config options that enable the driver source + files. + + This program must be run in the root directory of a Linux kernel + source tree. + + The default format is a report that is intended to be easily human + scannable. + + An alternate format can be selected by --config-format. This will + create output that can easily be edited to create a fragment that can + be appended to the existing kernel config file. Each entry consists of + multiple lines. The first line reports flags, the node path, compatible + value, driver file matching the compatible, configuration options, and + current values of the configuration options. For each configuration + option, the following lines report the current value and the value that + is required for the driver file to be included in the kernel. + + If a large number of drivers or config options is listed for a node, + and the '$pr_flag_value[$pr_flag_pos_hard_coded]' flag is set consider using --white-list-config and/or + --white-list-driver. If the white list option suppresses the correct + entry please report that as a bug. + + CAUTION: + This program uses heuristics to guess which driver(s) support each + compatible string and which config option(s) enables the driver(s). + Do not believe that the reported information is fully correct. + This program is intended to aid the process of determining the + proper kernel configuration for a device tree, but this is not + a fully automated process -- human involvement may still be + required! + + The driver match heuristic used is to search for source files + containing the compatible string enclosed in quotes. + + This program might not be able to find all drivers matching a + compatible string. + + Some makefiles are overly clever. This program was not made + complex enough to handle them. If no config option is listed + for a driver, look at the makefile for the driver source file. + Even if a config option is listed for a driver, some other + available config options may not be listed. + + FLAG values: +"; + + for ($k = 0; $k < $num_pr_flags; $k++) { + printf " %s %s\n", $pr_flag_value[$k], $pr_flag_help[$k]; + } + + print +" + Upper case letters indicate potential issues or problems. + + The flag: + +"; + + $k = $pr_flag_pos_hard_coded; + printf " %s %s\n", $pr_flag_value[$k], $pr_flag_help[$k]; + + print +" + will be set if the config or driver is in the white lists, even if + --white-list-config and --white-list-driver are not specified. + This is a hint that 1) many of these reported lines are likely to + be incorrect, and 2) using those options will reduce the number of + drivers and/or config options reported. + + --white-list-config and --white-list-driver may not be accurate if this + program is not well maintained. Use them with appropriate skepticism. + Use the --show-lists option to report the values in the list. + + Return value: + 0 if no error + 1 error processing command line + 2 unable to open or read kernel config file + 3 unable to open or process input device tree file(s) + + EXAMPLES: + + dt_to_config arch/arm/boot/dts/my_dts_file.dts + + Basic report. + + dt_to_config \\ + --config \${KBUILD_OUTPUT}/.config \\ + arch/\${ARCH}/boot/dts/my_dts_file.dts + + Full report, with config file issues noted. + + dt_to_config --include-suspect \\ + --config \${KBUILD_OUTPUT}/.config \\ + arch/\${ARCH}/boot/dts/my_dts_file.dts + + Report of node / compatible string / driver tuples that should + be further investigated. A node may have multiple compatible + strings. A compatible string may be matched by multiple drivers. + A driver may have config file issues noted. The compatible string + and/or driver may be in the white lists. + + dt_to_config --include-suspect --config-format \\ + --config ${KBUILD_OUTPUT}/.config \\ + arch/\${ARCH}/boot/dts/my_dts_file.dts + + Report of node / compatible string / driver tuples that should + be further investigated. The report can be edited to uncomment + the config options to select the desired tuple for a given node. + A node may have multiple compatible strings. A compatible string + may be matched by multiple drivers. A driver may have config file + issues noted. The compatible string and/or driver may be in the + white lists. + +"; +} + +sub set_flag() +{ + # pr_flags_ref is a reference to $pr_flags + + my $pr_flags_ref = shift; + my $pos = shift; + + substr $$pr_flags_ref, $pos, 1, $pr_flag_value[$pos]; + + return $pr_flags; +} + +sub print_flags() +{ + # return 1 if anything printed, else 0 + + # some fields of pn_arg_ref might not be used in this function, but + # extract all of them anyway. + my $pn_arg_ref = shift; + + my $compat = $pn_arg_ref->{compat}; + my $compatible_cnt = $pn_arg_ref->{compatible_cnt}; + my $config = $pn_arg_ref->{config}; + my $config_cnt = $pn_arg_ref->{config_cnt}; + my $driver = $pn_arg_ref->{driver}; + my $driver_cnt = $pn_arg_ref->{driver_cnt}; + my $full_node = $pn_arg_ref->{full_node}; + my $node = $pn_arg_ref->{node}; + my $node_enabled = $pn_arg_ref->{node_enabled}; + my $white_list = $pn_arg_ref->{white_list}; + + my $pr_flags = '-' x $num_pr_flags; + + + # ----- set flags in $pr_flags + + if ($compatible_cnt > 1) { + &set_flag(\$pr_flags, $pr_flag_pos_mcompatible); + } + + if ($config_cnt > 1) { + &set_flag(\$pr_flags, $pr_flag_pos_mconfig); + } + + if ($driver_cnt >= 1) { + &set_flag(\$pr_flags, $pr_flag_pos_driver); + } + + if ($driver_cnt > 1) { + &set_flag(\$pr_flags, $pr_flag_pos_mdriver); + } + + # These strings are the same way the linux kernel tests. + # The ePapr lists of values is slightly different. + if (!( + ($node_enabled eq "") || + ($node_enabled eq "ok") || + ($node_enabled eq "okay") + )) { + &set_flag(\$pr_flags, $pr_flag_pos_node_not_enabled); + } + + if ($white_list) { + &set_flag(\$pr_flags, $pr_flag_pos_white_list); + } + + if (exists($driver_hard_code_list{$compat}) || + (exists($driver_config_hard_code_list{$driver}) && + ($driver ne "no_driver"))) { + &set_flag(\$pr_flags, $pr_flag_pos_hard_coded); + } + + my @configs = split(' && ', $config); + for $configs (@configs) { + $not = $configs =~ /^!/; + $configs =~ s/^!//; + + if (($configs ne "no_config") && ($configs ne "no_makefile")) { + &set_flag(\$pr_flags, $pr_flag_pos_config); + } + + if (($config_cnt >= 1) && + ($configs !~ /CONFIG_/) && + (($configs ne "no_config") && ($configs ne "no_makefile"))) { + &set_flag(\$pr_flags, $pr_flag_pos_config_hard_coded); + } + + my $existing_config = $existing_config{$configs}; + if ($existing_config eq "m") { + &set_flag(\$pr_flags, $pr_flag_pos_config_m); + # Possible fail, depends on whether built in or + # module is desired. + &set_flag(\$pr_flags, $pr_flag_pos_config_test_fail); + } elsif ($existing_config eq "y") { + &set_flag(\$pr_flags, $pr_flag_pos_config_y); + if ($not) { + &set_flag(\$pr_flags, $pr_flag_pos_config_test_fail); + } + } elsif (($config_file) && ($configs =~ /CONFIG_/)) { + &set_flag(\$pr_flags, $pr_flag_pos_config_none); + if (!$not) { + &set_flag(\$pr_flags, $pr_flag_pos_config_test_fail); + } + } + } + + # ----- include / exclude filters + + if ($include_flag_pattern && ($pr_flags !~ m/$include_flag_pattern/)) { + return 0; + } + + if ($exclude_flag_pattern && ($pr_flags =~ m/$exclude_flag_pattern/)) { + return 0; + } + + if ($config_format) { + print "# "; + } + print "$pr_flags : "; + + return 1; +} + + +sub print_node() +{ + # return number of lines printed + + # some fields of pn_arg_ref might not be used in this function, but + # extract all of them anyway. + my $pn_arg_ref = shift; + + my $compat = $pn_arg_ref->{compat}; + my $compatible_cnt = $pn_arg_ref->{compatible_cnt}; + my $config = $pn_arg_ref->{config}; + my $config_cnt = $pn_arg_ref->{config_cnt}; + my $driver = $pn_arg_ref->{driver}; + my $driver_cnt = $pn_arg_ref->{driver_cnt}; + my $full_node = $pn_arg_ref->{full_node}; + my $node = $pn_arg_ref->{node}; + my $node_enabled = $pn_arg_ref->{node_enabled}; + my $white_list = $pn_arg_ref->{white_list}; + + my $separator; + + if (! &print_flags($pn_arg_ref)) { + return 0; + } + + + if ($short_name) { + print "$node"; + } else { + print "$full_node"; + } + print " : $compat : $driver : $config : "; + + my @configs = split(' && ', $config); + + if ($config_file) { + for $configs (@configs) { + $configs =~ s/^!//; + my $existing_config = $existing_config{$configs}; + if (!$existing_config) { + # check for /-m/, /-y/, or /-objs/ + if ($configs !~ /CONFIG_/) { + $existing_config = "x"; + }; + }; + if ($existing_config) { + print "$separator", "$existing_config"; + $separator = ", "; + } else { + print "$separator", "n"; + $separator = ", "; + } + } + } else { + print "none"; + } + + print "\n"; + + if ($config_format) { + for $configs (@configs) { + $not = $configs =~ /^!/; + $configs =~ s/^!//; + my $existing_config = $existing_config{$configs}; + + if ($not) { + if ($configs !~ /CONFIG_/) { + print "# $configs\n"; + } elsif ($existing_config eq "m") { + print "# $configs is m\n"; + print "# $configs=n\n"; + } elsif ($existing_config eq "y") { + print "# $configs is set\n"; + print "# $configs=n\n"; + } else { + print "# $configs is not set\n"; + print "# $configs=n\n"; + } + + } else { + if ($configs !~ /CONFIG_/) { + print "# $configs\n"; + } elsif ($existing_config eq "m") { + print "# $configs is m\n"; + print "# $configs=y\n"; + } elsif ($existing_config eq "y") { + print "# $configs is set\n"; + print "# $configs=y\n"; + } else { + print "# $configs is not set\n"; + print "# $configs=y\n"; + } + } + } + } + + return 1; +} + + +sub scan_makefile +{ + my $pn_arg_ref = shift; + my $driver = shift; + + # ----- Find Kconfig symbols that enable driver + + my ($dir, $base) = $driver =~ m{(.*)/(.*).c}; + + my $makefile = $dir . "/Makefile"; + if (! -r $makefile) { + $makefile = $dir . "/Kbuild"; + } + if (! -r $makefile) { + my $config; + + $config = 'no_makefile'; + push @{ $driver_config{$driver} }, $config; + return; + } + + if (!open(MAKEFILE_FILE, "<", "$makefile")) { + return; + } + + my $line; + my @config; + my @if_config; + my @make_var; + + NEXT_LINE: + while ($next_line = ) { + my $config; + my $if_config; + my $ifdef; + my $ifeq; + my $ifndef; + my $ifneq; + my $ifdef_config; + my $ifeq_config; + my $ifndef_config; + my $ifneq_config; + + chomp($next_line); + $line = $line . $next_line; + if ($next_line =~ /\\$/) { + $line =~ s/\\$/ /; + next NEXT_LINE; + } + if ($line =~ /^\s*#/) { + $line = ""; + next NEXT_LINE; + } + + # ----- condition ... else ... endif + + if ($line =~ /^([ ]\s*|)else\b/) { + $if_config = "!" . pop @if_config; + $if_config =~ s/^!!//; + push @if_config, $if_config; + $line =~ s/^([ ]\s*|)else\b//; + } + + ($null, $ifeq_config, $ifeq_config_val ) = $line =~ /^([ ]\s*|)ifeq\b.*\b(CONFIG_[A-Za-z0-9_]*)(.*)/; + ($null, $ifneq_config, $ifneq_config_val) = $line =~ /^([ ]\s*|)ifneq\b.*\b(CONFIG_[A-Za-z0-9_]*)(.*)/; + ($null, $ifdef_config) = $line =~ /^([ ]\s*|)ifdef\b.*\b(CONFIG_[A-Za-z0-9_]*)/; + ($null, $ifndef_config) = $line =~ /^([ ]\s*|)ifndef\b.*\b(CONFIG_[A-Za-z0-9_]*)/; + + ($null, $ifeq) = $line =~ /^([ ]\s*|)ifeq\b\s*(.*)/; + ($null, $ifneq) = $line =~ /^([ ]\s*|)ifneq\b\s*(.*)/; + ($null, $ifdef) = $line =~ /^([ ]\s*|)ifdef\b\s*(.*)/; + ($null, $ifndef) = $line =~ /^([ ]\s*|)ifndef\b\s*(.*)/; + + # Order of tests is important. Prefer "CONFIG_*" regex match over + # less specific regex match. + if ($ifdef_config) { + $if_config = $ifdef_config; + } elsif ($ifeq_config) { + if ($ifeq_config_val =~ /y/) { + $if_config = $ifeq_config; + } else { + $if_config = "!" . $ifeq_config; + } + } elsif ($ifndef_config) { + $if_config = "!" . $ifndef_config; + } elsif ($ifneq_config) { + if ($ifneq_config_val =~ /y/) { + $if_config = "!" . $ifneq_config; + } else { + $if_config = $ifneq_config; + } + } elsif ($ifdef) { + $if_config = $ifdef; + } elsif ($ifeq) { + $if_config = $ifeq; + } elsif ($ifndef) { + $if_config = "!" . $ifndef; + } elsif ($ifneq) { + $if_config = "!" . $ifneq; + } else { + $if_config = ""; + } + $if_config =~ s/^!!//; + + if ($if_config) { + push @if_config, $if_config; + $line = ""; + next NEXT_LINE; + } + + if ($line =~ /^([ ]\s*|)endif\b/) { + pop @if_config; + $line = ""; + next NEXT_LINE; + } + + # ----- simple CONFIG_* = *.[co] or xxx [+:?]*= *.[co] + # Most makefiles select on *.o, but + # arch/powerpc/boot/Makefile selects on *.c + + ($config) = $line =~ /(CONFIG_[A-Za-z0-9_]+).*\b$base.[co]\b/; + + # ----- match a make variable instead of *.[co] + # Recursively expanded variables are not handled. + + if (!$config) { + my $make_var; + ($make_var) = $line =~ /\s*(\S+?)\s*[+:\?]*=.*\b$base.[co]\b/; + if ($make_var) { + if ($make_var =~ /[a-zA-Z0-9]+-[ym]/) { + $config = $make_var; + } elsif ($make_var =~ /[a-zA-Z0-9]+-objs/) { + $config = $make_var; + } else { + push @make_var, $make_var; + } + } + } + + if (!$config) { + for $make_var (@make_var) { + ($config) = $line =~ /(CONFIG_[A-Za-z0-9_]+).*\b$make_var\b/; + last if ($config); + } + } + + if (!$config) { + for $make_var (@make_var) { + ($config) = $line =~ /\s*(\S+?)\s*[+:\?]*=.*\b$make_var\b/; + last if ($config); + } + } + + # ----- next if no config found + + if (!$config) { + $line = ""; + next NEXT_LINE; + } + + for $if_config (@if_config) { + $config = $if_config . " && " . $config; + } + + push @{ $driver_config{$driver} }, $config; + + $line = ""; + } + + close(MAKEFILE_FILE); + +} + + +sub find_kconfig +{ + my $pn_arg_ref = shift; + my $driver = shift; + + my $lines_printed = 0; + my @configs; + + if (!@{ $driver_config{$driver} }) { + &scan_makefile($pn_arg_ref, $driver); + if (!@{ $driver_config{$driver} }) { + push @{ $driver_config{$driver} }, "no_config"; + } + } + + @configs = @{ $driver_config{$driver} }; + + $$pn_arg_ref{config_cnt} = $#configs + 1; + for my $config (@configs) { + $$pn_arg_ref{config} = $config; + $lines_printed += &print_node($pn_arg_ref); + } + + return $lines_printed; +} + + +sub handle_compatible() +{ + my $full_node = shift; + my $node = shift; + my $compatible = shift; + my $node_enabled = shift; + + my $compat; + my $lines_printed = 0; + my %pn_arg = (); + + return if (!$node or !$compatible); + + # Do not process compatible property of root node, + # it is used to match board, not to bind a driver. + return if ($node eq "/"); + + $pn_arg{full_node} = $full_node; + $pn_arg{node} = $node; + $pn_arg{node_enabled} = $node_enabled; + + my @compatibles = split('", "', $compatible); + + $compatibles[0] =~ s/^"//; + $compatibles[$#compatibles] =~ s/"$//; + + $pn_arg{compatible_cnt} = $#compatibles + 1; + + COMPAT: + for $compat (@compatibles) { + + $pn_arg{compat} = $compat; + $pn_arg{driver_cnt} = 0; + $pn_arg{white_list} = 0; + + if (exists($compat_white_list{$compat})) { + $pn_arg{white_list} = 1; + $pn_arg{driver} = "no_driver"; + $pn_arg{config_cnt} = 1; + $pn_arg{config} = "no_config"; + $lines_printed += &print_node(\%pn_arg); + next COMPAT; + } + + # ----- if compat previously seen, use cached info + + if (exists($compat_driver{$compat})) { + for my $driver (@{ $compat_driver{$compat} }) { + $pn_arg{driver} = $driver; + $pn_arg{driver_cnt} = $driver_count{$compat}; + $pn_arg{config_cnt} = $#{ $driver_config{$driver}} + 1; + + for my $config (@{ $driver_config{$driver} }) { + $pn_arg{config} = $config; + $lines_printed += &print_node(\%pn_arg); + } + + if (!@{ $driver_config{$driver} }) { + # no config cached yet + # $driver in %driver_hard_code_list + # but not %driver_config_hard_code_list + $lines_printed += &find_kconfig(\%pn_arg, $driver); + } + } + next COMPAT; + } + + + # ----- Find drivers (source files that contain compatible) + + # this will miss arch/sparc/include/asm/parport.h + # It is better to move the compatible out of the .h + # than to add *.h. to the files list, because *.h generates + # a lot of false negatives. + my $files = '"*.c"'; + my $drivers = `git grep -l '"$compat"' -- $files`; + chomp($drivers); + if ($drivers eq "") { + $pn_arg{driver} = "no_driver"; + $pn_arg{config_cnt} = 1; + $pn_arg{config} = "no_config"; + push @{ $compat_driver{$compat} }, "no_driver"; + $lines_printed += &print_node(\%pn_arg); + next COMPAT; + } + + my @drivers = split("\n", $drivers); + $driver_count{$compat} = $#drivers + 1; + $pn_arg{driver_cnt} = $#drivers + 1; + + DRIVER: + for my $driver (@drivers) { + push @{ $compat_driver{$compat} }, $driver; + $pn_arg{driver} = $driver; + + # ----- if driver previously seen, use cached info + + $pn_arg{config_cnt} = $#{ $driver_config{$driver} } + 1; + for my $config (@{ $driver_config{$driver} }) { + $pn_arg{config} = $config; + $lines_printed += &print_node(\%pn_arg); + } + if (@{ $driver_config{$driver} }) { + next DRIVER; + } + + if ($black_list_driver) { + for $black (@black_list_driver) { + next DRIVER if ($driver =~ /^$black$/); + } + } + + + # ----- Find Kconfig symbols that enable driver + + $lines_printed += &find_kconfig(\%pn_arg, $driver); + + } + } + + # White space (line) between nodes for readability. + # Each node may report several compatibles. + # For each compatible, multiple drivers may be reported. + # For each driver, multiple CONFIG_ options may be reported. + if ($lines_printed) { + print "\n"; + } +} + +sub read_dts() +{ + my $file = shift; + + my $compatible = ""; + my $line; + my $node = ""; + my $node_enabled = ""; + + if (! -r $file) { + print STDERR "file '$file' is not readable or does not exist\n"; + exit 3; + } + + if (!open(DT_FILE, "-|", "$dtx_diff $file")) { + print STDERR "\n"; + print STDERR "shell command failed:\n"; + print STDERR " $dtx_diff $file\n"; + print STDERR "\n"; + exit 3; + } + + FILE: + while ($line = ) { + chomp($line); + + if ($line =~ /{/) { + + &handle_compatible($full_node, $node, $compatible, + $node_enabled); + + while ($end_node_count-- > 0) { + pop @full_node; + }; + $end_node_count = 0; + $full_node = @full_node[-1]; + + $node = $line; + $node =~ s/^\s*(.*)\s+\{.*/$1/; + $node =~ s/.*: //; + if ($node eq '/' ) { + $full_node = '/'; + } elsif ($full_node ne '/') { + $full_node = $full_node . '/' . $node; + } else { + $full_node = '/' . $node; + } + push @full_node, $full_node; + + $compatible = ""; + $node_enabled = ""; + next FILE; + } + + if ($line =~ /}/) { + $end_node_count++; + } + + if ($line =~ /(\s+|^)status =/) { + $node_enabled = $line; + $node_enabled =~ s/^\t*//; + $node_enabled =~ s/^status = "//; + $node_enabled =~ s/";$//; + next FILE; + } + + if ($line =~ /(\s+|^)compatible =/) { + # Extract all compatible entries for this device + # White space matching here and in handle_compatible() is + # precise, because input format is the output of dtc, + # which is invoked by dtx_diff. + $compatible = $line; + $compatible =~ s/^\t*//; + $compatible =~ s/^compatible = //; + $compatible =~ s/;$//; + } + } + + &handle_compatible($full_node, $node, $compatible, $node_enabled); + + close(DT_FILE); +} + + +sub read_config_file() +{ + if (! -r $config_file) { + print STDERR "file '$config_file' is not readable or does not exist\n"; + exit 2; + } + + if (!open(CONFIG_FILE, "<", "$config_file")) { + print STDERR "open $config_file failed\n"; + exit 2; + } + + my @line; + + LINE: + while ($line = ) { + chomp($line); + next LINE if ($line =~ /^\s*#/); + next LINE if ($line =~ /^\s*$/); + @line = split /=/, $line; + $existing_config{@line[0]} = @line[1]; + } + + close(CONFIG_FILE); +} + + +sub cmd_line_err() +{ + my $msg = shift; + + print STDERR "\n"; + print STDERR " ERROR processing command line options\n"; + print STDERR " $msg\n" if ($msg ne ""); + print STDERR "\n"; + print STDERR " For help, type '$script_name --help'\n"; + print STDERR "\n"; +} + + +# ----------------------------------------------------------------------------- +# program entry point + +Getopt::Long::Configure("no_ignore_case", "bundling"); + +if (!GetOptions( + "c=s" => \$config_file, + "config=s" => \$config_file, + "config-format" => \$config_format, + "exclude-flag=s" => \@exclude_flag, + "h" => \$help, + "help" => \$help, + "black-list-driver" => \$black_list_driver, + "white-list-config" => \$white_list_config, + "white-list-driver" => \$white_list_driver, + "include-flag=s" => \@include_flag, + "include-suspect" => \$include_suspect, + "short-name" => \$short_name, + "show-lists" => \$show_lists, + "version" => \$version, + )) { + + &cmd_line_err(); + + exit 1; +} + + +my $exit_after_messages = 0; + +if ($version) { + print STDERR "\n$script_name $VUFX\n\n"; + $exit_after_messages = 1; +} + + +if ($help) { + &usage; + $exit_after_messages = 1; +} + + +if ($show_lists) { + + print "\n"; + print "These compatibles are hard coded to have no driver.\n"; + print "\n"; + for my $compat (sort keys %compat_white_list) { + print " $compat\n"; + } + + + print "\n\n"; + print "The driver for these compatibles is hard coded (white list).\n"; + print "\n"; + my $max_compat_len = 0; + for my $compat (sort keys %driver_hard_code_list) { + if (length $compat > $max_compat_len) { + $max_compat_len = length $compat; + } + } + for my $compat (sort keys %driver_hard_code_list) { + if (($driver ne "hardcoded_no_driver") && ($driver ne "no_driver")) { + my $first = 1; + for my $driver (@{ $driver_hard_code_list{$compat} }) { + if ($first) { + print " $compat"; + print " " x ($max_compat_len - length $compat); + $first = 0; + } else { + print " ", " " x $max_compat_len; + } + print " $driver\n"; + } + } + } + + + print "\n\n"; + print "The configuration option for these drivers is hard coded (white list).\n"; + print "\n"; + my $max_driver_len = 0; + for my $driver (sort keys %driver_config_hard_code_list) { + if (length $driver > $max_driver_len) { + $max_driver_len = length $driver; + } + } + for my $driver (sort keys %driver_config_hard_code_list) { + if (($driver ne "hardcoded_no_driver") && ($driver ne "no_driver")) { + my $first = 1; + for my $config (@{ $driver_config_hard_code_list{$driver} }) { + if ($first) { + print " $driver"; + print " " x ($max_driver_len - length $driver); + $first = 0; + } else { + print " ", " " x $max_driver_len; + } + print " $config\n"; + } + } + } + + + print "\n\n"; + print "These drivers are black listed.\n"; + print "\n"; + for my $driver (@black_list_driver) { + print " $driver\n"; + } + + print "\n"; + + $exit_after_messages = 1; +} + + +if ($exit_after_messages) { + exit 0; +} + + +$exclude_flag_pattern = "["; +for my $exclude_flag (@exclude_flag) { + $exclude_flag_pattern = $exclude_flag_pattern . $exclude_flag; +} +$exclude_flag_pattern = $exclude_flag_pattern . "]"; +# clean up if empty +$exclude_flag_pattern =~ s/^\[\]$//; + + +$include_flag_pattern = "["; +for my $include_flag (@include_flag) { + $include_flag_pattern = $include_flag_pattern . $include_flag; +} +$include_flag_pattern = $include_flag_pattern . "]"; +# clean up if empty +$include_flag_pattern =~ s/^\[\]$//; + + +if ($exclude_flag_pattern) { + my $found = 0; + for $pr_flag_value (@pr_flag_value) { + if ($exclude_flag_pattern =~ m/$pr_flag_value/) { + $found = 1; + } + } + if (!$found) { + &cmd_line_err("invalid value for FLAG in --exclude-flag\n"); + exit 1 + } +} + +if ($include_flag_pattern) { + my $found = 0; + for $pr_flag_value (@pr_flag_value) { + if ($include_flag_pattern =~ m/$pr_flag_value/) { + $found = 1; + } + } + if (!$found) { + &cmd_line_err("invalid value for FLAG in --include-flag\n"); + exit 1 + } +} + +if ($include_suspect) { + $include_flag_pattern =~ s/\[//; + $include_flag_pattern =~ s/\]//; + $include_flag_pattern = "[" . $include_flag_pattern . "A-Z]"; +} + +if ($exclude_flag_pattern =~ m/$include_flag_pattern/) { + &cmd_line_err("the same flag appears in both --exclude-flag and --include-flag or --include-suspect\n"); + exit 1 +} + + +# ($#ARGV < 0) is valid for --help, --version +if ($#ARGV < 0) { + &cmd_line_err("device-tree... is required"); + exit 1 +} + + +if ($config_file) { + &read_config_file(); +} + + +# avoid pushing duplicates for this value +$driver = "hardcoded_no_driver"; +for $config ( @{ $driver_config_hard_code_list{$driver} } ) { + push @{ $driver_config{$driver} }, $config; +} + +if ($white_list_driver) { + for my $compat (keys %driver_hard_code_list) { + for my $driver (@{ $driver_hard_code_list{$compat} }) { + push @{ $compat_driver{$compat} }, $driver; + if ($driver ne "hardcoded_no_driver") { + $driver_count{$compat} = scalar @{ $compat_driver{$compat} }; + } + } + } +} + +if ($white_list_config) { + for my $driver (keys %driver_config_hard_code_list) { + if ($driver ne "hardcoded_no_driver") { + for $config ( @{ $driver_config_hard_code_list{$driver} } ) { + push @{ $driver_config{$driver} }, $config; + } + } + } +} + +if (-x "scripts/dtc/dtx_diff") { + $dtx_diff = "scripts/dtc/dtx_diff"; +} else { + + print STDERR "\n"; + print STDERR "$script_name must be run from the root directory of a Linux kernel tree\n"; + print STDERR "\n"; + exit 3; +} + +for $file (@ARGV) { + &read_dts($file); +} -- cgit v1.2.3