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 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 int disable_dprc_irq(struct fsl_mc_device *mc_dev) 462 { 463 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); 464 int error; 465 struct fsl_mc_io *mc_io = mc_dev->mc_io; 466 467 /* 468 * Disable generation of interrupt, while we configure it: 469 */ 470 error = dprc_set_irq_enable(mc_io, 0, mc_dev->mc_handle, 0, 0); 471 if (error < 0) { 472 dev_err(&mc_dev->dev, 473 "Disabling DPRC IRQ failed: dprc_set_irq_enable() failed: %d\n", 474 error); 475 return error; 476 } 477 478 /* 479 * Disable all interrupt causes for the interrupt: 480 */ 481 error = dprc_set_irq_mask(mc_io, 0, mc_dev->mc_handle, 0, 0x0); 482 if (error < 0) { 483 dev_err(&mc_dev->dev, 484 "Disabling DPRC IRQ failed: dprc_set_irq_mask() failed: %d\n", 485 error); 486 return error; 487 } 488 489 /* 490 * Clear any leftover interrupts: 491 */ 492 error = dprc_clear_irq_status(mc_io, 0, mc_dev->mc_handle, 0, ~0x0U); 493 if (error < 0) { 494 dev_err(&mc_dev->dev, 495 "Disabling DPRC IRQ failed: dprc_clear_irq_status() failed: %d\n", 496 error); 497 return error; 498 } 499 500 mc_bus->irq_enabled = 0; 501 502 return 0; 503 } 504 505 int get_dprc_irq_state(struct fsl_mc_device *mc_dev) 506 { 507 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); 508 509 return mc_bus->irq_enabled; 510 } 511 512 static int register_dprc_irq_handler(struct fsl_mc_device *mc_dev) 513 { 514 int error; 515 struct fsl_mc_device_irq *irq = mc_dev->irqs[0]; 516 517 /* 518 * NOTE: devm_request_threaded_irq() invokes the device-specific 519 * function that programs the MSI physically in the device 520 */ 521 error = devm_request_threaded_irq(&mc_dev->dev, 522 irq->msi_desc->irq, 523 dprc_irq0_handler, 524 dprc_irq0_handler_thread, 525 IRQF_NO_SUSPEND | IRQF_ONESHOT, 526 dev_name(&mc_dev->dev), 527 &mc_dev->dev); 528 if (error < 0) { 529 dev_err(&mc_dev->dev, 530 "devm_request_threaded_irq() failed: %d\n", 531 error); 532 return error; 533 } 534 535 return 0; 536 } 537 538 int enable_dprc_irq(struct fsl_mc_device *mc_dev) 539 { 540 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); 541 int error; 542 543 /* 544 * Enable all interrupt causes for the interrupt: 545 */ 546 error = dprc_set_irq_mask(mc_dev->mc_io, 0, mc_dev->mc_handle, 0, 547 ~0x0u); 548 if (error < 0) { 549 dev_err(&mc_dev->dev, 550 "Enabling DPRC IRQ failed: dprc_set_irq_mask() failed: %d\n", 551 error); 552 553 return error; 554 } 555 556 /* 557 * Enable generation of the interrupt: 558 */ 559 error = dprc_set_irq_enable(mc_dev->mc_io, 0, mc_dev->mc_handle, 0, 1); 560 if (error < 0) { 561 dev_err(&mc_dev->dev, 562 "Enabling DPRC IRQ failed: dprc_set_irq_enable() failed: %d\n", 563 error); 564 565 return error; 566 } 567 568 mc_bus->irq_enabled = 1; 569 570 return 0; 571 } 572 573 /* 574 * Setup interrupt for a given DPRC device 575 */ 576 static int dprc_setup_irq(struct fsl_mc_device *mc_dev) 577 { 578 int error; 579 580 error = fsl_mc_allocate_irqs(mc_dev); 581 if (error < 0) 582 return error; 583 584 error = disable_dprc_irq(mc_dev); 585 if (error < 0) 586 goto error_free_irqs; 587 588 error = register_dprc_irq_handler(mc_dev); 589 if (error < 0) 590 goto error_free_irqs; 591 592 error = enable_dprc_irq(mc_dev); 593 if (error < 0) 594 goto error_free_irqs; 595 596 return 0; 597 598 error_free_irqs: 599 fsl_mc_free_irqs(mc_dev); 600 return error; 601 } 602 603 /** 604 * dprc_setup - opens and creates a mc_io for DPRC 605 * 606 * @mc_dev: Pointer to fsl-mc device representing a DPRC 607 * 608 * It opens the physical DPRC in the MC. 609 * It configures the DPRC portal used to communicate with MC 610 */ 611 612 int dprc_setup(struct fsl_mc_device *mc_dev) 613 { 614 struct device *parent_dev = mc_dev->dev.parent; 615 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); 616 struct irq_domain *mc_msi_domain; 617 bool mc_io_created = false; 618 bool msi_domain_set = false; 619 bool uapi_created = false; 620 u16 major_ver, minor_ver; 621 size_t region_size; 622 int error; 623 624 if (!is_fsl_mc_bus_dprc(mc_dev)) 625 return -EINVAL; 626 627 if (dev_get_msi_domain(&mc_dev->dev)) 628 return -EINVAL; 629 630 if (!mc_dev->mc_io) { 631 /* 632 * This is a child DPRC: 633 */ 634 if (!dev_is_fsl_mc(parent_dev)) 635 return -EINVAL; 636 637 if (mc_dev->obj_desc.region_count == 0) 638 return -EINVAL; 639 640 region_size = resource_size(mc_dev->regions); 641 642 error = fsl_create_mc_io(&mc_dev->dev, 643 mc_dev->regions[0].start, 644 region_size, 645 NULL, 646 FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, 647 &mc_dev->mc_io); 648 if (error < 0) 649 return error; 650 651 mc_io_created = true; 652 } else { 653 error = fsl_mc_uapi_create_device_file(mc_bus); 654 if (error < 0) 655 return -EPROBE_DEFER; 656 uapi_created = true; 657 } 658 659 mc_msi_domain = fsl_mc_find_msi_domain(&mc_dev->dev); 660 if (!mc_msi_domain) { 661 dev_warn(&mc_dev->dev, 662 "WARNING: MC bus without interrupt support\n"); 663 } else { 664 dev_set_msi_domain(&mc_dev->dev, mc_msi_domain); 665 msi_domain_set = true; 666 } 667 668 error = dprc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id, 669 &mc_dev->mc_handle); 670 if (error < 0) { 671 dev_err(&mc_dev->dev, "dprc_open() failed: %d\n", error); 672 goto error_cleanup_msi_domain; 673 } 674 675 error = dprc_get_attributes(mc_dev->mc_io, 0, mc_dev->mc_handle, 676 &mc_bus->dprc_attr); 677 if (error < 0) { 678 dev_err(&mc_dev->dev, "dprc_get_attributes() failed: %d\n", 679 error); 680 goto error_cleanup_open; 681 } 682 683 error = dprc_get_api_version(mc_dev->mc_io, 0, 684 &major_ver, 685 &minor_ver); 686 if (error < 0) { 687 dev_err(&mc_dev->dev, "dprc_get_api_version() failed: %d\n", 688 error); 689 goto error_cleanup_open; 690 } 691 692 if (major_ver < DPRC_MIN_VER_MAJOR) { 693 dev_err(&mc_dev->dev, 694 "ERROR: DPRC version %d.%d not supported\n", 695 major_ver, minor_ver); 696 error = -ENOTSUPP; 697 goto error_cleanup_open; 698 } 699 700 return 0; 701 702 error_cleanup_open: 703 (void)dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); 704 705 error_cleanup_msi_domain: 706 if (msi_domain_set) 707 dev_set_msi_domain(&mc_dev->dev, NULL); 708 709 if (mc_io_created) { 710 fsl_destroy_mc_io(mc_dev->mc_io); 711 mc_dev->mc_io = NULL; 712 } 713 714 if (uapi_created) 715 fsl_mc_uapi_remove_device_file(mc_bus); 716 717 return error; 718 } 719 EXPORT_SYMBOL_GPL(dprc_setup); 720 721 /** 722 * dprc_probe - callback invoked when a DPRC is being bound to this driver 723 * 724 * @mc_dev: Pointer to fsl-mc device representing a DPRC 725 * 726 * It opens the physical DPRC in the MC. 727 * It scans the DPRC to discover the MC objects contained in it. 728 * It creates the interrupt pool for the MC bus associated with the DPRC. 729 * It configures the interrupts for the DPRC device itself. 730 */ 731 static int dprc_probe(struct fsl_mc_device *mc_dev) 732 { 733 int error; 734 735 error = dprc_setup(mc_dev); 736 if (error < 0) 737 return error; 738 739 /* 740 * Discover MC objects in DPRC object: 741 */ 742 error = dprc_scan_container(mc_dev, true); 743 if (error < 0) 744 goto dprc_cleanup; 745 746 /* 747 * Configure interrupt for the DPRC object associated with this MC bus: 748 */ 749 error = dprc_setup_irq(mc_dev); 750 if (error < 0) 751 goto scan_cleanup; 752 753 dev_info(&mc_dev->dev, "DPRC device bound to driver"); 754 return 0; 755 756 scan_cleanup: 757 device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove); 758 dprc_cleanup: 759 dprc_cleanup(mc_dev); 760 return error; 761 } 762 763 /* 764 * Tear down interrupt for a given DPRC object 765 */ 766 static void dprc_teardown_irq(struct fsl_mc_device *mc_dev) 767 { 768 struct fsl_mc_device_irq *irq = mc_dev->irqs[0]; 769 770 (void)disable_dprc_irq(mc_dev); 771 772 devm_free_irq(&mc_dev->dev, irq->msi_desc->irq, &mc_dev->dev); 773 774 fsl_mc_free_irqs(mc_dev); 775 } 776 777 /** 778 * dprc_cleanup - function that cleanups a DPRC 779 * 780 * @mc_dev: Pointer to fsl-mc device representing the DPRC 781 * 782 * It closes the DPRC device in the MC. 783 * It destroys the interrupt pool associated with this MC bus. 784 */ 785 786 int dprc_cleanup(struct fsl_mc_device *mc_dev) 787 { 788 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); 789 int error; 790 791 /* this function should be called only for DPRCs, it 792 * is an error to call it for regular objects 793 */ 794 if (!is_fsl_mc_bus_dprc(mc_dev)) 795 return -EINVAL; 796 797 if (dev_get_msi_domain(&mc_dev->dev)) { 798 fsl_mc_cleanup_irq_pool(mc_dev); 799 dev_set_msi_domain(&mc_dev->dev, NULL); 800 } 801 802 fsl_mc_cleanup_all_resource_pools(mc_dev); 803 804 /* if this step fails we cannot go further with cleanup as there is no way of 805 * communicating with the firmware 806 */ 807 if (!mc_dev->mc_io) { 808 dev_err(&mc_dev->dev, "mc_io is NULL, tear down cannot be performed in firmware\n"); 809 return -EINVAL; 810 } 811 812 error = dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); 813 if (error < 0) 814 dev_err(&mc_dev->dev, "dprc_close() failed: %d\n", error); 815 816 if (!fsl_mc_is_root_dprc(&mc_dev->dev)) { 817 fsl_destroy_mc_io(mc_dev->mc_io); 818 mc_dev->mc_io = NULL; 819 } else { 820 fsl_mc_uapi_remove_device_file(mc_bus); 821 } 822 823 return 0; 824 } 825 EXPORT_SYMBOL_GPL(dprc_cleanup); 826 827 /** 828 * dprc_remove - callback invoked when a DPRC is being unbound from this driver 829 * 830 * @mc_dev: Pointer to fsl-mc device representing the DPRC 831 * 832 * It removes the DPRC's child objects from Linux (not from the MC) and 833 * closes the DPRC device in the MC. 834 * It tears down the interrupts that were configured for the DPRC device. 835 * It destroys the interrupt pool associated with this MC bus. 836 */ 837 static int dprc_remove(struct fsl_mc_device *mc_dev) 838 { 839 struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); 840 841 if (!is_fsl_mc_bus_dprc(mc_dev)) 842 return -EINVAL; 843 844 if (!mc_bus->irq_resources) 845 return -EINVAL; 846 847 if (dev_get_msi_domain(&mc_dev->dev)) 848 dprc_teardown_irq(mc_dev); 849 850 device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove); 851 852 dprc_cleanup(mc_dev); 853 854 dev_info(&mc_dev->dev, "DPRC device unbound from driver"); 855 return 0; 856 } 857 858 static const struct fsl_mc_device_id match_id_table[] = { 859 { 860 .vendor = FSL_MC_VENDOR_FREESCALE, 861 .obj_type = "dprc"}, 862 {.vendor = 0x0}, 863 }; 864 865 static struct fsl_mc_driver dprc_driver = { 866 .driver = { 867 .name = FSL_MC_DPRC_DRIVER_NAME, 868 .owner = THIS_MODULE, 869 .pm = NULL, 870 }, 871 .match_id_table = match_id_table, 872 .probe = dprc_probe, 873 .remove = dprc_remove, 874 }; 875 876 int __init dprc_driver_init(void) 877 { 878 return fsl_mc_driver_register(&dprc_driver); 879 } 880 881 void dprc_driver_exit(void) 882 { 883 fsl_mc_driver_unregister(&dprc_driver); 884 } 885