diff options
author | Jan Beulich <JBeulich@suse.com> | 2012-09-18 07:29:03 -0400 |
---|---|---|
committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2012-09-18 10:44:17 -0400 |
commit | c3cb4709809e655a4ba5a716086c8bc5bbbbccdb (patch) | |
tree | bc3d42fb3a4723eb02efb161fd8f2a2bff77e5d6 /drivers/xen/xen-pciback/pci_stub.c | |
parent | ecc635f90adfe1b7cd5fd354f49edfbf24aa4e3e (diff) |
xen-pciback: support wild cards in slot specifications
Particularly for hiding sets of SR-IOV devices, specifying them all
individually is rather cumbersome. Therefore, allow function and slot
numbers to be replaced by a wildcard character ('*').
Unfortunately this gets complicated by the in-kernel sscanf()
implementation not being really standard conformant - matching of
plain text tails cannot be checked by the caller (a patch to overcome
this will be sent shortly, and a follow-up patch for simplifying the
code is planned to be sent when that fixed went upstream).
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/xen/xen-pciback/pci_stub.c')
-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 | ||