FILE
core.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/amd/pds_core/core.c
1// SPDX-License-Identifier: GPL-2.0 2/* Copyright(c) 2023 Advanced Micro Devices, Inc */ 3 4#include <linux/pci.h> 5#include <linux/vmalloc.h> 6 7#include "core.h" 8 9static BLOCKING_NOTIFIER_HEAD(pds_notify_chain); 10 11int pdsc_register_notify(struct notifier_block *nb) 12{ 13 return blocking_notifier_chain_register(&pds_notify_chain, nb); 14} 15EXPORT_SYMBOL_GPL(pdsc_register_notify); 16 17void pdsc_unregister_notify(struct notifier_block *nb) 18{ 19 blocking_notifier_chain_unregister(&pds_notify_chain, nb); 20} 21EXPORT_SYMBOL_GPL(pdsc_unregister_notify); 22 23void pdsc_notify(unsigned long event, void *data) 24{ 25 blocking_notifier_call_chain(&pds_notify_chain, event, data); 26} 27 28void pdsc_intr_free(struct pdsc *pdsc, int index) 29{ 30 struct pdsc_intr_info *intr_info; 31 32 if (index >= pdsc->nintrs || index < 0) { 33 WARN(true, "bad intr index %d\n", index); 34 return; 35 } 36 37 intr_info = &pdsc->intr_info[index]; 38 if (!intr_info->vector) 39 return; 40 dev_dbg(pdsc->dev, "%s: idx %d vec %d name %s\n", 41 __func__, index, intr_info->vector, intr_info->name); 42 43 pds_core_intr_mask(&pdsc->intr_ctrl[index], PDS_CORE_INTR_MASK_SET); 44 pds_core_intr_clean(&pdsc->intr_ctrl[index]); 45 46 free_irq(intr_info->vector, intr_info->data); 47 48 memset(intr_info, 0, sizeof(*intr_info)); 49} 50 51int pdsc_intr_alloc(struct pdsc *pdsc, char *name, 52 irq_handler_t handler, void *data) 53{ 54 struct pdsc_intr_info *intr_info; 55 unsigned int index; 56 int err; 57 58 /* Find the first available interrupt */ 59 for (index = 0; index < pdsc->nintrs; index++) 60 if (!pdsc->intr_info[index].vector) 61 break; 62 if (index >= pdsc->nintrs) { 63 dev_warn(pdsc->dev, "%s: no intr, index=%d nintrs=%d\n", 64 __func__, index, pdsc->nintrs); 65 return -ENOSPC; 66 } 67 68 pds_core_intr_clean_flags(&pdsc->intr_ctrl[index], 69 PDS_CORE_INTR_CRED_RESET_COALESCE); 70 71 intr_info = &pdsc->intr_info[index]; 72 73 intr_info->index = index; 74 intr_info->data = data; 75 strscpy(intr_info->name, name, sizeof(intr_info->name)); 76 77 /* Get the OS vector number for the interrupt */ 78 err = pci_irq_vector(pdsc->pdev, index); 79 if (err < 0) { 80 dev_err(pdsc->dev, "failed to get intr vector index %d: %pe\n", 81 index, ERR_PTR(err)); 82 goto err_out_free_intr; 83 } 84 intr_info->vector = err; 85 86 /* Init the device's intr mask */ 87 pds_core_intr_clean(&pdsc->intr_ctrl[index]); 88 pds_core_intr_mask_assert(&pdsc->intr_ctrl[index], 1); 89 pds_core_intr_mask(&pdsc->intr_ctrl[index], PDS_CORE_INTR_MASK_SET); 90 91 /* Register the isr with a name */ 92 err = request_irq(intr_info->vector, handler, 0, intr_info->name, data); 93 if (err) { 94 dev_err(pdsc->dev, "failed to get intr irq vector %d: %pe\n", 95 intr_info->vector, ERR_PTR(err)); 96 goto err_out_free_intr; 97 } 98 99 return index; 100 101err_out_free_intr: 102 pdsc_intr_free(pdsc, index); 103 return err; 104} 105 106static void pdsc_qcq_intr_free(struct pdsc *pdsc, struct pdsc_qcq *qcq) 107{ 108 if (!(qcq->flags & PDS_CORE_QCQ_F_INTR) || 109 qcq->intx == PDS_CORE_INTR_INDEX_NOT_ASSIGNED) 110 return; 111 112 pdsc_intr_free(pdsc, qcq->intx); 113 qcq->intx = PDS_CORE_INTR_INDEX_NOT_ASSIGNED; 114} 115 116static int pdsc_qcq_intr_alloc(struct pdsc *pdsc, struct pdsc_qcq *qcq) 117{ 118 char name[PDSC_INTR_NAME_MAX_SZ]; 119 int index; 120 121 if (!(qcq->flags & PDS_CORE_QCQ_F_INTR)) { 122 qcq->intx = PDS_CORE_INTR_INDEX_NOT_ASSIGNED; 123 return 0; 124 } 125 126 snprintf(name, sizeof(name), "%s-%d-%s", 127 PDS_CORE_DRV_NAME, pdsc->pdev->bus->number, qcq->q.name); 128 index = pdsc_intr_alloc(pdsc, name, pdsc_adminq_isr, pdsc); 129 if (index < 0) 130 return index; 131 qcq->intx = index; 132 qcq->cq.bound_intr = &pdsc->intr_info[index]; 133 134 return 0; 135} 136 137void pdsc_qcq_free(struct pdsc *pdsc, struct pdsc_qcq *qcq) 138{ 139 struct device *dev = pdsc->dev; 140 141 if (!(qcq && qcq->pdsc)) 142 return; 143 144 pdsc_debugfs_del_qcq(qcq); 145 146 pdsc_qcq_intr_free(pdsc, qcq); 147 148 if (qcq->q_base) 149 dma_free_coherent(dev, qcq->q_size, 150 qcq->q_base, qcq->q_base_pa); 151 152 if (qcq->cq_base) 153 dma_free_coherent(dev, qcq->cq_size, 154 qcq->cq_base, qcq->cq_base_pa); 155 156 vfree(qcq->cq.info); 157 vfree(qcq->q.info); 158 159 memset(qcq, 0, sizeof(*qcq)); 160} 161 162static void pdsc_q_map(struct pdsc_queue *q, void *base, dma_addr_t base_pa) 163{ 164 struct pdsc_q_info *cur; 165 unsigned int i; 166 167 q->base = base; 168 q->base_pa = base_pa; 169 170 for (i = 0, cur = q->info; i < q->num_descs; i++, cur++) { 171 cur->desc = base + (i * q->desc_size); 172 init_completion(&cur->completion); 173 } 174} 175 176static void pdsc_cq_map(struct pdsc_cq *cq, void *base, dma_addr_t base_pa) 177{ 178 struct pdsc_cq_info *cur; 179 unsigned int i; 180 181 cq->base = base; 182 cq->base_pa = base_pa; 183 184 for (i = 0, cur = cq->info; i < cq->num_descs; i++, cur++) 185 cur->comp = base + (i * cq->desc_size); 186} 187 188int pdsc_qcq_alloc(struct pdsc *pdsc, unsigned int type, unsigned int index, 189 const char *name, unsigned int flags, unsigned int num_descs, 190 unsigned int desc_size, unsigned int cq_desc_size, 191 unsigned int pid, struct pdsc_qcq *qcq) 192{ 193 struct device *dev = pdsc->dev; 194 void *q_base, *cq_base; 195 dma_addr_t cq_base_pa; 196 dma_addr_t q_base_pa; 197 int err; 198 199 qcq->q.info = vcalloc(num_descs, sizeof(*qcq->q.info)); 200 if (!qcq->q.info) { 201 err = -ENOMEM; 202 goto err_out; 203 } 204 205 qcq->pdsc = pdsc; 206 qcq->flags = flags; 207 INIT_WORK(&qcq->work, pdsc_work_thread); 208 209 qcq->q.type = type; 210 qcq->q.index = index; 211 qcq->q.num_descs = num_descs; 212 qcq->q.desc_size = desc_size; 213 qcq->q.tail_idx = 0; 214 qcq->q.head_idx = 0; 215 qcq->q.pid = pid; 216 snprintf(qcq->q.name, sizeof(qcq->q.name), "%s%u", name, index); 217 218 err = pdsc_qcq_intr_alloc(pdsc, qcq); 219 if (err) 220 goto err_out_free_q_info; 221 222 qcq->cq.info = vcalloc(num_descs, sizeof(*qcq->cq.info)); 223 if (!qcq->cq.info) { 224 err = -ENOMEM; 225 goto err_out_free_irq; 226 } 227 228 qcq->cq.num_descs = num_descs; 229 qcq->cq.desc_size = cq_desc_size; 230 qcq->cq.tail_idx = 0; 231 qcq->cq.done_color = 1; 232 233 if (flags & PDS_CORE_QCQ_F_NOTIFYQ) { 234 /* q & cq need to be contiguous in case of notifyq */ 235 qcq->q_size = PDS_PAGE_SIZE + 236 ALIGN(num_descs * desc_size, PDS_PAGE_SIZE) + 237 ALIGN(num_descs * cq_desc_size, PDS_PAGE_SIZE); 238 qcq->q_base = dma_alloc_coherent(dev, 239 qcq->q_size + qcq->cq_size, 240 &qcq->q_base_pa, 241 GFP_KERNEL); 242 if (!qcq->q_base) { 243 err = -ENOMEM; 244 goto err_out_free_cq_info; 245 } 246 q_base = PTR_ALIGN(qcq->q_base, PDS_PAGE_SIZE); 247 q_base_pa = ALIGN(qcq->q_base_pa, PDS_PAGE_SIZE); 248 pdsc_q_map(&qcq->q, q_base, q_base_pa); 249 250 cq_base = PTR_ALIGN(q_base + 251 ALIGN(num_descs * desc_size, PDS_PAGE_SIZE), 252 PDS_PAGE_SIZE); 253 cq_base_pa = ALIGN(qcq->q_base_pa + 254 ALIGN(num_descs * desc_size, PDS_PAGE_SIZE), 255 PDS_PAGE_SIZE); 256 257 } else { 258 /* q DMA descriptors */ 259 qcq->q_size = PDS_PAGE_SIZE + (num_descs * desc_size); 260 qcq->q_base = dma_alloc_coherent(dev, qcq->q_size, 261 &qcq->q_base_pa, 262 GFP_KERNEL); 263 if (!qcq->q_base) { 264 err = -ENOMEM; 265 goto err_out_free_cq_info; 266 } 267 q_base = PTR_ALIGN(qcq->q_base, PDS_PAGE_SIZE); 268 q_base_pa = ALIGN(qcq->q_base_pa, PDS_PAGE_SIZE); 269 pdsc_q_map(&qcq->q, q_base, q_base_pa); 270 271 /* cq DMA descriptors */ 272 qcq->cq_size = PDS_PAGE_SIZE + (num_descs * cq_desc_size); 273 qcq->cq_base = dma_alloc_coherent(dev, qcq->cq_size, 274 &qcq->cq_base_pa, 275 GFP_KERNEL); 276 if (!qcq->cq_base) { 277 err = -ENOMEM; 278 goto err_out_free_q; 279 } 280 cq_base = PTR_ALIGN(qcq->cq_base, PDS_PAGE_SIZE); 281 cq_base_pa = ALIGN(qcq->cq_base_pa, PDS_PAGE_SIZE); 282 } 283 284 pdsc_cq_map(&qcq->cq, cq_base, cq_base_pa); 285 qcq->cq.bound_q = &qcq->q; 286 287 pdsc_debugfs_add_qcq(pdsc, qcq); 288 289 return 0; 290 291err_out_free_q: 292 dma_free_coherent(dev, qcq->q_size, qcq->q_base, qcq->q_base_pa); 293err_out_free_cq_info: 294 vfree(qcq->cq.info); 295err_out_free_irq: 296 pdsc_qcq_intr_free(pdsc, qcq); 297err_out_free_q_info: 298 vfree(qcq->q.info); 299 memset(qcq, 0, sizeof(*qcq)); 300err_out: 301 dev_err(dev, "qcq alloc of %s%d failed %d\n", name, index, err); 302 return err; 303} 304 305static void pdsc_core_uninit(struct pdsc *pdsc) 306{ 307 pdsc_qcq_free(pdsc, &pdsc->notifyqcq); 308 pdsc_qcq_free(pdsc, &pdsc->adminqcq); 309 310 if (pdsc->kern_dbpage) { 311 iounmap(pdsc->kern_dbpage); 312 pdsc->kern_dbpage = NULL; 313 } 314} 315 316static int pdsc_core_init(struct pdsc *pdsc) 317{ 318 union pds_core_dev_comp comp = {}; 319 union pds_core_dev_cmd cmd = { 320 .init.opcode = PDS_CORE_CMD_INIT, 321 }; 322 struct pds_core_dev_init_data_out cido; 323 struct pds_core_dev_init_data_in cidi; 324 u32 dbid_count; 325 u32 dbpage_num; 326 int numdescs; 327 size_t sz; 328 int err; 329 330 numdescs = PDSC_ADMINQ_MAX_LENGTH; 331 err = pdsc_qcq_alloc(pdsc, PDS_CORE_QTYPE_ADMINQ, 0, "adminq", 332 PDS_CORE_QCQ_F_CORE | PDS_CORE_QCQ_F_INTR, 333 numdescs, 334 sizeof(union pds_core_adminq_cmd), 335 sizeof(union pds_core_adminq_comp), 336 0, &pdsc->adminqcq); 337 if (err) 338 return err; 339 340 err = pdsc_qcq_alloc(pdsc, PDS_CORE_QTYPE_NOTIFYQ, 0, "notifyq", 341 PDS_CORE_QCQ_F_NOTIFYQ, 342 PDSC_NOTIFYQ_LENGTH, 343 sizeof(struct pds_core_notifyq_cmd), 344 sizeof(union pds_core_notifyq_comp), 345 0, &pdsc->notifyqcq); 346 if (err) 347 goto err_out_uninit; 348 349 cidi.adminq_q_base = cpu_to_le64(pdsc->adminqcq.q_base_pa); 350 cidi.adminq_cq_base = cpu_to_le64(pdsc->adminqcq.cq_base_pa); 351 cidi.notifyq_cq_base = cpu_to_le64(pdsc->notifyqcq.cq.base_pa); 352 cidi.flags = cpu_to_le32(PDS_CORE_QINIT_F_IRQ | PDS_CORE_QINIT_F_ENA); 353 cidi.intr_index = cpu_to_le16(pdsc->adminqcq.intx); 354 cidi.adminq_ring_size = ilog2(pdsc->adminqcq.q.num_descs); 355 cidi.notifyq_ring_size = ilog2(pdsc->notifyqcq.q.num_descs); 356 357 mutex_lock(&pdsc->devcmd_lock); 358 359 sz = min_t(size_t, sizeof(cidi), sizeof(pdsc->cmd_regs->data)); 360 memcpy_toio(&pdsc->cmd_regs->data, &cidi, sz); 361 362 err = pdsc_devcmd_locked(pdsc, &cmd, &comp, pdsc->devcmd_timeout); 363 if (!err) { 364 sz = min_t(size_t, sizeof(cido), sizeof(pdsc->cmd_regs->data)); 365 memcpy_fromio(&cido, &pdsc->cmd_regs->data, sz); 366 } 367 368 mutex_unlock(&pdsc->devcmd_lock); 369 if (err) { 370 dev_err(pdsc->dev, "Device init command failed: %pe\n", 371 ERR_PTR(err)); 372 goto err_out_uninit; 373 } 374 375 pdsc->hw_index = le32_to_cpu(cido.core_hw_index); 376 377 dbid_count = le32_to_cpu(pdsc->dev_ident.ndbpgs_per_lif); 378 dbpage_num = pdsc->hw_index * dbid_count; 379 pdsc->kern_dbpage = pdsc_map_dbpage(pdsc, dbpage_num); 380 if (!pdsc->kern_dbpage) { 381 dev_err(pdsc->dev, "Cannot map dbpage, aborting\n"); 382 err = -ENOMEM; 383 goto err_out_uninit; 384 } 385 386 pdsc->adminqcq.q.hw_type = cido.adminq_hw_type; 387 pdsc->adminqcq.q.hw_index = le32_to_cpu(cido.adminq_hw_index); 388 pdsc->adminqcq.q.dbval = PDS_CORE_DBELL_QID(pdsc->adminqcq.q.hw_index); 389 390 pdsc->notifyqcq.q.hw_type = cido.notifyq_hw_type; 391 pdsc->notifyqcq.q.hw_index = le32_to_cpu(cido.notifyq_hw_index); 392 pdsc->notifyqcq.q.dbval = PDS_CORE_DBELL_QID(pdsc->notifyqcq.q.hw_index); 393 394 pdsc->last_eid = 0; 395 396 return 0; 397 398err_out_uninit: 399 pdsc_core_uninit(pdsc); 400 return err; 401} 402 403static struct pdsc_viftype pdsc_viftype_defaults[] = { 404 [PDS_DEV_TYPE_FWCTL] = { .name = PDS_DEV_TYPE_FWCTL_STR, 405 .enabled = true, 406 .vif_id = PDS_DEV_TYPE_FWCTL, 407 .dl_id = -1 }, 408 [PDS_DEV_TYPE_VDPA] = { .name = PDS_DEV_TYPE_VDPA_STR, 409 .vif_id = PDS_DEV_TYPE_VDPA, 410 .dl_id = DEVLINK_PARAM_GENERIC_ID_ENABLE_VNET }, 411 [PDS_DEV_TYPE_MAX] = {} 412}; 413 414static int pdsc_viftypes_init(struct pdsc *pdsc) 415{ 416 enum pds_core_vif_types vt; 417 418 pdsc->viftype_status = kcalloc(ARRAY_SIZE(pdsc_viftype_defaults), 419 sizeof(*pdsc->viftype_status), 420 GFP_KERNEL); 421 if (!pdsc->viftype_status) 422 return -ENOMEM; 423 424 for (vt = 0; vt < PDS_DEV_TYPE_MAX; vt++) { 425 bool vt_support; 426 427 if (!pdsc_viftype_defaults[vt].name) 428 continue; 429 430 /* Grab the defaults */ 431 pdsc->viftype_status[vt] = pdsc_viftype_defaults[vt]; 432 433 /* See what the Core device has for support */ 434 vt_support = !!le16_to_cpu(pdsc->dev_ident.vif_types[vt]); 435 436 dev_dbg(pdsc->dev, "VIF %s is %ssupported\n", 437 pdsc->viftype_status[vt].name, 438 vt_support ? "" : "not "); 439 440 pdsc->viftype_status[vt].supported = vt_support; 441 } 442 443 return 0; 444} 445 446int pdsc_setup(struct pdsc *pdsc, bool init) 447{ 448 int err; 449 450 err = pdsc_dev_init(pdsc); 451 if (err) 452 return err; 453 454 /* Set up the Core with the AdminQ and NotifyQ info */ 455 err = pdsc_core_init(pdsc); 456 if (err) 457 goto err_out_teardown; 458 459 /* Set up the VIFs */ 460 if (init) { 461 err = pdsc_viftypes_init(pdsc); 462 if (err) 463 goto err_out_teardown; 464 465 pdsc_debugfs_add_viftype(pdsc); 466 } 467 468 refcount_set(&pdsc->adminq_refcnt, 1); 469 clear_bit(PDSC_S_FW_DEAD, &pdsc->state); 470 return 0; 471 472err_out_teardown: 473 pdsc_teardown(pdsc, init); 474 return err; 475} 476 477void pdsc_teardown(struct pdsc *pdsc, bool removing) 478{ 479 if (!pdsc->pdev->is_virtfn) 480 pdsc_devcmd_reset(pdsc); 481 if (pdsc->adminqcq.work.func) 482 cancel_work_sync(&pdsc->adminqcq.work); 483 484 pdsc_core_uninit(pdsc); 485 486 if (removing) { 487 kfree(pdsc->viftype_status); 488 pdsc->viftype_status = NULL; 489 } 490 491 pdsc_dev_uninit(pdsc); 492 493 set_bit(PDSC_S_FW_DEAD, &pdsc->state); 494} 495 496int pdsc_start(struct pdsc *pdsc) 497{ 498 pds_core_intr_mask(&pdsc->intr_ctrl[pdsc->adminqcq.intx], 499 PDS_CORE_INTR_MASK_CLEAR); 500 501 return 0; 502} 503 504void pdsc_stop(struct pdsc *pdsc) 505{ 506 int i; 507 508 if (!pdsc->intr_info) 509 return; 510 511 /* Mask interrupts that are in use */ 512 for (i = 0; i < pdsc->nintrs; i++) 513 if (pdsc->intr_info[i].vector) 514 pds_core_intr_mask(&pdsc->intr_ctrl[i], 515 PDS_CORE_INTR_MASK_SET); 516} 517 518static void pdsc_adminq_wait_and_dec_once_unused(struct pdsc *pdsc) 519{ 520 /* The driver initializes the adminq_refcnt to 1 when the adminq is 521 * allocated and ready for use. Other users/requesters will increment 522 * the refcnt while in use. If the refcnt is down to 1 then the adminq 523 * is not in use and the refcnt can be cleared and adminq freed. Before 524 * calling this function the driver will set PDSC_S_FW_DEAD, which 525 * prevent subsequent attempts to use the adminq and increment the 526 * refcnt to fail. This guarantees that this function will eventually 527 * exit. 528 */ 529 while (!refcount_dec_if_one(&pdsc->adminq_refcnt)) { 530 dev_dbg_ratelimited(pdsc->dev, "%s: adminq in use\n", 531 __func__); 532 cpu_relax(); 533 } 534} 535 536void pdsc_fw_down(struct pdsc *pdsc) 537{ 538 union pds_core_notifyq_comp reset_event = { 539 .reset.ecode = cpu_to_le16(PDS_EVENT_RESET), 540 .reset.state = 0, 541 }; 542 543 if (test_and_set_bit(PDSC_S_FW_DEAD, &pdsc->state)) { 544 dev_warn(pdsc->dev, "%s: already happening\n", __func__); 545 return; 546 } 547 548 if (pdsc->pdev->is_virtfn) 549 return; 550 551 pdsc_adminq_wait_and_dec_once_unused(pdsc); 552 553 /* Notify clients of fw_down */ 554 if (pdsc->fw_reporter) 555 devlink_health_report(pdsc->fw_reporter, "FW down reported", pdsc); 556 pdsc_notify(PDS_EVENT_RESET, &reset_event); 557 558 pdsc_stop(pdsc); 559 pdsc_teardown(pdsc, PDSC_TEARDOWN_RECOVERY); 560} 561 562void pdsc_fw_up(struct pdsc *pdsc) 563{ 564 union pds_core_notifyq_comp reset_event = { 565 .reset.ecode = cpu_to_le16(PDS_EVENT_RESET), 566 .reset.state = 1, 567 }; 568 int err; 569 570 if (!test_bit(PDSC_S_FW_DEAD, &pdsc->state)) { 571 dev_err(pdsc->dev, "%s: fw not dead\n", __func__); 572 return; 573 } 574 575 if (pdsc->pdev->is_virtfn) { 576 clear_bit(PDSC_S_FW_DEAD, &pdsc->state); 577 return; 578 } 579 580 err = pdsc_setup(pdsc, PDSC_SETUP_RECOVERY); 581 if (err) 582 goto err_out; 583 584 err = pdsc_start(pdsc); 585 if (err) 586 goto err_out; 587 588 /* Notify clients of fw_up */ 589 pdsc->fw_recoveries++; 590 if (pdsc->fw_reporter) 591 devlink_health_reporter_state_update(pdsc->fw_reporter, 592 DEVLINK_HEALTH_REPORTER_STATE_HEALTHY); 593 pdsc_notify(PDS_EVENT_RESET, &reset_event); 594 595 return; 596 597err_out: 598 pdsc_teardown(pdsc, PDSC_TEARDOWN_RECOVERY); 599} 600 601void pdsc_pci_reset_thread(struct work_struct *work) 602{ 603 struct pdsc *pdsc = container_of(work, struct pdsc, pci_reset_work); 604 struct pci_dev *pdev = pdsc->pdev; 605 606 pci_dev_get(pdev); 607 pci_reset_function(pdev); 608 pci_dev_put(pdev); 609} 610 611static void pdsc_check_pci_health(struct pdsc *pdsc) 612{ 613 u8 fw_status; 614 615 /* some sort of teardown already in progress */ 616 if (!pdsc->info_regs) 617 return; 618 619 fw_status = ioread8(&pdsc->info_regs->fw_status); 620 621 /* is PCI broken? */ 622 if (fw_status != PDS_RC_BAD_PCI) 623 return; 624 625 /* prevent deadlock between pdsc_reset_prepare and pdsc_health_thread */ 626 queue_work(pdsc->wq, &pdsc->pci_reset_work); 627} 628 629void pdsc_health_thread(struct work_struct *work) 630{ 631 struct pdsc *pdsc = container_of(work, struct pdsc, health_work); 632 unsigned long mask; 633 bool healthy; 634 635 mutex_lock(&pdsc->config_lock); 636 637 /* Don't do a check when in a transition state */ 638 mask = BIT_ULL(PDSC_S_INITING_DRIVER) | 639 BIT_ULL(PDSC_S_STOPPING_DRIVER); 640 if (pdsc->state & mask) 641 goto out_unlock; 642 643 healthy = pdsc_is_fw_good(pdsc); 644 dev_dbg(pdsc->dev, "%s: health %d fw_status %#02x fw_heartbeat %d\n", 645 __func__, healthy, pdsc->fw_status, pdsc->last_hb); 646 647 if (test_bit(PDSC_S_FW_DEAD, &pdsc->state)) { 648 if (healthy) 649 pdsc_fw_up(pdsc); 650 } else { 651 if (!healthy) 652 pdsc_fw_down(pdsc); 653 } 654 655 pdsc_check_pci_health(pdsc); 656 657 pdsc->fw_generation = pdsc->fw_status & PDS_CORE_FW_STS_F_GENERATION; 658 659out_unlock: 660 mutex_unlock(&pdsc->config_lock); 661}
~/
Read-only file preview.