diff options
Diffstat (limited to 'drivers/pci/pci-sysfs.c')
-rw-r--r-- | drivers/pci/pci-sysfs.c | 104 |
1 files changed, 61 insertions, 43 deletions
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 25d010d449a3..31e99613a12e 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
@@ -526,10 +526,37 @@ exit: | |||
526 | return count; | 526 | return count; |
527 | } | 527 | } |
528 | 528 | ||
529 | static ssize_t sriov_drivers_autoprobe_show(struct device *dev, | ||
530 | struct device_attribute *attr, | ||
531 | char *buf) | ||
532 | { | ||
533 | struct pci_dev *pdev = to_pci_dev(dev); | ||
534 | |||
535 | return sprintf(buf, "%u\n", pdev->sriov->drivers_autoprobe); | ||
536 | } | ||
537 | |||
538 | static ssize_t sriov_drivers_autoprobe_store(struct device *dev, | ||
539 | struct device_attribute *attr, | ||
540 | const char *buf, size_t count) | ||
541 | { | ||
542 | struct pci_dev *pdev = to_pci_dev(dev); | ||
543 | bool drivers_autoprobe; | ||
544 | |||
545 | if (kstrtobool(buf, &drivers_autoprobe) < 0) | ||
546 | return -EINVAL; | ||
547 | |||
548 | pdev->sriov->drivers_autoprobe = drivers_autoprobe; | ||
549 | |||
550 | return count; | ||
551 | } | ||
552 | |||
529 | static struct device_attribute sriov_totalvfs_attr = __ATTR_RO(sriov_totalvfs); | 553 | static struct device_attribute sriov_totalvfs_attr = __ATTR_RO(sriov_totalvfs); |
530 | static struct device_attribute sriov_numvfs_attr = | 554 | static struct device_attribute sriov_numvfs_attr = |
531 | __ATTR(sriov_numvfs, (S_IRUGO|S_IWUSR|S_IWGRP), | 555 | __ATTR(sriov_numvfs, (S_IRUGO|S_IWUSR|S_IWGRP), |
532 | sriov_numvfs_show, sriov_numvfs_store); | 556 | sriov_numvfs_show, sriov_numvfs_store); |
557 | static struct device_attribute sriov_drivers_autoprobe_attr = | ||
558 | __ATTR(sriov_drivers_autoprobe, (S_IRUGO|S_IWUSR|S_IWGRP), | ||
559 | sriov_drivers_autoprobe_show, sriov_drivers_autoprobe_store); | ||
533 | #endif /* CONFIG_PCI_IOV */ | 560 | #endif /* CONFIG_PCI_IOV */ |
534 | 561 | ||
535 | static ssize_t driver_override_store(struct device *dev, | 562 | static ssize_t driver_override_store(struct device *dev, |
@@ -980,20 +1007,24 @@ void pci_remove_legacy_files(struct pci_bus *b) | |||
980 | } | 1007 | } |
981 | #endif /* HAVE_PCI_LEGACY */ | 1008 | #endif /* HAVE_PCI_LEGACY */ |
982 | 1009 | ||
983 | #ifdef HAVE_PCI_MMAP | 1010 | #if defined(HAVE_PCI_MMAP) || defined(ARCH_GENERIC_PCI_MMAP_RESOURCE) |
984 | 1011 | ||
985 | int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma, | 1012 | int pci_mmap_fits(struct pci_dev *pdev, int resno, struct vm_area_struct *vma, |
986 | enum pci_mmap_api mmap_api) | 1013 | enum pci_mmap_api mmap_api) |
987 | { | 1014 | { |
988 | unsigned long nr, start, size, pci_start; | 1015 | unsigned long nr, start, size; |
1016 | resource_size_t pci_start = 0, pci_end; | ||
989 | 1017 | ||
990 | if (pci_resource_len(pdev, resno) == 0) | 1018 | if (pci_resource_len(pdev, resno) == 0) |
991 | return 0; | 1019 | return 0; |
992 | nr = vma_pages(vma); | 1020 | nr = vma_pages(vma); |
993 | start = vma->vm_pgoff; | 1021 | start = vma->vm_pgoff; |
994 | size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1; | 1022 | size = ((pci_resource_len(pdev, resno) - 1) >> PAGE_SHIFT) + 1; |
995 | pci_start = (mmap_api == PCI_MMAP_PROCFS) ? | 1023 | if (mmap_api == PCI_MMAP_PROCFS) { |
996 | pci_resource_start(pdev, resno) >> PAGE_SHIFT : 0; | 1024 | pci_resource_to_user(pdev, resno, &pdev->resource[resno], |
1025 | &pci_start, &pci_end); | ||
1026 | pci_start >>= PAGE_SHIFT; | ||
1027 | } | ||
997 | if (start >= pci_start && start < pci_start + size && | 1028 | if (start >= pci_start && start < pci_start + size && |
998 | start + nr <= pci_start + size) | 1029 | start + nr <= pci_start + size) |
999 | return 1; | 1030 | return 1; |
@@ -1013,37 +1044,24 @@ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, | |||
1013 | struct vm_area_struct *vma, int write_combine) | 1044 | struct vm_area_struct *vma, int write_combine) |
1014 | { | 1045 | { |
1015 | struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj)); | 1046 | struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj)); |
1016 | struct resource *res = attr->private; | 1047 | int bar = (unsigned long)attr->private; |
1017 | enum pci_mmap_state mmap_type; | 1048 | enum pci_mmap_state mmap_type; |
1018 | resource_size_t start, end; | 1049 | struct resource *res = &pdev->resource[bar]; |
1019 | int i; | ||
1020 | |||
1021 | for (i = 0; i < PCI_ROM_RESOURCE; i++) | ||
1022 | if (res == &pdev->resource[i]) | ||
1023 | break; | ||
1024 | if (i >= PCI_ROM_RESOURCE) | ||
1025 | return -ENODEV; | ||
1026 | 1050 | ||
1027 | if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start)) | 1051 | if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(res->start)) |
1028 | return -EINVAL; | 1052 | return -EINVAL; |
1029 | 1053 | ||
1030 | if (!pci_mmap_fits(pdev, i, vma, PCI_MMAP_SYSFS)) { | 1054 | if (!pci_mmap_fits(pdev, bar, vma, PCI_MMAP_SYSFS)) { |
1031 | WARN(1, "process \"%s\" tried to map 0x%08lx bytes at page 0x%08lx on %s BAR %d (start 0x%16Lx, size 0x%16Lx)\n", | 1055 | WARN(1, "process \"%s\" tried to map 0x%08lx bytes at page 0x%08lx on %s BAR %d (start 0x%16Lx, size 0x%16Lx)\n", |
1032 | current->comm, vma->vm_end-vma->vm_start, vma->vm_pgoff, | 1056 | current->comm, vma->vm_end-vma->vm_start, vma->vm_pgoff, |
1033 | pci_name(pdev), i, | 1057 | pci_name(pdev), bar, |
1034 | (u64)pci_resource_start(pdev, i), | 1058 | (u64)pci_resource_start(pdev, bar), |
1035 | (u64)pci_resource_len(pdev, i)); | 1059 | (u64)pci_resource_len(pdev, bar)); |
1036 | return -EINVAL; | 1060 | return -EINVAL; |
1037 | } | 1061 | } |
1038 | |||
1039 | /* pci_mmap_page_range() expects the same kind of entry as coming | ||
1040 | * from /proc/bus/pci/ which is a "user visible" value. If this is | ||
1041 | * different from the resource itself, arch will do necessary fixup. | ||
1042 | */ | ||
1043 | pci_resource_to_user(pdev, i, res, &start, &end); | ||
1044 | vma->vm_pgoff += start >> PAGE_SHIFT; | ||
1045 | mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; | 1062 | mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; |
1046 | return pci_mmap_page_range(pdev, vma, mmap_type, write_combine); | 1063 | |
1064 | return pci_mmap_resource_range(pdev, bar, vma, mmap_type, write_combine); | ||
1047 | } | 1065 | } |
1048 | 1066 | ||
1049 | static int pci_mmap_resource_uc(struct file *filp, struct kobject *kobj, | 1067 | static int pci_mmap_resource_uc(struct file *filp, struct kobject *kobj, |
@@ -1065,22 +1083,18 @@ static ssize_t pci_resource_io(struct file *filp, struct kobject *kobj, | |||
1065 | loff_t off, size_t count, bool write) | 1083 | loff_t off, size_t count, bool write) |
1066 | { | 1084 | { |
1067 | struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj)); | 1085 | struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj)); |
1068 | struct resource *res = attr->private; | 1086 | int bar = (unsigned long)attr->private; |
1087 | struct resource *res; | ||
1069 | unsigned long port = off; | 1088 | unsigned long port = off; |
1070 | int i; | ||
1071 | 1089 | ||
1072 | for (i = 0; i < PCI_ROM_RESOURCE; i++) | 1090 | res = &pdev->resource[bar]; |
1073 | if (res == &pdev->resource[i]) | ||
1074 | break; | ||
1075 | if (i >= PCI_ROM_RESOURCE) | ||
1076 | return -ENODEV; | ||
1077 | 1091 | ||
1078 | port += pci_resource_start(pdev, i); | 1092 | port += pci_resource_start(pdev, bar); |
1079 | 1093 | ||
1080 | if (port > pci_resource_end(pdev, i)) | 1094 | if (port > pci_resource_end(pdev, bar)) |
1081 | return 0; | 1095 | return 0; |
1082 | 1096 | ||
1083 | if (port + count - 1 > pci_resource_end(pdev, i)) | 1097 | if (port + count - 1 > pci_resource_end(pdev, bar)) |
1084 | return -EINVAL; | 1098 | return -EINVAL; |
1085 | 1099 | ||
1086 | switch (count) { | 1100 | switch (count) { |
@@ -1170,16 +1184,19 @@ static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine) | |||
1170 | } else { | 1184 | } else { |
1171 | pdev->res_attr[num] = res_attr; | 1185 | pdev->res_attr[num] = res_attr; |
1172 | sprintf(res_attr_name, "resource%d", num); | 1186 | sprintf(res_attr_name, "resource%d", num); |
1173 | res_attr->mmap = pci_mmap_resource_uc; | 1187 | if (pci_resource_flags(pdev, num) & IORESOURCE_IO) { |
1174 | } | 1188 | res_attr->read = pci_read_resource_io; |
1175 | if (pci_resource_flags(pdev, num) & IORESOURCE_IO) { | 1189 | res_attr->write = pci_write_resource_io; |
1176 | res_attr->read = pci_read_resource_io; | 1190 | if (arch_can_pci_mmap_io()) |
1177 | res_attr->write = pci_write_resource_io; | 1191 | res_attr->mmap = pci_mmap_resource_uc; |
1192 | } else { | ||
1193 | res_attr->mmap = pci_mmap_resource_uc; | ||
1194 | } | ||
1178 | } | 1195 | } |
1179 | res_attr->attr.name = res_attr_name; | 1196 | res_attr->attr.name = res_attr_name; |
1180 | res_attr->attr.mode = S_IRUSR | S_IWUSR; | 1197 | res_attr->attr.mode = S_IRUSR | S_IWUSR; |
1181 | res_attr->size = pci_resource_len(pdev, num); | 1198 | res_attr->size = pci_resource_len(pdev, num); |
1182 | res_attr->private = &pdev->resource[num]; | 1199 | res_attr->private = (void *)(unsigned long)num; |
1183 | retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr); | 1200 | retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr); |
1184 | if (retval) | 1201 | if (retval) |
1185 | kfree(res_attr); | 1202 | kfree(res_attr); |
@@ -1207,9 +1224,9 @@ static int pci_create_resource_files(struct pci_dev *pdev) | |||
1207 | 1224 | ||
1208 | retval = pci_create_attr(pdev, i, 0); | 1225 | retval = pci_create_attr(pdev, i, 0); |
1209 | /* for prefetchable resources, create a WC mappable file */ | 1226 | /* for prefetchable resources, create a WC mappable file */ |
1210 | if (!retval && pdev->resource[i].flags & IORESOURCE_PREFETCH) | 1227 | if (!retval && arch_can_pci_mmap_wc() && |
1228 | pdev->resource[i].flags & IORESOURCE_PREFETCH) | ||
1211 | retval = pci_create_attr(pdev, i, 1); | 1229 | retval = pci_create_attr(pdev, i, 1); |
1212 | |||
1213 | if (retval) { | 1230 | if (retval) { |
1214 | pci_remove_resource_files(pdev); | 1231 | pci_remove_resource_files(pdev); |
1215 | return retval; | 1232 | return retval; |
@@ -1549,6 +1566,7 @@ static struct attribute_group pci_dev_hp_attr_group = { | |||
1549 | static struct attribute *sriov_dev_attrs[] = { | 1566 | static struct attribute *sriov_dev_attrs[] = { |
1550 | &sriov_totalvfs_attr.attr, | 1567 | &sriov_totalvfs_attr.attr, |
1551 | &sriov_numvfs_attr.attr, | 1568 | &sriov_numvfs_attr.attr, |
1569 | &sriov_drivers_autoprobe_attr.attr, | ||
1552 | NULL, | 1570 | NULL, |
1553 | }; | 1571 | }; |
1554 | 1572 | ||