xref: /openbmc/linux/drivers/xen/xen-pciback/conf_space_header.c (revision a92336a1176b2119eaa990a1e8bf3109665fdbc6)
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 
730edc14bSKonrad Rzeszutek Wilk #include <linux/kernel.h>
830edc14bSKonrad Rzeszutek Wilk #include <linux/pci.h>
930edc14bSKonrad Rzeszutek Wilk #include "pciback.h"
1030edc14bSKonrad Rzeszutek Wilk #include "conf_space.h"
1130edc14bSKonrad Rzeszutek Wilk 
1230edc14bSKonrad Rzeszutek Wilk struct pci_bar_info {
1330edc14bSKonrad Rzeszutek Wilk 	u32 val;
1430edc14bSKonrad Rzeszutek Wilk 	u32 len_val;
1530edc14bSKonrad Rzeszutek Wilk 	int which;
1630edc14bSKonrad Rzeszutek Wilk };
1730edc14bSKonrad Rzeszutek Wilk 
18*a92336a1SKonrad Rzeszutek Wilk #define DRV_NAME	"xen-pciback"
1930edc14bSKonrad Rzeszutek Wilk #define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
2030edc14bSKonrad Rzeszutek Wilk #define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
2130edc14bSKonrad Rzeszutek Wilk 
22fd5b221bSZhao, Yu static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
23fd5b221bSZhao, Yu {
24fd5b221bSZhao, Yu 	int i;
25fd5b221bSZhao, Yu 	int ret;
26fd5b221bSZhao, Yu 
27*a92336a1SKonrad Rzeszutek Wilk 	ret = xen_pcibk_read_config_word(dev, offset, value, data);
28fd5b221bSZhao, Yu 	if (!atomic_read(&dev->enable_cnt))
29fd5b221bSZhao, Yu 		return ret;
30fd5b221bSZhao, Yu 
31fd5b221bSZhao, Yu 	for (i = 0; i < PCI_ROM_RESOURCE; i++) {
32fd5b221bSZhao, Yu 		if (dev->resource[i].flags & IORESOURCE_IO)
33fd5b221bSZhao, Yu 			*value |= PCI_COMMAND_IO;
34fd5b221bSZhao, Yu 		if (dev->resource[i].flags & IORESOURCE_MEM)
35fd5b221bSZhao, Yu 			*value |= PCI_COMMAND_MEMORY;
36fd5b221bSZhao, Yu 	}
37fd5b221bSZhao, Yu 
38fd5b221bSZhao, Yu 	return ret;
39fd5b221bSZhao, Yu }
40fd5b221bSZhao, Yu 
4130edc14bSKonrad Rzeszutek Wilk static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
4230edc14bSKonrad Rzeszutek Wilk {
43*a92336a1SKonrad Rzeszutek Wilk 	struct xen_pcibk_dev_data *dev_data;
4430edc14bSKonrad Rzeszutek Wilk 	int err;
4530edc14bSKonrad Rzeszutek Wilk 
460513fe9eSKonrad Rzeszutek Wilk 	dev_data = pci_get_drvdata(dev);
4730edc14bSKonrad Rzeszutek Wilk 	if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
4830edc14bSKonrad Rzeszutek Wilk 		if (unlikely(verbose_request))
49*a92336a1SKonrad Rzeszutek Wilk 			printk(KERN_DEBUG DRV_NAME ": %s: enable\n",
5030edc14bSKonrad Rzeszutek Wilk 			       pci_name(dev));
5130edc14bSKonrad Rzeszutek Wilk 		err = pci_enable_device(dev);
5230edc14bSKonrad Rzeszutek Wilk 		if (err)
5330edc14bSKonrad Rzeszutek Wilk 			return err;
540513fe9eSKonrad Rzeszutek Wilk 		if (dev_data)
550513fe9eSKonrad Rzeszutek Wilk 			dev_data->enable_intx = 1;
5630edc14bSKonrad Rzeszutek Wilk 	} else if (pci_is_enabled(dev) && !is_enable_cmd(value)) {
5730edc14bSKonrad Rzeszutek Wilk 		if (unlikely(verbose_request))
58*a92336a1SKonrad Rzeszutek Wilk 			printk(KERN_DEBUG DRV_NAME ": %s: disable\n",
5930edc14bSKonrad Rzeszutek Wilk 			       pci_name(dev));
6030edc14bSKonrad Rzeszutek Wilk 		pci_disable_device(dev);
610513fe9eSKonrad Rzeszutek Wilk 		if (dev_data)
620513fe9eSKonrad Rzeszutek Wilk 			dev_data->enable_intx = 0;
6330edc14bSKonrad Rzeszutek Wilk 	}
6430edc14bSKonrad Rzeszutek Wilk 
6530edc14bSKonrad Rzeszutek Wilk 	if (!dev->is_busmaster && is_master_cmd(value)) {
6630edc14bSKonrad Rzeszutek Wilk 		if (unlikely(verbose_request))
67*a92336a1SKonrad Rzeszutek Wilk 			printk(KERN_DEBUG DRV_NAME ": %s: set bus master\n",
6830edc14bSKonrad Rzeszutek Wilk 			       pci_name(dev));
6930edc14bSKonrad Rzeszutek Wilk 		pci_set_master(dev);
7030edc14bSKonrad Rzeszutek Wilk 	}
7130edc14bSKonrad Rzeszutek Wilk 
7230edc14bSKonrad Rzeszutek Wilk 	if (value & PCI_COMMAND_INVALIDATE) {
7330edc14bSKonrad Rzeszutek Wilk 		if (unlikely(verbose_request))
7430edc14bSKonrad Rzeszutek Wilk 			printk(KERN_DEBUG
75*a92336a1SKonrad Rzeszutek Wilk 			       DRV_NAME ": %s: enable memory-write-invalidate\n",
7630edc14bSKonrad Rzeszutek Wilk 			       pci_name(dev));
7730edc14bSKonrad Rzeszutek Wilk 		err = pci_set_mwi(dev);
7830edc14bSKonrad Rzeszutek Wilk 		if (err) {
7930edc14bSKonrad Rzeszutek Wilk 			printk(KERN_WARNING
80*a92336a1SKonrad Rzeszutek Wilk 			       DRV_NAME ": %s: cannot enable "
8130edc14bSKonrad Rzeszutek Wilk 			       "memory-write-invalidate (%d)\n",
8230edc14bSKonrad Rzeszutek Wilk 			       pci_name(dev), err);
8330edc14bSKonrad Rzeszutek Wilk 			value &= ~PCI_COMMAND_INVALIDATE;
8430edc14bSKonrad Rzeszutek Wilk 		}
8530edc14bSKonrad Rzeszutek Wilk 	}
8630edc14bSKonrad Rzeszutek Wilk 
8730edc14bSKonrad Rzeszutek Wilk 	return pci_write_config_word(dev, offset, value);
8830edc14bSKonrad Rzeszutek Wilk }
8930edc14bSKonrad Rzeszutek Wilk 
9030edc14bSKonrad Rzeszutek Wilk static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
9130edc14bSKonrad Rzeszutek Wilk {
9230edc14bSKonrad Rzeszutek Wilk 	struct pci_bar_info *bar = data;
9330edc14bSKonrad Rzeszutek Wilk 
9430edc14bSKonrad Rzeszutek Wilk 	if (unlikely(!bar)) {
95*a92336a1SKonrad Rzeszutek Wilk 		printk(KERN_WARNING DRV_NAME ": driver data not found for %s\n",
9630edc14bSKonrad Rzeszutek Wilk 		       pci_name(dev));
9730edc14bSKonrad Rzeszutek Wilk 		return XEN_PCI_ERR_op_failed;
9830edc14bSKonrad Rzeszutek Wilk 	}
9930edc14bSKonrad Rzeszutek Wilk 
10030edc14bSKonrad Rzeszutek Wilk 	/* A write to obtain the length must happen as a 32-bit write.
10130edc14bSKonrad Rzeszutek Wilk 	 * This does not (yet) support writing individual bytes
10230edc14bSKonrad Rzeszutek Wilk 	 */
10330edc14bSKonrad Rzeszutek Wilk 	if (value == ~PCI_ROM_ADDRESS_ENABLE)
10430edc14bSKonrad Rzeszutek Wilk 		bar->which = 1;
10530edc14bSKonrad Rzeszutek Wilk 	else {
10630edc14bSKonrad Rzeszutek Wilk 		u32 tmpval;
10730edc14bSKonrad Rzeszutek Wilk 		pci_read_config_dword(dev, offset, &tmpval);
10830edc14bSKonrad Rzeszutek Wilk 		if (tmpval != bar->val && value == bar->val) {
10930edc14bSKonrad Rzeszutek Wilk 			/* Allow restoration of bar value. */
11030edc14bSKonrad Rzeszutek Wilk 			pci_write_config_dword(dev, offset, bar->val);
11130edc14bSKonrad Rzeszutek Wilk 		}
11230edc14bSKonrad Rzeszutek Wilk 		bar->which = 0;
11330edc14bSKonrad Rzeszutek Wilk 	}
11430edc14bSKonrad Rzeszutek Wilk 
11530edc14bSKonrad Rzeszutek Wilk 	/* Do we need to support enabling/disabling the rom address here? */
11630edc14bSKonrad Rzeszutek Wilk 
11730edc14bSKonrad Rzeszutek Wilk 	return 0;
11830edc14bSKonrad Rzeszutek Wilk }
11930edc14bSKonrad Rzeszutek Wilk 
12030edc14bSKonrad Rzeszutek Wilk /* For the BARs, only allow writes which write ~0 or
12130edc14bSKonrad Rzeszutek Wilk  * the correct resource information
12230edc14bSKonrad Rzeszutek Wilk  * (Needed for when the driver probes the resource usage)
12330edc14bSKonrad Rzeszutek Wilk  */
12430edc14bSKonrad Rzeszutek Wilk static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
12530edc14bSKonrad Rzeszutek Wilk {
12630edc14bSKonrad Rzeszutek Wilk 	struct pci_bar_info *bar = data;
12730edc14bSKonrad Rzeszutek Wilk 
12830edc14bSKonrad Rzeszutek Wilk 	if (unlikely(!bar)) {
129*a92336a1SKonrad Rzeszutek Wilk 		printk(KERN_WARNING DRV_NAME ": driver data not found for %s\n",
13030edc14bSKonrad Rzeszutek Wilk 		       pci_name(dev));
13130edc14bSKonrad Rzeszutek Wilk 		return XEN_PCI_ERR_op_failed;
13230edc14bSKonrad Rzeszutek Wilk 	}
13330edc14bSKonrad Rzeszutek Wilk 
13430edc14bSKonrad Rzeszutek Wilk 	/* A write to obtain the length must happen as a 32-bit write.
13530edc14bSKonrad Rzeszutek Wilk 	 * This does not (yet) support writing individual bytes
13630edc14bSKonrad Rzeszutek Wilk 	 */
13730edc14bSKonrad Rzeszutek Wilk 	if (value == ~0)
13830edc14bSKonrad Rzeszutek Wilk 		bar->which = 1;
13930edc14bSKonrad Rzeszutek Wilk 	else {
14030edc14bSKonrad Rzeszutek Wilk 		u32 tmpval;
14130edc14bSKonrad Rzeszutek Wilk 		pci_read_config_dword(dev, offset, &tmpval);
14230edc14bSKonrad Rzeszutek Wilk 		if (tmpval != bar->val && value == bar->val) {
14330edc14bSKonrad Rzeszutek Wilk 			/* Allow restoration of bar value. */
14430edc14bSKonrad Rzeszutek Wilk 			pci_write_config_dword(dev, offset, bar->val);
14530edc14bSKonrad Rzeszutek Wilk 		}
14630edc14bSKonrad Rzeszutek Wilk 		bar->which = 0;
14730edc14bSKonrad Rzeszutek Wilk 	}
14830edc14bSKonrad Rzeszutek Wilk 
14930edc14bSKonrad Rzeszutek Wilk 	return 0;
15030edc14bSKonrad Rzeszutek Wilk }
15130edc14bSKonrad Rzeszutek Wilk 
15230edc14bSKonrad Rzeszutek Wilk static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
15330edc14bSKonrad Rzeszutek Wilk {
15430edc14bSKonrad Rzeszutek Wilk 	struct pci_bar_info *bar = data;
15530edc14bSKonrad Rzeszutek Wilk 
15630edc14bSKonrad Rzeszutek Wilk 	if (unlikely(!bar)) {
157*a92336a1SKonrad Rzeszutek Wilk 		printk(KERN_WARNING DRV_NAME ": driver data not found for %s\n",
15830edc14bSKonrad Rzeszutek Wilk 		       pci_name(dev));
15930edc14bSKonrad Rzeszutek Wilk 		return XEN_PCI_ERR_op_failed;
16030edc14bSKonrad Rzeszutek Wilk 	}
16130edc14bSKonrad Rzeszutek Wilk 
16230edc14bSKonrad Rzeszutek Wilk 	*value = bar->which ? bar->len_val : bar->val;
16330edc14bSKonrad Rzeszutek Wilk 
16430edc14bSKonrad Rzeszutek Wilk 	return 0;
16530edc14bSKonrad Rzeszutek Wilk }
16630edc14bSKonrad Rzeszutek Wilk 
16730edc14bSKonrad Rzeszutek Wilk static inline void read_dev_bar(struct pci_dev *dev,
16830edc14bSKonrad Rzeszutek Wilk 				struct pci_bar_info *bar_info, int offset,
16930edc14bSKonrad Rzeszutek Wilk 				u32 len_mask)
17030edc14bSKonrad Rzeszutek Wilk {
171fd5b221bSZhao, Yu 	int	pos;
172fd5b221bSZhao, Yu 	struct resource	*res = dev->resource;
173fd5b221bSZhao, Yu 
174fd5b221bSZhao, Yu 	if (offset == PCI_ROM_ADDRESS || offset == PCI_ROM_ADDRESS1)
175fd5b221bSZhao, Yu 		pos = PCI_ROM_RESOURCE;
176fd5b221bSZhao, Yu 	else {
177fd5b221bSZhao, Yu 		pos = (offset - PCI_BASE_ADDRESS_0) / 4;
178fd5b221bSZhao, Yu 		if (pos && ((res[pos - 1].flags & (PCI_BASE_ADDRESS_SPACE |
179fd5b221bSZhao, Yu 				PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
180fd5b221bSZhao, Yu 			   (PCI_BASE_ADDRESS_SPACE_MEMORY |
181fd5b221bSZhao, Yu 				PCI_BASE_ADDRESS_MEM_TYPE_64))) {
182fd5b221bSZhao, Yu 			bar_info->val = res[pos - 1].start >> 32;
183fd5b221bSZhao, Yu 			bar_info->len_val = res[pos - 1].end >> 32;
184fd5b221bSZhao, Yu 			return;
185fd5b221bSZhao, Yu 		}
186fd5b221bSZhao, Yu 	}
187fd5b221bSZhao, Yu 
188fd5b221bSZhao, Yu 	bar_info->val = res[pos].start |
189fd5b221bSZhao, Yu 			(res[pos].flags & PCI_REGION_FLAG_MASK);
190fd5b221bSZhao, Yu 	bar_info->len_val = res[pos].end - res[pos].start + 1;
19130edc14bSKonrad Rzeszutek Wilk }
19230edc14bSKonrad Rzeszutek Wilk 
19330edc14bSKonrad Rzeszutek Wilk static void *bar_init(struct pci_dev *dev, int offset)
19430edc14bSKonrad Rzeszutek Wilk {
19530edc14bSKonrad Rzeszutek Wilk 	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
19630edc14bSKonrad Rzeszutek Wilk 
19730edc14bSKonrad Rzeszutek Wilk 	if (!bar)
19830edc14bSKonrad Rzeszutek Wilk 		return ERR_PTR(-ENOMEM);
19930edc14bSKonrad Rzeszutek Wilk 
20030edc14bSKonrad Rzeszutek Wilk 	read_dev_bar(dev, bar, offset, ~0);
20130edc14bSKonrad Rzeszutek Wilk 	bar->which = 0;
20230edc14bSKonrad Rzeszutek Wilk 
20330edc14bSKonrad Rzeszutek Wilk 	return bar;
20430edc14bSKonrad Rzeszutek Wilk }
20530edc14bSKonrad Rzeszutek Wilk 
20630edc14bSKonrad Rzeszutek Wilk static void *rom_init(struct pci_dev *dev, int offset)
20730edc14bSKonrad Rzeszutek Wilk {
20830edc14bSKonrad Rzeszutek Wilk 	struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
20930edc14bSKonrad Rzeszutek Wilk 
21030edc14bSKonrad Rzeszutek Wilk 	if (!bar)
21130edc14bSKonrad Rzeszutek Wilk 		return ERR_PTR(-ENOMEM);
21230edc14bSKonrad Rzeszutek Wilk 
21330edc14bSKonrad Rzeszutek Wilk 	read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);
21430edc14bSKonrad Rzeszutek Wilk 	bar->which = 0;
21530edc14bSKonrad Rzeszutek Wilk 
21630edc14bSKonrad Rzeszutek Wilk 	return bar;
21730edc14bSKonrad Rzeszutek Wilk }
21830edc14bSKonrad Rzeszutek Wilk 
21930edc14bSKonrad Rzeszutek Wilk static void bar_reset(struct pci_dev *dev, int offset, void *data)
22030edc14bSKonrad Rzeszutek Wilk {
22130edc14bSKonrad Rzeszutek Wilk 	struct pci_bar_info *bar = data;
22230edc14bSKonrad Rzeszutek Wilk 
22330edc14bSKonrad Rzeszutek Wilk 	bar->which = 0;
22430edc14bSKonrad Rzeszutek Wilk }
22530edc14bSKonrad Rzeszutek Wilk 
22630edc14bSKonrad Rzeszutek Wilk static void bar_release(struct pci_dev *dev, int offset, void *data)
22730edc14bSKonrad Rzeszutek Wilk {
22830edc14bSKonrad Rzeszutek Wilk 	kfree(data);
22930edc14bSKonrad Rzeszutek Wilk }
23030edc14bSKonrad Rzeszutek Wilk 
231*a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_read_vendor(struct pci_dev *dev, int offset,
232fd5b221bSZhao, Yu 			       u16 *value, void *data)
233fd5b221bSZhao, Yu {
234fd5b221bSZhao, Yu 	*value = dev->vendor;
235fd5b221bSZhao, Yu 
236fd5b221bSZhao, Yu 	return 0;
237fd5b221bSZhao, Yu }
238fd5b221bSZhao, Yu 
239*a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_read_device(struct pci_dev *dev, int offset,
240fd5b221bSZhao, Yu 			       u16 *value, void *data)
241fd5b221bSZhao, Yu {
242fd5b221bSZhao, Yu 	*value = dev->device;
243fd5b221bSZhao, Yu 
244fd5b221bSZhao, Yu 	return 0;
245fd5b221bSZhao, Yu }
246fd5b221bSZhao, Yu 
24730edc14bSKonrad Rzeszutek Wilk static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
24830edc14bSKonrad Rzeszutek Wilk 			  void *data)
24930edc14bSKonrad Rzeszutek Wilk {
25030edc14bSKonrad Rzeszutek Wilk 	*value = (u8) dev->irq;
25130edc14bSKonrad Rzeszutek Wilk 
25230edc14bSKonrad Rzeszutek Wilk 	return 0;
25330edc14bSKonrad Rzeszutek Wilk }
25430edc14bSKonrad Rzeszutek Wilk 
25530edc14bSKonrad Rzeszutek Wilk static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data)
25630edc14bSKonrad Rzeszutek Wilk {
25730edc14bSKonrad Rzeszutek Wilk 	u8 cur_value;
25830edc14bSKonrad Rzeszutek Wilk 	int err;
25930edc14bSKonrad Rzeszutek Wilk 
26030edc14bSKonrad Rzeszutek Wilk 	err = pci_read_config_byte(dev, offset, &cur_value);
26130edc14bSKonrad Rzeszutek Wilk 	if (err)
26230edc14bSKonrad Rzeszutek Wilk 		goto out;
26330edc14bSKonrad Rzeszutek Wilk 
26430edc14bSKonrad Rzeszutek Wilk 	if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START)
26530edc14bSKonrad Rzeszutek Wilk 	    || value == PCI_BIST_START)
26630edc14bSKonrad Rzeszutek Wilk 		err = pci_write_config_byte(dev, offset, value);
26730edc14bSKonrad Rzeszutek Wilk 
26830edc14bSKonrad Rzeszutek Wilk out:
26930edc14bSKonrad Rzeszutek Wilk 	return err;
27030edc14bSKonrad Rzeszutek Wilk }
27130edc14bSKonrad Rzeszutek Wilk 
27230edc14bSKonrad Rzeszutek Wilk static const struct config_field header_common[] = {
27330edc14bSKonrad Rzeszutek Wilk 	{
274fd5b221bSZhao, Yu 	 .offset    = PCI_VENDOR_ID,
275fd5b221bSZhao, Yu 	 .size      = 2,
276*a92336a1SKonrad Rzeszutek Wilk 	 .u.w.read  = xen_pcibk_read_vendor,
277fd5b221bSZhao, Yu 	},
278fd5b221bSZhao, Yu 	{
279fd5b221bSZhao, Yu 	 .offset    = PCI_DEVICE_ID,
280fd5b221bSZhao, Yu 	 .size      = 2,
281*a92336a1SKonrad Rzeszutek Wilk 	 .u.w.read  = xen_pcibk_read_device,
282fd5b221bSZhao, Yu 	},
283fd5b221bSZhao, Yu 	{
28430edc14bSKonrad Rzeszutek Wilk 	 .offset    = PCI_COMMAND,
28530edc14bSKonrad Rzeszutek Wilk 	 .size      = 2,
286fd5b221bSZhao, Yu 	 .u.w.read  = command_read,
28730edc14bSKonrad Rzeszutek Wilk 	 .u.w.write = command_write,
28830edc14bSKonrad Rzeszutek Wilk 	},
28930edc14bSKonrad Rzeszutek Wilk 	{
29030edc14bSKonrad Rzeszutek Wilk 	 .offset    = PCI_INTERRUPT_LINE,
29130edc14bSKonrad Rzeszutek Wilk 	 .size      = 1,
29230edc14bSKonrad Rzeszutek Wilk 	 .u.b.read  = interrupt_read,
29330edc14bSKonrad Rzeszutek Wilk 	},
29430edc14bSKonrad Rzeszutek Wilk 	{
29530edc14bSKonrad Rzeszutek Wilk 	 .offset    = PCI_INTERRUPT_PIN,
29630edc14bSKonrad Rzeszutek Wilk 	 .size      = 1,
297*a92336a1SKonrad Rzeszutek Wilk 	 .u.b.read  = xen_pcibk_read_config_byte,
29830edc14bSKonrad Rzeszutek Wilk 	},
29930edc14bSKonrad Rzeszutek Wilk 	{
30030edc14bSKonrad Rzeszutek Wilk 	 /* Any side effects of letting driver domain control cache line? */
30130edc14bSKonrad Rzeszutek Wilk 	 .offset    = PCI_CACHE_LINE_SIZE,
30230edc14bSKonrad Rzeszutek Wilk 	 .size      = 1,
303*a92336a1SKonrad Rzeszutek Wilk 	 .u.b.read  = xen_pcibk_read_config_byte,
304*a92336a1SKonrad Rzeszutek Wilk 	 .u.b.write = xen_pcibk_write_config_byte,
30530edc14bSKonrad Rzeszutek Wilk 	},
30630edc14bSKonrad Rzeszutek Wilk 	{
30730edc14bSKonrad Rzeszutek Wilk 	 .offset    = PCI_LATENCY_TIMER,
30830edc14bSKonrad Rzeszutek Wilk 	 .size      = 1,
309*a92336a1SKonrad Rzeszutek Wilk 	 .u.b.read  = xen_pcibk_read_config_byte,
31030edc14bSKonrad Rzeszutek Wilk 	},
31130edc14bSKonrad Rzeszutek Wilk 	{
31230edc14bSKonrad Rzeszutek Wilk 	 .offset    = PCI_BIST,
31330edc14bSKonrad Rzeszutek Wilk 	 .size      = 1,
314*a92336a1SKonrad Rzeszutek Wilk 	 .u.b.read  = xen_pcibk_read_config_byte,
31530edc14bSKonrad Rzeszutek Wilk 	 .u.b.write = bist_write,
31630edc14bSKonrad Rzeszutek Wilk 	},
31730edc14bSKonrad Rzeszutek Wilk 	{}
31830edc14bSKonrad Rzeszutek Wilk };
31930edc14bSKonrad Rzeszutek Wilk 
32030edc14bSKonrad Rzeszutek Wilk #define CFG_FIELD_BAR(reg_offset)			\
32130edc14bSKonrad Rzeszutek Wilk 	{						\
32230edc14bSKonrad Rzeszutek Wilk 	.offset     = reg_offset,			\
32330edc14bSKonrad Rzeszutek Wilk 	.size       = 4,				\
32430edc14bSKonrad Rzeszutek Wilk 	.init       = bar_init,				\
32530edc14bSKonrad Rzeszutek Wilk 	.reset      = bar_reset,			\
32630edc14bSKonrad Rzeszutek Wilk 	.release    = bar_release,			\
32730edc14bSKonrad Rzeszutek Wilk 	.u.dw.read  = bar_read,				\
32830edc14bSKonrad Rzeszutek Wilk 	.u.dw.write = bar_write,			\
32930edc14bSKonrad Rzeszutek Wilk 	}
33030edc14bSKonrad Rzeszutek Wilk 
33130edc14bSKonrad Rzeszutek Wilk #define CFG_FIELD_ROM(reg_offset)			\
33230edc14bSKonrad Rzeszutek Wilk 	{						\
33330edc14bSKonrad Rzeszutek Wilk 	.offset     = reg_offset,			\
33430edc14bSKonrad Rzeszutek Wilk 	.size       = 4,				\
33530edc14bSKonrad Rzeszutek Wilk 	.init       = rom_init,				\
33630edc14bSKonrad Rzeszutek Wilk 	.reset      = bar_reset,			\
33730edc14bSKonrad Rzeszutek Wilk 	.release    = bar_release,			\
33830edc14bSKonrad Rzeszutek Wilk 	.u.dw.read  = bar_read,				\
33930edc14bSKonrad Rzeszutek Wilk 	.u.dw.write = rom_write,			\
34030edc14bSKonrad Rzeszutek Wilk 	}
34130edc14bSKonrad Rzeszutek Wilk 
34230edc14bSKonrad Rzeszutek Wilk static const struct config_field header_0[] = {
34330edc14bSKonrad Rzeszutek Wilk 	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
34430edc14bSKonrad Rzeszutek Wilk 	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
34530edc14bSKonrad Rzeszutek Wilk 	CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
34630edc14bSKonrad Rzeszutek Wilk 	CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
34730edc14bSKonrad Rzeszutek Wilk 	CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
34830edc14bSKonrad Rzeszutek Wilk 	CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
34930edc14bSKonrad Rzeszutek Wilk 	CFG_FIELD_ROM(PCI_ROM_ADDRESS),
35030edc14bSKonrad Rzeszutek Wilk 	{}
35130edc14bSKonrad Rzeszutek Wilk };
35230edc14bSKonrad Rzeszutek Wilk 
35330edc14bSKonrad Rzeszutek Wilk static const struct config_field header_1[] = {
35430edc14bSKonrad Rzeszutek Wilk 	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
35530edc14bSKonrad Rzeszutek Wilk 	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
35630edc14bSKonrad Rzeszutek Wilk 	CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
35730edc14bSKonrad Rzeszutek Wilk 	{}
35830edc14bSKonrad Rzeszutek Wilk };
35930edc14bSKonrad Rzeszutek Wilk 
360*a92336a1SKonrad Rzeszutek Wilk int xen_pcibk_config_header_add_fields(struct pci_dev *dev)
36130edc14bSKonrad Rzeszutek Wilk {
36230edc14bSKonrad Rzeszutek Wilk 	int err;
36330edc14bSKonrad Rzeszutek Wilk 
364*a92336a1SKonrad Rzeszutek Wilk 	err = xen_pcibk_config_add_fields(dev, header_common);
36530edc14bSKonrad Rzeszutek Wilk 	if (err)
36630edc14bSKonrad Rzeszutek Wilk 		goto out;
36730edc14bSKonrad Rzeszutek Wilk 
36830edc14bSKonrad Rzeszutek Wilk 	switch (dev->hdr_type) {
36930edc14bSKonrad Rzeszutek Wilk 	case PCI_HEADER_TYPE_NORMAL:
370*a92336a1SKonrad Rzeszutek Wilk 		err = xen_pcibk_config_add_fields(dev, header_0);
37130edc14bSKonrad Rzeszutek Wilk 		break;
37230edc14bSKonrad Rzeszutek Wilk 
37330edc14bSKonrad Rzeszutek Wilk 	case PCI_HEADER_TYPE_BRIDGE:
374*a92336a1SKonrad Rzeszutek Wilk 		err = xen_pcibk_config_add_fields(dev, header_1);
37530edc14bSKonrad Rzeszutek Wilk 		break;
37630edc14bSKonrad Rzeszutek Wilk 
37730edc14bSKonrad Rzeszutek Wilk 	default:
37830edc14bSKonrad Rzeszutek Wilk 		err = -EINVAL;
379*a92336a1SKonrad Rzeszutek Wilk 		printk(KERN_ERR DRV_NAME ": %s: Unsupported header type %d!\n",
38030edc14bSKonrad Rzeszutek Wilk 		       pci_name(dev), dev->hdr_type);
38130edc14bSKonrad Rzeszutek Wilk 		break;
38230edc14bSKonrad Rzeszutek Wilk 	}
38330edc14bSKonrad Rzeszutek Wilk 
38430edc14bSKonrad Rzeszutek Wilk out:
38530edc14bSKonrad Rzeszutek Wilk 	return err;
38630edc14bSKonrad Rzeszutek Wilk }
387