FILE
hinic3_lld.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/huawei/hinic3/hinic3_lld.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.