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