Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * PCI Backend - Handle special overlays for broken devices.
0004  *
0005  * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
0006  * Author: Chris Bookholt <hap10@epoch.ncsc.mil>
0007  */
0008 
0009 #define dev_fmt(fmt) DRV_NAME ": " fmt
0010 
0011 #include <linux/kernel.h>
0012 #include <linux/pci.h>
0013 #include "pciback.h"
0014 #include "conf_space.h"
0015 #include "conf_space_quirks.h"
0016 
0017 LIST_HEAD(xen_pcibk_quirks);
0018 static inline const struct pci_device_id *
0019 match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
0020 {
0021     if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) &&
0022         (id->device == PCI_ANY_ID || id->device == dev->device) &&
0023         (id->subvendor == PCI_ANY_ID ||
0024                 id->subvendor == dev->subsystem_vendor) &&
0025         (id->subdevice == PCI_ANY_ID ||
0026                 id->subdevice == dev->subsystem_device) &&
0027         !((id->class ^ dev->class) & id->class_mask))
0028         return id;
0029     return NULL;
0030 }
0031 
0032 static struct xen_pcibk_config_quirk *xen_pcibk_find_quirk(struct pci_dev *dev)
0033 {
0034     struct xen_pcibk_config_quirk *tmp_quirk;
0035 
0036     list_for_each_entry(tmp_quirk, &xen_pcibk_quirks, quirks_list)
0037         if (match_one_device(&tmp_quirk->devid, dev) != NULL)
0038             goto out;
0039     tmp_quirk = NULL;
0040     dev_printk(KERN_DEBUG, &dev->dev,
0041            "quirk didn't match any device known\n");
0042 out:
0043     return tmp_quirk;
0044 }
0045 
0046 static inline void register_quirk(struct xen_pcibk_config_quirk *quirk)
0047 {
0048     list_add_tail(&quirk->quirks_list, &xen_pcibk_quirks);
0049 }
0050 
0051 int xen_pcibk_field_is_dup(struct pci_dev *dev, unsigned int reg)
0052 {
0053     int ret = 0;
0054     struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev);
0055     struct config_field_entry *cfg_entry;
0056 
0057     list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
0058         if (OFFSET(cfg_entry) == reg) {
0059             ret = 1;
0060             break;
0061         }
0062     }
0063     return ret;
0064 }
0065 
0066 int xen_pcibk_config_quirks_add_field(struct pci_dev *dev, struct config_field
0067                     *field)
0068 {
0069     int err = 0;
0070 
0071     switch (field->size) {
0072     case 1:
0073         field->u.b.read = xen_pcibk_read_config_byte;
0074         field->u.b.write = xen_pcibk_write_config_byte;
0075         break;
0076     case 2:
0077         field->u.w.read = xen_pcibk_read_config_word;
0078         field->u.w.write = xen_pcibk_write_config_word;
0079         break;
0080     case 4:
0081         field->u.dw.read = xen_pcibk_read_config_dword;
0082         field->u.dw.write = xen_pcibk_write_config_dword;
0083         break;
0084     default:
0085         err = -EINVAL;
0086         goto out;
0087     }
0088 
0089     xen_pcibk_config_add_field(dev, field);
0090 
0091 out:
0092     return err;
0093 }
0094 
0095 int xen_pcibk_config_quirks_init(struct pci_dev *dev)
0096 {
0097     struct xen_pcibk_config_quirk *quirk;
0098     int ret = 0;
0099 
0100     quirk = kzalloc(sizeof(*quirk), GFP_KERNEL);
0101     if (!quirk) {
0102         ret = -ENOMEM;
0103         goto out;
0104     }
0105 
0106     quirk->devid.vendor = dev->vendor;
0107     quirk->devid.device = dev->device;
0108     quirk->devid.subvendor = dev->subsystem_vendor;
0109     quirk->devid.subdevice = dev->subsystem_device;
0110     quirk->devid.class = 0;
0111     quirk->devid.class_mask = 0;
0112     quirk->devid.driver_data = 0UL;
0113 
0114     quirk->pdev = dev;
0115 
0116     register_quirk(quirk);
0117 out:
0118     return ret;
0119 }
0120 
0121 void xen_pcibk_config_field_free(struct config_field *field)
0122 {
0123     kfree(field);
0124 }
0125 
0126 int xen_pcibk_config_quirk_release(struct pci_dev *dev)
0127 {
0128     struct xen_pcibk_config_quirk *quirk;
0129     int ret = 0;
0130 
0131     quirk = xen_pcibk_find_quirk(dev);
0132     if (!quirk) {
0133         ret = -ENXIO;
0134         goto out;
0135     }
0136 
0137     list_del(&quirk->quirks_list);
0138     kfree(quirk);
0139 
0140 out:
0141     return ret;
0142 }