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 14af6fc858SJan Beulich struct pci_cmd_info { 15af6fc858SJan Beulich u16 val; 16af6fc858SJan Beulich }; 17af6fc858SJan 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 27af6fc858SJan Beulich /* Bits guests are allowed to control in permissive mode. */ 28af6fc858SJan Beulich #define PCI_COMMAND_GUEST (PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL| \ 29af6fc858SJan Beulich PCI_COMMAND_INVALIDATE|PCI_COMMAND_VGA_PALETTE| \ 30af6fc858SJan Beulich PCI_COMMAND_WAIT|PCI_COMMAND_FAST_BACK) 31af6fc858SJan Beulich 32af6fc858SJan Beulich static void *command_init(struct pci_dev *dev, int offset) 33af6fc858SJan Beulich { 34af6fc858SJan Beulich struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); 35af6fc858SJan Beulich int err; 36af6fc858SJan Beulich 37af6fc858SJan Beulich if (!cmd) 38af6fc858SJan Beulich return ERR_PTR(-ENOMEM); 39af6fc858SJan Beulich 40af6fc858SJan Beulich err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val); 41af6fc858SJan Beulich if (err) { 42af6fc858SJan Beulich kfree(cmd); 43af6fc858SJan Beulich return ERR_PTR(err); 44af6fc858SJan Beulich } 45af6fc858SJan Beulich 46af6fc858SJan Beulich return cmd; 47af6fc858SJan Beulich } 48af6fc858SJan Beulich 49fd5b221bSZhao, Yu static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data) 50fd5b221bSZhao, Yu { 51af6fc858SJan Beulich int ret = pci_read_config_word(dev, offset, value); 52af6fc858SJan Beulich const struct pci_cmd_info *cmd = data; 53fd5b221bSZhao, Yu 54af6fc858SJan Beulich *value &= PCI_COMMAND_GUEST; 55af6fc858SJan 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; 64af6fc858SJan Beulich u16 val; 65af6fc858SJan 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); 91278edfc0SJan Beulich } else if (dev->is_busmaster && !is_master_cmd(value)) { 92278edfc0SJan Beulich if (unlikely(verbose_request)) 93278edfc0SJan Beulich printk(KERN_DEBUG DRV_NAME ": %s: clear bus master\n", 94278edfc0SJan Beulich pci_name(dev)); 95278edfc0SJan Beulich pci_clear_master(dev); 9630edc14bSKonrad Rzeszutek Wilk } 9730edc14bSKonrad Rzeszutek Wilk 98278edfc0SJan Beulich if (!(cmd->val & PCI_COMMAND_INVALIDATE) && 99278edfc0SJan Beulich (value & PCI_COMMAND_INVALIDATE)) { 10030edc14bSKonrad Rzeszutek Wilk if (unlikely(verbose_request)) 10130edc14bSKonrad Rzeszutek Wilk printk(KERN_DEBUG 102a92336a1SKonrad Rzeszutek Wilk DRV_NAME ": %s: enable memory-write-invalidate\n", 10330edc14bSKonrad Rzeszutek Wilk pci_name(dev)); 10430edc14bSKonrad Rzeszutek Wilk err = pci_set_mwi(dev); 10530edc14bSKonrad Rzeszutek Wilk if (err) { 106283c0972SJoe Perches pr_warn("%s: cannot enable memory-write-invalidate (%d)\n", 10730edc14bSKonrad Rzeszutek Wilk pci_name(dev), err); 10830edc14bSKonrad Rzeszutek Wilk value &= ~PCI_COMMAND_INVALIDATE; 10930edc14bSKonrad Rzeszutek Wilk } 110278edfc0SJan Beulich } else if ((cmd->val & PCI_COMMAND_INVALIDATE) && 111278edfc0SJan Beulich !(value & PCI_COMMAND_INVALIDATE)) { 112278edfc0SJan Beulich if (unlikely(verbose_request)) 113278edfc0SJan Beulich printk(KERN_DEBUG 114278edfc0SJan Beulich DRV_NAME ": %s: disable memory-write-invalidate\n", 115278edfc0SJan Beulich pci_name(dev)); 116278edfc0SJan Beulich pci_clear_mwi(dev); 11730edc14bSKonrad Rzeszutek Wilk } 11830edc14bSKonrad Rzeszutek Wilk 119af6fc858SJan Beulich cmd->val = value; 120af6fc858SJan Beulich 1218014bcc8SBen Hutchings if (!xen_pcibk_permissive && (!dev_data || !dev_data->permissive)) 122af6fc858SJan Beulich return 0; 123af6fc858SJan Beulich 124af6fc858SJan Beulich /* Only allow the guest to control certain bits. */ 125af6fc858SJan Beulich err = pci_read_config_word(dev, offset, &val); 126af6fc858SJan Beulich if (err || val == value) 127af6fc858SJan Beulich return err; 128af6fc858SJan Beulich 129af6fc858SJan Beulich value &= PCI_COMMAND_GUEST; 130af6fc858SJan Beulich value |= val & ~PCI_COMMAND_GUEST; 131af6fc858SJan Beulich 13230edc14bSKonrad Rzeszutek Wilk return pci_write_config_word(dev, offset, value); 13330edc14bSKonrad Rzeszutek Wilk } 13430edc14bSKonrad Rzeszutek Wilk 13530edc14bSKonrad Rzeszutek Wilk static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data) 13630edc14bSKonrad Rzeszutek Wilk { 13730edc14bSKonrad Rzeszutek Wilk struct pci_bar_info *bar = data; 13830edc14bSKonrad Rzeszutek Wilk 13930edc14bSKonrad Rzeszutek Wilk if (unlikely(!bar)) { 140283c0972SJoe Perches pr_warn(DRV_NAME ": driver data not found for %s\n", 14130edc14bSKonrad Rzeszutek Wilk pci_name(dev)); 14230edc14bSKonrad Rzeszutek Wilk return XEN_PCI_ERR_op_failed; 14330edc14bSKonrad Rzeszutek Wilk } 14430edc14bSKonrad Rzeszutek Wilk 14530edc14bSKonrad Rzeszutek Wilk /* A write to obtain the length must happen as a 32-bit write. 14630edc14bSKonrad Rzeszutek Wilk * This does not (yet) support writing individual bytes 14730edc14bSKonrad Rzeszutek Wilk */ 148d2bd05d8SJan Beulich if ((value | ~PCI_ROM_ADDRESS_MASK) == ~0U) 14930edc14bSKonrad Rzeszutek Wilk bar->which = 1; 15030edc14bSKonrad Rzeszutek Wilk else { 15130edc14bSKonrad Rzeszutek Wilk u32 tmpval; 15230edc14bSKonrad Rzeszutek Wilk pci_read_config_dword(dev, offset, &tmpval); 15330edc14bSKonrad Rzeszutek Wilk if (tmpval != bar->val && value == bar->val) { 15430edc14bSKonrad Rzeszutek Wilk /* Allow restoration of bar value. */ 15530edc14bSKonrad Rzeszutek Wilk pci_write_config_dword(dev, offset, bar->val); 15630edc14bSKonrad Rzeszutek Wilk } 15730edc14bSKonrad Rzeszutek Wilk bar->which = 0; 15830edc14bSKonrad Rzeszutek Wilk } 15930edc14bSKonrad Rzeszutek Wilk 16030edc14bSKonrad Rzeszutek Wilk /* Do we need to support enabling/disabling the rom address here? */ 16130edc14bSKonrad Rzeszutek Wilk 16230edc14bSKonrad Rzeszutek Wilk return 0; 16330edc14bSKonrad Rzeszutek Wilk } 16430edc14bSKonrad Rzeszutek Wilk 16530edc14bSKonrad Rzeszutek Wilk /* For the BARs, only allow writes which write ~0 or 16630edc14bSKonrad Rzeszutek Wilk * the correct resource information 16730edc14bSKonrad Rzeszutek Wilk * (Needed for when the driver probes the resource usage) 16830edc14bSKonrad Rzeszutek Wilk */ 16930edc14bSKonrad Rzeszutek Wilk static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data) 17030edc14bSKonrad Rzeszutek Wilk { 17130edc14bSKonrad Rzeszutek Wilk struct pci_bar_info *bar = data; 17230edc14bSKonrad Rzeszutek Wilk 17330edc14bSKonrad Rzeszutek Wilk if (unlikely(!bar)) { 174283c0972SJoe Perches pr_warn(DRV_NAME ": driver data not found for %s\n", 17530edc14bSKonrad Rzeszutek Wilk pci_name(dev)); 17630edc14bSKonrad Rzeszutek Wilk return XEN_PCI_ERR_op_failed; 17730edc14bSKonrad Rzeszutek Wilk } 17830edc14bSKonrad Rzeszutek Wilk 17930edc14bSKonrad Rzeszutek Wilk /* A write to obtain the length must happen as a 32-bit write. 18030edc14bSKonrad Rzeszutek Wilk * This does not (yet) support writing individual bytes 18130edc14bSKonrad Rzeszutek Wilk */ 18230edc14bSKonrad Rzeszutek Wilk if (value == ~0) 18330edc14bSKonrad Rzeszutek Wilk bar->which = 1; 18430edc14bSKonrad Rzeszutek Wilk else { 18530edc14bSKonrad Rzeszutek Wilk u32 tmpval; 18630edc14bSKonrad Rzeszutek Wilk pci_read_config_dword(dev, offset, &tmpval); 18730edc14bSKonrad Rzeszutek Wilk if (tmpval != bar->val && value == bar->val) { 18830edc14bSKonrad Rzeszutek Wilk /* Allow restoration of bar value. */ 18930edc14bSKonrad Rzeszutek Wilk pci_write_config_dword(dev, offset, bar->val); 19030edc14bSKonrad Rzeszutek Wilk } 19130edc14bSKonrad Rzeszutek Wilk bar->which = 0; 19230edc14bSKonrad Rzeszutek Wilk } 19330edc14bSKonrad Rzeszutek Wilk 19430edc14bSKonrad Rzeszutek Wilk return 0; 19530edc14bSKonrad Rzeszutek Wilk } 19630edc14bSKonrad Rzeszutek Wilk 19730edc14bSKonrad Rzeszutek Wilk static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data) 19830edc14bSKonrad Rzeszutek Wilk { 19930edc14bSKonrad Rzeszutek Wilk struct pci_bar_info *bar = data; 20030edc14bSKonrad Rzeszutek Wilk 20130edc14bSKonrad Rzeszutek Wilk if (unlikely(!bar)) { 202283c0972SJoe Perches pr_warn(DRV_NAME ": driver data not found for %s\n", 20330edc14bSKonrad Rzeszutek Wilk pci_name(dev)); 20430edc14bSKonrad Rzeszutek Wilk return XEN_PCI_ERR_op_failed; 20530edc14bSKonrad Rzeszutek Wilk } 20630edc14bSKonrad Rzeszutek Wilk 20730edc14bSKonrad Rzeszutek Wilk *value = bar->which ? bar->len_val : bar->val; 20830edc14bSKonrad Rzeszutek Wilk 20930edc14bSKonrad Rzeszutek Wilk return 0; 21030edc14bSKonrad Rzeszutek Wilk } 21130edc14bSKonrad Rzeszutek Wilk 2126ad2655dSJan Beulich static void *bar_init(struct pci_dev *dev, int offset) 21330edc14bSKonrad Rzeszutek Wilk { 214*58520360SJan Beulich unsigned int pos; 215*58520360SJan Beulich const struct resource *res = dev->resource; 2166ad2655dSJan Beulich struct pci_bar_info *bar = kzalloc(sizeof(*bar), GFP_KERNEL); 2176ad2655dSJan Beulich 2186ad2655dSJan Beulich if (!bar) 2196ad2655dSJan Beulich return ERR_PTR(-ENOMEM); 220fd5b221bSZhao, Yu 221fd5b221bSZhao, Yu if (offset == PCI_ROM_ADDRESS || offset == PCI_ROM_ADDRESS1) 222fd5b221bSZhao, Yu pos = PCI_ROM_RESOURCE; 223fd5b221bSZhao, Yu else { 224fd5b221bSZhao, Yu pos = (offset - PCI_BASE_ADDRESS_0) / 4; 225c8670c22SJan Beulich if (pos && (res[pos - 1].flags & IORESOURCE_MEM_64)) { 2266ad2655dSJan Beulich bar->val = res[pos - 1].start >> 32; 2276ad2655dSJan Beulich bar->len_val = -resource_size(&res[pos - 1]) >> 32; 2286ad2655dSJan Beulich return bar; 229fd5b221bSZhao, Yu } 230fd5b221bSZhao, Yu } 231fd5b221bSZhao, Yu 232d2bd05d8SJan Beulich if (!res[pos].flags || 233d2bd05d8SJan Beulich (res[pos].flags & (IORESOURCE_DISABLED | IORESOURCE_UNSET | 234d2bd05d8SJan Beulich IORESOURCE_BUSY))) 2356ad2655dSJan Beulich return bar; 236d2bd05d8SJan Beulich 2376ad2655dSJan Beulich bar->val = res[pos].start | 238fd5b221bSZhao, Yu (res[pos].flags & PCI_REGION_FLAG_MASK); 2396ad2655dSJan Beulich bar->len_val = -resource_size(&res[pos]) | 240d2bd05d8SJan Beulich (res[pos].flags & PCI_REGION_FLAG_MASK); 24130edc14bSKonrad Rzeszutek Wilk 24230edc14bSKonrad Rzeszutek Wilk return bar; 24330edc14bSKonrad Rzeszutek Wilk } 24430edc14bSKonrad Rzeszutek Wilk 24530edc14bSKonrad Rzeszutek Wilk static void bar_reset(struct pci_dev *dev, int offset, void *data) 24630edc14bSKonrad Rzeszutek Wilk { 24730edc14bSKonrad Rzeszutek Wilk struct pci_bar_info *bar = data; 24830edc14bSKonrad Rzeszutek Wilk 24930edc14bSKonrad Rzeszutek Wilk bar->which = 0; 25030edc14bSKonrad Rzeszutek Wilk } 25130edc14bSKonrad Rzeszutek Wilk 25230edc14bSKonrad Rzeszutek Wilk static void bar_release(struct pci_dev *dev, int offset, void *data) 25330edc14bSKonrad Rzeszutek Wilk { 25430edc14bSKonrad Rzeszutek Wilk kfree(data); 25530edc14bSKonrad Rzeszutek Wilk } 25630edc14bSKonrad Rzeszutek Wilk 257a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_read_vendor(struct pci_dev *dev, int offset, 258fd5b221bSZhao, Yu u16 *value, void *data) 259fd5b221bSZhao, Yu { 260fd5b221bSZhao, Yu *value = dev->vendor; 261fd5b221bSZhao, Yu 262fd5b221bSZhao, Yu return 0; 263fd5b221bSZhao, Yu } 264fd5b221bSZhao, Yu 265a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_read_device(struct pci_dev *dev, int offset, 266fd5b221bSZhao, Yu u16 *value, void *data) 267fd5b221bSZhao, Yu { 268fd5b221bSZhao, Yu *value = dev->device; 269fd5b221bSZhao, Yu 270fd5b221bSZhao, Yu return 0; 271fd5b221bSZhao, Yu } 272fd5b221bSZhao, Yu 27330edc14bSKonrad Rzeszutek Wilk static int interrupt_read(struct pci_dev *dev, int offset, u8 * value, 27430edc14bSKonrad Rzeszutek Wilk void *data) 27530edc14bSKonrad Rzeszutek Wilk { 27630edc14bSKonrad Rzeszutek Wilk *value = (u8) dev->irq; 27730edc14bSKonrad Rzeszutek Wilk 27830edc14bSKonrad Rzeszutek Wilk return 0; 27930edc14bSKonrad Rzeszutek Wilk } 28030edc14bSKonrad Rzeszutek Wilk 28130edc14bSKonrad Rzeszutek Wilk static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data) 28230edc14bSKonrad Rzeszutek Wilk { 28330edc14bSKonrad Rzeszutek Wilk u8 cur_value; 28430edc14bSKonrad Rzeszutek Wilk int err; 28530edc14bSKonrad Rzeszutek Wilk 28630edc14bSKonrad Rzeszutek Wilk err = pci_read_config_byte(dev, offset, &cur_value); 28730edc14bSKonrad Rzeszutek Wilk if (err) 28830edc14bSKonrad Rzeszutek Wilk goto out; 28930edc14bSKonrad Rzeszutek Wilk 29030edc14bSKonrad Rzeszutek Wilk if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START) 29130edc14bSKonrad Rzeszutek Wilk || value == PCI_BIST_START) 29230edc14bSKonrad Rzeszutek Wilk err = pci_write_config_byte(dev, offset, value); 29330edc14bSKonrad Rzeszutek Wilk 29430edc14bSKonrad Rzeszutek Wilk out: 29530edc14bSKonrad Rzeszutek Wilk return err; 29630edc14bSKonrad Rzeszutek Wilk } 29730edc14bSKonrad Rzeszutek Wilk 29830edc14bSKonrad Rzeszutek Wilk static const struct config_field header_common[] = { 29930edc14bSKonrad Rzeszutek Wilk { 300fd5b221bSZhao, Yu .offset = PCI_VENDOR_ID, 301fd5b221bSZhao, Yu .size = 2, 302a92336a1SKonrad Rzeszutek Wilk .u.w.read = xen_pcibk_read_vendor, 303fd5b221bSZhao, Yu }, 304fd5b221bSZhao, Yu { 305fd5b221bSZhao, Yu .offset = PCI_DEVICE_ID, 306fd5b221bSZhao, Yu .size = 2, 307a92336a1SKonrad Rzeszutek Wilk .u.w.read = xen_pcibk_read_device, 308fd5b221bSZhao, Yu }, 309fd5b221bSZhao, Yu { 31030edc14bSKonrad Rzeszutek Wilk .offset = PCI_COMMAND, 31130edc14bSKonrad Rzeszutek Wilk .size = 2, 312af6fc858SJan Beulich .init = command_init, 313af6fc858SJan Beulich .release = bar_release, 314fd5b221bSZhao, Yu .u.w.read = command_read, 31530edc14bSKonrad Rzeszutek Wilk .u.w.write = command_write, 31630edc14bSKonrad Rzeszutek Wilk }, 31730edc14bSKonrad Rzeszutek Wilk { 31830edc14bSKonrad Rzeszutek Wilk .offset = PCI_INTERRUPT_LINE, 31930edc14bSKonrad Rzeszutek Wilk .size = 1, 32030edc14bSKonrad Rzeszutek Wilk .u.b.read = interrupt_read, 32130edc14bSKonrad Rzeszutek Wilk }, 32230edc14bSKonrad Rzeszutek Wilk { 32330edc14bSKonrad Rzeszutek Wilk .offset = PCI_INTERRUPT_PIN, 32430edc14bSKonrad Rzeszutek Wilk .size = 1, 325a92336a1SKonrad Rzeszutek Wilk .u.b.read = xen_pcibk_read_config_byte, 32630edc14bSKonrad Rzeszutek Wilk }, 32730edc14bSKonrad Rzeszutek Wilk { 32830edc14bSKonrad Rzeszutek Wilk /* Any side effects of letting driver domain control cache line? */ 32930edc14bSKonrad Rzeszutek Wilk .offset = PCI_CACHE_LINE_SIZE, 33030edc14bSKonrad Rzeszutek Wilk .size = 1, 331a92336a1SKonrad Rzeszutek Wilk .u.b.read = xen_pcibk_read_config_byte, 332a92336a1SKonrad Rzeszutek Wilk .u.b.write = xen_pcibk_write_config_byte, 33330edc14bSKonrad Rzeszutek Wilk }, 33430edc14bSKonrad Rzeszutek Wilk { 33530edc14bSKonrad Rzeszutek Wilk .offset = PCI_LATENCY_TIMER, 33630edc14bSKonrad Rzeszutek Wilk .size = 1, 337a92336a1SKonrad Rzeszutek Wilk .u.b.read = xen_pcibk_read_config_byte, 33830edc14bSKonrad Rzeszutek Wilk }, 33930edc14bSKonrad Rzeszutek Wilk { 34030edc14bSKonrad Rzeszutek Wilk .offset = PCI_BIST, 34130edc14bSKonrad Rzeszutek Wilk .size = 1, 342a92336a1SKonrad Rzeszutek Wilk .u.b.read = xen_pcibk_read_config_byte, 34330edc14bSKonrad Rzeszutek Wilk .u.b.write = bist_write, 34430edc14bSKonrad Rzeszutek Wilk }, 34530edc14bSKonrad Rzeszutek Wilk {} 34630edc14bSKonrad Rzeszutek Wilk }; 34730edc14bSKonrad Rzeszutek Wilk 34830edc14bSKonrad Rzeszutek Wilk #define CFG_FIELD_BAR(reg_offset) \ 34930edc14bSKonrad Rzeszutek Wilk { \ 35030edc14bSKonrad Rzeszutek Wilk .offset = reg_offset, \ 35130edc14bSKonrad Rzeszutek Wilk .size = 4, \ 35230edc14bSKonrad Rzeszutek Wilk .init = bar_init, \ 35330edc14bSKonrad Rzeszutek Wilk .reset = bar_reset, \ 35430edc14bSKonrad Rzeszutek Wilk .release = bar_release, \ 35530edc14bSKonrad Rzeszutek Wilk .u.dw.read = bar_read, \ 35630edc14bSKonrad Rzeszutek Wilk .u.dw.write = bar_write, \ 35730edc14bSKonrad Rzeszutek Wilk } 35830edc14bSKonrad Rzeszutek Wilk 35930edc14bSKonrad Rzeszutek Wilk #define CFG_FIELD_ROM(reg_offset) \ 36030edc14bSKonrad Rzeszutek Wilk { \ 36130edc14bSKonrad Rzeszutek Wilk .offset = reg_offset, \ 36230edc14bSKonrad Rzeszutek Wilk .size = 4, \ 363664093bbSJan Beulich .init = bar_init, \ 36430edc14bSKonrad Rzeszutek Wilk .reset = bar_reset, \ 36530edc14bSKonrad Rzeszutek Wilk .release = bar_release, \ 36630edc14bSKonrad Rzeszutek Wilk .u.dw.read = bar_read, \ 36730edc14bSKonrad Rzeszutek Wilk .u.dw.write = rom_write, \ 36830edc14bSKonrad Rzeszutek Wilk } 36930edc14bSKonrad Rzeszutek Wilk 37030edc14bSKonrad Rzeszutek Wilk static const struct config_field header_0[] = { 37130edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_0), 37230edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_1), 37330edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_2), 37430edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_3), 37530edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_4), 37630edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_5), 37730edc14bSKonrad Rzeszutek Wilk CFG_FIELD_ROM(PCI_ROM_ADDRESS), 37830edc14bSKonrad Rzeszutek Wilk {} 37930edc14bSKonrad Rzeszutek Wilk }; 38030edc14bSKonrad Rzeszutek Wilk 38130edc14bSKonrad Rzeszutek Wilk static const struct config_field header_1[] = { 38230edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_0), 38330edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_1), 38430edc14bSKonrad Rzeszutek Wilk CFG_FIELD_ROM(PCI_ROM_ADDRESS1), 38530edc14bSKonrad Rzeszutek Wilk {} 38630edc14bSKonrad Rzeszutek Wilk }; 38730edc14bSKonrad Rzeszutek Wilk 388a92336a1SKonrad Rzeszutek Wilk int xen_pcibk_config_header_add_fields(struct pci_dev *dev) 38930edc14bSKonrad Rzeszutek Wilk { 39030edc14bSKonrad Rzeszutek Wilk int err; 39130edc14bSKonrad Rzeszutek Wilk 392a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_config_add_fields(dev, header_common); 39330edc14bSKonrad Rzeszutek Wilk if (err) 39430edc14bSKonrad Rzeszutek Wilk goto out; 39530edc14bSKonrad Rzeszutek Wilk 39630edc14bSKonrad Rzeszutek Wilk switch (dev->hdr_type) { 39730edc14bSKonrad Rzeszutek Wilk case PCI_HEADER_TYPE_NORMAL: 398a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_config_add_fields(dev, header_0); 39930edc14bSKonrad Rzeszutek Wilk break; 40030edc14bSKonrad Rzeszutek Wilk 40130edc14bSKonrad Rzeszutek Wilk case PCI_HEADER_TYPE_BRIDGE: 402a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_config_add_fields(dev, header_1); 40330edc14bSKonrad Rzeszutek Wilk break; 40430edc14bSKonrad Rzeszutek Wilk 40530edc14bSKonrad Rzeszutek Wilk default: 40630edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 407283c0972SJoe Perches pr_err("%s: Unsupported header type %d!\n", 40830edc14bSKonrad Rzeszutek Wilk pci_name(dev), dev->hdr_type); 40930edc14bSKonrad Rzeszutek Wilk break; 41030edc14bSKonrad Rzeszutek Wilk } 41130edc14bSKonrad Rzeszutek Wilk 41230edc14bSKonrad Rzeszutek Wilk out: 41330edc14bSKonrad Rzeszutek Wilk return err; 41430edc14bSKonrad Rzeszutek Wilk } 415