xref: /qemu/hw/pci-bridge/pci_bridge_dev.c (revision 125ee0ed)
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 
22c0907c9eSPaolo Bonzini #include "hw/pci/pci_bridge.h"
23c0907c9eSPaolo Bonzini #include "hw/pci/pci_ids.h"
24c0907c9eSPaolo Bonzini #include "hw/pci/msi.h"
25c0907c9eSPaolo Bonzini #include "hw/pci/shpc.h"
26c0907c9eSPaolo Bonzini #include "hw/pci/slotid_cap.h"
27c0907c9eSPaolo Bonzini #include "exec/memory.h"
28c0907c9eSPaolo Bonzini #include "hw/pci/pci_bus.h"
29c0907c9eSPaolo Bonzini 
30c0907c9eSPaolo Bonzini struct PCIBridgeDev {
31c0907c9eSPaolo Bonzini     PCIBridge bridge;
32c0907c9eSPaolo Bonzini     MemoryRegion bar;
33c0907c9eSPaolo Bonzini     uint8_t chassis_nr;
34c0907c9eSPaolo Bonzini #define PCI_BRIDGE_DEV_F_MSI_REQ 0
35c0907c9eSPaolo Bonzini     uint32_t flags;
36c0907c9eSPaolo Bonzini };
37c0907c9eSPaolo Bonzini typedef struct PCIBridgeDev PCIBridgeDev;
38c0907c9eSPaolo Bonzini 
39c0907c9eSPaolo Bonzini static int pci_bridge_dev_initfn(PCIDevice *dev)
40c0907c9eSPaolo Bonzini {
41c0907c9eSPaolo Bonzini     PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
42c0907c9eSPaolo Bonzini     PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br);
43c0907c9eSPaolo Bonzini     int err;
44c0907c9eSPaolo Bonzini 
45c0907c9eSPaolo Bonzini     err = pci_bridge_initfn(dev, TYPE_PCI_BUS);
46c0907c9eSPaolo Bonzini     if (err) {
47c0907c9eSPaolo Bonzini         goto bridge_error;
48c0907c9eSPaolo Bonzini     }
4940c5dce9SPaolo Bonzini     memory_region_init(&bridge_dev->bar, OBJECT(dev), "shpc-bar", shpc_bar_size(dev));
50c0907c9eSPaolo Bonzini     err = shpc_init(dev, &br->sec_bus, &bridge_dev->bar, 0);
51c0907c9eSPaolo Bonzini     if (err) {
52c0907c9eSPaolo Bonzini         goto shpc_error;
53c0907c9eSPaolo Bonzini     }
54c0907c9eSPaolo Bonzini     err = slotid_cap_init(dev, 0, bridge_dev->chassis_nr, 0);
55c0907c9eSPaolo Bonzini     if (err) {
56c0907c9eSPaolo Bonzini         goto slotid_error;
57c0907c9eSPaolo Bonzini     }
58c0907c9eSPaolo Bonzini     if ((bridge_dev->flags & (1 << PCI_BRIDGE_DEV_F_MSI_REQ)) &&
59c0907c9eSPaolo Bonzini         msi_supported) {
60c0907c9eSPaolo Bonzini         err = msi_init(dev, 0, 1, true, true);
61c0907c9eSPaolo Bonzini         if (err < 0) {
62c0907c9eSPaolo Bonzini             goto msi_error;
63c0907c9eSPaolo Bonzini         }
64c0907c9eSPaolo Bonzini     }
65c0907c9eSPaolo Bonzini     /* TODO: spec recommends using 64 bit prefetcheable BAR.
66c0907c9eSPaolo Bonzini      * Check whether that works well. */
67c0907c9eSPaolo Bonzini     pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
68c0907c9eSPaolo Bonzini 		     PCI_BASE_ADDRESS_MEM_TYPE_64, &bridge_dev->bar);
69c0907c9eSPaolo Bonzini     dev->config[PCI_INTERRUPT_PIN] = 0x1;
70c0907c9eSPaolo Bonzini     return 0;
71c0907c9eSPaolo Bonzini msi_error:
72c0907c9eSPaolo Bonzini     slotid_cap_cleanup(dev);
73c0907c9eSPaolo Bonzini slotid_error:
74c0907c9eSPaolo Bonzini     shpc_cleanup(dev, &bridge_dev->bar);
75c0907c9eSPaolo Bonzini shpc_error:
76c0907c9eSPaolo Bonzini     memory_region_destroy(&bridge_dev->bar);
77c0907c9eSPaolo Bonzini     pci_bridge_exitfn(dev);
78c0907c9eSPaolo Bonzini bridge_error:
79c0907c9eSPaolo Bonzini     return err;
80c0907c9eSPaolo Bonzini }
81c0907c9eSPaolo Bonzini 
82c0907c9eSPaolo Bonzini static void pci_bridge_dev_exitfn(PCIDevice *dev)
83c0907c9eSPaolo Bonzini {
84c0907c9eSPaolo Bonzini     PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
85c0907c9eSPaolo Bonzini     PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br);
86c0907c9eSPaolo Bonzini     if (msi_present(dev)) {
87c0907c9eSPaolo Bonzini         msi_uninit(dev);
88c0907c9eSPaolo Bonzini     }
89c0907c9eSPaolo Bonzini     slotid_cap_cleanup(dev);
90c0907c9eSPaolo Bonzini     shpc_cleanup(dev, &bridge_dev->bar);
91c0907c9eSPaolo Bonzini     memory_region_destroy(&bridge_dev->bar);
92c0907c9eSPaolo Bonzini     pci_bridge_exitfn(dev);
93c0907c9eSPaolo Bonzini }
94c0907c9eSPaolo Bonzini 
95c0907c9eSPaolo Bonzini static void pci_bridge_dev_write_config(PCIDevice *d,
96c0907c9eSPaolo Bonzini                                         uint32_t address, uint32_t val, int len)
97c0907c9eSPaolo Bonzini {
98c0907c9eSPaolo Bonzini     pci_bridge_write_config(d, address, val, len);
99c0907c9eSPaolo Bonzini     if (msi_present(d)) {
100c0907c9eSPaolo Bonzini         msi_write_config(d, address, val, len);
101c0907c9eSPaolo Bonzini     }
102c0907c9eSPaolo Bonzini     shpc_cap_write_config(d, address, val, len);
103c0907c9eSPaolo Bonzini }
104c0907c9eSPaolo Bonzini 
105c0907c9eSPaolo Bonzini static void qdev_pci_bridge_dev_reset(DeviceState *qdev)
106c0907c9eSPaolo Bonzini {
107c0907c9eSPaolo Bonzini     PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
108c0907c9eSPaolo Bonzini 
109c0907c9eSPaolo Bonzini     pci_bridge_reset(qdev);
110c0907c9eSPaolo Bonzini     shpc_reset(dev);
111c0907c9eSPaolo Bonzini }
112c0907c9eSPaolo Bonzini 
113c0907c9eSPaolo Bonzini static Property pci_bridge_dev_properties[] = {
114c0907c9eSPaolo Bonzini                     /* Note: 0 is not a legal chassis number. */
115c0907c9eSPaolo Bonzini     DEFINE_PROP_UINT8("chassis_nr", PCIBridgeDev, chassis_nr, 0),
116c0907c9eSPaolo Bonzini     DEFINE_PROP_BIT("msi", PCIBridgeDev, flags, PCI_BRIDGE_DEV_F_MSI_REQ, true),
117c0907c9eSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
118c0907c9eSPaolo Bonzini };
119c0907c9eSPaolo Bonzini 
120c0907c9eSPaolo Bonzini static const VMStateDescription pci_bridge_dev_vmstate = {
121c0907c9eSPaolo Bonzini     .name = "pci_bridge",
122c0907c9eSPaolo Bonzini     .fields = (VMStateField[]) {
123c0907c9eSPaolo Bonzini         VMSTATE_PCI_DEVICE(bridge.dev, PCIBridgeDev),
124c0907c9eSPaolo Bonzini         SHPC_VMSTATE(bridge.dev.shpc, PCIBridgeDev),
125c0907c9eSPaolo Bonzini         VMSTATE_END_OF_LIST()
126c0907c9eSPaolo Bonzini     }
127c0907c9eSPaolo Bonzini };
128c0907c9eSPaolo Bonzini 
129c0907c9eSPaolo Bonzini static void pci_bridge_dev_class_init(ObjectClass *klass, void *data)
130c0907c9eSPaolo Bonzini {
131c0907c9eSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
132c0907c9eSPaolo Bonzini     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
133c0907c9eSPaolo Bonzini     k->init = pci_bridge_dev_initfn;
134c0907c9eSPaolo Bonzini     k->exit = pci_bridge_dev_exitfn;
135c0907c9eSPaolo Bonzini     k->config_write = pci_bridge_dev_write_config;
136c0907c9eSPaolo Bonzini     k->vendor_id = PCI_VENDOR_ID_REDHAT;
137c0907c9eSPaolo Bonzini     k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE;
138c0907c9eSPaolo Bonzini     k->class_id = PCI_CLASS_BRIDGE_PCI;
139c0907c9eSPaolo Bonzini     k->is_bridge = 1,
140c0907c9eSPaolo Bonzini     dc->desc = "Standard PCI Bridge";
141c0907c9eSPaolo Bonzini     dc->reset = qdev_pci_bridge_dev_reset;
142c0907c9eSPaolo Bonzini     dc->props = pci_bridge_dev_properties;
143c0907c9eSPaolo Bonzini     dc->vmsd = &pci_bridge_dev_vmstate;
144*125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
145c0907c9eSPaolo Bonzini }
146c0907c9eSPaolo Bonzini 
147c0907c9eSPaolo Bonzini static const TypeInfo pci_bridge_dev_info = {
148c0907c9eSPaolo Bonzini     .name = "pci-bridge",
149c0907c9eSPaolo Bonzini     .parent        = TYPE_PCI_DEVICE,
150c0907c9eSPaolo Bonzini     .instance_size = sizeof(PCIBridgeDev),
151c0907c9eSPaolo Bonzini     .class_init = pci_bridge_dev_class_init,
152c0907c9eSPaolo Bonzini };
153c0907c9eSPaolo Bonzini 
154c0907c9eSPaolo Bonzini static void pci_bridge_dev_register(void)
155c0907c9eSPaolo Bonzini {
156c0907c9eSPaolo Bonzini     type_register_static(&pci_bridge_dev_info);
157c0907c9eSPaolo Bonzini }
158c0907c9eSPaolo Bonzini 
159c0907c9eSPaolo Bonzini type_init(pci_bridge_dev_register);
160