162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * (C) Copyright 2002-2004 Greg Kroah-Hartman <greg@kroah.com>
462306a36Sopenharmony_ci * (C) Copyright 2002-2004 IBM Corp.
562306a36Sopenharmony_ci * (C) Copyright 2003 Matthew Wilcox
662306a36Sopenharmony_ci * (C) Copyright 2003 Hewlett-Packard
762306a36Sopenharmony_ci * (C) Copyright 2004 Jon Smirl <jonsmirl@yahoo.com>
862306a36Sopenharmony_ci * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <jbarnes@sgi.com>
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * File attributes for PCI devices
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Modeled after usb's driverfs.c
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/bitfield.h>
1662306a36Sopenharmony_ci#include <linux/kernel.h>
1762306a36Sopenharmony_ci#include <linux/sched.h>
1862306a36Sopenharmony_ci#include <linux/pci.h>
1962306a36Sopenharmony_ci#include <linux/stat.h>
2062306a36Sopenharmony_ci#include <linux/export.h>
2162306a36Sopenharmony_ci#include <linux/topology.h>
2262306a36Sopenharmony_ci#include <linux/mm.h>
2362306a36Sopenharmony_ci#include <linux/fs.h>
2462306a36Sopenharmony_ci#include <linux/capability.h>
2562306a36Sopenharmony_ci#include <linux/security.h>
2662306a36Sopenharmony_ci#include <linux/slab.h>
2762306a36Sopenharmony_ci#include <linux/vgaarb.h>
2862306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2962306a36Sopenharmony_ci#include <linux/msi.h>
3062306a36Sopenharmony_ci#include <linux/of.h>
3162306a36Sopenharmony_ci#include <linux/aperture.h>
3262306a36Sopenharmony_ci#include "pci.h"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic int sysfs_initialized;	/* = 0 */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* show configuration fields */
3762306a36Sopenharmony_ci#define pci_config_attr(field, format_string)				\
3862306a36Sopenharmony_cistatic ssize_t								\
3962306a36Sopenharmony_cifield##_show(struct device *dev, struct device_attribute *attr, char *buf)				\
4062306a36Sopenharmony_ci{									\
4162306a36Sopenharmony_ci	struct pci_dev *pdev;						\
4262306a36Sopenharmony_ci									\
4362306a36Sopenharmony_ci	pdev = to_pci_dev(dev);						\
4462306a36Sopenharmony_ci	return sysfs_emit(buf, format_string, pdev->field);		\
4562306a36Sopenharmony_ci}									\
4662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(field)
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cipci_config_attr(vendor, "0x%04x\n");
4962306a36Sopenharmony_cipci_config_attr(device, "0x%04x\n");
5062306a36Sopenharmony_cipci_config_attr(subsystem_vendor, "0x%04x\n");
5162306a36Sopenharmony_cipci_config_attr(subsystem_device, "0x%04x\n");
5262306a36Sopenharmony_cipci_config_attr(revision, "0x%02x\n");
5362306a36Sopenharmony_cipci_config_attr(class, "0x%06x\n");
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic ssize_t irq_show(struct device *dev,
5662306a36Sopenharmony_ci			struct device_attribute *attr,
5762306a36Sopenharmony_ci			char *buf)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#ifdef CONFIG_PCI_MSI
6262306a36Sopenharmony_ci	/*
6362306a36Sopenharmony_ci	 * For MSI, show the first MSI IRQ; for all other cases including
6462306a36Sopenharmony_ci	 * MSI-X, show the legacy INTx IRQ.
6562306a36Sopenharmony_ci	 */
6662306a36Sopenharmony_ci	if (pdev->msi_enabled)
6762306a36Sopenharmony_ci		return sysfs_emit(buf, "%u\n", pci_irq_vector(pdev, 0));
6862306a36Sopenharmony_ci#endif
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", pdev->irq);
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(irq);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic ssize_t broken_parity_status_show(struct device *dev,
7562306a36Sopenharmony_ci					 struct device_attribute *attr,
7662306a36Sopenharmony_ci					 char *buf)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
7962306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", pdev->broken_parity_status);
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic ssize_t broken_parity_status_store(struct device *dev,
8362306a36Sopenharmony_ci					  struct device_attribute *attr,
8462306a36Sopenharmony_ci					  const char *buf, size_t count)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
8762306a36Sopenharmony_ci	unsigned long val;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if (kstrtoul(buf, 0, &val) < 0)
9062306a36Sopenharmony_ci		return -EINVAL;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	pdev->broken_parity_status = !!val;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	return count;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_cistatic DEVICE_ATTR_RW(broken_parity_status);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic ssize_t pci_dev_show_local_cpu(struct device *dev, bool list,
9962306a36Sopenharmony_ci				      struct device_attribute *attr, char *buf)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	const struct cpumask *mask;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#ifdef CONFIG_NUMA
10462306a36Sopenharmony_ci	if (dev_to_node(dev) == NUMA_NO_NODE)
10562306a36Sopenharmony_ci		mask = cpu_online_mask;
10662306a36Sopenharmony_ci	else
10762306a36Sopenharmony_ci		mask = cpumask_of_node(dev_to_node(dev));
10862306a36Sopenharmony_ci#else
10962306a36Sopenharmony_ci	mask = cpumask_of_pcibus(to_pci_dev(dev)->bus);
11062306a36Sopenharmony_ci#endif
11162306a36Sopenharmony_ci	return cpumap_print_to_pagebuf(list, buf, mask);
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic ssize_t local_cpus_show(struct device *dev,
11562306a36Sopenharmony_ci			       struct device_attribute *attr, char *buf)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	return pci_dev_show_local_cpu(dev, false, attr, buf);
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(local_cpus);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic ssize_t local_cpulist_show(struct device *dev,
12262306a36Sopenharmony_ci				  struct device_attribute *attr, char *buf)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	return pci_dev_show_local_cpu(dev, true, attr, buf);
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(local_cpulist);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci/*
12962306a36Sopenharmony_ci * PCI Bus Class Devices
13062306a36Sopenharmony_ci */
13162306a36Sopenharmony_cistatic ssize_t cpuaffinity_show(struct device *dev,
13262306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	const struct cpumask *cpumask = cpumask_of_pcibus(to_pci_bus(dev));
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	return cpumap_print_to_pagebuf(false, buf, cpumask);
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(cpuaffinity);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic ssize_t cpulistaffinity_show(struct device *dev,
14162306a36Sopenharmony_ci				    struct device_attribute *attr, char *buf)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	const struct cpumask *cpumask = cpumask_of_pcibus(to_pci_bus(dev));
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	return cpumap_print_to_pagebuf(true, buf, cpumask);
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(cpulistaffinity);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic ssize_t power_state_show(struct device *dev,
15062306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n", pci_power_name(pdev->current_state));
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(power_state);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci/* show resources */
15962306a36Sopenharmony_cistatic ssize_t resource_show(struct device *dev, struct device_attribute *attr,
16062306a36Sopenharmony_ci			     char *buf)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct pci_dev *pci_dev = to_pci_dev(dev);
16362306a36Sopenharmony_ci	int i;
16462306a36Sopenharmony_ci	int max;
16562306a36Sopenharmony_ci	resource_size_t start, end;
16662306a36Sopenharmony_ci	size_t len = 0;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (pci_dev->subordinate)
16962306a36Sopenharmony_ci		max = DEVICE_COUNT_RESOURCE;
17062306a36Sopenharmony_ci	else
17162306a36Sopenharmony_ci		max = PCI_BRIDGE_RESOURCES;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	for (i = 0; i < max; i++) {
17462306a36Sopenharmony_ci		struct resource *res =  &pci_dev->resource[i];
17562306a36Sopenharmony_ci		pci_resource_to_user(pci_dev, i, res, &start, &end);
17662306a36Sopenharmony_ci		len += sysfs_emit_at(buf, len, "0x%016llx 0x%016llx 0x%016llx\n",
17762306a36Sopenharmony_ci				     (unsigned long long)start,
17862306a36Sopenharmony_ci				     (unsigned long long)end,
17962306a36Sopenharmony_ci				     (unsigned long long)res->flags);
18062306a36Sopenharmony_ci	}
18162306a36Sopenharmony_ci	return len;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(resource);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic ssize_t max_link_speed_show(struct device *dev,
18662306a36Sopenharmony_ci				   struct device_attribute *attr, char *buf)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n",
19162306a36Sopenharmony_ci			  pci_speed_string(pcie_get_speed_cap(pdev)));
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(max_link_speed);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic ssize_t max_link_width_show(struct device *dev,
19662306a36Sopenharmony_ci				   struct device_attribute *attr, char *buf)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", pcie_get_width_cap(pdev));
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(max_link_width);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic ssize_t current_link_speed_show(struct device *dev,
20562306a36Sopenharmony_ci				       struct device_attribute *attr, char *buf)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	struct pci_dev *pci_dev = to_pci_dev(dev);
20862306a36Sopenharmony_ci	u16 linkstat;
20962306a36Sopenharmony_ci	int err;
21062306a36Sopenharmony_ci	enum pci_bus_speed speed;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat);
21362306a36Sopenharmony_ci	if (err)
21462306a36Sopenharmony_ci		return -EINVAL;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	speed = pcie_link_speed[linkstat & PCI_EXP_LNKSTA_CLS];
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	return sysfs_emit(buf, "%s\n", pci_speed_string(speed));
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(current_link_speed);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistatic ssize_t current_link_width_show(struct device *dev,
22362306a36Sopenharmony_ci				       struct device_attribute *attr, char *buf)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	struct pci_dev *pci_dev = to_pci_dev(dev);
22662306a36Sopenharmony_ci	u16 linkstat;
22762306a36Sopenharmony_ci	int err;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat);
23062306a36Sopenharmony_ci	if (err)
23162306a36Sopenharmony_ci		return -EINVAL;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", FIELD_GET(PCI_EXP_LNKSTA_NLW, linkstat));
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(current_link_width);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic ssize_t secondary_bus_number_show(struct device *dev,
23862306a36Sopenharmony_ci					 struct device_attribute *attr,
23962306a36Sopenharmony_ci					 char *buf)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct pci_dev *pci_dev = to_pci_dev(dev);
24262306a36Sopenharmony_ci	u8 sec_bus;
24362306a36Sopenharmony_ci	int err;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	err = pci_read_config_byte(pci_dev, PCI_SECONDARY_BUS, &sec_bus);
24662306a36Sopenharmony_ci	if (err)
24762306a36Sopenharmony_ci		return -EINVAL;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", sec_bus);
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(secondary_bus_number);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic ssize_t subordinate_bus_number_show(struct device *dev,
25462306a36Sopenharmony_ci					   struct device_attribute *attr,
25562306a36Sopenharmony_ci					   char *buf)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	struct pci_dev *pci_dev = to_pci_dev(dev);
25862306a36Sopenharmony_ci	u8 sub_bus;
25962306a36Sopenharmony_ci	int err;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	err = pci_read_config_byte(pci_dev, PCI_SUBORDINATE_BUS, &sub_bus);
26262306a36Sopenharmony_ci	if (err)
26362306a36Sopenharmony_ci		return -EINVAL;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", sub_bus);
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(subordinate_bus_number);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic ssize_t ari_enabled_show(struct device *dev,
27062306a36Sopenharmony_ci				struct device_attribute *attr,
27162306a36Sopenharmony_ci				char *buf)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	struct pci_dev *pci_dev = to_pci_dev(dev);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", pci_ari_enabled(pci_dev->bus));
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(ari_enabled);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
28062306a36Sopenharmony_ci			     char *buf)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	struct pci_dev *pci_dev = to_pci_dev(dev);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	return sysfs_emit(buf, "pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02X\n",
28562306a36Sopenharmony_ci			  pci_dev->vendor, pci_dev->device,
28662306a36Sopenharmony_ci			  pci_dev->subsystem_vendor, pci_dev->subsystem_device,
28762306a36Sopenharmony_ci			  (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8),
28862306a36Sopenharmony_ci			  (u8)(pci_dev->class));
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(modalias);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_cistatic ssize_t enable_store(struct device *dev, struct device_attribute *attr,
29362306a36Sopenharmony_ci			     const char *buf, size_t count)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
29662306a36Sopenharmony_ci	unsigned long val;
29762306a36Sopenharmony_ci	ssize_t result = 0;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	/* this can crash the machine when done on the "wrong" device */
30062306a36Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
30162306a36Sopenharmony_ci		return -EPERM;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (kstrtoul(buf, 0, &val) < 0)
30462306a36Sopenharmony_ci		return -EINVAL;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	device_lock(dev);
30762306a36Sopenharmony_ci	if (dev->driver)
30862306a36Sopenharmony_ci		result = -EBUSY;
30962306a36Sopenharmony_ci	else if (val)
31062306a36Sopenharmony_ci		result = pci_enable_device(pdev);
31162306a36Sopenharmony_ci	else if (pci_is_enabled(pdev))
31262306a36Sopenharmony_ci		pci_disable_device(pdev);
31362306a36Sopenharmony_ci	else
31462306a36Sopenharmony_ci		result = -EIO;
31562306a36Sopenharmony_ci	device_unlock(dev);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	return result < 0 ? result : count;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cistatic ssize_t enable_show(struct device *dev, struct device_attribute *attr,
32162306a36Sopenharmony_ci			    char *buf)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct pci_dev *pdev;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	pdev = to_pci_dev(dev);
32662306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", atomic_read(&pdev->enable_cnt));
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_cistatic DEVICE_ATTR_RW(enable);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci#ifdef CONFIG_NUMA
33162306a36Sopenharmony_cistatic ssize_t numa_node_store(struct device *dev,
33262306a36Sopenharmony_ci			       struct device_attribute *attr, const char *buf,
33362306a36Sopenharmony_ci			       size_t count)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
33662306a36Sopenharmony_ci	int node;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
33962306a36Sopenharmony_ci		return -EPERM;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	if (kstrtoint(buf, 0, &node) < 0)
34262306a36Sopenharmony_ci		return -EINVAL;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	if ((node < 0 && node != NUMA_NO_NODE) || node >= MAX_NUMNODES)
34562306a36Sopenharmony_ci		return -EINVAL;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if (node != NUMA_NO_NODE && !node_online(node))
34862306a36Sopenharmony_ci		return -EINVAL;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
35162306a36Sopenharmony_ci	pci_alert(pdev, FW_BUG "Overriding NUMA node to %d.  Contact your vendor for updates.",
35262306a36Sopenharmony_ci		  node);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	dev->numa_node = node;
35562306a36Sopenharmony_ci	return count;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic ssize_t numa_node_show(struct device *dev, struct device_attribute *attr,
35962306a36Sopenharmony_ci			      char *buf)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", dev->numa_node);
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_cistatic DEVICE_ATTR_RW(numa_node);
36462306a36Sopenharmony_ci#endif
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic ssize_t dma_mask_bits_show(struct device *dev,
36762306a36Sopenharmony_ci				  struct device_attribute *attr, char *buf)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", fls64(pdev->dma_mask));
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(dma_mask_bits);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cistatic ssize_t consistent_dma_mask_bits_show(struct device *dev,
37662306a36Sopenharmony_ci					     struct device_attribute *attr,
37762306a36Sopenharmony_ci					     char *buf)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", fls64(dev->coherent_dma_mask));
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(consistent_dma_mask_bits);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic ssize_t msi_bus_show(struct device *dev, struct device_attribute *attr,
38462306a36Sopenharmony_ci			    char *buf)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
38762306a36Sopenharmony_ci	struct pci_bus *subordinate = pdev->subordinate;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", subordinate ?
39062306a36Sopenharmony_ci			  !(subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI)
39162306a36Sopenharmony_ci			    : !pdev->no_msi);
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic ssize_t msi_bus_store(struct device *dev, struct device_attribute *attr,
39562306a36Sopenharmony_ci			     const char *buf, size_t count)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
39862306a36Sopenharmony_ci	struct pci_bus *subordinate = pdev->subordinate;
39962306a36Sopenharmony_ci	unsigned long val;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
40262306a36Sopenharmony_ci		return -EPERM;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	if (kstrtoul(buf, 0, &val) < 0)
40562306a36Sopenharmony_ci		return -EINVAL;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	/*
40862306a36Sopenharmony_ci	 * "no_msi" and "bus_flags" only affect what happens when a driver
40962306a36Sopenharmony_ci	 * requests MSI or MSI-X.  They don't affect any drivers that have
41062306a36Sopenharmony_ci	 * already requested MSI or MSI-X.
41162306a36Sopenharmony_ci	 */
41262306a36Sopenharmony_ci	if (!subordinate) {
41362306a36Sopenharmony_ci		pdev->no_msi = !val;
41462306a36Sopenharmony_ci		pci_info(pdev, "MSI/MSI-X %s for future drivers\n",
41562306a36Sopenharmony_ci			 val ? "allowed" : "disallowed");
41662306a36Sopenharmony_ci		return count;
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	if (val)
42062306a36Sopenharmony_ci		subordinate->bus_flags &= ~PCI_BUS_FLAGS_NO_MSI;
42162306a36Sopenharmony_ci	else
42262306a36Sopenharmony_ci		subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	dev_info(&subordinate->dev, "MSI/MSI-X %s for future drivers of devices on this bus\n",
42562306a36Sopenharmony_ci		 val ? "allowed" : "disallowed");
42662306a36Sopenharmony_ci	return count;
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_cistatic DEVICE_ATTR_RW(msi_bus);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic ssize_t rescan_store(const struct bus_type *bus, const char *buf, size_t count)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	unsigned long val;
43362306a36Sopenharmony_ci	struct pci_bus *b = NULL;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	if (kstrtoul(buf, 0, &val) < 0)
43662306a36Sopenharmony_ci		return -EINVAL;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	if (val) {
43962306a36Sopenharmony_ci		pci_lock_rescan_remove();
44062306a36Sopenharmony_ci		while ((b = pci_find_next_bus(b)) != NULL)
44162306a36Sopenharmony_ci			pci_rescan_bus(b);
44262306a36Sopenharmony_ci		pci_unlock_rescan_remove();
44362306a36Sopenharmony_ci	}
44462306a36Sopenharmony_ci	return count;
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_cistatic BUS_ATTR_WO(rescan);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cistatic struct attribute *pci_bus_attrs[] = {
44962306a36Sopenharmony_ci	&bus_attr_rescan.attr,
45062306a36Sopenharmony_ci	NULL,
45162306a36Sopenharmony_ci};
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic const struct attribute_group pci_bus_group = {
45462306a36Sopenharmony_ci	.attrs = pci_bus_attrs,
45562306a36Sopenharmony_ci};
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ciconst struct attribute_group *pci_bus_groups[] = {
45862306a36Sopenharmony_ci	&pci_bus_group,
45962306a36Sopenharmony_ci	NULL,
46062306a36Sopenharmony_ci};
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic ssize_t dev_rescan_store(struct device *dev,
46362306a36Sopenharmony_ci				struct device_attribute *attr, const char *buf,
46462306a36Sopenharmony_ci				size_t count)
46562306a36Sopenharmony_ci{
46662306a36Sopenharmony_ci	unsigned long val;
46762306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	if (kstrtoul(buf, 0, &val) < 0)
47062306a36Sopenharmony_ci		return -EINVAL;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	if (val) {
47362306a36Sopenharmony_ci		pci_lock_rescan_remove();
47462306a36Sopenharmony_ci		pci_rescan_bus(pdev->bus);
47562306a36Sopenharmony_ci		pci_unlock_rescan_remove();
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci	return count;
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_cistatic struct device_attribute dev_attr_dev_rescan = __ATTR(rescan, 0200, NULL,
48062306a36Sopenharmony_ci							    dev_rescan_store);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic ssize_t remove_store(struct device *dev, struct device_attribute *attr,
48362306a36Sopenharmony_ci			    const char *buf, size_t count)
48462306a36Sopenharmony_ci{
48562306a36Sopenharmony_ci	unsigned long val;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	if (kstrtoul(buf, 0, &val) < 0)
48862306a36Sopenharmony_ci		return -EINVAL;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (val && device_remove_file_self(dev, attr))
49162306a36Sopenharmony_ci		pci_stop_and_remove_bus_device_locked(to_pci_dev(dev));
49262306a36Sopenharmony_ci	return count;
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_cistatic DEVICE_ATTR_IGNORE_LOCKDEP(remove, 0220, NULL,
49562306a36Sopenharmony_ci				  remove_store);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_cistatic ssize_t bus_rescan_store(struct device *dev,
49862306a36Sopenharmony_ci				struct device_attribute *attr,
49962306a36Sopenharmony_ci				const char *buf, size_t count)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	unsigned long val;
50262306a36Sopenharmony_ci	struct pci_bus *bus = to_pci_bus(dev);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	if (kstrtoul(buf, 0, &val) < 0)
50562306a36Sopenharmony_ci		return -EINVAL;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	if (val) {
50862306a36Sopenharmony_ci		pci_lock_rescan_remove();
50962306a36Sopenharmony_ci		if (!pci_is_root_bus(bus) && list_empty(&bus->devices))
51062306a36Sopenharmony_ci			pci_rescan_bus_bridge_resize(bus->self);
51162306a36Sopenharmony_ci		else
51262306a36Sopenharmony_ci			pci_rescan_bus(bus);
51362306a36Sopenharmony_ci		pci_unlock_rescan_remove();
51462306a36Sopenharmony_ci	}
51562306a36Sopenharmony_ci	return count;
51662306a36Sopenharmony_ci}
51762306a36Sopenharmony_cistatic struct device_attribute dev_attr_bus_rescan = __ATTR(rescan, 0200, NULL,
51862306a36Sopenharmony_ci							    bus_rescan_store);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci#if defined(CONFIG_PM) && defined(CONFIG_ACPI)
52162306a36Sopenharmony_cistatic ssize_t d3cold_allowed_store(struct device *dev,
52262306a36Sopenharmony_ci				    struct device_attribute *attr,
52362306a36Sopenharmony_ci				    const char *buf, size_t count)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
52662306a36Sopenharmony_ci	unsigned long val;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	if (kstrtoul(buf, 0, &val) < 0)
52962306a36Sopenharmony_ci		return -EINVAL;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	pdev->d3cold_allowed = !!val;
53262306a36Sopenharmony_ci	pci_bridge_d3_update(pdev);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	pm_runtime_resume(dev);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	return count;
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_cistatic ssize_t d3cold_allowed_show(struct device *dev,
54062306a36Sopenharmony_ci				   struct device_attribute *attr, char *buf)
54162306a36Sopenharmony_ci{
54262306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
54362306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", pdev->d3cold_allowed);
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_cistatic DEVICE_ATTR_RW(d3cold_allowed);
54662306a36Sopenharmony_ci#endif
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci#ifdef CONFIG_OF
54962306a36Sopenharmony_cistatic ssize_t devspec_show(struct device *dev,
55062306a36Sopenharmony_ci			    struct device_attribute *attr, char *buf)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
55362306a36Sopenharmony_ci	struct device_node *np = pci_device_to_OF_node(pdev);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	if (np == NULL)
55662306a36Sopenharmony_ci		return 0;
55762306a36Sopenharmony_ci	return sysfs_emit(buf, "%pOF\n", np);
55862306a36Sopenharmony_ci}
55962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(devspec);
56062306a36Sopenharmony_ci#endif
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_cistatic ssize_t driver_override_store(struct device *dev,
56362306a36Sopenharmony_ci				     struct device_attribute *attr,
56462306a36Sopenharmony_ci				     const char *buf, size_t count)
56562306a36Sopenharmony_ci{
56662306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
56762306a36Sopenharmony_ci	int ret;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	ret = driver_set_override(dev, &pdev->driver_override, buf, count);
57062306a36Sopenharmony_ci	if (ret)
57162306a36Sopenharmony_ci		return ret;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	return count;
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cistatic ssize_t driver_override_show(struct device *dev,
57762306a36Sopenharmony_ci				    struct device_attribute *attr, char *buf)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
58062306a36Sopenharmony_ci	ssize_t len;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	device_lock(dev);
58362306a36Sopenharmony_ci	len = sysfs_emit(buf, "%s\n", pdev->driver_override);
58462306a36Sopenharmony_ci	device_unlock(dev);
58562306a36Sopenharmony_ci	return len;
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_cistatic DEVICE_ATTR_RW(driver_override);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_cistatic struct attribute *pci_dev_attrs[] = {
59062306a36Sopenharmony_ci	&dev_attr_power_state.attr,
59162306a36Sopenharmony_ci	&dev_attr_resource.attr,
59262306a36Sopenharmony_ci	&dev_attr_vendor.attr,
59362306a36Sopenharmony_ci	&dev_attr_device.attr,
59462306a36Sopenharmony_ci	&dev_attr_subsystem_vendor.attr,
59562306a36Sopenharmony_ci	&dev_attr_subsystem_device.attr,
59662306a36Sopenharmony_ci	&dev_attr_revision.attr,
59762306a36Sopenharmony_ci	&dev_attr_class.attr,
59862306a36Sopenharmony_ci	&dev_attr_irq.attr,
59962306a36Sopenharmony_ci	&dev_attr_local_cpus.attr,
60062306a36Sopenharmony_ci	&dev_attr_local_cpulist.attr,
60162306a36Sopenharmony_ci	&dev_attr_modalias.attr,
60262306a36Sopenharmony_ci#ifdef CONFIG_NUMA
60362306a36Sopenharmony_ci	&dev_attr_numa_node.attr,
60462306a36Sopenharmony_ci#endif
60562306a36Sopenharmony_ci	&dev_attr_dma_mask_bits.attr,
60662306a36Sopenharmony_ci	&dev_attr_consistent_dma_mask_bits.attr,
60762306a36Sopenharmony_ci	&dev_attr_enable.attr,
60862306a36Sopenharmony_ci	&dev_attr_broken_parity_status.attr,
60962306a36Sopenharmony_ci	&dev_attr_msi_bus.attr,
61062306a36Sopenharmony_ci#if defined(CONFIG_PM) && defined(CONFIG_ACPI)
61162306a36Sopenharmony_ci	&dev_attr_d3cold_allowed.attr,
61262306a36Sopenharmony_ci#endif
61362306a36Sopenharmony_ci#ifdef CONFIG_OF
61462306a36Sopenharmony_ci	&dev_attr_devspec.attr,
61562306a36Sopenharmony_ci#endif
61662306a36Sopenharmony_ci	&dev_attr_driver_override.attr,
61762306a36Sopenharmony_ci	&dev_attr_ari_enabled.attr,
61862306a36Sopenharmony_ci	NULL,
61962306a36Sopenharmony_ci};
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_cistatic struct attribute *pci_bridge_attrs[] = {
62262306a36Sopenharmony_ci	&dev_attr_subordinate_bus_number.attr,
62362306a36Sopenharmony_ci	&dev_attr_secondary_bus_number.attr,
62462306a36Sopenharmony_ci	NULL,
62562306a36Sopenharmony_ci};
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_cistatic struct attribute *pcie_dev_attrs[] = {
62862306a36Sopenharmony_ci	&dev_attr_current_link_speed.attr,
62962306a36Sopenharmony_ci	&dev_attr_current_link_width.attr,
63062306a36Sopenharmony_ci	&dev_attr_max_link_width.attr,
63162306a36Sopenharmony_ci	&dev_attr_max_link_speed.attr,
63262306a36Sopenharmony_ci	NULL,
63362306a36Sopenharmony_ci};
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_cistatic struct attribute *pcibus_attrs[] = {
63662306a36Sopenharmony_ci	&dev_attr_bus_rescan.attr,
63762306a36Sopenharmony_ci	&dev_attr_cpuaffinity.attr,
63862306a36Sopenharmony_ci	&dev_attr_cpulistaffinity.attr,
63962306a36Sopenharmony_ci	NULL,
64062306a36Sopenharmony_ci};
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_cistatic const struct attribute_group pcibus_group = {
64362306a36Sopenharmony_ci	.attrs = pcibus_attrs,
64462306a36Sopenharmony_ci};
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ciconst struct attribute_group *pcibus_groups[] = {
64762306a36Sopenharmony_ci	&pcibus_group,
64862306a36Sopenharmony_ci	NULL,
64962306a36Sopenharmony_ci};
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_cistatic ssize_t boot_vga_show(struct device *dev, struct device_attribute *attr,
65262306a36Sopenharmony_ci			     char *buf)
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
65562306a36Sopenharmony_ci	struct pci_dev *vga_dev = vga_default_device();
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	if (vga_dev)
65862306a36Sopenharmony_ci		return sysfs_emit(buf, "%u\n", (pdev == vga_dev));
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n",
66162306a36Sopenharmony_ci			  !!(pdev->resource[PCI_ROM_RESOURCE].flags &
66262306a36Sopenharmony_ci			     IORESOURCE_ROM_SHADOW));
66362306a36Sopenharmony_ci}
66462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(boot_vga);
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_cistatic ssize_t pci_read_config(struct file *filp, struct kobject *kobj,
66762306a36Sopenharmony_ci			       struct bin_attribute *bin_attr, char *buf,
66862306a36Sopenharmony_ci			       loff_t off, size_t count)
66962306a36Sopenharmony_ci{
67062306a36Sopenharmony_ci	struct pci_dev *dev = to_pci_dev(kobj_to_dev(kobj));
67162306a36Sopenharmony_ci	unsigned int size = 64;
67262306a36Sopenharmony_ci	loff_t init_off = off;
67362306a36Sopenharmony_ci	u8 *data = (u8 *) buf;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	/* Several chips lock up trying to read undefined config space */
67662306a36Sopenharmony_ci	if (file_ns_capable(filp, &init_user_ns, CAP_SYS_ADMIN))
67762306a36Sopenharmony_ci		size = dev->cfg_size;
67862306a36Sopenharmony_ci	else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
67962306a36Sopenharmony_ci		size = 128;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	if (off > size)
68262306a36Sopenharmony_ci		return 0;
68362306a36Sopenharmony_ci	if (off + count > size) {
68462306a36Sopenharmony_ci		size -= off;
68562306a36Sopenharmony_ci		count = size;
68662306a36Sopenharmony_ci	} else {
68762306a36Sopenharmony_ci		size = count;
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	pci_config_pm_runtime_get(dev);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	if ((off & 1) && size) {
69362306a36Sopenharmony_ci		u8 val;
69462306a36Sopenharmony_ci		pci_user_read_config_byte(dev, off, &val);
69562306a36Sopenharmony_ci		data[off - init_off] = val;
69662306a36Sopenharmony_ci		off++;
69762306a36Sopenharmony_ci		size--;
69862306a36Sopenharmony_ci	}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	if ((off & 3) && size > 2) {
70162306a36Sopenharmony_ci		u16 val;
70262306a36Sopenharmony_ci		pci_user_read_config_word(dev, off, &val);
70362306a36Sopenharmony_ci		data[off - init_off] = val & 0xff;
70462306a36Sopenharmony_ci		data[off - init_off + 1] = (val >> 8) & 0xff;
70562306a36Sopenharmony_ci		off += 2;
70662306a36Sopenharmony_ci		size -= 2;
70762306a36Sopenharmony_ci	}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	while (size > 3) {
71062306a36Sopenharmony_ci		u32 val;
71162306a36Sopenharmony_ci		pci_user_read_config_dword(dev, off, &val);
71262306a36Sopenharmony_ci		data[off - init_off] = val & 0xff;
71362306a36Sopenharmony_ci		data[off - init_off + 1] = (val >> 8) & 0xff;
71462306a36Sopenharmony_ci		data[off - init_off + 2] = (val >> 16) & 0xff;
71562306a36Sopenharmony_ci		data[off - init_off + 3] = (val >> 24) & 0xff;
71662306a36Sopenharmony_ci		off += 4;
71762306a36Sopenharmony_ci		size -= 4;
71862306a36Sopenharmony_ci		cond_resched();
71962306a36Sopenharmony_ci	}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	if (size >= 2) {
72262306a36Sopenharmony_ci		u16 val;
72362306a36Sopenharmony_ci		pci_user_read_config_word(dev, off, &val);
72462306a36Sopenharmony_ci		data[off - init_off] = val & 0xff;
72562306a36Sopenharmony_ci		data[off - init_off + 1] = (val >> 8) & 0xff;
72662306a36Sopenharmony_ci		off += 2;
72762306a36Sopenharmony_ci		size -= 2;
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	if (size > 0) {
73162306a36Sopenharmony_ci		u8 val;
73262306a36Sopenharmony_ci		pci_user_read_config_byte(dev, off, &val);
73362306a36Sopenharmony_ci		data[off - init_off] = val;
73462306a36Sopenharmony_ci	}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	pci_config_pm_runtime_put(dev);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	return count;
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_cistatic ssize_t pci_write_config(struct file *filp, struct kobject *kobj,
74262306a36Sopenharmony_ci				struct bin_attribute *bin_attr, char *buf,
74362306a36Sopenharmony_ci				loff_t off, size_t count)
74462306a36Sopenharmony_ci{
74562306a36Sopenharmony_ci	struct pci_dev *dev = to_pci_dev(kobj_to_dev(kobj));
74662306a36Sopenharmony_ci	unsigned int size = count;
74762306a36Sopenharmony_ci	loff_t init_off = off;
74862306a36Sopenharmony_ci	u8 *data = (u8 *) buf;
74962306a36Sopenharmony_ci	int ret;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	ret = security_locked_down(LOCKDOWN_PCI_ACCESS);
75262306a36Sopenharmony_ci	if (ret)
75362306a36Sopenharmony_ci		return ret;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	if (resource_is_exclusive(&dev->driver_exclusive_resource, off,
75662306a36Sopenharmony_ci				  count)) {
75762306a36Sopenharmony_ci		pci_warn_once(dev, "%s: Unexpected write to kernel-exclusive config offset %llx",
75862306a36Sopenharmony_ci			      current->comm, off);
75962306a36Sopenharmony_ci		add_taint(TAINT_USER, LOCKDEP_STILL_OK);
76062306a36Sopenharmony_ci	}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	if (off > dev->cfg_size)
76362306a36Sopenharmony_ci		return 0;
76462306a36Sopenharmony_ci	if (off + count > dev->cfg_size) {
76562306a36Sopenharmony_ci		size = dev->cfg_size - off;
76662306a36Sopenharmony_ci		count = size;
76762306a36Sopenharmony_ci	}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	pci_config_pm_runtime_get(dev);
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	if ((off & 1) && size) {
77262306a36Sopenharmony_ci		pci_user_write_config_byte(dev, off, data[off - init_off]);
77362306a36Sopenharmony_ci		off++;
77462306a36Sopenharmony_ci		size--;
77562306a36Sopenharmony_ci	}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	if ((off & 3) && size > 2) {
77862306a36Sopenharmony_ci		u16 val = data[off - init_off];
77962306a36Sopenharmony_ci		val |= (u16) data[off - init_off + 1] << 8;
78062306a36Sopenharmony_ci		pci_user_write_config_word(dev, off, val);
78162306a36Sopenharmony_ci		off += 2;
78262306a36Sopenharmony_ci		size -= 2;
78362306a36Sopenharmony_ci	}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	while (size > 3) {
78662306a36Sopenharmony_ci		u32 val = data[off - init_off];
78762306a36Sopenharmony_ci		val |= (u32) data[off - init_off + 1] << 8;
78862306a36Sopenharmony_ci		val |= (u32) data[off - init_off + 2] << 16;
78962306a36Sopenharmony_ci		val |= (u32) data[off - init_off + 3] << 24;
79062306a36Sopenharmony_ci		pci_user_write_config_dword(dev, off, val);
79162306a36Sopenharmony_ci		off += 4;
79262306a36Sopenharmony_ci		size -= 4;
79362306a36Sopenharmony_ci	}
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	if (size >= 2) {
79662306a36Sopenharmony_ci		u16 val = data[off - init_off];
79762306a36Sopenharmony_ci		val |= (u16) data[off - init_off + 1] << 8;
79862306a36Sopenharmony_ci		pci_user_write_config_word(dev, off, val);
79962306a36Sopenharmony_ci		off += 2;
80062306a36Sopenharmony_ci		size -= 2;
80162306a36Sopenharmony_ci	}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	if (size)
80462306a36Sopenharmony_ci		pci_user_write_config_byte(dev, off, data[off - init_off]);
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	pci_config_pm_runtime_put(dev);
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	return count;
80962306a36Sopenharmony_ci}
81062306a36Sopenharmony_cistatic BIN_ATTR(config, 0644, pci_read_config, pci_write_config, 0);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_cistatic struct bin_attribute *pci_dev_config_attrs[] = {
81362306a36Sopenharmony_ci	&bin_attr_config,
81462306a36Sopenharmony_ci	NULL,
81562306a36Sopenharmony_ci};
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_cistatic umode_t pci_dev_config_attr_is_visible(struct kobject *kobj,
81862306a36Sopenharmony_ci					      struct bin_attribute *a, int n)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	a->size = PCI_CFG_SPACE_SIZE;
82362306a36Sopenharmony_ci	if (pdev->cfg_size > PCI_CFG_SPACE_SIZE)
82462306a36Sopenharmony_ci		a->size = PCI_CFG_SPACE_EXP_SIZE;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	return a->attr.mode;
82762306a36Sopenharmony_ci}
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_cistatic const struct attribute_group pci_dev_config_attr_group = {
83062306a36Sopenharmony_ci	.bin_attrs = pci_dev_config_attrs,
83162306a36Sopenharmony_ci	.is_bin_visible = pci_dev_config_attr_is_visible,
83262306a36Sopenharmony_ci};
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci#ifdef HAVE_PCI_LEGACY
83562306a36Sopenharmony_ci/**
83662306a36Sopenharmony_ci * pci_read_legacy_io - read byte(s) from legacy I/O port space
83762306a36Sopenharmony_ci * @filp: open sysfs file
83862306a36Sopenharmony_ci * @kobj: kobject corresponding to file to read from
83962306a36Sopenharmony_ci * @bin_attr: struct bin_attribute for this file
84062306a36Sopenharmony_ci * @buf: buffer to store results
84162306a36Sopenharmony_ci * @off: offset into legacy I/O port space
84262306a36Sopenharmony_ci * @count: number of bytes to read
84362306a36Sopenharmony_ci *
84462306a36Sopenharmony_ci * Reads 1, 2, or 4 bytes from legacy I/O port space using an arch specific
84562306a36Sopenharmony_ci * callback routine (pci_legacy_read).
84662306a36Sopenharmony_ci */
84762306a36Sopenharmony_cistatic ssize_t pci_read_legacy_io(struct file *filp, struct kobject *kobj,
84862306a36Sopenharmony_ci				  struct bin_attribute *bin_attr, char *buf,
84962306a36Sopenharmony_ci				  loff_t off, size_t count)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	/* Only support 1, 2 or 4 byte accesses */
85462306a36Sopenharmony_ci	if (count != 1 && count != 2 && count != 4)
85562306a36Sopenharmony_ci		return -EINVAL;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	return pci_legacy_read(bus, off, (u32 *)buf, count);
85862306a36Sopenharmony_ci}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci/**
86162306a36Sopenharmony_ci * pci_write_legacy_io - write byte(s) to legacy I/O port space
86262306a36Sopenharmony_ci * @filp: open sysfs file
86362306a36Sopenharmony_ci * @kobj: kobject corresponding to file to read from
86462306a36Sopenharmony_ci * @bin_attr: struct bin_attribute for this file
86562306a36Sopenharmony_ci * @buf: buffer containing value to be written
86662306a36Sopenharmony_ci * @off: offset into legacy I/O port space
86762306a36Sopenharmony_ci * @count: number of bytes to write
86862306a36Sopenharmony_ci *
86962306a36Sopenharmony_ci * Writes 1, 2, or 4 bytes from legacy I/O port space using an arch specific
87062306a36Sopenharmony_ci * callback routine (pci_legacy_write).
87162306a36Sopenharmony_ci */
87262306a36Sopenharmony_cistatic ssize_t pci_write_legacy_io(struct file *filp, struct kobject *kobj,
87362306a36Sopenharmony_ci				   struct bin_attribute *bin_attr, char *buf,
87462306a36Sopenharmony_ci				   loff_t off, size_t count)
87562306a36Sopenharmony_ci{
87662306a36Sopenharmony_ci	struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	/* Only support 1, 2 or 4 byte accesses */
87962306a36Sopenharmony_ci	if (count != 1 && count != 2 && count != 4)
88062306a36Sopenharmony_ci		return -EINVAL;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	return pci_legacy_write(bus, off, *(u32 *)buf, count);
88362306a36Sopenharmony_ci}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci/**
88662306a36Sopenharmony_ci * pci_mmap_legacy_mem - map legacy PCI memory into user memory space
88762306a36Sopenharmony_ci * @filp: open sysfs file
88862306a36Sopenharmony_ci * @kobj: kobject corresponding to device to be mapped
88962306a36Sopenharmony_ci * @attr: struct bin_attribute for this file
89062306a36Sopenharmony_ci * @vma: struct vm_area_struct passed to mmap
89162306a36Sopenharmony_ci *
89262306a36Sopenharmony_ci * Uses an arch specific callback, pci_mmap_legacy_mem_page_range, to mmap
89362306a36Sopenharmony_ci * legacy memory space (first meg of bus space) into application virtual
89462306a36Sopenharmony_ci * memory space.
89562306a36Sopenharmony_ci */
89662306a36Sopenharmony_cistatic int pci_mmap_legacy_mem(struct file *filp, struct kobject *kobj,
89762306a36Sopenharmony_ci			       struct bin_attribute *attr,
89862306a36Sopenharmony_ci			       struct vm_area_struct *vma)
89962306a36Sopenharmony_ci{
90062306a36Sopenharmony_ci	struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	return pci_mmap_legacy_page_range(bus, vma, pci_mmap_mem);
90362306a36Sopenharmony_ci}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci/**
90662306a36Sopenharmony_ci * pci_mmap_legacy_io - map legacy PCI IO into user memory space
90762306a36Sopenharmony_ci * @filp: open sysfs file
90862306a36Sopenharmony_ci * @kobj: kobject corresponding to device to be mapped
90962306a36Sopenharmony_ci * @attr: struct bin_attribute for this file
91062306a36Sopenharmony_ci * @vma: struct vm_area_struct passed to mmap
91162306a36Sopenharmony_ci *
91262306a36Sopenharmony_ci * Uses an arch specific callback, pci_mmap_legacy_io_page_range, to mmap
91362306a36Sopenharmony_ci * legacy IO space (first meg of bus space) into application virtual
91462306a36Sopenharmony_ci * memory space. Returns -ENOSYS if the operation isn't supported
91562306a36Sopenharmony_ci */
91662306a36Sopenharmony_cistatic int pci_mmap_legacy_io(struct file *filp, struct kobject *kobj,
91762306a36Sopenharmony_ci			      struct bin_attribute *attr,
91862306a36Sopenharmony_ci			      struct vm_area_struct *vma)
91962306a36Sopenharmony_ci{
92062306a36Sopenharmony_ci	struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	return pci_mmap_legacy_page_range(bus, vma, pci_mmap_io);
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci/**
92662306a36Sopenharmony_ci * pci_adjust_legacy_attr - adjustment of legacy file attributes
92762306a36Sopenharmony_ci * @b: bus to create files under
92862306a36Sopenharmony_ci * @mmap_type: I/O port or memory
92962306a36Sopenharmony_ci *
93062306a36Sopenharmony_ci * Stub implementation. Can be overridden by arch if necessary.
93162306a36Sopenharmony_ci */
93262306a36Sopenharmony_civoid __weak pci_adjust_legacy_attr(struct pci_bus *b,
93362306a36Sopenharmony_ci				   enum pci_mmap_state mmap_type)
93462306a36Sopenharmony_ci{
93562306a36Sopenharmony_ci}
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci/**
93862306a36Sopenharmony_ci * pci_create_legacy_files - create legacy I/O port and memory files
93962306a36Sopenharmony_ci * @b: bus to create files under
94062306a36Sopenharmony_ci *
94162306a36Sopenharmony_ci * Some platforms allow access to legacy I/O port and ISA memory space on
94262306a36Sopenharmony_ci * a per-bus basis.  This routine creates the files and ties them into
94362306a36Sopenharmony_ci * their associated read, write and mmap files from pci-sysfs.c
94462306a36Sopenharmony_ci *
94562306a36Sopenharmony_ci * On error unwind, but don't propagate the error to the caller
94662306a36Sopenharmony_ci * as it is ok to set up the PCI bus without these files.
94762306a36Sopenharmony_ci */
94862306a36Sopenharmony_civoid pci_create_legacy_files(struct pci_bus *b)
94962306a36Sopenharmony_ci{
95062306a36Sopenharmony_ci	int error;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	if (!sysfs_initialized)
95362306a36Sopenharmony_ci		return;
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	b->legacy_io = kcalloc(2, sizeof(struct bin_attribute),
95662306a36Sopenharmony_ci			       GFP_ATOMIC);
95762306a36Sopenharmony_ci	if (!b->legacy_io)
95862306a36Sopenharmony_ci		goto kzalloc_err;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	sysfs_bin_attr_init(b->legacy_io);
96162306a36Sopenharmony_ci	b->legacy_io->attr.name = "legacy_io";
96262306a36Sopenharmony_ci	b->legacy_io->size = 0xffff;
96362306a36Sopenharmony_ci	b->legacy_io->attr.mode = 0600;
96462306a36Sopenharmony_ci	b->legacy_io->read = pci_read_legacy_io;
96562306a36Sopenharmony_ci	b->legacy_io->write = pci_write_legacy_io;
96662306a36Sopenharmony_ci	b->legacy_io->mmap = pci_mmap_legacy_io;
96762306a36Sopenharmony_ci	b->legacy_io->f_mapping = iomem_get_mapping;
96862306a36Sopenharmony_ci	pci_adjust_legacy_attr(b, pci_mmap_io);
96962306a36Sopenharmony_ci	error = device_create_bin_file(&b->dev, b->legacy_io);
97062306a36Sopenharmony_ci	if (error)
97162306a36Sopenharmony_ci		goto legacy_io_err;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	/* Allocated above after the legacy_io struct */
97462306a36Sopenharmony_ci	b->legacy_mem = b->legacy_io + 1;
97562306a36Sopenharmony_ci	sysfs_bin_attr_init(b->legacy_mem);
97662306a36Sopenharmony_ci	b->legacy_mem->attr.name = "legacy_mem";
97762306a36Sopenharmony_ci	b->legacy_mem->size = 1024*1024;
97862306a36Sopenharmony_ci	b->legacy_mem->attr.mode = 0600;
97962306a36Sopenharmony_ci	b->legacy_mem->mmap = pci_mmap_legacy_mem;
98062306a36Sopenharmony_ci	b->legacy_mem->f_mapping = iomem_get_mapping;
98162306a36Sopenharmony_ci	pci_adjust_legacy_attr(b, pci_mmap_mem);
98262306a36Sopenharmony_ci	error = device_create_bin_file(&b->dev, b->legacy_mem);
98362306a36Sopenharmony_ci	if (error)
98462306a36Sopenharmony_ci		goto legacy_mem_err;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	return;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_cilegacy_mem_err:
98962306a36Sopenharmony_ci	device_remove_bin_file(&b->dev, b->legacy_io);
99062306a36Sopenharmony_cilegacy_io_err:
99162306a36Sopenharmony_ci	kfree(b->legacy_io);
99262306a36Sopenharmony_ci	b->legacy_io = NULL;
99362306a36Sopenharmony_cikzalloc_err:
99462306a36Sopenharmony_ci	dev_warn(&b->dev, "could not create legacy I/O port and ISA memory resources in sysfs\n");
99562306a36Sopenharmony_ci}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_civoid pci_remove_legacy_files(struct pci_bus *b)
99862306a36Sopenharmony_ci{
99962306a36Sopenharmony_ci	if (b->legacy_io) {
100062306a36Sopenharmony_ci		device_remove_bin_file(&b->dev, b->legacy_io);
100162306a36Sopenharmony_ci		device_remove_bin_file(&b->dev, b->legacy_mem);
100262306a36Sopenharmony_ci		kfree(b->legacy_io); /* both are allocated here */
100362306a36Sopenharmony_ci	}
100462306a36Sopenharmony_ci}
100562306a36Sopenharmony_ci#endif /* HAVE_PCI_LEGACY */
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci#if defined(HAVE_PCI_MMAP) || defined(ARCH_GENERIC_PCI_MMAP_RESOURCE)
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ciint pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma,
101062306a36Sopenharmony_ci		  enum pci_mmap_api mmap_api)
101162306a36Sopenharmony_ci{
101262306a36Sopenharmony_ci	unsigned long nr, start, size;
101362306a36Sopenharmony_ci	resource_size_t pci_start = 0, pci_end;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	if (pci_resource_len(pdev, resno) == 0)
101662306a36Sopenharmony_ci		return 0;
101762306a36Sopenharmony_ci	nr = vma_pages(vma);
101862306a36Sopenharmony_ci	start = vma->vm_pgoff;
101962306a36Sopenharmony_ci	size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1;
102062306a36Sopenharmony_ci	if (mmap_api == PCI_MMAP_PROCFS) {
102162306a36Sopenharmony_ci		pci_resource_to_user(pdev, resno, &pdev->resource[resno],
102262306a36Sopenharmony_ci				     &pci_start, &pci_end);
102362306a36Sopenharmony_ci		pci_start >>= PAGE_SHIFT;
102462306a36Sopenharmony_ci	}
102562306a36Sopenharmony_ci	if (start >= pci_start && start < pci_start + size &&
102662306a36Sopenharmony_ci			start + nr <= pci_start + size)
102762306a36Sopenharmony_ci		return 1;
102862306a36Sopenharmony_ci	return 0;
102962306a36Sopenharmony_ci}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci/**
103262306a36Sopenharmony_ci * pci_mmap_resource - map a PCI resource into user memory space
103362306a36Sopenharmony_ci * @kobj: kobject for mapping
103462306a36Sopenharmony_ci * @attr: struct bin_attribute for the file being mapped
103562306a36Sopenharmony_ci * @vma: struct vm_area_struct passed into the mmap
103662306a36Sopenharmony_ci * @write_combine: 1 for write_combine mapping
103762306a36Sopenharmony_ci *
103862306a36Sopenharmony_ci * Use the regular PCI mapping routines to map a PCI resource into userspace.
103962306a36Sopenharmony_ci */
104062306a36Sopenharmony_cistatic int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
104162306a36Sopenharmony_ci			     struct vm_area_struct *vma, int write_combine)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
104462306a36Sopenharmony_ci	int bar = (unsigned long)attr->private;
104562306a36Sopenharmony_ci	enum pci_mmap_state mmap_type;
104662306a36Sopenharmony_ci	struct resource *res = &pdev->resource[bar];
104762306a36Sopenharmony_ci	int ret;
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	ret = security_locked_down(LOCKDOWN_PCI_ACCESS);
105062306a36Sopenharmony_ci	if (ret)
105162306a36Sopenharmony_ci		return ret;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start))
105462306a36Sopenharmony_ci		return -EINVAL;
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	if (!pci_mmap_fits(pdev, bar, vma, PCI_MMAP_SYSFS))
105762306a36Sopenharmony_ci		return -EINVAL;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	return pci_mmap_resource_range(pdev, bar, vma, mmap_type, write_combine);
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_cistatic int pci_mmap_resource_uc(struct file *filp, struct kobject *kobj,
106562306a36Sopenharmony_ci				struct bin_attribute *attr,
106662306a36Sopenharmony_ci				struct vm_area_struct *vma)
106762306a36Sopenharmony_ci{
106862306a36Sopenharmony_ci	return pci_mmap_resource(kobj, attr, vma, 0);
106962306a36Sopenharmony_ci}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_cistatic int pci_mmap_resource_wc(struct file *filp, struct kobject *kobj,
107262306a36Sopenharmony_ci				struct bin_attribute *attr,
107362306a36Sopenharmony_ci				struct vm_area_struct *vma)
107462306a36Sopenharmony_ci{
107562306a36Sopenharmony_ci	return pci_mmap_resource(kobj, attr, vma, 1);
107662306a36Sopenharmony_ci}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_cistatic ssize_t pci_resource_io(struct file *filp, struct kobject *kobj,
107962306a36Sopenharmony_ci			       struct bin_attribute *attr, char *buf,
108062306a36Sopenharmony_ci			       loff_t off, size_t count, bool write)
108162306a36Sopenharmony_ci{
108262306a36Sopenharmony_ci#ifdef CONFIG_HAS_IOPORT
108362306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
108462306a36Sopenharmony_ci	int bar = (unsigned long)attr->private;
108562306a36Sopenharmony_ci	unsigned long port = off;
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	port += pci_resource_start(pdev, bar);
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	if (port > pci_resource_end(pdev, bar))
109062306a36Sopenharmony_ci		return 0;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	if (port + count - 1 > pci_resource_end(pdev, bar))
109362306a36Sopenharmony_ci		return -EINVAL;
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	switch (count) {
109662306a36Sopenharmony_ci	case 1:
109762306a36Sopenharmony_ci		if (write)
109862306a36Sopenharmony_ci			outb(*(u8 *)buf, port);
109962306a36Sopenharmony_ci		else
110062306a36Sopenharmony_ci			*(u8 *)buf = inb(port);
110162306a36Sopenharmony_ci		return 1;
110262306a36Sopenharmony_ci	case 2:
110362306a36Sopenharmony_ci		if (write)
110462306a36Sopenharmony_ci			outw(*(u16 *)buf, port);
110562306a36Sopenharmony_ci		else
110662306a36Sopenharmony_ci			*(u16 *)buf = inw(port);
110762306a36Sopenharmony_ci		return 2;
110862306a36Sopenharmony_ci	case 4:
110962306a36Sopenharmony_ci		if (write)
111062306a36Sopenharmony_ci			outl(*(u32 *)buf, port);
111162306a36Sopenharmony_ci		else
111262306a36Sopenharmony_ci			*(u32 *)buf = inl(port);
111362306a36Sopenharmony_ci		return 4;
111462306a36Sopenharmony_ci	}
111562306a36Sopenharmony_ci	return -EINVAL;
111662306a36Sopenharmony_ci#else
111762306a36Sopenharmony_ci	return -ENXIO;
111862306a36Sopenharmony_ci#endif
111962306a36Sopenharmony_ci}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_cistatic ssize_t pci_read_resource_io(struct file *filp, struct kobject *kobj,
112262306a36Sopenharmony_ci				    struct bin_attribute *attr, char *buf,
112362306a36Sopenharmony_ci				    loff_t off, size_t count)
112462306a36Sopenharmony_ci{
112562306a36Sopenharmony_ci	return pci_resource_io(filp, kobj, attr, buf, off, count, false);
112662306a36Sopenharmony_ci}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_cistatic ssize_t pci_write_resource_io(struct file *filp, struct kobject *kobj,
112962306a36Sopenharmony_ci				     struct bin_attribute *attr, char *buf,
113062306a36Sopenharmony_ci				     loff_t off, size_t count)
113162306a36Sopenharmony_ci{
113262306a36Sopenharmony_ci	int ret;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	ret = security_locked_down(LOCKDOWN_PCI_ACCESS);
113562306a36Sopenharmony_ci	if (ret)
113662306a36Sopenharmony_ci		return ret;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	return pci_resource_io(filp, kobj, attr, buf, off, count, true);
113962306a36Sopenharmony_ci}
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci/**
114262306a36Sopenharmony_ci * pci_remove_resource_files - cleanup resource files
114362306a36Sopenharmony_ci * @pdev: dev to cleanup
114462306a36Sopenharmony_ci *
114562306a36Sopenharmony_ci * If we created resource files for @pdev, remove them from sysfs and
114662306a36Sopenharmony_ci * free their resources.
114762306a36Sopenharmony_ci */
114862306a36Sopenharmony_cistatic void pci_remove_resource_files(struct pci_dev *pdev)
114962306a36Sopenharmony_ci{
115062306a36Sopenharmony_ci	int i;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
115362306a36Sopenharmony_ci		struct bin_attribute *res_attr;
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci		res_attr = pdev->res_attr[i];
115662306a36Sopenharmony_ci		if (res_attr) {
115762306a36Sopenharmony_ci			sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
115862306a36Sopenharmony_ci			kfree(res_attr);
115962306a36Sopenharmony_ci		}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci		res_attr = pdev->res_attr_wc[i];
116262306a36Sopenharmony_ci		if (res_attr) {
116362306a36Sopenharmony_ci			sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
116462306a36Sopenharmony_ci			kfree(res_attr);
116562306a36Sopenharmony_ci		}
116662306a36Sopenharmony_ci	}
116762306a36Sopenharmony_ci}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_cistatic int pci_create_attr(struct pci_dev *pdev, int num, int write_combine)
117062306a36Sopenharmony_ci{
117162306a36Sopenharmony_ci	/* allocate attribute structure, piggyback attribute name */
117262306a36Sopenharmony_ci	int name_len = write_combine ? 13 : 10;
117362306a36Sopenharmony_ci	struct bin_attribute *res_attr;
117462306a36Sopenharmony_ci	char *res_attr_name;
117562306a36Sopenharmony_ci	int retval;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	res_attr = kzalloc(sizeof(*res_attr) + name_len, GFP_ATOMIC);
117862306a36Sopenharmony_ci	if (!res_attr)
117962306a36Sopenharmony_ci		return -ENOMEM;
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	res_attr_name = (char *)(res_attr + 1);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	sysfs_bin_attr_init(res_attr);
118462306a36Sopenharmony_ci	if (write_combine) {
118562306a36Sopenharmony_ci		sprintf(res_attr_name, "resource%d_wc", num);
118662306a36Sopenharmony_ci		res_attr->mmap = pci_mmap_resource_wc;
118762306a36Sopenharmony_ci	} else {
118862306a36Sopenharmony_ci		sprintf(res_attr_name, "resource%d", num);
118962306a36Sopenharmony_ci		if (pci_resource_flags(pdev, num) & IORESOURCE_IO) {
119062306a36Sopenharmony_ci			res_attr->read = pci_read_resource_io;
119162306a36Sopenharmony_ci			res_attr->write = pci_write_resource_io;
119262306a36Sopenharmony_ci			if (arch_can_pci_mmap_io())
119362306a36Sopenharmony_ci				res_attr->mmap = pci_mmap_resource_uc;
119462306a36Sopenharmony_ci		} else {
119562306a36Sopenharmony_ci			res_attr->mmap = pci_mmap_resource_uc;
119662306a36Sopenharmony_ci		}
119762306a36Sopenharmony_ci	}
119862306a36Sopenharmony_ci	if (res_attr->mmap)
119962306a36Sopenharmony_ci		res_attr->f_mapping = iomem_get_mapping;
120062306a36Sopenharmony_ci	res_attr->attr.name = res_attr_name;
120162306a36Sopenharmony_ci	res_attr->attr.mode = 0600;
120262306a36Sopenharmony_ci	res_attr->size = pci_resource_len(pdev, num);
120362306a36Sopenharmony_ci	res_attr->private = (void *)(unsigned long)num;
120462306a36Sopenharmony_ci	retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
120562306a36Sopenharmony_ci	if (retval) {
120662306a36Sopenharmony_ci		kfree(res_attr);
120762306a36Sopenharmony_ci		return retval;
120862306a36Sopenharmony_ci	}
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	if (write_combine)
121162306a36Sopenharmony_ci		pdev->res_attr_wc[num] = res_attr;
121262306a36Sopenharmony_ci	else
121362306a36Sopenharmony_ci		pdev->res_attr[num] = res_attr;
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	return 0;
121662306a36Sopenharmony_ci}
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci/**
121962306a36Sopenharmony_ci * pci_create_resource_files - create resource files in sysfs for @dev
122062306a36Sopenharmony_ci * @pdev: dev in question
122162306a36Sopenharmony_ci *
122262306a36Sopenharmony_ci * Walk the resources in @pdev creating files for each resource available.
122362306a36Sopenharmony_ci */
122462306a36Sopenharmony_cistatic int pci_create_resource_files(struct pci_dev *pdev)
122562306a36Sopenharmony_ci{
122662306a36Sopenharmony_ci	int i;
122762306a36Sopenharmony_ci	int retval;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	/* Expose the PCI resources from this device as files */
123062306a36Sopenharmony_ci	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci		/* skip empty resources */
123362306a36Sopenharmony_ci		if (!pci_resource_len(pdev, i))
123462306a36Sopenharmony_ci			continue;
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci		retval = pci_create_attr(pdev, i, 0);
123762306a36Sopenharmony_ci		/* for prefetchable resources, create a WC mappable file */
123862306a36Sopenharmony_ci		if (!retval && arch_can_pci_mmap_wc() &&
123962306a36Sopenharmony_ci		    pdev->resource[i].flags & IORESOURCE_PREFETCH)
124062306a36Sopenharmony_ci			retval = pci_create_attr(pdev, i, 1);
124162306a36Sopenharmony_ci		if (retval) {
124262306a36Sopenharmony_ci			pci_remove_resource_files(pdev);
124362306a36Sopenharmony_ci			return retval;
124462306a36Sopenharmony_ci		}
124562306a36Sopenharmony_ci	}
124662306a36Sopenharmony_ci	return 0;
124762306a36Sopenharmony_ci}
124862306a36Sopenharmony_ci#else /* !(defined(HAVE_PCI_MMAP) || defined(ARCH_GENERIC_PCI_MMAP_RESOURCE)) */
124962306a36Sopenharmony_ciint __weak pci_create_resource_files(struct pci_dev *dev) { return 0; }
125062306a36Sopenharmony_civoid __weak pci_remove_resource_files(struct pci_dev *dev) { return; }
125162306a36Sopenharmony_ci#endif
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci/**
125462306a36Sopenharmony_ci * pci_write_rom - used to enable access to the PCI ROM display
125562306a36Sopenharmony_ci * @filp: sysfs file
125662306a36Sopenharmony_ci * @kobj: kernel object handle
125762306a36Sopenharmony_ci * @bin_attr: struct bin_attribute for this file
125862306a36Sopenharmony_ci * @buf: user input
125962306a36Sopenharmony_ci * @off: file offset
126062306a36Sopenharmony_ci * @count: number of byte in input
126162306a36Sopenharmony_ci *
126262306a36Sopenharmony_ci * writing anything except 0 enables it
126362306a36Sopenharmony_ci */
126462306a36Sopenharmony_cistatic ssize_t pci_write_rom(struct file *filp, struct kobject *kobj,
126562306a36Sopenharmony_ci			     struct bin_attribute *bin_attr, char *buf,
126662306a36Sopenharmony_ci			     loff_t off, size_t count)
126762306a36Sopenharmony_ci{
126862306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	if ((off ==  0) && (*buf == '0') && (count == 2))
127162306a36Sopenharmony_ci		pdev->rom_attr_enabled = 0;
127262306a36Sopenharmony_ci	else
127362306a36Sopenharmony_ci		pdev->rom_attr_enabled = 1;
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	return count;
127662306a36Sopenharmony_ci}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci/**
127962306a36Sopenharmony_ci * pci_read_rom - read a PCI ROM
128062306a36Sopenharmony_ci * @filp: sysfs file
128162306a36Sopenharmony_ci * @kobj: kernel object handle
128262306a36Sopenharmony_ci * @bin_attr: struct bin_attribute for this file
128362306a36Sopenharmony_ci * @buf: where to put the data we read from the ROM
128462306a36Sopenharmony_ci * @off: file offset
128562306a36Sopenharmony_ci * @count: number of bytes to read
128662306a36Sopenharmony_ci *
128762306a36Sopenharmony_ci * Put @count bytes starting at @off into @buf from the ROM in the PCI
128862306a36Sopenharmony_ci * device corresponding to @kobj.
128962306a36Sopenharmony_ci */
129062306a36Sopenharmony_cistatic ssize_t pci_read_rom(struct file *filp, struct kobject *kobj,
129162306a36Sopenharmony_ci			    struct bin_attribute *bin_attr, char *buf,
129262306a36Sopenharmony_ci			    loff_t off, size_t count)
129362306a36Sopenharmony_ci{
129462306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
129562306a36Sopenharmony_ci	void __iomem *rom;
129662306a36Sopenharmony_ci	size_t size;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	if (!pdev->rom_attr_enabled)
129962306a36Sopenharmony_ci		return -EINVAL;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	rom = pci_map_rom(pdev, &size);	/* size starts out as PCI window size */
130262306a36Sopenharmony_ci	if (!rom || !size)
130362306a36Sopenharmony_ci		return -EIO;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	if (off >= size)
130662306a36Sopenharmony_ci		count = 0;
130762306a36Sopenharmony_ci	else {
130862306a36Sopenharmony_ci		if (off + count > size)
130962306a36Sopenharmony_ci			count = size - off;
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci		memcpy_fromio(buf, rom + off, count);
131262306a36Sopenharmony_ci	}
131362306a36Sopenharmony_ci	pci_unmap_rom(pdev, rom);
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	return count;
131662306a36Sopenharmony_ci}
131762306a36Sopenharmony_cistatic BIN_ATTR(rom, 0600, pci_read_rom, pci_write_rom, 0);
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_cistatic struct bin_attribute *pci_dev_rom_attrs[] = {
132062306a36Sopenharmony_ci	&bin_attr_rom,
132162306a36Sopenharmony_ci	NULL,
132262306a36Sopenharmony_ci};
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_cistatic umode_t pci_dev_rom_attr_is_visible(struct kobject *kobj,
132562306a36Sopenharmony_ci					   struct bin_attribute *a, int n)
132662306a36Sopenharmony_ci{
132762306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
132862306a36Sopenharmony_ci	size_t rom_size;
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	/* If the device has a ROM, try to expose it in sysfs. */
133162306a36Sopenharmony_ci	rom_size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
133262306a36Sopenharmony_ci	if (!rom_size)
133362306a36Sopenharmony_ci		return 0;
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	a->size = rom_size;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	return a->attr.mode;
133862306a36Sopenharmony_ci}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_cistatic const struct attribute_group pci_dev_rom_attr_group = {
134162306a36Sopenharmony_ci	.bin_attrs = pci_dev_rom_attrs,
134262306a36Sopenharmony_ci	.is_bin_visible = pci_dev_rom_attr_is_visible,
134362306a36Sopenharmony_ci};
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_cistatic ssize_t reset_store(struct device *dev, struct device_attribute *attr,
134662306a36Sopenharmony_ci			   const char *buf, size_t count)
134762306a36Sopenharmony_ci{
134862306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
134962306a36Sopenharmony_ci	unsigned long val;
135062306a36Sopenharmony_ci	ssize_t result;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	if (kstrtoul(buf, 0, &val) < 0)
135362306a36Sopenharmony_ci		return -EINVAL;
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	if (val != 1)
135662306a36Sopenharmony_ci		return -EINVAL;
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	pm_runtime_get_sync(dev);
135962306a36Sopenharmony_ci	result = pci_reset_function(pdev);
136062306a36Sopenharmony_ci	pm_runtime_put(dev);
136162306a36Sopenharmony_ci	if (result < 0)
136262306a36Sopenharmony_ci		return result;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	return count;
136562306a36Sopenharmony_ci}
136662306a36Sopenharmony_cistatic DEVICE_ATTR_WO(reset);
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_cistatic struct attribute *pci_dev_reset_attrs[] = {
136962306a36Sopenharmony_ci	&dev_attr_reset.attr,
137062306a36Sopenharmony_ci	NULL,
137162306a36Sopenharmony_ci};
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_cistatic umode_t pci_dev_reset_attr_is_visible(struct kobject *kobj,
137462306a36Sopenharmony_ci					     struct attribute *a, int n)
137562306a36Sopenharmony_ci{
137662306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	if (!pci_reset_supported(pdev))
137962306a36Sopenharmony_ci		return 0;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	return a->mode;
138262306a36Sopenharmony_ci}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_cistatic const struct attribute_group pci_dev_reset_attr_group = {
138562306a36Sopenharmony_ci	.attrs = pci_dev_reset_attrs,
138662306a36Sopenharmony_ci	.is_visible = pci_dev_reset_attr_is_visible,
138762306a36Sopenharmony_ci};
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci#define pci_dev_resource_resize_attr(n)					\
139062306a36Sopenharmony_cistatic ssize_t resource##n##_resize_show(struct device *dev,		\
139162306a36Sopenharmony_ci					 struct device_attribute *attr,	\
139262306a36Sopenharmony_ci					 char * buf)			\
139362306a36Sopenharmony_ci{									\
139462306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);				\
139562306a36Sopenharmony_ci	ssize_t ret;							\
139662306a36Sopenharmony_ci									\
139762306a36Sopenharmony_ci	pci_config_pm_runtime_get(pdev);				\
139862306a36Sopenharmony_ci									\
139962306a36Sopenharmony_ci	ret = sysfs_emit(buf, "%016llx\n",				\
140062306a36Sopenharmony_ci			 (u64)pci_rebar_get_possible_sizes(pdev, n));	\
140162306a36Sopenharmony_ci									\
140262306a36Sopenharmony_ci	pci_config_pm_runtime_put(pdev);				\
140362306a36Sopenharmony_ci									\
140462306a36Sopenharmony_ci	return ret;							\
140562306a36Sopenharmony_ci}									\
140662306a36Sopenharmony_ci									\
140762306a36Sopenharmony_cistatic ssize_t resource##n##_resize_store(struct device *dev,		\
140862306a36Sopenharmony_ci					  struct device_attribute *attr,\
140962306a36Sopenharmony_ci					  const char *buf, size_t count)\
141062306a36Sopenharmony_ci{									\
141162306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);				\
141262306a36Sopenharmony_ci	unsigned long size, flags;					\
141362306a36Sopenharmony_ci	int ret, i;							\
141462306a36Sopenharmony_ci	u16 cmd;							\
141562306a36Sopenharmony_ci									\
141662306a36Sopenharmony_ci	if (kstrtoul(buf, 0, &size) < 0)				\
141762306a36Sopenharmony_ci		return -EINVAL;						\
141862306a36Sopenharmony_ci									\
141962306a36Sopenharmony_ci	device_lock(dev);						\
142062306a36Sopenharmony_ci	if (dev->driver) {						\
142162306a36Sopenharmony_ci		ret = -EBUSY;						\
142262306a36Sopenharmony_ci		goto unlock;						\
142362306a36Sopenharmony_ci	}								\
142462306a36Sopenharmony_ci									\
142562306a36Sopenharmony_ci	pci_config_pm_runtime_get(pdev);				\
142662306a36Sopenharmony_ci									\
142762306a36Sopenharmony_ci	if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {		\
142862306a36Sopenharmony_ci		ret = aperture_remove_conflicting_pci_devices(pdev,	\
142962306a36Sopenharmony_ci						"resourceN_resize");	\
143062306a36Sopenharmony_ci		if (ret)						\
143162306a36Sopenharmony_ci			goto pm_put;					\
143262306a36Sopenharmony_ci	}								\
143362306a36Sopenharmony_ci									\
143462306a36Sopenharmony_ci	pci_read_config_word(pdev, PCI_COMMAND, &cmd);			\
143562306a36Sopenharmony_ci	pci_write_config_word(pdev, PCI_COMMAND,			\
143662306a36Sopenharmony_ci			      cmd & ~PCI_COMMAND_MEMORY);		\
143762306a36Sopenharmony_ci									\
143862306a36Sopenharmony_ci	flags = pci_resource_flags(pdev, n);				\
143962306a36Sopenharmony_ci									\
144062306a36Sopenharmony_ci	pci_remove_resource_files(pdev);				\
144162306a36Sopenharmony_ci									\
144262306a36Sopenharmony_ci	for (i = 0; i < PCI_STD_NUM_BARS; i++) {			\
144362306a36Sopenharmony_ci		if (pci_resource_len(pdev, i) &&			\
144462306a36Sopenharmony_ci		    pci_resource_flags(pdev, i) == flags)		\
144562306a36Sopenharmony_ci			pci_release_resource(pdev, i);			\
144662306a36Sopenharmony_ci	}								\
144762306a36Sopenharmony_ci									\
144862306a36Sopenharmony_ci	ret = pci_resize_resource(pdev, n, size);			\
144962306a36Sopenharmony_ci									\
145062306a36Sopenharmony_ci	pci_assign_unassigned_bus_resources(pdev->bus);			\
145162306a36Sopenharmony_ci									\
145262306a36Sopenharmony_ci	if (pci_create_resource_files(pdev))				\
145362306a36Sopenharmony_ci		pci_warn(pdev, "Failed to recreate resource files after BAR resizing\n");\
145462306a36Sopenharmony_ci									\
145562306a36Sopenharmony_ci	pci_write_config_word(pdev, PCI_COMMAND, cmd);			\
145662306a36Sopenharmony_cipm_put:									\
145762306a36Sopenharmony_ci	pci_config_pm_runtime_put(pdev);				\
145862306a36Sopenharmony_ciunlock:									\
145962306a36Sopenharmony_ci	device_unlock(dev);						\
146062306a36Sopenharmony_ci									\
146162306a36Sopenharmony_ci	return ret ? ret : count;					\
146262306a36Sopenharmony_ci}									\
146362306a36Sopenharmony_cistatic DEVICE_ATTR_RW(resource##n##_resize)
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_cipci_dev_resource_resize_attr(0);
146662306a36Sopenharmony_cipci_dev_resource_resize_attr(1);
146762306a36Sopenharmony_cipci_dev_resource_resize_attr(2);
146862306a36Sopenharmony_cipci_dev_resource_resize_attr(3);
146962306a36Sopenharmony_cipci_dev_resource_resize_attr(4);
147062306a36Sopenharmony_cipci_dev_resource_resize_attr(5);
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_cistatic struct attribute *resource_resize_attrs[] = {
147362306a36Sopenharmony_ci	&dev_attr_resource0_resize.attr,
147462306a36Sopenharmony_ci	&dev_attr_resource1_resize.attr,
147562306a36Sopenharmony_ci	&dev_attr_resource2_resize.attr,
147662306a36Sopenharmony_ci	&dev_attr_resource3_resize.attr,
147762306a36Sopenharmony_ci	&dev_attr_resource4_resize.attr,
147862306a36Sopenharmony_ci	&dev_attr_resource5_resize.attr,
147962306a36Sopenharmony_ci	NULL,
148062306a36Sopenharmony_ci};
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_cistatic umode_t resource_resize_is_visible(struct kobject *kobj,
148362306a36Sopenharmony_ci					  struct attribute *a, int n)
148462306a36Sopenharmony_ci{
148562306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	return pci_rebar_get_current_size(pdev, n) < 0 ? 0 : a->mode;
148862306a36Sopenharmony_ci}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_cistatic const struct attribute_group pci_dev_resource_resize_group = {
149162306a36Sopenharmony_ci	.attrs = resource_resize_attrs,
149262306a36Sopenharmony_ci	.is_visible = resource_resize_is_visible,
149362306a36Sopenharmony_ci};
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ciint __must_check pci_create_sysfs_dev_files(struct pci_dev *pdev)
149662306a36Sopenharmony_ci{
149762306a36Sopenharmony_ci	if (!sysfs_initialized)
149862306a36Sopenharmony_ci		return -EACCES;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	return pci_create_resource_files(pdev);
150162306a36Sopenharmony_ci}
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci/**
150462306a36Sopenharmony_ci * pci_remove_sysfs_dev_files - cleanup PCI specific sysfs files
150562306a36Sopenharmony_ci * @pdev: device whose entries we should free
150662306a36Sopenharmony_ci *
150762306a36Sopenharmony_ci * Cleanup when @pdev is removed from sysfs.
150862306a36Sopenharmony_ci */
150962306a36Sopenharmony_civoid pci_remove_sysfs_dev_files(struct pci_dev *pdev)
151062306a36Sopenharmony_ci{
151162306a36Sopenharmony_ci	if (!sysfs_initialized)
151262306a36Sopenharmony_ci		return;
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci	pci_remove_resource_files(pdev);
151562306a36Sopenharmony_ci}
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_cistatic int __init pci_sysfs_init(void)
151862306a36Sopenharmony_ci{
151962306a36Sopenharmony_ci	struct pci_dev *pdev = NULL;
152062306a36Sopenharmony_ci	struct pci_bus *pbus = NULL;
152162306a36Sopenharmony_ci	int retval;
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	sysfs_initialized = 1;
152462306a36Sopenharmony_ci	for_each_pci_dev(pdev) {
152562306a36Sopenharmony_ci		retval = pci_create_sysfs_dev_files(pdev);
152662306a36Sopenharmony_ci		if (retval) {
152762306a36Sopenharmony_ci			pci_dev_put(pdev);
152862306a36Sopenharmony_ci			return retval;
152962306a36Sopenharmony_ci		}
153062306a36Sopenharmony_ci	}
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	while ((pbus = pci_find_next_bus(pbus)))
153362306a36Sopenharmony_ci		pci_create_legacy_files(pbus);
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	return 0;
153662306a36Sopenharmony_ci}
153762306a36Sopenharmony_cilate_initcall(pci_sysfs_init);
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_cistatic struct attribute *pci_dev_dev_attrs[] = {
154062306a36Sopenharmony_ci	&dev_attr_boot_vga.attr,
154162306a36Sopenharmony_ci	NULL,
154262306a36Sopenharmony_ci};
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_cistatic umode_t pci_dev_attrs_are_visible(struct kobject *kobj,
154562306a36Sopenharmony_ci					 struct attribute *a, int n)
154662306a36Sopenharmony_ci{
154762306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
154862306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	if (a == &dev_attr_boot_vga.attr)
155162306a36Sopenharmony_ci		if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
155262306a36Sopenharmony_ci			return 0;
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	return a->mode;
155562306a36Sopenharmony_ci}
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_cistatic struct attribute *pci_dev_hp_attrs[] = {
155862306a36Sopenharmony_ci	&dev_attr_remove.attr,
155962306a36Sopenharmony_ci	&dev_attr_dev_rescan.attr,
156062306a36Sopenharmony_ci	NULL,
156162306a36Sopenharmony_ci};
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_cistatic umode_t pci_dev_hp_attrs_are_visible(struct kobject *kobj,
156462306a36Sopenharmony_ci					    struct attribute *a, int n)
156562306a36Sopenharmony_ci{
156662306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
156762306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ci	if (pdev->is_virtfn)
157062306a36Sopenharmony_ci		return 0;
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	return a->mode;
157362306a36Sopenharmony_ci}
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_cistatic umode_t pci_bridge_attrs_are_visible(struct kobject *kobj,
157662306a36Sopenharmony_ci					    struct attribute *a, int n)
157762306a36Sopenharmony_ci{
157862306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
157962306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	if (pci_is_bridge(pdev))
158262306a36Sopenharmony_ci		return a->mode;
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	return 0;
158562306a36Sopenharmony_ci}
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_cistatic umode_t pcie_dev_attrs_are_visible(struct kobject *kobj,
158862306a36Sopenharmony_ci					  struct attribute *a, int n)
158962306a36Sopenharmony_ci{
159062306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
159162306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	if (pci_is_pcie(pdev))
159462306a36Sopenharmony_ci		return a->mode;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	return 0;
159762306a36Sopenharmony_ci}
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_cistatic const struct attribute_group pci_dev_group = {
160062306a36Sopenharmony_ci	.attrs = pci_dev_attrs,
160162306a36Sopenharmony_ci};
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ciconst struct attribute_group *pci_dev_groups[] = {
160462306a36Sopenharmony_ci	&pci_dev_group,
160562306a36Sopenharmony_ci	&pci_dev_config_attr_group,
160662306a36Sopenharmony_ci	&pci_dev_rom_attr_group,
160762306a36Sopenharmony_ci	&pci_dev_reset_attr_group,
160862306a36Sopenharmony_ci	&pci_dev_reset_method_attr_group,
160962306a36Sopenharmony_ci	&pci_dev_vpd_attr_group,
161062306a36Sopenharmony_ci#ifdef CONFIG_DMI
161162306a36Sopenharmony_ci	&pci_dev_smbios_attr_group,
161262306a36Sopenharmony_ci#endif
161362306a36Sopenharmony_ci#ifdef CONFIG_ACPI
161462306a36Sopenharmony_ci	&pci_dev_acpi_attr_group,
161562306a36Sopenharmony_ci#endif
161662306a36Sopenharmony_ci	&pci_dev_resource_resize_group,
161762306a36Sopenharmony_ci	NULL,
161862306a36Sopenharmony_ci};
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_cistatic const struct attribute_group pci_dev_hp_attr_group = {
162162306a36Sopenharmony_ci	.attrs = pci_dev_hp_attrs,
162262306a36Sopenharmony_ci	.is_visible = pci_dev_hp_attrs_are_visible,
162362306a36Sopenharmony_ci};
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_cistatic const struct attribute_group pci_dev_attr_group = {
162662306a36Sopenharmony_ci	.attrs = pci_dev_dev_attrs,
162762306a36Sopenharmony_ci	.is_visible = pci_dev_attrs_are_visible,
162862306a36Sopenharmony_ci};
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_cistatic const struct attribute_group pci_bridge_attr_group = {
163162306a36Sopenharmony_ci	.attrs = pci_bridge_attrs,
163262306a36Sopenharmony_ci	.is_visible = pci_bridge_attrs_are_visible,
163362306a36Sopenharmony_ci};
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_cistatic const struct attribute_group pcie_dev_attr_group = {
163662306a36Sopenharmony_ci	.attrs = pcie_dev_attrs,
163762306a36Sopenharmony_ci	.is_visible = pcie_dev_attrs_are_visible,
163862306a36Sopenharmony_ci};
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_cistatic const struct attribute_group *pci_dev_attr_groups[] = {
164162306a36Sopenharmony_ci	&pci_dev_attr_group,
164262306a36Sopenharmony_ci	&pci_dev_hp_attr_group,
164362306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV
164462306a36Sopenharmony_ci	&sriov_pf_dev_attr_group,
164562306a36Sopenharmony_ci	&sriov_vf_dev_attr_group,
164662306a36Sopenharmony_ci#endif
164762306a36Sopenharmony_ci	&pci_bridge_attr_group,
164862306a36Sopenharmony_ci	&pcie_dev_attr_group,
164962306a36Sopenharmony_ci#ifdef CONFIG_PCIEAER
165062306a36Sopenharmony_ci	&aer_stats_attr_group,
165162306a36Sopenharmony_ci#endif
165262306a36Sopenharmony_ci#ifdef CONFIG_PCIEASPM
165362306a36Sopenharmony_ci	&aspm_ctrl_attr_group,
165462306a36Sopenharmony_ci#endif
165562306a36Sopenharmony_ci	NULL,
165662306a36Sopenharmony_ci};
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ciconst struct device_type pci_dev_type = {
165962306a36Sopenharmony_ci	.groups = pci_dev_attr_groups,
166062306a36Sopenharmony_ci};
1661