qemu
306 строк · 9.7 Кб
1/*
2* Standard PCI Bridge Device
3*
4* Copyright (c) 2011 Red Hat Inc. Author: Michael S. Tsirkin <mst@redhat.com>
5*
6* http://www.pcisig.com/specifications/conventional/pci_to_pci_bridge_architecture/
7*
8* This program is free software; you can redistribute it and/or modify
9* it under the terms of the GNU General Public License as published by
10* the Free Software Foundation; either version 2 of the License, or
11* (at your option) any later version.
12*
13* This program is distributed in the hope that it will be useful,
14* but WITHOUT ANY WARRANTY; without even the implied warranty of
15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16* GNU General Public License for more details.
17*
18* You should have received a copy of the GNU General Public License along
19* with this program; if not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "qemu/osdep.h"23#include "qapi/error.h"24#include "qemu/module.h"25#include "hw/pci/pci_bridge.h"26#include "hw/pci/pci_ids.h"27#include "hw/pci/msi.h"28#include "hw/pci/shpc.h"29#include "hw/pci/slotid_cap.h"30#include "hw/qdev-properties.h"31#include "exec/memory.h"32#include "hw/pci/pci_bus.h"33#include "hw/hotplug.h"34#include "qom/object.h"35
36#define TYPE_PCI_BRIDGE_DEV "pci-bridge"37#define TYPE_PCI_BRIDGE_SEAT_DEV "pci-bridge-seat"38OBJECT_DECLARE_SIMPLE_TYPE(PCIBridgeDev, PCI_BRIDGE_DEV)39
40struct PCIBridgeDev {41/*< private >*/42PCIBridge parent_obj;43/*< public >*/44
45MemoryRegion bar;46uint8_t chassis_nr;47#define PCI_BRIDGE_DEV_F_SHPC_REQ 048uint32_t flags;49
50OnOffAuto msi;51
52/* additional resources to reserve */53PCIResReserve res_reserve;54};55
56static void pci_bridge_dev_realize(PCIDevice *dev, Error **errp)57{
58PCIBridge *br = PCI_BRIDGE(dev);59PCIBridgeDev *bridge_dev = PCI_BRIDGE_DEV(dev);60int err;61Error *local_err = NULL;62
63pci_bridge_initfn(dev, TYPE_PCI_BUS);64
65if (bridge_dev->flags & (1 << PCI_BRIDGE_DEV_F_SHPC_REQ)) {66dev->config[PCI_INTERRUPT_PIN] = 0x1;67memory_region_init(&bridge_dev->bar, OBJECT(dev), "shpc-bar",68shpc_bar_size(dev));69err = shpc_init(dev, &br->sec_bus, &bridge_dev->bar, 0, errp);70if (err) {71goto shpc_error;72}73} else {74/* MSI is not applicable without SHPC */75bridge_dev->msi = ON_OFF_AUTO_OFF;76}77
78err = slotid_cap_init(dev, 0, bridge_dev->chassis_nr, 0, errp);79if (err) {80goto slotid_error;81}82
83if (bridge_dev->msi != ON_OFF_AUTO_OFF) {84/* it means SHPC exists, because MSI is needed by SHPC */85
86err = msi_init(dev, 0, 1, true, true, &local_err);87/* Any error other than -ENOTSUP(board's MSI support is broken)88* is a programming error */
89assert(!err || err == -ENOTSUP);90if (err && bridge_dev->msi == ON_OFF_AUTO_ON) {91/* Can't satisfy user's explicit msi=on request, fail */92error_append_hint(&local_err, "You have to use msi=auto (default) "93"or msi=off with this machine type.\n");94error_propagate(errp, local_err);95goto msi_error;96}97assert(!local_err || bridge_dev->msi == ON_OFF_AUTO_AUTO);98/* With msi=auto, we fall back to MSI off silently */99error_free(local_err);100}101
102err = pci_bridge_qemu_reserve_cap_init(dev, 0,103bridge_dev->res_reserve, errp);104if (err) {105goto cap_error;106}107
108if (shpc_present(dev)) {109/* TODO: spec recommends using 64 bit prefetcheable BAR.110* Check whether that works well. */
111pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |112PCI_BASE_ADDRESS_MEM_TYPE_64, &bridge_dev->bar);113}114return;115
116cap_error:117msi_uninit(dev);118msi_error:119slotid_cap_cleanup(dev);120slotid_error:121if (shpc_present(dev)) {122shpc_cleanup(dev, &bridge_dev->bar);123}124shpc_error:125pci_bridge_exitfn(dev);126}
127
128static void pci_bridge_dev_exitfn(PCIDevice *dev)129{
130PCIBridgeDev *bridge_dev = PCI_BRIDGE_DEV(dev);131
132pci_del_capability(dev, PCI_CAP_ID_VNDR, sizeof(PCIBridgeQemuCap));133if (msi_present(dev)) {134msi_uninit(dev);135}136slotid_cap_cleanup(dev);137if (shpc_present(dev)) {138shpc_cleanup(dev, &bridge_dev->bar);139}140pci_bridge_exitfn(dev);141}
142
143static void pci_bridge_dev_instance_finalize(Object *obj)144{
145/* this function is idempotent and handles (PCIDevice.shpc == NULL) */146shpc_free(PCI_DEVICE(obj));147}
148
149static void pci_bridge_dev_write_config(PCIDevice *d,150uint32_t address, uint32_t val, int len)151{
152pci_bridge_write_config(d, address, val, len);153if (msi_present(d)) {154msi_write_config(d, address, val, len);155}156if (shpc_present(d)) {157shpc_cap_write_config(d, address, val, len);158}159}
160
161static void qdev_pci_bridge_dev_reset(DeviceState *qdev)162{
163PCIDevice *dev = PCI_DEVICE(qdev);164
165pci_bridge_reset(qdev);166if (shpc_present(dev)) {167shpc_reset(dev);168}169}
170
171static Property pci_bridge_dev_properties[] = {172/* Note: 0 is not a legal chassis number. */173DEFINE_PROP_UINT8(PCI_BRIDGE_DEV_PROP_CHASSIS_NR, PCIBridgeDev, chassis_nr,1740),175DEFINE_PROP_ON_OFF_AUTO(PCI_BRIDGE_DEV_PROP_MSI, PCIBridgeDev, msi,176ON_OFF_AUTO_AUTO),177DEFINE_PROP_BIT(PCI_BRIDGE_DEV_PROP_SHPC, PCIBridgeDev, flags,178PCI_BRIDGE_DEV_F_SHPC_REQ, true),179DEFINE_PROP_UINT32("bus-reserve", PCIBridgeDev,180res_reserve.bus, -1),181DEFINE_PROP_SIZE("io-reserve", PCIBridgeDev,182res_reserve.io, -1),183DEFINE_PROP_SIZE("mem-reserve", PCIBridgeDev,184res_reserve.mem_non_pref, -1),185DEFINE_PROP_SIZE("pref32-reserve", PCIBridgeDev,186res_reserve.mem_pref_32, -1),187DEFINE_PROP_SIZE("pref64-reserve", PCIBridgeDev,188res_reserve.mem_pref_64, -1),189DEFINE_PROP_END_OF_LIST(),190};191
192static bool pci_device_shpc_present(void *opaque, int version_id)193{
194PCIDevice *dev = opaque;195
196return shpc_present(dev);197}
198
199static const VMStateDescription pci_bridge_dev_vmstate = {200.name = "pci_bridge",201.priority = MIG_PRI_PCI_BUS,202.fields = (const VMStateField[]) {203VMSTATE_PCI_DEVICE(parent_obj, PCIBridge),204SHPC_VMSTATE(shpc, PCIDevice, pci_device_shpc_present),205VMSTATE_END_OF_LIST()206}207};208
209void pci_bridge_dev_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,210Error **errp)211{
212PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);213
214if (!shpc_present(pci_hotplug_dev)) {215error_setg(errp, "standard hotplug controller has been disabled for "216"this %s", object_get_typename(OBJECT(hotplug_dev)));217return;218}219shpc_device_plug_cb(hotplug_dev, dev, errp);220}
221
222void pci_bridge_dev_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,223Error **errp)224{
225PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);226
227g_assert(shpc_present(pci_hotplug_dev));228shpc_device_unplug_cb(hotplug_dev, dev, errp);229}
230
231void pci_bridge_dev_unplug_request_cb(HotplugHandler *hotplug_dev,232DeviceState *dev, Error **errp)233{
234PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);235
236if (!shpc_present(pci_hotplug_dev)) {237error_setg(errp, "standard hotplug controller has been disabled for "238"this %s", object_get_typename(OBJECT(hotplug_dev)));239return;240}241shpc_device_unplug_request_cb(hotplug_dev, dev, errp);242}
243
244static void pci_bridge_dev_class_init(ObjectClass *klass, void *data)245{
246DeviceClass *dc = DEVICE_CLASS(klass);247PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);248HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);249
250k->realize = pci_bridge_dev_realize;251k->exit = pci_bridge_dev_exitfn;252k->config_write = pci_bridge_dev_write_config;253k->vendor_id = PCI_VENDOR_ID_REDHAT;254k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE;255k->class_id = PCI_CLASS_BRIDGE_PCI;256dc->desc = "Standard PCI Bridge";257dc->reset = qdev_pci_bridge_dev_reset;258device_class_set_props(dc, pci_bridge_dev_properties);259dc->vmsd = &pci_bridge_dev_vmstate;260set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);261hc->plug = pci_bridge_dev_plug_cb;262hc->unplug = pci_bridge_dev_unplug_cb;263hc->unplug_request = pci_bridge_dev_unplug_request_cb;264}
265
266static const TypeInfo pci_bridge_dev_info = {267.name = TYPE_PCI_BRIDGE_DEV,268.parent = TYPE_PCI_BRIDGE,269.instance_size = sizeof(PCIBridgeDev),270.class_init = pci_bridge_dev_class_init,271.instance_finalize = pci_bridge_dev_instance_finalize,272.interfaces = (InterfaceInfo[]) {273{ TYPE_HOTPLUG_HANDLER },274{ INTERFACE_CONVENTIONAL_PCI_DEVICE },275{ }276}277};278
279/*
280* Multiseat bridge. Same as the standard pci bridge, only with a
281* different pci id, so we can match it easily in the guest for
282* automagic multiseat configuration. See docs/multiseat.txt for more.
283*/
284static void pci_bridge_dev_seat_class_init(ObjectClass *klass, void *data)285{
286DeviceClass *dc = DEVICE_CLASS(klass);287PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);288
289k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE_SEAT;290dc->desc = "Standard PCI Bridge (multiseat)";291}
292
293static const TypeInfo pci_bridge_dev_seat_info = {294.name = TYPE_PCI_BRIDGE_SEAT_DEV,295.parent = TYPE_PCI_BRIDGE_DEV,296.instance_size = sizeof(PCIBridgeDev),297.class_init = pci_bridge_dev_seat_class_init,298};299
300static void pci_bridge_dev_register(void)301{
302type_register_static(&pci_bridge_dev_info);303type_register_static(&pci_bridge_dev_seat_info);304}
305
306type_init(pci_bridge_dev_register);307