18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * PCI Backend - Handles the virtual fields in the configuration space headers.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
98c2ecf20Sopenharmony_ci#define dev_fmt pr_fmt
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/pci.h>
138c2ecf20Sopenharmony_ci#include "pciback.h"
148c2ecf20Sopenharmony_ci#include "conf_space.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistruct pci_cmd_info {
178c2ecf20Sopenharmony_ci	u16 val;
188c2ecf20Sopenharmony_ci};
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistruct pci_bar_info {
218c2ecf20Sopenharmony_ci	u32 val;
228c2ecf20Sopenharmony_ci	u32 len_val;
238c2ecf20Sopenharmony_ci	int which;
248c2ecf20Sopenharmony_ci};
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
278c2ecf20Sopenharmony_ci#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/* Bits guests are allowed to control in permissive mode. */
308c2ecf20Sopenharmony_ci#define PCI_COMMAND_GUEST (PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL| \
318c2ecf20Sopenharmony_ci			   PCI_COMMAND_INVALIDATE|PCI_COMMAND_VGA_PALETTE| \
328c2ecf20Sopenharmony_ci			   PCI_COMMAND_WAIT|PCI_COMMAND_FAST_BACK)
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic void *command_init(struct pci_dev *dev, int offset)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
378c2ecf20Sopenharmony_ci	int err;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	if (!cmd)
408c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val);
438c2ecf20Sopenharmony_ci	if (err) {
448c2ecf20Sopenharmony_ci		kfree(cmd);
458c2ecf20Sopenharmony_ci		return ERR_PTR(err);
468c2ecf20Sopenharmony_ci	}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	return cmd;
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	int ret = pci_read_config_word(dev, offset, value);
548c2ecf20Sopenharmony_ci	const struct pci_cmd_info *cmd = data;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	*value &= PCI_COMMAND_GUEST;
578c2ecf20Sopenharmony_ci	*value |= cmd->val & ~PCI_COMMAND_GUEST;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	return ret;
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	struct xen_pcibk_dev_data *dev_data;
658c2ecf20Sopenharmony_ci	int err;
668c2ecf20Sopenharmony_ci	u16 val;
678c2ecf20Sopenharmony_ci	struct pci_cmd_info *cmd = data;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	dev_data = pci_get_drvdata(dev);
708c2ecf20Sopenharmony_ci	if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
718c2ecf20Sopenharmony_ci		dev_dbg(&dev->dev, "enable\n");
728c2ecf20Sopenharmony_ci		err = pci_enable_device(dev);
738c2ecf20Sopenharmony_ci		if (err)
748c2ecf20Sopenharmony_ci			return err;
758c2ecf20Sopenharmony_ci		if (dev_data)
768c2ecf20Sopenharmony_ci			dev_data->enable_intx = 1;
778c2ecf20Sopenharmony_ci	} else if (pci_is_enabled(dev) && !is_enable_cmd(value)) {
788c2ecf20Sopenharmony_ci		dev_dbg(&dev->dev, "disable\n");
798c2ecf20Sopenharmony_ci		pci_disable_device(dev);
808c2ecf20Sopenharmony_ci		if (dev_data)
818c2ecf20Sopenharmony_ci			dev_data->enable_intx = 0;
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	if (!dev->is_busmaster && is_master_cmd(value)) {
858c2ecf20Sopenharmony_ci		dev_dbg(&dev->dev, "set bus master\n");
868c2ecf20Sopenharmony_ci		pci_set_master(dev);
878c2ecf20Sopenharmony_ci	} else if (dev->is_busmaster && !is_master_cmd(value)) {
888c2ecf20Sopenharmony_ci		dev_dbg(&dev->dev, "clear bus master\n");
898c2ecf20Sopenharmony_ci		pci_clear_master(dev);
908c2ecf20Sopenharmony_ci	}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if (!(cmd->val & PCI_COMMAND_INVALIDATE) &&
938c2ecf20Sopenharmony_ci	    (value & PCI_COMMAND_INVALIDATE)) {
948c2ecf20Sopenharmony_ci		dev_dbg(&dev->dev, "enable memory-write-invalidate\n");
958c2ecf20Sopenharmony_ci		err = pci_set_mwi(dev);
968c2ecf20Sopenharmony_ci		if (err) {
978c2ecf20Sopenharmony_ci			dev_warn(&dev->dev, "cannot enable memory-write-invalidate (%d)\n",
988c2ecf20Sopenharmony_ci				err);
998c2ecf20Sopenharmony_ci			value &= ~PCI_COMMAND_INVALIDATE;
1008c2ecf20Sopenharmony_ci		}
1018c2ecf20Sopenharmony_ci	} else if ((cmd->val & PCI_COMMAND_INVALIDATE) &&
1028c2ecf20Sopenharmony_ci		   !(value & PCI_COMMAND_INVALIDATE)) {
1038c2ecf20Sopenharmony_ci		dev_dbg(&dev->dev, "disable memory-write-invalidate\n");
1048c2ecf20Sopenharmony_ci		pci_clear_mwi(dev);
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	if (dev_data && dev_data->allow_interrupt_control &&
1088c2ecf20Sopenharmony_ci	    ((cmd->val ^ value) & PCI_COMMAND_INTX_DISABLE))
1098c2ecf20Sopenharmony_ci		pci_intx(dev, !(value & PCI_COMMAND_INTX_DISABLE));
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	cmd->val = value;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	if (!xen_pcibk_permissive && (!dev_data || !dev_data->permissive))
1148c2ecf20Sopenharmony_ci		return 0;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	/* Only allow the guest to control certain bits. */
1178c2ecf20Sopenharmony_ci	err = pci_read_config_word(dev, offset, &val);
1188c2ecf20Sopenharmony_ci	if (err || val == value)
1198c2ecf20Sopenharmony_ci		return err;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	value &= PCI_COMMAND_GUEST;
1228c2ecf20Sopenharmony_ci	value |= val & ~PCI_COMMAND_GUEST;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	return pci_write_config_word(dev, offset, value);
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	struct pci_bar_info *bar = data;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	if (unlikely(!bar)) {
1328c2ecf20Sopenharmony_ci		dev_warn(&dev->dev, "driver data not found\n");
1338c2ecf20Sopenharmony_ci		return XEN_PCI_ERR_op_failed;
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	/* A write to obtain the length must happen as a 32-bit write.
1378c2ecf20Sopenharmony_ci	 * This does not (yet) support writing individual bytes
1388c2ecf20Sopenharmony_ci	 */
1398c2ecf20Sopenharmony_ci	if ((value | ~PCI_ROM_ADDRESS_MASK) == ~0U)
1408c2ecf20Sopenharmony_ci		bar->which = 1;
1418c2ecf20Sopenharmony_ci	else {
1428c2ecf20Sopenharmony_ci		u32 tmpval;
1438c2ecf20Sopenharmony_ci		pci_read_config_dword(dev, offset, &tmpval);
1448c2ecf20Sopenharmony_ci		if (tmpval != bar->val && value == bar->val) {
1458c2ecf20Sopenharmony_ci			/* Allow restoration of bar value. */
1468c2ecf20Sopenharmony_ci			pci_write_config_dword(dev, offset, bar->val);
1478c2ecf20Sopenharmony_ci		}
1488c2ecf20Sopenharmony_ci		bar->which = 0;
1498c2ecf20Sopenharmony_ci	}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	/* Do we need to support enabling/disabling the rom address here? */
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	return 0;
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci/* For the BARs, only allow writes which write ~0 or
1578c2ecf20Sopenharmony_ci * the correct resource information
1588c2ecf20Sopenharmony_ci * (Needed for when the driver probes the resource usage)
1598c2ecf20Sopenharmony_ci */
1608c2ecf20Sopenharmony_cistatic int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	struct pci_bar_info *bar = data;
1638c2ecf20Sopenharmony_ci	unsigned int pos = (offset - PCI_BASE_ADDRESS_0) / 4;
1648c2ecf20Sopenharmony_ci	const struct resource *res = dev->resource;
1658c2ecf20Sopenharmony_ci	u32 mask;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	if (unlikely(!bar)) {
1688c2ecf20Sopenharmony_ci		dev_warn(&dev->dev, "driver data not found\n");
1698c2ecf20Sopenharmony_ci		return XEN_PCI_ERR_op_failed;
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	/* A write to obtain the length must happen as a 32-bit write.
1738c2ecf20Sopenharmony_ci	 * This does not (yet) support writing individual bytes
1748c2ecf20Sopenharmony_ci	 */
1758c2ecf20Sopenharmony_ci	if (res[pos].flags & IORESOURCE_IO)
1768c2ecf20Sopenharmony_ci		mask = ~PCI_BASE_ADDRESS_IO_MASK;
1778c2ecf20Sopenharmony_ci	else if (pos && (res[pos - 1].flags & IORESOURCE_MEM_64))
1788c2ecf20Sopenharmony_ci		mask = 0;
1798c2ecf20Sopenharmony_ci	else
1808c2ecf20Sopenharmony_ci		mask = ~PCI_BASE_ADDRESS_MEM_MASK;
1818c2ecf20Sopenharmony_ci	if ((value | mask) == ~0U)
1828c2ecf20Sopenharmony_ci		bar->which = 1;
1838c2ecf20Sopenharmony_ci	else {
1848c2ecf20Sopenharmony_ci		u32 tmpval;
1858c2ecf20Sopenharmony_ci		pci_read_config_dword(dev, offset, &tmpval);
1868c2ecf20Sopenharmony_ci		if (tmpval != bar->val && value == bar->val) {
1878c2ecf20Sopenharmony_ci			/* Allow restoration of bar value. */
1888c2ecf20Sopenharmony_ci			pci_write_config_dword(dev, offset, bar->val);
1898c2ecf20Sopenharmony_ci		}
1908c2ecf20Sopenharmony_ci		bar->which = 0;
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	return 0;
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cistatic int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	struct pci_bar_info *bar = data;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	if (unlikely(!bar)) {
2018c2ecf20Sopenharmony_ci		dev_warn(&dev->dev, "driver data not found\n");
2028c2ecf20Sopenharmony_ci		return XEN_PCI_ERR_op_failed;
2038c2ecf20Sopenharmony_ci	}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	*value = bar->which ? bar->len_val : bar->val;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	return 0;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cistatic void *bar_init(struct pci_dev *dev, int offset)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	unsigned int pos;
2138c2ecf20Sopenharmony_ci	const struct resource *res = dev->resource;
2148c2ecf20Sopenharmony_ci	struct pci_bar_info *bar = kzalloc(sizeof(*bar), GFP_KERNEL);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	if (!bar)
2178c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	if (offset == PCI_ROM_ADDRESS || offset == PCI_ROM_ADDRESS1)
2208c2ecf20Sopenharmony_ci		pos = PCI_ROM_RESOURCE;
2218c2ecf20Sopenharmony_ci	else {
2228c2ecf20Sopenharmony_ci		pos = (offset - PCI_BASE_ADDRESS_0) / 4;
2238c2ecf20Sopenharmony_ci		if (pos && (res[pos - 1].flags & IORESOURCE_MEM_64)) {
2248c2ecf20Sopenharmony_ci			bar->val = res[pos - 1].start >> 32;
2258c2ecf20Sopenharmony_ci			bar->len_val = -resource_size(&res[pos - 1]) >> 32;
2268c2ecf20Sopenharmony_ci			return bar;
2278c2ecf20Sopenharmony_ci		}
2288c2ecf20Sopenharmony_ci	}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	if (!res[pos].flags ||
2318c2ecf20Sopenharmony_ci	    (res[pos].flags & (IORESOURCE_DISABLED | IORESOURCE_UNSET |
2328c2ecf20Sopenharmony_ci			       IORESOURCE_BUSY)))
2338c2ecf20Sopenharmony_ci		return bar;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	bar->val = res[pos].start |
2368c2ecf20Sopenharmony_ci		   (res[pos].flags & PCI_REGION_FLAG_MASK);
2378c2ecf20Sopenharmony_ci	bar->len_val = -resource_size(&res[pos]) |
2388c2ecf20Sopenharmony_ci		       (res[pos].flags & PCI_REGION_FLAG_MASK);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	return bar;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic void bar_reset(struct pci_dev *dev, int offset, void *data)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	struct pci_bar_info *bar = data;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	bar->which = 0;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic void bar_release(struct pci_dev *dev, int offset, void *data)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	kfree(data);
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic int xen_pcibk_read_vendor(struct pci_dev *dev, int offset,
2568c2ecf20Sopenharmony_ci			       u16 *value, void *data)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	*value = dev->vendor;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	return 0;
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistatic int xen_pcibk_read_device(struct pci_dev *dev, int offset,
2648c2ecf20Sopenharmony_ci			       u16 *value, void *data)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	*value = dev->device;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	return 0;
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cistatic int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
2728c2ecf20Sopenharmony_ci			  void *data)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	*value = (u8) dev->irq;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	return 0;
2778c2ecf20Sopenharmony_ci}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_cistatic int bist_write(struct pci_dev *dev, int offset, u8 value, void *data)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	u8 cur_value;
2828c2ecf20Sopenharmony_ci	int err;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	err = pci_read_config_byte(dev, offset, &cur_value);
2858c2ecf20Sopenharmony_ci	if (err)
2868c2ecf20Sopenharmony_ci		goto out;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START)
2898c2ecf20Sopenharmony_ci	    || value == PCI_BIST_START)
2908c2ecf20Sopenharmony_ci		err = pci_write_config_byte(dev, offset, value);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ciout:
2938c2ecf20Sopenharmony_ci	return err;
2948c2ecf20Sopenharmony_ci}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_cistatic const struct config_field header_common[] = {
2978c2ecf20Sopenharmony_ci	{
2988c2ecf20Sopenharmony_ci	 .offset    = PCI_VENDOR_ID,
2998c2ecf20Sopenharmony_ci	 .size      = 2,
3008c2ecf20Sopenharmony_ci	 .u.w.read  = xen_pcibk_read_vendor,
3018c2ecf20Sopenharmony_ci	},
3028c2ecf20Sopenharmony_ci	{
3038c2ecf20Sopenharmony_ci	 .offset    = PCI_DEVICE_ID,
3048c2ecf20Sopenharmony_ci	 .size      = 2,
3058c2ecf20Sopenharmony_ci	 .u.w.read  = xen_pcibk_read_device,
3068c2ecf20Sopenharmony_ci	},
3078c2ecf20Sopenharmony_ci	{
3088c2ecf20Sopenharmony_ci	 .offset    = PCI_COMMAND,
3098c2ecf20Sopenharmony_ci	 .size      = 2,
3108c2ecf20Sopenharmony_ci	 .init      = command_init,
3118c2ecf20Sopenharmony_ci	 .release   = bar_release,
3128c2ecf20Sopenharmony_ci	 .u.w.read  = command_read,
3138c2ecf20Sopenharmony_ci	 .u.w.write = command_write,
3148c2ecf20Sopenharmony_ci	},
3158c2ecf20Sopenharmony_ci	{
3168c2ecf20Sopenharmony_ci	 .offset    = PCI_INTERRUPT_LINE,
3178c2ecf20Sopenharmony_ci	 .size      = 1,
3188c2ecf20Sopenharmony_ci	 .u.b.read  = interrupt_read,
3198c2ecf20Sopenharmony_ci	},
3208c2ecf20Sopenharmony_ci	{
3218c2ecf20Sopenharmony_ci	 .offset    = PCI_INTERRUPT_PIN,
3228c2ecf20Sopenharmony_ci	 .size      = 1,
3238c2ecf20Sopenharmony_ci	 .u.b.read  = xen_pcibk_read_config_byte,
3248c2ecf20Sopenharmony_ci	},
3258c2ecf20Sopenharmony_ci	{
3268c2ecf20Sopenharmony_ci	 /* Any side effects of letting driver domain control cache line? */
3278c2ecf20Sopenharmony_ci	 .offset    = PCI_CACHE_LINE_SIZE,
3288c2ecf20Sopenharmony_ci	 .size      = 1,
3298c2ecf20Sopenharmony_ci	 .u.b.read  = xen_pcibk_read_config_byte,
3308c2ecf20Sopenharmony_ci	 .u.b.write = xen_pcibk_write_config_byte,
3318c2ecf20Sopenharmony_ci	},
3328c2ecf20Sopenharmony_ci	{
3338c2ecf20Sopenharmony_ci	 .offset    = PCI_LATENCY_TIMER,
3348c2ecf20Sopenharmony_ci	 .size      = 1,
3358c2ecf20Sopenharmony_ci	 .u.b.read  = xen_pcibk_read_config_byte,
3368c2ecf20Sopenharmony_ci	},
3378c2ecf20Sopenharmony_ci	{
3388c2ecf20Sopenharmony_ci	 .offset    = PCI_BIST,
3398c2ecf20Sopenharmony_ci	 .size      = 1,
3408c2ecf20Sopenharmony_ci	 .u.b.read  = xen_pcibk_read_config_byte,
3418c2ecf20Sopenharmony_ci	 .u.b.write = bist_write,
3428c2ecf20Sopenharmony_ci	},
3438c2ecf20Sopenharmony_ci	{}
3448c2ecf20Sopenharmony_ci};
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci#define CFG_FIELD_BAR(reg_offset)			\
3478c2ecf20Sopenharmony_ci	{						\
3488c2ecf20Sopenharmony_ci	.offset     = reg_offset,			\
3498c2ecf20Sopenharmony_ci	.size       = 4,				\
3508c2ecf20Sopenharmony_ci	.init       = bar_init,				\
3518c2ecf20Sopenharmony_ci	.reset      = bar_reset,			\
3528c2ecf20Sopenharmony_ci	.release    = bar_release,			\
3538c2ecf20Sopenharmony_ci	.u.dw.read  = bar_read,				\
3548c2ecf20Sopenharmony_ci	.u.dw.write = bar_write,			\
3558c2ecf20Sopenharmony_ci	}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci#define CFG_FIELD_ROM(reg_offset)			\
3588c2ecf20Sopenharmony_ci	{						\
3598c2ecf20Sopenharmony_ci	.offset     = reg_offset,			\
3608c2ecf20Sopenharmony_ci	.size       = 4,				\
3618c2ecf20Sopenharmony_ci	.init       = bar_init,				\
3628c2ecf20Sopenharmony_ci	.reset      = bar_reset,			\
3638c2ecf20Sopenharmony_ci	.release    = bar_release,			\
3648c2ecf20Sopenharmony_ci	.u.dw.read  = bar_read,				\
3658c2ecf20Sopenharmony_ci	.u.dw.write = rom_write,			\
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_cistatic const struct config_field header_0[] = {
3698c2ecf20Sopenharmony_ci	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
3708c2ecf20Sopenharmony_ci	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
3718c2ecf20Sopenharmony_ci	CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
3728c2ecf20Sopenharmony_ci	CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
3738c2ecf20Sopenharmony_ci	CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
3748c2ecf20Sopenharmony_ci	CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
3758c2ecf20Sopenharmony_ci	CFG_FIELD_ROM(PCI_ROM_ADDRESS),
3768c2ecf20Sopenharmony_ci	{}
3778c2ecf20Sopenharmony_ci};
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_cistatic const struct config_field header_1[] = {
3808c2ecf20Sopenharmony_ci	CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
3818c2ecf20Sopenharmony_ci	CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
3828c2ecf20Sopenharmony_ci	CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
3838c2ecf20Sopenharmony_ci	{}
3848c2ecf20Sopenharmony_ci};
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ciint xen_pcibk_config_header_add_fields(struct pci_dev *dev)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	int err;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	err = xen_pcibk_config_add_fields(dev, header_common);
3918c2ecf20Sopenharmony_ci	if (err)
3928c2ecf20Sopenharmony_ci		goto out;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	switch (dev->hdr_type) {
3958c2ecf20Sopenharmony_ci	case PCI_HEADER_TYPE_NORMAL:
3968c2ecf20Sopenharmony_ci		err = xen_pcibk_config_add_fields(dev, header_0);
3978c2ecf20Sopenharmony_ci		break;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	case PCI_HEADER_TYPE_BRIDGE:
4008c2ecf20Sopenharmony_ci		err = xen_pcibk_config_add_fields(dev, header_1);
4018c2ecf20Sopenharmony_ci		break;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	default:
4048c2ecf20Sopenharmony_ci		err = -EINVAL;
4058c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "Unsupported header type %d!\n",
4068c2ecf20Sopenharmony_ci			dev->hdr_type);
4078c2ecf20Sopenharmony_ci		break;
4088c2ecf20Sopenharmony_ci	}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ciout:
4118c2ecf20Sopenharmony_ci	return err;
4128c2ecf20Sopenharmony_ci}
413