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