diff options
Diffstat (limited to 'drivers/pci/pci-sysfs.c')
-rw-r--r-- | drivers/pci/pci-sysfs.c | 95 |
1 files changed, 43 insertions, 52 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index c88485860a0a..c23619fb6c4b 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
@@ -58,13 +58,14 @@ static ssize_t broken_parity_status_store(struct device *dev, | |||
58 | const char *buf, size_t count) | 58 | const char *buf, size_t count) |
59 | { | 59 | { |
60 | struct pci_dev *pdev = to_pci_dev(dev); | 60 | struct pci_dev *pdev = to_pci_dev(dev); |
61 | ssize_t consumed = -EINVAL; | 61 | unsigned long val; |
62 | 62 | ||
63 | if ((count > 0) && (*buf == '0' || *buf == '1')) { | 63 | if (strict_strtoul(buf, 0, &val) < 0) |
64 | pdev->broken_parity_status = *buf == '1' ? 1 : 0; | 64 | return -EINVAL; |
65 | consumed = count; | 65 | |
66 | } | 66 | pdev->broken_parity_status = !!val; |
67 | return consumed; | 67 | |
68 | return count; | ||
68 | } | 69 | } |
69 | 70 | ||
70 | static ssize_t local_cpus_show(struct device *dev, | 71 | static ssize_t local_cpus_show(struct device *dev, |
@@ -101,11 +102,13 @@ resource_show(struct device * dev, struct device_attribute *attr, char * buf) | |||
101 | struct pci_dev * pci_dev = to_pci_dev(dev); | 102 | struct pci_dev * pci_dev = to_pci_dev(dev); |
102 | char * str = buf; | 103 | char * str = buf; |
103 | int i; | 104 | int i; |
104 | int max = 7; | 105 | int max; |
105 | resource_size_t start, end; | 106 | resource_size_t start, end; |
106 | 107 | ||
107 | if (pci_dev->subordinate) | 108 | if (pci_dev->subordinate) |
108 | max = DEVICE_COUNT_RESOURCE; | 109 | max = DEVICE_COUNT_RESOURCE; |
110 | else | ||
111 | max = PCI_BRIDGE_RESOURCES; | ||
109 | 112 | ||
110 | for (i = 0; i < max; i++) { | 113 | for (i = 0; i < max; i++) { |
111 | struct resource *res = &pci_dev->resource[i]; | 114 | struct resource *res = &pci_dev->resource[i]; |
@@ -133,19 +136,23 @@ static ssize_t is_enabled_store(struct device *dev, | |||
133 | struct device_attribute *attr, const char *buf, | 136 | struct device_attribute *attr, const char *buf, |
134 | size_t count) | 137 | size_t count) |
135 | { | 138 | { |
136 | ssize_t result = -EINVAL; | ||
137 | struct pci_dev *pdev = to_pci_dev(dev); | 139 | struct pci_dev *pdev = to_pci_dev(dev); |
140 | unsigned long val; | ||
141 | ssize_t result = strict_strtoul(buf, 0, &val); | ||
142 | |||
143 | if (result < 0) | ||
144 | return result; | ||
138 | 145 | ||
139 | /* this can crash the machine when done on the "wrong" device */ | 146 | /* this can crash the machine when done on the "wrong" device */ |
140 | if (!capable(CAP_SYS_ADMIN)) | 147 | if (!capable(CAP_SYS_ADMIN)) |
141 | return count; | 148 | return -EPERM; |
142 | 149 | ||
143 | if (*buf == '0') { | 150 | if (!val) { |
144 | if (atomic_read(&pdev->enable_cnt) != 0) | 151 | if (atomic_read(&pdev->enable_cnt) != 0) |
145 | pci_disable_device(pdev); | 152 | pci_disable_device(pdev); |
146 | else | 153 | else |
147 | result = -EIO; | 154 | result = -EIO; |
148 | } else if (*buf == '1') | 155 | } else |
149 | result = pci_enable_device(pdev); | 156 | result = pci_enable_device(pdev); |
150 | 157 | ||
151 | return result < 0 ? result : count; | 158 | return result < 0 ? result : count; |
@@ -185,25 +192,28 @@ msi_bus_store(struct device *dev, struct device_attribute *attr, | |||
185 | const char *buf, size_t count) | 192 | const char *buf, size_t count) |
186 | { | 193 | { |
187 | struct pci_dev *pdev = to_pci_dev(dev); | 194 | struct pci_dev *pdev = to_pci_dev(dev); |
195 | unsigned long val; | ||
196 | |||
197 | if (strict_strtoul(buf, 0, &val) < 0) | ||
198 | return -EINVAL; | ||
188 | 199 | ||
189 | /* bad things may happen if the no_msi flag is changed | 200 | /* bad things may happen if the no_msi flag is changed |
190 | * while some drivers are loaded */ | 201 | * while some drivers are loaded */ |
191 | if (!capable(CAP_SYS_ADMIN)) | 202 | if (!capable(CAP_SYS_ADMIN)) |
192 | return count; | 203 | return -EPERM; |
193 | 204 | ||
205 | /* Maybe pci devices without subordinate busses shouldn't even have this | ||
206 | * attribute in the first place? */ | ||
194 | if (!pdev->subordinate) | 207 | if (!pdev->subordinate) |
195 | return count; | 208 | return count; |
196 | 209 | ||
197 | if (*buf == '0') { | 210 | /* Is the flag going to change, or keep the value it already had? */ |
198 | pdev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; | 211 | if (!(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI) ^ |
199 | dev_warn(&pdev->dev, "forced subordinate bus to not support MSI," | 212 | !!val) { |
200 | " bad things could happen.\n"); | 213 | pdev->subordinate->bus_flags ^= PCI_BUS_FLAGS_NO_MSI; |
201 | } | ||
202 | 214 | ||
203 | if (*buf == '1') { | 215 | dev_warn(&pdev->dev, "forced subordinate bus to%s support MSI," |
204 | pdev->subordinate->bus_flags &= ~PCI_BUS_FLAGS_NO_MSI; | 216 | " bad things could happen\n", val ? "" : " not"); |
205 | dev_warn(&pdev->dev, "forced subordinate bus to support MSI," | ||
206 | " bad things could happen.\n"); | ||
207 | } | 217 | } |
208 | 218 | ||
209 | return count; | 219 | return count; |
@@ -361,55 +371,33 @@ pci_write_config(struct kobject *kobj, struct bin_attribute *bin_attr, | |||
361 | } | 371 | } |
362 | 372 | ||
363 | static ssize_t | 373 | static ssize_t |
364 | pci_read_vpd(struct kobject *kobj, struct bin_attribute *bin_attr, | 374 | read_vpd_attr(struct kobject *kobj, struct bin_attribute *bin_attr, |
365 | char *buf, loff_t off, size_t count) | 375 | char *buf, loff_t off, size_t count) |
366 | { | 376 | { |
367 | struct pci_dev *dev = | 377 | struct pci_dev *dev = |
368 | to_pci_dev(container_of(kobj, struct device, kobj)); | 378 | to_pci_dev(container_of(kobj, struct device, kobj)); |
369 | int end; | ||
370 | int ret; | ||
371 | 379 | ||
372 | if (off > bin_attr->size) | 380 | if (off > bin_attr->size) |
373 | count = 0; | 381 | count = 0; |
374 | else if (count > bin_attr->size - off) | 382 | else if (count > bin_attr->size - off) |
375 | count = bin_attr->size - off; | 383 | count = bin_attr->size - off; |
376 | end = off + count; | ||
377 | |||
378 | while (off < end) { | ||
379 | ret = dev->vpd->ops->read(dev, off, end - off, buf); | ||
380 | if (ret < 0) | ||
381 | return ret; | ||
382 | buf += ret; | ||
383 | off += ret; | ||
384 | } | ||
385 | 384 | ||
386 | return count; | 385 | return pci_read_vpd(dev, off, count, buf); |
387 | } | 386 | } |
388 | 387 | ||
389 | static ssize_t | 388 | static ssize_t |
390 | pci_write_vpd(struct kobject *kobj, struct bin_attribute *bin_attr, | 389 | write_vpd_attr(struct kobject *kobj, struct bin_attribute *bin_attr, |
391 | char *buf, loff_t off, size_t count) | 390 | char *buf, loff_t off, size_t count) |
392 | { | 391 | { |
393 | struct pci_dev *dev = | 392 | struct pci_dev *dev = |
394 | to_pci_dev(container_of(kobj, struct device, kobj)); | 393 | to_pci_dev(container_of(kobj, struct device, kobj)); |
395 | int end; | ||
396 | int ret; | ||
397 | 394 | ||
398 | if (off > bin_attr->size) | 395 | if (off > bin_attr->size) |
399 | count = 0; | 396 | count = 0; |
400 | else if (count > bin_attr->size - off) | 397 | else if (count > bin_attr->size - off) |
401 | count = bin_attr->size - off; | 398 | count = bin_attr->size - off; |
402 | end = off + count; | ||
403 | |||
404 | while (off < end) { | ||
405 | ret = dev->vpd->ops->write(dev, off, end - off, buf); | ||
406 | if (ret < 0) | ||
407 | return ret; | ||
408 | buf += ret; | ||
409 | off += ret; | ||
410 | } | ||
411 | 399 | ||
412 | return count; | 400 | return pci_write_vpd(dev, off, count, buf); |
413 | } | 401 | } |
414 | 402 | ||
415 | #ifdef HAVE_PCI_LEGACY | 403 | #ifdef HAVE_PCI_LEGACY |
@@ -569,7 +557,7 @@ void pci_remove_legacy_files(struct pci_bus *b) | |||
569 | 557 | ||
570 | #ifdef HAVE_PCI_MMAP | 558 | #ifdef HAVE_PCI_MMAP |
571 | 559 | ||
572 | static int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma) | 560 | int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma) |
573 | { | 561 | { |
574 | unsigned long nr, start, size; | 562 | unsigned long nr, start, size; |
575 | 563 | ||
@@ -620,6 +608,9 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, | |||
620 | vma->vm_pgoff += start >> PAGE_SHIFT; | 608 | vma->vm_pgoff += start >> PAGE_SHIFT; |
621 | mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; | 609 | mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; |
622 | 610 | ||
611 | if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(start)) | ||
612 | return -EINVAL; | ||
613 | |||
623 | return pci_mmap_page_range(pdev, vma, mmap_type, write_combine); | 614 | return pci_mmap_page_range(pdev, vma, mmap_type, write_combine); |
624 | } | 615 | } |
625 | 616 | ||
@@ -832,8 +823,8 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev) | |||
832 | attr->size = dev->vpd->len; | 823 | attr->size = dev->vpd->len; |
833 | attr->attr.name = "vpd"; | 824 | attr->attr.name = "vpd"; |
834 | attr->attr.mode = S_IRUSR | S_IWUSR; | 825 | attr->attr.mode = S_IRUSR | S_IWUSR; |
835 | attr->read = pci_read_vpd; | 826 | attr->read = read_vpd_attr; |
836 | attr->write = pci_write_vpd; | 827 | attr->write = write_vpd_attr; |
837 | retval = sysfs_create_bin_file(&dev->dev.kobj, attr); | 828 | retval = sysfs_create_bin_file(&dev->dev.kobj, attr); |
838 | if (retval) { | 829 | if (retval) { |
839 | kfree(dev->vpd->attr); | 830 | kfree(dev->vpd->attr); |