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