File Index
Files and directories
Sign in
FILE

hinic3_main.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/huawei/hinic3/hinic3_main.c C
  1// SPDX-License-Identifier: GPL-2.0
  2// Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
  3
  4#include <linux/etherdevice.h>
  5#include <linux/netdevice.h>
  6
  7#include "hinic3_common.h"
  8#include "hinic3_hw_comm.h"
  9#include "hinic3_hwdev.h"
 10#include "hinic3_hwif.h"
 11#include "hinic3_lld.h"
 12#include "hinic3_nic_cfg.h"
 13#include "hinic3_nic_dev.h"
 14#include "hinic3_nic_io.h"
 15#include "hinic3_rss.h"
 16#include "hinic3_rx.h"
 17#include "hinic3_tx.h"
 18
 19#define HINIC3_NIC_DRV_DESC  "Intelligent Network Interface Card Driver"
 20
 21#define HINIC3_RX_BUF_LEN          2048
 22#define HINIC3_LRO_REPLENISH_THLD  256
 23#define HINIC3_NIC_DEV_WQ_NAME     "hinic3_nic_dev_wq"
 24
 25#define HINIC3_SQ_DEPTH            1024
 26#define HINIC3_RQ_DEPTH            1024
 27
 28#define HINIC3_DEFAULT_TXRX_MSIX_PENDING_LIMIT      2
 29#define HINIC3_DEFAULT_TXRX_MSIX_COALESC_TIMER_CFG  25
 30#define HINIC3_DEFAULT_TXRX_MSIX_RESEND_TIMER_CFG   7
 31
 32static void init_intr_coal_param(struct net_device *netdev)
 33{
 34	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
 35	struct hinic3_intr_coal_info *info;
 36	u16 i;
 37
 38	for (i = 0; i < nic_dev->max_qps; i++) {
 39		info = &nic_dev->intr_coalesce[i];
 40		info->pending_limit = HINIC3_DEFAULT_TXRX_MSIX_PENDING_LIMIT;
 41		info->coalesce_timer_cfg = HINIC3_DEFAULT_TXRX_MSIX_COALESC_TIMER_CFG;
 42		info->resend_timer_cfg = HINIC3_DEFAULT_TXRX_MSIX_RESEND_TIMER_CFG;
 43	}
 44}
 45
 46static int hinic3_init_intr_coalesce(struct net_device *netdev)
 47{
 48	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
 49
 50	nic_dev->intr_coalesce = kcalloc(nic_dev->max_qps,
 51					 sizeof(*nic_dev->intr_coalesce),
 52					 GFP_KERNEL);
 53
 54	if (!nic_dev->intr_coalesce)
 55		return -ENOMEM;
 56
 57	init_intr_coal_param(netdev);
 58
 59	return 0;
 60}
 61
 62static void hinic3_free_intr_coalesce(struct net_device *netdev)
 63{
 64	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
 65
 66	kfree(nic_dev->intr_coalesce);
 67}
 68
 69static int hinic3_alloc_txrxqs(struct net_device *netdev)
 70{
 71	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
 72	struct hinic3_hwdev *hwdev = nic_dev->hwdev;
 73	int err;
 74
 75	err = hinic3_alloc_txqs(netdev);
 76	if (err) {
 77		dev_err(hwdev->dev, "Failed to alloc txqs\n");
 78		return err;
 79	}
 80
 81	err = hinic3_alloc_rxqs(netdev);
 82	if (err) {
 83		dev_err(hwdev->dev, "Failed to alloc rxqs\n");
 84		goto err_free_txqs;
 85	}
 86
 87	err = hinic3_init_intr_coalesce(netdev);
 88	if (err) {
 89		dev_err(hwdev->dev, "Failed to init_intr_coalesce\n");
 90		goto err_free_rxqs;
 91	}
 92
 93	return 0;
 94
 95err_free_rxqs:
 96	hinic3_free_rxqs(netdev);
 97
 98err_free_txqs:
 99	hinic3_free_txqs(netdev);
100
101	return err;
102}
103
104static void hinic3_free_txrxqs(struct net_device *netdev)
105{
106	hinic3_free_intr_coalesce(netdev);
107	hinic3_free_rxqs(netdev);
108	hinic3_free_txqs(netdev);
109}
110
111static int hinic3_init_nic_dev(struct net_device *netdev,
112			       struct hinic3_hwdev *hwdev)
113{
114	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
115	struct pci_dev *pdev = hwdev->pdev;
116
117	nic_dev->netdev = netdev;
118	SET_NETDEV_DEV(netdev, &pdev->dev);
119	nic_dev->hwdev = hwdev;
120	nic_dev->pdev = pdev;
121
122	nic_dev->rx_buf_len = HINIC3_RX_BUF_LEN;
123	nic_dev->lro_replenish_thld = HINIC3_LRO_REPLENISH_THLD;
124	nic_dev->nic_svc_cap = hwdev->cfg_mgmt->cap.nic_svc_cap;
125
126	return 0;
127}
128
129static int hinic3_sw_init(struct net_device *netdev)
130{
131	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
132	struct hinic3_hwdev *hwdev = nic_dev->hwdev;
133	int err;
134
135	nic_dev->q_params.sq_depth = HINIC3_SQ_DEPTH;
136	nic_dev->q_params.rq_depth = HINIC3_RQ_DEPTH;
137
138	hinic3_try_to_enable_rss(netdev);
139
140	/* VF driver always uses random MAC address. During VM migration to a
141	 * new device, the new device should learn the VMs old MAC rather than
142	 * provide its own MAC. The product design assumes that every VF is
143	 * suspectable to migration so the device avoids offering MAC address
144	 * to VFs.
145	 */
146	eth_hw_addr_random(netdev);
147	err = hinic3_set_mac(hwdev, netdev->dev_addr, 0,
148			     hinic3_global_func_id(hwdev));
149	if (err) {
150		dev_err(hwdev->dev, "Failed to set default MAC\n");
151		goto err_clear_rss_config;
152	}
153
154	err = hinic3_alloc_txrxqs(netdev);
155	if (err) {
156		dev_err(hwdev->dev, "Failed to alloc qps\n");
157		goto err_del_mac;
158	}
159
160	return 0;
161
162err_del_mac:
163	hinic3_del_mac(hwdev, netdev->dev_addr, 0,
164		       hinic3_global_func_id(hwdev));
165err_clear_rss_config:
166	hinic3_clear_rss_config(netdev);
167
168	return err;
169}
170
171static void hinic3_sw_uninit(struct net_device *netdev)
172{
173	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
174
175	hinic3_free_txrxqs(netdev);
176	hinic3_del_mac(nic_dev->hwdev, netdev->dev_addr, 0,
177		       hinic3_global_func_id(nic_dev->hwdev));
178	hinic3_clear_rss_config(netdev);
179}
180
181static void hinic3_assign_netdev_ops(struct net_device *netdev)
182{
183	hinic3_set_netdev_ops(netdev);
184}
185
186static void netdev_feature_init(struct net_device *netdev)
187{
188	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
189	netdev_features_t cso_fts = 0;
190	netdev_features_t tso_fts = 0;
191	netdev_features_t dft_fts;
192
193	dft_fts = NETIF_F_SG | NETIF_F_HIGHDMA;
194	if (hinic3_test_support(nic_dev, HINIC3_NIC_F_CSUM))
195		cso_fts |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM;
196	if (hinic3_test_support(nic_dev, HINIC3_NIC_F_SCTP_CRC))
197		cso_fts |= NETIF_F_SCTP_CRC;
198	if (hinic3_test_support(nic_dev, HINIC3_NIC_F_TSO))
199		tso_fts |= NETIF_F_TSO | NETIF_F_TSO6;
200
201	netdev->features |= dft_fts | cso_fts | tso_fts;
202}
203
204static int hinic3_set_default_hw_feature(struct net_device *netdev)
205{
206	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
207	struct hinic3_hwdev *hwdev = nic_dev->hwdev;
208	int err;
209
210	err = hinic3_set_nic_feature_to_hw(nic_dev);
211	if (err) {
212		dev_err(hwdev->dev, "Failed to set nic features\n");
213		return err;
214	}
215
216	return 0;
217}
218
219static void hinic3_link_status_change(struct net_device *netdev,
220				      bool link_status_up)
221{
222	struct hinic3_nic_dev *nic_dev = netdev_priv(netdev);
223
224	if (link_status_up) {
225		if (netif_carrier_ok(netdev))
226			return;
227
228		nic_dev->link_status_up = true;
229		netif_carrier_on(netdev);
230		netdev_dbg(netdev, "Link is up\n");
231	} else {
232		if (!netif_carrier_ok(netdev))
233			return;
234
235		nic_dev->link_status_up = false;
236		netif_carrier_off(netdev);
237		netdev_dbg(netdev, "Link is down\n");
238	}
239}
240
241static void hinic3_nic_event(struct auxiliary_device *adev,
242			     struct hinic3_event_info *event)
243{
244	struct hinic3_nic_dev *nic_dev = dev_get_drvdata(&adev->dev);
245	struct net_device *netdev;
246
247	netdev = nic_dev->netdev;
248
249	switch (HINIC3_SRV_EVENT_TYPE(event->service, event->type)) {
250	case HINIC3_SRV_EVENT_TYPE(HINIC3_EVENT_SRV_NIC,
251				   HINIC3_NIC_EVENT_LINK_UP):
252		hinic3_link_status_change(netdev, true);
253		break;
254	case HINIC3_SRV_EVENT_TYPE(HINIC3_EVENT_SRV_NIC,
255				   HINIC3_NIC_EVENT_LINK_DOWN):
256		hinic3_link_status_change(netdev, false);
257		break;
258	default:
259		break;
260	}
261}
262
263static int hinic3_nic_probe(struct auxiliary_device *adev,
264			    const struct auxiliary_device_id *id)
265{
266	struct hinic3_hwdev *hwdev = hinic3_adev_get_hwdev(adev);
267	struct pci_dev *pdev = hwdev->pdev;
268	struct hinic3_nic_dev *nic_dev;
269	struct net_device *netdev;
270	u16 max_qps, glb_func_id;
271	int err;
272
273	if (!hinic3_support_nic(hwdev)) {
274		dev_dbg(&adev->dev, "HW doesn't support nic\n");
275		return 0;
276	}
277
278	hinic3_adev_event_register(adev, hinic3_nic_event);
279
280	glb_func_id = hinic3_global_func_id(hwdev);
281	err = hinic3_func_reset(hwdev, glb_func_id, COMM_FUNC_RESET_BIT_NIC);
282	if (err) {
283		dev_err(&adev->dev, "Failed to reset function\n");
284		goto err_unregister_adev_event;
285	}
286
287	max_qps = hinic3_func_max_qnum(hwdev);
288	netdev = alloc_etherdev_mq(sizeof(*nic_dev), max_qps);
289	if (!netdev) {
290		dev_err(&adev->dev, "Failed to allocate netdev\n");
291		err = -ENOMEM;
292		goto err_unregister_adev_event;
293	}
294
295	nic_dev = netdev_priv(netdev);
296	dev_set_drvdata(&adev->dev, nic_dev);
297	err = hinic3_init_nic_dev(netdev, hwdev);
298	if (err)
299		goto err_free_netdev;
300
301	err = hinic3_init_nic_io(nic_dev);
302	if (err)
303		goto err_free_netdev;
304
305	err = hinic3_sw_init(netdev);
306	if (err)
307		goto err_free_nic_io;
308
309	hinic3_assign_netdev_ops(netdev);
310
311	netdev_feature_init(netdev);
312	err = hinic3_set_default_hw_feature(netdev);
313	if (err)
314		goto err_uninit_sw;
315
316	netif_carrier_off(netdev);
317
318	err = register_netdev(netdev);
319	if (err)
320		goto err_uninit_nic_feature;
321
322	return 0;
323
324err_uninit_nic_feature:
325	hinic3_update_nic_feature(nic_dev, 0);
326	hinic3_set_nic_feature_to_hw(nic_dev);
327
328err_uninit_sw:
329	hinic3_sw_uninit(netdev);
330
331err_free_nic_io:
332	hinic3_free_nic_io(nic_dev);
333
334err_free_netdev:
335	free_netdev(netdev);
336
337err_unregister_adev_event:
338	hinic3_adev_event_unregister(adev);
339	dev_err(&pdev->dev, "NIC service probe failed\n");
340
341	return err;
342}
343
344static void hinic3_nic_remove(struct auxiliary_device *adev)
345{
346	struct hinic3_nic_dev *nic_dev = dev_get_drvdata(&adev->dev);
347	struct net_device *netdev;
348
349	if (!hinic3_support_nic(nic_dev->hwdev))
350		return;
351
352	netdev = nic_dev->netdev;
353	unregister_netdev(netdev);
354
355	hinic3_update_nic_feature(nic_dev, 0);
356	hinic3_set_nic_feature_to_hw(nic_dev);
357	hinic3_sw_uninit(netdev);
358
359	hinic3_free_nic_io(nic_dev);
360
361	free_netdev(netdev);
362}
363
364static const struct auxiliary_device_id hinic3_nic_id_table[] = {
365	{
366		.name = HINIC3_NIC_DRV_NAME ".nic",
367	},
368	{}
369};
370
371static struct auxiliary_driver hinic3_nic_driver = {
372	.probe    = hinic3_nic_probe,
373	.remove   = hinic3_nic_remove,
374	.suspend  = NULL,
375	.resume   = NULL,
376	.name     = "nic",
377	.id_table = hinic3_nic_id_table,
378};
379
380static __init int hinic3_nic_lld_init(void)
381{
382	int err;
383
384	err = hinic3_lld_init();
385	if (err)
386		return err;
387
388	err = auxiliary_driver_register(&hinic3_nic_driver);
389	if (err) {
390		hinic3_lld_exit();
391		return err;
392	}
393
394	return 0;
395}
396
397static __exit void hinic3_nic_lld_exit(void)
398{
399	auxiliary_driver_unregister(&hinic3_nic_driver);
400
401	hinic3_lld_exit();
402}
403
404module_init(hinic3_nic_lld_init);
405module_exit(hinic3_nic_lld_exit);
406
407MODULE_AUTHOR("Huawei Technologies CO., Ltd");
408MODULE_DESCRIPTION(HINIC3_NIC_DRV_DESC);
409MODULE_LICENSE("GPL");
~/ Read-only file preview.