QEMU-Devel Archive on lore.kernel.org
 help / color / Atom feed
* [Qemu-devel] [RFC PATCH 0/7] qemu: CCIX pcie config space emulation
@ 2019-06-25 11:27 Jonathan Cameron
  2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 1/7] Temp: Add the PCI_EXT_ID_DVSEC definition to the qemu pci_regs.h copy Jonathan Cameron
                   ` (8 more replies)
  0 siblings, 9 replies; 11+ messages in thread
From: Jonathan Cameron @ 2019-06-25 11:27 UTC (permalink / raw)
  To: QEMU Developers
  Cc: Peter Maydell, jcm, linuxarm, Auger Eric, qemu-arm, Jonathan Cameron

CCIX topologies are 'layered' on top of PCIe tree topologies.
This is done primarily by allowing a single CCIX device to appear as
multiple disjoint nodes in the PCIe tree.

This layering is described via extensive PCIe DVSEC extended
capabilities in PCIe config space across all the functions that
are present in the device (some placement rules apply).

The extremely flexible nature of allowed topologies makes the
development of generic firmware and OS software difficult if we rely
on actual hardware setups, due to the large test set that is necessary.

To enable the ongoing work on EDK2 and within the Linux kernel and
userspace, this series provides the bare bones of what is necessary
to be able to test 'configuration' of a CCIX topology.  Note
that no actual CCIX data flow is being emulated within this patchset,
merely a substantial subset of the interface that allows the topologies
to be configured.  Testing has to rely on verification based on
the result rather than true emulation of the coherency protocol.
(that is a very different form of emulation for which other tools
are perhaps better suited).

For information on how to do the coherency protocol configuration,
see the forthcoming CCIX SW guide, in conjunction with the CCIX 1.0
Base Specification.

An example of a 2x2 mesh with a spur to the host can be run with:

qemu-system-aarch64 -M virt -m 1024 -cpu cortex-a53 \
...
 -device ioh3420,id=root_port1 \
 -device ccix-upstream-port,num_links=4,primaryport=true,rsam_entries=4,ccix_device="ccix_dev1",bus=root_port1,addr=0.0,multifunction="on",id=up0,port_id=0 \
 -device ccix-downstream-port,ccix_device="ccix_dev1",bus=up0,slot=0,chassis=2,id=bus_top,port_id=1 \
 -device ccix-downstream-port,ccix_device="ccix_dev1",bus=up0,slot=1,chassis=2,id=bus_left,port_id=2 \
 -device ccix-ep,primaryport=false,home_agents=1,request_agents=1,ccix_device="ccix_dev1",bus=root_port1,addr=0.1,multifunction="on" \
 -device ccix-upstream-port,num_links=4,primaryport=true,rsam_entries=4,ccix_device="ccix_dev2",bus=bus_top,addr=0.0,multifunction="on",id=up1,port_id=0 \
 -device ccix-downstream-port,ccix_device="ccix_dev2",bus=up1,slot=0,chassis=3,id=bus_right,port_id=1 \
 -device ccix-ep,primaryport=false,request_agents=2,ccix_device="ccix_dev2",bus=bus_top,addr=0.1,multifunction="on" \
 -device ccix-upstream-port,num_links=4,primaryport=true,rsam_entries=4,ccix_device="ccix_dev3",bus=bus_left,addr=0.0,multifunction="on",id=up2,port_id=0 \
 -device ccix-downstream-port,ccix_device="ccix_dev3",bus=up2,slot=0,chassis=4,id=bus_bottom,port_id=1,multifunciton="on" \
 -device ccix-ep,primaryport=false,request_agents=2,ccix_device="ccix_dev3",bus=bus_left,addr=0.1,multifunction="on" \
 -device ccix-ep,primaryport=true,request_agents=2,ccix_device="ccix_dev4",bus=bus_right,addr=0.0,port_id=0 \
 -device ccix-ep,primaryport=true,request_agents=2,ccix_device="ccix_dev4",bus=bus_bottom,addr=0.0,port_id=1


I'm not going to try drawing all the detail (it's bad enough
trying to draw these in inkscape, but in a very much simplifed
fashion, this generates.

-----------------
|     Host      |
|               | 
--- root_port1--
        |
        |
        v
-----------------          ---------------
|  ccix_dev1    | -------> |  ccix_dev2  |
-----------------          ---------------
        |                         |
        V                         V
-----------------          ---------------
|  ccix_dev3    | -------> |  ccix_dev4  |
-----------------          ---------------

$lspci -t
-[0000:00]-+-00.0
           +-01.0-[01-08]--+-00.0-[02-08]--+-00.0-[03-05]--+-00.0-[04-05]----00.0-[05]----00.0
                           |               |               |               \-00.1
                           |               |               \-01.0-[06-08]--+-00.0-[07-08]----00.0-[08]----00.0
                           |               |                               \-00.1
                           |               \-00.1
						       
RFC questions:

1.  The nature of CCIX devices is that we need to extend normal
    PCI devices, slots, and ports.  I could not find an elegant way of
    doing this without lots of code replication.  The current solution
    just exposes some internal functions from xio3130 port implementations.
    Is there a better way to do this?

2.  The association of the different PCIDevices to a given CCIX device is
    currently somewhat of a hack. Can anyone suggest a cleaner solution
    for this?  I can improved the current implementation, but don't really
    like that we basically search for all the parts whenever a cross
    device implementation is needed.

3.  Is emulation via a large number of PCIe devices like this a good
    approach or is there a nicer way to handle it?  Given we need to
    be able to 'spread' the CCIX device configuration across multiple
    PCIe functions anyway perhaps this is the most sensible approach.

4.  I've cut and paste a 100+ lines of code from each of the xio3130_*
    modules as we are also implemening PCIE up and downstream ports
    and as this is a emulation only device, we might as well use the
    same register set.  There are various possible ways to avoid this:
    * Add a library with the shared code in it.
    * Add an xio3130_upstream.h header and similar to allow the CCIX
      port modules to call those functions directly.
    * Don't worry about the replication in the interests of keeping
      the code structure simple.

5.  I'm not that familiar with qemu 'style' yet, so pointers on structures
    to use etc most welcome.

Note that not all elements of CCIX are supported by the current implementation,
for example slave agents and error records are missing.  These will follow
either in later revisions or as follow patches.  We also have no actual
accelerator functions in the current design and hence no mapping to RAs.

Only a subset of configuration constraints are currently implemented.
This will want tightenning up in future.

As we don't have any actual chunks of the spec in here so I haven't
added the statement from the trademark grant that follows.

Thanks,

Jonathan

This patch is being distributed by the CCIX Consortium, Inc. (CCIX) to
you and other parties that are paticipating (the "participants") in
qemu with the understanding that the participants will use CCIX's
name and trademark only when this patch is used in association with
qemu.

CCIX is also distributing this patch to these participants with the
understanding that if any portion of the CCIX specification will be
used or referenced in qemu, the participants will not modify the cited
portion of the CCIX specification and will give CCIX propery copyright
attribution by including the following copyright notice with
the cited part of the CCIX specification:
"© 2019 CCIX CONSORTIUM, INC. ALL RIGHTS RESERVED."

Jonathan Cameron (7):
  Temp: Add the PCI_EXT_ID_DVSEC definition to the qemu pci_regs.h copy.
  pci: Add Huawei vendor ID and Huawei Emulated CCIX Device IDs.
  pci: CCIX config space emulation library.
  pci-bridge: CCIX capable PCIE/CCIX switch upstream port.
  pci-bridge: CCIX capable PCIE/CCIX switch downstream port
  misc: CCIX endpoint function
  Temp: Add to ARM64 makefiles for testing

 default-configs/arm-softmmu.mak           |    3 +-
 hw/misc/Kconfig                           |    5 +
 hw/misc/Makefile.objs                     |    1 +
 hw/misc/ccix-ep.c                         |  112 ++
 hw/pci-bridge/Kconfig                     |    5 +
 hw/pci-bridge/Makefile.objs               |    1 +
 hw/pci-bridge/ccix_downstream.c           |  222 ++++
 hw/pci-bridge/ccix_upstream.c             |  197 ++++
 hw/pci/Kconfig                            |    3 +
 hw/pci/Makefile.objs                      |    1 +
 hw/pci/ccix_lib.c                         | 1299 +++++++++++++++++++++
 include/hw/misc/ccix.h                    |   28 +
 include/hw/pci/pci_ids.h                  |    7 +
 include/standard-headers/linux/pci_regs.h |    3 +-
 14 files changed, 1885 insertions(+), 2 deletions(-)
 create mode 100644 hw/misc/ccix-ep.c
 create mode 100644 hw/pci-bridge/ccix_downstream.c
 create mode 100644 hw/pci-bridge/ccix_upstream.c
 create mode 100644 hw/pci/ccix_lib.c
 create mode 100644 include/hw/misc/ccix.h

-- 
2.20.1



^ permalink raw reply	[flat|nested] 11+ messages in thread

* [Qemu-devel] [RFC PATCH 1/7] Temp: Add the PCI_EXT_ID_DVSEC definition to the qemu pci_regs.h copy.
  2019-06-25 11:27 [Qemu-devel] [RFC PATCH 0/7] qemu: CCIX pcie config space emulation Jonathan Cameron
@ 2019-06-25 11:27 ` Jonathan Cameron
  2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 2/7] pci: Add Huawei vendor ID and Huawei Emulated CCIX Device IDs Jonathan Cameron
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Jonathan Cameron @ 2019-06-25 11:27 UTC (permalink / raw)
  To: QEMU Developers
  Cc: Peter Maydell, jcm, linuxarm, Auger Eric, qemu-arm, Jonathan Cameron

This hasn't yet been added to the linux kernel tree, so for purposes
of this RFC just add it locally.

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 include/standard-headers/linux/pci_regs.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/standard-headers/linux/pci_regs.h b/include/standard-headers/linux/pci_regs.h
index 27164769d1..224b52e62b 100644
--- a/include/standard-headers/linux/pci_regs.h
+++ b/include/standard-headers/linux/pci_regs.h
@@ -709,7 +709,8 @@
 #define PCI_EXT_CAP_ID_DPC	0x1D	/* Downstream Port Containment */
 #define PCI_EXT_CAP_ID_L1SS	0x1E	/* L1 PM Substates */
 #define PCI_EXT_CAP_ID_PTM	0x1F	/* Precision Time Measurement */
-#define PCI_EXT_CAP_ID_MAX	PCI_EXT_CAP_ID_PTM
+#define PCI_EXT_CAP_ID_DVSEC	0x23    /* Designated Vendor-Specific */
+#define PCI_EXT_CAP_ID_MAX	PCI_EXT_CAP_ID_DVSEC
 
 #define PCI_EXT_CAP_DSN_SIZEOF	12
 #define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40
-- 
2.20.1



^ permalink raw reply	[flat|nested] 11+ messages in thread

* [Qemu-devel] [RFC PATCH 2/7] pci: Add Huawei vendor ID and Huawei Emulated CCIX Device IDs.
  2019-06-25 11:27 [Qemu-devel] [RFC PATCH 0/7] qemu: CCIX pcie config space emulation Jonathan Cameron
  2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 1/7] Temp: Add the PCI_EXT_ID_DVSEC definition to the qemu pci_regs.h copy Jonathan Cameron
@ 2019-06-25 11:27 ` Jonathan Cameron
  2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 3/7] pci: CCIX config space emulation library Jonathan Cameron
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Jonathan Cameron @ 2019-06-25 11:27 UTC (permalink / raw)
  To: QEMU Developers
  Cc: Peter Maydell, jcm, linuxarm, Auger Eric, qemu-arm, Jonathan Cameron

These device IDs have been allocated for emulated only devices,
giving us more flexibility than would be possible by emulating
real devices.

They will be used for the CCIX PCIe configuration space emulation
modules that follow.

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 include/hw/pci/pci_ids.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h
index 0abe27a53a..f49be07328 100644
--- a/include/hw/pci/pci_ids.h
+++ b/include/hw/pci/pci_ids.h
@@ -220,6 +220,11 @@
 #define PCI_VENDOR_ID_FREESCALE          0x1957
 #define PCI_DEVICE_ID_MPC8533E           0x0030
 
+#define PCI_VENDOR_ID_HUAWEI             0x19E5
+#define PCI_DEVICE_ID_HUAWEI_CCIX_UP     0xA260
+#define PCI_DEVICE_ID_HUAWEI_CCIX_DOWN   0xA261
+#define PCI_DEVICE_ID_HUAWEI_CCIX_EP     0xA262
+
 #define PCI_VENDOR_ID_INTEL              0x8086
 #define PCI_DEVICE_ID_INTEL_82378        0x0484
 #define PCI_DEVICE_ID_INTEL_82441        0x1237
-- 
2.20.1



^ permalink raw reply	[flat|nested] 11+ messages in thread

* [Qemu-devel] [RFC PATCH 3/7] pci: CCIX config space emulation library.
  2019-06-25 11:27 [Qemu-devel] [RFC PATCH 0/7] qemu: CCIX pcie config space emulation Jonathan Cameron
  2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 1/7] Temp: Add the PCI_EXT_ID_DVSEC definition to the qemu pci_regs.h copy Jonathan Cameron
  2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 2/7] pci: Add Huawei vendor ID and Huawei Emulated CCIX Device IDs Jonathan Cameron
@ 2019-06-25 11:27 ` Jonathan Cameron
  2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 4/7] pci-bridge: CCIX capable PCIE/CCIX switch upstream port Jonathan Cameron
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Jonathan Cameron @ 2019-06-25 11:27 UTC (permalink / raw)
  To: QEMU Developers
  Cc: Peter Maydell, jcm, linuxarm, Auger Eric, qemu-arm, Jonathan Cameron

The nature of the complex topologies supported by CCIX means
that it will be sometime before it is possible to construct many
of the interesting cases in hardware, and it will be extermely
hard to exercise all of the combinations whilst developing firwmare
and drivers.

To that end, the intent of this library and following device
emulations is to allow the construction of complex CCIX toplogies
via their overlaying on PCIe.  The CCIX topologies are configured
through CCIX specific PCIe DVSEC capabillity and control structures.

A typical mesh capable CCIX device will overlay onto N upstream
PCIe switch ports, M downstream PCIe switch ports, function 0
EPs which are not PCIe switch upstream ports, P functions 1+
which have additional CCIX protocol elements described and Q
functions 1+ which respresent acceleration functions, with no
CCIX protocol elements (these look to be normal PCIe functions
so are not covered by this patch set).

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 hw/pci/Kconfig           |    3 +
 hw/pci/Makefile.objs     |    1 +
 hw/pci/ccix_lib.c        | 1299 ++++++++++++++++++++++++++++++++++++++
 include/hw/misc/ccix.h   |   28 +
 include/hw/pci/pci_ids.h |    2 +
 5 files changed, 1333 insertions(+)

diff --git a/hw/pci/Kconfig b/hw/pci/Kconfig
index 77f8b005ff..605f8dcd18 100644
--- a/hw/pci/Kconfig
+++ b/hw/pci/Kconfig
@@ -13,3 +13,6 @@ config MSI_NONBROKEN
     # or support it and have a good implementation. See commit
     # 47d2b0f33c664533b8dbd5cb17faa8e6a01afe1f.
     bool
+
+config CCIX_LIB
+    bool
diff --git a/hw/pci/Makefile.objs b/hw/pci/Makefile.objs
index 8642fab622..efc17ff4dd 100644
--- a/hw/pci/Makefile.objs
+++ b/hw/pci/Makefile.objs
@@ -13,3 +13,4 @@ common-obj-$(CONFIG_PCI) += ccix_per.o
 
 common-obj-$(call lnot,$(CONFIG_PCI)) += pci-stub.o
 common-obj-$(CONFIG_ALL) += pci-stub.o
+common-obj-$(CONFIG_CCIX_LIB) += ccix_lib.o
diff --git a/hw/pci/ccix_lib.c b/hw/pci/ccix_lib.c
new file mode 100644
index 0000000000..544f90077d
--- /dev/null
+++ b/hw/pci/ccix_lib.c
@@ -0,0 +1,1299 @@
+/*
+ * CCIX configuration space creation library
+ *
+ * Copyright (c) 2019 Huawei
+ * Author: Jonathan Cameron <Jonathan.Cameron@Huawei.com>
+ *
+ * Portions copied from pci-testdev.c
+ * Copyright (c) 2012 Red Hat Inc.
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * 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/hw.h"
+#include "hw/pci/pci.h"
+#include "qemu/event_notifier.h"
+#include "sysemu/kvm.h"
+#include "hw/misc/ccix.h"
+
+/* Leave space for the SR-IDM and SW portal if enabled */
+#define CCIX_COMMON_CAP_MAX_SIZE                        10 * sizeof(uint32_t)
+
+#define CM_CAP_DW1_MULTIPORT_CAP_OFF                    0
+#define CM_CAP_DW1_MULTIPORT_CAP_M                      0x00000007
+#define CM_CAP_DW1_VERSION_CAP_OFF                      22
+#define CM_CAP_DW1_VERSION_CAP_M                        0x00C00000
+#define CM_CAP_DW1_DEVID_OFF                            24
+#define CM_CAP_DW1_DEVID_M                              0xFF000000
+
+#define CM_CAP_DW2_DISC_READY_CAP_OFF                   0
+#define CM_CAP_DW2_PART_CS_CAP_OFF                      1
+#define CM_CAP_DW2_PORT_AG_CAP_OFF                      2
+#define CM_CAP_DW2_CL_SIZE_CAP_OFF                      3
+#define CM_CAP_DW2_ADDR_W_CAP_OFF                       4
+#define CM_CAP_DW2_MH_CAP_OFF                           7
+#define CM_CAP_DW2_SW_PORT_CAP_OFF                      8
+#define CM_CAP_DW2_SAM_ALIGN_CAP_OFF                    9
+#define CM_CAP_DW2_READY_TIME_VAL_OFF                   19
+#define CM_CAP_DW2_READY_TIME_SCALE_OFF                 28
+
+/* COMMON_CAP III is reserved */
+#define CM_CAP_DW4_DEV_ERR_LOG_OFFSET_OFF               20
+#define CM_CAP_DW5_IDM_OFFSET_OFF                       20
+#define CM_CAP_DW6_RSAM_SIZE_OFF                        0
+#define CM_CAP_DW6_RSAM_OFFSET_OFF                      20
+#define CM_CAP_DW7_HSAM_SIZE_OFF                        0
+#define CM_CAP_DW7_HSAM_OFFSET_OFF                      20
+#define CM_CAP_DW8_SR_OFFSET_OFF                        20
+#define CM_CAP_DW9_SW_PORTAL_OFF                        0
+
+#define CM_CTL_DW1_DEVICE_EN_OFF                        0
+#define CM_CTL_DW1_PRIMARY_PORT_EN_OFF                  1
+#define CM_CTL_DW1_MESH_EN_OFF                          2
+#define CM_CTL_DW1_PORT_AG_EN_OFF                       4
+#define CM_CTL_DW1_IDM_TABLE_VALID_OFF                  5
+#define CM_CTL_DW1_RSAM_TABLE_VALID_OFF                 6
+#define CM_CTL_DW1_HSAM_TABLE_VALID_OFF                 7
+#define CM_CTL_DW1_SW_PORT_ENABLE_OFF                   8
+#define CM_CTL_DW1_ERR_AGENT_ID_OFF                     16
+#define CM_CTL_DW1_ERR_AGENT_ID_M                       0x003F0000
+#define CM_CTL_DW1_DEVID_OFF                            24
+#define CM_CTL_DW1_DEVID_M                              0xFF000000
+
+#define CM_CTL_DW2_PART_CS_EN_OFF                       1
+#define CM_CTL_DW2_CL_SIZE_EN_OFF                       3
+#define CM_CTL_DW2_ADDR_W_EN_OFF                        4
+#define CM_CTL_DW2_ADDR_W_EN_M                          0x00000070
+
+#define CCIX_PORT_CAP_SIZE                              5 * sizeof(uint32_t)
+
+#define PT_CAP_DW1_DISC_READY_OFF                       0
+#define PT_CAP_DW1_OPT_HEADER_OFF                       1
+#define PT_CAP_DW1_P2P_FORWARDING_OFF                   5
+#define PT_CAP_DW1_LINKS_OFF                            7
+#define PT_CAP_DW1_LINKS_M                              0x00001F80
+#define PT_CAP_DW1_PSAM_ENTRIES_OFF                     13
+#define PT_CAP_DW1_PSAM_ENTRIES_M                       0x0007E000
+#define PT_CAP_DW1_PORTID_OFF                           27
+#define PT_CAP_DW1_PORTID_M                             0xF8000000
+
+/* not including PSAM */
+#define CCIX_PORT_CTL_SIZE                              5 * sizeof(uint32_t)
+
+#define PT_CTL_DW1_PORT_EN_OFF                          0
+#define PT_CTL_DW1_OPT_HEADER_EN_OFF                    1
+#define PT_CTL_DW1_LINKS_EN_OFF                         7
+#define PT_CTL_DW1_LINKS_EN_M                           0x00001F80
+#define PT_CTL_DW1_PSAM_ENTRIES_EN_OFF                  13
+#define PT_CTL_DW1_PSAM_ENTRIES_EN_M                    0x0007E000
+
+#define CCIX_LINK_CAP_SIZE                              6 * sizeof(uint32_t)
+
+#define LK_CAP_DW1_DISC_READY_OFF                       0
+#define LK_CAP_DW1_CREDIT_TYPE_OFF                      1
+#define LK_CAP_DW1_MESSAGE_PACKING_OFF                  2
+#define LK_CAP_DW1_NOCOMPACK_OFF                        6
+#define LK_CAP_DW1_MAX_PKT_SIZE_OFF                     7
+#define LK_CAP_DW1_MAX_PKT_SIZE_M                       0x00000038
+#define LK_CAP_DW2_MAX_MEM_REQ_SEND_OFF                 0
+#define LK_CAP_DW2_MAX_MEM_REQ_SEND_M                   0x000003FF
+#define LK_CAP_DW2_MAX_SNP_REQ_SEND_OFF                 10
+#define LK_CAP_DW2_MAX_SNP_REQ_SEND_M                   0x000FFC00
+#define LK_CAP_DW2_MAX_DAT_REQ_SEND_OFF                 20
+#define LK_CAP_DW2_MAX_DAT_REQ_SEND_M                   0x3FF00000
+#define LK_CAP_DW3_MAX_MEM_REQ_RECV_OFF                 0
+#define LK_CAP_DW3_MAX_MEM_REQ_RECV_M                   0x000003FF
+#define LK_CAP_DW3_MAX_SNP_REQ_RECV_OFF                 10
+#define LK_CAP_DW3_MAX_SNP_REQ_RECV_M                   0x000FFC00
+#define LK_CAP_DW3_MAX_DAT_REQ_RECV_OFF                 20
+#define LK_CAP_DW3_MAX_DAT_REQ_RECV_M                   0x3FF00000
+#define LK_CAP_DW4_MAX_MISC_REQ_SEND_CAP_OFF            0
+#define LK_CAP_DW4_MAX_MISC_REQ_RECV_CAP_OFF            10
+
+/* Not including per link */
+#define CCIX_LINK_CTL_SIZE                              1 * sizeof(uint32_t)
+/* Not including BcastFwdCntlVctr, including Tranport ID map */
+#define CCIX_LINK_CTL_PER_LINK_SIZE                    (6 + 1) * sizeof(uint32_t)
+
+/* Per link controls */
+#define LK_CTL_DW1_LINK_EN_OFF                          0
+#define LK_CTL_DW1_CREDIT_EN_OFF                        1
+#define LK_CTL_DW1_MESSAGE_PACKING_EN_OFF               2
+#define LK_CTL_DW1_NO_COMP_ACK_EN_OFF                   6
+#define LK_CTL_DW1_MAX_PKT_SIZE_EN_OFF                  7
+#define LK_CTL_DW1_MAX_PKT_SIZE_EN_M                    0x00000380
+#define LK_CTL_DW1_LINK_ENT_ADDR_TYPE_OFF               10
+
+#define CCIX_RA_CAP_SIZE                                3 * sizeof(uint32_t)
+
+#define RA_CAP_DW1_RA_DISC_RDY_STAT_OFF                 0
+#define RA_CAP_DW1_RA_CACHE_FLUSH_TIME_VALUE_OFF        19
+#define RA_CAP_DW1_RA_CACHE_FLUSH_TIME_VALUE_M          0x0FF80000
+#define RA_CAP_DW1_RA_CACHE_FLUSH_TIME_SCALE_OFF        28
+#define RA_CAP_DW1_RA_CACHE_FLUSH_TIME_SCALE_M          0x70000000
+#define RA_CAP_DW1_RA_CACHE_FLUSH_STA_OFF               31
+
+#define RA_CAP_DW2_RA_ERROR_LOG_OFFSET_OFF              20
+
+#define CCIX_RA_CTL_SIZE                                4 * sizeof(uint32_t)
+
+#define RA_CTL_DW1_EN_OFF                               0
+#define RA_CTL_DW1_SNOOP_RESP_EN_OFF                    1
+#define RA_CTL_DW1_CACHE_FLUSH_EN_OFF                   14
+#define RA_CTL_DW1_CACHE_EN_OFF                         15
+#define RA_CTL_DW1_RAID_OFF                             26
+#define RA_CTL_DW1_RAID_M                               0xFC000000
+
+/* Excluding pool entries */
+#define CCIX_HA_CAP_SIZE                                3 * sizeof(uint32_t)
+
+#define HA_CAP_DW1_HA_DISC_RD_STAT_OFF                  0
+#define HA_CAP_DW1_NUM_HA_IDS_OFF                       1
+#define HA_CAP_DW1_HA_MEM_POOL_CAP_OFF                  8
+#define HA_CAP_DW1_HA_QACK_OFF                          14
+#define HA_CAP_DW1_HA_HW_QACK_CAP_OFF                   15
+#define HA_CAP_DW1_HA_MEM_EXP_CAP_OFF                   16
+#define HA_CAP_DW1_HA_EVICT_HINT_CAP_OFF                17
+#define HA_CAP_DW1_HA_WRITE_EVICT_FULL_HIT_CAP_OFF      18
+#define HA_CAP_DW1_MEM_POOL_READY_TIME_VALUE_OFF        19
+#define HA_CAP_DW1_MEM_POOL_READY_TIME_VALUE_M          0x0FF80000
+#define HA_CAP_DW1_MEM_POOL_READY_TIME_SCALE_OFF        28
+#define HA_CAP_DW1_MEM_POOL_READY_TIME_SCALE_M          0x70000000
+#define HA_CAP_DW1_MEM_POOL_READY_STA_OFF               31
+
+#define HA_CAP_DW2_HA_ERROR_LOG_OFF                     20
+
+#define MEM_POOL_CAP_DW1_READY_STA_OFF                  0
+#define MEM_POOL_CAP_DW1_GEN_MEM_TYPE_OFF               1
+enum {
+    mem_type_other = 0,
+    mem_type_expan,
+    mem_type_hole,
+    mem_type_rom,
+    mem_type_volatile,
+    mem_type_non_volatile,
+    mem_type_device,
+};
+
+#define MEM_POOL_CAP_DW1_SPEC_MEM_TYPE_OFF              4
+enum {
+    mem_spec_other = 0,
+    mem_spec_sram,
+    mem_spec_ddr,
+    mem_spec_nvdimm_f,
+    mem_spec_nvdimm_n,
+    mem_spec_hbm,
+    mem_spec_flash,
+};
+#define MEM_POOL_CAP_DW1_ADDR_CAP_OFF                   7
+#define MEM_POOL_CAP_DW1_MEM_ATTR_OFF                   8
+#define MEM_POOL_CAP_DW1_MEM_ATTR_DEV                   0x0
+#define MEM_POOL_CAP_DW1_MEM_ATTR_NONCACHE              0x4
+#define MEM_POOL_CAP_DW1_MEM_ATTR_NORMAL                0x5
+#define MEM_POOL_CAP_DW1_MEM_EXT_ATTR_OFF               11
+#define MEM_POOL_CAP_DW1_MEM_EXT_ATTR_NONE              0x0
+#define MEM_POOL_CAP_DW1_MEM_EXT_ATTR_PRIVATE           0x1
+#define MEM_POOL_CAP_DW1_MEM_POOL_SIZE_L_CAP_OFF        16
+
+#define MEM_POOL_CAP_DW2_MEM_POOL_SIZE_H_CAP_OFF        0
+
+/* Not including HAID or HBAT entries */
+#define CCIX_HA_CTL_SIZE                                6 * sizeof(uint32_t)
+#define CCIX_HAID_ENTRY_SIZE                            1 * sizeof(uint32_t)
+#define CCIX_BAT_ENTRY_SIZE                             2 * sizeof(uint32_t)
+
+#define CCIX_POOL_CAP_SIZE                              2 * sizeof(uint32_t)
+#define CCIX_GUID_SIZE                                  5 * sizeof(uint32_t)
+#define CCIX_SAM_ENTRY_SIZE                             3 * sizeof(uint32_t)
+#define CCIX_GUID_DW0                                   0xC3CB993B
+#define CCIX_GUID_DW1                                   0x02C4436F
+#define CCIX_GUID_DW2                                   0x9B68D271
+#define CCIX_GUID_DW3                                   0xF2E8CA31
+#define CCIX_GUID_DW4_VERSION_OFF                       0
+
+/* HACK - What is the best way to do this in Qemu? */
+CCIXState *CCIXFuncs[256];
+
+typedef void (*am_cb_t)(PCIDevice *d, CCIXState *s, uint16_t offset,
+                        uint16_t cap_start_offset, uint32_t val);
+struct am {
+    uint16_t offset;
+    uint16_t cap_start_offset;
+    am_cb_t am_cb;
+};
+
+static int am_cmp(const void *ap, const void *bp)
+{
+    const uint16_t *a;
+    const uint16_t *b;
+
+    a = ap;
+    b = bp;
+
+    return *a - *b;
+}
+
+void initialize_ccixstate(CCIXState *s, PCIDevice *d)
+{
+    s->am_tree = g_tree_new(am_cmp);
+    s->pci_dev = d;
+}
+
+static void am_table_add(PCIDevice *pci_dev, CCIXState *s, uint16_t offset,
+                         uint16_t cap_start_offset, am_cb_t cb)
+{
+    struct am *entry = g_malloc0(sizeof *entry);
+
+    if (entry) {
+        entry->offset = offset;
+        entry->cap_start_offset = cap_start_offset;
+        entry->am_cb = cb;
+        g_tree_insert(s->am_tree, &entry->offset, entry);
+    }
+}
+
+void ccix_write_config(PCIDevice *pci_dev, CCIXState *s, uint32_t addr, uint32_t val_in, int l)
+{
+    uint64_t key = addr;
+    struct am *entry = g_tree_lookup(s->am_tree, &key);
+
+    if (entry && entry->offset == addr)
+        entry->am_cb(pci_dev, s, addr, entry->cap_start_offset, val_in);
+}
+
+#define CCIX_COMP_ID_GENERAL     0x0000
+#define CCIX_COMP_ID_TDL_DVSEC   0x0001
+#define CCIX_COMP_ID_PRL_DVSEC   0x0002
+#define CCIX_COMP_ID_PRL_COMMON  0x0003
+#define CCIX_COMP_ID_PRL_PORT    0x0004
+#define CCIX_COMP_ID_PRL_LINK    0x0005
+#define CCIX_COMP_ID_HA          0x0006
+#define CCIX_COMP_ID_RA          0x0008
+#define CCIX_COMP_ID_SA          0x000A
+
+#define CCIX_DVSEC_CAP_POS_OFFSET 0x0C
+#define CCIX_DVSEC_CTR_POS_OFFSET 0x10
+
+static void ccix_dvsec_fill_dvsec_header(PCIDevice *pci_dev, uint16_t offset,
+                                         uint16_t cap_size,
+                                         uint16_t cap_offset,
+                                         uint16_t control_size,
+                                         uint16_t control_offset)
+{
+    uint32_t *dword_addr;
+
+    dword_addr = (uint32_t *)(pci_dev->config + offset +
+                              CCIX_DVSEC_CAP_POS_OFFSET);
+    *dword_addr = cap_size | (cap_offset << 20);
+    dword_addr = (uint32_t *)(pci_dev->config + offset +
+                              CCIX_DVSEC_CTR_POS_OFFSET);
+    *dword_addr = control_size | (control_offset << 20);
+}
+
+static void ccix_fill_cap_header(PCIDevice *pci_dev, uint16_t cap_offset,
+                                 uint16_t ccix_comp, uint16_t next_offset)
+{
+    uint8_t ver = 1;
+    uint32_t *dword_addr;
+
+    dword_addr = (uint32_t *)(pci_dev->config + cap_offset);
+    *dword_addr = ccix_comp | (ver << 16) | (next_offset << 20);
+}
+
+static void ra_ctl_dw1_set(PCIDevice *pci_dev, CCIXState *s,  uint16_t offset,
+                           uint16_t cap_start, uint32_t req_val)
+{
+    uint32_t cur_val, new_val = 0;
+    bool ra_en_cur, ra_en_req;
+    uint32_t capval;
+    bool ra_snoop_resp_en_cur, ra_snoop_resp_en_req;
+    bool ra_cache_flush_en_cur, ra_cache_flush_en_req;
+    bool ra_cache_en_cur, ra_cache_en_req;
+    uint8_t raid_cur, raid_req;
+
+    cur_val = pci_get_long(pci_dev->config + offset);
+    ra_en_cur = cur_val & (1 << RA_CTL_DW1_EN_OFF);
+    ra_en_req = req_val & (1 << RA_CTL_DW1_EN_OFF);
+
+    if (ra_en_cur != ra_en_req)
+        printf("Changing RA Enable to %d\n", ra_en_req);
+
+    if (ra_en_req)
+        new_val = (1 << RA_CTL_DW1_EN_OFF);
+
+    ra_snoop_resp_en_cur = cur_val & (1 << RA_CTL_DW1_SNOOP_RESP_EN_OFF);
+    ra_snoop_resp_en_req = req_val & (1 << RA_CTL_DW1_SNOOP_RESP_EN_OFF);
+
+    if (ra_snoop_resp_en_cur != ra_snoop_resp_en_req)
+        printf("Changing RA Snoop REsp Enabled to %d\n",
+               ra_snoop_resp_en_req);
+
+    if (ra_snoop_resp_en_req)
+        new_val |= (1 << RA_CTL_DW1_SNOOP_RESP_EN_OFF);
+
+    ra_cache_flush_en_cur = cur_val & (1 << RA_CTL_DW1_CACHE_FLUSH_EN_OFF);
+    ra_cache_flush_en_req = req_val & (1 << RA_CTL_DW1_CACHE_FLUSH_EN_OFF);
+    if (ra_cache_flush_en_cur != ra_cache_flush_en_req) {
+        printf("Enabling or disabling a cache flush %d\n",
+               ra_cache_flush_en_req);
+
+        //Make the cache flush status update instantaneous for now
+        capval = pci_get_long(pci_dev->config + cap_start + 0x4);
+        if (ra_cache_flush_en_req)
+            capval |= (1 << RA_CAP_DW1_RA_CACHE_FLUSH_STA_OFF);
+        else
+            capval &= ~ (1 << RA_CAP_DW1_RA_CACHE_FLUSH_STA_OFF);
+        pci_set_long(pci_dev->config + cap_start + 0x4, capval);
+    }
+    if (ra_cache_flush_en_req)
+        new_val |= (1 << RA_CTL_DW1_CACHE_FLUSH_EN_OFF);
+
+    ra_cache_en_cur = cur_val & (1 << RA_CTL_DW1_CACHE_EN_OFF);
+    ra_cache_en_req = req_val & (1 << RA_CTL_DW1_CACHE_EN_OFF);
+    if (ra_cache_en_cur != ra_cache_en_req)
+        printf("Enabling of disabling the RA cache %d\n", ra_cache_en_req);
+
+    if (ra_cache_en_req)
+        new_val |= (1 << RA_CTL_DW1_CACHE_EN_OFF);
+
+    raid_cur = (cur_val & RA_CTL_DW1_RAID_M) >> RA_CTL_DW1_RAID_OFF;
+    raid_req = (req_val & RA_CTL_DW1_RAID_M) >> RA_CTL_DW1_RAID_OFF;
+    if (raid_cur != raid_req)
+        printf("RA ID changing from %u to %u\n", raid_cur, raid_req);
+
+    new_val |= (raid_req << RA_CTL_DW1_RAID_OFF) & RA_CTL_DW1_RAID_M;
+
+    pci_set_long(pci_dev->config + offset, new_val);
+}
+
+
+static void comncntl1_set(PCIDevice *pci_dev, CCIXState *s, uint16_t offset,
+			  uint16_t cap_start, uint32_t req_val)
+{
+    uint32_t cur_val, new_val = 0;
+    bool dev_en_req, dev_en_cur;
+    bool pp_en_req, pp_en_cur;
+    bool id_val_req, id_val_cur;
+    bool rsam_val_req, rsam_val_cur;
+    uint8_t eaid_req, eaid_cur;
+    uint8_t devid_req, devid_cur;
+    int i;
+    uint32_t capval;
+
+    cur_val = pci_get_long(pci_dev->config + offset);
+
+    dev_en_req = req_val & (1 << CM_CTL_DW1_DEVICE_EN_OFF);
+    dev_en_cur = cur_val & (1 << CM_CTL_DW1_DEVICE_EN_OFF);
+    if (dev_en_req != dev_en_cur) {
+        printf("Dev enable changing to %d\n", dev_en_req);
+        /* Now I need to set it on all devices */
+        if (s->ccix_dev_name)
+            for (i = 0; i < sizeof(CCIXFuncs)/sizeof(*CCIXFuncs); i++) {
+                if (!CCIXFuncs[i] || !CCIXFuncs[i]->ccix_dev_name)
+                    continue;
+                if (CCIXFuncs[i] != s && !strcmp(CCIXFuncs[i]->ccix_dev_name, s->ccix_dev_name)) {
+                    pci_set_long(CCIXFuncs[i]->pci_dev->config + CCIXFuncs[i]->enable_offset,
+                                 pci_get_word(CCIXFuncs[i]->pci_dev->config + CCIXFuncs[i]->enable_offset) | 0x1);
+                }
+            }
+    }
+    if (dev_en_req)
+        new_val |= (1 << CM_CTL_DW1_DEVICE_EN_OFF);
+
+    pp_en_req = req_val & (1 << CM_CTL_DW1_PRIMARY_PORT_EN_OFF);
+    pp_en_cur = cur_val & (1 << CM_CTL_DW1_PRIMARY_PORT_EN_OFF);
+    if (pp_en_req != pp_en_cur)
+        printf("Primary port enable changing to %d\n", pp_en_req);
+    if (pp_en_req)
+        new_val |= (1 << CM_CTL_DW1_PRIMARY_PORT_EN_OFF);
+    /* NOT DOING MESH ENABLE FOR NOW */
+    /* NOT DOING PORT AG FOR NOW */
+
+    id_val_req = req_val & (1 << CM_CTL_DW1_IDM_TABLE_VALID_OFF);
+    id_val_cur = cur_val & (1 << CM_CTL_DW1_IDM_TABLE_VALID_OFF);
+    if (id_val_req != id_val_cur)
+        printf("Validity of IDM changing to %d\n", id_val_req);
+    if (id_val_req)
+        new_val |= (1 << CM_CTL_DW1_IDM_TABLE_VALID_OFF);
+
+    rsam_val_req = req_val & (1 << CM_CTL_DW1_RSAM_TABLE_VALID_OFF);
+    rsam_val_cur = cur_val & (1 << CM_CTL_DW1_RSAM_TABLE_VALID_OFF);
+    if (rsam_val_req != rsam_val_cur)
+        printf("RSAM valid changing to %d\n", rsam_val_req);
+    if (rsam_val_req)
+        new_val |= (1 << CM_CTL_DW1_RSAM_TABLE_VALID_OFF);
+    /* NOT DOING HSAM FOR NOW */
+    /* NOT DOING SW SERVICES PORTAL FOR NOW */
+
+    eaid_req = (req_val & CM_CTL_DW1_ERR_AGENT_ID_M) >>
+        CM_CTL_DW1_ERR_AGENT_ID_OFF;
+    eaid_cur = (cur_val & CM_CTL_DW1_ERR_AGENT_ID_M) >>
+        CM_CTL_DW1_ERR_AGENT_ID_OFF;
+    if (eaid_req != eaid_cur)
+        printf("EAID for device changing from %d to %d\n",
+               eaid_cur, eaid_req);
+    new_val |= eaid_req << CM_CTL_DW1_ERR_AGENT_ID_OFF;
+
+    devid_req = (req_val & CM_CTL_DW1_DEVID_M) >> CM_CTL_DW1_DEVID_OFF;
+    devid_cur = (cur_val & CM_CTL_DW1_DEVID_M) >> CM_CTL_DW1_DEVID_OFF;
+    if (devid_req != devid_cur) {
+        printf("DEVID changing from %d to %d, updating status\n",
+               devid_cur, devid_req);
+
+        capval = pci_get_long(pci_dev->config + cap_start + 0x4);
+        capval &= ~CM_CAP_DW1_DEVID_M;
+        capval |= (uint32_t)devid_req << CM_CAP_DW1_DEVID_OFF;
+        pci_set_long(pci_dev->config + cap_start + 4, capval);
+
+        if (s->ccix_dev_name)
+            for (i = 0; i < sizeof(CCIXFuncs)/sizeof(*CCIXFuncs); i++) {
+                if (!CCIXFuncs[i] || !CCIXFuncs[i]->ccix_dev_name)
+                    continue;
+                if (CCIXFuncs[i] != s && !strcmp(CCIXFuncs[i]->ccix_dev_name, s->ccix_dev_name)) {
+                    capval = pci_get_long(CCIXFuncs[i]->pci_dev->config + CCIXFuncs[i]->enable_offset);
+                    capval &= ~CM_CAP_DW1_DEVID_M;
+                    capval |= (uint32_t)devid_req << CM_CAP_DW1_DEVID_OFF;
+                    pci_set_long(CCIXFuncs[i]->pci_dev->config + CCIXFuncs[i]->enable_offset, capval);
+                }
+            }
+    }
+    new_val |= (uint32_t)devid_req << CM_CTL_DW1_DEVID_OFF;
+
+    pci_set_long(pci_dev->config + offset, new_val);
+}
+
+static void comncntl2_set(PCIDevice *pci_dev, CCIXState *s, uint16_t offset,
+              uint16_t cap_start, uint32_t req_val)
+{
+    uint32_t cur_val, new_val = 0;
+    bool partial_cur, partial_req;
+    uint32_t addrw_cur, addrw_req;
+
+    cur_val = pci_get_long(pci_dev->config + offset);
+
+    partial_cur = cur_val & (1 << CM_CTL_DW2_PART_CS_EN_OFF);
+    partial_req = req_val & (1 << CM_CTL_DW2_PART_CS_EN_OFF);
+    if (partial_cur != partial_req)
+        printf("Changing Partial Cache enable to %d\n", partial_req);
+    if (partial_req)
+        new_val = (1 << CM_CTL_DW2_PART_CS_EN_OFF);
+    /* Cacheline size 128 not yet supported */
+
+    addrw_cur = (cur_val & CM_CTL_DW2_ADDR_W_EN_M) >> CM_CTL_DW2_ADDR_W_EN_OFF;
+    addrw_req = (req_val & CM_CTL_DW2_ADDR_W_EN_M) >> CM_CTL_DW2_ADDR_W_EN_OFF;
+    /* No sanity checking yet */
+    if (addrw_cur != addrw_req)
+        printf("Changing Address Width to %d\n", addrw_req);
+    new_val = (addrw_req << CM_CTL_DW2_ADDR_W_EN_OFF);
+
+    pci_set_long(pci_dev->config + offset, new_val);
+}
+
+static void port_ctl_dw1_set(PCIDevice *pci_dev, CCIXState *s, uint16_t offset,
+                             uint16_t cap_start, uint32_t req_val)
+{
+    uint32_t cur_val;
+    uint32_t new_val = 0;
+    bool en_req, en_cur;
+    bool opt_req, opt_cur;
+    uint32_t links_req, links_cur;
+    uint32_t psam_req, psam_cur;
+
+    cur_val = pci_get_long(pci_dev->config + offset);
+    en_cur = cur_val & (1 << PT_CTL_DW1_PORT_EN_OFF);
+    en_req = req_val & (1 << PT_CTL_DW1_PORT_EN_OFF);
+    if (en_cur != en_req)
+        printf("Enabling of port changing to %d\n", en_req);
+    if (en_req)
+        new_val |= (1 << PT_CTL_DW1_PORT_EN_OFF);
+
+    opt_cur = cur_val & (1 << PT_CTL_DW1_OPT_HEADER_EN_OFF);
+    opt_req = req_val & (1 << PT_CTL_DW1_OPT_HEADER_EN_OFF);
+    if (opt_cur != opt_req)
+        printf("Enabling of optimized header changing to %d\n", opt_req);
+    if (opt_req)
+        new_val |= (1 << PT_CTL_DW1_OPT_HEADER_EN_OFF);
+
+    links_cur = (cur_val & PT_CTL_DW1_LINKS_EN_M) >> PT_CTL_DW1_LINKS_EN_OFF;
+    links_req = (req_val & PT_CTL_DW1_LINKS_EN_M) >> PT_CTL_DW1_LINKS_EN_OFF;
+    if (links_cur != links_req)
+        printf("Number of enabled links changing from %d to %d\n",
+               links_cur, links_req);
+    new_val |= (links_req << PT_CTL_DW1_LINKS_EN_OFF);
+
+    psam_cur = (cur_val & PT_CTL_DW1_PSAM_ENTRIES_EN_M) >>
+        PT_CTL_DW1_PSAM_ENTRIES_EN_OFF;
+    psam_req = (req_val & PT_CTL_DW1_PSAM_ENTRIES_EN_M) >>
+        PT_CTL_DW1_PSAM_ENTRIES_EN_OFF;
+    if (psam_cur != psam_req)
+        printf("Number of psam entries changing from %d to %d\n",
+               psam_cur, psam_req);
+    new_val |= (psam_req << PT_CTL_DW1_PSAM_ENTRIES_EN_OFF);
+
+    pci_set_long(pci_dev->config + offset, new_val);
+}
+
+static void lk_ctl_dw1_set(PCIDevice *pci_dev, CCIXState *s, uint16_t offset,
+               uint16_t cap_start, uint32_t req_val)
+{
+    uint32_t cur_val;
+    uint32_t new_val = 0;
+    bool en_cur, en_req;
+    bool cred_en_cur, cred_en_req;
+    bool mpack_en_cur, mpack_en_req;
+    bool nocompack_cur, nocompack_req;
+    uint32_t maxpkt_cur, maxpkt_req;
+    bool addr_type_cur, addr_type_req;
+
+    cur_val = pci_get_long(pci_dev->config + offset);
+
+    en_cur = cur_val & (1 << LK_CTL_DW1_LINK_EN_OFF);
+    en_req = req_val & (1 << LK_CTL_DW1_LINK_EN_OFF);
+    if (en_cur != en_req)
+        printf("Changing link enabled status to %d\n", en_req);
+    if (en_req)
+        new_val |= (1 << LK_CTL_DW1_LINK_EN_OFF);
+
+    cred_en_cur = cur_val & (1 << LK_CTL_DW1_CREDIT_EN_OFF);
+    cred_en_req = req_val & (1 << LK_CTL_DW1_CREDIT_EN_OFF);
+    if (cred_en_cur != cred_en_req)
+        printf("Changing link credit enable status to %d\n", cred_en_cur);
+    if (cred_en_req)
+        new_val |= (1 << LK_CTL_DW1_CREDIT_EN_OFF);
+
+    mpack_en_cur = cur_val & (1 << LK_CTL_DW1_MESSAGE_PACKING_EN_OFF);
+    mpack_en_req = req_val & (1 << LK_CTL_DW1_MESSAGE_PACKING_EN_OFF);
+    if (mpack_en_cur != mpack_en_req)
+        printf("Changing message packing enable to %d\n", mpack_en_req);
+    if (mpack_en_req)
+        new_val |= (1 << LK_CTL_DW1_MESSAGE_PACKING_EN_OFF);
+    nocompack_cur = cur_val & (1 << LK_CTL_DW1_NO_COMP_ACK_EN_OFF);
+    nocompack_req = req_val & (1 << LK_CTL_DW1_NO_COMP_ACK_EN_OFF);
+    if (nocompack_cur != nocompack_req)
+        printf("Setting nocompack for link to %d\n", nocompack_req);
+    if (nocompack_req)
+        new_val |= (1 << LK_CTL_DW1_NO_COMP_ACK_EN_OFF);
+
+    maxpkt_cur = (cur_val & LK_CTL_DW1_MAX_PKT_SIZE_EN_M) >>
+        LK_CTL_DW1_MAX_PKT_SIZE_EN_OFF;
+    maxpkt_req = (req_val & LK_CTL_DW1_MAX_PKT_SIZE_EN_M) >>
+        LK_CTL_DW1_MAX_PKT_SIZE_EN_OFF;
+    if (maxpkt_cur != maxpkt_req)
+        printf("Changing max packet size on link from %d to %d\n",
+               maxpkt_cur, maxpkt_req);
+    new_val |= maxpkt_req << LK_CTL_DW1_MAX_PKT_SIZE_EN_OFF;
+
+    addr_type_cur = cur_val & (1 << LK_CTL_DW1_LINK_ENT_ADDR_TYPE_OFF);
+    addr_type_req = req_val & (1 << LK_CTL_DW1_LINK_ENT_ADDR_TYPE_OFF);
+    if (addr_type_cur != addr_type_req)
+        printf("Link Entry Address Type changed to %d\n", addr_type_req);
+    if (addr_type_req)
+        new_val |= (1 << LK_CTL_DW1_LINK_ENT_ADDR_TYPE_OFF);
+
+    pci_set_long(pci_dev->config + offset, new_val);
+}
+
+static void lk_ctl_dw2_set(PCIDevice *pci_dev, CCIXState *s, uint16_t offset,
+               uint16_t cap_start, uint32_t req_val)
+{
+    uint32_t new_val = req_val;
+    /* TODO */
+    pci_set_long(pci_dev->config + offset, new_val);
+}
+
+static void lk_ctl_dw3_set(PCIDevice *pci_dev, CCIXState *s, uint16_t offset,
+               uint16_t cap_start, uint32_t req_val)
+{
+    uint32_t new_val = req_val;
+    /* TODO */
+    pci_set_long(pci_dev->config + offset, new_val);
+}
+
+static void lk_ctl_dw4_set(PCIDevice *pci_dev, CCIXState *s, uint16_t offset,
+               uint16_t cap_start, uint32_t req_val)
+{
+    uint32_t new_val = req_val;
+    /* TODO */
+    pci_set_long(pci_dev->config + offset, new_val);
+}
+
+static void idm_entry_set(PCIDevice *pci_dev, CCIXState *s, uint16_t offset,
+              uint16_t cap_start, uint32_t req_val)
+{
+    /* No sanity checking */
+    printf("Setting idm entry\n");
+    pci_set_long(pci_dev->config + offset, req_val);
+}
+
+static void psam_entry_dw0_set(PCIDevice *pci_dev, CCIXState *s, uint16_t offset,
+                   uint16_t cap_start, uint32_t req_val)
+{
+    /* No sanity checking */
+    printf("Setting psam entry dw0\n");
+    pci_set_long(pci_dev->config + offset, req_val);
+}
+
+static void psam_entry_dw1_set(PCIDevice *pci_dev, CCIXState *s, uint16_t offset,
+                   uint16_t cap_start, uint32_t req_val)
+{
+    /* No sanity checking */
+    printf("Setting psam entry dw1\n");
+    pci_set_long(pci_dev->config + offset, req_val);
+}
+
+static void psam_entry_dw2_set(PCIDevice *pci_dev, CCIXState *s, uint16_t offset,
+                   uint16_t cap_start, uint32_t req_val)
+{
+    /* No sanity checking */
+    printf("Setting psam entry dw2\n");
+    pci_set_long(pci_dev->config + offset, req_val);
+}
+
+
+static void sam_entry_dw0_set(PCIDevice *pci_dev, CCIXState *s, uint16_t offset,
+                  uint16_t cap_start, uint32_t req_val)
+{
+    /* No sanity checking */
+    printf("Setting sam entry dw0\n");
+    pci_set_long(pci_dev->config + offset, req_val);
+}
+
+static void sam_entry_dw1_set(PCIDevice *pci_dev, CCIXState *s, uint16_t offset,
+                  uint16_t cap_start, uint32_t req_val)
+{
+    /* No sanity checking */
+    printf("Setting sam entry dw1\n");
+    pci_set_long(pci_dev->config + offset, req_val);
+}
+
+static void sam_entry_dw2_set(PCIDevice *pci_dev, CCIXState *s, uint16_t offset,
+                  uint16_t cap_start, uint32_t req_val)
+{
+    /* No sanity checking */
+    printf("Setting sam entry dw2\n");
+    pci_set_long(pci_dev->config + offset, req_val);
+}
+
+static void ccix_prl_common_cap(PCIDevice *pci_dev,
+                                CCIXState *s,
+                                uint16_t this_cap_offset,
+                                uint16_t next_cap_offset,
+                                uint16_t device_err_log_offset,
+                                uint16_t idm_table_offset,
+                                uint16_t rsam_offset, uint16_t rsam_size,
+                                uint16_t hsam_offset, uint16_t hsam_size,
+                                uint16_t sr_table_offset,
+                                uint16_t sw_portal_offset)
+{
+    uint32_t *cap_start = (uint32_t *)(pci_dev->config + this_cap_offset);
+    uint32_t multiport_dev_cap;
+
+    /* Put in our first capability */
+    ccix_fill_cap_header(pci_dev, this_cap_offset, CCIX_COMP_ID_PRL_COMMON,
+                         next_cap_offset);
+    /* ComnCapStat1 */
+    if (s->flags & (1 << PRIMARY_PORT_BIT))
+        multiport_dev_cap = 0x7;
+    else
+        multiport_dev_cap = 0x5;
+
+    *(cap_start + 1) = (multiport_dev_cap << CM_CAP_DW1_MULTIPORT_CAP_OFF) |
+        (0 << CM_CAP_DW1_VERSION_CAP_OFF) |
+        (0 << CM_CAP_DW1_DEVID_OFF);
+    /* ComnCapStat2 */
+    *(cap_start + 2) = (1 << CM_CAP_DW2_DISC_READY_CAP_OFF) |
+        (0 << CM_CAP_DW2_PART_CS_CAP_OFF) |
+        (0 << CM_CAP_DW2_PORT_AG_CAP_OFF) |
+        /* 64 byte only */
+        (0 << CM_CAP_DW2_CL_SIZE_CAP_OFF) |
+        /* 48 bit addressing only */
+        (0 << CM_CAP_DW2_ADDR_W_CAP_OFF) |
+        /* No multihop port aggregation */
+        (0 << CM_CAP_DW2_MH_CAP_OFF) |
+        ((sw_portal_offset ? 1 : 0) << CM_CAP_DW2_SW_PORT_CAP_OFF) |
+        /* Natural alignment over 4GB */
+        (1 << CM_CAP_DW2_SAM_ALIGN_CAP_OFF) |
+        /* random time values */
+        (3 << CM_CAP_DW2_READY_TIME_VAL_OFF) |
+        (1 << CM_CAP_DW2_READY_TIME_SCALE_OFF);
+    /* ComnCapStat3 */
+    *(cap_start + 3) = 0;
+    /* Device Error Log Offset */
+    *(cap_start + 4) = device_err_log_offset << CM_CAP_DW4_DEV_ERR_LOG_OFFSET_OFF;
+    *(cap_start + 5) = idm_table_offset << CM_CAP_DW5_IDM_OFFSET_OFF;
+    *(cap_start + 6) = (rsam_size << CM_CAP_DW6_RSAM_SIZE_OFF) |
+        (rsam_offset << CM_CAP_DW6_RSAM_OFFSET_OFF);
+    *(cap_start + 7) = (hsam_size << CM_CAP_DW7_HSAM_SIZE_OFF) |
+        (hsam_offset << CM_CAP_DW7_HSAM_OFFSET_OFF);
+    *(cap_start + 8) = sr_table_offset << CM_CAP_DW8_SR_OFFSET_OFF;
+    *(cap_start + 9) = sw_portal_offset << CM_CAP_DW9_SW_PORTAL_OFF;
+}
+
+static void ccix_prl_ra_cap(PCIDevice *pci_dev,
+                            uint16_t this_cap_offset,
+                            uint16_t next_cap_offset,
+                            uint16_t error_log_offset)
+{
+    uint32_t *cap_start = (uint32_t *)(pci_dev->config + this_cap_offset);
+
+    ccix_fill_cap_header(pci_dev, this_cap_offset, CCIX_COMP_ID_RA, next_cap_offset);
+    *(cap_start + 1) = (1 << RA_CAP_DW1_RA_DISC_RDY_STAT_OFF) |
+        /* Some example values follow */
+        (3 << RA_CAP_DW1_RA_CACHE_FLUSH_TIME_VALUE_OFF) |
+        (1 << RA_CAP_DW1_RA_CACHE_FLUSH_TIME_SCALE_OFF) |
+        (0 << RA_CAP_DW1_RA_CACHE_FLUSH_STA_OFF);
+
+    *(cap_start + 2) = (error_log_offset << RA_CAP_DW2_RA_ERROR_LOG_OFFSET_OFF);
+}
+
+static void ccix_prl_ha_cap(PCIDevice *pci_dev,
+                            uint16_t this_cap_offset,
+                            uint16_t next_cap_offset,
+                            uint16_t error_log_offset,
+                            uint8_t num_ids,
+                            uint8_t num_pools)
+{
+    uint32_t *cap_start = (uint32_t *)(pci_dev->config + this_cap_offset);
+    int i;
+
+    ccix_fill_cap_header(pci_dev, this_cap_offset, CCIX_COMP_ID_HA, next_cap_offset);
+    *(cap_start + 1) = (1 << HA_CAP_DW1_HA_DISC_RD_STAT_OFF) |
+        ((num_ids - 1) << HA_CAP_DW1_NUM_HA_IDS_OFF) |
+        (num_pools << HA_CAP_DW1_HA_MEM_POOL_CAP_OFF) |
+        (0 << HA_CAP_DW1_HA_QACK_OFF) |
+        (0 << HA_CAP_DW1_HA_HW_QACK_CAP_OFF) |
+        (0 << HA_CAP_DW1_HA_MEM_EXP_CAP_OFF) | /* No support for SAs being homed here */
+        (0 << HA_CAP_DW1_HA_EVICT_HINT_CAP_OFF) |
+        (0 << HA_CAP_DW1_HA_WRITE_EVICT_FULL_HIT_CAP_OFF) |
+        (3 << HA_CAP_DW1_MEM_POOL_READY_TIME_VALUE_OFF) |
+        (4 << HA_CAP_DW1_MEM_POOL_READY_TIME_SCALE_OFF) |
+        (1 << HA_CAP_DW1_MEM_POOL_READY_STA_OFF);
+    *(cap_start + 2) = error_log_offset << HA_CAP_DW2_HA_ERROR_LOG_OFF;
+
+    for (i = 0; i < num_pools; i++) {
+        *(cap_start + 3 + i * 2) = (1 << MEM_POOL_CAP_DW1_READY_STA_OFF) |
+            (mem_type_volatile << MEM_POOL_CAP_DW1_GEN_MEM_TYPE_OFF) |
+            (mem_spec_hbm << MEM_POOL_CAP_DW1_SPEC_MEM_TYPE_OFF) |
+            (0 << MEM_POOL_CAP_DW1_ADDR_CAP_OFF) |
+            (MEM_POOL_CAP_DW1_MEM_ATTR_NORMAL << MEM_POOL_CAP_DW1_MEM_ATTR_OFF) |
+            (MEM_POOL_CAP_DW1_MEM_EXT_ATTR_NONE << MEM_POOL_CAP_DW1_MEM_EXT_ATTR_OFF) |
+            (0xFFFF << MEM_POOL_CAP_DW1_MEM_POOL_SIZE_L_CAP_OFF);
+        *(cap_start + 3 + i * 2 + 1) = 0xF << MEM_POOL_CAP_DW2_MEM_POOL_SIZE_H_CAP_OFF;
+    }
+}
+
+static void ccix_prl_port_cap(PCIDevice *pci_dev,
+                              CCIXState *s,
+                              uint16_t this_cap_offset,
+                              uint16_t next_cap_offset,
+                              uint16_t error_log_offset)
+{
+    uint32_t *cap_start = (uint32_t *)(pci_dev->config + this_cap_offset);
+
+    ccix_fill_cap_header(pci_dev, this_cap_offset, CCIX_COMP_ID_PRL_PORT,
+                         next_cap_offset);
+    *(cap_start + 1) = (1 << PT_CAP_DW1_DISC_READY_OFF) |
+        (1 << PT_CAP_DW1_OPT_HEADER_OFF) |
+        (0 << PT_CAP_DW1_P2P_FORWARDING_OFF) |
+        (s->num_links << PT_CAP_DW1_LINKS_OFF) |
+        (s->psam_entries << PT_CAP_DW1_PSAM_ENTRIES_OFF) |
+        ((s->port_id & 0xf) << PT_CAP_DW1_PORTID_OFF);
+    *(cap_start + 2) = 0; /* No Port AG */
+    *(cap_start + 3) = 0; /* No Port FW */
+    *(cap_start + 4) = error_log_offset << 20;
+}
+
+static void ccix_prl_link_cap(PCIDevice *pci_dev,
+                              uint16_t this_cap_offset,
+                              uint16_t next_cap_offset,
+                              uint16_t error_log_offset)
+{
+    uint32_t *cap_start = (uint32_t *)(pci_dev->config + this_cap_offset);
+
+    ccix_fill_cap_header(pci_dev, this_cap_offset, CCIX_COMP_ID_PRL_LINK,
+                         next_cap_offset);
+
+    *(cap_start + 1) = (1 << LK_CAP_DW1_DISC_READY_OFF) |
+        (0 << LK_CAP_DW1_CREDIT_TYPE_OFF) |
+        (1 << LK_CAP_DW1_MESSAGE_PACKING_OFF) |
+        (0 << LK_CAP_DW1_NOCOMPACK_OFF) |
+        (2 << LK_CAP_DW1_MAX_PKT_SIZE_OFF);
+
+    *(cap_start + 2) = (3 << LK_CAP_DW2_MAX_MEM_REQ_SEND_OFF) |
+        (4 << LK_CAP_DW2_MAX_SNP_REQ_SEND_OFF) |
+        (5 << LK_CAP_DW2_MAX_DAT_REQ_SEND_OFF);
+    *(cap_start + 3) = (6 << LK_CAP_DW3_MAX_MEM_REQ_RECV_OFF) |
+        (7 << LK_CAP_DW3_MAX_SNP_REQ_RECV_OFF) |
+        (8 << LK_CAP_DW3_MAX_DAT_REQ_RECV_OFF);
+    *(cap_start + 4) = (9 << LK_CAP_DW4_MAX_MISC_REQ_SEND_CAP_OFF) |
+        (10 << LK_CAP_DW4_MAX_MISC_REQ_RECV_CAP_OFF);
+    *(cap_start + 5) = error_log_offset << 20;
+}
+
+static void ccix_prl_common_ctl(PCIDevice *pci_dev,
+                                CCIXState *s,
+                                uint16_t this_ctl_offset,
+                                uint16_t next_ctl_offset)
+{
+    uint32_t *ctl_start = (uint32_t *)(pci_dev->config + this_ctl_offset);
+
+    ccix_fill_cap_header(pci_dev, this_ctl_offset, CCIX_COMP_ID_PRL_COMMON,
+                         next_ctl_offset);
+    /* ComnCntl1 */
+    *(ctl_start + 1) = (0 << CM_CTL_DW1_DEVICE_EN_OFF) |
+        (0 << CM_CTL_DW1_PRIMARY_PORT_EN_OFF) |
+        (0 << CM_CTL_DW1_MESH_EN_OFF) |
+        (0 << CM_CTL_DW1_PORT_AG_EN_OFF) |
+        (0 << CM_CTL_DW1_IDM_TABLE_VALID_OFF) |
+        (0 << CM_CTL_DW1_RSAM_TABLE_VALID_OFF) |
+        (0 << CM_CTL_DW1_HSAM_TABLE_VALID_OFF) |
+        (0 << CM_CTL_DW1_SW_PORT_ENABLE_OFF) |
+        (0 << CM_CTL_DW1_ERR_AGENT_ID_OFF) |
+        (0 << CM_CTL_DW1_DEVID_OFF);
+    am_table_add(pci_dev, s, this_ctl_offset + 4, this_ctl_offset, comncntl1_set);
+    s->enable_offset = this_ctl_offset + 4;
+    /* ComnCtl2 */
+    *(ctl_start + 2) = 0; // No support for anything in here yet.
+    am_table_add(pci_dev, s, this_ctl_offset + 8, this_ctl_offset, comncntl2_set);
+    /* No snoop request hash mask yet */
+    /* No SW Service Portal yet */
+}
+
+static void ccix_prl_ra_ctl(PCIDevice *pci_dev,
+                            CCIXState *s,
+                            uint16_t this_ctl_offset,
+                            uint16_t next_ctl_offset,
+                            uint16_t ra_id)
+{
+    uint32_t *ctl_start = (uint32_t *)(pci_dev->config + this_ctl_offset);
+
+    ccix_fill_cap_header(pci_dev, this_ctl_offset, CCIX_COMP_ID_RA,
+                         next_ctl_offset);
+
+    *(ctl_start + 1) = (0 << RA_CTL_DW1_EN_OFF) |
+        (0 << RA_CTL_DW1_SNOOP_RESP_EN_OFF) |
+        (0 << RA_CTL_DW1_CACHE_FLUSH_EN_OFF) |
+        (0 << RA_CTL_DW1_CACHE_EN_OFF) |
+        (0 << RA_CTL_DW1_RAID_OFF);
+    am_table_add(pci_dev, s, this_ctl_offset + 4, this_ctl_offset, ra_ctl_dw1_set);
+}
+
+static void ccix_prl_ha_ctl(PCIDevice *pci_dev,
+                            CCIXState *s,
+                            uint16_t this_ctl_offset,
+                            uint16_t next_ctl_offset,
+                            uint16_t num_ids,
+                            uint16_t num_pools)
+{
+    uint32_t *ctl_start = (uint32_t *)(pci_dev->config + this_ctl_offset);
+
+    ccix_fill_cap_header(pci_dev, this_ctl_offset, CCIX_COMP_ID_HA,
+                         next_ctl_offset);
+    *(ctl_start + 1) = 0;
+}
+
+static void ccix_prl_port_ctl(PCIDevice *pci_dev,
+                              CCIXState *s,
+                              uint16_t this_ctl_offset,
+                              uint16_t next_ctl_offset,
+                              uint8_t psam_table_entries)
+{
+    uint8_t i;
+    uint32_t *ctl_start = (uint32_t *)(pci_dev->config + this_ctl_offset);
+
+    ccix_fill_cap_header(pci_dev, this_ctl_offset, CCIX_COMP_ID_PRL_PORT,
+                         next_ctl_offset);
+    /* Port Control */
+    *(ctl_start + 1) = 0;
+    am_table_add(pci_dev, s, this_ctl_offset + 4, this_ctl_offset, port_ctl_dw1_set);
+
+    for (i = 0; i < psam_table_entries; i++) {
+        am_table_add(pci_dev, s, this_ctl_offset + 0x14 + (3 * i + 0) * 4,
+                     0, psam_entry_dw0_set);
+        am_table_add(pci_dev, s, this_ctl_offset + 0x14 + (3 * i + 1) * 4,
+                     0, psam_entry_dw1_set);
+        am_table_add(pci_dev, s, this_ctl_offset + 0x14 + (3 * i + 2) * 4,
+                     0, psam_entry_dw2_set);
+    }
+}
+
+static void ccix_prl_link_ctl(PCIDevice *pci_dev,
+                              CCIXState *s,
+                              uint16_t this_ctl_offset,
+                              uint16_t next_ctl_offset,
+                              uint8_t num_links)
+{
+    uint32_t *ctl_start = (uint32_t *)(pci_dev->config + this_ctl_offset);
+    uint8_t i;
+
+    ccix_fill_cap_header(pci_dev, this_ctl_offset, CCIX_COMP_ID_PRL_LINK,
+        next_ctl_offset);
+
+    for (i = 0; i < num_links; i++) {
+        /* LinkAttrCntl for link i */
+        *(ctl_start + 1 + i * 6) = 0;
+        am_table_add(pci_dev, s, this_ctl_offset + 4 + i * 24, 0, lk_ctl_dw1_set);
+        /* LinkMaxCreditCntl for link i */
+        *(ctl_start + 1 + i * 6 + 1) = 0;
+        am_table_add(pci_dev, s, this_ctl_offset + 4 + i * 24 + 4, 0, lk_ctl_dw2_set);
+        *(ctl_start + 1 + i * 6 + 2) = 0;
+        am_table_add(pci_dev, s, this_ctl_offset + 4 + i * 24 + 8, 0, lk_ctl_dw3_set);
+        *(ctl_start + 1 + i * 6 + 3) = 0;
+        am_table_add(pci_dev, s, this_ctl_offset + 4 + i * 24 + 0xC, 0, lk_ctl_dw4_set);
+
+        /* error fields - to do */
+        *(ctl_start + 1 + i * 24 + 4) = 0;
+        *(ctl_start + 1 + i * 24 + 5) = 0;
+    }
+    /* transport id */
+    for (i = 0; i < num_links; i++)
+        //to check
+        *(ctl_start + 1 + num_links * 6 + 4 * i) = 0;
+}
+
+static void ccix_idm(PCIDevice *pci_dev, CCIXState *s, uint16_t offset)
+{
+    int i;
+
+    for (i = 0; i < 64; i++)
+        am_table_add(pci_dev, s, offset + i * 4, 0, idm_entry_set);
+}
+
+static void ccix_sam(PCIDevice *pci_dev, CCIXState *s, uint16_t offset, uint8_t entries)
+{
+    int i;
+
+    for (i = 0; i < entries; i++) {
+        am_table_add(pci_dev, s, offset + 3 * i * 4, 0, sam_entry_dw0_set);
+        am_table_add(pci_dev, s, offset + (3 * i + 1) * 4, 0, sam_entry_dw1_set);
+        am_table_add(pci_dev, s, offset + (3 * i + 2) * 4, 0, sam_entry_dw2_set);
+    }
+}
+static void ccix_guid(PCIDevice *pci_dev, uint16_t offset)
+{
+    uint32_t *start = (uint32_t *)(pci_dev->config + offset);
+
+    *(start) = CCIX_GUID_DW0;
+    *(start + 1) = CCIX_GUID_DW1;
+    *(start + 2) = CCIX_GUID_DW2;
+    *(start + 3) = CCIX_GUID_DW3;
+    *(start + 4) = 1 << CCIX_GUID_DW4_VERSION_OFF;
+}
+
+/*FIXME: Is this generic enough that we should put it in the PCIe core */
+
+#define CCIX_DVSEC_HEADER_SIZE   0x14
+#define PCIE_DVSEC_HEADER_OFFSET 0x4 /* Offset from start of extend cap */
+#define PCIE_DVSEC_ID_OFFSET     0x8
+static void pcie_add_dvsec(PCIDevice *pci_dev, uint16_t offset,
+                           uint16_t size, uint16_t vendor_id, uint16_t dvsec_id,
+                           uint16_t ccix_guid_offset)
+{
+    uint16_t *word_addr;
+
+    pcie_add_capability(pci_dev, PCI_EXT_CAP_ID_DVSEC, 1, offset, size);
+    pci_set_word(pci_dev->config + offset + PCIE_DVSEC_HEADER_OFFSET,
+                 vendor_id);
+    word_addr = (uint16_t *)(pci_dev->config + offset + PCIE_DVSEC_HEADER_OFFSET + 2);
+    *word_addr = 0x1 | (size << 4);
+
+    word_addr = (uint16_t *)(pci_dev->config + offset + PCIE_DVSEC_ID_OFFSET);
+    *word_addr = dvsec_id;
+    word_addr = (uint16_t *)(pci_dev->config + offset + PCIE_DVSEC_ID_OFFSET + 2);
+    *word_addr = (ccix_guid_offset << 4);
+}
+
+void ccix_set_port(CCIXState *s)
+{
+    s->flags |= (1 << CCIX_IS_PORT);
+    /* Enforce rule of how many psam entries if links is greater than 1 */
+    if ((s->num_links > 1) &&
+        (s->psam_entries < s->num_links + 1)) {
+        printf("Increased psam entries to minimum allowed\n");
+        s->psam_entries = s->num_links + 1;
+    }
+}
+
+enum  ccix_entry_type {
+    common_cap,
+    ra_cap,
+    ha_cap,
+    port_cap,
+    link_cap,
+    end_cap,
+    common_ctl,
+    ra_ctl,
+    ha_ctl,
+    port_ctl,
+    link_ctl,
+    end_ctl,
+    idm_table,
+    sr_table,
+    rsam,
+    hsam,
+    guid,
+};
+
+struct ccix_cap {
+    uint16_t size;
+    uint16_t offset;
+    enum ccix_entry_type type;
+};
+
+static void ccix_add_cap(GList **l, enum ccix_entry_type type, uint16_t size)
+{
+    struct ccix_cap *c;
+    
+    c = malloc(sizeof(*c));
+    c->type = type;
+    c->size = size;
+    *l = g_list_append(*l, c);
+}
+
+uint16_t ccix_add_prldvsec(PCIDevice *pci_dev, CCIXState *s, uint16_t offset)
+{
+    /* Runtime configuration of the following is not yet implemented */
+    uint16_t ha_num_pools = 2;
+    uint16_t ha_num_ids = 8;
+    /* Error log not yet implemented */
+    uint16_t error_log_offset = 0;
+    uint16_t idm_offset = 0;
+    uint16_t sr_offset = 0;
+    uint16_t rsam_offset = 0;
+    uint16_t hsam_offset = 0;
+    uint16_t guid_offset = 0;
+    uint16_t max_offset = 0;
+    uint16_t next_offset;
+    uint16_t cap_size = 0;
+    uint16_t cap_offset;
+    uint16_t ctl_size = 0;
+    uint16_t ctl_offset;
+    struct ccix_cap *c;
+    GList *li;
+    GList *cap_list = NULL;
+    GList *ctl_list = NULL;
+    GList *other_list = NULL;
+    int i;
+
+    /*
+     * Build up lists of the CCIX capabilities, controls and other blocks so that we
+     * can work out their layout in config space before writing the header.
+     */
+    ccix_add_cap(&cap_list, common_cap, CCIX_COMMON_CAP_MAX_SIZE);
+    if (s->flags & (1 << PRIMARY_PORT_BIT))
+            ccix_add_cap(&ctl_list, common_ctl, 0x10);
+    for (i = 0; i < s->num_ras; i++) {
+        ccix_add_cap(&cap_list, ra_cap, CCIX_RA_CAP_SIZE);
+        ccix_add_cap(&ctl_list, ra_ctl, CCIX_RA_CTL_SIZE);
+    }
+    for (i = 0; i < s->num_has; i++) {
+        ccix_add_cap(&cap_list, ha_cap, CCIX_HA_CAP_SIZE + CCIX_POOL_CAP_SIZE * ha_num_pools);
+        ccix_add_cap(&ctl_list, ha_ctl,
+                     CCIX_HA_CTL_SIZE +
+                     (ha_num_ids + 3) / 4 * CCIX_HAID_ENTRY_SIZE +
+                     ha_num_pools * CCIX_BAT_ENTRY_SIZE);
+    }
+
+    /* Only functions with CCIX ports may have port and link structures */
+    if (s->flags & (1 << CCIX_IS_PORT)) {
+        ccix_add_cap(&cap_list, port_cap, CCIX_PORT_CAP_SIZE);
+        ccix_add_cap(&ctl_list, port_ctl,
+                     CCIX_PORT_CTL_SIZE + 12 * s->psam_entries);
+        ccix_add_cap(&cap_list, link_cap, CCIX_LINK_CAP_SIZE);
+        ccix_add_cap(&ctl_list, link_ctl,
+                     CCIX_LINK_CTL_SIZE + CCIX_LINK_CTL_PER_LINK_SIZE * s->num_links);
+    }
+
+    if (s->flags & (1 << PRIMARY_PORT_BIT)) {
+        ccix_add_cap(&other_list, idm_table, 64 * 4);
+        if (s->rsam_entries)
+            ccix_add_cap(&other_list, rsam, CCIX_SAM_ENTRY_SIZE * s->rsam_entries);
+        if (s->hsam_entries)
+            ccix_add_cap(&other_list, hsam, CCIX_SAM_ENTRY_SIZE * s->hsam_entries);
+        ccix_add_cap(&other_list, guid, CCIX_GUID_SIZE);
+    }
+    
+    cap_offset = offset + CCIX_DVSEC_HEADER_SIZE;
+    next_offset = cap_offset;
+    for (li = cap_list; li != NULL; li = li->next) {
+        c = (struct ccix_cap *)li->data;
+        c->offset = next_offset;
+        if (li->next == NULL)
+            next_offset = 0;
+        else {
+            next_offset = c->offset + c->size;
+        }
+        cap_size += c->size;
+        max_offset = c->offset + c->size;
+    }
+    
+    next_offset = max_offset;
+    ctl_offset = max_offset;
+    for (li = ctl_list; li != NULL; li = li->next) {
+        c = (struct ccix_cap *)li->data;
+        c->offset = next_offset;
+        if (li->next == NULL)
+            next_offset = 0;
+        else
+            next_offset = c->offset + c->size;
+
+        max_offset = c->offset + c->size;
+        ctl_size += c->size;
+    }
+
+    next_offset = max_offset;
+    for (li = other_list; li != NULL; li = li->next) {
+        c = (struct ccix_cap *)li->data;
+        c->offset = next_offset;
+        switch (c->type) {
+        case
+            idm_table: idm_offset = c->offset;
+            break;
+        case sr_table:
+            sr_offset = c->offset;
+            break;
+        case hsam:
+            hsam_offset = c->offset;
+            break;
+        case rsam:
+            rsam_offset = c->offset;
+            break;
+        case guid:
+            guid_offset = c->offset;
+            break;
+        default:
+            break;
+        }
+        if (li->next == NULL)
+            next_offset = 0;
+        else
+            next_offset = c->offset + c->size;
+        max_offset = c->offset + c->size;
+    }
+
+    /* Will eventually take some description and make a prl. For now one RA */
+    pcie_add_dvsec(pci_dev, offset, max_offset - offset, PCI_VENDOR_ID_CCIX,
+                   CCIX_COMP_ID_PRL_DVSEC, guid_offset);
+    
+    ccix_dvsec_fill_dvsec_header(pci_dev, offset, cap_size, cap_offset,
+                                 ctl_size, ctl_offset);
+
+    for (li = cap_list; li != NULL; li = li->next) {
+        c = (struct ccix_cap *)li->data;
+        if (li->next)
+            next_offset = ((struct ccix_cap *)(li->next->data))->offset;
+        else
+            next_offset = 0;
+        switch (c->type) {
+        case common_cap:
+            ccix_prl_common_cap(pci_dev, s, c->offset, next_offset,
+                                0, /* No support for device error log */
+                                idm_offset,
+                                rsam_offset, CCIX_SAM_ENTRY_SIZE * s->rsam_entries,
+                                hsam_offset, CCIX_SAM_ENTRY_SIZE * s->hsam_entries,
+                                sr_offset,
+                                0 /* No support for sw portal */);
+               break;
+        case ra_cap:
+            ccix_prl_ra_cap(pci_dev, c->offset, next_offset, error_log_offset);
+            break;
+        case ha_cap:
+            ccix_prl_ha_cap(pci_dev, c->offset, next_offset, error_log_offset,
+                            ha_num_ids, ha_num_pools);
+            break;
+        case port_cap:
+            ccix_prl_port_cap(pci_dev, s, c->offset, next_offset, error_log_offset);
+            break;
+        case link_cap:
+            ccix_prl_link_cap(pci_dev, c->offset, next_offset, error_log_offset);
+            break;
+        default:
+            break;
+        }
+    }
+
+    for (li = ctl_list; li != NULL; li = li->next) {
+        c = (struct ccix_cap *)li->data;
+        if (li->next)
+            next_offset = ((struct ccix_cap *)(li->next->data))->offset;
+        else
+            next_offset =0;
+        switch (c->type) {
+        case common_ctl:
+            ccix_prl_common_ctl(pci_dev, s, c->offset, next_offset);
+            break;
+        case ra_ctl:
+            ccix_prl_ra_ctl(pci_dev, s, c->offset, next_offset, 0);
+            break;
+        case ha_ctl:
+            ccix_prl_ha_ctl(pci_dev, s, c->offset, next_offset, ha_num_ids, ha_num_pools);
+            break;
+        case port_ctl:
+            ccix_prl_port_ctl(pci_dev, s, c->offset, next_offset, s->psam_entries);
+            break;
+        case link_ctl:
+            ccix_prl_link_ctl(pci_dev, s, c->offset, next_offset, s->num_links);
+            break;
+        default:
+            break;
+        }
+    }
+
+    for (li = other_list; li != NULL; li = li->next) {
+        c = (struct ccix_cap *)li->data;
+        switch(c->type) {
+            case idm_table:
+                ccix_idm(pci_dev, s, c->offset);
+                break;
+            case sr_table:
+                ccix_idm(pci_dev, s, c->offset);
+                break;
+            case rsam:
+                ccix_sam(pci_dev, s, c->offset, s->rsam_entries);
+                break;
+            case hsam:
+                ccix_sam(pci_dev, s, c->offset, s->hsam_entries);
+                break;
+            case guid:
+                ccix_guid(pci_dev, c->offset);
+                break;
+            default:
+                break;
+        }
+    }
+    return max_offset;
+}
+
+uint16_t ccix_add_tdldvsec(PCIDevice *pci_dev, uint16_t offset)
+{
+    const uint16_t dvsec_size = 17 * sizeof(uint32_t);
+
+    pcie_add_dvsec(pci_dev, offset, dvsec_size, PCI_VENDOR_ID_CCIX,
+                   CCIX_COMP_ID_TDL_DVSEC, 0);
+
+    return offset + dvsec_size;
+}
+
+void ccix_register(CCIXState *s)
+{
+    int i;
+
+    if (s->ccix_dev_name)
+        for (i = 0; i < sizeof(CCIXFuncs)/sizeof(*CCIXFuncs); i++)
+            if (!CCIXFuncs[i]) {
+                CCIXFuncs[i] = s;
+                break;
+            }
+}
diff --git a/include/hw/misc/ccix.h b/include/hw/misc/ccix.h
new file mode 100644
index 0000000000..94aa904b53
--- /dev/null
+++ b/include/hw/misc/ccix.h
@@ -0,0 +1,28 @@
+
+#include "hw/pci/pcie_port.h"
+typedef struct CCIXState {
+    GTree *am_tree;
+#define PRIMARY_PORT_BIT 0
+#define CCIX_IS_PORT 1
+    uint32_t flags;
+    char *ccix_dev_name;
+    uint8_t port_id;
+    uint8_t num_links;
+    uint8_t psam_entries;
+    uint8_t num_ras;
+    uint8_t num_has;
+    uint8_t rsam_entries;
+    uint8_t hsam_entries;
+    PCIDevice *pci_dev;
+    uint16_t enable_offset;
+} CCIXState;
+
+extern CCIXState *CCIXFuncs[256];
+
+uint16_t ccix_add_prldvsec(PCIDevice *pci_dev, CCIXState *s, uint16_t offset);
+void ccix_write_config(PCIDevice *pci_dev, CCIXState *s, uint32_t addr, uint32_t val_in, int l);
+uint16_t ccix_add_tdldvsec(PCIDevice *pci_dev, uint16_t offset);
+void initialize_ccixstate(CCIXState *s, PCIDevice *pci_dev);
+void ccix_register(CCIXState *s);
+
+void ccix_set_port(CCIXState *s);
diff --git a/include/hw/pci/pci_ids.h b/include/hw/pci/pci_ids.h
index f49be07328..19675fdac1 100644
--- a/include/hw/pci/pci_ids.h
+++ b/include/hw/pci/pci_ids.h
@@ -225,6 +225,8 @@
 #define PCI_DEVICE_ID_HUAWEI_CCIX_DOWN   0xA261
 #define PCI_DEVICE_ID_HUAWEI_CCIX_EP     0xA262
 
+#define PCI_VENDOR_ID_CCIX               0x1e2c
+
 #define PCI_VENDOR_ID_INTEL              0x8086
 #define PCI_DEVICE_ID_INTEL_82378        0x0484
 #define PCI_DEVICE_ID_INTEL_82441        0x1237
-- 
2.20.1



^ permalink raw reply	[flat|nested] 11+ messages in thread

* [Qemu-devel] [RFC PATCH 4/7] pci-bridge: CCIX capable PCIE/CCIX switch upstream port.
  2019-06-25 11:27 [Qemu-devel] [RFC PATCH 0/7] qemu: CCIX pcie config space emulation Jonathan Cameron
                   ` (2 preceding siblings ...)
  2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 3/7] pci: CCIX config space emulation library Jonathan Cameron
@ 2019-06-25 11:27 ` Jonathan Cameron
  2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 5/7] pci-bridge: CCIX capable PCIE/CCIX switch downstream port Jonathan Cameron
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Jonathan Cameron @ 2019-06-25 11:27 UTC (permalink / raw)
  To: QEMU Developers
  Cc: Peter Maydell, jcm, linuxarm, Auger Eric, qemu-arm, Jonathan Cameron

Note that these occur as function 0 within CCIX devices that
have many other elements in the PCIE topology.

This driver has around 100 lines of code copied directly from
the xio3130-upstream.c file. There are various options to
avoid this:

1) Expose the xio3130 functions so this module can just call them.
2) Create a library for the code that is shared.
3) Don't worry too much about it as it's likely they will diverge
   overtime as we extend the CCIX driver.

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 hw/pci-bridge/Kconfig         |   5 +
 hw/pci-bridge/Makefile.objs   |   1 +
 hw/pci-bridge/ccix_upstream.c | 197 ++++++++++++++++++++++++++++++++++
 3 files changed, 203 insertions(+)

diff --git a/hw/pci-bridge/Kconfig b/hw/pci-bridge/Kconfig
index a51ec716f5..f6ff8975a5 100644
--- a/hw/pci-bridge/Kconfig
+++ b/hw/pci-bridge/Kconfig
@@ -27,3 +27,8 @@ config DEC_PCI
 
 config SIMBA
     bool
+
+config CCIX_SWITCH
+    default y if CCIX_EP
+    depends on PCI_EXPRESS && MSI_NONBROKEN
+    select CCIX_LIB
diff --git a/hw/pci-bridge/Makefile.objs b/hw/pci-bridge/Makefile.objs
index 47065f87d9..e266e39fed 100644
--- a/hw/pci-bridge/Makefile.objs
+++ b/hw/pci-bridge/Makefile.objs
@@ -8,3 +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
diff --git a/hw/pci-bridge/ccix_upstream.c b/hw/pci-bridge/ccix_upstream.c
new file mode 100644
index 0000000000..f2b8441fba
--- /dev/null
+++ b/hw/pci-bridge/ccix_upstream.c
@@ -0,0 +1,197 @@
+/*
+ * ccix_upstream.c
+ * CCIX / pci express upstream port switch
+ *
+ * Copyright (c) 2019 Jonathan Camerom <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 "hw/misc/ccix.h"
+#include "qemu/module.h"
+
+/*
+ * As no CCIX devices have publically available specs, just use
+ * the xio3130 elements for the PCIe specific parts.
+ */
+#define XIO3130_REVISION                0x2
+#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_UP_PORT "ccix-upstream-port"
+
+#define CCIX_UP_DEV(obj) OBJECT_CHECK(CCIXUpPortState, (obj), TYPE_CCIX_UP_PORT)
+
+typedef struct CCIXUpPortState {
+    PCIEPort parent_obj;
+    struct CCIXState s;
+} CCIXUpPortState;
+
+static void ccix_upstream_port_write_config(PCIDevice *d, uint32_t address,
+                                            uint32_t val, int len)
+{
+    CCIXUpPortState *s = CCIX_UP_DEV(d);
+    pci_bridge_write_config(d, address, val, len);
+    pcie_cap_flr_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 xio3130_upstream_reset(DeviceState *qdev)
+{
+    PCIDevice *d = PCI_DEVICE(qdev);
+
+    pci_bridge_reset(qdev);
+    pcie_cap_deverr_reset(d);
+}
+
+static void ccix_upstream_port_realize(PCIDevice *d, Error **errp)
+{
+    CCIXUpPortState *s = CCIX_UP_DEV(d);
+    PCIEPort *p = PCIE_PORT(d);
+    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_UPSTREAM,
+                       p->port, errp);
+    if (rc < 0) {
+        goto err_msi;
+    }
+    pcie_cap_flr_init(d);
+    pcie_cap_deverr_init(d);
+
+    rc = pcie_aer_init(d, PCI_ERR_VER, XIO3130_AER_OFFSET,
+                       PCI_ERR_SIZEOF, errp);
+    if (rc < 0) {
+        goto err;
+    }
+    initialize_ccixstate(&s->s, d);
+    ccix_set_port(&s->s);
+    offset = ccix_add_prldvsec(d, &s->s, offset);
+    ccix_register(&s->s);
+
+    return;
+
+err:
+    pcie_cap_exit(d);
+err_msi:
+    msi_uninit(d);
+err_bridge:
+    pci_bridge_exitfn(d);
+}
+
+static Property ccix_props[] = {
+    DEFINE_PROP_STRING("ccix_device", CCIXUpPortState, s.ccix_dev_name),
+    DEFINE_PROP_BIT("primaryport", CCIXUpPortState, s.flags, PRIMARY_PORT_BIT, true),
+    DEFINE_PROP_UINT8("port_id", CCIXUpPortState, s.port_id, 0),
+    DEFINE_PROP_UINT8("num_links", CCIXUpPortState, s.num_links, 1),
+    DEFINE_PROP_UINT8("psam_entries", CCIXUpPortState, s.psam_entries, 0),
+    DEFINE_PROP_UINT8("request_agents", CCIXUpPortState, s.num_ras, 0),
+    DEFINE_PROP_UINT8("home_agents", CCIXUpPortState, s.num_has, 0),
+    DEFINE_PROP_UINT8("hsam_entries", CCIXUpPortState, s.hsam_entries, 0),
+    DEFINE_PROP_UINT8("rsam_entries", CCIXUpPortState, s.rsam_entries, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ccix_upstream_exitfn(PCIDevice *d)
+{
+    pcie_aer_exit(d);
+    pcie_cap_exit(d);
+    msi_uninit(d);
+    pci_bridge_exitfn(d);
+}
+
+static const VMStateDescription vmstate_ccix_upstream = {
+    .name = "ccix-upstream-port",
+    .priority = MIG_PRI_PCI_BUS,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(parent_obj.parent_obj, PCIEPort),
+        VMSTATE_STRUCT(parent_obj.parent_obj.exp.aer_log, PCIEPort, 0,
+                       vmstate_pcie_aer_log, PCIEAERLog),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void ccix_upstream_port_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->is_bridge = true;
+    k->config_write = ccix_upstream_port_write_config;
+    k->realize = ccix_upstream_port_realize;
+    k->exit = ccix_upstream_exitfn;
+    k->vendor_id = PCI_VENDOR_ID_HUAWEI;
+    k->device_id = PCI_DEVICE_ID_HUAWEI_CCIX_UP;
+    k->revision = 1;
+    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+    dc->desc = "CCIX / PCIe switch upstream port";
+    dc->props = ccix_props;
+    dc->reset = xio3130_upstream_reset;
+    dc->vmsd = &vmstate_ccix_upstream;
+}
+
+static const TypeInfo ccix_upstream_port_info = {
+    .name = TYPE_CCIX_UP_PORT,
+    .parent = TYPE_PCIE_PORT,
+    .class_init = ccix_upstream_port_init,
+    .instance_size = sizeof(CCIXUpPortState),
+    .interfaces = (InterfaceInfo[]) {
+        { INTERFACE_PCIE_DEVICE },
+        { }
+    },
+};
+
+static void ccix_upstream_register_types(void)
+{
+    type_register_static(&ccix_upstream_port_info);
+}
+
+type_init(ccix_upstream_register_types)
-- 
2.20.1



^ permalink raw reply	[flat|nested] 11+ messages in thread

* [Qemu-devel] [RFC PATCH 5/7] pci-bridge: CCIX capable PCIE/CCIX switch downstream port
  2019-06-25 11:27 [Qemu-devel] [RFC PATCH 0/7] qemu: CCIX pcie config space emulation Jonathan Cameron
                   ` (3 preceding siblings ...)
  2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 4/7] pci-bridge: CCIX capable PCIE/CCIX switch upstream port Jonathan Cameron
@ 2019-06-25 11:27 ` Jonathan Cameron
  2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 6/7] misc: CCIX endpoint function Jonathan Cameron
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Jonathan Cameron @ 2019-06-25 11:27 UTC (permalink / raw)
  To: QEMU Developers
  Cc: Peter Maydell, jcm, linuxarm, Auger Eric, qemu-arm, Jonathan Cameron

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(-)

diff --git a/hw/pci-bridge/Makefile.objs b/hw/pci-bridge/Makefile.objs
index e266e39fed..78a49fb90b 100644
--- a/hw/pci-bridge/Makefile.objs
+++ b/hw/pci-bridge/Makefile.objs
@@ -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
diff --git a/hw/pci-bridge/ccix_downstream.c b/hw/pci-bridge/ccix_downstream.c
new file mode 100644
index 0000000000..92c66431e2
--- /dev/null
+++ b/hw/pci-bridge/ccix_downstream.c
@@ -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)
+    
-- 
2.20.1



^ permalink raw reply	[flat|nested] 11+ messages in thread

* [Qemu-devel] [RFC PATCH 6/7] misc: CCIX endpoint function
  2019-06-25 11:27 [Qemu-devel] [RFC PATCH 0/7] qemu: CCIX pcie config space emulation Jonathan Cameron
                   ` (4 preceding siblings ...)
  2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 5/7] pci-bridge: CCIX capable PCIE/CCIX switch downstream port Jonathan Cameron
@ 2019-06-25 11:27 ` Jonathan Cameron
  2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 7/7] Temp: Add to ARM64 makefiles for testing Jonathan Cameron
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Jonathan Cameron @ 2019-06-25 11:27 UTC (permalink / raw)
  To: QEMU Developers
  Cc: Peter Maydell, jcm, linuxarm, Auger Eric, qemu-arm, Jonathan Cameron

This handles the case where a given function is not also a
PCIe topology upstream or downstream port.

This include, non function 0 functions on upstream ports and
any function on a device without a PCIe switch.  Note that
this doesn't exclude the possibility of this being the upstream
port of a CCIX layer switch.

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 hw/misc/Kconfig       |   5 ++
 hw/misc/Makefile.objs |   1 +
 hw/misc/ccix-ep.c     | 112 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 118 insertions(+)

diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
index 385e1b0cec..7aba167999 100644
--- a/hw/misc/Kconfig
+++ b/hw/misc/Kconfig
@@ -118,3 +118,8 @@ config AUX
     select I2C
 
 source macio/Kconfig
+
+config CCIX_EP
+    bool
+    select CCIX_LIB
+    
\ No newline at end of file
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 77b9df9796..56a6cb3591 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -6,6 +6,7 @@ common-obj-$(CONFIG_ISA_DEBUG) += debugexit.o
 common-obj-$(CONFIG_SGA) += sga.o
 common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o
 common-obj-$(CONFIG_PCI_TESTDEV) += pci-testdev.o
+common-obj-$(CONFIG_CCIX_EP) += ccix-ep.o
 common-obj-$(CONFIG_EDU) += edu.o
 common-obj-$(CONFIG_PCA9552) += pca9552.o
 
diff --git a/hw/misc/ccix-ep.c b/hw/misc/ccix-ep.c
new file mode 100644
index 0000000000..40a5b22dd8
--- /dev/null
+++ b/hw/misc/ccix-ep.c
@@ -0,0 +1,112 @@
+/*
+ * CCIX EP configuration space test device
+ *
+ * Copyright (c) 2019 Huawei
+ * Author: Jonathan Cameron <Jonathan.Cameron@Huawei.com>
+ *
+ * Portions copied from pci-testdev.c
+ * Copyright (c) 2012 Red Hat Inc.
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ *
+ * 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/hw.h"
+#include "hw/pci/pci.h"
+#include "qemu/event_notifier.h"
+#include "sysemu/kvm.h"
+#include "hw/misc/ccix.h"
+#include "qemu/module.h"
+
+typedef struct CCIXEpState {
+    PCIDevice parent_obj;
+    struct CCIXState s;
+
+} CCIXEpState;
+
+#define TYPE_CCIX_EP "ccix-ep"
+#define CCIX_EP_DEV(obj) OBJECT_CHECK(CCIXEpState, (obj), TYPE_CCIX_EP)
+
+static void ccix_ep_write_config(PCIDevice *pci_dev, uint32_t addr,
+                                 uint32_t val_in, int l)
+{
+    CCIXEpState *s = CCIX_EP_DEV(pci_dev);
+
+    ccix_write_config(pci_dev, &s->s, addr, val_in, l); 
+    pci_default_write_config(pci_dev, addr, val_in, l);
+}
+
+static void ccix_ep_realize(PCIDevice *pci_dev, Error **errp)
+{
+    CCIXEpState *s = CCIX_EP_DEV(pci_dev);
+    int offset = PCI_CONFIG_SPACE_SIZE;
+
+    if (PCI_FUNC(pci_dev->devfn) == 0)
+        ccix_set_port(&s->s);
+    initialize_ccixstate(&s->s, pci_dev);
+    pci_dev->config_write = ccix_ep_write_config;
+    pcie_endpoint_cap_init(pci_dev, 0);
+    offset = ccix_add_prldvsec(pci_dev, &s->s, offset);
+    if (s->s.flags & (1 << CCIX_IS_PORT))
+        ccix_add_tdldvsec(pci_dev, offset);
+
+    pci_dev->config[PCI_INTERRUPT_PIN] = 0; /* no interrupt pin */
+    ccix_register(&s->s);
+}
+
+static Property ccix_props[] = {
+    DEFINE_PROP_STRING("ccix_device", CCIXEpState, s.ccix_dev_name),
+    DEFINE_PROP_BIT("primaryport", CCIXEpState, s.flags, PRIMARY_PORT_BIT, true),
+    DEFINE_PROP_UINT8("port_id", CCIXEpState, s.port_id, 0),
+    DEFINE_PROP_UINT8("num_links", CCIXEpState, s.num_links, 1),
+    DEFINE_PROP_UINT8("psam_entries", CCIXEpState, s.psam_entries, 0),
+    DEFINE_PROP_UINT8("request_agents", CCIXEpState, s.num_ras, 0),
+    DEFINE_PROP_UINT8("home_agents", CCIXEpState, s.num_has, 0),
+    DEFINE_PROP_UINT8("hsam_entries", CCIXEpState, s.hsam_entries, 0),
+    DEFINE_PROP_UINT8("rsam_entries", CCIXEpState, s.rsam_entries, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ccix_ep_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->realize = ccix_ep_realize;
+    k->vendor_id = PCI_VENDOR_ID_HUAWEI;
+    k->device_id = PCI_DEVICE_ID_HUAWEI_CCIX_EP;
+    k->revision = 0x00;
+    k->class_id = PCI_CLASS_OTHERS;
+    dc->desc = "CCIX EP Test Device";
+    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+    dc->props = ccix_props;
+}
+
+static const TypeInfo ccix_ep_info = {
+    .name          = TYPE_CCIX_EP,
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(CCIXEpState),
+    .class_init    = ccix_ep_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { INTERFACE_PCIE_DEVICE },
+        { },
+    },
+};
+
+static void ccix_register_types(void)
+{
+    type_register_static(&ccix_ep_info);
+}
+
+type_init(ccix_register_types)
-- 
2.20.1



^ permalink raw reply	[flat|nested] 11+ messages in thread

* [Qemu-devel] [RFC PATCH 7/7] Temp: Add to ARM64 makefiles for testing
  2019-06-25 11:27 [Qemu-devel] [RFC PATCH 0/7] qemu: CCIX pcie config space emulation Jonathan Cameron
                   ` (5 preceding siblings ...)
  2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 6/7] misc: CCIX endpoint function Jonathan Cameron
@ 2019-06-25 11:27 ` Jonathan Cameron
  2019-08-06 11:19 ` [Qemu-devel] [RFC PATCH 0/7] qemu: CCIX pcie config space emulation Jonathan Cameron
  2019-08-16 12:59 ` Peter Maydell
  8 siblings, 0 replies; 11+ messages in thread
From: Jonathan Cameron @ 2019-06-25 11:27 UTC (permalink / raw)
  To: QEMU Developers
  Cc: Peter Maydell, jcm, linuxarm, Auger Eric, qemu-arm, Jonathan Cameron

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 default-configs/arm-softmmu.mak | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 3158e1a10a..d5d4c8ecf1 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -41,4 +41,5 @@ CONFIG_FSL_IMX7=y
 CONFIG_FSL_IMX6UL=y
 CONFIG_SEMIHOSTING=y
 CONFIG_ACPI_APEI=y
-
+CONFIG_CCIX_LIB=y
+CONFIG_CCIX_EP=y
\ No newline at end of file
-- 
2.20.1



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 0/7] qemu: CCIX pcie config space emulation
  2019-06-25 11:27 [Qemu-devel] [RFC PATCH 0/7] qemu: CCIX pcie config space emulation Jonathan Cameron
                   ` (6 preceding siblings ...)
  2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 7/7] Temp: Add to ARM64 makefiles for testing Jonathan Cameron
@ 2019-08-06 11:19 ` Jonathan Cameron
  2019-08-16 12:59 ` Peter Maydell
  8 siblings, 0 replies; 11+ messages in thread
From: Jonathan Cameron @ 2019-08-06 11:19 UTC (permalink / raw)
  To: QEMU Developers; +Cc: Peter Maydell, qemu-arm, linuxarm, jcm, Auger Eric

For reference alongside this patch set.

Evaluation version of the CCIX 1.0a base specification now available,
(though there is a form to complete and license agreement)..

https://www.ccixconsortium.com/ccix-library/download-form/

Thanks,

Jonathan

On Tue, 25 Jun 2019 19:27:45 +0800
Jonathan Cameron <Jonathan.Cameron@huawei.com> wrote:

> CCIX topologies are 'layered' on top of PCIe tree topologies.
> This is done primarily by allowing a single CCIX device to appear as
> multiple disjoint nodes in the PCIe tree.
> 
> This layering is described via extensive PCIe DVSEC extended
> capabilities in PCIe config space across all the functions that
> are present in the device (some placement rules apply).
> 
> The extremely flexible nature of allowed topologies makes the
> development of generic firmware and OS software difficult if we rely
> on actual hardware setups, due to the large test set that is necessary.
> 
> To enable the ongoing work on EDK2 and within the Linux kernel and
> userspace, this series provides the bare bones of what is necessary
> to be able to test 'configuration' of a CCIX topology.  Note
> that no actual CCIX data flow is being emulated within this patchset,
> merely a substantial subset of the interface that allows the topologies
> to be configured.  Testing has to rely on verification based on
> the result rather than true emulation of the coherency protocol.
> (that is a very different form of emulation for which other tools
> are perhaps better suited).
> 
> For information on how to do the coherency protocol configuration,
> see the forthcoming CCIX SW guide, in conjunction with the CCIX 1.0
> Base Specification.
> 
> An example of a 2x2 mesh with a spur to the host can be run with:
> 
> qemu-system-aarch64 -M virt -m 1024 -cpu cortex-a53 \
> ...
>  -device ioh3420,id=root_port1 \
>  -device ccix-upstream-port,num_links=4,primaryport=true,rsam_entries=4,ccix_device="ccix_dev1",bus=root_port1,addr=0.0,multifunction="on",id=up0,port_id=0 \
>  -device ccix-downstream-port,ccix_device="ccix_dev1",bus=up0,slot=0,chassis=2,id=bus_top,port_id=1 \
>  -device ccix-downstream-port,ccix_device="ccix_dev1",bus=up0,slot=1,chassis=2,id=bus_left,port_id=2 \
>  -device ccix-ep,primaryport=false,home_agents=1,request_agents=1,ccix_device="ccix_dev1",bus=root_port1,addr=0.1,multifunction="on" \
>  -device ccix-upstream-port,num_links=4,primaryport=true,rsam_entries=4,ccix_device="ccix_dev2",bus=bus_top,addr=0.0,multifunction="on",id=up1,port_id=0 \
>  -device ccix-downstream-port,ccix_device="ccix_dev2",bus=up1,slot=0,chassis=3,id=bus_right,port_id=1 \
>  -device ccix-ep,primaryport=false,request_agents=2,ccix_device="ccix_dev2",bus=bus_top,addr=0.1,multifunction="on" \
>  -device ccix-upstream-port,num_links=4,primaryport=true,rsam_entries=4,ccix_device="ccix_dev3",bus=bus_left,addr=0.0,multifunction="on",id=up2,port_id=0 \
>  -device ccix-downstream-port,ccix_device="ccix_dev3",bus=up2,slot=0,chassis=4,id=bus_bottom,port_id=1,multifunciton="on" \
>  -device ccix-ep,primaryport=false,request_agents=2,ccix_device="ccix_dev3",bus=bus_left,addr=0.1,multifunction="on" \
>  -device ccix-ep,primaryport=true,request_agents=2,ccix_device="ccix_dev4",bus=bus_right,addr=0.0,port_id=0 \
>  -device ccix-ep,primaryport=true,request_agents=2,ccix_device="ccix_dev4",bus=bus_bottom,addr=0.0,port_id=1
> 
> 
> I'm not going to try drawing all the detail (it's bad enough
> trying to draw these in inkscape, but in a very much simplifed
> fashion, this generates.
> 
> -----------------
> |     Host      |
> |               | 
> --- root_port1--
>         |
>         |
>         v
> -----------------          ---------------
> |  ccix_dev1    | -------> |  ccix_dev2  |
> -----------------          ---------------
>         |                         |
>         V                         V
> -----------------          ---------------
> |  ccix_dev3    | -------> |  ccix_dev4  |
> -----------------          ---------------
> 
> $lspci -t
> -[0000:00]-+-00.0
>            +-01.0-[01-08]--+-00.0-[02-08]--+-00.0-[03-05]--+-00.0-[04-05]----00.0-[05]----00.0
>                            |               |               |               \-00.1
>                            |               |               \-01.0-[06-08]--+-00.0-[07-08]----00.0-[08]----00.0
>                            |               |                               \-00.1
>                            |               \-00.1
> 						       
> RFC questions:
> 
> 1.  The nature of CCIX devices is that we need to extend normal
>     PCI devices, slots, and ports.  I could not find an elegant way of
>     doing this without lots of code replication.  The current solution
>     just exposes some internal functions from xio3130 port implementations.
>     Is there a better way to do this?
> 
> 2.  The association of the different PCIDevices to a given CCIX device is
>     currently somewhat of a hack. Can anyone suggest a cleaner solution
>     for this?  I can improved the current implementation, but don't really
>     like that we basically search for all the parts whenever a cross
>     device implementation is needed.
> 
> 3.  Is emulation via a large number of PCIe devices like this a good
>     approach or is there a nicer way to handle it?  Given we need to
>     be able to 'spread' the CCIX device configuration across multiple
>     PCIe functions anyway perhaps this is the most sensible approach.
> 
> 4.  I've cut and paste a 100+ lines of code from each of the xio3130_*
>     modules as we are also implemening PCIE up and downstream ports
>     and as this is a emulation only device, we might as well use the
>     same register set.  There are various possible ways to avoid this:
>     * Add a library with the shared code in it.
>     * Add an xio3130_upstream.h header and similar to allow the CCIX
>       port modules to call those functions directly.
>     * Don't worry about the replication in the interests of keeping
>       the code structure simple.
> 
> 5.  I'm not that familiar with qemu 'style' yet, so pointers on structures
>     to use etc most welcome.
> 
> Note that not all elements of CCIX are supported by the current implementation,
> for example slave agents and error records are missing.  These will follow
> either in later revisions or as follow patches.  We also have no actual
> accelerator functions in the current design and hence no mapping to RAs.
> 
> Only a subset of configuration constraints are currently implemented.
> This will want tightenning up in future.
> 
> As we don't have any actual chunks of the spec in here so I haven't
> added the statement from the trademark grant that follows.
> 
> Thanks,
> 
> Jonathan
> 
> This patch is being distributed by the CCIX Consortium, Inc. (CCIX) to
> you and other parties that are paticipating (the "participants") in
> qemu with the understanding that the participants will use CCIX's
> name and trademark only when this patch is used in association with
> qemu.
> 
> CCIX is also distributing this patch to these participants with the
> understanding that if any portion of the CCIX specification will be
> used or referenced in qemu, the participants will not modify the cited
> portion of the CCIX specification and will give CCIX propery copyright
> attribution by including the following copyright notice with
> the cited part of the CCIX specification:
> "© 2019 CCIX CONSORTIUM, INC. ALL RIGHTS RESERVED."
> 
> Jonathan Cameron (7):
>   Temp: Add the PCI_EXT_ID_DVSEC definition to the qemu pci_regs.h copy.
>   pci: Add Huawei vendor ID and Huawei Emulated CCIX Device IDs.
>   pci: CCIX config space emulation library.
>   pci-bridge: CCIX capable PCIE/CCIX switch upstream port.
>   pci-bridge: CCIX capable PCIE/CCIX switch downstream port
>   misc: CCIX endpoint function
>   Temp: Add to ARM64 makefiles for testing
> 
>  default-configs/arm-softmmu.mak           |    3 +-
>  hw/misc/Kconfig                           |    5 +
>  hw/misc/Makefile.objs                     |    1 +
>  hw/misc/ccix-ep.c                         |  112 ++
>  hw/pci-bridge/Kconfig                     |    5 +
>  hw/pci-bridge/Makefile.objs               |    1 +
>  hw/pci-bridge/ccix_downstream.c           |  222 ++++
>  hw/pci-bridge/ccix_upstream.c             |  197 ++++
>  hw/pci/Kconfig                            |    3 +
>  hw/pci/Makefile.objs                      |    1 +
>  hw/pci/ccix_lib.c                         | 1299 +++++++++++++++++++++
>  include/hw/misc/ccix.h                    |   28 +
>  include/hw/pci/pci_ids.h                  |    7 +
>  include/standard-headers/linux/pci_regs.h |    3 +-
>  14 files changed, 1885 insertions(+), 2 deletions(-)
>  create mode 100644 hw/misc/ccix-ep.c
>  create mode 100644 hw/pci-bridge/ccix_downstream.c
>  create mode 100644 hw/pci-bridge/ccix_upstream.c
>  create mode 100644 hw/pci/ccix_lib.c
>  create mode 100644 include/hw/misc/ccix.h
> 




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 0/7] qemu: CCIX pcie config space emulation
  2019-06-25 11:27 [Qemu-devel] [RFC PATCH 0/7] qemu: CCIX pcie config space emulation Jonathan Cameron
                   ` (7 preceding siblings ...)
  2019-08-06 11:19 ` [Qemu-devel] [RFC PATCH 0/7] qemu: CCIX pcie config space emulation Jonathan Cameron
@ 2019-08-16 12:59 ` Peter Maydell
  2019-08-19  9:47   ` Jonathan Cameron
  8 siblings, 1 reply; 11+ messages in thread
From: Peter Maydell @ 2019-08-16 12:59 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Auger Eric, qemu-arm, Linuxarm, QEMU Developers, Jon Masters

On Tue, 25 Jun 2019 at 12:28, Jonathan Cameron
<Jonathan.Cameron@huawei.com> wrote:
>
> CCIX topologies are 'layered' on top of PCIe tree topologies.
> This is done primarily by allowing a single CCIX device to appear as
> multiple disjoint nodes in the PCIe tree.

> This patch is being distributed by the CCIX Consortium, Inc. (CCIX) to
> you and other parties that are paticipating (the "participants") in
> qemu with the understanding that the participants will use CCIX's
> name and trademark only when this patch is used in association with
> qemu.
>
> CCIX is also distributing this patch to these participants with the
> understanding that if any portion of the CCIX specification will be
> used or referenced in qemu, the participants will not modify the cited
> portion of the CCIX specification and will give CCIX propery copyright
> attribution by including the following copyright notice with
> the cited part of the CCIX specification:
> "© 2019 CCIX CONSORTIUM, INC. ALL RIGHTS RESERVED."

(Apologies for replying to this now quite old email, but your
more recent followup email drew it to my attention.)

I think that as a project, QEMU can't take patches which come
with this kind of additional constraint on top of the GPL. Could
you drop these extra legal clauses, please?

thanks
-- PMM


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [Qemu-devel] [RFC PATCH 0/7] qemu: CCIX pcie config space emulation
  2019-08-16 12:59 ` Peter Maydell
@ 2019-08-19  9:47   ` Jonathan Cameron
  0 siblings, 0 replies; 11+ messages in thread
From: Jonathan Cameron @ 2019-08-19  9:47 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Auger Eric, qemu-arm, Linuxarm, QEMU Developers, Jon Masters

On Fri, 16 Aug 2019 13:59:02 +0100
Peter Maydell <peter.maydell@linaro.org> wrote:

> On Tue, 25 Jun 2019 at 12:28, Jonathan Cameron
> <Jonathan.Cameron@huawei.com> wrote:
> >
> > CCIX topologies are 'layered' on top of PCIe tree topologies.
> > This is done primarily by allowing a single CCIX device to appear as
> > multiple disjoint nodes in the PCIe tree.  
> 
> > This patch is being distributed by the CCIX Consortium, Inc. (CCIX) to
> > you and other parties that are paticipating (the "participants") in
> > qemu with the understanding that the participants will use CCIX's
> > name and trademark only when this patch is used in association with
> > qemu.
> >
> > CCIX is also distributing this patch to these participants with the
> > understanding that if any portion of the CCIX specification will be
> > used or referenced in qemu, the participants will not modify the cited
> > portion of the CCIX specification and will give CCIX propery copyright
> > attribution by including the following copyright notice with
> > the cited part of the CCIX specification:
> > "© 2019 CCIX CONSORTIUM, INC. ALL RIGHTS RESERVED."  
> 
> (Apologies for replying to this now quite old email, but your
> more recent followup email drew it to my attention.)
> 
> I think that as a project, QEMU can't take patches which come
> with this kind of additional constraint on top of the GPL. Could
> you drop these extra legal clauses, please?

Jon, if you could raise this with CCIX legal that would be great.

Thanks,

Jonathan
 
> 
> thanks
> -- PMM




^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, back to index

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-25 11:27 [Qemu-devel] [RFC PATCH 0/7] qemu: CCIX pcie config space emulation Jonathan Cameron
2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 1/7] Temp: Add the PCI_EXT_ID_DVSEC definition to the qemu pci_regs.h copy Jonathan Cameron
2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 2/7] pci: Add Huawei vendor ID and Huawei Emulated CCIX Device IDs Jonathan Cameron
2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 3/7] pci: CCIX config space emulation library Jonathan Cameron
2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 4/7] pci-bridge: CCIX capable PCIE/CCIX switch upstream port Jonathan Cameron
2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 5/7] pci-bridge: CCIX capable PCIE/CCIX switch downstream port Jonathan Cameron
2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 6/7] misc: CCIX endpoint function Jonathan Cameron
2019-06-25 11:27 ` [Qemu-devel] [RFC PATCH 7/7] Temp: Add to ARM64 makefiles for testing Jonathan Cameron
2019-08-06 11:19 ` [Qemu-devel] [RFC PATCH 0/7] qemu: CCIX pcie config space emulation Jonathan Cameron
2019-08-16 12:59 ` Peter Maydell
2019-08-19  9:47   ` Jonathan Cameron

QEMU-Devel Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/qemu-devel/0 qemu-devel/git/0.git
	git clone --mirror https://lore.kernel.org/qemu-devel/1 qemu-devel/git/1.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 qemu-devel qemu-devel/ https://lore.kernel.org/qemu-devel \
		qemu-devel@nongnu.org
	public-inbox-index qemu-devel

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.nongnu.qemu-devel


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git