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