130edc14bSKonrad Rzeszutek Wilk /* 230edc14bSKonrad Rzeszutek Wilk * PCI Backend - Handles the virtual fields in the configuration space headers. 330edc14bSKonrad Rzeszutek Wilk * 430edc14bSKonrad Rzeszutek Wilk * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 530edc14bSKonrad Rzeszutek Wilk */ 630edc14bSKonrad Rzeszutek Wilk 7283c0972SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 8283c0972SJoe Perches 930edc14bSKonrad Rzeszutek Wilk #include <linux/kernel.h> 1030edc14bSKonrad Rzeszutek Wilk #include <linux/pci.h> 1130edc14bSKonrad Rzeszutek Wilk #include "pciback.h" 1230edc14bSKonrad Rzeszutek Wilk #include "conf_space.h" 1330edc14bSKonrad Rzeszutek Wilk 14*af6fc858SJan Beulich struct pci_cmd_info { 15*af6fc858SJan Beulich u16 val; 16*af6fc858SJan Beulich }; 17*af6fc858SJan Beulich 1830edc14bSKonrad Rzeszutek Wilk struct pci_bar_info { 1930edc14bSKonrad Rzeszutek Wilk u32 val; 2030edc14bSKonrad Rzeszutek Wilk u32 len_val; 2130edc14bSKonrad Rzeszutek Wilk int which; 2230edc14bSKonrad Rzeszutek Wilk }; 2330edc14bSKonrad Rzeszutek Wilk 2430edc14bSKonrad Rzeszutek Wilk #define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO)) 2530edc14bSKonrad Rzeszutek Wilk #define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER) 2630edc14bSKonrad Rzeszutek Wilk 27*af6fc858SJan Beulich /* Bits guests are allowed to control in permissive mode. */ 28*af6fc858SJan Beulich #define PCI_COMMAND_GUEST (PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL| \ 29*af6fc858SJan Beulich PCI_COMMAND_INVALIDATE|PCI_COMMAND_VGA_PALETTE| \ 30*af6fc858SJan Beulich PCI_COMMAND_WAIT|PCI_COMMAND_FAST_BACK) 31*af6fc858SJan Beulich 32*af6fc858SJan Beulich static void *command_init(struct pci_dev *dev, int offset) 33*af6fc858SJan Beulich { 34*af6fc858SJan Beulich struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); 35*af6fc858SJan Beulich int err; 36*af6fc858SJan Beulich 37*af6fc858SJan Beulich if (!cmd) 38*af6fc858SJan Beulich return ERR_PTR(-ENOMEM); 39*af6fc858SJan Beulich 40*af6fc858SJan Beulich err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val); 41*af6fc858SJan Beulich if (err) { 42*af6fc858SJan Beulich kfree(cmd); 43*af6fc858SJan Beulich return ERR_PTR(err); 44*af6fc858SJan Beulich } 45*af6fc858SJan Beulich 46*af6fc858SJan Beulich return cmd; 47*af6fc858SJan Beulich } 48*af6fc858SJan Beulich 49fd5b221bSZhao, Yu static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data) 50fd5b221bSZhao, Yu { 51*af6fc858SJan Beulich int ret = pci_read_config_word(dev, offset, value); 52*af6fc858SJan Beulich const struct pci_cmd_info *cmd = data; 53fd5b221bSZhao, Yu 54*af6fc858SJan Beulich *value &= PCI_COMMAND_GUEST; 55*af6fc858SJan Beulich *value |= cmd->val & ~PCI_COMMAND_GUEST; 56fd5b221bSZhao, Yu 57fd5b221bSZhao, Yu return ret; 58fd5b221bSZhao, Yu } 59fd5b221bSZhao, Yu 6030edc14bSKonrad Rzeszutek Wilk static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) 6130edc14bSKonrad Rzeszutek Wilk { 62a92336a1SKonrad Rzeszutek Wilk struct xen_pcibk_dev_data *dev_data; 6330edc14bSKonrad Rzeszutek Wilk int err; 64*af6fc858SJan Beulich u16 val; 65*af6fc858SJan Beulich struct pci_cmd_info *cmd = data; 6630edc14bSKonrad Rzeszutek Wilk 670513fe9eSKonrad Rzeszutek Wilk dev_data = pci_get_drvdata(dev); 6830edc14bSKonrad Rzeszutek Wilk if (!pci_is_enabled(dev) && is_enable_cmd(value)) { 6930edc14bSKonrad Rzeszutek Wilk if (unlikely(verbose_request)) 70a92336a1SKonrad Rzeszutek Wilk printk(KERN_DEBUG DRV_NAME ": %s: enable\n", 7130edc14bSKonrad Rzeszutek Wilk pci_name(dev)); 7230edc14bSKonrad Rzeszutek Wilk err = pci_enable_device(dev); 7330edc14bSKonrad Rzeszutek Wilk if (err) 7430edc14bSKonrad Rzeszutek Wilk return err; 750513fe9eSKonrad Rzeszutek Wilk if (dev_data) 760513fe9eSKonrad Rzeszutek Wilk dev_data->enable_intx = 1; 7730edc14bSKonrad Rzeszutek Wilk } else if (pci_is_enabled(dev) && !is_enable_cmd(value)) { 7830edc14bSKonrad Rzeszutek Wilk if (unlikely(verbose_request)) 79a92336a1SKonrad Rzeszutek Wilk printk(KERN_DEBUG DRV_NAME ": %s: disable\n", 8030edc14bSKonrad Rzeszutek Wilk pci_name(dev)); 8130edc14bSKonrad Rzeszutek Wilk pci_disable_device(dev); 820513fe9eSKonrad Rzeszutek Wilk if (dev_data) 830513fe9eSKonrad Rzeszutek Wilk dev_data->enable_intx = 0; 8430edc14bSKonrad Rzeszutek Wilk } 8530edc14bSKonrad Rzeszutek Wilk 8630edc14bSKonrad Rzeszutek Wilk if (!dev->is_busmaster && is_master_cmd(value)) { 8730edc14bSKonrad Rzeszutek Wilk if (unlikely(verbose_request)) 88a92336a1SKonrad Rzeszutek Wilk printk(KERN_DEBUG DRV_NAME ": %s: set bus master\n", 8930edc14bSKonrad Rzeszutek Wilk pci_name(dev)); 9030edc14bSKonrad Rzeszutek Wilk pci_set_master(dev); 9130edc14bSKonrad Rzeszutek Wilk } 9230edc14bSKonrad Rzeszutek Wilk 9330edc14bSKonrad Rzeszutek Wilk if (value & PCI_COMMAND_INVALIDATE) { 9430edc14bSKonrad Rzeszutek Wilk if (unlikely(verbose_request)) 9530edc14bSKonrad Rzeszutek Wilk printk(KERN_DEBUG 96a92336a1SKonrad Rzeszutek Wilk DRV_NAME ": %s: enable memory-write-invalidate\n", 9730edc14bSKonrad Rzeszutek Wilk pci_name(dev)); 9830edc14bSKonrad Rzeszutek Wilk err = pci_set_mwi(dev); 9930edc14bSKonrad Rzeszutek Wilk if (err) { 100283c0972SJoe Perches pr_warn("%s: cannot enable memory-write-invalidate (%d)\n", 10130edc14bSKonrad Rzeszutek Wilk pci_name(dev), err); 10230edc14bSKonrad Rzeszutek Wilk value &= ~PCI_COMMAND_INVALIDATE; 10330edc14bSKonrad Rzeszutek Wilk } 10430edc14bSKonrad Rzeszutek Wilk } 10530edc14bSKonrad Rzeszutek Wilk 106*af6fc858SJan Beulich cmd->val = value; 107*af6fc858SJan Beulich 108*af6fc858SJan Beulich if (!permissive && (!dev_data || !dev_data->permissive)) 109*af6fc858SJan Beulich return 0; 110*af6fc858SJan Beulich 111*af6fc858SJan Beulich /* Only allow the guest to control certain bits. */ 112*af6fc858SJan Beulich err = pci_read_config_word(dev, offset, &val); 113*af6fc858SJan Beulich if (err || val == value) 114*af6fc858SJan Beulich return err; 115*af6fc858SJan Beulich 116*af6fc858SJan Beulich value &= PCI_COMMAND_GUEST; 117*af6fc858SJan Beulich value |= val & ~PCI_COMMAND_GUEST; 118*af6fc858SJan Beulich 11930edc14bSKonrad Rzeszutek Wilk return pci_write_config_word(dev, offset, value); 12030edc14bSKonrad Rzeszutek Wilk } 12130edc14bSKonrad Rzeszutek Wilk 12230edc14bSKonrad Rzeszutek Wilk static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data) 12330edc14bSKonrad Rzeszutek Wilk { 12430edc14bSKonrad Rzeszutek Wilk struct pci_bar_info *bar = data; 12530edc14bSKonrad Rzeszutek Wilk 12630edc14bSKonrad Rzeszutek Wilk if (unlikely(!bar)) { 127283c0972SJoe Perches pr_warn(DRV_NAME ": driver data not found for %s\n", 12830edc14bSKonrad Rzeszutek Wilk pci_name(dev)); 12930edc14bSKonrad Rzeszutek Wilk return XEN_PCI_ERR_op_failed; 13030edc14bSKonrad Rzeszutek Wilk } 13130edc14bSKonrad Rzeszutek Wilk 13230edc14bSKonrad Rzeszutek Wilk /* A write to obtain the length must happen as a 32-bit write. 13330edc14bSKonrad Rzeszutek Wilk * This does not (yet) support writing individual bytes 13430edc14bSKonrad Rzeszutek Wilk */ 13530edc14bSKonrad Rzeszutek Wilk if (value == ~PCI_ROM_ADDRESS_ENABLE) 13630edc14bSKonrad Rzeszutek Wilk bar->which = 1; 13730edc14bSKonrad Rzeszutek Wilk else { 13830edc14bSKonrad Rzeszutek Wilk u32 tmpval; 13930edc14bSKonrad Rzeszutek Wilk pci_read_config_dword(dev, offset, &tmpval); 14030edc14bSKonrad Rzeszutek Wilk if (tmpval != bar->val && value == bar->val) { 14130edc14bSKonrad Rzeszutek Wilk /* Allow restoration of bar value. */ 14230edc14bSKonrad Rzeszutek Wilk pci_write_config_dword(dev, offset, bar->val); 14330edc14bSKonrad Rzeszutek Wilk } 14430edc14bSKonrad Rzeszutek Wilk bar->which = 0; 14530edc14bSKonrad Rzeszutek Wilk } 14630edc14bSKonrad Rzeszutek Wilk 14730edc14bSKonrad Rzeszutek Wilk /* Do we need to support enabling/disabling the rom address here? */ 14830edc14bSKonrad Rzeszutek Wilk 14930edc14bSKonrad Rzeszutek Wilk return 0; 15030edc14bSKonrad Rzeszutek Wilk } 15130edc14bSKonrad Rzeszutek Wilk 15230edc14bSKonrad Rzeszutek Wilk /* For the BARs, only allow writes which write ~0 or 15330edc14bSKonrad Rzeszutek Wilk * the correct resource information 15430edc14bSKonrad Rzeszutek Wilk * (Needed for when the driver probes the resource usage) 15530edc14bSKonrad Rzeszutek Wilk */ 15630edc14bSKonrad Rzeszutek Wilk static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data) 15730edc14bSKonrad Rzeszutek Wilk { 15830edc14bSKonrad Rzeszutek Wilk struct pci_bar_info *bar = data; 15930edc14bSKonrad Rzeszutek Wilk 16030edc14bSKonrad Rzeszutek Wilk if (unlikely(!bar)) { 161283c0972SJoe Perches pr_warn(DRV_NAME ": driver data not found for %s\n", 16230edc14bSKonrad Rzeszutek Wilk pci_name(dev)); 16330edc14bSKonrad Rzeszutek Wilk return XEN_PCI_ERR_op_failed; 16430edc14bSKonrad Rzeszutek Wilk } 16530edc14bSKonrad Rzeszutek Wilk 16630edc14bSKonrad Rzeszutek Wilk /* A write to obtain the length must happen as a 32-bit write. 16730edc14bSKonrad Rzeszutek Wilk * This does not (yet) support writing individual bytes 16830edc14bSKonrad Rzeszutek Wilk */ 16930edc14bSKonrad Rzeszutek Wilk if (value == ~0) 17030edc14bSKonrad Rzeszutek Wilk bar->which = 1; 17130edc14bSKonrad Rzeszutek Wilk else { 17230edc14bSKonrad Rzeszutek Wilk u32 tmpval; 17330edc14bSKonrad Rzeszutek Wilk pci_read_config_dword(dev, offset, &tmpval); 17430edc14bSKonrad Rzeszutek Wilk if (tmpval != bar->val && value == bar->val) { 17530edc14bSKonrad Rzeszutek Wilk /* Allow restoration of bar value. */ 17630edc14bSKonrad Rzeszutek Wilk pci_write_config_dword(dev, offset, bar->val); 17730edc14bSKonrad Rzeszutek Wilk } 17830edc14bSKonrad Rzeszutek Wilk bar->which = 0; 17930edc14bSKonrad Rzeszutek Wilk } 18030edc14bSKonrad Rzeszutek Wilk 18130edc14bSKonrad Rzeszutek Wilk return 0; 18230edc14bSKonrad Rzeszutek Wilk } 18330edc14bSKonrad Rzeszutek Wilk 18430edc14bSKonrad Rzeszutek Wilk static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data) 18530edc14bSKonrad Rzeszutek Wilk { 18630edc14bSKonrad Rzeszutek Wilk struct pci_bar_info *bar = data; 18730edc14bSKonrad Rzeszutek Wilk 18830edc14bSKonrad Rzeszutek Wilk if (unlikely(!bar)) { 189283c0972SJoe Perches pr_warn(DRV_NAME ": driver data not found for %s\n", 19030edc14bSKonrad Rzeszutek Wilk pci_name(dev)); 19130edc14bSKonrad Rzeszutek Wilk return XEN_PCI_ERR_op_failed; 19230edc14bSKonrad Rzeszutek Wilk } 19330edc14bSKonrad Rzeszutek Wilk 19430edc14bSKonrad Rzeszutek Wilk *value = bar->which ? bar->len_val : bar->val; 19530edc14bSKonrad Rzeszutek Wilk 19630edc14bSKonrad Rzeszutek Wilk return 0; 19730edc14bSKonrad Rzeszutek Wilk } 19830edc14bSKonrad Rzeszutek Wilk 19930edc14bSKonrad Rzeszutek Wilk static inline void read_dev_bar(struct pci_dev *dev, 20030edc14bSKonrad Rzeszutek Wilk struct pci_bar_info *bar_info, int offset, 20130edc14bSKonrad Rzeszutek Wilk u32 len_mask) 20230edc14bSKonrad Rzeszutek Wilk { 203fd5b221bSZhao, Yu int pos; 204fd5b221bSZhao, Yu struct resource *res = dev->resource; 205fd5b221bSZhao, Yu 206fd5b221bSZhao, Yu if (offset == PCI_ROM_ADDRESS || offset == PCI_ROM_ADDRESS1) 207fd5b221bSZhao, Yu pos = PCI_ROM_RESOURCE; 208fd5b221bSZhao, Yu else { 209fd5b221bSZhao, Yu pos = (offset - PCI_BASE_ADDRESS_0) / 4; 210fd5b221bSZhao, Yu if (pos && ((res[pos - 1].flags & (PCI_BASE_ADDRESS_SPACE | 211fd5b221bSZhao, Yu PCI_BASE_ADDRESS_MEM_TYPE_MASK)) == 212fd5b221bSZhao, Yu (PCI_BASE_ADDRESS_SPACE_MEMORY | 213fd5b221bSZhao, Yu PCI_BASE_ADDRESS_MEM_TYPE_64))) { 214fd5b221bSZhao, Yu bar_info->val = res[pos - 1].start >> 32; 215fd5b221bSZhao, Yu bar_info->len_val = res[pos - 1].end >> 32; 216fd5b221bSZhao, Yu return; 217fd5b221bSZhao, Yu } 218fd5b221bSZhao, Yu } 219fd5b221bSZhao, Yu 220fd5b221bSZhao, Yu bar_info->val = res[pos].start | 221fd5b221bSZhao, Yu (res[pos].flags & PCI_REGION_FLAG_MASK); 2225fa99911SThomas Meyer bar_info->len_val = resource_size(&res[pos]); 22330edc14bSKonrad Rzeszutek Wilk } 22430edc14bSKonrad Rzeszutek Wilk 22530edc14bSKonrad Rzeszutek Wilk static void *bar_init(struct pci_dev *dev, int offset) 22630edc14bSKonrad Rzeszutek Wilk { 22730edc14bSKonrad Rzeszutek Wilk struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL); 22830edc14bSKonrad Rzeszutek Wilk 22930edc14bSKonrad Rzeszutek Wilk if (!bar) 23030edc14bSKonrad Rzeszutek Wilk return ERR_PTR(-ENOMEM); 23130edc14bSKonrad Rzeszutek Wilk 23230edc14bSKonrad Rzeszutek Wilk read_dev_bar(dev, bar, offset, ~0); 23330edc14bSKonrad Rzeszutek Wilk bar->which = 0; 23430edc14bSKonrad Rzeszutek Wilk 23530edc14bSKonrad Rzeszutek Wilk return bar; 23630edc14bSKonrad Rzeszutek Wilk } 23730edc14bSKonrad Rzeszutek Wilk 23830edc14bSKonrad Rzeszutek Wilk static void *rom_init(struct pci_dev *dev, int offset) 23930edc14bSKonrad Rzeszutek Wilk { 24030edc14bSKonrad Rzeszutek Wilk struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL); 24130edc14bSKonrad Rzeszutek Wilk 24230edc14bSKonrad Rzeszutek Wilk if (!bar) 24330edc14bSKonrad Rzeszutek Wilk return ERR_PTR(-ENOMEM); 24430edc14bSKonrad Rzeszutek Wilk 24530edc14bSKonrad Rzeszutek Wilk read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE); 24630edc14bSKonrad Rzeszutek Wilk bar->which = 0; 24730edc14bSKonrad Rzeszutek Wilk 24830edc14bSKonrad Rzeszutek Wilk return bar; 24930edc14bSKonrad Rzeszutek Wilk } 25030edc14bSKonrad Rzeszutek Wilk 25130edc14bSKonrad Rzeszutek Wilk static void bar_reset(struct pci_dev *dev, int offset, void *data) 25230edc14bSKonrad Rzeszutek Wilk { 25330edc14bSKonrad Rzeszutek Wilk struct pci_bar_info *bar = data; 25430edc14bSKonrad Rzeszutek Wilk 25530edc14bSKonrad Rzeszutek Wilk bar->which = 0; 25630edc14bSKonrad Rzeszutek Wilk } 25730edc14bSKonrad Rzeszutek Wilk 25830edc14bSKonrad Rzeszutek Wilk static void bar_release(struct pci_dev *dev, int offset, void *data) 25930edc14bSKonrad Rzeszutek Wilk { 26030edc14bSKonrad Rzeszutek Wilk kfree(data); 26130edc14bSKonrad Rzeszutek Wilk } 26230edc14bSKonrad Rzeszutek Wilk 263a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_read_vendor(struct pci_dev *dev, int offset, 264fd5b221bSZhao, Yu u16 *value, void *data) 265fd5b221bSZhao, Yu { 266fd5b221bSZhao, Yu *value = dev->vendor; 267fd5b221bSZhao, Yu 268fd5b221bSZhao, Yu return 0; 269fd5b221bSZhao, Yu } 270fd5b221bSZhao, Yu 271a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_read_device(struct pci_dev *dev, int offset, 272fd5b221bSZhao, Yu u16 *value, void *data) 273fd5b221bSZhao, Yu { 274fd5b221bSZhao, Yu *value = dev->device; 275fd5b221bSZhao, Yu 276fd5b221bSZhao, Yu return 0; 277fd5b221bSZhao, Yu } 278fd5b221bSZhao, Yu 27930edc14bSKonrad Rzeszutek Wilk static int interrupt_read(struct pci_dev *dev, int offset, u8 * value, 28030edc14bSKonrad Rzeszutek Wilk void *data) 28130edc14bSKonrad Rzeszutek Wilk { 28230edc14bSKonrad Rzeszutek Wilk *value = (u8) dev->irq; 28330edc14bSKonrad Rzeszutek Wilk 28430edc14bSKonrad Rzeszutek Wilk return 0; 28530edc14bSKonrad Rzeszutek Wilk } 28630edc14bSKonrad Rzeszutek Wilk 28730edc14bSKonrad Rzeszutek Wilk static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data) 28830edc14bSKonrad Rzeszutek Wilk { 28930edc14bSKonrad Rzeszutek Wilk u8 cur_value; 29030edc14bSKonrad Rzeszutek Wilk int err; 29130edc14bSKonrad Rzeszutek Wilk 29230edc14bSKonrad Rzeszutek Wilk err = pci_read_config_byte(dev, offset, &cur_value); 29330edc14bSKonrad Rzeszutek Wilk if (err) 29430edc14bSKonrad Rzeszutek Wilk goto out; 29530edc14bSKonrad Rzeszutek Wilk 29630edc14bSKonrad Rzeszutek Wilk if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START) 29730edc14bSKonrad Rzeszutek Wilk || value == PCI_BIST_START) 29830edc14bSKonrad Rzeszutek Wilk err = pci_write_config_byte(dev, offset, value); 29930edc14bSKonrad Rzeszutek Wilk 30030edc14bSKonrad Rzeszutek Wilk out: 30130edc14bSKonrad Rzeszutek Wilk return err; 30230edc14bSKonrad Rzeszutek Wilk } 30330edc14bSKonrad Rzeszutek Wilk 30430edc14bSKonrad Rzeszutek Wilk static const struct config_field header_common[] = { 30530edc14bSKonrad Rzeszutek Wilk { 306fd5b221bSZhao, Yu .offset = PCI_VENDOR_ID, 307fd5b221bSZhao, Yu .size = 2, 308a92336a1SKonrad Rzeszutek Wilk .u.w.read = xen_pcibk_read_vendor, 309fd5b221bSZhao, Yu }, 310fd5b221bSZhao, Yu { 311fd5b221bSZhao, Yu .offset = PCI_DEVICE_ID, 312fd5b221bSZhao, Yu .size = 2, 313a92336a1SKonrad Rzeszutek Wilk .u.w.read = xen_pcibk_read_device, 314fd5b221bSZhao, Yu }, 315fd5b221bSZhao, Yu { 31630edc14bSKonrad Rzeszutek Wilk .offset = PCI_COMMAND, 31730edc14bSKonrad Rzeszutek Wilk .size = 2, 318*af6fc858SJan Beulich .init = command_init, 319*af6fc858SJan Beulich .release = bar_release, 320fd5b221bSZhao, Yu .u.w.read = command_read, 32130edc14bSKonrad Rzeszutek Wilk .u.w.write = command_write, 32230edc14bSKonrad Rzeszutek Wilk }, 32330edc14bSKonrad Rzeszutek Wilk { 32430edc14bSKonrad Rzeszutek Wilk .offset = PCI_INTERRUPT_LINE, 32530edc14bSKonrad Rzeszutek Wilk .size = 1, 32630edc14bSKonrad Rzeszutek Wilk .u.b.read = interrupt_read, 32730edc14bSKonrad Rzeszutek Wilk }, 32830edc14bSKonrad Rzeszutek Wilk { 32930edc14bSKonrad Rzeszutek Wilk .offset = PCI_INTERRUPT_PIN, 33030edc14bSKonrad Rzeszutek Wilk .size = 1, 331a92336a1SKonrad Rzeszutek Wilk .u.b.read = xen_pcibk_read_config_byte, 33230edc14bSKonrad Rzeszutek Wilk }, 33330edc14bSKonrad Rzeszutek Wilk { 33430edc14bSKonrad Rzeszutek Wilk /* Any side effects of letting driver domain control cache line? */ 33530edc14bSKonrad Rzeszutek Wilk .offset = PCI_CACHE_LINE_SIZE, 33630edc14bSKonrad Rzeszutek Wilk .size = 1, 337a92336a1SKonrad Rzeszutek Wilk .u.b.read = xen_pcibk_read_config_byte, 338a92336a1SKonrad Rzeszutek Wilk .u.b.write = xen_pcibk_write_config_byte, 33930edc14bSKonrad Rzeszutek Wilk }, 34030edc14bSKonrad Rzeszutek Wilk { 34130edc14bSKonrad Rzeszutek Wilk .offset = PCI_LATENCY_TIMER, 34230edc14bSKonrad Rzeszutek Wilk .size = 1, 343a92336a1SKonrad Rzeszutek Wilk .u.b.read = xen_pcibk_read_config_byte, 34430edc14bSKonrad Rzeszutek Wilk }, 34530edc14bSKonrad Rzeszutek Wilk { 34630edc14bSKonrad Rzeszutek Wilk .offset = PCI_BIST, 34730edc14bSKonrad Rzeszutek Wilk .size = 1, 348a92336a1SKonrad Rzeszutek Wilk .u.b.read = xen_pcibk_read_config_byte, 34930edc14bSKonrad Rzeszutek Wilk .u.b.write = bist_write, 35030edc14bSKonrad Rzeszutek Wilk }, 35130edc14bSKonrad Rzeszutek Wilk {} 35230edc14bSKonrad Rzeszutek Wilk }; 35330edc14bSKonrad Rzeszutek Wilk 35430edc14bSKonrad Rzeszutek Wilk #define CFG_FIELD_BAR(reg_offset) \ 35530edc14bSKonrad Rzeszutek Wilk { \ 35630edc14bSKonrad Rzeszutek Wilk .offset = reg_offset, \ 35730edc14bSKonrad Rzeszutek Wilk .size = 4, \ 35830edc14bSKonrad Rzeszutek Wilk .init = bar_init, \ 35930edc14bSKonrad Rzeszutek Wilk .reset = bar_reset, \ 36030edc14bSKonrad Rzeszutek Wilk .release = bar_release, \ 36130edc14bSKonrad Rzeszutek Wilk .u.dw.read = bar_read, \ 36230edc14bSKonrad Rzeszutek Wilk .u.dw.write = bar_write, \ 36330edc14bSKonrad Rzeszutek Wilk } 36430edc14bSKonrad Rzeszutek Wilk 36530edc14bSKonrad Rzeszutek Wilk #define CFG_FIELD_ROM(reg_offset) \ 36630edc14bSKonrad Rzeszutek Wilk { \ 36730edc14bSKonrad Rzeszutek Wilk .offset = reg_offset, \ 36830edc14bSKonrad Rzeszutek Wilk .size = 4, \ 36930edc14bSKonrad Rzeszutek Wilk .init = rom_init, \ 37030edc14bSKonrad Rzeszutek Wilk .reset = bar_reset, \ 37130edc14bSKonrad Rzeszutek Wilk .release = bar_release, \ 37230edc14bSKonrad Rzeszutek Wilk .u.dw.read = bar_read, \ 37330edc14bSKonrad Rzeszutek Wilk .u.dw.write = rom_write, \ 37430edc14bSKonrad Rzeszutek Wilk } 37530edc14bSKonrad Rzeszutek Wilk 37630edc14bSKonrad Rzeszutek Wilk static const struct config_field header_0[] = { 37730edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_0), 37830edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_1), 37930edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_2), 38030edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_3), 38130edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_4), 38230edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_5), 38330edc14bSKonrad Rzeszutek Wilk CFG_FIELD_ROM(PCI_ROM_ADDRESS), 38430edc14bSKonrad Rzeszutek Wilk {} 38530edc14bSKonrad Rzeszutek Wilk }; 38630edc14bSKonrad Rzeszutek Wilk 38730edc14bSKonrad Rzeszutek Wilk static const struct config_field header_1[] = { 38830edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_0), 38930edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_1), 39030edc14bSKonrad Rzeszutek Wilk CFG_FIELD_ROM(PCI_ROM_ADDRESS1), 39130edc14bSKonrad Rzeszutek Wilk {} 39230edc14bSKonrad Rzeszutek Wilk }; 39330edc14bSKonrad Rzeszutek Wilk 394a92336a1SKonrad Rzeszutek Wilk int xen_pcibk_config_header_add_fields(struct pci_dev *dev) 39530edc14bSKonrad Rzeszutek Wilk { 39630edc14bSKonrad Rzeszutek Wilk int err; 39730edc14bSKonrad Rzeszutek Wilk 398a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_config_add_fields(dev, header_common); 39930edc14bSKonrad Rzeszutek Wilk if (err) 40030edc14bSKonrad Rzeszutek Wilk goto out; 40130edc14bSKonrad Rzeszutek Wilk 40230edc14bSKonrad Rzeszutek Wilk switch (dev->hdr_type) { 40330edc14bSKonrad Rzeszutek Wilk case PCI_HEADER_TYPE_NORMAL: 404a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_config_add_fields(dev, header_0); 40530edc14bSKonrad Rzeszutek Wilk break; 40630edc14bSKonrad Rzeszutek Wilk 40730edc14bSKonrad Rzeszutek Wilk case PCI_HEADER_TYPE_BRIDGE: 408a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_config_add_fields(dev, header_1); 40930edc14bSKonrad Rzeszutek Wilk break; 41030edc14bSKonrad Rzeszutek Wilk 41130edc14bSKonrad Rzeszutek Wilk default: 41230edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 413283c0972SJoe Perches pr_err("%s: Unsupported header type %d!\n", 41430edc14bSKonrad Rzeszutek Wilk pci_name(dev), dev->hdr_type); 41530edc14bSKonrad Rzeszutek Wilk break; 41630edc14bSKonrad Rzeszutek Wilk } 41730edc14bSKonrad Rzeszutek Wilk 41830edc14bSKonrad Rzeszutek Wilk out: 41930edc14bSKonrad Rzeszutek Wilk return err; 42030edc14bSKonrad Rzeszutek Wilk } 421