1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Freescale data path resource container (DPRC) driver 4 * 5 * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. 6 * Copyright 2019-2020 NXP 7 * Author: German Rivera <German.Rivera@freescale.com> 8 * 9 */ 10 11 #include <linux/module.h> 12 #include <linux/slab.h> 13 #include <linux/interrupt.h> 14 #include <linux/msi.h> 15 #include <linux/fsl/mc.h> 16 17 #include "fsl-mc-private.h" 18 19 #define FSL_MC_DPRC_DRIVER_NAME "fsl_mc_dprc" 20 21 struct fsl_mc_child_objs { 22 int child_count; 23 struct fsl_mc_obj_desc *child_array; 24 }; 25 26 static bool fsl_mc_device_match(struct fsl_mc_device *mc_dev, 27 struct fsl_mc_obj_desc *obj_desc) 28 { 29 return mc_dev->obj_desc.id == obj_desc->id && 30 strcmp(mc_dev->obj_desc.type, obj_desc->type) == 0; 31 } 32 33 static bool fsl_mc_obj_desc_is_allocatable(struct fsl_mc_obj_desc *obj) 34 { 35 if (strcmp(obj->type, "dpmcp") == 0 || 36 strcmp(obj->type, "dpcon") == 0 || 37 strcmp(obj->type, "dpbp") == 0) 38 return true; 39 else 40 return false; 41 } 42 43 static int __fsl_mc_device_remove_if_not_in_mc(struct device *dev, void *data) 44 { 45 int i; 46 struct fsl_mc_child_objs *objs; 47 struct fsl_mc_device *mc_dev; 48 49 mc_dev = to_fsl_mc_device(dev); 50 objs = data; 51 52 for (i = 0; i < objs->child_count; i++) { 53 struct fsl_mc_obj_desc *obj_desc = &objs->child_array[i]; 54 55 if (strlen(obj_desc->type) != 0 && 56 fsl_mc_device_match(mc_dev, obj_desc)) 57 break; 58 } 59 60 if (i == objs->child_count) 61 fsl_mc_device_remove(mc_dev); 62 63 return 0; 64 } 65 66 static int __fsl_mc_device_remove(struct device *dev, void *data) 67 { 68 fsl_mc_device_remove(to_fsl_mc_device(dev)); 69 return 0; 70 } 71 72 /** 73 * dprc_remove_devices - Removes devices for objects removed from a DPRC 74 * 75 * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object 76 * @obj_desc_array: array of object descriptors for child objects currently 77 * present in the DPRC in the MC. 78 * @num_child_objects_in_mc: number of entries in obj_desc_array 79 * 80 * Synchronizes the state of the Linux bus driver with the actual state of 81 * the MC by removing devices that represent MC objects that have 82 * been dynamically removed in the physical DPRC. 83 */ 84 void dprc_remove_devices(struct fsl_mc_device *mc_bus_dev, 85 struct fsl_mc_obj_desc *obj_desc_array, 86 int num_child_objects_in_mc) 87 { 88 if (num_child_objects_in_mc != 0) { 89 /* 90 * Remove child objects that are in the DPRC in Linux, 91 * but not in the MC: 92 */ 93 struct fsl_mc_child_objs objs; 94 95 objs.child_count = num_child_objects_in_mc; 96 objs.child_array = obj_desc_array; 97 device_for_each_child(&mc_bus_dev->dev, &objs, 98 __fsl_mc_device_remove_if_not_in_mc); 99 } else { 100 /* 101 * There are no child objects for this DPRC in the MC. 102 * So, remove all the child devices from Linux: 103 */ 104 device_for_each_child(&mc_bus_dev->dev, NULL, 105 __fsl_mc_device_remove); 106 } 107 } 108 EXPORT_SYMBOL_GPL(dprc_remove_devices); 109 110 static int __fsl_mc_device_match(struct device *dev, void *data) 111 { 112 struct fsl_mc_obj_desc *obj_desc = data; 113 struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); 114 115 return fsl_mc_device_match(mc_dev, obj_desc); 116 } 117 118 struct fsl_mc_device *fsl_mc_device_lookup(struct fsl_mc_obj_desc *obj_desc, 119 struct fsl_mc_device *mc_bus_dev) 120 { 121 struct device *dev; 122 123 dev = device_find_child(&mc_bus_dev->dev, obj_desc, 124 __fsl_mc_device_match); 125 126 return dev ? to_fsl_mc_device(dev) : NULL; 127 } 128 129 /** 130 * check_plugged_state_change - Check change in an MC object's plugged state 131 * 132 * @mc_dev: pointer to the fsl-mc device for a given MC object 133 * @obj_desc: pointer to the MC object's descriptor in the MC 134 * 135 * If the plugged state has changed from unplugged to plugged, the fsl-mc 136 * device is bound to the corresponding device driver. 137 * If the plugged state has changed from plugged to unplugged, the fsl-mc 138 * device is unbound from the corresponding device driver. 139 */ 140 static void check_plugged_state_change(struct fsl_mc_device *mc_dev, 141 struct fsl_mc_obj_desc *obj_desc) 142 { 143 int error; 144 u32 plugged_flag_at_mc = 145 obj_desc->state & FSL_MC_OBJ_STATE_PLUGGED; 146 147 if (plugged_flag_at_mc != 148 (mc_dev->obj_desc.state & FSL_MC_OBJ_STATE_PLUGGED)) { 149 if (plugged_flag_at_mc) { 150 mc_dev->obj_desc.state |= FSL_MC_OBJ_STATE_PLUGGED; 151 error = device_attach(&mc_dev->dev); 152 if (error < 0) { 153 dev_err(&mc_dev->dev, 154 "device_attach() failed: %d\n", 155 error); 156 } 157 } else { 158 mc_dev->obj_desc.state &= ~FSL_MC_OBJ_STATE_PLUGGED; 159 device_release_driver(&mc_dev->dev); 160 } 161 } 162 } 163 164 static void fsl_mc_obj_device_add(struct fsl_mc_device *mc_bus_dev, 165 struct fsl_mc_obj_desc *obj_desc) 166 { 167 int error; 168 struct fsl_mc_device *child_dev; 169 170 /* 171 * Check if device is already known to Linux: 172 */ 173 child_dev = fsl_mc_device_lookup(obj_desc, mc_bus_dev); 174 if (child_dev) { 175 check_plugged_state_change(child_dev, obj_desc); 176 put_device(&child_dev->dev); 177 } else { 178 error = fsl_mc_device_add(obj_desc, NULL, &mc_bus_dev->dev, 179 &child_dev); 180 if (error < 0) 181 return; 182 } 183 } 184 185 /** 186 * dprc_add_new_devices - Adds devices to the logical bus for a DPRC 187 * 188 * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object 189 * @obj_desc_array: array of device descriptors for child devices currently 190 * present in the physical DPRC. 191 * @num_child_objects_in_mc: number of entries in obj_desc_array 192 * 193 * Synchronizes the state of the Linux bus driver with the actual 194 * state of the MC by adding objects that have been newly discovered 195 * in the physical DPRC. 196 */ 197 static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev, 198 struct fsl_mc_obj_desc *obj_desc_array, 199 int num_child_objects_in_mc) 200 { 201 int i; 202 203 /* probe the allocable objects first */ 204 for (i = 0; i < num_child_objects_in_mc; i++) { 205 struct fsl_mc_obj_desc *obj_desc = &obj_desc_array[i]; 206 207 if (strlen(obj_desc->type) > 0 && 208 fsl_mc_obj_desc_is_allocatable(obj_desc)) 209 fsl_mc_obj_device_add(mc_bus_dev, obj_desc); 210 } 211 212 for (i = 0; i < num_child_objects_in_mc; i++) { 213 struct fsl_mc_obj_desc *obj_desc = &obj_desc_array[i]; 214 215 if (strlen(obj_desc->type) > 0 && 216 !fsl_mc_obj_desc_is_allocatable(obj_desc)) 217 fsl_mc_obj_device_add(mc_bus_dev, obj_desc); 218 } 219 } 220 221 /** 222 * dprc_scan_objects - Discover objects in a DPRC 223 * 224 * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object 225 * @alloc_interrupts: if true the function allocates the interrupt pool, 226 * otherwise the interrupt allocation is delayed 227 * 228 * Detects objects added and removed from a DPRC and synchronizes the 229 * state of the Linux bus driver, MC by adding and removing 230 * devices accordingly. 231 * Two types of devices can be found in a DPRC: allocatable objects (e.g., 232 * dpbp, dpmcp) and non-allocatable devices (e.g., dprc, dpni). 233 * All allocatable devices needed to be probed before all non-allocatable 234 * devices, to ensure that device drivers for non-allocatable 235 * devices can allocate any type of allocatable devices. 236 * That is, we need to ensure that the corresponding resource pools are 237 * populated before they can get allocation requests from probe callbacks 238 * of the device drivers for the non-allocatable devices. 239 */ 240 static int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev, 241 bool alloc_interrupts) 242 { 243 int num_child_objects; 244 int dprc_get_obj_failures; 245 int error; 246 unsigned int irq_count = mc_bus_dev->obj_desc.irq_count; 247 struct fsl_mc_obj_desc *child_obj_desc_array = NULL; 248 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); 249 250 error = dprc_get_obj_count(mc_bus_dev->mc_io, 251 0, 252 mc_bus_dev->mc_handle, 253 &num_child_objects); 254 if (error < 0) { 255 dev_err(&mc_bus_dev->dev, "dprc_get_obj_count() failed: %d\n", 256 error); 257 return error; 258 } 259 260 if (num_child_objects != 0) { 261 int i; 262 263 child_obj_desc_array = 264 devm_kmalloc_array(&mc_bus_dev->dev, num_child_objects, 265 sizeof(*child_obj_desc_array), 266 GFP_KERNEL); 267 if (!child_obj_desc_array) 268 return -ENOMEM; 269 270 /* 271 * Discover objects currently present in the physical DPRC: 272 */ 273 dprc_get_obj_failures = 0; 274 for (i = 0; i < num_child_objects; i++) { 275 struct fsl_mc_obj_desc *obj_desc = 276 &child_obj_desc_array[i]; 277 278 error = dprc_get_obj(mc_bus_dev->mc_io, 279 0, 280 mc_bus_dev->mc_handle, 281 i, obj_desc); 282 if (error < 0) { 283 dev_err(&mc_bus_dev->dev, 284 "dprc_get_obj(i=%d) failed: %d\n", 285 i, error); 286 /* 287 * Mark the obj entry as "invalid", by using the 288 * empty string as obj type: 289 */ 290 obj_desc->type[0] = '\0'; 291 obj_desc->id = error; 292 dprc_get_obj_failures++; 293 continue; 294 } 295 296 /* 297 * add a quirk for all versions of dpsec < 4.0...none 298 * are coherent regardless of what the MC reports. 299 */ 300 if ((strcmp(obj_desc->type, "dpseci") == 0) && 301 (obj_desc->ver_major < 4)) 302 obj_desc->flags |= 303 FSL_MC_OBJ_FLAG_NO_MEM_SHAREABILITY; 304 305 irq_count += obj_desc->irq_count; 306 dev_dbg(&mc_bus_dev->dev, 307 "Discovered object: type %s, id %d\n", 308 obj_desc->type, obj_desc->id); 309 } 310 311 if (dprc_get_obj_failures != 0) { 312 dev_err(&mc_bus_dev->dev, 313 "%d out of %d devices could not be retrieved\n", 314 dprc_get_obj_failures, num_child_objects); 315 } 316 } 317 318 /* 319 * Allocate IRQ's before binding the scanned devices with their 320 * respective drivers. 321 */ 322 if (dev_get_msi_domain(&mc_bus_dev->dev)) { 323 if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) { 324 dev_warn(&mc_bus_dev->dev, 325 "IRQs needed (%u) exceed IRQs preallocated (%u)\n", 326 irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS); 327 } 328 329 if (alloc_interrupts && !mc_bus->irq_resources) { 330 error = fsl_mc_populate_irq_pool(mc_bus_dev, 331 FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS); 332 if (error < 0) 333 return error; 334 } 335 } 336 337 dprc_remove_devices(mc_bus_dev, child_obj_desc_array, 338 num_child_objects); 339 340 dprc_add_new_devices(mc_bus_dev, child_obj_desc_array, 341 num_child_objects); 342 343 if (child_obj_desc_array) 344 devm_kfree(&mc_bus_dev->dev, child_obj_desc_array); 345 346 return 0; 347 } 348 349 /** 350 * dprc_scan_container - Scans a physical DPRC and synchronizes Linux bus state 351 * 352 * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object 353 * 354 * Scans the physical DPRC and synchronizes the state of the Linux 355 * bus driver with the actual state of the MC by adding and removing 356 * devices as appropriate. 357 */ 358 int dprc_scan_container(struct fsl_mc_device *mc_bus_dev, 359 bool alloc_interrupts) 360 { 361 int error = 0; 362 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); 363 364 fsl_mc_init_all_resource_pools(mc_bus_dev); 365 366 /* 367 * Discover objects in the DPRC: 368 */ 369 mutex_lock(&mc_bus->scan_mutex); 370 error = dprc_scan_objects(mc_bus_dev, alloc_interrupts); 371 mutex_unlock(&mc_bus->scan_mutex); 372 373 return error; 374 } 375 EXPORT_SYMBOL_GPL(dprc_scan_container); 376 /** 377 * dprc_irq0_handler - Regular ISR for DPRC interrupt 0 378 * 379 * @irq: IRQ number of the interrupt being handled 380 * @arg: Pointer to device structure 381 */ 382 static irqreturn_t dprc_irq0_handler(int irq_num, void *arg) 383 { 384 return IRQ_WAKE_THREAD; 385 } 386 387 /** 388 * dprc_irq0_handler_thread - Handler thread function for DPRC interrupt 0 389 * 390 * @irq: IRQ number of the interrupt being handled 391 * @arg: Pointer to device structure 392 */ 393 static irqreturn_t dprc_irq0_handler_thread(int irq_num, void *arg) 394 { 395 int error; 396 u32 status; 397 struct device *dev = arg; 398 struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); 399 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); 400 struct fsl_mc_io *mc_io = mc_dev->mc_io; 401 struct msi_desc *msi_desc = mc_dev->irqs[0]->msi_desc; 402 403 dev_dbg(dev, "DPRC IRQ %d triggered on CPU %u\n", 404 irq_num, smp_processor_id()); 405 406 if (!(mc_dev->flags & FSL_MC_IS_DPRC)) 407 return IRQ_HANDLED; 408 409 mutex_lock(&mc_bus->scan_mutex); 410 if (!msi_desc || msi_desc->irq != (u32)irq_num) 411 goto out; 412 413 status = 0; 414 error = dprc_get_irq_status(mc_io, 0, mc_dev->mc_handle, 0, 415 &status); 416 if (error < 0) { 417 dev_err(dev, 418 "dprc_get_irq_status() failed: %d\n", error); 419 goto out; 420 } 421 422 error = dprc_clear_irq_status(mc_io, 0, mc_dev->mc_handle, 0, 423 status); 424 if (error < 0) { 425 dev_err(dev, 426 "dprc_clear_irq_status() failed: %d\n", error); 427 goto out; 428 } 429 430 if (status & (DPRC_IRQ_EVENT_OBJ_ADDED | 431 DPRC_IRQ_EVENT_OBJ_REMOVED | 432 DPRC_IRQ_EVENT_CONTAINER_DESTROYED | 433 DPRC_IRQ_EVENT_OBJ_DESTROYED | 434 DPRC_IRQ_EVENT_OBJ_CREATED)) { 435 436 error = dprc_scan_objects(mc_dev, true); 437 if (error < 0) { 438 /* 439 * If the error is -ENXIO, we ignore it, as it indicates 440 * that the object scan was aborted, as we detected that 441 * an object was removed from the DPRC in the MC, while 442 * we were scanning the DPRC. 443 */ 444 if (error != -ENXIO) { 445 dev_err(dev, "dprc_scan_objects() failed: %d\n", 446 error); 447 } 448 449 goto out; 450 } 451 } 452 453 out: 454 mutex_unlock(&mc_bus->scan_mutex); 455 return IRQ_HANDLED; 456 } 457 458 /* 459 * Disable and clear interrupt for a given DPRC object 460 */ 461 static int disable_dprc_irq(struct fsl_mc_device *mc_dev) 462 { 463 int error; 464 struct fsl_mc_io *mc_io = mc_dev->mc_io; 465 466 /* 467 * Disable generation of interrupt, while we configure it: 468 */ 469 error = dprc_set_irq_enable(mc_io, 0, mc_dev->mc_handle, 0, 0); 470 if (error < 0) { 471 dev_err(&mc_dev->dev, 472 "Disabling DPRC IRQ failed: dprc_set_irq_enable() failed: %d\n", 473 error); 474 return error; 475 } 476 477 /* 478 * Disable all interrupt causes for the interrupt: 479 */ 480 error = dprc_set_irq_mask(mc_io, 0, mc_dev->mc_handle, 0, 0x0); 481 if (error < 0) { 482 dev_err(&mc_dev->dev, 483 "Disabling DPRC IRQ failed: dprc_set_irq_mask() failed: %d\n", 484 error); 485 return error; 486 } 487 488 /* 489 * Clear any leftover interrupts: 490 */ 491 error = dprc_clear_irq_status(mc_io, 0, mc_dev->mc_handle, 0, ~0x0U); 492 if (error < 0) { 493 dev_err(&mc_dev->dev, 494 "Disabling DPRC IRQ failed: dprc_clear_irq_status() failed: %d\n", 495 error); 496 return error; 497 } 498 499 return 0; 500 } 501 502 static int register_dprc_irq_handler(struct fsl_mc_device *mc_dev) 503 { 504 int error; 505 struct fsl_mc_device_irq *irq = mc_dev->irqs[0]; 506 507 /* 508 * NOTE: devm_request_threaded_irq() invokes the device-specific 509 * function that programs the MSI physically in the device 510 */ 511 error = devm_request_threaded_irq(&mc_dev->dev, 512 irq->msi_desc->irq, 513 dprc_irq0_handler, 514 dprc_irq0_handler_thread, 515 IRQF_NO_SUSPEND | IRQF_ONESHOT, 516 dev_name(&mc_dev->dev), 517 &mc_dev->dev); 518 if (error < 0) { 519 dev_err(&mc_dev->dev, 520 "devm_request_threaded_irq() failed: %d\n", 521 error); 522 return error; 523 } 524 525 return 0; 526 } 527 528 static int enable_dprc_irq(struct fsl_mc_device *mc_dev) 529 { 530 int error; 531 532 /* 533 * Enable all interrupt causes for the interrupt: 534 */ 535 error = dprc_set_irq_mask(mc_dev->mc_io, 0, mc_dev->mc_handle, 0, 536 ~0x0u); 537 if (error < 0) { 538 dev_err(&mc_dev->dev, 539 "Enabling DPRC IRQ failed: dprc_set_irq_mask() failed: %d\n", 540 error); 541 542 return error; 543 } 544 545 /* 546 * Enable generation of the interrupt: 547 */ 548 error = dprc_set_irq_enable(mc_dev->mc_io, 0, mc_dev->mc_handle, 0, 1); 549 if (error < 0) { 550 dev_err(&mc_dev->dev, 551 "Enabling DPRC IRQ failed: dprc_set_irq_enable() failed: %d\n", 552 error); 553 554 return error; 555 } 556 557 return 0; 558 } 559 560 /* 561 * Setup interrupt for a given DPRC device 562 */ 563 static int dprc_setup_irq(struct fsl_mc_device *mc_dev) 564 { 565 int error; 566 567 error = fsl_mc_allocate_irqs(mc_dev); 568 if (error < 0) 569 return error; 570 571 error = disable_dprc_irq(mc_dev); 572 if (error < 0) 573 goto error_free_irqs; 574 575 error = register_dprc_irq_handler(mc_dev); 576 if (error < 0) 577 goto error_free_irqs; 578 579 error = enable_dprc_irq(mc_dev); 580 if (error < 0) 581 goto error_free_irqs; 582 583 return 0; 584 585 error_free_irqs: 586 fsl_mc_free_irqs(mc_dev); 587 return error; 588 } 589 590 /** 591 * dprc_setup - opens and creates a mc_io for DPRC 592 * 593 * @mc_dev: Pointer to fsl-mc device representing a DPRC 594 * 595 * It opens the physical DPRC in the MC. 596 * It configures the DPRC portal used to communicate with MC 597 */ 598 599 int dprc_setup(struct fsl_mc_device *mc_dev) 600 { 601 struct device *parent_dev = mc_dev->dev.parent; 602 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); 603 struct irq_domain *mc_msi_domain; 604 bool mc_io_created = false; 605 bool msi_domain_set = false; 606 u16 major_ver, minor_ver; 607 size_t region_size; 608 int error; 609 610 if (!is_fsl_mc_bus_dprc(mc_dev)) 611 return -EINVAL; 612 613 if (dev_get_msi_domain(&mc_dev->dev)) 614 return -EINVAL; 615 616 if (!mc_dev->mc_io) { 617 /* 618 * This is a child DPRC: 619 */ 620 if (!dev_is_fsl_mc(parent_dev)) 621 return -EINVAL; 622 623 if (mc_dev->obj_desc.region_count == 0) 624 return -EINVAL; 625 626 region_size = resource_size(mc_dev->regions); 627 628 error = fsl_create_mc_io(&mc_dev->dev, 629 mc_dev->regions[0].start, 630 region_size, 631 NULL, 632 FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, 633 &mc_dev->mc_io); 634 if (error < 0) 635 return error; 636 637 mc_io_created = true; 638 } 639 640 mc_msi_domain = fsl_mc_find_msi_domain(&mc_dev->dev); 641 if (!mc_msi_domain) { 642 dev_warn(&mc_dev->dev, 643 "WARNING: MC bus without interrupt support\n"); 644 } else { 645 dev_set_msi_domain(&mc_dev->dev, mc_msi_domain); 646 msi_domain_set = true; 647 } 648 649 error = dprc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id, 650 &mc_dev->mc_handle); 651 if (error < 0) { 652 dev_err(&mc_dev->dev, "dprc_open() failed: %d\n", error); 653 goto error_cleanup_msi_domain; 654 } 655 656 error = dprc_get_attributes(mc_dev->mc_io, 0, mc_dev->mc_handle, 657 &mc_bus->dprc_attr); 658 if (error < 0) { 659 dev_err(&mc_dev->dev, "dprc_get_attributes() failed: %d\n", 660 error); 661 goto error_cleanup_open; 662 } 663 664 error = dprc_get_api_version(mc_dev->mc_io, 0, 665 &major_ver, 666 &minor_ver); 667 if (error < 0) { 668 dev_err(&mc_dev->dev, "dprc_get_api_version() failed: %d\n", 669 error); 670 goto error_cleanup_open; 671 } 672 673 if (major_ver < DPRC_MIN_VER_MAJOR || 674 (major_ver == DPRC_MIN_VER_MAJOR && 675 minor_ver < DPRC_MIN_VER_MINOR)) { 676 dev_err(&mc_dev->dev, 677 "ERROR: DPRC version %d.%d not supported\n", 678 major_ver, minor_ver); 679 error = -ENOTSUPP; 680 goto error_cleanup_open; 681 } 682 683 return 0; 684 685 error_cleanup_open: 686 (void)dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); 687 688 error_cleanup_msi_domain: 689 if (msi_domain_set) 690 dev_set_msi_domain(&mc_dev->dev, NULL); 691 692 if (mc_io_created) { 693 fsl_destroy_mc_io(mc_dev->mc_io); 694 mc_dev->mc_io = NULL; 695 } 696 697 return error; 698 } 699 EXPORT_SYMBOL_GPL(dprc_setup); 700 701 /** 702 * dprc_probe - callback invoked when a DPRC is being bound to this driver 703 * 704 * @mc_dev: Pointer to fsl-mc device representing a DPRC 705 * 706 * It opens the physical DPRC in the MC. 707 * It scans the DPRC to discover the MC objects contained in it. 708 * It creates the interrupt pool for the MC bus associated with the DPRC. 709 * It configures the interrupts for the DPRC device itself. 710 */ 711 static int dprc_probe(struct fsl_mc_device *mc_dev) 712 { 713 int error; 714 715 error = dprc_setup(mc_dev); 716 if (error < 0) 717 return error; 718 719 /* 720 * Discover MC objects in DPRC object: 721 */ 722 error = dprc_scan_container(mc_dev, true); 723 if (error < 0) 724 goto dprc_cleanup; 725 726 /* 727 * Configure interrupt for the DPRC object associated with this MC bus: 728 */ 729 error = dprc_setup_irq(mc_dev); 730 if (error < 0) 731 goto scan_cleanup; 732 733 dev_info(&mc_dev->dev, "DPRC device bound to driver"); 734 return 0; 735 736 scan_cleanup: 737 device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove); 738 dprc_cleanup: 739 dprc_cleanup(mc_dev); 740 return error; 741 } 742 743 /* 744 * Tear down interrupt for a given DPRC object 745 */ 746 static void dprc_teardown_irq(struct fsl_mc_device *mc_dev) 747 { 748 struct fsl_mc_device_irq *irq = mc_dev->irqs[0]; 749 750 (void)disable_dprc_irq(mc_dev); 751 752 devm_free_irq(&mc_dev->dev, irq->msi_desc->irq, &mc_dev->dev); 753 754 fsl_mc_free_irqs(mc_dev); 755 } 756 757 /** 758 * dprc_cleanup - function that cleanups a DPRC 759 * 760 * @mc_dev: Pointer to fsl-mc device representing the DPRC 761 * 762 * It closes the DPRC device in the MC. 763 * It destroys the interrupt pool associated with this MC bus. 764 */ 765 766 int dprc_cleanup(struct fsl_mc_device *mc_dev) 767 { 768 int error; 769 770 /* this function should be called only for DPRCs, it 771 * is an error to call it for regular objects 772 */ 773 if (!is_fsl_mc_bus_dprc(mc_dev)) 774 return -EINVAL; 775 776 if (dev_get_msi_domain(&mc_dev->dev)) { 777 fsl_mc_cleanup_irq_pool(mc_dev); 778 dev_set_msi_domain(&mc_dev->dev, NULL); 779 } 780 781 fsl_mc_cleanup_all_resource_pools(mc_dev); 782 783 /* if this step fails we cannot go further with cleanup as there is no way of 784 * communicating with the firmware 785 */ 786 if (!mc_dev->mc_io) { 787 dev_err(&mc_dev->dev, "mc_io is NULL, tear down cannot be performed in firmware\n"); 788 return -EINVAL; 789 } 790 791 error = dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); 792 if (error < 0) 793 dev_err(&mc_dev->dev, "dprc_close() failed: %d\n", error); 794 795 if (!fsl_mc_is_root_dprc(&mc_dev->dev)) { 796 fsl_destroy_mc_io(mc_dev->mc_io); 797 mc_dev->mc_io = NULL; 798 } 799 800 return 0; 801 } 802 EXPORT_SYMBOL_GPL(dprc_cleanup); 803 804 /** 805 * dprc_remove - callback invoked when a DPRC is being unbound from this driver 806 * 807 * @mc_dev: Pointer to fsl-mc device representing the DPRC 808 * 809 * It removes the DPRC's child objects from Linux (not from the MC) and 810 * closes the DPRC device in the MC. 811 * It tears down the interrupts that were configured for the DPRC device. 812 * It destroys the interrupt pool associated with this MC bus. 813 */ 814 static int dprc_remove(struct fsl_mc_device *mc_dev) 815 { 816 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); 817 818 if (!is_fsl_mc_bus_dprc(mc_dev)) 819 return -EINVAL; 820 821 if (!mc_bus->irq_resources) 822 return -EINVAL; 823 824 if (dev_get_msi_domain(&mc_dev->dev)) 825 dprc_teardown_irq(mc_dev); 826 827 device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove); 828 829 dprc_cleanup(mc_dev); 830 831 dev_info(&mc_dev->dev, "DPRC device unbound from driver"); 832 return 0; 833 } 834 835 static const struct fsl_mc_device_id match_id_table[] = { 836 { 837 .vendor = FSL_MC_VENDOR_FREESCALE, 838 .obj_type = "dprc"}, 839 {.vendor = 0x0}, 840 }; 841 842 static struct fsl_mc_driver dprc_driver = { 843 .driver = { 844 .name = FSL_MC_DPRC_DRIVER_NAME, 845 .owner = THIS_MODULE, 846 .pm = NULL, 847 }, 848 .match_id_table = match_id_table, 849 .probe = dprc_probe, 850 .remove = dprc_remove, 851 }; 852 853 int __init dprc_driver_init(void) 854 { 855 return fsl_mc_driver_register(&dprc_driver); 856 } 857 858 void dprc_driver_exit(void) 859 { 860 fsl_mc_driver_unregister(&dprc_driver); 861 } 862