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