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; 172*8c28ef3fSJan Beulich unsigned int pos = (offset - PCI_BASE_ADDRESS_0) / 4; 173*8c28ef3fSJan Beulich const struct resource *res = dev->resource; 174*8c28ef3fSJan Beulich u32 mask; 17530edc14bSKonrad Rzeszutek Wilk 17630edc14bSKonrad Rzeszutek Wilk if (unlikely(!bar)) { 177283c0972SJoe Perches pr_warn(DRV_NAME ": driver data not found for %s\n", 17830edc14bSKonrad Rzeszutek Wilk pci_name(dev)); 17930edc14bSKonrad Rzeszutek Wilk return XEN_PCI_ERR_op_failed; 18030edc14bSKonrad Rzeszutek Wilk } 18130edc14bSKonrad Rzeszutek Wilk 18230edc14bSKonrad Rzeszutek Wilk /* A write to obtain the length must happen as a 32-bit write. 18330edc14bSKonrad Rzeszutek Wilk * This does not (yet) support writing individual bytes 18430edc14bSKonrad Rzeszutek Wilk */ 185*8c28ef3fSJan Beulich if (res[pos].flags & IORESOURCE_IO) 186*8c28ef3fSJan Beulich mask = ~PCI_BASE_ADDRESS_IO_MASK; 187*8c28ef3fSJan Beulich else if (pos && (res[pos - 1].flags & IORESOURCE_MEM_64)) 188*8c28ef3fSJan Beulich mask = 0; 189*8c28ef3fSJan Beulich else 190*8c28ef3fSJan Beulich mask = ~PCI_BASE_ADDRESS_MEM_MASK; 191*8c28ef3fSJan Beulich if ((value | mask) == ~0U) 19230edc14bSKonrad Rzeszutek Wilk bar->which = 1; 19330edc14bSKonrad Rzeszutek Wilk else { 19430edc14bSKonrad Rzeszutek Wilk u32 tmpval; 19530edc14bSKonrad Rzeszutek Wilk pci_read_config_dword(dev, offset, &tmpval); 19630edc14bSKonrad Rzeszutek Wilk if (tmpval != bar->val && value == bar->val) { 19730edc14bSKonrad Rzeszutek Wilk /* Allow restoration of bar value. */ 19830edc14bSKonrad Rzeszutek Wilk pci_write_config_dword(dev, offset, bar->val); 19930edc14bSKonrad Rzeszutek Wilk } 20030edc14bSKonrad Rzeszutek Wilk bar->which = 0; 20130edc14bSKonrad Rzeszutek Wilk } 20230edc14bSKonrad Rzeszutek Wilk 20330edc14bSKonrad Rzeszutek Wilk return 0; 20430edc14bSKonrad Rzeszutek Wilk } 20530edc14bSKonrad Rzeszutek Wilk 20630edc14bSKonrad Rzeszutek Wilk static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data) 20730edc14bSKonrad Rzeszutek Wilk { 20830edc14bSKonrad Rzeszutek Wilk struct pci_bar_info *bar = data; 20930edc14bSKonrad Rzeszutek Wilk 21030edc14bSKonrad Rzeszutek Wilk if (unlikely(!bar)) { 211283c0972SJoe Perches pr_warn(DRV_NAME ": driver data not found for %s\n", 21230edc14bSKonrad Rzeszutek Wilk pci_name(dev)); 21330edc14bSKonrad Rzeszutek Wilk return XEN_PCI_ERR_op_failed; 21430edc14bSKonrad Rzeszutek Wilk } 21530edc14bSKonrad Rzeszutek Wilk 21630edc14bSKonrad Rzeszutek Wilk *value = bar->which ? bar->len_val : bar->val; 21730edc14bSKonrad Rzeszutek Wilk 21830edc14bSKonrad Rzeszutek Wilk return 0; 21930edc14bSKonrad Rzeszutek Wilk } 22030edc14bSKonrad Rzeszutek Wilk 2216ad2655dSJan Beulich static void *bar_init(struct pci_dev *dev, int offset) 22230edc14bSKonrad Rzeszutek Wilk { 22358520360SJan Beulich unsigned int pos; 22458520360SJan Beulich const struct resource *res = dev->resource; 2256ad2655dSJan Beulich struct pci_bar_info *bar = kzalloc(sizeof(*bar), GFP_KERNEL); 2266ad2655dSJan Beulich 2276ad2655dSJan Beulich if (!bar) 2286ad2655dSJan Beulich return ERR_PTR(-ENOMEM); 229fd5b221bSZhao, Yu 230fd5b221bSZhao, Yu if (offset == PCI_ROM_ADDRESS || offset == PCI_ROM_ADDRESS1) 231fd5b221bSZhao, Yu pos = PCI_ROM_RESOURCE; 232fd5b221bSZhao, Yu else { 233fd5b221bSZhao, Yu pos = (offset - PCI_BASE_ADDRESS_0) / 4; 234c8670c22SJan Beulich if (pos && (res[pos - 1].flags & IORESOURCE_MEM_64)) { 2356ad2655dSJan Beulich bar->val = res[pos - 1].start >> 32; 2366ad2655dSJan Beulich bar->len_val = -resource_size(&res[pos - 1]) >> 32; 2376ad2655dSJan Beulich return bar; 238fd5b221bSZhao, Yu } 239fd5b221bSZhao, Yu } 240fd5b221bSZhao, Yu 241d2bd05d8SJan Beulich if (!res[pos].flags || 242d2bd05d8SJan Beulich (res[pos].flags & (IORESOURCE_DISABLED | IORESOURCE_UNSET | 243d2bd05d8SJan Beulich IORESOURCE_BUSY))) 2446ad2655dSJan Beulich return bar; 245d2bd05d8SJan Beulich 2466ad2655dSJan Beulich bar->val = res[pos].start | 247fd5b221bSZhao, Yu (res[pos].flags & PCI_REGION_FLAG_MASK); 2486ad2655dSJan Beulich bar->len_val = -resource_size(&res[pos]) | 249d2bd05d8SJan Beulich (res[pos].flags & PCI_REGION_FLAG_MASK); 25030edc14bSKonrad Rzeszutek Wilk 25130edc14bSKonrad Rzeszutek Wilk return bar; 25230edc14bSKonrad Rzeszutek Wilk } 25330edc14bSKonrad Rzeszutek Wilk 25430edc14bSKonrad Rzeszutek Wilk static void bar_reset(struct pci_dev *dev, int offset, void *data) 25530edc14bSKonrad Rzeszutek Wilk { 25630edc14bSKonrad Rzeszutek Wilk struct pci_bar_info *bar = data; 25730edc14bSKonrad Rzeszutek Wilk 25830edc14bSKonrad Rzeszutek Wilk bar->which = 0; 25930edc14bSKonrad Rzeszutek Wilk } 26030edc14bSKonrad Rzeszutek Wilk 26130edc14bSKonrad Rzeszutek Wilk static void bar_release(struct pci_dev *dev, int offset, void *data) 26230edc14bSKonrad Rzeszutek Wilk { 26330edc14bSKonrad Rzeszutek Wilk kfree(data); 26430edc14bSKonrad Rzeszutek Wilk } 26530edc14bSKonrad Rzeszutek Wilk 266a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_read_vendor(struct pci_dev *dev, int offset, 267fd5b221bSZhao, Yu u16 *value, void *data) 268fd5b221bSZhao, Yu { 269fd5b221bSZhao, Yu *value = dev->vendor; 270fd5b221bSZhao, Yu 271fd5b221bSZhao, Yu return 0; 272fd5b221bSZhao, Yu } 273fd5b221bSZhao, Yu 274a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_read_device(struct pci_dev *dev, int offset, 275fd5b221bSZhao, Yu u16 *value, void *data) 276fd5b221bSZhao, Yu { 277fd5b221bSZhao, Yu *value = dev->device; 278fd5b221bSZhao, Yu 279fd5b221bSZhao, Yu return 0; 280fd5b221bSZhao, Yu } 281fd5b221bSZhao, Yu 28230edc14bSKonrad Rzeszutek Wilk static int interrupt_read(struct pci_dev *dev, int offset, u8 * value, 28330edc14bSKonrad Rzeszutek Wilk void *data) 28430edc14bSKonrad Rzeszutek Wilk { 28530edc14bSKonrad Rzeszutek Wilk *value = (u8) dev->irq; 28630edc14bSKonrad Rzeszutek Wilk 28730edc14bSKonrad Rzeszutek Wilk return 0; 28830edc14bSKonrad Rzeszutek Wilk } 28930edc14bSKonrad Rzeszutek Wilk 29030edc14bSKonrad Rzeszutek Wilk static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data) 29130edc14bSKonrad Rzeszutek Wilk { 29230edc14bSKonrad Rzeszutek Wilk u8 cur_value; 29330edc14bSKonrad Rzeszutek Wilk int err; 29430edc14bSKonrad Rzeszutek Wilk 29530edc14bSKonrad Rzeszutek Wilk err = pci_read_config_byte(dev, offset, &cur_value); 29630edc14bSKonrad Rzeszutek Wilk if (err) 29730edc14bSKonrad Rzeszutek Wilk goto out; 29830edc14bSKonrad Rzeszutek Wilk 29930edc14bSKonrad Rzeszutek Wilk if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START) 30030edc14bSKonrad Rzeszutek Wilk || value == PCI_BIST_START) 30130edc14bSKonrad Rzeszutek Wilk err = pci_write_config_byte(dev, offset, value); 30230edc14bSKonrad Rzeszutek Wilk 30330edc14bSKonrad Rzeszutek Wilk out: 30430edc14bSKonrad Rzeszutek Wilk return err; 30530edc14bSKonrad Rzeszutek Wilk } 30630edc14bSKonrad Rzeszutek Wilk 30730edc14bSKonrad Rzeszutek Wilk static const struct config_field header_common[] = { 30830edc14bSKonrad Rzeszutek Wilk { 309fd5b221bSZhao, Yu .offset = PCI_VENDOR_ID, 310fd5b221bSZhao, Yu .size = 2, 311a92336a1SKonrad Rzeszutek Wilk .u.w.read = xen_pcibk_read_vendor, 312fd5b221bSZhao, Yu }, 313fd5b221bSZhao, Yu { 314fd5b221bSZhao, Yu .offset = PCI_DEVICE_ID, 315fd5b221bSZhao, Yu .size = 2, 316a92336a1SKonrad Rzeszutek Wilk .u.w.read = xen_pcibk_read_device, 317fd5b221bSZhao, Yu }, 318fd5b221bSZhao, Yu { 31930edc14bSKonrad Rzeszutek Wilk .offset = PCI_COMMAND, 32030edc14bSKonrad Rzeszutek Wilk .size = 2, 321af6fc858SJan Beulich .init = command_init, 322af6fc858SJan Beulich .release = bar_release, 323fd5b221bSZhao, Yu .u.w.read = command_read, 32430edc14bSKonrad Rzeszutek Wilk .u.w.write = command_write, 32530edc14bSKonrad Rzeszutek Wilk }, 32630edc14bSKonrad Rzeszutek Wilk { 32730edc14bSKonrad Rzeszutek Wilk .offset = PCI_INTERRUPT_LINE, 32830edc14bSKonrad Rzeszutek Wilk .size = 1, 32930edc14bSKonrad Rzeszutek Wilk .u.b.read = interrupt_read, 33030edc14bSKonrad Rzeszutek Wilk }, 33130edc14bSKonrad Rzeszutek Wilk { 33230edc14bSKonrad Rzeszutek Wilk .offset = PCI_INTERRUPT_PIN, 33330edc14bSKonrad Rzeszutek Wilk .size = 1, 334a92336a1SKonrad Rzeszutek Wilk .u.b.read = xen_pcibk_read_config_byte, 33530edc14bSKonrad Rzeszutek Wilk }, 33630edc14bSKonrad Rzeszutek Wilk { 33730edc14bSKonrad Rzeszutek Wilk /* Any side effects of letting driver domain control cache line? */ 33830edc14bSKonrad Rzeszutek Wilk .offset = PCI_CACHE_LINE_SIZE, 33930edc14bSKonrad Rzeszutek Wilk .size = 1, 340a92336a1SKonrad Rzeszutek Wilk .u.b.read = xen_pcibk_read_config_byte, 341a92336a1SKonrad Rzeszutek Wilk .u.b.write = xen_pcibk_write_config_byte, 34230edc14bSKonrad Rzeszutek Wilk }, 34330edc14bSKonrad Rzeszutek Wilk { 34430edc14bSKonrad Rzeszutek Wilk .offset = PCI_LATENCY_TIMER, 34530edc14bSKonrad Rzeszutek Wilk .size = 1, 346a92336a1SKonrad Rzeszutek Wilk .u.b.read = xen_pcibk_read_config_byte, 34730edc14bSKonrad Rzeszutek Wilk }, 34830edc14bSKonrad Rzeszutek Wilk { 34930edc14bSKonrad Rzeszutek Wilk .offset = PCI_BIST, 35030edc14bSKonrad Rzeszutek Wilk .size = 1, 351a92336a1SKonrad Rzeszutek Wilk .u.b.read = xen_pcibk_read_config_byte, 35230edc14bSKonrad Rzeszutek Wilk .u.b.write = bist_write, 35330edc14bSKonrad Rzeszutek Wilk }, 35430edc14bSKonrad Rzeszutek Wilk {} 35530edc14bSKonrad Rzeszutek Wilk }; 35630edc14bSKonrad Rzeszutek Wilk 35730edc14bSKonrad Rzeszutek Wilk #define CFG_FIELD_BAR(reg_offset) \ 35830edc14bSKonrad Rzeszutek Wilk { \ 35930edc14bSKonrad Rzeszutek Wilk .offset = reg_offset, \ 36030edc14bSKonrad Rzeszutek Wilk .size = 4, \ 36130edc14bSKonrad Rzeszutek Wilk .init = bar_init, \ 36230edc14bSKonrad Rzeszutek Wilk .reset = bar_reset, \ 36330edc14bSKonrad Rzeszutek Wilk .release = bar_release, \ 36430edc14bSKonrad Rzeszutek Wilk .u.dw.read = bar_read, \ 36530edc14bSKonrad Rzeszutek Wilk .u.dw.write = bar_write, \ 36630edc14bSKonrad Rzeszutek Wilk } 36730edc14bSKonrad Rzeszutek Wilk 36830edc14bSKonrad Rzeszutek Wilk #define CFG_FIELD_ROM(reg_offset) \ 36930edc14bSKonrad Rzeszutek Wilk { \ 37030edc14bSKonrad Rzeszutek Wilk .offset = reg_offset, \ 37130edc14bSKonrad Rzeszutek Wilk .size = 4, \ 372664093bbSJan Beulich .init = bar_init, \ 37330edc14bSKonrad Rzeszutek Wilk .reset = bar_reset, \ 37430edc14bSKonrad Rzeszutek Wilk .release = bar_release, \ 37530edc14bSKonrad Rzeszutek Wilk .u.dw.read = bar_read, \ 37630edc14bSKonrad Rzeszutek Wilk .u.dw.write = rom_write, \ 37730edc14bSKonrad Rzeszutek Wilk } 37830edc14bSKonrad Rzeszutek Wilk 37930edc14bSKonrad Rzeszutek Wilk static const struct config_field header_0[] = { 38030edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_0), 38130edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_1), 38230edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_2), 38330edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_3), 38430edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_4), 38530edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_5), 38630edc14bSKonrad Rzeszutek Wilk CFG_FIELD_ROM(PCI_ROM_ADDRESS), 38730edc14bSKonrad Rzeszutek Wilk {} 38830edc14bSKonrad Rzeszutek Wilk }; 38930edc14bSKonrad Rzeszutek Wilk 39030edc14bSKonrad Rzeszutek Wilk static const struct config_field header_1[] = { 39130edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_0), 39230edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_1), 39330edc14bSKonrad Rzeszutek Wilk CFG_FIELD_ROM(PCI_ROM_ADDRESS1), 39430edc14bSKonrad Rzeszutek Wilk {} 39530edc14bSKonrad Rzeszutek Wilk }; 39630edc14bSKonrad Rzeszutek Wilk 397a92336a1SKonrad Rzeszutek Wilk int xen_pcibk_config_header_add_fields(struct pci_dev *dev) 39830edc14bSKonrad Rzeszutek Wilk { 39930edc14bSKonrad Rzeszutek Wilk int err; 40030edc14bSKonrad Rzeszutek Wilk 401a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_config_add_fields(dev, header_common); 40230edc14bSKonrad Rzeszutek Wilk if (err) 40330edc14bSKonrad Rzeszutek Wilk goto out; 40430edc14bSKonrad Rzeszutek Wilk 40530edc14bSKonrad Rzeszutek Wilk switch (dev->hdr_type) { 40630edc14bSKonrad Rzeszutek Wilk case PCI_HEADER_TYPE_NORMAL: 407a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_config_add_fields(dev, header_0); 40830edc14bSKonrad Rzeszutek Wilk break; 40930edc14bSKonrad Rzeszutek Wilk 41030edc14bSKonrad Rzeszutek Wilk case PCI_HEADER_TYPE_BRIDGE: 411a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_config_add_fields(dev, header_1); 41230edc14bSKonrad Rzeszutek Wilk break; 41330edc14bSKonrad Rzeszutek Wilk 41430edc14bSKonrad Rzeszutek Wilk default: 41530edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 416283c0972SJoe Perches pr_err("%s: Unsupported header type %d!\n", 41730edc14bSKonrad Rzeszutek Wilk pci_name(dev), dev->hdr_type); 41830edc14bSKonrad Rzeszutek Wilk break; 41930edc14bSKonrad Rzeszutek Wilk } 42030edc14bSKonrad Rzeszutek Wilk 42130edc14bSKonrad Rzeszutek Wilk out: 42230edc14bSKonrad Rzeszutek Wilk return err; 42330edc14bSKonrad Rzeszutek Wilk } 424