1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
230edc14bSKonrad Rzeszutek Wilk /*
330edc14bSKonrad Rzeszutek Wilk * PCI Backend - Handles the virtual fields in the configuration space headers.
430edc14bSKonrad Rzeszutek Wilk *
530edc14bSKonrad Rzeszutek Wilk * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
630edc14bSKonrad Rzeszutek Wilk */
730edc14bSKonrad Rzeszutek Wilk
8283c0972SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
969049454SBjorn Helgaas #define dev_fmt pr_fmt
10283c0972SJoe Perches
1130edc14bSKonrad Rzeszutek Wilk #include <linux/kernel.h>
1230edc14bSKonrad Rzeszutek Wilk #include <linux/pci.h>
1330edc14bSKonrad Rzeszutek Wilk #include "pciback.h"
1430edc14bSKonrad Rzeszutek Wilk #include "conf_space.h"
1530edc14bSKonrad Rzeszutek Wilk
16af6fc858SJan Beulich struct pci_cmd_info {
17af6fc858SJan Beulich u16 val;
18af6fc858SJan Beulich };
19af6fc858SJan Beulich
2030edc14bSKonrad Rzeszutek Wilk struct pci_bar_info {
2130edc14bSKonrad Rzeszutek Wilk u32 val;
2230edc14bSKonrad Rzeszutek Wilk u32 len_val;
2330edc14bSKonrad Rzeszutek Wilk int which;
2430edc14bSKonrad Rzeszutek Wilk };
2530edc14bSKonrad Rzeszutek Wilk
2630edc14bSKonrad Rzeszutek Wilk #define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
2730edc14bSKonrad Rzeszutek Wilk #define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
2830edc14bSKonrad Rzeszutek Wilk
29af6fc858SJan Beulich /* Bits guests are allowed to control in permissive mode. */
30af6fc858SJan Beulich #define PCI_COMMAND_GUEST (PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL| \
31af6fc858SJan Beulich PCI_COMMAND_INVALIDATE|PCI_COMMAND_VGA_PALETTE| \
32af6fc858SJan Beulich PCI_COMMAND_WAIT|PCI_COMMAND_FAST_BACK)
33af6fc858SJan Beulich
command_init(struct pci_dev * dev,int offset)34af6fc858SJan Beulich static void *command_init(struct pci_dev *dev, int offset)
35af6fc858SJan Beulich {
36af6fc858SJan Beulich struct pci_cmd_info *cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
37af6fc858SJan Beulich int err;
38af6fc858SJan Beulich
39af6fc858SJan Beulich if (!cmd)
40af6fc858SJan Beulich return ERR_PTR(-ENOMEM);
41af6fc858SJan Beulich
42af6fc858SJan Beulich err = pci_read_config_word(dev, PCI_COMMAND, &cmd->val);
43af6fc858SJan Beulich if (err) {
44af6fc858SJan Beulich kfree(cmd);
45af6fc858SJan Beulich return ERR_PTR(err);
46af6fc858SJan Beulich }
47af6fc858SJan Beulich
48af6fc858SJan Beulich return cmd;
49af6fc858SJan Beulich }
50af6fc858SJan Beulich
command_read(struct pci_dev * dev,int offset,u16 * value,void * data)51fd5b221bSZhao, Yu static int command_read(struct pci_dev *dev, int offset, u16 *value, void *data)
52fd5b221bSZhao, Yu {
53af6fc858SJan Beulich int ret = pci_read_config_word(dev, offset, value);
54af6fc858SJan Beulich const struct pci_cmd_info *cmd = data;
55fd5b221bSZhao, Yu
56af6fc858SJan Beulich *value &= PCI_COMMAND_GUEST;
57af6fc858SJan Beulich *value |= cmd->val & ~PCI_COMMAND_GUEST;
58fd5b221bSZhao, Yu
59fd5b221bSZhao, Yu return ret;
60fd5b221bSZhao, Yu }
61fd5b221bSZhao, Yu
command_write(struct pci_dev * dev,int offset,u16 value,void * data)6230edc14bSKonrad Rzeszutek Wilk static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
6330edc14bSKonrad Rzeszutek Wilk {
64a92336a1SKonrad Rzeszutek Wilk struct xen_pcibk_dev_data *dev_data;
6530edc14bSKonrad Rzeszutek Wilk int err;
66af6fc858SJan Beulich u16 val;
67af6fc858SJan Beulich struct pci_cmd_info *cmd = data;
6830edc14bSKonrad Rzeszutek Wilk
690513fe9eSKonrad Rzeszutek Wilk dev_data = pci_get_drvdata(dev);
7030edc14bSKonrad Rzeszutek Wilk if (!pci_is_enabled(dev) && is_enable_cmd(value)) {
714969a3a2SBoris Ostrovsky dev_dbg(&dev->dev, "enable\n");
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)) {
784969a3a2SBoris Ostrovsky dev_dbg(&dev->dev, "disable\n");
7930edc14bSKonrad Rzeszutek Wilk pci_disable_device(dev);
800513fe9eSKonrad Rzeszutek Wilk if (dev_data)
810513fe9eSKonrad Rzeszutek Wilk dev_data->enable_intx = 0;
8230edc14bSKonrad Rzeszutek Wilk }
8330edc14bSKonrad Rzeszutek Wilk
8430edc14bSKonrad Rzeszutek Wilk if (!dev->is_busmaster && is_master_cmd(value)) {
854969a3a2SBoris Ostrovsky dev_dbg(&dev->dev, "set bus master\n");
8630edc14bSKonrad Rzeszutek Wilk pci_set_master(dev);
87278edfc0SJan Beulich } else if (dev->is_busmaster && !is_master_cmd(value)) {
884969a3a2SBoris Ostrovsky dev_dbg(&dev->dev, "clear bus master\n");
89278edfc0SJan Beulich pci_clear_master(dev);
9030edc14bSKonrad Rzeszutek Wilk }
9130edc14bSKonrad Rzeszutek Wilk
92278edfc0SJan Beulich if (!(cmd->val & PCI_COMMAND_INVALIDATE) &&
93278edfc0SJan Beulich (value & PCI_COMMAND_INVALIDATE)) {
944969a3a2SBoris Ostrovsky dev_dbg(&dev->dev, "enable memory-write-invalidate\n");
9530edc14bSKonrad Rzeszutek Wilk err = pci_set_mwi(dev);
9630edc14bSKonrad Rzeszutek Wilk if (err) {
9769049454SBjorn Helgaas dev_warn(&dev->dev, "cannot enable memory-write-invalidate (%d)\n",
9869049454SBjorn Helgaas err);
9930edc14bSKonrad Rzeszutek Wilk value &= ~PCI_COMMAND_INVALIDATE;
10030edc14bSKonrad Rzeszutek Wilk }
101278edfc0SJan Beulich } else if ((cmd->val & PCI_COMMAND_INVALIDATE) &&
102278edfc0SJan Beulich !(value & PCI_COMMAND_INVALIDATE)) {
1034969a3a2SBoris Ostrovsky dev_dbg(&dev->dev, "disable memory-write-invalidate\n");
104278edfc0SJan Beulich pci_clear_mwi(dev);
10530edc14bSKonrad Rzeszutek Wilk }
10630edc14bSKonrad Rzeszutek Wilk
107*90e8b749SMarek Marczykowski-Górecki if (dev_data && dev_data->allow_interrupt_control &&
108*90e8b749SMarek Marczykowski-Górecki ((cmd->val ^ value) & PCI_COMMAND_INTX_DISABLE))
109*90e8b749SMarek Marczykowski-Górecki pci_intx(dev, !(value & PCI_COMMAND_INTX_DISABLE));
110476878e4SMarek Marczykowski-Górecki
111af6fc858SJan Beulich cmd->val = value;
112af6fc858SJan Beulich
1138014bcc8SBen Hutchings if (!xen_pcibk_permissive && (!dev_data || !dev_data->permissive))
114af6fc858SJan Beulich return 0;
115af6fc858SJan Beulich
116af6fc858SJan Beulich /* Only allow the guest to control certain bits. */
117af6fc858SJan Beulich err = pci_read_config_word(dev, offset, &val);
118af6fc858SJan Beulich if (err || val == value)
119af6fc858SJan Beulich return err;
120af6fc858SJan Beulich
121af6fc858SJan Beulich value &= PCI_COMMAND_GUEST;
122af6fc858SJan Beulich value |= val & ~PCI_COMMAND_GUEST;
123af6fc858SJan Beulich
12430edc14bSKonrad Rzeszutek Wilk return pci_write_config_word(dev, offset, value);
12530edc14bSKonrad Rzeszutek Wilk }
12630edc14bSKonrad Rzeszutek Wilk
rom_write(struct pci_dev * dev,int offset,u32 value,void * data)12730edc14bSKonrad Rzeszutek Wilk static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
12830edc14bSKonrad Rzeszutek Wilk {
12930edc14bSKonrad Rzeszutek Wilk struct pci_bar_info *bar = data;
13030edc14bSKonrad Rzeszutek Wilk
13130edc14bSKonrad Rzeszutek Wilk if (unlikely(!bar)) {
13269049454SBjorn Helgaas dev_warn(&dev->dev, "driver data not found\n");
13330edc14bSKonrad Rzeszutek Wilk return XEN_PCI_ERR_op_failed;
13430edc14bSKonrad Rzeszutek Wilk }
13530edc14bSKonrad Rzeszutek Wilk
13630edc14bSKonrad Rzeszutek Wilk /* A write to obtain the length must happen as a 32-bit write.
13730edc14bSKonrad Rzeszutek Wilk * This does not (yet) support writing individual bytes
13830edc14bSKonrad Rzeszutek Wilk */
139d2bd05d8SJan Beulich if ((value | ~PCI_ROM_ADDRESS_MASK) == ~0U)
14030edc14bSKonrad Rzeszutek Wilk bar->which = 1;
14130edc14bSKonrad Rzeszutek Wilk else {
14230edc14bSKonrad Rzeszutek Wilk u32 tmpval;
14330edc14bSKonrad Rzeszutek Wilk pci_read_config_dword(dev, offset, &tmpval);
14430edc14bSKonrad Rzeszutek Wilk if (tmpval != bar->val && value == bar->val) {
14530edc14bSKonrad Rzeszutek Wilk /* Allow restoration of bar value. */
14630edc14bSKonrad Rzeszutek Wilk pci_write_config_dword(dev, offset, bar->val);
14730edc14bSKonrad Rzeszutek Wilk }
14830edc14bSKonrad Rzeszutek Wilk bar->which = 0;
14930edc14bSKonrad Rzeszutek Wilk }
15030edc14bSKonrad Rzeszutek Wilk
15130edc14bSKonrad Rzeszutek Wilk /* Do we need to support enabling/disabling the rom address here? */
15230edc14bSKonrad Rzeszutek Wilk
15330edc14bSKonrad Rzeszutek Wilk return 0;
15430edc14bSKonrad Rzeszutek Wilk }
15530edc14bSKonrad Rzeszutek Wilk
15630edc14bSKonrad Rzeszutek Wilk /* For the BARs, only allow writes which write ~0 or
15730edc14bSKonrad Rzeszutek Wilk * the correct resource information
15830edc14bSKonrad Rzeszutek Wilk * (Needed for when the driver probes the resource usage)
15930edc14bSKonrad Rzeszutek Wilk */
bar_write(struct pci_dev * dev,int offset,u32 value,void * data)16030edc14bSKonrad Rzeszutek Wilk static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
16130edc14bSKonrad Rzeszutek Wilk {
16230edc14bSKonrad Rzeszutek Wilk struct pci_bar_info *bar = data;
1638c28ef3fSJan Beulich unsigned int pos = (offset - PCI_BASE_ADDRESS_0) / 4;
1648c28ef3fSJan Beulich const struct resource *res = dev->resource;
1658c28ef3fSJan Beulich u32 mask;
16630edc14bSKonrad Rzeszutek Wilk
16730edc14bSKonrad Rzeszutek Wilk if (unlikely(!bar)) {
16869049454SBjorn Helgaas dev_warn(&dev->dev, "driver data not found\n");
16930edc14bSKonrad Rzeszutek Wilk return XEN_PCI_ERR_op_failed;
17030edc14bSKonrad Rzeszutek Wilk }
17130edc14bSKonrad Rzeszutek Wilk
17230edc14bSKonrad Rzeszutek Wilk /* A write to obtain the length must happen as a 32-bit write.
17330edc14bSKonrad Rzeszutek Wilk * This does not (yet) support writing individual bytes
17430edc14bSKonrad Rzeszutek Wilk */
1758c28ef3fSJan Beulich if (res[pos].flags & IORESOURCE_IO)
1768c28ef3fSJan Beulich mask = ~PCI_BASE_ADDRESS_IO_MASK;
1778c28ef3fSJan Beulich else if (pos && (res[pos - 1].flags & IORESOURCE_MEM_64))
1788c28ef3fSJan Beulich mask = 0;
1798c28ef3fSJan Beulich else
1808c28ef3fSJan Beulich mask = ~PCI_BASE_ADDRESS_MEM_MASK;
1818c28ef3fSJan Beulich if ((value | mask) == ~0U)
18230edc14bSKonrad Rzeszutek Wilk bar->which = 1;
18330edc14bSKonrad Rzeszutek Wilk else {
18430edc14bSKonrad Rzeszutek Wilk u32 tmpval;
18530edc14bSKonrad Rzeszutek Wilk pci_read_config_dword(dev, offset, &tmpval);
18630edc14bSKonrad Rzeszutek Wilk if (tmpval != bar->val && value == bar->val) {
18730edc14bSKonrad Rzeszutek Wilk /* Allow restoration of bar value. */
18830edc14bSKonrad Rzeszutek Wilk pci_write_config_dword(dev, offset, bar->val);
18930edc14bSKonrad Rzeszutek Wilk }
19030edc14bSKonrad Rzeszutek Wilk bar->which = 0;
19130edc14bSKonrad Rzeszutek Wilk }
19230edc14bSKonrad Rzeszutek Wilk
19330edc14bSKonrad Rzeszutek Wilk return 0;
19430edc14bSKonrad Rzeszutek Wilk }
19530edc14bSKonrad Rzeszutek Wilk
bar_read(struct pci_dev * dev,int offset,u32 * value,void * data)19630edc14bSKonrad Rzeszutek Wilk static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
19730edc14bSKonrad Rzeszutek Wilk {
19830edc14bSKonrad Rzeszutek Wilk struct pci_bar_info *bar = data;
19930edc14bSKonrad Rzeszutek Wilk
20030edc14bSKonrad Rzeszutek Wilk if (unlikely(!bar)) {
20169049454SBjorn Helgaas dev_warn(&dev->dev, "driver data not found\n");
20230edc14bSKonrad Rzeszutek Wilk return XEN_PCI_ERR_op_failed;
20330edc14bSKonrad Rzeszutek Wilk }
20430edc14bSKonrad Rzeszutek Wilk
20530edc14bSKonrad Rzeszutek Wilk *value = bar->which ? bar->len_val : bar->val;
20630edc14bSKonrad Rzeszutek Wilk
20730edc14bSKonrad Rzeszutek Wilk return 0;
20830edc14bSKonrad Rzeszutek Wilk }
20930edc14bSKonrad Rzeszutek Wilk
bar_init(struct pci_dev * dev,int offset)2106ad2655dSJan Beulich static void *bar_init(struct pci_dev *dev, int offset)
21130edc14bSKonrad Rzeszutek Wilk {
21258520360SJan Beulich unsigned int pos;
21358520360SJan Beulich const struct resource *res = dev->resource;
2146ad2655dSJan Beulich struct pci_bar_info *bar = kzalloc(sizeof(*bar), GFP_KERNEL);
2156ad2655dSJan Beulich
2166ad2655dSJan Beulich if (!bar)
2176ad2655dSJan Beulich return ERR_PTR(-ENOMEM);
218fd5b221bSZhao, Yu
219fd5b221bSZhao, Yu if (offset == PCI_ROM_ADDRESS || offset == PCI_ROM_ADDRESS1)
220fd5b221bSZhao, Yu pos = PCI_ROM_RESOURCE;
221fd5b221bSZhao, Yu else {
222fd5b221bSZhao, Yu pos = (offset - PCI_BASE_ADDRESS_0) / 4;
223c8670c22SJan Beulich if (pos && (res[pos - 1].flags & IORESOURCE_MEM_64)) {
224a67efff2SOleksandr Andrushchenko /*
225a67efff2SOleksandr Andrushchenko * Use ">> 16 >> 16" instead of direct ">> 32" shift
226a67efff2SOleksandr Andrushchenko * to avoid warnings on 32-bit architectures.
227a67efff2SOleksandr Andrushchenko */
228a67efff2SOleksandr Andrushchenko bar->val = res[pos - 1].start >> 16 >> 16;
229a67efff2SOleksandr Andrushchenko bar->len_val = -resource_size(&res[pos - 1]) >> 16 >> 16;
2306ad2655dSJan Beulich return bar;
231fd5b221bSZhao, Yu }
232fd5b221bSZhao, Yu }
233fd5b221bSZhao, Yu
234d2bd05d8SJan Beulich if (!res[pos].flags ||
235d2bd05d8SJan Beulich (res[pos].flags & (IORESOURCE_DISABLED | IORESOURCE_UNSET |
236d2bd05d8SJan Beulich IORESOURCE_BUSY)))
2376ad2655dSJan Beulich return bar;
238d2bd05d8SJan Beulich
2396ad2655dSJan Beulich bar->val = res[pos].start |
240fd5b221bSZhao, Yu (res[pos].flags & PCI_REGION_FLAG_MASK);
2416ad2655dSJan Beulich bar->len_val = -resource_size(&res[pos]) |
242d2bd05d8SJan Beulich (res[pos].flags & PCI_REGION_FLAG_MASK);
24330edc14bSKonrad Rzeszutek Wilk
24430edc14bSKonrad Rzeszutek Wilk return bar;
24530edc14bSKonrad Rzeszutek Wilk }
24630edc14bSKonrad Rzeszutek Wilk
bar_reset(struct pci_dev * dev,int offset,void * data)24730edc14bSKonrad Rzeszutek Wilk static void bar_reset(struct pci_dev *dev, int offset, void *data)
24830edc14bSKonrad Rzeszutek Wilk {
24930edc14bSKonrad Rzeszutek Wilk struct pci_bar_info *bar = data;
25030edc14bSKonrad Rzeszutek Wilk
25130edc14bSKonrad Rzeszutek Wilk bar->which = 0;
25230edc14bSKonrad Rzeszutek Wilk }
25330edc14bSKonrad Rzeszutek Wilk
bar_release(struct pci_dev * dev,int offset,void * data)25430edc14bSKonrad Rzeszutek Wilk static void bar_release(struct pci_dev *dev, int offset, void *data)
25530edc14bSKonrad Rzeszutek Wilk {
25630edc14bSKonrad Rzeszutek Wilk kfree(data);
25730edc14bSKonrad Rzeszutek Wilk }
25830edc14bSKonrad Rzeszutek Wilk
xen_pcibk_read_vendor(struct pci_dev * dev,int offset,u16 * value,void * data)259a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_read_vendor(struct pci_dev *dev, int offset,
260fd5b221bSZhao, Yu u16 *value, void *data)
261fd5b221bSZhao, Yu {
262fd5b221bSZhao, Yu *value = dev->vendor;
263fd5b221bSZhao, Yu
264fd5b221bSZhao, Yu return 0;
265fd5b221bSZhao, Yu }
266fd5b221bSZhao, Yu
xen_pcibk_read_device(struct pci_dev * dev,int offset,u16 * value,void * data)267a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_read_device(struct pci_dev *dev, int offset,
268fd5b221bSZhao, Yu u16 *value, void *data)
269fd5b221bSZhao, Yu {
270fd5b221bSZhao, Yu *value = dev->device;
271fd5b221bSZhao, Yu
272fd5b221bSZhao, Yu return 0;
273fd5b221bSZhao, Yu }
274fd5b221bSZhao, Yu
interrupt_read(struct pci_dev * dev,int offset,u8 * value,void * data)27530edc14bSKonrad Rzeszutek Wilk static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
27630edc14bSKonrad Rzeszutek Wilk void *data)
27730edc14bSKonrad Rzeszutek Wilk {
27830edc14bSKonrad Rzeszutek Wilk *value = (u8) dev->irq;
27930edc14bSKonrad Rzeszutek Wilk
28030edc14bSKonrad Rzeszutek Wilk return 0;
28130edc14bSKonrad Rzeszutek Wilk }
28230edc14bSKonrad Rzeszutek Wilk
bist_write(struct pci_dev * dev,int offset,u8 value,void * data)28330edc14bSKonrad Rzeszutek Wilk static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data)
28430edc14bSKonrad Rzeszutek Wilk {
28530edc14bSKonrad Rzeszutek Wilk u8 cur_value;
28630edc14bSKonrad Rzeszutek Wilk int err;
28730edc14bSKonrad Rzeszutek Wilk
28830edc14bSKonrad Rzeszutek Wilk err = pci_read_config_byte(dev, offset, &cur_value);
28930edc14bSKonrad Rzeszutek Wilk if (err)
29030edc14bSKonrad Rzeszutek Wilk goto out;
29130edc14bSKonrad Rzeszutek Wilk
29230edc14bSKonrad Rzeszutek Wilk if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START)
29330edc14bSKonrad Rzeszutek Wilk || value == PCI_BIST_START)
29430edc14bSKonrad Rzeszutek Wilk err = pci_write_config_byte(dev, offset, value);
29530edc14bSKonrad Rzeszutek Wilk
29630edc14bSKonrad Rzeszutek Wilk out:
29730edc14bSKonrad Rzeszutek Wilk return err;
29830edc14bSKonrad Rzeszutek Wilk }
29930edc14bSKonrad Rzeszutek Wilk
30030edc14bSKonrad Rzeszutek Wilk static const struct config_field header_common[] = {
30130edc14bSKonrad Rzeszutek Wilk {
302fd5b221bSZhao, Yu .offset = PCI_VENDOR_ID,
303fd5b221bSZhao, Yu .size = 2,
304a92336a1SKonrad Rzeszutek Wilk .u.w.read = xen_pcibk_read_vendor,
305fd5b221bSZhao, Yu },
306fd5b221bSZhao, Yu {
307fd5b221bSZhao, Yu .offset = PCI_DEVICE_ID,
308fd5b221bSZhao, Yu .size = 2,
309a92336a1SKonrad Rzeszutek Wilk .u.w.read = xen_pcibk_read_device,
310fd5b221bSZhao, Yu },
311fd5b221bSZhao, Yu {
31230edc14bSKonrad Rzeszutek Wilk .offset = PCI_COMMAND,
31330edc14bSKonrad Rzeszutek Wilk .size = 2,
314af6fc858SJan Beulich .init = command_init,
315af6fc858SJan Beulich .release = bar_release,
316fd5b221bSZhao, Yu .u.w.read = command_read,
31730edc14bSKonrad Rzeszutek Wilk .u.w.write = command_write,
31830edc14bSKonrad Rzeszutek Wilk },
31930edc14bSKonrad Rzeszutek Wilk {
32030edc14bSKonrad Rzeszutek Wilk .offset = PCI_INTERRUPT_LINE,
32130edc14bSKonrad Rzeszutek Wilk .size = 1,
32230edc14bSKonrad Rzeszutek Wilk .u.b.read = interrupt_read,
32330edc14bSKonrad Rzeszutek Wilk },
32430edc14bSKonrad Rzeszutek Wilk {
32530edc14bSKonrad Rzeszutek Wilk .offset = PCI_INTERRUPT_PIN,
32630edc14bSKonrad Rzeszutek Wilk .size = 1,
327a92336a1SKonrad Rzeszutek Wilk .u.b.read = xen_pcibk_read_config_byte,
32830edc14bSKonrad Rzeszutek Wilk },
32930edc14bSKonrad Rzeszutek Wilk {
33030edc14bSKonrad Rzeszutek Wilk /* Any side effects of letting driver domain control cache line? */
33130edc14bSKonrad Rzeszutek Wilk .offset = PCI_CACHE_LINE_SIZE,
33230edc14bSKonrad Rzeszutek Wilk .size = 1,
333a92336a1SKonrad Rzeszutek Wilk .u.b.read = xen_pcibk_read_config_byte,
334a92336a1SKonrad Rzeszutek Wilk .u.b.write = xen_pcibk_write_config_byte,
33530edc14bSKonrad Rzeszutek Wilk },
33630edc14bSKonrad Rzeszutek Wilk {
33730edc14bSKonrad Rzeszutek Wilk .offset = PCI_LATENCY_TIMER,
33830edc14bSKonrad Rzeszutek Wilk .size = 1,
339a92336a1SKonrad Rzeszutek Wilk .u.b.read = xen_pcibk_read_config_byte,
34030edc14bSKonrad Rzeszutek Wilk },
34130edc14bSKonrad Rzeszutek Wilk {
34230edc14bSKonrad Rzeszutek Wilk .offset = PCI_BIST,
34330edc14bSKonrad Rzeszutek Wilk .size = 1,
344a92336a1SKonrad Rzeszutek Wilk .u.b.read = xen_pcibk_read_config_byte,
34530edc14bSKonrad Rzeszutek Wilk .u.b.write = bist_write,
34630edc14bSKonrad Rzeszutek Wilk },
34730edc14bSKonrad Rzeszutek Wilk {}
34830edc14bSKonrad Rzeszutek Wilk };
34930edc14bSKonrad Rzeszutek Wilk
35030edc14bSKonrad Rzeszutek Wilk #define CFG_FIELD_BAR(reg_offset) \
35130edc14bSKonrad Rzeszutek Wilk { \
35230edc14bSKonrad Rzeszutek Wilk .offset = reg_offset, \
35330edc14bSKonrad Rzeszutek Wilk .size = 4, \
35430edc14bSKonrad Rzeszutek Wilk .init = bar_init, \
35530edc14bSKonrad Rzeszutek Wilk .reset = bar_reset, \
35630edc14bSKonrad Rzeszutek Wilk .release = bar_release, \
35730edc14bSKonrad Rzeszutek Wilk .u.dw.read = bar_read, \
35830edc14bSKonrad Rzeszutek Wilk .u.dw.write = bar_write, \
35930edc14bSKonrad Rzeszutek Wilk }
36030edc14bSKonrad Rzeszutek Wilk
36130edc14bSKonrad Rzeszutek Wilk #define CFG_FIELD_ROM(reg_offset) \
36230edc14bSKonrad Rzeszutek Wilk { \
36330edc14bSKonrad Rzeszutek Wilk .offset = reg_offset, \
36430edc14bSKonrad Rzeszutek Wilk .size = 4, \
365664093bbSJan Beulich .init = bar_init, \
36630edc14bSKonrad Rzeszutek Wilk .reset = bar_reset, \
36730edc14bSKonrad Rzeszutek Wilk .release = bar_release, \
36830edc14bSKonrad Rzeszutek Wilk .u.dw.read = bar_read, \
36930edc14bSKonrad Rzeszutek Wilk .u.dw.write = rom_write, \
37030edc14bSKonrad Rzeszutek Wilk }
37130edc14bSKonrad Rzeszutek Wilk
37230edc14bSKonrad Rzeszutek Wilk static const struct config_field header_0[] = {
37330edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
37430edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
37530edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
37630edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
37730edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
37830edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
37930edc14bSKonrad Rzeszutek Wilk CFG_FIELD_ROM(PCI_ROM_ADDRESS),
38030edc14bSKonrad Rzeszutek Wilk {}
38130edc14bSKonrad Rzeszutek Wilk };
38230edc14bSKonrad Rzeszutek Wilk
38330edc14bSKonrad Rzeszutek Wilk static const struct config_field header_1[] = {
38430edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
38530edc14bSKonrad Rzeszutek Wilk CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
38630edc14bSKonrad Rzeszutek Wilk CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
38730edc14bSKonrad Rzeszutek Wilk {}
38830edc14bSKonrad Rzeszutek Wilk };
38930edc14bSKonrad Rzeszutek Wilk
xen_pcibk_config_header_add_fields(struct pci_dev * dev)390a92336a1SKonrad Rzeszutek Wilk int xen_pcibk_config_header_add_fields(struct pci_dev *dev)
39130edc14bSKonrad Rzeszutek Wilk {
39230edc14bSKonrad Rzeszutek Wilk int err;
39330edc14bSKonrad Rzeszutek Wilk
394a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_config_add_fields(dev, header_common);
39530edc14bSKonrad Rzeszutek Wilk if (err)
39630edc14bSKonrad Rzeszutek Wilk goto out;
39730edc14bSKonrad Rzeszutek Wilk
39830edc14bSKonrad Rzeszutek Wilk switch (dev->hdr_type) {
39930edc14bSKonrad Rzeszutek Wilk case PCI_HEADER_TYPE_NORMAL:
400a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_config_add_fields(dev, header_0);
40130edc14bSKonrad Rzeszutek Wilk break;
40230edc14bSKonrad Rzeszutek Wilk
40330edc14bSKonrad Rzeszutek Wilk case PCI_HEADER_TYPE_BRIDGE:
404a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_config_add_fields(dev, header_1);
40530edc14bSKonrad Rzeszutek Wilk break;
40630edc14bSKonrad Rzeszutek Wilk
40730edc14bSKonrad Rzeszutek Wilk default:
40830edc14bSKonrad Rzeszutek Wilk err = -EINVAL;
40969049454SBjorn Helgaas dev_err(&dev->dev, "Unsupported header type %d!\n",
41069049454SBjorn Helgaas dev->hdr_type);
41130edc14bSKonrad Rzeszutek Wilk break;
41230edc14bSKonrad Rzeszutek Wilk }
41330edc14bSKonrad Rzeszutek Wilk
41430edc14bSKonrad Rzeszutek Wilk out:
41530edc14bSKonrad Rzeszutek Wilk return err;
41630edc14bSKonrad Rzeszutek Wilk }
417