1315a1350SMichael S. Tsirkin /*
2315a1350SMichael S. Tsirkin * pci_host.c
3315a1350SMichael S. Tsirkin *
4315a1350SMichael S. Tsirkin * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
5315a1350SMichael S. Tsirkin * VA Linux Systems Japan K.K.
6315a1350SMichael S. Tsirkin *
7315a1350SMichael S. Tsirkin * This program is free software; you can redistribute it and/or modify
8315a1350SMichael S. Tsirkin * it under the terms of the GNU General Public License as published by
9315a1350SMichael S. Tsirkin * the Free Software Foundation; either version 2 of the License, or
10315a1350SMichael S. Tsirkin * (at your option) any later version.
11315a1350SMichael S. Tsirkin
12315a1350SMichael S. Tsirkin * This program is distributed in the hope that it will be useful,
13315a1350SMichael S. Tsirkin * but WITHOUT ANY WARRANTY; without even the implied warranty of
14315a1350SMichael S. Tsirkin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15315a1350SMichael S. Tsirkin * GNU General Public License for more details.
16315a1350SMichael S. Tsirkin
17315a1350SMichael S. Tsirkin * You should have received a copy of the GNU General Public License along
18315a1350SMichael S. Tsirkin * with this program; if not, see <http://www.gnu.org/licenses/>.
19315a1350SMichael S. Tsirkin */
20315a1350SMichael S. Tsirkin
2197d5408fSPeter Maydell #include "qemu/osdep.h"
22c759b24fSMichael S. Tsirkin #include "hw/pci/pci.h"
23c2077e2cSAlex Williamson #include "hw/pci/pci_bridge.h"
24c759b24fSMichael S. Tsirkin #include "hw/pci/pci_host.h"
252ebc2121SHogan Wang #include "hw/qdev-properties.h"
260b8fa32fSMarkus Armbruster #include "qemu/module.h"
273f1e1478SCao jin #include "hw/pci/pci_bus.h"
282ebc2121SHogan Wang #include "migration/vmstate.h"
293bf4dfddSAlexey Kardashevskiy #include "trace.h"
30315a1350SMichael S. Tsirkin
31315a1350SMichael S. Tsirkin /* debug PCI */
32315a1350SMichael S. Tsirkin //#define DEBUG_PCI
33315a1350SMichael S. Tsirkin
34315a1350SMichael S. Tsirkin #ifdef DEBUG_PCI
35315a1350SMichael S. Tsirkin #define PCI_DPRINTF(fmt, ...) \
36315a1350SMichael S. Tsirkin do { printf("pci_host_data: " fmt , ## __VA_ARGS__); } while (0)
37315a1350SMichael S. Tsirkin #else
38315a1350SMichael S. Tsirkin #define PCI_DPRINTF(fmt, ...)
39315a1350SMichael S. Tsirkin #endif
40315a1350SMichael S. Tsirkin
41315a1350SMichael S. Tsirkin /*
42315a1350SMichael S. Tsirkin * PCI address
43315a1350SMichael S. Tsirkin * bit 16 - 24: bus number
44315a1350SMichael S. Tsirkin * bit 8 - 15: devfun number
45315a1350SMichael S. Tsirkin * bit 0 - 7: offset in configuration space of a given pci device
46315a1350SMichael S. Tsirkin */
47315a1350SMichael S. Tsirkin
48085d8134SPeter Maydell /* the helper function to get a PCIDevice* for a given pci address */
pci_dev_find_by_addr(PCIBus * bus,uint32_t addr)49315a1350SMichael S. Tsirkin static inline PCIDevice *pci_dev_find_by_addr(PCIBus *bus, uint32_t addr)
50315a1350SMichael S. Tsirkin {
51315a1350SMichael S. Tsirkin uint8_t bus_num = addr >> 16;
52315a1350SMichael S. Tsirkin uint8_t devfn = addr >> 8;
53315a1350SMichael S. Tsirkin
54315a1350SMichael S. Tsirkin return pci_find_device(bus, bus_num, devfn);
55315a1350SMichael S. Tsirkin }
56315a1350SMichael S. Tsirkin
pci_adjust_config_limit(PCIBus * bus,uint32_t * limit)57c2077e2cSAlex Williamson static void pci_adjust_config_limit(PCIBus *bus, uint32_t *limit)
58c2077e2cSAlex Williamson {
592f57db8aSDavid Gibson if ((*limit > PCI_CONFIG_SPACE_SIZE) &&
602f57db8aSDavid Gibson !pci_bus_allows_extended_config_space(bus)) {
61c2077e2cSAlex Williamson *limit = PCI_CONFIG_SPACE_SIZE;
62c2077e2cSAlex Williamson }
63c2077e2cSAlex Williamson }
64c2077e2cSAlex Williamson
is_pci_dev_ejected(PCIDevice * pci_dev)65348e3544SYuri Benditovich static bool is_pci_dev_ejected(PCIDevice *pci_dev)
66348e3544SYuri Benditovich {
67348e3544SYuri Benditovich /*
68348e3544SYuri Benditovich * device unplug was requested and the guest acked it,
69348e3544SYuri Benditovich * so we stop responding config accesses even if the
70348e3544SYuri Benditovich * device is not deleted (failover flow)
71348e3544SYuri Benditovich */
72348e3544SYuri Benditovich return pci_dev && pci_dev->partially_hotplugged &&
73348e3544SYuri Benditovich !pci_dev->qdev.pending_deleted_event;
74348e3544SYuri Benditovich }
75348e3544SYuri Benditovich
pci_host_config_write_common(PCIDevice * pci_dev,uint32_t addr,uint32_t limit,uint32_t val,uint32_t len)76315a1350SMichael S. Tsirkin void pci_host_config_write_common(PCIDevice *pci_dev, uint32_t addr,
77315a1350SMichael S. Tsirkin uint32_t limit, uint32_t val, uint32_t len)
78315a1350SMichael S. Tsirkin {
79c2077e2cSAlex Williamson pci_adjust_config_limit(pci_get_bus(pci_dev), &limit);
80c2077e2cSAlex Williamson if (limit <= addr) {
81c2077e2cSAlex Williamson return;
82c2077e2cSAlex Williamson }
83c2077e2cSAlex Williamson
84315a1350SMichael S. Tsirkin assert(len <= 4);
853f1e1478SCao jin /* non-zero functions are only exposed when function 0 is present,
863f1e1478SCao jin * allowing direct removal of unexposed functions.
873f1e1478SCao jin */
8823786d13SGerd Hoffmann if ((pci_dev->qdev.hotplugged && !pci_get_function_0(pci_dev)) ||
89*93829009SMichael S. Tsirkin !pci_dev->has_power || is_pci_dev_ejected(pci_dev)) {
903f1e1478SCao jin return;
913f1e1478SCao jin }
923f1e1478SCao jin
93deeb956cSLaurent Vivier trace_pci_cfg_write(pci_dev->name, pci_dev_bus_num(pci_dev),
94deeb956cSLaurent Vivier PCI_SLOT(pci_dev->devfn),
953bf4dfddSAlexey Kardashevskiy PCI_FUNC(pci_dev->devfn), addr, val);
96315a1350SMichael S. Tsirkin pci_dev->config_write(pci_dev, addr, val, MIN(len, limit - addr));
97315a1350SMichael S. Tsirkin }
98315a1350SMichael S. Tsirkin
pci_host_config_read_common(PCIDevice * pci_dev,uint32_t addr,uint32_t limit,uint32_t len)99315a1350SMichael S. Tsirkin uint32_t pci_host_config_read_common(PCIDevice *pci_dev, uint32_t addr,
100315a1350SMichael S. Tsirkin uint32_t limit, uint32_t len)
101315a1350SMichael S. Tsirkin {
1023bf4dfddSAlexey Kardashevskiy uint32_t ret;
1033bf4dfddSAlexey Kardashevskiy
104c2077e2cSAlex Williamson pci_adjust_config_limit(pci_get_bus(pci_dev), &limit);
105c2077e2cSAlex Williamson if (limit <= addr) {
106c2077e2cSAlex Williamson return ~0x0;
107c2077e2cSAlex Williamson }
108c2077e2cSAlex Williamson
109315a1350SMichael S. Tsirkin assert(len <= 4);
1103f1e1478SCao jin /* non-zero functions are only exposed when function 0 is present,
1113f1e1478SCao jin * allowing direct removal of unexposed functions.
1123f1e1478SCao jin */
11323786d13SGerd Hoffmann if ((pci_dev->qdev.hotplugged && !pci_get_function_0(pci_dev)) ||
114*93829009SMichael S. Tsirkin !pci_dev->has_power || is_pci_dev_ejected(pci_dev)) {
1153f1e1478SCao jin return ~0x0;
1163f1e1478SCao jin }
1173f1e1478SCao jin
1183bf4dfddSAlexey Kardashevskiy ret = pci_dev->config_read(pci_dev, addr, MIN(len, limit - addr));
119deeb956cSLaurent Vivier trace_pci_cfg_read(pci_dev->name, pci_dev_bus_num(pci_dev),
120deeb956cSLaurent Vivier PCI_SLOT(pci_dev->devfn),
1213bf4dfddSAlexey Kardashevskiy PCI_FUNC(pci_dev->devfn), addr, ret);
1223bf4dfddSAlexey Kardashevskiy
1233bf4dfddSAlexey Kardashevskiy return ret;
124315a1350SMichael S. Tsirkin }
125315a1350SMichael S. Tsirkin
pci_data_write(PCIBus * s,uint32_t addr,uint32_t val,unsigned len)126f2a7e8f1SPhilippe Mathieu-Daudé void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, unsigned len)
127315a1350SMichael S. Tsirkin {
128315a1350SMichael S. Tsirkin PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
129315a1350SMichael S. Tsirkin uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
130315a1350SMichael S. Tsirkin
131315a1350SMichael S. Tsirkin if (!pci_dev) {
1321bdad09bSPhilippe Mathieu-Daudé trace_pci_cfg_write("empty", extract32(addr, 16, 8),
1331bdad09bSPhilippe Mathieu-Daudé extract32(addr, 11, 5), extract32(addr, 8, 3),
1341bdad09bSPhilippe Mathieu-Daudé config_addr, val);
135315a1350SMichael S. Tsirkin return;
136315a1350SMichael S. Tsirkin }
137315a1350SMichael S. Tsirkin
138315a1350SMichael S. Tsirkin pci_host_config_write_common(pci_dev, config_addr, PCI_CONFIG_SPACE_SIZE,
139315a1350SMichael S. Tsirkin val, len);
140315a1350SMichael S. Tsirkin }
141315a1350SMichael S. Tsirkin
pci_data_read(PCIBus * s,uint32_t addr,unsigned len)142f2a7e8f1SPhilippe Mathieu-Daudé uint32_t pci_data_read(PCIBus *s, uint32_t addr, unsigned len)
143315a1350SMichael S. Tsirkin {
144315a1350SMichael S. Tsirkin PCIDevice *pci_dev = pci_dev_find_by_addr(s, addr);
145315a1350SMichael S. Tsirkin uint32_t config_addr = addr & (PCI_CONFIG_SPACE_SIZE - 1);
146315a1350SMichael S. Tsirkin
147315a1350SMichael S. Tsirkin if (!pci_dev) {
1481bdad09bSPhilippe Mathieu-Daudé trace_pci_cfg_read("empty", extract32(addr, 16, 8),
1491bdad09bSPhilippe Mathieu-Daudé extract32(addr, 11, 5), extract32(addr, 8, 3),
1501bdad09bSPhilippe Mathieu-Daudé config_addr, ~0x0);
151315a1350SMichael S. Tsirkin return ~0x0;
152315a1350SMichael S. Tsirkin }
153315a1350SMichael S. Tsirkin
1544ce537a7SPhilippe Mathieu-Daudé return pci_host_config_read_common(pci_dev, config_addr,
155315a1350SMichael S. Tsirkin PCI_CONFIG_SPACE_SIZE, len);
156315a1350SMichael S. Tsirkin }
157315a1350SMichael S. Tsirkin
pci_host_config_write(void * opaque,hwaddr addr,uint64_t val,unsigned len)158315a1350SMichael S. Tsirkin static void pci_host_config_write(void *opaque, hwaddr addr,
159315a1350SMichael S. Tsirkin uint64_t val, unsigned len)
160315a1350SMichael S. Tsirkin {
161315a1350SMichael S. Tsirkin PCIHostState *s = opaque;
162315a1350SMichael S. Tsirkin
163883f2c59SPhilippe Mathieu-Daudé PCI_DPRINTF("%s addr " HWADDR_FMT_plx " len %d val %"PRIx64"\n",
164315a1350SMichael S. Tsirkin __func__, addr, len, val);
165315a1350SMichael S. Tsirkin if (addr != 0 || len != 4) {
166315a1350SMichael S. Tsirkin return;
167315a1350SMichael S. Tsirkin }
168315a1350SMichael S. Tsirkin s->config_reg = val;
169315a1350SMichael S. Tsirkin }
170315a1350SMichael S. Tsirkin
pci_host_config_read(void * opaque,hwaddr addr,unsigned len)171315a1350SMichael S. Tsirkin static uint64_t pci_host_config_read(void *opaque, hwaddr addr,
172315a1350SMichael S. Tsirkin unsigned len)
173315a1350SMichael S. Tsirkin {
174315a1350SMichael S. Tsirkin PCIHostState *s = opaque;
175315a1350SMichael S. Tsirkin uint32_t val = s->config_reg;
176315a1350SMichael S. Tsirkin
177883f2c59SPhilippe Mathieu-Daudé PCI_DPRINTF("%s addr " HWADDR_FMT_plx " len %d val %"PRIx32"\n",
178315a1350SMichael S. Tsirkin __func__, addr, len, val);
179315a1350SMichael S. Tsirkin return val;
180315a1350SMichael S. Tsirkin }
181315a1350SMichael S. Tsirkin
pci_host_data_write(void * opaque,hwaddr addr,uint64_t val,unsigned len)182315a1350SMichael S. Tsirkin static void pci_host_data_write(void *opaque, hwaddr addr,
183315a1350SMichael S. Tsirkin uint64_t val, unsigned len)
184315a1350SMichael S. Tsirkin {
185315a1350SMichael S. Tsirkin PCIHostState *s = opaque;
1864ce537a7SPhilippe Mathieu-Daudé
187315a1350SMichael S. Tsirkin if (s->config_reg & (1u << 31))
188315a1350SMichael S. Tsirkin pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
189315a1350SMichael S. Tsirkin }
190315a1350SMichael S. Tsirkin
pci_host_data_read(void * opaque,hwaddr addr,unsigned len)191315a1350SMichael S. Tsirkin static uint64_t pci_host_data_read(void *opaque,
192315a1350SMichael S. Tsirkin hwaddr addr, unsigned len)
193315a1350SMichael S. Tsirkin {
194315a1350SMichael S. Tsirkin PCIHostState *s = opaque;
1954ce537a7SPhilippe Mathieu-Daudé
196ac43fa50SPeter Maydell if (!(s->config_reg & (1U << 31))) {
197315a1350SMichael S. Tsirkin return 0xffffffff;
198ac43fa50SPeter Maydell }
1994ce537a7SPhilippe Mathieu-Daudé return pci_data_read(s->bus, s->config_reg | (addr & 3), len);
200315a1350SMichael S. Tsirkin }
201315a1350SMichael S. Tsirkin
202315a1350SMichael S. Tsirkin const MemoryRegionOps pci_host_conf_le_ops = {
203315a1350SMichael S. Tsirkin .read = pci_host_config_read,
204315a1350SMichael S. Tsirkin .write = pci_host_config_write,
205315a1350SMichael S. Tsirkin .endianness = DEVICE_LITTLE_ENDIAN,
206315a1350SMichael S. Tsirkin };
207315a1350SMichael S. Tsirkin
208315a1350SMichael S. Tsirkin const MemoryRegionOps pci_host_conf_be_ops = {
209315a1350SMichael S. Tsirkin .read = pci_host_config_read,
210315a1350SMichael S. Tsirkin .write = pci_host_config_write,
211315a1350SMichael S. Tsirkin .endianness = DEVICE_BIG_ENDIAN,
212315a1350SMichael S. Tsirkin };
213315a1350SMichael S. Tsirkin
214315a1350SMichael S. Tsirkin const MemoryRegionOps pci_host_data_le_ops = {
215315a1350SMichael S. Tsirkin .read = pci_host_data_read,
216315a1350SMichael S. Tsirkin .write = pci_host_data_write,
217315a1350SMichael S. Tsirkin .endianness = DEVICE_LITTLE_ENDIAN,
218315a1350SMichael S. Tsirkin };
219315a1350SMichael S. Tsirkin
220315a1350SMichael S. Tsirkin const MemoryRegionOps pci_host_data_be_ops = {
221315a1350SMichael S. Tsirkin .read = pci_host_data_read,
222315a1350SMichael S. Tsirkin .write = pci_host_data_write,
223315a1350SMichael S. Tsirkin .endianness = DEVICE_BIG_ENDIAN,
224315a1350SMichael S. Tsirkin };
225315a1350SMichael S. Tsirkin
pci_host_needed(void * opaque)2262ebc2121SHogan Wang static bool pci_host_needed(void *opaque)
2272ebc2121SHogan Wang {
2282ebc2121SHogan Wang PCIHostState *s = opaque;
2292ebc2121SHogan Wang return s->mig_enabled;
2302ebc2121SHogan Wang }
2312ebc2121SHogan Wang
2322ebc2121SHogan Wang const VMStateDescription vmstate_pcihost = {
2332ebc2121SHogan Wang .name = "PCIHost",
2342ebc2121SHogan Wang .needed = pci_host_needed,
2352ebc2121SHogan Wang .version_id = 1,
2362ebc2121SHogan Wang .minimum_version_id = 1,
2378e5e0890SRichard Henderson .fields = (const VMStateField[]) {
2382ebc2121SHogan Wang VMSTATE_UINT32(config_reg, PCIHostState),
2392ebc2121SHogan Wang VMSTATE_END_OF_LIST()
2402ebc2121SHogan Wang }
2412ebc2121SHogan Wang };
2422ebc2121SHogan Wang
2432ebc2121SHogan Wang static Property pci_host_properties_common[] = {
2442ebc2121SHogan Wang DEFINE_PROP_BOOL("x-config-reg-migration-enabled", PCIHostState,
2452ebc2121SHogan Wang mig_enabled, true),
2463b20f4caSBernhard Beschow DEFINE_PROP_BOOL(PCI_HOST_BYPASS_IOMMU, PCIHostState, bypass_iommu, false),
2472ebc2121SHogan Wang DEFINE_PROP_END_OF_LIST(),
2482ebc2121SHogan Wang };
2492ebc2121SHogan Wang
pci_host_class_init(ObjectClass * klass,void * data)2502ebc2121SHogan Wang static void pci_host_class_init(ObjectClass *klass, void *data)
2512ebc2121SHogan Wang {
2522ebc2121SHogan Wang DeviceClass *dc = DEVICE_CLASS(klass);
2532ebc2121SHogan Wang device_class_set_props(dc, pci_host_properties_common);
2542ebc2121SHogan Wang dc->vmsd = &vmstate_pcihost;
2552ebc2121SHogan Wang }
2562ebc2121SHogan Wang
257315a1350SMichael S. Tsirkin static const TypeInfo pci_host_type_info = {
258315a1350SMichael S. Tsirkin .name = TYPE_PCI_HOST_BRIDGE,
259315a1350SMichael S. Tsirkin .parent = TYPE_SYS_BUS_DEVICE,
260315a1350SMichael S. Tsirkin .abstract = true,
261568f0690SDavid Gibson .class_size = sizeof(PCIHostBridgeClass),
262315a1350SMichael S. Tsirkin .instance_size = sizeof(PCIHostState),
2632ebc2121SHogan Wang .class_init = pci_host_class_init,
264315a1350SMichael S. Tsirkin };
265315a1350SMichael S. Tsirkin
pci_host_register_types(void)266315a1350SMichael S. Tsirkin static void pci_host_register_types(void)
267315a1350SMichael S. Tsirkin {
268315a1350SMichael S. Tsirkin type_register_static(&pci_host_type_info);
269315a1350SMichael S. Tsirkin }
270315a1350SMichael S. Tsirkin
271315a1350SMichael S. Tsirkin type_init(pci_host_register_types)
272