| .. | .. |
|---|
| 3 | 3 | * Freescale data path resource container (DPRC) driver |
|---|
| 4 | 4 | * |
|---|
| 5 | 5 | * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. |
|---|
| 6 | + * Copyright 2019-2020 NXP |
|---|
| 6 | 7 | * Author: German Rivera <German.Rivera@freescale.com> |
|---|
| 7 | 8 | * |
|---|
| 8 | 9 | */ |
|---|
| .. | .. |
|---|
| 27 | 28 | { |
|---|
| 28 | 29 | return mc_dev->obj_desc.id == obj_desc->id && |
|---|
| 29 | 30 | strcmp(mc_dev->obj_desc.type, obj_desc->type) == 0; |
|---|
| 31 | +} |
|---|
| 30 | 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; |
|---|
| 31 | 41 | } |
|---|
| 32 | 42 | |
|---|
| 33 | 43 | static int __fsl_mc_device_remove_if_not_in_mc(struct device *dev, void *data) |
|---|
| .. | .. |
|---|
| 71 | 81 | * the MC by removing devices that represent MC objects that have |
|---|
| 72 | 82 | * been dynamically removed in the physical DPRC. |
|---|
| 73 | 83 | */ |
|---|
| 74 | | -static void dprc_remove_devices(struct fsl_mc_device *mc_bus_dev, |
|---|
| 75 | | - struct fsl_mc_obj_desc *obj_desc_array, |
|---|
| 76 | | - int num_child_objects_in_mc) |
|---|
| 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) |
|---|
| 77 | 87 | { |
|---|
| 78 | 88 | if (num_child_objects_in_mc != 0) { |
|---|
| 79 | 89 | /* |
|---|
| .. | .. |
|---|
| 95 | 105 | __fsl_mc_device_remove); |
|---|
| 96 | 106 | } |
|---|
| 97 | 107 | } |
|---|
| 108 | +EXPORT_SYMBOL_GPL(dprc_remove_devices); |
|---|
| 98 | 109 | |
|---|
| 99 | 110 | static int __fsl_mc_device_match(struct device *dev, void *data) |
|---|
| 100 | 111 | { |
|---|
| .. | .. |
|---|
| 104 | 115 | return fsl_mc_device_match(mc_dev, obj_desc); |
|---|
| 105 | 116 | } |
|---|
| 106 | 117 | |
|---|
| 107 | | -static struct fsl_mc_device *fsl_mc_device_lookup(struct fsl_mc_obj_desc |
|---|
| 108 | | - *obj_desc, |
|---|
| 109 | | - struct fsl_mc_device |
|---|
| 110 | | - *mc_bus_dev) |
|---|
| 118 | +struct fsl_mc_device *fsl_mc_device_lookup(struct fsl_mc_obj_desc *obj_desc, |
|---|
| 119 | + struct fsl_mc_device *mc_bus_dev) |
|---|
| 111 | 120 | { |
|---|
| 112 | 121 | struct device *dev; |
|---|
| 113 | 122 | |
|---|
| .. | .. |
|---|
| 152 | 161 | } |
|---|
| 153 | 162 | } |
|---|
| 154 | 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 | + |
|---|
| 155 | 185 | /** |
|---|
| 156 | 186 | * dprc_add_new_devices - Adds devices to the logical bus for a DPRC |
|---|
| 157 | 187 | * |
|---|
| .. | .. |
|---|
| 168 | 198 | struct fsl_mc_obj_desc *obj_desc_array, |
|---|
| 169 | 199 | int num_child_objects_in_mc) |
|---|
| 170 | 200 | { |
|---|
| 171 | | - int error; |
|---|
| 172 | 201 | int i; |
|---|
| 173 | 202 | |
|---|
| 203 | + /* probe the allocable objects first */ |
|---|
| 174 | 204 | for (i = 0; i < num_child_objects_in_mc; i++) { |
|---|
| 175 | | - struct fsl_mc_device *child_dev; |
|---|
| 176 | 205 | struct fsl_mc_obj_desc *obj_desc = &obj_desc_array[i]; |
|---|
| 177 | 206 | |
|---|
| 178 | | - if (strlen(obj_desc->type) == 0) |
|---|
| 179 | | - continue; |
|---|
| 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 | + } |
|---|
| 180 | 211 | |
|---|
| 181 | | - /* |
|---|
| 182 | | - * Check if device is already known to Linux: |
|---|
| 183 | | - */ |
|---|
| 184 | | - child_dev = fsl_mc_device_lookup(obj_desc, mc_bus_dev); |
|---|
| 185 | | - if (child_dev) { |
|---|
| 186 | | - check_plugged_state_change(child_dev, obj_desc); |
|---|
| 187 | | - put_device(&child_dev->dev); |
|---|
| 188 | | - continue; |
|---|
| 189 | | - } |
|---|
| 212 | + for (i = 0; i < num_child_objects_in_mc; i++) { |
|---|
| 213 | + struct fsl_mc_obj_desc *obj_desc = &obj_desc_array[i]; |
|---|
| 190 | 214 | |
|---|
| 191 | | - error = fsl_mc_device_add(obj_desc, NULL, &mc_bus_dev->dev, |
|---|
| 192 | | - &child_dev); |
|---|
| 193 | | - if (error < 0) |
|---|
| 194 | | - continue; |
|---|
| 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); |
|---|
| 195 | 218 | } |
|---|
| 196 | 219 | } |
|---|
| 197 | 220 | |
|---|
| .. | .. |
|---|
| 199 | 222 | * dprc_scan_objects - Discover objects in a DPRC |
|---|
| 200 | 223 | * |
|---|
| 201 | 224 | * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object |
|---|
| 202 | | - * @total_irq_count: If argument is provided the function populates the |
|---|
| 203 | | - * total number of IRQs created by objects in the DPRC. |
|---|
| 225 | + * @alloc_interrupts: if true the function allocates the interrupt pool, |
|---|
| 226 | + * otherwise the interrupt allocation is delayed |
|---|
| 204 | 227 | * |
|---|
| 205 | 228 | * Detects objects added and removed from a DPRC and synchronizes the |
|---|
| 206 | 229 | * state of the Linux bus driver, MC by adding and removing |
|---|
| .. | .. |
|---|
| 215 | 238 | * of the device drivers for the non-allocatable devices. |
|---|
| 216 | 239 | */ |
|---|
| 217 | 240 | static int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev, |
|---|
| 218 | | - unsigned int *total_irq_count) |
|---|
| 241 | + bool alloc_interrupts) |
|---|
| 219 | 242 | { |
|---|
| 220 | 243 | int num_child_objects; |
|---|
| 221 | 244 | int dprc_get_obj_failures; |
|---|
| .. | .. |
|---|
| 296 | 319 | * Allocate IRQ's before binding the scanned devices with their |
|---|
| 297 | 320 | * respective drivers. |
|---|
| 298 | 321 | */ |
|---|
| 299 | | - if (dev_get_msi_domain(&mc_bus_dev->dev) && !mc_bus->irq_resources) { |
|---|
| 322 | + if (dev_get_msi_domain(&mc_bus_dev->dev)) { |
|---|
| 300 | 323 | if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) { |
|---|
| 301 | 324 | dev_warn(&mc_bus_dev->dev, |
|---|
| 302 | 325 | "IRQs needed (%u) exceed IRQs preallocated (%u)\n", |
|---|
| 303 | 326 | irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS); |
|---|
| 304 | 327 | } |
|---|
| 305 | 328 | |
|---|
| 306 | | - error = fsl_mc_populate_irq_pool(mc_bus, |
|---|
| 307 | | - FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS); |
|---|
| 308 | | - if (error < 0) |
|---|
| 309 | | - return error; |
|---|
| 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 | + } |
|---|
| 310 | 335 | } |
|---|
| 311 | | - |
|---|
| 312 | | - if (total_irq_count) |
|---|
| 313 | | - *total_irq_count = irq_count; |
|---|
| 314 | 336 | |
|---|
| 315 | 337 | dprc_remove_devices(mc_bus_dev, child_obj_desc_array, |
|---|
| 316 | 338 | num_child_objects); |
|---|
| .. | .. |
|---|
| 333 | 355 | * bus driver with the actual state of the MC by adding and removing |
|---|
| 334 | 356 | * devices as appropriate. |
|---|
| 335 | 357 | */ |
|---|
| 336 | | -static int dprc_scan_container(struct fsl_mc_device *mc_bus_dev) |
|---|
| 358 | +int dprc_scan_container(struct fsl_mc_device *mc_bus_dev, |
|---|
| 359 | + bool alloc_interrupts) |
|---|
| 337 | 360 | { |
|---|
| 338 | | - int error; |
|---|
| 361 | + int error = 0; |
|---|
| 339 | 362 | struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); |
|---|
| 340 | 363 | |
|---|
| 341 | 364 | fsl_mc_init_all_resource_pools(mc_bus_dev); |
|---|
| .. | .. |
|---|
| 344 | 367 | * Discover objects in the DPRC: |
|---|
| 345 | 368 | */ |
|---|
| 346 | 369 | mutex_lock(&mc_bus->scan_mutex); |
|---|
| 347 | | - error = dprc_scan_objects(mc_bus_dev, NULL); |
|---|
| 370 | + error = dprc_scan_objects(mc_bus_dev, alloc_interrupts); |
|---|
| 348 | 371 | mutex_unlock(&mc_bus->scan_mutex); |
|---|
| 349 | | - if (error < 0) { |
|---|
| 350 | | - fsl_mc_cleanup_all_resource_pools(mc_bus_dev); |
|---|
| 351 | | - return error; |
|---|
| 352 | | - } |
|---|
| 353 | 372 | |
|---|
| 354 | | - return 0; |
|---|
| 373 | + return error; |
|---|
| 355 | 374 | } |
|---|
| 356 | | - |
|---|
| 375 | +EXPORT_SYMBOL_GPL(dprc_scan_container); |
|---|
| 357 | 376 | /** |
|---|
| 358 | 377 | * dprc_irq0_handler - Regular ISR for DPRC interrupt 0 |
|---|
| 359 | 378 | * |
|---|
| .. | .. |
|---|
| 413 | 432 | DPRC_IRQ_EVENT_CONTAINER_DESTROYED | |
|---|
| 414 | 433 | DPRC_IRQ_EVENT_OBJ_DESTROYED | |
|---|
| 415 | 434 | DPRC_IRQ_EVENT_OBJ_CREATED)) { |
|---|
| 416 | | - unsigned int irq_count; |
|---|
| 417 | 435 | |
|---|
| 418 | | - error = dprc_scan_objects(mc_dev, &irq_count); |
|---|
| 436 | + error = dprc_scan_objects(mc_dev, true); |
|---|
| 419 | 437 | if (error < 0) { |
|---|
| 420 | 438 | /* |
|---|
| 421 | 439 | * If the error is -ENXIO, we ignore it, as it indicates |
|---|
| .. | .. |
|---|
| 429 | 447 | } |
|---|
| 430 | 448 | |
|---|
| 431 | 449 | goto out; |
|---|
| 432 | | - } |
|---|
| 433 | | - |
|---|
| 434 | | - if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) { |
|---|
| 435 | | - dev_warn(dev, |
|---|
| 436 | | - "IRQs needed (%u) exceed IRQs preallocated (%u)\n", |
|---|
| 437 | | - irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS); |
|---|
| 438 | 450 | } |
|---|
| 439 | 451 | } |
|---|
| 440 | 452 | |
|---|
| .. | .. |
|---|
| 576 | 588 | } |
|---|
| 577 | 589 | |
|---|
| 578 | 590 | /** |
|---|
| 579 | | - * dprc_probe - callback invoked when a DPRC is being bound to this driver |
|---|
| 591 | + * dprc_setup - opens and creates a mc_io for DPRC |
|---|
| 580 | 592 | * |
|---|
| 581 | 593 | * @mc_dev: Pointer to fsl-mc device representing a DPRC |
|---|
| 582 | 594 | * |
|---|
| 583 | 595 | * It opens the physical DPRC in the MC. |
|---|
| 584 | | - * It scans the DPRC to discover the MC objects contained in it. |
|---|
| 585 | | - * It creates the interrupt pool for the MC bus associated with the DPRC. |
|---|
| 586 | | - * It configures the interrupts for the DPRC device itself. |
|---|
| 596 | + * It configures the DPRC portal used to communicate with MC |
|---|
| 587 | 597 | */ |
|---|
| 588 | | -static int dprc_probe(struct fsl_mc_device *mc_dev) |
|---|
| 598 | + |
|---|
| 599 | +int dprc_setup(struct fsl_mc_device *mc_dev) |
|---|
| 589 | 600 | { |
|---|
| 590 | | - int error; |
|---|
| 591 | | - size_t region_size; |
|---|
| 592 | 601 | struct device *parent_dev = mc_dev->dev.parent; |
|---|
| 593 | 602 | struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); |
|---|
| 603 | + struct irq_domain *mc_msi_domain; |
|---|
| 594 | 604 | bool mc_io_created = false; |
|---|
| 595 | 605 | bool msi_domain_set = false; |
|---|
| 596 | 606 | u16 major_ver, minor_ver; |
|---|
| 607 | + size_t region_size; |
|---|
| 608 | + int error; |
|---|
| 597 | 609 | |
|---|
| 598 | 610 | if (!is_fsl_mc_bus_dprc(mc_dev)) |
|---|
| 599 | 611 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 623 | 635 | return error; |
|---|
| 624 | 636 | |
|---|
| 625 | 637 | mc_io_created = true; |
|---|
| 638 | + } |
|---|
| 626 | 639 | |
|---|
| 627 | | - /* |
|---|
| 628 | | - * Inherit parent MSI domain: |
|---|
| 629 | | - */ |
|---|
| 630 | | - dev_set_msi_domain(&mc_dev->dev, |
|---|
| 631 | | - dev_get_msi_domain(parent_dev)); |
|---|
| 632 | | - msi_domain_set = true; |
|---|
| 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"); |
|---|
| 633 | 644 | } else { |
|---|
| 634 | | - /* |
|---|
| 635 | | - * This is a root DPRC |
|---|
| 636 | | - */ |
|---|
| 637 | | - struct irq_domain *mc_msi_domain; |
|---|
| 638 | | - |
|---|
| 639 | | - if (dev_is_fsl_mc(parent_dev)) |
|---|
| 640 | | - return -EINVAL; |
|---|
| 641 | | - |
|---|
| 642 | | - error = fsl_mc_find_msi_domain(parent_dev, |
|---|
| 643 | | - &mc_msi_domain); |
|---|
| 644 | | - if (error < 0) { |
|---|
| 645 | | - dev_warn(&mc_dev->dev, |
|---|
| 646 | | - "WARNING: MC bus without interrupt support\n"); |
|---|
| 647 | | - } else { |
|---|
| 648 | | - dev_set_msi_domain(&mc_dev->dev, mc_msi_domain); |
|---|
| 649 | | - msi_domain_set = true; |
|---|
| 650 | | - } |
|---|
| 645 | + dev_set_msi_domain(&mc_dev->dev, mc_msi_domain); |
|---|
| 646 | + msi_domain_set = true; |
|---|
| 651 | 647 | } |
|---|
| 652 | 648 | |
|---|
| 653 | 649 | error = dprc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id, |
|---|
| .. | .. |
|---|
| 684 | 680 | goto error_cleanup_open; |
|---|
| 685 | 681 | } |
|---|
| 686 | 682 | |
|---|
| 687 | | - mutex_init(&mc_bus->scan_mutex); |
|---|
| 688 | | - |
|---|
| 689 | | - /* |
|---|
| 690 | | - * Discover MC objects in DPRC object: |
|---|
| 691 | | - */ |
|---|
| 692 | | - error = dprc_scan_container(mc_dev); |
|---|
| 693 | | - if (error < 0) |
|---|
| 694 | | - goto error_cleanup_open; |
|---|
| 695 | | - |
|---|
| 696 | | - /* |
|---|
| 697 | | - * Configure interrupt for the DPRC object associated with this MC bus: |
|---|
| 698 | | - */ |
|---|
| 699 | | - error = dprc_setup_irq(mc_dev); |
|---|
| 700 | | - if (error < 0) |
|---|
| 701 | | - goto error_cleanup_open; |
|---|
| 702 | | - |
|---|
| 703 | | - dev_info(&mc_dev->dev, "DPRC device bound to driver"); |
|---|
| 704 | 683 | return 0; |
|---|
| 705 | 684 | |
|---|
| 706 | 685 | error_cleanup_open: |
|---|
| .. | .. |
|---|
| 715 | 694 | mc_dev->mc_io = NULL; |
|---|
| 716 | 695 | } |
|---|
| 717 | 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); |
|---|
| 718 | 740 | return error; |
|---|
| 719 | 741 | } |
|---|
| 720 | 742 | |
|---|
| .. | .. |
|---|
| 733 | 755 | } |
|---|
| 734 | 756 | |
|---|
| 735 | 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 | +/** |
|---|
| 736 | 805 | * dprc_remove - callback invoked when a DPRC is being unbound from this driver |
|---|
| 737 | 806 | * |
|---|
| 738 | 807 | * @mc_dev: Pointer to fsl-mc device representing the DPRC |
|---|
| .. | .. |
|---|
| 744 | 813 | */ |
|---|
| 745 | 814 | static int dprc_remove(struct fsl_mc_device *mc_dev) |
|---|
| 746 | 815 | { |
|---|
| 747 | | - int error; |
|---|
| 748 | 816 | struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); |
|---|
| 749 | 817 | |
|---|
| 750 | 818 | if (!is_fsl_mc_bus_dprc(mc_dev)) |
|---|
| 751 | | - return -EINVAL; |
|---|
| 752 | | - if (!mc_dev->mc_io) |
|---|
| 753 | 819 | return -EINVAL; |
|---|
| 754 | 820 | |
|---|
| 755 | 821 | if (!mc_bus->irq_resources) |
|---|
| .. | .. |
|---|
| 760 | 826 | |
|---|
| 761 | 827 | device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove); |
|---|
| 762 | 828 | |
|---|
| 763 | | - if (dev_get_msi_domain(&mc_dev->dev)) { |
|---|
| 764 | | - fsl_mc_cleanup_irq_pool(mc_bus); |
|---|
| 765 | | - dev_set_msi_domain(&mc_dev->dev, NULL); |
|---|
| 766 | | - } |
|---|
| 767 | | - |
|---|
| 768 | | - fsl_mc_cleanup_all_resource_pools(mc_dev); |
|---|
| 769 | | - |
|---|
| 770 | | - error = dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); |
|---|
| 771 | | - if (error < 0) |
|---|
| 772 | | - dev_err(&mc_dev->dev, "dprc_close() failed: %d\n", error); |
|---|
| 773 | | - |
|---|
| 774 | | - if (!fsl_mc_is_root_dprc(&mc_dev->dev)) { |
|---|
| 775 | | - fsl_destroy_mc_io(mc_dev->mc_io); |
|---|
| 776 | | - mc_dev->mc_io = NULL; |
|---|
| 777 | | - } |
|---|
| 829 | + dprc_cleanup(mc_dev); |
|---|
| 778 | 830 | |
|---|
| 779 | 831 | dev_info(&mc_dev->dev, "DPRC device unbound from driver"); |
|---|
| 780 | 832 | return 0; |
|---|