diff options
| -rw-r--r-- | Documentation/filesystems/sysfs-pci.txt | 1 | ||||
| -rw-r--r-- | arch/x86/kernel/pci-dma.c | 14 | ||||
| -rw-r--r-- | arch/x86/pci/common.c | 8 | ||||
| -rw-r--r-- | drivers/pci/pci-driver.c | 2 | ||||
| -rw-r--r-- | drivers/pci/pci-sysfs.c | 85 | ||||
| -rw-r--r-- | include/linux/pci.h | 1 |
6 files changed, 79 insertions, 32 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/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index c5ef1af8e79d..dc00a1331ace 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c | |||
| @@ -378,6 +378,7 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, | |||
| 378 | struct page *page; | 378 | struct page *page; |
| 379 | unsigned long dma_mask = 0; | 379 | unsigned long dma_mask = 0; |
| 380 | dma_addr_t bus; | 380 | dma_addr_t bus; |
| 381 | int noretry = 0; | ||
| 381 | 382 | ||
| 382 | /* ignore region specifiers */ | 383 | /* ignore region specifiers */ |
| 383 | gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); | 384 | gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); |
| @@ -397,20 +398,25 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, | |||
| 397 | if (dev->dma_mask == NULL) | 398 | if (dev->dma_mask == NULL) |
| 398 | return NULL; | 399 | return NULL; |
| 399 | 400 | ||
| 400 | /* Don't invoke OOM killer */ | 401 | /* Don't invoke OOM killer or retry in lower 16MB DMA zone */ |
| 401 | gfp |= __GFP_NORETRY; | 402 | if (gfp & __GFP_DMA) |
| 403 | noretry = 1; | ||
| 402 | 404 | ||
| 403 | #ifdef CONFIG_X86_64 | 405 | #ifdef CONFIG_X86_64 |
| 404 | /* Why <=? Even when the mask is smaller than 4GB it is often | 406 | /* Why <=? Even when the mask is smaller than 4GB it is often |
| 405 | larger than 16MB and in this case we have a chance of | 407 | larger than 16MB and in this case we have a chance of |
| 406 | finding fitting memory in the next higher zone first. If | 408 | finding fitting memory in the next higher zone first. If |
| 407 | not retry with true GFP_DMA. -AK */ | 409 | not retry with true GFP_DMA. -AK */ |
| 408 | if (dma_mask <= DMA_32BIT_MASK && !(gfp & GFP_DMA)) | 410 | if (dma_mask <= DMA_32BIT_MASK && !(gfp & GFP_DMA)) { |
| 409 | gfp |= GFP_DMA32; | 411 | gfp |= GFP_DMA32; |
| 412 | if (dma_mask < DMA_32BIT_MASK) | ||
| 413 | noretry = 1; | ||
| 414 | } | ||
| 410 | #endif | 415 | #endif |
| 411 | 416 | ||
| 412 | again: | 417 | again: |
| 413 | page = dma_alloc_pages(dev, gfp, get_order(size)); | 418 | page = dma_alloc_pages(dev, |
| 419 | noretry ? gfp | __GFP_NORETRY : gfp, get_order(size)); | ||
| 414 | if (page == NULL) | 420 | if (page == NULL) |
| 415 | return NULL; | 421 | return NULL; |
| 416 | 422 | ||
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 6e64aaf00d1d..940185ecaeda 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c | |||
| @@ -328,18 +328,18 @@ static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = { | |||
| 328 | #endif | 328 | #endif |
| 329 | { | 329 | { |
| 330 | .callback = set_bf_sort, | 330 | .callback = set_bf_sort, |
| 331 | .ident = "HP ProLiant DL385 G2", | 331 | .ident = "HP ProLiant DL360", |
| 332 | .matches = { | 332 | .matches = { |
| 333 | DMI_MATCH(DMI_SYS_VENDOR, "HP"), | 333 | DMI_MATCH(DMI_SYS_VENDOR, "HP"), |
| 334 | DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL385 G2"), | 334 | DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL360"), |
| 335 | }, | 335 | }, |
| 336 | }, | 336 | }, |
| 337 | { | 337 | { |
| 338 | .callback = set_bf_sort, | 338 | .callback = set_bf_sort, |
| 339 | .ident = "HP ProLiant DL585 G2", | 339 | .ident = "HP ProLiant DL380", |
| 340 | .matches = { | 340 | .matches = { |
| 341 | DMI_MATCH(DMI_SYS_VENDOR, "HP"), | 341 | DMI_MATCH(DMI_SYS_VENDOR, "HP"), |
| 342 | DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL585 G2"), | 342 | DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL380"), |
| 343 | }, | 343 | }, |
| 344 | }, | 344 | }, |
| 345 | {} | 345 | {} |
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 72cf61ed8f96..e1637bd82b8e 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c | |||
| @@ -181,7 +181,7 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev, | |||
| 181 | any need to change it. */ | 181 | any need to change it. */ |
| 182 | struct mempolicy *oldpol; | 182 | struct mempolicy *oldpol; |
| 183 | cpumask_t oldmask = current->cpus_allowed; | 183 | cpumask_t oldmask = current->cpus_allowed; |
| 184 | int node = pcibus_to_node(dev->bus); | 184 | int node = dev_to_node(&dev->dev); |
| 185 | 185 | ||
| 186 | if (node >= 0) { | 186 | if (node >= 0) { |
| 187 | node_to_cpumask_ptr(nodecpumask, node); | 187 | node_to_cpumask_ptr(nodecpumask, node); |
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; |
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 |
