ia64/linux-2.6.18-xen.hg

annotate drivers/pci/pci-sysfs.c @ 816:f77ac4979fae

Backport: PCI: define PCI resource names in an 'enum'

commit fde09c6d8f92de0c9f75698a75f0989f2234c517
Author: Yu Zhao <yu.zhao@intel.com>
Date: Sat Nov 22 02:39:32 2008 +0800

PCI: define PCI resource names in an 'enum'

This patch moves all definitions of the PCI resource names to an
'enum',
and also replaces some hard-coded resource variables with symbol
names. This change eases introduction of device specific
resources.

Reviewed-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: Yu Zhao <yu.zhao@intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>

Signed-off-by: Yu Zhao <yu.zhao@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Mar 13 08:50:15 2009 +0000 (2009-03-13)
parents 3e8752eb6d9c
children
rev   line source
ian@0 1 /*
ian@0 2 * drivers/pci/pci-sysfs.c
ian@0 3 *
ian@0 4 * (C) Copyright 2002-2004 Greg Kroah-Hartman <greg@kroah.com>
ian@0 5 * (C) Copyright 2002-2004 IBM Corp.
ian@0 6 * (C) Copyright 2003 Matthew Wilcox
ian@0 7 * (C) Copyright 2003 Hewlett-Packard
ian@0 8 * (C) Copyright 2004 Jon Smirl <jonsmirl@yahoo.com>
ian@0 9 * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <jbarnes@sgi.com>
ian@0 10 *
ian@0 11 * File attributes for PCI devices
ian@0 12 *
ian@0 13 * Modeled after usb's driverfs.c
ian@0 14 *
ian@0 15 */
ian@0 16
ian@0 17
ian@0 18 #include <linux/kernel.h>
ian@0 19 #include <linux/pci.h>
ian@0 20 #include <linux/stat.h>
ian@0 21 #include <linux/topology.h>
ian@0 22 #include <linux/mm.h>
ian@0 23
ian@0 24 #include "pci.h"
ian@0 25
ian@0 26 static int sysfs_initialized; /* = 0 */
ian@0 27
ian@0 28 /* show configuration fields */
ian@0 29 #define pci_config_attr(field, format_string) \
ian@0 30 static ssize_t \
ian@0 31 field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
ian@0 32 { \
ian@0 33 struct pci_dev *pdev; \
ian@0 34 \
ian@0 35 pdev = to_pci_dev (dev); \
ian@0 36 return sprintf (buf, format_string, pdev->field); \
ian@0 37 }
ian@0 38
ian@0 39 pci_config_attr(vendor, "0x%04x\n");
ian@0 40 pci_config_attr(device, "0x%04x\n");
ian@0 41 pci_config_attr(subsystem_vendor, "0x%04x\n");
ian@0 42 pci_config_attr(subsystem_device, "0x%04x\n");
ian@0 43 pci_config_attr(class, "0x%06x\n");
ian@0 44 pci_config_attr(irq, "%u\n");
ian@0 45 pci_config_attr(is_enabled, "%u\n");
ian@0 46
ian@0 47 static ssize_t broken_parity_status_show(struct device *dev,
ian@0 48 struct device_attribute *attr,
ian@0 49 char *buf)
ian@0 50 {
ian@0 51 struct pci_dev *pdev = to_pci_dev(dev);
ian@0 52 return sprintf (buf, "%u\n", pdev->broken_parity_status);
ian@0 53 }
ian@0 54
ian@0 55 static ssize_t broken_parity_status_store(struct device *dev,
ian@0 56 struct device_attribute *attr,
ian@0 57 const char *buf, size_t count)
ian@0 58 {
ian@0 59 struct pci_dev *pdev = to_pci_dev(dev);
ian@0 60 ssize_t consumed = -EINVAL;
ian@0 61
ian@0 62 if ((count > 0) && (*buf == '0' || *buf == '1')) {
ian@0 63 pdev->broken_parity_status = *buf == '1' ? 1 : 0;
ian@0 64 consumed = count;
ian@0 65 }
ian@0 66 return consumed;
ian@0 67 }
ian@0 68
ian@0 69 static ssize_t local_cpus_show(struct device *dev,
ian@0 70 struct device_attribute *attr, char *buf)
ian@0 71 {
ian@0 72 cpumask_t mask;
ian@0 73 int len;
ian@0 74
ian@0 75 mask = pcibus_to_cpumask(to_pci_dev(dev)->bus);
ian@0 76 len = cpumask_scnprintf(buf, PAGE_SIZE-2, mask);
ian@0 77 strcat(buf,"\n");
ian@0 78 return 1+len;
ian@0 79 }
ian@0 80
ian@0 81 /* show resources */
ian@0 82 static ssize_t
ian@0 83 resource_show(struct device * dev, struct device_attribute *attr, char * buf)
ian@0 84 {
ian@0 85 struct pci_dev * pci_dev = to_pci_dev(dev);
ian@0 86 char * str = buf;
ian@0 87 int i;
keir@816 88 int max;
ian@0 89 resource_size_t start, end;
ian@0 90
ian@0 91 if (pci_dev->subordinate)
ian@0 92 max = DEVICE_COUNT_RESOURCE;
keir@816 93 else
keir@816 94 max = PCI_BRIDGE_RESOURCES;
ian@0 95
ian@0 96 for (i = 0; i < max; i++) {
ian@0 97 struct resource *res = &pci_dev->resource[i];
ian@0 98 pci_resource_to_user(pci_dev, i, res, &start, &end);
ian@0 99 str += sprintf(str,"0x%016llx 0x%016llx 0x%016llx\n",
ian@0 100 (unsigned long long)start,
ian@0 101 (unsigned long long)end,
ian@0 102 (unsigned long long)res->flags);
ian@0 103 }
ian@0 104 return (str - buf);
ian@0 105 }
ian@0 106
ian@0 107 static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
ian@0 108 {
ian@0 109 struct pci_dev *pci_dev = to_pci_dev(dev);
ian@0 110
ian@0 111 return sprintf(buf, "pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n",
ian@0 112 pci_dev->vendor, pci_dev->device,
ian@0 113 pci_dev->subsystem_vendor, pci_dev->subsystem_device,
ian@0 114 (u8)(pci_dev->class >> 16), (u8)(pci_dev->class >> 8),
ian@0 115 (u8)(pci_dev->class));
ian@0 116 }
ian@0 117 static ssize_t
ian@0 118 is_enabled_store(struct device *dev, struct device_attribute *attr,
ian@0 119 const char *buf, size_t count)
ian@0 120 {
ian@0 121 struct pci_dev *pdev = to_pci_dev(dev);
ian@0 122
ian@0 123 /* this can crash the machine when done on the "wrong" device */
ian@0 124 if (!capable(CAP_SYS_ADMIN))
ian@0 125 return count;
ian@0 126
ian@0 127 if (*buf == '0')
ian@0 128 pci_disable_device(pdev);
ian@0 129
ian@0 130 if (*buf == '1')
ian@0 131 pci_enable_device(pdev);
ian@0 132
ian@0 133 return count;
ian@0 134 }
ian@0 135
ian@0 136
ian@0 137 struct device_attribute pci_dev_attrs[] = {
ian@0 138 __ATTR_RO(resource),
ian@0 139 __ATTR_RO(vendor),
ian@0 140 __ATTR_RO(device),
ian@0 141 __ATTR_RO(subsystem_vendor),
ian@0 142 __ATTR_RO(subsystem_device),
ian@0 143 __ATTR_RO(class),
ian@0 144 __ATTR_RO(irq),
ian@0 145 __ATTR_RO(local_cpus),
ian@0 146 __ATTR_RO(modalias),
ian@0 147 __ATTR(enable, 0600, is_enabled_show, is_enabled_store),
ian@0 148 __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR),
ian@0 149 broken_parity_status_show,broken_parity_status_store),
ian@0 150 __ATTR_NULL,
ian@0 151 };
ian@0 152
ian@0 153 static ssize_t
ian@0 154 pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
ian@0 155 {
ian@0 156 struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
ian@0 157 unsigned int size = 64;
ian@0 158 loff_t init_off = off;
ian@0 159 u8 *data = (u8*) buf;
ian@0 160
ian@0 161 /* Several chips lock up trying to read undefined config space */
ian@0 162 if (capable(CAP_SYS_ADMIN)) {
ian@0 163 size = dev->cfg_size;
ian@0 164 } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
ian@0 165 size = 128;
ian@0 166 }
ian@0 167
ian@0 168 if (off > size)
ian@0 169 return 0;
ian@0 170 if (off + count > size) {
ian@0 171 size -= off;
ian@0 172 count = size;
ian@0 173 } else {
ian@0 174 size = count;
ian@0 175 }
ian@0 176
ian@0 177 if ((off & 1) && size) {
ian@0 178 u8 val;
ian@0 179 pci_user_read_config_byte(dev, off, &val);
ian@0 180 data[off - init_off] = val;
ian@0 181 off++;
ian@0 182 size--;
ian@0 183 }
ian@0 184
ian@0 185 if ((off & 3) && size > 2) {
ian@0 186 u16 val;
ian@0 187 pci_user_read_config_word(dev, off, &val);
ian@0 188 data[off - init_off] = val & 0xff;
ian@0 189 data[off - init_off + 1] = (val >> 8) & 0xff;
ian@0 190 off += 2;
ian@0 191 size -= 2;
ian@0 192 }
ian@0 193
ian@0 194 while (size > 3) {
ian@0 195 u32 val;
ian@0 196 pci_user_read_config_dword(dev, off, &val);
ian@0 197 data[off - init_off] = val & 0xff;
ian@0 198 data[off - init_off + 1] = (val >> 8) & 0xff;
ian@0 199 data[off - init_off + 2] = (val >> 16) & 0xff;
ian@0 200 data[off - init_off + 3] = (val >> 24) & 0xff;
ian@0 201 off += 4;
ian@0 202 size -= 4;
ian@0 203 }
ian@0 204
ian@0 205 if (size >= 2) {
ian@0 206 u16 val;
ian@0 207 pci_user_read_config_word(dev, off, &val);
ian@0 208 data[off - init_off] = val & 0xff;
ian@0 209 data[off - init_off + 1] = (val >> 8) & 0xff;
ian@0 210 off += 2;
ian@0 211 size -= 2;
ian@0 212 }
ian@0 213
ian@0 214 if (size > 0) {
ian@0 215 u8 val;
ian@0 216 pci_user_read_config_byte(dev, off, &val);
ian@0 217 data[off - init_off] = val;
ian@0 218 off++;
ian@0 219 --size;
ian@0 220 }
ian@0 221
ian@0 222 return count;
ian@0 223 }
ian@0 224
ian@0 225 static ssize_t
ian@0 226 pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
ian@0 227 {
ian@0 228 struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
ian@0 229 unsigned int size = count;
ian@0 230 loff_t init_off = off;
ian@0 231 u8 *data = (u8*) buf;
ian@0 232
ian@0 233 if (off > dev->cfg_size)
ian@0 234 return 0;
ian@0 235 if (off + count > dev->cfg_size) {
ian@0 236 size = dev->cfg_size - off;
ian@0 237 count = size;
ian@0 238 }
ian@0 239
ian@0 240 if ((off & 1) && size) {
ian@0 241 pci_user_write_config_byte(dev, off, data[off - init_off]);
ian@0 242 off++;
ian@0 243 size--;
ian@0 244 }
ian@0 245
ian@0 246 if ((off & 3) && size > 2) {
ian@0 247 u16 val = data[off - init_off];
ian@0 248 val |= (u16) data[off - init_off + 1] << 8;
ian@0 249 pci_user_write_config_word(dev, off, val);
ian@0 250 off += 2;
ian@0 251 size -= 2;
ian@0 252 }
ian@0 253
ian@0 254 while (size > 3) {
ian@0 255 u32 val = data[off - init_off];
ian@0 256 val |= (u32) data[off - init_off + 1] << 8;
ian@0 257 val |= (u32) data[off - init_off + 2] << 16;
ian@0 258 val |= (u32) data[off - init_off + 3] << 24;
ian@0 259 pci_user_write_config_dword(dev, off, val);
ian@0 260 off += 4;
ian@0 261 size -= 4;
ian@0 262 }
ian@0 263
ian@0 264 if (size >= 2) {
ian@0 265 u16 val = data[off - init_off];
ian@0 266 val |= (u16) data[off - init_off + 1] << 8;
ian@0 267 pci_user_write_config_word(dev, off, val);
ian@0 268 off += 2;
ian@0 269 size -= 2;
ian@0 270 }
ian@0 271
ian@0 272 if (size) {
ian@0 273 pci_user_write_config_byte(dev, off, data[off - init_off]);
ian@0 274 off++;
ian@0 275 --size;
ian@0 276 }
ian@0 277
ian@0 278 return count;
ian@0 279 }
ian@0 280
ian@0 281 #ifdef HAVE_PCI_LEGACY
ian@0 282 /**
ian@0 283 * pci_read_legacy_io - read byte(s) from legacy I/O port space
ian@0 284 * @kobj: kobject corresponding to file to read from
ian@0 285 * @buf: buffer to store results
ian@0 286 * @off: offset into legacy I/O port space
ian@0 287 * @count: number of bytes to read
ian@0 288 *
ian@0 289 * Reads 1, 2, or 4 bytes from legacy I/O port space using an arch specific
ian@0 290 * callback routine (pci_legacy_read).
ian@0 291 */
ian@0 292 ssize_t
ian@0 293 pci_read_legacy_io(struct kobject *kobj, char *buf, loff_t off, size_t count)
ian@0 294 {
ian@0 295 struct pci_bus *bus = to_pci_bus(container_of(kobj,
ian@0 296 struct class_device,
ian@0 297 kobj));
ian@0 298
ian@0 299 /* Only support 1, 2 or 4 byte accesses */
ian@0 300 if (count != 1 && count != 2 && count != 4)
ian@0 301 return -EINVAL;
ian@0 302
ian@0 303 return pci_legacy_read(bus, off, (u32 *)buf, count);
ian@0 304 }
ian@0 305
ian@0 306 /**
ian@0 307 * pci_write_legacy_io - write byte(s) to legacy I/O port space
ian@0 308 * @kobj: kobject corresponding to file to read from
ian@0 309 * @buf: buffer containing value to be written
ian@0 310 * @off: offset into legacy I/O port space
ian@0 311 * @count: number of bytes to write
ian@0 312 *
ian@0 313 * Writes 1, 2, or 4 bytes from legacy I/O port space using an arch specific
ian@0 314 * callback routine (pci_legacy_write).
ian@0 315 */
ian@0 316 ssize_t
ian@0 317 pci_write_legacy_io(struct kobject *kobj, char *buf, loff_t off, size_t count)
ian@0 318 {
ian@0 319 struct pci_bus *bus = to_pci_bus(container_of(kobj,
ian@0 320 struct class_device,
ian@0 321 kobj));
ian@0 322 /* Only support 1, 2 or 4 byte accesses */
ian@0 323 if (count != 1 && count != 2 && count != 4)
ian@0 324 return -EINVAL;
ian@0 325
ian@0 326 return pci_legacy_write(bus, off, *(u32 *)buf, count);
ian@0 327 }
ian@0 328
ian@0 329 /**
ian@0 330 * pci_mmap_legacy_mem - map legacy PCI memory into user memory space
ian@0 331 * @kobj: kobject corresponding to device to be mapped
ian@0 332 * @attr: struct bin_attribute for this file
ian@0 333 * @vma: struct vm_area_struct passed to mmap
ian@0 334 *
ian@0 335 * Uses an arch specific callback, pci_mmap_legacy_page_range, to mmap
ian@0 336 * legacy memory space (first meg of bus space) into application virtual
ian@0 337 * memory space.
ian@0 338 */
ian@0 339 int
ian@0 340 pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr,
ian@0 341 struct vm_area_struct *vma)
ian@0 342 {
ian@0 343 struct pci_bus *bus = to_pci_bus(container_of(kobj,
ian@0 344 struct class_device,
ian@0 345 kobj));
ian@0 346
ian@0 347 return pci_mmap_legacy_page_range(bus, vma);
ian@0 348 }
ian@0 349 #endif /* HAVE_PCI_LEGACY */
ian@0 350
ian@0 351 #ifdef HAVE_PCI_MMAP
ian@0 352 /**
ian@0 353 * pci_mmap_resource - map a PCI resource into user memory space
ian@0 354 * @kobj: kobject for mapping
ian@0 355 * @attr: struct bin_attribute for the file being mapped
ian@0 356 * @vma: struct vm_area_struct passed into the mmap
ian@0 357 *
ian@0 358 * Use the regular PCI mapping routines to map a PCI resource into userspace.
ian@0 359 * FIXME: write combining? maybe automatic for prefetchable regions?
ian@0 360 */
ian@0 361 static int
ian@0 362 pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
ian@0 363 struct vm_area_struct *vma)
ian@0 364 {
ian@0 365 struct pci_dev *pdev = to_pci_dev(container_of(kobj,
ian@0 366 struct device, kobj));
ian@0 367 struct resource *res = (struct resource *)attr->private;
ian@0 368 enum pci_mmap_state mmap_type;
ian@0 369 resource_size_t start, end;
ian@0 370 int i;
ian@0 371
ian@0 372 for (i = 0; i < PCI_ROM_RESOURCE; i++)
ian@0 373 if (res == &pdev->resource[i])
ian@0 374 break;
ian@0 375 if (i >= PCI_ROM_RESOURCE)
ian@0 376 return -ENODEV;
ian@0 377
ian@0 378 /* pci_mmap_page_range() expects the same kind of entry as coming
ian@0 379 * from /proc/bus/pci/ which is a "user visible" value. If this is
ian@0 380 * different from the resource itself, arch will do necessary fixup.
ian@0 381 */
ian@0 382 pci_resource_to_user(pdev, i, res, &start, &end);
ian@0 383 vma->vm_pgoff += start >> PAGE_SHIFT;
ian@0 384 mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
ian@0 385
ian@0 386 return pci_mmap_page_range(pdev, vma, mmap_type, 0);
ian@0 387 }
ian@0 388
ian@0 389 /**
ian@0 390 * pci_create_resource_files - create resource files in sysfs for @dev
ian@0 391 * @dev: dev in question
ian@0 392 *
ian@0 393 * Walk the resources in @dev creating files for each resource available.
ian@0 394 */
ian@0 395 static void
ian@0 396 pci_create_resource_files(struct pci_dev *pdev)
ian@0 397 {
ian@0 398 int i;
ian@0 399
ian@0 400 /* Expose the PCI resources from this device as files */
ian@0 401 for (i = 0; i < PCI_ROM_RESOURCE; i++) {
ian@0 402 struct bin_attribute *res_attr;
ian@0 403
ian@0 404 /* skip empty resources */
ian@0 405 if (!pci_resource_len(pdev, i))
ian@0 406 continue;
ian@0 407
ian@0 408 /* allocate attribute structure, piggyback attribute name */
ian@0 409 res_attr = kzalloc(sizeof(*res_attr) + 10, GFP_ATOMIC);
ian@0 410 if (res_attr) {
ian@0 411 char *res_attr_name = (char *)(res_attr + 1);
ian@0 412
ian@0 413 pdev->res_attr[i] = res_attr;
ian@0 414 sprintf(res_attr_name, "resource%d", i);
ian@0 415 res_attr->attr.name = res_attr_name;
ian@0 416 res_attr->attr.mode = S_IRUSR | S_IWUSR;
ian@0 417 res_attr->attr.owner = THIS_MODULE;
ian@0 418 res_attr->size = pci_resource_len(pdev, i);
ian@0 419 res_attr->mmap = pci_mmap_resource;
ian@0 420 res_attr->private = &pdev->resource[i];
ian@0 421 sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
ian@0 422 }
ian@0 423 }
ian@0 424 }
ian@0 425
ian@0 426 /**
ian@0 427 * pci_remove_resource_files - cleanup resource files
ian@0 428 * @dev: dev to cleanup
ian@0 429 *
ian@0 430 * If we created resource files for @dev, remove them from sysfs and
ian@0 431 * free their resources.
ian@0 432 */
ian@0 433 static void
ian@0 434 pci_remove_resource_files(struct pci_dev *pdev)
ian@0 435 {
ian@0 436 int i;
ian@0 437
ian@0 438 for (i = 0; i < PCI_ROM_RESOURCE; i++) {
ian@0 439 struct bin_attribute *res_attr;
ian@0 440
ian@0 441 res_attr = pdev->res_attr[i];
ian@0 442 if (res_attr) {
ian@0 443 sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
ian@0 444 kfree(res_attr);
ian@0 445 }
ian@0 446 }
ian@0 447 }
ian@0 448 #else /* !HAVE_PCI_MMAP */
ian@0 449 static inline void pci_create_resource_files(struct pci_dev *dev) { return; }
ian@0 450 static inline void pci_remove_resource_files(struct pci_dev *dev) { return; }
ian@0 451 #endif /* HAVE_PCI_MMAP */
ian@0 452
ian@0 453 /**
ian@0 454 * pci_write_rom - used to enable access to the PCI ROM display
ian@0 455 * @kobj: kernel object handle
ian@0 456 * @buf: user input
ian@0 457 * @off: file offset
ian@0 458 * @count: number of byte in input
ian@0 459 *
ian@0 460 * writing anything except 0 enables it
ian@0 461 */
ian@0 462 static ssize_t
ian@0 463 pci_write_rom(struct kobject *kobj, char *buf, loff_t off, size_t count)
ian@0 464 {
ian@0 465 struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj));
ian@0 466
ian@0 467 if ((off == 0) && (*buf == '0') && (count == 2))
ian@0 468 pdev->rom_attr_enabled = 0;
ian@0 469 else
ian@0 470 pdev->rom_attr_enabled = 1;
ian@0 471
ian@0 472 return count;
ian@0 473 }
ian@0 474
ian@0 475 /**
ian@0 476 * pci_read_rom - read a PCI ROM
ian@0 477 * @kobj: kernel object handle
ian@0 478 * @buf: where to put the data we read from the ROM
ian@0 479 * @off: file offset
ian@0 480 * @count: number of bytes to read
ian@0 481 *
ian@0 482 * Put @count bytes starting at @off into @buf from the ROM in the PCI
ian@0 483 * device corresponding to @kobj.
ian@0 484 */
ian@0 485 static ssize_t
ian@0 486 pci_read_rom(struct kobject *kobj, char *buf, loff_t off, size_t count)
ian@0 487 {
ian@0 488 struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj));
ian@0 489 void __iomem *rom;
ian@0 490 size_t size;
ian@0 491
ian@0 492 if (!pdev->rom_attr_enabled)
ian@0 493 return -EINVAL;
ian@0 494
ian@0 495 rom = pci_map_rom(pdev, &size); /* size starts out as PCI window size */
ian@0 496 if (!rom)
ian@0 497 return 0;
ian@0 498
ian@0 499 if (off >= size)
ian@0 500 count = 0;
ian@0 501 else {
ian@0 502 if (off + count > size)
ian@0 503 count = size - off;
ian@0 504
ian@0 505 memcpy_fromio(buf, rom + off, count);
ian@0 506 }
ian@0 507 pci_unmap_rom(pdev, rom);
ian@0 508
ian@0 509 return count;
ian@0 510 }
ian@0 511
ian@0 512 static struct bin_attribute pci_config_attr = {
ian@0 513 .attr = {
ian@0 514 .name = "config",
ian@0 515 .mode = S_IRUGO | S_IWUSR,
ian@0 516 .owner = THIS_MODULE,
ian@0 517 },
ian@0 518 .size = 256,
ian@0 519 .read = pci_read_config,
ian@0 520 .write = pci_write_config,
ian@0 521 };
ian@0 522
ian@0 523 static struct bin_attribute pcie_config_attr = {
ian@0 524 .attr = {
ian@0 525 .name = "config",
ian@0 526 .mode = S_IRUGO | S_IWUSR,
ian@0 527 .owner = THIS_MODULE,
ian@0 528 },
ian@0 529 .size = 4096,
ian@0 530 .read = pci_read_config,
ian@0 531 .write = pci_write_config,
ian@0 532 };
ian@0 533
ian@0 534 int pci_create_sysfs_dev_files (struct pci_dev *pdev)
ian@0 535 {
ian@0 536 if (!sysfs_initialized)
ian@0 537 return -EACCES;
ian@0 538
ian@0 539 if (pdev->cfg_size < 4096)
ian@0 540 sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
ian@0 541 else
ian@0 542 sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
ian@0 543
ian@0 544 pci_create_resource_files(pdev);
ian@0 545
ian@0 546 /* If the device has a ROM, try to expose it in sysfs. */
ian@0 547 if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) {
ian@0 548 struct bin_attribute *rom_attr;
ian@0 549
ian@0 550 rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC);
ian@0 551 if (rom_attr) {
ian@0 552 pdev->rom_attr = rom_attr;
ian@0 553 rom_attr->size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
ian@0 554 rom_attr->attr.name = "rom";
ian@0 555 rom_attr->attr.mode = S_IRUSR;
ian@0 556 rom_attr->attr.owner = THIS_MODULE;
ian@0 557 rom_attr->read = pci_read_rom;
ian@0 558 rom_attr->write = pci_write_rom;
ian@0 559 sysfs_create_bin_file(&pdev->dev.kobj, rom_attr);
ian@0 560 }
ian@0 561 }
ian@0 562 /* add platform-specific attributes */
ian@0 563 pcibios_add_platform_entries(pdev);
ian@0 564
ian@0 565 return 0;
ian@0 566 }
ian@0 567
ian@0 568 /**
ian@0 569 * pci_remove_sysfs_dev_files - cleanup PCI specific sysfs files
ian@0 570 * @pdev: device whose entries we should free
ian@0 571 *
ian@0 572 * Cleanup when @pdev is removed from sysfs.
ian@0 573 */
ian@0 574 void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
ian@0 575 {
ian@240 576 if (!sysfs_initialized)
ian@240 577 return;
ian@240 578
ian@0 579 if (pdev->cfg_size < 4096)
ian@0 580 sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
ian@0 581 else
ian@0 582 sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
ian@0 583
ian@0 584 pci_remove_resource_files(pdev);
ian@0 585
ian@0 586 if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) {
ian@0 587 if (pdev->rom_attr) {
ian@0 588 sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr);
ian@0 589 kfree(pdev->rom_attr);
ian@0 590 }
ian@0 591 }
ian@0 592 }
ian@0 593
ian@0 594 static int __init pci_sysfs_init(void)
ian@0 595 {
ian@0 596 struct pci_dev *pdev = NULL;
ian@0 597
ian@0 598 sysfs_initialized = 1;
ian@0 599 for_each_pci_dev(pdev)
ian@0 600 pci_create_sysfs_dev_files(pdev);
ian@0 601
ian@0 602 return 0;
ian@0 603 }
ian@0 604
ian@0 605 __initcall(pci_sysfs_init);