File Index
Files and directories
Sign in
FILE

hinic3_lld.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/huawei/hinic3/hinic3_lld.c C
  1// SPDX-License-Identifier: GPL-2.0
  2// Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
  3
  4#include <linux/delay.h>
  5#include <linux/iopoll.h>
  6
  7#include "hinic3_hw_cfg.h"
  8#include "hinic3_hwdev.h"
  9#include "hinic3_lld.h"
 10#include "hinic3_mgmt.h"
 11#include "hinic3_pci_id_tbl.h"
 12
 13#define HINIC3_VF_PCI_CFG_REG_BAR  0
 14#define HINIC3_PCI_INTR_REG_BAR    2
 15#define HINIC3_PCI_DB_BAR          4
 16
 17#define HINIC3_EVENT_POLL_SLEEP_US   1000
 18#define HINIC3_EVENT_POLL_TIMEOUT_US 10000000
 19
 20static struct hinic3_adev_device {
 21	const char *name;
 22} hinic3_adev_devices[HINIC3_SERVICE_T_MAX] = {
 23	[HINIC3_SERVICE_T_NIC] = {
 24		.name = "nic",
 25	},
 26};
 27
 28static bool hinic3_adev_svc_supported(struct hinic3_hwdev *hwdev,
 29				      enum hinic3_service_type svc_type)
 30{
 31	switch (svc_type) {
 32	case HINIC3_SERVICE_T_NIC:
 33		return hinic3_support_nic(hwdev);
 34	default:
 35		break;
 36	}
 37
 38	return false;
 39}
 40
 41static void hinic3_comm_adev_release(struct device *dev)
 42{
 43	struct hinic3_adev *hadev = container_of(dev, struct hinic3_adev,
 44						 adev.dev);
 45
 46	kfree(hadev);
 47}
 48
 49static struct hinic3_adev *hinic3_add_one_adev(struct hinic3_hwdev *hwdev,
 50					       enum hinic3_service_type svc_type)
 51{
 52	struct hinic3_adev *hadev;
 53	const char *svc_name;
 54	int ret;
 55
 56	hadev = kzalloc(sizeof(*hadev), GFP_KERNEL);
 57	if (!hadev)
 58		return NULL;
 59
 60	svc_name = hinic3_adev_devices[svc_type].name;
 61	hadev->adev.name = svc_name;
 62	hadev->adev.id = hwdev->dev_id;
 63	hadev->adev.dev.parent = hwdev->dev;
 64	hadev->adev.dev.release = hinic3_comm_adev_release;
 65	hadev->svc_type = svc_type;
 66	hadev->hwdev = hwdev;
 67
 68	ret = auxiliary_device_init(&hadev->adev);
 69	if (ret) {
 70		dev_err(hwdev->dev, "failed init adev %s %u\n",
 71			svc_name, hwdev->dev_id);
 72		kfree(hadev);
 73		return NULL;
 74	}
 75
 76	ret = auxiliary_device_add(&hadev->adev);
 77	if (ret) {
 78		dev_err(hwdev->dev, "failed to add adev %s %u\n",
 79			svc_name, hwdev->dev_id);
 80		auxiliary_device_uninit(&hadev->adev);
 81		return NULL;
 82	}
 83
 84	return hadev;
 85}
 86
 87static void hinic3_del_one_adev(struct hinic3_hwdev *hwdev,
 88				enum hinic3_service_type svc_type)
 89{
 90	struct hinic3_pcidev *pci_adapter = hwdev->adapter;
 91	struct hinic3_adev *hadev;
 92	int timeout;
 93	bool state;
 94
 95	timeout = read_poll_timeout(test_and_set_bit, state, !state,
 96				    HINIC3_EVENT_POLL_SLEEP_US,
 97				    HINIC3_EVENT_POLL_TIMEOUT_US,
 98				    false, svc_type, &pci_adapter->state);
 99
100	hadev = pci_adapter->hadev[svc_type];
101	auxiliary_device_delete(&hadev->adev);
102	auxiliary_device_uninit(&hadev->adev);
103	pci_adapter->hadev[svc_type] = NULL;
104	if (!timeout)
105		clear_bit(svc_type, &pci_adapter->state);
106}
107
108static int hinic3_attach_aux_devices(struct hinic3_hwdev *hwdev)
109{
110	struct hinic3_pcidev *pci_adapter = hwdev->adapter;
111	enum hinic3_service_type svc_type;
112
113	mutex_lock(&pci_adapter->pdev_mutex);
114
115	for (svc_type = 0; svc_type < HINIC3_SERVICE_T_MAX; svc_type++) {
116		if (!hinic3_adev_svc_supported(hwdev, svc_type))
117			continue;
118
119		pci_adapter->hadev[svc_type] = hinic3_add_one_adev(hwdev,
120								   svc_type);
121		if (!pci_adapter->hadev[svc_type])
122			goto err_del_adevs;
123	}
124	mutex_unlock(&pci_adapter->pdev_mutex);
125
126	return 0;
127
128err_del_adevs:
129	while (svc_type > 0) {
130		svc_type--;
131		if (pci_adapter->hadev[svc_type]) {
132			hinic3_del_one_adev(hwdev, svc_type);
133			pci_adapter->hadev[svc_type] = NULL;
134		}
135	}
136	mutex_unlock(&pci_adapter->pdev_mutex);
137
138	return -ENOMEM;
139}
140
141static void hinic3_detach_aux_devices(struct hinic3_hwdev *hwdev)
142{
143	struct hinic3_pcidev *pci_adapter = hwdev->adapter;
144	int i;
145
146	mutex_lock(&pci_adapter->pdev_mutex);
147	for (i = 0; i < ARRAY_SIZE(hinic3_adev_devices); i++) {
148		if (pci_adapter->hadev[i])
149			hinic3_del_one_adev(hwdev, i);
150	}
151	mutex_unlock(&pci_adapter->pdev_mutex);
152}
153
154struct hinic3_hwdev *hinic3_adev_get_hwdev(struct auxiliary_device *adev)
155{
156	struct hinic3_adev *hadev;
157
158	hadev = container_of(adev, struct hinic3_adev, adev);
159
160	return hadev->hwdev;
161}
162
163void hinic3_adev_event_register(struct auxiliary_device *adev,
164				void (*event_handler)(struct auxiliary_device *adev,
165						      struct hinic3_event_info *event))
166{
167	struct hinic3_adev *hadev;
168
169	hadev = container_of(adev, struct hinic3_adev, adev);
170	hadev->event = event_handler;
171}
172
173void hinic3_adev_event_unregister(struct auxiliary_device *adev)
174{
175	struct hinic3_adev *hadev;
176
177	hadev = container_of(adev, struct hinic3_adev, adev);
178	hadev->event = NULL;
179}
180
181static int hinic3_mapping_bar(struct pci_dev *pdev,
182			      struct hinic3_pcidev *pci_adapter)
183{
184	pci_adapter->cfg_reg_base = pci_ioremap_bar(pdev,
185						    HINIC3_VF_PCI_CFG_REG_BAR);
186	if (!pci_adapter->cfg_reg_base) {
187		dev_err(&pdev->dev, "Failed to map configuration regs\n");
188		return -ENOMEM;
189	}
190
191	pci_adapter->intr_reg_base = pci_ioremap_bar(pdev,
192						     HINIC3_PCI_INTR_REG_BAR);
193	if (!pci_adapter->intr_reg_base) {
194		dev_err(&pdev->dev, "Failed to map interrupt regs\n");
195		goto err_unmap_cfg_reg_base;
196	}
197
198	pci_adapter->db_base_phy = pci_resource_start(pdev, HINIC3_PCI_DB_BAR);
199	pci_adapter->db_dwqe_len = pci_resource_len(pdev, HINIC3_PCI_DB_BAR);
200	pci_adapter->db_base = pci_ioremap_bar(pdev, HINIC3_PCI_DB_BAR);
201	if (!pci_adapter->db_base) {
202		dev_err(&pdev->dev, "Failed to map doorbell regs\n");
203		goto err_unmap_intr_reg_base;
204	}
205
206	return 0;
207
208err_unmap_intr_reg_base:
209	iounmap(pci_adapter->intr_reg_base);
210
211err_unmap_cfg_reg_base:
212	iounmap(pci_adapter->cfg_reg_base);
213
214	return -ENOMEM;
215}
216
217static void hinic3_unmapping_bar(struct hinic3_pcidev *pci_adapter)
218{
219	iounmap(pci_adapter->db_base);
220	iounmap(pci_adapter->intr_reg_base);
221	iounmap(pci_adapter->cfg_reg_base);
222}
223
224static int hinic3_pci_init(struct pci_dev *pdev)
225{
226	struct hinic3_pcidev *pci_adapter;
227	int err;
228
229	pci_adapter = kzalloc(sizeof(*pci_adapter), GFP_KERNEL);
230	if (!pci_adapter)
231		return -ENOMEM;
232
233	pci_adapter->pdev = pdev;
234	mutex_init(&pci_adapter->pdev_mutex);
235
236	pci_set_drvdata(pdev, pci_adapter);
237
238	err = pci_enable_device(pdev);
239	if (err) {
240		dev_err(&pdev->dev, "Failed to enable PCI device\n");
241		goto err_free_pci_adapter;
242	}
243
244	err = pci_request_regions(pdev, HINIC3_NIC_DRV_NAME);
245	if (err) {
246		dev_err(&pdev->dev, "Failed to request regions\n");
247		goto err_disable_device;
248	}
249
250	pci_set_master(pdev);
251
252	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
253	if (err) {
254		dev_err(&pdev->dev, "Failed to set DMA mask\n");
255		goto err_release_regions;
256	}
257
258	return 0;
259
260err_release_regions:
261	pci_clear_master(pdev);
262	pci_release_regions(pdev);
263
264err_disable_device:
265	pci_disable_device(pdev);
266
267err_free_pci_adapter:
268	pci_set_drvdata(pdev, NULL);
269	mutex_destroy(&pci_adapter->pdev_mutex);
270	kfree(pci_adapter);
271
272	return err;
273}
274
275static void hinic3_pci_uninit(struct pci_dev *pdev)
276{
277	struct hinic3_pcidev *pci_adapter = pci_get_drvdata(pdev);
278
279	pci_clear_master(pdev);
280	pci_release_regions(pdev);
281	pci_disable_device(pdev);
282	pci_set_drvdata(pdev, NULL);
283	mutex_destroy(&pci_adapter->pdev_mutex);
284	kfree(pci_adapter);
285}
286
287static int hinic3_func_init(struct pci_dev *pdev,
288			    struct hinic3_pcidev *pci_adapter)
289{
290	int err;
291
292	err = hinic3_init_hwdev(pdev);
293	if (err) {
294		dev_err(&pdev->dev, "Failed to initialize hardware device\n");
295		return err;
296	}
297
298	err = hinic3_attach_aux_devices(pci_adapter->hwdev);
299	if (err)
300		goto err_free_hwdev;
301
302	return 0;
303
304err_free_hwdev:
305	hinic3_free_hwdev(pci_adapter->hwdev);
306
307	return err;
308}
309
310static void hinic3_func_uninit(struct pci_dev *pdev)
311{
312	struct hinic3_pcidev *pci_adapter = pci_get_drvdata(pdev);
313
314	hinic3_flush_mgmt_workq(pci_adapter->hwdev);
315	hinic3_detach_aux_devices(pci_adapter->hwdev);
316	hinic3_free_hwdev(pci_adapter->hwdev);
317}
318
319static int hinic3_probe_func(struct hinic3_pcidev *pci_adapter)
320{
321	struct pci_dev *pdev = pci_adapter->pdev;
322	int err;
323
324	err = hinic3_mapping_bar(pdev, pci_adapter);
325	if (err) {
326		dev_err(&pdev->dev, "Failed to map bar\n");
327		goto err_out;
328	}
329
330	err = hinic3_func_init(pdev, pci_adapter);
331	if (err)
332		goto err_unmap_bar;
333
334	return 0;
335
336err_unmap_bar:
337	hinic3_unmapping_bar(pci_adapter);
338
339err_out:
340	dev_err(&pdev->dev, "PCIe device probe function failed\n");
341
342	return err;
343}
344
345static void hinic3_remove_func(struct hinic3_pcidev *pci_adapter)
346{
347	struct pci_dev *pdev = pci_adapter->pdev;
348
349	hinic3_func_uninit(pdev);
350	hinic3_unmapping_bar(pci_adapter);
351}
352
353static int hinic3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
354{
355	struct hinic3_pcidev *pci_adapter;
356	int err;
357
358	err = hinic3_pci_init(pdev);
359	if (err)
360		goto err_out;
361
362	pci_adapter = pci_get_drvdata(pdev);
363	err = hinic3_probe_func(pci_adapter);
364	if (err)
365		goto err_uninit_pci;
366
367	return 0;
368
369err_uninit_pci:
370	hinic3_pci_uninit(pdev);
371
372err_out:
373	dev_err(&pdev->dev, "PCIe device probe failed\n");
374
375	return err;
376}
377
378static void hinic3_remove(struct pci_dev *pdev)
379{
380	struct hinic3_pcidev *pci_adapter = pci_get_drvdata(pdev);
381
382	hinic3_remove_func(pci_adapter);
383	hinic3_pci_uninit(pdev);
384}
385
386static const struct pci_device_id hinic3_pci_table[] = {
387	{PCI_VDEVICE(HUAWEI, PCI_DEV_ID_HINIC3_VF), 0},
388	{0, 0}
389
390};
391
392MODULE_DEVICE_TABLE(pci, hinic3_pci_table);
393
394static void hinic3_shutdown(struct pci_dev *pdev)
395{
396	struct hinic3_pcidev *pci_adapter = pci_get_drvdata(pdev);
397
398	pci_disable_device(pdev);
399
400	if (pci_adapter)
401		hinic3_set_api_stop(pci_adapter->hwdev);
402}
403
404static struct pci_driver hinic3_driver = {
405	.name            = HINIC3_NIC_DRV_NAME,
406	.id_table        = hinic3_pci_table,
407	.probe           = hinic3_probe,
408	.remove          = hinic3_remove,
409	.shutdown        = hinic3_shutdown,
410	.sriov_configure = pci_sriov_configure_simple
411};
412
413int hinic3_lld_init(void)
414{
415	return pci_register_driver(&hinic3_driver);
416}
417
418void hinic3_lld_exit(void)
419{
420	pci_unregister_driver(&hinic3_driver);
421}
~/ Read-only file preview.