aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci-sysfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/pci-sysfs.c')
-rw-r--r--drivers/pci/pci-sysfs.c95
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
70static ssize_t local_cpus_show(struct device *dev, 71static 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
363static ssize_t 373static ssize_t
364pci_read_vpd(struct kobject *kobj, struct bin_attribute *bin_attr, 374read_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
389static ssize_t 388static ssize_t
390pci_write_vpd(struct kobject *kobj, struct bin_attribute *bin_attr, 389write_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
572static int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma) 560int 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);