1 /* 2 * PCI Expander Bridge Device Emulation 3 * 4 * Copyright (C) 2015 Red Hat Inc 5 * 6 * Authors: 7 * Marcel Apfelbaum <marcel@redhat.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2 or later. 10 * See the COPYING file in the top-level directory. 11 */ 12 13 #include "hw/pci/pci.h" 14 #include "hw/pci/pci_bus.h" 15 #include "hw/pci/pci_host.h" 16 #include "hw/pci/pci_bus.h" 17 #include "hw/pci/pci_bridge.h" 18 #include "hw/i386/pc.h" 19 #include "qemu/range.h" 20 #include "qemu/error-report.h" 21 #include "sysemu/numa.h" 22 23 #define TYPE_PXB_BUS "pxb-bus" 24 #define PXB_BUS(obj) OBJECT_CHECK(PXBBus, (obj), TYPE_PXB_BUS) 25 26 typedef struct PXBBus { 27 /*< private >*/ 28 PCIBus parent_obj; 29 /*< public >*/ 30 31 char bus_path[8]; 32 } PXBBus; 33 34 #define TYPE_PXB_DEVICE "pxb" 35 #define PXB_DEV(obj) OBJECT_CHECK(PXBDev, (obj), TYPE_PXB_DEVICE) 36 37 typedef struct PXBDev { 38 /*< private >*/ 39 PCIDevice parent_obj; 40 /*< public >*/ 41 42 uint8_t bus_nr; 43 uint16_t numa_node; 44 } PXBDev; 45 46 static GList *pxb_dev_list; 47 48 #define TYPE_PXB_HOST "pxb-host" 49 50 static int pxb_bus_num(PCIBus *bus) 51 { 52 PXBDev *pxb = PXB_DEV(bus->parent_dev); 53 54 return pxb->bus_nr; 55 } 56 57 static bool pxb_is_root(PCIBus *bus) 58 { 59 return true; /* by definition */ 60 } 61 62 static uint16_t pxb_bus_numa_node(PCIBus *bus) 63 { 64 PXBDev *pxb = PXB_DEV(bus->parent_dev); 65 66 return pxb->numa_node; 67 } 68 69 static void pxb_bus_class_init(ObjectClass *class, void *data) 70 { 71 PCIBusClass *pbc = PCI_BUS_CLASS(class); 72 73 pbc->bus_num = pxb_bus_num; 74 pbc->is_root = pxb_is_root; 75 pbc->numa_node = pxb_bus_numa_node; 76 } 77 78 static const TypeInfo pxb_bus_info = { 79 .name = TYPE_PXB_BUS, 80 .parent = TYPE_PCI_BUS, 81 .instance_size = sizeof(PXBBus), 82 .class_init = pxb_bus_class_init, 83 }; 84 85 static const char *pxb_host_root_bus_path(PCIHostState *host_bridge, 86 PCIBus *rootbus) 87 { 88 PXBBus *bus = PXB_BUS(rootbus); 89 90 snprintf(bus->bus_path, 8, "0000:%02x", pxb_bus_num(rootbus)); 91 return bus->bus_path; 92 } 93 94 static char *pxb_host_ofw_unit_address(const SysBusDevice *dev) 95 { 96 const PCIHostState *pxb_host; 97 const PCIBus *pxb_bus; 98 const PXBDev *pxb_dev; 99 int position; 100 const DeviceState *pxb_dev_base; 101 const PCIHostState *main_host; 102 const SysBusDevice *main_host_sbd; 103 104 pxb_host = PCI_HOST_BRIDGE(dev); 105 pxb_bus = pxb_host->bus; 106 pxb_dev = PXB_DEV(pxb_bus->parent_dev); 107 position = g_list_index(pxb_dev_list, pxb_dev); 108 assert(position >= 0); 109 110 pxb_dev_base = DEVICE(pxb_dev); 111 main_host = PCI_HOST_BRIDGE(pxb_dev_base->parent_bus->parent); 112 main_host_sbd = SYS_BUS_DEVICE(main_host); 113 114 if (main_host_sbd->num_mmio > 0) { 115 return g_strdup_printf(TARGET_FMT_plx ",%x", 116 main_host_sbd->mmio[0].addr, position + 1); 117 } 118 if (main_host_sbd->num_pio > 0) { 119 return g_strdup_printf("i%04x,%x", 120 main_host_sbd->pio[0], position + 1); 121 } 122 return NULL; 123 } 124 125 static void pxb_host_class_init(ObjectClass *class, void *data) 126 { 127 DeviceClass *dc = DEVICE_CLASS(class); 128 SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(class); 129 PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class); 130 131 dc->fw_name = "pci"; 132 sbc->explicit_ofw_unit_address = pxb_host_ofw_unit_address; 133 hc->root_bus_path = pxb_host_root_bus_path; 134 } 135 136 static const TypeInfo pxb_host_info = { 137 .name = TYPE_PXB_HOST, 138 .parent = TYPE_PCI_HOST_BRIDGE, 139 .class_init = pxb_host_class_init, 140 }; 141 142 /* 143 * Registers the PXB bus as a child of the i440fx root bus. 144 * 145 * Returns 0 on successs, -1 if i440fx host was not 146 * found or the bus number is already in use. 147 */ 148 static int pxb_register_bus(PCIDevice *dev, PCIBus *pxb_bus) 149 { 150 PCIBus *bus = dev->bus; 151 int pxb_bus_num = pci_bus_num(pxb_bus); 152 153 if (bus->parent_dev) { 154 error_report("PXB devices can be attached only to root bus."); 155 return -1; 156 } 157 158 QLIST_FOREACH(bus, &bus->child, sibling) { 159 if (pci_bus_num(bus) == pxb_bus_num) { 160 error_report("Bus %d is already in use.", pxb_bus_num); 161 return -1; 162 } 163 } 164 QLIST_INSERT_HEAD(&dev->bus->child, pxb_bus, sibling); 165 166 return 0; 167 } 168 169 static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin) 170 { 171 PCIDevice *pxb = pci_dev->bus->parent_dev; 172 173 /* 174 * The bios does not index the pxb slot number when 175 * it computes the IRQ because it resides on bus 0 176 * and not on the current bus. 177 * However QEMU routes the irq through bus 0 and adds 178 * the pxb slot to the IRQ computation of the PXB 179 * device. 180 * 181 * Synchronize between bios and QEMU by canceling 182 * pxb's effect. 183 */ 184 return pin - PCI_SLOT(pxb->devfn); 185 } 186 187 static gint pxb_compare(gconstpointer a, gconstpointer b) 188 { 189 const PXBDev *pxb_a = a, *pxb_b = b; 190 191 return pxb_a->bus_nr < pxb_b->bus_nr ? -1 : 192 pxb_a->bus_nr > pxb_b->bus_nr ? 1 : 193 0; 194 } 195 196 static int pxb_dev_initfn(PCIDevice *dev) 197 { 198 PXBDev *pxb = PXB_DEV(dev); 199 DeviceState *ds, *bds; 200 PCIBus *bus; 201 const char *dev_name = NULL; 202 203 if (pxb->numa_node != NUMA_NODE_UNASSIGNED && 204 pxb->numa_node >= nb_numa_nodes) { 205 error_report("Illegal numa node %d.", pxb->numa_node); 206 return -EINVAL; 207 } 208 209 if (dev->qdev.id && *dev->qdev.id) { 210 dev_name = dev->qdev.id; 211 } 212 213 ds = qdev_create(NULL, TYPE_PXB_HOST); 214 bus = pci_bus_new(ds, "pxb-internal", NULL, NULL, 0, TYPE_PXB_BUS); 215 216 bus->parent_dev = dev; 217 bus->address_space_mem = dev->bus->address_space_mem; 218 bus->address_space_io = dev->bus->address_space_io; 219 bus->map_irq = pxb_map_irq_fn; 220 221 bds = qdev_create(BUS(bus), "pci-bridge"); 222 bds->id = dev_name; 223 qdev_prop_set_uint8(bds, PCI_BRIDGE_DEV_PROP_CHASSIS_NR, pxb->bus_nr); 224 qdev_prop_set_bit(bds, PCI_BRIDGE_DEV_PROP_SHPC, false); 225 226 PCI_HOST_BRIDGE(ds)->bus = bus; 227 228 if (pxb_register_bus(dev, bus)) { 229 return -EINVAL; 230 } 231 232 qdev_init_nofail(ds); 233 qdev_init_nofail(bds); 234 235 pci_word_test_and_set_mask(dev->config + PCI_STATUS, 236 PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK); 237 pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST); 238 239 pxb_dev_list = g_list_insert_sorted(pxb_dev_list, pxb, pxb_compare); 240 return 0; 241 } 242 243 static void pxb_dev_exitfn(PCIDevice *pci_dev) 244 { 245 PXBDev *pxb = PXB_DEV(pci_dev); 246 247 pxb_dev_list = g_list_remove(pxb_dev_list, pxb); 248 } 249 250 static Property pxb_dev_properties[] = { 251 /* Note: 0 is not a legal a PXB bus number. */ 252 DEFINE_PROP_UINT8("bus_nr", PXBDev, bus_nr, 0), 253 DEFINE_PROP_UINT16("numa_node", PXBDev, numa_node, NUMA_NODE_UNASSIGNED), 254 DEFINE_PROP_END_OF_LIST(), 255 }; 256 257 static void pxb_dev_class_init(ObjectClass *klass, void *data) 258 { 259 DeviceClass *dc = DEVICE_CLASS(klass); 260 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 261 262 k->init = pxb_dev_initfn; 263 k->exit = pxb_dev_exitfn; 264 k->vendor_id = PCI_VENDOR_ID_REDHAT; 265 k->device_id = PCI_DEVICE_ID_REDHAT_PXB; 266 k->class_id = PCI_CLASS_BRIDGE_HOST; 267 268 dc->desc = "PCI Expander Bridge"; 269 dc->props = pxb_dev_properties; 270 } 271 272 static const TypeInfo pxb_dev_info = { 273 .name = TYPE_PXB_DEVICE, 274 .parent = TYPE_PCI_DEVICE, 275 .instance_size = sizeof(PXBDev), 276 .class_init = pxb_dev_class_init, 277 }; 278 279 static void pxb_register_types(void) 280 { 281 type_register_static(&pxb_bus_info); 282 type_register_static(&pxb_host_info); 283 type_register_static(&pxb_dev_info); 284 } 285 286 type_init(pxb_register_types) 287