xref: /linux/drivers/net/ethernet/alibaba/eea/eea_net.c (revision 4e88fb3234c864b67338ca8d48ca515cf9992ab6)
14c45a51eSXuan Zhuo // SPDX-License-Identifier: GPL-2.0-or-later
24c45a51eSXuan Zhuo /*
34c45a51eSXuan Zhuo  * Driver for Alibaba Elastic Ethernet Adapter.
44c45a51eSXuan Zhuo  *
54c45a51eSXuan Zhuo  * Copyright (C) 2025 Alibaba Inc.
64c45a51eSXuan Zhuo  */
74c45a51eSXuan Zhuo 
84c45a51eSXuan Zhuo #include <linux/etherdevice.h>
94c45a51eSXuan Zhuo #include <linux/module.h>
104c45a51eSXuan Zhuo #include <linux/netdevice.h>
114c45a51eSXuan Zhuo #include <linux/rtnetlink.h>
124c45a51eSXuan Zhuo #include <net/netdev_queues.h>
134c45a51eSXuan Zhuo 
144c45a51eSXuan Zhuo #include "eea_adminq.h"
154c45a51eSXuan Zhuo #include "eea_net.h"
164c45a51eSXuan Zhuo #include "eea_pci.h"
174c45a51eSXuan Zhuo #include "eea_ring.h"
184c45a51eSXuan Zhuo 
194c45a51eSXuan Zhuo #define EEA_SPLIT_HDR_SIZE ALIGN(128, L1_CACHE_BYTES)
204c45a51eSXuan Zhuo 
21aa8bca4cSXuan Zhuo static irqreturn_t eea_irq_handler(int irq, void *data)
22aa8bca4cSXuan Zhuo {
23aa8bca4cSXuan Zhuo 	struct eea_irq_blk *blk = data;
24aa8bca4cSXuan Zhuo 
25aa8bca4cSXuan Zhuo 	napi_schedule_irqoff(&blk->napi);
26aa8bca4cSXuan Zhuo 
27aa8bca4cSXuan Zhuo 	return IRQ_HANDLED;
28aa8bca4cSXuan Zhuo }
29aa8bca4cSXuan Zhuo 
30aa8bca4cSXuan Zhuo static void eea_free_irq_blk(struct eea_net *enet)
31aa8bca4cSXuan Zhuo {
32aa8bca4cSXuan Zhuo 	struct eea_irq_blk *blk;
33aa8bca4cSXuan Zhuo 	u32 num;
34aa8bca4cSXuan Zhuo 	int i;
35aa8bca4cSXuan Zhuo 
36aa8bca4cSXuan Zhuo 	if (!enet->irq_blks)
37aa8bca4cSXuan Zhuo 		return;
38aa8bca4cSXuan Zhuo 
39aa8bca4cSXuan Zhuo 	num = enet->edev->rx_num;
40aa8bca4cSXuan Zhuo 
41aa8bca4cSXuan Zhuo 	for (i = 0; i < num; i++) {
42aa8bca4cSXuan Zhuo 		blk = &enet->irq_blks[i];
43aa8bca4cSXuan Zhuo 
44aa8bca4cSXuan Zhuo 		if (blk->ready)
45aa8bca4cSXuan Zhuo 			eea_pci_free_irq(blk);
46aa8bca4cSXuan Zhuo 
47aa8bca4cSXuan Zhuo 		blk->ready = false;
48aa8bca4cSXuan Zhuo 	}
49aa8bca4cSXuan Zhuo 
50aa8bca4cSXuan Zhuo 	kvfree(enet->irq_blks);
51aa8bca4cSXuan Zhuo 	enet->irq_blks = NULL;
52aa8bca4cSXuan Zhuo }
53aa8bca4cSXuan Zhuo 
54aa8bca4cSXuan Zhuo /* The driver will always attempt to allocate IRQ blocks based on the maximum
55aa8bca4cSXuan Zhuo  * possible queue num.
56aa8bca4cSXuan Zhuo  */
57aa8bca4cSXuan Zhuo static int eea_alloc_irq_blks(struct eea_net *enet)
58aa8bca4cSXuan Zhuo {
59aa8bca4cSXuan Zhuo 	struct eea_device *edev = enet->edev;
60aa8bca4cSXuan Zhuo 	struct eea_irq_blk *blk, *irq_blks;
61aa8bca4cSXuan Zhuo 	int i, err, num;
62aa8bca4cSXuan Zhuo 
63aa8bca4cSXuan Zhuo 	num = enet->edev->rx_num;
64aa8bca4cSXuan Zhuo 
65aa8bca4cSXuan Zhuo 	irq_blks = kvcalloc(num, sizeof(*blk), GFP_KERNEL);
66aa8bca4cSXuan Zhuo 	if (!irq_blks)
67aa8bca4cSXuan Zhuo 		return -ENOMEM;
68aa8bca4cSXuan Zhuo 
69aa8bca4cSXuan Zhuo 	enet->irq_blks = irq_blks;
70aa8bca4cSXuan Zhuo 
71aa8bca4cSXuan Zhuo 	for (i = 0; i < num; i++) {
72aa8bca4cSXuan Zhuo 		blk = &irq_blks[i];
73aa8bca4cSXuan Zhuo 		blk->idx = i;
74aa8bca4cSXuan Zhuo 
75aa8bca4cSXuan Zhuo 		/* vec 0 is for error notify. */
76aa8bca4cSXuan Zhuo 		blk->msix_vec = i + 1;
77aa8bca4cSXuan Zhuo 
78aa8bca4cSXuan Zhuo 		err = eea_pci_request_irq(edev, blk, eea_irq_handler);
79aa8bca4cSXuan Zhuo 		if (err)
80aa8bca4cSXuan Zhuo 			goto err_free_irq_blk;
81aa8bca4cSXuan Zhuo 
82aa8bca4cSXuan Zhuo 		blk->ready = true;
83aa8bca4cSXuan Zhuo 	}
84aa8bca4cSXuan Zhuo 
85aa8bca4cSXuan Zhuo 	return 0;
86aa8bca4cSXuan Zhuo 
87aa8bca4cSXuan Zhuo err_free_irq_blk:
88aa8bca4cSXuan Zhuo 	eea_free_irq_blk(enet);
89aa8bca4cSXuan Zhuo 	return err;
90aa8bca4cSXuan Zhuo }
91aa8bca4cSXuan Zhuo 
92aa8bca4cSXuan Zhuo static int eea_update_queues(struct eea_net *enet)
93aa8bca4cSXuan Zhuo {
94aa8bca4cSXuan Zhuo 	return netif_set_real_num_queues(enet->netdev, enet->cfg.tx_ring_num,
95aa8bca4cSXuan Zhuo 					 enet->cfg.rx_ring_num);
96aa8bca4cSXuan Zhuo }
97aa8bca4cSXuan Zhuo 
98aa8bca4cSXuan Zhuo void eea_init_ctx(struct eea_net *enet, struct eea_net_init_ctx *ctx)
99aa8bca4cSXuan Zhuo {
100aa8bca4cSXuan Zhuo 	memset(ctx, 0, sizeof(*ctx));
101aa8bca4cSXuan Zhuo 
102aa8bca4cSXuan Zhuo 	ctx->netdev = enet->netdev;
103aa8bca4cSXuan Zhuo 	ctx->edev = enet->edev;
104aa8bca4cSXuan Zhuo 	ctx->cfg = enet->cfg;
105aa8bca4cSXuan Zhuo }
106aa8bca4cSXuan Zhuo 
107aa8bca4cSXuan Zhuo static void eea_bind_q_and_cfg(struct eea_net *enet,
108aa8bca4cSXuan Zhuo 			       struct eea_net_init_ctx *ctx)
109aa8bca4cSXuan Zhuo {
110aa8bca4cSXuan Zhuo 	struct eea_irq_blk *blk;
111aa8bca4cSXuan Zhuo 	struct eea_net_rx *rx;
112aa8bca4cSXuan Zhuo 	struct eea_net_tx *tx;
113aa8bca4cSXuan Zhuo 	int i;
114aa8bca4cSXuan Zhuo 
115*4e88fb32SXuan Zhuo 	/* Since 'ndo_get_stats64' is not called in softirq context, there is no
116*4e88fb32SXuan Zhuo 	 * need to use 'spin_lock_bh'.
117*4e88fb32SXuan Zhuo 	 */
118*4e88fb32SXuan Zhuo 	spin_lock(&enet->stats_lock);
119*4e88fb32SXuan Zhuo 
120aa8bca4cSXuan Zhuo 	enet->cfg = ctx->cfg;
121aa8bca4cSXuan Zhuo 	enet->rx = ctx->rx;
122aa8bca4cSXuan Zhuo 	enet->tx = ctx->tx;
123aa8bca4cSXuan Zhuo 
124aa8bca4cSXuan Zhuo 	for (i = 0; i < ctx->cfg.rx_ring_num; i++) {
125aa8bca4cSXuan Zhuo 		blk = &enet->irq_blks[i];
126aa8bca4cSXuan Zhuo 
127aa8bca4cSXuan Zhuo 		rx = ctx->rx[i];
128aa8bca4cSXuan Zhuo 		tx = &ctx->tx[i];
129aa8bca4cSXuan Zhuo 
130aa8bca4cSXuan Zhuo 		rx->enet = enet;
131aa8bca4cSXuan Zhuo 		rx->napi = &blk->napi;
132aa8bca4cSXuan Zhuo 		rx->ering->msix_vec = blk->msix_vec;
133aa8bca4cSXuan Zhuo 
134aa8bca4cSXuan Zhuo 		tx->enet = enet;
135aa8bca4cSXuan Zhuo 		tx->ering->msix_vec = blk->msix_vec;
136aa8bca4cSXuan Zhuo 
137aa8bca4cSXuan Zhuo 		blk->rx = rx;
138aa8bca4cSXuan Zhuo 	}
139*4e88fb32SXuan Zhuo 
140*4e88fb32SXuan Zhuo 	spin_unlock(&enet->stats_lock);
141aa8bca4cSXuan Zhuo }
142aa8bca4cSXuan Zhuo 
143aa8bca4cSXuan Zhuo static void eea_unbind_q_and_cfg(struct eea_net *enet,
144aa8bca4cSXuan Zhuo 				 struct eea_net_init_ctx *ctx)
145aa8bca4cSXuan Zhuo {
146aa8bca4cSXuan Zhuo 	struct eea_irq_blk *blk;
147aa8bca4cSXuan Zhuo 	struct eea_net_rx *rx;
148aa8bca4cSXuan Zhuo 	int i;
149aa8bca4cSXuan Zhuo 
150*4e88fb32SXuan Zhuo 	spin_lock(&enet->stats_lock);
151*4e88fb32SXuan Zhuo 
152aa8bca4cSXuan Zhuo 	ctx->cfg = enet->cfg;
153aa8bca4cSXuan Zhuo 	ctx->rx = enet->rx;
154aa8bca4cSXuan Zhuo 	ctx->tx = enet->tx;
155aa8bca4cSXuan Zhuo 
156aa8bca4cSXuan Zhuo 	enet->rx = NULL;
157aa8bca4cSXuan Zhuo 	enet->tx = NULL;
158aa8bca4cSXuan Zhuo 
159aa8bca4cSXuan Zhuo 	for (i = 0; i < ctx->cfg.rx_ring_num; i++) {
160aa8bca4cSXuan Zhuo 		blk = &enet->irq_blks[i];
161aa8bca4cSXuan Zhuo 
162aa8bca4cSXuan Zhuo 		rx = ctx->rx[i];
163aa8bca4cSXuan Zhuo 
164aa8bca4cSXuan Zhuo 		rx->napi = NULL;
165aa8bca4cSXuan Zhuo 
166aa8bca4cSXuan Zhuo 		blk->rx = NULL;
167aa8bca4cSXuan Zhuo 	}
168*4e88fb32SXuan Zhuo 
169*4e88fb32SXuan Zhuo 	spin_unlock(&enet->stats_lock);
170aa8bca4cSXuan Zhuo }
171aa8bca4cSXuan Zhuo 
172aa8bca4cSXuan Zhuo static void eea_free_rxtx_q_mem(struct eea_net_init_ctx *ctx)
173aa8bca4cSXuan Zhuo {
174aa8bca4cSXuan Zhuo 	struct eea_net_rx *rx;
175aa8bca4cSXuan Zhuo 	struct eea_net_tx *tx;
176aa8bca4cSXuan Zhuo 	int i;
177aa8bca4cSXuan Zhuo 
178aa8bca4cSXuan Zhuo 	for (i = 0; i < ctx->cfg.rx_ring_num; i++) {
179aa8bca4cSXuan Zhuo 		rx = ctx->rx[i];
180aa8bca4cSXuan Zhuo 		tx = &ctx->tx[i];
181aa8bca4cSXuan Zhuo 
182aa8bca4cSXuan Zhuo 		eea_free_rx(rx, &ctx->cfg);
183aa8bca4cSXuan Zhuo 		eea_free_tx(tx, &ctx->cfg);
184aa8bca4cSXuan Zhuo 	}
185aa8bca4cSXuan Zhuo 
186aa8bca4cSXuan Zhuo 	kvfree(ctx->rx);
187aa8bca4cSXuan Zhuo 	kvfree(ctx->tx);
188aa8bca4cSXuan Zhuo }
189aa8bca4cSXuan Zhuo 
190aa8bca4cSXuan Zhuo /* alloc tx/rx: struct, ring, meta, pp, napi */
191aa8bca4cSXuan Zhuo static int eea_alloc_rxtx_q_mem(struct eea_net_init_ctx *ctx)
192aa8bca4cSXuan Zhuo {
193aa8bca4cSXuan Zhuo 	struct eea_net_rx *rx;
194aa8bca4cSXuan Zhuo 	struct eea_net_tx *tx;
195aa8bca4cSXuan Zhuo 	int err, i;
196aa8bca4cSXuan Zhuo 
197aa8bca4cSXuan Zhuo 	ctx->tx = kvcalloc(ctx->cfg.tx_ring_num, sizeof(*ctx->tx), GFP_KERNEL);
198aa8bca4cSXuan Zhuo 	if (!ctx->tx)
199aa8bca4cSXuan Zhuo 		return -ENOMEM;
200aa8bca4cSXuan Zhuo 
201aa8bca4cSXuan Zhuo 	ctx->rx = kvcalloc(ctx->cfg.rx_ring_num, sizeof(*ctx->rx), GFP_KERNEL);
202aa8bca4cSXuan Zhuo 	if (!ctx->rx)
203aa8bca4cSXuan Zhuo 		goto err_free_tx;
204aa8bca4cSXuan Zhuo 
205aa8bca4cSXuan Zhuo 	ctx->cfg.rx_sq_desc_size = sizeof(struct eea_rx_desc);
206aa8bca4cSXuan Zhuo 	ctx->cfg.rx_cq_desc_size = sizeof(struct eea_rx_cdesc);
207aa8bca4cSXuan Zhuo 	ctx->cfg.tx_sq_desc_size = sizeof(struct eea_tx_desc);
208aa8bca4cSXuan Zhuo 	ctx->cfg.tx_cq_desc_size = sizeof(struct eea_tx_cdesc);
209aa8bca4cSXuan Zhuo 
210aa8bca4cSXuan Zhuo 	/* ethtool may config this. */
211aa8bca4cSXuan Zhuo 	if (!ctx->cfg.split_hdr)
212aa8bca4cSXuan Zhuo 		ctx->cfg.rx_sq_desc_size = sizeof(struct eea_rx_desc_no_hdr);
213aa8bca4cSXuan Zhuo 
214aa8bca4cSXuan Zhuo 	for (i = 0; i < ctx->cfg.rx_ring_num; i++) {
215aa8bca4cSXuan Zhuo 		rx = eea_alloc_rx(ctx, i);
216aa8bca4cSXuan Zhuo 		if (!rx)
217aa8bca4cSXuan Zhuo 			goto err_free;
218aa8bca4cSXuan Zhuo 
219aa8bca4cSXuan Zhuo 		ctx->rx[i] = rx;
220aa8bca4cSXuan Zhuo 
221aa8bca4cSXuan Zhuo 		tx = ctx->tx + i;
222aa8bca4cSXuan Zhuo 		err = eea_alloc_tx(ctx, tx, i);
223aa8bca4cSXuan Zhuo 		if (err)
224aa8bca4cSXuan Zhuo 			goto err_free;
225aa8bca4cSXuan Zhuo 	}
226aa8bca4cSXuan Zhuo 
227aa8bca4cSXuan Zhuo 	return 0;
228aa8bca4cSXuan Zhuo 
229aa8bca4cSXuan Zhuo err_free:
230aa8bca4cSXuan Zhuo 	for (i = 0; i < ctx->cfg.rx_ring_num; i++) {
231aa8bca4cSXuan Zhuo 		rx = ctx->rx[i];
232aa8bca4cSXuan Zhuo 		tx = ctx->tx + i;
233aa8bca4cSXuan Zhuo 
234aa8bca4cSXuan Zhuo 		eea_free_rx(rx, &ctx->cfg);
235aa8bca4cSXuan Zhuo 		eea_free_tx(tx, &ctx->cfg);
236aa8bca4cSXuan Zhuo 	}
237aa8bca4cSXuan Zhuo 
238aa8bca4cSXuan Zhuo 	kvfree(ctx->rx);
239aa8bca4cSXuan Zhuo 
240aa8bca4cSXuan Zhuo err_free_tx:
241aa8bca4cSXuan Zhuo 	kvfree(ctx->tx);
242aa8bca4cSXuan Zhuo 	return -ENOMEM;
243aa8bca4cSXuan Zhuo }
244aa8bca4cSXuan Zhuo 
245aa8bca4cSXuan Zhuo static int eea_hw_active_ring(struct eea_net *enet)
246aa8bca4cSXuan Zhuo {
247aa8bca4cSXuan Zhuo 	return eea_adminq_create_q(enet, enet->cfg.rx_ring_num
248aa8bca4cSXuan Zhuo 				   + enet->cfg.tx_ring_num, 0);
249aa8bca4cSXuan Zhuo }
250aa8bca4cSXuan Zhuo 
251aa8bca4cSXuan Zhuo static int eea_hw_unactive_ring(struct eea_net *enet)
252aa8bca4cSXuan Zhuo {
253aa8bca4cSXuan Zhuo 	int err;
254aa8bca4cSXuan Zhuo 
255aa8bca4cSXuan Zhuo 	err = eea_adminq_destroy_all_q(enet);
256aa8bca4cSXuan Zhuo 	if (err)
257aa8bca4cSXuan Zhuo 		netdev_warn(enet->netdev, "unactive rxtx ring failed.\n");
258aa8bca4cSXuan Zhuo 
259aa8bca4cSXuan Zhuo 	return err;
260aa8bca4cSXuan Zhuo }
261aa8bca4cSXuan Zhuo 
262aa8bca4cSXuan Zhuo /* stop rx napi, stop tx queue. */
263aa8bca4cSXuan Zhuo static void eea_stop_rxtx(struct net_device *netdev)
264aa8bca4cSXuan Zhuo {
265aa8bca4cSXuan Zhuo 	struct eea_net *enet = netdev_priv(netdev);
266aa8bca4cSXuan Zhuo 	int i;
267aa8bca4cSXuan Zhuo 
268aa8bca4cSXuan Zhuo 	netif_tx_disable(netdev);
269aa8bca4cSXuan Zhuo 
270aa8bca4cSXuan Zhuo 	for (i = 0; i < enet->cfg.rx_ring_num; i++)
271aa8bca4cSXuan Zhuo 		enet_rx_stop(enet->rx[i]);
272aa8bca4cSXuan Zhuo 
273aa8bca4cSXuan Zhuo 	netif_carrier_off(netdev);
274aa8bca4cSXuan Zhuo }
275aa8bca4cSXuan Zhuo 
276aa8bca4cSXuan Zhuo static void eea_start_rxtx(struct eea_net *enet)
277aa8bca4cSXuan Zhuo {
278aa8bca4cSXuan Zhuo 	int i;
279aa8bca4cSXuan Zhuo 
280aa8bca4cSXuan Zhuo 	for (i = 0; i < enet->cfg.rx_ring_num; i++)
281aa8bca4cSXuan Zhuo 		enet_rx_start(enet->rx[i]);
282aa8bca4cSXuan Zhuo 
283aa8bca4cSXuan Zhuo 	netif_tx_start_all_queues(enet->netdev);
284aa8bca4cSXuan Zhuo 	netif_carrier_on(enet->netdev);
285aa8bca4cSXuan Zhuo 
286aa8bca4cSXuan Zhuo 	enet->started = true;
287aa8bca4cSXuan Zhuo }
288aa8bca4cSXuan Zhuo 
289aa8bca4cSXuan Zhuo static int eea_netdev_stop(struct net_device *netdev)
290aa8bca4cSXuan Zhuo {
291aa8bca4cSXuan Zhuo 	struct eea_net *enet = netdev_priv(netdev);
292aa8bca4cSXuan Zhuo 	struct eea_net_init_ctx ctx;
293aa8bca4cSXuan Zhuo 
294aa8bca4cSXuan Zhuo 	/* This function can be called during device anomaly recovery. To
295aa8bca4cSXuan Zhuo 	 * prevent duplicate stop operations, the `started` flag is introduced
296aa8bca4cSXuan Zhuo 	 * for checking.
297aa8bca4cSXuan Zhuo 	 */
298aa8bca4cSXuan Zhuo 
299aa8bca4cSXuan Zhuo 	if (!enet->started) {
300aa8bca4cSXuan Zhuo 		netdev_warn(netdev, "eea netdev stop: but dev is not started.\n");
301aa8bca4cSXuan Zhuo 		return 0;
302aa8bca4cSXuan Zhuo 	}
303aa8bca4cSXuan Zhuo 
304aa8bca4cSXuan Zhuo 	eea_init_ctx(enet, &ctx);
305aa8bca4cSXuan Zhuo 
306aa8bca4cSXuan Zhuo 	eea_stop_rxtx(netdev);
307aa8bca4cSXuan Zhuo 	eea_hw_unactive_ring(enet);
308aa8bca4cSXuan Zhuo 	eea_unbind_q_and_cfg(enet, &ctx);
309aa8bca4cSXuan Zhuo 	eea_free_rxtx_q_mem(&ctx);
310aa8bca4cSXuan Zhuo 
311aa8bca4cSXuan Zhuo 	enet->started = false;
312aa8bca4cSXuan Zhuo 
313aa8bca4cSXuan Zhuo 	return 0;
314aa8bca4cSXuan Zhuo }
315aa8bca4cSXuan Zhuo 
316aa8bca4cSXuan Zhuo static int eea_netdev_open(struct net_device *netdev)
317aa8bca4cSXuan Zhuo {
318aa8bca4cSXuan Zhuo 	struct eea_net *enet = netdev_priv(netdev);
319aa8bca4cSXuan Zhuo 	struct eea_net_init_ctx ctx;
320aa8bca4cSXuan Zhuo 	int err;
321aa8bca4cSXuan Zhuo 
322aa8bca4cSXuan Zhuo 	if (enet->link_err) {
323aa8bca4cSXuan Zhuo 		netdev_err(netdev, "netdev open err, because link error: %d\n",
324aa8bca4cSXuan Zhuo 			   enet->link_err);
325aa8bca4cSXuan Zhuo 		return -EBUSY;
326aa8bca4cSXuan Zhuo 	}
327aa8bca4cSXuan Zhuo 
328aa8bca4cSXuan Zhuo 	eea_init_ctx(enet, &ctx);
329aa8bca4cSXuan Zhuo 
330aa8bca4cSXuan Zhuo 	err = eea_alloc_rxtx_q_mem(&ctx);
331aa8bca4cSXuan Zhuo 	if (err)
332aa8bca4cSXuan Zhuo 		goto err_done;
333aa8bca4cSXuan Zhuo 
334aa8bca4cSXuan Zhuo 	eea_bind_q_and_cfg(enet, &ctx);
335aa8bca4cSXuan Zhuo 
336aa8bca4cSXuan Zhuo 	err = eea_update_queues(enet);
337aa8bca4cSXuan Zhuo 	if (err)
338aa8bca4cSXuan Zhuo 		goto err_free_q;
339aa8bca4cSXuan Zhuo 
340aa8bca4cSXuan Zhuo 	err = eea_hw_active_ring(enet);
341aa8bca4cSXuan Zhuo 	if (err)
342aa8bca4cSXuan Zhuo 		goto err_free_q;
343aa8bca4cSXuan Zhuo 
344aa8bca4cSXuan Zhuo 	eea_start_rxtx(enet);
345aa8bca4cSXuan Zhuo 
346aa8bca4cSXuan Zhuo 	return 0;
347aa8bca4cSXuan Zhuo 
348aa8bca4cSXuan Zhuo err_free_q:
349aa8bca4cSXuan Zhuo 	eea_unbind_q_and_cfg(enet, &ctx);
350aa8bca4cSXuan Zhuo 	eea_free_rxtx_q_mem(&ctx);
351aa8bca4cSXuan Zhuo 
352aa8bca4cSXuan Zhuo err_done:
353aa8bca4cSXuan Zhuo 	return err;
354aa8bca4cSXuan Zhuo }
355aa8bca4cSXuan Zhuo 
356*4e88fb32SXuan Zhuo /* Statistics may be reset to zero upon device reset. This is expected behavior
357*4e88fb32SXuan Zhuo  * for now and will be addressed in the future.
358*4e88fb32SXuan Zhuo  */
359*4e88fb32SXuan Zhuo static void eea_stats(struct net_device *netdev, struct rtnl_link_stats64 *tot)
360*4e88fb32SXuan Zhuo {
361*4e88fb32SXuan Zhuo 	struct eea_net *enet = netdev_priv(netdev);
362*4e88fb32SXuan Zhuo 	u64 packets, bytes, drop, lerr;
363*4e88fb32SXuan Zhuo 	u32 start;
364*4e88fb32SXuan Zhuo 	int i;
365*4e88fb32SXuan Zhuo 
366*4e88fb32SXuan Zhuo 	spin_lock(&enet->stats_lock);
367*4e88fb32SXuan Zhuo 
368*4e88fb32SXuan Zhuo 	if (enet->rx) {
369*4e88fb32SXuan Zhuo 		for (i = 0; i < enet->cfg.rx_ring_num; i++) {
370*4e88fb32SXuan Zhuo 			struct eea_net_rx *rx = enet->rx[i];
371*4e88fb32SXuan Zhuo 
372*4e88fb32SXuan Zhuo 			do {
373*4e88fb32SXuan Zhuo 				start = u64_stats_fetch_begin(&rx->stats.syncp);
374*4e88fb32SXuan Zhuo 				packets = u64_stats_read(&rx->stats.packets);
375*4e88fb32SXuan Zhuo 				bytes = u64_stats_read(&rx->stats.bytes);
376*4e88fb32SXuan Zhuo 				drop = u64_stats_read(&rx->stats.drops);
377*4e88fb32SXuan Zhuo 				lerr = u64_stats_read(&rx->stats.length_errors);
378*4e88fb32SXuan Zhuo 			} while (u64_stats_fetch_retry(&rx->stats.syncp,
379*4e88fb32SXuan Zhuo 						       start));
380*4e88fb32SXuan Zhuo 
381*4e88fb32SXuan Zhuo 			tot->rx_packets       += packets;
382*4e88fb32SXuan Zhuo 			tot->rx_bytes         += bytes;
383*4e88fb32SXuan Zhuo 			tot->rx_dropped       += drop;
384*4e88fb32SXuan Zhuo 			tot->rx_length_errors += lerr;
385*4e88fb32SXuan Zhuo 			tot->rx_errors        += lerr;
386*4e88fb32SXuan Zhuo 		}
387*4e88fb32SXuan Zhuo 	}
388*4e88fb32SXuan Zhuo 
389*4e88fb32SXuan Zhuo 	if (enet->tx) {
390*4e88fb32SXuan Zhuo 		for (i = 0; i < enet->cfg.tx_ring_num; i++) {
391*4e88fb32SXuan Zhuo 			struct eea_net_tx *tx = &enet->tx[i];
392*4e88fb32SXuan Zhuo 
393*4e88fb32SXuan Zhuo 			do {
394*4e88fb32SXuan Zhuo 				start = u64_stats_fetch_begin(&tx->stats.syncp);
395*4e88fb32SXuan Zhuo 				packets = u64_stats_read(&tx->stats.packets);
396*4e88fb32SXuan Zhuo 				bytes = u64_stats_read(&tx->stats.bytes);
397*4e88fb32SXuan Zhuo 				drop = u64_stats_read(&tx->stats.drops);
398*4e88fb32SXuan Zhuo 			} while (u64_stats_fetch_retry(&tx->stats.syncp,
399*4e88fb32SXuan Zhuo 						       start));
400*4e88fb32SXuan Zhuo 
401*4e88fb32SXuan Zhuo 			tot->tx_packets += packets;
402*4e88fb32SXuan Zhuo 			tot->tx_bytes   += bytes;
403*4e88fb32SXuan Zhuo 			tot->tx_dropped += drop;
404*4e88fb32SXuan Zhuo 		}
405*4e88fb32SXuan Zhuo 	}
406*4e88fb32SXuan Zhuo 
407*4e88fb32SXuan Zhuo 	spin_unlock(&enet->stats_lock);
408*4e88fb32SXuan Zhuo }
409*4e88fb32SXuan Zhuo 
410aa8bca4cSXuan Zhuo /* resources: ring, buffers, irq */
411aa8bca4cSXuan Zhuo int eea_reset_hw_resources(struct eea_net *enet, struct eea_net_init_ctx *ctx)
412aa8bca4cSXuan Zhuo {
413aa8bca4cSXuan Zhuo 	struct eea_net_init_ctx ctx_old = {0};
414aa8bca4cSXuan Zhuo 	int err, error;
415aa8bca4cSXuan Zhuo 
416aa8bca4cSXuan Zhuo 	if (!netif_running(enet->netdev) || !enet->started) {
417*4e88fb32SXuan Zhuo 		spin_lock(&enet->stats_lock);
418aa8bca4cSXuan Zhuo 		enet->cfg = ctx->cfg;
419*4e88fb32SXuan Zhuo 		spin_unlock(&enet->stats_lock);
420aa8bca4cSXuan Zhuo 		return 0;
421aa8bca4cSXuan Zhuo 	}
422aa8bca4cSXuan Zhuo 
423aa8bca4cSXuan Zhuo 	err = eea_alloc_rxtx_q_mem(ctx);
424aa8bca4cSXuan Zhuo 	if (err) {
425aa8bca4cSXuan Zhuo 		netdev_warn(enet->netdev,
426aa8bca4cSXuan Zhuo 			    "eea reset: alloc q failed. stop reset. err %d\n",
427aa8bca4cSXuan Zhuo 			    err);
428aa8bca4cSXuan Zhuo 		return err;
429aa8bca4cSXuan Zhuo 	}
430aa8bca4cSXuan Zhuo 
431aa8bca4cSXuan Zhuo 	eea_stop_rxtx(enet->netdev);
432aa8bca4cSXuan Zhuo 	eea_hw_unactive_ring(enet);
433aa8bca4cSXuan Zhuo 
434aa8bca4cSXuan Zhuo 	eea_unbind_q_and_cfg(enet, &ctx_old);
435aa8bca4cSXuan Zhuo 	eea_bind_q_and_cfg(enet, ctx);
436aa8bca4cSXuan Zhuo 
437aa8bca4cSXuan Zhuo 	err = eea_update_queues(enet);
438aa8bca4cSXuan Zhuo 	if (err) {
439aa8bca4cSXuan Zhuo 		netdev_err(enet->netdev,
440aa8bca4cSXuan Zhuo 			   "eea reset: set real num queues failed. err %d\n",
441aa8bca4cSXuan Zhuo 			   err);
442aa8bca4cSXuan Zhuo 		goto err_bind_old;
443aa8bca4cSXuan Zhuo 	}
444aa8bca4cSXuan Zhuo 
445aa8bca4cSXuan Zhuo 	err = eea_hw_active_ring(enet);
446aa8bca4cSXuan Zhuo 	if (err) {
447aa8bca4cSXuan Zhuo 		netdev_err(enet->netdev, "eea reset: active new ring. err %d\n",
448aa8bca4cSXuan Zhuo 			   err);
449aa8bca4cSXuan Zhuo 		eea_unbind_q_and_cfg(enet, ctx);
450aa8bca4cSXuan Zhuo 		goto err_free_q;
451aa8bca4cSXuan Zhuo 	}
452aa8bca4cSXuan Zhuo 
453aa8bca4cSXuan Zhuo 	eea_start_rxtx(enet);
454aa8bca4cSXuan Zhuo 	eea_free_rxtx_q_mem(&ctx_old);
455aa8bca4cSXuan Zhuo 	return 0;
456aa8bca4cSXuan Zhuo 
457aa8bca4cSXuan Zhuo err_bind_old:
458aa8bca4cSXuan Zhuo 	eea_unbind_q_and_cfg(enet, ctx);
459aa8bca4cSXuan Zhuo 	eea_bind_q_and_cfg(enet, &ctx_old);
460aa8bca4cSXuan Zhuo 	error = eea_hw_active_ring(enet);
461aa8bca4cSXuan Zhuo 	if (error) {
462aa8bca4cSXuan Zhuo 		netdev_err(enet->netdev, "eea reset: active old ring. err %d\n",
463aa8bca4cSXuan Zhuo 			   error);
464aa8bca4cSXuan Zhuo 		eea_unbind_q_and_cfg(enet, &ctx_old);
465aa8bca4cSXuan Zhuo 		err = error;
466aa8bca4cSXuan Zhuo 		goto err_free_q;
467aa8bca4cSXuan Zhuo 	}
468aa8bca4cSXuan Zhuo 
469aa8bca4cSXuan Zhuo 	eea_start_rxtx(enet);
470aa8bca4cSXuan Zhuo 	eea_free_rxtx_q_mem(ctx);
471aa8bca4cSXuan Zhuo 	return err;
472aa8bca4cSXuan Zhuo 
473aa8bca4cSXuan Zhuo err_free_q:
474aa8bca4cSXuan Zhuo 
475aa8bca4cSXuan Zhuo 	/* An exception occurred at the hardware level, and there's not much we
476aa8bca4cSXuan Zhuo 	 * can do about it -- we can only release the resources first.
477aa8bca4cSXuan Zhuo 	 */
478aa8bca4cSXuan Zhuo 	eea_free_rxtx_q_mem(ctx);
479aa8bca4cSXuan Zhuo 	eea_free_rxtx_q_mem(&ctx_old);
480aa8bca4cSXuan Zhuo 	enet->started = false;
481aa8bca4cSXuan Zhuo 	return err;
482aa8bca4cSXuan Zhuo }
483aa8bca4cSXuan Zhuo 
484aa8bca4cSXuan Zhuo int eea_queues_check_and_reset(struct eea_device *edev)
485aa8bca4cSXuan Zhuo {
486aa8bca4cSXuan Zhuo 	struct eea_aq_dev_status dstatus = {0};
487aa8bca4cSXuan Zhuo 	struct eea_aq_queue_status *qstatus;
488aa8bca4cSXuan Zhuo 	struct eea_aq_queue_status *qs;
489aa8bca4cSXuan Zhuo 	struct eea_net_init_ctx ctx;
490aa8bca4cSXuan Zhuo 	bool need_reset = false;
491aa8bca4cSXuan Zhuo 	int i, err = 0;
492aa8bca4cSXuan Zhuo 
493aa8bca4cSXuan Zhuo 	rtnl_lock();
494aa8bca4cSXuan Zhuo 
495aa8bca4cSXuan Zhuo 	if (!netif_running(edev->enet->netdev))
496aa8bca4cSXuan Zhuo 		goto err_unlock;
497aa8bca4cSXuan Zhuo 
498aa8bca4cSXuan Zhuo 	/* Maybe stopped by ha. */
499aa8bca4cSXuan Zhuo 	if (!edev->enet->started || edev->enet->link_err)
500aa8bca4cSXuan Zhuo 		goto err_unlock;
501aa8bca4cSXuan Zhuo 
502aa8bca4cSXuan Zhuo 	err = eea_adminq_dev_status(edev->enet, &dstatus);
503aa8bca4cSXuan Zhuo 	if (err) {
504aa8bca4cSXuan Zhuo 		netdev_warn(edev->enet->netdev, "query queue status failed.\n");
505aa8bca4cSXuan Zhuo 		goto err_unlock;
506aa8bca4cSXuan Zhuo 	}
507aa8bca4cSXuan Zhuo 
508aa8bca4cSXuan Zhuo 	if (le16_to_cpu(dstatus.status->link_status) == EEA_LINK_DOWN_STATUS) {
509aa8bca4cSXuan Zhuo 		/* The device is broken, can not be up. */
510aa8bca4cSXuan Zhuo 		eea_netdev_stop(edev->enet->netdev);
511aa8bca4cSXuan Zhuo 		edev->enet->link_err = EEA_LINK_ERR_LINK_DOWN;
512aa8bca4cSXuan Zhuo 		netdev_warn(edev->enet->netdev, "device link is down. stop device.\n");
513aa8bca4cSXuan Zhuo 		goto err_free;
514aa8bca4cSXuan Zhuo 	}
515aa8bca4cSXuan Zhuo 
516aa8bca4cSXuan Zhuo 	qstatus = dstatus.status->q_status;
517aa8bca4cSXuan Zhuo 
518aa8bca4cSXuan Zhuo 	for (i = 0; i < dstatus.num; ++i) {
519aa8bca4cSXuan Zhuo 		qs = &qstatus[i];
520aa8bca4cSXuan Zhuo 
521aa8bca4cSXuan Zhuo 		if (le16_to_cpu(qs->status) == EEA_QUEUE_STATUS_NEED_RESET) {
522aa8bca4cSXuan Zhuo 			netdev_warn(edev->enet->netdev,
523aa8bca4cSXuan Zhuo 				    "queue status: queue %u needs to reset\n",
524aa8bca4cSXuan Zhuo 				    le16_to_cpu(qs->qidx));
525aa8bca4cSXuan Zhuo 			need_reset = true;
526aa8bca4cSXuan Zhuo 		}
527aa8bca4cSXuan Zhuo 	}
528aa8bca4cSXuan Zhuo 
529aa8bca4cSXuan Zhuo 	if (need_reset) {
530aa8bca4cSXuan Zhuo 		eea_init_ctx(edev->enet, &ctx);
531aa8bca4cSXuan Zhuo 		err = eea_reset_hw_resources(edev->enet, &ctx);
532aa8bca4cSXuan Zhuo 	}
533aa8bca4cSXuan Zhuo 
534aa8bca4cSXuan Zhuo err_free:
535aa8bca4cSXuan Zhuo 	kfree(dstatus.status);
536aa8bca4cSXuan Zhuo 
537aa8bca4cSXuan Zhuo err_unlock:
538aa8bca4cSXuan Zhuo 	rtnl_unlock();
539aa8bca4cSXuan Zhuo 	return err;
540aa8bca4cSXuan Zhuo }
541aa8bca4cSXuan Zhuo 
5424c45a51eSXuan Zhuo static int eea_update_cfg(struct eea_net *enet,
5434c45a51eSXuan Zhuo 			  struct eea_device *edev,
5444c45a51eSXuan Zhuo 			  struct eea_aq_cfg *hwcfg)
5454c45a51eSXuan Zhuo {
5464c45a51eSXuan Zhuo 	u32 rx_max = le32_to_cpu(hwcfg->rx_depth_max);
5474c45a51eSXuan Zhuo 	u32 tx_max = le32_to_cpu(hwcfg->tx_depth_max);
5484c45a51eSXuan Zhuo 	u32 rx_def = le32_to_cpu(hwcfg->rx_depth_def);
5494c45a51eSXuan Zhuo 	u32 tx_def = le32_to_cpu(hwcfg->tx_depth_def);
5504c45a51eSXuan Zhuo 
5514c45a51eSXuan Zhuo 	/* Now, we assert that the rx ring num is equal to the tx ring num. */
5524c45a51eSXuan Zhuo 	if (edev->rx_num != edev->tx_num) {
5534c45a51eSXuan Zhuo 		dev_err(edev->dma_dev, "Inconsistent ring num: RX %u, TX %u\n",
5544c45a51eSXuan Zhuo 			edev->rx_num, edev->tx_num);
5554c45a51eSXuan Zhuo 		return -EINVAL;
5564c45a51eSXuan Zhuo 	}
5574c45a51eSXuan Zhuo 
5584c45a51eSXuan Zhuo 	if (rx_max > EEA_NET_IO_HW_RING_DEPTH_MAX ||
5594c45a51eSXuan Zhuo 	    rx_max < EEA_NET_IO_HW_RING_DEPTH_MIN ||
5604c45a51eSXuan Zhuo 	    tx_max > EEA_NET_IO_HW_RING_DEPTH_MAX ||
5614c45a51eSXuan Zhuo 	    tx_max < EEA_NET_IO_HW_RING_DEPTH_MIN) {
5624c45a51eSXuan Zhuo 		dev_err(edev->dma_dev, "Invalid HW max depth: RX %u, TX %u\n",
5634c45a51eSXuan Zhuo 			rx_max, tx_max);
5644c45a51eSXuan Zhuo 		return -EINVAL;
5654c45a51eSXuan Zhuo 	}
5664c45a51eSXuan Zhuo 
5674c45a51eSXuan Zhuo 	if (rx_def > rx_max ||
5684c45a51eSXuan Zhuo 	    tx_def > tx_max ||
5694c45a51eSXuan Zhuo 	    rx_def < EEA_NET_IO_HW_RING_DEPTH_MIN ||
5704c45a51eSXuan Zhuo 	    tx_def < EEA_NET_IO_HW_RING_DEPTH_MIN) {
5714c45a51eSXuan Zhuo 		dev_err(edev->dma_dev, "Invalid default depth: RX %u (max %u), TX %u (max %u)\n",
5724c45a51eSXuan Zhuo 			rx_def, rx_max, tx_def, tx_max);
5734c45a51eSXuan Zhuo 		return -EINVAL;
5744c45a51eSXuan Zhuo 	}
5754c45a51eSXuan Zhuo 
5764c45a51eSXuan Zhuo 	if (!is_power_of_2(rx_max) || !is_power_of_2(tx_max) ||
5774c45a51eSXuan Zhuo 	    !is_power_of_2(rx_def) || !is_power_of_2(tx_def)) {
5784c45a51eSXuan Zhuo 		dev_err(edev->dma_dev, "Ring depth must be power of 2\n");
5794c45a51eSXuan Zhuo 		return -EINVAL;
5804c45a51eSXuan Zhuo 	}
5814c45a51eSXuan Zhuo 
5824c45a51eSXuan Zhuo 	enet->cfg_hw.rx_ring_depth = rx_max;
5834c45a51eSXuan Zhuo 	enet->cfg_hw.tx_ring_depth = tx_max;
5844c45a51eSXuan Zhuo 	enet->cfg_hw.rx_ring_num = edev->rx_num;
5854c45a51eSXuan Zhuo 	enet->cfg_hw.tx_ring_num = edev->tx_num;
5864c45a51eSXuan Zhuo 	enet->cfg_hw.split_hdr = EEA_SPLIT_HDR_SIZE;
5874c45a51eSXuan Zhuo 
5884c45a51eSXuan Zhuo 	enet->cfg.rx_ring_depth = rx_def;
5894c45a51eSXuan Zhuo 	enet->cfg.tx_ring_depth = tx_def;
5904c45a51eSXuan Zhuo 	enet->cfg.rx_ring_num = edev->rx_num;
5914c45a51eSXuan Zhuo 	enet->cfg.tx_ring_num = edev->tx_num;
5924c45a51eSXuan Zhuo 
5934c45a51eSXuan Zhuo 	return 0;
5944c45a51eSXuan Zhuo }
5954c45a51eSXuan Zhuo 
5964c45a51eSXuan Zhuo static int eea_netdev_init_features(struct net_device *netdev,
5974c45a51eSXuan Zhuo 				    struct eea_net *enet,
5984c45a51eSXuan Zhuo 				    struct eea_device *edev)
5994c45a51eSXuan Zhuo {
6004c45a51eSXuan Zhuo 	struct eea_aq_cfg *cfg;
6014c45a51eSXuan Zhuo 	int err;
6024c45a51eSXuan Zhuo 	u32 mtu;
6034c45a51eSXuan Zhuo 
6044c45a51eSXuan Zhuo 	cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
6054c45a51eSXuan Zhuo 	if (!cfg)
6064c45a51eSXuan Zhuo 		return -ENOMEM;
6074c45a51eSXuan Zhuo 
6084c45a51eSXuan Zhuo 	err = eea_adminq_query_cfg(enet, cfg);
6094c45a51eSXuan Zhuo 	if (err)
6104c45a51eSXuan Zhuo 		goto err_free;
6114c45a51eSXuan Zhuo 
6124c45a51eSXuan Zhuo 	mtu = le16_to_cpu(cfg->mtu);
6134c45a51eSXuan Zhuo 	if (mtu < ETH_MIN_MTU) {
6144c45a51eSXuan Zhuo 		dev_err(edev->dma_dev, "The device gave us an invalid MTU. Here we can only exit the initialization. %u < %u\n",
6154c45a51eSXuan Zhuo 			mtu, ETH_MIN_MTU);
6164c45a51eSXuan Zhuo 		err = -EINVAL;
6174c45a51eSXuan Zhuo 		goto err_free;
6184c45a51eSXuan Zhuo 	}
6194c45a51eSXuan Zhuo 
6204c45a51eSXuan Zhuo 	err = eea_update_cfg(enet, edev, cfg);
6214c45a51eSXuan Zhuo 	if (err)
6224c45a51eSXuan Zhuo 		goto err_free;
6234c45a51eSXuan Zhuo 
6244c45a51eSXuan Zhuo 	netdev->priv_flags |= IFF_UNICAST_FLT;
6254c45a51eSXuan Zhuo 	netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
6264c45a51eSXuan Zhuo 
6274c45a51eSXuan Zhuo 	netdev->hw_features |= NETIF_F_HW_CSUM;
6284c45a51eSXuan Zhuo 	netdev->hw_features |= NETIF_F_GRO_HW;
6294c45a51eSXuan Zhuo 	netdev->hw_features |= NETIF_F_SG;
6304c45a51eSXuan Zhuo 	netdev->hw_features |= NETIF_F_TSO;
6314c45a51eSXuan Zhuo 	netdev->hw_features |= NETIF_F_TSO_ECN;
6324c45a51eSXuan Zhuo 	netdev->hw_features |= NETIF_F_TSO6;
6334c45a51eSXuan Zhuo 	netdev->hw_features |= NETIF_F_GSO_UDP_L4;
6344c45a51eSXuan Zhuo 
6354c45a51eSXuan Zhuo 	netdev->features |= NETIF_F_HIGHDMA;
6364c45a51eSXuan Zhuo 	netdev->features |= NETIF_F_HW_CSUM;
6374c45a51eSXuan Zhuo 	netdev->features |= NETIF_F_SG;
6384c45a51eSXuan Zhuo 	netdev->features |= NETIF_F_GSO_ROBUST;
6394c45a51eSXuan Zhuo 	netdev->features |= netdev->hw_features & NETIF_F_ALL_TSO;
6404c45a51eSXuan Zhuo 	netdev->features |= NETIF_F_RXCSUM;
6414c45a51eSXuan Zhuo 	netdev->features |= NETIF_F_GRO_HW;
6424c45a51eSXuan Zhuo 
6434c45a51eSXuan Zhuo 	netdev->vlan_features = netdev->features;
6444c45a51eSXuan Zhuo 
6454c45a51eSXuan Zhuo 	if (!is_valid_ether_addr(cfg->mac)) {
6464c45a51eSXuan Zhuo 		dev_err(edev->dma_dev, "The device gave invalid mac %pM\n",
6474c45a51eSXuan Zhuo 			cfg->mac);
6484c45a51eSXuan Zhuo 		err = -EINVAL;
6494c45a51eSXuan Zhuo 		goto err_free;
6504c45a51eSXuan Zhuo 	}
6514c45a51eSXuan Zhuo 
6524c45a51eSXuan Zhuo 	eth_hw_addr_set(netdev, cfg->mac);
6534c45a51eSXuan Zhuo 
6544c45a51eSXuan Zhuo 	enet->speed = SPEED_UNKNOWN;
6554c45a51eSXuan Zhuo 	enet->duplex = DUPLEX_UNKNOWN;
6564c45a51eSXuan Zhuo 
6574c45a51eSXuan Zhuo 	netdev->min_mtu = ETH_MIN_MTU;
6584c45a51eSXuan Zhuo 
6594c45a51eSXuan Zhuo 	netdev->mtu = mtu;
6604c45a51eSXuan Zhuo 
6614c45a51eSXuan Zhuo 	/* If jumbo frames are already enabled, then the returned MTU will be a
6624c45a51eSXuan Zhuo 	 * jumbo MTU, and the driver will automatically enable jumbo frame
6634c45a51eSXuan Zhuo 	 * support by default.
6644c45a51eSXuan Zhuo 	 */
6654c45a51eSXuan Zhuo 	netdev->max_mtu = mtu;
6664c45a51eSXuan Zhuo 
6674c45a51eSXuan Zhuo err_free:
6684c45a51eSXuan Zhuo 	kfree(cfg);
6694c45a51eSXuan Zhuo 	return err;
6704c45a51eSXuan Zhuo }
6714c45a51eSXuan Zhuo 
6724c45a51eSXuan Zhuo static const struct net_device_ops eea_netdev = {
673aa8bca4cSXuan Zhuo 	.ndo_open           = eea_netdev_open,
674aa8bca4cSXuan Zhuo 	.ndo_stop           = eea_netdev_stop,
675aa8bca4cSXuan Zhuo 	.ndo_start_xmit     = eea_tx_xmit,
6764c45a51eSXuan Zhuo 	.ndo_validate_addr  = eth_validate_addr,
677*4e88fb32SXuan Zhuo 	.ndo_get_stats64    = eea_stats,
6784c45a51eSXuan Zhuo 	.ndo_features_check = passthru_features_check,
6794c45a51eSXuan Zhuo };
6804c45a51eSXuan Zhuo 
6814c45a51eSXuan Zhuo static struct eea_net *eea_netdev_alloc(struct eea_device *edev, u32 pairs)
6824c45a51eSXuan Zhuo {
6834c45a51eSXuan Zhuo 	struct net_device *netdev;
6844c45a51eSXuan Zhuo 	struct eea_net *enet;
685aa8bca4cSXuan Zhuo 	int err;
6864c45a51eSXuan Zhuo 
6874c45a51eSXuan Zhuo 	netdev = alloc_etherdev_mq(sizeof(struct eea_net), pairs);
6884c45a51eSXuan Zhuo 	if (!netdev) {
6894c45a51eSXuan Zhuo 		dev_err(edev->dma_dev,
6904c45a51eSXuan Zhuo 			"alloc_etherdev_mq failed with pairs %d\n", pairs);
6914c45a51eSXuan Zhuo 		return NULL;
6924c45a51eSXuan Zhuo 	}
6934c45a51eSXuan Zhuo 
6944c45a51eSXuan Zhuo 	netdev->netdev_ops = &eea_netdev;
6955f4f7bc0SXuan Zhuo 	netdev->ethtool_ops = &eea_ethtool_ops;
6964c45a51eSXuan Zhuo 	SET_NETDEV_DEV(netdev, edev->dma_dev);
6974c45a51eSXuan Zhuo 
6984c45a51eSXuan Zhuo 	enet = netdev_priv(netdev);
6994c45a51eSXuan Zhuo 	enet->netdev = netdev;
7004c45a51eSXuan Zhuo 	enet->edev = edev;
7014c45a51eSXuan Zhuo 	edev->enet = enet;
7024c45a51eSXuan Zhuo 
703aa8bca4cSXuan Zhuo 	err = eea_alloc_irq_blks(enet);
704aa8bca4cSXuan Zhuo 	if (err) {
705aa8bca4cSXuan Zhuo 		dev_err(edev->dma_dev,
706aa8bca4cSXuan Zhuo 			"eea_alloc_irq_blks failed with pairs %d\n", pairs);
707aa8bca4cSXuan Zhuo 		free_netdev(netdev);
708aa8bca4cSXuan Zhuo 		return NULL;
709aa8bca4cSXuan Zhuo 	}
710aa8bca4cSXuan Zhuo 
711*4e88fb32SXuan Zhuo 	spin_lock_init(&enet->stats_lock);
712*4e88fb32SXuan Zhuo 
7134c45a51eSXuan Zhuo 	return enet;
7144c45a51eSXuan Zhuo }
7154c45a51eSXuan Zhuo 
716df9cad6bSXuan Zhuo static void eea_update_ts_off(struct eea_device *edev, struct eea_net *enet)
717df9cad6bSXuan Zhuo {
718df9cad6bSXuan Zhuo 	u64 ts;
719df9cad6bSXuan Zhuo 
720df9cad6bSXuan Zhuo 	ts = eea_pci_device_ts(edev);
721df9cad6bSXuan Zhuo 
722df9cad6bSXuan Zhuo 	enet->hw_ts_offset = ktime_get_real() - ts;
723df9cad6bSXuan Zhuo }
724df9cad6bSXuan Zhuo 
725aa8bca4cSXuan Zhuo static int eea_net_reprobe(struct eea_device *edev)
726aa8bca4cSXuan Zhuo {
727aa8bca4cSXuan Zhuo 	struct eea_net *enet = edev->enet;
728aa8bca4cSXuan Zhuo 	int err = 0;
729aa8bca4cSXuan Zhuo 
730aa8bca4cSXuan Zhuo 	enet->edev = edev;
731aa8bca4cSXuan Zhuo 
732aa8bca4cSXuan Zhuo 	if (!enet->adminq.ring) {
733aa8bca4cSXuan Zhuo 		err = eea_create_adminq(enet, edev->rx_num + edev->tx_num);
734aa8bca4cSXuan Zhuo 		if (err)
735aa8bca4cSXuan Zhuo 			return err;
736aa8bca4cSXuan Zhuo 	}
737aa8bca4cSXuan Zhuo 
738aa8bca4cSXuan Zhuo 	err = eea_alloc_irq_blks(enet);
739aa8bca4cSXuan Zhuo 	if (err)
740aa8bca4cSXuan Zhuo 		goto err_destroy_aq;
741aa8bca4cSXuan Zhuo 
742df9cad6bSXuan Zhuo 	eea_update_ts_off(edev, enet);
743df9cad6bSXuan Zhuo 
744aa8bca4cSXuan Zhuo 	rtnl_lock();
745aa8bca4cSXuan Zhuo 
746aa8bca4cSXuan Zhuo 	enet->link_err = 0;
747aa8bca4cSXuan Zhuo 	if (edev->ha_reset_netdev_running &&
748aa8bca4cSXuan Zhuo 	    netif_running(edev->enet->netdev)) {
749aa8bca4cSXuan Zhuo 		err = eea_netdev_open(enet->netdev);
750aa8bca4cSXuan Zhuo 		if (err) {
751aa8bca4cSXuan Zhuo 			enet->link_err = EEA_LINK_ERR_HA_RESET_DEV;
752aa8bca4cSXuan Zhuo 			rtnl_unlock();
753aa8bca4cSXuan Zhuo 			goto err_free_irq_blks;
754aa8bca4cSXuan Zhuo 		}
755aa8bca4cSXuan Zhuo 	}
756aa8bca4cSXuan Zhuo 
757aa8bca4cSXuan Zhuo 	rtnl_unlock();
758aa8bca4cSXuan Zhuo 
759aa8bca4cSXuan Zhuo 	enet->wait_pci_ready = false;
760aa8bca4cSXuan Zhuo 	return 0;
761aa8bca4cSXuan Zhuo 
762aa8bca4cSXuan Zhuo err_free_irq_blks:
763aa8bca4cSXuan Zhuo 	eea_free_irq_blk(enet);
764aa8bca4cSXuan Zhuo 
765aa8bca4cSXuan Zhuo err_destroy_aq:
766aa8bca4cSXuan Zhuo 	eea_destroy_adminq(enet);
767aa8bca4cSXuan Zhuo 
768aa8bca4cSXuan Zhuo 	return err;
769aa8bca4cSXuan Zhuo }
770aa8bca4cSXuan Zhuo 
7714c45a51eSXuan Zhuo int eea_net_probe(struct eea_device *edev)
7724c45a51eSXuan Zhuo {
7734c45a51eSXuan Zhuo 	struct eea_net *enet;
7744c45a51eSXuan Zhuo 	int err = -ENOMEM;
7754c45a51eSXuan Zhuo 
776aa8bca4cSXuan Zhuo 	/* If edev->enet is not null, then this is called from ha reset worker.
777aa8bca4cSXuan Zhuo 	 * Call eea_net_reprobe() directly.
778aa8bca4cSXuan Zhuo 	 */
779aa8bca4cSXuan Zhuo 	if (edev->enet)
780aa8bca4cSXuan Zhuo 		return eea_net_reprobe(edev);
781aa8bca4cSXuan Zhuo 
7824c45a51eSXuan Zhuo 	enet = eea_netdev_alloc(edev, edev->rx_num);
7834c45a51eSXuan Zhuo 	if (!enet)
7844c45a51eSXuan Zhuo 		return -ENOMEM;
7854c45a51eSXuan Zhuo 
7864c45a51eSXuan Zhuo 	err = eea_create_adminq(enet, edev->rx_num + edev->tx_num);
7874c45a51eSXuan Zhuo 	if (err)
7884c45a51eSXuan Zhuo 		goto err_free_netdev;
7894c45a51eSXuan Zhuo 
7904c45a51eSXuan Zhuo 	eea_adminq_config_host_info(enet);
7914c45a51eSXuan Zhuo 
7924c45a51eSXuan Zhuo 	err = eea_netdev_init_features(enet->netdev, enet, edev);
7934c45a51eSXuan Zhuo 	if (err)
7944c45a51eSXuan Zhuo 		goto err_reset_dev;
7954c45a51eSXuan Zhuo 
796df9cad6bSXuan Zhuo 	eea_update_ts_off(edev, enet);
797df9cad6bSXuan Zhuo 
798*4e88fb32SXuan Zhuo 	netif_carrier_off(enet->netdev);
7994c45a51eSXuan Zhuo 
800*4e88fb32SXuan Zhuo 	err = register_netdev(enet->netdev);
801*4e88fb32SXuan Zhuo 	if (err)
802*4e88fb32SXuan Zhuo 		goto err_reset_dev;
803*4e88fb32SXuan Zhuo 
804*4e88fb32SXuan Zhuo 	netdev_dbg(enet->netdev, "eea probe success.\n");
8054c45a51eSXuan Zhuo 
8064c45a51eSXuan Zhuo 	return 0;
8074c45a51eSXuan Zhuo 
8084c45a51eSXuan Zhuo err_reset_dev:
8094c45a51eSXuan Zhuo 	eea_device_reset(edev);
8104c45a51eSXuan Zhuo 	eea_destroy_adminq(enet);
8114c45a51eSXuan Zhuo 
8124c45a51eSXuan Zhuo err_free_netdev:
813aa8bca4cSXuan Zhuo 	eea_free_irq_blk(enet);
8144c45a51eSXuan Zhuo 	free_netdev(enet->netdev);
8154c45a51eSXuan Zhuo 	return err;
8164c45a51eSXuan Zhuo }
8174c45a51eSXuan Zhuo 
818aa8bca4cSXuan Zhuo static void eea_net_ha_reset_remove(struct eea_net *enet,
819aa8bca4cSXuan Zhuo 				    struct eea_device *edev)
820aa8bca4cSXuan Zhuo {
821aa8bca4cSXuan Zhuo 	rtnl_lock();
822aa8bca4cSXuan Zhuo 	edev->ha_reset_netdev_running = false;
823aa8bca4cSXuan Zhuo 	if (netif_running(enet->netdev)) {
824aa8bca4cSXuan Zhuo 		eea_netdev_stop(enet->netdev);
825aa8bca4cSXuan Zhuo 		edev->ha_reset_netdev_running = true;
826aa8bca4cSXuan Zhuo 	}
827aa8bca4cSXuan Zhuo 
828aa8bca4cSXuan Zhuo 	/* Prevent that the user set up the net device. */
829aa8bca4cSXuan Zhuo 	enet->link_err = EEA_LINK_ERR_HA_RESET_DEV;
830aa8bca4cSXuan Zhuo 
831aa8bca4cSXuan Zhuo 	rtnl_unlock();
832aa8bca4cSXuan Zhuo 
833aa8bca4cSXuan Zhuo 	eea_device_reset(edev);
834aa8bca4cSXuan Zhuo 	eea_destroy_adminq(enet);
835aa8bca4cSXuan Zhuo 	eea_free_irq_blk(enet);
836aa8bca4cSXuan Zhuo 
837aa8bca4cSXuan Zhuo 	enet->wait_pci_ready = true;
838aa8bca4cSXuan Zhuo }
839aa8bca4cSXuan Zhuo 
840aa8bca4cSXuan Zhuo void eea_net_remove(struct eea_device *edev, bool ha)
8414c45a51eSXuan Zhuo {
8424c45a51eSXuan Zhuo 	struct net_device *netdev;
8434c45a51eSXuan Zhuo 	struct eea_net *enet;
8444c45a51eSXuan Zhuo 
8454c45a51eSXuan Zhuo 	enet = edev->enet;
8464c45a51eSXuan Zhuo 	netdev = enet->netdev;
8474c45a51eSXuan Zhuo 
848aa8bca4cSXuan Zhuo 	if (ha) {
849aa8bca4cSXuan Zhuo 		if (enet->wait_pci_ready)
850aa8bca4cSXuan Zhuo 			return;
8514c45a51eSXuan Zhuo 
852aa8bca4cSXuan Zhuo 		eea_net_ha_reset_remove(enet, edev);
853aa8bca4cSXuan Zhuo 		return;
854aa8bca4cSXuan Zhuo 	}
855aa8bca4cSXuan Zhuo 
856*4e88fb32SXuan Zhuo 	unregister_netdev(netdev);
857*4e88fb32SXuan Zhuo 
858aa8bca4cSXuan Zhuo 	if (!enet->wait_pci_ready) {
8594c45a51eSXuan Zhuo 		eea_device_reset(edev);
8604c45a51eSXuan Zhuo 		eea_destroy_adminq(enet);
861aa8bca4cSXuan Zhuo 		eea_free_irq_blk(enet);
862aa8bca4cSXuan Zhuo 	}
8634c45a51eSXuan Zhuo 
8644c45a51eSXuan Zhuo 	free_netdev(netdev);
8654c45a51eSXuan Zhuo }
8664c45a51eSXuan Zhuo 
8674c45a51eSXuan Zhuo void eea_net_shutdown(struct eea_device *edev)
8684c45a51eSXuan Zhuo {
8694c45a51eSXuan Zhuo 	struct net_device *netdev;
8704c45a51eSXuan Zhuo 	struct eea_net *enet;
8714c45a51eSXuan Zhuo 
8724c45a51eSXuan Zhuo 	enet = edev->enet;
8734c45a51eSXuan Zhuo 	netdev = enet->netdev;
8744c45a51eSXuan Zhuo 
8754c45a51eSXuan Zhuo 	rtnl_lock();
8764c45a51eSXuan Zhuo 
8774c45a51eSXuan Zhuo 	netif_device_detach(netdev);
878*4e88fb32SXuan Zhuo 	dev_close(netdev);
8794c45a51eSXuan Zhuo 
880aa8bca4cSXuan Zhuo 	if (!enet->wait_pci_ready) {
8814c45a51eSXuan Zhuo 		eea_device_reset(edev);
8824c45a51eSXuan Zhuo 		eea_destroy_adminq(enet);
883aa8bca4cSXuan Zhuo 		eea_free_irq_blk(enet);
884aa8bca4cSXuan Zhuo 	}
8854c45a51eSXuan Zhuo 
8864c45a51eSXuan Zhuo 	rtnl_unlock();
8874c45a51eSXuan Zhuo }
888