diff options
| -rw-r--r-- | drivers/xen/xen-pciback/pci_stub.c | 89 |
1 files changed, 82 insertions, 7 deletions
diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c index 03342728bf23..20e1c42c1c48 100644 --- a/drivers/xen/xen-pciback/pci_stub.c +++ b/drivers/xen/xen-pciback/pci_stub.c | |||
| @@ -897,17 +897,41 @@ static inline int str_to_slot(const char *buf, int *domain, int *bus, | |||
| 897 | int *slot, int *func) | 897 | int *slot, int *func) |
| 898 | { | 898 | { |
| 899 | int err; | 899 | int err; |
| 900 | char wc = '*'; | ||
| 900 | 901 | ||
| 901 | err = sscanf(buf, " %x:%x:%x.%x", domain, bus, slot, func); | 902 | err = sscanf(buf, " %x:%x:%x.%x", domain, bus, slot, func); |
| 902 | if (err == 4) | 903 | switch (err) { |
| 904 | case 3: | ||
| 905 | *func = -1; | ||
| 906 | err = sscanf(buf, " %x:%x:%x.%c", domain, bus, slot, &wc); | ||
| 907 | break; | ||
| 908 | case 2: | ||
| 909 | *slot = *func = -1; | ||
| 910 | err = sscanf(buf, " %x:%x:*.%c", domain, bus, &wc); | ||
| 911 | if (err >= 2) | ||
| 912 | ++err; | ||
| 913 | break; | ||
| 914 | } | ||
| 915 | if (err == 4 && wc == '*') | ||
| 903 | return 0; | 916 | return 0; |
| 904 | else if (err < 0) | 917 | else if (err < 0) |
| 905 | return -EINVAL; | 918 | return -EINVAL; |
| 906 | 919 | ||
| 907 | /* try again without domain */ | 920 | /* try again without domain */ |
| 908 | *domain = 0; | 921 | *domain = 0; |
| 922 | wc = '*'; | ||
| 909 | err = sscanf(buf, " %x:%x.%x", bus, slot, func); | 923 | err = sscanf(buf, " %x:%x.%x", bus, slot, func); |
| 910 | if (err == 3) | 924 | switch (err) { |
| 925 | case 2: | ||
| 926 | *func = -1; | ||
| 927 | err = sscanf(buf, " %x:%x.%c", bus, slot, &wc); | ||
| 928 | break; | ||
| 929 | case 1: | ||
| 930 | *slot = *func = -1; | ||
| 931 | err = sscanf(buf, " %x:*.%c", bus, &wc) + 1; | ||
| 932 | break; | ||
| 933 | } | ||
| 934 | if (err == 3 && wc == '*') | ||
| 911 | return 0; | 935 | return 0; |
| 912 | 936 | ||
| 913 | return -EINVAL; | 937 | return -EINVAL; |
| @@ -930,6 +954,19 @@ static int pcistub_device_id_add(int domain, int bus, int slot, int func) | |||
| 930 | { | 954 | { |
| 931 | struct pcistub_device_id *pci_dev_id; | 955 | struct pcistub_device_id *pci_dev_id; |
| 932 | unsigned long flags; | 956 | unsigned long flags; |
| 957 | int rc = 0; | ||
| 958 | |||
| 959 | if (slot < 0) { | ||
| 960 | for (slot = 0; !rc && slot < 32; ++slot) | ||
| 961 | rc = pcistub_device_id_add(domain, bus, slot, func); | ||
| 962 | return rc; | ||
| 963 | } | ||
| 964 | |||
| 965 | if (func < 0) { | ||
| 966 | for (func = 0; !rc && func < 8; ++func) | ||
| 967 | rc = pcistub_device_id_add(domain, bus, slot, func); | ||
| 968 | return rc; | ||
| 969 | } | ||
| 933 | 970 | ||
| 934 | pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL); | 971 | pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL); |
| 935 | if (!pci_dev_id) | 972 | if (!pci_dev_id) |
| @@ -952,15 +989,15 @@ static int pcistub_device_id_add(int domain, int bus, int slot, int func) | |||
| 952 | static int pcistub_device_id_remove(int domain, int bus, int slot, int func) | 989 | static int pcistub_device_id_remove(int domain, int bus, int slot, int func) |
| 953 | { | 990 | { |
| 954 | struct pcistub_device_id *pci_dev_id, *t; | 991 | struct pcistub_device_id *pci_dev_id, *t; |
| 955 | int devfn = PCI_DEVFN(slot, func); | ||
| 956 | int err = -ENOENT; | 992 | int err = -ENOENT; |
| 957 | unsigned long flags; | 993 | unsigned long flags; |
| 958 | 994 | ||
| 959 | spin_lock_irqsave(&device_ids_lock, flags); | 995 | spin_lock_irqsave(&device_ids_lock, flags); |
| 960 | list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids, | 996 | list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids, |
| 961 | slot_list) { | 997 | slot_list) { |
| 962 | if (pci_dev_id->domain == domain | 998 | if (pci_dev_id->domain == domain && pci_dev_id->bus == bus |
| 963 | && pci_dev_id->bus == bus && pci_dev_id->devfn == devfn) { | 999 | && (slot < 0 || PCI_SLOT(pci_dev_id->devfn) == slot) |
| 1000 | && (func < 0 || PCI_FUNC(pci_dev_id->devfn) == func)) { | ||
| 964 | /* Don't break; here because it's possible the same | 1001 | /* Don't break; here because it's possible the same |
| 965 | * slot could be in the list more than once | 1002 | * slot could be in the list more than once |
| 966 | */ | 1003 | */ |
| @@ -1216,6 +1253,10 @@ static ssize_t permissive_add(struct device_driver *drv, const char *buf, | |||
| 1216 | err = str_to_slot(buf, &domain, &bus, &slot, &func); | 1253 | err = str_to_slot(buf, &domain, &bus, &slot, &func); |
| 1217 | if (err) | 1254 | if (err) |
| 1218 | goto out; | 1255 | goto out; |
| 1256 | if (slot < 0 || func < 0) { | ||
| 1257 | err = -EINVAL; | ||
| 1258 | goto out; | ||
| 1259 | } | ||
| 1219 | psdev = pcistub_device_find(domain, bus, slot, func); | 1260 | psdev = pcistub_device_find(domain, bus, slot, func); |
| 1220 | if (!psdev) { | 1261 | if (!psdev) { |
| 1221 | err = -ENODEV; | 1262 | err = -ENODEV; |
| @@ -1297,17 +1338,51 @@ static int __init pcistub_init(void) | |||
| 1297 | 1338 | ||
| 1298 | if (pci_devs_to_hide && *pci_devs_to_hide) { | 1339 | if (pci_devs_to_hide && *pci_devs_to_hide) { |
| 1299 | do { | 1340 | do { |
| 1341 | char wc = '*'; | ||
| 1342 | |||
| 1300 | parsed = 0; | 1343 | parsed = 0; |
| 1301 | 1344 | ||
| 1302 | err = sscanf(pci_devs_to_hide + pos, | 1345 | err = sscanf(pci_devs_to_hide + pos, |
| 1303 | " (%x:%x:%x.%x) %n", | 1346 | " (%x:%x:%x.%x) %n", |
| 1304 | &domain, &bus, &slot, &func, &parsed); | 1347 | &domain, &bus, &slot, &func, &parsed); |
| 1305 | if (err != 4) { | 1348 | switch (err) { |
| 1349 | case 3: | ||
| 1350 | func = -1; | ||
| 1351 | err = sscanf(pci_devs_to_hide + pos, | ||
| 1352 | " (%x:%x:%x.%c) %n", | ||
| 1353 | &domain, &bus, &slot, &wc, | ||
| 1354 | &parsed); | ||
| 1355 | break; | ||
| 1356 | case 2: | ||
| 1357 | slot = func = -1; | ||
| 1358 | err = sscanf(pci_devs_to_hide + pos, | ||
| 1359 | " (%x:%x:*.%c) %n", | ||
| 1360 | &domain, &bus, &wc, &parsed) + 1; | ||
| 1361 | break; | ||
| 1362 | } | ||
| 1363 | |||
| 1364 | if (err != 4 || wc != '*') { | ||
| 1306 | domain = 0; | 1365 | domain = 0; |
| 1366 | wc = '*'; | ||
| 1307 | err = sscanf(pci_devs_to_hide + pos, | 1367 | err = sscanf(pci_devs_to_hide + pos, |
| 1308 | " (%x:%x.%x) %n", | 1368 | " (%x:%x.%x) %n", |
| 1309 | &bus, &slot, &func, &parsed); | 1369 | &bus, &slot, &func, &parsed); |
| 1310 | if (err != 3) | 1370 | switch (err) { |
| 1371 | case 2: | ||
| 1372 | func = -1; | ||
| 1373 | err = sscanf(pci_devs_to_hide + pos, | ||
| 1374 | " (%x:%x.%c) %n", | ||
| 1375 | &bus, &slot, &wc, | ||
| 1376 | &parsed); | ||
| 1377 | break; | ||
| 1378 | case 1: | ||
| 1379 | slot = func = -1; | ||
| 1380 | err = sscanf(pci_devs_to_hide + pos, | ||
| 1381 | " (%x:*.%c) %n", | ||
| 1382 | &bus, &wc, &parsed) + 1; | ||
| 1383 | break; | ||
| 1384 | } | ||
| 1385 | if (err != 3 || wc != '*') | ||
| 1311 | goto parse_error; | 1386 | goto parse_error; |
| 1312 | } | 1387 | } |
| 1313 | 1388 | ||
