123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- /*
- * Base class for PCI Express Root Ports
- *
- * Copyright (C) 2017 Red Hat Inc
- *
- * Authors:
- * Marcel Apfelbaum <marcel@redhat.com>
- *
- * Most of the code was migrated from hw/pci-bridge/ioh3420.
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- */
- #include "qemu/osdep.h"
- #include "qapi/error.h"
- #include "qemu/module.h"
- #include "hw/pci/pcie_port.h"
- #include "hw/qdev-properties.h"
- static void rp_aer_vector_update(PCIDevice *d)
- {
- PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d);
- if (rpc->aer_vector) {
- pcie_aer_root_set_vector(d, rpc->aer_vector(d));
- }
- }
- static void rp_write_config(PCIDevice *d, uint32_t address,
- uint32_t val, int len)
- {
- uint32_t root_cmd =
- pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND);
- uint16_t slt_ctl, slt_sta;
- pcie_cap_slot_get(d, &slt_ctl, &slt_sta);
- pci_bridge_write_config(d, address, val, len);
- rp_aer_vector_update(d);
- pcie_cap_slot_write_config(d, slt_ctl, slt_sta, address, val, len);
- pcie_aer_write_config(d, address, val, len);
- pcie_aer_root_write_config(d, address, val, len, root_cmd);
- }
- static void rp_reset(DeviceState *qdev)
- {
- PCIDevice *d = PCI_DEVICE(qdev);
- rp_aer_vector_update(d);
- pcie_cap_root_reset(d);
- pcie_cap_deverr_reset(d);
- pcie_cap_slot_reset(d);
- pcie_cap_arifwd_reset(d);
- pcie_acs_reset(d);
- pcie_aer_root_reset(d);
- pci_bridge_reset(qdev);
- pci_bridge_disable_base_limit(d);
- }
- static void rp_realize(PCIDevice *d, Error **errp)
- {
- PCIEPort *p = PCIE_PORT(d);
- PCIESlot *s = PCIE_SLOT(d);
- PCIDeviceClass *dc = PCI_DEVICE_GET_CLASS(d);
- PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d);
- int rc;
- pci_config_set_interrupt_pin(d->config, 1);
- pci_bridge_initfn(d, TYPE_PCIE_BUS);
- pcie_port_init_reg(d);
- rc = pci_bridge_ssvid_init(d, rpc->ssvid_offset, dc->vendor_id,
- rpc->ssid, errp);
- if (rc < 0) {
- error_append_hint(errp, "Can't init SSV ID, error %d\n", rc);
- goto err_bridge;
- }
- if (rpc->interrupts_init) {
- rc = rpc->interrupts_init(d, errp);
- if (rc < 0) {
- goto err_bridge;
- }
- }
- rc = pcie_cap_init(d, rpc->exp_offset, PCI_EXP_TYPE_ROOT_PORT,
- p->port, errp);
- if (rc < 0) {
- error_append_hint(errp, "Can't add Root Port capability, "
- "error %d\n", rc);
- goto err_int;
- }
- pcie_cap_arifwd_init(d);
- pcie_cap_deverr_init(d);
- pcie_cap_slot_init(d, s->slot);
- pcie_cap_root_init(d);
- pcie_chassis_create(s->chassis);
- rc = pcie_chassis_add_slot(s);
- if (rc < 0) {
- error_setg(errp, "Can't add chassis slot, error %d", rc);
- goto err_pcie_cap;
- }
- rc = pcie_aer_init(d, PCI_ERR_VER, rpc->aer_offset,
- PCI_ERR_SIZEOF, errp);
- if (rc < 0) {
- goto err;
- }
- pcie_aer_root_init(d);
- rp_aer_vector_update(d);
- if (rpc->acs_offset && !s->disable_acs) {
- pcie_acs_init(d, rpc->acs_offset);
- }
- return;
- err:
- pcie_chassis_del_slot(s);
- err_pcie_cap:
- pcie_cap_exit(d);
- err_int:
- if (rpc->interrupts_uninit) {
- rpc->interrupts_uninit(d);
- }
- err_bridge:
- pci_bridge_exitfn(d);
- }
- static void rp_exit(PCIDevice *d)
- {
- PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d);
- PCIESlot *s = PCIE_SLOT(d);
- pcie_aer_exit(d);
- pcie_chassis_del_slot(s);
- pcie_cap_exit(d);
- if (rpc->interrupts_uninit) {
- rpc->interrupts_uninit(d);
- }
- pci_bridge_exitfn(d);
- }
- static Property rp_props[] = {
- DEFINE_PROP_BIT(COMPAT_PROP_PCP, PCIDevice, cap_present,
- QEMU_PCIE_SLTCAP_PCP_BITNR, true),
- DEFINE_PROP_BOOL("disable-acs", PCIESlot, disable_acs, false),
- DEFINE_PROP_END_OF_LIST()
- };
- static void rp_instance_post_init(Object *obj)
- {
- PCIESlot *s = PCIE_SLOT(obj);
- if (!s->speed) {
- s->speed = QEMU_PCI_EXP_LNK_2_5GT;
- }
- if (!s->width) {
- s->width = QEMU_PCI_EXP_LNK_X1;
- }
- }
- static void rp_class_init(ObjectClass *klass, void *data)
- {
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- k->is_bridge = true;
- k->config_write = rp_write_config;
- k->realize = rp_realize;
- k->exit = rp_exit;
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
- dc->reset = rp_reset;
- dc->props = rp_props;
- }
- static const TypeInfo rp_info = {
- .name = TYPE_PCIE_ROOT_PORT,
- .parent = TYPE_PCIE_SLOT,
- .instance_post_init = rp_instance_post_init,
- .class_init = rp_class_init,
- .abstract = true,
- .class_size = sizeof(PCIERootPortClass),
- .interfaces = (InterfaceInfo[]) {
- { INTERFACE_PCIE_DEVICE },
- { }
- },
- };
- static void rp_register_types(void)
- {
- type_register_static(&rp_info);
- }
- type_init(rp_register_types)
|