11cf4323eSThomas Huth /*
21cf4323eSThomas Huth * libqos PCI bindings
31cf4323eSThomas Huth *
41cf4323eSThomas Huth * Copyright IBM, Corp. 2012-2013
51cf4323eSThomas Huth *
61cf4323eSThomas Huth * Authors:
71cf4323eSThomas Huth * Anthony Liguori <aliguori@us.ibm.com>
81cf4323eSThomas Huth *
91cf4323eSThomas Huth * This work is licensed under the terms of the GNU GPL, version 2 or later.
101cf4323eSThomas Huth * See the COPYING file in the top-level directory.
111cf4323eSThomas Huth */
121cf4323eSThomas Huth
131cf4323eSThomas Huth #include "qemu/osdep.h"
14a2ce7dbdSPaolo Bonzini #include "pci.h"
151cf4323eSThomas Huth
16efe84f03SLaurent Vivier #include "hw/pci/pci.h"
17efe84f03SLaurent Vivier #include "hw/pci/pci_bridge.h"
181cf4323eSThomas Huth #include "hw/pci/pci_regs.h"
191cf4323eSThomas Huth #include "qemu/host-utils.h"
20a2ce7dbdSPaolo Bonzini #include "qgraph.h"
211cf4323eSThomas Huth
qpci_device_foreach(QPCIBus * bus,int vendor_id,int device_id,void (* func)(QPCIDevice * dev,int devfn,void * data),void * data)221cf4323eSThomas Huth void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id,
231cf4323eSThomas Huth void (*func)(QPCIDevice *dev, int devfn, void *data),
241cf4323eSThomas Huth void *data)
251cf4323eSThomas Huth {
261cf4323eSThomas Huth int slot;
271cf4323eSThomas Huth
281cf4323eSThomas Huth for (slot = 0; slot < 32; slot++) {
291cf4323eSThomas Huth int fn;
301cf4323eSThomas Huth
311cf4323eSThomas Huth for (fn = 0; fn < 8; fn++) {
321cf4323eSThomas Huth QPCIDevice *dev;
331cf4323eSThomas Huth
341cf4323eSThomas Huth dev = qpci_device_find(bus, QPCI_DEVFN(slot, fn));
351cf4323eSThomas Huth if (!dev) {
361cf4323eSThomas Huth continue;
371cf4323eSThomas Huth }
381cf4323eSThomas Huth
391cf4323eSThomas Huth if (vendor_id != -1 &&
401cf4323eSThomas Huth qpci_config_readw(dev, PCI_VENDOR_ID) != vendor_id) {
411cf4323eSThomas Huth g_free(dev);
421cf4323eSThomas Huth continue;
431cf4323eSThomas Huth }
441cf4323eSThomas Huth
451cf4323eSThomas Huth if (device_id != -1 &&
461cf4323eSThomas Huth qpci_config_readw(dev, PCI_DEVICE_ID) != device_id) {
471cf4323eSThomas Huth g_free(dev);
481cf4323eSThomas Huth continue;
491cf4323eSThomas Huth }
501cf4323eSThomas Huth
511cf4323eSThomas Huth func(dev, QPCI_DEVFN(slot, fn), data);
521cf4323eSThomas Huth }
531cf4323eSThomas Huth }
541cf4323eSThomas Huth }
551cf4323eSThomas Huth
qpci_has_buggy_msi(QPCIDevice * dev)561cf4323eSThomas Huth bool qpci_has_buggy_msi(QPCIDevice *dev)
571cf4323eSThomas Huth {
581cf4323eSThomas Huth return dev->bus->has_buggy_msi;
591cf4323eSThomas Huth }
601cf4323eSThomas Huth
qpci_check_buggy_msi(QPCIDevice * dev)611cf4323eSThomas Huth bool qpci_check_buggy_msi(QPCIDevice *dev)
621cf4323eSThomas Huth {
631cf4323eSThomas Huth if (qpci_has_buggy_msi(dev)) {
641cf4323eSThomas Huth g_test_skip("Skipping due to incomplete support for MSI");
651cf4323eSThomas Huth return true;
661cf4323eSThomas Huth }
671cf4323eSThomas Huth return false;
681cf4323eSThomas Huth }
691cf4323eSThomas Huth
qpci_device_set(QPCIDevice * dev,QPCIBus * bus,int devfn)701cf4323eSThomas Huth static void qpci_device_set(QPCIDevice *dev, QPCIBus *bus, int devfn)
711cf4323eSThomas Huth {
721cf4323eSThomas Huth g_assert(dev);
731cf4323eSThomas Huth
741cf4323eSThomas Huth dev->bus = bus;
751cf4323eSThomas Huth dev->devfn = devfn;
761cf4323eSThomas Huth }
771cf4323eSThomas Huth
qpci_device_find(QPCIBus * bus,int devfn)781cf4323eSThomas Huth QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn)
791cf4323eSThomas Huth {
801cf4323eSThomas Huth QPCIDevice *dev;
811cf4323eSThomas Huth
821cf4323eSThomas Huth dev = g_malloc0(sizeof(*dev));
831cf4323eSThomas Huth qpci_device_set(dev, bus, devfn);
841cf4323eSThomas Huth
851cf4323eSThomas Huth if (qpci_config_readw(dev, PCI_VENDOR_ID) == 0xFFFF) {
861cf4323eSThomas Huth g_free(dev);
871cf4323eSThomas Huth return NULL;
881cf4323eSThomas Huth }
891cf4323eSThomas Huth
901cf4323eSThomas Huth return dev;
911cf4323eSThomas Huth }
921cf4323eSThomas Huth
qpci_device_init(QPCIDevice * dev,QPCIBus * bus,QPCIAddress * addr)931cf4323eSThomas Huth void qpci_device_init(QPCIDevice *dev, QPCIBus *bus, QPCIAddress *addr)
941cf4323eSThomas Huth {
951cf4323eSThomas Huth uint16_t vendor_id, device_id;
961cf4323eSThomas Huth
971cf4323eSThomas Huth qpci_device_set(dev, bus, addr->devfn);
981cf4323eSThomas Huth vendor_id = qpci_config_readw(dev, PCI_VENDOR_ID);
991cf4323eSThomas Huth device_id = qpci_config_readw(dev, PCI_DEVICE_ID);
1001cf4323eSThomas Huth g_assert(!addr->vendor_id || vendor_id == addr->vendor_id);
1011cf4323eSThomas Huth g_assert(!addr->device_id || device_id == addr->device_id);
1021cf4323eSThomas Huth }
1031cf4323eSThomas Huth
qpci_find_resource_reserve_capability(QPCIDevice * dev)104efe84f03SLaurent Vivier static uint8_t qpci_find_resource_reserve_capability(QPCIDevice *dev)
105efe84f03SLaurent Vivier {
106efe84f03SLaurent Vivier uint16_t device_id;
107efe84f03SLaurent Vivier uint8_t cap = 0;
108efe84f03SLaurent Vivier
109efe84f03SLaurent Vivier if (qpci_config_readw(dev, PCI_VENDOR_ID) != PCI_VENDOR_ID_REDHAT) {
110efe84f03SLaurent Vivier return 0;
111efe84f03SLaurent Vivier }
112efe84f03SLaurent Vivier
113efe84f03SLaurent Vivier device_id = qpci_config_readw(dev, PCI_DEVICE_ID);
114efe84f03SLaurent Vivier
115efe84f03SLaurent Vivier if (device_id != PCI_DEVICE_ID_REDHAT_PCIE_RP &&
116efe84f03SLaurent Vivier device_id != PCI_DEVICE_ID_REDHAT_BRIDGE) {
117efe84f03SLaurent Vivier return 0;
118efe84f03SLaurent Vivier }
119efe84f03SLaurent Vivier
120efe84f03SLaurent Vivier do {
121efe84f03SLaurent Vivier cap = qpci_find_capability(dev, PCI_CAP_ID_VNDR, cap);
122efe84f03SLaurent Vivier } while (cap &&
123efe84f03SLaurent Vivier qpci_config_readb(dev, cap + REDHAT_PCI_CAP_TYPE_OFFSET) !=
124efe84f03SLaurent Vivier REDHAT_PCI_CAP_RESOURCE_RESERVE);
125efe84f03SLaurent Vivier if (cap) {
126efe84f03SLaurent Vivier uint8_t cap_len = qpci_config_readb(dev, cap + PCI_CAP_FLAGS);
127efe84f03SLaurent Vivier if (cap_len < REDHAT_PCI_CAP_RES_RESERVE_CAP_SIZE) {
128efe84f03SLaurent Vivier return 0;
129efe84f03SLaurent Vivier }
130efe84f03SLaurent Vivier }
131efe84f03SLaurent Vivier return cap;
132efe84f03SLaurent Vivier }
133efe84f03SLaurent Vivier
qpci_secondary_buses_rec(QPCIBus * qbus,int bus,int * pci_bus)134efe84f03SLaurent Vivier static void qpci_secondary_buses_rec(QPCIBus *qbus, int bus, int *pci_bus)
135efe84f03SLaurent Vivier {
136efe84f03SLaurent Vivier QPCIDevice *dev;
137efe84f03SLaurent Vivier uint16_t class;
138efe84f03SLaurent Vivier uint8_t pribus, secbus, subbus;
139efe84f03SLaurent Vivier int index;
140efe84f03SLaurent Vivier
141efe84f03SLaurent Vivier for (index = 0; index < 32; index++) {
142efe84f03SLaurent Vivier dev = qpci_device_find(qbus, QPCI_DEVFN(bus + index, 0));
143efe84f03SLaurent Vivier if (dev == NULL) {
144efe84f03SLaurent Vivier continue;
145efe84f03SLaurent Vivier }
146efe84f03SLaurent Vivier class = qpci_config_readw(dev, PCI_CLASS_DEVICE);
147efe84f03SLaurent Vivier if (class == PCI_CLASS_BRIDGE_PCI) {
148efe84f03SLaurent Vivier qpci_config_writeb(dev, PCI_SECONDARY_BUS, 255);
149efe84f03SLaurent Vivier qpci_config_writeb(dev, PCI_SUBORDINATE_BUS, 0);
150efe84f03SLaurent Vivier }
151efe84f03SLaurent Vivier g_free(dev);
152efe84f03SLaurent Vivier }
153efe84f03SLaurent Vivier
154efe84f03SLaurent Vivier for (index = 0; index < 32; index++) {
155efe84f03SLaurent Vivier dev = qpci_device_find(qbus, QPCI_DEVFN(bus + index, 0));
156efe84f03SLaurent Vivier if (dev == NULL) {
157efe84f03SLaurent Vivier continue;
158efe84f03SLaurent Vivier }
159efe84f03SLaurent Vivier class = qpci_config_readw(dev, PCI_CLASS_DEVICE);
160efe84f03SLaurent Vivier if (class != PCI_CLASS_BRIDGE_PCI) {
161efe84f03SLaurent Vivier g_free(dev);
162efe84f03SLaurent Vivier continue;
163efe84f03SLaurent Vivier }
164efe84f03SLaurent Vivier
165efe84f03SLaurent Vivier pribus = qpci_config_readb(dev, PCI_PRIMARY_BUS);
166efe84f03SLaurent Vivier if (pribus != bus) {
167efe84f03SLaurent Vivier qpci_config_writeb(dev, PCI_PRIMARY_BUS, bus);
168efe84f03SLaurent Vivier }
169efe84f03SLaurent Vivier
170efe84f03SLaurent Vivier secbus = qpci_config_readb(dev, PCI_SECONDARY_BUS);
171efe84f03SLaurent Vivier (*pci_bus)++;
172efe84f03SLaurent Vivier if (*pci_bus != secbus) {
173efe84f03SLaurent Vivier secbus = *pci_bus;
174efe84f03SLaurent Vivier qpci_config_writeb(dev, PCI_SECONDARY_BUS, secbus);
175efe84f03SLaurent Vivier }
176efe84f03SLaurent Vivier
177efe84f03SLaurent Vivier subbus = qpci_config_readb(dev, PCI_SUBORDINATE_BUS);
178efe84f03SLaurent Vivier qpci_config_writeb(dev, PCI_SUBORDINATE_BUS, 255);
179efe84f03SLaurent Vivier
180efe84f03SLaurent Vivier qpci_secondary_buses_rec(qbus, secbus << 5, pci_bus);
181efe84f03SLaurent Vivier
182efe84f03SLaurent Vivier if (subbus != *pci_bus) {
183efe84f03SLaurent Vivier uint8_t res_bus = *pci_bus;
184efe84f03SLaurent Vivier uint8_t cap = qpci_find_resource_reserve_capability(dev);
185efe84f03SLaurent Vivier
186efe84f03SLaurent Vivier if (cap) {
187efe84f03SLaurent Vivier uint32_t tmp_res_bus;
188efe84f03SLaurent Vivier
189efe84f03SLaurent Vivier tmp_res_bus = qpci_config_readl(dev, cap +
190efe84f03SLaurent Vivier REDHAT_PCI_CAP_RES_RESERVE_BUS_RES);
191efe84f03SLaurent Vivier if (tmp_res_bus != (uint32_t)-1) {
192efe84f03SLaurent Vivier res_bus = tmp_res_bus & 0xFF;
193efe84f03SLaurent Vivier if ((uint8_t)(res_bus + secbus) < secbus ||
194efe84f03SLaurent Vivier (uint8_t)(res_bus + secbus) < res_bus) {
195efe84f03SLaurent Vivier res_bus = 0;
196efe84f03SLaurent Vivier }
197efe84f03SLaurent Vivier if (secbus + res_bus > *pci_bus) {
198efe84f03SLaurent Vivier res_bus = secbus + res_bus;
199efe84f03SLaurent Vivier }
200efe84f03SLaurent Vivier }
201efe84f03SLaurent Vivier }
202efe84f03SLaurent Vivier subbus = res_bus;
203efe84f03SLaurent Vivier *pci_bus = res_bus;
204efe84f03SLaurent Vivier }
205efe84f03SLaurent Vivier
206efe84f03SLaurent Vivier qpci_config_writeb(dev, PCI_SUBORDINATE_BUS, subbus);
207efe84f03SLaurent Vivier g_free(dev);
208efe84f03SLaurent Vivier }
209efe84f03SLaurent Vivier }
210efe84f03SLaurent Vivier
qpci_secondary_buses_init(QPCIBus * bus)211efe84f03SLaurent Vivier int qpci_secondary_buses_init(QPCIBus *bus)
212efe84f03SLaurent Vivier {
213efe84f03SLaurent Vivier int last_bus = 0;
214efe84f03SLaurent Vivier
215efe84f03SLaurent Vivier qpci_secondary_buses_rec(bus, 0, &last_bus);
216efe84f03SLaurent Vivier
217efe84f03SLaurent Vivier return last_bus;
218efe84f03SLaurent Vivier }
219efe84f03SLaurent Vivier
220efe84f03SLaurent Vivier
qpci_device_enable(QPCIDevice * dev)2211cf4323eSThomas Huth void qpci_device_enable(QPCIDevice *dev)
2221cf4323eSThomas Huth {
2231cf4323eSThomas Huth uint16_t cmd;
2241cf4323eSThomas Huth
2251cf4323eSThomas Huth /* FIXME -- does this need to be a bus callout? */
2261cf4323eSThomas Huth cmd = qpci_config_readw(dev, PCI_COMMAND);
2271cf4323eSThomas Huth cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
2281cf4323eSThomas Huth qpci_config_writew(dev, PCI_COMMAND, cmd);
2291cf4323eSThomas Huth
2301cf4323eSThomas Huth /* Verify the bits are now set. */
2311cf4323eSThomas Huth cmd = qpci_config_readw(dev, PCI_COMMAND);
2321cf4323eSThomas Huth g_assert_cmphex(cmd & PCI_COMMAND_IO, ==, PCI_COMMAND_IO);
2331cf4323eSThomas Huth g_assert_cmphex(cmd & PCI_COMMAND_MEMORY, ==, PCI_COMMAND_MEMORY);
2341cf4323eSThomas Huth g_assert_cmphex(cmd & PCI_COMMAND_MASTER, ==, PCI_COMMAND_MASTER);
2351cf4323eSThomas Huth }
2361cf4323eSThomas Huth
2371cf4323eSThomas Huth /**
2381cf4323eSThomas Huth * qpci_find_capability:
2391cf4323eSThomas Huth * @dev: the PCI device
2401cf4323eSThomas Huth * @id: the PCI Capability ID (PCI_CAP_ID_*)
2411cf4323eSThomas Huth * @start_addr: 0 to begin iteration or the last return value to continue
2421cf4323eSThomas Huth * iteration
2431cf4323eSThomas Huth *
2441cf4323eSThomas Huth * Iterate over the PCI Capabilities List.
2451cf4323eSThomas Huth *
2461cf4323eSThomas Huth * Returns: PCI Configuration Space offset of the capabililty structure or
2471cf4323eSThomas Huth * 0 if no further matching capability is found
2481cf4323eSThomas Huth */
qpci_find_capability(QPCIDevice * dev,uint8_t id,uint8_t start_addr)2491cf4323eSThomas Huth uint8_t qpci_find_capability(QPCIDevice *dev, uint8_t id, uint8_t start_addr)
2501cf4323eSThomas Huth {
2511cf4323eSThomas Huth uint8_t cap;
2521cf4323eSThomas Huth uint8_t addr;
2531cf4323eSThomas Huth
2541cf4323eSThomas Huth if (start_addr) {
2551cf4323eSThomas Huth addr = qpci_config_readb(dev, start_addr + PCI_CAP_LIST_NEXT);
2561cf4323eSThomas Huth } else {
2571cf4323eSThomas Huth addr = qpci_config_readb(dev, PCI_CAPABILITY_LIST);
2581cf4323eSThomas Huth }
2591cf4323eSThomas Huth
2601cf4323eSThomas Huth do {
2611cf4323eSThomas Huth cap = qpci_config_readb(dev, addr);
2621cf4323eSThomas Huth if (cap != id) {
2631cf4323eSThomas Huth addr = qpci_config_readb(dev, addr + PCI_CAP_LIST_NEXT);
2641cf4323eSThomas Huth }
2651cf4323eSThomas Huth } while (cap != id && addr != 0);
2661cf4323eSThomas Huth
2671cf4323eSThomas Huth return addr;
2681cf4323eSThomas Huth }
2691cf4323eSThomas Huth
qpci_msix_enable(QPCIDevice * dev)2701cf4323eSThomas Huth void qpci_msix_enable(QPCIDevice *dev)
2711cf4323eSThomas Huth {
2721cf4323eSThomas Huth uint8_t addr;
2731cf4323eSThomas Huth uint16_t val;
2741cf4323eSThomas Huth uint32_t table;
2751cf4323eSThomas Huth uint8_t bir_table;
2761cf4323eSThomas Huth uint8_t bir_pba;
2771cf4323eSThomas Huth
2781cf4323eSThomas Huth addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX, 0);
2791cf4323eSThomas Huth g_assert_cmphex(addr, !=, 0);
2801cf4323eSThomas Huth
2811cf4323eSThomas Huth val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
2821cf4323eSThomas Huth qpci_config_writew(dev, addr + PCI_MSIX_FLAGS, val | PCI_MSIX_FLAGS_ENABLE);
2831cf4323eSThomas Huth
2841cf4323eSThomas Huth table = qpci_config_readl(dev, addr + PCI_MSIX_TABLE);
2851cf4323eSThomas Huth bir_table = table & PCI_MSIX_FLAGS_BIRMASK;
2861cf4323eSThomas Huth dev->msix_table_bar = qpci_iomap(dev, bir_table, NULL);
2871cf4323eSThomas Huth dev->msix_table_off = table & ~PCI_MSIX_FLAGS_BIRMASK;
2881cf4323eSThomas Huth
2891cf4323eSThomas Huth table = qpci_config_readl(dev, addr + PCI_MSIX_PBA);
2901cf4323eSThomas Huth bir_pba = table & PCI_MSIX_FLAGS_BIRMASK;
2911cf4323eSThomas Huth if (bir_pba != bir_table) {
2921cf4323eSThomas Huth dev->msix_pba_bar = qpci_iomap(dev, bir_pba, NULL);
2931cf4323eSThomas Huth } else {
2941cf4323eSThomas Huth dev->msix_pba_bar = dev->msix_table_bar;
2951cf4323eSThomas Huth }
2961cf4323eSThomas Huth dev->msix_pba_off = table & ~PCI_MSIX_FLAGS_BIRMASK;
2971cf4323eSThomas Huth
2981cf4323eSThomas Huth dev->msix_enabled = true;
2991cf4323eSThomas Huth }
3001cf4323eSThomas Huth
qpci_msix_disable(QPCIDevice * dev)3011cf4323eSThomas Huth void qpci_msix_disable(QPCIDevice *dev)
3021cf4323eSThomas Huth {
3031cf4323eSThomas Huth uint8_t addr;
3041cf4323eSThomas Huth uint16_t val;
3051cf4323eSThomas Huth
3061cf4323eSThomas Huth g_assert(dev->msix_enabled);
3071cf4323eSThomas Huth addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX, 0);
3081cf4323eSThomas Huth g_assert_cmphex(addr, !=, 0);
3091cf4323eSThomas Huth val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
3101cf4323eSThomas Huth qpci_config_writew(dev, addr + PCI_MSIX_FLAGS,
3111cf4323eSThomas Huth val & ~PCI_MSIX_FLAGS_ENABLE);
3121cf4323eSThomas Huth
3131cf4323eSThomas Huth if (dev->msix_pba_bar.addr != dev->msix_table_bar.addr) {
3141cf4323eSThomas Huth qpci_iounmap(dev, dev->msix_pba_bar);
3151cf4323eSThomas Huth }
3161cf4323eSThomas Huth qpci_iounmap(dev, dev->msix_table_bar);
3171cf4323eSThomas Huth
3181cf4323eSThomas Huth dev->msix_enabled = 0;
3191cf4323eSThomas Huth dev->msix_table_off = 0;
3201cf4323eSThomas Huth dev->msix_pba_off = 0;
3211cf4323eSThomas Huth }
3221cf4323eSThomas Huth
qpci_msix_pending(QPCIDevice * dev,uint16_t entry)3231cf4323eSThomas Huth bool qpci_msix_pending(QPCIDevice *dev, uint16_t entry)
3241cf4323eSThomas Huth {
3251cf4323eSThomas Huth uint32_t pba_entry;
3261cf4323eSThomas Huth uint8_t bit_n = entry % 32;
3271cf4323eSThomas Huth uint64_t off = (entry / 32) * PCI_MSIX_ENTRY_SIZE / 4;
3281cf4323eSThomas Huth
3291cf4323eSThomas Huth g_assert(dev->msix_enabled);
3301cf4323eSThomas Huth pba_entry = qpci_io_readl(dev, dev->msix_pba_bar, dev->msix_pba_off + off);
3311cf4323eSThomas Huth qpci_io_writel(dev, dev->msix_pba_bar, dev->msix_pba_off + off,
3321cf4323eSThomas Huth pba_entry & ~(1 << bit_n));
3331cf4323eSThomas Huth return (pba_entry & (1 << bit_n)) != 0;
3341cf4323eSThomas Huth }
3351cf4323eSThomas Huth
qpci_msix_masked(QPCIDevice * dev,uint16_t entry)3361cf4323eSThomas Huth bool qpci_msix_masked(QPCIDevice *dev, uint16_t entry)
3371cf4323eSThomas Huth {
3381cf4323eSThomas Huth uint8_t addr;
3391cf4323eSThomas Huth uint16_t val;
3401cf4323eSThomas Huth uint64_t vector_off = dev->msix_table_off + entry * PCI_MSIX_ENTRY_SIZE;
3411cf4323eSThomas Huth
3421cf4323eSThomas Huth g_assert(dev->msix_enabled);
3431cf4323eSThomas Huth addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX, 0);
3441cf4323eSThomas Huth g_assert_cmphex(addr, !=, 0);
3451cf4323eSThomas Huth val = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
3461cf4323eSThomas Huth
3471cf4323eSThomas Huth if (val & PCI_MSIX_FLAGS_MASKALL) {
3481cf4323eSThomas Huth return true;
3491cf4323eSThomas Huth } else {
3501cf4323eSThomas Huth return (qpci_io_readl(dev, dev->msix_table_bar,
3511cf4323eSThomas Huth vector_off + PCI_MSIX_ENTRY_VECTOR_CTRL)
3521cf4323eSThomas Huth & PCI_MSIX_ENTRY_CTRL_MASKBIT) != 0;
3531cf4323eSThomas Huth }
3541cf4323eSThomas Huth }
3551cf4323eSThomas Huth
qpci_msix_table_size(QPCIDevice * dev)3561cf4323eSThomas Huth uint16_t qpci_msix_table_size(QPCIDevice *dev)
3571cf4323eSThomas Huth {
3581cf4323eSThomas Huth uint8_t addr;
3591cf4323eSThomas Huth uint16_t control;
3601cf4323eSThomas Huth
3611cf4323eSThomas Huth addr = qpci_find_capability(dev, PCI_CAP_ID_MSIX, 0);
3621cf4323eSThomas Huth g_assert_cmphex(addr, !=, 0);
3631cf4323eSThomas Huth
3641cf4323eSThomas Huth control = qpci_config_readw(dev, addr + PCI_MSIX_FLAGS);
3651cf4323eSThomas Huth return (control & PCI_MSIX_FLAGS_QSIZE) + 1;
3661cf4323eSThomas Huth }
3671cf4323eSThomas Huth
qpci_config_readb(QPCIDevice * dev,uint8_t offset)3681cf4323eSThomas Huth uint8_t qpci_config_readb(QPCIDevice *dev, uint8_t offset)
3691cf4323eSThomas Huth {
3701cf4323eSThomas Huth return dev->bus->config_readb(dev->bus, dev->devfn, offset);
3711cf4323eSThomas Huth }
3721cf4323eSThomas Huth
qpci_config_readw(QPCIDevice * dev,uint8_t offset)3731cf4323eSThomas Huth uint16_t qpci_config_readw(QPCIDevice *dev, uint8_t offset)
3741cf4323eSThomas Huth {
3751cf4323eSThomas Huth return dev->bus->config_readw(dev->bus, dev->devfn, offset);
3761cf4323eSThomas Huth }
3771cf4323eSThomas Huth
qpci_config_readl(QPCIDevice * dev,uint8_t offset)3781cf4323eSThomas Huth uint32_t qpci_config_readl(QPCIDevice *dev, uint8_t offset)
3791cf4323eSThomas Huth {
3801cf4323eSThomas Huth return dev->bus->config_readl(dev->bus, dev->devfn, offset);
3811cf4323eSThomas Huth }
3821cf4323eSThomas Huth
3831cf4323eSThomas Huth
qpci_config_writeb(QPCIDevice * dev,uint8_t offset,uint8_t value)3841cf4323eSThomas Huth void qpci_config_writeb(QPCIDevice *dev, uint8_t offset, uint8_t value)
3851cf4323eSThomas Huth {
3861cf4323eSThomas Huth dev->bus->config_writeb(dev->bus, dev->devfn, offset, value);
3871cf4323eSThomas Huth }
3881cf4323eSThomas Huth
qpci_config_writew(QPCIDevice * dev,uint8_t offset,uint16_t value)3891cf4323eSThomas Huth void qpci_config_writew(QPCIDevice *dev, uint8_t offset, uint16_t value)
3901cf4323eSThomas Huth {
3911cf4323eSThomas Huth dev->bus->config_writew(dev->bus, dev->devfn, offset, value);
3921cf4323eSThomas Huth }
3931cf4323eSThomas Huth
qpci_config_writel(QPCIDevice * dev,uint8_t offset,uint32_t value)3941cf4323eSThomas Huth void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value)
3951cf4323eSThomas Huth {
3961cf4323eSThomas Huth dev->bus->config_writel(dev->bus, dev->devfn, offset, value);
3971cf4323eSThomas Huth }
3981cf4323eSThomas Huth
qpci_io_readb(QPCIDevice * dev,QPCIBar token,uint64_t off)3991cf4323eSThomas Huth uint8_t qpci_io_readb(QPCIDevice *dev, QPCIBar token, uint64_t off)
4001cf4323eSThomas Huth {
401*3df72d1cSEric Auger QPCIBus *bus = dev->bus;
402*3df72d1cSEric Auger
403*3df72d1cSEric Auger if (token.is_io) {
404*3df72d1cSEric Auger return bus->pio_readb(bus, token.addr + off);
4051cf4323eSThomas Huth } else {
4061cf4323eSThomas Huth uint8_t val;
407*3df72d1cSEric Auger
408*3df72d1cSEric Auger bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
4091cf4323eSThomas Huth return val;
4101cf4323eSThomas Huth }
4111cf4323eSThomas Huth }
4121cf4323eSThomas Huth
qpci_io_readw(QPCIDevice * dev,QPCIBar token,uint64_t off)4131cf4323eSThomas Huth uint16_t qpci_io_readw(QPCIDevice *dev, QPCIBar token, uint64_t off)
4141cf4323eSThomas Huth {
415*3df72d1cSEric Auger QPCIBus *bus = dev->bus;
416*3df72d1cSEric Auger
417*3df72d1cSEric Auger if (token.is_io) {
418*3df72d1cSEric Auger return bus->pio_readw(bus, token.addr + off);
4191cf4323eSThomas Huth } else {
4201cf4323eSThomas Huth uint16_t val;
421*3df72d1cSEric Auger
422*3df72d1cSEric Auger bus->memread(bus, token.addr + off, &val, sizeof(val));
4231cf4323eSThomas Huth return le16_to_cpu(val);
4241cf4323eSThomas Huth }
4251cf4323eSThomas Huth }
4261cf4323eSThomas Huth
qpci_io_readl(QPCIDevice * dev,QPCIBar token,uint64_t off)4271cf4323eSThomas Huth uint32_t qpci_io_readl(QPCIDevice *dev, QPCIBar token, uint64_t off)
4281cf4323eSThomas Huth {
429*3df72d1cSEric Auger QPCIBus *bus = dev->bus;
430*3df72d1cSEric Auger
431*3df72d1cSEric Auger if (token.is_io) {
432*3df72d1cSEric Auger return bus->pio_readl(bus, token.addr + off);
4331cf4323eSThomas Huth } else {
4341cf4323eSThomas Huth uint32_t val;
435*3df72d1cSEric Auger
436*3df72d1cSEric Auger bus->memread(dev->bus, token.addr + off, &val, sizeof(val));
4371cf4323eSThomas Huth return le32_to_cpu(val);
4381cf4323eSThomas Huth }
4391cf4323eSThomas Huth }
4401cf4323eSThomas Huth
qpci_io_readq(QPCIDevice * dev,QPCIBar token,uint64_t off)4411cf4323eSThomas Huth uint64_t qpci_io_readq(QPCIDevice *dev, QPCIBar token, uint64_t off)
4421cf4323eSThomas Huth {
443*3df72d1cSEric Auger QPCIBus *bus = dev->bus;
444*3df72d1cSEric Auger
445*3df72d1cSEric Auger if (token.is_io) {
446*3df72d1cSEric Auger return bus->pio_readq(bus, token.addr + off);
4471cf4323eSThomas Huth } else {
4481cf4323eSThomas Huth uint64_t val;
449*3df72d1cSEric Auger
450*3df72d1cSEric Auger bus->memread(bus, token.addr + off, &val, sizeof(val));
4511cf4323eSThomas Huth return le64_to_cpu(val);
4521cf4323eSThomas Huth }
4531cf4323eSThomas Huth }
4541cf4323eSThomas Huth
qpci_io_writeb(QPCIDevice * dev,QPCIBar token,uint64_t off,uint8_t value)4551cf4323eSThomas Huth void qpci_io_writeb(QPCIDevice *dev, QPCIBar token, uint64_t off,
4561cf4323eSThomas Huth uint8_t value)
4571cf4323eSThomas Huth {
458*3df72d1cSEric Auger QPCIBus *bus = dev->bus;
459*3df72d1cSEric Auger
460*3df72d1cSEric Auger if (token.is_io) {
461*3df72d1cSEric Auger bus->pio_writeb(bus, token.addr + off, value);
4621cf4323eSThomas Huth } else {
463*3df72d1cSEric Auger bus->memwrite(bus, token.addr + off, &value, sizeof(value));
4641cf4323eSThomas Huth }
4651cf4323eSThomas Huth }
4661cf4323eSThomas Huth
qpci_io_writew(QPCIDevice * dev,QPCIBar token,uint64_t off,uint16_t value)4671cf4323eSThomas Huth void qpci_io_writew(QPCIDevice *dev, QPCIBar token, uint64_t off,
4681cf4323eSThomas Huth uint16_t value)
4691cf4323eSThomas Huth {
470*3df72d1cSEric Auger QPCIBus *bus = dev->bus;
471*3df72d1cSEric Auger
472*3df72d1cSEric Auger if (token.is_io) {
473*3df72d1cSEric Auger bus->pio_writew(bus, token.addr + off, value);
4741cf4323eSThomas Huth } else {
4751cf4323eSThomas Huth value = cpu_to_le16(value);
476*3df72d1cSEric Auger bus->memwrite(bus, token.addr + off, &value, sizeof(value));
4771cf4323eSThomas Huth }
4781cf4323eSThomas Huth }
4791cf4323eSThomas Huth
qpci_io_writel(QPCIDevice * dev,QPCIBar token,uint64_t off,uint32_t value)4801cf4323eSThomas Huth void qpci_io_writel(QPCIDevice *dev, QPCIBar token, uint64_t off,
4811cf4323eSThomas Huth uint32_t value)
4821cf4323eSThomas Huth {
483*3df72d1cSEric Auger QPCIBus *bus = dev->bus;
484*3df72d1cSEric Auger
485*3df72d1cSEric Auger if (token.is_io) {
486*3df72d1cSEric Auger bus->pio_writel(bus, token.addr + off, value);
4871cf4323eSThomas Huth } else {
4881cf4323eSThomas Huth value = cpu_to_le32(value);
489*3df72d1cSEric Auger bus->memwrite(bus, token.addr + off, &value, sizeof(value));
4901cf4323eSThomas Huth }
4911cf4323eSThomas Huth }
4921cf4323eSThomas Huth
qpci_io_writeq(QPCIDevice * dev,QPCIBar token,uint64_t off,uint64_t value)4931cf4323eSThomas Huth void qpci_io_writeq(QPCIDevice *dev, QPCIBar token, uint64_t off,
4941cf4323eSThomas Huth uint64_t value)
4951cf4323eSThomas Huth {
496*3df72d1cSEric Auger QPCIBus *bus = dev->bus;
497*3df72d1cSEric Auger
498*3df72d1cSEric Auger if (token.is_io) {
499*3df72d1cSEric Auger bus->pio_writeq(bus, token.addr + off, value);
5001cf4323eSThomas Huth } else {
5011cf4323eSThomas Huth value = cpu_to_le64(value);
502*3df72d1cSEric Auger bus->memwrite(bus, token.addr + off, &value, sizeof(value));
5031cf4323eSThomas Huth }
5041cf4323eSThomas Huth }
5051cf4323eSThomas Huth
qpci_memread(QPCIDevice * dev,QPCIBar token,uint64_t off,void * buf,size_t len)5061cf4323eSThomas Huth void qpci_memread(QPCIDevice *dev, QPCIBar token, uint64_t off,
5071cf4323eSThomas Huth void *buf, size_t len)
5081cf4323eSThomas Huth {
509*3df72d1cSEric Auger g_assert(!token.is_io);
5101cf4323eSThomas Huth dev->bus->memread(dev->bus, token.addr + off, buf, len);
5111cf4323eSThomas Huth }
5121cf4323eSThomas Huth
qpci_memwrite(QPCIDevice * dev,QPCIBar token,uint64_t off,const void * buf,size_t len)5131cf4323eSThomas Huth void qpci_memwrite(QPCIDevice *dev, QPCIBar token, uint64_t off,
5141cf4323eSThomas Huth const void *buf, size_t len)
5151cf4323eSThomas Huth {
516*3df72d1cSEric Auger g_assert(!token.is_io);
5171cf4323eSThomas Huth dev->bus->memwrite(dev->bus, token.addr + off, buf, len);
5181cf4323eSThomas Huth }
5191cf4323eSThomas Huth
qpci_iomap(QPCIDevice * dev,int barno,uint64_t * sizeptr)5201cf4323eSThomas Huth QPCIBar qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr)
5211cf4323eSThomas Huth {
5221cf4323eSThomas Huth QPCIBus *bus = dev->bus;
5231cf4323eSThomas Huth static const int bar_reg_map[] = {
5241cf4323eSThomas Huth PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2,
5251cf4323eSThomas Huth PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5,
5261cf4323eSThomas Huth };
5271cf4323eSThomas Huth QPCIBar bar;
5281cf4323eSThomas Huth int bar_reg;
5291cf4323eSThomas Huth uint32_t addr, size;
5301cf4323eSThomas Huth uint32_t io_type;
5311cf4323eSThomas Huth uint64_t loc;
5321cf4323eSThomas Huth
5331cf4323eSThomas Huth g_assert(barno >= 0 && barno <= 5);
5341cf4323eSThomas Huth bar_reg = bar_reg_map[barno];
5351cf4323eSThomas Huth
5361cf4323eSThomas Huth qpci_config_writel(dev, bar_reg, 0xFFFFFFFF);
5371cf4323eSThomas Huth addr = qpci_config_readl(dev, bar_reg);
5381cf4323eSThomas Huth
5391cf4323eSThomas Huth io_type = addr & PCI_BASE_ADDRESS_SPACE;
5401cf4323eSThomas Huth if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
5411cf4323eSThomas Huth addr &= PCI_BASE_ADDRESS_IO_MASK;
5421cf4323eSThomas Huth } else {
5431cf4323eSThomas Huth addr &= PCI_BASE_ADDRESS_MEM_MASK;
5441cf4323eSThomas Huth }
5451cf4323eSThomas Huth
5461cf4323eSThomas Huth g_assert(addr); /* Must have *some* size bits */
5471cf4323eSThomas Huth
5481cf4323eSThomas Huth size = 1U << ctz32(addr);
5491cf4323eSThomas Huth if (sizeptr) {
5501cf4323eSThomas Huth *sizeptr = size;
5511cf4323eSThomas Huth }
5521cf4323eSThomas Huth
5531cf4323eSThomas Huth if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
5541cf4323eSThomas Huth loc = QEMU_ALIGN_UP(bus->pio_alloc_ptr, size);
5551cf4323eSThomas Huth
5561cf4323eSThomas Huth g_assert(loc >= bus->pio_alloc_ptr);
557*3df72d1cSEric Auger g_assert(loc + size <= bus->pio_limit);
5581cf4323eSThomas Huth
5591cf4323eSThomas Huth bus->pio_alloc_ptr = loc + size;
560*3df72d1cSEric Auger bar.is_io = true;
5611cf4323eSThomas Huth
5621cf4323eSThomas Huth qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO);
5631cf4323eSThomas Huth } else {
5641cf4323eSThomas Huth loc = QEMU_ALIGN_UP(bus->mmio_alloc_ptr, size);
5651cf4323eSThomas Huth
5661cf4323eSThomas Huth /* Check for space */
5671cf4323eSThomas Huth g_assert(loc >= bus->mmio_alloc_ptr);
5681cf4323eSThomas Huth g_assert(loc + size <= bus->mmio_limit);
5691cf4323eSThomas Huth
5701cf4323eSThomas Huth bus->mmio_alloc_ptr = loc + size;
571*3df72d1cSEric Auger bar.is_io = false;
5721cf4323eSThomas Huth
5731cf4323eSThomas Huth qpci_config_writel(dev, bar_reg, loc);
5741cf4323eSThomas Huth }
5751cf4323eSThomas Huth
5761cf4323eSThomas Huth bar.addr = loc;
5771cf4323eSThomas Huth return bar;
5781cf4323eSThomas Huth }
5791cf4323eSThomas Huth
qpci_iounmap(QPCIDevice * dev,QPCIBar bar)5801cf4323eSThomas Huth void qpci_iounmap(QPCIDevice *dev, QPCIBar bar)
5811cf4323eSThomas Huth {
5821cf4323eSThomas Huth /* FIXME */
5831cf4323eSThomas Huth }
5841cf4323eSThomas Huth
qpci_legacy_iomap(QPCIDevice * dev,uint16_t addr)5851cf4323eSThomas Huth QPCIBar qpci_legacy_iomap(QPCIDevice *dev, uint16_t addr)
5861cf4323eSThomas Huth {
587*3df72d1cSEric Auger QPCIBar bar = { .addr = addr, .is_io = true };
5881cf4323eSThomas Huth return bar;
5891cf4323eSThomas Huth }
5901cf4323eSThomas Huth
add_qpci_address(QOSGraphEdgeOptions * opts,QPCIAddress * addr)5911cf4323eSThomas Huth void add_qpci_address(QOSGraphEdgeOptions *opts, QPCIAddress *addr)
5921cf4323eSThomas Huth {
5931cf4323eSThomas Huth g_assert(addr);
5941cf4323eSThomas Huth g_assert(opts);
5951cf4323eSThomas Huth
5961cf4323eSThomas Huth opts->arg = addr;
5971cf4323eSThomas Huth opts->size_arg = sizeof(QPCIAddress);
5981cf4323eSThomas Huth }
599