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