@@ -8,4 +8,4 @@ common-obj-$(CONFIG_I82801B11) += i82801b11.o
common-obj-$(CONFIG_DEC_PCI) += dec.o
# Sun4u
common-obj-$(CONFIG_SIMBA) += simba.o
-common-obj-$(CONFIG_CCIX_SWITCH) += ccix_upstream.o
+common-obj-$(CONFIG_CCIX_SWITCH) += ccix_upstream.o ccix_downstream.o
new file mode 100644
@@ -0,0 +1,222 @@
+/*
+ * ccix_downstream.c
+ * A PCIe downstream switch port with CCIX support.
+ *
+ * Copyright (c) 2019 Jonathan Cameron <Jonathan.Cameron@huawei.com>
+ * Huawei
+ * Based on: xio3130_downstream.c
+ * Copyright (c) 2010 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/pci/pci_ids.h"
+#include "hw/pci/msi.h"
+#include "hw/pci/pcie.h"
+#include "hw/pci/pcie_port.h"
+#include "qapi/error.h"
+#include "hw/misc/ccix.h"
+#include "qemu/module.h"
+
+/*
+ * No public spec is available for a CCIX downstream port so for
+ * now use the values from teh xio3130 pcie downstream port
+ */
+#define XIO3130_MSI_OFFSET 0x70
+#define XIO3130_MSI_SUPPORTED_FLAGS PCI_MSI_FLAGS_64BIT
+#define XIO3130_MSI_NR_VECTOR 1
+#define XIO3130_SSVID_OFFSET 0x80
+#define XIO3130_SSVID_SVID 0
+#define XIO3130_SSVID_SSID 0
+#define XIO3130_EXP_OFFSET 0x90
+#define XIO3130_AER_OFFSET 0x100
+
+#define TYPE_CCIX_DOWN_PORT "ccix-downstream-port"
+
+#define CCIX_DOWN_DEV(obj) OBJECT_CHECK(CCIXDownPortState, (obj), TYPE_CCIX_DOWN_PORT)
+
+typedef struct CCIXDownPortState {
+ PCIESlot parent_obj;
+ struct CCIXState s;
+} CCIXDownPortState;
+
+static void ccix_downstream_write_config(PCIDevice *d, uint32_t address,
+ uint32_t val, int len)
+{
+ CCIXDownPortState *s = CCIX_DOWN_DEV(d);
+
+ pci_bridge_write_config(d, address, val, len);
+ pcie_cap_flr_write_config(d, address, val, len);
+ pcie_cap_slot_write_config(d, address, val, len);
+ pcie_aer_write_config(d, address, val, len);
+ ccix_write_config(d, &s->s, address, val, len);
+}
+
+static void ccix_downstream_reset(DeviceState *qdev)
+{
+ PCIDevice *d = PCI_DEVICE(qdev);
+
+ pcie_cap_deverr_reset(d);
+ pcie_cap_slot_reset(d);
+ pcie_cap_arifwd_reset(d);
+ pci_bridge_reset(qdev);
+}
+
+static void ccix_downstream_realize(PCIDevice *d, Error **errp)
+{
+ PCIEPort *p = PCIE_PORT(d);
+ PCIESlot *s = PCIE_SLOT(d);
+ CCIXDownPortState *cs = CCIX_DOWN_DEV(d);
+ /* Allow space for existing extended capabilities from xio3130 */
+ uint32_t offset = 0x180;
+ int rc;
+
+ pci_bridge_initfn(d, TYPE_PCIE_BUS);
+ pcie_port_init_reg(d);
+
+ rc = msi_init(d, XIO3130_MSI_OFFSET, XIO3130_MSI_NR_VECTOR,
+ XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
+ XIO3130_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT,
+ errp);
+ if (rc < 0) {
+ assert(rc == -ENOTSUP);
+ goto err_bridge;
+ }
+
+ rc = pci_bridge_ssvid_init(d, XIO3130_SSVID_OFFSET,
+ XIO3130_SSVID_SVID, XIO3130_SSVID_SSID,
+ errp);
+ if (rc < 0) {
+ goto err_bridge;
+ }
+
+ rc = pcie_cap_init(d, XIO3130_EXP_OFFSET, PCI_EXP_TYPE_DOWNSTREAM,
+ p->port, errp);
+ if (rc < 0) {
+ goto err_msi;
+ }
+ pcie_cap_flr_init(d);
+ pcie_cap_deverr_init(d);
+ pcie_cap_slot_init(d, s->slot);
+ pcie_cap_arifwd_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, XIO3130_AER_OFFSET,
+ PCI_ERR_SIZEOF, errp);
+ if (rc < 0) {
+ goto err;
+ }
+ initialize_ccixstate(&cs->s, d);
+ ccix_set_port(&cs->s);
+ offset = ccix_add_prldvsec(d, &cs->s, offset);
+ ccix_add_tdldvsec(d, offset);
+ ccix_register(&cs->s);
+
+ return;
+
+err:
+ pcie_chassis_del_slot(s);
+err_pcie_cap:
+ pcie_cap_exit(d);
+err_msi:
+ msi_uninit(d);
+err_bridge:
+ pci_bridge_exitfn(d);
+}
+
+static void ccix_downstream_exitfn(PCIDevice *d)
+{
+ PCIESlot *s = PCIE_SLOT(d);
+
+ pcie_aer_exit(d);
+ pcie_chassis_del_slot(s);
+ pcie_cap_exit(d);
+ msi_uninit(d);
+ pci_bridge_exitfn(d);
+}
+
+static Property ccix_props[] = {
+ DEFINE_PROP_STRING("ccix_device", CCIXDownPortState, s.ccix_dev_name),
+ DEFINE_PROP_BIT("primaryport", CCIXDownPortState, s.flags, PRIMARY_PORT_BIT, false),
+ DEFINE_PROP_UINT8("port_id", CCIXDownPortState, s.port_id, 0),
+ DEFINE_PROP_UINT8("num_links", CCIXDownPortState, s.num_links, 1),
+ DEFINE_PROP_UINT8("psam_entries", CCIXDownPortState, s.psam_entries, 0),
+ DEFINE_PROP_UINT8("request_agents", CCIXDownPortState, s.num_ras, 0),
+ DEFINE_PROP_UINT8("home_agents", CCIXDownPortState, s.num_has, 0),
+ DEFINE_PROP_UINT8("hsam_entries", CCIXDownPortState, s.hsam_entries, 0),
+ DEFINE_PROP_UINT8("rsam_entries", CCIXDownPortState, s.rsam_entries, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription vmstate_ccix_downstream = {
+ .name = "ccix-downstream-port",
+ .priority = MIG_PRI_PCI_BUS,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .post_load = pcie_cap_slot_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(parent_obj.parent_obj.parent_obj, PCIESlot),
+ VMSTATE_STRUCT(parent_obj.parent_obj.parent_obj.exp.aer_log,
+ PCIESlot, 0, vmstate_pcie_aer_log, PCIEAERLog),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+
+static void ccix_downstream_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->is_bridge = true;
+ k->config_write = ccix_downstream_write_config;
+ k->realize = ccix_downstream_realize;
+ k->exit = ccix_downstream_exitfn;
+ /* Temp values for the RFC */
+ k->vendor_id = PCI_VENDOR_ID_HUAWEI;
+ k->device_id = PCI_DEVICE_ID_HUAWEI_CCIX_DOWN;;
+ k->revision = 1;
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+ dc->desc = "CCIX / PCIE switch downstream port";
+ dc->reset = ccix_downstream_reset;
+ dc->vmsd = &vmstate_ccix_downstream;
+ dc->props = ccix_props;
+}
+
+static const TypeInfo ccix_downstream_info = {
+ .name = TYPE_CCIX_DOWN_PORT,
+ .parent = TYPE_PCIE_SLOT,
+ .class_init = ccix_downstream_class_init,
+ .instance_size = sizeof(CCIXDownPortState),
+ .interfaces = (InterfaceInfo[]) {
+ { INTERFACE_PCIE_DEVICE },
+ { }
+ },
+};
+
+static void ccix_downstream_register_types(void)
+{
+ type_register_static(&ccix_downstream_info);
+}
+
+type_init(ccix_downstream_register_types)
+
Note that this is simply emulation of the configuration space. Has the same issue with cut and paste code as the upstream port driver. Solution likely to be the same. Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> --- hw/pci-bridge/Makefile.objs | 2 +- hw/pci-bridge/ccix_downstream.c | 222 ++++++++++++++++++++++++++++++++ 2 files changed, 223 insertions(+), 1 deletion(-)