File Index
Files and directories
Sign in
FILE

conf_space_quirks.c

File preview with syntax highlighting.

linux-6.19.14/drivers/xen/xen-pciback/conf_space_quirks.c C
  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
 17LIST_HEAD(xen_pcibk_quirks);
 18static inline const struct pci_device_id *
 19match_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
 32static 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");
 42out:
 43	return tmp_quirk;
 44}
 45
 46static inline void register_quirk(struct xen_pcibk_config_quirk *quirk)
 47{
 48	list_add_tail(&quirk->quirks_list, &xen_pcibk_quirks);
 49}
 50
 51int 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
 66int 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
 91out:
 92	return err;
 93}
 94
 95int 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);
117out:
118	return ret;
119}
120
121void xen_pcibk_config_field_free(struct config_field *field)
122{
123	kfree(field);
124}
125
126int 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
140out:
141	return ret;
142}
~/ Read-only file preview.