162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PCI Backend - Handles the virtual fields in the configuration space headers.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
962306a36Sopenharmony_ci#define dev_fmt pr_fmt
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/pci.h>
1362306a36Sopenharmony_ci#include "pciback.h"
1462306a36Sopenharmony_ci#include "conf_space.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistruct pci_cmd_info {
1762306a36Sopenharmony_ci	u16 val;
1862306a36Sopenharmony_ci};
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistruct pci_bar_info {
2162306a36Sopenharmony_ci	u32 val;
2262306a36Sopenharmony_ci	u32 len_val;
2362306a36Sopenharmony_ci	int which;
2462306a36Sopenharmony_ci};
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
2762306a36Sopenharmony_ci#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/* Bits guests are allowed to control in permissive mode. */
3062306a36Sopenharmony_ci#define PCI_COMMAND_GUEST (PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL| \
3162306a36Sopenharmony_ci			   PCI_COMMAND_INVALIDATE|PCI_COMMAND_VGA_PALETTE| \
3262306a36Sopenharmony_ci			   PCI_COMMAND_WAIT|PCI_COMMAND_FAST_BACK)
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic void *command_init(struct pci_dev *dev, int offset)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
3762306a36Sopenharmony_ci	int err;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	if (!cmd)
4062306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val);
4362306a36Sopenharmony_ci	if (err) {
4462306a36Sopenharmony_ci		kfree(cmd);
4562306a36Sopenharmony_ci		return ERR_PTR(err);
4662306a36Sopenharmony_ci	}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	return cmd;
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	int ret = pci_read_config_word(dev, offset, value);
5462306a36Sopenharmony_ci	const struct pci_cmd_info *cmd = data;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	*value &= PCI_COMMAND_GUEST;
5762306a36Sopenharmony_ci	*value |= cmd->val & ~PCI_COMMAND_GUEST;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	return ret;
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct xen_pcibk_dev_data *dev_data;
6562306a36Sopenharmony_ci	int err;
6662306a36Sopenharmony_ci	u16 val;
6762306a36Sopenharmony_ci	struct pci_cmd_info *cmd = data;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	dev_data = pci_get_drvdata(dev);
7062306a36Sopenharmony_ci	if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
7162306a36Sopenharmony_ci		dev_dbg(&dev->dev, "enable\n");
7262306a36Sopenharmony_ci		err = pci_enable_device(dev);
7362306a36Sopenharmony_ci		if (err)
7462306a36Sopenharmony_ci			return err;
7562306a36Sopenharmony_ci		if (dev_data)
7662306a36Sopenharmony_ci			dev_data->enable_intx = 1;
7762306a36Sopenharmony_ci	} else if (pci_is_enabled(dev) && !is_enable_cmd(value)) {
7862306a36Sopenharmony_ci		dev_dbg(&dev->dev, "disable\n");
7962306a36Sopenharmony_ci		pci_disable_device(dev);
8062306a36Sopenharmony_ci		if (dev_data)
8162306a36Sopenharmony_ci			dev_data->enable_intx = 0;
8262306a36Sopenharmony_ci	}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	if (!dev->is_busmaster && is_master_cmd(value)) {
8562306a36Sopenharmony_ci		dev_dbg(&dev->dev, "set bus master\n");
8662306a36Sopenharmony_ci		pci_set_master(dev);
8762306a36Sopenharmony_ci	} else if (dev->is_busmaster && !is_master_cmd(value)) {
8862306a36Sopenharmony_ci		dev_dbg(&dev->dev, "clear bus master\n");
8962306a36Sopenharmony_ci		pci_clear_master(dev);
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	if (!(cmd->val & PCI_COMMAND_INVALIDATE) &&
9362306a36Sopenharmony_ci	    (value & PCI_COMMAND_INVALIDATE)) {
9462306a36Sopenharmony_ci		dev_dbg(&dev->dev, "enable memory-write-invalidate\n");
9562306a36Sopenharmony_ci		err = pci_set_mwi(dev);
9662306a36Sopenharmony_ci		if (err) {
9762306a36Sopenharmony_ci			dev_warn(&dev->dev, "cannot enable memory-write-invalidate (%d)\n",
9862306a36Sopenharmony_ci				err);
9962306a36Sopenharmony_ci			value &= ~PCI_COMMAND_INVALIDATE;
10062306a36Sopenharmony_ci		}
10162306a36Sopenharmony_ci	} else if ((cmd->val & PCI_COMMAND_INVALIDATE) &&
10262306a36Sopenharmony_ci		   !(value & PCI_COMMAND_INVALIDATE)) {
10362306a36Sopenharmony_ci		dev_dbg(&dev->dev, "disable memory-write-invalidate\n");
10462306a36Sopenharmony_ci		pci_clear_mwi(dev);
10562306a36Sopenharmony_ci	}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	if (dev_data && dev_data->allow_interrupt_control &&
10862306a36Sopenharmony_ci	    ((cmd->val ^ value) & PCI_COMMAND_INTX_DISABLE))
10962306a36Sopenharmony_ci		pci_intx(dev, !(value & PCI_COMMAND_INTX_DISABLE));
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	cmd->val = value;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	if (!xen_pcibk_permissive && (!dev_data || !dev_data->permissive))
11462306a36Sopenharmony_ci		return 0;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	/* Only allow the guest to control certain bits. */
11762306a36Sopenharmony_ci	err = pci_read_config_word(dev, offset, &val);
11862306a36Sopenharmony_ci	if (err || val == value)
11962306a36Sopenharmony_ci		return err;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	value &= PCI_COMMAND_GUEST;
12262306a36Sopenharmony_ci	value |= val & ~PCI_COMMAND_GUEST;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	return pci_write_config_word(dev, offset, value);
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	struct pci_bar_info *bar = data;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	if (unlikely(!bar)) {
13262306a36Sopenharmony_ci		dev_warn(&dev->dev, "driver data not found\n");
13362306a36Sopenharmony_ci		return XEN_PCI_ERR_op_failed;
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	/* A write to obtain the length must happen as a 32-bit write.
13762306a36Sopenharmony_ci	 * This does not (yet) support writing individual bytes
13862306a36Sopenharmony_ci	 */
13962306a36Sopenharmony_ci	if ((value | ~PCI_ROM_ADDRESS_MASK) == ~0U)
14062306a36Sopenharmony_ci		bar->which = 1;
14162306a36Sopenharmony_ci	else {
14262306a36Sopenharmony_ci		u32 tmpval;
14362306a36Sopenharmony_ci		pci_read_config_dword(dev, offset, &tmpval);
14462306a36Sopenharmony_ci		if (tmpval != bar->val && value == bar->val) {
14562306a36Sopenharmony_ci			/* Allow restoration of bar value. */
14662306a36Sopenharmony_ci			pci_write_config_dword(dev, offset, bar->val);
14762306a36Sopenharmony_ci		}
14862306a36Sopenharmony_ci		bar->which = 0;
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	/* Do we need to support enabling/disabling the rom address here? */
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	return 0;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/* For the BARs, only allow writes which write ~0 or
15762306a36Sopenharmony_ci * the correct resource information
15862306a36Sopenharmony_ci * (Needed for when the driver probes the resource usage)
15962306a36Sopenharmony_ci */
16062306a36Sopenharmony_cistatic int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct pci_bar_info *bar = data;
16362306a36Sopenharmony_ci	unsigned int pos = (offset - PCI_BASE_ADDRESS_0) / 4;
16462306a36Sopenharmony_ci	const struct resource *res = dev->resource;
16562306a36Sopenharmony_ci	u32 mask;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	if (unlikely(!bar)) {
16862306a36Sopenharmony_ci		dev_warn(&dev->dev, "driver data not found\n");
16962306a36Sopenharmony_ci		return XEN_PCI_ERR_op_failed;
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	/* A write to obtain the length must happen as a 32-bit write.
17362306a36Sopenharmony_ci	 * This does not (yet) support writing individual bytes
17462306a36Sopenharmony_ci	 */
17562306a36Sopenharmony_ci	if (res[pos].flags & IORESOURCE_IO)
17662306a36Sopenharmony_ci		mask = ~PCI_BASE_ADDRESS_IO_MASK;
17762306a36Sopenharmony_ci	else if (pos && (res[pos - 1].flags & IORESOURCE_MEM_64))
17862306a36Sopenharmony_ci		mask = 0;
17962306a36Sopenharmony_ci	else
18062306a36Sopenharmony_ci		mask = ~PCI_BASE_ADDRESS_MEM_MASK;
18162306a36Sopenharmony_ci	if ((value | mask) == ~0U)
18262306a36Sopenharmony_ci		bar->which = 1;
18362306a36Sopenharmony_ci	else {
18462306a36Sopenharmony_ci		u32 tmpval;
18562306a36Sopenharmony_ci		pci_read_config_dword(dev, offset, &tmpval);
18662306a36Sopenharmony_ci		if (tmpval != bar->val && value == bar->val) {
18762306a36Sopenharmony_ci			/* Allow restoration of bar value. */
18862306a36Sopenharmony_ci			pci_write_config_dword(dev, offset, bar->val);
18962306a36Sopenharmony_ci		}
19062306a36Sopenharmony_ci		bar->which = 0;
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	return 0;
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	struct pci_bar_info *bar = data;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	if (unlikely(!bar)) {
20162306a36Sopenharmony_ci		dev_warn(&dev->dev, "driver data not found\n");
20262306a36Sopenharmony_ci		return XEN_PCI_ERR_op_failed;
20362306a36Sopenharmony_ci	}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	*value = bar->which ? bar->len_val : bar->val;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	return 0;
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic void *bar_init(struct pci_dev *dev, int offset)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	unsigned int pos;
21362306a36Sopenharmony_ci	const struct resource *res = dev->resource;
21462306a36Sopenharmony_ci	struct pci_bar_info *bar = kzalloc(sizeof(*bar), GFP_KERNEL);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	if (!bar)
21762306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	if (offset == PCI_ROM_ADDRESS || offset == PCI_ROM_ADDRESS1)
22062306a36Sopenharmony_ci		pos = PCI_ROM_RESOURCE;
22162306a36Sopenharmony_ci	else {
22262306a36Sopenharmony_ci		pos = (offset - PCI_BASE_ADDRESS_0) / 4;
22362306a36Sopenharmony_ci		if (pos && (res[pos - 1].flags & IORESOURCE_MEM_64)) {
22462306a36Sopenharmony_ci			/*
22562306a36Sopenharmony_ci			 * Use ">> 16 >> 16" instead of direct ">> 32" shift
22662306a36Sopenharmony_ci			 * to avoid warnings on 32-bit architectures.
22762306a36Sopenharmony_ci			 */
22862306a36Sopenharmony_ci			bar->val = res[pos - 1].start >> 16 >> 16;
22962306a36Sopenharmony_ci			bar->len_val = -resource_size(&res[pos - 1]) >> 16 >> 16;
23062306a36Sopenharmony_ci			return bar;
23162306a36Sopenharmony_ci		}
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	if (!res[pos].flags ||
23562306a36Sopenharmony_ci	    (res[pos].flags & (IORESOURCE_DISABLED | IORESOURCE_UNSET |
23662306a36Sopenharmony_ci			       IORESOURCE_BUSY)))
23762306a36Sopenharmony_ci		return bar;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	bar->val = res[pos].start |
24062306a36Sopenharmony_ci		   (res[pos].flags & PCI_REGION_FLAG_MASK);
24162306a36Sopenharmony_ci	bar->len_val = -resource_size(&res[pos]) |
24262306a36Sopenharmony_ci		       (res[pos].flags & PCI_REGION_FLAG_MASK);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	return bar;
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic void bar_reset(struct pci_dev *dev, int offset, void *data)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	struct pci_bar_info *bar = data;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	bar->which = 0;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic void bar_release(struct pci_dev *dev, int offset, void *data)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	kfree(data);
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic int xen_pcibk_read_vendor(struct pci_dev *dev, int offset,
26062306a36Sopenharmony_ci			       u16 *value, void *data)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	*value = dev->vendor;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return 0;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic int xen_pcibk_read_device(struct pci_dev *dev, int offset,
26862306a36Sopenharmony_ci			       u16 *value, void *data)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	*value = dev->device;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	return 0;
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_cistatic int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
27662306a36Sopenharmony_ci			  void *data)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	*value = (u8) dev->irq;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	return 0;
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic int bist_write(struct pci_dev *dev, int offset, u8 value, void *data)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	u8 cur_value;
28662306a36Sopenharmony_ci	int err;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	err = pci_read_config_byte(dev, offset, &cur_value);
28962306a36Sopenharmony_ci	if (err)
29062306a36Sopenharmony_ci		goto out;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START)
29362306a36Sopenharmony_ci	    || value == PCI_BIST_START)
29462306a36Sopenharmony_ci		err = pci_write_config_byte(dev, offset, value);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ciout:
29762306a36Sopenharmony_ci	return err;
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic const struct config_field header_common[] = {
30162306a36Sopenharmony_ci	{
30262306a36Sopenharmony_ci	 .offset    = PCI_VENDOR_ID,
30362306a36Sopenharmony_ci	 .size      = 2,
30462306a36Sopenharmony_ci	 .u.w.read  = xen_pcibk_read_vendor,
30562306a36Sopenharmony_ci	},
30662306a36Sopenharmony_ci	{
30762306a36Sopenharmony_ci	 .offset    = PCI_DEVICE_ID,
30862306a36Sopenharmony_ci	 .size      = 2,
30962306a36Sopenharmony_ci	 .u.w.read  = xen_pcibk_read_device,
31062306a36Sopenharmony_ci	},
31162306a36Sopenharmony_ci	{
31262306a36Sopenharmony_ci	 .offset    = PCI_COMMAND,
31362306a36Sopenharmony_ci	 .size      = 2,
31462306a36Sopenharmony_ci	 .init      = command_init,
31562306a36Sopenharmony_ci	 .release   = bar_release,
31662306a36Sopenharmony_ci	 .u.w.read  = command_read,
31762306a36Sopenharmony_ci	 .u.w.write = command_write,
31862306a36Sopenharmony_ci	},
31962306a36Sopenharmony_ci	{
32062306a36Sopenharmony_ci	 .offset    = PCI_INTERRUPT_LINE,
32162306a36Sopenharmony_ci	 .size      = 1,
32262306a36Sopenharmony_ci	 .u.b.read  = interrupt_read,
32362306a36Sopenharmony_ci	},
32462306a36Sopenharmony_ci	{
32562306a36Sopenharmony_ci	 .offset    = PCI_INTERRUPT_PIN,
32662306a36Sopenharmony_ci	 .size      = 1,
32762306a36Sopenharmony_ci	 .u.b.read  = xen_pcibk_read_config_byte,
32862306a36Sopenharmony_ci	},
32962306a36Sopenharmony_ci	{
33062306a36Sopenharmony_ci	 /* Any side effects of letting driver domain control cache line? */
33162306a36Sopenharmony_ci	 .offset    = PCI_CACHE_LINE_SIZE,
33262306a36Sopenharmony_ci	 .size      = 1,
33362306a36Sopenharmony_ci	 .u.b.read  = xen_pcibk_read_config_byte,
33462306a36Sopenharmony_ci	 .u.b.write = xen_pcibk_write_config_byte,
33562306a36Sopenharmony_ci	},
33662306a36Sopenharmony_ci	{
33762306a36Sopenharmony_ci	 .offset    = PCI_LATENCY_TIMER,
33862306a36Sopenharmony_ci	 .size      = 1,
33962306a36Sopenharmony_ci	 .u.b.read  = xen_pcibk_read_config_byte,
34062306a36Sopenharmony_ci	},
34162306a36Sopenharmony_ci	{
34262306a36Sopenharmony_ci	 .offset    = PCI_BIST,
34362306a36Sopenharmony_ci	 .size      = 1,
34462306a36Sopenharmony_ci	 .u.b.read  = xen_pcibk_read_config_byte,
34562306a36Sopenharmony_ci	 .u.b.write = bist_write,
34662306a36Sopenharmony_ci	},
34762306a36Sopenharmony_ci	{}
34862306a36Sopenharmony_ci};
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci#define CFG_FIELD_BAR(reg_offset)			\
35162306a36Sopenharmony_ci	{						\
35262306a36Sopenharmony_ci	.offset     = reg_offset,			\
35362306a36Sopenharmony_ci	.size       = 4,				\
35462306a36Sopenharmony_ci	.init       = bar_init,				\
35562306a36Sopenharmony_ci	.reset      = bar_reset,			\
35662306a36Sopenharmony_ci	.release    = bar_release,			\
35762306a36Sopenharmony_ci	.u.dw.read  = bar_read,				\
35862306a36Sopenharmony_ci	.u.dw.write = bar_write,			\
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci#define CFG_FIELD_ROM(reg_offset)			\
36262306a36Sopenharmony_ci	{						\
36362306a36Sopenharmony_ci	.offset     = reg_offset,			\
36462306a36Sopenharmony_ci	.size       = 4,				\
36562306a36Sopenharmony_ci	.init       = bar_init,				\
36662306a36Sopenharmony_ci	.reset      = bar_reset,			\
36762306a36Sopenharmony_ci	.release    = bar_release,			\
36862306a36Sopenharmony_ci	.u.dw.read  = bar_read,				\
36962306a36Sopenharmony_ci	.u.dw.write = rom_write,			\
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic const struct config_field header_0[] = {
37362306a36Sopenharmony_ci	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
37462306a36Sopenharmony_ci	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
37562306a36Sopenharmony_ci	CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
37662306a36Sopenharmony_ci	CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
37762306a36Sopenharmony_ci	CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
37862306a36Sopenharmony_ci	CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
37962306a36Sopenharmony_ci	CFG_FIELD_ROM(PCI_ROM_ADDRESS),
38062306a36Sopenharmony_ci	{}
38162306a36Sopenharmony_ci};
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cistatic const struct config_field header_1[] = {
38462306a36Sopenharmony_ci	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
38562306a36Sopenharmony_ci	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
38662306a36Sopenharmony_ci	CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
38762306a36Sopenharmony_ci	{}
38862306a36Sopenharmony_ci};
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ciint xen_pcibk_config_header_add_fields(struct pci_dev *dev)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	int err;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	err = xen_pcibk_config_add_fields(dev, header_common);
39562306a36Sopenharmony_ci	if (err)
39662306a36Sopenharmony_ci		goto out;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	switch (dev->hdr_type) {
39962306a36Sopenharmony_ci	case PCI_HEADER_TYPE_NORMAL:
40062306a36Sopenharmony_ci		err = xen_pcibk_config_add_fields(dev, header_0);
40162306a36Sopenharmony_ci		break;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	case PCI_HEADER_TYPE_BRIDGE:
40462306a36Sopenharmony_ci		err = xen_pcibk_config_add_fields(dev, header_1);
40562306a36Sopenharmony_ci		break;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	default:
40862306a36Sopenharmony_ci		err = -EINVAL;
40962306a36Sopenharmony_ci		dev_err(&dev->dev, "Unsupported header type %d!\n",
41062306a36Sopenharmony_ci			dev->hdr_type);
41162306a36Sopenharmony_ci		break;
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ciout:
41562306a36Sopenharmony_ci	return err;
41662306a36Sopenharmony_ci}
417