diff --git a/drivers/crypto/qat/qat_device.c b/drivers/crypto/qat/qat_device.c
index cdf4f7058..75af1e8bc 100644
--- a/drivers/crypto/qat/qat_device.c
+++ b/drivers/crypto/qat/qat_device.c
@@ -20,6 +20,10 @@ struct qat_gen_hw_data qp_gen_config[] =  {
 	},
 };
 
+
+static struct qat_pci_device qat_pci_devices[QAT_MAX_PCI_DEVICES];
+static int qat_nb_pci_devices;
+
 int qat_dev_config(__rte_unused struct rte_cryptodev *dev,
 		__rte_unused struct rte_cryptodev_config *config)
 {
@@ -72,3 +76,126 @@ void qat_dev_info_get(struct rte_cryptodev *dev,
 		info->pci_dev = RTE_DEV_TO_PCI(dev->device);
 	}
 }
+
+
+static struct qat_pci_device *
+qat_pci_get_dev(uint8_t dev_id)
+{
+	return &qat_pci_devices[dev_id];
+}
+static struct qat_pci_device *
+qat_pci_get_named_dev(const char *name)
+{
+	struct qat_pci_device *dev;
+	unsigned int i;
+
+	if (name == NULL)
+		return NULL;
+
+	for (i = 0; i < QAT_MAX_PCI_DEVICES; i++) {
+		dev = &qat_pci_devices[i];
+
+		if ((dev->attached == QAT_ATTACHED) &&
+				(strcmp(dev->name, name) == 0))
+			return dev;
+	}
+
+	return NULL;
+}
+
+static uint8_t
+qat_pci_find_free_device_index(void)
+{
+	uint8_t dev_id;
+
+	for (dev_id = 0; dev_id < QAT_MAX_PCI_DEVICES; dev_id++) {
+		if (qat_pci_devices[dev_id].attached == QAT_DETACHED)
+			break;
+	}
+	return dev_id;
+}
+
+struct qat_pci_device *
+qat_get_qat_dev_from_pci_dev(struct rte_pci_device *pci_dev)
+{
+	char name[QAT_DEV_NAME_MAX_LEN];
+
+	rte_pci_device_name(&pci_dev->addr, name, sizeof(name));
+
+	return qat_pci_get_named_dev(name);
+}
+
+struct qat_pci_device *
+qat_pci_device_allocate(struct rte_pci_device *pci_dev)
+{
+	struct qat_pci_device *qat_dev;
+	uint8_t qat_dev_id;
+	char name[QAT_DEV_NAME_MAX_LEN];
+
+	rte_pci_device_name(&pci_dev->addr, name, sizeof(name));
+
+	if (qat_pci_get_named_dev(name) != NULL) {
+		PMD_DRV_LOG(ERR, "QAT device with name %s already allocated!",
+				name);
+		return NULL;
+	}
+
+	qat_dev_id = qat_pci_find_free_device_index();
+	if (qat_dev_id == QAT_MAX_PCI_DEVICES) {
+		PMD_DRV_LOG(ERR, "Reached maximum number of QAT devices");
+		return NULL;
+	}
+
+	qat_dev = qat_pci_get_dev(qat_dev_id);
+	snprintf(qat_dev->name, QAT_DEV_NAME_MAX_LEN, "%s", name);
+	qat_dev->pci_dev = pci_dev;
+	switch (qat_dev->pci_dev->id.device_id) {
+	case 0x0443:
+		qat_dev->qat_dev_gen = QAT_GEN1;
+		break;
+	case 0x37c9:
+	case 0x19e3:
+	case 0x6f55:
+		qat_dev->qat_dev_gen = QAT_GEN2;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Invalid dev_id, can't determine generation");
+		return NULL;
+	}
+
+	rte_spinlock_init(&qat_dev->arb_csr_lock);
+
+	qat_dev->attached = QAT_ATTACHED;
+
+	qat_nb_pci_devices++;
+
+	PMD_DRV_LOG(DEBUG, "QAT device %d allocated, total QATs %d",
+				qat_dev_id, qat_nb_pci_devices);
+
+	return qat_dev;
+}
+
+int
+qat_pci_device_release(struct rte_pci_device *pci_dev)
+{
+	struct qat_pci_device *qat_dev;
+	char name[QAT_DEV_NAME_MAX_LEN];
+
+	if (pci_dev == NULL)
+		return -EINVAL;
+
+	rte_pci_device_name(&pci_dev->addr, name, sizeof(name));
+	qat_dev = qat_pci_get_named_dev(name);
+	if (qat_dev != NULL) {
+
+		/* Check that there are no service devs still on pci device */
+		if (qat_dev->sym_dev != NULL)
+			return -EBUSY;
+
+		qat_dev->attached = QAT_DETACHED;
+		qat_nb_pci_devices--;
+	}
+	PMD_DRV_LOG(DEBUG, "QAT device %s released, total QATs %d",
+				name, qat_nb_pci_devices);
+	return 0;
+}
diff --git a/drivers/crypto/qat/qat_device.h b/drivers/crypto/qat/qat_device.h
index 0983e3c2e..d83ad632c 100644
--- a/drivers/crypto/qat/qat_device.h
+++ b/drivers/crypto/qat/qat_device.h
@@ -11,15 +11,58 @@
 #include "adf_transport_access_macros.h"
 #include "qat_qp.h"
 
+
+#define QAT_DETACHED  (0)
+#define QAT_ATTACHED  (1)
+
+#define QAT_MAX_PCI_DEVICES	48
+#define QAT_DEV_NAME_MAX_LEN	64
+
+
 extern uint8_t cryptodev_qat_driver_id;
 
 extern int qat_sym_qp_release(struct rte_cryptodev *dev,
 	uint16_t queue_pair_id);
 
-/** private data structure for each QAT device.
- * In this context a QAT device is a device offering only one service,
- * so there can be more than 1 device on a pci_dev (VF),
- * one for symmetric crypto, one for compression
+/*
+ * This struct holds all the data about a QAT pci device
+ * including data about all services it supports.
+ * It contains
+ *  - hw_data
+ *  - config data
+ *  - runtime data
+ */
+struct qat_pci_device {
+
+	/* data used by all services */
+	char name[QAT_DEV_NAME_MAX_LEN];
+	/**< Name of qat pci device */
+	struct rte_pci_device *pci_dev;
+	/**< PCI information. */
+	enum qat_device_gen qat_dev_gen;
+	/**< QAT device generation */
+	rte_spinlock_t arb_csr_lock;
+	/* protects accesses to the arbiter CSR */
+	__extension__
+	uint8_t attached : 1;
+	/**< Flag indicating the device is attached */
+
+	/* data relating to symmetric crypto service */
+	struct qat_pmd_private *sym_dev;
+	/**< link back to cryptodev private data */
+	unsigned int max_nb_sym_queue_pairs;
+	/**< Max number of queue pairs supported by device */
+
+	/* data relating to compression service */
+
+	/* data relating to asymmetric crypto service */
+
+};
+
+/** private data structure for a QAT device.
+ * This QAT device is a device offering only symmetric crypto service,
+ * there can be one of these on each qat_pci_device (VF),
+ * in future there may also be private data structures for other services.
  */
 struct qat_pmd_private {
 	unsigned int max_nb_queue_pairs;
@@ -34,6 +77,8 @@ struct qat_pmd_private {
 	/**< PCI information. */
 	uint8_t dev_id;
 	/**< Device ID for this instance */
+	struct qat_pci_device *qat_dev;
+	/**< The qat pci device hosting the service */
 };
 
 struct qat_gen_hw_data {
@@ -51,4 +96,11 @@ int qat_dev_close(struct rte_cryptodev *dev);
 void qat_dev_info_get(struct rte_cryptodev *dev,
 	struct rte_cryptodev_info *info);
 
+struct qat_pci_device *
+qat_pci_device_allocate(struct rte_pci_device *pci_dev);
+int
+qat_pci_device_release(struct rte_pci_device *pci_dev);
+struct qat_pci_device *
+qat_get_qat_dev_from_pci_dev(struct rte_pci_device *pci_dev);
+
 #endif /* _QAT_DEVICE_H_ */
diff --git a/drivers/crypto/qat/rte_qat_cryptodev.c b/drivers/crypto/qat/rte_qat_cryptodev.c
index fe19b18b6..6ab870cad 100644
--- a/drivers/crypto/qat/rte_qat_cryptodev.c
+++ b/drivers/crypto/qat/rte_qat_cryptodev.c
@@ -69,17 +69,28 @@ static const struct rte_pci_id pci_id_qat_map[] = {
 		{.device_id = 0},
 };
 
+
+
 static int
-crypto_qat_create(const char *name, struct rte_pci_device *pci_dev,
-		struct rte_cryptodev_pmd_init_params *init_params)
+qat_sym_dev_create(struct qat_pci_device *qat_pci_dev)
 {
+	struct rte_cryptodev_pmd_init_params init_params = {
+			.name = "",
+			.socket_id = qat_pci_dev->pci_dev->device.numa_node,
+			.private_data_size = sizeof(struct qat_pmd_private),
+			.max_nb_sessions = RTE_QAT_PMD_MAX_NB_SESSIONS
+	};
+	char name[RTE_CRYPTODEV_NAME_MAX_LEN];
 	struct rte_cryptodev *cryptodev;
 	struct qat_pmd_private *internals;
 
-	PMD_INIT_FUNC_TRACE();
+	snprintf(name, RTE_CRYPTODEV_NAME_MAX_LEN, "%s_%s",
+			qat_pci_dev->name, "sym");
+	PMD_DRV_LOG(DEBUG, "Creating QAT SYM device %s", name);
+
+	cryptodev = rte_cryptodev_pmd_create(name,
+			&qat_pci_dev->pci_dev->device, &init_params);
 
-	cryptodev = rte_cryptodev_pmd_create(name, &pci_dev->device,
-			init_params);
 	if (cryptodev == NULL)
 		return -ENODEV;
 
@@ -95,7 +106,10 @@ crypto_qat_create(const char *name, struct rte_pci_device *pci_dev,
 			RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER;
 
 	internals = cryptodev->data->dev_private;
-	internals->max_nb_sessions = init_params->max_nb_sessions;
+	internals->qat_dev = qat_pci_dev;
+	qat_pci_dev->sym_dev = internals;
+
+	internals->max_nb_sessions = init_params.max_nb_sessions;
 	internals->pci_dev = RTE_DEV_TO_PCI(cryptodev->device);
 	internals->dev_id = cryptodev->data->dev_id;
 	switch (internals->pci_dev->id.device_id) {
@@ -111,68 +125,120 @@ crypto_qat_create(const char *name, struct rte_pci_device *pci_dev,
 		break;
 	default:
 		PMD_DRV_LOG(ERR,
-			"Invalid dev_id, can't determine capabilities");
+				"Invalid dev_id, can't determine capabilities");
 		break;
 	}
 
-	/*
-	 * For secondary processes, we don't initialise any further as primary
-	 * has already done this work. Only check we don't need a different
-	 * RX function
-	 */
-	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
-		PMD_DRV_LOG(DEBUG, "Device already initialised by primary process");
 		return 0;
-	}
+}
+
+static int
+qat_sym_dev_destroy(struct qat_pci_device *qat_pci_dev)
+{
+	struct rte_cryptodev *cryptodev;
+
+	if (qat_pci_dev == NULL)
+		return -ENODEV;
+	if (qat_pci_dev->sym_dev == NULL)
+		return 0;
+
+	/* free crypto device */
+	cryptodev = rte_cryptodev_pmd_get_dev(qat_pci_dev->sym_dev->dev_id);
+	rte_cryptodev_pmd_destroy(cryptodev);
+	qat_pci_dev->sym_dev = NULL;
+
+	return 0;
+}
+
+static int
+qat_comp_dev_create(struct qat_pci_device *qat_pci_dev __rte_unused)
+{
+	return 0;
+}
+
+static int
+qat_comp_dev_destroy(struct qat_pci_device *qat_pci_dev __rte_unused)
+{
+	return 0;
+}
 
+static int
+qat_asym_dev_create(struct qat_pci_device *qat_pci_dev __rte_unused)
+{
 	return 0;
 }
 
-static int crypto_qat_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+static int
+qat_asym_dev_destroy(struct qat_pci_device *qat_pci_dev __rte_unused)
+{
+	return 0;
+}
+
+static int
+qat_pci_dev_destroy(struct qat_pci_device *qat_pci_dev,
 		struct rte_pci_device *pci_dev)
 {
-	struct rte_cryptodev_pmd_init_params init_params = {
-		.name = "",
-		.socket_id = pci_dev->device.numa_node,
-		.private_data_size = sizeof(struct qat_pmd_private),
-		.max_nb_sessions = RTE_QAT_PMD_MAX_NB_SESSIONS
-	};
-	char name[RTE_CRYPTODEV_NAME_MAX_LEN];
+	qat_sym_dev_destroy(qat_pci_dev);
+	qat_comp_dev_destroy(qat_pci_dev);
+	qat_asym_dev_destroy(qat_pci_dev);
+	return qat_pci_device_release(pci_dev);
+}
+
+static int qat_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
+		struct rte_pci_device *pci_dev)
+{
+	int ret = 0;
+	struct qat_pci_device *qat_pci_dev;
 
 	PMD_DRV_LOG(DEBUG, "Found QAT device at %02x:%02x.%x",
 			pci_dev->addr.bus,
 			pci_dev->addr.devid,
 			pci_dev->addr.function);
 
-	rte_pci_device_name(&pci_dev->addr, name, sizeof(name));
+	qat_pci_dev = qat_pci_device_allocate(pci_dev);
+	if (qat_pci_dev == NULL)
+		return -ENODEV;
+
+	ret = qat_sym_dev_create(qat_pci_dev);
+	if (ret != 0)
+		goto error_out;
+
+	ret = qat_comp_dev_create(qat_pci_dev);
+	if (ret != 0)
+		goto error_out;
+
+	ret = qat_asym_dev_create(qat_pci_dev);
+	if (ret != 0)
+		goto error_out;
+
+	return 0;
+
+error_out:
+	qat_pci_dev_destroy(qat_pci_dev, pci_dev);
+	return ret;
 
-	return crypto_qat_create(name, pci_dev, &init_params);
 }
 
-static int crypto_qat_pci_remove(struct rte_pci_device *pci_dev)
+static int qat_pci_remove(struct rte_pci_device *pci_dev)
 {
-	struct rte_cryptodev *cryptodev;
-	char cryptodev_name[RTE_CRYPTODEV_NAME_MAX_LEN];
+	struct qat_pci_device *qat_pci_dev;
 
 	if (pci_dev == NULL)
 		return -EINVAL;
 
-	rte_pci_device_name(&pci_dev->addr, cryptodev_name,
-			sizeof(cryptodev_name));
+	qat_pci_dev = qat_get_qat_dev_from_pci_dev(pci_dev);
+	if (qat_pci_dev == NULL)
+		return 0;
 
-	cryptodev = rte_cryptodev_pmd_get_named_dev(cryptodev_name);
-	if (cryptodev == NULL)
-		return -ENODEV;
+	return qat_pci_dev_destroy(qat_pci_dev, pci_dev);
 
-	/* free crypto device */
-	return rte_cryptodev_pmd_destroy(cryptodev);
 }
 
 static struct rte_pci_driver rte_qat_pmd = {
 	.id_table = pci_id_qat_map,
 	.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
-	.probe = crypto_qat_pci_probe,
-	.remove = crypto_qat_pci_remove
+	.probe = qat_pci_probe,
+	.remove = qat_pci_remove
 };
 
 static struct cryptodev_driver qat_crypto_drv;
