xref: /openbmc/linux/drivers/xen/xen-pciback/conf_space_header.c (revision af6fc858a35b90e89ea7a7ee58e66628c55c776b)
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