xref: /openbmc/qemu/hw/pci/pcie_port.c (revision 84344ee2)
1315a1350SMichael S. Tsirkin /*
2315a1350SMichael S. Tsirkin  * pcie_port.c
3315a1350SMichael S. Tsirkin  *
4315a1350SMichael S. Tsirkin  * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
5315a1350SMichael S. Tsirkin  *                    VA Linux Systems Japan K.K.
6315a1350SMichael S. Tsirkin  *
7315a1350SMichael S. Tsirkin  * This program is free software; you can redistribute it and/or modify
8315a1350SMichael S. Tsirkin  * it under the terms of the GNU General Public License as published by
9315a1350SMichael S. Tsirkin  * the Free Software Foundation; either version 2 of the License, or
10315a1350SMichael S. Tsirkin  * (at your option) any later version.
11315a1350SMichael S. Tsirkin  *
12315a1350SMichael S. Tsirkin  * This program is distributed in the hope that it will be useful,
13315a1350SMichael S. Tsirkin  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14315a1350SMichael S. Tsirkin  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15315a1350SMichael S. Tsirkin  * GNU General Public License for more details.
16315a1350SMichael S. Tsirkin  *
17315a1350SMichael S. Tsirkin  * You should have received a copy of the GNU General Public License along
18315a1350SMichael S. Tsirkin  * with this program; if not, see <http://www.gnu.org/licenses/>.
19315a1350SMichael S. Tsirkin  */
20315a1350SMichael S. Tsirkin 
2197d5408fSPeter Maydell #include "qemu/osdep.h"
22c759b24fSMichael S. Tsirkin #include "hw/pci/pcie_port.h"
23a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
240b8fa32fSMarkus Armbruster #include "qemu/module.h"
25a66e657eSIgor Mammedov #include "hw/hotplug.h"
26315a1350SMichael S. Tsirkin 
pcie_port_init_reg(PCIDevice * d)27315a1350SMichael S. Tsirkin void pcie_port_init_reg(PCIDevice *d)
28315a1350SMichael S. Tsirkin {
29315a1350SMichael S. Tsirkin     /* Unlike pci bridge,
30315a1350SMichael S. Tsirkin        66MHz and fast back to back don't apply to pci express port. */
31315a1350SMichael S. Tsirkin     pci_set_word(d->config + PCI_STATUS, 0);
32315a1350SMichael S. Tsirkin     pci_set_word(d->config + PCI_SEC_STATUS, 0);
33315a1350SMichael S. Tsirkin 
3445eb768cSMichael S. Tsirkin     /*
3545eb768cSMichael S. Tsirkin      * Unlike conventional pci bridge, for some bits the spec states:
3645eb768cSMichael S. Tsirkin      * Does not apply to PCI Express and must be hardwired to 0.
3745eb768cSMichael S. Tsirkin      */
3845eb768cSMichael S. Tsirkin     pci_word_test_and_clear_mask(d->wmask + PCI_BRIDGE_CONTROL,
3945eb768cSMichael S. Tsirkin                                  PCI_BRIDGE_CTL_MASTER_ABORT |
4045eb768cSMichael S. Tsirkin                                  PCI_BRIDGE_CTL_FAST_BACK |
4145eb768cSMichael S. Tsirkin                                  PCI_BRIDGE_CTL_DISCARD |
4245eb768cSMichael S. Tsirkin                                  PCI_BRIDGE_CTL_SEC_DISCARD |
4345eb768cSMichael S. Tsirkin                                  PCI_BRIDGE_CTL_DISCARD_STATUS |
4445eb768cSMichael S. Tsirkin                                  PCI_BRIDGE_CTL_DISCARD_SERR);
45315a1350SMichael S. Tsirkin }
46315a1350SMichael S. Tsirkin 
47315a1350SMichael S. Tsirkin /**************************************************************************
48315a1350SMichael S. Tsirkin  * (chassis number, pcie physical slot number) -> pcie slot conversion
49315a1350SMichael S. Tsirkin  */
50315a1350SMichael S. Tsirkin struct PCIEChassis {
51315a1350SMichael S. Tsirkin     uint8_t     number;
52315a1350SMichael S. Tsirkin 
53315a1350SMichael S. Tsirkin     QLIST_HEAD(, PCIESlot) slots;
54315a1350SMichael S. Tsirkin     QLIST_ENTRY(PCIEChassis) next;
55315a1350SMichael S. Tsirkin };
56315a1350SMichael S. Tsirkin 
57315a1350SMichael S. Tsirkin static QLIST_HEAD(, PCIEChassis) chassis = QLIST_HEAD_INITIALIZER(chassis);
58315a1350SMichael S. Tsirkin 
pcie_chassis_find(uint8_t chassis_number)59315a1350SMichael S. Tsirkin static struct PCIEChassis *pcie_chassis_find(uint8_t chassis_number)
60315a1350SMichael S. Tsirkin {
61315a1350SMichael S. Tsirkin     struct PCIEChassis *c;
62315a1350SMichael S. Tsirkin     QLIST_FOREACH(c, &chassis, next) {
63315a1350SMichael S. Tsirkin         if (c->number == chassis_number) {
64315a1350SMichael S. Tsirkin             break;
65315a1350SMichael S. Tsirkin         }
66315a1350SMichael S. Tsirkin     }
67315a1350SMichael S. Tsirkin     return c;
68315a1350SMichael S. Tsirkin }
69315a1350SMichael S. Tsirkin 
pcie_chassis_create(uint8_t chassis_number)70315a1350SMichael S. Tsirkin void pcie_chassis_create(uint8_t chassis_number)
71315a1350SMichael S. Tsirkin {
72315a1350SMichael S. Tsirkin     struct PCIEChassis *c;
73315a1350SMichael S. Tsirkin     c = pcie_chassis_find(chassis_number);
74315a1350SMichael S. Tsirkin     if (c) {
75315a1350SMichael S. Tsirkin         return;
76315a1350SMichael S. Tsirkin     }
77315a1350SMichael S. Tsirkin     c = g_malloc0(sizeof(*c));
78315a1350SMichael S. Tsirkin     c->number = chassis_number;
79315a1350SMichael S. Tsirkin     QLIST_INIT(&c->slots);
80315a1350SMichael S. Tsirkin     QLIST_INSERT_HEAD(&chassis, c, next);
81315a1350SMichael S. Tsirkin }
82315a1350SMichael S. Tsirkin 
pcie_chassis_find_slot_with_chassis(struct PCIEChassis * c,uint8_t slot)83315a1350SMichael S. Tsirkin static PCIESlot *pcie_chassis_find_slot_with_chassis(struct PCIEChassis *c,
84315a1350SMichael S. Tsirkin                                                      uint8_t slot)
85315a1350SMichael S. Tsirkin {
86315a1350SMichael S. Tsirkin     PCIESlot *s;
87315a1350SMichael S. Tsirkin     QLIST_FOREACH(s, &c->slots, next) {
88315a1350SMichael S. Tsirkin         if (s->slot == slot) {
89315a1350SMichael S. Tsirkin             break;
90315a1350SMichael S. Tsirkin         }
91315a1350SMichael S. Tsirkin     }
92315a1350SMichael S. Tsirkin     return s;
93315a1350SMichael S. Tsirkin }
94315a1350SMichael S. Tsirkin 
pcie_chassis_find_slot(uint8_t chassis_number,uint16_t slot)95315a1350SMichael S. Tsirkin PCIESlot *pcie_chassis_find_slot(uint8_t chassis_number, uint16_t slot)
96315a1350SMichael S. Tsirkin {
97315a1350SMichael S. Tsirkin     struct PCIEChassis *c;
98315a1350SMichael S. Tsirkin     c = pcie_chassis_find(chassis_number);
99315a1350SMichael S. Tsirkin     if (!c) {
100315a1350SMichael S. Tsirkin         return NULL;
101315a1350SMichael S. Tsirkin     }
102315a1350SMichael S. Tsirkin     return pcie_chassis_find_slot_with_chassis(c, slot);
103315a1350SMichael S. Tsirkin }
104315a1350SMichael S. Tsirkin 
pcie_chassis_add_slot(struct PCIESlot * slot)105315a1350SMichael S. Tsirkin int pcie_chassis_add_slot(struct PCIESlot *slot)
106315a1350SMichael S. Tsirkin {
107315a1350SMichael S. Tsirkin     struct PCIEChassis *c;
108315a1350SMichael S. Tsirkin     c = pcie_chassis_find(slot->chassis);
109315a1350SMichael S. Tsirkin     if (!c) {
110315a1350SMichael S. Tsirkin         return -ENODEV;
111315a1350SMichael S. Tsirkin     }
112315a1350SMichael S. Tsirkin     if (pcie_chassis_find_slot_with_chassis(c, slot->slot)) {
113315a1350SMichael S. Tsirkin         return -EBUSY;
114315a1350SMichael S. Tsirkin     }
115315a1350SMichael S. Tsirkin     QLIST_INSERT_HEAD(&c->slots, slot, next);
116315a1350SMichael S. Tsirkin     return 0;
117315a1350SMichael S. Tsirkin }
118315a1350SMichael S. Tsirkin 
pcie_chassis_del_slot(PCIESlot * s)119315a1350SMichael S. Tsirkin void pcie_chassis_del_slot(PCIESlot *s)
120315a1350SMichael S. Tsirkin {
121315a1350SMichael S. Tsirkin     QLIST_REMOVE(s, next);
122315a1350SMichael S. Tsirkin }
123bcb75750SAndreas Färber 
124bcb75750SAndreas Färber static Property pcie_port_props[] = {
125bcb75750SAndreas Färber     DEFINE_PROP_UINT8("port", PCIEPort, port, 0),
126bcb75750SAndreas Färber     DEFINE_PROP_UINT16("aer_log_max", PCIEPort,
127bcb75750SAndreas Färber                        parent_obj.parent_obj.exp.aer_log.log_max,
128bcb75750SAndreas Färber                        PCIE_AER_LOG_MAX_DEFAULT),
129bcb75750SAndreas Färber     DEFINE_PROP_END_OF_LIST()
130bcb75750SAndreas Färber };
131bcb75750SAndreas Färber 
pcie_port_class_init(ObjectClass * oc,void * data)132bcb75750SAndreas Färber static void pcie_port_class_init(ObjectClass *oc, void *data)
133bcb75750SAndreas Färber {
134bcb75750SAndreas Färber     DeviceClass *dc = DEVICE_CLASS(oc);
135bcb75750SAndreas Färber 
1364f67d30bSMarc-André Lureau     device_class_set_props(dc, pcie_port_props);
137bcb75750SAndreas Färber }
138bcb75750SAndreas Färber 
pcie_find_port_by_pn(PCIBus * bus,uint8_t pn)139aa970ed5SJonathan Cameron PCIDevice *pcie_find_port_by_pn(PCIBus *bus, uint8_t pn)
140aa970ed5SJonathan Cameron {
141aa970ed5SJonathan Cameron     int devfn;
142aa970ed5SJonathan Cameron 
143aa970ed5SJonathan Cameron     for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
144aa970ed5SJonathan Cameron         PCIDevice *d = bus->devices[devfn];
145aa970ed5SJonathan Cameron         PCIEPort *port;
146aa970ed5SJonathan Cameron 
147aa970ed5SJonathan Cameron         if (!d || !pci_is_express(d) || !d->exp.exp_cap) {
148aa970ed5SJonathan Cameron             continue;
149aa970ed5SJonathan Cameron         }
150aa970ed5SJonathan Cameron 
151aa970ed5SJonathan Cameron         if (!object_dynamic_cast(OBJECT(d), TYPE_PCIE_PORT)) {
152aa970ed5SJonathan Cameron             continue;
153aa970ed5SJonathan Cameron         }
154aa970ed5SJonathan Cameron 
155aa970ed5SJonathan Cameron         port = PCIE_PORT(d);
156aa970ed5SJonathan Cameron         if (port->port == pn) {
157aa970ed5SJonathan Cameron             return d;
158aa970ed5SJonathan Cameron         }
159aa970ed5SJonathan Cameron     }
160aa970ed5SJonathan Cameron 
161aa970ed5SJonathan Cameron     return NULL;
162aa970ed5SJonathan Cameron }
163aa970ed5SJonathan Cameron 
164*84344ee2SJonathan Cameron /* Find first port in devfn number order */
pcie_find_port_first(PCIBus * bus)165*84344ee2SJonathan Cameron PCIDevice *pcie_find_port_first(PCIBus *bus)
166*84344ee2SJonathan Cameron {
167*84344ee2SJonathan Cameron     int devfn;
168*84344ee2SJonathan Cameron 
169*84344ee2SJonathan Cameron     for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
170*84344ee2SJonathan Cameron         PCIDevice *d = bus->devices[devfn];
171*84344ee2SJonathan Cameron 
172*84344ee2SJonathan Cameron         if (!d || !pci_is_express(d) || !d->exp.exp_cap) {
173*84344ee2SJonathan Cameron             continue;
174*84344ee2SJonathan Cameron         }
175*84344ee2SJonathan Cameron 
176*84344ee2SJonathan Cameron         if (object_dynamic_cast(OBJECT(d), TYPE_PCIE_PORT)) {
177*84344ee2SJonathan Cameron             return d;
178*84344ee2SJonathan Cameron         }
179*84344ee2SJonathan Cameron     }
180*84344ee2SJonathan Cameron 
181*84344ee2SJonathan Cameron     return NULL;
182*84344ee2SJonathan Cameron }
183*84344ee2SJonathan Cameron 
pcie_count_ds_ports(PCIBus * bus)184*84344ee2SJonathan Cameron int pcie_count_ds_ports(PCIBus *bus)
185*84344ee2SJonathan Cameron {
186*84344ee2SJonathan Cameron     int dsp_count = 0;
187*84344ee2SJonathan Cameron     int devfn;
188*84344ee2SJonathan Cameron 
189*84344ee2SJonathan Cameron     for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
190*84344ee2SJonathan Cameron         PCIDevice *d = bus->devices[devfn];
191*84344ee2SJonathan Cameron 
192*84344ee2SJonathan Cameron         if (!d || !pci_is_express(d) || !d->exp.exp_cap) {
193*84344ee2SJonathan Cameron             continue;
194*84344ee2SJonathan Cameron         }
195*84344ee2SJonathan Cameron         if (object_dynamic_cast(OBJECT(d), TYPE_PCIE_PORT)) {
196*84344ee2SJonathan Cameron             dsp_count++;
197*84344ee2SJonathan Cameron         }
198*84344ee2SJonathan Cameron     }
199*84344ee2SJonathan Cameron     return dsp_count;
200*84344ee2SJonathan Cameron }
201*84344ee2SJonathan Cameron 
pcie_slot_is_hotpluggbale_bus(HotplugHandler * plug_handler,BusState * bus)202ceefa0b7SIgor Mammedov static bool pcie_slot_is_hotpluggbale_bus(HotplugHandler *plug_handler,
203ceefa0b7SIgor Mammedov                                           BusState *bus)
204ceefa0b7SIgor Mammedov {
205ceefa0b7SIgor Mammedov     PCIESlot *s = PCIE_SLOT(bus->parent);
206ceefa0b7SIgor Mammedov     return s->hotplug;
207ceefa0b7SIgor Mammedov }
208ceefa0b7SIgor Mammedov 
209bcb75750SAndreas Färber static const TypeInfo pcie_port_type_info = {
210bcb75750SAndreas Färber     .name = TYPE_PCIE_PORT,
211bcb75750SAndreas Färber     .parent = TYPE_PCI_BRIDGE,
212bcb75750SAndreas Färber     .instance_size = sizeof(PCIEPort),
213bcb75750SAndreas Färber     .abstract = true,
214bcb75750SAndreas Färber     .class_init = pcie_port_class_init,
215bcb75750SAndreas Färber };
216bcb75750SAndreas Färber 
217bcb75750SAndreas Färber static Property pcie_slot_props[] = {
218bcb75750SAndreas Färber     DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
219bcb75750SAndreas Färber     DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
220530a0963SJulia Suvorova     DEFINE_PROP_BOOL("hotplug", PCIESlot, hotplug, true),
2211d77e157SIgor Mammedov     DEFINE_PROP_BOOL("x-do-not-expose-native-hotplug-cap", PCIESlot,
2221d77e157SIgor Mammedov                      hide_native_hotplug_cap, false),
223bcb75750SAndreas Färber     DEFINE_PROP_END_OF_LIST()
224bcb75750SAndreas Färber };
225bcb75750SAndreas Färber 
pcie_slot_class_init(ObjectClass * oc,void * data)226bcb75750SAndreas Färber static void pcie_slot_class_init(ObjectClass *oc, void *data)
227bcb75750SAndreas Färber {
228bcb75750SAndreas Färber     DeviceClass *dc = DEVICE_CLASS(oc);
229a66e657eSIgor Mammedov     HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
230bcb75750SAndreas Färber 
2314f67d30bSMarc-André Lureau     device_class_set_props(dc, pcie_slot_props);
232b9731850SDavid Hildenbrand     hc->pre_plug = pcie_cap_slot_pre_plug_cb;
2335571727aSDavid Hildenbrand     hc->plug = pcie_cap_slot_plug_cb;
234a1952d01SDavid Hildenbrand     hc->unplug = pcie_cap_slot_unplug_cb;
2355571727aSDavid Hildenbrand     hc->unplug_request = pcie_cap_slot_unplug_request_cb;
236ceefa0b7SIgor Mammedov     hc->is_hotpluggable_bus = pcie_slot_is_hotpluggbale_bus;
237bcb75750SAndreas Färber }
238bcb75750SAndreas Färber 
239bcb75750SAndreas Färber static const TypeInfo pcie_slot_type_info = {
240bcb75750SAndreas Färber     .name = TYPE_PCIE_SLOT,
241bcb75750SAndreas Färber     .parent = TYPE_PCIE_PORT,
242bcb75750SAndreas Färber     .instance_size = sizeof(PCIESlot),
243bcb75750SAndreas Färber     .abstract = true,
244bcb75750SAndreas Färber     .class_init = pcie_slot_class_init,
245a66e657eSIgor Mammedov     .interfaces = (InterfaceInfo[]) {
246a66e657eSIgor Mammedov         { TYPE_HOTPLUG_HANDLER },
247a66e657eSIgor Mammedov         { }
248a66e657eSIgor Mammedov     }
249bcb75750SAndreas Färber };
250bcb75750SAndreas Färber 
pcie_port_register_types(void)251bcb75750SAndreas Färber static void pcie_port_register_types(void)
252bcb75750SAndreas Färber {
253bcb75750SAndreas Färber     type_register_static(&pcie_port_type_info);
254bcb75750SAndreas Färber     type_register_static(&pcie_slot_type_info);
255bcb75750SAndreas Färber }
256bcb75750SAndreas Färber 
257bcb75750SAndreas Färber type_init(pcie_port_register_types)
258