qemu/hw/pci/pcie_port.c
<<
>>
Prefs
   1/*
   2 * pcie_port.c
   3 *
   4 * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
   5 *                    VA Linux Systems Japan K.K.
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License along
  18 * with this program; if not, see <http://www.gnu.org/licenses/>.
  19 */
  20
  21#include "qemu/osdep.h"
  22#include "hw/pci/pcie_port.h"
  23#include "qemu/module.h"
  24#include "hw/hotplug.h"
  25
  26void pcie_port_init_reg(PCIDevice *d)
  27{
  28    /* Unlike pci bridge,
  29       66MHz and fast back to back don't apply to pci express port. */
  30    pci_set_word(d->config + PCI_STATUS, 0);
  31    pci_set_word(d->config + PCI_SEC_STATUS, 0);
  32
  33    /*
  34     * Unlike conventional pci bridge, for some bits the spec states:
  35     * Does not apply to PCI Express and must be hardwired to 0.
  36     */
  37    pci_word_test_and_clear_mask(d->wmask + PCI_BRIDGE_CONTROL,
  38                                 PCI_BRIDGE_CTL_MASTER_ABORT |
  39                                 PCI_BRIDGE_CTL_FAST_BACK |
  40                                 PCI_BRIDGE_CTL_DISCARD |
  41                                 PCI_BRIDGE_CTL_SEC_DISCARD |
  42                                 PCI_BRIDGE_CTL_DISCARD_STATUS |
  43                                 PCI_BRIDGE_CTL_DISCARD_SERR);
  44}
  45
  46/**************************************************************************
  47 * (chassis number, pcie physical slot number) -> pcie slot conversion
  48 */
  49struct PCIEChassis {
  50    uint8_t     number;
  51
  52    QLIST_HEAD(, PCIESlot) slots;
  53    QLIST_ENTRY(PCIEChassis) next;
  54};
  55
  56static QLIST_HEAD(, PCIEChassis) chassis = QLIST_HEAD_INITIALIZER(chassis);
  57
  58static struct PCIEChassis *pcie_chassis_find(uint8_t chassis_number)
  59{
  60    struct PCIEChassis *c;
  61    QLIST_FOREACH(c, &chassis, next) {
  62        if (c->number == chassis_number) {
  63            break;
  64        }
  65    }
  66    return c;
  67}
  68
  69void pcie_chassis_create(uint8_t chassis_number)
  70{
  71    struct PCIEChassis *c;
  72    c = pcie_chassis_find(chassis_number);
  73    if (c) {
  74        return;
  75    }
  76    c = g_malloc0(sizeof(*c));
  77    c->number = chassis_number;
  78    QLIST_INIT(&c->slots);
  79    QLIST_INSERT_HEAD(&chassis, c, next);
  80}
  81
  82static PCIESlot *pcie_chassis_find_slot_with_chassis(struct PCIEChassis *c,
  83                                                     uint8_t slot)
  84{
  85    PCIESlot *s;
  86    QLIST_FOREACH(s, &c->slots, next) {
  87        if (s->slot == slot) {
  88            break;
  89        }
  90    }
  91    return s;
  92}
  93
  94PCIESlot *pcie_chassis_find_slot(uint8_t chassis_number, uint16_t slot)
  95{
  96    struct PCIEChassis *c;
  97    c = pcie_chassis_find(chassis_number);
  98    if (!c) {
  99        return NULL;
 100    }
 101    return pcie_chassis_find_slot_with_chassis(c, slot);
 102}
 103
 104int pcie_chassis_add_slot(struct PCIESlot *slot)
 105{
 106    struct PCIEChassis *c;
 107    c = pcie_chassis_find(slot->chassis);
 108    if (!c) {
 109        return -ENODEV;
 110    }
 111    if (pcie_chassis_find_slot_with_chassis(c, slot->slot)) {
 112        return -EBUSY;
 113    }
 114    QLIST_INSERT_HEAD(&c->slots, slot, next);
 115    return 0;
 116}
 117
 118void pcie_chassis_del_slot(PCIESlot *s)
 119{
 120    QLIST_REMOVE(s, next);
 121}
 122
 123static Property pcie_port_props[] = {
 124    DEFINE_PROP_UINT8("port", PCIEPort, port, 0),
 125    DEFINE_PROP_UINT16("aer_log_max", PCIEPort,
 126                       parent_obj.parent_obj.exp.aer_log.log_max,
 127                       PCIE_AER_LOG_MAX_DEFAULT),
 128    DEFINE_PROP_END_OF_LIST()
 129};
 130
 131static void pcie_port_class_init(ObjectClass *oc, void *data)
 132{
 133    DeviceClass *dc = DEVICE_CLASS(oc);
 134
 135    dc->props = pcie_port_props;
 136}
 137
 138static const TypeInfo pcie_port_type_info = {
 139    .name = TYPE_PCIE_PORT,
 140    .parent = TYPE_PCI_BRIDGE,
 141    .instance_size = sizeof(PCIEPort),
 142    .abstract = true,
 143    .class_init = pcie_port_class_init,
 144};
 145
 146static Property pcie_slot_props[] = {
 147    DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
 148    DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
 149    DEFINE_PROP_END_OF_LIST()
 150};
 151
 152static void pcie_slot_class_init(ObjectClass *oc, void *data)
 153{
 154    DeviceClass *dc = DEVICE_CLASS(oc);
 155    HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
 156
 157    dc->props = pcie_slot_props;
 158    hc->pre_plug = pcie_cap_slot_pre_plug_cb;
 159    hc->plug = pcie_cap_slot_plug_cb;
 160    hc->unplug = pcie_cap_slot_unplug_cb;
 161    hc->unplug_request = pcie_cap_slot_unplug_request_cb;
 162}
 163
 164static const TypeInfo pcie_slot_type_info = {
 165    .name = TYPE_PCIE_SLOT,
 166    .parent = TYPE_PCIE_PORT,
 167    .instance_size = sizeof(PCIESlot),
 168    .abstract = true,
 169    .class_init = pcie_slot_class_init,
 170    .interfaces = (InterfaceInfo[]) {
 171        { TYPE_HOTPLUG_HANDLER },
 172        { }
 173    }
 174};
 175
 176static void pcie_port_register_types(void)
 177{
 178    type_register_static(&pcie_port_type_info);
 179    type_register_static(&pcie_slot_type_info);
 180}
 181
 182type_init(pcie_port_register_types)
 183