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