blob: d2f1354fd189cfee66b1f2e57509064f483ed4ac [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * drivers/pci/pci-sysfs.c
3 *
4 * (C) Copyright 2002-2004 Greg Kroah-Hartman <greg@kroah.com>
5 * (C) Copyright 2002-2004 IBM Corp.
6 * (C) Copyright 2003 Matthew Wilcox
7 * (C) Copyright 2003 Hewlett-Packard
8 * (C) Copyright 2004 Jon Smirl <jonsmirl@yahoo.com>
9 * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <jbarnes@sgi.com>
10 *
11 * File attributes for PCI devices
12 *
13 * Modeled after usb's driverfs.c
14 *
15 */
16
17
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/kernel.h>
Linus Torvaldsb5ff7df2008-10-02 18:52:51 -070019#include <linux/sched.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <linux/pci.h>
21#include <linux/stat.h>
22#include <linux/topology.h>
23#include <linux/mm.h>
Alexey Dobriyanaa0ac362007-07-15 23:40:39 -070024#include <linux/capability.h>
Shaohua Li7d715a62008-02-25 09:46:41 +080025#include <linux/pci-aspm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include "pci.h"
27
28static int sysfs_initialized; /* = 0 */
29
30/* show configuration fields */
31#define pci_config_attr(field, format_string) \
32static ssize_t \
Yani Ioannoue404e272005-05-17 06:42:58 -040033field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
Linus Torvalds1da177e2005-04-16 15:20:36 -070034{ \
35 struct pci_dev *pdev; \
36 \
37 pdev = to_pci_dev (dev); \
38 return sprintf (buf, format_string, pdev->field); \
39}
40
41pci_config_attr(vendor, "0x%04x\n");
42pci_config_attr(device, "0x%04x\n");
43pci_config_attr(subsystem_vendor, "0x%04x\n");
44pci_config_attr(subsystem_device, "0x%04x\n");
45pci_config_attr(class, "0x%06x\n");
46pci_config_attr(irq, "%u\n");
47
Doug Thompsonbdee9d92006-06-14 16:59:48 -070048static ssize_t broken_parity_status_show(struct device *dev,
49 struct device_attribute *attr,
50 char *buf)
51{
52 struct pci_dev *pdev = to_pci_dev(dev);
53 return sprintf (buf, "%u\n", pdev->broken_parity_status);
54}
55
56static ssize_t broken_parity_status_store(struct device *dev,
57 struct device_attribute *attr,
58 const char *buf, size_t count)
59{
60 struct pci_dev *pdev = to_pci_dev(dev);
Trent Piepho92425a42008-11-30 17:10:12 -080061 unsigned long val;
Doug Thompsonbdee9d92006-06-14 16:59:48 -070062
Trent Piepho92425a42008-11-30 17:10:12 -080063 if (strict_strtoul(buf, 0, &val) < 0)
64 return -EINVAL;
65
66 pdev->broken_parity_status = !!val;
67
68 return count;
Doug Thompsonbdee9d92006-06-14 16:59:48 -070069}
70
Alan Cox4327edf2005-09-10 00:25:49 -070071static ssize_t local_cpus_show(struct device *dev,
72 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -070073{
Alan Cox4327edf2005-09-10 00:25:49 -070074 cpumask_t mask;
75 int len;
76
77 mask = pcibus_to_cpumask(to_pci_dev(dev)->bus);
Rusty Russell29c01772008-12-13 21:20:25 +103078 len = cpumask_scnprintf(buf, PAGE_SIZE-2, &mask);
Mike Travis39106dc2008-04-08 11:43:03 -070079 buf[len++] = '\n';
80 buf[len] = '\0';
81 return len;
82}
83
84
85static ssize_t local_cpulist_show(struct device *dev,
86 struct device_attribute *attr, char *buf)
87{
88 cpumask_t mask;
89 int len;
90
91 mask = pcibus_to_cpumask(to_pci_dev(dev)->bus);
Rusty Russell29c01772008-12-13 21:20:25 +103092 len = cpulist_scnprintf(buf, PAGE_SIZE-2, &mask);
Mike Travis39106dc2008-04-08 11:43:03 -070093 buf[len++] = '\n';
94 buf[len] = '\0';
95 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096}
97
98/* show resources */
99static ssize_t
Yani Ioannoue404e272005-05-17 06:42:58 -0400100resource_show(struct device * dev, struct device_attribute *attr, char * buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101{
102 struct pci_dev * pci_dev = to_pci_dev(dev);
103 char * str = buf;
104 int i;
105 int max = 7;
Greg Kroah-Hartmane31dd6e2006-06-12 17:06:02 -0700106 resource_size_t start, end;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
108 if (pci_dev->subordinate)
109 max = DEVICE_COUNT_RESOURCE;
110
111 for (i = 0; i < max; i++) {
Michael Ellerman2311b1f2005-05-13 17:44:10 +1000112 struct resource *res = &pci_dev->resource[i];
113 pci_resource_to_user(pci_dev, i, res, &start, &end);
114 str += sprintf(str,"0x%016llx 0x%016llx 0x%016llx\n",
115 (unsigned long long)start,
116 (unsigned long long)end,
117 (unsigned long long)res->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 }
119 return (str - buf);
120}
121
Greg Kroah-Hartman87c8a442005-06-19 12:21:43 +0200122static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
Greg KH98885492005-05-05 11:57:25 -0700123{
124 struct pci_dev *pci_dev = to_pci_dev(dev);
125
126 return sprintf(buf, "pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n",
127 pci_dev->vendor, pci_dev->device,
128 pci_dev->subsystem_vendor, pci_dev->subsystem_device,
129 (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8),
130 (u8)(pci_dev->class));
131}
Inaky Perez-Gonzalezbae94d02006-11-22 12:40:31 -0800132
133static ssize_t is_enabled_store(struct device *dev,
134 struct device_attribute *attr, const char *buf,
135 size_t count)
Arjan van de Ven9f125d32006-04-29 10:59:08 +0200136{
137 struct pci_dev *pdev = to_pci_dev(dev);
Trent Piepho92425a42008-11-30 17:10:12 -0800138 unsigned long val;
139 ssize_t result = strict_strtoul(buf, 0, &val);
140
141 if (result < 0)
142 return result;
Arjan van de Ven9f125d32006-04-29 10:59:08 +0200143
144 /* this can crash the machine when done on the "wrong" device */
145 if (!capable(CAP_SYS_ADMIN))
Trent Piepho92425a42008-11-30 17:10:12 -0800146 return -EPERM;
Arjan van de Ven9f125d32006-04-29 10:59:08 +0200147
Trent Piepho92425a42008-11-30 17:10:12 -0800148 if (!val) {
Inaky Perez-Gonzalezbae94d02006-11-22 12:40:31 -0800149 if (atomic_read(&pdev->enable_cnt) != 0)
150 pci_disable_device(pdev);
151 else
152 result = -EIO;
Trent Piepho92425a42008-11-30 17:10:12 -0800153 } else
Inaky Perez-Gonzalezbae94d02006-11-22 12:40:31 -0800154 result = pci_enable_device(pdev);
Arjan van de Ven9f125d32006-04-29 10:59:08 +0200155
Inaky Perez-Gonzalezbae94d02006-11-22 12:40:31 -0800156 return result < 0 ? result : count;
157}
Arjan van de Ven9f125d32006-04-29 10:59:08 +0200158
Inaky Perez-Gonzalezbae94d02006-11-22 12:40:31 -0800159static ssize_t is_enabled_show(struct device *dev,
160 struct device_attribute *attr, char *buf)
161{
162 struct pci_dev *pdev;
163
164 pdev = to_pci_dev (dev);
165 return sprintf (buf, "%u\n", atomic_read(&pdev->enable_cnt));
Arjan van de Ven9f125d32006-04-29 10:59:08 +0200166}
167
Brice Goglin81bb0e12007-01-28 10:53:40 +0100168#ifdef CONFIG_NUMA
169static ssize_t
170numa_node_show(struct device *dev, struct device_attribute *attr, char *buf)
171{
172 return sprintf (buf, "%d\n", dev->numa_node);
173}
174#endif
175
Brice Goglinfe970642006-08-31 01:55:15 -0400176static ssize_t
177msi_bus_show(struct device *dev, struct device_attribute *attr, char *buf)
178{
179 struct pci_dev *pdev = to_pci_dev(dev);
180
181 if (!pdev->subordinate)
182 return 0;
183
184 return sprintf (buf, "%u\n",
185 !(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI));
186}
187
188static ssize_t
189msi_bus_store(struct device *dev, struct device_attribute *attr,
190 const char *buf, size_t count)
191{
192 struct pci_dev *pdev = to_pci_dev(dev);
Trent Piepho92425a42008-11-30 17:10:12 -0800193 unsigned long val;
194
195 if (strict_strtoul(buf, 0, &val) < 0)
196 return -EINVAL;
Brice Goglinfe970642006-08-31 01:55:15 -0400197
198 /* bad things may happen if the no_msi flag is changed
199 * while some drivers are loaded */
200 if (!capable(CAP_SYS_ADMIN))
Trent Piepho92425a42008-11-30 17:10:12 -0800201 return -EPERM;
Brice Goglinfe970642006-08-31 01:55:15 -0400202
Trent Piepho92425a42008-11-30 17:10:12 -0800203 /* Maybe pci devices without subordinate busses shouldn't even have this
204 * attribute in the first place? */
Brice Goglinfe970642006-08-31 01:55:15 -0400205 if (!pdev->subordinate)
206 return count;
207
Trent Piepho92425a42008-11-30 17:10:12 -0800208 /* Is the flag going to change, or keep the value it already had? */
209 if (!(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI) ^
210 !!val) {
211 pdev->subordinate->bus_flags ^= PCI_BUS_FLAGS_NO_MSI;
Brice Goglinfe970642006-08-31 01:55:15 -0400212
Trent Piepho92425a42008-11-30 17:10:12 -0800213 dev_warn(&pdev->dev, "forced subordinate bus to%s support MSI,"
214 " bad things could happen\n", val ? "" : " not");
Brice Goglinfe970642006-08-31 01:55:15 -0400215 }
216
217 return count;
218}
Greg KH98885492005-05-05 11:57:25 -0700219
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220struct device_attribute pci_dev_attrs[] = {
221 __ATTR_RO(resource),
222 __ATTR_RO(vendor),
223 __ATTR_RO(device),
224 __ATTR_RO(subsystem_vendor),
225 __ATTR_RO(subsystem_device),
226 __ATTR_RO(class),
227 __ATTR_RO(irq),
228 __ATTR_RO(local_cpus),
Mike Travis39106dc2008-04-08 11:43:03 -0700229 __ATTR_RO(local_cpulist),
Greg KH98885492005-05-05 11:57:25 -0700230 __ATTR_RO(modalias),
Brice Goglin81bb0e12007-01-28 10:53:40 +0100231#ifdef CONFIG_NUMA
232 __ATTR_RO(numa_node),
233#endif
Arjan van de Ven9f125d32006-04-29 10:59:08 +0200234 __ATTR(enable, 0600, is_enabled_show, is_enabled_store),
Doug Thompsonbdee9d92006-06-14 16:59:48 -0700235 __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR),
236 broken_parity_status_show,broken_parity_status_store),
Brice Goglinfe970642006-08-31 01:55:15 -0400237 __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 __ATTR_NULL,
239};
240
241static ssize_t
Zhang Rui91a69022007-06-09 13:57:22 +0800242pci_read_config(struct kobject *kobj, struct bin_attribute *bin_attr,
243 char *buf, loff_t off, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244{
245 struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
246 unsigned int size = 64;
247 loff_t init_off = off;
ssant@in.ibm.com4c0619a2005-04-08 14:53:31 +0900248 u8 *data = (u8*) buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249
250 /* Several chips lock up trying to read undefined config space */
251 if (capable(CAP_SYS_ADMIN)) {
252 size = dev->cfg_size;
253 } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
254 size = 128;
255 }
256
257 if (off > size)
258 return 0;
259 if (off + count > size) {
260 size -= off;
261 count = size;
262 } else {
263 size = count;
264 }
265
ssant@in.ibm.com4c0619a2005-04-08 14:53:31 +0900266 if ((off & 1) && size) {
267 u8 val;
Brian Kinge04b0ea2005-09-27 01:21:55 -0700268 pci_user_read_config_byte(dev, off, &val);
ssant@in.ibm.com4c0619a2005-04-08 14:53:31 +0900269 data[off - init_off] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 off++;
ssant@in.ibm.com4c0619a2005-04-08 14:53:31 +0900271 size--;
272 }
273
274 if ((off & 3) && size > 2) {
275 u16 val;
Brian Kinge04b0ea2005-09-27 01:21:55 -0700276 pci_user_read_config_word(dev, off, &val);
ssant@in.ibm.com4c0619a2005-04-08 14:53:31 +0900277 data[off - init_off] = val & 0xff;
278 data[off - init_off + 1] = (val >> 8) & 0xff;
279 off += 2;
280 size -= 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 }
282
283 while (size > 3) {
ssant@in.ibm.com4c0619a2005-04-08 14:53:31 +0900284 u32 val;
Brian Kinge04b0ea2005-09-27 01:21:55 -0700285 pci_user_read_config_dword(dev, off, &val);
ssant@in.ibm.com4c0619a2005-04-08 14:53:31 +0900286 data[off - init_off] = val & 0xff;
287 data[off - init_off + 1] = (val >> 8) & 0xff;
288 data[off - init_off + 2] = (val >> 16) & 0xff;
289 data[off - init_off + 3] = (val >> 24) & 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 off += 4;
291 size -= 4;
292 }
293
ssant@in.ibm.com4c0619a2005-04-08 14:53:31 +0900294 if (size >= 2) {
295 u16 val;
Brian Kinge04b0ea2005-09-27 01:21:55 -0700296 pci_user_read_config_word(dev, off, &val);
ssant@in.ibm.com4c0619a2005-04-08 14:53:31 +0900297 data[off - init_off] = val & 0xff;
298 data[off - init_off + 1] = (val >> 8) & 0xff;
299 off += 2;
300 size -= 2;
301 }
302
303 if (size > 0) {
304 u8 val;
Brian Kinge04b0ea2005-09-27 01:21:55 -0700305 pci_user_read_config_byte(dev, off, &val);
ssant@in.ibm.com4c0619a2005-04-08 14:53:31 +0900306 data[off - init_off] = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 off++;
308 --size;
309 }
310
311 return count;
312}
313
314static ssize_t
Zhang Rui91a69022007-06-09 13:57:22 +0800315pci_write_config(struct kobject *kobj, struct bin_attribute *bin_attr,
316 char *buf, loff_t off, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317{
318 struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
319 unsigned int size = count;
320 loff_t init_off = off;
ssant@in.ibm.com4c0619a2005-04-08 14:53:31 +0900321 u8 *data = (u8*) buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
323 if (off > dev->cfg_size)
324 return 0;
325 if (off + count > dev->cfg_size) {
326 size = dev->cfg_size - off;
327 count = size;
328 }
ssant@in.ibm.com4c0619a2005-04-08 14:53:31 +0900329
330 if ((off & 1) && size) {
Brian Kinge04b0ea2005-09-27 01:21:55 -0700331 pci_user_write_config_byte(dev, off, data[off - init_off]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 off++;
ssant@in.ibm.com4c0619a2005-04-08 14:53:31 +0900333 size--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 }
ssant@in.ibm.com4c0619a2005-04-08 14:53:31 +0900335
336 if ((off & 3) && size > 2) {
337 u16 val = data[off - init_off];
338 val |= (u16) data[off - init_off + 1] << 8;
Brian Kinge04b0ea2005-09-27 01:21:55 -0700339 pci_user_write_config_word(dev, off, val);
ssant@in.ibm.com4c0619a2005-04-08 14:53:31 +0900340 off += 2;
341 size -= 2;
342 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
344 while (size > 3) {
ssant@in.ibm.com4c0619a2005-04-08 14:53:31 +0900345 u32 val = data[off - init_off];
346 val |= (u32) data[off - init_off + 1] << 8;
347 val |= (u32) data[off - init_off + 2] << 16;
348 val |= (u32) data[off - init_off + 3] << 24;
Brian Kinge04b0ea2005-09-27 01:21:55 -0700349 pci_user_write_config_dword(dev, off, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 off += 4;
351 size -= 4;
352 }
ssant@in.ibm.com4c0619a2005-04-08 14:53:31 +0900353
354 if (size >= 2) {
355 u16 val = data[off - init_off];
356 val |= (u16) data[off - init_off + 1] << 8;
Brian Kinge04b0ea2005-09-27 01:21:55 -0700357 pci_user_write_config_word(dev, off, val);
ssant@in.ibm.com4c0619a2005-04-08 14:53:31 +0900358 off += 2;
359 size -= 2;
360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
ssant@in.ibm.com4c0619a2005-04-08 14:53:31 +0900362 if (size) {
Brian Kinge04b0ea2005-09-27 01:21:55 -0700363 pci_user_write_config_byte(dev, off, data[off - init_off]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 off++;
365 --size;
366 }
367
368 return count;
369}
370
Ben Hutchings94e61082008-03-05 16:52:39 +0000371static ssize_t
372pci_read_vpd(struct kobject *kobj, struct bin_attribute *bin_attr,
373 char *buf, loff_t off, size_t count)
374{
375 struct pci_dev *dev =
376 to_pci_dev(container_of(kobj, struct device, kobj));
377 int end;
378 int ret;
379
380 if (off > bin_attr->size)
381 count = 0;
382 else if (count > bin_attr->size - off)
383 count = bin_attr->size - off;
384 end = off + count;
385
386 while (off < end) {
387 ret = dev->vpd->ops->read(dev, off, end - off, buf);
388 if (ret < 0)
389 return ret;
390 buf += ret;
391 off += ret;
392 }
393
394 return count;
395}
396
397static ssize_t
398pci_write_vpd(struct kobject *kobj, struct bin_attribute *bin_attr,
399 char *buf, loff_t off, size_t count)
400{
401 struct pci_dev *dev =
402 to_pci_dev(container_of(kobj, struct device, kobj));
403 int end;
404 int ret;
405
406 if (off > bin_attr->size)
407 count = 0;
408 else if (count > bin_attr->size - off)
409 count = bin_attr->size - off;
410 end = off + count;
411
412 while (off < end) {
413 ret = dev->vpd->ops->write(dev, off, end - off, buf);
414 if (ret < 0)
415 return ret;
416 buf += ret;
417 off += ret;
418 }
419
420 return count;
421}
422
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423#ifdef HAVE_PCI_LEGACY
424/**
425 * pci_read_legacy_io - read byte(s) from legacy I/O port space
426 * @kobj: kobject corresponding to file to read from
427 * @buf: buffer to store results
428 * @off: offset into legacy I/O port space
429 * @count: number of bytes to read
430 *
431 * Reads 1, 2, or 4 bytes from legacy I/O port space using an arch specific
432 * callback routine (pci_legacy_read).
433 */
Benjamin Herrenschmidtf19aeb12008-10-03 19:49:32 +1000434static ssize_t
Zhang Rui91a69022007-06-09 13:57:22 +0800435pci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
436 char *buf, loff_t off, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437{
438 struct pci_bus *bus = to_pci_bus(container_of(kobj,
Greg Kroah-Hartmanfd7d1ce2007-05-22 22:47:54 -0400439 struct device,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 kobj));
441
442 /* Only support 1, 2 or 4 byte accesses */
443 if (count != 1 && count != 2 && count != 4)
444 return -EINVAL;
445
446 return pci_legacy_read(bus, off, (u32 *)buf, count);
447}
448
449/**
450 * pci_write_legacy_io - write byte(s) to legacy I/O port space
451 * @kobj: kobject corresponding to file to read from
452 * @buf: buffer containing value to be written
453 * @off: offset into legacy I/O port space
454 * @count: number of bytes to write
455 *
456 * Writes 1, 2, or 4 bytes from legacy I/O port space using an arch specific
457 * callback routine (pci_legacy_write).
458 */
Benjamin Herrenschmidtf19aeb12008-10-03 19:49:32 +1000459static ssize_t
Zhang Rui91a69022007-06-09 13:57:22 +0800460pci_write_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
461 char *buf, loff_t off, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462{
463 struct pci_bus *bus = to_pci_bus(container_of(kobj,
Greg Kroah-Hartmanfd7d1ce2007-05-22 22:47:54 -0400464 struct device,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 kobj));
466 /* Only support 1, 2 or 4 byte accesses */
467 if (count != 1 && count != 2 && count != 4)
468 return -EINVAL;
469
470 return pci_legacy_write(bus, off, *(u32 *)buf, count);
471}
472
473/**
474 * pci_mmap_legacy_mem - map legacy PCI memory into user memory space
475 * @kobj: kobject corresponding to device to be mapped
476 * @attr: struct bin_attribute for this file
477 * @vma: struct vm_area_struct passed to mmap
478 *
Benjamin Herrenschmidtf19aeb12008-10-03 19:49:32 +1000479 * Uses an arch specific callback, pci_mmap_legacy_mem_page_range, to mmap
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 * legacy memory space (first meg of bus space) into application virtual
481 * memory space.
482 */
Benjamin Herrenschmidtf19aeb12008-10-03 19:49:32 +1000483static int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr,
485 struct vm_area_struct *vma)
486{
487 struct pci_bus *bus = to_pci_bus(container_of(kobj,
Greg Kroah-Hartmanfd7d1ce2007-05-22 22:47:54 -0400488 struct device,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 kobj));
490
Benjamin Herrenschmidtf19aeb12008-10-03 19:49:32 +1000491 return pci_mmap_legacy_page_range(bus, vma, pci_mmap_mem);
492}
493
494/**
495 * pci_mmap_legacy_io - map legacy PCI IO into user memory space
496 * @kobj: kobject corresponding to device to be mapped
497 * @attr: struct bin_attribute for this file
498 * @vma: struct vm_area_struct passed to mmap
499 *
500 * Uses an arch specific callback, pci_mmap_legacy_io_page_range, to mmap
501 * legacy IO space (first meg of bus space) into application virtual
502 * memory space. Returns -ENOSYS if the operation isn't supported
503 */
504static int
505pci_mmap_legacy_io(struct kobject *kobj, struct bin_attribute *attr,
506 struct vm_area_struct *vma)
507{
508 struct pci_bus *bus = to_pci_bus(container_of(kobj,
509 struct device,
510 kobj));
511
512 return pci_mmap_legacy_page_range(bus, vma, pci_mmap_io);
513}
514
515/**
516 * pci_create_legacy_files - create legacy I/O port and memory files
517 * @b: bus to create files under
518 *
519 * Some platforms allow access to legacy I/O port and ISA memory space on
520 * a per-bus basis. This routine creates the files and ties them into
521 * their associated read, write and mmap files from pci-sysfs.c
522 *
523 * On error unwind, but don't propogate the error to the caller
524 * as it is ok to set up the PCI bus without these files.
525 */
526void pci_create_legacy_files(struct pci_bus *b)
527{
528 int error;
529
530 b->legacy_io = kzalloc(sizeof(struct bin_attribute) * 2,
531 GFP_ATOMIC);
532 if (!b->legacy_io)
533 goto kzalloc_err;
534
535 b->legacy_io->attr.name = "legacy_io";
536 b->legacy_io->size = 0xffff;
537 b->legacy_io->attr.mode = S_IRUSR | S_IWUSR;
538 b->legacy_io->read = pci_read_legacy_io;
539 b->legacy_io->write = pci_write_legacy_io;
540 b->legacy_io->mmap = pci_mmap_legacy_io;
541 error = device_create_bin_file(&b->dev, b->legacy_io);
542 if (error)
543 goto legacy_io_err;
544
545 /* Allocated above after the legacy_io struct */
546 b->legacy_mem = b->legacy_io + 1;
547 b->legacy_mem->attr.name = "legacy_mem";
548 b->legacy_mem->size = 1024*1024;
549 b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR;
550 b->legacy_mem->mmap = pci_mmap_legacy_mem;
551 error = device_create_bin_file(&b->dev, b->legacy_mem);
552 if (error)
553 goto legacy_mem_err;
554
555 return;
556
557legacy_mem_err:
558 device_remove_bin_file(&b->dev, b->legacy_io);
559legacy_io_err:
560 kfree(b->legacy_io);
561 b->legacy_io = NULL;
562kzalloc_err:
563 printk(KERN_WARNING "pci: warning: could not create legacy I/O port "
564 "and ISA memory resources to sysfs\n");
565 return;
566}
567
568void pci_remove_legacy_files(struct pci_bus *b)
569{
570 if (b->legacy_io) {
571 device_remove_bin_file(&b->dev, b->legacy_io);
572 device_remove_bin_file(&b->dev, b->legacy_mem);
573 kfree(b->legacy_io); /* both are allocated here */
574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575}
576#endif /* HAVE_PCI_LEGACY */
577
578#ifdef HAVE_PCI_MMAP
Linus Torvaldsb5ff7df2008-10-02 18:52:51 -0700579
Jesse Barnes9eff02e2008-10-24 10:32:33 -0700580int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma)
Linus Torvaldsb5ff7df2008-10-02 18:52:51 -0700581{
582 unsigned long nr, start, size;
583
584 nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
585 start = vma->vm_pgoff;
Ed Swierk88e7df02008-11-03 14:41:16 -0800586 size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1;
Linus Torvaldsb5ff7df2008-10-02 18:52:51 -0700587 if (start < size && size - start >= nr)
588 return 1;
589 WARN(1, "process \"%s\" tried to map 0x%08lx-0x%08lx on %s BAR %d (size 0x%08lx)\n",
590 current->comm, start, start+nr, pci_name(pdev), resno, size);
591 return 0;
592}
593
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594/**
595 * pci_mmap_resource - map a PCI resource into user memory space
596 * @kobj: kobject for mapping
597 * @attr: struct bin_attribute for the file being mapped
598 * @vma: struct vm_area_struct passed into the mmap
venkatesh.pallipadi@intel.com45aec1ae2008-03-18 17:00:22 -0700599 * @write_combine: 1 for write_combine mapping
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 *
601 * Use the regular PCI mapping routines to map a PCI resource into userspace.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 */
603static int
604pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
venkatesh.pallipadi@intel.com45aec1ae2008-03-18 17:00:22 -0700605 struct vm_area_struct *vma, int write_combine)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606{
607 struct pci_dev *pdev = to_pci_dev(container_of(kobj,
608 struct device, kobj));
609 struct resource *res = (struct resource *)attr->private;
610 enum pci_mmap_state mmap_type;
Greg Kroah-Hartmane31dd6e2006-06-12 17:06:02 -0700611 resource_size_t start, end;
Michael Ellerman2311b1f2005-05-13 17:44:10 +1000612 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
Michael Ellerman2311b1f2005-05-13 17:44:10 +1000614 for (i = 0; i < PCI_ROM_RESOURCE; i++)
615 if (res == &pdev->resource[i])
616 break;
617 if (i >= PCI_ROM_RESOURCE)
618 return -ENODEV;
619
Linus Torvaldsb5ff7df2008-10-02 18:52:51 -0700620 if (!pci_mmap_fits(pdev, i, vma))
621 return -EINVAL;
622
Michael Ellerman2311b1f2005-05-13 17:44:10 +1000623 /* pci_mmap_page_range() expects the same kind of entry as coming
624 * from /proc/bus/pci/ which is a "user visible" value. If this is
625 * different from the resource itself, arch will do necessary fixup.
626 */
627 pci_resource_to_user(pdev, i, res, &start, &end);
628 vma->vm_pgoff += start >> PAGE_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
630
Arjan van de Vene8de1482008-10-22 19:55:31 -0700631 if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(start))
632 return -EINVAL;
633
venkatesh.pallipadi@intel.com45aec1ae2008-03-18 17:00:22 -0700634 return pci_mmap_page_range(pdev, vma, mmap_type, write_combine);
635}
636
637static int
638pci_mmap_resource_uc(struct kobject *kobj, struct bin_attribute *attr,
639 struct vm_area_struct *vma)
640{
641 return pci_mmap_resource(kobj, attr, vma, 0);
642}
643
644static int
645pci_mmap_resource_wc(struct kobject *kobj, struct bin_attribute *attr,
646 struct vm_area_struct *vma)
647{
648 return pci_mmap_resource(kobj, attr, vma, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649}
650
651/**
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700652 * pci_remove_resource_files - cleanup resource files
653 * @dev: dev to cleanup
654 *
655 * If we created resource files for @dev, remove them from sysfs and
656 * free their resources.
657 */
658static void
659pci_remove_resource_files(struct pci_dev *pdev)
660{
661 int i;
662
663 for (i = 0; i < PCI_ROM_RESOURCE; i++) {
664 struct bin_attribute *res_attr;
665
666 res_attr = pdev->res_attr[i];
667 if (res_attr) {
668 sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
669 kfree(res_attr);
670 }
venkatesh.pallipadi@intel.com45aec1ae2008-03-18 17:00:22 -0700671
672 res_attr = pdev->res_attr_wc[i];
673 if (res_attr) {
674 sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
675 kfree(res_attr);
676 }
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700677 }
678}
679
venkatesh.pallipadi@intel.com45aec1ae2008-03-18 17:00:22 -0700680static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine)
681{
682 /* allocate attribute structure, piggyback attribute name */
683 int name_len = write_combine ? 13 : 10;
684 struct bin_attribute *res_attr;
685 int retval;
686
687 res_attr = kzalloc(sizeof(*res_attr) + name_len, GFP_ATOMIC);
688 if (res_attr) {
689 char *res_attr_name = (char *)(res_attr + 1);
690
691 if (write_combine) {
692 pdev->res_attr_wc[num] = res_attr;
693 sprintf(res_attr_name, "resource%d_wc", num);
694 res_attr->mmap = pci_mmap_resource_wc;
695 } else {
696 pdev->res_attr[num] = res_attr;
697 sprintf(res_attr_name, "resource%d", num);
698 res_attr->mmap = pci_mmap_resource_uc;
699 }
700 res_attr->attr.name = res_attr_name;
701 res_attr->attr.mode = S_IRUSR | S_IWUSR;
702 res_attr->size = pci_resource_len(pdev, num);
703 res_attr->private = &pdev->resource[num];
704 retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
705 } else
706 retval = -ENOMEM;
707
708 return retval;
709}
710
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700711/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 * pci_create_resource_files - create resource files in sysfs for @dev
713 * @dev: dev in question
714 *
715 * Walk the resources in @dev creating files for each resource available.
716 */
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700717static int pci_create_resource_files(struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718{
719 int i;
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700720 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
722 /* Expose the PCI resources from this device as files */
723 for (i = 0; i < PCI_ROM_RESOURCE; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
725 /* skip empty resources */
726 if (!pci_resource_len(pdev, i))
727 continue;
728
venkatesh.pallipadi@intel.com45aec1ae2008-03-18 17:00:22 -0700729 retval = pci_create_attr(pdev, i, 0);
730 /* for prefetchable resources, create a WC mappable file */
731 if (!retval && pdev->resource[i].flags & IORESOURCE_PREFETCH)
732 retval = pci_create_attr(pdev, i, 1);
Dmitry Torokhovd48593b2005-04-29 00:58:46 -0500733
venkatesh.pallipadi@intel.com45aec1ae2008-03-18 17:00:22 -0700734 if (retval) {
735 pci_remove_resource_files(pdev);
736 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 }
738 }
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700739 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740}
741#else /* !HAVE_PCI_MMAP */
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700742static inline int pci_create_resource_files(struct pci_dev *dev) { return 0; }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743static inline void pci_remove_resource_files(struct pci_dev *dev) { return; }
744#endif /* HAVE_PCI_MMAP */
745
746/**
747 * pci_write_rom - used to enable access to the PCI ROM display
748 * @kobj: kernel object handle
749 * @buf: user input
750 * @off: file offset
751 * @count: number of byte in input
752 *
753 * writing anything except 0 enables it
754 */
755static ssize_t
Zhang Rui91a69022007-06-09 13:57:22 +0800756pci_write_rom(struct kobject *kobj, struct bin_attribute *bin_attr,
757 char *buf, loff_t off, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758{
759 struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj));
760
761 if ((off == 0) && (*buf == '0') && (count == 2))
762 pdev->rom_attr_enabled = 0;
763 else
764 pdev->rom_attr_enabled = 1;
765
766 return count;
767}
768
769/**
770 * pci_read_rom - read a PCI ROM
771 * @kobj: kernel object handle
772 * @buf: where to put the data we read from the ROM
773 * @off: file offset
774 * @count: number of bytes to read
775 *
776 * Put @count bytes starting at @off into @buf from the ROM in the PCI
777 * device corresponding to @kobj.
778 */
779static ssize_t
Zhang Rui91a69022007-06-09 13:57:22 +0800780pci_read_rom(struct kobject *kobj, struct bin_attribute *bin_attr,
781 char *buf, loff_t off, size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782{
783 struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj));
784 void __iomem *rom;
785 size_t size;
786
787 if (!pdev->rom_attr_enabled)
788 return -EINVAL;
789
790 rom = pci_map_rom(pdev, &size); /* size starts out as PCI window size */
791 if (!rom)
792 return 0;
793
794 if (off >= size)
795 count = 0;
796 else {
797 if (off + count > size)
798 count = size - off;
799
800 memcpy_fromio(buf, rom + off, count);
801 }
802 pci_unmap_rom(pdev, rom);
803
804 return count;
805}
806
807static struct bin_attribute pci_config_attr = {
808 .attr = {
809 .name = "config",
810 .mode = S_IRUGO | S_IWUSR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 },
Zhao, Yu557848c2008-10-13 19:18:07 +0800812 .size = PCI_CFG_SPACE_SIZE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 .read = pci_read_config,
814 .write = pci_write_config,
815};
816
817static struct bin_attribute pcie_config_attr = {
818 .attr = {
819 .name = "config",
820 .mode = S_IRUGO | S_IWUSR,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 },
Zhao, Yu557848c2008-10-13 19:18:07 +0800822 .size = PCI_CFG_SPACE_EXP_SIZE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 .read = pci_read_config,
824 .write = pci_write_config,
825};
826
Michael Ellermana2cd52c2007-05-08 12:03:08 +1000827int __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev)
Michael Ellerman575e3342007-05-08 12:03:07 +1000828{
Michael Ellermana2cd52c2007-05-08 12:03:08 +1000829 return 0;
Michael Ellerman575e3342007-05-08 12:03:07 +1000830}
831
Zhao, Yu280c73d2008-10-13 20:01:00 +0800832static int pci_create_capabilities_sysfs(struct pci_dev *dev)
833{
834 int retval;
835 struct bin_attribute *attr;
836
837 /* If the device has VPD, try to expose it in sysfs. */
838 if (dev->vpd) {
839 attr = kzalloc(sizeof(*attr), GFP_ATOMIC);
840 if (!attr)
841 return -ENOMEM;
842
843 attr->size = dev->vpd->len;
844 attr->attr.name = "vpd";
845 attr->attr.mode = S_IRUSR | S_IWUSR;
846 attr->read = pci_read_vpd;
847 attr->write = pci_write_vpd;
848 retval = sysfs_create_bin_file(&dev->dev.kobj, attr);
849 if (retval) {
850 kfree(dev->vpd->attr);
851 return retval;
852 }
853 dev->vpd->attr = attr;
854 }
855
856 /* Active State Power Management */
857 pcie_aspm_create_sysfs_dev_files(dev);
858
859 return 0;
860}
861
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700862int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863{
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700864 int retval;
Zhao, Yu280c73d2008-10-13 20:01:00 +0800865 int rom_size = 0;
866 struct bin_attribute *attr;
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700867
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 if (!sysfs_initialized)
869 return -EACCES;
870
Zhao, Yu557848c2008-10-13 19:18:07 +0800871 if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700872 retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 else
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700874 retval = sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
875 if (retval)
876 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700878 retval = pci_create_resource_files(pdev);
879 if (retval)
Zhao, Yu280c73d2008-10-13 20:01:00 +0800880 goto err_config_file;
881
882 if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
883 rom_size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
884 else if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)
885 rom_size = 0x20000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886
887 /* If the device has a ROM, try to expose it in sysfs. */
Zhao, Yu280c73d2008-10-13 20:01:00 +0800888 if (rom_size) {
Ben Hutchings94e61082008-03-05 16:52:39 +0000889 attr = kzalloc(sizeof(*attr), GFP_ATOMIC);
Zhao, Yu280c73d2008-10-13 20:01:00 +0800890 if (!attr) {
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700891 retval = -ENOMEM;
Michael Ellerman9890b122007-04-18 13:34:12 +1000892 goto err_resource_files;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 }
Zhao, Yu280c73d2008-10-13 20:01:00 +0800894 attr->size = rom_size;
895 attr->attr.name = "rom";
896 attr->attr.mode = S_IRUSR;
897 attr->read = pci_read_rom;
898 attr->write = pci_write_rom;
899 retval = sysfs_create_bin_file(&pdev->dev.kobj, attr);
900 if (retval) {
901 kfree(attr);
902 goto err_resource_files;
903 }
904 pdev->rom_attr = attr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 }
Zhao, Yu280c73d2008-10-13 20:01:00 +0800906
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 /* add platform-specific attributes */
Zhao, Yu280c73d2008-10-13 20:01:00 +0800908 retval = pcibios_add_platform_entries(pdev);
909 if (retval)
Michael Ellermana2cd52c2007-05-08 12:03:08 +1000910 goto err_rom_file;
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700911
Zhao, Yu280c73d2008-10-13 20:01:00 +0800912 /* add sysfs entries for various capabilities */
913 retval = pci_create_capabilities_sysfs(pdev);
914 if (retval)
915 goto err_rom_file;
Shaohua Li7d715a62008-02-25 09:46:41 +0800916
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 return 0;
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700918
Michael Ellermana2cd52c2007-05-08 12:03:08 +1000919err_rom_file:
Zhao, Yu280c73d2008-10-13 20:01:00 +0800920 if (rom_size) {
Ben Hutchings94e61082008-03-05 16:52:39 +0000921 sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
Zhao, Yu280c73d2008-10-13 20:01:00 +0800922 kfree(pdev->rom_attr);
923 pdev->rom_attr = NULL;
924 }
Michael Ellerman9890b122007-04-18 13:34:12 +1000925err_resource_files:
926 pci_remove_resource_files(pdev);
Ben Hutchings94e61082008-03-05 16:52:39 +0000927err_config_file:
Zhao, Yu557848c2008-10-13 19:18:07 +0800928 if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700929 sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
930 else
931 sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
932err:
933 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934}
935
Zhao, Yu280c73d2008-10-13 20:01:00 +0800936static void pci_remove_capabilities_sysfs(struct pci_dev *dev)
937{
938 if (dev->vpd && dev->vpd->attr) {
939 sysfs_remove_bin_file(&dev->dev.kobj, dev->vpd->attr);
940 kfree(dev->vpd->attr);
941 }
942
943 pcie_aspm_remove_sysfs_dev_files(dev);
944}
945
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946/**
947 * pci_remove_sysfs_dev_files - cleanup PCI specific sysfs files
948 * @pdev: device whose entries we should free
949 *
950 * Cleanup when @pdev is removed from sysfs.
951 */
952void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
953{
Zhao, Yu280c73d2008-10-13 20:01:00 +0800954 int rom_size = 0;
955
David Millerd67afe52006-11-10 12:27:48 -0800956 if (!sysfs_initialized)
957 return;
958
Zhao, Yu280c73d2008-10-13 20:01:00 +0800959 pci_remove_capabilities_sysfs(pdev);
Shaohua Li7d715a62008-02-25 09:46:41 +0800960
Zhao, Yu557848c2008-10-13 19:18:07 +0800961 if (pdev->cfg_size < PCI_CFG_SPACE_EXP_SIZE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
963 else
964 sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
965
966 pci_remove_resource_files(pdev);
967
Zhao, Yu280c73d2008-10-13 20:01:00 +0800968 if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
969 rom_size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
970 else if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)
971 rom_size = 0x20000;
972
973 if (rom_size && pdev->rom_attr) {
974 sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
975 kfree(pdev->rom_attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 }
977}
978
979static int __init pci_sysfs_init(void)
980{
981 struct pci_dev *pdev = NULL;
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700982 int retval;
983
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 sysfs_initialized = 1;
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700985 for_each_pci_dev(pdev) {
986 retval = pci_create_sysfs_dev_files(pdev);
Julia Lawall151fc5d2007-11-20 08:41:16 +0100987 if (retval) {
988 pci_dev_put(pdev);
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700989 return retval;
Julia Lawall151fc5d2007-11-20 08:41:16 +0100990 }
Greg Kroah-Hartmanb19441a2006-08-28 11:43:25 -0700991 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
993 return 0;
994}
995
Jesse Barnes40ee9e92007-03-24 11:03:32 -0700996late_initcall(pci_sysfs_init);