1/* 2 * Freescale Management Complex (MC) bus driver 3 * 4 * Copyright (C) 2014 Freescale Semiconductor, Inc. 5 * Author: German Rivera <German.Rivera@freescale.com> 6 * 7 * This file is licensed under the terms of the GNU General Public 8 * License version 2. This program is licensed "as is" without any 9 * warranty of any kind, whether express or implied. 10 */ 11 12#include "../include/mc-private.h" 13#include <linux/module.h> 14#include <linux/of_device.h> 15#include <linux/of_address.h> 16#include <linux/ioport.h> 17#include <linux/slab.h> 18#include <linux/limits.h> 19#include "../include/dpmng.h" 20#include "../include/mc-sys.h" 21#include "dprc-cmd.h" 22 23static struct kmem_cache *mc_dev_cache; 24 25/** 26 * fsl_mc_bus_match - device to driver matching callback 27 * @dev: the MC object device structure to match against 28 * @drv: the device driver to search for matching MC object device id 29 * structures 30 * 31 * Returns 1 on success, 0 otherwise. 32 */ 33static int fsl_mc_bus_match(struct device *dev, struct device_driver *drv) 34{ 35 const struct fsl_mc_device_match_id *id; 36 struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); 37 struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(drv); 38 bool found = false; 39 bool major_version_mismatch = false; 40 bool minor_version_mismatch = false; 41 42 if (WARN_ON(!fsl_mc_bus_type.dev_root)) 43 goto out; 44 45 if (!mc_drv->match_id_table) 46 goto out; 47 48 /* 49 * If the object is not 'plugged' don't match. 50 * Only exception is the root DPRC, which is a special case. 51 */ 52 if ((mc_dev->obj_desc.state & DPRC_OBJ_STATE_PLUGGED) == 0 && 53 &mc_dev->dev != fsl_mc_bus_type.dev_root) 54 goto out; 55 56 /* 57 * Traverse the match_id table of the given driver, trying to find 58 * a matching for the given MC object device. 59 */ 60 for (id = mc_drv->match_id_table; id->vendor != 0x0; id++) { 61 if (id->vendor == mc_dev->obj_desc.vendor && 62 strcmp(id->obj_type, mc_dev->obj_desc.type) == 0) { 63 if (id->ver_major == mc_dev->obj_desc.ver_major) { 64 found = true; 65 if (id->ver_minor != mc_dev->obj_desc.ver_minor) 66 minor_version_mismatch = true; 67 } else { 68 major_version_mismatch = true; 69 } 70 71 break; 72 } 73 } 74 75 if (major_version_mismatch) { 76 dev_warn(dev, 77 "Major version mismatch: driver version %u.%u, MC object version %u.%u\n", 78 id->ver_major, id->ver_minor, 79 mc_dev->obj_desc.ver_major, 80 mc_dev->obj_desc.ver_minor); 81 } else if (minor_version_mismatch) { 82 dev_warn(dev, 83 "Minor version mismatch: driver version %u.%u, MC object version %u.%u\n", 84 id->ver_major, id->ver_minor, 85 mc_dev->obj_desc.ver_major, 86 mc_dev->obj_desc.ver_minor); 87 } 88 89out: 90 dev_dbg(dev, "%smatched\n", found ? "" : "not "); 91 return found; 92} 93 94/** 95 * fsl_mc_bus_uevent - callback invoked when a device is added 96 */ 97static int fsl_mc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) 98{ 99 pr_debug("%s invoked\n", __func__); 100 return 0; 101} 102 103struct bus_type fsl_mc_bus_type = { 104 .name = "fsl-mc", 105 .match = fsl_mc_bus_match, 106 .uevent = fsl_mc_bus_uevent, 107}; 108EXPORT_SYMBOL_GPL(fsl_mc_bus_type); 109 110static int fsl_mc_driver_probe(struct device *dev) 111{ 112 struct fsl_mc_driver *mc_drv; 113 struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); 114 int error; 115 116 if (WARN_ON(!dev->driver)) 117 return -EINVAL; 118 119 mc_drv = to_fsl_mc_driver(dev->driver); 120 if (WARN_ON(!mc_drv->probe)) 121 return -EINVAL; 122 123 error = mc_drv->probe(mc_dev); 124 if (error < 0) { 125 dev_err(dev, "MC object device probe callback failed: %d\n", 126 error); 127 return error; 128 } 129 130 return 0; 131} 132 133static int fsl_mc_driver_remove(struct device *dev) 134{ 135 struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver); 136 struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); 137 int error; 138 139 if (WARN_ON(!dev->driver)) 140 return -EINVAL; 141 142 error = mc_drv->remove(mc_dev); 143 if (error < 0) { 144 dev_err(dev, 145 "MC object device remove callback failed: %d\n", 146 error); 147 return error; 148 } 149 150 return 0; 151} 152 153static void fsl_mc_driver_shutdown(struct device *dev) 154{ 155 struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver); 156 struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); 157 158 mc_drv->shutdown(mc_dev); 159} 160 161/** 162 * __fsl_mc_driver_register - registers a child device driver with the 163 * MC bus 164 * 165 * This function is implicitly invoked from the registration function of 166 * fsl_mc device drivers, which is generated by the 167 * module_fsl_mc_driver() macro. 168 */ 169int __fsl_mc_driver_register(struct fsl_mc_driver *mc_driver, 170 struct module *owner) 171{ 172 int error; 173 174 mc_driver->driver.owner = owner; 175 mc_driver->driver.bus = &fsl_mc_bus_type; 176 177 if (mc_driver->probe) 178 mc_driver->driver.probe = fsl_mc_driver_probe; 179 180 if (mc_driver->remove) 181 mc_driver->driver.remove = fsl_mc_driver_remove; 182 183 if (mc_driver->shutdown) 184 mc_driver->driver.shutdown = fsl_mc_driver_shutdown; 185 186 error = driver_register(&mc_driver->driver); 187 if (error < 0) { 188 pr_err("driver_register() failed for %s: %d\n", 189 mc_driver->driver.name, error); 190 return error; 191 } 192 193 pr_info("MC object device driver %s registered\n", 194 mc_driver->driver.name); 195 return 0; 196} 197EXPORT_SYMBOL_GPL(__fsl_mc_driver_register); 198 199/** 200 * fsl_mc_driver_unregister - unregisters a device driver from the 201 * MC bus 202 */ 203void fsl_mc_driver_unregister(struct fsl_mc_driver *mc_driver) 204{ 205 driver_unregister(&mc_driver->driver); 206} 207EXPORT_SYMBOL_GPL(fsl_mc_driver_unregister); 208 209static int get_dprc_icid(struct fsl_mc_io *mc_io, 210 int container_id, uint16_t *icid) 211{ 212 uint16_t dprc_handle; 213 struct dprc_attributes attr; 214 int error; 215 216 error = dprc_open(mc_io, container_id, &dprc_handle); 217 if (error < 0) { 218 pr_err("dprc_open() failed: %d\n", error); 219 return error; 220 } 221 222 memset(&attr, 0, sizeof(attr)); 223 error = dprc_get_attributes(mc_io, dprc_handle, &attr); 224 if (error < 0) { 225 pr_err("dprc_get_attributes() failed: %d\n", error); 226 goto common_cleanup; 227 } 228 229 *icid = attr.icid; 230 error = 0; 231 232common_cleanup: 233 (void)dprc_close(mc_io, dprc_handle); 234 return error; 235} 236 237static int translate_mc_addr(uint64_t mc_addr, phys_addr_t *phys_addr) 238{ 239 int i; 240 struct fsl_mc *mc = dev_get_drvdata(fsl_mc_bus_type.dev_root->parent); 241 242 if (mc->num_translation_ranges == 0) { 243 /* 244 * Do identity mapping: 245 */ 246 *phys_addr = mc_addr; 247 return 0; 248 } 249 250 for (i = 0; i < mc->num_translation_ranges; i++) { 251 struct fsl_mc_addr_translation_range *range = 252 &mc->translation_ranges[i]; 253 254 if (mc_addr >= range->start_mc_addr && 255 mc_addr < range->end_mc_addr) { 256 *phys_addr = range->start_phys_addr + 257 (mc_addr - range->start_mc_addr); 258 return 0; 259 } 260 } 261 262 return -EFAULT; 263} 264 265static int fsl_mc_device_get_mmio_regions(struct fsl_mc_device *mc_dev, 266 struct fsl_mc_device *mc_bus_dev) 267{ 268 int i; 269 int error; 270 struct resource *regions; 271 struct dprc_obj_desc *obj_desc = &mc_dev->obj_desc; 272 struct device *parent_dev = mc_dev->dev.parent; 273 274 regions = kmalloc_array(obj_desc->region_count, 275 sizeof(regions[0]), GFP_KERNEL); 276 if (!regions) 277 return -ENOMEM; 278 279 for (i = 0; i < obj_desc->region_count; i++) { 280 struct dprc_region_desc region_desc; 281 282 error = dprc_get_obj_region(mc_bus_dev->mc_io, 283 mc_bus_dev->mc_handle, 284 obj_desc->type, 285 obj_desc->id, i, ®ion_desc); 286 if (error < 0) { 287 dev_err(parent_dev, 288 "dprc_get_obj_region() failed: %d\n", error); 289 goto error_cleanup_regions; 290 } 291 292 WARN_ON(region_desc.base_paddr == 0x0); 293 WARN_ON(region_desc.size == 0); 294 error = translate_mc_addr(region_desc.base_paddr, 295 ®ions[i].start); 296 if (error < 0) { 297 dev_err(parent_dev, 298 "Invalid MC address: %#llx\n", 299 region_desc.base_paddr); 300 goto error_cleanup_regions; 301 } 302 303 regions[i].end = regions[i].start + region_desc.size - 1; 304 regions[i].name = "fsl-mc object MMIO region"; 305 regions[i].flags = IORESOURCE_IO; 306 } 307 308 mc_dev->regions = regions; 309 return 0; 310 311error_cleanup_regions: 312 kfree(regions); 313 return error; 314} 315 316/** 317 * Add a newly discovered MC object device to be visible in Linux 318 */ 319int fsl_mc_device_add(struct dprc_obj_desc *obj_desc, 320 struct fsl_mc_io *mc_io, 321 struct device *parent_dev, 322 struct fsl_mc_device **new_mc_dev) 323{ 324 int error; 325 struct fsl_mc_device *mc_dev = NULL; 326 struct fsl_mc_bus *mc_bus = NULL; 327 struct fsl_mc_device *parent_mc_dev; 328 329 if (parent_dev->bus == &fsl_mc_bus_type) 330 parent_mc_dev = to_fsl_mc_device(parent_dev); 331 else 332 parent_mc_dev = NULL; 333 334 if (strcmp(obj_desc->type, "dprc") == 0) { 335 /* 336 * Allocate an MC bus device object: 337 */ 338 mc_bus = devm_kzalloc(parent_dev, sizeof(*mc_bus), GFP_KERNEL); 339 if (!mc_bus) 340 return -ENOMEM; 341 342 mc_dev = &mc_bus->mc_dev; 343 } else { 344 /* 345 * Allocate a regular fsl_mc_device object: 346 */ 347 mc_dev = kmem_cache_zalloc(mc_dev_cache, GFP_KERNEL); 348 if (!mc_dev) 349 return -ENOMEM; 350 } 351 352 mc_dev->obj_desc = *obj_desc; 353 mc_dev->mc_io = mc_io; 354 device_initialize(&mc_dev->dev); 355 mc_dev->dev.parent = parent_dev; 356 mc_dev->dev.bus = &fsl_mc_bus_type; 357 dev_set_name(&mc_dev->dev, "%s.%d", obj_desc->type, obj_desc->id); 358 359 if (strcmp(obj_desc->type, "dprc") == 0) { 360 struct fsl_mc_io *mc_io2; 361 362 mc_dev->flags |= FSL_MC_IS_DPRC; 363 364 /* 365 * To get the DPRC's ICID, we need to open the DPRC 366 * in get_dprc_icid(). For child DPRCs, we do so using the 367 * parent DPRC's MC portal instead of the child DPRC's MC 368 * portal, in case the child DPRC is already opened with 369 * its own portal (e.g., the DPRC used by AIOP). 370 * 371 * NOTE: There cannot be more than one active open for a 372 * given MC object, using the same MC portal. 373 */ 374 if (parent_mc_dev) { 375 /* 376 * device being added is a child DPRC device 377 */ 378 mc_io2 = parent_mc_dev->mc_io; 379 } else { 380 /* 381 * device being added is the root DPRC device 382 */ 383 if (WARN_ON(!mc_io)) { 384 error = -EINVAL; 385 goto error_cleanup_dev; 386 } 387 388 mc_io2 = mc_io; 389 390 if (!fsl_mc_bus_type.dev_root) 391 fsl_mc_bus_type.dev_root = &mc_dev->dev; 392 } 393 394 error = get_dprc_icid(mc_io2, obj_desc->id, &mc_dev->icid); 395 if (error < 0) 396 goto error_cleanup_dev; 397 } else { 398 /* 399 * A non-DPRC MC object device has to be a child of another 400 * MC object (specifically a DPRC object) 401 */ 402 mc_dev->icid = parent_mc_dev->icid; 403 mc_dev->dma_mask = FSL_MC_DEFAULT_DMA_MASK; 404 mc_dev->dev.dma_mask = &mc_dev->dma_mask; 405 } 406 407 /* 408 * Get MMIO regions for the device from the MC: 409 * 410 * NOTE: the root DPRC is a special case as its MMIO region is 411 * obtained from the device tree 412 */ 413 if (parent_mc_dev && obj_desc->region_count != 0) { 414 error = fsl_mc_device_get_mmio_regions(mc_dev, 415 parent_mc_dev); 416 if (error < 0) 417 goto error_cleanup_dev; 418 } 419 420 /* 421 * The device-specific probe callback will get invoked by device_add() 422 */ 423 error = device_add(&mc_dev->dev); 424 if (error < 0) { 425 dev_err(parent_dev, 426 "device_add() failed for device %s: %d\n", 427 dev_name(&mc_dev->dev), error); 428 goto error_cleanup_dev; 429 } 430 431 (void)get_device(&mc_dev->dev); 432 dev_dbg(parent_dev, "Added MC object device %s\n", 433 dev_name(&mc_dev->dev)); 434 435 *new_mc_dev = mc_dev; 436 return 0; 437 438error_cleanup_dev: 439 kfree(mc_dev->regions); 440 if (mc_bus) 441 devm_kfree(parent_dev, mc_bus); 442 else 443 kmem_cache_free(mc_dev_cache, mc_dev); 444 445 return error; 446} 447EXPORT_SYMBOL_GPL(fsl_mc_device_add); 448 449/** 450 * fsl_mc_device_remove - Remove a MC object device from being visible to 451 * Linux 452 * 453 * @mc_dev: Pointer to a MC object device object 454 */ 455void fsl_mc_device_remove(struct fsl_mc_device *mc_dev) 456{ 457 struct fsl_mc_bus *mc_bus = NULL; 458 459 kfree(mc_dev->regions); 460 461 /* 462 * The device-specific remove callback will get invoked by device_del() 463 */ 464 device_del(&mc_dev->dev); 465 put_device(&mc_dev->dev); 466 467 if (strcmp(mc_dev->obj_desc.type, "dprc") == 0) { 468 mc_bus = to_fsl_mc_bus(mc_dev); 469 if (mc_dev->mc_io) { 470 fsl_destroy_mc_io(mc_dev->mc_io); 471 mc_dev->mc_io = NULL; 472 } 473 474 if (&mc_dev->dev == fsl_mc_bus_type.dev_root) 475 fsl_mc_bus_type.dev_root = NULL; 476 } 477 478 if (mc_bus) 479 devm_kfree(mc_dev->dev.parent, mc_bus); 480 else 481 kmem_cache_free(mc_dev_cache, mc_dev); 482} 483EXPORT_SYMBOL_GPL(fsl_mc_device_remove); 484 485static int parse_mc_ranges(struct device *dev, 486 int *paddr_cells, 487 int *mc_addr_cells, 488 int *mc_size_cells, 489 const __be32 **ranges_start, 490 uint8_t *num_ranges) 491{ 492 const __be32 *prop; 493 int range_tuple_cell_count; 494 int ranges_len; 495 int tuple_len; 496 struct device_node *mc_node = dev->of_node; 497 498 *ranges_start = of_get_property(mc_node, "ranges", &ranges_len); 499 if (!(*ranges_start) || !ranges_len) { 500 dev_warn(dev, 501 "missing or empty ranges property for device tree node '%s'\n", 502 mc_node->name); 503 504 *num_ranges = 0; 505 return 0; 506 } 507 508 *paddr_cells = of_n_addr_cells(mc_node); 509 510 prop = of_get_property(mc_node, "#address-cells", NULL); 511 if (prop) 512 *mc_addr_cells = be32_to_cpup(prop); 513 else 514 *mc_addr_cells = *paddr_cells; 515 516 prop = of_get_property(mc_node, "#size-cells", NULL); 517 if (prop) 518 *mc_size_cells = be32_to_cpup(prop); 519 else 520 *mc_size_cells = of_n_size_cells(mc_node); 521 522 range_tuple_cell_count = *paddr_cells + *mc_addr_cells + 523 *mc_size_cells; 524 525 tuple_len = range_tuple_cell_count * sizeof(__be32); 526 if (ranges_len % tuple_len != 0) { 527 dev_err(dev, "malformed ranges property '%s'\n", mc_node->name); 528 return -EINVAL; 529 } 530 531 *num_ranges = ranges_len / tuple_len; 532 return 0; 533} 534 535static int get_mc_addr_translation_ranges(struct device *dev, 536 struct fsl_mc_addr_translation_range 537 **ranges, 538 uint8_t *num_ranges) 539{ 540 int error; 541 int paddr_cells; 542 int mc_addr_cells; 543 int mc_size_cells; 544 int i; 545 const __be32 *ranges_start; 546 const __be32 *cell; 547 548 error = parse_mc_ranges(dev, 549 &paddr_cells, 550 &mc_addr_cells, 551 &mc_size_cells, 552 &ranges_start, 553 num_ranges); 554 if (error < 0) 555 return error; 556 557 if (!(*num_ranges)) { 558 /* 559 * Missing or empty ranges property ("ranges;") for the 560 * 'fsl,qoriq-mc' node. In this case, identity mapping 561 * will be used. 562 */ 563 *ranges = NULL; 564 return 0; 565 } 566 567 *ranges = devm_kcalloc(dev, *num_ranges, 568 sizeof(struct fsl_mc_addr_translation_range), 569 GFP_KERNEL); 570 if (!(*ranges)) 571 return -ENOMEM; 572 573 cell = ranges_start; 574 for (i = 0; i < *num_ranges; ++i) { 575 struct fsl_mc_addr_translation_range *range = &(*ranges)[i]; 576 577 range->start_mc_addr = of_read_number(cell, mc_addr_cells); 578 cell += mc_addr_cells; 579 range->start_phys_addr = of_read_number(cell, paddr_cells); 580 cell += paddr_cells; 581 range->end_mc_addr = range->start_mc_addr + 582 of_read_number(cell, mc_size_cells); 583 584 cell += mc_size_cells; 585 } 586 587 return 0; 588} 589 590/** 591 * fsl_mc_bus_probe - callback invoked when the root MC bus is being 592 * added 593 */ 594static int fsl_mc_bus_probe(struct platform_device *pdev) 595{ 596 struct dprc_obj_desc obj_desc; 597 int error; 598 struct fsl_mc *mc; 599 struct fsl_mc_device *mc_bus_dev = NULL; 600 struct fsl_mc_io *mc_io = NULL; 601 int container_id; 602 phys_addr_t mc_portal_phys_addr; 603 uint32_t mc_portal_size; 604 struct mc_version mc_version; 605 struct resource res; 606 607 dev_info(&pdev->dev, "Root MC bus device probed"); 608 609 mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL); 610 if (!mc) 611 return -ENOMEM; 612 613 platform_set_drvdata(pdev, mc); 614 615 /* 616 * Get physical address of MC portal for the root DPRC: 617 */ 618 error = of_address_to_resource(pdev->dev.of_node, 0, &res); 619 if (error < 0) { 620 dev_err(&pdev->dev, 621 "of_address_to_resource() failed for %s\n", 622 pdev->dev.of_node->full_name); 623 return error; 624 } 625 626 mc_portal_phys_addr = res.start; 627 mc_portal_size = resource_size(&res); 628 error = fsl_create_mc_io(&pdev->dev, mc_portal_phys_addr, 629 mc_portal_size, NULL, 0, &mc_io); 630 if (error < 0) 631 return error; 632 633 error = mc_get_version(mc_io, &mc_version); 634 if (error != 0) { 635 dev_err(&pdev->dev, 636 "mc_get_version() failed with error %d\n", error); 637 goto error_cleanup_mc_io; 638 } 639 640 dev_info(&pdev->dev, 641 "Freescale Management Complex Firmware version: %u.%u.%u\n", 642 mc_version.major, mc_version.minor, mc_version.revision); 643 644 if (mc_version.major < MC_VER_MAJOR) { 645 dev_err(&pdev->dev, 646 "ERROR: MC firmware version not supported by driver (driver version: %u.%u)\n", 647 MC_VER_MAJOR, MC_VER_MINOR); 648 error = -ENOTSUPP; 649 goto error_cleanup_mc_io; 650 } 651 652 if (mc_version.major > MC_VER_MAJOR) { 653 dev_warn(&pdev->dev, 654 "WARNING: driver may not support newer MC firmware features (driver version: %u.%u)\n", 655 MC_VER_MAJOR, MC_VER_MINOR); 656 } 657 658 error = get_mc_addr_translation_ranges(&pdev->dev, 659 &mc->translation_ranges, 660 &mc->num_translation_ranges); 661 if (error < 0) 662 goto error_cleanup_mc_io; 663 664 error = dpmng_get_container_id(mc_io, &container_id); 665 if (error < 0) { 666 dev_err(&pdev->dev, 667 "dpmng_get_container_id() failed: %d\n", error); 668 goto error_cleanup_mc_io; 669 } 670 671 obj_desc.vendor = FSL_MC_VENDOR_FREESCALE; 672 strcpy(obj_desc.type, "dprc"); 673 obj_desc.id = container_id; 674 obj_desc.ver_major = DPRC_VER_MAJOR; 675 obj_desc.ver_minor = DPRC_VER_MINOR; 676 obj_desc.region_count = 0; 677 678 error = fsl_mc_device_add(&obj_desc, mc_io, &pdev->dev, &mc_bus_dev); 679 if (error < 0) 680 goto error_cleanup_mc_io; 681 682 mc->root_mc_bus_dev = mc_bus_dev; 683 return 0; 684 685error_cleanup_mc_io: 686 fsl_destroy_mc_io(mc_io); 687 return error; 688} 689 690/** 691 * fsl_mc_bus_remove - callback invoked when the root MC bus is being 692 * removed 693 */ 694static int fsl_mc_bus_remove(struct platform_device *pdev) 695{ 696 struct fsl_mc *mc = platform_get_drvdata(pdev); 697 698 if (WARN_ON(&mc->root_mc_bus_dev->dev != fsl_mc_bus_type.dev_root)) 699 return -EINVAL; 700 701 fsl_mc_device_remove(mc->root_mc_bus_dev); 702 dev_info(&pdev->dev, "Root MC bus device removed"); 703 return 0; 704} 705 706static const struct of_device_id fsl_mc_bus_match_table[] = { 707 {.compatible = "fsl,qoriq-mc",}, 708 {}, 709}; 710 711MODULE_DEVICE_TABLE(of, fsl_mc_bus_match_table); 712 713static struct platform_driver fsl_mc_bus_driver = { 714 .driver = { 715 .name = "fsl_mc_bus", 716 .owner = THIS_MODULE, 717 .pm = NULL, 718 .of_match_table = fsl_mc_bus_match_table, 719 }, 720 .probe = fsl_mc_bus_probe, 721 .remove = fsl_mc_bus_remove, 722}; 723 724static int __init fsl_mc_bus_driver_init(void) 725{ 726 int error; 727 728 mc_dev_cache = kmem_cache_create("fsl_mc_device", 729 sizeof(struct fsl_mc_device), 0, 0, 730 NULL); 731 if (!mc_dev_cache) { 732 pr_err("Could not create fsl_mc_device cache\n"); 733 return -ENOMEM; 734 } 735 736 error = bus_register(&fsl_mc_bus_type); 737 if (error < 0) { 738 pr_err("fsl-mc bus type registration failed: %d\n", error); 739 goto error_cleanup_cache; 740 } 741 742 pr_info("fsl-mc bus type registered\n"); 743 744 error = platform_driver_register(&fsl_mc_bus_driver); 745 if (error < 0) { 746 pr_err("platform_driver_register() failed: %d\n", error); 747 goto error_cleanup_bus; 748 } 749 750 error = dprc_driver_init(); 751 if (error < 0) 752 goto error_cleanup_driver; 753 754 error = fsl_mc_allocator_driver_init(); 755 if (error < 0) 756 goto error_cleanup_dprc_driver; 757 758 return 0; 759 760error_cleanup_dprc_driver: 761 dprc_driver_exit(); 762 763error_cleanup_driver: 764 platform_driver_unregister(&fsl_mc_bus_driver); 765 766error_cleanup_bus: 767 bus_unregister(&fsl_mc_bus_type); 768 769error_cleanup_cache: 770 kmem_cache_destroy(mc_dev_cache); 771 return error; 772} 773 774postcore_initcall(fsl_mc_bus_driver_init); 775 776static void __exit fsl_mc_bus_driver_exit(void) 777{ 778 if (WARN_ON(!mc_dev_cache)) 779 return; 780 781 fsl_mc_allocator_driver_exit(); 782 dprc_driver_exit(); 783 platform_driver_unregister(&fsl_mc_bus_driver); 784 bus_unregister(&fsl_mc_bus_type); 785 kmem_cache_destroy(mc_dev_cache); 786 pr_info("MC bus unregistered\n"); 787} 788 789module_exit(fsl_mc_bus_driver_exit); 790 791MODULE_AUTHOR("Freescale Semiconductor Inc."); 792MODULE_DESCRIPTION("Freescale Management Complex (MC) bus driver"); 793MODULE_LICENSE("GPL"); 794