xref: /dpdk/drivers/net/sfc/sfc_ethdev.c (revision a8ad8cf83f01afce616ffcc7a19bc44bc8609b96)
163d588ffSAndrew Rybchenko /*-
263d588ffSAndrew Rybchenko  * Copyright (c) 2016 Solarflare Communications Inc.
363d588ffSAndrew Rybchenko  * All rights reserved.
463d588ffSAndrew Rybchenko  *
563d588ffSAndrew Rybchenko  * This software was jointly developed between OKTET Labs (under contract
663d588ffSAndrew Rybchenko  * for Solarflare) and Solarflare Communications, Inc.
763d588ffSAndrew Rybchenko  *
863d588ffSAndrew Rybchenko  * Redistribution and use in source and binary forms, with or without
963d588ffSAndrew Rybchenko  * modification, are permitted provided that the following conditions are met:
1063d588ffSAndrew Rybchenko  *
1163d588ffSAndrew Rybchenko  * 1. Redistributions of source code must retain the above copyright notice,
1263d588ffSAndrew Rybchenko  *    this list of conditions and the following disclaimer.
1363d588ffSAndrew Rybchenko  * 2. Redistributions in binary form must reproduce the above copyright notice,
1463d588ffSAndrew Rybchenko  *    this list of conditions and the following disclaimer in the documentation
1563d588ffSAndrew Rybchenko  *    and/or other materials provided with the distribution.
1663d588ffSAndrew Rybchenko  *
1763d588ffSAndrew Rybchenko  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1863d588ffSAndrew Rybchenko  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
1963d588ffSAndrew Rybchenko  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2063d588ffSAndrew Rybchenko  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
2163d588ffSAndrew Rybchenko  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2263d588ffSAndrew Rybchenko  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2363d588ffSAndrew Rybchenko  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2463d588ffSAndrew Rybchenko  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2563d588ffSAndrew Rybchenko  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2663d588ffSAndrew Rybchenko  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
2763d588ffSAndrew Rybchenko  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2863d588ffSAndrew Rybchenko  */
2963d588ffSAndrew Rybchenko 
3063d588ffSAndrew Rybchenko #include <rte_dev.h>
3163d588ffSAndrew Rybchenko #include <rte_ethdev.h>
3263d588ffSAndrew Rybchenko #include <rte_pci.h>
3363d588ffSAndrew Rybchenko 
34ba641f20SAndrew Rybchenko #include "efx.h"
35ba641f20SAndrew Rybchenko 
3663d588ffSAndrew Rybchenko #include "sfc.h"
3763d588ffSAndrew Rybchenko #include "sfc_debug.h"
3863d588ffSAndrew Rybchenko #include "sfc_log.h"
3963d588ffSAndrew Rybchenko #include "sfc_kvargs.h"
40886f8d8aSArtem Andreev #include "sfc_ev.h"
41ce35b05cSAndrew Rybchenko #include "sfc_rx.h"
4263d588ffSAndrew Rybchenko 
4363d588ffSAndrew Rybchenko 
4463d588ffSAndrew Rybchenko static void
4563d588ffSAndrew Rybchenko sfc_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
4663d588ffSAndrew Rybchenko {
4763d588ffSAndrew Rybchenko 	struct sfc_adapter *sa = dev->data->dev_private;
4863d588ffSAndrew Rybchenko 
4963d588ffSAndrew Rybchenko 	sfc_log_init(sa, "entry");
5063d588ffSAndrew Rybchenko 
5163d588ffSAndrew Rybchenko 	dev_info->pci_dev = RTE_DEV_TO_PCI(dev->device);
5203ed2119SAndrew Rybchenko 	dev_info->max_rx_pktlen = EFX_MAC_PDU_MAX;
53a8e64c6bSAndrew Rybchenko 
54ce35b05cSAndrew Rybchenko 	dev_info->max_rx_queues = sa->rxq_max;
55*a8ad8cf8SIvan Malov 	dev_info->max_tx_queues = sa->txq_max;
56ce35b05cSAndrew Rybchenko 
57a8e64c6bSAndrew Rybchenko 	/* By default packets are dropped if no descriptors are available */
58a8e64c6bSAndrew Rybchenko 	dev_info->default_rxconf.rx_drop_en = 1;
59a8e64c6bSAndrew Rybchenko 
60*a8ad8cf8SIvan Malov 	dev_info->tx_offload_capa =
61*a8ad8cf8SIvan Malov 		DEV_TX_OFFLOAD_IPV4_CKSUM |
62*a8ad8cf8SIvan Malov 		DEV_TX_OFFLOAD_UDP_CKSUM |
63*a8ad8cf8SIvan Malov 		DEV_TX_OFFLOAD_TCP_CKSUM;
64*a8ad8cf8SIvan Malov 
65*a8ad8cf8SIvan Malov 	dev_info->default_txconf.txq_flags = ETH_TXQ_FLAGS_NOVLANOFFL |
66*a8ad8cf8SIvan Malov 					     ETH_TXQ_FLAGS_NOXSUMSCTP;
67*a8ad8cf8SIvan Malov 
68a8e64c6bSAndrew Rybchenko 	dev_info->rx_desc_lim.nb_max = EFX_RXQ_MAXNDESCS;
69a8e64c6bSAndrew Rybchenko 	dev_info->rx_desc_lim.nb_min = EFX_RXQ_MINNDESCS;
70a8e64c6bSAndrew Rybchenko 	/* The RXQ hardware requires that the descriptor count is a power
71a8e64c6bSAndrew Rybchenko 	 * of 2, but rx_desc_lim cannot properly describe that constraint.
72a8e64c6bSAndrew Rybchenko 	 */
73a8e64c6bSAndrew Rybchenko 	dev_info->rx_desc_lim.nb_align = EFX_RXQ_MINNDESCS;
74*a8ad8cf8SIvan Malov 
75*a8ad8cf8SIvan Malov 	dev_info->tx_desc_lim.nb_max = sa->txq_max_entries;
76*a8ad8cf8SIvan Malov 	dev_info->tx_desc_lim.nb_min = EFX_TXQ_MINNDESCS;
77*a8ad8cf8SIvan Malov 	/*
78*a8ad8cf8SIvan Malov 	 * The TXQ hardware requires that the descriptor count is a power
79*a8ad8cf8SIvan Malov 	 * of 2, but tx_desc_lim cannot properly describe that constraint
80*a8ad8cf8SIvan Malov 	 */
81*a8ad8cf8SIvan Malov 	dev_info->tx_desc_lim.nb_align = EFX_TXQ_MINNDESCS;
8263d588ffSAndrew Rybchenko }
8363d588ffSAndrew Rybchenko 
84aaa3f5f0SAndrew Rybchenko static int
85aaa3f5f0SAndrew Rybchenko sfc_dev_configure(struct rte_eth_dev *dev)
86aaa3f5f0SAndrew Rybchenko {
87aaa3f5f0SAndrew Rybchenko 	struct rte_eth_dev_data *dev_data = dev->data;
88aaa3f5f0SAndrew Rybchenko 	struct sfc_adapter *sa = dev_data->dev_private;
89aaa3f5f0SAndrew Rybchenko 	int rc;
90aaa3f5f0SAndrew Rybchenko 
91aaa3f5f0SAndrew Rybchenko 	sfc_log_init(sa, "entry n_rxq=%u n_txq=%u",
92aaa3f5f0SAndrew Rybchenko 		     dev_data->nb_rx_queues, dev_data->nb_tx_queues);
93aaa3f5f0SAndrew Rybchenko 
94aaa3f5f0SAndrew Rybchenko 	sfc_adapter_lock(sa);
95aaa3f5f0SAndrew Rybchenko 	switch (sa->state) {
96aaa3f5f0SAndrew Rybchenko 	case SFC_ADAPTER_CONFIGURED:
97aaa3f5f0SAndrew Rybchenko 		sfc_close(sa);
98aaa3f5f0SAndrew Rybchenko 		SFC_ASSERT(sa->state == SFC_ADAPTER_INITIALIZED);
99aaa3f5f0SAndrew Rybchenko 		/* FALLTHROUGH */
100aaa3f5f0SAndrew Rybchenko 	case SFC_ADAPTER_INITIALIZED:
101aaa3f5f0SAndrew Rybchenko 		rc = sfc_configure(sa);
102aaa3f5f0SAndrew Rybchenko 		break;
103aaa3f5f0SAndrew Rybchenko 	default:
104aaa3f5f0SAndrew Rybchenko 		sfc_err(sa, "unexpected adapter state %u to configure",
105aaa3f5f0SAndrew Rybchenko 			sa->state);
106aaa3f5f0SAndrew Rybchenko 		rc = EINVAL;
107aaa3f5f0SAndrew Rybchenko 		break;
108aaa3f5f0SAndrew Rybchenko 	}
109aaa3f5f0SAndrew Rybchenko 	sfc_adapter_unlock(sa);
110aaa3f5f0SAndrew Rybchenko 
111aaa3f5f0SAndrew Rybchenko 	sfc_log_init(sa, "done %d", rc);
112aaa3f5f0SAndrew Rybchenko 	SFC_ASSERT(rc >= 0);
113aaa3f5f0SAndrew Rybchenko 	return -rc;
114aaa3f5f0SAndrew Rybchenko }
115aaa3f5f0SAndrew Rybchenko 
11693fcf09bSAndrew Rybchenko static int
11793fcf09bSAndrew Rybchenko sfc_dev_start(struct rte_eth_dev *dev)
11893fcf09bSAndrew Rybchenko {
11993fcf09bSAndrew Rybchenko 	struct sfc_adapter *sa = dev->data->dev_private;
12093fcf09bSAndrew Rybchenko 	int rc;
12193fcf09bSAndrew Rybchenko 
12293fcf09bSAndrew Rybchenko 	sfc_log_init(sa, "entry");
12393fcf09bSAndrew Rybchenko 
12493fcf09bSAndrew Rybchenko 	sfc_adapter_lock(sa);
12593fcf09bSAndrew Rybchenko 	rc = sfc_start(sa);
12693fcf09bSAndrew Rybchenko 	sfc_adapter_unlock(sa);
12793fcf09bSAndrew Rybchenko 
12893fcf09bSAndrew Rybchenko 	sfc_log_init(sa, "done %d", rc);
12993fcf09bSAndrew Rybchenko 	SFC_ASSERT(rc >= 0);
13093fcf09bSAndrew Rybchenko 	return -rc;
13193fcf09bSAndrew Rybchenko }
13293fcf09bSAndrew Rybchenko 
133886f8d8aSArtem Andreev static int
134886f8d8aSArtem Andreev sfc_dev_link_update(struct rte_eth_dev *dev, int wait_to_complete)
135886f8d8aSArtem Andreev {
136886f8d8aSArtem Andreev 	struct sfc_adapter *sa = dev->data->dev_private;
137886f8d8aSArtem Andreev 	struct rte_eth_link *dev_link = &dev->data->dev_link;
138886f8d8aSArtem Andreev 	struct rte_eth_link old_link;
139886f8d8aSArtem Andreev 	struct rte_eth_link current_link;
140886f8d8aSArtem Andreev 
141886f8d8aSArtem Andreev 	sfc_log_init(sa, "entry");
142886f8d8aSArtem Andreev 
143886f8d8aSArtem Andreev 	if (sa->state != SFC_ADAPTER_STARTED)
144886f8d8aSArtem Andreev 		return 0;
145886f8d8aSArtem Andreev 
146886f8d8aSArtem Andreev retry:
147886f8d8aSArtem Andreev 	EFX_STATIC_ASSERT(sizeof(*dev_link) == sizeof(rte_atomic64_t));
148886f8d8aSArtem Andreev 	*(int64_t *)&old_link = rte_atomic64_read((rte_atomic64_t *)dev_link);
149886f8d8aSArtem Andreev 
150886f8d8aSArtem Andreev 	if (wait_to_complete) {
151886f8d8aSArtem Andreev 		efx_link_mode_t link_mode;
152886f8d8aSArtem Andreev 
153886f8d8aSArtem Andreev 		efx_port_poll(sa->nic, &link_mode);
154886f8d8aSArtem Andreev 		sfc_port_link_mode_to_info(link_mode, &current_link);
155886f8d8aSArtem Andreev 
156886f8d8aSArtem Andreev 		if (!rte_atomic64_cmpset((volatile uint64_t *)dev_link,
157886f8d8aSArtem Andreev 					 *(uint64_t *)&old_link,
158886f8d8aSArtem Andreev 					 *(uint64_t *)&current_link))
159886f8d8aSArtem Andreev 			goto retry;
160886f8d8aSArtem Andreev 	} else {
161886f8d8aSArtem Andreev 		sfc_ev_mgmt_qpoll(sa);
162886f8d8aSArtem Andreev 		*(int64_t *)&current_link =
163886f8d8aSArtem Andreev 			rte_atomic64_read((rte_atomic64_t *)dev_link);
164886f8d8aSArtem Andreev 	}
165886f8d8aSArtem Andreev 
166886f8d8aSArtem Andreev 	if (old_link.link_status != current_link.link_status)
167886f8d8aSArtem Andreev 		sfc_info(sa, "Link status is %s",
168886f8d8aSArtem Andreev 			 current_link.link_status ? "UP" : "DOWN");
169886f8d8aSArtem Andreev 
170886f8d8aSArtem Andreev 	return old_link.link_status == current_link.link_status ? 0 : -1;
171886f8d8aSArtem Andreev }
172886f8d8aSArtem Andreev 
17393fcf09bSAndrew Rybchenko static void
17493fcf09bSAndrew Rybchenko sfc_dev_stop(struct rte_eth_dev *dev)
17593fcf09bSAndrew Rybchenko {
17693fcf09bSAndrew Rybchenko 	struct sfc_adapter *sa = dev->data->dev_private;
17793fcf09bSAndrew Rybchenko 
17893fcf09bSAndrew Rybchenko 	sfc_log_init(sa, "entry");
17993fcf09bSAndrew Rybchenko 
18093fcf09bSAndrew Rybchenko 	sfc_adapter_lock(sa);
18193fcf09bSAndrew Rybchenko 	sfc_stop(sa);
18293fcf09bSAndrew Rybchenko 	sfc_adapter_unlock(sa);
18393fcf09bSAndrew Rybchenko 
18493fcf09bSAndrew Rybchenko 	sfc_log_init(sa, "done");
18593fcf09bSAndrew Rybchenko }
18693fcf09bSAndrew Rybchenko 
187aaa3f5f0SAndrew Rybchenko static void
188aaa3f5f0SAndrew Rybchenko sfc_dev_close(struct rte_eth_dev *dev)
189aaa3f5f0SAndrew Rybchenko {
190aaa3f5f0SAndrew Rybchenko 	struct sfc_adapter *sa = dev->data->dev_private;
191aaa3f5f0SAndrew Rybchenko 
192aaa3f5f0SAndrew Rybchenko 	sfc_log_init(sa, "entry");
193aaa3f5f0SAndrew Rybchenko 
194aaa3f5f0SAndrew Rybchenko 	sfc_adapter_lock(sa);
195aaa3f5f0SAndrew Rybchenko 	switch (sa->state) {
19693fcf09bSAndrew Rybchenko 	case SFC_ADAPTER_STARTED:
19793fcf09bSAndrew Rybchenko 		sfc_stop(sa);
19893fcf09bSAndrew Rybchenko 		SFC_ASSERT(sa->state == SFC_ADAPTER_CONFIGURED);
19993fcf09bSAndrew Rybchenko 		/* FALLTHROUGH */
200aaa3f5f0SAndrew Rybchenko 	case SFC_ADAPTER_CONFIGURED:
201aaa3f5f0SAndrew Rybchenko 		sfc_close(sa);
202aaa3f5f0SAndrew Rybchenko 		SFC_ASSERT(sa->state == SFC_ADAPTER_INITIALIZED);
203aaa3f5f0SAndrew Rybchenko 		/* FALLTHROUGH */
204aaa3f5f0SAndrew Rybchenko 	case SFC_ADAPTER_INITIALIZED:
205aaa3f5f0SAndrew Rybchenko 		break;
206aaa3f5f0SAndrew Rybchenko 	default:
207aaa3f5f0SAndrew Rybchenko 		sfc_err(sa, "unexpected adapter state %u on close", sa->state);
208aaa3f5f0SAndrew Rybchenko 		break;
209aaa3f5f0SAndrew Rybchenko 	}
210aaa3f5f0SAndrew Rybchenko 	sfc_adapter_unlock(sa);
211aaa3f5f0SAndrew Rybchenko 
212aaa3f5f0SAndrew Rybchenko 	sfc_log_init(sa, "done");
213aaa3f5f0SAndrew Rybchenko }
214aaa3f5f0SAndrew Rybchenko 
215ce35b05cSAndrew Rybchenko static int
216ce35b05cSAndrew Rybchenko sfc_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
217ce35b05cSAndrew Rybchenko 		   uint16_t nb_rx_desc, unsigned int socket_id,
218ce35b05cSAndrew Rybchenko 		   const struct rte_eth_rxconf *rx_conf,
219ce35b05cSAndrew Rybchenko 		   struct rte_mempool *mb_pool)
220ce35b05cSAndrew Rybchenko {
221ce35b05cSAndrew Rybchenko 	struct sfc_adapter *sa = dev->data->dev_private;
222ce35b05cSAndrew Rybchenko 	int rc;
223ce35b05cSAndrew Rybchenko 
224ce35b05cSAndrew Rybchenko 	sfc_log_init(sa, "RxQ=%u nb_rx_desc=%u socket_id=%u",
225ce35b05cSAndrew Rybchenko 		     rx_queue_id, nb_rx_desc, socket_id);
226ce35b05cSAndrew Rybchenko 
227ce35b05cSAndrew Rybchenko 	sfc_adapter_lock(sa);
228ce35b05cSAndrew Rybchenko 
229ce35b05cSAndrew Rybchenko 	rc = sfc_rx_qinit(sa, rx_queue_id, nb_rx_desc, socket_id,
230ce35b05cSAndrew Rybchenko 			  rx_conf, mb_pool);
231ce35b05cSAndrew Rybchenko 	if (rc != 0)
232ce35b05cSAndrew Rybchenko 		goto fail_rx_qinit;
233ce35b05cSAndrew Rybchenko 
234ce35b05cSAndrew Rybchenko 	dev->data->rx_queues[rx_queue_id] = sa->rxq_info[rx_queue_id].rxq;
235ce35b05cSAndrew Rybchenko 
236ce35b05cSAndrew Rybchenko 	sfc_adapter_unlock(sa);
237ce35b05cSAndrew Rybchenko 
238ce35b05cSAndrew Rybchenko 	return 0;
239ce35b05cSAndrew Rybchenko 
240ce35b05cSAndrew Rybchenko fail_rx_qinit:
241ce35b05cSAndrew Rybchenko 	sfc_adapter_unlock(sa);
242ce35b05cSAndrew Rybchenko 	SFC_ASSERT(rc > 0);
243ce35b05cSAndrew Rybchenko 	return -rc;
244ce35b05cSAndrew Rybchenko }
245ce35b05cSAndrew Rybchenko 
246ce35b05cSAndrew Rybchenko static void
247ce35b05cSAndrew Rybchenko sfc_rx_queue_release(void *queue)
248ce35b05cSAndrew Rybchenko {
249ce35b05cSAndrew Rybchenko 	struct sfc_rxq *rxq = queue;
250ce35b05cSAndrew Rybchenko 	struct sfc_adapter *sa;
251ce35b05cSAndrew Rybchenko 	unsigned int sw_index;
252ce35b05cSAndrew Rybchenko 
253ce35b05cSAndrew Rybchenko 	if (rxq == NULL)
254ce35b05cSAndrew Rybchenko 		return;
255ce35b05cSAndrew Rybchenko 
256ce35b05cSAndrew Rybchenko 	sa = rxq->evq->sa;
257ce35b05cSAndrew Rybchenko 	sfc_adapter_lock(sa);
258ce35b05cSAndrew Rybchenko 
259ce35b05cSAndrew Rybchenko 	sw_index = sfc_rxq_sw_index(rxq);
260ce35b05cSAndrew Rybchenko 
261ce35b05cSAndrew Rybchenko 	sfc_log_init(sa, "RxQ=%u", sw_index);
262ce35b05cSAndrew Rybchenko 
263ce35b05cSAndrew Rybchenko 	sa->eth_dev->data->rx_queues[sw_index] = NULL;
264ce35b05cSAndrew Rybchenko 
265ce35b05cSAndrew Rybchenko 	sfc_rx_qfini(sa, sw_index);
266ce35b05cSAndrew Rybchenko 
267ce35b05cSAndrew Rybchenko 	sfc_adapter_unlock(sa);
268ce35b05cSAndrew Rybchenko }
269ce35b05cSAndrew Rybchenko 
27063d588ffSAndrew Rybchenko static const struct eth_dev_ops sfc_eth_dev_ops = {
271aaa3f5f0SAndrew Rybchenko 	.dev_configure			= sfc_dev_configure,
27293fcf09bSAndrew Rybchenko 	.dev_start			= sfc_dev_start,
27393fcf09bSAndrew Rybchenko 	.dev_stop			= sfc_dev_stop,
274aaa3f5f0SAndrew Rybchenko 	.dev_close			= sfc_dev_close,
275886f8d8aSArtem Andreev 	.link_update			= sfc_dev_link_update,
27663d588ffSAndrew Rybchenko 	.dev_infos_get			= sfc_dev_infos_get,
277ce35b05cSAndrew Rybchenko 	.rx_queue_setup			= sfc_rx_queue_setup,
278ce35b05cSAndrew Rybchenko 	.rx_queue_release		= sfc_rx_queue_release,
27963d588ffSAndrew Rybchenko };
28063d588ffSAndrew Rybchenko 
28163d588ffSAndrew Rybchenko static int
28263d588ffSAndrew Rybchenko sfc_eth_dev_init(struct rte_eth_dev *dev)
28363d588ffSAndrew Rybchenko {
28463d588ffSAndrew Rybchenko 	struct sfc_adapter *sa = dev->data->dev_private;
28563d588ffSAndrew Rybchenko 	struct rte_pci_device *pci_dev = SFC_DEV_TO_PCI(dev);
28663d588ffSAndrew Rybchenko 	int rc;
287ba641f20SAndrew Rybchenko 	const efx_nic_cfg_t *encp;
288ba641f20SAndrew Rybchenko 	const struct ether_addr *from;
28963d588ffSAndrew Rybchenko 
29063d588ffSAndrew Rybchenko 	/* Required for logging */
29163d588ffSAndrew Rybchenko 	sa->eth_dev = dev;
29263d588ffSAndrew Rybchenko 
29363d588ffSAndrew Rybchenko 	/* Copy PCI device info to the dev->data */
29463d588ffSAndrew Rybchenko 	rte_eth_copy_pci_info(dev, pci_dev);
29563d588ffSAndrew Rybchenko 
29663d588ffSAndrew Rybchenko 	rc = sfc_kvargs_parse(sa);
29763d588ffSAndrew Rybchenko 	if (rc != 0)
29863d588ffSAndrew Rybchenko 		goto fail_kvargs_parse;
29963d588ffSAndrew Rybchenko 
30063d588ffSAndrew Rybchenko 	rc = sfc_kvargs_process(sa, SFC_KVARG_DEBUG_INIT,
30163d588ffSAndrew Rybchenko 				sfc_kvarg_bool_handler, &sa->debug_init);
30263d588ffSAndrew Rybchenko 	if (rc != 0)
30363d588ffSAndrew Rybchenko 		goto fail_kvarg_debug_init;
30463d588ffSAndrew Rybchenko 
30563d588ffSAndrew Rybchenko 	sfc_log_init(sa, "entry");
30663d588ffSAndrew Rybchenko 
307ba641f20SAndrew Rybchenko 	dev->data->mac_addrs = rte_zmalloc("sfc", ETHER_ADDR_LEN, 0);
308ba641f20SAndrew Rybchenko 	if (dev->data->mac_addrs == NULL) {
309ba641f20SAndrew Rybchenko 		rc = ENOMEM;
310ba641f20SAndrew Rybchenko 		goto fail_mac_addrs;
311ba641f20SAndrew Rybchenko 	}
312ba641f20SAndrew Rybchenko 
313ba641f20SAndrew Rybchenko 	sfc_adapter_lock_init(sa);
314ba641f20SAndrew Rybchenko 	sfc_adapter_lock(sa);
315ba641f20SAndrew Rybchenko 
316ba641f20SAndrew Rybchenko 	sfc_log_init(sa, "attaching");
317ba641f20SAndrew Rybchenko 	rc = sfc_attach(sa);
318ba641f20SAndrew Rybchenko 	if (rc != 0)
319ba641f20SAndrew Rybchenko 		goto fail_attach;
320ba641f20SAndrew Rybchenko 
321ba641f20SAndrew Rybchenko 	encp = efx_nic_cfg_get(sa->nic);
322ba641f20SAndrew Rybchenko 
323ba641f20SAndrew Rybchenko 	/*
324ba641f20SAndrew Rybchenko 	 * The arguments are really reverse order in comparison to
325ba641f20SAndrew Rybchenko 	 * Linux kernel. Copy from NIC config to Ethernet device data.
326ba641f20SAndrew Rybchenko 	 */
327ba641f20SAndrew Rybchenko 	from = (const struct ether_addr *)(encp->enc_mac_addr);
328ba641f20SAndrew Rybchenko 	ether_addr_copy(from, &dev->data->mac_addrs[0]);
329ba641f20SAndrew Rybchenko 
33063d588ffSAndrew Rybchenko 	dev->dev_ops = &sfc_eth_dev_ops;
331921f6cf1SAndrew Rybchenko 	dev->rx_pkt_burst = &sfc_recv_pkts;
33263d588ffSAndrew Rybchenko 
333ba641f20SAndrew Rybchenko 	sfc_adapter_unlock(sa);
334ba641f20SAndrew Rybchenko 
33563d588ffSAndrew Rybchenko 	sfc_log_init(sa, "done");
33663d588ffSAndrew Rybchenko 	return 0;
33763d588ffSAndrew Rybchenko 
338ba641f20SAndrew Rybchenko fail_attach:
339ba641f20SAndrew Rybchenko 	sfc_adapter_unlock(sa);
340ba641f20SAndrew Rybchenko 	sfc_adapter_lock_fini(sa);
341ba641f20SAndrew Rybchenko 	rte_free(dev->data->mac_addrs);
342ba641f20SAndrew Rybchenko 	dev->data->mac_addrs = NULL;
343ba641f20SAndrew Rybchenko 
344ba641f20SAndrew Rybchenko fail_mac_addrs:
34563d588ffSAndrew Rybchenko fail_kvarg_debug_init:
34663d588ffSAndrew Rybchenko 	sfc_kvargs_cleanup(sa);
34763d588ffSAndrew Rybchenko 
34863d588ffSAndrew Rybchenko fail_kvargs_parse:
34963d588ffSAndrew Rybchenko 	sfc_log_init(sa, "failed %d", rc);
35063d588ffSAndrew Rybchenko 	SFC_ASSERT(rc > 0);
35163d588ffSAndrew Rybchenko 	return -rc;
35263d588ffSAndrew Rybchenko }
35363d588ffSAndrew Rybchenko 
35463d588ffSAndrew Rybchenko static int
35563d588ffSAndrew Rybchenko sfc_eth_dev_uninit(struct rte_eth_dev *dev)
35663d588ffSAndrew Rybchenko {
35763d588ffSAndrew Rybchenko 	struct sfc_adapter *sa = dev->data->dev_private;
35863d588ffSAndrew Rybchenko 
35963d588ffSAndrew Rybchenko 	sfc_log_init(sa, "entry");
36063d588ffSAndrew Rybchenko 
361ba641f20SAndrew Rybchenko 	sfc_adapter_lock(sa);
362ba641f20SAndrew Rybchenko 
363ba641f20SAndrew Rybchenko 	sfc_detach(sa);
364ba641f20SAndrew Rybchenko 
365ba641f20SAndrew Rybchenko 	rte_free(dev->data->mac_addrs);
366ba641f20SAndrew Rybchenko 	dev->data->mac_addrs = NULL;
367ba641f20SAndrew Rybchenko 
36863d588ffSAndrew Rybchenko 	dev->dev_ops = NULL;
369921f6cf1SAndrew Rybchenko 	dev->rx_pkt_burst = NULL;
37063d588ffSAndrew Rybchenko 
37163d588ffSAndrew Rybchenko 	sfc_kvargs_cleanup(sa);
37263d588ffSAndrew Rybchenko 
373ba641f20SAndrew Rybchenko 	sfc_adapter_unlock(sa);
374ba641f20SAndrew Rybchenko 	sfc_adapter_lock_fini(sa);
375ba641f20SAndrew Rybchenko 
37663d588ffSAndrew Rybchenko 	sfc_log_init(sa, "done");
37763d588ffSAndrew Rybchenko 
37863d588ffSAndrew Rybchenko 	/* Required for logging, so cleanup last */
37963d588ffSAndrew Rybchenko 	sa->eth_dev = NULL;
38063d588ffSAndrew Rybchenko 	return 0;
38163d588ffSAndrew Rybchenko }
38263d588ffSAndrew Rybchenko 
38363d588ffSAndrew Rybchenko static const struct rte_pci_id pci_id_sfc_efx_map[] = {
384ba641f20SAndrew Rybchenko 	{ RTE_PCI_DEVICE(EFX_PCI_VENID_SFC, EFX_PCI_DEVID_FARMINGDALE) },
385ba641f20SAndrew Rybchenko 	{ RTE_PCI_DEVICE(EFX_PCI_VENID_SFC, EFX_PCI_DEVID_GREENPORT) },
386ba641f20SAndrew Rybchenko 	{ RTE_PCI_DEVICE(EFX_PCI_VENID_SFC, EFX_PCI_DEVID_MEDFORD) },
38763d588ffSAndrew Rybchenko 	{ .vendor_id = 0 /* sentinel */ }
38863d588ffSAndrew Rybchenko };
38963d588ffSAndrew Rybchenko 
39063d588ffSAndrew Rybchenko static struct eth_driver sfc_efx_pmd = {
39163d588ffSAndrew Rybchenko 	.pci_drv = {
39263d588ffSAndrew Rybchenko 		.id_table = pci_id_sfc_efx_map,
393ba641f20SAndrew Rybchenko 		.drv_flags =
394ba641f20SAndrew Rybchenko 			RTE_PCI_DRV_NEED_MAPPING,
39563d588ffSAndrew Rybchenko 		.probe = rte_eth_dev_pci_probe,
39663d588ffSAndrew Rybchenko 		.remove = rte_eth_dev_pci_remove,
39763d588ffSAndrew Rybchenko 	},
39863d588ffSAndrew Rybchenko 	.eth_dev_init = sfc_eth_dev_init,
39963d588ffSAndrew Rybchenko 	.eth_dev_uninit = sfc_eth_dev_uninit,
40063d588ffSAndrew Rybchenko 	.dev_private_size = sizeof(struct sfc_adapter),
40163d588ffSAndrew Rybchenko };
40263d588ffSAndrew Rybchenko 
40363d588ffSAndrew Rybchenko RTE_PMD_REGISTER_PCI(net_sfc_efx, sfc_efx_pmd.pci_drv);
40463d588ffSAndrew Rybchenko RTE_PMD_REGISTER_PCI_TABLE(net_sfc_efx, pci_id_sfc_efx_map);
40563d588ffSAndrew Rybchenko RTE_PMD_REGISTER_PARAM_STRING(net_sfc_efx,
40663d588ffSAndrew Rybchenko 	SFC_KVARG_DEBUG_INIT "=" SFC_KVARG_VALUES_BOOL);
407