diff options
Diffstat (limited to 'drivers/xen/xen-pciback')
-rw-r--r-- | drivers/xen/xen-pciback/pci_stub.c | 136 |
1 files changed, 106 insertions, 30 deletions
diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c index 92ff01dbeb10..961d664e2d2f 100644 --- a/drivers/xen/xen-pciback/pci_stub.c +++ b/drivers/xen/xen-pciback/pci_stub.c | |||
@@ -362,6 +362,7 @@ static int __devinit pcistub_init_device(struct pci_dev *dev) | |||
362 | else { | 362 | else { |
363 | dev_dbg(&dev->dev, "reseting (FLR, D3, etc) the device\n"); | 363 | dev_dbg(&dev->dev, "reseting (FLR, D3, etc) the device\n"); |
364 | __pci_reset_function_locked(dev); | 364 | __pci_reset_function_locked(dev); |
365 | pci_restore_state(dev); | ||
365 | } | 366 | } |
366 | /* Now disable the device (this also ensures some private device | 367 | /* Now disable the device (this also ensures some private device |
367 | * data is setup before we export) | 368 | * data is setup before we export) |
@@ -681,14 +682,14 @@ static pci_ers_result_t xen_pcibk_slot_reset(struct pci_dev *dev) | |||
681 | dev_err(&dev->dev, DRV_NAME " device is not connected or owned" | 682 | dev_err(&dev->dev, DRV_NAME " device is not connected or owned" |
682 | " by HVM, kill it\n"); | 683 | " by HVM, kill it\n"); |
683 | kill_domain_by_device(psdev); | 684 | kill_domain_by_device(psdev); |
684 | goto release; | 685 | goto end; |
685 | } | 686 | } |
686 | 687 | ||
687 | if (!test_bit(_XEN_PCIB_AERHANDLER, | 688 | if (!test_bit(_XEN_PCIB_AERHANDLER, |
688 | (unsigned long *)&psdev->pdev->sh_info->flags)) { | 689 | (unsigned long *)&psdev->pdev->sh_info->flags)) { |
689 | dev_err(&dev->dev, | 690 | dev_err(&dev->dev, |
690 | "guest with no AER driver should have been killed\n"); | 691 | "guest with no AER driver should have been killed\n"); |
691 | goto release; | 692 | goto end; |
692 | } | 693 | } |
693 | result = common_process(psdev, 1, XEN_PCI_OP_aer_slotreset, result); | 694 | result = common_process(psdev, 1, XEN_PCI_OP_aer_slotreset, result); |
694 | 695 | ||
@@ -698,9 +699,9 @@ static pci_ers_result_t xen_pcibk_slot_reset(struct pci_dev *dev) | |||
698 | "No AER slot_reset service or disconnected!\n"); | 699 | "No AER slot_reset service or disconnected!\n"); |
699 | kill_domain_by_device(psdev); | 700 | kill_domain_by_device(psdev); |
700 | } | 701 | } |
701 | release: | ||
702 | pcistub_device_put(psdev); | ||
703 | end: | 702 | end: |
703 | if (psdev) | ||
704 | pcistub_device_put(psdev); | ||
704 | up_write(&pcistub_sem); | 705 | up_write(&pcistub_sem); |
705 | return result; | 706 | return result; |
706 | 707 | ||
@@ -739,14 +740,14 @@ static pci_ers_result_t xen_pcibk_mmio_enabled(struct pci_dev *dev) | |||
739 | dev_err(&dev->dev, DRV_NAME " device is not connected or owned" | 740 | dev_err(&dev->dev, DRV_NAME " device is not connected or owned" |
740 | " by HVM, kill it\n"); | 741 | " by HVM, kill it\n"); |
741 | kill_domain_by_device(psdev); | 742 | kill_domain_by_device(psdev); |
742 | goto release; | 743 | goto end; |
743 | } | 744 | } |
744 | 745 | ||
745 | if (!test_bit(_XEN_PCIB_AERHANDLER, | 746 | if (!test_bit(_XEN_PCIB_AERHANDLER, |
746 | (unsigned long *)&psdev->pdev->sh_info->flags)) { | 747 | (unsigned long *)&psdev->pdev->sh_info->flags)) { |
747 | dev_err(&dev->dev, | 748 | dev_err(&dev->dev, |
748 | "guest with no AER driver should have been killed\n"); | 749 | "guest with no AER driver should have been killed\n"); |
749 | goto release; | 750 | goto end; |
750 | } | 751 | } |
751 | result = common_process(psdev, 1, XEN_PCI_OP_aer_mmio, result); | 752 | result = common_process(psdev, 1, XEN_PCI_OP_aer_mmio, result); |
752 | 753 | ||
@@ -756,9 +757,9 @@ static pci_ers_result_t xen_pcibk_mmio_enabled(struct pci_dev *dev) | |||
756 | "No AER mmio_enabled service or disconnected!\n"); | 757 | "No AER mmio_enabled service or disconnected!\n"); |
757 | kill_domain_by_device(psdev); | 758 | kill_domain_by_device(psdev); |
758 | } | 759 | } |
759 | release: | ||
760 | pcistub_device_put(psdev); | ||
761 | end: | 760 | end: |
761 | if (psdev) | ||
762 | pcistub_device_put(psdev); | ||
762 | up_write(&pcistub_sem); | 763 | up_write(&pcistub_sem); |
763 | return result; | 764 | return result; |
764 | } | 765 | } |
@@ -797,7 +798,7 @@ static pci_ers_result_t xen_pcibk_error_detected(struct pci_dev *dev, | |||
797 | dev_err(&dev->dev, DRV_NAME " device is not connected or owned" | 798 | dev_err(&dev->dev, DRV_NAME " device is not connected or owned" |
798 | " by HVM, kill it\n"); | 799 | " by HVM, kill it\n"); |
799 | kill_domain_by_device(psdev); | 800 | kill_domain_by_device(psdev); |
800 | goto release; | 801 | goto end; |
801 | } | 802 | } |
802 | 803 | ||
803 | /*Guest owns the device yet no aer handler regiested, kill guest*/ | 804 | /*Guest owns the device yet no aer handler regiested, kill guest*/ |
@@ -805,7 +806,7 @@ static pci_ers_result_t xen_pcibk_error_detected(struct pci_dev *dev, | |||
805 | (unsigned long *)&psdev->pdev->sh_info->flags)) { | 806 | (unsigned long *)&psdev->pdev->sh_info->flags)) { |
806 | dev_dbg(&dev->dev, "guest may have no aer driver, kill it\n"); | 807 | dev_dbg(&dev->dev, "guest may have no aer driver, kill it\n"); |
807 | kill_domain_by_device(psdev); | 808 | kill_domain_by_device(psdev); |
808 | goto release; | 809 | goto end; |
809 | } | 810 | } |
810 | result = common_process(psdev, error, XEN_PCI_OP_aer_detected, result); | 811 | result = common_process(psdev, error, XEN_PCI_OP_aer_detected, result); |
811 | 812 | ||
@@ -815,9 +816,9 @@ static pci_ers_result_t xen_pcibk_error_detected(struct pci_dev *dev, | |||
815 | "No AER error_detected service or disconnected!\n"); | 816 | "No AER error_detected service or disconnected!\n"); |
816 | kill_domain_by_device(psdev); | 817 | kill_domain_by_device(psdev); |
817 | } | 818 | } |
818 | release: | ||
819 | pcistub_device_put(psdev); | ||
820 | end: | 819 | end: |
820 | if (psdev) | ||
821 | pcistub_device_put(psdev); | ||
821 | up_write(&pcistub_sem); | 822 | up_write(&pcistub_sem); |
822 | return result; | 823 | return result; |
823 | } | 824 | } |
@@ -851,7 +852,7 @@ static void xen_pcibk_error_resume(struct pci_dev *dev) | |||
851 | dev_err(&dev->dev, DRV_NAME " device is not connected or owned" | 852 | dev_err(&dev->dev, DRV_NAME " device is not connected or owned" |
852 | " by HVM, kill it\n"); | 853 | " by HVM, kill it\n"); |
853 | kill_domain_by_device(psdev); | 854 | kill_domain_by_device(psdev); |
854 | goto release; | 855 | goto end; |
855 | } | 856 | } |
856 | 857 | ||
857 | if (!test_bit(_XEN_PCIB_AERHANDLER, | 858 | if (!test_bit(_XEN_PCIB_AERHANDLER, |
@@ -859,13 +860,13 @@ static void xen_pcibk_error_resume(struct pci_dev *dev) | |||
859 | dev_err(&dev->dev, | 860 | dev_err(&dev->dev, |
860 | "guest with no AER driver should have been killed\n"); | 861 | "guest with no AER driver should have been killed\n"); |
861 | kill_domain_by_device(psdev); | 862 | kill_domain_by_device(psdev); |
862 | goto release; | 863 | goto end; |
863 | } | 864 | } |
864 | common_process(psdev, 1, XEN_PCI_OP_aer_resume, | 865 | common_process(psdev, 1, XEN_PCI_OP_aer_resume, |
865 | PCI_ERS_RESULT_RECOVERED); | 866 | PCI_ERS_RESULT_RECOVERED); |
866 | release: | ||
867 | pcistub_device_put(psdev); | ||
868 | end: | 867 | end: |
868 | if (psdev) | ||
869 | pcistub_device_put(psdev); | ||
869 | up_write(&pcistub_sem); | 870 | up_write(&pcistub_sem); |
870 | return; | 871 | return; |
871 | } | 872 | } |
@@ -897,17 +898,41 @@ static inline int str_to_slot(const char *buf, int *domain, int *bus, | |||
897 | int *slot, int *func) | 898 | int *slot, int *func) |
898 | { | 899 | { |
899 | int err; | 900 | int err; |
901 | char wc = '*'; | ||
900 | 902 | ||
901 | err = sscanf(buf, " %x:%x:%x.%x", domain, bus, slot, func); | 903 | err = sscanf(buf, " %x:%x:%x.%x", domain, bus, slot, func); |
902 | if (err == 4) | 904 | switch (err) { |
905 | case 3: | ||
906 | *func = -1; | ||
907 | err = sscanf(buf, " %x:%x:%x.%c", domain, bus, slot, &wc); | ||
908 | break; | ||
909 | case 2: | ||
910 | *slot = *func = -1; | ||
911 | err = sscanf(buf, " %x:%x:*.%c", domain, bus, &wc); | ||
912 | if (err >= 2) | ||
913 | ++err; | ||
914 | break; | ||
915 | } | ||
916 | if (err == 4 && wc == '*') | ||
903 | return 0; | 917 | return 0; |
904 | else if (err < 0) | 918 | else if (err < 0) |
905 | return -EINVAL; | 919 | return -EINVAL; |
906 | 920 | ||
907 | /* try again without domain */ | 921 | /* try again without domain */ |
908 | *domain = 0; | 922 | *domain = 0; |
923 | wc = '*'; | ||
909 | err = sscanf(buf, " %x:%x.%x", bus, slot, func); | 924 | err = sscanf(buf, " %x:%x.%x", bus, slot, func); |
910 | if (err == 3) | 925 | switch (err) { |
926 | case 2: | ||
927 | *func = -1; | ||
928 | err = sscanf(buf, " %x:%x.%c", bus, slot, &wc); | ||
929 | break; | ||
930 | case 1: | ||
931 | *slot = *func = -1; | ||
932 | err = sscanf(buf, " %x:*.%c", bus, &wc) + 1; | ||
933 | break; | ||
934 | } | ||
935 | if (err == 3 && wc == '*') | ||
911 | return 0; | 936 | return 0; |
912 | 937 | ||
913 | return -EINVAL; | 938 | return -EINVAL; |
@@ -930,6 +955,19 @@ static int pcistub_device_id_add(int domain, int bus, int slot, int func) | |||
930 | { | 955 | { |
931 | struct pcistub_device_id *pci_dev_id; | 956 | struct pcistub_device_id *pci_dev_id; |
932 | unsigned long flags; | 957 | unsigned long flags; |
958 | int rc = 0; | ||
959 | |||
960 | if (slot < 0) { | ||
961 | for (slot = 0; !rc && slot < 32; ++slot) | ||
962 | rc = pcistub_device_id_add(domain, bus, slot, func); | ||
963 | return rc; | ||
964 | } | ||
965 | |||
966 | if (func < 0) { | ||
967 | for (func = 0; !rc && func < 8; ++func) | ||
968 | rc = pcistub_device_id_add(domain, bus, slot, func); | ||
969 | return rc; | ||
970 | } | ||
933 | 971 | ||
934 | pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL); | 972 | pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL); |
935 | if (!pci_dev_id) | 973 | if (!pci_dev_id) |
@@ -952,15 +990,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) | 990 | static int pcistub_device_id_remove(int domain, int bus, int slot, int func) |
953 | { | 991 | { |
954 | struct pcistub_device_id *pci_dev_id, *t; | 992 | struct pcistub_device_id *pci_dev_id, *t; |
955 | int devfn = PCI_DEVFN(slot, func); | ||
956 | int err = -ENOENT; | 993 | int err = -ENOENT; |
957 | unsigned long flags; | 994 | unsigned long flags; |
958 | 995 | ||
959 | spin_lock_irqsave(&device_ids_lock, flags); | 996 | spin_lock_irqsave(&device_ids_lock, flags); |
960 | list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids, | 997 | list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids, |
961 | slot_list) { | 998 | slot_list) { |
962 | if (pci_dev_id->domain == domain | 999 | if (pci_dev_id->domain == domain && pci_dev_id->bus == bus |
963 | && pci_dev_id->bus == bus && pci_dev_id->devfn == devfn) { | 1000 | && (slot < 0 || PCI_SLOT(pci_dev_id->devfn) == slot) |
1001 | && (func < 0 || PCI_FUNC(pci_dev_id->devfn) == func)) { | ||
964 | /* Don't break; here because it's possible the same | 1002 | /* Don't break; here because it's possible the same |
965 | * slot could be in the list more than once | 1003 | * slot could be in the list more than once |
966 | */ | 1004 | */ |
@@ -987,7 +1025,7 @@ static int pcistub_reg_add(int domain, int bus, int slot, int func, int reg, | |||
987 | struct config_field *field; | 1025 | struct config_field *field; |
988 | 1026 | ||
989 | psdev = pcistub_device_find(domain, bus, slot, func); | 1027 | psdev = pcistub_device_find(domain, bus, slot, func); |
990 | if (!psdev || !psdev->dev) { | 1028 | if (!psdev) { |
991 | err = -ENODEV; | 1029 | err = -ENODEV; |
992 | goto out; | 1030 | goto out; |
993 | } | 1031 | } |
@@ -1011,6 +1049,8 @@ static int pcistub_reg_add(int domain, int bus, int slot, int func, int reg, | |||
1011 | if (err) | 1049 | if (err) |
1012 | kfree(field); | 1050 | kfree(field); |
1013 | out: | 1051 | out: |
1052 | if (psdev) | ||
1053 | pcistub_device_put(psdev); | ||
1014 | return err; | 1054 | return err; |
1015 | } | 1055 | } |
1016 | 1056 | ||
@@ -1115,10 +1155,9 @@ static ssize_t pcistub_irq_handler_switch(struct device_driver *drv, | |||
1115 | 1155 | ||
1116 | err = str_to_slot(buf, &domain, &bus, &slot, &func); | 1156 | err = str_to_slot(buf, &domain, &bus, &slot, &func); |
1117 | if (err) | 1157 | if (err) |
1118 | goto out; | 1158 | return err; |
1119 | 1159 | ||
1120 | psdev = pcistub_device_find(domain, bus, slot, func); | 1160 | psdev = pcistub_device_find(domain, bus, slot, func); |
1121 | |||
1122 | if (!psdev) | 1161 | if (!psdev) |
1123 | goto out; | 1162 | goto out; |
1124 | 1163 | ||
@@ -1134,6 +1173,8 @@ static ssize_t pcistub_irq_handler_switch(struct device_driver *drv, | |||
1134 | if (dev_data->isr_on) | 1173 | if (dev_data->isr_on) |
1135 | dev_data->ack_intr = 1; | 1174 | dev_data->ack_intr = 1; |
1136 | out: | 1175 | out: |
1176 | if (psdev) | ||
1177 | pcistub_device_put(psdev); | ||
1137 | if (!err) | 1178 | if (!err) |
1138 | err = count; | 1179 | err = count; |
1139 | return err; | 1180 | return err; |
@@ -1216,15 +1257,16 @@ static ssize_t permissive_add(struct device_driver *drv, const char *buf, | |||
1216 | err = str_to_slot(buf, &domain, &bus, &slot, &func); | 1257 | err = str_to_slot(buf, &domain, &bus, &slot, &func); |
1217 | if (err) | 1258 | if (err) |
1218 | goto out; | 1259 | goto out; |
1260 | if (slot < 0 || func < 0) { | ||
1261 | err = -EINVAL; | ||
1262 | goto out; | ||
1263 | } | ||
1219 | psdev = pcistub_device_find(domain, bus, slot, func); | 1264 | psdev = pcistub_device_find(domain, bus, slot, func); |
1220 | if (!psdev) { | 1265 | if (!psdev) { |
1221 | err = -ENODEV; | 1266 | err = -ENODEV; |
1222 | goto out; | 1267 | goto out; |
1223 | } | 1268 | } |
1224 | if (!psdev->dev) { | 1269 | |
1225 | err = -ENODEV; | ||
1226 | goto release; | ||
1227 | } | ||
1228 | dev_data = pci_get_drvdata(psdev->dev); | 1270 | dev_data = pci_get_drvdata(psdev->dev); |
1229 | /* the driver data for a device should never be null at this point */ | 1271 | /* the driver data for a device should never be null at this point */ |
1230 | if (!dev_data) { | 1272 | if (!dev_data) { |
@@ -1297,17 +1339,51 @@ static int __init pcistub_init(void) | |||
1297 | 1339 | ||
1298 | if (pci_devs_to_hide && *pci_devs_to_hide) { | 1340 | if (pci_devs_to_hide && *pci_devs_to_hide) { |
1299 | do { | 1341 | do { |
1342 | char wc = '*'; | ||
1343 | |||
1300 | parsed = 0; | 1344 | parsed = 0; |
1301 | 1345 | ||
1302 | err = sscanf(pci_devs_to_hide + pos, | 1346 | err = sscanf(pci_devs_to_hide + pos, |
1303 | " (%x:%x:%x.%x) %n", | 1347 | " (%x:%x:%x.%x) %n", |
1304 | &domain, &bus, &slot, &func, &parsed); | 1348 | &domain, &bus, &slot, &func, &parsed); |
1305 | if (err != 4) { | 1349 | switch (err) { |
1350 | case 3: | ||
1351 | func = -1; | ||
1352 | err = sscanf(pci_devs_to_hide + pos, | ||
1353 | " (%x:%x:%x.%c) %n", | ||
1354 | &domain, &bus, &slot, &wc, | ||
1355 | &parsed); | ||
1356 | break; | ||
1357 | case 2: | ||
1358 | slot = func = -1; | ||
1359 | err = sscanf(pci_devs_to_hide + pos, | ||
1360 | " (%x:%x:*.%c) %n", | ||
1361 | &domain, &bus, &wc, &parsed) + 1; | ||
1362 | break; | ||
1363 | } | ||
1364 | |||
1365 | if (err != 4 || wc != '*') { | ||
1306 | domain = 0; | 1366 | domain = 0; |
1367 | wc = '*'; | ||
1307 | err = sscanf(pci_devs_to_hide + pos, | 1368 | err = sscanf(pci_devs_to_hide + pos, |
1308 | " (%x:%x.%x) %n", | 1369 | " (%x:%x.%x) %n", |
1309 | &bus, &slot, &func, &parsed); | 1370 | &bus, &slot, &func, &parsed); |
1310 | if (err != 3) | 1371 | switch (err) { |
1372 | case 2: | ||
1373 | func = -1; | ||
1374 | err = sscanf(pci_devs_to_hide + pos, | ||
1375 | " (%x:%x.%c) %n", | ||
1376 | &bus, &slot, &wc, | ||
1377 | &parsed); | ||
1378 | break; | ||
1379 | case 1: | ||
1380 | slot = func = -1; | ||
1381 | err = sscanf(pci_devs_to_hide + pos, | ||
1382 | " (%x:*.%c) %n", | ||
1383 | &bus, &wc, &parsed) + 1; | ||
1384 | break; | ||
1385 | } | ||
1386 | if (err != 3 || wc != '*') | ||
1311 | goto parse_error; | 1387 | goto parse_error; |
1312 | } | 1388 | } |
1313 | 1389 | ||