162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PCI Backend - Functions for creating a virtual configuration space for
462306a36Sopenharmony_ci *               exported PCI Devices.
562306a36Sopenharmony_ci *               It's dangerous to allow PCI Driver Domains to change their
662306a36Sopenharmony_ci *               device's resources (memory, i/o ports, interrupts). We need to
762306a36Sopenharmony_ci *               restrict changes to certain PCI Configuration registers:
862306a36Sopenharmony_ci *               BARs, INTERRUPT_PIN, most registers in the header...
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define dev_fmt(fmt) DRV_NAME ": " fmt
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/kernel.h>
1662306a36Sopenharmony_ci#include <linux/moduleparam.h>
1762306a36Sopenharmony_ci#include <linux/pci.h>
1862306a36Sopenharmony_ci#include "pciback.h"
1962306a36Sopenharmony_ci#include "conf_space.h"
2062306a36Sopenharmony_ci#include "conf_space_quirks.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cibool xen_pcibk_permissive;
2362306a36Sopenharmony_cimodule_param_named(permissive, xen_pcibk_permissive, bool, 0644);
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* This is where xen_pcibk_read_config_byte, xen_pcibk_read_config_word,
2662306a36Sopenharmony_ci * xen_pcibk_write_config_word, and xen_pcibk_write_config_byte are created. */
2762306a36Sopenharmony_ci#define DEFINE_PCI_CONFIG(op, size, type)			\
2862306a36Sopenharmony_ciint xen_pcibk_##op##_config_##size				\
2962306a36Sopenharmony_ci(struct pci_dev *dev, int offset, type value, void *data)	\
3062306a36Sopenharmony_ci{								\
3162306a36Sopenharmony_ci	return pci_##op##_config_##size(dev, offset, value);	\
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ciDEFINE_PCI_CONFIG(read, byte, u8 *)
3562306a36Sopenharmony_ciDEFINE_PCI_CONFIG(read, word, u16 *)
3662306a36Sopenharmony_ciDEFINE_PCI_CONFIG(read, dword, u32 *)
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ciDEFINE_PCI_CONFIG(write, byte, u8)
3962306a36Sopenharmony_ciDEFINE_PCI_CONFIG(write, word, u16)
4062306a36Sopenharmony_ciDEFINE_PCI_CONFIG(write, dword, u32)
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic int conf_space_read(struct pci_dev *dev,
4362306a36Sopenharmony_ci			   const struct config_field_entry *entry,
4462306a36Sopenharmony_ci			   int offset, u32 *value)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	int ret = 0;
4762306a36Sopenharmony_ci	const struct config_field *field = entry->field;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	*value = 0;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	switch (field->size) {
5262306a36Sopenharmony_ci	case 1:
5362306a36Sopenharmony_ci		if (field->u.b.read)
5462306a36Sopenharmony_ci			ret = field->u.b.read(dev, offset, (u8 *) value,
5562306a36Sopenharmony_ci					      entry->data);
5662306a36Sopenharmony_ci		break;
5762306a36Sopenharmony_ci	case 2:
5862306a36Sopenharmony_ci		if (field->u.w.read)
5962306a36Sopenharmony_ci			ret = field->u.w.read(dev, offset, (u16 *) value,
6062306a36Sopenharmony_ci					      entry->data);
6162306a36Sopenharmony_ci		break;
6262306a36Sopenharmony_ci	case 4:
6362306a36Sopenharmony_ci		if (field->u.dw.read)
6462306a36Sopenharmony_ci			ret = field->u.dw.read(dev, offset, value, entry->data);
6562306a36Sopenharmony_ci		break;
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci	return ret;
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic int conf_space_write(struct pci_dev *dev,
7162306a36Sopenharmony_ci			    const struct config_field_entry *entry,
7262306a36Sopenharmony_ci			    int offset, u32 value)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	int ret = 0;
7562306a36Sopenharmony_ci	const struct config_field *field = entry->field;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	switch (field->size) {
7862306a36Sopenharmony_ci	case 1:
7962306a36Sopenharmony_ci		if (field->u.b.write)
8062306a36Sopenharmony_ci			ret = field->u.b.write(dev, offset, (u8) value,
8162306a36Sopenharmony_ci					       entry->data);
8262306a36Sopenharmony_ci		break;
8362306a36Sopenharmony_ci	case 2:
8462306a36Sopenharmony_ci		if (field->u.w.write)
8562306a36Sopenharmony_ci			ret = field->u.w.write(dev, offset, (u16) value,
8662306a36Sopenharmony_ci					       entry->data);
8762306a36Sopenharmony_ci		break;
8862306a36Sopenharmony_ci	case 4:
8962306a36Sopenharmony_ci		if (field->u.dw.write)
9062306a36Sopenharmony_ci			ret = field->u.dw.write(dev, offset, value,
9162306a36Sopenharmony_ci						entry->data);
9262306a36Sopenharmony_ci		break;
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci	return ret;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic inline u32 get_mask(int size)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	if (size == 1)
10062306a36Sopenharmony_ci		return 0xff;
10162306a36Sopenharmony_ci	else if (size == 2)
10262306a36Sopenharmony_ci		return 0xffff;
10362306a36Sopenharmony_ci	else
10462306a36Sopenharmony_ci		return 0xffffffff;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic inline int valid_request(int offset, int size)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	/* Validate request (no un-aligned requests) */
11062306a36Sopenharmony_ci	if ((size == 1 || size == 2 || size == 4) && (offset % size) == 0)
11162306a36Sopenharmony_ci		return 1;
11262306a36Sopenharmony_ci	return 0;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic inline u32 merge_value(u32 val, u32 new_val, u32 new_val_mask,
11662306a36Sopenharmony_ci			      int offset)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	if (offset >= 0) {
11962306a36Sopenharmony_ci		new_val_mask <<= (offset * 8);
12062306a36Sopenharmony_ci		new_val <<= (offset * 8);
12162306a36Sopenharmony_ci	} else {
12262306a36Sopenharmony_ci		new_val_mask >>= (offset * -8);
12362306a36Sopenharmony_ci		new_val >>= (offset * -8);
12462306a36Sopenharmony_ci	}
12562306a36Sopenharmony_ci	val = (val & ~new_val_mask) | (new_val & new_val_mask);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	return val;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic int xen_pcibios_err_to_errno(int err)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	switch (err) {
13362306a36Sopenharmony_ci	case PCIBIOS_SUCCESSFUL:
13462306a36Sopenharmony_ci		return XEN_PCI_ERR_success;
13562306a36Sopenharmony_ci	case PCIBIOS_DEVICE_NOT_FOUND:
13662306a36Sopenharmony_ci		return XEN_PCI_ERR_dev_not_found;
13762306a36Sopenharmony_ci	case PCIBIOS_BAD_REGISTER_NUMBER:
13862306a36Sopenharmony_ci		return XEN_PCI_ERR_invalid_offset;
13962306a36Sopenharmony_ci	case PCIBIOS_FUNC_NOT_SUPPORTED:
14062306a36Sopenharmony_ci		return XEN_PCI_ERR_not_implemented;
14162306a36Sopenharmony_ci	case PCIBIOS_SET_FAILED:
14262306a36Sopenharmony_ci		return XEN_PCI_ERR_access_denied;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci	return err;
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ciint xen_pcibk_config_read(struct pci_dev *dev, int offset, int size,
14862306a36Sopenharmony_ci			  u32 *ret_val)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	int err = 0;
15162306a36Sopenharmony_ci	struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev);
15262306a36Sopenharmony_ci	const struct config_field_entry *cfg_entry;
15362306a36Sopenharmony_ci	const struct config_field *field;
15462306a36Sopenharmony_ci	int field_start, field_end;
15562306a36Sopenharmony_ci	/* if read fails for any reason, return 0
15662306a36Sopenharmony_ci	 * (as if device didn't respond) */
15762306a36Sopenharmony_ci	u32 value = 0, tmp_val;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	dev_dbg(&dev->dev, "read %d bytes at 0x%x\n", size, offset);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if (!valid_request(offset, size)) {
16262306a36Sopenharmony_ci		err = XEN_PCI_ERR_invalid_offset;
16362306a36Sopenharmony_ci		goto out;
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	/* Get the real value first, then modify as appropriate */
16762306a36Sopenharmony_ci	switch (size) {
16862306a36Sopenharmony_ci	case 1:
16962306a36Sopenharmony_ci		err = pci_read_config_byte(dev, offset, (u8 *) &value);
17062306a36Sopenharmony_ci		break;
17162306a36Sopenharmony_ci	case 2:
17262306a36Sopenharmony_ci		err = pci_read_config_word(dev, offset, (u16 *) &value);
17362306a36Sopenharmony_ci		break;
17462306a36Sopenharmony_ci	case 4:
17562306a36Sopenharmony_ci		err = pci_read_config_dword(dev, offset, &value);
17662306a36Sopenharmony_ci		break;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
18062306a36Sopenharmony_ci		field = cfg_entry->field;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci		field_start = OFFSET(cfg_entry);
18362306a36Sopenharmony_ci		field_end = OFFSET(cfg_entry) + field->size;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci		if (offset + size > field_start && field_end > offset) {
18662306a36Sopenharmony_ci			err = conf_space_read(dev, cfg_entry, field_start,
18762306a36Sopenharmony_ci					      &tmp_val);
18862306a36Sopenharmony_ci			if (err)
18962306a36Sopenharmony_ci				goto out;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci			value = merge_value(value, tmp_val,
19262306a36Sopenharmony_ci					    get_mask(field->size),
19362306a36Sopenharmony_ci					    field_start - offset);
19462306a36Sopenharmony_ci		}
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ciout:
19862306a36Sopenharmony_ci	dev_dbg(&dev->dev, "read %d bytes at 0x%x = %x\n", size, offset, value);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	*ret_val = value;
20162306a36Sopenharmony_ci	return xen_pcibios_err_to_errno(err);
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ciint xen_pcibk_config_write(struct pci_dev *dev, int offset, int size, u32 value)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	int err = 0, handled = 0;
20762306a36Sopenharmony_ci	struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev);
20862306a36Sopenharmony_ci	const struct config_field_entry *cfg_entry;
20962306a36Sopenharmony_ci	const struct config_field *field;
21062306a36Sopenharmony_ci	u32 tmp_val;
21162306a36Sopenharmony_ci	int field_start, field_end;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	dev_dbg(&dev->dev, "write request %d bytes at 0x%x = %x\n",
21462306a36Sopenharmony_ci		size, offset, value);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	if (!valid_request(offset, size))
21762306a36Sopenharmony_ci		return XEN_PCI_ERR_invalid_offset;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
22062306a36Sopenharmony_ci		field = cfg_entry->field;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci		field_start = OFFSET(cfg_entry);
22362306a36Sopenharmony_ci		field_end = OFFSET(cfg_entry) + field->size;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		if (offset + size > field_start && field_end > offset) {
22662306a36Sopenharmony_ci			err = conf_space_read(dev, cfg_entry, field_start,
22762306a36Sopenharmony_ci					      &tmp_val);
22862306a36Sopenharmony_ci			if (err)
22962306a36Sopenharmony_ci				break;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci			tmp_val = merge_value(tmp_val, value, get_mask(size),
23262306a36Sopenharmony_ci					      offset - field_start);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci			err = conf_space_write(dev, cfg_entry, field_start,
23562306a36Sopenharmony_ci					       tmp_val);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci			/* handled is set true here, but not every byte
23862306a36Sopenharmony_ci			 * may have been written! Properly detecting if
23962306a36Sopenharmony_ci			 * every byte is handled is unnecessary as the
24062306a36Sopenharmony_ci			 * flag is used to detect devices that need
24162306a36Sopenharmony_ci			 * special helpers to work correctly.
24262306a36Sopenharmony_ci			 */
24362306a36Sopenharmony_ci			handled = 1;
24462306a36Sopenharmony_ci		}
24562306a36Sopenharmony_ci	}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (!handled && !err) {
24862306a36Sopenharmony_ci		/* By default, anything not specificially handled above is
24962306a36Sopenharmony_ci		 * read-only. The permissive flag changes this behavior so
25062306a36Sopenharmony_ci		 * that anything not specifically handled above is writable.
25162306a36Sopenharmony_ci		 * This means that some fields may still be read-only because
25262306a36Sopenharmony_ci		 * they have entries in the config_field list that intercept
25362306a36Sopenharmony_ci		 * the write and do nothing. */
25462306a36Sopenharmony_ci		if (dev_data->permissive || xen_pcibk_permissive) {
25562306a36Sopenharmony_ci			switch (size) {
25662306a36Sopenharmony_ci			case 1:
25762306a36Sopenharmony_ci				err = pci_write_config_byte(dev, offset,
25862306a36Sopenharmony_ci							    (u8) value);
25962306a36Sopenharmony_ci				break;
26062306a36Sopenharmony_ci			case 2:
26162306a36Sopenharmony_ci				err = pci_write_config_word(dev, offset,
26262306a36Sopenharmony_ci							    (u16) value);
26362306a36Sopenharmony_ci				break;
26462306a36Sopenharmony_ci			case 4:
26562306a36Sopenharmony_ci				err = pci_write_config_dword(dev, offset,
26662306a36Sopenharmony_ci							     (u32) value);
26762306a36Sopenharmony_ci				break;
26862306a36Sopenharmony_ci			}
26962306a36Sopenharmony_ci		} else if (!dev_data->warned_on_write) {
27062306a36Sopenharmony_ci			dev_data->warned_on_write = 1;
27162306a36Sopenharmony_ci			dev_warn(&dev->dev, "Driver tried to write to a "
27262306a36Sopenharmony_ci				 "read-only configuration space field at offset"
27362306a36Sopenharmony_ci				 " 0x%x, size %d. This may be harmless, but if "
27462306a36Sopenharmony_ci				 "you have problems with your device:\n"
27562306a36Sopenharmony_ci				 "1) see permissive attribute in sysfs\n"
27662306a36Sopenharmony_ci				 "2) report problems to the xen-devel "
27762306a36Sopenharmony_ci				 "mailing list along with details of your "
27862306a36Sopenharmony_ci				 "device obtained from lspci.\n", offset, size);
27962306a36Sopenharmony_ci		}
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	return xen_pcibios_err_to_errno(err);
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ciint xen_pcibk_get_interrupt_type(struct pci_dev *dev)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	int err;
28862306a36Sopenharmony_ci	u16 val;
28962306a36Sopenharmony_ci	int ret = 0;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	/*
29262306a36Sopenharmony_ci	 * Do not trust dev->msi(x)_enabled here, as enabling could be done
29362306a36Sopenharmony_ci	 * bypassing the pci_*msi* functions, by the qemu.
29462306a36Sopenharmony_ci	 */
29562306a36Sopenharmony_ci	if (dev->msi_cap) {
29662306a36Sopenharmony_ci		err = pci_read_config_word(dev,
29762306a36Sopenharmony_ci				dev->msi_cap + PCI_MSI_FLAGS,
29862306a36Sopenharmony_ci				&val);
29962306a36Sopenharmony_ci		if (err)
30062306a36Sopenharmony_ci			return err;
30162306a36Sopenharmony_ci		if (val & PCI_MSI_FLAGS_ENABLE)
30262306a36Sopenharmony_ci			ret |= INTERRUPT_TYPE_MSI;
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci	if (dev->msix_cap) {
30562306a36Sopenharmony_ci		err = pci_read_config_word(dev,
30662306a36Sopenharmony_ci				dev->msix_cap + PCI_MSIX_FLAGS,
30762306a36Sopenharmony_ci				&val);
30862306a36Sopenharmony_ci		if (err)
30962306a36Sopenharmony_ci			return err;
31062306a36Sopenharmony_ci		if (val & PCI_MSIX_FLAGS_ENABLE)
31162306a36Sopenharmony_ci			ret |= INTERRUPT_TYPE_MSIX;
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	/*
31562306a36Sopenharmony_ci	 * PCIe spec says device cannot use INTx if MSI/MSI-X is enabled,
31662306a36Sopenharmony_ci	 * so check for INTx only when both are disabled.
31762306a36Sopenharmony_ci	 */
31862306a36Sopenharmony_ci	if (!ret) {
31962306a36Sopenharmony_ci		err = pci_read_config_word(dev, PCI_COMMAND, &val);
32062306a36Sopenharmony_ci		if (err)
32162306a36Sopenharmony_ci			return err;
32262306a36Sopenharmony_ci		if (!(val & PCI_COMMAND_INTX_DISABLE))
32362306a36Sopenharmony_ci			ret |= INTERRUPT_TYPE_INTX;
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	return ret ?: INTERRUPT_TYPE_NONE;
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_civoid xen_pcibk_config_free_dyn_fields(struct pci_dev *dev)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev);
33262306a36Sopenharmony_ci	struct config_field_entry *cfg_entry, *t;
33362306a36Sopenharmony_ci	const struct config_field *field;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	dev_dbg(&dev->dev, "free-ing dynamically allocated virtual "
33662306a36Sopenharmony_ci			   "configuration space fields\n");
33762306a36Sopenharmony_ci	if (!dev_data)
33862306a36Sopenharmony_ci		return;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
34162306a36Sopenharmony_ci		field = cfg_entry->field;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci		if (field->clean) {
34462306a36Sopenharmony_ci			field->clean((struct config_field *)field);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci			kfree(cfg_entry->data);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci			list_del(&cfg_entry->list);
34962306a36Sopenharmony_ci			kfree(cfg_entry);
35062306a36Sopenharmony_ci		}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_civoid xen_pcibk_config_reset_dev(struct pci_dev *dev)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev);
35862306a36Sopenharmony_ci	const struct config_field_entry *cfg_entry;
35962306a36Sopenharmony_ci	const struct config_field *field;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	dev_dbg(&dev->dev, "resetting virtual configuration space\n");
36262306a36Sopenharmony_ci	if (!dev_data)
36362306a36Sopenharmony_ci		return;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
36662306a36Sopenharmony_ci		field = cfg_entry->field;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci		if (field->reset)
36962306a36Sopenharmony_ci			field->reset(dev, OFFSET(cfg_entry), cfg_entry->data);
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_civoid xen_pcibk_config_free_dev(struct pci_dev *dev)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev);
37662306a36Sopenharmony_ci	struct config_field_entry *cfg_entry, *t;
37762306a36Sopenharmony_ci	const struct config_field *field;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	dev_dbg(&dev->dev, "free-ing virtual configuration space fields\n");
38062306a36Sopenharmony_ci	if (!dev_data)
38162306a36Sopenharmony_ci		return;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
38462306a36Sopenharmony_ci		list_del(&cfg_entry->list);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci		field = cfg_entry->field;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci		if (field->release)
38962306a36Sopenharmony_ci			field->release(dev, OFFSET(cfg_entry), cfg_entry->data);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci		kfree(cfg_entry);
39262306a36Sopenharmony_ci	}
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ciint xen_pcibk_config_add_field_offset(struct pci_dev *dev,
39662306a36Sopenharmony_ci				    const struct config_field *field,
39762306a36Sopenharmony_ci				    unsigned int base_offset)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	int err = 0;
40062306a36Sopenharmony_ci	struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev);
40162306a36Sopenharmony_ci	struct config_field_entry *cfg_entry;
40262306a36Sopenharmony_ci	void *tmp;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL);
40562306a36Sopenharmony_ci	if (!cfg_entry) {
40662306a36Sopenharmony_ci		err = -ENOMEM;
40762306a36Sopenharmony_ci		goto out;
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	cfg_entry->data = NULL;
41162306a36Sopenharmony_ci	cfg_entry->field = field;
41262306a36Sopenharmony_ci	cfg_entry->base_offset = base_offset;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	/* silently ignore duplicate fields */
41562306a36Sopenharmony_ci	err = xen_pcibk_field_is_dup(dev, OFFSET(cfg_entry));
41662306a36Sopenharmony_ci	if (err)
41762306a36Sopenharmony_ci		goto out;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	if (field->init) {
42062306a36Sopenharmony_ci		tmp = field->init(dev, OFFSET(cfg_entry));
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci		if (IS_ERR(tmp)) {
42362306a36Sopenharmony_ci			err = PTR_ERR(tmp);
42462306a36Sopenharmony_ci			goto out;
42562306a36Sopenharmony_ci		}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci		cfg_entry->data = tmp;
42862306a36Sopenharmony_ci	}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	dev_dbg(&dev->dev, "added config field at offset 0x%02x\n",
43162306a36Sopenharmony_ci		OFFSET(cfg_entry));
43262306a36Sopenharmony_ci	list_add_tail(&cfg_entry->list, &dev_data->config_fields);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ciout:
43562306a36Sopenharmony_ci	if (err)
43662306a36Sopenharmony_ci		kfree(cfg_entry);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	return err;
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci/* This sets up the device's virtual configuration space to keep track of
44262306a36Sopenharmony_ci * certain registers (like the base address registers (BARs) so that we can
44362306a36Sopenharmony_ci * keep the client from manipulating them directly.
44462306a36Sopenharmony_ci */
44562306a36Sopenharmony_ciint xen_pcibk_config_init_dev(struct pci_dev *dev)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	int err = 0;
44862306a36Sopenharmony_ci	struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	dev_dbg(&dev->dev, "initializing virtual configuration space\n");
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	INIT_LIST_HEAD(&dev_data->config_fields);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	err = xen_pcibk_config_header_add_fields(dev);
45562306a36Sopenharmony_ci	if (err)
45662306a36Sopenharmony_ci		goto out;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	err = xen_pcibk_config_capability_add_fields(dev);
45962306a36Sopenharmony_ci	if (err)
46062306a36Sopenharmony_ci		goto out;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	err = xen_pcibk_config_quirks_init(dev);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ciout:
46562306a36Sopenharmony_ci	return err;
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ciint xen_pcibk_config_init(void)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	return xen_pcibk_config_capability_init();
47162306a36Sopenharmony_ci}
472