130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk/* 230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk * PCI Backend - Handle special overlays for broken devices. 330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk * 430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk * Author: Chris Bookholt <hap10@epoch.ncsc.mil> 630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk */ 730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk#include <linux/kernel.h> 930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk#include <linux/pci.h> 1030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk#include "pciback.h" 1130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk#include "conf_space.h" 1230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk#include "conf_space_quirks.h" 1330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 14a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek WilkLIST_HEAD(xen_pcibk_quirks); 1530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkstatic inline const struct pci_device_id * 1630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkmatch_one_device(const struct pci_device_id *id, const struct pci_dev *dev) 1730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{ 1830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) && 1930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk (id->device == PCI_ANY_ID || id->device == dev->device) && 2030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk (id->subvendor == PCI_ANY_ID || 2130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk id->subvendor == dev->subsystem_vendor) && 2230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk (id->subdevice == PCI_ANY_ID || 2330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk id->subdevice == dev->subsystem_device) && 2430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk !((id->class ^ dev->class) & id->class_mask)) 2530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk return id; 2630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk return NULL; 2730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk} 2830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 29a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic struct xen_pcibk_config_quirk *xen_pcibk_find_quirk(struct pci_dev *dev) 3030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{ 31a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk struct xen_pcibk_config_quirk *tmp_quirk; 3230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 33a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk list_for_each_entry(tmp_quirk, &xen_pcibk_quirks, quirks_list) 3430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk if (match_one_device(&tmp_quirk->devid, dev) != NULL) 3530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk goto out; 3630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk tmp_quirk = NULL; 37a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk printk(KERN_DEBUG DRV_NAME 38402c5e15b44070461dcc2f41536c16d0cfbca9c3Jan Beulich ": quirk didn't match any device known\n"); 3930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout: 4030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk return tmp_quirk; 4130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk} 4230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 43a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkstatic inline void register_quirk(struct xen_pcibk_config_quirk *quirk) 4430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{ 45a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk list_add_tail(&quirk->quirks_list, &xen_pcibk_quirks); 4630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk} 4730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 48a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkint xen_pcibk_field_is_dup(struct pci_dev *dev, unsigned int reg) 4930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{ 5030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk int ret = 0; 51a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev); 5230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk struct config_field_entry *cfg_entry; 5330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 5430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk list_for_each_entry(cfg_entry, &dev_data->config_fields, list) { 5530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk if (OFFSET(cfg_entry) == reg) { 5630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk ret = 1; 5730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk break; 5830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk } 5930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk } 6030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk return ret; 6130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk} 6230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 63a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkint xen_pcibk_config_quirks_add_field(struct pci_dev *dev, struct config_field 6430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk *field) 6530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{ 6630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk int err = 0; 6730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 6830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk switch (field->size) { 6930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk case 1: 70a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk field->u.b.read = xen_pcibk_read_config_byte; 71a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk field->u.b.write = xen_pcibk_write_config_byte; 7230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk break; 7330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk case 2: 74a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk field->u.w.read = xen_pcibk_read_config_word; 75a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk field->u.w.write = xen_pcibk_write_config_word; 7630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk break; 7730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk case 4: 78a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk field->u.dw.read = xen_pcibk_read_config_dword; 79a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk field->u.dw.write = xen_pcibk_write_config_dword; 8030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk break; 8130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk default: 8230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk err = -EINVAL; 8330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk goto out; 8430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk } 8530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 86a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk xen_pcibk_config_add_field(dev, field); 8730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 8830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout: 8930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk return err; 9030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk} 9130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 92a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkint xen_pcibk_config_quirks_init(struct pci_dev *dev) 9330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{ 94a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk struct xen_pcibk_config_quirk *quirk; 9530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk int ret = 0; 9630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 9730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk quirk = kzalloc(sizeof(*quirk), GFP_ATOMIC); 9830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk if (!quirk) { 9930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk ret = -ENOMEM; 10030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk goto out; 10130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk } 10230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 10330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk quirk->devid.vendor = dev->vendor; 10430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk quirk->devid.device = dev->device; 10530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk quirk->devid.subvendor = dev->subsystem_vendor; 10630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk quirk->devid.subdevice = dev->subsystem_device; 10730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk quirk->devid.class = 0; 10830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk quirk->devid.class_mask = 0; 10930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk quirk->devid.driver_data = 0UL; 11030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 11130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk quirk->pdev = dev; 11230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 11330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk register_quirk(quirk); 11430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout: 11530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk return ret; 11630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk} 11730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 118a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkvoid xen_pcibk_config_field_free(struct config_field *field) 11930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{ 12030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk kfree(field); 12130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk} 12230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 123a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilkint xen_pcibk_config_quirk_release(struct pci_dev *dev) 12430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk{ 125a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk struct xen_pcibk_config_quirk *quirk; 12630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk int ret = 0; 12730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 128a92336a1176b2119eaa990a1e8bf3109665fdbc6Konrad Rzeszutek Wilk quirk = xen_pcibk_find_quirk(dev); 12930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk if (!quirk) { 13030edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk ret = -ENXIO; 13130edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk goto out; 13230edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk } 13330edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 13430edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk list_del(&quirk->quirks_list); 13530edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk kfree(quirk); 13630edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk 13730edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilkout: 13830edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk return ret; 13930edc14bf39afde24ef7db2de66c91805db80828Konrad Rzeszutek Wilk} 140