diff options
Diffstat (limited to 'drivers/pci/pci-sysfs.c')
-rw-r--r-- | drivers/pci/pci-sysfs.c | 94 |
1 files changed, 84 insertions, 10 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index b5a7d9bfcb24..7bcf12adced7 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/mm.h> | 23 | #include <linux/mm.h> |
24 | #include <linux/fs.h> | 24 | #include <linux/fs.h> |
25 | #include <linux/capability.h> | 25 | #include <linux/capability.h> |
26 | #include <linux/security.h> | ||
26 | #include <linux/pci-aspm.h> | 27 | #include <linux/pci-aspm.h> |
27 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
28 | #include "pci.h" | 29 | #include "pci.h" |
@@ -107,6 +108,40 @@ static ssize_t local_cpulist_show(struct device *dev, | |||
107 | return len; | 108 | return len; |
108 | } | 109 | } |
109 | 110 | ||
111 | /* | ||
112 | * PCI Bus Class Devices | ||
113 | */ | ||
114 | static ssize_t pci_bus_show_cpuaffinity(struct device *dev, | ||
115 | int type, | ||
116 | struct device_attribute *attr, | ||
117 | char *buf) | ||
118 | { | ||
119 | int ret; | ||
120 | const struct cpumask *cpumask; | ||
121 | |||
122 | cpumask = cpumask_of_pcibus(to_pci_bus(dev)); | ||
123 | ret = type ? | ||
124 | cpulist_scnprintf(buf, PAGE_SIZE-2, cpumask) : | ||
125 | cpumask_scnprintf(buf, PAGE_SIZE-2, cpumask); | ||
126 | buf[ret++] = '\n'; | ||
127 | buf[ret] = '\0'; | ||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | static inline ssize_t pci_bus_show_cpumaskaffinity(struct device *dev, | ||
132 | struct device_attribute *attr, | ||
133 | char *buf) | ||
134 | { | ||
135 | return pci_bus_show_cpuaffinity(dev, 0, attr, buf); | ||
136 | } | ||
137 | |||
138 | static inline ssize_t pci_bus_show_cpulistaffinity(struct device *dev, | ||
139 | struct device_attribute *attr, | ||
140 | char *buf) | ||
141 | { | ||
142 | return pci_bus_show_cpuaffinity(dev, 1, attr, buf); | ||
143 | } | ||
144 | |||
110 | /* show resources */ | 145 | /* show resources */ |
111 | static ssize_t | 146 | static ssize_t |
112 | resource_show(struct device * dev, struct device_attribute *attr, char * buf) | 147 | resource_show(struct device * dev, struct device_attribute *attr, char * buf) |
@@ -317,6 +352,25 @@ remove_store(struct device *dev, struct device_attribute *dummy, | |||
317 | count = ret; | 352 | count = ret; |
318 | return count; | 353 | return count; |
319 | } | 354 | } |
355 | |||
356 | static ssize_t | ||
357 | dev_bus_rescan_store(struct device *dev, struct device_attribute *attr, | ||
358 | const char *buf, size_t count) | ||
359 | { | ||
360 | unsigned long val; | ||
361 | struct pci_bus *bus = to_pci_bus(dev); | ||
362 | |||
363 | if (strict_strtoul(buf, 0, &val) < 0) | ||
364 | return -EINVAL; | ||
365 | |||
366 | if (val) { | ||
367 | mutex_lock(&pci_remove_rescan_mutex); | ||
368 | pci_rescan_bus(bus); | ||
369 | mutex_unlock(&pci_remove_rescan_mutex); | ||
370 | } | ||
371 | return count; | ||
372 | } | ||
373 | |||
320 | #endif | 374 | #endif |
321 | 375 | ||
322 | struct device_attribute pci_dev_attrs[] = { | 376 | struct device_attribute pci_dev_attrs[] = { |
@@ -346,6 +400,15 @@ struct device_attribute pci_dev_attrs[] = { | |||
346 | __ATTR_NULL, | 400 | __ATTR_NULL, |
347 | }; | 401 | }; |
348 | 402 | ||
403 | struct device_attribute pcibus_dev_attrs[] = { | ||
404 | #ifdef CONFIG_HOTPLUG | ||
405 | __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_bus_rescan_store), | ||
406 | #endif | ||
407 | __ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpumaskaffinity, NULL), | ||
408 | __ATTR(cpulistaffinity, S_IRUGO, pci_bus_show_cpulistaffinity, NULL), | ||
409 | __ATTR_NULL, | ||
410 | }; | ||
411 | |||
349 | static ssize_t | 412 | static ssize_t |
350 | boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf) | 413 | boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf) |
351 | { | 414 | { |
@@ -368,7 +431,7 @@ pci_read_config(struct file *filp, struct kobject *kobj, | |||
368 | u8 *data = (u8*) buf; | 431 | u8 *data = (u8*) buf; |
369 | 432 | ||
370 | /* Several chips lock up trying to read undefined config space */ | 433 | /* Several chips lock up trying to read undefined config space */ |
371 | if (cap_raised(filp->f_cred->cap_effective, CAP_SYS_ADMIN)) { | 434 | if (security_capable(&init_user_ns, filp->f_cred, CAP_SYS_ADMIN) == 0) { |
372 | size = dev->cfg_size; | 435 | size = dev->cfg_size; |
373 | } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { | 436 | } else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { |
374 | size = 128; | 437 | size = 128; |
@@ -644,7 +707,7 @@ pci_adjust_legacy_attr(struct pci_bus *b, enum pci_mmap_state mmap_type) | |||
644 | * a per-bus basis. This routine creates the files and ties them into | 707 | * a per-bus basis. This routine creates the files and ties them into |
645 | * their associated read, write and mmap files from pci-sysfs.c | 708 | * their associated read, write and mmap files from pci-sysfs.c |
646 | * | 709 | * |
647 | * On error unwind, but don't propogate the error to the caller | 710 | * On error unwind, but don't propagate the error to the caller |
648 | * as it is ok to set up the PCI bus without these files. | 711 | * as it is ok to set up the PCI bus without these files. |
649 | */ | 712 | */ |
650 | void pci_create_legacy_files(struct pci_bus *b) | 713 | void pci_create_legacy_files(struct pci_bus *b) |
@@ -705,17 +768,21 @@ void pci_remove_legacy_files(struct pci_bus *b) | |||
705 | 768 | ||
706 | #ifdef HAVE_PCI_MMAP | 769 | #ifdef HAVE_PCI_MMAP |
707 | 770 | ||
708 | int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma) | 771 | int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma, |
772 | enum pci_mmap_api mmap_api) | ||
709 | { | 773 | { |
710 | unsigned long nr, start, size; | 774 | unsigned long nr, start, size, pci_start; |
711 | 775 | ||
776 | if (pci_resource_len(pdev, resno) == 0) | ||
777 | return 0; | ||
712 | nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; | 778 | nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; |
713 | start = vma->vm_pgoff; | 779 | start = vma->vm_pgoff; |
714 | size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1; | 780 | size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1; |
715 | if (start < size && size - start >= nr) | 781 | pci_start = (mmap_api == PCI_MMAP_PROCFS) ? |
782 | pci_resource_start(pdev, resno) >> PAGE_SHIFT : 0; | ||
783 | if (start >= pci_start && start < pci_start + size && | ||
784 | start + nr <= pci_start + size) | ||
716 | return 1; | 785 | return 1; |
717 | WARN(1, "process \"%s\" tried to map 0x%08lx-0x%08lx on %s BAR %d (size 0x%08lx)\n", | ||
718 | current->comm, start, start+nr, pci_name(pdev), resno, size); | ||
719 | return 0; | 786 | return 0; |
720 | } | 787 | } |
721 | 788 | ||
@@ -745,8 +812,15 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, | |||
745 | if (i >= PCI_ROM_RESOURCE) | 812 | if (i >= PCI_ROM_RESOURCE) |
746 | return -ENODEV; | 813 | return -ENODEV; |
747 | 814 | ||
748 | if (!pci_mmap_fits(pdev, i, vma)) | 815 | if (!pci_mmap_fits(pdev, i, vma, PCI_MMAP_SYSFS)) { |
816 | WARN(1, "process \"%s\" tried to map 0x%08lx bytes " | ||
817 | "at page 0x%08lx on %s BAR %d (start 0x%16Lx, size 0x%16Lx)\n", | ||
818 | current->comm, vma->vm_end-vma->vm_start, vma->vm_pgoff, | ||
819 | pci_name(pdev), i, | ||
820 | (u64)pci_resource_start(pdev, i), | ||
821 | (u64)pci_resource_len(pdev, i)); | ||
749 | return -EINVAL; | 822 | return -EINVAL; |
823 | } | ||
750 | 824 | ||
751 | /* pci_mmap_page_range() expects the same kind of entry as coming | 825 | /* pci_mmap_page_range() expects the same kind of entry as coming |
752 | * from /proc/bus/pci/ which is a "user visible" value. If this is | 826 | * from /proc/bus/pci/ which is a "user visible" value. If this is |
@@ -1076,7 +1150,7 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev) | |||
1076 | attr->write = write_vpd_attr; | 1150 | attr->write = write_vpd_attr; |
1077 | retval = sysfs_create_bin_file(&dev->dev.kobj, attr); | 1151 | retval = sysfs_create_bin_file(&dev->dev.kobj, attr); |
1078 | if (retval) { | 1152 | if (retval) { |
1079 | kfree(dev->vpd->attr); | 1153 | kfree(attr); |
1080 | return retval; | 1154 | return retval; |
1081 | } | 1155 | } |
1082 | dev->vpd->attr = attr; | 1156 | dev->vpd->attr = attr; |
@@ -1138,7 +1212,7 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) | |||
1138 | sysfs_bin_attr_init(attr); | 1212 | sysfs_bin_attr_init(attr); |
1139 | attr->size = rom_size; | 1213 | attr->size = rom_size; |
1140 | attr->attr.name = "rom"; | 1214 | attr->attr.name = "rom"; |
1141 | attr->attr.mode = S_IRUSR; | 1215 | attr->attr.mode = S_IRUSR | S_IWUSR; |
1142 | attr->read = pci_read_rom; | 1216 | attr->read = pci_read_rom; |
1143 | attr->write = pci_write_rom; | 1217 | attr->write = pci_write_rom; |
1144 | retval = sysfs_create_bin_file(&pdev->dev.kobj, attr); | 1218 | retval = sysfs_create_bin_file(&pdev->dev.kobj, attr); |