1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * PCI Backend - Handle special overlays for broken devices. 4 * 5 * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 6 * Author: Chris Bookholt <hap10@epoch.ncsc.mil> 7 */ 8 9 #include <linux/kernel.h> 10 #include <linux/pci.h> 11 #include "pciback.h" 12 #include "conf_space.h" 13 #include "conf_space_quirks.h" 14 15 LIST_HEAD(xen_pcibk_quirks); 16 static inline const struct pci_device_id * 17 match_one_device(const struct pci_device_id *id, const struct pci_dev *dev) 18 { 19 if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) && 20 (id->device == PCI_ANY_ID || id->device == dev->device) && 21 (id->subvendor == PCI_ANY_ID || 22 id->subvendor == dev->subsystem_vendor) && 23 (id->subdevice == PCI_ANY_ID || 24 id->subdevice == dev->subsystem_device) && 25 !((id->class ^ dev->class) & id->class_mask)) 26 return id; 27 return NULL; 28 } 29 30 static struct xen_pcibk_config_quirk *xen_pcibk_find_quirk(struct pci_dev *dev) 31 { 32 struct xen_pcibk_config_quirk *tmp_quirk; 33 34 list_for_each_entry(tmp_quirk, &xen_pcibk_quirks, quirks_list) 35 if (match_one_device(&tmp_quirk->devid, dev) != NULL) 36 goto out; 37 tmp_quirk = NULL; 38 printk(KERN_DEBUG DRV_NAME 39 ": quirk didn't match any device known\n"); 40 out: 41 return tmp_quirk; 42 } 43 44 static inline void register_quirk(struct xen_pcibk_config_quirk *quirk) 45 { 46 list_add_tail(&quirk->quirks_list, &xen_pcibk_quirks); 47 } 48 49 int xen_pcibk_field_is_dup(struct pci_dev *dev, unsigned int reg) 50 { 51 int ret = 0; 52 struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev); 53 struct config_field_entry *cfg_entry; 54 55 list_for_each_entry(cfg_entry, &dev_data->config_fields, list) { 56 if (OFFSET(cfg_entry) == reg) { 57 ret = 1; 58 break; 59 } 60 } 61 return ret; 62 } 63 64 int xen_pcibk_config_quirks_add_field(struct pci_dev *dev, struct config_field 65 *field) 66 { 67 int err = 0; 68 69 switch (field->size) { 70 case 1: 71 field->u.b.read = xen_pcibk_read_config_byte; 72 field->u.b.write = xen_pcibk_write_config_byte; 73 break; 74 case 2: 75 field->u.w.read = xen_pcibk_read_config_word; 76 field->u.w.write = xen_pcibk_write_config_word; 77 break; 78 case 4: 79 field->u.dw.read = xen_pcibk_read_config_dword; 80 field->u.dw.write = xen_pcibk_write_config_dword; 81 break; 82 default: 83 err = -EINVAL; 84 goto out; 85 } 86 87 xen_pcibk_config_add_field(dev, field); 88 89 out: 90 return err; 91 } 92 93 int xen_pcibk_config_quirks_init(struct pci_dev *dev) 94 { 95 struct xen_pcibk_config_quirk *quirk; 96 int ret = 0; 97 98 quirk = kzalloc(sizeof(*quirk), GFP_ATOMIC); 99 if (!quirk) { 100 ret = -ENOMEM; 101 goto out; 102 } 103 104 quirk->devid.vendor = dev->vendor; 105 quirk->devid.device = dev->device; 106 quirk->devid.subvendor = dev->subsystem_vendor; 107 quirk->devid.subdevice = dev->subsystem_device; 108 quirk->devid.class = 0; 109 quirk->devid.class_mask = 0; 110 quirk->devid.driver_data = 0UL; 111 112 quirk->pdev = dev; 113 114 register_quirk(quirk); 115 out: 116 return ret; 117 } 118 119 void xen_pcibk_config_field_free(struct config_field *field) 120 { 121 kfree(field); 122 } 123 124 int xen_pcibk_config_quirk_release(struct pci_dev *dev) 125 { 126 struct xen_pcibk_config_quirk *quirk; 127 int ret = 0; 128 129 quirk = xen_pcibk_find_quirk(dev); 130 if (!quirk) { 131 ret = -ENXIO; 132 goto out; 133 } 134 135 list_del(&quirk->quirks_list); 136 kfree(quirk); 137 138 out: 139 return ret; 140 } 141