1 /* 2 * Intel(R) Trace Hub driver core 3 * 4 * Copyright (C) 2014-2015 Intel Corporation. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 */ 15 16 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 17 18 #include <linux/types.h> 19 #include <linux/module.h> 20 #include <linux/device.h> 21 #include <linux/sysfs.h> 22 #include <linux/kdev_t.h> 23 #include <linux/debugfs.h> 24 #include <linux/idr.h> 25 #include <linux/pci.h> 26 #include <linux/pm_runtime.h> 27 #include <linux/dma-mapping.h> 28 29 #include "intel_th.h" 30 #include "debug.h" 31 32 static bool host_mode __read_mostly; 33 module_param(host_mode, bool, 0444); 34 35 static DEFINE_IDA(intel_th_ida); 36 37 static int intel_th_match(struct device *dev, struct device_driver *driver) 38 { 39 struct intel_th_driver *thdrv = to_intel_th_driver(driver); 40 struct intel_th_device *thdev = to_intel_th_device(dev); 41 42 if (thdev->type == INTEL_TH_SWITCH && 43 (!thdrv->enable || !thdrv->disable)) 44 return 0; 45 46 return !strcmp(thdev->name, driver->name); 47 } 48 49 static int intel_th_child_remove(struct device *dev, void *data) 50 { 51 device_release_driver(dev); 52 53 return 0; 54 } 55 56 static int intel_th_probe(struct device *dev) 57 { 58 struct intel_th_driver *thdrv = to_intel_th_driver(dev->driver); 59 struct intel_th_device *thdev = to_intel_th_device(dev); 60 struct intel_th_driver *hubdrv; 61 struct intel_th_device *hub = NULL; 62 int ret; 63 64 if (thdev->type == INTEL_TH_SWITCH) 65 hub = thdev; 66 else if (dev->parent) 67 hub = to_intel_th_device(dev->parent); 68 69 if (!hub || !hub->dev.driver) 70 return -EPROBE_DEFER; 71 72 hubdrv = to_intel_th_driver(hub->dev.driver); 73 74 pm_runtime_set_active(dev); 75 pm_runtime_no_callbacks(dev); 76 pm_runtime_enable(dev); 77 78 ret = thdrv->probe(to_intel_th_device(dev)); 79 if (ret) 80 goto out_pm; 81 82 if (thdrv->attr_group) { 83 ret = sysfs_create_group(&thdev->dev.kobj, thdrv->attr_group); 84 if (ret) 85 goto out; 86 } 87 88 if (thdev->type == INTEL_TH_OUTPUT && 89 !intel_th_output_assigned(thdev)) 90 /* does not talk to hardware */ 91 ret = hubdrv->assign(hub, thdev); 92 93 out: 94 if (ret) 95 thdrv->remove(thdev); 96 97 out_pm: 98 if (ret) 99 pm_runtime_disable(dev); 100 101 return ret; 102 } 103 104 static int intel_th_remove(struct device *dev) 105 { 106 struct intel_th_driver *thdrv = to_intel_th_driver(dev->driver); 107 struct intel_th_device *thdev = to_intel_th_device(dev); 108 struct intel_th_device *hub = to_intel_th_device(dev->parent); 109 int err; 110 111 if (thdev->type == INTEL_TH_SWITCH) { 112 err = device_for_each_child(dev, thdev, intel_th_child_remove); 113 if (err) 114 return err; 115 } 116 117 if (thdrv->attr_group) 118 sysfs_remove_group(&thdev->dev.kobj, thdrv->attr_group); 119 120 pm_runtime_get_sync(dev); 121 122 thdrv->remove(thdev); 123 124 if (intel_th_output_assigned(thdev)) { 125 struct intel_th_driver *hubdrv = 126 to_intel_th_driver(dev->parent->driver); 127 128 if (hub->dev.driver) 129 /* does not talk to hardware */ 130 hubdrv->unassign(hub, thdev); 131 } 132 133 pm_runtime_disable(dev); 134 pm_runtime_set_active(dev); 135 pm_runtime_enable(dev); 136 137 return 0; 138 } 139 140 static struct bus_type intel_th_bus = { 141 .name = "intel_th", 142 .dev_attrs = NULL, 143 .match = intel_th_match, 144 .probe = intel_th_probe, 145 .remove = intel_th_remove, 146 }; 147 148 static void intel_th_device_free(struct intel_th_device *thdev); 149 150 static void intel_th_device_release(struct device *dev) 151 { 152 intel_th_device_free(to_intel_th_device(dev)); 153 } 154 155 static struct device_type intel_th_source_device_type = { 156 .name = "intel_th_source_device", 157 .release = intel_th_device_release, 158 }; 159 160 static struct intel_th *to_intel_th(struct intel_th_device *thdev) 161 { 162 /* 163 * subdevice tree is flat: if this one is not a switch, its 164 * parent must be 165 */ 166 if (thdev->type != INTEL_TH_SWITCH) 167 thdev = to_intel_th_hub(thdev); 168 169 if (WARN_ON_ONCE(!thdev || thdev->type != INTEL_TH_SWITCH)) 170 return NULL; 171 172 return dev_get_drvdata(thdev->dev.parent); 173 } 174 175 static char *intel_th_output_devnode(struct device *dev, umode_t *mode, 176 kuid_t *uid, kgid_t *gid) 177 { 178 struct intel_th_device *thdev = to_intel_th_device(dev); 179 struct intel_th *th = to_intel_th(thdev); 180 char *node; 181 182 if (thdev->id >= 0) 183 node = kasprintf(GFP_KERNEL, "intel_th%d/%s%d", th->id, 184 thdev->name, thdev->id); 185 else 186 node = kasprintf(GFP_KERNEL, "intel_th%d/%s", th->id, 187 thdev->name); 188 189 return node; 190 } 191 192 static ssize_t port_show(struct device *dev, struct device_attribute *attr, 193 char *buf) 194 { 195 struct intel_th_device *thdev = to_intel_th_device(dev); 196 197 if (thdev->output.port >= 0) 198 return scnprintf(buf, PAGE_SIZE, "%u\n", thdev->output.port); 199 200 return scnprintf(buf, PAGE_SIZE, "unassigned\n"); 201 } 202 203 static DEVICE_ATTR_RO(port); 204 205 static int intel_th_output_activate(struct intel_th_device *thdev) 206 { 207 struct intel_th_driver *thdrv = 208 to_intel_th_driver_or_null(thdev->dev.driver); 209 int ret = 0; 210 211 if (!thdrv) 212 return -ENODEV; 213 214 if (!try_module_get(thdrv->driver.owner)) 215 return -ENODEV; 216 217 pm_runtime_get_sync(&thdev->dev); 218 219 if (thdrv->activate) 220 ret = thdrv->activate(thdev); 221 else 222 intel_th_trace_enable(thdev); 223 224 if (ret) 225 pm_runtime_put(&thdev->dev); 226 227 return ret; 228 } 229 230 static void intel_th_output_deactivate(struct intel_th_device *thdev) 231 { 232 struct intel_th_driver *thdrv = 233 to_intel_th_driver_or_null(thdev->dev.driver); 234 235 if (!thdrv) 236 return; 237 238 if (thdrv->deactivate) 239 thdrv->deactivate(thdev); 240 else 241 intel_th_trace_disable(thdev); 242 243 pm_runtime_put(&thdev->dev); 244 module_put(thdrv->driver.owner); 245 } 246 247 static ssize_t active_show(struct device *dev, struct device_attribute *attr, 248 char *buf) 249 { 250 struct intel_th_device *thdev = to_intel_th_device(dev); 251 252 return scnprintf(buf, PAGE_SIZE, "%d\n", thdev->output.active); 253 } 254 255 static ssize_t active_store(struct device *dev, struct device_attribute *attr, 256 const char *buf, size_t size) 257 { 258 struct intel_th_device *thdev = to_intel_th_device(dev); 259 unsigned long val; 260 int ret; 261 262 ret = kstrtoul(buf, 10, &val); 263 if (ret) 264 return ret; 265 266 if (!!val != thdev->output.active) { 267 if (val) 268 ret = intel_th_output_activate(thdev); 269 else 270 intel_th_output_deactivate(thdev); 271 } 272 273 return ret ? ret : size; 274 } 275 276 static DEVICE_ATTR_RW(active); 277 278 static struct attribute *intel_th_output_attrs[] = { 279 &dev_attr_port.attr, 280 &dev_attr_active.attr, 281 NULL, 282 }; 283 284 ATTRIBUTE_GROUPS(intel_th_output); 285 286 static struct device_type intel_th_output_device_type = { 287 .name = "intel_th_output_device", 288 .groups = intel_th_output_groups, 289 .release = intel_th_device_release, 290 .devnode = intel_th_output_devnode, 291 }; 292 293 static struct device_type intel_th_switch_device_type = { 294 .name = "intel_th_switch_device", 295 .release = intel_th_device_release, 296 }; 297 298 static struct device_type *intel_th_device_type[] = { 299 [INTEL_TH_SOURCE] = &intel_th_source_device_type, 300 [INTEL_TH_OUTPUT] = &intel_th_output_device_type, 301 [INTEL_TH_SWITCH] = &intel_th_switch_device_type, 302 }; 303 304 int intel_th_driver_register(struct intel_th_driver *thdrv) 305 { 306 if (!thdrv->probe || !thdrv->remove) 307 return -EINVAL; 308 309 thdrv->driver.bus = &intel_th_bus; 310 311 return driver_register(&thdrv->driver); 312 } 313 EXPORT_SYMBOL_GPL(intel_th_driver_register); 314 315 void intel_th_driver_unregister(struct intel_th_driver *thdrv) 316 { 317 driver_unregister(&thdrv->driver); 318 } 319 EXPORT_SYMBOL_GPL(intel_th_driver_unregister); 320 321 static struct intel_th_device * 322 intel_th_device_alloc(struct intel_th *th, unsigned int type, const char *name, 323 int id) 324 { 325 struct device *parent; 326 struct intel_th_device *thdev; 327 328 if (type == INTEL_TH_SWITCH) 329 parent = th->dev; 330 else 331 parent = &th->hub->dev; 332 333 thdev = kzalloc(sizeof(*thdev) + strlen(name) + 1, GFP_KERNEL); 334 if (!thdev) 335 return NULL; 336 337 thdev->id = id; 338 thdev->type = type; 339 340 strcpy(thdev->name, name); 341 device_initialize(&thdev->dev); 342 thdev->dev.bus = &intel_th_bus; 343 thdev->dev.type = intel_th_device_type[type]; 344 thdev->dev.parent = parent; 345 thdev->dev.dma_mask = parent->dma_mask; 346 thdev->dev.dma_parms = parent->dma_parms; 347 dma_set_coherent_mask(&thdev->dev, parent->coherent_dma_mask); 348 if (id >= 0) 349 dev_set_name(&thdev->dev, "%d-%s%d", th->id, name, id); 350 else 351 dev_set_name(&thdev->dev, "%d-%s", th->id, name); 352 353 return thdev; 354 } 355 356 static int intel_th_device_add_resources(struct intel_th_device *thdev, 357 struct resource *res, int nres) 358 { 359 struct resource *r; 360 361 r = kmemdup(res, sizeof(*res) * nres, GFP_KERNEL); 362 if (!r) 363 return -ENOMEM; 364 365 thdev->resource = r; 366 thdev->num_resources = nres; 367 368 return 0; 369 } 370 371 static void intel_th_device_remove(struct intel_th_device *thdev) 372 { 373 device_del(&thdev->dev); 374 put_device(&thdev->dev); 375 } 376 377 static void intel_th_device_free(struct intel_th_device *thdev) 378 { 379 kfree(thdev->resource); 380 kfree(thdev); 381 } 382 383 /* 384 * Intel(R) Trace Hub subdevices 385 */ 386 static const struct intel_th_subdevice { 387 const char *name; 388 struct resource res[3]; 389 unsigned nres; 390 unsigned type; 391 unsigned otype; 392 unsigned scrpd; 393 int id; 394 } intel_th_subdevices[TH_SUBDEVICE_MAX] = { 395 { 396 .nres = 1, 397 .res = { 398 { 399 .start = REG_GTH_OFFSET, 400 .end = REG_GTH_OFFSET + REG_GTH_LENGTH - 1, 401 .flags = IORESOURCE_MEM, 402 }, 403 }, 404 .name = "gth", 405 .type = INTEL_TH_SWITCH, 406 .id = -1, 407 }, 408 { 409 .nres = 2, 410 .res = { 411 { 412 .start = REG_MSU_OFFSET, 413 .end = REG_MSU_OFFSET + REG_MSU_LENGTH - 1, 414 .flags = IORESOURCE_MEM, 415 }, 416 { 417 .start = BUF_MSU_OFFSET, 418 .end = BUF_MSU_OFFSET + BUF_MSU_LENGTH - 1, 419 .flags = IORESOURCE_MEM, 420 }, 421 }, 422 .name = "msc", 423 .id = 0, 424 .type = INTEL_TH_OUTPUT, 425 .otype = GTH_MSU, 426 .scrpd = SCRPD_MEM_IS_PRIM_DEST | SCRPD_MSC0_IS_ENABLED, 427 }, 428 { 429 .nres = 2, 430 .res = { 431 { 432 .start = REG_MSU_OFFSET, 433 .end = REG_MSU_OFFSET + REG_MSU_LENGTH - 1, 434 .flags = IORESOURCE_MEM, 435 }, 436 { 437 .start = BUF_MSU_OFFSET, 438 .end = BUF_MSU_OFFSET + BUF_MSU_LENGTH - 1, 439 .flags = IORESOURCE_MEM, 440 }, 441 }, 442 .name = "msc", 443 .id = 1, 444 .type = INTEL_TH_OUTPUT, 445 .otype = GTH_MSU, 446 .scrpd = SCRPD_MEM_IS_PRIM_DEST | SCRPD_MSC1_IS_ENABLED, 447 }, 448 { 449 .nres = 2, 450 .res = { 451 { 452 .start = REG_STH_OFFSET, 453 .end = REG_STH_OFFSET + REG_STH_LENGTH - 1, 454 .flags = IORESOURCE_MEM, 455 }, 456 { 457 .start = TH_MMIO_SW, 458 .end = 0, 459 .flags = IORESOURCE_MEM, 460 }, 461 }, 462 .id = -1, 463 .name = "sth", 464 .type = INTEL_TH_SOURCE, 465 }, 466 { 467 .nres = 1, 468 .res = { 469 { 470 .start = REG_PTI_OFFSET, 471 .end = REG_PTI_OFFSET + REG_PTI_LENGTH - 1, 472 .flags = IORESOURCE_MEM, 473 }, 474 }, 475 .id = -1, 476 .name = "pti", 477 .type = INTEL_TH_OUTPUT, 478 .otype = GTH_PTI, 479 .scrpd = SCRPD_PTI_IS_PRIM_DEST, 480 }, 481 { 482 .nres = 1, 483 .res = { 484 { 485 .start = REG_DCIH_OFFSET, 486 .end = REG_DCIH_OFFSET + REG_DCIH_LENGTH - 1, 487 .flags = IORESOURCE_MEM, 488 }, 489 }, 490 .id = -1, 491 .name = "dcih", 492 .type = INTEL_TH_OUTPUT, 493 }, 494 }; 495 496 #ifdef CONFIG_MODULES 497 static void __intel_th_request_hub_module(struct work_struct *work) 498 { 499 struct intel_th *th = container_of(work, struct intel_th, 500 request_module_work); 501 502 request_module("intel_th_%s", th->hub->name); 503 } 504 505 static int intel_th_request_hub_module(struct intel_th *th) 506 { 507 INIT_WORK(&th->request_module_work, __intel_th_request_hub_module); 508 schedule_work(&th->request_module_work); 509 510 return 0; 511 } 512 513 static void intel_th_request_hub_module_flush(struct intel_th *th) 514 { 515 flush_work(&th->request_module_work); 516 } 517 #else 518 static inline int intel_th_request_hub_module(struct intel_th *th) 519 { 520 return -EINVAL; 521 } 522 523 static inline void intel_th_request_hub_module_flush(struct intel_th *th) 524 { 525 } 526 #endif /* CONFIG_MODULES */ 527 528 static int intel_th_populate(struct intel_th *th, struct resource *devres, 529 unsigned int ndevres, int irq) 530 { 531 struct resource res[3]; 532 unsigned int req = 0; 533 int src, dst, err; 534 535 /* create devices for each intel_th_subdevice */ 536 for (src = 0, dst = 0; src < ARRAY_SIZE(intel_th_subdevices); src++) { 537 const struct intel_th_subdevice *subdev = 538 &intel_th_subdevices[src]; 539 struct intel_th_device *thdev; 540 int r; 541 542 /* only allow SOURCE and SWITCH devices in host mode */ 543 if (host_mode && subdev->type == INTEL_TH_OUTPUT) 544 continue; 545 546 thdev = intel_th_device_alloc(th, subdev->type, subdev->name, 547 subdev->id); 548 if (!thdev) { 549 err = -ENOMEM; 550 goto kill_subdevs; 551 } 552 553 memcpy(res, subdev->res, 554 sizeof(struct resource) * subdev->nres); 555 556 for (r = 0; r < subdev->nres; r++) { 557 int bar = TH_MMIO_CONFIG; 558 559 /* 560 * Take .end == 0 to mean 'take the whole bar', 561 * .start then tells us which bar it is. Default to 562 * TH_MMIO_CONFIG. 563 */ 564 if (!res[r].end && res[r].flags == IORESOURCE_MEM) { 565 bar = res[r].start; 566 res[r].start = 0; 567 res[r].end = resource_size(&devres[bar]) - 1; 568 } 569 570 if (res[r].flags & IORESOURCE_MEM) { 571 res[r].start += devres[bar].start; 572 res[r].end += devres[bar].start; 573 574 dev_dbg(th->dev, "%s:%d @ %pR\n", 575 subdev->name, r, &res[r]); 576 } else if (res[r].flags & IORESOURCE_IRQ) { 577 res[r].start = irq; 578 } 579 } 580 581 err = intel_th_device_add_resources(thdev, res, subdev->nres); 582 if (err) { 583 put_device(&thdev->dev); 584 goto kill_subdevs; 585 } 586 587 if (subdev->type == INTEL_TH_OUTPUT) { 588 thdev->dev.devt = MKDEV(th->major, dst); 589 thdev->output.type = subdev->otype; 590 thdev->output.port = -1; 591 thdev->output.scratchpad = subdev->scrpd; 592 } else if (subdev->type == INTEL_TH_SWITCH) { 593 thdev->host_mode = host_mode; 594 } 595 596 err = device_add(&thdev->dev); 597 if (err) { 598 put_device(&thdev->dev); 599 goto kill_subdevs; 600 } 601 602 /* need switch driver to be loaded to enumerate the rest */ 603 if (subdev->type == INTEL_TH_SWITCH && !req) { 604 th->hub = thdev; 605 err = intel_th_request_hub_module(th); 606 if (!err) 607 req++; 608 } 609 610 th->thdev[dst++] = thdev; 611 } 612 613 return 0; 614 615 kill_subdevs: 616 for (; dst >= 0; dst--) 617 intel_th_device_remove(th->thdev[dst]); 618 619 return err; 620 } 621 622 static int match_devt(struct device *dev, void *data) 623 { 624 dev_t devt = (dev_t)(unsigned long)data; 625 626 return dev->devt == devt; 627 } 628 629 static int intel_th_output_open(struct inode *inode, struct file *file) 630 { 631 const struct file_operations *fops; 632 struct intel_th_driver *thdrv; 633 struct device *dev; 634 int err; 635 636 dev = bus_find_device(&intel_th_bus, NULL, 637 (void *)(unsigned long)inode->i_rdev, 638 match_devt); 639 if (!dev || !dev->driver) 640 return -ENODEV; 641 642 thdrv = to_intel_th_driver(dev->driver); 643 fops = fops_get(thdrv->fops); 644 if (!fops) 645 return -ENODEV; 646 647 replace_fops(file, fops); 648 649 file->private_data = to_intel_th_device(dev); 650 651 if (file->f_op->open) { 652 err = file->f_op->open(inode, file); 653 return err; 654 } 655 656 return 0; 657 } 658 659 static const struct file_operations intel_th_output_fops = { 660 .open = intel_th_output_open, 661 .llseek = noop_llseek, 662 }; 663 664 /** 665 * intel_th_alloc() - allocate a new Intel TH device and its subdevices 666 * @dev: parent device 667 * @devres: parent's resources 668 * @ndevres: number of resources 669 * @irq: irq number 670 */ 671 struct intel_th * 672 intel_th_alloc(struct device *dev, struct resource *devres, 673 unsigned int ndevres, int irq) 674 { 675 struct intel_th *th; 676 int err; 677 678 th = kzalloc(sizeof(*th), GFP_KERNEL); 679 if (!th) 680 return ERR_PTR(-ENOMEM); 681 682 th->id = ida_simple_get(&intel_th_ida, 0, 0, GFP_KERNEL); 683 if (th->id < 0) { 684 err = th->id; 685 goto err_alloc; 686 } 687 688 th->major = __register_chrdev(0, 0, TH_POSSIBLE_OUTPUTS, 689 "intel_th/output", &intel_th_output_fops); 690 if (th->major < 0) { 691 err = th->major; 692 goto err_ida; 693 } 694 th->dev = dev; 695 696 dev_set_drvdata(dev, th); 697 698 pm_runtime_no_callbacks(dev); 699 pm_runtime_put(dev); 700 pm_runtime_allow(dev); 701 702 err = intel_th_populate(th, devres, ndevres, irq); 703 if (err) 704 goto err_chrdev; 705 706 return th; 707 708 err_chrdev: 709 pm_runtime_forbid(dev); 710 711 __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS, 712 "intel_th/output"); 713 714 err_ida: 715 ida_simple_remove(&intel_th_ida, th->id); 716 717 err_alloc: 718 kfree(th); 719 720 return ERR_PTR(err); 721 } 722 EXPORT_SYMBOL_GPL(intel_th_alloc); 723 724 void intel_th_free(struct intel_th *th) 725 { 726 int i; 727 728 intel_th_request_hub_module_flush(th); 729 for (i = 0; i < TH_SUBDEVICE_MAX; i++) 730 if (th->thdev[i] && th->thdev[i] != th->hub) 731 intel_th_device_remove(th->thdev[i]); 732 733 intel_th_device_remove(th->hub); 734 735 pm_runtime_get_sync(th->dev); 736 pm_runtime_forbid(th->dev); 737 738 __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS, 739 "intel_th/output"); 740 741 ida_simple_remove(&intel_th_ida, th->id); 742 743 kfree(th); 744 } 745 EXPORT_SYMBOL_GPL(intel_th_free); 746 747 /** 748 * intel_th_trace_enable() - enable tracing for an output device 749 * @thdev: output device that requests tracing be enabled 750 */ 751 int intel_th_trace_enable(struct intel_th_device *thdev) 752 { 753 struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent); 754 struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver); 755 756 if (WARN_ON_ONCE(hub->type != INTEL_TH_SWITCH)) 757 return -EINVAL; 758 759 if (WARN_ON_ONCE(thdev->type != INTEL_TH_OUTPUT)) 760 return -EINVAL; 761 762 pm_runtime_get_sync(&thdev->dev); 763 hubdrv->enable(hub, &thdev->output); 764 765 return 0; 766 } 767 EXPORT_SYMBOL_GPL(intel_th_trace_enable); 768 769 /** 770 * intel_th_trace_disable() - disable tracing for an output device 771 * @thdev: output device that requests tracing be disabled 772 */ 773 int intel_th_trace_disable(struct intel_th_device *thdev) 774 { 775 struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent); 776 struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver); 777 778 WARN_ON_ONCE(hub->type != INTEL_TH_SWITCH); 779 if (WARN_ON_ONCE(thdev->type != INTEL_TH_OUTPUT)) 780 return -EINVAL; 781 782 hubdrv->disable(hub, &thdev->output); 783 pm_runtime_put(&thdev->dev); 784 785 return 0; 786 } 787 EXPORT_SYMBOL_GPL(intel_th_trace_disable); 788 789 int intel_th_set_output(struct intel_th_device *thdev, 790 unsigned int master) 791 { 792 struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent); 793 struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver); 794 795 if (!hubdrv->set_output) 796 return -ENOTSUPP; 797 798 return hubdrv->set_output(hub, master); 799 } 800 EXPORT_SYMBOL_GPL(intel_th_set_output); 801 802 static int __init intel_th_init(void) 803 { 804 intel_th_debug_init(); 805 806 return bus_register(&intel_th_bus); 807 } 808 subsys_initcall(intel_th_init); 809 810 static void __exit intel_th_exit(void) 811 { 812 intel_th_debug_done(); 813 814 bus_unregister(&intel_th_bus); 815 } 816 module_exit(intel_th_exit); 817 818 MODULE_LICENSE("GPL v2"); 819 MODULE_DESCRIPTION("Intel(R) Trace Hub controller driver"); 820 MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>"); 821