File Index
Files and directories
Sign in
FILE

bnge_core.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/broadcom/bnge/bnge_core.c C
  1// SPDX-License-Identifier: GPL-2.0
  2// Copyright (c) 2025 Broadcom.
  3
  4#include <linux/init.h>
  5#include <linux/crash_dump.h>
  6#include <linux/module.h>
  7#include <linux/pci.h>
  8
  9#include "bnge.h"
 10#include "bnge_devlink.h"
 11#include "bnge_hwrm.h"
 12#include "bnge_hwrm_lib.h"
 13
 14MODULE_LICENSE("GPL");
 15MODULE_DESCRIPTION(DRV_SUMMARY);
 16
 17char bnge_driver_name[] = DRV_NAME;
 18
 19static const struct {
 20	char *name;
 21} board_info[] = {
 22	[BCM57708] = { "Broadcom BCM57708 ThorUltra 50Gb/100Gb/200Gb/400Gb/800Gb Ethernet" },
 23};
 24
 25static const struct pci_device_id bnge_pci_tbl[] = {
 26	{ PCI_VDEVICE(BROADCOM, 0x1780), .driver_data = BCM57708 },
 27	/* Required last entry */
 28	{0, }
 29};
 30MODULE_DEVICE_TABLE(pci, bnge_pci_tbl);
 31
 32static void bnge_print_device_info(struct pci_dev *pdev, enum board_idx idx)
 33{
 34	struct device *dev = &pdev->dev;
 35
 36	dev_info(dev, "%s found at mem %lx\n", board_info[idx].name,
 37		 (long)pci_resource_start(pdev, 0));
 38
 39	pcie_print_link_status(pdev);
 40}
 41
 42bool bnge_aux_registered(struct bnge_dev *bd)
 43{
 44	struct bnge_auxr_dev *ba_dev = bd->auxr_dev;
 45
 46	if (ba_dev && ba_dev->auxr_info->msix_requested)
 47		return true;
 48
 49	return false;
 50}
 51
 52static void bnge_nvm_cfg_ver_get(struct bnge_dev *bd)
 53{
 54	struct hwrm_nvm_get_dev_info_output nvm_info;
 55
 56	if (!bnge_hwrm_nvm_dev_info(bd, &nvm_info))
 57		snprintf(bd->nvm_cfg_ver, FW_VER_STR_LEN, "%d.%d.%d",
 58			 nvm_info.nvm_cfg_ver_maj, nvm_info.nvm_cfg_ver_min,
 59			 nvm_info.nvm_cfg_ver_upd);
 60}
 61
 62static int bnge_func_qcaps(struct bnge_dev *bd)
 63{
 64	int rc;
 65
 66	rc = bnge_hwrm_func_qcaps(bd);
 67	if (rc)
 68		return rc;
 69
 70	rc = bnge_hwrm_queue_qportcfg(bd);
 71	if (rc) {
 72		dev_err(bd->dev, "query qportcfg failure rc: %d\n", rc);
 73		return rc;
 74	}
 75
 76	rc = bnge_hwrm_func_resc_qcaps(bd);
 77	if (rc) {
 78		dev_err(bd->dev, "query resc caps failure rc: %d\n", rc);
 79		return rc;
 80	}
 81
 82	rc = bnge_hwrm_func_qcfg(bd);
 83	if (rc) {
 84		dev_err(bd->dev, "query config failure rc: %d\n", rc);
 85		return rc;
 86	}
 87
 88	rc = bnge_hwrm_vnic_qcaps(bd);
 89	if (rc) {
 90		dev_err(bd->dev, "vnic caps failure rc: %d\n", rc);
 91		return rc;
 92	}
 93
 94	return 0;
 95}
 96
 97static void bnge_fw_unregister_dev(struct bnge_dev *bd)
 98{
 99	/* ctx mem free after unrgtr only */
100	bnge_hwrm_func_drv_unrgtr(bd);
101	bnge_free_ctx_mem(bd);
102}
103
104static void bnge_set_dflt_rss_hash_type(struct bnge_dev *bd)
105{
106	bd->rss_hash_cfg = VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4 |
107			   VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4 |
108			   VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6 |
109			   VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6 |
110			   VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4 |
111			   VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
112}
113
114static int bnge_fw_register_dev(struct bnge_dev *bd)
115{
116	int rc;
117
118	bd->fw_cap = 0;
119	rc = bnge_hwrm_ver_get(bd);
120	if (rc) {
121		dev_err(bd->dev, "Get Version command failed rc: %d\n", rc);
122		return rc;
123	}
124
125	bnge_nvm_cfg_ver_get(bd);
126
127	rc = bnge_hwrm_func_reset(bd);
128	if (rc) {
129		dev_err(bd->dev, "Failed to reset function rc: %d\n", rc);
130		return rc;
131	}
132
133	bnge_hwrm_fw_set_time(bd);
134
135	rc =  bnge_hwrm_func_drv_rgtr(bd);
136	if (rc) {
137		dev_err(bd->dev, "Failed to rgtr with firmware rc: %d\n", rc);
138		return rc;
139	}
140
141	rc = bnge_alloc_ctx_mem(bd);
142	if (rc) {
143		dev_err(bd->dev, "Failed to allocate ctx mem rc: %d\n", rc);
144		goto err_func_unrgtr;
145	}
146
147	/* Get the resources and configuration from firmware */
148	rc = bnge_func_qcaps(bd);
149	if (rc) {
150		dev_err(bd->dev, "Failed initial configuration rc: %d\n", rc);
151		rc = -ENODEV;
152		goto err_func_unrgtr;
153	}
154
155	bnge_set_dflt_rss_hash_type(bd);
156
157	return 0;
158
159err_func_unrgtr:
160	bnge_fw_unregister_dev(bd);
161	return rc;
162}
163
164static void bnge_pci_disable(struct pci_dev *pdev)
165{
166	pci_release_regions(pdev);
167	if (pci_is_enabled(pdev))
168		pci_disable_device(pdev);
169}
170
171static int bnge_pci_enable(struct pci_dev *pdev)
172{
173	int rc;
174
175	rc = pci_enable_device(pdev);
176	if (rc) {
177		dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n");
178		return rc;
179	}
180
181	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
182		dev_err(&pdev->dev,
183			"Cannot find PCI device base address, aborting\n");
184		rc = -ENODEV;
185		goto err_pci_disable;
186	}
187
188	rc = pci_request_regions(pdev, bnge_driver_name);
189	if (rc) {
190		dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n");
191		goto err_pci_disable;
192	}
193
194	dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
195
196	pci_set_master(pdev);
197
198	return 0;
199
200err_pci_disable:
201	pci_disable_device(pdev);
202	return rc;
203}
204
205static void bnge_unmap_bars(struct pci_dev *pdev)
206{
207	struct bnge_dev *bd = pci_get_drvdata(pdev);
208
209	if (bd->bar1) {
210		pci_iounmap(pdev, bd->bar1);
211		bd->bar1 = NULL;
212	}
213
214	if (bd->bar0) {
215		pci_iounmap(pdev, bd->bar0);
216		bd->bar0 = NULL;
217	}
218}
219
220static void bnge_set_max_func_irqs(struct bnge_dev *bd,
221				   unsigned int max_irqs)
222{
223	bd->hw_resc.max_irqs = max_irqs;
224}
225
226static int bnge_get_max_irq(struct pci_dev *pdev)
227{
228	u16 ctrl;
229
230	pci_read_config_word(pdev, pdev->msix_cap + PCI_MSIX_FLAGS, &ctrl);
231	return (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1;
232}
233
234static int bnge_map_db_bar(struct bnge_dev *bd)
235{
236	if (!bd->db_size)
237		return -ENODEV;
238
239	bd->bar1 = pci_iomap(bd->pdev, 2, bd->db_size);
240	if (!bd->bar1)
241		return -ENOMEM;
242
243	return 0;
244}
245
246static int bnge_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
247{
248	unsigned int max_irqs;
249	struct bnge_dev *bd;
250	int rc;
251
252	if (pci_is_bridge(pdev))
253		return -ENODEV;
254
255	if (!pdev->msix_cap) {
256		dev_err(&pdev->dev, "MSIX capability missing, aborting\n");
257		return -ENODEV;
258	}
259
260	if (is_kdump_kernel()) {
261		pci_clear_master(pdev);
262		pcie_flr(pdev);
263	}
264
265	rc = bnge_pci_enable(pdev);
266	if (rc)
267		return rc;
268
269	bnge_print_device_info(pdev, ent->driver_data);
270
271	bd = bnge_devlink_alloc(pdev);
272	if (!bd) {
273		dev_err(&pdev->dev, "Devlink allocation failed\n");
274		rc = -ENOMEM;
275		goto err_pci_disable;
276	}
277
278	bd->bar0 = pci_ioremap_bar(pdev, 0);
279	if (!bd->bar0) {
280		dev_err(&pdev->dev, "Failed mapping BAR-0, aborting\n");
281		rc = -ENOMEM;
282		goto err_devl_free;
283	}
284
285	rc = bnge_init_hwrm_resources(bd);
286	if (rc)
287		goto err_bar_unmap;
288
289	rc = bnge_fw_register_dev(bd);
290	if (rc) {
291		dev_err(&pdev->dev, "Failed to register with firmware rc = %d\n", rc);
292		goto err_hwrm_cleanup;
293	}
294
295	bnge_devlink_register(bd);
296
297	max_irqs = bnge_get_max_irq(pdev);
298	bnge_set_max_func_irqs(bd, max_irqs);
299
300	bnge_aux_init_dflt_config(bd);
301
302	rc = bnge_net_init_dflt_config(bd);
303	if (rc) {
304		dev_err(&pdev->dev, "Error setting up default cfg to netdev rc = %d\n",
305			rc);
306		goto err_fw_reg;
307	}
308
309	rc = bnge_map_db_bar(bd);
310	if (rc) {
311		dev_err(&pdev->dev, "Failed mapping doorbell BAR rc = %d, aborting\n",
312			rc);
313		goto err_config_uninit;
314	}
315
316#if BITS_PER_LONG == 32
317	spin_lock_init(&bd->db_lock);
318#endif
319
320	bnge_rdma_aux_device_init(bd);
321
322	rc = bnge_alloc_irqs(bd);
323	if (rc) {
324		dev_err(&pdev->dev, "Error IRQ allocation rc = %d\n", rc);
325		goto err_uninit_auxr;
326	}
327
328	rc = bnge_netdev_alloc(bd, max_irqs);
329	if (rc)
330		goto err_free_irq;
331
332	bnge_rdma_aux_device_add(bd);
333
334	pci_save_state(pdev);
335
336	return 0;
337
338err_free_irq:
339	bnge_free_irqs(bd);
340
341err_uninit_auxr:
342	bnge_rdma_aux_device_uninit(bd);
343
344err_config_uninit:
345	bnge_net_uninit_dflt_config(bd);
346
347err_fw_reg:
348	bnge_devlink_unregister(bd);
349	bnge_fw_unregister_dev(bd);
350
351err_hwrm_cleanup:
352	bnge_cleanup_hwrm_resources(bd);
353
354err_bar_unmap:
355	bnge_unmap_bars(pdev);
356
357err_devl_free:
358	bnge_devlink_free(bd);
359
360err_pci_disable:
361	bnge_pci_disable(pdev);
362	return rc;
363}
364
365static void bnge_remove_one(struct pci_dev *pdev)
366{
367	struct bnge_dev *bd = pci_get_drvdata(pdev);
368
369	bnge_rdma_aux_device_del(bd);
370
371	bnge_netdev_free(bd);
372
373	bnge_free_irqs(bd);
374
375	bnge_rdma_aux_device_uninit(bd);
376
377	bnge_net_uninit_dflt_config(bd);
378
379	bnge_devlink_unregister(bd);
380
381	bnge_fw_unregister_dev(bd);
382
383	bnge_cleanup_hwrm_resources(bd);
384
385	bnge_unmap_bars(pdev);
386
387	bnge_devlink_free(bd);
388
389	bnge_pci_disable(pdev);
390}
391
392static void bnge_shutdown(struct pci_dev *pdev)
393{
394	pci_disable_device(pdev);
395
396	if (system_state == SYSTEM_POWER_OFF) {
397		pci_wake_from_d3(pdev, 0);
398		pci_set_power_state(pdev, PCI_D3hot);
399	}
400}
401
402static struct pci_driver bnge_driver = {
403	.name		= bnge_driver_name,
404	.id_table	= bnge_pci_tbl,
405	.probe		= bnge_probe_one,
406	.remove		= bnge_remove_one,
407	.shutdown	= bnge_shutdown,
408};
409
410static int __init bnge_init_module(void)
411{
412	return pci_register_driver(&bnge_driver);
413}
414module_init(bnge_init_module);
415
416static void __exit bnge_exit_module(void)
417{
418	pci_unregister_driver(&bnge_driver);
419}
420module_exit(bnge_exit_module);
~/ Read-only file preview.