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 |