brintos

brintos / linux-shallow public Read only

0
0
Text · 3.1 KiB · 7dc2810 Raw
143 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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 ": " fmt10 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_field67				    *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}143