diff options
| -rw-r--r-- | Documentation/filesystems/sysfs-pci.txt | 1 | ||||
| -rw-r--r-- | drivers/pci/pci-sysfs.c | 84 | ||||
| -rw-r--r-- | include/linux/pci.h | 1 |
3 files changed, 64 insertions, 22 deletions
diff --git a/Documentation/filesystems/sysfs-pci.txt b/Documentation/filesystems/sysfs-pci.txt index 5daa2aaec2c5..68ef48839c04 100644 --- a/Documentation/filesystems/sysfs-pci.txt +++ b/Documentation/filesystems/sysfs-pci.txt | |||
| @@ -36,6 +36,7 @@ files, each with their own function. | |||
| 36 | local_cpus nearby CPU mask (cpumask, ro) | 36 | local_cpus nearby CPU mask (cpumask, ro) |
| 37 | resource PCI resource host addresses (ascii, ro) | 37 | resource PCI resource host addresses (ascii, ro) |
| 38 | resource0..N PCI resource N, if present (binary, mmap) | 38 | resource0..N PCI resource N, if present (binary, mmap) |
| 39 | resource0_wc..N_wc PCI WC map resource N, if prefetchable (binary, mmap) | ||
| 39 | rom PCI ROM resource, if present (binary, ro) | 40 | rom PCI ROM resource, if present (binary, ro) |
| 40 | subsystem_device PCI subsystem device (ascii, ro) | 41 | subsystem_device PCI subsystem device (ascii, ro) |
| 41 | subsystem_vendor PCI subsystem vendor (ascii, ro) | 42 | subsystem_vendor PCI subsystem vendor (ascii, ro) |
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 271d41cc05ab..9ec7d3977a82 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
| @@ -489,13 +489,14 @@ pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr, | |||
| 489 | * @kobj: kobject for mapping | 489 | * @kobj: kobject for mapping |
| 490 | * @attr: struct bin_attribute for the file being mapped | 490 | * @attr: struct bin_attribute for the file being mapped |
| 491 | * @vma: struct vm_area_struct passed into the mmap | 491 | * @vma: struct vm_area_struct passed into the mmap |
| 492 | * @write_combine: 1 for write_combine mapping | ||
| 492 | * | 493 | * |
| 493 | * Use the regular PCI mapping routines to map a PCI resource into userspace. | 494 | * Use the regular PCI mapping routines to map a PCI resource into userspace. |
| 494 | * FIXME: write combining? maybe automatic for prefetchable regions? | 495 | * FIXME: write combining? maybe automatic for prefetchable regions? |
| 495 | */ | 496 | */ |
| 496 | static int | 497 | static int |
| 497 | pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, | 498 | pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, |
| 498 | struct vm_area_struct *vma) | 499 | struct vm_area_struct *vma, int write_combine) |
| 499 | { | 500 | { |
| 500 | struct pci_dev *pdev = to_pci_dev(container_of(kobj, | 501 | struct pci_dev *pdev = to_pci_dev(container_of(kobj, |
| 501 | struct device, kobj)); | 502 | struct device, kobj)); |
| @@ -518,7 +519,21 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, | |||
| 518 | vma->vm_pgoff += start >> PAGE_SHIFT; | 519 | vma->vm_pgoff += start >> PAGE_SHIFT; |
| 519 | mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; | 520 | mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; |
| 520 | 521 | ||
| 521 | return pci_mmap_page_range(pdev, vma, mmap_type, 0); | 522 | return pci_mmap_page_range(pdev, vma, mmap_type, write_combine); |
| 523 | } | ||
| 524 | |||
| 525 | static int | ||
| 526 | pci_mmap_resource_uc(struct kobject *kobj, struct bin_attribute *attr, | ||
| 527 | struct vm_area_struct *vma) | ||
| 528 | { | ||
| 529 | return pci_mmap_resource(kobj, attr, vma, 0); | ||
| 530 | } | ||
| 531 | |||
| 532 | static int | ||
| 533 | pci_mmap_resource_wc(struct kobject *kobj, struct bin_attribute *attr, | ||
| 534 | struct vm_area_struct *vma) | ||
| 535 | { | ||
| 536 | return pci_mmap_resource(kobj, attr, vma, 1); | ||
| 522 | } | 537 | } |
| 523 | 538 | ||
| 524 | /** | 539 | /** |
| @@ -541,9 +556,46 @@ pci_remove_resource_files(struct pci_dev *pdev) | |||
| 541 | sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); | 556 | sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); |
| 542 | kfree(res_attr); | 557 | kfree(res_attr); |
| 543 | } | 558 | } |
| 559 | |||
| 560 | res_attr = pdev->res_attr_wc[i]; | ||
| 561 | if (res_attr) { | ||
| 562 | sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); | ||
| 563 | kfree(res_attr); | ||
| 564 | } | ||
| 544 | } | 565 | } |
| 545 | } | 566 | } |
| 546 | 567 | ||
| 568 | static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine) | ||
| 569 | { | ||
| 570 | /* allocate attribute structure, piggyback attribute name */ | ||
| 571 | int name_len = write_combine ? 13 : 10; | ||
| 572 | struct bin_attribute *res_attr; | ||
| 573 | int retval; | ||
| 574 | |||
| 575 | res_attr = kzalloc(sizeof(*res_attr) + name_len, GFP_ATOMIC); | ||
| 576 | if (res_attr) { | ||
| 577 | char *res_attr_name = (char *)(res_attr + 1); | ||
| 578 | |||
| 579 | if (write_combine) { | ||
| 580 | pdev->res_attr_wc[num] = res_attr; | ||
| 581 | sprintf(res_attr_name, "resource%d_wc", num); | ||
| 582 | res_attr->mmap = pci_mmap_resource_wc; | ||
| 583 | } else { | ||
| 584 | pdev->res_attr[num] = res_attr; | ||
| 585 | sprintf(res_attr_name, "resource%d", num); | ||
| 586 | res_attr->mmap = pci_mmap_resource_uc; | ||
| 587 | } | ||
| 588 | res_attr->attr.name = res_attr_name; | ||
| 589 | res_attr->attr.mode = S_IRUSR | S_IWUSR; | ||
| 590 | res_attr->size = pci_resource_len(pdev, num); | ||
| 591 | res_attr->private = &pdev->resource[num]; | ||
| 592 | retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr); | ||
| 593 | } else | ||
| 594 | retval = -ENOMEM; | ||
| 595 | |||
| 596 | return retval; | ||
| 597 | } | ||
| 598 | |||
| 547 | /** | 599 | /** |
| 548 | * pci_create_resource_files - create resource files in sysfs for @dev | 600 | * pci_create_resource_files - create resource files in sysfs for @dev |
| 549 | * @dev: dev in question | 601 | * @dev: dev in question |
| @@ -557,31 +609,19 @@ static int pci_create_resource_files(struct pci_dev *pdev) | |||
| 557 | 609 | ||
| 558 | /* Expose the PCI resources from this device as files */ | 610 | /* Expose the PCI resources from this device as files */ |
| 559 | for (i = 0; i < PCI_ROM_RESOURCE; i++) { | 611 | for (i = 0; i < PCI_ROM_RESOURCE; i++) { |
| 560 | struct bin_attribute *res_attr; | ||
| 561 | 612 | ||
| 562 | /* skip empty resources */ | 613 | /* skip empty resources */ |
| 563 | if (!pci_resource_len(pdev, i)) | 614 | if (!pci_resource_len(pdev, i)) |
| 564 | continue; | 615 | continue; |
| 565 | 616 | ||
| 566 | /* allocate attribute structure, piggyback attribute name */ | 617 | retval = pci_create_attr(pdev, i, 0); |
| 567 | res_attr = kzalloc(sizeof(*res_attr) + 10, GFP_ATOMIC); | 618 | /* for prefetchable resources, create a WC mappable file */ |
| 568 | if (res_attr) { | 619 | if (!retval && pdev->resource[i].flags & IORESOURCE_PREFETCH) |
| 569 | char *res_attr_name = (char *)(res_attr + 1); | 620 | retval = pci_create_attr(pdev, i, 1); |
| 570 | 621 | ||
| 571 | pdev->res_attr[i] = res_attr; | 622 | if (retval) { |
| 572 | sprintf(res_attr_name, "resource%d", i); | 623 | pci_remove_resource_files(pdev); |
| 573 | res_attr->attr.name = res_attr_name; | 624 | return retval; |
| 574 | res_attr->attr.mode = S_IRUSR | S_IWUSR; | ||
| 575 | res_attr->size = pci_resource_len(pdev, i); | ||
| 576 | res_attr->mmap = pci_mmap_resource; | ||
| 577 | res_attr->private = &pdev->resource[i]; | ||
| 578 | retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr); | ||
| 579 | if (retval) { | ||
| 580 | pci_remove_resource_files(pdev); | ||
| 581 | return retval; | ||
| 582 | } | ||
| 583 | } else { | ||
| 584 | return -ENOMEM; | ||
| 585 | } | 625 | } |
| 586 | } | 626 | } |
| 587 | return 0; | 627 | return 0; |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 509159bcd4e7..d18b1dd49fab 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
| @@ -206,6 +206,7 @@ struct pci_dev { | |||
| 206 | struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */ | 206 | struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */ |
| 207 | int rom_attr_enabled; /* has display of the rom attribute been enabled? */ | 207 | int rom_attr_enabled; /* has display of the rom attribute been enabled? */ |
| 208 | struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ | 208 | struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ |
| 209 | struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */ | ||
| 209 | #ifdef CONFIG_PCI_MSI | 210 | #ifdef CONFIG_PCI_MSI |
| 210 | struct list_head msi_list; | 211 | struct list_head msi_list; |
| 211 | #endif | 212 | #endif |
