root / hw / pci-bridge / pci_bridge_dev.c @ 216db403
History | View | Annotate | Download (5.1 kB)
1 | 4eb812f7 | Michael S. Tsirkin | /*
|
---|---|---|---|
2 | 4eb812f7 | Michael S. Tsirkin | * Standard PCI Bridge Device
|
3 | 4eb812f7 | Michael S. Tsirkin | *
|
4 | 4eb812f7 | Michael S. Tsirkin | * Copyright (c) 2011 Red Hat Inc. Author: Michael S. Tsirkin <mst@redhat.com>
|
5 | 4eb812f7 | Michael S. Tsirkin | *
|
6 | 4eb812f7 | Michael S. Tsirkin | * http://www.pcisig.com/specifications/conventional/pci_to_pci_bridge_architecture/
|
7 | 4eb812f7 | Michael S. Tsirkin | *
|
8 | 4eb812f7 | Michael S. Tsirkin | * This program is free software; you can redistribute it and/or modify
|
9 | 4eb812f7 | Michael S. Tsirkin | * it under the terms of the GNU General Public License as published by
|
10 | 4eb812f7 | Michael S. Tsirkin | * the Free Software Foundation; either version 2 of the License, or
|
11 | 4eb812f7 | Michael S. Tsirkin | * (at your option) any later version.
|
12 | 4eb812f7 | Michael S. Tsirkin | *
|
13 | 4eb812f7 | Michael S. Tsirkin | * This program is distributed in the hope that it will be useful,
|
14 | 4eb812f7 | Michael S. Tsirkin | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15 | 4eb812f7 | Michael S. Tsirkin | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16 | 4eb812f7 | Michael S. Tsirkin | * GNU General Public License for more details.
|
17 | 4eb812f7 | Michael S. Tsirkin | *
|
18 | 4eb812f7 | Michael S. Tsirkin | * You should have received a copy of the GNU General Public License along
|
19 | 4eb812f7 | Michael S. Tsirkin | * with this program; if not, see <http://www.gnu.org/licenses/>.
|
20 | 4eb812f7 | Michael S. Tsirkin | */
|
21 | 4eb812f7 | Michael S. Tsirkin | |
22 | 83c9f4ca | Paolo Bonzini | #include "hw/pci/pci_bridge.h" |
23 | 83c9f4ca | Paolo Bonzini | #include "hw/pci/pci_ids.h" |
24 | 83c9f4ca | Paolo Bonzini | #include "hw/pci/msi.h" |
25 | 83c9f4ca | Paolo Bonzini | #include "hw/pci/shpc.h" |
26 | 83c9f4ca | Paolo Bonzini | #include "hw/pci/slotid_cap.h" |
27 | 022c62cb | Paolo Bonzini | #include "exec/memory.h" |
28 | 83c9f4ca | Paolo Bonzini | #include "hw/pci/pci_bus.h" |
29 | 5d268704 | Igor Mammedov | #include "hw/hotplug.h" |
30 | 4eb812f7 | Michael S. Tsirkin | |
31 | 57524e14 | Andreas Färber | #define TYPE_PCI_BRIDGE_DEV "pci-bridge" |
32 | 57524e14 | Andreas Färber | #define PCI_BRIDGE_DEV(obj) \
|
33 | 57524e14 | Andreas Färber | OBJECT_CHECK(PCIBridgeDev, (obj), TYPE_PCI_BRIDGE_DEV) |
34 | 57524e14 | Andreas Färber | |
35 | 4eb812f7 | Michael S. Tsirkin | struct PCIBridgeDev {
|
36 | 57524e14 | Andreas Färber | /*< private >*/
|
37 | 57524e14 | Andreas Färber | PCIBridge parent_obj; |
38 | 57524e14 | Andreas Färber | /*< public >*/
|
39 | 57524e14 | Andreas Färber | |
40 | 4eb812f7 | Michael S. Tsirkin | MemoryRegion bar; |
41 | 4eb812f7 | Michael S. Tsirkin | uint8_t chassis_nr; |
42 | 4eb812f7 | Michael S. Tsirkin | #define PCI_BRIDGE_DEV_F_MSI_REQ 0 |
43 | 4eb812f7 | Michael S. Tsirkin | uint32_t flags; |
44 | 4eb812f7 | Michael S. Tsirkin | }; |
45 | 4eb812f7 | Michael S. Tsirkin | typedef struct PCIBridgeDev PCIBridgeDev; |
46 | 4eb812f7 | Michael S. Tsirkin | |
47 | 4eb812f7 | Michael S. Tsirkin | static int pci_bridge_dev_initfn(PCIDevice *dev) |
48 | 4eb812f7 | Michael S. Tsirkin | { |
49 | f055e96b | Andreas Färber | PCIBridge *br = PCI_BRIDGE(dev); |
50 | 57524e14 | Andreas Färber | PCIBridgeDev *bridge_dev = PCI_BRIDGE_DEV(dev); |
51 | f90c2bcd | Alex Williamson | int err;
|
52 | f90c2bcd | Alex Williamson | |
53 | 60a0e443 | Alex Williamson | err = pci_bridge_initfn(dev, TYPE_PCI_BUS); |
54 | 4eb812f7 | Michael S. Tsirkin | if (err) {
|
55 | 4eb812f7 | Michael S. Tsirkin | goto bridge_error;
|
56 | 4eb812f7 | Michael S. Tsirkin | } |
57 | c008ac0c | Marcel Apfelbaum | dev->config[PCI_INTERRUPT_PIN] = 0x1;
|
58 | 40c5dce9 | Paolo Bonzini | memory_region_init(&bridge_dev->bar, OBJECT(dev), "shpc-bar", shpc_bar_size(dev));
|
59 | 4eb812f7 | Michael S. Tsirkin | err = shpc_init(dev, &br->sec_bus, &bridge_dev->bar, 0);
|
60 | 4eb812f7 | Michael S. Tsirkin | if (err) {
|
61 | 4eb812f7 | Michael S. Tsirkin | goto shpc_error;
|
62 | 4eb812f7 | Michael S. Tsirkin | } |
63 | 4eb812f7 | Michael S. Tsirkin | err = slotid_cap_init(dev, 0, bridge_dev->chassis_nr, 0); |
64 | 4eb812f7 | Michael S. Tsirkin | if (err) {
|
65 | 4eb812f7 | Michael S. Tsirkin | goto slotid_error;
|
66 | 4eb812f7 | Michael S. Tsirkin | } |
67 | 4eb812f7 | Michael S. Tsirkin | if ((bridge_dev->flags & (1 << PCI_BRIDGE_DEV_F_MSI_REQ)) && |
68 | 4eb812f7 | Michael S. Tsirkin | msi_supported) { |
69 | 4eb812f7 | Michael S. Tsirkin | err = msi_init(dev, 0, 1, true, true); |
70 | 4eb812f7 | Michael S. Tsirkin | if (err < 0) { |
71 | 4eb812f7 | Michael S. Tsirkin | goto msi_error;
|
72 | 4eb812f7 | Michael S. Tsirkin | } |
73 | 4eb812f7 | Michael S. Tsirkin | } |
74 | 4eb812f7 | Michael S. Tsirkin | /* TODO: spec recommends using 64 bit prefetcheable BAR.
|
75 | 4eb812f7 | Michael S. Tsirkin | * Check whether that works well. */
|
76 | 4eb812f7 | Michael S. Tsirkin | pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY |
|
77 | 4eb812f7 | Michael S. Tsirkin | PCI_BASE_ADDRESS_MEM_TYPE_64, &bridge_dev->bar); |
78 | 4eb812f7 | Michael S. Tsirkin | return 0; |
79 | 4eb812f7 | Michael S. Tsirkin | msi_error:
|
80 | 4eb812f7 | Michael S. Tsirkin | slotid_cap_cleanup(dev); |
81 | 4eb812f7 | Michael S. Tsirkin | slotid_error:
|
82 | 4eb812f7 | Michael S. Tsirkin | shpc_cleanup(dev, &bridge_dev->bar); |
83 | 4eb812f7 | Michael S. Tsirkin | shpc_error:
|
84 | 4eb812f7 | Michael S. Tsirkin | memory_region_destroy(&bridge_dev->bar); |
85 | f90c2bcd | Alex Williamson | pci_bridge_exitfn(dev); |
86 | 4eb812f7 | Michael S. Tsirkin | bridge_error:
|
87 | 4eb812f7 | Michael S. Tsirkin | return err;
|
88 | 4eb812f7 | Michael S. Tsirkin | } |
89 | 4eb812f7 | Michael S. Tsirkin | |
90 | f90c2bcd | Alex Williamson | static void pci_bridge_dev_exitfn(PCIDevice *dev) |
91 | 4eb812f7 | Michael S. Tsirkin | { |
92 | 57524e14 | Andreas Färber | PCIBridgeDev *bridge_dev = PCI_BRIDGE_DEV(dev); |
93 | 4eb812f7 | Michael S. Tsirkin | if (msi_present(dev)) {
|
94 | 4eb812f7 | Michael S. Tsirkin | msi_uninit(dev); |
95 | 4eb812f7 | Michael S. Tsirkin | } |
96 | 4eb812f7 | Michael S. Tsirkin | slotid_cap_cleanup(dev); |
97 | 4eb812f7 | Michael S. Tsirkin | shpc_cleanup(dev, &bridge_dev->bar); |
98 | 4eb812f7 | Michael S. Tsirkin | memory_region_destroy(&bridge_dev->bar); |
99 | f90c2bcd | Alex Williamson | pci_bridge_exitfn(dev); |
100 | 4eb812f7 | Michael S. Tsirkin | } |
101 | 4eb812f7 | Michael S. Tsirkin | |
102 | 4eb812f7 | Michael S. Tsirkin | static void pci_bridge_dev_write_config(PCIDevice *d, |
103 | 4eb812f7 | Michael S. Tsirkin | uint32_t address, uint32_t val, int len)
|
104 | 4eb812f7 | Michael S. Tsirkin | { |
105 | 4eb812f7 | Michael S. Tsirkin | pci_bridge_write_config(d, address, val, len); |
106 | 4eb812f7 | Michael S. Tsirkin | if (msi_present(d)) {
|
107 | 4eb812f7 | Michael S. Tsirkin | msi_write_config(d, address, val, len); |
108 | 4eb812f7 | Michael S. Tsirkin | } |
109 | 4eb812f7 | Michael S. Tsirkin | shpc_cap_write_config(d, address, val, len); |
110 | 4eb812f7 | Michael S. Tsirkin | } |
111 | 4eb812f7 | Michael S. Tsirkin | |
112 | 4eb812f7 | Michael S. Tsirkin | static void qdev_pci_bridge_dev_reset(DeviceState *qdev) |
113 | 4eb812f7 | Michael S. Tsirkin | { |
114 | 57524e14 | Andreas Färber | PCIDevice *dev = PCI_DEVICE(qdev); |
115 | cbd2d434 | Jan Kiszka | |
116 | 4eb812f7 | Michael S. Tsirkin | pci_bridge_reset(qdev); |
117 | 4eb812f7 | Michael S. Tsirkin | shpc_reset(dev); |
118 | 4eb812f7 | Michael S. Tsirkin | } |
119 | 4eb812f7 | Michael S. Tsirkin | |
120 | 4eb812f7 | Michael S. Tsirkin | static Property pci_bridge_dev_properties[] = {
|
121 | 4eb812f7 | Michael S. Tsirkin | /* Note: 0 is not a legal chassis number. */
|
122 | 4eb812f7 | Michael S. Tsirkin | DEFINE_PROP_UINT8("chassis_nr", PCIBridgeDev, chassis_nr, 0), |
123 | 4eb812f7 | Michael S. Tsirkin | DEFINE_PROP_BIT("msi", PCIBridgeDev, flags, PCI_BRIDGE_DEV_F_MSI_REQ, true), |
124 | 4eb812f7 | Michael S. Tsirkin | DEFINE_PROP_END_OF_LIST(), |
125 | 4eb812f7 | Michael S. Tsirkin | }; |
126 | 4eb812f7 | Michael S. Tsirkin | |
127 | 4eb812f7 | Michael S. Tsirkin | static const VMStateDescription pci_bridge_dev_vmstate = { |
128 | 4eb812f7 | Michael S. Tsirkin | .name = "pci_bridge",
|
129 | 4eb812f7 | Michael S. Tsirkin | .fields = (VMStateField[]) { |
130 | 57524e14 | Andreas Färber | VMSTATE_PCI_DEVICE(parent_obj, PCIBridge), |
131 | 57524e14 | Andreas Färber | SHPC_VMSTATE(shpc, PCIDevice), |
132 | 4eb812f7 | Michael S. Tsirkin | VMSTATE_END_OF_LIST() |
133 | 4eb812f7 | Michael S. Tsirkin | } |
134 | 4eb812f7 | Michael S. Tsirkin | }; |
135 | 4eb812f7 | Michael S. Tsirkin | |
136 | 4eb812f7 | Michael S. Tsirkin | static void pci_bridge_dev_class_init(ObjectClass *klass, void *data) |
137 | 4eb812f7 | Michael S. Tsirkin | { |
138 | 4eb812f7 | Michael S. Tsirkin | DeviceClass *dc = DEVICE_CLASS(klass); |
139 | 4eb812f7 | Michael S. Tsirkin | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
140 | 5d268704 | Igor Mammedov | HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); |
141 | 5d268704 | Igor Mammedov | |
142 | 4eb812f7 | Michael S. Tsirkin | k->init = pci_bridge_dev_initfn; |
143 | 4eb812f7 | Michael S. Tsirkin | k->exit = pci_bridge_dev_exitfn; |
144 | 4eb812f7 | Michael S. Tsirkin | k->config_write = pci_bridge_dev_write_config; |
145 | 5c03a254 | Paolo Bonzini | k->vendor_id = PCI_VENDOR_ID_REDHAT; |
146 | 5c03a254 | Paolo Bonzini | k->device_id = PCI_DEVICE_ID_REDHAT_BRIDGE; |
147 | 4eb812f7 | Michael S. Tsirkin | k->class_id = PCI_CLASS_BRIDGE_PCI; |
148 | 4eb812f7 | Michael S. Tsirkin | k->is_bridge = 1,
|
149 | 4eb812f7 | Michael S. Tsirkin | dc->desc = "Standard PCI Bridge";
|
150 | 4eb812f7 | Michael S. Tsirkin | dc->reset = qdev_pci_bridge_dev_reset; |
151 | 4eb812f7 | Michael S. Tsirkin | dc->props = pci_bridge_dev_properties; |
152 | 4eb812f7 | Michael S. Tsirkin | dc->vmsd = &pci_bridge_dev_vmstate; |
153 | 125ee0ed | Marcel Apfelbaum | set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); |
154 | 5d268704 | Igor Mammedov | hc->plug = shpc_device_hotplug_cb; |
155 | 5d268704 | Igor Mammedov | hc->unplug = shpc_device_hot_unplug_cb; |
156 | 4eb812f7 | Michael S. Tsirkin | } |
157 | 4eb812f7 | Michael S. Tsirkin | |
158 | 8c43a6f0 | Andreas Färber | static const TypeInfo pci_bridge_dev_info = { |
159 | 57524e14 | Andreas Färber | .name = TYPE_PCI_BRIDGE_DEV, |
160 | f055e96b | Andreas Färber | .parent = TYPE_PCI_BRIDGE, |
161 | 4eb812f7 | Michael S. Tsirkin | .instance_size = sizeof(PCIBridgeDev),
|
162 | 4eb812f7 | Michael S. Tsirkin | .class_init = pci_bridge_dev_class_init, |
163 | 5d268704 | Igor Mammedov | .interfaces = (InterfaceInfo[]) { |
164 | 5d268704 | Igor Mammedov | { TYPE_HOTPLUG_HANDLER }, |
165 | 5d268704 | Igor Mammedov | { } |
166 | 5d268704 | Igor Mammedov | } |
167 | 4eb812f7 | Michael S. Tsirkin | }; |
168 | 4eb812f7 | Michael S. Tsirkin | |
169 | 4eb812f7 | Michael S. Tsirkin | static void pci_bridge_dev_register(void) |
170 | 4eb812f7 | Michael S. Tsirkin | { |
171 | 4eb812f7 | Michael S. Tsirkin | type_register_static(&pci_bridge_dev_info); |
172 | 4eb812f7 | Michael S. Tsirkin | } |
173 | 4eb812f7 | Michael S. Tsirkin | |
174 | 4eb812f7 | Michael S. Tsirkin | type_init(pci_bridge_dev_register); |