aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/sysfs-pci.txt1
-rw-r--r--drivers/pci/pci-sysfs.c84
-rw-r--r--include/linux/pci.h1
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 */
496static int 497static int
497pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, 498pci_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
525static int
526pci_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
532static int
533pci_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
568static 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