diff --git a/core/pci-virt.c b/core/pci-virt.c
index b531470bbae7..38c4fd745034 100644
--- a/core/pci-virt.c
+++ b/core/pci-virt.c
@@ -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;
+}
diff --git a/hw/npu.c b/hw/npu.c
index ad44a56000a2..31e54a7a2f0d 100644
--- a/hw/npu.c
+++ b/hw/npu.c
@@ -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.
@@ -737,63 +710,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,
@@ -903,12 +819,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,
@@ -1576,7 +1492,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)
 	{
 		/**
diff --git a/hw/npu2.c b/hw/npu2.c
index 9f83fd046c4c..67e595960ece 100644
--- a/hw/npu2.c
+++ b/hw/npu2.c
@@ -399,37 +399,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;
@@ -926,58 +895,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,
@@ -1037,12 +954,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,
@@ -1599,7 +1516,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)
 	{
 		/**
diff --git a/include/pci-virt.h b/include/pci-virt.h
index 7c787cf863a0..481d426011fc 100644
--- a/include/pci-virt.h
+++ b/include/pci-virt.h
@@ -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 */
