diff options
Diffstat (limited to 'drivers/pci/pci-sysfs.c')
| -rw-r--r-- | drivers/pci/pci-sysfs.c | 85 |
1 files changed, 62 insertions, 23 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 271d41cc05ab..6f3c7446c329 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
| @@ -489,13 +489,13 @@ 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 | */ | 495 | */ |
| 496 | static int | 496 | static int |
| 497 | pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, | 497 | pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, |
| 498 | struct vm_area_struct *vma) | 498 | struct vm_area_struct *vma, int write_combine) |
| 499 | { | 499 | { |
| 500 | struct pci_dev *pdev = to_pci_dev(container_of(kobj, | 500 | struct pci_dev *pdev = to_pci_dev(container_of(kobj, |
| 501 | struct device, kobj)); | 501 | struct device, kobj)); |
| @@ -518,7 +518,21 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, | |||
| 518 | vma->vm_pgoff += start >> PAGE_SHIFT; | 518 | vma->vm_pgoff += start >> PAGE_SHIFT; |
| 519 | mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; | 519 | mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; |
| 520 | 520 | ||
| 521 | return pci_mmap_page_range(pdev, vma, mmap_type, 0); | 521 | return pci_mmap_page_range(pdev, vma, mmap_type, write_combine); |
| 522 | } | ||
| 523 | |||
| 524 | static int | ||
| 525 | pci_mmap_resource_uc(struct kobject *kobj, struct bin_attribute *attr, | ||
| 526 | struct vm_area_struct *vma) | ||
| 527 | { | ||
| 528 | return pci_mmap_resource(kobj, attr, vma, 0); | ||
| 529 | } | ||
| 530 | |||
| 531 | static int | ||
| 532 | pci_mmap_resource_wc(struct kobject *kobj, struct bin_attribute *attr, | ||
| 533 | struct vm_area_struct *vma) | ||
| 534 | { | ||
| 535 | return pci_mmap_resource(kobj, attr, vma, 1); | ||
| 522 | } | 536 | } |
| 523 | 537 | ||
| 524 | /** | 538 | /** |
| @@ -541,9 +555,46 @@ pci_remove_resource_files(struct pci_dev *pdev) | |||
| 541 | sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); | 555 | sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); |
| 542 | kfree(res_attr); | 556 | kfree(res_attr); |
| 543 | } | 557 | } |
| 558 | |||
| 559 | res_attr = pdev->res_attr_wc[i]; | ||
| 560 | if (res_attr) { | ||
| 561 | sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); | ||
| 562 | kfree(res_attr); | ||
| 563 | } | ||
| 544 | } | 564 | } |
| 545 | } | 565 | } |
| 546 | 566 | ||
| 567 | static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine) | ||
| 568 | { | ||
| 569 | /* allocate attribute structure, piggyback attribute name */ | ||
| 570 | int name_len = write_combine ? 13 : 10; | ||
| 571 | struct bin_attribute *res_attr; | ||
| 572 | int retval; | ||
| 573 | |||
| 574 | res_attr = kzalloc(sizeof(*res_attr) + name_len, GFP_ATOMIC); | ||
| 575 | if (res_attr) { | ||
| 576 | char *res_attr_name = (char *)(res_attr + 1); | ||
| 577 | |||
| 578 | if (write_combine) { | ||
| 579 | pdev->res_attr_wc[num] = res_attr; | ||
| 580 | sprintf(res_attr_name, "resource%d_wc", num); | ||
| 581 | res_attr->mmap = pci_mmap_resource_wc; | ||
| 582 | } else { | ||
| 583 | pdev->res_attr[num] = res_attr; | ||
| 584 | sprintf(res_attr_name, "resource%d", num); | ||
| 585 | res_attr->mmap = pci_mmap_resource_uc; | ||
| 586 | } | ||
| 587 | res_attr->attr.name = res_attr_name; | ||
| 588 | res_attr->attr.mode = S_IRUSR | S_IWUSR; | ||
| 589 | res_attr->size = pci_resource_len(pdev, num); | ||
| 590 | res_attr->private = &pdev->resource[num]; | ||
| 591 | retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr); | ||
| 592 | } else | ||
| 593 | retval = -ENOMEM; | ||
| 594 | |||
| 595 | return retval; | ||
| 596 | } | ||
| 597 | |||
| 547 | /** | 598 | /** |
| 548 | * pci_create_resource_files - create resource files in sysfs for @dev | 599 | * pci_create_resource_files - create resource files in sysfs for @dev |
| 549 | * @dev: dev in question | 600 | * @dev: dev in question |
| @@ -557,31 +608,19 @@ static int pci_create_resource_files(struct pci_dev *pdev) | |||
| 557 | 608 | ||
| 558 | /* Expose the PCI resources from this device as files */ | 609 | /* Expose the PCI resources from this device as files */ |
| 559 | for (i = 0; i < PCI_ROM_RESOURCE; i++) { | 610 | for (i = 0; i < PCI_ROM_RESOURCE; i++) { |
| 560 | struct bin_attribute *res_attr; | ||
| 561 | 611 | ||
| 562 | /* skip empty resources */ | 612 | /* skip empty resources */ |
| 563 | if (!pci_resource_len(pdev, i)) | 613 | if (!pci_resource_len(pdev, i)) |
| 564 | continue; | 614 | continue; |
| 565 | 615 | ||
| 566 | /* allocate attribute structure, piggyback attribute name */ | 616 | retval = pci_create_attr(pdev, i, 0); |
| 567 | res_attr = kzalloc(sizeof(*res_attr) + 10, GFP_ATOMIC); | 617 | /* for prefetchable resources, create a WC mappable file */ |
| 568 | if (res_attr) { | 618 | if (!retval && pdev->resource[i].flags & IORESOURCE_PREFETCH) |
| 569 | char *res_attr_name = (char *)(res_attr + 1); | 619 | retval = pci_create_attr(pdev, i, 1); |
| 570 | 620 | ||
| 571 | pdev->res_attr[i] = res_attr; | 621 | if (retval) { |
| 572 | sprintf(res_attr_name, "resource%d", i); | 622 | pci_remove_resource_files(pdev); |
| 573 | res_attr->attr.name = res_attr_name; | 623 | 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 | } | 624 | } |
| 586 | } | 625 | } |
| 587 | return 0; | 626 | return 0; |
