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