xref: /dpdk/drivers/net/avp/avp_ethdev.c (revision e99981af34632ecce3bac82d05db97b08308f9b5)
150da8b0dSAllain Legacy /* SPDX-License-Identifier: BSD-3-Clause
250da8b0dSAllain Legacy  * Copyright(c) 2013-2017 Wind River Systems, Inc.
3908072e9SAllain Legacy  */
4908072e9SAllain Legacy 
5908072e9SAllain Legacy #include <stdint.h>
6908072e9SAllain Legacy #include <string.h>
7908072e9SAllain Legacy #include <stdio.h>
8908072e9SAllain Legacy #include <errno.h>
9908072e9SAllain Legacy #include <unistd.h>
10908072e9SAllain Legacy 
11df96fd0dSBruce Richardson #include <ethdev_driver.h>
12df96fd0dSBruce Richardson #include <ethdev_pci.h>
13908072e9SAllain Legacy #include <rte_memcpy.h>
14908072e9SAllain Legacy #include <rte_string_fns.h>
15908072e9SAllain Legacy #include <rte_malloc.h>
16908072e9SAllain Legacy #include <rte_atomic.h>
17908072e9SAllain Legacy #include <rte_branch_prediction.h>
18908072e9SAllain Legacy #include <rte_pci.h>
191f37cb2bSDavid Marchand #include <bus_pci_driver.h>
20908072e9SAllain Legacy #include <rte_ether.h>
21908072e9SAllain Legacy #include <rte_common.h>
22908072e9SAllain Legacy #include <rte_cycles.h>
2382e140b8SAllain Legacy #include <rte_spinlock.h>
24908072e9SAllain Legacy #include <rte_byteorder.h>
251acb7f54SDavid Marchand #include <dev_driver.h>
26908072e9SAllain Legacy #include <rte_memory.h>
27908072e9SAllain Legacy #include <rte_eal.h>
28c0ad5842SAllain Legacy #include <rte_io.h>
29908072e9SAllain Legacy 
30908072e9SAllain Legacy #include "rte_avp_common.h"
31908072e9SAllain Legacy #include "rte_avp_fifo.h"
32908072e9SAllain Legacy 
33908072e9SAllain Legacy #include "avp_logs.h"
34908072e9SAllain Legacy 
3582e140b8SAllain Legacy static int avp_dev_create(struct rte_pci_device *pci_dev,
3682e140b8SAllain Legacy 			  struct rte_eth_dev *eth_dev);
37908072e9SAllain Legacy 
381a859223SAllain Legacy static int avp_dev_configure(struct rte_eth_dev *dev);
39ea37523dSAllain Legacy static int avp_dev_start(struct rte_eth_dev *dev);
4062024eb8SIvan Ilchenko static int avp_dev_stop(struct rte_eth_dev *dev);
41b142387bSThomas Monjalon static int avp_dev_close(struct rte_eth_dev *dev);
42bdad90d1SIvan Ilchenko static int avp_dev_info_get(struct rte_eth_dev *dev,
431a859223SAllain Legacy 			    struct rte_eth_dev_info *dev_info);
44289ba0c0SDavid Harton static int avp_vlan_offload_set(struct rte_eth_dev *dev, int mask);
45dd2c630aSFerruh Yigit static int avp_dev_link_update(struct rte_eth_dev *dev, int wait_to_complete);
469039c812SAndrew Rybchenko static int avp_dev_promiscuous_enable(struct rte_eth_dev *dev);
479039c812SAndrew Rybchenko static int avp_dev_promiscuous_disable(struct rte_eth_dev *dev);
488129545eSAllain Legacy 
49cce4367fSAllain Legacy static int avp_dev_rx_queue_setup(struct rte_eth_dev *dev,
50cce4367fSAllain Legacy 				  uint16_t rx_queue_id,
51cce4367fSAllain Legacy 				  uint16_t nb_rx_desc,
52cce4367fSAllain Legacy 				  unsigned int socket_id,
53cce4367fSAllain Legacy 				  const struct rte_eth_rxconf *rx_conf,
54cce4367fSAllain Legacy 				  struct rte_mempool *pool);
551a859223SAllain Legacy 
56cce4367fSAllain Legacy static int avp_dev_tx_queue_setup(struct rte_eth_dev *dev,
57cce4367fSAllain Legacy 				  uint16_t tx_queue_id,
58cce4367fSAllain Legacy 				  uint16_t nb_tx_desc,
59cce4367fSAllain Legacy 				  unsigned int socket_id,
60cce4367fSAllain Legacy 				  const struct rte_eth_txconf *tx_conf);
61cce4367fSAllain Legacy 
6250db69fdSAllain Legacy static uint16_t avp_recv_scattered_pkts(void *rx_queue,
6350db69fdSAllain Legacy 					struct rte_mbuf **rx_pkts,
6450db69fdSAllain Legacy 					uint16_t nb_pkts);
6550db69fdSAllain Legacy 
6650db69fdSAllain Legacy static uint16_t avp_recv_pkts(void *rx_queue,
6750db69fdSAllain Legacy 			      struct rte_mbuf **rx_pkts,
6850db69fdSAllain Legacy 			      uint16_t nb_pkts);
69295abce2SAllain Legacy 
70295abce2SAllain Legacy static uint16_t avp_xmit_scattered_pkts(void *tx_queue,
71295abce2SAllain Legacy 					struct rte_mbuf **tx_pkts,
72295abce2SAllain Legacy 					uint16_t nb_pkts);
73295abce2SAllain Legacy 
74295abce2SAllain Legacy static uint16_t avp_xmit_pkts(void *tx_queue,
75295abce2SAllain Legacy 			      struct rte_mbuf **tx_pkts,
76295abce2SAllain Legacy 			      uint16_t nb_pkts);
77295abce2SAllain Legacy 
787483341aSXueming Li static void avp_dev_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid);
797483341aSXueming Li static void avp_dev_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid);
80295abce2SAllain Legacy 
81d5b0924bSMatan Azrad static int avp_dev_stats_get(struct rte_eth_dev *dev,
825a5abe2dSAllain Legacy 			      struct rte_eth_stats *stats);
839970a9adSIgor Romanov static int avp_dev_stats_reset(struct rte_eth_dev *dev);
845a5abe2dSAllain Legacy 
85295abce2SAllain Legacy 
8650db69fdSAllain Legacy #define AVP_MAX_RX_BURST 64
87295abce2SAllain Legacy #define AVP_MAX_TX_BURST 64
88908072e9SAllain Legacy #define AVP_MAX_MAC_ADDRS 1
8935b2d13fSOlivier Matz #define AVP_MIN_RX_BUFSIZE RTE_ETHER_MIN_LEN
90908072e9SAllain Legacy 
91908072e9SAllain Legacy 
92908072e9SAllain Legacy /*
93908072e9SAllain Legacy  * Defines the number of microseconds to wait before checking the response
94908072e9SAllain Legacy  * queue for completion.
95908072e9SAllain Legacy  */
96908072e9SAllain Legacy #define AVP_REQUEST_DELAY_USECS (5000)
97908072e9SAllain Legacy 
98908072e9SAllain Legacy /*
99908072e9SAllain Legacy  * Defines the number times to check the response queue for completion before
100908072e9SAllain Legacy  * declaring a timeout.
101908072e9SAllain Legacy  */
102908072e9SAllain Legacy #define AVP_MAX_REQUEST_RETRY (100)
103908072e9SAllain Legacy 
104908072e9SAllain Legacy /* Defines the current PCI driver version number */
105908072e9SAllain Legacy #define AVP_DPDK_DRIVER_VERSION RTE_AVP_CURRENT_GUEST_VERSION
106908072e9SAllain Legacy 
107908072e9SAllain Legacy /*
108908072e9SAllain Legacy  * The set of PCI devices this driver supports
109908072e9SAllain Legacy  */
110908072e9SAllain Legacy static const struct rte_pci_id pci_id_avp_map[] = {
111908072e9SAllain Legacy 	{ .vendor_id = RTE_AVP_PCI_VENDOR_ID,
112908072e9SAllain Legacy 	  .device_id = RTE_AVP_PCI_DEVICE_ID,
113908072e9SAllain Legacy 	  .subsystem_vendor_id = RTE_AVP_PCI_SUB_VENDOR_ID,
114908072e9SAllain Legacy 	  .subsystem_device_id = RTE_AVP_PCI_SUB_DEVICE_ID,
115908072e9SAllain Legacy 	  .class_id = RTE_CLASS_ANY_ID,
116908072e9SAllain Legacy 	},
117908072e9SAllain Legacy 
118908072e9SAllain Legacy 	{ .vendor_id = 0, /* sentinel */
119908072e9SAllain Legacy 	},
120908072e9SAllain Legacy };
121908072e9SAllain Legacy 
1221a859223SAllain Legacy /*
1231a859223SAllain Legacy  * dev_ops for avp, bare necessities for basic operation
1241a859223SAllain Legacy  */
1251a859223SAllain Legacy static const struct eth_dev_ops avp_eth_dev_ops = {
1261a859223SAllain Legacy 	.dev_configure       = avp_dev_configure,
127ea37523dSAllain Legacy 	.dev_start           = avp_dev_start,
128ea37523dSAllain Legacy 	.dev_stop            = avp_dev_stop,
129ea37523dSAllain Legacy 	.dev_close           = avp_dev_close,
1301a859223SAllain Legacy 	.dev_infos_get       = avp_dev_info_get,
1311a859223SAllain Legacy 	.vlan_offload_set    = avp_vlan_offload_set,
1325a5abe2dSAllain Legacy 	.stats_get           = avp_dev_stats_get,
1335a5abe2dSAllain Legacy 	.stats_reset         = avp_dev_stats_reset,
1341a859223SAllain Legacy 	.link_update         = avp_dev_link_update,
1358129545eSAllain Legacy 	.promiscuous_enable  = avp_dev_promiscuous_enable,
1368129545eSAllain Legacy 	.promiscuous_disable = avp_dev_promiscuous_disable,
137cce4367fSAllain Legacy 	.rx_queue_setup      = avp_dev_rx_queue_setup,
138cce4367fSAllain Legacy 	.rx_queue_release    = avp_dev_rx_queue_release,
139cce4367fSAllain Legacy 	.tx_queue_setup      = avp_dev_tx_queue_setup,
140cce4367fSAllain Legacy 	.tx_queue_release    = avp_dev_tx_queue_release,
1411a859223SAllain Legacy };
142908072e9SAllain Legacy 
143c0ad5842SAllain Legacy /**@{ AVP device flags */
144c0ad5842SAllain Legacy #define AVP_F_PROMISC (1 << 1)
145c0ad5842SAllain Legacy #define AVP_F_CONFIGURED (1 << 2)
146c0ad5842SAllain Legacy #define AVP_F_LINKUP (1 << 3)
14782e140b8SAllain Legacy #define AVP_F_DETACHED (1 << 4)
148c0ad5842SAllain Legacy /**@} */
149c0ad5842SAllain Legacy 
150c0ad5842SAllain Legacy /* Ethernet device validation marker */
151c0ad5842SAllain Legacy #define AVP_ETHDEV_MAGIC 0x92972862
152c0ad5842SAllain Legacy 
153908072e9SAllain Legacy /*
154908072e9SAllain Legacy  * Defines the AVP device attributes which are attached to an RTE ethernet
155908072e9SAllain Legacy  * device
156908072e9SAllain Legacy  */
15727595cd8STyler Retzlaff struct __rte_cache_aligned avp_dev {
158908072e9SAllain Legacy 	uint32_t magic; /**< Memory validation marker */
159908072e9SAllain Legacy 	uint64_t device_id; /**< Unique system identifier */
1606d13ea8eSOlivier Matz 	struct rte_ether_addr ethaddr; /**< Host specified MAC address */
161908072e9SAllain Legacy 	struct rte_eth_dev_data *dev_data;
162908072e9SAllain Legacy 	/**< Back pointer to ethernet device data */
163908072e9SAllain Legacy 	volatile uint32_t flags; /**< Device operational flags */
164f8244c63SZhiyong Yang 	uint16_t port_id; /**< Ethernet port identifier */
165908072e9SAllain Legacy 	struct rte_mempool *pool; /**< pkt mbuf mempool */
166908072e9SAllain Legacy 	unsigned int guest_mbuf_size; /**< local pool mbuf size */
167908072e9SAllain Legacy 	unsigned int host_mbuf_size; /**< host mbuf size */
168908072e9SAllain Legacy 	unsigned int max_rx_pkt_len; /**< maximum receive unit */
169908072e9SAllain Legacy 	uint32_t host_features; /**< Supported feature bitmap */
170908072e9SAllain Legacy 	uint32_t features; /**< Enabled feature bitmap */
171908072e9SAllain Legacy 	unsigned int num_tx_queues; /**< Negotiated number of transmit queues */
172908072e9SAllain Legacy 	unsigned int max_tx_queues; /**< Maximum number of transmit queues */
173908072e9SAllain Legacy 	unsigned int num_rx_queues; /**< Negotiated number of receive queues */
174908072e9SAllain Legacy 	unsigned int max_rx_queues; /**< Maximum number of receive queues */
175908072e9SAllain Legacy 
176908072e9SAllain Legacy 	struct rte_avp_fifo *tx_q[RTE_AVP_MAX_QUEUES]; /**< TX queue */
177908072e9SAllain Legacy 	struct rte_avp_fifo *rx_q[RTE_AVP_MAX_QUEUES]; /**< RX queue */
178908072e9SAllain Legacy 	struct rte_avp_fifo *alloc_q[RTE_AVP_MAX_QUEUES];
179908072e9SAllain Legacy 	/**< Allocated mbufs queue */
180908072e9SAllain Legacy 	struct rte_avp_fifo *free_q[RTE_AVP_MAX_QUEUES];
181908072e9SAllain Legacy 	/**< To be freed mbufs queue */
182908072e9SAllain Legacy 
18382e140b8SAllain Legacy 	/* mutual exclusion over the 'flag' and 'resp_q/req_q' fields */
18482e140b8SAllain Legacy 	rte_spinlock_t lock;
18582e140b8SAllain Legacy 
186908072e9SAllain Legacy 	/* For request & response */
187908072e9SAllain Legacy 	struct rte_avp_fifo *req_q; /**< Request queue */
188908072e9SAllain Legacy 	struct rte_avp_fifo *resp_q; /**< Response queue */
189908072e9SAllain Legacy 	void *host_sync_addr; /**< (host) Req/Resp Mem address */
190908072e9SAllain Legacy 	void *sync_addr; /**< Req/Resp Mem address */
191908072e9SAllain Legacy 	void *host_mbuf_addr; /**< (host) MBUF pool start address */
192908072e9SAllain Legacy 	void *mbuf_addr; /**< MBUF pool start address */
19327595cd8STyler Retzlaff };
194908072e9SAllain Legacy 
195908072e9SAllain Legacy /* RTE ethernet private data */
19627595cd8STyler Retzlaff struct __rte_cache_aligned avp_adapter {
197908072e9SAllain Legacy 	struct avp_dev avp;
19827595cd8STyler Retzlaff };
199908072e9SAllain Legacy 
200c0ad5842SAllain Legacy 
201c0ad5842SAllain Legacy /* 32-bit MMIO register write */
202c0ad5842SAllain Legacy #define AVP_WRITE32(_value, _addr) rte_write32_relaxed((_value), (_addr))
203c0ad5842SAllain Legacy 
204c0ad5842SAllain Legacy /* 32-bit MMIO register read */
205c0ad5842SAllain Legacy #define AVP_READ32(_addr) rte_read32_relaxed((_addr))
206c0ad5842SAllain Legacy 
207908072e9SAllain Legacy /* Macro to cast the ethernet device private data to a AVP object */
208908072e9SAllain Legacy #define AVP_DEV_PRIVATE_TO_HW(adapter) \
209908072e9SAllain Legacy 	(&((struct avp_adapter *)adapter)->avp)
210908072e9SAllain Legacy 
211908072e9SAllain Legacy /*
212c0ad5842SAllain Legacy  * Defines the structure of a AVP device queue for the purpose of handling the
213c0ad5842SAllain Legacy  * receive and transmit burst callback functions
214c0ad5842SAllain Legacy  */
215c0ad5842SAllain Legacy struct avp_queue {
216c0ad5842SAllain Legacy 	struct rte_eth_dev_data *dev_data;
217c0ad5842SAllain Legacy 	/**< Backpointer to ethernet device data */
218c0ad5842SAllain Legacy 	struct avp_dev *avp; /**< Backpointer to AVP device */
219c0ad5842SAllain Legacy 	uint16_t queue_id;
220c0ad5842SAllain Legacy 	/**< Queue identifier used for indexing current queue */
221c0ad5842SAllain Legacy 	uint16_t queue_base;
222c0ad5842SAllain Legacy 	/**< Base queue identifier for queue servicing */
223c0ad5842SAllain Legacy 	uint16_t queue_limit;
224c0ad5842SAllain Legacy 	/**< Maximum queue identifier for queue servicing */
225c0ad5842SAllain Legacy 
226c0ad5842SAllain Legacy 	uint64_t packets;
227c0ad5842SAllain Legacy 	uint64_t bytes;
228c0ad5842SAllain Legacy 	uint64_t errors;
229c0ad5842SAllain Legacy };
230c0ad5842SAllain Legacy 
2311a859223SAllain Legacy /* send a request and wait for a response
2321a859223SAllain Legacy  *
2331a859223SAllain Legacy  * @warning must be called while holding the avp->lock spinlock.
2341a859223SAllain Legacy  */
2351a859223SAllain Legacy static int
2361a859223SAllain Legacy avp_dev_process_request(struct avp_dev *avp, struct rte_avp_request *request)
2371a859223SAllain Legacy {
2381a859223SAllain Legacy 	unsigned int retry = AVP_MAX_REQUEST_RETRY;
2391a859223SAllain Legacy 	void *resp_addr = NULL;
2401a859223SAllain Legacy 	unsigned int count;
2411a859223SAllain Legacy 	int ret;
2421a859223SAllain Legacy 
243*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "Sending request %u to host", request->req_id);
2441a859223SAllain Legacy 
2451a859223SAllain Legacy 	request->result = -ENOTSUP;
2461a859223SAllain Legacy 
2471a859223SAllain Legacy 	/* Discard any stale responses before starting a new request */
2481a859223SAllain Legacy 	while (avp_fifo_get(avp->resp_q, (void **)&resp_addr, 1))
249*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(DEBUG, "Discarding stale response");
2501a859223SAllain Legacy 
2511a859223SAllain Legacy 	rte_memcpy(avp->sync_addr, request, sizeof(*request));
2521a859223SAllain Legacy 	count = avp_fifo_put(avp->req_q, &avp->host_sync_addr, 1);
2531a859223SAllain Legacy 	if (count < 1) {
254*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Cannot send request %u to host",
2551a859223SAllain Legacy 			    request->req_id);
2561a859223SAllain Legacy 		ret = -EBUSY;
2571a859223SAllain Legacy 		goto done;
2581a859223SAllain Legacy 	}
2591a859223SAllain Legacy 
2601a859223SAllain Legacy 	while (retry--) {
2611a859223SAllain Legacy 		/* wait for a response */
2621a859223SAllain Legacy 		usleep(AVP_REQUEST_DELAY_USECS);
2631a859223SAllain Legacy 
2641a859223SAllain Legacy 		count = avp_fifo_count(avp->resp_q);
2651a859223SAllain Legacy 		if (count >= 1) {
2661a859223SAllain Legacy 			/* response received */
2671a859223SAllain Legacy 			break;
2681a859223SAllain Legacy 		}
2691a859223SAllain Legacy 
270e6b87501SFerruh Yigit 		if (retry == 0) {
271*e99981afSDavid Marchand 			PMD_DRV_LOG_LINE(ERR, "Timeout while waiting for a response for %u",
2721a859223SAllain Legacy 				    request->req_id);
2731a859223SAllain Legacy 			ret = -ETIME;
2741a859223SAllain Legacy 			goto done;
2751a859223SAllain Legacy 		}
2761a859223SAllain Legacy 	}
2771a859223SAllain Legacy 
2781a859223SAllain Legacy 	/* retrieve the response */
2791a859223SAllain Legacy 	count = avp_fifo_get(avp->resp_q, (void **)&resp_addr, 1);
2801a859223SAllain Legacy 	if ((count != 1) || (resp_addr != avp->host_sync_addr)) {
281*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Invalid response from host, count=%u resp=%p host_sync_addr=%p",
2821a859223SAllain Legacy 			    count, resp_addr, avp->host_sync_addr);
2831a859223SAllain Legacy 		ret = -ENODATA;
2841a859223SAllain Legacy 		goto done;
2851a859223SAllain Legacy 	}
2861a859223SAllain Legacy 
2871a859223SAllain Legacy 	/* copy to user buffer */
2881a859223SAllain Legacy 	rte_memcpy(request, avp->sync_addr, sizeof(*request));
2891a859223SAllain Legacy 	ret = 0;
2901a859223SAllain Legacy 
291*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "Result %d received for request %u",
2921a859223SAllain Legacy 		    request->result, request->req_id);
2931a859223SAllain Legacy 
2941a859223SAllain Legacy done:
2951a859223SAllain Legacy 	return ret;
2961a859223SAllain Legacy }
2971a859223SAllain Legacy 
2981a859223SAllain Legacy static int
299ea37523dSAllain Legacy avp_dev_ctrl_set_link_state(struct rte_eth_dev *eth_dev, unsigned int state)
300ea37523dSAllain Legacy {
301ea37523dSAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
302ea37523dSAllain Legacy 	struct rte_avp_request request;
303ea37523dSAllain Legacy 	int ret;
304ea37523dSAllain Legacy 
305ea37523dSAllain Legacy 	/* setup a link state change request */
306ea37523dSAllain Legacy 	memset(&request, 0, sizeof(request));
307ea37523dSAllain Legacy 	request.req_id = RTE_AVP_REQ_CFG_NETWORK_IF;
308ea37523dSAllain Legacy 	request.if_up = state;
309ea37523dSAllain Legacy 
310ea37523dSAllain Legacy 	ret = avp_dev_process_request(avp, &request);
311ea37523dSAllain Legacy 
312ea37523dSAllain Legacy 	return ret == 0 ? request.result : ret;
313ea37523dSAllain Legacy }
314ea37523dSAllain Legacy 
315ea37523dSAllain Legacy static int
3161a859223SAllain Legacy avp_dev_ctrl_set_config(struct rte_eth_dev *eth_dev,
3171a859223SAllain Legacy 			struct rte_avp_device_config *config)
3181a859223SAllain Legacy {
3191a859223SAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
3201a859223SAllain Legacy 	struct rte_avp_request request;
3211a859223SAllain Legacy 	int ret;
3221a859223SAllain Legacy 
3231a859223SAllain Legacy 	/* setup a configure request */
3241a859223SAllain Legacy 	memset(&request, 0, sizeof(request));
3251a859223SAllain Legacy 	request.req_id = RTE_AVP_REQ_CFG_DEVICE;
3261a859223SAllain Legacy 	memcpy(&request.config, config, sizeof(request.config));
3271a859223SAllain Legacy 
3281a859223SAllain Legacy 	ret = avp_dev_process_request(avp, &request);
3291a859223SAllain Legacy 
3301a859223SAllain Legacy 	return ret == 0 ? request.result : ret;
3311a859223SAllain Legacy }
3321a859223SAllain Legacy 
333ea37523dSAllain Legacy static int
334ea37523dSAllain Legacy avp_dev_ctrl_shutdown(struct rte_eth_dev *eth_dev)
335ea37523dSAllain Legacy {
336ea37523dSAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
337ea37523dSAllain Legacy 	struct rte_avp_request request;
338ea37523dSAllain Legacy 	int ret;
339ea37523dSAllain Legacy 
340ea37523dSAllain Legacy 	/* setup a shutdown request */
341ea37523dSAllain Legacy 	memset(&request, 0, sizeof(request));
342ea37523dSAllain Legacy 	request.req_id = RTE_AVP_REQ_SHUTDOWN_DEVICE;
343ea37523dSAllain Legacy 
344ea37523dSAllain Legacy 	ret = avp_dev_process_request(avp, &request);
345ea37523dSAllain Legacy 
346ea37523dSAllain Legacy 	return ret == 0 ? request.result : ret;
347ea37523dSAllain Legacy }
348ea37523dSAllain Legacy 
34950db69fdSAllain Legacy /* translate from host mbuf virtual address to guest virtual address */
35050db69fdSAllain Legacy static inline void *
35150db69fdSAllain Legacy avp_dev_translate_buffer(struct avp_dev *avp, void *host_mbuf_address)
35250db69fdSAllain Legacy {
35350db69fdSAllain Legacy 	return RTE_PTR_ADD(RTE_PTR_SUB(host_mbuf_address,
35450db69fdSAllain Legacy 				       (uintptr_t)avp->host_mbuf_addr),
35550db69fdSAllain Legacy 			   (uintptr_t)avp->mbuf_addr);
35650db69fdSAllain Legacy }
35750db69fdSAllain Legacy 
358c0ad5842SAllain Legacy /* translate from host physical address to guest virtual address */
359c0ad5842SAllain Legacy static void *
360c0ad5842SAllain Legacy avp_dev_translate_address(struct rte_eth_dev *eth_dev,
361df6e0a06SSantosh Shukla 			  rte_iova_t host_phys_addr)
362c0ad5842SAllain Legacy {
363c0802544SFerruh Yigit 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
364c0ad5842SAllain Legacy 	struct rte_mem_resource *resource;
365c0ad5842SAllain Legacy 	struct rte_avp_memmap_info *info;
366c0ad5842SAllain Legacy 	struct rte_avp_memmap *map;
367c0ad5842SAllain Legacy 	off_t offset;
368c0ad5842SAllain Legacy 	void *addr;
369c0ad5842SAllain Legacy 	unsigned int i;
370c0ad5842SAllain Legacy 
371c0ad5842SAllain Legacy 	addr = pci_dev->mem_resource[RTE_AVP_PCI_MEMORY_BAR].addr;
372c0ad5842SAllain Legacy 	resource = &pci_dev->mem_resource[RTE_AVP_PCI_MEMMAP_BAR];
373c0ad5842SAllain Legacy 	info = (struct rte_avp_memmap_info *)resource->addr;
374c0ad5842SAllain Legacy 
375c0ad5842SAllain Legacy 	offset = 0;
376c0ad5842SAllain Legacy 	for (i = 0; i < info->nb_maps; i++) {
377c0ad5842SAllain Legacy 		/* search all segments looking for a matching address */
378c0ad5842SAllain Legacy 		map = &info->maps[i];
379c0ad5842SAllain Legacy 
380c0ad5842SAllain Legacy 		if ((host_phys_addr >= map->phys_addr) &&
381c0ad5842SAllain Legacy 			(host_phys_addr < (map->phys_addr + map->length))) {
382c0ad5842SAllain Legacy 			/* address is within this segment */
383c0ad5842SAllain Legacy 			offset += (host_phys_addr - map->phys_addr);
3848a70b112SBruce Richardson 			addr = RTE_PTR_ADD(addr, (uintptr_t)offset);
385c0ad5842SAllain Legacy 
386*e99981afSDavid Marchand 			PMD_DRV_LOG_LINE(DEBUG, "Translating host physical 0x%" PRIx64 " to guest virtual 0x%p",
387c0ad5842SAllain Legacy 				    host_phys_addr, addr);
388c0ad5842SAllain Legacy 
389c0ad5842SAllain Legacy 			return addr;
390c0ad5842SAllain Legacy 		}
391c0ad5842SAllain Legacy 		offset += map->length;
392c0ad5842SAllain Legacy 	}
393c0ad5842SAllain Legacy 
394c0ad5842SAllain Legacy 	return NULL;
395c0ad5842SAllain Legacy }
396c0ad5842SAllain Legacy 
397c0ad5842SAllain Legacy /* verify that the incoming device version is compatible with our version */
398c0ad5842SAllain Legacy static int
399c0ad5842SAllain Legacy avp_dev_version_check(uint32_t version)
400c0ad5842SAllain Legacy {
401c0ad5842SAllain Legacy 	uint32_t driver = RTE_AVP_STRIP_MINOR_VERSION(AVP_DPDK_DRIVER_VERSION);
402c0ad5842SAllain Legacy 	uint32_t device = RTE_AVP_STRIP_MINOR_VERSION(version);
403c0ad5842SAllain Legacy 
404c0ad5842SAllain Legacy 	if (device <= driver) {
405c0ad5842SAllain Legacy 		/* the host driver version is less than or equal to ours */
406c0ad5842SAllain Legacy 		return 0;
407c0ad5842SAllain Legacy 	}
408c0ad5842SAllain Legacy 
409c0ad5842SAllain Legacy 	return 1;
410c0ad5842SAllain Legacy }
411c0ad5842SAllain Legacy 
412c0ad5842SAllain Legacy /* verify that memory regions have expected version and validation markers */
413c0ad5842SAllain Legacy static int
414c0ad5842SAllain Legacy avp_dev_check_regions(struct rte_eth_dev *eth_dev)
415c0ad5842SAllain Legacy {
416c0802544SFerruh Yigit 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
417c0ad5842SAllain Legacy 	struct rte_avp_memmap_info *memmap;
418c0ad5842SAllain Legacy 	struct rte_avp_device_info *info;
419c0ad5842SAllain Legacy 	struct rte_mem_resource *resource;
420c0ad5842SAllain Legacy 	unsigned int i;
421c0ad5842SAllain Legacy 
422c0ad5842SAllain Legacy 	/* Dump resource info for debug */
423c0ad5842SAllain Legacy 	for (i = 0; i < PCI_MAX_RESOURCE; i++) {
424c0ad5842SAllain Legacy 		resource = &pci_dev->mem_resource[i];
425c0ad5842SAllain Legacy 		if ((resource->phys_addr == 0) || (resource->len == 0))
426c0ad5842SAllain Legacy 			continue;
427c0ad5842SAllain Legacy 
428*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(DEBUG, "resource[%u]: phys=0x%" PRIx64 " len=%" PRIu64 " addr=%p",
429c0ad5842SAllain Legacy 			    i, resource->phys_addr,
430c0ad5842SAllain Legacy 			    resource->len, resource->addr);
431c0ad5842SAllain Legacy 
432c0ad5842SAllain Legacy 		switch (i) {
433c0ad5842SAllain Legacy 		case RTE_AVP_PCI_MEMMAP_BAR:
434c0ad5842SAllain Legacy 			memmap = (struct rte_avp_memmap_info *)resource->addr;
435c0ad5842SAllain Legacy 			if ((memmap->magic != RTE_AVP_MEMMAP_MAGIC) ||
436c0ad5842SAllain Legacy 			    (memmap->version != RTE_AVP_MEMMAP_VERSION)) {
437*e99981afSDavid Marchand 				PMD_DRV_LOG_LINE(ERR, "Invalid memmap magic 0x%08x and version %u",
438c0ad5842SAllain Legacy 					    memmap->magic, memmap->version);
439c0ad5842SAllain Legacy 				return -EINVAL;
440c0ad5842SAllain Legacy 			}
441c0ad5842SAllain Legacy 			break;
442c0ad5842SAllain Legacy 
443c0ad5842SAllain Legacy 		case RTE_AVP_PCI_DEVICE_BAR:
444c0ad5842SAllain Legacy 			info = (struct rte_avp_device_info *)resource->addr;
445c0ad5842SAllain Legacy 			if ((info->magic != RTE_AVP_DEVICE_MAGIC) ||
446c0ad5842SAllain Legacy 			    avp_dev_version_check(info->version)) {
447*e99981afSDavid Marchand 				PMD_DRV_LOG_LINE(ERR, "Invalid device info magic 0x%08x or version 0x%08x > 0x%08x",
448c0ad5842SAllain Legacy 					    info->magic, info->version,
449c0ad5842SAllain Legacy 					    AVP_DPDK_DRIVER_VERSION);
450c0ad5842SAllain Legacy 				return -EINVAL;
451c0ad5842SAllain Legacy 			}
452c0ad5842SAllain Legacy 			break;
453c0ad5842SAllain Legacy 
454c0ad5842SAllain Legacy 		case RTE_AVP_PCI_MEMORY_BAR:
455c0ad5842SAllain Legacy 		case RTE_AVP_PCI_MMIO_BAR:
456c0ad5842SAllain Legacy 			if (resource->addr == NULL) {
457*e99981afSDavid Marchand 				PMD_DRV_LOG_LINE(ERR, "Missing address space for BAR%u",
458c0ad5842SAllain Legacy 					    i);
459c0ad5842SAllain Legacy 				return -EINVAL;
460c0ad5842SAllain Legacy 			}
461c0ad5842SAllain Legacy 			break;
462c0ad5842SAllain Legacy 
463c0ad5842SAllain Legacy 		case RTE_AVP_PCI_MSIX_BAR:
464c0ad5842SAllain Legacy 		default:
465c0ad5842SAllain Legacy 			/* no validation required */
466c0ad5842SAllain Legacy 			break;
467c0ad5842SAllain Legacy 		}
468c0ad5842SAllain Legacy 	}
469c0ad5842SAllain Legacy 
470c0ad5842SAllain Legacy 	return 0;
471c0ad5842SAllain Legacy }
472c0ad5842SAllain Legacy 
47382e140b8SAllain Legacy static int
47482e140b8SAllain Legacy avp_dev_detach(struct rte_eth_dev *eth_dev)
47582e140b8SAllain Legacy {
47682e140b8SAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
47782e140b8SAllain Legacy 	int ret;
47882e140b8SAllain Legacy 
479*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(NOTICE, "Detaching port %u from AVP device 0x%" PRIx64 "",
48082e140b8SAllain Legacy 		    eth_dev->data->port_id, avp->device_id);
48182e140b8SAllain Legacy 
48282e140b8SAllain Legacy 	rte_spinlock_lock(&avp->lock);
48382e140b8SAllain Legacy 
48482e140b8SAllain Legacy 	if (avp->flags & AVP_F_DETACHED) {
485*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(NOTICE, "port %u already detached",
48682e140b8SAllain Legacy 			    eth_dev->data->port_id);
48782e140b8SAllain Legacy 		ret = 0;
48882e140b8SAllain Legacy 		goto unlock;
48982e140b8SAllain Legacy 	}
49082e140b8SAllain Legacy 
49182e140b8SAllain Legacy 	/* shutdown the device first so the host stops sending us packets. */
49282e140b8SAllain Legacy 	ret = avp_dev_ctrl_shutdown(eth_dev);
49382e140b8SAllain Legacy 	if (ret < 0) {
494*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Failed to send/recv shutdown to host, ret=%d",
49582e140b8SAllain Legacy 			    ret);
49682e140b8SAllain Legacy 		avp->flags &= ~AVP_F_DETACHED;
49782e140b8SAllain Legacy 		goto unlock;
49882e140b8SAllain Legacy 	}
49982e140b8SAllain Legacy 
50082e140b8SAllain Legacy 	avp->flags |= AVP_F_DETACHED;
50182e140b8SAllain Legacy 	rte_wmb();
50282e140b8SAllain Legacy 
50382e140b8SAllain Legacy 	/* wait for queues to acknowledge the presence of the detach flag */
50482e140b8SAllain Legacy 	rte_delay_ms(1);
50582e140b8SAllain Legacy 
50682e140b8SAllain Legacy 	ret = 0;
50782e140b8SAllain Legacy 
50882e140b8SAllain Legacy unlock:
50982e140b8SAllain Legacy 	rte_spinlock_unlock(&avp->lock);
51082e140b8SAllain Legacy 	return ret;
51182e140b8SAllain Legacy }
51282e140b8SAllain Legacy 
5131a859223SAllain Legacy static void
514cce4367fSAllain Legacy _avp_set_rx_queue_mappings(struct rte_eth_dev *eth_dev, uint16_t rx_queue_id)
515cce4367fSAllain Legacy {
516cce4367fSAllain Legacy 	struct avp_dev *avp =
517cce4367fSAllain Legacy 		AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
518cce4367fSAllain Legacy 	struct avp_queue *rxq;
519cce4367fSAllain Legacy 	uint16_t queue_count;
520cce4367fSAllain Legacy 	uint16_t remainder;
521cce4367fSAllain Legacy 
522cce4367fSAllain Legacy 	rxq = (struct avp_queue *)eth_dev->data->rx_queues[rx_queue_id];
523cce4367fSAllain Legacy 
524cce4367fSAllain Legacy 	/*
525cce4367fSAllain Legacy 	 * Must map all AVP fifos as evenly as possible between the configured
526cce4367fSAllain Legacy 	 * device queues.  Each device queue will service a subset of the AVP
527cce4367fSAllain Legacy 	 * fifos. If there is an odd number of device queues the first set of
528cce4367fSAllain Legacy 	 * device queues will get the extra AVP fifos.
529cce4367fSAllain Legacy 	 */
530cce4367fSAllain Legacy 	queue_count = avp->num_rx_queues / eth_dev->data->nb_rx_queues;
531cce4367fSAllain Legacy 	remainder = avp->num_rx_queues % eth_dev->data->nb_rx_queues;
532cce4367fSAllain Legacy 	if (rx_queue_id < remainder) {
533cce4367fSAllain Legacy 		/* these queues must service one extra FIFO */
534cce4367fSAllain Legacy 		rxq->queue_base = rx_queue_id * (queue_count + 1);
535cce4367fSAllain Legacy 		rxq->queue_limit = rxq->queue_base + (queue_count + 1) - 1;
536cce4367fSAllain Legacy 	} else {
537cce4367fSAllain Legacy 		/* these queues service the regular number of FIFO */
538cce4367fSAllain Legacy 		rxq->queue_base = ((remainder * (queue_count + 1)) +
539cce4367fSAllain Legacy 				   ((rx_queue_id - remainder) * queue_count));
540cce4367fSAllain Legacy 		rxq->queue_limit = rxq->queue_base + queue_count - 1;
541cce4367fSAllain Legacy 	}
542cce4367fSAllain Legacy 
543*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "rxq %u at %p base %u limit %u",
544cce4367fSAllain Legacy 		    rx_queue_id, rxq, rxq->queue_base, rxq->queue_limit);
545cce4367fSAllain Legacy 
546cce4367fSAllain Legacy 	rxq->queue_id = rxq->queue_base;
547cce4367fSAllain Legacy }
548cce4367fSAllain Legacy 
549cce4367fSAllain Legacy static void
5501a859223SAllain Legacy _avp_set_queue_counts(struct rte_eth_dev *eth_dev)
5511a859223SAllain Legacy {
552c0802544SFerruh Yigit 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
5531a859223SAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
5541a859223SAllain Legacy 	struct rte_avp_device_info *host_info;
5551a859223SAllain Legacy 	void *addr;
5561a859223SAllain Legacy 
5571a859223SAllain Legacy 	addr = pci_dev->mem_resource[RTE_AVP_PCI_DEVICE_BAR].addr;
5581a859223SAllain Legacy 	host_info = (struct rte_avp_device_info *)addr;
5591a859223SAllain Legacy 
5601a859223SAllain Legacy 	/*
5611a859223SAllain Legacy 	 * the transmit direction is not negotiated beyond respecting the max
5621a859223SAllain Legacy 	 * number of queues because the host can handle arbitrary guest tx
5631a859223SAllain Legacy 	 * queues (host rx queues).
5641a859223SAllain Legacy 	 */
5651a859223SAllain Legacy 	avp->num_tx_queues = eth_dev->data->nb_tx_queues;
5661a859223SAllain Legacy 
5671a859223SAllain Legacy 	/*
5681a859223SAllain Legacy 	 * the receive direction is more restrictive.  The host requires a
5691a859223SAllain Legacy 	 * minimum number of guest rx queues (host tx queues) therefore
5701a859223SAllain Legacy 	 * negotiate a value that is at least as large as the host minimum
5711a859223SAllain Legacy 	 * requirement.  If the host and guest values are not identical then a
5721a859223SAllain Legacy 	 * mapping will be established in the receive_queue_setup function.
5731a859223SAllain Legacy 	 */
5741a859223SAllain Legacy 	avp->num_rx_queues = RTE_MAX(host_info->min_rx_queues,
5751a859223SAllain Legacy 				     eth_dev->data->nb_rx_queues);
5761a859223SAllain Legacy 
577*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "Requesting %u Tx and %u Rx queues from host",
5781a859223SAllain Legacy 		    avp->num_tx_queues, avp->num_rx_queues);
5791a859223SAllain Legacy }
5801a859223SAllain Legacy 
58182e140b8SAllain Legacy static int
58282e140b8SAllain Legacy avp_dev_attach(struct rte_eth_dev *eth_dev)
58382e140b8SAllain Legacy {
58482e140b8SAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
58582e140b8SAllain Legacy 	struct rte_avp_device_config config;
58682e140b8SAllain Legacy 	unsigned int i;
58782e140b8SAllain Legacy 	int ret;
58882e140b8SAllain Legacy 
589*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(NOTICE, "Attaching port %u to AVP device 0x%" PRIx64 "",
59082e140b8SAllain Legacy 		    eth_dev->data->port_id, avp->device_id);
59182e140b8SAllain Legacy 
59282e140b8SAllain Legacy 	rte_spinlock_lock(&avp->lock);
59382e140b8SAllain Legacy 
59482e140b8SAllain Legacy 	if (!(avp->flags & AVP_F_DETACHED)) {
595*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(NOTICE, "port %u already attached",
59682e140b8SAllain Legacy 			    eth_dev->data->port_id);
59782e140b8SAllain Legacy 		ret = 0;
59882e140b8SAllain Legacy 		goto unlock;
59982e140b8SAllain Legacy 	}
60082e140b8SAllain Legacy 
60182e140b8SAllain Legacy 	/*
60282e140b8SAllain Legacy 	 * make sure that the detached flag is set prior to reconfiguring the
60382e140b8SAllain Legacy 	 * queues.
60482e140b8SAllain Legacy 	 */
60582e140b8SAllain Legacy 	avp->flags |= AVP_F_DETACHED;
60682e140b8SAllain Legacy 	rte_wmb();
60782e140b8SAllain Legacy 
60882e140b8SAllain Legacy 	/*
60982e140b8SAllain Legacy 	 * re-run the device create utility which will parse the new host info
61082e140b8SAllain Legacy 	 * and setup the AVP device queue pointers.
61182e140b8SAllain Legacy 	 */
612c0802544SFerruh Yigit 	ret = avp_dev_create(RTE_ETH_DEV_TO_PCI(eth_dev), eth_dev);
61382e140b8SAllain Legacy 	if (ret < 0) {
614*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Failed to re-create AVP device, ret=%d",
61582e140b8SAllain Legacy 			    ret);
61682e140b8SAllain Legacy 		goto unlock;
61782e140b8SAllain Legacy 	}
61882e140b8SAllain Legacy 
61982e140b8SAllain Legacy 	if (avp->flags & AVP_F_CONFIGURED) {
62082e140b8SAllain Legacy 		/*
62182e140b8SAllain Legacy 		 * Update the receive queue mapping to handle cases where the
62282e140b8SAllain Legacy 		 * source and destination hosts have different queue
62382e140b8SAllain Legacy 		 * requirements.  As long as the DETACHED flag is asserted the
62482e140b8SAllain Legacy 		 * queue table should not be referenced so it should be safe to
62582e140b8SAllain Legacy 		 * update it.
62682e140b8SAllain Legacy 		 */
62782e140b8SAllain Legacy 		_avp_set_queue_counts(eth_dev);
62882e140b8SAllain Legacy 		for (i = 0; i < eth_dev->data->nb_rx_queues; i++)
62982e140b8SAllain Legacy 			_avp_set_rx_queue_mappings(eth_dev, i);
63082e140b8SAllain Legacy 
63182e140b8SAllain Legacy 		/*
63282e140b8SAllain Legacy 		 * Update the host with our config details so that it knows the
63382e140b8SAllain Legacy 		 * device is active.
63482e140b8SAllain Legacy 		 */
63582e140b8SAllain Legacy 		memset(&config, 0, sizeof(config));
63682e140b8SAllain Legacy 		config.device_id = avp->device_id;
63782e140b8SAllain Legacy 		config.driver_type = RTE_AVP_DRIVER_TYPE_DPDK;
63882e140b8SAllain Legacy 		config.driver_version = AVP_DPDK_DRIVER_VERSION;
63982e140b8SAllain Legacy 		config.features = avp->features;
64082e140b8SAllain Legacy 		config.num_tx_queues = avp->num_tx_queues;
64182e140b8SAllain Legacy 		config.num_rx_queues = avp->num_rx_queues;
64282e140b8SAllain Legacy 		config.if_up = !!(avp->flags & AVP_F_LINKUP);
64382e140b8SAllain Legacy 
64482e140b8SAllain Legacy 		ret = avp_dev_ctrl_set_config(eth_dev, &config);
64582e140b8SAllain Legacy 		if (ret < 0) {
646*e99981afSDavid Marchand 			PMD_DRV_LOG_LINE(ERR, "Config request failed by host, ret=%d",
64782e140b8SAllain Legacy 				    ret);
64882e140b8SAllain Legacy 			goto unlock;
64982e140b8SAllain Legacy 		}
65082e140b8SAllain Legacy 	}
65182e140b8SAllain Legacy 
65282e140b8SAllain Legacy 	rte_wmb();
65382e140b8SAllain Legacy 	avp->flags &= ~AVP_F_DETACHED;
65482e140b8SAllain Legacy 
65582e140b8SAllain Legacy 	ret = 0;
65682e140b8SAllain Legacy 
65782e140b8SAllain Legacy unlock:
65882e140b8SAllain Legacy 	rte_spinlock_unlock(&avp->lock);
65982e140b8SAllain Legacy 	return ret;
66082e140b8SAllain Legacy }
66182e140b8SAllain Legacy 
66282e140b8SAllain Legacy static void
663c23a1a30SQi Zhang avp_dev_interrupt_handler(void *data)
66482e140b8SAllain Legacy {
66582e140b8SAllain Legacy 	struct rte_eth_dev *eth_dev = data;
666c0802544SFerruh Yigit 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
66782e140b8SAllain Legacy 	void *registers = pci_dev->mem_resource[RTE_AVP_PCI_MMIO_BAR].addr;
66882e140b8SAllain Legacy 	uint32_t status, value;
66982e140b8SAllain Legacy 	int ret;
67082e140b8SAllain Legacy 
67182e140b8SAllain Legacy 	if (registers == NULL)
67282e140b8SAllain Legacy 		rte_panic("no mapped MMIO register space\n");
67382e140b8SAllain Legacy 
67482e140b8SAllain Legacy 	/* read the interrupt status register
67582e140b8SAllain Legacy 	 * note: this register clears on read so all raised interrupts must be
67682e140b8SAllain Legacy 	 *    handled or remembered for later processing
67782e140b8SAllain Legacy 	 */
67882e140b8SAllain Legacy 	status = AVP_READ32(
67982e140b8SAllain Legacy 		RTE_PTR_ADD(registers,
68082e140b8SAllain Legacy 			    RTE_AVP_INTERRUPT_STATUS_OFFSET));
68182e140b8SAllain Legacy 
682f353fbc5SFerruh Yigit 	if (status & RTE_AVP_MIGRATION_INTERRUPT_MASK) {
68382e140b8SAllain Legacy 		/* handle interrupt based on current status */
68482e140b8SAllain Legacy 		value = AVP_READ32(
68582e140b8SAllain Legacy 			RTE_PTR_ADD(registers,
68682e140b8SAllain Legacy 				    RTE_AVP_MIGRATION_STATUS_OFFSET));
68782e140b8SAllain Legacy 		switch (value) {
68882e140b8SAllain Legacy 		case RTE_AVP_MIGRATION_DETACHED:
68982e140b8SAllain Legacy 			ret = avp_dev_detach(eth_dev);
69082e140b8SAllain Legacy 			break;
69182e140b8SAllain Legacy 		case RTE_AVP_MIGRATION_ATTACHED:
69282e140b8SAllain Legacy 			ret = avp_dev_attach(eth_dev);
69382e140b8SAllain Legacy 			break;
69482e140b8SAllain Legacy 		default:
695*e99981afSDavid Marchand 			PMD_DRV_LOG_LINE(ERR, "unexpected migration status, status=%u",
69682e140b8SAllain Legacy 				    value);
69782e140b8SAllain Legacy 			ret = -EINVAL;
69882e140b8SAllain Legacy 		}
69982e140b8SAllain Legacy 
70082e140b8SAllain Legacy 		/* acknowledge the request by writing out our current status */
70182e140b8SAllain Legacy 		value = (ret == 0 ? value : RTE_AVP_MIGRATION_ERROR);
70282e140b8SAllain Legacy 		AVP_WRITE32(value,
70382e140b8SAllain Legacy 			    RTE_PTR_ADD(registers,
70482e140b8SAllain Legacy 					RTE_AVP_MIGRATION_ACK_OFFSET));
70582e140b8SAllain Legacy 
706*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(NOTICE, "AVP migration interrupt handled");
70782e140b8SAllain Legacy 	}
70882e140b8SAllain Legacy 
70982e140b8SAllain Legacy 	if (status & ~RTE_AVP_MIGRATION_INTERRUPT_MASK)
710*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(WARNING, "AVP unexpected interrupt, status=0x%08x",
71182e140b8SAllain Legacy 			    status);
71282e140b8SAllain Legacy 
71382e140b8SAllain Legacy 	/* re-enable UIO interrupt handling */
714d61138d4SHarman Kalra 	ret = rte_intr_ack(pci_dev->intr_handle);
71582e140b8SAllain Legacy 	if (ret < 0) {
716*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Failed to re-enable UIO interrupts, ret=%d",
71782e140b8SAllain Legacy 			    ret);
71882e140b8SAllain Legacy 		/* continue */
71982e140b8SAllain Legacy 	}
72082e140b8SAllain Legacy }
72182e140b8SAllain Legacy 
72282e140b8SAllain Legacy static int
72382e140b8SAllain Legacy avp_dev_enable_interrupts(struct rte_eth_dev *eth_dev)
72482e140b8SAllain Legacy {
725c0802544SFerruh Yigit 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
72682e140b8SAllain Legacy 	void *registers = pci_dev->mem_resource[RTE_AVP_PCI_MMIO_BAR].addr;
72782e140b8SAllain Legacy 	int ret;
72882e140b8SAllain Legacy 
72982e140b8SAllain Legacy 	if (registers == NULL)
73082e140b8SAllain Legacy 		return -EINVAL;
73182e140b8SAllain Legacy 
73282e140b8SAllain Legacy 	/* enable UIO interrupt handling */
733d61138d4SHarman Kalra 	ret = rte_intr_enable(pci_dev->intr_handle);
73482e140b8SAllain Legacy 	if (ret < 0) {
735*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Failed to enable UIO interrupts, ret=%d",
73682e140b8SAllain Legacy 			    ret);
73782e140b8SAllain Legacy 		return ret;
73882e140b8SAllain Legacy 	}
73982e140b8SAllain Legacy 
74082e140b8SAllain Legacy 	/* inform the device that all interrupts are enabled */
74182e140b8SAllain Legacy 	AVP_WRITE32(RTE_AVP_APP_INTERRUPTS_MASK,
74282e140b8SAllain Legacy 		    RTE_PTR_ADD(registers, RTE_AVP_INTERRUPT_MASK_OFFSET));
74382e140b8SAllain Legacy 
74482e140b8SAllain Legacy 	return 0;
74582e140b8SAllain Legacy }
74682e140b8SAllain Legacy 
74782e140b8SAllain Legacy static int
74882e140b8SAllain Legacy avp_dev_disable_interrupts(struct rte_eth_dev *eth_dev)
74982e140b8SAllain Legacy {
750c0802544SFerruh Yigit 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
75182e140b8SAllain Legacy 	void *registers = pci_dev->mem_resource[RTE_AVP_PCI_MMIO_BAR].addr;
75282e140b8SAllain Legacy 	int ret;
75382e140b8SAllain Legacy 
75482e140b8SAllain Legacy 	if (registers == NULL)
75582e140b8SAllain Legacy 		return 0;
75682e140b8SAllain Legacy 
75782e140b8SAllain Legacy 	/* inform the device that all interrupts are disabled */
75882e140b8SAllain Legacy 	AVP_WRITE32(RTE_AVP_NO_INTERRUPTS_MASK,
75982e140b8SAllain Legacy 		    RTE_PTR_ADD(registers, RTE_AVP_INTERRUPT_MASK_OFFSET));
76082e140b8SAllain Legacy 
76182e140b8SAllain Legacy 	/* enable UIO interrupt handling */
762d61138d4SHarman Kalra 	ret = rte_intr_disable(pci_dev->intr_handle);
76382e140b8SAllain Legacy 	if (ret < 0) {
764*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Failed to disable UIO interrupts, ret=%d",
76582e140b8SAllain Legacy 			    ret);
76682e140b8SAllain Legacy 		return ret;
76782e140b8SAllain Legacy 	}
76882e140b8SAllain Legacy 
76982e140b8SAllain Legacy 	return 0;
77082e140b8SAllain Legacy }
77182e140b8SAllain Legacy 
77282e140b8SAllain Legacy static int
77382e140b8SAllain Legacy avp_dev_setup_interrupts(struct rte_eth_dev *eth_dev)
77482e140b8SAllain Legacy {
775c0802544SFerruh Yigit 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
77682e140b8SAllain Legacy 	int ret;
77782e140b8SAllain Legacy 
77882e140b8SAllain Legacy 	/* register a callback handler with UIO for interrupt notifications */
779d61138d4SHarman Kalra 	ret = rte_intr_callback_register(pci_dev->intr_handle,
78082e140b8SAllain Legacy 					 avp_dev_interrupt_handler,
78182e140b8SAllain Legacy 					 (void *)eth_dev);
78282e140b8SAllain Legacy 	if (ret < 0) {
783*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Failed to register UIO interrupt callback, ret=%d",
78482e140b8SAllain Legacy 			    ret);
78582e140b8SAllain Legacy 		return ret;
78682e140b8SAllain Legacy 	}
78782e140b8SAllain Legacy 
78882e140b8SAllain Legacy 	/* enable interrupt processing */
78982e140b8SAllain Legacy 	return avp_dev_enable_interrupts(eth_dev);
79082e140b8SAllain Legacy }
79182e140b8SAllain Legacy 
79282e140b8SAllain Legacy static int
79382e140b8SAllain Legacy avp_dev_migration_pending(struct rte_eth_dev *eth_dev)
79482e140b8SAllain Legacy {
795c0802544SFerruh Yigit 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
79682e140b8SAllain Legacy 	void *registers = pci_dev->mem_resource[RTE_AVP_PCI_MMIO_BAR].addr;
79782e140b8SAllain Legacy 	uint32_t value;
79882e140b8SAllain Legacy 
79982e140b8SAllain Legacy 	if (registers == NULL)
80082e140b8SAllain Legacy 		return 0;
80182e140b8SAllain Legacy 
80282e140b8SAllain Legacy 	value = AVP_READ32(RTE_PTR_ADD(registers,
80382e140b8SAllain Legacy 				       RTE_AVP_MIGRATION_STATUS_OFFSET));
80482e140b8SAllain Legacy 	if (value == RTE_AVP_MIGRATION_DETACHED) {
80582e140b8SAllain Legacy 		/* migration is in progress; ack it if we have not already */
80682e140b8SAllain Legacy 		AVP_WRITE32(value,
80782e140b8SAllain Legacy 			    RTE_PTR_ADD(registers,
80882e140b8SAllain Legacy 					RTE_AVP_MIGRATION_ACK_OFFSET));
80982e140b8SAllain Legacy 		return 1;
81082e140b8SAllain Legacy 	}
81182e140b8SAllain Legacy 	return 0;
81282e140b8SAllain Legacy }
81382e140b8SAllain Legacy 
814c0ad5842SAllain Legacy /*
815c0ad5842SAllain Legacy  * create a AVP device using the supplied device info by first translating it
816c0ad5842SAllain Legacy  * to guest address space(s).
817c0ad5842SAllain Legacy  */
818c0ad5842SAllain Legacy static int
819c0ad5842SAllain Legacy avp_dev_create(struct rte_pci_device *pci_dev,
820c0ad5842SAllain Legacy 	       struct rte_eth_dev *eth_dev)
821c0ad5842SAllain Legacy {
822c0ad5842SAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
823c0ad5842SAllain Legacy 	struct rte_avp_device_info *host_info;
824c0ad5842SAllain Legacy 	struct rte_mem_resource *resource;
825c0ad5842SAllain Legacy 	unsigned int i;
826c0ad5842SAllain Legacy 
827c0ad5842SAllain Legacy 	resource = &pci_dev->mem_resource[RTE_AVP_PCI_DEVICE_BAR];
828c0ad5842SAllain Legacy 	if (resource->addr == NULL) {
829*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "BAR%u is not mapped",
830c0ad5842SAllain Legacy 			    RTE_AVP_PCI_DEVICE_BAR);
831c0ad5842SAllain Legacy 		return -EFAULT;
832c0ad5842SAllain Legacy 	}
833c0ad5842SAllain Legacy 	host_info = (struct rte_avp_device_info *)resource->addr;
834c0ad5842SAllain Legacy 
835c0ad5842SAllain Legacy 	if ((host_info->magic != RTE_AVP_DEVICE_MAGIC) ||
836c0ad5842SAllain Legacy 		avp_dev_version_check(host_info->version)) {
837*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Invalid AVP PCI device, magic 0x%08x version 0x%08x > 0x%08x",
838c0ad5842SAllain Legacy 			    host_info->magic, host_info->version,
839c0ad5842SAllain Legacy 			    AVP_DPDK_DRIVER_VERSION);
840c0ad5842SAllain Legacy 		return -EINVAL;
841c0ad5842SAllain Legacy 	}
842c0ad5842SAllain Legacy 
843*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "AVP host device is v%u.%u.%u",
844c0ad5842SAllain Legacy 		    RTE_AVP_GET_RELEASE_VERSION(host_info->version),
845c0ad5842SAllain Legacy 		    RTE_AVP_GET_MAJOR_VERSION(host_info->version),
846c0ad5842SAllain Legacy 		    RTE_AVP_GET_MINOR_VERSION(host_info->version));
847c0ad5842SAllain Legacy 
848*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "AVP host supports %u to %u TX queue(s)",
849c0ad5842SAllain Legacy 		    host_info->min_tx_queues, host_info->max_tx_queues);
850*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "AVP host supports %u to %u RX queue(s)",
851c0ad5842SAllain Legacy 		    host_info->min_rx_queues, host_info->max_rx_queues);
852*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "AVP host supports features 0x%08x",
853c0ad5842SAllain Legacy 		    host_info->features);
854c0ad5842SAllain Legacy 
855c0ad5842SAllain Legacy 	if (avp->magic != AVP_ETHDEV_MAGIC) {
856c0ad5842SAllain Legacy 		/*
857c0ad5842SAllain Legacy 		 * First time initialization (i.e., not during a VM
858c0ad5842SAllain Legacy 		 * migration)
859c0ad5842SAllain Legacy 		 */
860c0ad5842SAllain Legacy 		memset(avp, 0, sizeof(*avp));
861c0ad5842SAllain Legacy 		avp->magic = AVP_ETHDEV_MAGIC;
862c0ad5842SAllain Legacy 		avp->dev_data = eth_dev->data;
863c0ad5842SAllain Legacy 		avp->port_id = eth_dev->data->port_id;
864c0ad5842SAllain Legacy 		avp->host_mbuf_size = host_info->mbuf_size;
865c0ad5842SAllain Legacy 		avp->host_features = host_info->features;
86682e140b8SAllain Legacy 		rte_spinlock_init(&avp->lock);
867c0ad5842SAllain Legacy 		memcpy(&avp->ethaddr.addr_bytes[0],
86835b2d13fSOlivier Matz 		       host_info->ethaddr, RTE_ETHER_ADDR_LEN);
869c0ad5842SAllain Legacy 		/* adjust max values to not exceed our max */
870c0ad5842SAllain Legacy 		avp->max_tx_queues =
871c0ad5842SAllain Legacy 			RTE_MIN(host_info->max_tx_queues, RTE_AVP_MAX_QUEUES);
872c0ad5842SAllain Legacy 		avp->max_rx_queues =
873c0ad5842SAllain Legacy 			RTE_MIN(host_info->max_rx_queues, RTE_AVP_MAX_QUEUES);
874c0ad5842SAllain Legacy 	} else {
875c0ad5842SAllain Legacy 		/* Re-attaching during migration */
876c0ad5842SAllain Legacy 
877c0ad5842SAllain Legacy 		/* TODO... requires validation of host values */
878c0ad5842SAllain Legacy 		if ((host_info->features & avp->features) != avp->features) {
879*e99981afSDavid Marchand 			PMD_DRV_LOG_LINE(ERR, "AVP host features mismatched; 0x%08x, host=0x%08x",
880c0ad5842SAllain Legacy 				    avp->features, host_info->features);
881c0ad5842SAllain Legacy 			/* this should not be possible; continue for now */
882c0ad5842SAllain Legacy 		}
883c0ad5842SAllain Legacy 	}
884c0ad5842SAllain Legacy 
885c0ad5842SAllain Legacy 	/* the device id is allowed to change over migrations */
886c0ad5842SAllain Legacy 	avp->device_id = host_info->device_id;
887c0ad5842SAllain Legacy 
888c0ad5842SAllain Legacy 	/* translate incoming host addresses to guest address space */
889*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "AVP first host tx queue at 0x%" PRIx64 "",
890c0ad5842SAllain Legacy 		    host_info->tx_phys);
891*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "AVP first host alloc queue at 0x%" PRIx64 "",
892c0ad5842SAllain Legacy 		    host_info->alloc_phys);
893c0ad5842SAllain Legacy 	for (i = 0; i < avp->max_tx_queues; i++) {
894c0ad5842SAllain Legacy 		avp->tx_q[i] = avp_dev_translate_address(eth_dev,
895c0ad5842SAllain Legacy 			host_info->tx_phys + (i * host_info->tx_size));
896c0ad5842SAllain Legacy 
897c0ad5842SAllain Legacy 		avp->alloc_q[i] = avp_dev_translate_address(eth_dev,
898c0ad5842SAllain Legacy 			host_info->alloc_phys + (i * host_info->alloc_size));
899c0ad5842SAllain Legacy 	}
900c0ad5842SAllain Legacy 
901*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "AVP first host rx queue at 0x%" PRIx64 "",
902c0ad5842SAllain Legacy 		    host_info->rx_phys);
903*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "AVP first host free queue at 0x%" PRIx64 "",
904c0ad5842SAllain Legacy 		    host_info->free_phys);
905c0ad5842SAllain Legacy 	for (i = 0; i < avp->max_rx_queues; i++) {
906c0ad5842SAllain Legacy 		avp->rx_q[i] = avp_dev_translate_address(eth_dev,
907c0ad5842SAllain Legacy 			host_info->rx_phys + (i * host_info->rx_size));
908c0ad5842SAllain Legacy 		avp->free_q[i] = avp_dev_translate_address(eth_dev,
909c0ad5842SAllain Legacy 			host_info->free_phys + (i * host_info->free_size));
910c0ad5842SAllain Legacy 	}
911c0ad5842SAllain Legacy 
912*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "AVP host request queue at 0x%" PRIx64 "",
913c0ad5842SAllain Legacy 		    host_info->req_phys);
914*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "AVP host response queue at 0x%" PRIx64 "",
915c0ad5842SAllain Legacy 		    host_info->resp_phys);
916*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "AVP host sync address at 0x%" PRIx64 "",
917c0ad5842SAllain Legacy 		    host_info->sync_phys);
918*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "AVP host mbuf address at 0x%" PRIx64 "",
919c0ad5842SAllain Legacy 		    host_info->mbuf_phys);
920c0ad5842SAllain Legacy 	avp->req_q = avp_dev_translate_address(eth_dev, host_info->req_phys);
921c0ad5842SAllain Legacy 	avp->resp_q = avp_dev_translate_address(eth_dev, host_info->resp_phys);
922c0ad5842SAllain Legacy 	avp->sync_addr =
923c0ad5842SAllain Legacy 		avp_dev_translate_address(eth_dev, host_info->sync_phys);
924c0ad5842SAllain Legacy 	avp->mbuf_addr =
925c0ad5842SAllain Legacy 		avp_dev_translate_address(eth_dev, host_info->mbuf_phys);
926c0ad5842SAllain Legacy 
927c0ad5842SAllain Legacy 	/*
928c0ad5842SAllain Legacy 	 * store the host mbuf virtual address so that we can calculate
929c0ad5842SAllain Legacy 	 * relative offsets for each mbuf as they are processed
930c0ad5842SAllain Legacy 	 */
931c0ad5842SAllain Legacy 	avp->host_mbuf_addr = host_info->mbuf_va;
932c0ad5842SAllain Legacy 	avp->host_sync_addr = host_info->sync_va;
933c0ad5842SAllain Legacy 
934c0ad5842SAllain Legacy 	/*
935c0ad5842SAllain Legacy 	 * store the maximum packet length that is supported by the host.
936c0ad5842SAllain Legacy 	 */
937c0ad5842SAllain Legacy 	avp->max_rx_pkt_len = host_info->max_rx_pkt_len;
938*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "AVP host max receive packet length is %u",
939c0ad5842SAllain Legacy 				host_info->max_rx_pkt_len);
940c0ad5842SAllain Legacy 
941c0ad5842SAllain Legacy 	return 0;
942c0ad5842SAllain Legacy }
943c0ad5842SAllain Legacy 
944c0ad5842SAllain Legacy /*
945908072e9SAllain Legacy  * This function is based on probe() function in avp_pci.c
946908072e9SAllain Legacy  * It returns 0 on success.
947908072e9SAllain Legacy  */
948908072e9SAllain Legacy static int
949908072e9SAllain Legacy eth_avp_dev_init(struct rte_eth_dev *eth_dev)
950908072e9SAllain Legacy {
951c0ad5842SAllain Legacy 	struct avp_dev *avp =
952c0ad5842SAllain Legacy 		AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
953908072e9SAllain Legacy 	struct rte_pci_device *pci_dev;
954c0ad5842SAllain Legacy 	int ret;
955908072e9SAllain Legacy 
956c0802544SFerruh Yigit 	pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
9571a859223SAllain Legacy 	eth_dev->dev_ops = &avp_eth_dev_ops;
95850db69fdSAllain Legacy 	eth_dev->rx_pkt_burst = &avp_recv_pkts;
959295abce2SAllain Legacy 	eth_dev->tx_pkt_burst = &avp_xmit_pkts;
960908072e9SAllain Legacy 
961908072e9SAllain Legacy 	if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
962908072e9SAllain Legacy 		/*
963908072e9SAllain Legacy 		 * no setup required on secondary processes.  All data is saved
964908072e9SAllain Legacy 		 * in dev_private by the primary process. All resource should
965908072e9SAllain Legacy 		 * be mapped to the same virtual address so all pointers should
966908072e9SAllain Legacy 		 * be valid.
967908072e9SAllain Legacy 		 */
96850db69fdSAllain Legacy 		if (eth_dev->data->scattered_rx) {
969*e99981afSDavid Marchand 			PMD_DRV_LOG_LINE(NOTICE, "AVP device configured for chained mbufs");
97050db69fdSAllain Legacy 			eth_dev->rx_pkt_burst = avp_recv_scattered_pkts;
971295abce2SAllain Legacy 			eth_dev->tx_pkt_burst = avp_xmit_scattered_pkts;
97250db69fdSAllain Legacy 		}
973908072e9SAllain Legacy 		return 0;
974908072e9SAllain Legacy 	}
975908072e9SAllain Legacy 
976908072e9SAllain Legacy 	rte_eth_copy_pci_info(eth_dev, pci_dev);
977f30e69b4SFerruh Yigit 	eth_dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
978908072e9SAllain Legacy 
97982e140b8SAllain Legacy 	/* Check current migration status */
98082e140b8SAllain Legacy 	if (avp_dev_migration_pending(eth_dev)) {
981*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "VM live migration operation in progress");
98282e140b8SAllain Legacy 		return -EBUSY;
98382e140b8SAllain Legacy 	}
98482e140b8SAllain Legacy 
985c0ad5842SAllain Legacy 	/* Check BAR resources */
986c0ad5842SAllain Legacy 	ret = avp_dev_check_regions(eth_dev);
987c0ad5842SAllain Legacy 	if (ret < 0) {
988*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Failed to validate BAR resources, ret=%d",
989c0ad5842SAllain Legacy 			    ret);
990c0ad5842SAllain Legacy 		return ret;
991c0ad5842SAllain Legacy 	}
992c0ad5842SAllain Legacy 
99382e140b8SAllain Legacy 	/* Enable interrupts */
99482e140b8SAllain Legacy 	ret = avp_dev_setup_interrupts(eth_dev);
99582e140b8SAllain Legacy 	if (ret < 0) {
996*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Failed to enable interrupts, ret=%d", ret);
99782e140b8SAllain Legacy 		return ret;
99882e140b8SAllain Legacy 	}
99982e140b8SAllain Legacy 
1000c0ad5842SAllain Legacy 	/* Handle each subtype */
1001c0ad5842SAllain Legacy 	ret = avp_dev_create(pci_dev, eth_dev);
1002c0ad5842SAllain Legacy 	if (ret < 0) {
1003*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Failed to create device, ret=%d", ret);
1004c0ad5842SAllain Legacy 		return ret;
1005c0ad5842SAllain Legacy 	}
1006c0ad5842SAllain Legacy 
1007c0ad5842SAllain Legacy 	/* Allocate memory for storing MAC addresses */
100835b2d13fSOlivier Matz 	eth_dev->data->mac_addrs = rte_zmalloc("avp_ethdev",
100935b2d13fSOlivier Matz 					RTE_ETHER_ADDR_LEN, 0);
1010c0ad5842SAllain Legacy 	if (eth_dev->data->mac_addrs == NULL) {
1011*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Failed to allocate %d bytes needed to store MAC addresses",
101235b2d13fSOlivier Matz 			    RTE_ETHER_ADDR_LEN);
1013c0ad5842SAllain Legacy 		return -ENOMEM;
1014c0ad5842SAllain Legacy 	}
1015c0ad5842SAllain Legacy 
1016c0ad5842SAllain Legacy 	/* Get a mac from device config */
1017538da7a1SOlivier Matz 	rte_ether_addr_copy(&avp->ethaddr, &eth_dev->data->mac_addrs[0]);
1018c0ad5842SAllain Legacy 
1019908072e9SAllain Legacy 	return 0;
1020908072e9SAllain Legacy }
1021908072e9SAllain Legacy 
1022908072e9SAllain Legacy static int
1023908072e9SAllain Legacy eth_avp_dev_uninit(struct rte_eth_dev *eth_dev)
1024908072e9SAllain Legacy {
1025908072e9SAllain Legacy 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
1026908072e9SAllain Legacy 		return -EPERM;
1027908072e9SAllain Legacy 
1028908072e9SAllain Legacy 	if (eth_dev->data == NULL)
1029908072e9SAllain Legacy 		return 0;
1030908072e9SAllain Legacy 
103115fb42d5SAllain Legacy 	avp_dev_close(eth_dev);
103282e140b8SAllain Legacy 
1033908072e9SAllain Legacy 	return 0;
1034908072e9SAllain Legacy }
1035908072e9SAllain Legacy 
1036fdf91e0fSJan Blunck static int
1037fdf91e0fSJan Blunck eth_avp_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
1038fdf91e0fSJan Blunck 		  struct rte_pci_device *pci_dev)
1039908072e9SAllain Legacy {
104001a98fddSThomas Monjalon 	return rte_eth_dev_pci_generic_probe(pci_dev, sizeof(struct avp_adapter),
104101a98fddSThomas Monjalon 			eth_avp_dev_init);
1042fdf91e0fSJan Blunck }
1043fdf91e0fSJan Blunck 
1044fdf91e0fSJan Blunck static int
1045fdf91e0fSJan Blunck eth_avp_pci_remove(struct rte_pci_device *pci_dev)
1046fdf91e0fSJan Blunck {
1047fdf91e0fSJan Blunck 	return rte_eth_dev_pci_generic_remove(pci_dev,
1048fdf91e0fSJan Blunck 					      eth_avp_dev_uninit);
1049fdf91e0fSJan Blunck }
1050fdf91e0fSJan Blunck 
1051fdf91e0fSJan Blunck static struct rte_pci_driver rte_avp_pmd = {
1052908072e9SAllain Legacy 	.id_table = pci_id_avp_map,
1053908072e9SAllain Legacy 	.drv_flags = RTE_PCI_DRV_NEED_MAPPING,
1054fdf91e0fSJan Blunck 	.probe = eth_avp_pci_probe,
1055fdf91e0fSJan Blunck 	.remove = eth_avp_pci_remove,
1056908072e9SAllain Legacy };
1057908072e9SAllain Legacy 
10581a859223SAllain Legacy static int
105950db69fdSAllain Legacy avp_dev_enable_scattered(struct rte_eth_dev *eth_dev,
106050db69fdSAllain Legacy 			 struct avp_dev *avp)
106150db69fdSAllain Legacy {
10621bb4a528SFerruh Yigit 	unsigned int max_rx_pktlen;
106350db69fdSAllain Legacy 
10641bb4a528SFerruh Yigit 	max_rx_pktlen = eth_dev->data->mtu + RTE_ETHER_HDR_LEN +
10651bb4a528SFerruh Yigit 		RTE_ETHER_CRC_LEN;
106650db69fdSAllain Legacy 
10671bb4a528SFerruh Yigit 	if (max_rx_pktlen > avp->guest_mbuf_size ||
10681bb4a528SFerruh Yigit 	    max_rx_pktlen > avp->host_mbuf_size) {
106950db69fdSAllain Legacy 		/*
107050db69fdSAllain Legacy 		 * If the guest MTU is greater than either the host or guest
107150db69fdSAllain Legacy 		 * buffers then chained mbufs have to be enabled in the TX
107250db69fdSAllain Legacy 		 * direction.  It is assumed that the application will not need
10731bb4a528SFerruh Yigit 		 * to send packets larger than their MTU.
107450db69fdSAllain Legacy 		 */
107550db69fdSAllain Legacy 		return 1;
107650db69fdSAllain Legacy 	}
107750db69fdSAllain Legacy 
107850db69fdSAllain Legacy 	if ((avp->max_rx_pkt_len > avp->guest_mbuf_size) ||
107950db69fdSAllain Legacy 	    (avp->max_rx_pkt_len > avp->host_mbuf_size)) {
108050db69fdSAllain Legacy 		/*
108150db69fdSAllain Legacy 		 * If the host MRU is greater than its own mbuf size or the
108250db69fdSAllain Legacy 		 * guest mbuf size then chained mbufs have to be enabled in the
108350db69fdSAllain Legacy 		 * RX direction.
108450db69fdSAllain Legacy 		 */
108550db69fdSAllain Legacy 		return 1;
108650db69fdSAllain Legacy 	}
108750db69fdSAllain Legacy 
108850db69fdSAllain Legacy 	return 0;
108950db69fdSAllain Legacy }
109050db69fdSAllain Legacy 
109150db69fdSAllain Legacy static int
1092cce4367fSAllain Legacy avp_dev_rx_queue_setup(struct rte_eth_dev *eth_dev,
1093cce4367fSAllain Legacy 		       uint16_t rx_queue_id,
1094cce4367fSAllain Legacy 		       uint16_t nb_rx_desc,
1095cce4367fSAllain Legacy 		       unsigned int socket_id,
1096cce4367fSAllain Legacy 		       const struct rte_eth_rxconf *rx_conf,
1097cce4367fSAllain Legacy 		       struct rte_mempool *pool)
1098cce4367fSAllain Legacy {
1099cce4367fSAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
1100cce4367fSAllain Legacy 	struct rte_pktmbuf_pool_private *mbp_priv;
1101cce4367fSAllain Legacy 	struct avp_queue *rxq;
1102cce4367fSAllain Legacy 
1103cce4367fSAllain Legacy 	if (rx_queue_id >= eth_dev->data->nb_rx_queues) {
1104*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "RX queue id is out of range: rx_queue_id=%u, nb_rx_queues=%u",
1105cce4367fSAllain Legacy 			    rx_queue_id, eth_dev->data->nb_rx_queues);
1106cce4367fSAllain Legacy 		return -EINVAL;
1107cce4367fSAllain Legacy 	}
1108cce4367fSAllain Legacy 
1109cce4367fSAllain Legacy 	/* Save mbuf pool pointer */
1110cce4367fSAllain Legacy 	avp->pool = pool;
1111cce4367fSAllain Legacy 
1112cce4367fSAllain Legacy 	/* Save the local mbuf size */
1113cce4367fSAllain Legacy 	mbp_priv = rte_mempool_get_priv(pool);
1114cce4367fSAllain Legacy 	avp->guest_mbuf_size = (uint16_t)(mbp_priv->mbuf_data_room_size);
1115cce4367fSAllain Legacy 	avp->guest_mbuf_size -= RTE_PKTMBUF_HEADROOM;
1116cce4367fSAllain Legacy 
111750db69fdSAllain Legacy 	if (avp_dev_enable_scattered(eth_dev, avp)) {
111850db69fdSAllain Legacy 		if (!eth_dev->data->scattered_rx) {
1119*e99981afSDavid Marchand 			PMD_DRV_LOG_LINE(NOTICE, "AVP device configured for chained mbufs");
112050db69fdSAllain Legacy 			eth_dev->data->scattered_rx = 1;
112150db69fdSAllain Legacy 			eth_dev->rx_pkt_burst = avp_recv_scattered_pkts;
1122295abce2SAllain Legacy 			eth_dev->tx_pkt_burst = avp_xmit_scattered_pkts;
112350db69fdSAllain Legacy 		}
112450db69fdSAllain Legacy 	}
112550db69fdSAllain Legacy 
1126*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "AVP max_rx_pkt_len=(%u,%u) mbuf_size=(%u,%u)",
1127cce4367fSAllain Legacy 		    avp->max_rx_pkt_len,
11281bb4a528SFerruh Yigit 		    eth_dev->data->mtu + RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN,
1129cce4367fSAllain Legacy 		    avp->host_mbuf_size,
1130cce4367fSAllain Legacy 		    avp->guest_mbuf_size);
1131cce4367fSAllain Legacy 
1132cce4367fSAllain Legacy 	/* allocate a queue object */
1133cce4367fSAllain Legacy 	rxq = rte_zmalloc_socket("ethdev RX queue", sizeof(struct avp_queue),
1134cce4367fSAllain Legacy 				 RTE_CACHE_LINE_SIZE, socket_id);
1135cce4367fSAllain Legacy 	if (rxq == NULL) {
1136*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Failed to allocate new Rx queue object");
1137cce4367fSAllain Legacy 		return -ENOMEM;
1138cce4367fSAllain Legacy 	}
1139cce4367fSAllain Legacy 
1140cce4367fSAllain Legacy 	/* save back pointers to AVP and Ethernet devices */
1141cce4367fSAllain Legacy 	rxq->avp = avp;
1142cce4367fSAllain Legacy 	rxq->dev_data = eth_dev->data;
1143cce4367fSAllain Legacy 	eth_dev->data->rx_queues[rx_queue_id] = (void *)rxq;
1144cce4367fSAllain Legacy 
1145cce4367fSAllain Legacy 	/* setup the queue receive mapping for the current queue. */
1146cce4367fSAllain Legacy 	_avp_set_rx_queue_mappings(eth_dev, rx_queue_id);
1147cce4367fSAllain Legacy 
1148*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "Rx queue %u setup at %p", rx_queue_id, rxq);
1149cce4367fSAllain Legacy 
1150cce4367fSAllain Legacy 	(void)nb_rx_desc;
1151cce4367fSAllain Legacy 	(void)rx_conf;
1152cce4367fSAllain Legacy 	return 0;
1153cce4367fSAllain Legacy }
1154cce4367fSAllain Legacy 
1155cce4367fSAllain Legacy static int
1156cce4367fSAllain Legacy avp_dev_tx_queue_setup(struct rte_eth_dev *eth_dev,
1157cce4367fSAllain Legacy 		       uint16_t tx_queue_id,
1158cce4367fSAllain Legacy 		       uint16_t nb_tx_desc,
1159cce4367fSAllain Legacy 		       unsigned int socket_id,
1160cce4367fSAllain Legacy 		       const struct rte_eth_txconf *tx_conf)
1161cce4367fSAllain Legacy {
1162cce4367fSAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
1163cce4367fSAllain Legacy 	struct avp_queue *txq;
1164cce4367fSAllain Legacy 
1165cce4367fSAllain Legacy 	if (tx_queue_id >= eth_dev->data->nb_tx_queues) {
1166*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "TX queue id is out of range: tx_queue_id=%u, nb_tx_queues=%u",
1167cce4367fSAllain Legacy 			    tx_queue_id, eth_dev->data->nb_tx_queues);
1168cce4367fSAllain Legacy 		return -EINVAL;
1169cce4367fSAllain Legacy 	}
1170cce4367fSAllain Legacy 
1171cce4367fSAllain Legacy 	/* allocate a queue object */
1172cce4367fSAllain Legacy 	txq = rte_zmalloc_socket("ethdev TX queue", sizeof(struct avp_queue),
1173cce4367fSAllain Legacy 				 RTE_CACHE_LINE_SIZE, socket_id);
1174cce4367fSAllain Legacy 	if (txq == NULL) {
1175*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Failed to allocate new Tx queue object");
1176cce4367fSAllain Legacy 		return -ENOMEM;
1177cce4367fSAllain Legacy 	}
1178cce4367fSAllain Legacy 
1179cce4367fSAllain Legacy 	/* only the configured set of transmit queues are used */
1180cce4367fSAllain Legacy 	txq->queue_id = tx_queue_id;
1181cce4367fSAllain Legacy 	txq->queue_base = tx_queue_id;
1182cce4367fSAllain Legacy 	txq->queue_limit = tx_queue_id;
1183cce4367fSAllain Legacy 
1184cce4367fSAllain Legacy 	/* save back pointers to AVP and Ethernet devices */
1185cce4367fSAllain Legacy 	txq->avp = avp;
1186cce4367fSAllain Legacy 	txq->dev_data = eth_dev->data;
1187cce4367fSAllain Legacy 	eth_dev->data->tx_queues[tx_queue_id] = (void *)txq;
1188cce4367fSAllain Legacy 
1189*e99981afSDavid Marchand 	PMD_DRV_LOG_LINE(DEBUG, "Tx queue %u setup at %p", tx_queue_id, txq);
1190cce4367fSAllain Legacy 
1191cce4367fSAllain Legacy 	(void)nb_tx_desc;
1192cce4367fSAllain Legacy 	(void)tx_conf;
1193cce4367fSAllain Legacy 	return 0;
1194cce4367fSAllain Legacy }
1195cce4367fSAllain Legacy 
119650db69fdSAllain Legacy static inline int
11976d13ea8eSOlivier Matz _avp_cmp_ether_addr(struct rte_ether_addr *a, struct rte_ether_addr *b)
119850db69fdSAllain Legacy {
119950db69fdSAllain Legacy 	uint16_t *_a = (uint16_t *)&a->addr_bytes[0];
120050db69fdSAllain Legacy 	uint16_t *_b = (uint16_t *)&b->addr_bytes[0];
120150db69fdSAllain Legacy 	return (_a[0] ^ _b[0]) | (_a[1] ^ _b[1]) | (_a[2] ^ _b[2]);
120250db69fdSAllain Legacy }
120350db69fdSAllain Legacy 
120450db69fdSAllain Legacy static inline int
120550db69fdSAllain Legacy _avp_mac_filter(struct avp_dev *avp, struct rte_mbuf *m)
120650db69fdSAllain Legacy {
12076d13ea8eSOlivier Matz 	struct rte_ether_hdr *eth = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
120850db69fdSAllain Legacy 
120904d43857SDmitry Kozlyuk 	if (likely(_avp_cmp_ether_addr(&avp->ethaddr, &eth->dst_addr) == 0)) {
121050db69fdSAllain Legacy 		/* allow all packets destined to our address */
121150db69fdSAllain Legacy 		return 0;
121250db69fdSAllain Legacy 	}
121350db69fdSAllain Legacy 
121404d43857SDmitry Kozlyuk 	if (likely(rte_is_broadcast_ether_addr(&eth->dst_addr))) {
121550db69fdSAllain Legacy 		/* allow all broadcast packets */
121650db69fdSAllain Legacy 		return 0;
121750db69fdSAllain Legacy 	}
121850db69fdSAllain Legacy 
121904d43857SDmitry Kozlyuk 	if (likely(rte_is_multicast_ether_addr(&eth->dst_addr))) {
122050db69fdSAllain Legacy 		/* allow all multicast packets */
122150db69fdSAllain Legacy 		return 0;
122250db69fdSAllain Legacy 	}
122350db69fdSAllain Legacy 
122450db69fdSAllain Legacy 	if (avp->flags & AVP_F_PROMISC) {
122550db69fdSAllain Legacy 		/* allow all packets when in promiscuous mode */
122650db69fdSAllain Legacy 		return 0;
122750db69fdSAllain Legacy 	}
122850db69fdSAllain Legacy 
122950db69fdSAllain Legacy 	return -1;
123050db69fdSAllain Legacy }
123150db69fdSAllain Legacy 
123250db69fdSAllain Legacy #ifdef RTE_LIBRTE_AVP_DEBUG_BUFFERS
123350db69fdSAllain Legacy static inline void
123450db69fdSAllain Legacy __avp_dev_buffer_sanity_check(struct avp_dev *avp, struct rte_avp_desc *buf)
123550db69fdSAllain Legacy {
123650db69fdSAllain Legacy 	struct rte_avp_desc *first_buf;
123750db69fdSAllain Legacy 	struct rte_avp_desc *pkt_buf;
123850db69fdSAllain Legacy 	unsigned int pkt_len;
123950db69fdSAllain Legacy 	unsigned int nb_segs;
124050db69fdSAllain Legacy 	void *pkt_data;
124150db69fdSAllain Legacy 	unsigned int i;
124250db69fdSAllain Legacy 
124350db69fdSAllain Legacy 	first_buf = avp_dev_translate_buffer(avp, buf);
124450db69fdSAllain Legacy 
124550db69fdSAllain Legacy 	i = 0;
124650db69fdSAllain Legacy 	pkt_len = 0;
124750db69fdSAllain Legacy 	nb_segs = first_buf->nb_segs;
124850db69fdSAllain Legacy 	do {
124950db69fdSAllain Legacy 		/* Adjust pointers for guest addressing */
125050db69fdSAllain Legacy 		pkt_buf = avp_dev_translate_buffer(avp, buf);
125150db69fdSAllain Legacy 		if (pkt_buf == NULL)
125250db69fdSAllain Legacy 			rte_panic("bad buffer: segment %u has an invalid address %p\n",
125350db69fdSAllain Legacy 				  i, buf);
125450db69fdSAllain Legacy 		pkt_data = avp_dev_translate_buffer(avp, pkt_buf->data);
125550db69fdSAllain Legacy 		if (pkt_data == NULL)
125650db69fdSAllain Legacy 			rte_panic("bad buffer: segment %u has a NULL data pointer\n",
125750db69fdSAllain Legacy 				  i);
125850db69fdSAllain Legacy 		if (pkt_buf->data_len == 0)
125950db69fdSAllain Legacy 			rte_panic("bad buffer: segment %u has 0 data length\n",
126050db69fdSAllain Legacy 				  i);
126150db69fdSAllain Legacy 		pkt_len += pkt_buf->data_len;
126250db69fdSAllain Legacy 		nb_segs--;
126350db69fdSAllain Legacy 		i++;
126450db69fdSAllain Legacy 
126550db69fdSAllain Legacy 	} while (nb_segs && (buf = pkt_buf->next) != NULL);
126650db69fdSAllain Legacy 
126750db69fdSAllain Legacy 	if (nb_segs != 0)
126850db69fdSAllain Legacy 		rte_panic("bad buffer: expected %u segments found %u\n",
126950db69fdSAllain Legacy 			  first_buf->nb_segs, (first_buf->nb_segs - nb_segs));
127050db69fdSAllain Legacy 	if (pkt_len != first_buf->pkt_len)
127150db69fdSAllain Legacy 		rte_panic("bad buffer: expected length %u found %u\n",
127250db69fdSAllain Legacy 			  first_buf->pkt_len, pkt_len);
127350db69fdSAllain Legacy }
127450db69fdSAllain Legacy 
127550db69fdSAllain Legacy #define avp_dev_buffer_sanity_check(a, b) \
127650db69fdSAllain Legacy 	__avp_dev_buffer_sanity_check((a), (b))
127750db69fdSAllain Legacy 
127850db69fdSAllain Legacy #else /* RTE_LIBRTE_AVP_DEBUG_BUFFERS */
127950db69fdSAllain Legacy 
128050db69fdSAllain Legacy #define avp_dev_buffer_sanity_check(a, b) do {} while (0)
128150db69fdSAllain Legacy 
128250db69fdSAllain Legacy #endif
128350db69fdSAllain Legacy 
128450db69fdSAllain Legacy /*
128550db69fdSAllain Legacy  * Copy a host buffer chain to a set of mbufs.	This function assumes that
128650db69fdSAllain Legacy  * there exactly the required number of mbufs to copy all source bytes.
128750db69fdSAllain Legacy  */
128850db69fdSAllain Legacy static inline struct rte_mbuf *
128950db69fdSAllain Legacy avp_dev_copy_from_buffers(struct avp_dev *avp,
129050db69fdSAllain Legacy 			  struct rte_avp_desc *buf,
129150db69fdSAllain Legacy 			  struct rte_mbuf **mbufs,
129250db69fdSAllain Legacy 			  unsigned int count)
129350db69fdSAllain Legacy {
129450db69fdSAllain Legacy 	struct rte_mbuf *m_previous = NULL;
129550db69fdSAllain Legacy 	struct rte_avp_desc *pkt_buf;
129650db69fdSAllain Legacy 	unsigned int total_length = 0;
129750db69fdSAllain Legacy 	unsigned int copy_length;
129850db69fdSAllain Legacy 	unsigned int src_offset;
129950db69fdSAllain Legacy 	struct rte_mbuf *m;
130050db69fdSAllain Legacy 	uint16_t ol_flags;
130150db69fdSAllain Legacy 	uint16_t vlan_tci;
130250db69fdSAllain Legacy 	void *pkt_data;
130350db69fdSAllain Legacy 	unsigned int i;
130450db69fdSAllain Legacy 
130550db69fdSAllain Legacy 	avp_dev_buffer_sanity_check(avp, buf);
130650db69fdSAllain Legacy 
130750db69fdSAllain Legacy 	/* setup the first source buffer */
130850db69fdSAllain Legacy 	pkt_buf = avp_dev_translate_buffer(avp, buf);
130950db69fdSAllain Legacy 	pkt_data = avp_dev_translate_buffer(avp, pkt_buf->data);
131050db69fdSAllain Legacy 	total_length = pkt_buf->pkt_len;
131150db69fdSAllain Legacy 	src_offset = 0;
131250db69fdSAllain Legacy 
131350db69fdSAllain Legacy 	if (pkt_buf->ol_flags & RTE_AVP_RX_VLAN_PKT) {
1314daa02b5cSOlivier Matz 		ol_flags = RTE_MBUF_F_RX_VLAN;
131550db69fdSAllain Legacy 		vlan_tci = pkt_buf->vlan_tci;
131650db69fdSAllain Legacy 	} else {
131750db69fdSAllain Legacy 		ol_flags = 0;
131850db69fdSAllain Legacy 		vlan_tci = 0;
131950db69fdSAllain Legacy 	}
132050db69fdSAllain Legacy 
132150db69fdSAllain Legacy 	for (i = 0; (i < count) && (buf != NULL); i++) {
132250db69fdSAllain Legacy 		/* fill each destination buffer */
132350db69fdSAllain Legacy 		m = mbufs[i];
132450db69fdSAllain Legacy 
132550db69fdSAllain Legacy 		if (m_previous != NULL)
132650db69fdSAllain Legacy 			m_previous->next = m;
132750db69fdSAllain Legacy 
132850db69fdSAllain Legacy 		m_previous = m;
132950db69fdSAllain Legacy 
133050db69fdSAllain Legacy 		do {
133150db69fdSAllain Legacy 			/*
133250db69fdSAllain Legacy 			 * Copy as many source buffers as will fit in the
133350db69fdSAllain Legacy 			 * destination buffer.
133450db69fdSAllain Legacy 			 */
133550db69fdSAllain Legacy 			copy_length = RTE_MIN((avp->guest_mbuf_size -
133650db69fdSAllain Legacy 					       rte_pktmbuf_data_len(m)),
133750db69fdSAllain Legacy 					      (pkt_buf->data_len -
133850db69fdSAllain Legacy 					       src_offset));
133950db69fdSAllain Legacy 			rte_memcpy(RTE_PTR_ADD(rte_pktmbuf_mtod(m, void *),
134050db69fdSAllain Legacy 					       rte_pktmbuf_data_len(m)),
134150db69fdSAllain Legacy 				   RTE_PTR_ADD(pkt_data, src_offset),
134250db69fdSAllain Legacy 				   copy_length);
134350db69fdSAllain Legacy 			rte_pktmbuf_data_len(m) += copy_length;
134450db69fdSAllain Legacy 			src_offset += copy_length;
134550db69fdSAllain Legacy 
134650db69fdSAllain Legacy 			if (likely(src_offset == pkt_buf->data_len)) {
134750db69fdSAllain Legacy 				/* need a new source buffer */
134850db69fdSAllain Legacy 				buf = pkt_buf->next;
134950db69fdSAllain Legacy 				if (buf != NULL) {
135050db69fdSAllain Legacy 					pkt_buf = avp_dev_translate_buffer(
135150db69fdSAllain Legacy 						avp, buf);
135250db69fdSAllain Legacy 					pkt_data = avp_dev_translate_buffer(
135350db69fdSAllain Legacy 						avp, pkt_buf->data);
135450db69fdSAllain Legacy 					src_offset = 0;
135550db69fdSAllain Legacy 				}
135650db69fdSAllain Legacy 			}
135750db69fdSAllain Legacy 
135850db69fdSAllain Legacy 			if (unlikely(rte_pktmbuf_data_len(m) ==
135950db69fdSAllain Legacy 				     avp->guest_mbuf_size)) {
136050db69fdSAllain Legacy 				/* need a new destination mbuf */
136150db69fdSAllain Legacy 				break;
136250db69fdSAllain Legacy 			}
136350db69fdSAllain Legacy 
136450db69fdSAllain Legacy 		} while (buf != NULL);
136550db69fdSAllain Legacy 	}
136650db69fdSAllain Legacy 
136750db69fdSAllain Legacy 	m = mbufs[0];
136850db69fdSAllain Legacy 	m->ol_flags = ol_flags;
136950db69fdSAllain Legacy 	m->nb_segs = count;
137050db69fdSAllain Legacy 	rte_pktmbuf_pkt_len(m) = total_length;
137150db69fdSAllain Legacy 	m->vlan_tci = vlan_tci;
137250db69fdSAllain Legacy 
137350db69fdSAllain Legacy 	__rte_mbuf_sanity_check(m, 1);
137450db69fdSAllain Legacy 
137550db69fdSAllain Legacy 	return m;
137650db69fdSAllain Legacy }
137750db69fdSAllain Legacy 
137850db69fdSAllain Legacy static uint16_t
137950db69fdSAllain Legacy avp_recv_scattered_pkts(void *rx_queue,
138050db69fdSAllain Legacy 			struct rte_mbuf **rx_pkts,
138150db69fdSAllain Legacy 			uint16_t nb_pkts)
138250db69fdSAllain Legacy {
138350db69fdSAllain Legacy 	struct avp_queue *rxq = (struct avp_queue *)rx_queue;
138450db69fdSAllain Legacy 	struct rte_avp_desc *avp_bufs[AVP_MAX_RX_BURST];
138550db69fdSAllain Legacy 	struct rte_mbuf *mbufs[RTE_AVP_MAX_MBUF_SEGMENTS];
138650db69fdSAllain Legacy 	struct avp_dev *avp = rxq->avp;
138750db69fdSAllain Legacy 	struct rte_avp_desc *pkt_buf;
138850db69fdSAllain Legacy 	struct rte_avp_fifo *free_q;
138950db69fdSAllain Legacy 	struct rte_avp_fifo *rx_q;
139050db69fdSAllain Legacy 	struct rte_avp_desc *buf;
139150db69fdSAllain Legacy 	unsigned int count, avail, n;
139250db69fdSAllain Legacy 	unsigned int guest_mbuf_size;
139350db69fdSAllain Legacy 	struct rte_mbuf *m;
139450db69fdSAllain Legacy 	unsigned int required;
139550db69fdSAllain Legacy 	unsigned int buf_len;
139650db69fdSAllain Legacy 	unsigned int port_id;
139750db69fdSAllain Legacy 	unsigned int i;
139850db69fdSAllain Legacy 
139982e140b8SAllain Legacy 	if (unlikely(avp->flags & AVP_F_DETACHED)) {
140082e140b8SAllain Legacy 		/* VM live migration in progress */
140182e140b8SAllain Legacy 		return 0;
140282e140b8SAllain Legacy 	}
140382e140b8SAllain Legacy 
140450db69fdSAllain Legacy 	guest_mbuf_size = avp->guest_mbuf_size;
140550db69fdSAllain Legacy 	port_id = avp->port_id;
140650db69fdSAllain Legacy 	rx_q = avp->rx_q[rxq->queue_id];
140750db69fdSAllain Legacy 	free_q = avp->free_q[rxq->queue_id];
140850db69fdSAllain Legacy 
140950db69fdSAllain Legacy 	/* setup next queue to service */
141050db69fdSAllain Legacy 	rxq->queue_id = (rxq->queue_id < rxq->queue_limit) ?
141150db69fdSAllain Legacy 		(rxq->queue_id + 1) : rxq->queue_base;
141250db69fdSAllain Legacy 
141350db69fdSAllain Legacy 	/* determine how many slots are available in the free queue */
141450db69fdSAllain Legacy 	count = avp_fifo_free_count(free_q);
141550db69fdSAllain Legacy 
141650db69fdSAllain Legacy 	/* determine how many packets are available in the rx queue */
141750db69fdSAllain Legacy 	avail = avp_fifo_count(rx_q);
141850db69fdSAllain Legacy 
141950db69fdSAllain Legacy 	/* determine how many packets can be received */
142050db69fdSAllain Legacy 	count = RTE_MIN(count, avail);
142150db69fdSAllain Legacy 	count = RTE_MIN(count, nb_pkts);
142250db69fdSAllain Legacy 	count = RTE_MIN(count, (unsigned int)AVP_MAX_RX_BURST);
142350db69fdSAllain Legacy 
142450db69fdSAllain Legacy 	if (unlikely(count == 0)) {
142550db69fdSAllain Legacy 		/* no free buffers, or no buffers on the rx queue */
142650db69fdSAllain Legacy 		return 0;
142750db69fdSAllain Legacy 	}
142850db69fdSAllain Legacy 
142950db69fdSAllain Legacy 	/* retrieve pending packets */
143050db69fdSAllain Legacy 	n = avp_fifo_get(rx_q, (void **)&avp_bufs, count);
1431*e99981afSDavid Marchand 	PMD_RX_LOG_LINE(DEBUG, "Receiving %u packets from Rx queue at %p",
143250db69fdSAllain Legacy 		   count, rx_q);
143350db69fdSAllain Legacy 
143450db69fdSAllain Legacy 	count = 0;
143550db69fdSAllain Legacy 	for (i = 0; i < n; i++) {
143650db69fdSAllain Legacy 		/* prefetch next entry while processing current one */
143750db69fdSAllain Legacy 		if (i + 1 < n) {
143850db69fdSAllain Legacy 			pkt_buf = avp_dev_translate_buffer(avp,
143950db69fdSAllain Legacy 							   avp_bufs[i + 1]);
144050db69fdSAllain Legacy 			rte_prefetch0(pkt_buf);
144150db69fdSAllain Legacy 		}
144250db69fdSAllain Legacy 		buf = avp_bufs[i];
144350db69fdSAllain Legacy 
144450db69fdSAllain Legacy 		/* Peek into the first buffer to determine the total length */
144550db69fdSAllain Legacy 		pkt_buf = avp_dev_translate_buffer(avp, buf);
144650db69fdSAllain Legacy 		buf_len = pkt_buf->pkt_len;
144750db69fdSAllain Legacy 
144850db69fdSAllain Legacy 		/* Allocate enough mbufs to receive the entire packet */
144950db69fdSAllain Legacy 		required = (buf_len + guest_mbuf_size - 1) / guest_mbuf_size;
145050db69fdSAllain Legacy 		if (rte_pktmbuf_alloc_bulk(avp->pool, mbufs, required)) {
145150db69fdSAllain Legacy 			rxq->dev_data->rx_mbuf_alloc_failed++;
145250db69fdSAllain Legacy 			continue;
145350db69fdSAllain Legacy 		}
145450db69fdSAllain Legacy 
145550db69fdSAllain Legacy 		/* Copy the data from the buffers to our mbufs */
145650db69fdSAllain Legacy 		m = avp_dev_copy_from_buffers(avp, buf, mbufs, required);
145750db69fdSAllain Legacy 
145850db69fdSAllain Legacy 		/* finalize mbuf */
145950db69fdSAllain Legacy 		m->port = port_id;
146050db69fdSAllain Legacy 
146150db69fdSAllain Legacy 		if (_avp_mac_filter(avp, m) != 0) {
146250db69fdSAllain Legacy 			/* silently discard packets not destined to our MAC */
146350db69fdSAllain Legacy 			rte_pktmbuf_free(m);
146450db69fdSAllain Legacy 			continue;
146550db69fdSAllain Legacy 		}
146650db69fdSAllain Legacy 
146750db69fdSAllain Legacy 		/* return new mbuf to caller */
146850db69fdSAllain Legacy 		rx_pkts[count++] = m;
146950db69fdSAllain Legacy 		rxq->bytes += buf_len;
147050db69fdSAllain Legacy 	}
147150db69fdSAllain Legacy 
147250db69fdSAllain Legacy 	rxq->packets += count;
147350db69fdSAllain Legacy 
147450db69fdSAllain Legacy 	/* return the buffers to the free queue */
147550db69fdSAllain Legacy 	avp_fifo_put(free_q, (void **)&avp_bufs[0], n);
147650db69fdSAllain Legacy 
147750db69fdSAllain Legacy 	return count;
147850db69fdSAllain Legacy }
147950db69fdSAllain Legacy 
148050db69fdSAllain Legacy 
148150db69fdSAllain Legacy static uint16_t
148250db69fdSAllain Legacy avp_recv_pkts(void *rx_queue,
148350db69fdSAllain Legacy 	      struct rte_mbuf **rx_pkts,
148450db69fdSAllain Legacy 	      uint16_t nb_pkts)
148550db69fdSAllain Legacy {
148650db69fdSAllain Legacy 	struct avp_queue *rxq = (struct avp_queue *)rx_queue;
148750db69fdSAllain Legacy 	struct rte_avp_desc *avp_bufs[AVP_MAX_RX_BURST];
148850db69fdSAllain Legacy 	struct avp_dev *avp = rxq->avp;
148950db69fdSAllain Legacy 	struct rte_avp_desc *pkt_buf;
149050db69fdSAllain Legacy 	struct rte_avp_fifo *free_q;
149150db69fdSAllain Legacy 	struct rte_avp_fifo *rx_q;
149250db69fdSAllain Legacy 	unsigned int count, avail, n;
149350db69fdSAllain Legacy 	unsigned int pkt_len;
149450db69fdSAllain Legacy 	struct rte_mbuf *m;
149550db69fdSAllain Legacy 	char *pkt_data;
149650db69fdSAllain Legacy 	unsigned int i;
149750db69fdSAllain Legacy 
149882e140b8SAllain Legacy 	if (unlikely(avp->flags & AVP_F_DETACHED)) {
149982e140b8SAllain Legacy 		/* VM live migration in progress */
150082e140b8SAllain Legacy 		return 0;
150182e140b8SAllain Legacy 	}
150282e140b8SAllain Legacy 
150350db69fdSAllain Legacy 	rx_q = avp->rx_q[rxq->queue_id];
150450db69fdSAllain Legacy 	free_q = avp->free_q[rxq->queue_id];
150550db69fdSAllain Legacy 
150650db69fdSAllain Legacy 	/* setup next queue to service */
150750db69fdSAllain Legacy 	rxq->queue_id = (rxq->queue_id < rxq->queue_limit) ?
150850db69fdSAllain Legacy 		(rxq->queue_id + 1) : rxq->queue_base;
150950db69fdSAllain Legacy 
151050db69fdSAllain Legacy 	/* determine how many slots are available in the free queue */
151150db69fdSAllain Legacy 	count = avp_fifo_free_count(free_q);
151250db69fdSAllain Legacy 
151350db69fdSAllain Legacy 	/* determine how many packets are available in the rx queue */
151450db69fdSAllain Legacy 	avail = avp_fifo_count(rx_q);
151550db69fdSAllain Legacy 
151650db69fdSAllain Legacy 	/* determine how many packets can be received */
151750db69fdSAllain Legacy 	count = RTE_MIN(count, avail);
151850db69fdSAllain Legacy 	count = RTE_MIN(count, nb_pkts);
151950db69fdSAllain Legacy 	count = RTE_MIN(count, (unsigned int)AVP_MAX_RX_BURST);
152050db69fdSAllain Legacy 
152150db69fdSAllain Legacy 	if (unlikely(count == 0)) {
152250db69fdSAllain Legacy 		/* no free buffers, or no buffers on the rx queue */
152350db69fdSAllain Legacy 		return 0;
152450db69fdSAllain Legacy 	}
152550db69fdSAllain Legacy 
152650db69fdSAllain Legacy 	/* retrieve pending packets */
152750db69fdSAllain Legacy 	n = avp_fifo_get(rx_q, (void **)&avp_bufs, count);
1528*e99981afSDavid Marchand 	PMD_RX_LOG_LINE(DEBUG, "Receiving %u packets from Rx queue at %p",
152950db69fdSAllain Legacy 		   count, rx_q);
153050db69fdSAllain Legacy 
153150db69fdSAllain Legacy 	count = 0;
153250db69fdSAllain Legacy 	for (i = 0; i < n; i++) {
153350db69fdSAllain Legacy 		/* prefetch next entry while processing current one */
153450db69fdSAllain Legacy 		if (i < n - 1) {
153550db69fdSAllain Legacy 			pkt_buf = avp_dev_translate_buffer(avp,
153650db69fdSAllain Legacy 							   avp_bufs[i + 1]);
153750db69fdSAllain Legacy 			rte_prefetch0(pkt_buf);
153850db69fdSAllain Legacy 		}
153950db69fdSAllain Legacy 
154050db69fdSAllain Legacy 		/* Adjust host pointers for guest addressing */
154150db69fdSAllain Legacy 		pkt_buf = avp_dev_translate_buffer(avp, avp_bufs[i]);
154250db69fdSAllain Legacy 		pkt_data = avp_dev_translate_buffer(avp, pkt_buf->data);
154350db69fdSAllain Legacy 		pkt_len = pkt_buf->pkt_len;
154450db69fdSAllain Legacy 
154550db69fdSAllain Legacy 		if (unlikely((pkt_len > avp->guest_mbuf_size) ||
154650db69fdSAllain Legacy 			     (pkt_buf->nb_segs > 1))) {
154750db69fdSAllain Legacy 			/*
154850db69fdSAllain Legacy 			 * application should be using the scattered receive
154950db69fdSAllain Legacy 			 * function
155050db69fdSAllain Legacy 			 */
155150db69fdSAllain Legacy 			rxq->errors++;
155250db69fdSAllain Legacy 			continue;
155350db69fdSAllain Legacy 		}
155450db69fdSAllain Legacy 
155550db69fdSAllain Legacy 		/* process each packet to be transmitted */
155650db69fdSAllain Legacy 		m = rte_pktmbuf_alloc(avp->pool);
155750db69fdSAllain Legacy 		if (unlikely(m == NULL)) {
155850db69fdSAllain Legacy 			rxq->dev_data->rx_mbuf_alloc_failed++;
155950db69fdSAllain Legacy 			continue;
156050db69fdSAllain Legacy 		}
156150db69fdSAllain Legacy 
156250db69fdSAllain Legacy 		/* copy data out of the host buffer to our buffer */
156350db69fdSAllain Legacy 		m->data_off = RTE_PKTMBUF_HEADROOM;
156450db69fdSAllain Legacy 		rte_memcpy(rte_pktmbuf_mtod(m, void *), pkt_data, pkt_len);
156550db69fdSAllain Legacy 
156650db69fdSAllain Legacy 		/* initialize the local mbuf */
156750db69fdSAllain Legacy 		rte_pktmbuf_data_len(m) = pkt_len;
156850db69fdSAllain Legacy 		rte_pktmbuf_pkt_len(m) = pkt_len;
156950db69fdSAllain Legacy 		m->port = avp->port_id;
157050db69fdSAllain Legacy 
157150db69fdSAllain Legacy 		if (pkt_buf->ol_flags & RTE_AVP_RX_VLAN_PKT) {
1572daa02b5cSOlivier Matz 			m->ol_flags = RTE_MBUF_F_RX_VLAN;
157350db69fdSAllain Legacy 			m->vlan_tci = pkt_buf->vlan_tci;
157450db69fdSAllain Legacy 		}
157550db69fdSAllain Legacy 
157650db69fdSAllain Legacy 		if (_avp_mac_filter(avp, m) != 0) {
157750db69fdSAllain Legacy 			/* silently discard packets not destined to our MAC */
157850db69fdSAllain Legacy 			rte_pktmbuf_free(m);
157950db69fdSAllain Legacy 			continue;
158050db69fdSAllain Legacy 		}
158150db69fdSAllain Legacy 
158250db69fdSAllain Legacy 		/* return new mbuf to caller */
158350db69fdSAllain Legacy 		rx_pkts[count++] = m;
158450db69fdSAllain Legacy 		rxq->bytes += pkt_len;
158550db69fdSAllain Legacy 	}
158650db69fdSAllain Legacy 
158750db69fdSAllain Legacy 	rxq->packets += count;
158850db69fdSAllain Legacy 
158950db69fdSAllain Legacy 	/* return the buffers to the free queue */
159050db69fdSAllain Legacy 	avp_fifo_put(free_q, (void **)&avp_bufs[0], n);
159150db69fdSAllain Legacy 
159250db69fdSAllain Legacy 	return count;
159350db69fdSAllain Legacy }
159450db69fdSAllain Legacy 
1595295abce2SAllain Legacy /*
1596295abce2SAllain Legacy  * Copy a chained mbuf to a set of host buffers.  This function assumes that
1597295abce2SAllain Legacy  * there are sufficient destination buffers to contain the entire source
1598295abce2SAllain Legacy  * packet.
1599295abce2SAllain Legacy  */
1600295abce2SAllain Legacy static inline uint16_t
1601295abce2SAllain Legacy avp_dev_copy_to_buffers(struct avp_dev *avp,
1602295abce2SAllain Legacy 			struct rte_mbuf *mbuf,
1603295abce2SAllain Legacy 			struct rte_avp_desc **buffers,
1604295abce2SAllain Legacy 			unsigned int count)
1605295abce2SAllain Legacy {
1606295abce2SAllain Legacy 	struct rte_avp_desc *previous_buf = NULL;
1607295abce2SAllain Legacy 	struct rte_avp_desc *first_buf = NULL;
1608295abce2SAllain Legacy 	struct rte_avp_desc *pkt_buf;
1609295abce2SAllain Legacy 	struct rte_avp_desc *buf;
1610295abce2SAllain Legacy 	size_t total_length;
1611295abce2SAllain Legacy 	struct rte_mbuf *m;
1612295abce2SAllain Legacy 	size_t copy_length;
1613295abce2SAllain Legacy 	size_t src_offset;
1614295abce2SAllain Legacy 	char *pkt_data;
1615295abce2SAllain Legacy 	unsigned int i;
1616295abce2SAllain Legacy 
1617295abce2SAllain Legacy 	__rte_mbuf_sanity_check(mbuf, 1);
1618295abce2SAllain Legacy 
1619295abce2SAllain Legacy 	m = mbuf;
1620295abce2SAllain Legacy 	src_offset = 0;
1621295abce2SAllain Legacy 	total_length = rte_pktmbuf_pkt_len(m);
1622295abce2SAllain Legacy 	for (i = 0; (i < count) && (m != NULL); i++) {
1623295abce2SAllain Legacy 		/* fill each destination buffer */
1624295abce2SAllain Legacy 		buf = buffers[i];
1625295abce2SAllain Legacy 
1626295abce2SAllain Legacy 		if (i < count - 1) {
1627295abce2SAllain Legacy 			/* prefetch next entry while processing this one */
1628295abce2SAllain Legacy 			pkt_buf = avp_dev_translate_buffer(avp, buffers[i + 1]);
1629295abce2SAllain Legacy 			rte_prefetch0(pkt_buf);
1630295abce2SAllain Legacy 		}
1631295abce2SAllain Legacy 
1632295abce2SAllain Legacy 		/* Adjust pointers for guest addressing */
1633295abce2SAllain Legacy 		pkt_buf = avp_dev_translate_buffer(avp, buf);
1634295abce2SAllain Legacy 		pkt_data = avp_dev_translate_buffer(avp, pkt_buf->data);
1635295abce2SAllain Legacy 
1636295abce2SAllain Legacy 		/* setup the buffer chain */
1637295abce2SAllain Legacy 		if (previous_buf != NULL)
1638295abce2SAllain Legacy 			previous_buf->next = buf;
1639295abce2SAllain Legacy 		else
1640295abce2SAllain Legacy 			first_buf = pkt_buf;
1641295abce2SAllain Legacy 
1642295abce2SAllain Legacy 		previous_buf = pkt_buf;
1643295abce2SAllain Legacy 
1644295abce2SAllain Legacy 		do {
1645295abce2SAllain Legacy 			/*
1646295abce2SAllain Legacy 			 * copy as many source mbuf segments as will fit in the
1647295abce2SAllain Legacy 			 * destination buffer.
1648295abce2SAllain Legacy 			 */
1649295abce2SAllain Legacy 			copy_length = RTE_MIN((avp->host_mbuf_size -
1650295abce2SAllain Legacy 					       pkt_buf->data_len),
1651295abce2SAllain Legacy 					      (rte_pktmbuf_data_len(m) -
1652295abce2SAllain Legacy 					       src_offset));
1653295abce2SAllain Legacy 			rte_memcpy(RTE_PTR_ADD(pkt_data, pkt_buf->data_len),
1654295abce2SAllain Legacy 				   RTE_PTR_ADD(rte_pktmbuf_mtod(m, void *),
1655295abce2SAllain Legacy 					       src_offset),
1656295abce2SAllain Legacy 				   copy_length);
1657295abce2SAllain Legacy 			pkt_buf->data_len += copy_length;
1658295abce2SAllain Legacy 			src_offset += copy_length;
1659295abce2SAllain Legacy 
1660295abce2SAllain Legacy 			if (likely(src_offset == rte_pktmbuf_data_len(m))) {
1661295abce2SAllain Legacy 				/* need a new source buffer */
1662295abce2SAllain Legacy 				m = m->next;
1663295abce2SAllain Legacy 				src_offset = 0;
1664295abce2SAllain Legacy 			}
1665295abce2SAllain Legacy 
1666295abce2SAllain Legacy 			if (unlikely(pkt_buf->data_len ==
1667295abce2SAllain Legacy 				     avp->host_mbuf_size)) {
1668295abce2SAllain Legacy 				/* need a new destination buffer */
1669295abce2SAllain Legacy 				break;
1670295abce2SAllain Legacy 			}
1671295abce2SAllain Legacy 
1672295abce2SAllain Legacy 		} while (m != NULL);
1673295abce2SAllain Legacy 	}
1674295abce2SAllain Legacy 
1675295abce2SAllain Legacy 	first_buf->nb_segs = count;
1676295abce2SAllain Legacy 	first_buf->pkt_len = total_length;
1677295abce2SAllain Legacy 
1678daa02b5cSOlivier Matz 	if (mbuf->ol_flags & RTE_MBUF_F_TX_VLAN) {
1679295abce2SAllain Legacy 		first_buf->ol_flags |= RTE_AVP_TX_VLAN_PKT;
1680295abce2SAllain Legacy 		first_buf->vlan_tci = mbuf->vlan_tci;
1681295abce2SAllain Legacy 	}
1682295abce2SAllain Legacy 
1683295abce2SAllain Legacy 	avp_dev_buffer_sanity_check(avp, buffers[0]);
1684295abce2SAllain Legacy 
1685295abce2SAllain Legacy 	return total_length;
1686295abce2SAllain Legacy }
1687295abce2SAllain Legacy 
1688295abce2SAllain Legacy 
1689295abce2SAllain Legacy static uint16_t
1690295abce2SAllain Legacy avp_xmit_scattered_pkts(void *tx_queue,
1691295abce2SAllain Legacy 			struct rte_mbuf **tx_pkts,
1692295abce2SAllain Legacy 			uint16_t nb_pkts)
1693295abce2SAllain Legacy {
1694295abce2SAllain Legacy 	struct rte_avp_desc *avp_bufs[(AVP_MAX_TX_BURST *
1695ec87d3b2SKevin Traynor 				       RTE_AVP_MAX_MBUF_SEGMENTS)] = {};
1696295abce2SAllain Legacy 	struct avp_queue *txq = (struct avp_queue *)tx_queue;
1697295abce2SAllain Legacy 	struct rte_avp_desc *tx_bufs[AVP_MAX_TX_BURST];
1698295abce2SAllain Legacy 	struct avp_dev *avp = txq->avp;
1699295abce2SAllain Legacy 	struct rte_avp_fifo *alloc_q;
1700295abce2SAllain Legacy 	struct rte_avp_fifo *tx_q;
1701295abce2SAllain Legacy 	unsigned int count, avail, n;
1702295abce2SAllain Legacy 	unsigned int orig_nb_pkts;
1703295abce2SAllain Legacy 	struct rte_mbuf *m;
1704295abce2SAllain Legacy 	unsigned int required;
1705295abce2SAllain Legacy 	unsigned int segments;
1706295abce2SAllain Legacy 	unsigned int tx_bytes;
1707295abce2SAllain Legacy 	unsigned int i;
1708295abce2SAllain Legacy 
1709295abce2SAllain Legacy 	orig_nb_pkts = nb_pkts;
171082e140b8SAllain Legacy 	if (unlikely(avp->flags & AVP_F_DETACHED)) {
171182e140b8SAllain Legacy 		/* VM live migration in progress */
171282e140b8SAllain Legacy 		/* TODO ... buffer for X packets then drop? */
171382e140b8SAllain Legacy 		txq->errors += nb_pkts;
171482e140b8SAllain Legacy 		return 0;
171582e140b8SAllain Legacy 	}
171682e140b8SAllain Legacy 
1717295abce2SAllain Legacy 	tx_q = avp->tx_q[txq->queue_id];
1718295abce2SAllain Legacy 	alloc_q = avp->alloc_q[txq->queue_id];
1719295abce2SAllain Legacy 
1720295abce2SAllain Legacy 	/* limit the number of transmitted packets to the max burst size */
1721295abce2SAllain Legacy 	if (unlikely(nb_pkts > AVP_MAX_TX_BURST))
1722295abce2SAllain Legacy 		nb_pkts = AVP_MAX_TX_BURST;
1723295abce2SAllain Legacy 
1724295abce2SAllain Legacy 	/* determine how many buffers are available to copy into */
1725295abce2SAllain Legacy 	avail = avp_fifo_count(alloc_q);
1726295abce2SAllain Legacy 	if (unlikely(avail > (AVP_MAX_TX_BURST *
1727295abce2SAllain Legacy 			      RTE_AVP_MAX_MBUF_SEGMENTS)))
1728295abce2SAllain Legacy 		avail = AVP_MAX_TX_BURST * RTE_AVP_MAX_MBUF_SEGMENTS;
1729295abce2SAllain Legacy 
1730295abce2SAllain Legacy 	/* determine how many slots are available in the transmit queue */
1731295abce2SAllain Legacy 	count = avp_fifo_free_count(tx_q);
1732295abce2SAllain Legacy 
1733295abce2SAllain Legacy 	/* determine how many packets can be sent */
1734295abce2SAllain Legacy 	nb_pkts = RTE_MIN(count, nb_pkts);
1735295abce2SAllain Legacy 
1736295abce2SAllain Legacy 	/* determine how many packets will fit in the available buffers */
1737295abce2SAllain Legacy 	count = 0;
1738295abce2SAllain Legacy 	segments = 0;
1739295abce2SAllain Legacy 	for (i = 0; i < nb_pkts; i++) {
1740295abce2SAllain Legacy 		m = tx_pkts[i];
1741295abce2SAllain Legacy 		if (likely(i < (unsigned int)nb_pkts - 1)) {
1742295abce2SAllain Legacy 			/* prefetch next entry while processing this one */
1743295abce2SAllain Legacy 			rte_prefetch0(tx_pkts[i + 1]);
1744295abce2SAllain Legacy 		}
1745295abce2SAllain Legacy 		required = (rte_pktmbuf_pkt_len(m) + avp->host_mbuf_size - 1) /
1746295abce2SAllain Legacy 			avp->host_mbuf_size;
1747295abce2SAllain Legacy 
1748295abce2SAllain Legacy 		if (unlikely((required == 0) ||
1749295abce2SAllain Legacy 			     (required > RTE_AVP_MAX_MBUF_SEGMENTS)))
1750295abce2SAllain Legacy 			break;
1751295abce2SAllain Legacy 		else if (unlikely(required + segments > avail))
1752295abce2SAllain Legacy 			break;
1753295abce2SAllain Legacy 		segments += required;
1754295abce2SAllain Legacy 		count++;
1755295abce2SAllain Legacy 	}
1756295abce2SAllain Legacy 	nb_pkts = count;
1757295abce2SAllain Legacy 
1758295abce2SAllain Legacy 	if (unlikely(nb_pkts == 0)) {
1759295abce2SAllain Legacy 		/* no available buffers, or no space on the tx queue */
1760295abce2SAllain Legacy 		txq->errors += orig_nb_pkts;
1761295abce2SAllain Legacy 		return 0;
1762295abce2SAllain Legacy 	}
1763295abce2SAllain Legacy 
1764*e99981afSDavid Marchand 	PMD_TX_LOG_LINE(DEBUG, "Sending %u packets on Tx queue at %p",
1765295abce2SAllain Legacy 		   nb_pkts, tx_q);
1766295abce2SAllain Legacy 
1767295abce2SAllain Legacy 	/* retrieve sufficient send buffers */
1768295abce2SAllain Legacy 	n = avp_fifo_get(alloc_q, (void **)&avp_bufs, segments);
1769295abce2SAllain Legacy 	if (unlikely(n != segments)) {
1770*e99981afSDavid Marchand 		PMD_TX_LOG_LINE(DEBUG, "Failed to allocate buffers n=%u, segments=%u, orig=%u",
1771295abce2SAllain Legacy 			   n, segments, orig_nb_pkts);
1772295abce2SAllain Legacy 		txq->errors += orig_nb_pkts;
1773295abce2SAllain Legacy 		return 0;
1774295abce2SAllain Legacy 	}
1775295abce2SAllain Legacy 
1776295abce2SAllain Legacy 	tx_bytes = 0;
1777295abce2SAllain Legacy 	count = 0;
1778295abce2SAllain Legacy 	for (i = 0; i < nb_pkts; i++) {
1779295abce2SAllain Legacy 		/* process each packet to be transmitted */
1780295abce2SAllain Legacy 		m = tx_pkts[i];
1781295abce2SAllain Legacy 
1782295abce2SAllain Legacy 		/* determine how many buffers are required for this packet */
1783295abce2SAllain Legacy 		required = (rte_pktmbuf_pkt_len(m) + avp->host_mbuf_size - 1) /
1784295abce2SAllain Legacy 			avp->host_mbuf_size;
1785295abce2SAllain Legacy 
1786295abce2SAllain Legacy 		tx_bytes += avp_dev_copy_to_buffers(avp, m,
1787295abce2SAllain Legacy 						    &avp_bufs[count], required);
1788295abce2SAllain Legacy 		tx_bufs[i] = avp_bufs[count];
1789295abce2SAllain Legacy 		count += required;
1790295abce2SAllain Legacy 
1791295abce2SAllain Legacy 		/* free the original mbuf */
1792295abce2SAllain Legacy 		rte_pktmbuf_free(m);
1793295abce2SAllain Legacy 	}
1794295abce2SAllain Legacy 
1795295abce2SAllain Legacy 	txq->packets += nb_pkts;
1796295abce2SAllain Legacy 	txq->bytes += tx_bytes;
1797295abce2SAllain Legacy 
1798295abce2SAllain Legacy #ifdef RTE_LIBRTE_AVP_DEBUG_BUFFERS
1799295abce2SAllain Legacy 	for (i = 0; i < nb_pkts; i++)
1800295abce2SAllain Legacy 		avp_dev_buffer_sanity_check(avp, tx_bufs[i]);
1801295abce2SAllain Legacy #endif
1802295abce2SAllain Legacy 
1803295abce2SAllain Legacy 	/* send the packets */
1804295abce2SAllain Legacy 	n = avp_fifo_put(tx_q, (void **)&tx_bufs[0], nb_pkts);
1805295abce2SAllain Legacy 	if (unlikely(n != orig_nb_pkts))
1806295abce2SAllain Legacy 		txq->errors += (orig_nb_pkts - n);
1807295abce2SAllain Legacy 
1808295abce2SAllain Legacy 	return n;
1809295abce2SAllain Legacy }
1810295abce2SAllain Legacy 
1811295abce2SAllain Legacy 
1812295abce2SAllain Legacy static uint16_t
1813295abce2SAllain Legacy avp_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
1814295abce2SAllain Legacy {
1815295abce2SAllain Legacy 	struct avp_queue *txq = (struct avp_queue *)tx_queue;
1816295abce2SAllain Legacy 	struct rte_avp_desc *avp_bufs[AVP_MAX_TX_BURST];
1817295abce2SAllain Legacy 	struct avp_dev *avp = txq->avp;
1818295abce2SAllain Legacy 	struct rte_avp_desc *pkt_buf;
1819295abce2SAllain Legacy 	struct rte_avp_fifo *alloc_q;
1820295abce2SAllain Legacy 	struct rte_avp_fifo *tx_q;
1821295abce2SAllain Legacy 	unsigned int count, avail, n;
1822295abce2SAllain Legacy 	struct rte_mbuf *m;
1823295abce2SAllain Legacy 	unsigned int pkt_len;
1824295abce2SAllain Legacy 	unsigned int tx_bytes;
1825295abce2SAllain Legacy 	char *pkt_data;
1826295abce2SAllain Legacy 	unsigned int i;
1827295abce2SAllain Legacy 
182882e140b8SAllain Legacy 	if (unlikely(avp->flags & AVP_F_DETACHED)) {
182982e140b8SAllain Legacy 		/* VM live migration in progress */
183082e140b8SAllain Legacy 		/* TODO ... buffer for X packets then drop?! */
183182e140b8SAllain Legacy 		txq->errors++;
183282e140b8SAllain Legacy 		return 0;
183382e140b8SAllain Legacy 	}
183482e140b8SAllain Legacy 
1835295abce2SAllain Legacy 	tx_q = avp->tx_q[txq->queue_id];
1836295abce2SAllain Legacy 	alloc_q = avp->alloc_q[txq->queue_id];
1837295abce2SAllain Legacy 
1838295abce2SAllain Legacy 	/* limit the number of transmitted packets to the max burst size */
1839295abce2SAllain Legacy 	if (unlikely(nb_pkts > AVP_MAX_TX_BURST))
1840295abce2SAllain Legacy 		nb_pkts = AVP_MAX_TX_BURST;
1841295abce2SAllain Legacy 
1842295abce2SAllain Legacy 	/* determine how many buffers are available to copy into */
1843295abce2SAllain Legacy 	avail = avp_fifo_count(alloc_q);
1844295abce2SAllain Legacy 
1845295abce2SAllain Legacy 	/* determine how many slots are available in the transmit queue */
1846295abce2SAllain Legacy 	count = avp_fifo_free_count(tx_q);
1847295abce2SAllain Legacy 
1848295abce2SAllain Legacy 	/* determine how many packets can be sent */
1849295abce2SAllain Legacy 	count = RTE_MIN(count, avail);
1850295abce2SAllain Legacy 	count = RTE_MIN(count, nb_pkts);
1851295abce2SAllain Legacy 
1852295abce2SAllain Legacy 	if (unlikely(count == 0)) {
1853295abce2SAllain Legacy 		/* no available buffers, or no space on the tx queue */
1854295abce2SAllain Legacy 		txq->errors += nb_pkts;
1855295abce2SAllain Legacy 		return 0;
1856295abce2SAllain Legacy 	}
1857295abce2SAllain Legacy 
1858*e99981afSDavid Marchand 	PMD_TX_LOG_LINE(DEBUG, "Sending %u packets on Tx queue at %p",
1859295abce2SAllain Legacy 		   count, tx_q);
1860295abce2SAllain Legacy 
1861295abce2SAllain Legacy 	/* retrieve sufficient send buffers */
1862295abce2SAllain Legacy 	n = avp_fifo_get(alloc_q, (void **)&avp_bufs, count);
1863295abce2SAllain Legacy 	if (unlikely(n != count)) {
1864295abce2SAllain Legacy 		txq->errors++;
1865295abce2SAllain Legacy 		return 0;
1866295abce2SAllain Legacy 	}
1867295abce2SAllain Legacy 
1868295abce2SAllain Legacy 	tx_bytes = 0;
1869295abce2SAllain Legacy 	for (i = 0; i < count; i++) {
1870295abce2SAllain Legacy 		/* prefetch next entry while processing the current one */
1871295abce2SAllain Legacy 		if (i < count - 1) {
1872295abce2SAllain Legacy 			pkt_buf = avp_dev_translate_buffer(avp,
1873295abce2SAllain Legacy 							   avp_bufs[i + 1]);
1874295abce2SAllain Legacy 			rte_prefetch0(pkt_buf);
1875295abce2SAllain Legacy 		}
1876295abce2SAllain Legacy 
1877295abce2SAllain Legacy 		/* process each packet to be transmitted */
1878295abce2SAllain Legacy 		m = tx_pkts[i];
1879295abce2SAllain Legacy 
1880295abce2SAllain Legacy 		/* Adjust pointers for guest addressing */
1881295abce2SAllain Legacy 		pkt_buf = avp_dev_translate_buffer(avp, avp_bufs[i]);
1882295abce2SAllain Legacy 		pkt_data = avp_dev_translate_buffer(avp, pkt_buf->data);
1883295abce2SAllain Legacy 		pkt_len = rte_pktmbuf_pkt_len(m);
1884295abce2SAllain Legacy 
1885295abce2SAllain Legacy 		if (unlikely((pkt_len > avp->guest_mbuf_size) ||
1886295abce2SAllain Legacy 					 (pkt_len > avp->host_mbuf_size))) {
1887295abce2SAllain Legacy 			/*
1888295abce2SAllain Legacy 			 * application should be using the scattered transmit
1889295abce2SAllain Legacy 			 * function; send it truncated to avoid the performance
1890295abce2SAllain Legacy 			 * hit of having to manage returning the already
1891295abce2SAllain Legacy 			 * allocated buffer to the free list.  This should not
18921bb4a528SFerruh Yigit 			 * happen since the application should have not send
18931bb4a528SFerruh Yigit 			 * packages larger than its MTU and it should be
1894295abce2SAllain Legacy 			 * policing its own packet sizes.
1895295abce2SAllain Legacy 			 */
1896295abce2SAllain Legacy 			txq->errors++;
1897295abce2SAllain Legacy 			pkt_len = RTE_MIN(avp->guest_mbuf_size,
1898295abce2SAllain Legacy 					  avp->host_mbuf_size);
1899295abce2SAllain Legacy 		}
1900295abce2SAllain Legacy 
1901295abce2SAllain Legacy 		/* copy data out of our mbuf and into the AVP buffer */
1902295abce2SAllain Legacy 		rte_memcpy(pkt_data, rte_pktmbuf_mtod(m, void *), pkt_len);
1903295abce2SAllain Legacy 		pkt_buf->pkt_len = pkt_len;
1904295abce2SAllain Legacy 		pkt_buf->data_len = pkt_len;
1905295abce2SAllain Legacy 		pkt_buf->nb_segs = 1;
1906295abce2SAllain Legacy 		pkt_buf->next = NULL;
1907295abce2SAllain Legacy 
1908daa02b5cSOlivier Matz 		if (m->ol_flags & RTE_MBUF_F_TX_VLAN) {
1909295abce2SAllain Legacy 			pkt_buf->ol_flags |= RTE_AVP_TX_VLAN_PKT;
1910295abce2SAllain Legacy 			pkt_buf->vlan_tci = m->vlan_tci;
1911295abce2SAllain Legacy 		}
1912295abce2SAllain Legacy 
1913295abce2SAllain Legacy 		tx_bytes += pkt_len;
1914295abce2SAllain Legacy 
1915295abce2SAllain Legacy 		/* free the original mbuf */
1916295abce2SAllain Legacy 		rte_pktmbuf_free(m);
1917295abce2SAllain Legacy 	}
1918295abce2SAllain Legacy 
1919295abce2SAllain Legacy 	txq->packets += count;
1920295abce2SAllain Legacy 	txq->bytes += tx_bytes;
1921295abce2SAllain Legacy 
1922295abce2SAllain Legacy 	/* send the packets */
1923295abce2SAllain Legacy 	n = avp_fifo_put(tx_q, (void **)&avp_bufs[0], count);
1924295abce2SAllain Legacy 
1925295abce2SAllain Legacy 	return n;
1926295abce2SAllain Legacy }
1927295abce2SAllain Legacy 
1928cce4367fSAllain Legacy static void
19297483341aSXueming Li avp_dev_rx_queue_release(struct rte_eth_dev *eth_dev, uint16_t rx_queue_id)
1930cce4367fSAllain Legacy {
19317483341aSXueming Li 	if (eth_dev->data->rx_queues[rx_queue_id] != NULL) {
19327483341aSXueming Li 		rte_free(eth_dev->data->rx_queues[rx_queue_id]);
19337483341aSXueming Li 		eth_dev->data->rx_queues[rx_queue_id] = NULL;
1934cce4367fSAllain Legacy 	}
193515fb42d5SAllain Legacy }
193615fb42d5SAllain Legacy 
193715fb42d5SAllain Legacy static void
193815fb42d5SAllain Legacy avp_dev_rx_queue_release_all(struct rte_eth_dev *eth_dev)
193915fb42d5SAllain Legacy {
194015fb42d5SAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
194115fb42d5SAllain Legacy 	struct rte_eth_dev_data *data = avp->dev_data;
194215fb42d5SAllain Legacy 	unsigned int i;
194315fb42d5SAllain Legacy 
194415fb42d5SAllain Legacy 	for (i = 0; i < avp->num_rx_queues; i++) {
194515fb42d5SAllain Legacy 		if (data->rx_queues[i]) {
194615fb42d5SAllain Legacy 			rte_free(data->rx_queues[i]);
194715fb42d5SAllain Legacy 			data->rx_queues[i] = NULL;
194815fb42d5SAllain Legacy 		}
194915fb42d5SAllain Legacy 	}
195015fb42d5SAllain Legacy }
1951cce4367fSAllain Legacy 
1952cce4367fSAllain Legacy static void
19537483341aSXueming Li avp_dev_tx_queue_release(struct rte_eth_dev *eth_dev, uint16_t tx_queue_id)
1954cce4367fSAllain Legacy {
19557483341aSXueming Li 	if (eth_dev->data->tx_queues[tx_queue_id] != NULL) {
19567483341aSXueming Li 		rte_free(eth_dev->data->tx_queues[tx_queue_id]);
19577483341aSXueming Li 		eth_dev->data->tx_queues[tx_queue_id] = NULL;
1958cce4367fSAllain Legacy 	}
195915fb42d5SAllain Legacy }
196015fb42d5SAllain Legacy 
196115fb42d5SAllain Legacy static void
196215fb42d5SAllain Legacy avp_dev_tx_queue_release_all(struct rte_eth_dev *eth_dev)
196315fb42d5SAllain Legacy {
196415fb42d5SAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
196515fb42d5SAllain Legacy 	struct rte_eth_dev_data *data = avp->dev_data;
196615fb42d5SAllain Legacy 	unsigned int i;
196715fb42d5SAllain Legacy 
196815fb42d5SAllain Legacy 	for (i = 0; i < avp->num_tx_queues; i++) {
196915fb42d5SAllain Legacy 		if (data->tx_queues[i]) {
197015fb42d5SAllain Legacy 			rte_free(data->tx_queues[i]);
197115fb42d5SAllain Legacy 			data->tx_queues[i] = NULL;
197215fb42d5SAllain Legacy 		}
197315fb42d5SAllain Legacy 	}
197415fb42d5SAllain Legacy }
1975cce4367fSAllain Legacy 
1976cce4367fSAllain Legacy static int
19771a859223SAllain Legacy avp_dev_configure(struct rte_eth_dev *eth_dev)
19781a859223SAllain Legacy {
1979c0802544SFerruh Yigit 	struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
19801a859223SAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
19811a859223SAllain Legacy 	struct rte_avp_device_info *host_info;
19821a859223SAllain Legacy 	struct rte_avp_device_config config;
19831a859223SAllain Legacy 	int mask = 0;
19841a859223SAllain Legacy 	void *addr;
19851a859223SAllain Legacy 	int ret;
19861a859223SAllain Legacy 
198782e140b8SAllain Legacy 	rte_spinlock_lock(&avp->lock);
198882e140b8SAllain Legacy 	if (avp->flags & AVP_F_DETACHED) {
1989*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Operation not supported during VM live migration");
199082e140b8SAllain Legacy 		ret = -ENOTSUP;
199182e140b8SAllain Legacy 		goto unlock;
199282e140b8SAllain Legacy 	}
199382e140b8SAllain Legacy 
19941a859223SAllain Legacy 	addr = pci_dev->mem_resource[RTE_AVP_PCI_DEVICE_BAR].addr;
19951a859223SAllain Legacy 	host_info = (struct rte_avp_device_info *)addr;
19961a859223SAllain Legacy 
19971a859223SAllain Legacy 	/* Setup required number of queues */
19981a859223SAllain Legacy 	_avp_set_queue_counts(eth_dev);
19991a859223SAllain Legacy 
2000295968d1SFerruh Yigit 	mask = (RTE_ETH_VLAN_STRIP_MASK |
2001295968d1SFerruh Yigit 		RTE_ETH_VLAN_FILTER_MASK |
2002295968d1SFerruh Yigit 		RTE_ETH_VLAN_EXTEND_MASK);
2003289ba0c0SDavid Harton 	ret = avp_vlan_offload_set(eth_dev, mask);
2004289ba0c0SDavid Harton 	if (ret < 0) {
2005*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "VLAN offload set failed by host, ret=%d",
2006289ba0c0SDavid Harton 			    ret);
2007289ba0c0SDavid Harton 		goto unlock;
2008289ba0c0SDavid Harton 	}
20091a859223SAllain Legacy 
20101a859223SAllain Legacy 	/* update device config */
20111a859223SAllain Legacy 	memset(&config, 0, sizeof(config));
20121a859223SAllain Legacy 	config.device_id = host_info->device_id;
20131a859223SAllain Legacy 	config.driver_type = RTE_AVP_DRIVER_TYPE_DPDK;
20141a859223SAllain Legacy 	config.driver_version = AVP_DPDK_DRIVER_VERSION;
20151a859223SAllain Legacy 	config.features = avp->features;
20161a859223SAllain Legacy 	config.num_tx_queues = avp->num_tx_queues;
20171a859223SAllain Legacy 	config.num_rx_queues = avp->num_rx_queues;
20181a859223SAllain Legacy 
20191a859223SAllain Legacy 	ret = avp_dev_ctrl_set_config(eth_dev, &config);
20201a859223SAllain Legacy 	if (ret < 0) {
2021*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Config request failed by host, ret=%d",
20221a859223SAllain Legacy 			    ret);
20231a859223SAllain Legacy 		goto unlock;
20241a859223SAllain Legacy 	}
20251a859223SAllain Legacy 
20261a859223SAllain Legacy 	avp->flags |= AVP_F_CONFIGURED;
20271a859223SAllain Legacy 	ret = 0;
20281a859223SAllain Legacy 
20291a859223SAllain Legacy unlock:
203082e140b8SAllain Legacy 	rte_spinlock_unlock(&avp->lock);
20311a859223SAllain Legacy 	return ret;
20321a859223SAllain Legacy }
20331a859223SAllain Legacy 
2034ea37523dSAllain Legacy static int
2035ea37523dSAllain Legacy avp_dev_start(struct rte_eth_dev *eth_dev)
2036ea37523dSAllain Legacy {
2037ea37523dSAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
203868601507SJie Hai 	uint16_t i;
2039ea37523dSAllain Legacy 	int ret;
2040ea37523dSAllain Legacy 
204182e140b8SAllain Legacy 	rte_spinlock_lock(&avp->lock);
204282e140b8SAllain Legacy 	if (avp->flags & AVP_F_DETACHED) {
2043*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Operation not supported during VM live migration");
204482e140b8SAllain Legacy 		ret = -ENOTSUP;
204582e140b8SAllain Legacy 		goto unlock;
204682e140b8SAllain Legacy 	}
204782e140b8SAllain Legacy 
2048ea37523dSAllain Legacy 	/* update link state */
2049ea37523dSAllain Legacy 	ret = avp_dev_ctrl_set_link_state(eth_dev, 1);
2050ea37523dSAllain Legacy 	if (ret < 0) {
2051*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Link state change failed by host, ret=%d",
2052ea37523dSAllain Legacy 			    ret);
2053ea37523dSAllain Legacy 		goto unlock;
2054ea37523dSAllain Legacy 	}
2055ea37523dSAllain Legacy 
2056ea37523dSAllain Legacy 	/* remember current link state */
2057ea37523dSAllain Legacy 	avp->flags |= AVP_F_LINKUP;
2058ea37523dSAllain Legacy 
205968601507SJie Hai 	for (i = 0; i < avp->num_rx_queues; i++)
206068601507SJie Hai 		eth_dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
206168601507SJie Hai 	for (i = 0; i < avp->num_tx_queues; i++)
206268601507SJie Hai 		eth_dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
206368601507SJie Hai 
2064ea37523dSAllain Legacy 	ret = 0;
2065ea37523dSAllain Legacy 
2066ea37523dSAllain Legacy unlock:
206782e140b8SAllain Legacy 	rte_spinlock_unlock(&avp->lock);
2068ea37523dSAllain Legacy 	return ret;
2069ea37523dSAllain Legacy }
2070ea37523dSAllain Legacy 
207162024eb8SIvan Ilchenko static int
2072ea37523dSAllain Legacy avp_dev_stop(struct rte_eth_dev *eth_dev)
2073ea37523dSAllain Legacy {
2074ea37523dSAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
207568601507SJie Hai 	uint16_t i;
2076ea37523dSAllain Legacy 	int ret;
2077ea37523dSAllain Legacy 
207882e140b8SAllain Legacy 	rte_spinlock_lock(&avp->lock);
207982e140b8SAllain Legacy 	if (avp->flags & AVP_F_DETACHED) {
2080*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Operation not supported during VM live migration");
208162024eb8SIvan Ilchenko 		ret = -ENOTSUP;
208282e140b8SAllain Legacy 		goto unlock;
208382e140b8SAllain Legacy 	}
208482e140b8SAllain Legacy 
208582e140b8SAllain Legacy 	/* remember current link state */
2086ea37523dSAllain Legacy 	avp->flags &= ~AVP_F_LINKUP;
2087ea37523dSAllain Legacy 
2088ea37523dSAllain Legacy 	/* update link state */
2089ea37523dSAllain Legacy 	ret = avp_dev_ctrl_set_link_state(eth_dev, 0);
2090ea37523dSAllain Legacy 	if (ret < 0) {
2091*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Link state change failed by host, ret=%d",
2092ea37523dSAllain Legacy 			    ret);
2093ea37523dSAllain Legacy 	}
209482e140b8SAllain Legacy 
209568601507SJie Hai 	for (i = 0; i < avp->num_rx_queues; i++)
209668601507SJie Hai 		eth_dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
209768601507SJie Hai 	for (i = 0; i < avp->num_tx_queues; i++)
209868601507SJie Hai 		eth_dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
209968601507SJie Hai 
210082e140b8SAllain Legacy unlock:
210182e140b8SAllain Legacy 	rte_spinlock_unlock(&avp->lock);
210262024eb8SIvan Ilchenko 	return ret;
2103ea37523dSAllain Legacy }
2104ea37523dSAllain Legacy 
2105b142387bSThomas Monjalon static int
2106ea37523dSAllain Legacy avp_dev_close(struct rte_eth_dev *eth_dev)
2107ea37523dSAllain Legacy {
2108ea37523dSAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
2109ea37523dSAllain Legacy 	int ret;
2110ea37523dSAllain Legacy 
211130410493SThomas Monjalon 	if (rte_eal_process_type() != RTE_PROC_PRIMARY)
211230410493SThomas Monjalon 		return 0;
211330410493SThomas Monjalon 
211482e140b8SAllain Legacy 	rte_spinlock_lock(&avp->lock);
211582e140b8SAllain Legacy 	if (avp->flags & AVP_F_DETACHED) {
2116*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Operation not supported during VM live migration");
211782e140b8SAllain Legacy 		goto unlock;
211882e140b8SAllain Legacy 	}
211982e140b8SAllain Legacy 
2120ea37523dSAllain Legacy 	/* remember current link state */
2121ea37523dSAllain Legacy 	avp->flags &= ~AVP_F_LINKUP;
2122ea37523dSAllain Legacy 	avp->flags &= ~AVP_F_CONFIGURED;
2123ea37523dSAllain Legacy 
212482e140b8SAllain Legacy 	ret = avp_dev_disable_interrupts(eth_dev);
212582e140b8SAllain Legacy 	if (ret < 0) {
2126*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Failed to disable interrupts");
212782e140b8SAllain Legacy 		/* continue */
212882e140b8SAllain Legacy 	}
212982e140b8SAllain Legacy 
2130ea37523dSAllain Legacy 	/* update device state */
2131ea37523dSAllain Legacy 	ret = avp_dev_ctrl_shutdown(eth_dev);
2132ea37523dSAllain Legacy 	if (ret < 0) {
2133*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(ERR, "Device shutdown failed by host, ret=%d",
2134ea37523dSAllain Legacy 			    ret);
2135ea37523dSAllain Legacy 		/* continue */
2136ea37523dSAllain Legacy 	}
213782e140b8SAllain Legacy 
213815fb42d5SAllain Legacy 	/* release dynamic storage for rx/tx queues */
213915fb42d5SAllain Legacy 	avp_dev_rx_queue_release_all(eth_dev);
214015fb42d5SAllain Legacy 	avp_dev_tx_queue_release_all(eth_dev);
214115fb42d5SAllain Legacy 
214282e140b8SAllain Legacy unlock:
214382e140b8SAllain Legacy 	rte_spinlock_unlock(&avp->lock);
2144b142387bSThomas Monjalon 	return 0;
2145ea37523dSAllain Legacy }
21461a859223SAllain Legacy 
21471a859223SAllain Legacy static int
21481a859223SAllain Legacy avp_dev_link_update(struct rte_eth_dev *eth_dev,
21491a859223SAllain Legacy 					__rte_unused int wait_to_complete)
21501a859223SAllain Legacy {
21511a859223SAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
21521a859223SAllain Legacy 	struct rte_eth_link *link = &eth_dev->data->dev_link;
21531a859223SAllain Legacy 
2154295968d1SFerruh Yigit 	link->link_speed = RTE_ETH_SPEED_NUM_10G;
2155295968d1SFerruh Yigit 	link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
21561a859223SAllain Legacy 	link->link_status = !!(avp->flags & AVP_F_LINKUP);
21571a859223SAllain Legacy 
21581a859223SAllain Legacy 	return -1;
21591a859223SAllain Legacy }
21601a859223SAllain Legacy 
21619039c812SAndrew Rybchenko static int
21628129545eSAllain Legacy avp_dev_promiscuous_enable(struct rte_eth_dev *eth_dev)
21638129545eSAllain Legacy {
21648129545eSAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
21658129545eSAllain Legacy 
216682e140b8SAllain Legacy 	rte_spinlock_lock(&avp->lock);
21678129545eSAllain Legacy 	if ((avp->flags & AVP_F_PROMISC) == 0) {
21688129545eSAllain Legacy 		avp->flags |= AVP_F_PROMISC;
2169*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(DEBUG, "Promiscuous mode enabled on %u",
21708129545eSAllain Legacy 			    eth_dev->data->port_id);
21718129545eSAllain Legacy 	}
217282e140b8SAllain Legacy 	rte_spinlock_unlock(&avp->lock);
21739039c812SAndrew Rybchenko 
21749039c812SAndrew Rybchenko 	return 0;
21758129545eSAllain Legacy }
21768129545eSAllain Legacy 
21779039c812SAndrew Rybchenko static int
21788129545eSAllain Legacy avp_dev_promiscuous_disable(struct rte_eth_dev *eth_dev)
21798129545eSAllain Legacy {
21808129545eSAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
21818129545eSAllain Legacy 
218282e140b8SAllain Legacy 	rte_spinlock_lock(&avp->lock);
21838129545eSAllain Legacy 	if ((avp->flags & AVP_F_PROMISC) != 0) {
21848129545eSAllain Legacy 		avp->flags &= ~AVP_F_PROMISC;
2185*e99981afSDavid Marchand 		PMD_DRV_LOG_LINE(DEBUG, "Promiscuous mode disabled on %u",
21868129545eSAllain Legacy 			    eth_dev->data->port_id);
21878129545eSAllain Legacy 	}
218882e140b8SAllain Legacy 	rte_spinlock_unlock(&avp->lock);
21899039c812SAndrew Rybchenko 
21909039c812SAndrew Rybchenko 	return 0;
21918129545eSAllain Legacy }
21921a859223SAllain Legacy 
2193bdad90d1SIvan Ilchenko static int
21941a859223SAllain Legacy avp_dev_info_get(struct rte_eth_dev *eth_dev,
21951a859223SAllain Legacy 		 struct rte_eth_dev_info *dev_info)
21961a859223SAllain Legacy {
21971a859223SAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
21981a859223SAllain Legacy 
21991a859223SAllain Legacy 	dev_info->max_rx_queues = avp->max_rx_queues;
22001a859223SAllain Legacy 	dev_info->max_tx_queues = avp->max_tx_queues;
22011a859223SAllain Legacy 	dev_info->min_rx_bufsize = AVP_MIN_RX_BUFSIZE;
22021a859223SAllain Legacy 	dev_info->max_rx_pktlen = avp->max_rx_pkt_len;
22031a859223SAllain Legacy 	dev_info->max_mac_addrs = AVP_MAX_MAC_ADDRS;
22041a859223SAllain Legacy 	if (avp->host_features & RTE_AVP_FEATURE_VLAN_OFFLOAD) {
2205295968d1SFerruh Yigit 		dev_info->rx_offload_capa = RTE_ETH_RX_OFFLOAD_VLAN_STRIP;
2206295968d1SFerruh Yigit 		dev_info->tx_offload_capa = RTE_ETH_TX_OFFLOAD_VLAN_INSERT;
22071a859223SAllain Legacy 	}
2208bdad90d1SIvan Ilchenko 
2209bdad90d1SIvan Ilchenko 	return 0;
22101a859223SAllain Legacy }
22111a859223SAllain Legacy 
2212289ba0c0SDavid Harton static int
22131a859223SAllain Legacy avp_vlan_offload_set(struct rte_eth_dev *eth_dev, int mask)
22141a859223SAllain Legacy {
22151a859223SAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
2216462b66d8SAllain Legacy 	struct rte_eth_conf *dev_conf = &eth_dev->data->dev_conf;
2217462b66d8SAllain Legacy 	uint64_t offloads = dev_conf->rxmode.offloads;
22181a859223SAllain Legacy 
2219295968d1SFerruh Yigit 	if (mask & RTE_ETH_VLAN_STRIP_MASK) {
22201a859223SAllain Legacy 		if (avp->host_features & RTE_AVP_FEATURE_VLAN_OFFLOAD) {
2221295968d1SFerruh Yigit 			if (offloads & RTE_ETH_RX_OFFLOAD_VLAN_STRIP)
22221a859223SAllain Legacy 				avp->features |= RTE_AVP_FEATURE_VLAN_OFFLOAD;
22231a859223SAllain Legacy 			else
22241a859223SAllain Legacy 				avp->features &= ~RTE_AVP_FEATURE_VLAN_OFFLOAD;
22251a859223SAllain Legacy 		} else {
2226*e99981afSDavid Marchand 			PMD_DRV_LOG_LINE(ERR, "VLAN strip offload not supported");
22271a859223SAllain Legacy 		}
22281a859223SAllain Legacy 	}
22291a859223SAllain Legacy 
2230295968d1SFerruh Yigit 	if (mask & RTE_ETH_VLAN_FILTER_MASK) {
2231295968d1SFerruh Yigit 		if (offloads & RTE_ETH_RX_OFFLOAD_VLAN_FILTER)
2232*e99981afSDavid Marchand 			PMD_DRV_LOG_LINE(ERR, "VLAN filter offload not supported");
22331a859223SAllain Legacy 	}
22341a859223SAllain Legacy 
2235295968d1SFerruh Yigit 	if (mask & RTE_ETH_VLAN_EXTEND_MASK) {
2236295968d1SFerruh Yigit 		if (offloads & RTE_ETH_RX_OFFLOAD_VLAN_EXTEND)
2237*e99981afSDavid Marchand 			PMD_DRV_LOG_LINE(ERR, "VLAN extend offload not supported");
22381a859223SAllain Legacy 	}
2239289ba0c0SDavid Harton 
2240289ba0c0SDavid Harton 	return 0;
22411a859223SAllain Legacy }
22421a859223SAllain Legacy 
2243d5b0924bSMatan Azrad static int
22445a5abe2dSAllain Legacy avp_dev_stats_get(struct rte_eth_dev *eth_dev, struct rte_eth_stats *stats)
22455a5abe2dSAllain Legacy {
22465a5abe2dSAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
22475a5abe2dSAllain Legacy 	unsigned int i;
22485a5abe2dSAllain Legacy 
22495a5abe2dSAllain Legacy 	for (i = 0; i < avp->num_rx_queues; i++) {
22505a5abe2dSAllain Legacy 		struct avp_queue *rxq = avp->dev_data->rx_queues[i];
22515a5abe2dSAllain Legacy 
22525a5abe2dSAllain Legacy 		if (rxq) {
22535a5abe2dSAllain Legacy 			stats->ipackets += rxq->packets;
22545a5abe2dSAllain Legacy 			stats->ibytes += rxq->bytes;
22555a5abe2dSAllain Legacy 			stats->ierrors += rxq->errors;
22565a5abe2dSAllain Legacy 
22575a5abe2dSAllain Legacy 			stats->q_ipackets[i] += rxq->packets;
22585a5abe2dSAllain Legacy 			stats->q_ibytes[i] += rxq->bytes;
22595a5abe2dSAllain Legacy 			stats->q_errors[i] += rxq->errors;
22605a5abe2dSAllain Legacy 		}
22615a5abe2dSAllain Legacy 	}
22625a5abe2dSAllain Legacy 
22635a5abe2dSAllain Legacy 	for (i = 0; i < avp->num_tx_queues; i++) {
22645a5abe2dSAllain Legacy 		struct avp_queue *txq = avp->dev_data->tx_queues[i];
22655a5abe2dSAllain Legacy 
22665a5abe2dSAllain Legacy 		if (txq) {
22675a5abe2dSAllain Legacy 			stats->opackets += txq->packets;
22685a5abe2dSAllain Legacy 			stats->obytes += txq->bytes;
22695a5abe2dSAllain Legacy 			stats->oerrors += txq->errors;
22705a5abe2dSAllain Legacy 
22715a5abe2dSAllain Legacy 			stats->q_opackets[i] += txq->packets;
22725a5abe2dSAllain Legacy 			stats->q_obytes[i] += txq->bytes;
22735a5abe2dSAllain Legacy 		}
22745a5abe2dSAllain Legacy 	}
2275d5b0924bSMatan Azrad 
2276d5b0924bSMatan Azrad 	return 0;
22775a5abe2dSAllain Legacy }
22785a5abe2dSAllain Legacy 
22799970a9adSIgor Romanov static int
22805a5abe2dSAllain Legacy avp_dev_stats_reset(struct rte_eth_dev *eth_dev)
22815a5abe2dSAllain Legacy {
22825a5abe2dSAllain Legacy 	struct avp_dev *avp = AVP_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
22835a5abe2dSAllain Legacy 	unsigned int i;
22845a5abe2dSAllain Legacy 
22855a5abe2dSAllain Legacy 	for (i = 0; i < avp->num_rx_queues; i++) {
22865a5abe2dSAllain Legacy 		struct avp_queue *rxq = avp->dev_data->rx_queues[i];
22875a5abe2dSAllain Legacy 
22885a5abe2dSAllain Legacy 		if (rxq) {
22895a5abe2dSAllain Legacy 			rxq->bytes = 0;
22905a5abe2dSAllain Legacy 			rxq->packets = 0;
22915a5abe2dSAllain Legacy 			rxq->errors = 0;
22925a5abe2dSAllain Legacy 		}
22935a5abe2dSAllain Legacy 	}
22945a5abe2dSAllain Legacy 
22955a5abe2dSAllain Legacy 	for (i = 0; i < avp->num_tx_queues; i++) {
22965a5abe2dSAllain Legacy 		struct avp_queue *txq = avp->dev_data->tx_queues[i];
22975a5abe2dSAllain Legacy 
22985a5abe2dSAllain Legacy 		if (txq) {
22995a5abe2dSAllain Legacy 			txq->bytes = 0;
23005a5abe2dSAllain Legacy 			txq->packets = 0;
23015a5abe2dSAllain Legacy 			txq->errors = 0;
23025a5abe2dSAllain Legacy 		}
23035a5abe2dSAllain Legacy 	}
23049970a9adSIgor Romanov 
23059970a9adSIgor Romanov 	return 0;
23065a5abe2dSAllain Legacy }
23075a5abe2dSAllain Legacy 
2308fdf91e0fSJan Blunck RTE_PMD_REGISTER_PCI(net_avp, rte_avp_pmd);
2309908072e9SAllain Legacy RTE_PMD_REGISTER_PCI_TABLE(net_avp, pci_id_avp_map);
2310eeded204SDavid Marchand RTE_LOG_REGISTER_SUFFIX(avp_logtype_driver, driver, NOTICE);
2311