Changes in 4.19.296
NFS/pNFS: Report EINVAL errors from connect() to the server
ata: ahci: Drop pointless VPRINTK() calls and convert the remaining ones
ata: libahci: clear pending interrupt status
netfilter: nf_tables: disallow element removal on anonymous sets
selftests/tls: Add {} to avoid static checker warning
selftests: tls: swap the TX and RX sockets in some tests
ipv4: fix null-deref in ipv4_link_failure
powerpc/perf/hv-24x7: Update domain value check
net: hns3: add 5ms delay before clear firmware reset irq source
net: add atomic_long_t to net_device_stats fields
net: bridge: use DEV_STATS_INC()
team: fix null-ptr-deref when team device type is changed
gpio: tb10x: Fix an error handling path in tb10x_gpio_probe()
i2c: mux: demux-pinctrl: check the return value of devm_kstrdup()
Input: i8042 - add quirk for TUXEDO Gemini 17 Gen1/Clevo PD70PN
scsi: qla2xxx: Add protection mask module parameters
scsi: qla2xxx: Remove unsupported ql2xenabledif option
scsi: megaraid_sas: Load balance completions across all MSI-X
scsi: megaraid_sas: Fix deadlock on firmware crashdump
ext4: remove the 'group' parameter of ext4_trim_extent
ext4: add new helper interface ext4_try_to_trim_range()
ext4: scope ret locally in ext4_try_to_trim_range()
ext4: change s_last_trim_minblks type to unsigned long
ext4: mark group as trimmed only if it was fully scanned
ext4: replace the traditional ternary conditional operator with with max()/min()
ext4: move setting of trimmed bit into ext4_try_to_trim_range()
ext4: do not let fstrim block system suspend
MIPS: Alchemy: only build mmc support helpers if au1xmmc is enabled
clk: tegra: fix error return case for recalc_rate
ARM: dts: ti: omap: motorola-mapphone: Fix abe_clkctrl warning on boot
gpio: pmic-eic-sprd: Add can_sleep flag for PMIC EIC chip
parisc: sba: Fix compile warning wrt list of SBA devices
parisc: iosapic.c: Fix sparse warnings
parisc: drivers: Fix sparse warning
parisc: irq: Make irq_stack_union static to avoid sparse warning
selftests/ftrace: Correctly enable event in instance-event.tc
ring-buffer: Avoid softlockup in ring_buffer_resize()
ata: libata-eh: do not clear ATA_PFLAG_EH_PENDING in ata_eh_reset()
bpf: Clarify error expectations from bpf_clone_redirect
fbdev/sh7760fb: Depend on FB=y
nvme-pci: do not set the NUMA node of device if it has none
watchdog: iTCO_wdt: No need to stop the timer in probe
watchdog: iTCO_wdt: Set NO_REBOOT if the watchdog is not already running
net: Fix unwanted sign extension in netdev_stats_to_stats64()
scsi: megaraid_sas: Enable msix_load_balance for Invader and later controllers
Smack:- Use overlay inode label in smack_inode_copy_up()
smack: Retrieve transmuting information in smack_inode_getsecurity()
smack: Record transmuting in smk_transmuted
serial: 8250_port: Check IRQ data before use
nilfs2: fix potential use after free in nilfs_gccache_submit_read_data()
ALSA: hda: Disable power save for solving pop issue on Lenovo ThinkCentre M70q
ata: libata-scsi: ignore reserved bits for REPORT SUPPORTED OPERATION CODES
i2c: i801: unregister tco_pdev in i801_probe() error path
btrfs: properly report 0 avail for very full file systems
net: thunderbolt: Fix TCPv6 GSO checksum calculation
ata: libata-core: Fix ata_port_request_pm() locking
ata: libata-core: Fix port and device removal
ata: libata-core: Do not register PM operations for SAS ports
ata: libata-sata: increase PMP SRST timeout to 10s
fs: binfmt_elf_efpic: fix personality for ELF-FDPIC
ext4: fix rec_len verify error
ata: libata: disallow dev-initiated LPM transitions to unsupported states
Revert "drivers core: Use sysfs_emit and sysfs_emit_at for show(device *...) functions"
media: dvb: symbol fixup for dvb_attach() - again
Revert "PCI: qcom: Disable write access to read only registers for IP v2.3.3"
scsi: zfcp: Fix a double put in zfcp_port_enqueue()
qed/red_ll2: Fix undefined behavior bug in struct qed_ll2_info
wifi: mwifiex: Fix tlv_buf_left calculation
net: replace calls to sock->ops->connect() with kernel_connect()
ubi: Refuse attaching if mtd's erasesize is 0
wifi: mwifiex: Fix oob check condition in mwifiex_process_rx_packet
drivers/net: process the result of hdlc_open() and add call of hdlc_close() in uhdlc_close()
regmap: rbtree: Fix wrong register marked as in-cache when creating new node
scsi: target: core: Fix deadlock due to recursive locking
modpost: add missing else to the "of" check
ipv4, ipv6: Fix handling of transhdrlen in __ip{,6}_append_data()
net: usb: smsc75xx: Fix uninit-value access in __smsc75xx_read_reg
net: stmmac: dwmac-stm32: fix resume on STM32 MCU
tcp: fix quick-ack counting to count actual ACKs of new data
tcp: fix delayed ACKs for MSS boundary condition
sctp: update transport state when processing a dupcook packet
sctp: update hb timer immediately after users change hb_interval
cpupower: add Makefile dependencies for install targets
IB/mlx4: Fix the size of a buffer in add_port_entries()
gpio: aspeed: fix the GPIO number passed to pinctrl_gpio_set_config()
gpio: pxa: disable pinctrl calls for MMP_GPIO
RDMA/cma: Fix truncation compilation warning in make_cma_ports
RDMA/mlx5: Fix NULL string error
parisc: Restore __ldcw_align for PA-RISC 2.0 processors
dccp: fix dccp_v4_err()/dccp_v6_err() again
Revert "rtnetlink: Reject negative ifindexes in RTM_NEWLINK"
rtnetlink: Reject negative ifindexes in RTM_NEWLINK
xen/events: replace evtchn_rwlock with RCU
Linux 4.19.296
Change-Id: I4f76959ead91691fe9a242cb5b158fc8dc67bf39
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
262 lines
6.3 KiB
C
262 lines
6.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (C) ST-Ericsson SA 2011
|
|
*
|
|
* Author: Lee Jones <lee.jones@linaro.org> for ST-Ericsson.
|
|
*/
|
|
|
|
#include <linux/sysfs.h>
|
|
#include <linux/init.h>
|
|
#include <linux/stat.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/idr.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/sys_soc.h>
|
|
#include <linux/err.h>
|
|
#include <linux/glob.h>
|
|
|
|
static DEFINE_IDA(soc_ida);
|
|
|
|
static ssize_t soc_info_get(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf);
|
|
|
|
struct soc_device {
|
|
struct device dev;
|
|
struct soc_device_attribute *attr;
|
|
int soc_dev_num;
|
|
};
|
|
|
|
static struct bus_type soc_bus_type = {
|
|
.name = "soc",
|
|
};
|
|
|
|
static DEVICE_ATTR(machine, S_IRUGO, soc_info_get, NULL);
|
|
static DEVICE_ATTR(family, S_IRUGO, soc_info_get, NULL);
|
|
static DEVICE_ATTR(soc_id, S_IRUGO, soc_info_get, NULL);
|
|
static DEVICE_ATTR(revision, S_IRUGO, soc_info_get, NULL);
|
|
|
|
struct device *soc_device_to_device(struct soc_device *soc_dev)
|
|
{
|
|
return &soc_dev->dev;
|
|
}
|
|
EXPORT_SYMBOL_GPL(soc_device_to_device);
|
|
|
|
static umode_t soc_attribute_mode(struct kobject *kobj,
|
|
struct attribute *attr,
|
|
int index)
|
|
{
|
|
struct device *dev = container_of(kobj, struct device, kobj);
|
|
struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
|
|
|
|
if ((attr == &dev_attr_machine.attr)
|
|
&& (soc_dev->attr->machine != NULL))
|
|
return attr->mode;
|
|
if ((attr == &dev_attr_family.attr)
|
|
&& (soc_dev->attr->family != NULL))
|
|
return attr->mode;
|
|
if ((attr == &dev_attr_revision.attr)
|
|
&& (soc_dev->attr->revision != NULL))
|
|
return attr->mode;
|
|
if ((attr == &dev_attr_soc_id.attr)
|
|
&& (soc_dev->attr->soc_id != NULL))
|
|
return attr->mode;
|
|
|
|
/* Unknown or unfilled attribute. */
|
|
return 0;
|
|
}
|
|
|
|
static ssize_t soc_info_get(struct device *dev,
|
|
struct device_attribute *attr,
|
|
char *buf)
|
|
{
|
|
struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
|
|
|
|
if (attr == &dev_attr_machine)
|
|
return sprintf(buf, "%s\n", soc_dev->attr->machine);
|
|
if (attr == &dev_attr_family)
|
|
return sprintf(buf, "%s\n", soc_dev->attr->family);
|
|
if (attr == &dev_attr_revision)
|
|
return sprintf(buf, "%s\n", soc_dev->attr->revision);
|
|
if (attr == &dev_attr_soc_id)
|
|
return sprintf(buf, "%s\n", soc_dev->attr->soc_id);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
static struct attribute *soc_attr[] = {
|
|
&dev_attr_machine.attr,
|
|
&dev_attr_family.attr,
|
|
&dev_attr_soc_id.attr,
|
|
&dev_attr_revision.attr,
|
|
NULL,
|
|
};
|
|
|
|
static const struct attribute_group soc_attr_group = {
|
|
.attrs = soc_attr,
|
|
.is_visible = soc_attribute_mode,
|
|
};
|
|
|
|
static const struct attribute_group *soc_attr_groups[] = {
|
|
&soc_attr_group,
|
|
NULL,
|
|
};
|
|
|
|
static void soc_release(struct device *dev)
|
|
{
|
|
struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
|
|
|
|
kfree(soc_dev);
|
|
}
|
|
|
|
static struct soc_device_attribute *early_soc_dev_attr;
|
|
|
|
struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr)
|
|
{
|
|
struct soc_device *soc_dev;
|
|
int ret;
|
|
|
|
if (!soc_bus_type.p) {
|
|
if (early_soc_dev_attr)
|
|
return ERR_PTR(-EBUSY);
|
|
early_soc_dev_attr = soc_dev_attr;
|
|
return NULL;
|
|
}
|
|
|
|
soc_dev = kzalloc(sizeof(*soc_dev), GFP_KERNEL);
|
|
if (!soc_dev) {
|
|
ret = -ENOMEM;
|
|
goto out1;
|
|
}
|
|
|
|
/* Fetch a unique (reclaimable) SOC ID. */
|
|
ret = ida_simple_get(&soc_ida, 0, 0, GFP_KERNEL);
|
|
if (ret < 0)
|
|
goto out2;
|
|
soc_dev->soc_dev_num = ret;
|
|
|
|
soc_dev->attr = soc_dev_attr;
|
|
soc_dev->dev.bus = &soc_bus_type;
|
|
soc_dev->dev.groups = soc_attr_groups;
|
|
soc_dev->dev.release = soc_release;
|
|
|
|
dev_set_name(&soc_dev->dev, "soc%d", soc_dev->soc_dev_num);
|
|
|
|
ret = device_register(&soc_dev->dev);
|
|
if (ret)
|
|
goto out3;
|
|
|
|
return soc_dev;
|
|
|
|
out3:
|
|
ida_simple_remove(&soc_ida, soc_dev->soc_dev_num);
|
|
put_device(&soc_dev->dev);
|
|
soc_dev = NULL;
|
|
out2:
|
|
kfree(soc_dev);
|
|
out1:
|
|
return ERR_PTR(ret);
|
|
}
|
|
EXPORT_SYMBOL_GPL(soc_device_register);
|
|
|
|
/* Ensure soc_dev->attr is freed prior to calling soc_device_unregister. */
|
|
void soc_device_unregister(struct soc_device *soc_dev)
|
|
{
|
|
ida_simple_remove(&soc_ida, soc_dev->soc_dev_num);
|
|
|
|
device_unregister(&soc_dev->dev);
|
|
early_soc_dev_attr = NULL;
|
|
}
|
|
EXPORT_SYMBOL_GPL(soc_device_unregister);
|
|
|
|
static int __init soc_bus_register(void)
|
|
{
|
|
int ret;
|
|
|
|
ret = bus_register(&soc_bus_type);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (early_soc_dev_attr)
|
|
return PTR_ERR(soc_device_register(early_soc_dev_attr));
|
|
|
|
return 0;
|
|
}
|
|
core_initcall(soc_bus_register);
|
|
|
|
static int soc_device_match_attr(const struct soc_device_attribute *attr,
|
|
const struct soc_device_attribute *match)
|
|
{
|
|
if (match->machine &&
|
|
(!attr->machine || !glob_match(match->machine, attr->machine)))
|
|
return 0;
|
|
|
|
if (match->family &&
|
|
(!attr->family || !glob_match(match->family, attr->family)))
|
|
return 0;
|
|
|
|
if (match->revision &&
|
|
(!attr->revision || !glob_match(match->revision, attr->revision)))
|
|
return 0;
|
|
|
|
if (match->soc_id &&
|
|
(!attr->soc_id || !glob_match(match->soc_id, attr->soc_id)))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int soc_device_match_one(struct device *dev, void *arg)
|
|
{
|
|
struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
|
|
|
|
return soc_device_match_attr(soc_dev->attr, arg);
|
|
}
|
|
|
|
/*
|
|
* soc_device_match - identify the SoC in the machine
|
|
* @matches: zero-terminated array of possible matches
|
|
*
|
|
* returns the first matching entry of the argument array, or NULL
|
|
* if none of them match.
|
|
*
|
|
* This function is meant as a helper in place of of_match_node()
|
|
* in cases where either no device tree is available or the information
|
|
* in a device node is insufficient to identify a particular variant
|
|
* by its compatible strings or other properties. For new devices,
|
|
* the DT binding should always provide unique compatible strings
|
|
* that allow the use of of_match_node() instead.
|
|
*
|
|
* The calling function can use the .data entry of the
|
|
* soc_device_attribute to pass a structure or function pointer for
|
|
* each entry.
|
|
*/
|
|
const struct soc_device_attribute *soc_device_match(
|
|
const struct soc_device_attribute *matches)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (!matches)
|
|
return NULL;
|
|
|
|
while (!ret) {
|
|
if (!(matches->machine || matches->family ||
|
|
matches->revision || matches->soc_id))
|
|
break;
|
|
ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches,
|
|
soc_device_match_one);
|
|
if (ret < 0 && early_soc_dev_attr)
|
|
ret = soc_device_match_attr(early_soc_dev_attr,
|
|
matches);
|
|
if (ret < 0)
|
|
return NULL;
|
|
if (!ret)
|
|
matches++;
|
|
else
|
|
return matches;
|
|
}
|
|
return NULL;
|
|
}
|
|
EXPORT_SYMBOL_GPL(soc_device_match);
|