linux/drivers/hwtracing/intel_th/core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Intel(R) Trace Hub driver core
   4 *
   5 * Copyright (C) 2014-2015 Intel Corporation.
   6 */
   7
   8#define pr_fmt(fmt)     KBUILD_MODNAME ": " fmt
   9
  10#include <linux/types.h>
  11#include <linux/module.h>
  12#include <linux/device.h>
  13#include <linux/sysfs.h>
  14#include <linux/kdev_t.h>
  15#include <linux/debugfs.h>
  16#include <linux/idr.h>
  17#include <linux/pci.h>
  18#include <linux/pm_runtime.h>
  19#include <linux/dma-mapping.h>
  20
  21#include "intel_th.h"
  22#include "debug.h"
  23
  24static bool host_mode __read_mostly;
  25module_param(host_mode, bool, 0444);
  26
  27static DEFINE_IDA(intel_th_ida);
  28
  29static int intel_th_match(struct device *dev, struct device_driver *driver)
  30{
  31        struct intel_th_driver *thdrv = to_intel_th_driver(driver);
  32        struct intel_th_device *thdev = to_intel_th_device(dev);
  33
  34        if (thdev->type == INTEL_TH_SWITCH &&
  35            (!thdrv->enable || !thdrv->disable))
  36                return 0;
  37
  38        return !strcmp(thdev->name, driver->name);
  39}
  40
  41static int intel_th_child_remove(struct device *dev, void *data)
  42{
  43        device_release_driver(dev);
  44
  45        return 0;
  46}
  47
  48static int intel_th_probe(struct device *dev)
  49{
  50        struct intel_th_driver *thdrv = to_intel_th_driver(dev->driver);
  51        struct intel_th_device *thdev = to_intel_th_device(dev);
  52        struct intel_th_driver *hubdrv;
  53        struct intel_th_device *hub = NULL;
  54        int ret;
  55
  56        if (thdev->type == INTEL_TH_SWITCH)
  57                hub = thdev;
  58        else if (dev->parent)
  59                hub = to_intel_th_device(dev->parent);
  60
  61        if (!hub || !hub->dev.driver)
  62                return -EPROBE_DEFER;
  63
  64        hubdrv = to_intel_th_driver(hub->dev.driver);
  65
  66        pm_runtime_set_active(dev);
  67        pm_runtime_no_callbacks(dev);
  68        pm_runtime_enable(dev);
  69
  70        ret = thdrv->probe(to_intel_th_device(dev));
  71        if (ret)
  72                goto out_pm;
  73
  74        if (thdrv->attr_group) {
  75                ret = sysfs_create_group(&thdev->dev.kobj, thdrv->attr_group);
  76                if (ret)
  77                        goto out;
  78        }
  79
  80        if (thdev->type == INTEL_TH_OUTPUT &&
  81            !intel_th_output_assigned(thdev))
  82                /* does not talk to hardware */
  83                ret = hubdrv->assign(hub, thdev);
  84
  85out:
  86        if (ret)
  87                thdrv->remove(thdev);
  88
  89out_pm:
  90        if (ret)
  91                pm_runtime_disable(dev);
  92
  93        return ret;
  94}
  95
  96static void intel_th_device_remove(struct intel_th_device *thdev);
  97
  98static int intel_th_remove(struct device *dev)
  99{
 100        struct intel_th_driver *thdrv = to_intel_th_driver(dev->driver);
 101        struct intel_th_device *thdev = to_intel_th_device(dev);
 102        struct intel_th_device *hub = to_intel_th_hub(thdev);
 103
 104        if (thdev->type == INTEL_TH_SWITCH) {
 105                struct intel_th *th = to_intel_th(hub);
 106                int i, lowest;
 107
 108                /*
 109                 * disconnect outputs
 110                 *
 111                 * intel_th_child_remove returns 0 unconditionally, so there is
 112                 * no need to check the return value of device_for_each_child.
 113                 */
 114                device_for_each_child(dev, thdev, intel_th_child_remove);
 115
 116                /*
 117                 * Remove outputs, that is, hub's children: they are created
 118                 * at hub's probe time by having the hub call
 119                 * intel_th_output_enable() for each of them.
 120                 */
 121                for (i = 0, lowest = -1; i < th->num_thdevs; i++) {
 122                        /*
 123                         * Move the non-output devices from higher up the
 124                         * th->thdev[] array to lower positions to maintain
 125                         * a contiguous array.
 126                         */
 127                        if (th->thdev[i]->type != INTEL_TH_OUTPUT) {
 128                                if (lowest >= 0) {
 129                                        th->thdev[lowest] = th->thdev[i];
 130                                        th->thdev[i] = NULL;
 131                                        ++lowest;
 132                                }
 133
 134                                continue;
 135                        }
 136
 137                        if (lowest == -1)
 138                                lowest = i;
 139
 140                        intel_th_device_remove(th->thdev[i]);
 141                        th->thdev[i] = NULL;
 142                }
 143
 144                if (lowest >= 0)
 145                        th->num_thdevs = lowest;
 146        }
 147
 148        if (thdrv->attr_group)
 149                sysfs_remove_group(&thdev->dev.kobj, thdrv->attr_group);
 150
 151        pm_runtime_get_sync(dev);
 152
 153        thdrv->remove(thdev);
 154
 155        if (intel_th_output_assigned(thdev)) {
 156                struct intel_th_driver *hubdrv =
 157                        to_intel_th_driver(dev->parent->driver);
 158
 159                if (hub->dev.driver)
 160                        /* does not talk to hardware */
 161                        hubdrv->unassign(hub, thdev);
 162        }
 163
 164        pm_runtime_disable(dev);
 165        pm_runtime_set_active(dev);
 166        pm_runtime_enable(dev);
 167
 168        return 0;
 169}
 170
 171static struct bus_type intel_th_bus = {
 172        .name           = "intel_th",
 173        .match          = intel_th_match,
 174        .probe          = intel_th_probe,
 175        .remove         = intel_th_remove,
 176};
 177
 178static void intel_th_device_free(struct intel_th_device *thdev);
 179
 180static void intel_th_device_release(struct device *dev)
 181{
 182        intel_th_device_free(to_intel_th_device(dev));
 183}
 184
 185static struct device_type intel_th_source_device_type = {
 186        .name           = "intel_th_source_device",
 187        .release        = intel_th_device_release,
 188};
 189
 190static char *intel_th_output_devnode(struct device *dev, umode_t *mode,
 191                                     kuid_t *uid, kgid_t *gid)
 192{
 193        struct intel_th_device *thdev = to_intel_th_device(dev);
 194        struct intel_th *th = to_intel_th(thdev);
 195        char *node;
 196
 197        if (thdev->id >= 0)
 198                node = kasprintf(GFP_KERNEL, "intel_th%d/%s%d", th->id,
 199                                 thdev->name, thdev->id);
 200        else
 201                node = kasprintf(GFP_KERNEL, "intel_th%d/%s", th->id,
 202                                 thdev->name);
 203
 204        return node;
 205}
 206
 207static ssize_t port_show(struct device *dev, struct device_attribute *attr,
 208                         char *buf)
 209{
 210        struct intel_th_device *thdev = to_intel_th_device(dev);
 211
 212        if (thdev->output.port >= 0)
 213                return scnprintf(buf, PAGE_SIZE, "%u\n", thdev->output.port);
 214
 215        return scnprintf(buf, PAGE_SIZE, "unassigned\n");
 216}
 217
 218static DEVICE_ATTR_RO(port);
 219
 220static void intel_th_trace_prepare(struct intel_th_device *thdev)
 221{
 222        struct intel_th_device *hub = to_intel_th_hub(thdev);
 223        struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
 224
 225        if (hub->type != INTEL_TH_SWITCH)
 226                return;
 227
 228        if (thdev->type != INTEL_TH_OUTPUT)
 229                return;
 230
 231        pm_runtime_get_sync(&thdev->dev);
 232        hubdrv->prepare(hub, &thdev->output);
 233        pm_runtime_put(&thdev->dev);
 234}
 235
 236static int intel_th_output_activate(struct intel_th_device *thdev)
 237{
 238        struct intel_th_driver *thdrv =
 239                to_intel_th_driver_or_null(thdev->dev.driver);
 240        struct intel_th *th = to_intel_th(thdev);
 241        int ret = 0;
 242
 243        if (!thdrv)
 244                return -ENODEV;
 245
 246        if (!try_module_get(thdrv->driver.owner))
 247                return -ENODEV;
 248
 249        pm_runtime_get_sync(&thdev->dev);
 250
 251        if (th->activate)
 252                ret = th->activate(th);
 253        if (ret)
 254                goto fail_put;
 255
 256        intel_th_trace_prepare(thdev);
 257        if (thdrv->activate)
 258                ret = thdrv->activate(thdev);
 259        else
 260                intel_th_trace_enable(thdev);
 261
 262        if (ret)
 263                goto fail_deactivate;
 264
 265        return 0;
 266
 267fail_deactivate:
 268        if (th->deactivate)
 269                th->deactivate(th);
 270
 271fail_put:
 272        pm_runtime_put(&thdev->dev);
 273        module_put(thdrv->driver.owner);
 274
 275        return ret;
 276}
 277
 278static void intel_th_output_deactivate(struct intel_th_device *thdev)
 279{
 280        struct intel_th_driver *thdrv =
 281                to_intel_th_driver_or_null(thdev->dev.driver);
 282        struct intel_th *th = to_intel_th(thdev);
 283
 284        if (!thdrv)
 285                return;
 286
 287        if (thdrv->deactivate)
 288                thdrv->deactivate(thdev);
 289        else
 290                intel_th_trace_disable(thdev);
 291
 292        if (th->deactivate)
 293                th->deactivate(th);
 294
 295        pm_runtime_put(&thdev->dev);
 296        module_put(thdrv->driver.owner);
 297}
 298
 299static ssize_t active_show(struct device *dev, struct device_attribute *attr,
 300                           char *buf)
 301{
 302        struct intel_th_device *thdev = to_intel_th_device(dev);
 303
 304        return scnprintf(buf, PAGE_SIZE, "%d\n", thdev->output.active);
 305}
 306
 307static ssize_t active_store(struct device *dev, struct device_attribute *attr,
 308                            const char *buf, size_t size)
 309{
 310        struct intel_th_device *thdev = to_intel_th_device(dev);
 311        unsigned long val;
 312        int ret;
 313
 314        ret = kstrtoul(buf, 10, &val);
 315        if (ret)
 316                return ret;
 317
 318        if (!!val != thdev->output.active) {
 319                if (val)
 320                        ret = intel_th_output_activate(thdev);
 321                else
 322                        intel_th_output_deactivate(thdev);
 323        }
 324
 325        return ret ? ret : size;
 326}
 327
 328static DEVICE_ATTR_RW(active);
 329
 330static struct attribute *intel_th_output_attrs[] = {
 331        &dev_attr_port.attr,
 332        &dev_attr_active.attr,
 333        NULL,
 334};
 335
 336ATTRIBUTE_GROUPS(intel_th_output);
 337
 338static struct device_type intel_th_output_device_type = {
 339        .name           = "intel_th_output_device",
 340        .groups         = intel_th_output_groups,
 341        .release        = intel_th_device_release,
 342        .devnode        = intel_th_output_devnode,
 343};
 344
 345static struct device_type intel_th_switch_device_type = {
 346        .name           = "intel_th_switch_device",
 347        .release        = intel_th_device_release,
 348};
 349
 350static struct device_type *intel_th_device_type[] = {
 351        [INTEL_TH_SOURCE]       = &intel_th_source_device_type,
 352        [INTEL_TH_OUTPUT]       = &intel_th_output_device_type,
 353        [INTEL_TH_SWITCH]       = &intel_th_switch_device_type,
 354};
 355
 356int intel_th_driver_register(struct intel_th_driver *thdrv)
 357{
 358        if (!thdrv->probe || !thdrv->remove)
 359                return -EINVAL;
 360
 361        thdrv->driver.bus = &intel_th_bus;
 362
 363        return driver_register(&thdrv->driver);
 364}
 365EXPORT_SYMBOL_GPL(intel_th_driver_register);
 366
 367void intel_th_driver_unregister(struct intel_th_driver *thdrv)
 368{
 369        driver_unregister(&thdrv->driver);
 370}
 371EXPORT_SYMBOL_GPL(intel_th_driver_unregister);
 372
 373static struct intel_th_device *
 374intel_th_device_alloc(struct intel_th *th, unsigned int type, const char *name,
 375                      int id)
 376{
 377        struct device *parent;
 378        struct intel_th_device *thdev;
 379
 380        if (type == INTEL_TH_OUTPUT)
 381                parent = &th->hub->dev;
 382        else
 383                parent = th->dev;
 384
 385        thdev = kzalloc(sizeof(*thdev) + strlen(name) + 1, GFP_KERNEL);
 386        if (!thdev)
 387                return NULL;
 388
 389        thdev->id = id;
 390        thdev->type = type;
 391
 392        strcpy(thdev->name, name);
 393        device_initialize(&thdev->dev);
 394        thdev->dev.bus = &intel_th_bus;
 395        thdev->dev.type = intel_th_device_type[type];
 396        thdev->dev.parent = parent;
 397        thdev->dev.dma_mask = parent->dma_mask;
 398        thdev->dev.dma_parms = parent->dma_parms;
 399        dma_set_coherent_mask(&thdev->dev, parent->coherent_dma_mask);
 400        if (id >= 0)
 401                dev_set_name(&thdev->dev, "%d-%s%d", th->id, name, id);
 402        else
 403                dev_set_name(&thdev->dev, "%d-%s", th->id, name);
 404
 405        return thdev;
 406}
 407
 408static int intel_th_device_add_resources(struct intel_th_device *thdev,
 409                                         struct resource *res, int nres)
 410{
 411        struct resource *r;
 412
 413        r = kmemdup(res, sizeof(*res) * nres, GFP_KERNEL);
 414        if (!r)
 415                return -ENOMEM;
 416
 417        thdev->resource = r;
 418        thdev->num_resources = nres;
 419
 420        return 0;
 421}
 422
 423static void intel_th_device_remove(struct intel_th_device *thdev)
 424{
 425        device_del(&thdev->dev);
 426        put_device(&thdev->dev);
 427}
 428
 429static void intel_th_device_free(struct intel_th_device *thdev)
 430{
 431        kfree(thdev->resource);
 432        kfree(thdev);
 433}
 434
 435/*
 436 * Intel(R) Trace Hub subdevices
 437 */
 438static const struct intel_th_subdevice {
 439        const char              *name;
 440        struct resource         res[3];
 441        unsigned                nres;
 442        unsigned                type;
 443        unsigned                otype;
 444        bool                    mknode;
 445        unsigned                scrpd;
 446        int                     id;
 447} intel_th_subdevices[] = {
 448        {
 449                .nres   = 1,
 450                .res    = {
 451                        {
 452                                /* Handle TSCU and CTS from GTH driver */
 453                                .start  = REG_GTH_OFFSET,
 454                                .end    = REG_CTS_OFFSET + REG_CTS_LENGTH - 1,
 455                                .flags  = IORESOURCE_MEM,
 456                        },
 457                },
 458                .name   = "gth",
 459                .type   = INTEL_TH_SWITCH,
 460                .id     = -1,
 461        },
 462        {
 463                .nres   = 2,
 464                .res    = {
 465                        {
 466                                .start  = REG_MSU_OFFSET,
 467                                .end    = REG_MSU_OFFSET + REG_MSU_LENGTH - 1,
 468                                .flags  = IORESOURCE_MEM,
 469                        },
 470                        {
 471                                .start  = BUF_MSU_OFFSET,
 472                                .end    = BUF_MSU_OFFSET + BUF_MSU_LENGTH - 1,
 473                                .flags  = IORESOURCE_MEM,
 474                        },
 475                },
 476                .name   = "msc",
 477                .id     = 0,
 478                .type   = INTEL_TH_OUTPUT,
 479                .mknode = true,
 480                .otype  = GTH_MSU,
 481                .scrpd  = SCRPD_MEM_IS_PRIM_DEST | SCRPD_MSC0_IS_ENABLED,
 482        },
 483        {
 484                .nres   = 2,
 485                .res    = {
 486                        {
 487                                .start  = REG_MSU_OFFSET,
 488                                .end    = REG_MSU_OFFSET + REG_MSU_LENGTH - 1,
 489                                .flags  = IORESOURCE_MEM,
 490                        },
 491                        {
 492                                .start  = BUF_MSU_OFFSET,
 493                                .end    = BUF_MSU_OFFSET + BUF_MSU_LENGTH - 1,
 494                                .flags  = IORESOURCE_MEM,
 495                        },
 496                },
 497                .name   = "msc",
 498                .id     = 1,
 499                .type   = INTEL_TH_OUTPUT,
 500                .mknode = true,
 501                .otype  = GTH_MSU,
 502                .scrpd  = SCRPD_MEM_IS_PRIM_DEST | SCRPD_MSC1_IS_ENABLED,
 503        },
 504        {
 505                .nres   = 2,
 506                .res    = {
 507                        {
 508                                .start  = REG_STH_OFFSET,
 509                                .end    = REG_STH_OFFSET + REG_STH_LENGTH - 1,
 510                                .flags  = IORESOURCE_MEM,
 511                        },
 512                        {
 513                                .start  = TH_MMIO_SW,
 514                                .end    = 0,
 515                                .flags  = IORESOURCE_MEM,
 516                        },
 517                },
 518                .id     = -1,
 519                .name   = "sth",
 520                .type   = INTEL_TH_SOURCE,
 521        },
 522        {
 523                .nres   = 2,
 524                .res    = {
 525                        {
 526                                .start  = REG_STH_OFFSET,
 527                                .end    = REG_STH_OFFSET + REG_STH_LENGTH - 1,
 528                                .flags  = IORESOURCE_MEM,
 529                        },
 530                        {
 531                                .start  = TH_MMIO_RTIT,
 532                                .end    = 0,
 533                                .flags  = IORESOURCE_MEM,
 534                        },
 535                },
 536                .id     = -1,
 537                .name   = "rtit",
 538                .type   = INTEL_TH_SOURCE,
 539        },
 540        {
 541                .nres   = 1,
 542                .res    = {
 543                        {
 544                                .start  = REG_PTI_OFFSET,
 545                                .end    = REG_PTI_OFFSET + REG_PTI_LENGTH - 1,
 546                                .flags  = IORESOURCE_MEM,
 547                        },
 548                },
 549                .id     = -1,
 550                .name   = "pti",
 551                .type   = INTEL_TH_OUTPUT,
 552                .otype  = GTH_PTI,
 553                .scrpd  = SCRPD_PTI_IS_PRIM_DEST,
 554        },
 555        {
 556                .nres   = 1,
 557                .res    = {
 558                        {
 559                                .start  = REG_PTI_OFFSET,
 560                                .end    = REG_PTI_OFFSET + REG_PTI_LENGTH - 1,
 561                                .flags  = IORESOURCE_MEM,
 562                        },
 563                },
 564                .id     = -1,
 565                .name   = "lpp",
 566                .type   = INTEL_TH_OUTPUT,
 567                .otype  = GTH_LPP,
 568                .scrpd  = SCRPD_PTI_IS_PRIM_DEST,
 569        },
 570        {
 571                .nres   = 1,
 572                .res    = {
 573                        {
 574                                .start  = REG_DCIH_OFFSET,
 575                                .end    = REG_DCIH_OFFSET + REG_DCIH_LENGTH - 1,
 576                                .flags  = IORESOURCE_MEM,
 577                        },
 578                },
 579                .id     = -1,
 580                .name   = "dcih",
 581                .type   = INTEL_TH_OUTPUT,
 582        },
 583};
 584
 585#ifdef CONFIG_MODULES
 586static void __intel_th_request_hub_module(struct work_struct *work)
 587{
 588        struct intel_th *th = container_of(work, struct intel_th,
 589                                           request_module_work);
 590
 591        request_module("intel_th_%s", th->hub->name);
 592}
 593
 594static int intel_th_request_hub_module(struct intel_th *th)
 595{
 596        INIT_WORK(&th->request_module_work, __intel_th_request_hub_module);
 597        schedule_work(&th->request_module_work);
 598
 599        return 0;
 600}
 601
 602static void intel_th_request_hub_module_flush(struct intel_th *th)
 603{
 604        flush_work(&th->request_module_work);
 605}
 606#else
 607static inline int intel_th_request_hub_module(struct intel_th *th)
 608{
 609        return -EINVAL;
 610}
 611
 612static inline void intel_th_request_hub_module_flush(struct intel_th *th)
 613{
 614}
 615#endif /* CONFIG_MODULES */
 616
 617static struct intel_th_device *
 618intel_th_subdevice_alloc(struct intel_th *th,
 619                         const struct intel_th_subdevice *subdev)
 620{
 621        struct intel_th_device *thdev;
 622        struct resource res[3];
 623        unsigned int req = 0;
 624        int r, err;
 625
 626        thdev = intel_th_device_alloc(th, subdev->type, subdev->name,
 627                                      subdev->id);
 628        if (!thdev)
 629                return ERR_PTR(-ENOMEM);
 630
 631        thdev->drvdata = th->drvdata;
 632
 633        memcpy(res, subdev->res,
 634               sizeof(struct resource) * subdev->nres);
 635
 636        for (r = 0; r < subdev->nres; r++) {
 637                struct resource *devres = th->resource;
 638                int bar = TH_MMIO_CONFIG;
 639
 640                /*
 641                 * Take .end == 0 to mean 'take the whole bar',
 642                 * .start then tells us which bar it is. Default to
 643                 * TH_MMIO_CONFIG.
 644                 */
 645                if (!res[r].end && res[r].flags == IORESOURCE_MEM) {
 646                        bar = res[r].start;
 647                        err = -ENODEV;
 648                        if (bar >= th->num_resources)
 649                                goto fail_put_device;
 650                        res[r].start = 0;
 651                        res[r].end = resource_size(&devres[bar]) - 1;
 652                }
 653
 654                if (res[r].flags & IORESOURCE_MEM) {
 655                        res[r].start    += devres[bar].start;
 656                        res[r].end      += devres[bar].start;
 657
 658                        dev_dbg(th->dev, "%s:%d @ %pR\n",
 659                                subdev->name, r, &res[r]);
 660                } else if (res[r].flags & IORESOURCE_IRQ) {
 661                        /*
 662                         * Only pass on the IRQ if we have useful interrupts:
 663                         * the ones that can be configured via MINTCTL.
 664                         */
 665                        if (INTEL_TH_CAP(th, has_mintctl) && th->irq != -1)
 666                                res[r].start = th->irq;
 667                }
 668        }
 669
 670        err = intel_th_device_add_resources(thdev, res, subdev->nres);
 671        if (err)
 672                goto fail_put_device;
 673
 674        if (subdev->type == INTEL_TH_OUTPUT) {
 675                if (subdev->mknode)
 676                        thdev->dev.devt = MKDEV(th->major, th->num_thdevs);
 677                thdev->output.type = subdev->otype;
 678                thdev->output.port = -1;
 679                thdev->output.scratchpad = subdev->scrpd;
 680        } else if (subdev->type == INTEL_TH_SWITCH) {
 681                thdev->host_mode =
 682                        INTEL_TH_CAP(th, host_mode_only) ? true : host_mode;
 683                th->hub = thdev;
 684        }
 685
 686        err = device_add(&thdev->dev);
 687        if (err)
 688                goto fail_free_res;
 689
 690        /* need switch driver to be loaded to enumerate the rest */
 691        if (subdev->type == INTEL_TH_SWITCH && !req) {
 692                err = intel_th_request_hub_module(th);
 693                if (!err)
 694                        req++;
 695        }
 696
 697        return thdev;
 698
 699fail_free_res:
 700        kfree(thdev->resource);
 701
 702fail_put_device:
 703        put_device(&thdev->dev);
 704
 705        return ERR_PTR(err);
 706}
 707
 708/**
 709 * intel_th_output_enable() - find and enable a device for a given output type
 710 * @th:         Intel TH instance
 711 * @otype:      output type
 712 *
 713 * Go through the unallocated output devices, find the first one whos type
 714 * matches @otype and instantiate it. These devices are removed when the hub
 715 * device is removed, see intel_th_remove().
 716 */
 717int intel_th_output_enable(struct intel_th *th, unsigned int otype)
 718{
 719        struct intel_th_device *thdev;
 720        int src = 0, dst = 0;
 721
 722        for (src = 0, dst = 0; dst <= th->num_thdevs; src++, dst++) {
 723                for (; src < ARRAY_SIZE(intel_th_subdevices); src++) {
 724                        if (intel_th_subdevices[src].type != INTEL_TH_OUTPUT)
 725                                continue;
 726
 727                        if (intel_th_subdevices[src].otype != otype)
 728                                continue;
 729
 730                        break;
 731                }
 732
 733                /* no unallocated matching subdevices */
 734                if (src == ARRAY_SIZE(intel_th_subdevices))
 735                        return -ENODEV;
 736
 737                for (; dst < th->num_thdevs; dst++) {
 738                        if (th->thdev[dst]->type != INTEL_TH_OUTPUT)
 739                                continue;
 740
 741                        if (th->thdev[dst]->output.type != otype)
 742                                continue;
 743
 744                        break;
 745                }
 746
 747                /*
 748                 * intel_th_subdevices[src] matches our requirements and is
 749                 * not matched in th::thdev[]
 750                 */
 751                if (dst == th->num_thdevs)
 752                        goto found;
 753        }
 754
 755        return -ENODEV;
 756
 757found:
 758        thdev = intel_th_subdevice_alloc(th, &intel_th_subdevices[src]);
 759        if (IS_ERR(thdev))
 760                return PTR_ERR(thdev);
 761
 762        th->thdev[th->num_thdevs++] = thdev;
 763
 764        return 0;
 765}
 766EXPORT_SYMBOL_GPL(intel_th_output_enable);
 767
 768static int intel_th_populate(struct intel_th *th)
 769{
 770        int src;
 771
 772        /* create devices for each intel_th_subdevice */
 773        for (src = 0; src < ARRAY_SIZE(intel_th_subdevices); src++) {
 774                const struct intel_th_subdevice *subdev =
 775                        &intel_th_subdevices[src];
 776                struct intel_th_device *thdev;
 777
 778                /* only allow SOURCE and SWITCH devices in host mode */
 779                if ((INTEL_TH_CAP(th, host_mode_only) || host_mode) &&
 780                    subdev->type == INTEL_TH_OUTPUT)
 781                        continue;
 782
 783                /*
 784                 * don't enable port OUTPUTs in this path; SWITCH enables them
 785                 * via intel_th_output_enable()
 786                 */
 787                if (subdev->type == INTEL_TH_OUTPUT &&
 788                    subdev->otype != GTH_NONE)
 789                        continue;
 790
 791                thdev = intel_th_subdevice_alloc(th, subdev);
 792                /* note: caller should free subdevices from th::thdev[] */
 793                if (IS_ERR(thdev)) {
 794                        /* ENODEV for individual subdevices is allowed */
 795                        if (PTR_ERR(thdev) == -ENODEV)
 796                                continue;
 797
 798                        return PTR_ERR(thdev);
 799                }
 800
 801                th->thdev[th->num_thdevs++] = thdev;
 802        }
 803
 804        return 0;
 805}
 806
 807static int intel_th_output_open(struct inode *inode, struct file *file)
 808{
 809        const struct file_operations *fops;
 810        struct intel_th_driver *thdrv;
 811        struct device *dev;
 812        int err;
 813
 814        dev = bus_find_device_by_devt(&intel_th_bus, inode->i_rdev);
 815        if (!dev || !dev->driver)
 816                return -ENODEV;
 817
 818        thdrv = to_intel_th_driver(dev->driver);
 819        fops = fops_get(thdrv->fops);
 820        if (!fops)
 821                return -ENODEV;
 822
 823        replace_fops(file, fops);
 824
 825        file->private_data = to_intel_th_device(dev);
 826
 827        if (file->f_op->open) {
 828                err = file->f_op->open(inode, file);
 829                return err;
 830        }
 831
 832        return 0;
 833}
 834
 835static const struct file_operations intel_th_output_fops = {
 836        .open   = intel_th_output_open,
 837        .llseek = noop_llseek,
 838};
 839
 840static irqreturn_t intel_th_irq(int irq, void *data)
 841{
 842        struct intel_th *th = data;
 843        irqreturn_t ret = IRQ_NONE;
 844        struct intel_th_driver *d;
 845        int i;
 846
 847        for (i = 0; i < th->num_thdevs; i++) {
 848                if (th->thdev[i]->type != INTEL_TH_OUTPUT)
 849                        continue;
 850
 851                d = to_intel_th_driver(th->thdev[i]->dev.driver);
 852                if (d && d->irq)
 853                        ret |= d->irq(th->thdev[i]);
 854        }
 855
 856        return ret;
 857}
 858
 859/**
 860 * intel_th_alloc() - allocate a new Intel TH device and its subdevices
 861 * @dev:        parent device
 862 * @devres:     resources indexed by th_mmio_idx
 863 * @irq:        irq number
 864 */
 865struct intel_th *
 866intel_th_alloc(struct device *dev, const struct intel_th_drvdata *drvdata,
 867               struct resource *devres, unsigned int ndevres)
 868{
 869        int err, r, nr_mmios = 0;
 870        struct intel_th *th;
 871
 872        th = kzalloc(sizeof(*th), GFP_KERNEL);
 873        if (!th)
 874                return ERR_PTR(-ENOMEM);
 875
 876        th->id = ida_simple_get(&intel_th_ida, 0, 0, GFP_KERNEL);
 877        if (th->id < 0) {
 878                err = th->id;
 879                goto err_alloc;
 880        }
 881
 882        th->major = __register_chrdev(0, 0, TH_POSSIBLE_OUTPUTS,
 883                                      "intel_th/output", &intel_th_output_fops);
 884        if (th->major < 0) {
 885                err = th->major;
 886                goto err_ida;
 887        }
 888        th->irq = -1;
 889        th->dev = dev;
 890        th->drvdata = drvdata;
 891
 892        for (r = 0; r < ndevres; r++)
 893                switch (devres[r].flags & IORESOURCE_TYPE_BITS) {
 894                case IORESOURCE_MEM:
 895                        th->resource[nr_mmios++] = devres[r];
 896                        break;
 897                case IORESOURCE_IRQ:
 898                        err = devm_request_irq(dev, devres[r].start,
 899                                               intel_th_irq, IRQF_SHARED,
 900                                               dev_name(dev), th);
 901                        if (err)
 902                                goto err_chrdev;
 903
 904                        if (th->irq == -1)
 905                                th->irq = devres[r].start;
 906                        th->num_irqs++;
 907                        break;
 908                default:
 909                        dev_warn(dev, "Unknown resource type %lx\n",
 910                                 devres[r].flags);
 911                        break;
 912                }
 913
 914        th->num_resources = nr_mmios;
 915
 916        dev_set_drvdata(dev, th);
 917
 918        pm_runtime_no_callbacks(dev);
 919        pm_runtime_put(dev);
 920        pm_runtime_allow(dev);
 921
 922        err = intel_th_populate(th);
 923        if (err) {
 924                /* free the subdevices and undo everything */
 925                intel_th_free(th);
 926                return ERR_PTR(err);
 927        }
 928
 929        return th;
 930
 931err_chrdev:
 932        __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS,
 933                            "intel_th/output");
 934
 935err_ida:
 936        ida_simple_remove(&intel_th_ida, th->id);
 937
 938err_alloc:
 939        kfree(th);
 940
 941        return ERR_PTR(err);
 942}
 943EXPORT_SYMBOL_GPL(intel_th_alloc);
 944
 945void intel_th_free(struct intel_th *th)
 946{
 947        int i;
 948
 949        intel_th_request_hub_module_flush(th);
 950
 951        intel_th_device_remove(th->hub);
 952        for (i = 0; i < th->num_thdevs; i++) {
 953                if (th->thdev[i] != th->hub)
 954                        intel_th_device_remove(th->thdev[i]);
 955                th->thdev[i] = NULL;
 956        }
 957
 958        th->num_thdevs = 0;
 959
 960        for (i = 0; i < th->num_irqs; i++)
 961                devm_free_irq(th->dev, th->irq + i, th);
 962
 963        pm_runtime_get_sync(th->dev);
 964        pm_runtime_forbid(th->dev);
 965
 966        __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS,
 967                            "intel_th/output");
 968
 969        ida_simple_remove(&intel_th_ida, th->id);
 970
 971        kfree(th);
 972}
 973EXPORT_SYMBOL_GPL(intel_th_free);
 974
 975/**
 976 * intel_th_trace_enable() - enable tracing for an output device
 977 * @thdev:      output device that requests tracing be enabled
 978 */
 979int intel_th_trace_enable(struct intel_th_device *thdev)
 980{
 981        struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent);
 982        struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
 983
 984        if (WARN_ON_ONCE(hub->type != INTEL_TH_SWITCH))
 985                return -EINVAL;
 986
 987        if (WARN_ON_ONCE(thdev->type != INTEL_TH_OUTPUT))
 988                return -EINVAL;
 989
 990        pm_runtime_get_sync(&thdev->dev);
 991        hubdrv->enable(hub, &thdev->output);
 992
 993        return 0;
 994}
 995EXPORT_SYMBOL_GPL(intel_th_trace_enable);
 996
 997/**
 998 * intel_th_trace_switch() - execute a switch sequence
 999 * @thdev:      output device that requests tracing switch
1000 */
1001int intel_th_trace_switch(struct intel_th_device *thdev)
1002{
1003        struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent);
1004        struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
1005
1006        if (WARN_ON_ONCE(hub->type != INTEL_TH_SWITCH))
1007                return -EINVAL;
1008
1009        if (WARN_ON_ONCE(thdev->type != INTEL_TH_OUTPUT))
1010                return -EINVAL;
1011
1012        hubdrv->trig_switch(hub, &thdev->output);
1013
1014        return 0;
1015}
1016EXPORT_SYMBOL_GPL(intel_th_trace_switch);
1017
1018/**
1019 * intel_th_trace_disable() - disable tracing for an output device
1020 * @thdev:      output device that requests tracing be disabled
1021 */
1022int intel_th_trace_disable(struct intel_th_device *thdev)
1023{
1024        struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent);
1025        struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
1026
1027        WARN_ON_ONCE(hub->type != INTEL_TH_SWITCH);
1028        if (WARN_ON_ONCE(thdev->type != INTEL_TH_OUTPUT))
1029                return -EINVAL;
1030
1031        hubdrv->disable(hub, &thdev->output);
1032        pm_runtime_put(&thdev->dev);
1033
1034        return 0;
1035}
1036EXPORT_SYMBOL_GPL(intel_th_trace_disable);
1037
1038int intel_th_set_output(struct intel_th_device *thdev,
1039                        unsigned int master)
1040{
1041        struct intel_th_device *hub = to_intel_th_hub(thdev);
1042        struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
1043        int ret;
1044
1045        /* In host mode, this is up to the external debugger, do nothing. */
1046        if (hub->host_mode)
1047                return 0;
1048
1049        /*
1050         * hub is instantiated together with the source device that
1051         * calls here, so guaranteed to be present.
1052         */
1053        hubdrv = to_intel_th_driver(hub->dev.driver);
1054        if (!hubdrv || !try_module_get(hubdrv->driver.owner))
1055                return -EINVAL;
1056
1057        if (!hubdrv->set_output) {
1058                ret = -ENOTSUPP;
1059                goto out;
1060        }
1061
1062        ret = hubdrv->set_output(hub, master);
1063
1064out:
1065        module_put(hubdrv->driver.owner);
1066        return ret;
1067}
1068EXPORT_SYMBOL_GPL(intel_th_set_output);
1069
1070static int __init intel_th_init(void)
1071{
1072        intel_th_debug_init();
1073
1074        return bus_register(&intel_th_bus);
1075}
1076subsys_initcall(intel_th_init);
1077
1078static void __exit intel_th_exit(void)
1079{
1080        intel_th_debug_done();
1081
1082        bus_unregister(&intel_th_bus);
1083}
1084module_exit(intel_th_exit);
1085
1086MODULE_LICENSE("GPL v2");
1087MODULE_DESCRIPTION("Intel(R) Trace Hub controller driver");
1088MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");
1089