1c0907c9eSPaolo Bonzini /*
2c0907c9eSPaolo Bonzini * Standard PCI Bridge Device
3c0907c9eSPaolo Bonzini *
4c0907c9eSPaolo Bonzini * Copyright (c) 2011 Red Hat Inc. Author: Michael S. Tsirkin <mst@redhat.com>
5c0907c9eSPaolo Bonzini *
6c0907c9eSPaolo Bonzini * http://www.pcisig.com/specifications/conventional/pci_to_pci_bridge_architecture/
7c0907c9eSPaolo Bonzini *
8c0907c9eSPaolo Bonzini * This program is free software; you can redistribute it and/or modify
9c0907c9eSPaolo Bonzini * it under the terms of the GNU General Public License as published by
10c0907c9eSPaolo Bonzini * the Free Software Foundation; either version 2 of the License, or
11c0907c9eSPaolo Bonzini * (at your option) any later version.
12c0907c9eSPaolo Bonzini *
13c0907c9eSPaolo Bonzini * This program is distributed in the hope that it will be useful,
14c0907c9eSPaolo Bonzini * but WITHOUT ANY WARRANTY; without even the implied warranty of
15c0907c9eSPaolo Bonzini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16c0907c9eSPaolo Bonzini * GNU General Public License for more details.
17c0907c9eSPaolo Bonzini *
18c0907c9eSPaolo Bonzini * You should have received a copy of the GNU General Public License along
19c0907c9eSPaolo Bonzini * with this program; if not, see <http://www.gnu.org/licenses/>.
20c0907c9eSPaolo Bonzini */
21c0907c9eSPaolo Bonzini
2297d5408fSPeter Maydell #include "qemu/osdep.h"
23da34e65cSMarkus Armbruster #include "qapi/error.h"
240b8fa32fSMarkus Armbruster #include "qemu/module.h"
25c0907c9eSPaolo Bonzini #include "hw/pci/pci_bridge.h"
26c0907c9eSPaolo Bonzini #include "hw/pci/pci_ids.h"
27c0907c9eSPaolo Bonzini #include "hw/pci/msi.h"
28c0907c9eSPaolo Bonzini #include "hw/pci/shpc.h"
29c0907c9eSPaolo Bonzini #include "hw/pci/slotid_cap.h"
30a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
31c0907c9eSPaolo Bonzini #include "exec/memory.h"
32c0907c9eSPaolo Bonzini #include "hw/pci/pci_bus.h"
335d268704SIgor Mammedov #include "hw/hotplug.h"
34db1015e9SEduardo Habkost #include "qom/object.h"
35c0907c9eSPaolo Bonzini
3657524e14SAndreas Färber #define TYPE_PCI_BRIDGE_DEV "pci-bridge"
37eb6c6a60SGerd Hoffmann #define TYPE_PCI_BRIDGE_SEAT_DEV "pci-bridge-seat"
388063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(PCIBridgeDev, PCI_BRIDGE_DEV)
3957524e14SAndreas Färber
40c0907c9eSPaolo Bonzini struct PCIBridgeDev {
4157524e14SAndreas Färber /*< private >*/
4257524e14SAndreas Färber PCIBridge parent_obj;
4357524e14SAndreas Färber /*< public >*/
4457524e14SAndreas Färber
45c0907c9eSPaolo Bonzini MemoryRegion bar;
46c0907c9eSPaolo Bonzini uint8_t chassis_nr;
4769b205bbSCao jin #define PCI_BRIDGE_DEV_F_SHPC_REQ 0
48c0907c9eSPaolo Bonzini uint32_t flags;
4969b205bbSCao jin
5069b205bbSCao jin OnOffAuto msi;
516755e618SJing Liu
526755e618SJing Liu /* additional resources to reserve */
536755e618SJing Liu PCIResReserve res_reserve;
54c0907c9eSPaolo Bonzini };
55c0907c9eSPaolo Bonzini
pci_bridge_dev_realize(PCIDevice * dev,Error ** errp)56344475e7SMao Zhongyi static void pci_bridge_dev_realize(PCIDevice *dev, Error **errp)
57c0907c9eSPaolo Bonzini {
58f055e96bSAndreas Färber PCIBridge *br = PCI_BRIDGE(dev);
5957524e14SAndreas Färber PCIBridgeDev *bridge_dev = PCI_BRIDGE_DEV(dev);
60c0907c9eSPaolo Bonzini int err;
611108b2f8SCao jin Error *local_err = NULL;
62c0907c9eSPaolo Bonzini
639cfaa007SCao jin pci_bridge_initfn(dev, TYPE_PCI_BUS);
649cfaa007SCao jin
654e5c9bfeSLaszlo Ersek if (bridge_dev->flags & (1 << PCI_BRIDGE_DEV_F_SHPC_REQ)) {
66c008ac0cSMarcel Apfelbaum dev->config[PCI_INTERRUPT_PIN] = 0x1;
674e5c9bfeSLaszlo Ersek memory_region_init(&bridge_dev->bar, OBJECT(dev), "shpc-bar",
684e5c9bfeSLaszlo Ersek shpc_bar_size(dev));
69344475e7SMao Zhongyi err = shpc_init(dev, &br->sec_bus, &bridge_dev->bar, 0, errp);
70c0907c9eSPaolo Bonzini if (err) {
71c0907c9eSPaolo Bonzini goto shpc_error;
72c0907c9eSPaolo Bonzini }
734e5c9bfeSLaszlo Ersek } else {
744e5c9bfeSLaszlo Ersek /* MSI is not applicable without SHPC */
7569b205bbSCao jin bridge_dev->msi = ON_OFF_AUTO_OFF;
764e5c9bfeSLaszlo Ersek }
7752ea63deSCao jin
78344475e7SMao Zhongyi err = slotid_cap_init(dev, 0, bridge_dev->chassis_nr, 0, errp);
79c0907c9eSPaolo Bonzini if (err) {
80c0907c9eSPaolo Bonzini goto slotid_error;
81c0907c9eSPaolo Bonzini }
8252ea63deSCao jin
831108b2f8SCao jin if (bridge_dev->msi != ON_OFF_AUTO_OFF) {
841108b2f8SCao jin /* it means SHPC exists, because MSI is needed by SHPC */
851108b2f8SCao jin
861108b2f8SCao jin err = msi_init(dev, 0, 1, true, true, &local_err);
871108b2f8SCao jin /* Any error other than -ENOTSUP(board's MSI support is broken)
881108b2f8SCao jin * is a programming error */
891108b2f8SCao jin assert(!err || err == -ENOTSUP);
901108b2f8SCao jin if (err && bridge_dev->msi == ON_OFF_AUTO_ON) {
911108b2f8SCao jin /* Can't satisfy user's explicit msi=on request, fail */
921108b2f8SCao jin error_append_hint(&local_err, "You have to use msi=auto (default) "
931108b2f8SCao jin "or msi=off with this machine type.\n");
94344475e7SMao Zhongyi error_propagate(errp, local_err);
95c0907c9eSPaolo Bonzini goto msi_error;
96c0907c9eSPaolo Bonzini }
971108b2f8SCao jin assert(!local_err || bridge_dev->msi == ON_OFF_AUTO_AUTO);
981108b2f8SCao jin /* With msi=auto, we fall back to MSI off silently */
991108b2f8SCao jin error_free(local_err);
100c0907c9eSPaolo Bonzini }
10152ea63deSCao jin
1026755e618SJing Liu err = pci_bridge_qemu_reserve_cap_init(dev, 0,
1036755e618SJing Liu bridge_dev->res_reserve, errp);
1046755e618SJing Liu if (err) {
1056755e618SJing Liu goto cap_error;
1066755e618SJing Liu }
1076755e618SJing Liu
1084e5c9bfeSLaszlo Ersek if (shpc_present(dev)) {
109c0907c9eSPaolo Bonzini /* TODO: spec recommends using 64 bit prefetcheable BAR.
110c0907c9eSPaolo Bonzini * Check whether that works well. */
111c0907c9eSPaolo Bonzini pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
112c0907c9eSPaolo Bonzini PCI_BASE_ADDRESS_MEM_TYPE_64, &bridge_dev->bar);
1134e5c9bfeSLaszlo Ersek }
114344475e7SMao Zhongyi return;
11552ea63deSCao jin
1166755e618SJing Liu cap_error:
1176755e618SJing Liu msi_uninit(dev);
118c0907c9eSPaolo Bonzini msi_error:
119c0907c9eSPaolo Bonzini slotid_cap_cleanup(dev);
120c0907c9eSPaolo Bonzini slotid_error:
1214e5c9bfeSLaszlo Ersek if (shpc_present(dev)) {
122c0907c9eSPaolo Bonzini shpc_cleanup(dev, &bridge_dev->bar);
1234e5c9bfeSLaszlo Ersek }
124c0907c9eSPaolo Bonzini shpc_error:
125c0907c9eSPaolo Bonzini pci_bridge_exitfn(dev);
126c0907c9eSPaolo Bonzini }
127c0907c9eSPaolo Bonzini
pci_bridge_dev_exitfn(PCIDevice * dev)128c0907c9eSPaolo Bonzini static void pci_bridge_dev_exitfn(PCIDevice *dev)
129c0907c9eSPaolo Bonzini {
13057524e14SAndreas Färber PCIBridgeDev *bridge_dev = PCI_BRIDGE_DEV(dev);
1316755e618SJing Liu
1326755e618SJing Liu pci_del_capability(dev, PCI_CAP_ID_VNDR, sizeof(PCIBridgeQemuCap));
133c0907c9eSPaolo Bonzini if (msi_present(dev)) {
134c0907c9eSPaolo Bonzini msi_uninit(dev);
135c0907c9eSPaolo Bonzini }
136c0907c9eSPaolo Bonzini slotid_cap_cleanup(dev);
1374e5c9bfeSLaszlo Ersek if (shpc_present(dev)) {
138c0907c9eSPaolo Bonzini shpc_cleanup(dev, &bridge_dev->bar);
1394e5c9bfeSLaszlo Ersek }
140c0907c9eSPaolo Bonzini pci_bridge_exitfn(dev);
141c0907c9eSPaolo Bonzini }
142c0907c9eSPaolo Bonzini
pci_bridge_dev_instance_finalize(Object * obj)1435cd5e701SPaolo Bonzini static void pci_bridge_dev_instance_finalize(Object *obj)
1445cd5e701SPaolo Bonzini {
1454e5c9bfeSLaszlo Ersek /* this function is idempotent and handles (PCIDevice.shpc == NULL) */
1465cd5e701SPaolo Bonzini shpc_free(PCI_DEVICE(obj));
1475cd5e701SPaolo Bonzini }
1485cd5e701SPaolo Bonzini
pci_bridge_dev_write_config(PCIDevice * d,uint32_t address,uint32_t val,int len)149c0907c9eSPaolo Bonzini static void pci_bridge_dev_write_config(PCIDevice *d,
150c0907c9eSPaolo Bonzini uint32_t address, uint32_t val, int len)
151c0907c9eSPaolo Bonzini {
152c0907c9eSPaolo Bonzini pci_bridge_write_config(d, address, val, len);
153c0907c9eSPaolo Bonzini if (msi_present(d)) {
154c0907c9eSPaolo Bonzini msi_write_config(d, address, val, len);
155c0907c9eSPaolo Bonzini }
1564e5c9bfeSLaszlo Ersek if (shpc_present(d)) {
157c0907c9eSPaolo Bonzini shpc_cap_write_config(d, address, val, len);
158c0907c9eSPaolo Bonzini }
1594e5c9bfeSLaszlo Ersek }
160c0907c9eSPaolo Bonzini
qdev_pci_bridge_dev_reset(DeviceState * qdev)161c0907c9eSPaolo Bonzini static void qdev_pci_bridge_dev_reset(DeviceState *qdev)
162c0907c9eSPaolo Bonzini {
16357524e14SAndreas Färber PCIDevice *dev = PCI_DEVICE(qdev);
164c0907c9eSPaolo Bonzini
165c0907c9eSPaolo Bonzini pci_bridge_reset(qdev);
1664e5c9bfeSLaszlo Ersek if (shpc_present(dev)) {
167c0907c9eSPaolo Bonzini shpc_reset(dev);
168c0907c9eSPaolo Bonzini }
1694e5c9bfeSLaszlo Ersek }
170c0907c9eSPaolo Bonzini
171c0907c9eSPaolo Bonzini static Property pci_bridge_dev_properties[] = {
172c0907c9eSPaolo Bonzini /* Note: 0 is not a legal chassis number. */
1733cf0ecb3SLaszlo Ersek DEFINE_PROP_UINT8(PCI_BRIDGE_DEV_PROP_CHASSIS_NR, PCIBridgeDev, chassis_nr,
1743cf0ecb3SLaszlo Ersek 0),
17569b205bbSCao jin DEFINE_PROP_ON_OFF_AUTO(PCI_BRIDGE_DEV_PROP_MSI, PCIBridgeDev, msi,
17669b205bbSCao jin ON_OFF_AUTO_AUTO),
1774e5c9bfeSLaszlo Ersek DEFINE_PROP_BIT(PCI_BRIDGE_DEV_PROP_SHPC, PCIBridgeDev, flags,
1782fa35662SMarcel Apfelbaum PCI_BRIDGE_DEV_F_SHPC_REQ, true),
1796755e618SJing Liu DEFINE_PROP_UINT32("bus-reserve", PCIBridgeDev,
1806755e618SJing Liu res_reserve.bus, -1),
1816755e618SJing Liu DEFINE_PROP_SIZE("io-reserve", PCIBridgeDev,
1826755e618SJing Liu res_reserve.io, -1),
1836755e618SJing Liu DEFINE_PROP_SIZE("mem-reserve", PCIBridgeDev,
1846755e618SJing Liu res_reserve.mem_non_pref, -1),
1856755e618SJing Liu DEFINE_PROP_SIZE("pref32-reserve", PCIBridgeDev,
1866755e618SJing Liu res_reserve.mem_pref_32, -1),
1876755e618SJing Liu DEFINE_PROP_SIZE("pref64-reserve", PCIBridgeDev,
1886755e618SJing Liu res_reserve.mem_pref_64, -1),
189c0907c9eSPaolo Bonzini DEFINE_PROP_END_OF_LIST(),
190c0907c9eSPaolo Bonzini };
191c0907c9eSPaolo Bonzini
pci_device_shpc_present(void * opaque,int version_id)1924e5c9bfeSLaszlo Ersek static bool pci_device_shpc_present(void *opaque, int version_id)
1934e5c9bfeSLaszlo Ersek {
1944e5c9bfeSLaszlo Ersek PCIDevice *dev = opaque;
1954e5c9bfeSLaszlo Ersek
1964e5c9bfeSLaszlo Ersek return shpc_present(dev);
1974e5c9bfeSLaszlo Ersek }
1984e5c9bfeSLaszlo Ersek
199c0907c9eSPaolo Bonzini static const VMStateDescription pci_bridge_dev_vmstate = {
200c0907c9eSPaolo Bonzini .name = "pci_bridge",
2019d6b9db1SPeter Xu .priority = MIG_PRI_PCI_BUS,
202f026c578SRichard Henderson .fields = (const VMStateField[]) {
20357524e14SAndreas Färber VMSTATE_PCI_DEVICE(parent_obj, PCIBridge),
2044e5c9bfeSLaszlo Ersek SHPC_VMSTATE(shpc, PCIDevice, pci_device_shpc_present),
205c0907c9eSPaolo Bonzini VMSTATE_END_OF_LIST()
206c0907c9eSPaolo Bonzini }
207c0907c9eSPaolo Bonzini };
208c0907c9eSPaolo Bonzini
pci_bridge_dev_plug_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)20962b76563SDavid Hildenbrand void pci_bridge_dev_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
21062b76563SDavid Hildenbrand Error **errp)
2114e5c9bfeSLaszlo Ersek {
2124e5c9bfeSLaszlo Ersek PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
2134e5c9bfeSLaszlo Ersek
2144e5c9bfeSLaszlo Ersek if (!shpc_present(pci_hotplug_dev)) {
2154e5c9bfeSLaszlo Ersek error_setg(errp, "standard hotplug controller has been disabled for "
21662b76563SDavid Hildenbrand "this %s", object_get_typename(OBJECT(hotplug_dev)));
2174e5c9bfeSLaszlo Ersek return;
2184e5c9bfeSLaszlo Ersek }
219851fedfbSDavid Hildenbrand shpc_device_plug_cb(hotplug_dev, dev, errp);
2204e5c9bfeSLaszlo Ersek }
2214e5c9bfeSLaszlo Ersek
pci_bridge_dev_unplug_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)2228f560cdcSDavid Hildenbrand void pci_bridge_dev_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
2238f560cdcSDavid Hildenbrand Error **errp)
2248f560cdcSDavid Hildenbrand {
2258f560cdcSDavid Hildenbrand PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
2268f560cdcSDavid Hildenbrand
2278f560cdcSDavid Hildenbrand g_assert(shpc_present(pci_hotplug_dev));
2288f560cdcSDavid Hildenbrand shpc_device_unplug_cb(hotplug_dev, dev, errp);
2298f560cdcSDavid Hildenbrand }
2308f560cdcSDavid Hildenbrand
pci_bridge_dev_unplug_request_cb(HotplugHandler * hotplug_dev,DeviceState * dev,Error ** errp)23162b76563SDavid Hildenbrand void pci_bridge_dev_unplug_request_cb(HotplugHandler *hotplug_dev,
232851fedfbSDavid Hildenbrand DeviceState *dev, Error **errp)
2334e5c9bfeSLaszlo Ersek {
2344e5c9bfeSLaszlo Ersek PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);
2354e5c9bfeSLaszlo Ersek
2364e5c9bfeSLaszlo Ersek if (!shpc_present(pci_hotplug_dev)) {
2374e5c9bfeSLaszlo Ersek error_setg(errp, "standard hotplug controller has been disabled for "
23862b76563SDavid Hildenbrand "this %s", object_get_typename(OBJECT(hotplug_dev)));
2394e5c9bfeSLaszlo Ersek return;
2404e5c9bfeSLaszlo Ersek }
241851fedfbSDavid Hildenbrand shpc_device_unplug_request_cb(hotplug_dev, dev, errp);
2424e5c9bfeSLaszlo Ersek }
2434e5c9bfeSLaszlo Ersek
pci_bridge_dev_class_init(ObjectClass * klass,void * data)244c0907c9eSPaolo Bonzini static void pci_bridge_dev_class_init(ObjectClass *klass, void *data)
245c0907c9eSPaolo Bonzini {
246c0907c9eSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass);
247c0907c9eSPaolo Bonzini PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
2485d268704SIgor Mammedov HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
2495d268704SIgor Mammedov
250344475e7SMao Zhongyi k->realize = pci_bridge_dev_realize;
251c0907c9eSPaolo Bonzini k->exit = pci_bridge_dev_exitfn;
252c0907c9eSPaolo Bonzini k->config_write = pci_bridge_dev_write_config;
253c0907c9eSPaolo Bonzini k->vendor_id = PCI_VENDOR_ID_REDHAT;
254c0907c9eSPaolo Bonzini k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE;
255c0907c9eSPaolo Bonzini k->class_id = PCI_CLASS_BRIDGE_PCI;
256c0907c9eSPaolo Bonzini dc->desc = "Standard PCI Bridge";
257*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, qdev_pci_bridge_dev_reset);
2584f67d30bSMarc-André Lureau device_class_set_props(dc, pci_bridge_dev_properties);
259c0907c9eSPaolo Bonzini dc->vmsd = &pci_bridge_dev_vmstate;
260125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
261851fedfbSDavid Hildenbrand hc->plug = pci_bridge_dev_plug_cb;
2628f560cdcSDavid Hildenbrand hc->unplug = pci_bridge_dev_unplug_cb;
263851fedfbSDavid Hildenbrand hc->unplug_request = pci_bridge_dev_unplug_request_cb;
264c0907c9eSPaolo Bonzini }
265c0907c9eSPaolo Bonzini
266c0907c9eSPaolo Bonzini static const TypeInfo pci_bridge_dev_info = {
26757524e14SAndreas Färber .name = TYPE_PCI_BRIDGE_DEV,
268f055e96bSAndreas Färber .parent = TYPE_PCI_BRIDGE,
269c0907c9eSPaolo Bonzini .instance_size = sizeof(PCIBridgeDev),
270c0907c9eSPaolo Bonzini .class_init = pci_bridge_dev_class_init,
2715cd5e701SPaolo Bonzini .instance_finalize = pci_bridge_dev_instance_finalize,
2725d268704SIgor Mammedov .interfaces = (InterfaceInfo[]) {
2735d268704SIgor Mammedov { TYPE_HOTPLUG_HANDLER },
274fd3b02c8SEduardo Habkost { INTERFACE_CONVENTIONAL_PCI_DEVICE },
2755d268704SIgor Mammedov { }
2765d268704SIgor Mammedov }
277c0907c9eSPaolo Bonzini };
278c0907c9eSPaolo Bonzini
279eb6c6a60SGerd Hoffmann /*
280eb6c6a60SGerd Hoffmann * Multiseat bridge. Same as the standard pci bridge, only with a
281eb6c6a60SGerd Hoffmann * different pci id, so we can match it easily in the guest for
282eb6c6a60SGerd Hoffmann * automagic multiseat configuration. See docs/multiseat.txt for more.
283eb6c6a60SGerd Hoffmann */
pci_bridge_dev_seat_class_init(ObjectClass * klass,void * data)284eb6c6a60SGerd Hoffmann static void pci_bridge_dev_seat_class_init(ObjectClass *klass, void *data)
285eb6c6a60SGerd Hoffmann {
286eb6c6a60SGerd Hoffmann DeviceClass *dc = DEVICE_CLASS(klass);
287eb6c6a60SGerd Hoffmann PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
288eb6c6a60SGerd Hoffmann
289eb6c6a60SGerd Hoffmann k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE_SEAT;
290eb6c6a60SGerd Hoffmann dc->desc = "Standard PCI Bridge (multiseat)";
291eb6c6a60SGerd Hoffmann }
292eb6c6a60SGerd Hoffmann
293eb6c6a60SGerd Hoffmann static const TypeInfo pci_bridge_dev_seat_info = {
294eb6c6a60SGerd Hoffmann .name = TYPE_PCI_BRIDGE_SEAT_DEV,
295eb6c6a60SGerd Hoffmann .parent = TYPE_PCI_BRIDGE_DEV,
296eb6c6a60SGerd Hoffmann .instance_size = sizeof(PCIBridgeDev),
297eb6c6a60SGerd Hoffmann .class_init = pci_bridge_dev_seat_class_init,
298eb6c6a60SGerd Hoffmann };
299eb6c6a60SGerd Hoffmann
pci_bridge_dev_register(void)300c0907c9eSPaolo Bonzini static void pci_bridge_dev_register(void)
301c0907c9eSPaolo Bonzini {
302c0907c9eSPaolo Bonzini type_register_static(&pci_bridge_dev_info);
303eb6c6a60SGerd Hoffmann type_register_static(&pci_bridge_dev_seat_info);
304c0907c9eSPaolo Bonzini }
305c0907c9eSPaolo Bonzini
306c0907c9eSPaolo Bonzini type_init(pci_bridge_dev_register);
307