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