xref: /openbmc/linux/drivers/pci/pci-sysfs.c (revision 278002edb19bce2c628fafb0af936e77000f3a5b)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * (C) Copyright 2002-2004 Greg Kroah-Hartman <greg@kroah.com>
41da177e4SLinus Torvalds  * (C) Copyright 2002-2004 IBM Corp.
51da177e4SLinus Torvalds  * (C) Copyright 2003 Matthew Wilcox
61da177e4SLinus Torvalds  * (C) Copyright 2003 Hewlett-Packard
71da177e4SLinus Torvalds  * (C) Copyright 2004 Jon Smirl <jonsmirl@yahoo.com>
81da177e4SLinus Torvalds  * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <jbarnes@sgi.com>
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  * File attributes for PCI devices
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * Modeled after usb's driverfs.c
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds 
15d4c5d6fcSIlpo Järvinen #include <linux/bitfield.h>
161da177e4SLinus Torvalds #include <linux/kernel.h>
17b5ff7df3SLinus Torvalds #include <linux/sched.h>
181da177e4SLinus Torvalds #include <linux/pci.h>
191da177e4SLinus Torvalds #include <linux/stat.h>
20363c75dbSPaul Gortmaker #include <linux/export.h>
211da177e4SLinus Torvalds #include <linux/topology.h>
221da177e4SLinus Torvalds #include <linux/mm.h>
23de139a33SChris Wright #include <linux/fs.h>
24aa0ac365SAlexey Dobriyan #include <linux/capability.h>
25a628e7b8SChris Wright #include <linux/security.h>
265a0e3ad6STejun Heo #include <linux/slab.h>
271a39b310SMatthew Garrett #include <linux/vgaarb.h>
28448bd857SHuang Ying #include <linux/pm_runtime.h>
29ac8e3cefSBarry Song #include <linux/msi.h>
30dfc73e7aSSebastian Ott #include <linux/of.h>
3191fa1277SAlex Williamson #include <linux/aperture.h>
321da177e4SLinus Torvalds #include "pci.h"
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds static int sysfs_initialized;	/* = 0 */
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds /* show configuration fields */
371da177e4SLinus Torvalds #define pci_config_attr(field, format_string)				\
381da177e4SLinus Torvalds static ssize_t								\
39e404e274SYani Ioannou field##_show(struct device *dev, struct device_attribute *attr, char *buf)				\
401da177e4SLinus Torvalds {									\
411da177e4SLinus Torvalds 	struct pci_dev *pdev;						\
421da177e4SLinus Torvalds 									\
431da177e4SLinus Torvalds 	pdev = to_pci_dev(dev);						\
44ad025f8eSKrzysztof Wilczyński 	return sysfs_emit(buf, format_string, pdev->field);		\
455136b2daSGreg Kroah-Hartman }									\
465136b2daSGreg Kroah-Hartman static DEVICE_ATTR_RO(field)
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds pci_config_attr(vendor, "0x%04x\n");
491da177e4SLinus Torvalds pci_config_attr(device, "0x%04x\n");
501da177e4SLinus Torvalds pci_config_attr(subsystem_vendor, "0x%04x\n");
511da177e4SLinus Torvalds pci_config_attr(subsystem_device, "0x%04x\n");
52702ed3beSEmil Velikov pci_config_attr(revision, "0x%02x\n");
531da177e4SLinus Torvalds pci_config_attr(class, "0x%06x\n");
54ac8e3cefSBarry Song 
irq_show(struct device * dev,struct device_attribute * attr,char * buf)55ac8e3cefSBarry Song static ssize_t irq_show(struct device *dev,
56ac8e3cefSBarry Song 			struct device_attribute *attr,
57ac8e3cefSBarry Song 			char *buf)
58ac8e3cefSBarry Song {
59ac8e3cefSBarry Song 	struct pci_dev *pdev = to_pci_dev(dev);
60ac8e3cefSBarry Song 
61ac8e3cefSBarry Song #ifdef CONFIG_PCI_MSI
62ac8e3cefSBarry Song 	/*
63ac8e3cefSBarry Song 	 * For MSI, show the first MSI IRQ; for all other cases including
64ac8e3cefSBarry Song 	 * MSI-X, show the legacy INTx IRQ.
65ac8e3cefSBarry Song 	 */
66793c5006SThomas Gleixner 	if (pdev->msi_enabled)
67793c5006SThomas Gleixner 		return sysfs_emit(buf, "%u\n", pci_irq_vector(pdev, 0));
68ac8e3cefSBarry Song #endif
69ac8e3cefSBarry Song 
70ac8e3cefSBarry Song 	return sysfs_emit(buf, "%u\n", pdev->irq);
71ac8e3cefSBarry Song }
72ac8e3cefSBarry Song static DEVICE_ATTR_RO(irq);
731da177e4SLinus Torvalds 
broken_parity_status_show(struct device * dev,struct device_attribute * attr,char * buf)74bdee9d98SDoug Thompson static ssize_t broken_parity_status_show(struct device *dev,
75bdee9d98SDoug Thompson 					 struct device_attribute *attr,
76bdee9d98SDoug Thompson 					 char *buf)
77bdee9d98SDoug Thompson {
78bdee9d98SDoug Thompson 	struct pci_dev *pdev = to_pci_dev(dev);
79ad025f8eSKrzysztof Wilczyński 	return sysfs_emit(buf, "%u\n", pdev->broken_parity_status);
80bdee9d98SDoug Thompson }
81bdee9d98SDoug Thompson 
broken_parity_status_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)82bdee9d98SDoug Thompson static ssize_t broken_parity_status_store(struct device *dev,
83bdee9d98SDoug Thompson 					  struct device_attribute *attr,
84bdee9d98SDoug Thompson 					  const char *buf, size_t count)
85bdee9d98SDoug Thompson {
86bdee9d98SDoug Thompson 	struct pci_dev *pdev = to_pci_dev(dev);
8792425a40STrent Piepho 	unsigned long val;
88bdee9d98SDoug Thompson 
899a994e8eSJingoo Han 	if (kstrtoul(buf, 0, &val) < 0)
9092425a40STrent Piepho 		return -EINVAL;
9192425a40STrent Piepho 
9292425a40STrent Piepho 	pdev->broken_parity_status = !!val;
9392425a40STrent Piepho 
9492425a40STrent Piepho 	return count;
95bdee9d98SDoug Thompson }
965136b2daSGreg Kroah-Hartman static DEVICE_ATTR_RW(broken_parity_status);
97bdee9d98SDoug Thompson 
pci_dev_show_local_cpu(struct device * dev,bool list,struct device_attribute * attr,char * buf)985aaba363SSudeep Holla static ssize_t pci_dev_show_local_cpu(struct device *dev, bool list,
993c78bc61SRyan Desfosses 				      struct device_attribute *attr, char *buf)
1001da177e4SLinus Torvalds {
1013be83050SMike Travis 	const struct cpumask *mask;
1024327edf6SAlan Cox 
103e0cd5160SAndreas Herrmann #ifdef CONFIG_NUMA
104cee0ad4aSMax Gurtovoy 	if (dev_to_node(dev) == NUMA_NO_NODE)
105cee0ad4aSMax Gurtovoy 		mask = cpu_online_mask;
106cee0ad4aSMax Gurtovoy 	else
107cee0ad4aSMax Gurtovoy 		mask = cpumask_of_node(dev_to_node(dev));
108e0cd5160SAndreas Herrmann #else
1093be83050SMike Travis 	mask = cpumask_of_pcibus(to_pci_dev(dev)->bus);
110e0cd5160SAndreas Herrmann #endif
1115aaba363SSudeep Holla 	return cpumap_print_to_pagebuf(list, buf, mask);
11239106dcfSMike Travis }
11339106dcfSMike Travis 
local_cpus_show(struct device * dev,struct device_attribute * attr,char * buf)114c489f5fbSYijing Wang static ssize_t local_cpus_show(struct device *dev,
115c489f5fbSYijing Wang 			       struct device_attribute *attr, char *buf)
116c489f5fbSYijing Wang {
1175aaba363SSudeep Holla 	return pci_dev_show_local_cpu(dev, false, attr, buf);
118c489f5fbSYijing Wang }
1195136b2daSGreg Kroah-Hartman static DEVICE_ATTR_RO(local_cpus);
12039106dcfSMike Travis 
local_cpulist_show(struct device * dev,struct device_attribute * attr,char * buf)12139106dcfSMike Travis static ssize_t local_cpulist_show(struct device *dev,
12239106dcfSMike Travis 				  struct device_attribute *attr, char *buf)
12339106dcfSMike Travis {
1245aaba363SSudeep Holla 	return pci_dev_show_local_cpu(dev, true, attr, buf);
1251da177e4SLinus Torvalds }
1265136b2daSGreg Kroah-Hartman static DEVICE_ATTR_RO(local_cpulist);
1271da177e4SLinus Torvalds 
128dc2c2c9dSYinghai Lu /*
129dc2c2c9dSYinghai Lu  * PCI Bus Class Devices
130dc2c2c9dSYinghai Lu  */
cpuaffinity_show(struct device * dev,struct device_attribute * attr,char * buf)13156039e65SGreg Kroah-Hartman static ssize_t cpuaffinity_show(struct device *dev,
13256039e65SGreg Kroah-Hartman 				struct device_attribute *attr, char *buf)
133dc2c2c9dSYinghai Lu {
1345aaba363SSudeep Holla 	const struct cpumask *cpumask = cpumask_of_pcibus(to_pci_bus(dev));
1355aaba363SSudeep Holla 
1365aaba363SSudeep Holla 	return cpumap_print_to_pagebuf(false, buf, cpumask);
137dc2c2c9dSYinghai Lu }
13856039e65SGreg Kroah-Hartman static DEVICE_ATTR_RO(cpuaffinity);
139dc2c2c9dSYinghai Lu 
cpulistaffinity_show(struct device * dev,struct device_attribute * attr,char * buf)14056039e65SGreg Kroah-Hartman static ssize_t cpulistaffinity_show(struct device *dev,
14156039e65SGreg Kroah-Hartman 				    struct device_attribute *attr, char *buf)
142dc2c2c9dSYinghai Lu {
1435aaba363SSudeep Holla 	const struct cpumask *cpumask = cpumask_of_pcibus(to_pci_bus(dev));
1445aaba363SSudeep Holla 
1455aaba363SSudeep Holla 	return cpumap_print_to_pagebuf(true, buf, cpumask);
146dc2c2c9dSYinghai Lu }
14756039e65SGreg Kroah-Hartman static DEVICE_ATTR_RO(cpulistaffinity);
148dc2c2c9dSYinghai Lu 
power_state_show(struct device * dev,struct device_attribute * attr,char * buf)14980a129afSMaximilian Luz static ssize_t power_state_show(struct device *dev,
15080a129afSMaximilian Luz 				struct device_attribute *attr, char *buf)
15180a129afSMaximilian Luz {
15280a129afSMaximilian Luz 	struct pci_dev *pdev = to_pci_dev(dev);
15380a129afSMaximilian Luz 
154ad025f8eSKrzysztof Wilczyński 	return sysfs_emit(buf, "%s\n", pci_power_name(pdev->current_state));
15580a129afSMaximilian Luz }
15680a129afSMaximilian Luz static DEVICE_ATTR_RO(power_state);
15780a129afSMaximilian Luz 
1581da177e4SLinus Torvalds /* show resources */
resource_show(struct device * dev,struct device_attribute * attr,char * buf)1593c78bc61SRyan Desfosses static ssize_t resource_show(struct device *dev, struct device_attribute *attr,
1603c78bc61SRyan Desfosses 			     char *buf)
1611da177e4SLinus Torvalds {
1621da177e4SLinus Torvalds 	struct pci_dev *pci_dev = to_pci_dev(dev);
1631da177e4SLinus Torvalds 	int i;
164fde09c6dSYu Zhao 	int max;
165e31dd6e4SGreg Kroah-Hartman 	resource_size_t start, end;
166ad025f8eSKrzysztof Wilczyński 	size_t len = 0;
1671da177e4SLinus Torvalds 
1681da177e4SLinus Torvalds 	if (pci_dev->subordinate)
1691da177e4SLinus Torvalds 		max = DEVICE_COUNT_RESOURCE;
170fde09c6dSYu Zhao 	else
171fde09c6dSYu Zhao 		max = PCI_BRIDGE_RESOURCES;
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds 	for (i = 0; i < max; i++) {
1742311b1f2SMichael Ellerman 		struct resource *res =  &pci_dev->resource[i];
1752311b1f2SMichael Ellerman 		pci_resource_to_user(pci_dev, i, res, &start, &end);
176ad025f8eSKrzysztof Wilczyński 		len += sysfs_emit_at(buf, len, "0x%016llx 0x%016llx 0x%016llx\n",
1772311b1f2SMichael Ellerman 				     (unsigned long long)start,
1782311b1f2SMichael Ellerman 				     (unsigned long long)end,
1792311b1f2SMichael Ellerman 				     (unsigned long long)res->flags);
1801da177e4SLinus Torvalds 	}
181ad025f8eSKrzysztof Wilczyński 	return len;
1821da177e4SLinus Torvalds }
1835136b2daSGreg Kroah-Hartman static DEVICE_ATTR_RO(resource);
1841da177e4SLinus Torvalds 
max_link_speed_show(struct device * dev,struct device_attribute * attr,char * buf)18556c1af46SWong Vee Khee static ssize_t max_link_speed_show(struct device *dev,
18656c1af46SWong Vee Khee 				   struct device_attribute *attr, char *buf)
18756c1af46SWong Vee Khee {
1886cf57be0STal Gilboa 	struct pci_dev *pdev = to_pci_dev(dev);
18956c1af46SWong Vee Khee 
190ad025f8eSKrzysztof Wilczyński 	return sysfs_emit(buf, "%s\n",
1916348a34dSBjorn Helgaas 			  pci_speed_string(pcie_get_speed_cap(pdev)));
19256c1af46SWong Vee Khee }
19356c1af46SWong Vee Khee static DEVICE_ATTR_RO(max_link_speed);
19456c1af46SWong Vee Khee 
max_link_width_show(struct device * dev,struct device_attribute * attr,char * buf)19556c1af46SWong Vee Khee static ssize_t max_link_width_show(struct device *dev,
19656c1af46SWong Vee Khee 				   struct device_attribute *attr, char *buf)
19756c1af46SWong Vee Khee {
198c70b65fbSTal Gilboa 	struct pci_dev *pdev = to_pci_dev(dev);
19956c1af46SWong Vee Khee 
200ad025f8eSKrzysztof Wilczyński 	return sysfs_emit(buf, "%u\n", pcie_get_width_cap(pdev));
20156c1af46SWong Vee Khee }
20256c1af46SWong Vee Khee static DEVICE_ATTR_RO(max_link_width);
20356c1af46SWong Vee Khee 
current_link_speed_show(struct device * dev,struct device_attribute * attr,char * buf)20456c1af46SWong Vee Khee static ssize_t current_link_speed_show(struct device *dev,
20556c1af46SWong Vee Khee 				       struct device_attribute *attr, char *buf)
20656c1af46SWong Vee Khee {
20756c1af46SWong Vee Khee 	struct pci_dev *pci_dev = to_pci_dev(dev);
20856c1af46SWong Vee Khee 	u16 linkstat;
20956c1af46SWong Vee Khee 	int err;
2106348a34dSBjorn Helgaas 	enum pci_bus_speed speed;
21156c1af46SWong Vee Khee 
21256c1af46SWong Vee Khee 	err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat);
21356c1af46SWong Vee Khee 	if (err)
21456c1af46SWong Vee Khee 		return -EINVAL;
21556c1af46SWong Vee Khee 
2166348a34dSBjorn Helgaas 	speed = pcie_link_speed[linkstat & PCI_EXP_LNKSTA_CLS];
21756c1af46SWong Vee Khee 
218ad025f8eSKrzysztof Wilczyński 	return sysfs_emit(buf, "%s\n", pci_speed_string(speed));
21956c1af46SWong Vee Khee }
22056c1af46SWong Vee Khee static DEVICE_ATTR_RO(current_link_speed);
22156c1af46SWong Vee Khee 
current_link_width_show(struct device * dev,struct device_attribute * attr,char * buf)22256c1af46SWong Vee Khee static ssize_t current_link_width_show(struct device *dev,
22356c1af46SWong Vee Khee 				       struct device_attribute *attr, char *buf)
22456c1af46SWong Vee Khee {
22556c1af46SWong Vee Khee 	struct pci_dev *pci_dev = to_pci_dev(dev);
22656c1af46SWong Vee Khee 	u16 linkstat;
22756c1af46SWong Vee Khee 	int err;
22856c1af46SWong Vee Khee 
22956c1af46SWong Vee Khee 	err = pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &linkstat);
23056c1af46SWong Vee Khee 	if (err)
23156c1af46SWong Vee Khee 		return -EINVAL;
23256c1af46SWong Vee Khee 
233d4c5d6fcSIlpo Järvinen 	return sysfs_emit(buf, "%u\n", FIELD_GET(PCI_EXP_LNKSTA_NLW, linkstat));
23456c1af46SWong Vee Khee }
23556c1af46SWong Vee Khee static DEVICE_ATTR_RO(current_link_width);
23656c1af46SWong Vee Khee 
secondary_bus_number_show(struct device * dev,struct device_attribute * attr,char * buf)23756c1af46SWong Vee Khee static ssize_t secondary_bus_number_show(struct device *dev,
23856c1af46SWong Vee Khee 					 struct device_attribute *attr,
23956c1af46SWong Vee Khee 					 char *buf)
24056c1af46SWong Vee Khee {
24156c1af46SWong Vee Khee 	struct pci_dev *pci_dev = to_pci_dev(dev);
24256c1af46SWong Vee Khee 	u8 sec_bus;
24356c1af46SWong Vee Khee 	int err;
24456c1af46SWong Vee Khee 
24556c1af46SWong Vee Khee 	err = pci_read_config_byte(pci_dev, PCI_SECONDARY_BUS, &sec_bus);
24656c1af46SWong Vee Khee 	if (err)
24756c1af46SWong Vee Khee 		return -EINVAL;
24856c1af46SWong Vee Khee 
249ad025f8eSKrzysztof Wilczyński 	return sysfs_emit(buf, "%u\n", sec_bus);
25056c1af46SWong Vee Khee }
25156c1af46SWong Vee Khee static DEVICE_ATTR_RO(secondary_bus_number);
25256c1af46SWong Vee Khee 
subordinate_bus_number_show(struct device * dev,struct device_attribute * attr,char * buf)25356c1af46SWong Vee Khee static ssize_t subordinate_bus_number_show(struct device *dev,
25456c1af46SWong Vee Khee 					   struct device_attribute *attr,
25556c1af46SWong Vee Khee 					   char *buf)
25656c1af46SWong Vee Khee {
25756c1af46SWong Vee Khee 	struct pci_dev *pci_dev = to_pci_dev(dev);
25856c1af46SWong Vee Khee 	u8 sub_bus;
25956c1af46SWong Vee Khee 	int err;
26056c1af46SWong Vee Khee 
26156c1af46SWong Vee Khee 	err = pci_read_config_byte(pci_dev, PCI_SUBORDINATE_BUS, &sub_bus);
26256c1af46SWong Vee Khee 	if (err)
26356c1af46SWong Vee Khee 		return -EINVAL;
26456c1af46SWong Vee Khee 
265ad025f8eSKrzysztof Wilczyński 	return sysfs_emit(buf, "%u\n", sub_bus);
26656c1af46SWong Vee Khee }
26756c1af46SWong Vee Khee static DEVICE_ATTR_RO(subordinate_bus_number);
26856c1af46SWong Vee Khee 
ari_enabled_show(struct device * dev,struct device_attribute * attr,char * buf)2690077a845SStuart Hayes static ssize_t ari_enabled_show(struct device *dev,
2700077a845SStuart Hayes 				struct device_attribute *attr,
2710077a845SStuart Hayes 				char *buf)
2720077a845SStuart Hayes {
2730077a845SStuart Hayes 	struct pci_dev *pci_dev = to_pci_dev(dev);
2740077a845SStuart Hayes 
275ad025f8eSKrzysztof Wilczyński 	return sysfs_emit(buf, "%u\n", pci_ari_enabled(pci_dev->bus));
2760077a845SStuart Hayes }
2770077a845SStuart Hayes static DEVICE_ATTR_RO(ari_enabled);
2780077a845SStuart Hayes 
modalias_show(struct device * dev,struct device_attribute * attr,char * buf)2793c78bc61SRyan Desfosses static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
2803c78bc61SRyan Desfosses 			     char *buf)
2819888549eSGreg KH {
2829888549eSGreg KH 	struct pci_dev *pci_dev = to_pci_dev(dev);
2839888549eSGreg KH 
284ad025f8eSKrzysztof Wilczyński 	return sysfs_emit(buf, "pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02X\n",
2859888549eSGreg KH 			  pci_dev->vendor, pci_dev->device,
2869888549eSGreg KH 			  pci_dev->subsystem_vendor, pci_dev->subsystem_device,
2879888549eSGreg KH 			  (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8),
2889888549eSGreg KH 			  (u8)(pci_dev->class));
2899888549eSGreg KH }
2905136b2daSGreg Kroah-Hartman static DEVICE_ATTR_RO(modalias);
291bae94d02SInaky Perez-Gonzalez 
enable_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)292d8e7d53aSGreg Kroah-Hartman static ssize_t enable_store(struct device *dev, struct device_attribute *attr,
2933c78bc61SRyan Desfosses 			     const char *buf, size_t count)
2949f125d30SArjan van de Ven {
2959f125d30SArjan van de Ven 	struct pci_dev *pdev = to_pci_dev(dev);
29692425a40STrent Piepho 	unsigned long val;
29736f354ecSKrzysztof Wilczyński 	ssize_t result = 0;
2989f125d30SArjan van de Ven 
2999f125d30SArjan van de Ven 	/* this can crash the machine when done on the "wrong" device */
3009f125d30SArjan van de Ven 	if (!capable(CAP_SYS_ADMIN))
30192425a40STrent Piepho 		return -EPERM;
3029f125d30SArjan van de Ven 
30336f354ecSKrzysztof Wilczyński 	if (kstrtoul(buf, 0, &val) < 0)
30436f354ecSKrzysztof Wilczyński 		return -EINVAL;
30595e83e21SKrzysztof Wilczyński 
3066f5cdfa8SChristoph Hellwig 	device_lock(dev);
3076f5cdfa8SChristoph Hellwig 	if (dev->driver)
3086f5cdfa8SChristoph Hellwig 		result = -EBUSY;
3096f5cdfa8SChristoph Hellwig 	else if (val)
3106f5cdfa8SChristoph Hellwig 		result = pci_enable_device(pdev);
3116f5cdfa8SChristoph Hellwig 	else if (pci_is_enabled(pdev))
3129f125d30SArjan van de Ven 		pci_disable_device(pdev);
313bae94d02SInaky Perez-Gonzalez 	else
314bae94d02SInaky Perez-Gonzalez 		result = -EIO;
3156f5cdfa8SChristoph Hellwig 	device_unlock(dev);
3169f125d30SArjan van de Ven 
317bae94d02SInaky Perez-Gonzalez 	return result < 0 ? result : count;
318bae94d02SInaky Perez-Gonzalez }
3199f125d30SArjan van de Ven 
enable_show(struct device * dev,struct device_attribute * attr,char * buf)320d8e7d53aSGreg Kroah-Hartman static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
3213c78bc61SRyan Desfosses 			    char *buf)
322bae94d02SInaky Perez-Gonzalez {
323bae94d02SInaky Perez-Gonzalez 	struct pci_dev *pdev;
324bae94d02SInaky Perez-Gonzalez 
325bae94d02SInaky Perez-Gonzalez 	pdev = to_pci_dev(dev);
326ad025f8eSKrzysztof Wilczyński 	return sysfs_emit(buf, "%u\n", atomic_read(&pdev->enable_cnt));
3279f125d30SArjan van de Ven }
328d8e7d53aSGreg Kroah-Hartman static DEVICE_ATTR_RW(enable);
3299f125d30SArjan van de Ven 
33081bb0e19SBrice Goglin #ifdef CONFIG_NUMA
numa_node_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)33163692df1SPrarit Bhargava static ssize_t numa_node_store(struct device *dev,
33263692df1SPrarit Bhargava 			       struct device_attribute *attr, const char *buf,
33363692df1SPrarit Bhargava 			       size_t count)
33463692df1SPrarit Bhargava {
33563692df1SPrarit Bhargava 	struct pci_dev *pdev = to_pci_dev(dev);
33636f354ecSKrzysztof Wilczyński 	int node;
33763692df1SPrarit Bhargava 
33863692df1SPrarit Bhargava 	if (!capable(CAP_SYS_ADMIN))
33963692df1SPrarit Bhargava 		return -EPERM;
34063692df1SPrarit Bhargava 
34136f354ecSKrzysztof Wilczyński 	if (kstrtoint(buf, 0, &node) < 0)
34236f354ecSKrzysztof Wilczyński 		return -EINVAL;
34363692df1SPrarit Bhargava 
3443dcc8d39SMathias Krause 	if ((node < 0 && node != NUMA_NO_NODE) || node >= MAX_NUMNODES)
3453dcc8d39SMathias Krause 		return -EINVAL;
3463dcc8d39SMathias Krause 
3473dcc8d39SMathias Krause 	if (node != NUMA_NO_NODE && !node_online(node))
34863692df1SPrarit Bhargava 		return -EINVAL;
34963692df1SPrarit Bhargava 
35063692df1SPrarit Bhargava 	add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
3517506dc79SFrederick Lawler 	pci_alert(pdev, FW_BUG "Overriding NUMA node to %d.  Contact your vendor for updates.",
35263692df1SPrarit Bhargava 		  node);
35363692df1SPrarit Bhargava 
35463692df1SPrarit Bhargava 	dev->numa_node = node;
35563692df1SPrarit Bhargava 	return count;
35663692df1SPrarit Bhargava }
35763692df1SPrarit Bhargava 
numa_node_show(struct device * dev,struct device_attribute * attr,char * buf)3583c78bc61SRyan Desfosses static ssize_t numa_node_show(struct device *dev, struct device_attribute *attr,
3593c78bc61SRyan Desfosses 			      char *buf)
36081bb0e19SBrice Goglin {
361ad025f8eSKrzysztof Wilczyński 	return sysfs_emit(buf, "%d\n", dev->numa_node);
36281bb0e19SBrice Goglin }
36363692df1SPrarit Bhargava static DEVICE_ATTR_RW(numa_node);
36481bb0e19SBrice Goglin #endif
36581bb0e19SBrice Goglin 
dma_mask_bits_show(struct device * dev,struct device_attribute * attr,char * buf)3663c78bc61SRyan Desfosses static ssize_t dma_mask_bits_show(struct device *dev,
3673c78bc61SRyan Desfosses 				  struct device_attribute *attr, char *buf)
368bb965401SYinghai Lu {
369bb965401SYinghai Lu 	struct pci_dev *pdev = to_pci_dev(dev);
370bb965401SYinghai Lu 
371ad025f8eSKrzysztof Wilczyński 	return sysfs_emit(buf, "%d\n", fls64(pdev->dma_mask));
372bb965401SYinghai Lu }
3735136b2daSGreg Kroah-Hartman static DEVICE_ATTR_RO(dma_mask_bits);
374bb965401SYinghai Lu 
consistent_dma_mask_bits_show(struct device * dev,struct device_attribute * attr,char * buf)3753c78bc61SRyan Desfosses static ssize_t consistent_dma_mask_bits_show(struct device *dev,
3763c78bc61SRyan Desfosses 					     struct device_attribute *attr,
377bb965401SYinghai Lu 					     char *buf)
378bb965401SYinghai Lu {
379ad025f8eSKrzysztof Wilczyński 	return sysfs_emit(buf, "%d\n", fls64(dev->coherent_dma_mask));
380bb965401SYinghai Lu }
3815136b2daSGreg Kroah-Hartman static DEVICE_ATTR_RO(consistent_dma_mask_bits);
382bb965401SYinghai Lu 
msi_bus_show(struct device * dev,struct device_attribute * attr,char * buf)3833c78bc61SRyan Desfosses static ssize_t msi_bus_show(struct device *dev, struct device_attribute *attr,
3843c78bc61SRyan Desfosses 			    char *buf)
385fe97064cSBrice Goglin {
386fe97064cSBrice Goglin 	struct pci_dev *pdev = to_pci_dev(dev);
387468ff15aSYijing Wang 	struct pci_bus *subordinate = pdev->subordinate;
388fe97064cSBrice Goglin 
389ad025f8eSKrzysztof Wilczyński 	return sysfs_emit(buf, "%u\n", subordinate ?
390468ff15aSYijing Wang 			  !(subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI)
391468ff15aSYijing Wang 			    : !pdev->no_msi);
392fe97064cSBrice Goglin }
393fe97064cSBrice Goglin 
msi_bus_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)3943c78bc61SRyan Desfosses static ssize_t msi_bus_store(struct device *dev, struct device_attribute *attr,
395fe97064cSBrice Goglin 			     const char *buf, size_t count)
396fe97064cSBrice Goglin {
397fe97064cSBrice Goglin 	struct pci_dev *pdev = to_pci_dev(dev);
398468ff15aSYijing Wang 	struct pci_bus *subordinate = pdev->subordinate;
39992425a40STrent Piepho 	unsigned long val;
40092425a40STrent Piepho 
401fe97064cSBrice Goglin 	if (!capable(CAP_SYS_ADMIN))
40292425a40STrent Piepho 		return -EPERM;
403fe97064cSBrice Goglin 
40495e83e21SKrzysztof Wilczyński 	if (kstrtoul(buf, 0, &val) < 0)
40595e83e21SKrzysztof Wilczyński 		return -EINVAL;
40695e83e21SKrzysztof Wilczyński 
407f7625980SBjorn Helgaas 	/*
408468ff15aSYijing Wang 	 * "no_msi" and "bus_flags" only affect what happens when a driver
409468ff15aSYijing Wang 	 * requests MSI or MSI-X.  They don't affect any drivers that have
410468ff15aSYijing Wang 	 * already requested MSI or MSI-X.
411f7625980SBjorn Helgaas 	 */
412468ff15aSYijing Wang 	if (!subordinate) {
413468ff15aSYijing Wang 		pdev->no_msi = !val;
4147506dc79SFrederick Lawler 		pci_info(pdev, "MSI/MSI-X %s for future drivers\n",
415468ff15aSYijing Wang 			 val ? "allowed" : "disallowed");
416fe97064cSBrice Goglin 		return count;
417fe97064cSBrice Goglin 	}
418fe97064cSBrice Goglin 
419468ff15aSYijing Wang 	if (val)
420468ff15aSYijing Wang 		subordinate->bus_flags &= ~PCI_BUS_FLAGS_NO_MSI;
421468ff15aSYijing Wang 	else
422468ff15aSYijing Wang 		subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
423468ff15aSYijing Wang 
424468ff15aSYijing Wang 	dev_info(&subordinate->dev, "MSI/MSI-X %s for future drivers of devices on this bus\n",
425468ff15aSYijing Wang 		 val ? "allowed" : "disallowed");
426fe97064cSBrice Goglin 	return count;
427fe97064cSBrice Goglin }
4285136b2daSGreg Kroah-Hartman static DEVICE_ATTR_RW(msi_bus);
4299888549eSGreg KH 
rescan_store(const struct bus_type * bus,const char * buf,size_t count)43075cff725SGreg Kroah-Hartman static ssize_t rescan_store(const struct bus_type *bus, const char *buf, size_t count)
431705b1aaaSAlex Chiang {
432705b1aaaSAlex Chiang 	unsigned long val;
433705b1aaaSAlex Chiang 	struct pci_bus *b = NULL;
434705b1aaaSAlex Chiang 
4359a994e8eSJingoo Han 	if (kstrtoul(buf, 0, &val) < 0)
436705b1aaaSAlex Chiang 		return -EINVAL;
437705b1aaaSAlex Chiang 
438705b1aaaSAlex Chiang 	if (val) {
4399d16947bSRafael J. Wysocki 		pci_lock_rescan_remove();
440705b1aaaSAlex Chiang 		while ((b = pci_find_next_bus(b)) != NULL)
441705b1aaaSAlex Chiang 			pci_rescan_bus(b);
4429d16947bSRafael J. Wysocki 		pci_unlock_rescan_remove();
443705b1aaaSAlex Chiang 	}
444705b1aaaSAlex Chiang 	return count;
445705b1aaaSAlex Chiang }
4461094f6d0SGreg Kroah-Hartman static BUS_ATTR_WO(rescan);
447705b1aaaSAlex Chiang 
448bf22c90fSSachin Kamat static struct attribute *pci_bus_attrs[] = {
4490f49ba55SGreg Kroah-Hartman 	&bus_attr_rescan.attr,
4500f49ba55SGreg Kroah-Hartman 	NULL,
4510f49ba55SGreg Kroah-Hartman };
4520f49ba55SGreg Kroah-Hartman 
4530f49ba55SGreg Kroah-Hartman static const struct attribute_group pci_bus_group = {
4540f49ba55SGreg Kroah-Hartman 	.attrs = pci_bus_attrs,
4550f49ba55SGreg Kroah-Hartman };
4560f49ba55SGreg Kroah-Hartman 
4570f49ba55SGreg Kroah-Hartman const struct attribute_group *pci_bus_groups[] = {
4580f49ba55SGreg Kroah-Hartman 	&pci_bus_group,
4590f49ba55SGreg Kroah-Hartman 	NULL,
460705b1aaaSAlex Chiang };
46177c27c7bSAlex Chiang 
dev_rescan_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)4623c78bc61SRyan Desfosses static ssize_t dev_rescan_store(struct device *dev,
4633c78bc61SRyan Desfosses 				struct device_attribute *attr, const char *buf,
4643c78bc61SRyan Desfosses 				size_t count)
465738a6396SAlex Chiang {
466738a6396SAlex Chiang 	unsigned long val;
467738a6396SAlex Chiang 	struct pci_dev *pdev = to_pci_dev(dev);
468738a6396SAlex Chiang 
4699a994e8eSJingoo Han 	if (kstrtoul(buf, 0, &val) < 0)
470738a6396SAlex Chiang 		return -EINVAL;
471738a6396SAlex Chiang 
472738a6396SAlex Chiang 	if (val) {
4739d16947bSRafael J. Wysocki 		pci_lock_rescan_remove();
474738a6396SAlex Chiang 		pci_rescan_bus(pdev->bus);
4759d16947bSRafael J. Wysocki 		pci_unlock_rescan_remove();
476738a6396SAlex Chiang 	}
477738a6396SAlex Chiang 	return count;
478738a6396SAlex Chiang }
479bd641fd8SKelsey Skunberg static struct device_attribute dev_attr_dev_rescan = __ATTR(rescan, 0200, NULL,
480bd641fd8SKelsey Skunberg 							    dev_rescan_store);
481738a6396SAlex Chiang 
remove_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)4823c78bc61SRyan Desfosses static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
48377c27c7bSAlex Chiang 			    const char *buf, size_t count)
48477c27c7bSAlex Chiang {
48577c27c7bSAlex Chiang 	unsigned long val;
48677c27c7bSAlex Chiang 
4879a994e8eSJingoo Han 	if (kstrtoul(buf, 0, &val) < 0)
48877c27c7bSAlex Chiang 		return -EINVAL;
48977c27c7bSAlex Chiang 
490bc6caf02STejun Heo 	if (val && device_remove_file_self(dev, attr))
491bc6caf02STejun Heo 		pci_stop_and_remove_bus_device_locked(to_pci_dev(dev));
49277c27c7bSAlex Chiang 	return count;
49377c27c7bSAlex Chiang }
494e2154044SKelsey Skunberg static DEVICE_ATTR_IGNORE_LOCKDEP(remove, 0220, NULL,
4958bdfa145SKelsey Skunberg 				  remove_store);
496b9d320fcSYinghai Lu 
bus_rescan_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)4974e2b7943SKelsey Skunberg static ssize_t bus_rescan_store(struct device *dev,
4983c78bc61SRyan Desfosses 				struct device_attribute *attr,
499b9d320fcSYinghai Lu 				const char *buf, size_t count)
500b9d320fcSYinghai Lu {
501b9d320fcSYinghai Lu 	unsigned long val;
502b9d320fcSYinghai Lu 	struct pci_bus *bus = to_pci_bus(dev);
503b9d320fcSYinghai Lu 
5049a994e8eSJingoo Han 	if (kstrtoul(buf, 0, &val) < 0)
505b9d320fcSYinghai Lu 		return -EINVAL;
506b9d320fcSYinghai Lu 
507b9d320fcSYinghai Lu 	if (val) {
5089d16947bSRafael J. Wysocki 		pci_lock_rescan_remove();
5092f320521SYinghai Lu 		if (!pci_is_root_bus(bus) && list_empty(&bus->devices))
5102f320521SYinghai Lu 			pci_rescan_bus_bridge_resize(bus->self);
5112f320521SYinghai Lu 		else
512b9d320fcSYinghai Lu 			pci_rescan_bus(bus);
5139d16947bSRafael J. Wysocki 		pci_unlock_rescan_remove();
514b9d320fcSYinghai Lu 	}
515b9d320fcSYinghai Lu 	return count;
516b9d320fcSYinghai Lu }
517bd641fd8SKelsey Skunberg static struct device_attribute dev_attr_bus_rescan = __ATTR(rescan, 0200, NULL,
518bd641fd8SKelsey Skunberg 							    bus_rescan_store);
519b9d320fcSYinghai Lu 
reset_subordinate_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)520*407476ebSKeith Busch static ssize_t reset_subordinate_store(struct device *dev,
521*407476ebSKeith Busch 				struct device_attribute *attr,
522*407476ebSKeith Busch 				const char *buf, size_t count)
523*407476ebSKeith Busch {
524*407476ebSKeith Busch 	struct pci_dev *pdev = to_pci_dev(dev);
525*407476ebSKeith Busch 	struct pci_bus *bus = pdev->subordinate;
526*407476ebSKeith Busch 	unsigned long val;
527*407476ebSKeith Busch 
528*407476ebSKeith Busch 	if (!capable(CAP_SYS_ADMIN))
529*407476ebSKeith Busch 		return -EPERM;
530*407476ebSKeith Busch 
531*407476ebSKeith Busch 	if (kstrtoul(buf, 0, &val) < 0)
532*407476ebSKeith Busch 		return -EINVAL;
533*407476ebSKeith Busch 
534*407476ebSKeith Busch 	if (val) {
535*407476ebSKeith Busch 		int ret = __pci_reset_bus(bus);
536*407476ebSKeith Busch 
537*407476ebSKeith Busch 		if (ret)
538*407476ebSKeith Busch 			return ret;
539*407476ebSKeith Busch 	}
540*407476ebSKeith Busch 
541*407476ebSKeith Busch 	return count;
542*407476ebSKeith Busch }
543*407476ebSKeith Busch static DEVICE_ATTR_WO(reset_subordinate);
544*407476ebSKeith Busch 
545fbb988beSRafael J. Wysocki #if defined(CONFIG_PM) && defined(CONFIG_ACPI)
d3cold_allowed_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)546448bd857SHuang Ying static ssize_t d3cold_allowed_store(struct device *dev,
547448bd857SHuang Ying 				    struct device_attribute *attr,
548448bd857SHuang Ying 				    const char *buf, size_t count)
549448bd857SHuang Ying {
550448bd857SHuang Ying 	struct pci_dev *pdev = to_pci_dev(dev);
551448bd857SHuang Ying 	unsigned long val;
552448bd857SHuang Ying 
5539a994e8eSJingoo Han 	if (kstrtoul(buf, 0, &val) < 0)
554448bd857SHuang Ying 		return -EINVAL;
555448bd857SHuang Ying 
556448bd857SHuang Ying 	pdev->d3cold_allowed = !!val;
5570763bcefSLukas Wunner 	pci_bridge_d3_update(pdev);
5589d26d3a8SMika Westerberg 
559448bd857SHuang Ying 	pm_runtime_resume(dev);
560448bd857SHuang Ying 
561448bd857SHuang Ying 	return count;
562448bd857SHuang Ying }
563448bd857SHuang Ying 
d3cold_allowed_show(struct device * dev,struct device_attribute * attr,char * buf)564448bd857SHuang Ying static ssize_t d3cold_allowed_show(struct device *dev,
565448bd857SHuang Ying 				   struct device_attribute *attr, char *buf)
566448bd857SHuang Ying {
567448bd857SHuang Ying 	struct pci_dev *pdev = to_pci_dev(dev);
568ad025f8eSKrzysztof Wilczyński 	return sysfs_emit(buf, "%u\n", pdev->d3cold_allowed);
569448bd857SHuang Ying }
5705136b2daSGreg Kroah-Hartman static DEVICE_ATTR_RW(d3cold_allowed);
571448bd857SHuang Ying #endif
572448bd857SHuang Ying 
573dfc73e7aSSebastian Ott #ifdef CONFIG_OF
devspec_show(struct device * dev,struct device_attribute * attr,char * buf)574dfc73e7aSSebastian Ott static ssize_t devspec_show(struct device *dev,
575dfc73e7aSSebastian Ott 			    struct device_attribute *attr, char *buf)
576dfc73e7aSSebastian Ott {
577dfc73e7aSSebastian Ott 	struct pci_dev *pdev = to_pci_dev(dev);
578dfc73e7aSSebastian Ott 	struct device_node *np = pci_device_to_OF_node(pdev);
579dfc73e7aSSebastian Ott 
580b63773a8SRob Herring 	if (np == NULL)
581dfc73e7aSSebastian Ott 		return 0;
58214c19b2aSKrzysztof Wilczyński 	return sysfs_emit(buf, "%pOF\n", np);
583dfc73e7aSSebastian Ott }
584dfc73e7aSSebastian Ott static DEVICE_ATTR_RO(devspec);
585dfc73e7aSSebastian Ott #endif
586dfc73e7aSSebastian Ott 
driver_override_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)587782a985dSAlex Williamson static ssize_t driver_override_store(struct device *dev,
588782a985dSAlex Williamson 				     struct device_attribute *attr,
589782a985dSAlex Williamson 				     const char *buf, size_t count)
590782a985dSAlex Williamson {
591782a985dSAlex Williamson 	struct pci_dev *pdev = to_pci_dev(dev);
59223d99bafSKrzysztof Kozlowski 	int ret;
593782a985dSAlex Williamson 
59423d99bafSKrzysztof Kozlowski 	ret = driver_set_override(dev, &pdev->driver_override, buf, count);
59523d99bafSKrzysztof Kozlowski 	if (ret)
59623d99bafSKrzysztof Kozlowski 		return ret;
597782a985dSAlex Williamson 
598782a985dSAlex Williamson 	return count;
599782a985dSAlex Williamson }
600782a985dSAlex Williamson 
driver_override_show(struct device * dev,struct device_attribute * attr,char * buf)601782a985dSAlex Williamson static ssize_t driver_override_show(struct device *dev,
602782a985dSAlex Williamson 				    struct device_attribute *attr, char *buf)
603782a985dSAlex Williamson {
604782a985dSAlex Williamson 	struct pci_dev *pdev = to_pci_dev(dev);
6059561475dSNicolai Stange 	ssize_t len;
606782a985dSAlex Williamson 
6079561475dSNicolai Stange 	device_lock(dev);
608ad025f8eSKrzysztof Wilczyński 	len = sysfs_emit(buf, "%s\n", pdev->driver_override);
6099561475dSNicolai Stange 	device_unlock(dev);
6109561475dSNicolai Stange 	return len;
611782a985dSAlex Williamson }
612782a985dSAlex Williamson static DEVICE_ATTR_RW(driver_override);
613782a985dSAlex Williamson 
614bf22c90fSSachin Kamat static struct attribute *pci_dev_attrs[] = {
61580a129afSMaximilian Luz 	&dev_attr_power_state.attr,
6165136b2daSGreg Kroah-Hartman 	&dev_attr_resource.attr,
6175136b2daSGreg Kroah-Hartman 	&dev_attr_vendor.attr,
6185136b2daSGreg Kroah-Hartman 	&dev_attr_device.attr,
6195136b2daSGreg Kroah-Hartman 	&dev_attr_subsystem_vendor.attr,
6205136b2daSGreg Kroah-Hartman 	&dev_attr_subsystem_device.attr,
621702ed3beSEmil Velikov 	&dev_attr_revision.attr,
6225136b2daSGreg Kroah-Hartman 	&dev_attr_class.attr,
6235136b2daSGreg Kroah-Hartman 	&dev_attr_irq.attr,
6245136b2daSGreg Kroah-Hartman 	&dev_attr_local_cpus.attr,
6255136b2daSGreg Kroah-Hartman 	&dev_attr_local_cpulist.attr,
6265136b2daSGreg Kroah-Hartman 	&dev_attr_modalias.attr,
62781bb0e19SBrice Goglin #ifdef CONFIG_NUMA
6285136b2daSGreg Kroah-Hartman 	&dev_attr_numa_node.attr,
62981bb0e19SBrice Goglin #endif
6305136b2daSGreg Kroah-Hartman 	&dev_attr_dma_mask_bits.attr,
6315136b2daSGreg Kroah-Hartman 	&dev_attr_consistent_dma_mask_bits.attr,
632d8e7d53aSGreg Kroah-Hartman 	&dev_attr_enable.attr,
6335136b2daSGreg Kroah-Hartman 	&dev_attr_broken_parity_status.attr,
6345136b2daSGreg Kroah-Hartman 	&dev_attr_msi_bus.attr,
635fbb988beSRafael J. Wysocki #if defined(CONFIG_PM) && defined(CONFIG_ACPI)
6365136b2daSGreg Kroah-Hartman 	&dev_attr_d3cold_allowed.attr,
637448bd857SHuang Ying #endif
638dfc73e7aSSebastian Ott #ifdef CONFIG_OF
639dfc73e7aSSebastian Ott 	&dev_attr_devspec.attr,
640dfc73e7aSSebastian Ott #endif
641782a985dSAlex Williamson 	&dev_attr_driver_override.attr,
6420077a845SStuart Hayes 	&dev_attr_ari_enabled.attr,
6435136b2daSGreg Kroah-Hartman 	NULL,
6445136b2daSGreg Kroah-Hartman };
6455136b2daSGreg Kroah-Hartman 
64656c1af46SWong Vee Khee static struct attribute *pci_bridge_attrs[] = {
64756c1af46SWong Vee Khee 	&dev_attr_subordinate_bus_number.attr,
64856c1af46SWong Vee Khee 	&dev_attr_secondary_bus_number.attr,
649*407476ebSKeith Busch 	&dev_attr_reset_subordinate.attr,
65056c1af46SWong Vee Khee 	NULL,
6515136b2daSGreg Kroah-Hartman };
6525136b2daSGreg Kroah-Hartman 
65356c1af46SWong Vee Khee static struct attribute *pcie_dev_attrs[] = {
65456c1af46SWong Vee Khee 	&dev_attr_current_link_speed.attr,
65556c1af46SWong Vee Khee 	&dev_attr_current_link_width.attr,
65656c1af46SWong Vee Khee 	&dev_attr_max_link_width.attr,
65756c1af46SWong Vee Khee 	&dev_attr_max_link_speed.attr,
6585136b2daSGreg Kroah-Hartman 	NULL,
6591da177e4SLinus Torvalds };
6601da177e4SLinus Torvalds 
66156039e65SGreg Kroah-Hartman static struct attribute *pcibus_attrs[] = {
6628bdfa145SKelsey Skunberg 	&dev_attr_bus_rescan.attr,
66356039e65SGreg Kroah-Hartman 	&dev_attr_cpuaffinity.attr,
66456039e65SGreg Kroah-Hartman 	&dev_attr_cpulistaffinity.attr,
66556039e65SGreg Kroah-Hartman 	NULL,
66656039e65SGreg Kroah-Hartman };
66756039e65SGreg Kroah-Hartman 
66856039e65SGreg Kroah-Hartman static const struct attribute_group pcibus_group = {
66956039e65SGreg Kroah-Hartman 	.attrs = pcibus_attrs,
67056039e65SGreg Kroah-Hartman };
67156039e65SGreg Kroah-Hartman 
67256039e65SGreg Kroah-Hartman const struct attribute_group *pcibus_groups[] = {
67356039e65SGreg Kroah-Hartman 	&pcibus_group,
67456039e65SGreg Kroah-Hartman 	NULL,
675b9d320fcSYinghai Lu };
676b9d320fcSYinghai Lu 
boot_vga_show(struct device * dev,struct device_attribute * attr,char * buf)6773c78bc61SRyan Desfosses static ssize_t boot_vga_show(struct device *dev, struct device_attribute *attr,
6783c78bc61SRyan Desfosses 			     char *buf)
679217f45deSDave Airlie {
680217f45deSDave Airlie 	struct pci_dev *pdev = to_pci_dev(dev);
6811a39b310SMatthew Garrett 	struct pci_dev *vga_dev = vga_default_device();
6821a39b310SMatthew Garrett 
6831a39b310SMatthew Garrett 	if (vga_dev)
684ad025f8eSKrzysztof Wilczyński 		return sysfs_emit(buf, "%u\n", (pdev == vga_dev));
685217f45deSDave Airlie 
686ad025f8eSKrzysztof Wilczyński 	return sysfs_emit(buf, "%u\n",
687217f45deSDave Airlie 			  !!(pdev->resource[PCI_ROM_RESOURCE].flags &
688217f45deSDave Airlie 			     IORESOURCE_ROM_SHADOW));
689217f45deSDave Airlie }
6908bdfa145SKelsey Skunberg static DEVICE_ATTR_RO(boot_vga);
691217f45deSDave Airlie 
pci_read_config(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)6923c78bc61SRyan Desfosses static ssize_t pci_read_config(struct file *filp, struct kobject *kobj,
6933c78bc61SRyan Desfosses 			       struct bin_attribute *bin_attr, char *buf,
6943c78bc61SRyan Desfosses 			       loff_t off, size_t count)
6951da177e4SLinus Torvalds {
696554a6037SGeliang Tang 	struct pci_dev *dev = to_pci_dev(kobj_to_dev(kobj));
6971da177e4SLinus Torvalds 	unsigned int size = 64;
6981da177e4SLinus Torvalds 	loff_t init_off = off;
6994c0619adSssant@in.ibm.com 	u8 *data = (u8 *) buf;
7001da177e4SLinus Torvalds 
7011da177e4SLinus Torvalds 	/* Several chips lock up trying to read undefined config space */
702ab0fa82bSLinus Torvalds 	if (file_ns_capable(filp, &init_user_ns, CAP_SYS_ADMIN))
7031da177e4SLinus Torvalds 		size = dev->cfg_size;
7043c78bc61SRyan Desfosses 	else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
7051da177e4SLinus Torvalds 		size = 128;
7061da177e4SLinus Torvalds 
7071da177e4SLinus Torvalds 	if (off > size)
7081da177e4SLinus Torvalds 		return 0;
7091da177e4SLinus Torvalds 	if (off + count > size) {
7101da177e4SLinus Torvalds 		size -= off;
7111da177e4SLinus Torvalds 		count = size;
7121da177e4SLinus Torvalds 	} else {
7131da177e4SLinus Torvalds 		size = count;
7141da177e4SLinus Torvalds 	}
7151da177e4SLinus Torvalds 
7163d8387efSHuang Ying 	pci_config_pm_runtime_get(dev);
7173d8387efSHuang Ying 
7184c0619adSssant@in.ibm.com 	if ((off & 1) && size) {
7194c0619adSssant@in.ibm.com 		u8 val;
720e04b0ea2SBrian King 		pci_user_read_config_byte(dev, off, &val);
7214c0619adSssant@in.ibm.com 		data[off - init_off] = val;
7221da177e4SLinus Torvalds 		off++;
7234c0619adSssant@in.ibm.com 		size--;
7244c0619adSssant@in.ibm.com 	}
7254c0619adSssant@in.ibm.com 
7264c0619adSssant@in.ibm.com 	if ((off & 3) && size > 2) {
7274c0619adSssant@in.ibm.com 		u16 val;
728e04b0ea2SBrian King 		pci_user_read_config_word(dev, off, &val);
7294c0619adSssant@in.ibm.com 		data[off - init_off] = val & 0xff;
7304c0619adSssant@in.ibm.com 		data[off - init_off + 1] = (val >> 8) & 0xff;
7314c0619adSssant@in.ibm.com 		off += 2;
7324c0619adSssant@in.ibm.com 		size -= 2;
7331da177e4SLinus Torvalds 	}
7341da177e4SLinus Torvalds 
7351da177e4SLinus Torvalds 	while (size > 3) {
7364c0619adSssant@in.ibm.com 		u32 val;
737e04b0ea2SBrian King 		pci_user_read_config_dword(dev, off, &val);
7384c0619adSssant@in.ibm.com 		data[off - init_off] = val & 0xff;
7394c0619adSssant@in.ibm.com 		data[off - init_off + 1] = (val >> 8) & 0xff;
7404c0619adSssant@in.ibm.com 		data[off - init_off + 2] = (val >> 16) & 0xff;
7414c0619adSssant@in.ibm.com 		data[off - init_off + 3] = (val >> 24) & 0xff;
7421da177e4SLinus Torvalds 		off += 4;
7431da177e4SLinus Torvalds 		size -= 4;
7442ce02a86SJiang Biao 		cond_resched();
7451da177e4SLinus Torvalds 	}
7461da177e4SLinus Torvalds 
7474c0619adSssant@in.ibm.com 	if (size >= 2) {
7484c0619adSssant@in.ibm.com 		u16 val;
749e04b0ea2SBrian King 		pci_user_read_config_word(dev, off, &val);
7504c0619adSssant@in.ibm.com 		data[off - init_off] = val & 0xff;
7514c0619adSssant@in.ibm.com 		data[off - init_off + 1] = (val >> 8) & 0xff;
7524c0619adSssant@in.ibm.com 		off += 2;
7534c0619adSssant@in.ibm.com 		size -= 2;
7544c0619adSssant@in.ibm.com 	}
7554c0619adSssant@in.ibm.com 
7564c0619adSssant@in.ibm.com 	if (size > 0) {
7574c0619adSssant@in.ibm.com 		u8 val;
758e04b0ea2SBrian King 		pci_user_read_config_byte(dev, off, &val);
7594c0619adSssant@in.ibm.com 		data[off - init_off] = val;
7601da177e4SLinus Torvalds 	}
7611da177e4SLinus Torvalds 
7623d8387efSHuang Ying 	pci_config_pm_runtime_put(dev);
7633d8387efSHuang Ying 
7641da177e4SLinus Torvalds 	return count;
7651da177e4SLinus Torvalds }
7661da177e4SLinus Torvalds 
pci_write_config(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)7673c78bc61SRyan Desfosses static ssize_t pci_write_config(struct file *filp, struct kobject *kobj,
7683c78bc61SRyan Desfosses 				struct bin_attribute *bin_attr, char *buf,
7693c78bc61SRyan Desfosses 				loff_t off, size_t count)
7701da177e4SLinus Torvalds {
771554a6037SGeliang Tang 	struct pci_dev *dev = to_pci_dev(kobj_to_dev(kobj));
7721da177e4SLinus Torvalds 	unsigned int size = count;
7731da177e4SLinus Torvalds 	loff_t init_off = off;
7744c0619adSssant@in.ibm.com 	u8 *data = (u8 *) buf;
775eb627e17SMatthew Garrett 	int ret;
776eb627e17SMatthew Garrett 
777eb627e17SMatthew Garrett 	ret = security_locked_down(LOCKDOWN_PCI_ACCESS);
778eb627e17SMatthew Garrett 	if (ret)
779eb627e17SMatthew Garrett 		return ret;
7801da177e4SLinus Torvalds 
78127829479SIra Weiny 	if (resource_is_exclusive(&dev->driver_exclusive_resource, off,
78227829479SIra Weiny 				  count)) {
78327829479SIra Weiny 		pci_warn_once(dev, "%s: Unexpected write to kernel-exclusive config offset %llx",
78427829479SIra Weiny 			      current->comm, off);
78527829479SIra Weiny 		add_taint(TAINT_USER, LOCKDEP_STILL_OK);
78627829479SIra Weiny 	}
78727829479SIra Weiny 
7881da177e4SLinus Torvalds 	if (off > dev->cfg_size)
7891da177e4SLinus Torvalds 		return 0;
7901da177e4SLinus Torvalds 	if (off + count > dev->cfg_size) {
7911da177e4SLinus Torvalds 		size = dev->cfg_size - off;
7921da177e4SLinus Torvalds 		count = size;
7931da177e4SLinus Torvalds 	}
7941da177e4SLinus Torvalds 
7953d8387efSHuang Ying 	pci_config_pm_runtime_get(dev);
7963d8387efSHuang Ying 
7974c0619adSssant@in.ibm.com 	if ((off & 1) && size) {
798e04b0ea2SBrian King 		pci_user_write_config_byte(dev, off, data[off - init_off]);
7991da177e4SLinus Torvalds 		off++;
8004c0619adSssant@in.ibm.com 		size--;
8014c0619adSssant@in.ibm.com 	}
8024c0619adSssant@in.ibm.com 
8034c0619adSssant@in.ibm.com 	if ((off & 3) && size > 2) {
8044c0619adSssant@in.ibm.com 		u16 val = data[off - init_off];
8054c0619adSssant@in.ibm.com 		val |= (u16) data[off - init_off + 1] << 8;
806e04b0ea2SBrian King 		pci_user_write_config_word(dev, off, val);
8074c0619adSssant@in.ibm.com 		off += 2;
8084c0619adSssant@in.ibm.com 		size -= 2;
8091da177e4SLinus Torvalds 	}
8101da177e4SLinus Torvalds 
8111da177e4SLinus Torvalds 	while (size > 3) {
8124c0619adSssant@in.ibm.com 		u32 val = data[off - init_off];
8134c0619adSssant@in.ibm.com 		val |= (u32) data[off - init_off + 1] << 8;
8144c0619adSssant@in.ibm.com 		val |= (u32) data[off - init_off + 2] << 16;
8154c0619adSssant@in.ibm.com 		val |= (u32) data[off - init_off + 3] << 24;
816e04b0ea2SBrian King 		pci_user_write_config_dword(dev, off, val);
8171da177e4SLinus Torvalds 		off += 4;
8181da177e4SLinus Torvalds 		size -= 4;
8191da177e4SLinus Torvalds 	}
8201da177e4SLinus Torvalds 
8214c0619adSssant@in.ibm.com 	if (size >= 2) {
8224c0619adSssant@in.ibm.com 		u16 val = data[off - init_off];
8234c0619adSssant@in.ibm.com 		val |= (u16) data[off - init_off + 1] << 8;
824e04b0ea2SBrian King 		pci_user_write_config_word(dev, off, val);
8254c0619adSssant@in.ibm.com 		off += 2;
8264c0619adSssant@in.ibm.com 		size -= 2;
8274c0619adSssant@in.ibm.com 	}
8284c0619adSssant@in.ibm.com 
829c50762a8SBjorn Helgaas 	if (size)
830e04b0ea2SBrian King 		pci_user_write_config_byte(dev, off, data[off - init_off]);
8311da177e4SLinus Torvalds 
8323d8387efSHuang Ying 	pci_config_pm_runtime_put(dev);
8333d8387efSHuang Ying 
8341da177e4SLinus Torvalds 	return count;
8351da177e4SLinus Torvalds }
836e1d3f326SKrzysztof Wilczyński static BIN_ATTR(config, 0644, pci_read_config, pci_write_config, 0);
837e1d3f326SKrzysztof Wilczyński 
838e1d3f326SKrzysztof Wilczyński static struct bin_attribute *pci_dev_config_attrs[] = {
839e1d3f326SKrzysztof Wilczyński 	&bin_attr_config,
840e1d3f326SKrzysztof Wilczyński 	NULL,
841e1d3f326SKrzysztof Wilczyński };
842e1d3f326SKrzysztof Wilczyński 
pci_dev_config_attr_is_visible(struct kobject * kobj,struct bin_attribute * a,int n)843e1d3f326SKrzysztof Wilczyński static umode_t pci_dev_config_attr_is_visible(struct kobject *kobj,
844e1d3f326SKrzysztof Wilczyński 					      struct bin_attribute *a, int n)
845e1d3f326SKrzysztof Wilczyński {
846e1d3f326SKrzysztof Wilczyński 	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
847e1d3f326SKrzysztof Wilczyński 
848e1d3f326SKrzysztof Wilczyński 	a->size = PCI_CFG_SPACE_SIZE;
849e1d3f326SKrzysztof Wilczyński 	if (pdev->cfg_size > PCI_CFG_SPACE_SIZE)
850e1d3f326SKrzysztof Wilczyński 		a->size = PCI_CFG_SPACE_EXP_SIZE;
851e1d3f326SKrzysztof Wilczyński 
852e1d3f326SKrzysztof Wilczyński 	return a->attr.mode;
853e1d3f326SKrzysztof Wilczyński }
854e1d3f326SKrzysztof Wilczyński 
855e1d3f326SKrzysztof Wilczyński static const struct attribute_group pci_dev_config_attr_group = {
856e1d3f326SKrzysztof Wilczyński 	.bin_attrs = pci_dev_config_attrs,
857e1d3f326SKrzysztof Wilczyński 	.is_bin_visible = pci_dev_config_attr_is_visible,
858e1d3f326SKrzysztof Wilczyński };
8591da177e4SLinus Torvalds 
8601da177e4SLinus Torvalds #ifdef HAVE_PCI_LEGACY
8611da177e4SLinus Torvalds /**
8621da177e4SLinus Torvalds  * pci_read_legacy_io - read byte(s) from legacy I/O port space
8632c3c8beaSChris Wright  * @filp: open sysfs file
8641da177e4SLinus Torvalds  * @kobj: kobject corresponding to file to read from
865cffb2fafSRandy Dunlap  * @bin_attr: struct bin_attribute for this file
8661da177e4SLinus Torvalds  * @buf: buffer to store results
8671da177e4SLinus Torvalds  * @off: offset into legacy I/O port space
8681da177e4SLinus Torvalds  * @count: number of bytes to read
8691da177e4SLinus Torvalds  *
8701da177e4SLinus Torvalds  * Reads 1, 2, or 4 bytes from legacy I/O port space using an arch specific
8711da177e4SLinus Torvalds  * callback routine (pci_legacy_read).
8721da177e4SLinus Torvalds  */
pci_read_legacy_io(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)8733c78bc61SRyan Desfosses static ssize_t pci_read_legacy_io(struct file *filp, struct kobject *kobj,
8743c78bc61SRyan Desfosses 				  struct bin_attribute *bin_attr, char *buf,
8753c78bc61SRyan Desfosses 				  loff_t off, size_t count)
8761da177e4SLinus Torvalds {
877554a6037SGeliang Tang 	struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
8781da177e4SLinus Torvalds 
8791da177e4SLinus Torvalds 	/* Only support 1, 2 or 4 byte accesses */
8801da177e4SLinus Torvalds 	if (count != 1 && count != 2 && count != 4)
8811da177e4SLinus Torvalds 		return -EINVAL;
8821da177e4SLinus Torvalds 
8831da177e4SLinus Torvalds 	return pci_legacy_read(bus, off, (u32 *)buf, count);
8841da177e4SLinus Torvalds }
8851da177e4SLinus Torvalds 
8861da177e4SLinus Torvalds /**
8871da177e4SLinus Torvalds  * pci_write_legacy_io - write byte(s) to legacy I/O port space
8882c3c8beaSChris Wright  * @filp: open sysfs file
8891da177e4SLinus Torvalds  * @kobj: kobject corresponding to file to read from
890cffb2fafSRandy Dunlap  * @bin_attr: struct bin_attribute for this file
8911da177e4SLinus Torvalds  * @buf: buffer containing value to be written
8921da177e4SLinus Torvalds  * @off: offset into legacy I/O port space
8931da177e4SLinus Torvalds  * @count: number of bytes to write
8941da177e4SLinus Torvalds  *
8951da177e4SLinus Torvalds  * Writes 1, 2, or 4 bytes from legacy I/O port space using an arch specific
8961da177e4SLinus Torvalds  * callback routine (pci_legacy_write).
8971da177e4SLinus Torvalds  */
pci_write_legacy_io(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)8983c78bc61SRyan Desfosses static ssize_t pci_write_legacy_io(struct file *filp, struct kobject *kobj,
8993c78bc61SRyan Desfosses 				   struct bin_attribute *bin_attr, char *buf,
9003c78bc61SRyan Desfosses 				   loff_t off, size_t count)
9011da177e4SLinus Torvalds {
902554a6037SGeliang Tang 	struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
9033c78bc61SRyan Desfosses 
9041da177e4SLinus Torvalds 	/* Only support 1, 2 or 4 byte accesses */
9051da177e4SLinus Torvalds 	if (count != 1 && count != 2 && count != 4)
9061da177e4SLinus Torvalds 		return -EINVAL;
9071da177e4SLinus Torvalds 
9081da177e4SLinus Torvalds 	return pci_legacy_write(bus, off, *(u32 *)buf, count);
9091da177e4SLinus Torvalds }
9101da177e4SLinus Torvalds 
9111da177e4SLinus Torvalds /**
9121da177e4SLinus Torvalds  * pci_mmap_legacy_mem - map legacy PCI memory into user memory space
9132c3c8beaSChris Wright  * @filp: open sysfs file
9141da177e4SLinus Torvalds  * @kobj: kobject corresponding to device to be mapped
9151da177e4SLinus Torvalds  * @attr: struct bin_attribute for this file
9161da177e4SLinus Torvalds  * @vma: struct vm_area_struct passed to mmap
9171da177e4SLinus Torvalds  *
918f19aeb1fSBenjamin Herrenschmidt  * Uses an arch specific callback, pci_mmap_legacy_mem_page_range, to mmap
9191da177e4SLinus Torvalds  * legacy memory space (first meg of bus space) into application virtual
9201da177e4SLinus Torvalds  * memory space.
9211da177e4SLinus Torvalds  */
pci_mmap_legacy_mem(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,struct vm_area_struct * vma)9223c78bc61SRyan Desfosses static int pci_mmap_legacy_mem(struct file *filp, struct kobject *kobj,
9232c3c8beaSChris Wright 			       struct bin_attribute *attr,
9241da177e4SLinus Torvalds 			       struct vm_area_struct *vma)
9251da177e4SLinus Torvalds {
926554a6037SGeliang Tang 	struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
9271da177e4SLinus Torvalds 
928f19aeb1fSBenjamin Herrenschmidt 	return pci_mmap_legacy_page_range(bus, vma, pci_mmap_mem);
929f19aeb1fSBenjamin Herrenschmidt }
930f19aeb1fSBenjamin Herrenschmidt 
931f19aeb1fSBenjamin Herrenschmidt /**
932f19aeb1fSBenjamin Herrenschmidt  * pci_mmap_legacy_io - map legacy PCI IO into user memory space
9332c3c8beaSChris Wright  * @filp: open sysfs file
934f19aeb1fSBenjamin Herrenschmidt  * @kobj: kobject corresponding to device to be mapped
935f19aeb1fSBenjamin Herrenschmidt  * @attr: struct bin_attribute for this file
936f19aeb1fSBenjamin Herrenschmidt  * @vma: struct vm_area_struct passed to mmap
937f19aeb1fSBenjamin Herrenschmidt  *
938f19aeb1fSBenjamin Herrenschmidt  * Uses an arch specific callback, pci_mmap_legacy_io_page_range, to mmap
939f19aeb1fSBenjamin Herrenschmidt  * legacy IO space (first meg of bus space) into application virtual
940f19aeb1fSBenjamin Herrenschmidt  * memory space. Returns -ENOSYS if the operation isn't supported
941f19aeb1fSBenjamin Herrenschmidt  */
pci_mmap_legacy_io(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,struct vm_area_struct * vma)9423c78bc61SRyan Desfosses static int pci_mmap_legacy_io(struct file *filp, struct kobject *kobj,
9432c3c8beaSChris Wright 			      struct bin_attribute *attr,
944f19aeb1fSBenjamin Herrenschmidt 			      struct vm_area_struct *vma)
945f19aeb1fSBenjamin Herrenschmidt {
946554a6037SGeliang Tang 	struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
947f19aeb1fSBenjamin Herrenschmidt 
948f19aeb1fSBenjamin Herrenschmidt 	return pci_mmap_legacy_page_range(bus, vma, pci_mmap_io);
949f19aeb1fSBenjamin Herrenschmidt }
950f19aeb1fSBenjamin Herrenschmidt 
951f19aeb1fSBenjamin Herrenschmidt /**
95210a0ef39SIvan Kokshaysky  * pci_adjust_legacy_attr - adjustment of legacy file attributes
95310a0ef39SIvan Kokshaysky  * @b: bus to create files under
95410a0ef39SIvan Kokshaysky  * @mmap_type: I/O port or memory
95510a0ef39SIvan Kokshaysky  *
95610a0ef39SIvan Kokshaysky  * Stub implementation. Can be overridden by arch if necessary.
95710a0ef39SIvan Kokshaysky  */
pci_adjust_legacy_attr(struct pci_bus * b,enum pci_mmap_state mmap_type)9583c78bc61SRyan Desfosses void __weak pci_adjust_legacy_attr(struct pci_bus *b,
9593c78bc61SRyan Desfosses 				   enum pci_mmap_state mmap_type)
96010a0ef39SIvan Kokshaysky {
96110a0ef39SIvan Kokshaysky }
96210a0ef39SIvan Kokshaysky 
96310a0ef39SIvan Kokshaysky /**
964f19aeb1fSBenjamin Herrenschmidt  * pci_create_legacy_files - create legacy I/O port and memory files
965f19aeb1fSBenjamin Herrenschmidt  * @b: bus to create files under
966f19aeb1fSBenjamin Herrenschmidt  *
967f19aeb1fSBenjamin Herrenschmidt  * Some platforms allow access to legacy I/O port and ISA memory space on
968f19aeb1fSBenjamin Herrenschmidt  * a per-bus basis.  This routine creates the files and ties them into
969f19aeb1fSBenjamin Herrenschmidt  * their associated read, write and mmap files from pci-sysfs.c
970f19aeb1fSBenjamin Herrenschmidt  *
97125985edcSLucas De Marchi  * On error unwind, but don't propagate the error to the caller
972f19aeb1fSBenjamin Herrenschmidt  * as it is ok to set up the PCI bus without these files.
973f19aeb1fSBenjamin Herrenschmidt  */
pci_create_legacy_files(struct pci_bus * b)974f19aeb1fSBenjamin Herrenschmidt void pci_create_legacy_files(struct pci_bus *b)
975f19aeb1fSBenjamin Herrenschmidt {
976f19aeb1fSBenjamin Herrenschmidt 	int error;
977f19aeb1fSBenjamin Herrenschmidt 
978efd532a6SDaniel Vetter 	if (!sysfs_initialized)
979efd532a6SDaniel Vetter 		return;
980efd532a6SDaniel Vetter 
9816396bb22SKees Cook 	b->legacy_io = kcalloc(2, sizeof(struct bin_attribute),
982f19aeb1fSBenjamin Herrenschmidt 			       GFP_ATOMIC);
983f19aeb1fSBenjamin Herrenschmidt 	if (!b->legacy_io)
984f19aeb1fSBenjamin Herrenschmidt 		goto kzalloc_err;
985f19aeb1fSBenjamin Herrenschmidt 
98662e877b8SStephen Rothwell 	sysfs_bin_attr_init(b->legacy_io);
987f19aeb1fSBenjamin Herrenschmidt 	b->legacy_io->attr.name = "legacy_io";
988f19aeb1fSBenjamin Herrenschmidt 	b->legacy_io->size = 0xffff;
989e2154044SKelsey Skunberg 	b->legacy_io->attr.mode = 0600;
990f19aeb1fSBenjamin Herrenschmidt 	b->legacy_io->read = pci_read_legacy_io;
991f19aeb1fSBenjamin Herrenschmidt 	b->legacy_io->write = pci_write_legacy_io;
992f19aeb1fSBenjamin Herrenschmidt 	b->legacy_io->mmap = pci_mmap_legacy_io;
993f06aff92SKrzysztof Wilczyński 	b->legacy_io->f_mapping = iomem_get_mapping;
99410a0ef39SIvan Kokshaysky 	pci_adjust_legacy_attr(b, pci_mmap_io);
995f19aeb1fSBenjamin Herrenschmidt 	error = device_create_bin_file(&b->dev, b->legacy_io);
996f19aeb1fSBenjamin Herrenschmidt 	if (error)
997f19aeb1fSBenjamin Herrenschmidt 		goto legacy_io_err;
998f19aeb1fSBenjamin Herrenschmidt 
999f19aeb1fSBenjamin Herrenschmidt 	/* Allocated above after the legacy_io struct */
1000f19aeb1fSBenjamin Herrenschmidt 	b->legacy_mem = b->legacy_io + 1;
10016757eca3SMel Gorman 	sysfs_bin_attr_init(b->legacy_mem);
1002f19aeb1fSBenjamin Herrenschmidt 	b->legacy_mem->attr.name = "legacy_mem";
1003f19aeb1fSBenjamin Herrenschmidt 	b->legacy_mem->size = 1024*1024;
1004e2154044SKelsey Skunberg 	b->legacy_mem->attr.mode = 0600;
1005f19aeb1fSBenjamin Herrenschmidt 	b->legacy_mem->mmap = pci_mmap_legacy_mem;
1006c6c3c570SLinus Torvalds 	b->legacy_mem->f_mapping = iomem_get_mapping;
100710a0ef39SIvan Kokshaysky 	pci_adjust_legacy_attr(b, pci_mmap_mem);
1008f19aeb1fSBenjamin Herrenschmidt 	error = device_create_bin_file(&b->dev, b->legacy_mem);
1009f19aeb1fSBenjamin Herrenschmidt 	if (error)
1010f19aeb1fSBenjamin Herrenschmidt 		goto legacy_mem_err;
1011f19aeb1fSBenjamin Herrenschmidt 
1012f19aeb1fSBenjamin Herrenschmidt 	return;
1013f19aeb1fSBenjamin Herrenschmidt 
1014f19aeb1fSBenjamin Herrenschmidt legacy_mem_err:
1015f19aeb1fSBenjamin Herrenschmidt 	device_remove_bin_file(&b->dev, b->legacy_io);
1016f19aeb1fSBenjamin Herrenschmidt legacy_io_err:
1017f19aeb1fSBenjamin Herrenschmidt 	kfree(b->legacy_io);
1018f19aeb1fSBenjamin Herrenschmidt 	b->legacy_io = NULL;
1019f19aeb1fSBenjamin Herrenschmidt kzalloc_err:
10207db4af43SBjorn Helgaas 	dev_warn(&b->dev, "could not create legacy I/O port and ISA memory resources in sysfs\n");
1021f19aeb1fSBenjamin Herrenschmidt }
1022f19aeb1fSBenjamin Herrenschmidt 
pci_remove_legacy_files(struct pci_bus * b)1023f19aeb1fSBenjamin Herrenschmidt void pci_remove_legacy_files(struct pci_bus *b)
1024f19aeb1fSBenjamin Herrenschmidt {
1025f19aeb1fSBenjamin Herrenschmidt 	if (b->legacy_io) {
1026f19aeb1fSBenjamin Herrenschmidt 		device_remove_bin_file(&b->dev, b->legacy_io);
1027f19aeb1fSBenjamin Herrenschmidt 		device_remove_bin_file(&b->dev, b->legacy_mem);
1028f19aeb1fSBenjamin Herrenschmidt 		kfree(b->legacy_io); /* both are allocated here */
1029f19aeb1fSBenjamin Herrenschmidt 	}
10301da177e4SLinus Torvalds }
10311da177e4SLinus Torvalds #endif /* HAVE_PCI_LEGACY */
10321da177e4SLinus Torvalds 
1033f7195824SDavid Woodhouse #if defined(HAVE_PCI_MMAP) || defined(ARCH_GENERIC_PCI_MMAP_RESOURCE)
1034b5ff7df3SLinus Torvalds 
pci_mmap_fits(struct pci_dev * pdev,int resno,struct vm_area_struct * vma,enum pci_mmap_api mmap_api)10353b519e4eSMartin Wilck int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma,
10363b519e4eSMartin Wilck 		  enum pci_mmap_api mmap_api)
1037b5ff7df3SLinus Torvalds {
10386bccc7f4SDavid Woodhouse 	unsigned long nr, start, size;
10396bccc7f4SDavid Woodhouse 	resource_size_t pci_start = 0, pci_end;
1040b5ff7df3SLinus Torvalds 
10413b519e4eSMartin Wilck 	if (pci_resource_len(pdev, resno) == 0)
10423b519e4eSMartin Wilck 		return 0;
104364b00175SLibin 	nr = vma_pages(vma);
1044b5ff7df3SLinus Torvalds 	start = vma->vm_pgoff;
104588e7df0bSEd Swierk 	size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1;
10466bccc7f4SDavid Woodhouse 	if (mmap_api == PCI_MMAP_PROCFS) {
10476bccc7f4SDavid Woodhouse 		pci_resource_to_user(pdev, resno, &pdev->resource[resno],
10486bccc7f4SDavid Woodhouse 				     &pci_start, &pci_end);
10496bccc7f4SDavid Woodhouse 		pci_start >>= PAGE_SHIFT;
10506bccc7f4SDavid Woodhouse 	}
10513b519e4eSMartin Wilck 	if (start >= pci_start && start < pci_start + size &&
10523b519e4eSMartin Wilck 			start + nr <= pci_start + size)
1053b5ff7df3SLinus Torvalds 		return 1;
1054b5ff7df3SLinus Torvalds 	return 0;
1055b5ff7df3SLinus Torvalds }
1056b5ff7df3SLinus Torvalds 
10571da177e4SLinus Torvalds /**
10581da177e4SLinus Torvalds  * pci_mmap_resource - map a PCI resource into user memory space
10591da177e4SLinus Torvalds  * @kobj: kobject for mapping
10601da177e4SLinus Torvalds  * @attr: struct bin_attribute for the file being mapped
10611da177e4SLinus Torvalds  * @vma: struct vm_area_struct passed into the mmap
106245aec1aeSvenkatesh.pallipadi@intel.com  * @write_combine: 1 for write_combine mapping
10631da177e4SLinus Torvalds  *
10641da177e4SLinus Torvalds  * Use the regular PCI mapping routines to map a PCI resource into userspace.
10651da177e4SLinus Torvalds  */
pci_mmap_resource(struct kobject * kobj,struct bin_attribute * attr,struct vm_area_struct * vma,int write_combine)10663c78bc61SRyan Desfosses static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
106745aec1aeSvenkatesh.pallipadi@intel.com 			     struct vm_area_struct *vma, int write_combine)
10681da177e4SLinus Torvalds {
1069554a6037SGeliang Tang 	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
1070dca40b18SDavid Woodhouse 	int bar = (unsigned long)attr->private;
10711da177e4SLinus Torvalds 	enum pci_mmap_state mmap_type;
1072dca40b18SDavid Woodhouse 	struct resource *res = &pdev->resource[bar];
1073eb627e17SMatthew Garrett 	int ret;
1074eb627e17SMatthew Garrett 
1075eb627e17SMatthew Garrett 	ret = security_locked_down(LOCKDOWN_PCI_ACCESS);
1076eb627e17SMatthew Garrett 	if (ret)
1077eb627e17SMatthew Garrett 		return ret;
10782311b1f2SMichael Ellerman 
1079ca620723SBjorn Helgaas 	if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start))
1080ca620723SBjorn Helgaas 		return -EINVAL;
1081ca620723SBjorn Helgaas 
10827a094909SBjorn Helgaas 	if (!pci_mmap_fits(pdev, bar, vma, PCI_MMAP_SYSFS))
1083b5ff7df3SLinus Torvalds 		return -EINVAL;
10847a094909SBjorn Helgaas 
10851da177e4SLinus Torvalds 	mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
1086f7195824SDavid Woodhouse 
1087f7195824SDavid Woodhouse 	return pci_mmap_resource_range(pdev, bar, vma, mmap_type, write_combine);
108845aec1aeSvenkatesh.pallipadi@intel.com }
108945aec1aeSvenkatesh.pallipadi@intel.com 
pci_mmap_resource_uc(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,struct vm_area_struct * vma)10903c78bc61SRyan Desfosses static int pci_mmap_resource_uc(struct file *filp, struct kobject *kobj,
10912c3c8beaSChris Wright 				struct bin_attribute *attr,
109245aec1aeSvenkatesh.pallipadi@intel.com 				struct vm_area_struct *vma)
109345aec1aeSvenkatesh.pallipadi@intel.com {
109445aec1aeSvenkatesh.pallipadi@intel.com 	return pci_mmap_resource(kobj, attr, vma, 0);
109545aec1aeSvenkatesh.pallipadi@intel.com }
109645aec1aeSvenkatesh.pallipadi@intel.com 
pci_mmap_resource_wc(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,struct vm_area_struct * vma)10973c78bc61SRyan Desfosses static int pci_mmap_resource_wc(struct file *filp, struct kobject *kobj,
10982c3c8beaSChris Wright 				struct bin_attribute *attr,
109945aec1aeSvenkatesh.pallipadi@intel.com 				struct vm_area_struct *vma)
110045aec1aeSvenkatesh.pallipadi@intel.com {
110145aec1aeSvenkatesh.pallipadi@intel.com 	return pci_mmap_resource(kobj, attr, vma, 1);
11021da177e4SLinus Torvalds }
11031da177e4SLinus Torvalds 
pci_resource_io(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t off,size_t count,bool write)11043c78bc61SRyan Desfosses static ssize_t pci_resource_io(struct file *filp, struct kobject *kobj,
11058633328bSAlex Williamson 			       struct bin_attribute *attr, char *buf,
11068633328bSAlex Williamson 			       loff_t off, size_t count, bool write)
11078633328bSAlex Williamson {
11085da1b588SNiklas Schnelle #ifdef CONFIG_HAS_IOPORT
1109554a6037SGeliang Tang 	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
1110dca40b18SDavid Woodhouse 	int bar = (unsigned long)attr->private;
11118633328bSAlex Williamson 	unsigned long port = off;
11128633328bSAlex Williamson 
1113dca40b18SDavid Woodhouse 	port += pci_resource_start(pdev, bar);
11148633328bSAlex Williamson 
1115dca40b18SDavid Woodhouse 	if (port > pci_resource_end(pdev, bar))
11168633328bSAlex Williamson 		return 0;
11178633328bSAlex Williamson 
1118dca40b18SDavid Woodhouse 	if (port + count - 1 > pci_resource_end(pdev, bar))
11198633328bSAlex Williamson 		return -EINVAL;
11208633328bSAlex Williamson 
11218633328bSAlex Williamson 	switch (count) {
11228633328bSAlex Williamson 	case 1:
11238633328bSAlex Williamson 		if (write)
11248633328bSAlex Williamson 			outb(*(u8 *)buf, port);
11258633328bSAlex Williamson 		else
11268633328bSAlex Williamson 			*(u8 *)buf = inb(port);
11278633328bSAlex Williamson 		return 1;
11288633328bSAlex Williamson 	case 2:
11298633328bSAlex Williamson 		if (write)
11308633328bSAlex Williamson 			outw(*(u16 *)buf, port);
11318633328bSAlex Williamson 		else
11328633328bSAlex Williamson 			*(u16 *)buf = inw(port);
11338633328bSAlex Williamson 		return 2;
11348633328bSAlex Williamson 	case 4:
11358633328bSAlex Williamson 		if (write)
11368633328bSAlex Williamson 			outl(*(u32 *)buf, port);
11378633328bSAlex Williamson 		else
11388633328bSAlex Williamson 			*(u32 *)buf = inl(port);
11398633328bSAlex Williamson 		return 4;
11408633328bSAlex Williamson 	}
11418633328bSAlex Williamson 	return -EINVAL;
11425da1b588SNiklas Schnelle #else
11435da1b588SNiklas Schnelle 	return -ENXIO;
11445da1b588SNiklas Schnelle #endif
11458633328bSAlex Williamson }
11468633328bSAlex Williamson 
pci_read_resource_io(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t off,size_t count)11473c78bc61SRyan Desfosses static ssize_t pci_read_resource_io(struct file *filp, struct kobject *kobj,
11488633328bSAlex Williamson 				    struct bin_attribute *attr, char *buf,
11498633328bSAlex Williamson 				    loff_t off, size_t count)
11508633328bSAlex Williamson {
11518633328bSAlex Williamson 	return pci_resource_io(filp, kobj, attr, buf, off, count, false);
11528633328bSAlex Williamson }
11538633328bSAlex Williamson 
pci_write_resource_io(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t off,size_t count)11543c78bc61SRyan Desfosses static ssize_t pci_write_resource_io(struct file *filp, struct kobject *kobj,
11558633328bSAlex Williamson 				     struct bin_attribute *attr, char *buf,
11568633328bSAlex Williamson 				     loff_t off, size_t count)
11578633328bSAlex Williamson {
1158eb627e17SMatthew Garrett 	int ret;
1159eb627e17SMatthew Garrett 
1160eb627e17SMatthew Garrett 	ret = security_locked_down(LOCKDOWN_PCI_ACCESS);
1161eb627e17SMatthew Garrett 	if (ret)
1162eb627e17SMatthew Garrett 		return ret;
1163eb627e17SMatthew Garrett 
11648633328bSAlex Williamson 	return pci_resource_io(filp, kobj, attr, buf, off, count, true);
11658633328bSAlex Williamson }
11668633328bSAlex Williamson 
11671da177e4SLinus Torvalds /**
1168b19441afSGreg Kroah-Hartman  * pci_remove_resource_files - cleanup resource files
1169cffb2fafSRandy Dunlap  * @pdev: dev to cleanup
1170b19441afSGreg Kroah-Hartman  *
1171cffb2fafSRandy Dunlap  * If we created resource files for @pdev, remove them from sysfs and
1172b19441afSGreg Kroah-Hartman  * free their resources.
1173b19441afSGreg Kroah-Hartman  */
pci_remove_resource_files(struct pci_dev * pdev)11743c78bc61SRyan Desfosses static void pci_remove_resource_files(struct pci_dev *pdev)
1175b19441afSGreg Kroah-Hartman {
1176b19441afSGreg Kroah-Hartman 	int i;
1177b19441afSGreg Kroah-Hartman 
1178c9c13ba4SDenis Efremov 	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
1179b19441afSGreg Kroah-Hartman 		struct bin_attribute *res_attr;
1180b19441afSGreg Kroah-Hartman 
1181b19441afSGreg Kroah-Hartman 		res_attr = pdev->res_attr[i];
1182b19441afSGreg Kroah-Hartman 		if (res_attr) {
1183b19441afSGreg Kroah-Hartman 			sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
1184b19441afSGreg Kroah-Hartman 			kfree(res_attr);
1185b19441afSGreg Kroah-Hartman 		}
118645aec1aeSvenkatesh.pallipadi@intel.com 
118745aec1aeSvenkatesh.pallipadi@intel.com 		res_attr = pdev->res_attr_wc[i];
118845aec1aeSvenkatesh.pallipadi@intel.com 		if (res_attr) {
118945aec1aeSvenkatesh.pallipadi@intel.com 			sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
119045aec1aeSvenkatesh.pallipadi@intel.com 			kfree(res_attr);
1191b19441afSGreg Kroah-Hartman 		}
1192b19441afSGreg Kroah-Hartman 	}
119345aec1aeSvenkatesh.pallipadi@intel.com }
119445aec1aeSvenkatesh.pallipadi@intel.com 
pci_create_attr(struct pci_dev * pdev,int num,int write_combine)119545aec1aeSvenkatesh.pallipadi@intel.com static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine)
119645aec1aeSvenkatesh.pallipadi@intel.com {
119745aec1aeSvenkatesh.pallipadi@intel.com 	/* allocate attribute structure, piggyback attribute name */
119845aec1aeSvenkatesh.pallipadi@intel.com 	int name_len = write_combine ? 13 : 10;
119945aec1aeSvenkatesh.pallipadi@intel.com 	struct bin_attribute *res_attr;
1200bd5174dfSBjorn Helgaas 	char *res_attr_name;
120145aec1aeSvenkatesh.pallipadi@intel.com 	int retval;
120245aec1aeSvenkatesh.pallipadi@intel.com 
120345aec1aeSvenkatesh.pallipadi@intel.com 	res_attr = kzalloc(sizeof(*res_attr) + name_len, GFP_ATOMIC);
1204bd5174dfSBjorn Helgaas 	if (!res_attr)
1205bd5174dfSBjorn Helgaas 		return -ENOMEM;
1206bd5174dfSBjorn Helgaas 
1207bd5174dfSBjorn Helgaas 	res_attr_name = (char *)(res_attr + 1);
120845aec1aeSvenkatesh.pallipadi@intel.com 
1209a07e4156SEric W. Biederman 	sysfs_bin_attr_init(res_attr);
121045aec1aeSvenkatesh.pallipadi@intel.com 	if (write_combine) {
121145aec1aeSvenkatesh.pallipadi@intel.com 		sprintf(res_attr_name, "resource%d_wc", num);
121245aec1aeSvenkatesh.pallipadi@intel.com 		res_attr->mmap = pci_mmap_resource_wc;
121345aec1aeSvenkatesh.pallipadi@intel.com 	} else {
121445aec1aeSvenkatesh.pallipadi@intel.com 		sprintf(res_attr_name, "resource%d", num);
12158633328bSAlex Williamson 		if (pci_resource_flags(pdev, num) & IORESOURCE_IO) {
12168633328bSAlex Williamson 			res_attr->read = pci_read_resource_io;
12178633328bSAlex Williamson 			res_attr->write = pci_write_resource_io;
1218e854d8b2SDavid Woodhouse 			if (arch_can_pci_mmap_io())
1219e854d8b2SDavid Woodhouse 				res_attr->mmap = pci_mmap_resource_uc;
1220e854d8b2SDavid Woodhouse 		} else {
1221e854d8b2SDavid Woodhouse 			res_attr->mmap = pci_mmap_resource_uc;
1222e854d8b2SDavid Woodhouse 		}
12238633328bSAlex Williamson 	}
1224636b21b5SDaniel Vetter 	if (res_attr->mmap)
1225f06aff92SKrzysztof Wilczyński 		res_attr->f_mapping = iomem_get_mapping;
122645aec1aeSvenkatesh.pallipadi@intel.com 	res_attr->attr.name = res_attr_name;
1227e2154044SKelsey Skunberg 	res_attr->attr.mode = 0600;
122845aec1aeSvenkatesh.pallipadi@intel.com 	res_attr->size = pci_resource_len(pdev, num);
1229dca40b18SDavid Woodhouse 	res_attr->private = (void *)(unsigned long)num;
123045aec1aeSvenkatesh.pallipadi@intel.com 	retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
1231aa382ffaSSascha Hauer 	if (retval) {
1232b562ec8fSBjorn Helgaas 		kfree(res_attr);
123345aec1aeSvenkatesh.pallipadi@intel.com 		return retval;
123445aec1aeSvenkatesh.pallipadi@intel.com 	}
1235b19441afSGreg Kroah-Hartman 
1236aa382ffaSSascha Hauer 	if (write_combine)
1237aa382ffaSSascha Hauer 		pdev->res_attr_wc[num] = res_attr;
1238aa382ffaSSascha Hauer 	else
1239aa382ffaSSascha Hauer 		pdev->res_attr[num] = res_attr;
1240aa382ffaSSascha Hauer 
1241aa382ffaSSascha Hauer 	return 0;
1242aa382ffaSSascha Hauer }
1243aa382ffaSSascha Hauer 
1244b19441afSGreg Kroah-Hartman /**
12451da177e4SLinus Torvalds  * pci_create_resource_files - create resource files in sysfs for @dev
1246cffb2fafSRandy Dunlap  * @pdev: dev in question
12471da177e4SLinus Torvalds  *
1248cffb2fafSRandy Dunlap  * Walk the resources in @pdev creating files for each resource available.
12491da177e4SLinus Torvalds  */
pci_create_resource_files(struct pci_dev * pdev)1250b19441afSGreg Kroah-Hartman static int pci_create_resource_files(struct pci_dev *pdev)
12511da177e4SLinus Torvalds {
12521da177e4SLinus Torvalds 	int i;
1253b19441afSGreg Kroah-Hartman 	int retval;
12541da177e4SLinus Torvalds 
12551da177e4SLinus Torvalds 	/* Expose the PCI resources from this device as files */
1256c9c13ba4SDenis Efremov 	for (i = 0; i < PCI_STD_NUM_BARS; i++) {
12571da177e4SLinus Torvalds 
12581da177e4SLinus Torvalds 		/* skip empty resources */
12591da177e4SLinus Torvalds 		if (!pci_resource_len(pdev, i))
12601da177e4SLinus Torvalds 			continue;
12611da177e4SLinus Torvalds 
126245aec1aeSvenkatesh.pallipadi@intel.com 		retval = pci_create_attr(pdev, i, 0);
126345aec1aeSvenkatesh.pallipadi@intel.com 		/* for prefetchable resources, create a WC mappable file */
1264ae749c7aSDavid Woodhouse 		if (!retval && arch_can_pci_mmap_wc() &&
1265ae749c7aSDavid Woodhouse 		    pdev->resource[i].flags & IORESOURCE_PREFETCH)
126645aec1aeSvenkatesh.pallipadi@intel.com 			retval = pci_create_attr(pdev, i, 1);
1267b19441afSGreg Kroah-Hartman 		if (retval) {
1268b19441afSGreg Kroah-Hartman 			pci_remove_resource_files(pdev);
1269b19441afSGreg Kroah-Hartman 			return retval;
1270b19441afSGreg Kroah-Hartman 		}
12711da177e4SLinus Torvalds 	}
1272b19441afSGreg Kroah-Hartman 	return 0;
12731da177e4SLinus Torvalds }
12748c46d543SClint Sbisa #else /* !(defined(HAVE_PCI_MMAP) || defined(ARCH_GENERIC_PCI_MMAP_RESOURCE)) */
pci_create_resource_files(struct pci_dev * dev)127510a0ef39SIvan Kokshaysky int __weak pci_create_resource_files(struct pci_dev *dev) { return 0; }
pci_remove_resource_files(struct pci_dev * dev)127610a0ef39SIvan Kokshaysky void __weak pci_remove_resource_files(struct pci_dev *dev) { return; }
12778c46d543SClint Sbisa #endif
12781da177e4SLinus Torvalds 
12791da177e4SLinus Torvalds /**
12801da177e4SLinus Torvalds  * pci_write_rom - used to enable access to the PCI ROM display
12812c3c8beaSChris Wright  * @filp: sysfs file
12821da177e4SLinus Torvalds  * @kobj: kernel object handle
1283cffb2fafSRandy Dunlap  * @bin_attr: struct bin_attribute for this file
12841da177e4SLinus Torvalds  * @buf: user input
12851da177e4SLinus Torvalds  * @off: file offset
12861da177e4SLinus Torvalds  * @count: number of byte in input
12871da177e4SLinus Torvalds  *
12881da177e4SLinus Torvalds  * writing anything except 0 enables it
12891da177e4SLinus Torvalds  */
pci_write_rom(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)12903c78bc61SRyan Desfosses static ssize_t pci_write_rom(struct file *filp, struct kobject *kobj,
12913c78bc61SRyan Desfosses 			     struct bin_attribute *bin_attr, char *buf,
12923c78bc61SRyan Desfosses 			     loff_t off, size_t count)
12931da177e4SLinus Torvalds {
1294554a6037SGeliang Tang 	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
12951da177e4SLinus Torvalds 
12961da177e4SLinus Torvalds 	if ((off ==  0) && (*buf == '0') && (count == 2))
12971da177e4SLinus Torvalds 		pdev->rom_attr_enabled = 0;
12981da177e4SLinus Torvalds 	else
12991da177e4SLinus Torvalds 		pdev->rom_attr_enabled = 1;
13001da177e4SLinus Torvalds 
13011da177e4SLinus Torvalds 	return count;
13021da177e4SLinus Torvalds }
13031da177e4SLinus Torvalds 
13041da177e4SLinus Torvalds /**
13051da177e4SLinus Torvalds  * pci_read_rom - read a PCI ROM
13062c3c8beaSChris Wright  * @filp: sysfs file
13071da177e4SLinus Torvalds  * @kobj: kernel object handle
1308cffb2fafSRandy Dunlap  * @bin_attr: struct bin_attribute for this file
13091da177e4SLinus Torvalds  * @buf: where to put the data we read from the ROM
13101da177e4SLinus Torvalds  * @off: file offset
13111da177e4SLinus Torvalds  * @count: number of bytes to read
13121da177e4SLinus Torvalds  *
13131da177e4SLinus Torvalds  * Put @count bytes starting at @off into @buf from the ROM in the PCI
13141da177e4SLinus Torvalds  * device corresponding to @kobj.
13151da177e4SLinus Torvalds  */
pci_read_rom(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)13163c78bc61SRyan Desfosses static ssize_t pci_read_rom(struct file *filp, struct kobject *kobj,
13173c78bc61SRyan Desfosses 			    struct bin_attribute *bin_attr, char *buf,
13183c78bc61SRyan Desfosses 			    loff_t off, size_t count)
13191da177e4SLinus Torvalds {
1320554a6037SGeliang Tang 	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
13211da177e4SLinus Torvalds 	void __iomem *rom;
13221da177e4SLinus Torvalds 	size_t size;
13231da177e4SLinus Torvalds 
13241da177e4SLinus Torvalds 	if (!pdev->rom_attr_enabled)
13251da177e4SLinus Torvalds 		return -EINVAL;
13261da177e4SLinus Torvalds 
13271da177e4SLinus Torvalds 	rom = pci_map_rom(pdev, &size);	/* size starts out as PCI window size */
132897c44836STimothy S. Nelson 	if (!rom || !size)
132997c44836STimothy S. Nelson 		return -EIO;
13301da177e4SLinus Torvalds 
13311da177e4SLinus Torvalds 	if (off >= size)
13321da177e4SLinus Torvalds 		count = 0;
13331da177e4SLinus Torvalds 	else {
13341da177e4SLinus Torvalds 		if (off + count > size)
13351da177e4SLinus Torvalds 			count = size - off;
13361da177e4SLinus Torvalds 
13371da177e4SLinus Torvalds 		memcpy_fromio(buf, rom + off, count);
13381da177e4SLinus Torvalds 	}
13391da177e4SLinus Torvalds 	pci_unmap_rom(pdev, rom);
13401da177e4SLinus Torvalds 
13411da177e4SLinus Torvalds 	return count;
13421da177e4SLinus Torvalds }
1343527139d7SKrzysztof Wilczyński static BIN_ATTR(rom, 0600, pci_read_rom, pci_write_rom, 0);
13441da177e4SLinus Torvalds 
1345527139d7SKrzysztof Wilczyński static struct bin_attribute *pci_dev_rom_attrs[] = {
1346527139d7SKrzysztof Wilczyński 	&bin_attr_rom,
1347527139d7SKrzysztof Wilczyński 	NULL,
13481da177e4SLinus Torvalds };
13491da177e4SLinus Torvalds 
pci_dev_rom_attr_is_visible(struct kobject * kobj,struct bin_attribute * a,int n)1350527139d7SKrzysztof Wilczyński static umode_t pci_dev_rom_attr_is_visible(struct kobject *kobj,
1351527139d7SKrzysztof Wilczyński 					   struct bin_attribute *a, int n)
1352527139d7SKrzysztof Wilczyński {
1353527139d7SKrzysztof Wilczyński 	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
1354527139d7SKrzysztof Wilczyński 	size_t rom_size;
1355527139d7SKrzysztof Wilczyński 
1356527139d7SKrzysztof Wilczyński 	/* If the device has a ROM, try to expose it in sysfs. */
1357527139d7SKrzysztof Wilczyński 	rom_size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
1358527139d7SKrzysztof Wilczyński 	if (!rom_size)
1359527139d7SKrzysztof Wilczyński 		return 0;
1360527139d7SKrzysztof Wilczyński 
1361527139d7SKrzysztof Wilczyński 	a->size = rom_size;
1362527139d7SKrzysztof Wilczyński 
1363527139d7SKrzysztof Wilczyński 	return a->attr.mode;
1364527139d7SKrzysztof Wilczyński }
1365527139d7SKrzysztof Wilczyński 
1366527139d7SKrzysztof Wilczyński static const struct attribute_group pci_dev_rom_attr_group = {
1367527139d7SKrzysztof Wilczyński 	.bin_attrs = pci_dev_rom_attrs,
1368527139d7SKrzysztof Wilczyński 	.is_bin_visible = pci_dev_rom_attr_is_visible,
13691da177e4SLinus Torvalds };
13701da177e4SLinus Torvalds 
reset_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)13713c78bc61SRyan Desfosses static ssize_t reset_store(struct device *dev, struct device_attribute *attr,
13723c78bc61SRyan Desfosses 			   const char *buf, size_t count)
1373711d5779SMichael S. Tsirkin {
1374711d5779SMichael S. Tsirkin 	struct pci_dev *pdev = to_pci_dev(dev);
1375711d5779SMichael S. Tsirkin 	unsigned long val;
137636f354ecSKrzysztof Wilczyński 	ssize_t result;
1377711d5779SMichael S. Tsirkin 
137836f354ecSKrzysztof Wilczyński 	if (kstrtoul(buf, 0, &val) < 0)
137936f354ecSKrzysztof Wilczyński 		return -EINVAL;
1380711d5779SMichael S. Tsirkin 
1381711d5779SMichael S. Tsirkin 	if (val != 1)
1382711d5779SMichael S. Tsirkin 		return -EINVAL;
1383447c5dd7SMichal Schmidt 
138482c3fbffSLukas Wunner 	pm_runtime_get_sync(dev);
1385447c5dd7SMichal Schmidt 	result = pci_reset_function(pdev);
138682c3fbffSLukas Wunner 	pm_runtime_put(dev);
1387447c5dd7SMichal Schmidt 	if (result < 0)
1388447c5dd7SMichal Schmidt 		return result;
1389447c5dd7SMichal Schmidt 
1390447c5dd7SMichal Schmidt 	return count;
1391711d5779SMichael S. Tsirkin }
1392f42c35eaSKrzysztof Wilczyński static DEVICE_ATTR_WO(reset);
1393711d5779SMichael S. Tsirkin 
1394f42c35eaSKrzysztof Wilczyński static struct attribute *pci_dev_reset_attrs[] = {
1395f42c35eaSKrzysztof Wilczyński 	&dev_attr_reset.attr,
1396f42c35eaSKrzysztof Wilczyński 	NULL,
1397f42c35eaSKrzysztof Wilczyński };
1398711d5779SMichael S. Tsirkin 
pci_dev_reset_attr_is_visible(struct kobject * kobj,struct attribute * a,int n)1399f42c35eaSKrzysztof Wilczyński static umode_t pci_dev_reset_attr_is_visible(struct kobject *kobj,
1400f42c35eaSKrzysztof Wilczyński 					     struct attribute *a, int n)
1401280c73d3SZhao, Yu {
1402f42c35eaSKrzysztof Wilczyński 	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
1403280c73d3SZhao, Yu 
14044ec36dfeSAmey Narkhede 	if (!pci_reset_supported(pdev))
1405280c73d3SZhao, Yu 		return 0;
1406711d5779SMichael S. Tsirkin 
1407f42c35eaSKrzysztof Wilczyński 	return a->mode;
1408280c73d3SZhao, Yu }
1409280c73d3SZhao, Yu 
1410f42c35eaSKrzysztof Wilczyński static const struct attribute_group pci_dev_reset_attr_group = {
1411f42c35eaSKrzysztof Wilczyński 	.attrs = pci_dev_reset_attrs,
1412f42c35eaSKrzysztof Wilczyński 	.is_visible = pci_dev_reset_attr_is_visible,
1413f42c35eaSKrzysztof Wilczyński };
1414f42c35eaSKrzysztof Wilczyński 
141591fa1277SAlex Williamson #define pci_dev_resource_resize_attr(n)					\
141691fa1277SAlex Williamson static ssize_t resource##n##_resize_show(struct device *dev,		\
141791fa1277SAlex Williamson 					 struct device_attribute *attr,	\
141891fa1277SAlex Williamson 					 char * buf)			\
141991fa1277SAlex Williamson {									\
142091fa1277SAlex Williamson 	struct pci_dev *pdev = to_pci_dev(dev);				\
142191fa1277SAlex Williamson 	ssize_t ret;							\
142291fa1277SAlex Williamson 									\
142391fa1277SAlex Williamson 	pci_config_pm_runtime_get(pdev);				\
142491fa1277SAlex Williamson 									\
142591fa1277SAlex Williamson 	ret = sysfs_emit(buf, "%016llx\n",				\
142691fa1277SAlex Williamson 			 (u64)pci_rebar_get_possible_sizes(pdev, n));	\
142791fa1277SAlex Williamson 									\
142891fa1277SAlex Williamson 	pci_config_pm_runtime_put(pdev);				\
142991fa1277SAlex Williamson 									\
143091fa1277SAlex Williamson 	return ret;							\
143191fa1277SAlex Williamson }									\
143291fa1277SAlex Williamson 									\
143391fa1277SAlex Williamson static ssize_t resource##n##_resize_store(struct device *dev,		\
143491fa1277SAlex Williamson 					  struct device_attribute *attr,\
143591fa1277SAlex Williamson 					  const char *buf, size_t count)\
143691fa1277SAlex Williamson {									\
143791fa1277SAlex Williamson 	struct pci_dev *pdev = to_pci_dev(dev);				\
143891fa1277SAlex Williamson 	unsigned long size, flags;					\
143991fa1277SAlex Williamson 	int ret, i;							\
144091fa1277SAlex Williamson 	u16 cmd;							\
144191fa1277SAlex Williamson 									\
144291fa1277SAlex Williamson 	if (kstrtoul(buf, 0, &size) < 0)				\
144391fa1277SAlex Williamson 		return -EINVAL;						\
144491fa1277SAlex Williamson 									\
144591fa1277SAlex Williamson 	device_lock(dev);						\
144691fa1277SAlex Williamson 	if (dev->driver) {						\
144791fa1277SAlex Williamson 		ret = -EBUSY;						\
144891fa1277SAlex Williamson 		goto unlock;						\
144991fa1277SAlex Williamson 	}								\
145091fa1277SAlex Williamson 									\
145191fa1277SAlex Williamson 	pci_config_pm_runtime_get(pdev);				\
145291fa1277SAlex Williamson 									\
145391fa1277SAlex Williamson 	if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {		\
145491fa1277SAlex Williamson 		ret = aperture_remove_conflicting_pci_devices(pdev,	\
145591fa1277SAlex Williamson 						"resourceN_resize");	\
145691fa1277SAlex Williamson 		if (ret)						\
145791fa1277SAlex Williamson 			goto pm_put;					\
145891fa1277SAlex Williamson 	}								\
145991fa1277SAlex Williamson 									\
146091fa1277SAlex Williamson 	pci_read_config_word(pdev, PCI_COMMAND, &cmd);			\
146191fa1277SAlex Williamson 	pci_write_config_word(pdev, PCI_COMMAND,			\
146291fa1277SAlex Williamson 			      cmd & ~PCI_COMMAND_MEMORY);		\
146391fa1277SAlex Williamson 									\
146491fa1277SAlex Williamson 	flags = pci_resource_flags(pdev, n);				\
146591fa1277SAlex Williamson 									\
146691fa1277SAlex Williamson 	pci_remove_resource_files(pdev);				\
146791fa1277SAlex Williamson 									\
146891fa1277SAlex Williamson 	for (i = 0; i < PCI_STD_NUM_BARS; i++) {			\
146991fa1277SAlex Williamson 		if (pci_resource_len(pdev, i) &&			\
147091fa1277SAlex Williamson 		    pci_resource_flags(pdev, i) == flags)		\
147191fa1277SAlex Williamson 			pci_release_resource(pdev, i);			\
147291fa1277SAlex Williamson 	}								\
147391fa1277SAlex Williamson 									\
147491fa1277SAlex Williamson 	ret = pci_resize_resource(pdev, n, size);			\
147591fa1277SAlex Williamson 									\
147691fa1277SAlex Williamson 	pci_assign_unassigned_bus_resources(pdev->bus);			\
147791fa1277SAlex Williamson 									\
147891fa1277SAlex Williamson 	if (pci_create_resource_files(pdev))				\
147991fa1277SAlex Williamson 		pci_warn(pdev, "Failed to recreate resource files after BAR resizing\n");\
148091fa1277SAlex Williamson 									\
148191fa1277SAlex Williamson 	pci_write_config_word(pdev, PCI_COMMAND, cmd);			\
148291fa1277SAlex Williamson pm_put:									\
148391fa1277SAlex Williamson 	pci_config_pm_runtime_put(pdev);				\
148491fa1277SAlex Williamson unlock:									\
148591fa1277SAlex Williamson 	device_unlock(dev);						\
148691fa1277SAlex Williamson 									\
148791fa1277SAlex Williamson 	return ret ? ret : count;					\
148891fa1277SAlex Williamson }									\
148991fa1277SAlex Williamson static DEVICE_ATTR_RW(resource##n##_resize)
149091fa1277SAlex Williamson 
149191fa1277SAlex Williamson pci_dev_resource_resize_attr(0);
149291fa1277SAlex Williamson pci_dev_resource_resize_attr(1);
149391fa1277SAlex Williamson pci_dev_resource_resize_attr(2);
149491fa1277SAlex Williamson pci_dev_resource_resize_attr(3);
149591fa1277SAlex Williamson pci_dev_resource_resize_attr(4);
149691fa1277SAlex Williamson pci_dev_resource_resize_attr(5);
149791fa1277SAlex Williamson 
149891fa1277SAlex Williamson static struct attribute *resource_resize_attrs[] = {
149991fa1277SAlex Williamson 	&dev_attr_resource0_resize.attr,
150091fa1277SAlex Williamson 	&dev_attr_resource1_resize.attr,
150191fa1277SAlex Williamson 	&dev_attr_resource2_resize.attr,
150291fa1277SAlex Williamson 	&dev_attr_resource3_resize.attr,
150391fa1277SAlex Williamson 	&dev_attr_resource4_resize.attr,
150491fa1277SAlex Williamson 	&dev_attr_resource5_resize.attr,
150591fa1277SAlex Williamson 	NULL,
150691fa1277SAlex Williamson };
150791fa1277SAlex Williamson 
resource_resize_is_visible(struct kobject * kobj,struct attribute * a,int n)150891fa1277SAlex Williamson static umode_t resource_resize_is_visible(struct kobject *kobj,
150991fa1277SAlex Williamson 					  struct attribute *a, int n)
151091fa1277SAlex Williamson {
151191fa1277SAlex Williamson 	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
151291fa1277SAlex Williamson 
151391fa1277SAlex Williamson 	return pci_rebar_get_current_size(pdev, n) < 0 ? 0 : a->mode;
151491fa1277SAlex Williamson }
151591fa1277SAlex Williamson 
151691fa1277SAlex Williamson static const struct attribute_group pci_dev_resource_resize_group = {
151791fa1277SAlex Williamson 	.attrs = resource_resize_attrs,
151891fa1277SAlex Williamson 	.is_visible = resource_resize_is_visible,
151991fa1277SAlex Williamson };
152091fa1277SAlex Williamson 
pci_create_sysfs_dev_files(struct pci_dev * pdev)1521b19441afSGreg Kroah-Hartman int __must_check pci_create_sysfs_dev_files(struct pci_dev *pdev)
15221da177e4SLinus Torvalds {
15231da177e4SLinus Torvalds 	if (!sysfs_initialized)
15241da177e4SLinus Torvalds 		return -EACCES;
15251da177e4SLinus Torvalds 
1526506140f9SKrzysztof Wilczyński 	return pci_create_resource_files(pdev);
1527280c73d3SZhao, Yu }
1528280c73d3SZhao, Yu 
15291da177e4SLinus Torvalds /**
15301da177e4SLinus Torvalds  * pci_remove_sysfs_dev_files - cleanup PCI specific sysfs files
15311da177e4SLinus Torvalds  * @pdev: device whose entries we should free
15321da177e4SLinus Torvalds  *
15331da177e4SLinus Torvalds  * Cleanup when @pdev is removed from sysfs.
15341da177e4SLinus Torvalds  */
pci_remove_sysfs_dev_files(struct pci_dev * pdev)15351da177e4SLinus Torvalds void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
15361da177e4SLinus Torvalds {
1537d67afe5eSDavid Miller 	if (!sysfs_initialized)
1538d67afe5eSDavid Miller 		return;
1539d67afe5eSDavid Miller 
15401da177e4SLinus Torvalds 	pci_remove_resource_files(pdev);
15411da177e4SLinus Torvalds }
15421da177e4SLinus Torvalds 
pci_sysfs_init(void)15431da177e4SLinus Torvalds static int __init pci_sysfs_init(void)
15441da177e4SLinus Torvalds {
15451da177e4SLinus Torvalds 	struct pci_dev *pdev = NULL;
1546efd532a6SDaniel Vetter 	struct pci_bus *pbus = NULL;
1547b19441afSGreg Kroah-Hartman 	int retval;
15481da177e4SLinus Torvalds 
15491da177e4SLinus Torvalds 	sysfs_initialized = 1;
1550b19441afSGreg Kroah-Hartman 	for_each_pci_dev(pdev) {
1551b19441afSGreg Kroah-Hartman 		retval = pci_create_sysfs_dev_files(pdev);
1552151fc5dfSJulia Lawall 		if (retval) {
1553151fc5dfSJulia Lawall 			pci_dev_put(pdev);
1554b19441afSGreg Kroah-Hartman 			return retval;
1555b19441afSGreg Kroah-Hartman 		}
1556151fc5dfSJulia Lawall 	}
15571da177e4SLinus Torvalds 
1558efd532a6SDaniel Vetter 	while ((pbus = pci_find_next_bus(pbus)))
1559efd532a6SDaniel Vetter 		pci_create_legacy_files(pbus);
1560efd532a6SDaniel Vetter 
15611da177e4SLinus Torvalds 	return 0;
15621da177e4SLinus Torvalds }
156340ee9e9fSJesse Barnes late_initcall(pci_sysfs_init);
15644e15c46bSYinghai Lu 
15654e15c46bSYinghai Lu static struct attribute *pci_dev_dev_attrs[] = {
15668bdfa145SKelsey Skunberg 	&dev_attr_boot_vga.attr,
15674e15c46bSYinghai Lu 	NULL,
15684e15c46bSYinghai Lu };
15694e15c46bSYinghai Lu 
pci_dev_attrs_are_visible(struct kobject * kobj,struct attribute * a,int n)15704e15c46bSYinghai Lu static umode_t pci_dev_attrs_are_visible(struct kobject *kobj,
15714e15c46bSYinghai Lu 					 struct attribute *a, int n)
15724e15c46bSYinghai Lu {
1573554a6037SGeliang Tang 	struct device *dev = kobj_to_dev(kobj);
1574625e1d59SYinghai Lu 	struct pci_dev *pdev = to_pci_dev(dev);
1575625e1d59SYinghai Lu 
15768bdfa145SKelsey Skunberg 	if (a == &dev_attr_boot_vga.attr)
1577625e1d59SYinghai Lu 		if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
1578625e1d59SYinghai Lu 			return 0;
1579625e1d59SYinghai Lu 
15804e15c46bSYinghai Lu 	return a->mode;
15814e15c46bSYinghai Lu }
15824e15c46bSYinghai Lu 
1583dfab88beSJiang Liu static struct attribute *pci_dev_hp_attrs[] = {
15848bdfa145SKelsey Skunberg 	&dev_attr_remove.attr,
15854e2b7943SKelsey Skunberg 	&dev_attr_dev_rescan.attr,
1586dfab88beSJiang Liu 	NULL,
1587dfab88beSJiang Liu };
1588dfab88beSJiang Liu 
pci_dev_hp_attrs_are_visible(struct kobject * kobj,struct attribute * a,int n)1589dfab88beSJiang Liu static umode_t pci_dev_hp_attrs_are_visible(struct kobject *kobj,
1590dfab88beSJiang Liu 					    struct attribute *a, int n)
1591dfab88beSJiang Liu {
1592554a6037SGeliang Tang 	struct device *dev = kobj_to_dev(kobj);
1593dfab88beSJiang Liu 	struct pci_dev *pdev = to_pci_dev(dev);
1594dfab88beSJiang Liu 
1595dfab88beSJiang Liu 	if (pdev->is_virtfn)
1596dfab88beSJiang Liu 		return 0;
1597dfab88beSJiang Liu 
1598dfab88beSJiang Liu 	return a->mode;
1599dfab88beSJiang Liu }
1600dfab88beSJiang Liu 
pci_bridge_attrs_are_visible(struct kobject * kobj,struct attribute * a,int n)160156c1af46SWong Vee Khee static umode_t pci_bridge_attrs_are_visible(struct kobject *kobj,
160256c1af46SWong Vee Khee 					    struct attribute *a, int n)
160356c1af46SWong Vee Khee {
160456c1af46SWong Vee Khee 	struct device *dev = kobj_to_dev(kobj);
160556c1af46SWong Vee Khee 	struct pci_dev *pdev = to_pci_dev(dev);
160656c1af46SWong Vee Khee 
160756c1af46SWong Vee Khee 	if (pci_is_bridge(pdev))
160856c1af46SWong Vee Khee 		return a->mode;
160956c1af46SWong Vee Khee 
161056c1af46SWong Vee Khee 	return 0;
161156c1af46SWong Vee Khee }
161256c1af46SWong Vee Khee 
pcie_dev_attrs_are_visible(struct kobject * kobj,struct attribute * a,int n)161356c1af46SWong Vee Khee static umode_t pcie_dev_attrs_are_visible(struct kobject *kobj,
161456c1af46SWong Vee Khee 					  struct attribute *a, int n)
161556c1af46SWong Vee Khee {
161656c1af46SWong Vee Khee 	struct device *dev = kobj_to_dev(kobj);
161756c1af46SWong Vee Khee 	struct pci_dev *pdev = to_pci_dev(dev);
161856c1af46SWong Vee Khee 
161956c1af46SWong Vee Khee 	if (pci_is_pcie(pdev))
162056c1af46SWong Vee Khee 		return a->mode;
162156c1af46SWong Vee Khee 
162256c1af46SWong Vee Khee 	return 0;
162356c1af46SWong Vee Khee }
162456c1af46SWong Vee Khee 
162556c1af46SWong Vee Khee static const struct attribute_group pci_dev_group = {
162656c1af46SWong Vee Khee 	.attrs = pci_dev_attrs,
162756c1af46SWong Vee Khee };
162856c1af46SWong Vee Khee 
162956c1af46SWong Vee Khee const struct attribute_group *pci_dev_groups[] = {
163056c1af46SWong Vee Khee 	&pci_dev_group,
1631e1d3f326SKrzysztof Wilczyński 	&pci_dev_config_attr_group,
1632527139d7SKrzysztof Wilczyński 	&pci_dev_rom_attr_group,
1633f42c35eaSKrzysztof Wilczyński 	&pci_dev_reset_attr_group,
1634d88f521dSAmey Narkhede 	&pci_dev_reset_method_attr_group,
1635d93f8399SKrzysztof Wilczyński 	&pci_dev_vpd_attr_group,
1636506140f9SKrzysztof Wilczyński #ifdef CONFIG_DMI
1637506140f9SKrzysztof Wilczyński 	&pci_dev_smbios_attr_group,
1638506140f9SKrzysztof Wilczyński #endif
1639506140f9SKrzysztof Wilczyński #ifdef CONFIG_ACPI
1640506140f9SKrzysztof Wilczyński 	&pci_dev_acpi_attr_group,
1641506140f9SKrzysztof Wilczyński #endif
164291fa1277SAlex Williamson 	&pci_dev_resource_resize_group,
164356c1af46SWong Vee Khee 	NULL,
164456c1af46SWong Vee Khee };
164556c1af46SWong Vee Khee 
1646e7ea9825SArvind Yadav static const struct attribute_group pci_dev_hp_attr_group = {
1647dfab88beSJiang Liu 	.attrs = pci_dev_hp_attrs,
1648dfab88beSJiang Liu 	.is_visible = pci_dev_hp_attrs_are_visible,
1649dfab88beSJiang Liu };
1650dfab88beSJiang Liu 
1651e7ea9825SArvind Yadav static const struct attribute_group pci_dev_attr_group = {
16524e15c46bSYinghai Lu 	.attrs = pci_dev_dev_attrs,
16534e15c46bSYinghai Lu 	.is_visible = pci_dev_attrs_are_visible,
16544e15c46bSYinghai Lu };
16554e15c46bSYinghai Lu 
1656e7ea9825SArvind Yadav static const struct attribute_group pci_bridge_attr_group = {
165756c1af46SWong Vee Khee 	.attrs = pci_bridge_attrs,
165856c1af46SWong Vee Khee 	.is_visible = pci_bridge_attrs_are_visible,
165956c1af46SWong Vee Khee };
166056c1af46SWong Vee Khee 
1661e7ea9825SArvind Yadav static const struct attribute_group pcie_dev_attr_group = {
166256c1af46SWong Vee Khee 	.attrs = pcie_dev_attrs,
166356c1af46SWong Vee Khee 	.is_visible = pcie_dev_attrs_are_visible,
166456c1af46SWong Vee Khee };
166556c1af46SWong Vee Khee 
16664e15c46bSYinghai Lu static const struct attribute_group *pci_dev_attr_groups[] = {
16674e15c46bSYinghai Lu 	&pci_dev_attr_group,
1668dfab88beSJiang Liu 	&pci_dev_hp_attr_group,
16691789382aSDonald Dutile #ifdef CONFIG_PCI_IOV
1670c3d5c2d9SLeon Romanovsky 	&sriov_pf_dev_attr_group,
1671c3d5c2d9SLeon Romanovsky 	&sriov_vf_dev_attr_group,
16721789382aSDonald Dutile #endif
167356c1af46SWong Vee Khee 	&pci_bridge_attr_group,
167456c1af46SWong Vee Khee 	&pcie_dev_attr_group,
167581aa5206SRajat Jain #ifdef CONFIG_PCIEAER
167681aa5206SRajat Jain 	&aer_stats_attr_group,
167781aa5206SRajat Jain #endif
167872ea91afSHeiner Kallweit #ifdef CONFIG_PCIEASPM
167972ea91afSHeiner Kallweit 	&aspm_ctrl_attr_group,
168072ea91afSHeiner Kallweit #endif
16814e15c46bSYinghai Lu 	NULL,
16824e15c46bSYinghai Lu };
16834e15c46bSYinghai Lu 
168469f2dc24SBhumika Goyal const struct device_type pci_dev_type = {
16854e15c46bSYinghai Lu 	.groups = pci_dev_attr_groups,
16864e15c46bSYinghai Lu };
1687