@@ -17,6 +17,7 @@
#include <skiboot.h>
#include <pci.h>
#include <pci-virt.h>
+#include <pci-slot.h>
void pci_virt_cfg_read_raw(struct pci_virt_device *pvd,
uint32_t space, uint32_t offset,
@@ -217,6 +218,35 @@ out:
return OPAL_SUCCESS;
}
+#define PCI_VIRT_CFG_READ(size, type) \
+int64_t pci_virt_cfg_read##size(struct phb *phb, uint32_t bdfn, \
+ uint32_t offset, type *data) \
+{ \
+ uint32_t val; \
+ int64_t ret; \
+ \
+ ret = pci_virt_cfg_read(phb, bdfn, offset, sizeof(*data), &val); \
+ *data = (type)val; \
+ return ret; \
+}
+
+#define PCI_VIRT_CFG_WRITE(size, type) \
+int64_t pci_virt_cfg_write##size(struct phb *phb, uint32_t bdfn, \
+ uint32_t offset, type data) \
+{ \
+ uint32_t val = data; \
+ \
+ return pci_virt_cfg_write(phb, bdfn, offset, sizeof(data), val); \
+}
+
+PCI_VIRT_CFG_READ(8, u8);
+PCI_VIRT_CFG_READ(16, u16);
+PCI_VIRT_CFG_READ(32, u32);
+PCI_VIRT_CFG_WRITE(8, u8);
+PCI_VIRT_CFG_WRITE(16, u16);
+PCI_VIRT_CFG_WRITE(32, u32);
+
+
struct pci_virt_device *pci_virt_add_device(struct phb *phb, uint32_t bdfn,
uint32_t cfg_size, void *data)
{
@@ -263,3 +293,60 @@ struct pci_virt_device *pci_virt_add_device(struct phb *phb, uint32_t bdfn,
return pvd;
}
+
+/* dummy slot management */
+
+static int64_t virt_get_link_state(struct pci_slot *slot __unused, uint8_t *val)
+{
+ /*
+ * As we're emulating all PCI stuff, the link bandwidth
+ * isn't big deal anyway.
+ */
+ *val = OPAL_SHPC_LINK_UP_x1;
+ return OPAL_SUCCESS;
+}
+
+static int64_t virt_get_power_state(struct pci_slot *slot __unused, uint8_t *val)
+{
+ *val = PCI_SLOT_POWER_ON;
+ return OPAL_SUCCESS;
+}
+
+static int64_t virt_hreset(struct pci_slot *slot __unused)
+{
+ return OPAL_SUCCESS;
+}
+
+static int64_t virt_freset(struct pci_slot *slot __unused)
+{
+ /* FIXME: PHB fundamental reset, which need to be
+ * figured out later. It's used by EEH recovery
+ * upon fenced AT.
+ */
+ return OPAL_SUCCESS;
+}
+
+struct pci_slot *virt_slot_create(struct phb *phb)
+{
+ struct pci_slot *slot;
+
+ slot = pci_slot_alloc(phb, NULL);
+ if (!slot)
+ return slot;
+
+ /* Elementary functions */
+ slot->ops.get_presence_state = NULL;
+ slot->ops.get_link_state = virt_get_link_state;
+ slot->ops.get_power_state = virt_get_power_state;
+ slot->ops.get_attention_state = NULL;
+ slot->ops.get_latch_state = NULL;
+ slot->ops.set_power_state = NULL;
+ slot->ops.set_attention_state = NULL;
+ slot->ops.prepare_link_change = NULL;
+ slot->ops.poll_link = NULL;
+ slot->ops.hreset = virt_hreset;
+ slot->ops.freset = virt_freset;
+ slot->ops.creset = NULL;
+
+ return slot;
+}
@@ -311,33 +311,6 @@ static struct npu_dev *bdfn_to_npu_dev(struct npu *p, uint32_t bdfn)
return NULL;
}
-#define NPU_CFG_READ(size, type) \
-static int64_t npu_cfg_read##size(struct phb *phb, uint32_t bdfn, \
- uint32_t offset, type *data) \
-{ \
- uint32_t val; \
- int64_t ret; \
- \
- ret = pci_virt_cfg_read(phb, bdfn, offset, sizeof(*data), &val); \
- *data = (type)val; \
- return ret; \
-}
-#define NPU_CFG_WRITE(size, type) \
-static int64_t npu_cfg_write##size(struct phb *phb, uint32_t bdfn, \
- uint32_t offset, type data) \
-{ \
- uint32_t val = data; \
- \
- return pci_virt_cfg_write(phb, bdfn, offset, sizeof(data), val); \
-}
-
-NPU_CFG_READ(8, u8);
-NPU_CFG_READ(16, u16);
-NPU_CFG_READ(32, u32);
-NPU_CFG_WRITE(8, u8);
-NPU_CFG_WRITE(16, u16);
-NPU_CFG_WRITE(32, u32);
-
/*
* Locate the real PCI device targeted by this NVlink by matching devices
* against slots.
@@ -742,63 +715,6 @@ static int64_t npu_set_pe(struct phb *phb,
return OPAL_SUCCESS;
}
-static int64_t npu_get_link_state(struct pci_slot *slot __unused, uint8_t *val)
-{
- /* As we're emulating all PCI stuff, the link bandwidth
- * isn't big deal anyway.
- */
- *val = OPAL_SHPC_LINK_UP_x1;
- return OPAL_SUCCESS;
-}
-
-static int64_t npu_get_power_state(struct pci_slot *slot __unused, uint8_t *val)
-{
- *val = PCI_SLOT_POWER_ON;
- return OPAL_SUCCESS;
-}
-
-static int64_t npu_hreset(struct pci_slot *slot __unused)
-{
- prlog(PR_DEBUG, "NPU: driver should call reset procedure here\n");
-
- return OPAL_SUCCESS;
-}
-
-static int64_t npu_freset(struct pci_slot *slot __unused)
-{
- /* FIXME: PHB fundamental reset, which need to be
- * figured out later. It's used by EEH recovery
- * upon fenced AT.
- */
- return OPAL_SUCCESS;
-}
-
-static struct pci_slot *npu_slot_create(struct phb *phb)
-{
- struct pci_slot *slot;
-
- slot = pci_slot_alloc(phb, NULL);
- if (!slot)
- return slot;
-
- /* Elementary functions */
- slot->ops.get_presence_state = NULL;
- slot->ops.get_link_state = npu_get_link_state;
- slot->ops.get_power_state = npu_get_power_state;
- slot->ops.get_attention_state = NULL;
- slot->ops.get_latch_state = NULL;
- slot->ops.set_power_state = NULL;
- slot->ops.set_attention_state = NULL;
-
- slot->ops.prepare_link_change = NULL;
- slot->ops.poll_link = NULL;
- slot->ops.hreset = npu_hreset;
- slot->ops.freset = npu_freset;
- slot->ops.creset = NULL;
-
- return slot;
-}
-
static int64_t npu_freeze_status(struct phb *phb,
uint64_t pe_number __unused,
uint8_t *freeze_state,
@@ -908,12 +824,12 @@ static int64_t npu_err_inject(struct phb *phb, uint64_t pe_number,
}
static const struct phb_ops npu_ops = {
- .cfg_read8 = npu_cfg_read8,
- .cfg_read16 = npu_cfg_read16,
- .cfg_read32 = npu_cfg_read32,
- .cfg_write8 = npu_cfg_write8,
- .cfg_write16 = npu_cfg_write16,
- .cfg_write32 = npu_cfg_write32,
+ .cfg_read8 = pci_virt_cfg_read8,
+ .cfg_read16 = pci_virt_cfg_read16,
+ .cfg_read32 = pci_virt_cfg_read32,
+ .cfg_write8 = pci_virt_cfg_write8,
+ .cfg_write16 = pci_virt_cfg_write16,
+ .cfg_write32 = pci_virt_cfg_write32,
.choose_bus = NULL,
.get_reserved_pe_number = NULL,
.device_init = NULL,
@@ -1581,7 +1497,7 @@ static void npu_create_phb(struct dt_node *dn)
npu_add_phb_properties(p);
/* Create PHB slot */
- slot = npu_slot_create(&p->phb);
+ slot = virt_slot_create(&p->phb);
if (!slot)
{
/**
@@ -374,37 +374,6 @@ static int64_t npu2_dev_cfg_bar(void *dev, struct pci_cfg_reg_filter *pcrf,
return npu2_cfg_read_bar(ndev, pcrf, offset, len, data);
}
-#define NPU2_CFG_READ(size, type) \
-static int64_t npu2_cfg_read##size(struct phb *phb, uint32_t bdfn, \
- uint32_t offset, type *data) \
-{ \
- uint32_t val; \
- int64_t ret; \
- \
- ret = pci_virt_cfg_read(phb, bdfn, offset, \
- sizeof(*data), &val); \
- *data = (type)val; \
- return ret; \
-}
-#define NPU2_CFG_WRITE(size, type) \
-static int64_t npu2_cfg_write##size(struct phb *phb, uint32_t bdfn, \
- uint32_t offset, type data) \
-{ \
- uint32_t val = data; \
- int64_t ret; \
- \
- ret = pci_virt_cfg_write(phb, bdfn, offset, \
- sizeof(data), val); \
- return ret; \
-}
-
-NPU2_CFG_READ(8, u8);
-NPU2_CFG_READ(16, u16);
-NPU2_CFG_READ(32, u32);
-NPU2_CFG_WRITE(8, u8);
-NPU2_CFG_WRITE(16, u16);
-NPU2_CFG_WRITE(32, u32);
-
static struct dt_node *npu2_create_memory_dn(uint64_t addr, uint64_t size)
{
struct dt_node *mem;
@@ -892,58 +861,6 @@ static int64_t npu2_set_pe(struct phb *phb,
return OPAL_SUCCESS;
}
-static int64_t npu2_get_link_state(struct pci_slot *slot __unused, uint8_t *val)
-{
- /*
- * As we're emulating all PCI stuff, the link bandwidth
- * isn't big deal anyway.
- */
- *val = OPAL_SHPC_LINK_UP_x1;
- return OPAL_SUCCESS;
-}
-
-static int64_t npu2_get_power_state(struct pci_slot *slot __unused, uint8_t *val)
-{
- *val = PCI_SLOT_POWER_ON;
- return OPAL_SUCCESS;
-}
-
-static int64_t npu2_hreset(struct pci_slot *slot __unused)
-{
- return OPAL_SUCCESS;
-}
-
-static int64_t npu2_freset(struct pci_slot *slot __unused)
-{
- return OPAL_SUCCESS;
-}
-
-static struct pci_slot *npu2_slot_create(struct phb *phb)
-{
- struct pci_slot *slot;
-
- slot = pci_slot_alloc(phb, NULL);
- if (!slot)
- return slot;
-
- /* Elementary functions */
- slot->ops.get_presence_state = NULL;
- slot->ops.get_link_state = npu2_get_link_state;
- slot->ops.get_power_state = npu2_get_power_state;
- slot->ops.get_attention_state = NULL;
- slot->ops.get_latch_state = NULL;
- slot->ops.set_power_state = NULL;
- slot->ops.set_attention_state = NULL;
-
- slot->ops.prepare_link_change = NULL;
- slot->ops.poll_link = NULL;
- slot->ops.hreset = npu2_hreset;
- slot->ops.freset = npu2_freset;
- slot->ops.creset = NULL;
-
- return slot;
-}
-
static int64_t npu2_freeze_status(struct phb *phb __unused,
uint64_t pe_number __unused,
uint8_t *freeze_state,
@@ -1003,12 +920,12 @@ static int64_t npu2_tce_kill(struct phb *phb, uint32_t kill_type,
}
static const struct phb_ops npu_ops = {
- .cfg_read8 = npu2_cfg_read8,
- .cfg_read16 = npu2_cfg_read16,
- .cfg_read32 = npu2_cfg_read32,
- .cfg_write8 = npu2_cfg_write8,
- .cfg_write16 = npu2_cfg_write16,
- .cfg_write32 = npu2_cfg_write32,
+ .cfg_read8 = pci_virt_cfg_read8,
+ .cfg_read16 = pci_virt_cfg_read16,
+ .cfg_read32 = pci_virt_cfg_read32,
+ .cfg_write8 = pci_virt_cfg_write8,
+ .cfg_write16 = pci_virt_cfg_write16,
+ .cfg_write32 = pci_virt_cfg_write32,
.choose_bus = NULL,
.device_init = NULL,
.phb_final_fixup = npu2_phb_final_fixup,
@@ -1525,7 +1442,7 @@ static void npu2_create_phb(struct dt_node *dn)
npu2_populate_devices(p, dn);
npu2_add_phb_properties(p);
- slot = npu2_slot_create(&p->phb);
+ slot = virt_slot_create(&p->phb);
if (!slot)
{
/**
@@ -59,7 +59,34 @@ extern struct pci_virt_device *pci_virt_add_device(struct phb *phb,
uint32_t cfg_size,
void *data);
-/* Config space accessors */
+/*
+ * The virtual config spaces is made up of three arrays (spaces) for:
+ *
+ * Normal
+ * Read only (RO)
+ * Write 1 to clear (W1C)
+ *
+ * The normal space is the "real" config space and if you read from it directly
+ * you will see the contents of the PCI config space. The other two come into
+ * play when writing. Writes are masked against the contents of the RO space
+ * to ensure that any bits that were marked as read only when the virtual config
+ * space was initialised will remain the same. The W1C space works similarly,
+ * with it's contents being used to generate a mask of bits to be cleared.
+ *
+ *
+ * Legend:
+ *
+ * d - struct pci_virt_device
+ * o - byte offset to read/write from
+ * s - Size of the config space IO (1/2/4)
+ * v - Value to write or the pointer to read into
+ *
+ * r - value to write into the RO space
+ * w - value to write into the W1C space
+ *
+ * In general, when setting up a config space use the PCI_VIRT_CFG_*_*() macros.
+ */
+
#define PCI_VIRT_CFG_NORMAL_RD(d, o, s, v) \
pci_virt_cfg_read_raw(d, PCI_VIRT_CFG_NORMAL, o, s, v)
#define PCI_VIRT_CFG_NORMAL_WR(d, o, s, v) \
@@ -82,4 +109,15 @@ extern struct pci_virt_device *pci_virt_add_device(struct phb *phb,
#define PCI_VIRT_CFG_INIT_RO(d, o, s, v) \
PCI_VIRT_CFG_INIT(d, o, s, v, 0xffffffff, 0)
+/* templates for use with virtual PHBs */
+int64_t pci_virt_cfg_read8(struct phb *, uint32_t, uint32_t, uint8_t *);
+int64_t pci_virt_cfg_read16(struct phb *, uint32_t, uint32_t, uint16_t *);
+int64_t pci_virt_cfg_read32(struct phb *, uint32_t, uint32_t, uint32_t *);
+
+int64_t pci_virt_cfg_write8(struct phb *, uint32_t, uint32_t, uint8_t);
+int64_t pci_virt_cfg_write16(struct phb *, uint32_t, uint32_t, uint16_t);
+int64_t pci_virt_cfg_write32(struct phb *, uint32_t, uint32_t, uint32_t);
+
+struct pci_slot *virt_slot_create(struct phb *phb);
+
#endif /* __VIRT_PCI_H */
Currently we only use the virtual PHB infrastructure for creating the emulated NVlink PHBs. As a result npu.c and npu2.c contain functionality useful for any virtual PHB which should really be generic code. This patch moves this functionality into pci-virt.c to reduce the duplication. Signed-off-by: Oliver O'Halloran <oohall@gmail.com> --- core/pci-virt.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++ hw/npu.c | 98 ++++-------------------------------------------------- hw/npu2.c | 97 ++++------------------------------------------------- include/pci-virt.h | 40 +++++++++++++++++++++- 4 files changed, 140 insertions(+), 182 deletions(-)