xref: /dpdk/drivers/crypto/virtio/virtio_pci.c (revision a65a34a85ebf5ee6dda53d680393b0342ff7fdb9)
125500d4bSJay Zhou /* SPDX-License-Identifier: BSD-3-Clause
225500d4bSJay Zhou  * Copyright(c) 2018 HUAWEI TECHNOLOGIES CO., LTD.
325500d4bSJay Zhou  */
425500d4bSJay Zhou 
525500d4bSJay Zhou #include <stdint.h>
625500d4bSJay Zhou 
7742bde12SBruce Richardson #ifdef RTE_EXEC_ENV_LINUX
825500d4bSJay Zhou  #include <dirent.h>
925500d4bSJay Zhou  #include <fcntl.h>
1025500d4bSJay Zhou #endif
1125500d4bSJay Zhou 
1225500d4bSJay Zhou #include <rte_io.h>
1325500d4bSJay Zhou #include <rte_bus.h>
1425500d4bSJay Zhou 
1525500d4bSJay Zhou #include "virtio_pci.h"
1625500d4bSJay Zhou #include "virtqueue.h"
1725500d4bSJay Zhou 
1825500d4bSJay Zhou /*
1925500d4bSJay Zhou  * Following macros are derived from linux/pci_regs.h, however,
2025500d4bSJay Zhou  * we can't simply include that header here, as there is no such
2125500d4bSJay Zhou  * file for non-Linux platform.
2225500d4bSJay Zhou  */
2325500d4bSJay Zhou #define PCI_CAPABILITY_LIST	0x34
2425500d4bSJay Zhou #define PCI_CAP_ID_VNDR		0x09
2525500d4bSJay Zhou #define PCI_CAP_ID_MSIX		0x11
2625500d4bSJay Zhou 
2725500d4bSJay Zhou /*
2825500d4bSJay Zhou  * The remaining space is defined by each driver as the per-driver
2925500d4bSJay Zhou  * configuration space.
3025500d4bSJay Zhou  */
3125500d4bSJay Zhou #define VIRTIO_PCI_CONFIG(hw) \
3225500d4bSJay Zhou 		(((hw)->use_msix == VIRTIO_MSIX_ENABLED) ? 24 : 20)
3325500d4bSJay Zhou 
342c449644SFerruh Yigit struct virtio_hw_internal crypto_virtio_hw_internal[RTE_MAX_VIRTIO_CRYPTO];
3525500d4bSJay Zhou 
3625500d4bSJay Zhou static inline int
3725500d4bSJay Zhou check_vq_phys_addr_ok(struct virtqueue *vq)
3825500d4bSJay Zhou {
3925500d4bSJay Zhou 	/* Virtio PCI device VIRTIO_PCI_QUEUE_PF register is 32bit,
4025500d4bSJay Zhou 	 * and only accepts 32 bit page frame number.
4125500d4bSJay Zhou 	 * Check if the allocated physical memory exceeds 16TB.
4225500d4bSJay Zhou 	 */
4325500d4bSJay Zhou 	if ((vq->vq_ring_mem + vq->vq_ring_size - 1) >>
4425500d4bSJay Zhou 			(VIRTIO_PCI_QUEUE_ADDR_SHIFT + 32)) {
4525500d4bSJay Zhou 		VIRTIO_CRYPTO_INIT_LOG_ERR("vring address shouldn't be above 16TB!");
4625500d4bSJay Zhou 		return 0;
4725500d4bSJay Zhou 	}
4825500d4bSJay Zhou 
4925500d4bSJay Zhou 	return 1;
5025500d4bSJay Zhou }
5125500d4bSJay Zhou 
5225500d4bSJay Zhou static inline void
5325500d4bSJay Zhou io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
5425500d4bSJay Zhou {
5525500d4bSJay Zhou 	rte_write32(val & ((1ULL << 32) - 1), lo);
5625500d4bSJay Zhou 	rte_write32(val >> 32,		     hi);
5725500d4bSJay Zhou }
5825500d4bSJay Zhou 
5925500d4bSJay Zhou static void
6025500d4bSJay Zhou modern_read_dev_config(struct virtio_crypto_hw *hw, size_t offset,
6125500d4bSJay Zhou 		       void *dst, int length)
6225500d4bSJay Zhou {
6325500d4bSJay Zhou 	int i;
6425500d4bSJay Zhou 	uint8_t *p;
6525500d4bSJay Zhou 	uint8_t old_gen, new_gen;
6625500d4bSJay Zhou 
6725500d4bSJay Zhou 	do {
6825500d4bSJay Zhou 		old_gen = rte_read8(&hw->common_cfg->config_generation);
6925500d4bSJay Zhou 
7025500d4bSJay Zhou 		p = dst;
7125500d4bSJay Zhou 		for (i = 0;  i < length; i++)
7225500d4bSJay Zhou 			*p++ = rte_read8((uint8_t *)hw->dev_cfg + offset + i);
7325500d4bSJay Zhou 
7425500d4bSJay Zhou 		new_gen = rte_read8(&hw->common_cfg->config_generation);
7525500d4bSJay Zhou 	} while (old_gen != new_gen);
7625500d4bSJay Zhou }
7725500d4bSJay Zhou 
7825500d4bSJay Zhou static void
7925500d4bSJay Zhou modern_write_dev_config(struct virtio_crypto_hw *hw, size_t offset,
8025500d4bSJay Zhou 			const void *src, int length)
8125500d4bSJay Zhou {
8225500d4bSJay Zhou 	int i;
8325500d4bSJay Zhou 	const uint8_t *p = src;
8425500d4bSJay Zhou 
8525500d4bSJay Zhou 	for (i = 0;  i < length; i++)
8625500d4bSJay Zhou 		rte_write8((*p++), (((uint8_t *)hw->dev_cfg) + offset + i));
8725500d4bSJay Zhou }
8825500d4bSJay Zhou 
8925500d4bSJay Zhou static uint64_t
9025500d4bSJay Zhou modern_get_features(struct virtio_crypto_hw *hw)
9125500d4bSJay Zhou {
9225500d4bSJay Zhou 	uint32_t features_lo, features_hi;
9325500d4bSJay Zhou 
9425500d4bSJay Zhou 	rte_write32(0, &hw->common_cfg->device_feature_select);
9525500d4bSJay Zhou 	features_lo = rte_read32(&hw->common_cfg->device_feature);
9625500d4bSJay Zhou 
9725500d4bSJay Zhou 	rte_write32(1, &hw->common_cfg->device_feature_select);
9825500d4bSJay Zhou 	features_hi = rte_read32(&hw->common_cfg->device_feature);
9925500d4bSJay Zhou 
10025500d4bSJay Zhou 	return ((uint64_t)features_hi << 32) | features_lo;
10125500d4bSJay Zhou }
10225500d4bSJay Zhou 
10325500d4bSJay Zhou static void
10425500d4bSJay Zhou modern_set_features(struct virtio_crypto_hw *hw, uint64_t features)
10525500d4bSJay Zhou {
10625500d4bSJay Zhou 	rte_write32(0, &hw->common_cfg->guest_feature_select);
10725500d4bSJay Zhou 	rte_write32(features & ((1ULL << 32) - 1),
10825500d4bSJay Zhou 		    &hw->common_cfg->guest_feature);
10925500d4bSJay Zhou 
11025500d4bSJay Zhou 	rte_write32(1, &hw->common_cfg->guest_feature_select);
11125500d4bSJay Zhou 	rte_write32(features >> 32,
11225500d4bSJay Zhou 		    &hw->common_cfg->guest_feature);
11325500d4bSJay Zhou }
11425500d4bSJay Zhou 
11525500d4bSJay Zhou static uint8_t
11625500d4bSJay Zhou modern_get_status(struct virtio_crypto_hw *hw)
11725500d4bSJay Zhou {
11825500d4bSJay Zhou 	return rte_read8(&hw->common_cfg->device_status);
11925500d4bSJay Zhou }
12025500d4bSJay Zhou 
12125500d4bSJay Zhou static void
12225500d4bSJay Zhou modern_set_status(struct virtio_crypto_hw *hw, uint8_t status)
12325500d4bSJay Zhou {
12425500d4bSJay Zhou 	rte_write8(status, &hw->common_cfg->device_status);
12525500d4bSJay Zhou }
12625500d4bSJay Zhou 
12725500d4bSJay Zhou static void
12825500d4bSJay Zhou modern_reset(struct virtio_crypto_hw *hw)
12925500d4bSJay Zhou {
13025500d4bSJay Zhou 	modern_set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
13125500d4bSJay Zhou 	modern_get_status(hw);
13225500d4bSJay Zhou }
13325500d4bSJay Zhou 
13425500d4bSJay Zhou static uint8_t
13525500d4bSJay Zhou modern_get_isr(struct virtio_crypto_hw *hw)
13625500d4bSJay Zhou {
13725500d4bSJay Zhou 	return rte_read8(hw->isr);
13825500d4bSJay Zhou }
13925500d4bSJay Zhou 
14025500d4bSJay Zhou static uint16_t
14125500d4bSJay Zhou modern_set_config_irq(struct virtio_crypto_hw *hw, uint16_t vec)
14225500d4bSJay Zhou {
14325500d4bSJay Zhou 	rte_write16(vec, &hw->common_cfg->msix_config);
14425500d4bSJay Zhou 	return rte_read16(&hw->common_cfg->msix_config);
14525500d4bSJay Zhou }
14625500d4bSJay Zhou 
14725500d4bSJay Zhou static uint16_t
14825500d4bSJay Zhou modern_set_queue_irq(struct virtio_crypto_hw *hw, struct virtqueue *vq,
14925500d4bSJay Zhou 		uint16_t vec)
15025500d4bSJay Zhou {
15125500d4bSJay Zhou 	rte_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
15225500d4bSJay Zhou 	rte_write16(vec, &hw->common_cfg->queue_msix_vector);
15325500d4bSJay Zhou 	return rte_read16(&hw->common_cfg->queue_msix_vector);
15425500d4bSJay Zhou }
15525500d4bSJay Zhou 
15625500d4bSJay Zhou static uint16_t
15725500d4bSJay Zhou modern_get_queue_num(struct virtio_crypto_hw *hw, uint16_t queue_id)
15825500d4bSJay Zhou {
15925500d4bSJay Zhou 	rte_write16(queue_id, &hw->common_cfg->queue_select);
16025500d4bSJay Zhou 	return rte_read16(&hw->common_cfg->queue_size);
16125500d4bSJay Zhou }
16225500d4bSJay Zhou 
16325500d4bSJay Zhou static int
16425500d4bSJay Zhou modern_setup_queue(struct virtio_crypto_hw *hw, struct virtqueue *vq)
16525500d4bSJay Zhou {
16625500d4bSJay Zhou 	uint64_t desc_addr, avail_addr, used_addr;
16725500d4bSJay Zhou 	uint16_t notify_off;
16825500d4bSJay Zhou 
16925500d4bSJay Zhou 	if (!check_vq_phys_addr_ok(vq))
17025500d4bSJay Zhou 		return -1;
17125500d4bSJay Zhou 
17225500d4bSJay Zhou 	desc_addr = vq->vq_ring_mem;
17325500d4bSJay Zhou 	avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc);
17425500d4bSJay Zhou 	used_addr = RTE_ALIGN_CEIL(avail_addr + offsetof(struct vring_avail,
17525500d4bSJay Zhou 							 ring[vq->vq_nentries]),
17625500d4bSJay Zhou 				   VIRTIO_PCI_VRING_ALIGN);
17725500d4bSJay Zhou 
17825500d4bSJay Zhou 	rte_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
17925500d4bSJay Zhou 
18025500d4bSJay Zhou 	io_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo,
18125500d4bSJay Zhou 				      &hw->common_cfg->queue_desc_hi);
18225500d4bSJay Zhou 	io_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo,
18325500d4bSJay Zhou 				       &hw->common_cfg->queue_avail_hi);
18425500d4bSJay Zhou 	io_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo,
18525500d4bSJay Zhou 				      &hw->common_cfg->queue_used_hi);
18625500d4bSJay Zhou 
18725500d4bSJay Zhou 	notify_off = rte_read16(&hw->common_cfg->queue_notify_off);
18825500d4bSJay Zhou 	vq->notify_addr = (void *)((uint8_t *)hw->notify_base +
18925500d4bSJay Zhou 				notify_off * hw->notify_off_multiplier);
19025500d4bSJay Zhou 
19125500d4bSJay Zhou 	rte_write16(1, &hw->common_cfg->queue_enable);
19225500d4bSJay Zhou 
19325500d4bSJay Zhou 	VIRTIO_CRYPTO_INIT_LOG_DBG("queue %u addresses:", vq->vq_queue_index);
19425500d4bSJay Zhou 	VIRTIO_CRYPTO_INIT_LOG_DBG("\t desc_addr: %" PRIx64, desc_addr);
19525500d4bSJay Zhou 	VIRTIO_CRYPTO_INIT_LOG_DBG("\t aval_addr: %" PRIx64, avail_addr);
19625500d4bSJay Zhou 	VIRTIO_CRYPTO_INIT_LOG_DBG("\t used_addr: %" PRIx64, used_addr);
19725500d4bSJay Zhou 	VIRTIO_CRYPTO_INIT_LOG_DBG("\t notify addr: %p (notify offset: %u)",
19825500d4bSJay Zhou 		vq->notify_addr, notify_off);
19925500d4bSJay Zhou 
20025500d4bSJay Zhou 	return 0;
20125500d4bSJay Zhou }
20225500d4bSJay Zhou 
20325500d4bSJay Zhou static void
20425500d4bSJay Zhou modern_del_queue(struct virtio_crypto_hw *hw, struct virtqueue *vq)
20525500d4bSJay Zhou {
20625500d4bSJay Zhou 	rte_write16(vq->vq_queue_index, &hw->common_cfg->queue_select);
20725500d4bSJay Zhou 
20825500d4bSJay Zhou 	io_write64_twopart(0, &hw->common_cfg->queue_desc_lo,
20925500d4bSJay Zhou 				  &hw->common_cfg->queue_desc_hi);
21025500d4bSJay Zhou 	io_write64_twopart(0, &hw->common_cfg->queue_avail_lo,
21125500d4bSJay Zhou 				  &hw->common_cfg->queue_avail_hi);
21225500d4bSJay Zhou 	io_write64_twopart(0, &hw->common_cfg->queue_used_lo,
21325500d4bSJay Zhou 				  &hw->common_cfg->queue_used_hi);
21425500d4bSJay Zhou 
21525500d4bSJay Zhou 	rte_write16(0, &hw->common_cfg->queue_enable);
21625500d4bSJay Zhou }
21725500d4bSJay Zhou 
21825500d4bSJay Zhou static void
21925500d4bSJay Zhou modern_notify_queue(struct virtio_crypto_hw *hw __rte_unused,
22025500d4bSJay Zhou 		struct virtqueue *vq)
22125500d4bSJay Zhou {
22225500d4bSJay Zhou 	rte_write16(vq->vq_queue_index, vq->notify_addr);
22325500d4bSJay Zhou }
22425500d4bSJay Zhou 
22525500d4bSJay Zhou const struct virtio_pci_ops virtio_crypto_modern_ops = {
22625500d4bSJay Zhou 	.read_dev_cfg	= modern_read_dev_config,
22725500d4bSJay Zhou 	.write_dev_cfg	= modern_write_dev_config,
22825500d4bSJay Zhou 	.reset		= modern_reset,
22925500d4bSJay Zhou 	.get_status	= modern_get_status,
23025500d4bSJay Zhou 	.set_status	= modern_set_status,
23125500d4bSJay Zhou 	.get_features	= modern_get_features,
23225500d4bSJay Zhou 	.set_features	= modern_set_features,
23325500d4bSJay Zhou 	.get_isr	= modern_get_isr,
23425500d4bSJay Zhou 	.set_config_irq	= modern_set_config_irq,
23525500d4bSJay Zhou 	.set_queue_irq  = modern_set_queue_irq,
23625500d4bSJay Zhou 	.get_queue_num	= modern_get_queue_num,
23725500d4bSJay Zhou 	.setup_queue	= modern_setup_queue,
23825500d4bSJay Zhou 	.del_queue	= modern_del_queue,
23925500d4bSJay Zhou 	.notify_queue	= modern_notify_queue,
24025500d4bSJay Zhou };
24125500d4bSJay Zhou 
24225500d4bSJay Zhou void
24325500d4bSJay Zhou vtpci_read_cryptodev_config(struct virtio_crypto_hw *hw, size_t offset,
24425500d4bSJay Zhou 		void *dst, int length)
24525500d4bSJay Zhou {
24625500d4bSJay Zhou 	VTPCI_OPS(hw)->read_dev_cfg(hw, offset, dst, length);
24725500d4bSJay Zhou }
24825500d4bSJay Zhou 
24925500d4bSJay Zhou void
25025500d4bSJay Zhou vtpci_write_cryptodev_config(struct virtio_crypto_hw *hw, size_t offset,
25125500d4bSJay Zhou 		const void *src, int length)
25225500d4bSJay Zhou {
25325500d4bSJay Zhou 	VTPCI_OPS(hw)->write_dev_cfg(hw, offset, src, length);
25425500d4bSJay Zhou }
25525500d4bSJay Zhou 
25625500d4bSJay Zhou uint64_t
25725500d4bSJay Zhou vtpci_cryptodev_negotiate_features(struct virtio_crypto_hw *hw,
25825500d4bSJay Zhou 		uint64_t host_features)
25925500d4bSJay Zhou {
26025500d4bSJay Zhou 	uint64_t features;
26125500d4bSJay Zhou 
26225500d4bSJay Zhou 	/*
26325500d4bSJay Zhou 	 * Limit negotiated features to what the driver, virtqueue, and
26425500d4bSJay Zhou 	 * host all support.
26525500d4bSJay Zhou 	 */
26625500d4bSJay Zhou 	features = host_features & hw->guest_features;
26725500d4bSJay Zhou 	VTPCI_OPS(hw)->set_features(hw, features);
26825500d4bSJay Zhou 
26925500d4bSJay Zhou 	return features;
27025500d4bSJay Zhou }
27125500d4bSJay Zhou 
27225500d4bSJay Zhou void
27325500d4bSJay Zhou vtpci_cryptodev_reset(struct virtio_crypto_hw *hw)
27425500d4bSJay Zhou {
27525500d4bSJay Zhou 	VTPCI_OPS(hw)->set_status(hw, VIRTIO_CONFIG_STATUS_RESET);
27625500d4bSJay Zhou 	/* flush status write */
27725500d4bSJay Zhou 	VTPCI_OPS(hw)->get_status(hw);
27825500d4bSJay Zhou }
27925500d4bSJay Zhou 
28025500d4bSJay Zhou void
28125500d4bSJay Zhou vtpci_cryptodev_reinit_complete(struct virtio_crypto_hw *hw)
28225500d4bSJay Zhou {
28325500d4bSJay Zhou 	vtpci_cryptodev_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK);
28425500d4bSJay Zhou }
28525500d4bSJay Zhou 
28625500d4bSJay Zhou void
28725500d4bSJay Zhou vtpci_cryptodev_set_status(struct virtio_crypto_hw *hw, uint8_t status)
28825500d4bSJay Zhou {
28925500d4bSJay Zhou 	if (status != VIRTIO_CONFIG_STATUS_RESET)
29025500d4bSJay Zhou 		status |= VTPCI_OPS(hw)->get_status(hw);
29125500d4bSJay Zhou 
29225500d4bSJay Zhou 	VTPCI_OPS(hw)->set_status(hw, status);
29325500d4bSJay Zhou }
29425500d4bSJay Zhou 
29525500d4bSJay Zhou uint8_t
29625500d4bSJay Zhou vtpci_cryptodev_get_status(struct virtio_crypto_hw *hw)
29725500d4bSJay Zhou {
29825500d4bSJay Zhou 	return VTPCI_OPS(hw)->get_status(hw);
29925500d4bSJay Zhou }
30025500d4bSJay Zhou 
30125500d4bSJay Zhou uint8_t
30225500d4bSJay Zhou vtpci_cryptodev_isr(struct virtio_crypto_hw *hw)
30325500d4bSJay Zhou {
30425500d4bSJay Zhou 	return VTPCI_OPS(hw)->get_isr(hw);
30525500d4bSJay Zhou }
30625500d4bSJay Zhou 
30725500d4bSJay Zhou static void *
30825500d4bSJay Zhou get_cfg_addr(struct rte_pci_device *dev, struct virtio_pci_cap *cap)
30925500d4bSJay Zhou {
31025500d4bSJay Zhou 	uint8_t  bar    = cap->bar;
31125500d4bSJay Zhou 	uint32_t length = cap->length;
31225500d4bSJay Zhou 	uint32_t offset = cap->offset;
31325500d4bSJay Zhou 	uint8_t *base;
31425500d4bSJay Zhou 
31525500d4bSJay Zhou 	if (bar >= PCI_MAX_RESOURCE) {
31625500d4bSJay Zhou 		VIRTIO_CRYPTO_INIT_LOG_ERR("invalid bar: %u", bar);
31725500d4bSJay Zhou 		return NULL;
31825500d4bSJay Zhou 	}
31925500d4bSJay Zhou 
32025500d4bSJay Zhou 	if (offset + length < offset) {
32125500d4bSJay Zhou 		VIRTIO_CRYPTO_INIT_LOG_ERR("offset(%u) + length(%u) overflows",
32225500d4bSJay Zhou 			offset, length);
32325500d4bSJay Zhou 		return NULL;
32425500d4bSJay Zhou 	}
32525500d4bSJay Zhou 
32625500d4bSJay Zhou 	if (offset + length > dev->mem_resource[bar].len) {
32725500d4bSJay Zhou 		VIRTIO_CRYPTO_INIT_LOG_ERR(
32825500d4bSJay Zhou 			"invalid cap: overflows bar space: %u > %" PRIu64,
32925500d4bSJay Zhou 			offset + length, dev->mem_resource[bar].len);
33025500d4bSJay Zhou 		return NULL;
33125500d4bSJay Zhou 	}
33225500d4bSJay Zhou 
33325500d4bSJay Zhou 	base = dev->mem_resource[bar].addr;
33425500d4bSJay Zhou 	if (base == NULL) {
33525500d4bSJay Zhou 		VIRTIO_CRYPTO_INIT_LOG_ERR("bar %u base addr is NULL", bar);
33625500d4bSJay Zhou 		return NULL;
33725500d4bSJay Zhou 	}
33825500d4bSJay Zhou 
33925500d4bSJay Zhou 	return base + offset;
34025500d4bSJay Zhou }
34125500d4bSJay Zhou 
34225500d4bSJay Zhou #define PCI_MSIX_ENABLE 0x8000
34325500d4bSJay Zhou 
34425500d4bSJay Zhou static int
34525500d4bSJay Zhou virtio_read_caps(struct rte_pci_device *dev, struct virtio_crypto_hw *hw)
34625500d4bSJay Zhou {
34725500d4bSJay Zhou 	uint8_t pos;
34825500d4bSJay Zhou 	struct virtio_pci_cap cap;
34925500d4bSJay Zhou 	int ret;
35025500d4bSJay Zhou 
35125500d4bSJay Zhou 	if (rte_pci_map_device(dev)) {
35225500d4bSJay Zhou 		VIRTIO_CRYPTO_INIT_LOG_DBG("failed to map pci device!");
35325500d4bSJay Zhou 		return -1;
35425500d4bSJay Zhou 	}
35525500d4bSJay Zhou 
35625500d4bSJay Zhou 	ret = rte_pci_read_config(dev, &pos, 1, PCI_CAPABILITY_LIST);
35725500d4bSJay Zhou 	if (ret < 0) {
35825500d4bSJay Zhou 		VIRTIO_CRYPTO_INIT_LOG_DBG("failed to read pci capability list");
35925500d4bSJay Zhou 		return -1;
36025500d4bSJay Zhou 	}
36125500d4bSJay Zhou 
36225500d4bSJay Zhou 	while (pos) {
36325500d4bSJay Zhou 		ret = rte_pci_read_config(dev, &cap, sizeof(cap), pos);
36425500d4bSJay Zhou 		if (ret < 0) {
36525500d4bSJay Zhou 			VIRTIO_CRYPTO_INIT_LOG_ERR(
36625500d4bSJay Zhou 				"failed to read pci cap at pos: %x", pos);
36725500d4bSJay Zhou 			break;
36825500d4bSJay Zhou 		}
36925500d4bSJay Zhou 
37025500d4bSJay Zhou 		if (cap.cap_vndr == PCI_CAP_ID_MSIX) {
37125500d4bSJay Zhou 			/* Transitional devices would also have this capability,
37225500d4bSJay Zhou 			 * that's why we also check if msix is enabled.
37325500d4bSJay Zhou 			 * 1st byte is cap ID; 2nd byte is the position of next
37425500d4bSJay Zhou 			 * cap; next two bytes are the flags.
37525500d4bSJay Zhou 			 */
37625500d4bSJay Zhou 			uint16_t flags = ((uint16_t *)&cap)[1];
37725500d4bSJay Zhou 
37825500d4bSJay Zhou 			if (flags & PCI_MSIX_ENABLE)
37925500d4bSJay Zhou 				hw->use_msix = VIRTIO_MSIX_ENABLED;
38025500d4bSJay Zhou 			else
38125500d4bSJay Zhou 				hw->use_msix = VIRTIO_MSIX_DISABLED;
38225500d4bSJay Zhou 		}
38325500d4bSJay Zhou 
38425500d4bSJay Zhou 		if (cap.cap_vndr != PCI_CAP_ID_VNDR) {
38525500d4bSJay Zhou 			VIRTIO_CRYPTO_INIT_LOG_DBG(
38625500d4bSJay Zhou 				"[%2x] skipping non VNDR cap id: %02x",
38725500d4bSJay Zhou 				pos, cap.cap_vndr);
38825500d4bSJay Zhou 			goto next;
38925500d4bSJay Zhou 		}
39025500d4bSJay Zhou 
39125500d4bSJay Zhou 		VIRTIO_CRYPTO_INIT_LOG_DBG(
39225500d4bSJay Zhou 			"[%2x] cfg type: %u, bar: %u, offset: %04x, len: %u",
39325500d4bSJay Zhou 			pos, cap.cfg_type, cap.bar, cap.offset, cap.length);
39425500d4bSJay Zhou 
39525500d4bSJay Zhou 		switch (cap.cfg_type) {
39625500d4bSJay Zhou 		case VIRTIO_PCI_CAP_COMMON_CFG:
39725500d4bSJay Zhou 			hw->common_cfg = get_cfg_addr(dev, &cap);
39825500d4bSJay Zhou 			break;
39925500d4bSJay Zhou 		case VIRTIO_PCI_CAP_NOTIFY_CFG:
400691733e7SChenbo Xia 			ret = rte_pci_read_config(dev, &hw->notify_off_multiplier,
40125500d4bSJay Zhou 					4, pos + sizeof(cap));
402691733e7SChenbo Xia 			if (ret != 4)
403691733e7SChenbo Xia 				VIRTIO_CRYPTO_INIT_LOG_ERR(
404691733e7SChenbo Xia 					"failed to read notify_off_multiplier: ret %d", ret);
405691733e7SChenbo Xia 			else
40625500d4bSJay Zhou 				hw->notify_base = get_cfg_addr(dev, &cap);
40725500d4bSJay Zhou 			break;
40825500d4bSJay Zhou 		case VIRTIO_PCI_CAP_DEVICE_CFG:
40925500d4bSJay Zhou 			hw->dev_cfg = get_cfg_addr(dev, &cap);
41025500d4bSJay Zhou 			break;
41125500d4bSJay Zhou 		case VIRTIO_PCI_CAP_ISR_CFG:
41225500d4bSJay Zhou 			hw->isr = get_cfg_addr(dev, &cap);
41325500d4bSJay Zhou 			break;
41425500d4bSJay Zhou 		}
41525500d4bSJay Zhou 
41625500d4bSJay Zhou next:
41725500d4bSJay Zhou 		pos = cap.cap_next;
41825500d4bSJay Zhou 	}
41925500d4bSJay Zhou 
42025500d4bSJay Zhou 	if (hw->common_cfg == NULL || hw->notify_base == NULL ||
42125500d4bSJay Zhou 	    hw->dev_cfg == NULL    || hw->isr == NULL) {
42225500d4bSJay Zhou 		VIRTIO_CRYPTO_INIT_LOG_INFO("no modern virtio pci device found.");
42325500d4bSJay Zhou 		return -1;
42425500d4bSJay Zhou 	}
42525500d4bSJay Zhou 
42625500d4bSJay Zhou 	VIRTIO_CRYPTO_INIT_LOG_INFO("found modern virtio pci device.");
42725500d4bSJay Zhou 
42825500d4bSJay Zhou 	VIRTIO_CRYPTO_INIT_LOG_DBG("common cfg mapped at: %p", hw->common_cfg);
42925500d4bSJay Zhou 	VIRTIO_CRYPTO_INIT_LOG_DBG("device cfg mapped at: %p", hw->dev_cfg);
43025500d4bSJay Zhou 	VIRTIO_CRYPTO_INIT_LOG_DBG("isr cfg mapped at: %p", hw->isr);
43125500d4bSJay Zhou 	VIRTIO_CRYPTO_INIT_LOG_DBG("notify base: %p, notify off multiplier: %u",
43225500d4bSJay Zhou 		hw->notify_base, hw->notify_off_multiplier);
43325500d4bSJay Zhou 
43425500d4bSJay Zhou 	return 0;
43525500d4bSJay Zhou }
43625500d4bSJay Zhou 
43725500d4bSJay Zhou /*
43825500d4bSJay Zhou  * Return -1:
43925500d4bSJay Zhou  *   if there is error mapping with VFIO/UIO.
44025500d4bSJay Zhou  *   if port map error when driver type is KDRV_NONE.
441*a65a34a8SStephen Hemminger  *   if marked as allowed but driver type is KDRV_UNKNOWN.
44225500d4bSJay Zhou  * Return 1 if kernel driver is managing the device.
44325500d4bSJay Zhou  * Return 0 on success.
44425500d4bSJay Zhou  */
44525500d4bSJay Zhou int
44625500d4bSJay Zhou vtpci_cryptodev_init(struct rte_pci_device *dev, struct virtio_crypto_hw *hw)
44725500d4bSJay Zhou {
44825500d4bSJay Zhou 	/*
44925500d4bSJay Zhou 	 * Try if we can succeed reading virtio pci caps, which exists
45025500d4bSJay Zhou 	 * only on modern pci device. If failed, we fallback to legacy
45125500d4bSJay Zhou 	 * virtio handling.
45225500d4bSJay Zhou 	 */
45325500d4bSJay Zhou 	if (virtio_read_caps(dev, hw) == 0) {
45425500d4bSJay Zhou 		VIRTIO_CRYPTO_INIT_LOG_INFO("modern virtio pci detected.");
4552c449644SFerruh Yigit 		crypto_virtio_hw_internal[hw->dev_id].vtpci_ops =
45625500d4bSJay Zhou 					&virtio_crypto_modern_ops;
45725500d4bSJay Zhou 		hw->modern = 1;
45825500d4bSJay Zhou 		return 0;
45925500d4bSJay Zhou 	}
46025500d4bSJay Zhou 
46125500d4bSJay Zhou 	/*
46225500d4bSJay Zhou 	 * virtio crypto conforms to virtio 1.0 and doesn't support
46325500d4bSJay Zhou 	 * legacy mode
46425500d4bSJay Zhou 	 */
46525500d4bSJay Zhou 	return -1;
46625500d4bSJay Zhou }
467