linux/drivers/hwtracing/intel_th/gth.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Intel(R) Trace Hub Global Trace Hub
   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/io.h>
  14#include <linux/mm.h>
  15#include <linux/slab.h>
  16#include <linux/bitmap.h>
  17#include <linux/pm_runtime.h>
  18
  19#include "intel_th.h"
  20#include "gth.h"
  21
  22struct gth_device;
  23
  24/**
  25 * struct gth_output - GTH view on an output port
  26 * @gth:        backlink to the GTH device
  27 * @output:     link to output device's output descriptor
  28 * @index:      output port number
  29 * @port_type:  one of GTH_* port type values
  30 * @master:     bitmap of masters configured for this output
  31 */
  32struct gth_output {
  33        struct gth_device       *gth;
  34        struct intel_th_output  *output;
  35        unsigned int            index;
  36        unsigned int            port_type;
  37        DECLARE_BITMAP(master, TH_CONFIGURABLE_MASTERS + 1);
  38};
  39
  40/**
  41 * struct gth_device - GTH device
  42 * @dev:        driver core's device
  43 * @base:       register window base address
  44 * @output_group:       attributes describing output ports
  45 * @master_group:       attributes describing master assignments
  46 * @output:             output ports
  47 * @master:             master/output port assignments
  48 * @gth_lock:           serializes accesses to GTH bits
  49 */
  50struct gth_device {
  51        struct device           *dev;
  52        void __iomem            *base;
  53
  54        struct attribute_group  output_group;
  55        struct attribute_group  master_group;
  56        struct gth_output       output[TH_POSSIBLE_OUTPUTS];
  57        signed char             master[TH_CONFIGURABLE_MASTERS + 1];
  58        spinlock_t              gth_lock;
  59};
  60
  61static void gth_output_set(struct gth_device *gth, int port,
  62                           unsigned int config)
  63{
  64        unsigned long reg = port & 4 ? REG_GTH_GTHOPT1 : REG_GTH_GTHOPT0;
  65        u32 val;
  66        int shift = (port & 3) * 8;
  67
  68        val = ioread32(gth->base + reg);
  69        val &= ~(0xff << shift);
  70        val |= config << shift;
  71        iowrite32(val, gth->base + reg);
  72}
  73
  74static unsigned int gth_output_get(struct gth_device *gth, int port)
  75{
  76        unsigned long reg = port & 4 ? REG_GTH_GTHOPT1 : REG_GTH_GTHOPT0;
  77        u32 val;
  78        int shift = (port & 3) * 8;
  79
  80        val = ioread32(gth->base + reg);
  81        val &= 0xff << shift;
  82        val >>= shift;
  83
  84        return val;
  85}
  86
  87static void gth_smcfreq_set(struct gth_device *gth, int port,
  88                            unsigned int freq)
  89{
  90        unsigned long reg = REG_GTH_SMCR0 + ((port / 2) * 4);
  91        int shift = (port & 1) * 16;
  92        u32 val;
  93
  94        val = ioread32(gth->base + reg);
  95        val &= ~(0xffff << shift);
  96        val |= freq << shift;
  97        iowrite32(val, gth->base + reg);
  98}
  99
 100static unsigned int gth_smcfreq_get(struct gth_device *gth, int port)
 101{
 102        unsigned long reg = REG_GTH_SMCR0 + ((port / 2) * 4);
 103        int shift = (port & 1) * 16;
 104        u32 val;
 105
 106        val = ioread32(gth->base + reg);
 107        val &= 0xffff << shift;
 108        val >>= shift;
 109
 110        return val;
 111}
 112
 113/*
 114 * "masters" attribute group
 115 */
 116
 117struct master_attribute {
 118        struct device_attribute attr;
 119        struct gth_device       *gth;
 120        unsigned int            master;
 121};
 122
 123static void
 124gth_master_set(struct gth_device *gth, unsigned int master, int port)
 125{
 126        unsigned int reg = REG_GTH_SWDEST0 + ((master >> 1) & ~3u);
 127        unsigned int shift = (master & 0x7) * 4;
 128        u32 val;
 129
 130        if (master >= 256) {
 131                reg = REG_GTH_GSWTDEST;
 132                shift = 0;
 133        }
 134
 135        val = ioread32(gth->base + reg);
 136        val &= ~(0xf << shift);
 137        if (port >= 0)
 138                val |= (0x8 | port) << shift;
 139        iowrite32(val, gth->base + reg);
 140}
 141
 142static ssize_t master_attr_show(struct device *dev,
 143                                struct device_attribute *attr,
 144                                char *buf)
 145{
 146        struct master_attribute *ma =
 147                container_of(attr, struct master_attribute, attr);
 148        struct gth_device *gth = ma->gth;
 149        size_t count;
 150        int port;
 151
 152        spin_lock(&gth->gth_lock);
 153        port = gth->master[ma->master];
 154        spin_unlock(&gth->gth_lock);
 155
 156        if (port >= 0)
 157                count = snprintf(buf, PAGE_SIZE, "%x\n", port);
 158        else
 159                count = snprintf(buf, PAGE_SIZE, "disabled\n");
 160
 161        return count;
 162}
 163
 164static ssize_t master_attr_store(struct device *dev,
 165                                 struct device_attribute *attr,
 166                                 const char *buf, size_t count)
 167{
 168        struct master_attribute *ma =
 169                container_of(attr, struct master_attribute, attr);
 170        struct gth_device *gth = ma->gth;
 171        int old_port, port;
 172
 173        if (kstrtoint(buf, 10, &port) < 0)
 174                return -EINVAL;
 175
 176        if (port >= TH_POSSIBLE_OUTPUTS || port < -1)
 177                return -EINVAL;
 178
 179        spin_lock(&gth->gth_lock);
 180
 181        /* disconnect from the previous output port, if any */
 182        old_port = gth->master[ma->master];
 183        if (old_port >= 0) {
 184                gth->master[ma->master] = -1;
 185                clear_bit(ma->master, gth->output[old_port].master);
 186
 187                /*
 188                 * if the port is active, program this setting,
 189                 * implies that runtime PM is on
 190                 */
 191                if (gth->output[old_port].output->active)
 192                        gth_master_set(gth, ma->master, -1);
 193        }
 194
 195        /* connect to the new output port, if any */
 196        if (port >= 0) {
 197                /* check if there's a driver for this port */
 198                if (!gth->output[port].output) {
 199                        count = -ENODEV;
 200                        goto unlock;
 201                }
 202
 203                set_bit(ma->master, gth->output[port].master);
 204
 205                /* if the port is active, program this setting, see above */
 206                if (gth->output[port].output->active)
 207                        gth_master_set(gth, ma->master, port);
 208        }
 209
 210        gth->master[ma->master] = port;
 211
 212unlock:
 213        spin_unlock(&gth->gth_lock);
 214
 215        return count;
 216}
 217
 218struct output_attribute {
 219        struct device_attribute attr;
 220        struct gth_device       *gth;
 221        unsigned int            port;
 222        unsigned int            parm;
 223};
 224
 225#define OUTPUT_PARM(_name, _mask, _r, _w, _what)                        \
 226        [TH_OUTPUT_PARM(_name)] = { .name = __stringify(_name),         \
 227                                    .get = gth_ ## _what ## _get,       \
 228                                    .set = gth_ ## _what ## _set,       \
 229                                    .mask = (_mask),                    \
 230                                    .readable = (_r),                   \
 231                                    .writable = (_w) }
 232
 233static const struct output_parm {
 234        const char      *name;
 235        unsigned int    (*get)(struct gth_device *gth, int port);
 236        void            (*set)(struct gth_device *gth, int port,
 237                               unsigned int val);
 238        unsigned int    mask;
 239        unsigned int    readable : 1,
 240                        writable : 1;
 241} output_parms[] = {
 242        OUTPUT_PARM(port,       0x7,    1, 0, output),
 243        OUTPUT_PARM(null,       BIT(3), 1, 1, output),
 244        OUTPUT_PARM(drop,       BIT(4), 1, 1, output),
 245        OUTPUT_PARM(reset,      BIT(5), 1, 0, output),
 246        OUTPUT_PARM(flush,      BIT(7), 0, 1, output),
 247        OUTPUT_PARM(smcfreq,    0xffff, 1, 1, smcfreq),
 248};
 249
 250static void
 251gth_output_parm_set(struct gth_device *gth, int port, unsigned int parm,
 252                    unsigned int val)
 253{
 254        unsigned int config = output_parms[parm].get(gth, port);
 255        unsigned int mask = output_parms[parm].mask;
 256        unsigned int shift = __ffs(mask);
 257
 258        config &= ~mask;
 259        config |= (val << shift) & mask;
 260        output_parms[parm].set(gth, port, config);
 261}
 262
 263static unsigned int
 264gth_output_parm_get(struct gth_device *gth, int port, unsigned int parm)
 265{
 266        unsigned int config = output_parms[parm].get(gth, port);
 267        unsigned int mask = output_parms[parm].mask;
 268        unsigned int shift = __ffs(mask);
 269
 270        config &= mask;
 271        config >>= shift;
 272        return config;
 273}
 274
 275/*
 276 * Reset outputs and sources
 277 */
 278static int intel_th_gth_reset(struct gth_device *gth)
 279{
 280        u32 reg;
 281        int port, i;
 282
 283        reg = ioread32(gth->base + REG_GTH_SCRPD0);
 284        if (reg & SCRPD_DEBUGGER_IN_USE)
 285                return -EBUSY;
 286
 287        /* Always save/restore STH and TU registers in S0ix entry/exit */
 288        reg |= SCRPD_STH_IS_ENABLED | SCRPD_TRIGGER_IS_ENABLED;
 289        iowrite32(reg, gth->base + REG_GTH_SCRPD0);
 290
 291        /* output ports */
 292        for (port = 0; port < 8; port++) {
 293                if (gth_output_parm_get(gth, port, TH_OUTPUT_PARM(port)) ==
 294                    GTH_NONE)
 295                        continue;
 296
 297                gth_output_set(gth, port, 0);
 298                gth_smcfreq_set(gth, port, 16);
 299        }
 300        /* disable overrides */
 301        iowrite32(0, gth->base + REG_GTH_DESTOVR);
 302
 303        /* masters swdest_0~31 and gswdest */
 304        for (i = 0; i < 33; i++)
 305                iowrite32(0, gth->base + REG_GTH_SWDEST0 + i * 4);
 306
 307        /* sources */
 308        iowrite32(0, gth->base + REG_GTH_SCR);
 309        iowrite32(0xfc, gth->base + REG_GTH_SCR2);
 310
 311        return 0;
 312}
 313
 314/*
 315 * "outputs" attribute group
 316 */
 317
 318static ssize_t output_attr_show(struct device *dev,
 319                                struct device_attribute *attr,
 320                                char *buf)
 321{
 322        struct output_attribute *oa =
 323                container_of(attr, struct output_attribute, attr);
 324        struct gth_device *gth = oa->gth;
 325        size_t count;
 326
 327        pm_runtime_get_sync(dev);
 328
 329        spin_lock(&gth->gth_lock);
 330        count = snprintf(buf, PAGE_SIZE, "%x\n",
 331                         gth_output_parm_get(gth, oa->port, oa->parm));
 332        spin_unlock(&gth->gth_lock);
 333
 334        pm_runtime_put(dev);
 335
 336        return count;
 337}
 338
 339static ssize_t output_attr_store(struct device *dev,
 340                                 struct device_attribute *attr,
 341                                 const char *buf, size_t count)
 342{
 343        struct output_attribute *oa =
 344                container_of(attr, struct output_attribute, attr);
 345        struct gth_device *gth = oa->gth;
 346        unsigned int config;
 347
 348        if (kstrtouint(buf, 16, &config) < 0)
 349                return -EINVAL;
 350
 351        pm_runtime_get_sync(dev);
 352
 353        spin_lock(&gth->gth_lock);
 354        gth_output_parm_set(gth, oa->port, oa->parm, config);
 355        spin_unlock(&gth->gth_lock);
 356
 357        pm_runtime_put(dev);
 358
 359        return count;
 360}
 361
 362static int intel_th_master_attributes(struct gth_device *gth)
 363{
 364        struct master_attribute *master_attrs;
 365        struct attribute **attrs;
 366        int i, nattrs = TH_CONFIGURABLE_MASTERS + 2;
 367
 368        attrs = devm_kcalloc(gth->dev, nattrs, sizeof(void *), GFP_KERNEL);
 369        if (!attrs)
 370                return -ENOMEM;
 371
 372        master_attrs = devm_kcalloc(gth->dev, nattrs,
 373                                    sizeof(struct master_attribute),
 374                                    GFP_KERNEL);
 375        if (!master_attrs)
 376                return -ENOMEM;
 377
 378        for (i = 0; i < TH_CONFIGURABLE_MASTERS + 1; i++) {
 379                char *name;
 380
 381                name = devm_kasprintf(gth->dev, GFP_KERNEL, "%d%s", i,
 382                                      i == TH_CONFIGURABLE_MASTERS ? "+" : "");
 383                if (!name)
 384                        return -ENOMEM;
 385
 386                master_attrs[i].attr.attr.name = name;
 387                master_attrs[i].attr.attr.mode = S_IRUGO | S_IWUSR;
 388                master_attrs[i].attr.show = master_attr_show;
 389                master_attrs[i].attr.store = master_attr_store;
 390
 391                sysfs_attr_init(&master_attrs[i].attr.attr);
 392                attrs[i] = &master_attrs[i].attr.attr;
 393
 394                master_attrs[i].gth = gth;
 395                master_attrs[i].master = i;
 396        }
 397
 398        gth->master_group.name  = "masters";
 399        gth->master_group.attrs = attrs;
 400
 401        return sysfs_create_group(&gth->dev->kobj, &gth->master_group);
 402}
 403
 404static int intel_th_output_attributes(struct gth_device *gth)
 405{
 406        struct output_attribute *out_attrs;
 407        struct attribute **attrs;
 408        int i, j, nouts = TH_POSSIBLE_OUTPUTS;
 409        int nparms = ARRAY_SIZE(output_parms);
 410        int nattrs = nouts * nparms + 1;
 411
 412        attrs = devm_kcalloc(gth->dev, nattrs, sizeof(void *), GFP_KERNEL);
 413        if (!attrs)
 414                return -ENOMEM;
 415
 416        out_attrs = devm_kcalloc(gth->dev, nattrs,
 417                                 sizeof(struct output_attribute),
 418                                 GFP_KERNEL);
 419        if (!out_attrs)
 420                return -ENOMEM;
 421
 422        for (i = 0; i < nouts; i++) {
 423                for (j = 0; j < nparms; j++) {
 424                        unsigned int idx = i * nparms + j;
 425                        char *name;
 426
 427                        name = devm_kasprintf(gth->dev, GFP_KERNEL, "%d_%s", i,
 428                                              output_parms[j].name);
 429                        if (!name)
 430                                return -ENOMEM;
 431
 432                        out_attrs[idx].attr.attr.name = name;
 433
 434                        if (output_parms[j].readable) {
 435                                out_attrs[idx].attr.attr.mode |= S_IRUGO;
 436                                out_attrs[idx].attr.show = output_attr_show;
 437                        }
 438
 439                        if (output_parms[j].writable) {
 440                                out_attrs[idx].attr.attr.mode |= S_IWUSR;
 441                                out_attrs[idx].attr.store = output_attr_store;
 442                        }
 443
 444                        sysfs_attr_init(&out_attrs[idx].attr.attr);
 445                        attrs[idx] = &out_attrs[idx].attr.attr;
 446
 447                        out_attrs[idx].gth = gth;
 448                        out_attrs[idx].port = i;
 449                        out_attrs[idx].parm = j;
 450                }
 451        }
 452
 453        gth->output_group.name  = "outputs";
 454        gth->output_group.attrs = attrs;
 455
 456        return sysfs_create_group(&gth->dev->kobj, &gth->output_group);
 457}
 458
 459/**
 460 * intel_th_gth_disable() - disable tracing to an output device
 461 * @thdev:      GTH device
 462 * @output:     output device's descriptor
 463 *
 464 * This will deconfigure all masters set to output to this device,
 465 * disable tracing using force storeEn off signal and wait for the
 466 * "pipeline empty" bit for corresponding output port.
 467 */
 468static void intel_th_gth_disable(struct intel_th_device *thdev,
 469                                 struct intel_th_output *output)
 470{
 471        struct gth_device *gth = dev_get_drvdata(&thdev->dev);
 472        unsigned long count;
 473        int master;
 474        u32 reg;
 475
 476        spin_lock(&gth->gth_lock);
 477        output->active = false;
 478
 479        for_each_set_bit(master, gth->output[output->port].master,
 480                         TH_CONFIGURABLE_MASTERS) {
 481                gth_master_set(gth, master, -1);
 482        }
 483        spin_unlock(&gth->gth_lock);
 484
 485        iowrite32(0, gth->base + REG_GTH_SCR);
 486        iowrite32(0xfd, gth->base + REG_GTH_SCR2);
 487
 488        /* wait on pipeline empty for the given port */
 489        for (reg = 0, count = GTH_PLE_WAITLOOP_DEPTH;
 490             count && !(reg & BIT(output->port)); count--) {
 491                reg = ioread32(gth->base + REG_GTH_STAT);
 492                cpu_relax();
 493        }
 494
 495        /* clear force capture done for next captures */
 496        iowrite32(0xfc, gth->base + REG_GTH_SCR2);
 497
 498        if (!count)
 499                dev_dbg(&thdev->dev, "timeout waiting for GTH[%d] PLE\n",
 500                        output->port);
 501
 502        reg = ioread32(gth->base + REG_GTH_SCRPD0);
 503        reg &= ~output->scratchpad;
 504        iowrite32(reg, gth->base + REG_GTH_SCRPD0);
 505}
 506
 507static void gth_tscu_resync(struct gth_device *gth)
 508{
 509        u32 reg;
 510
 511        reg = ioread32(gth->base + REG_TSCU_TSUCTRL);
 512        reg &= ~TSUCTRL_CTCRESYNC;
 513        iowrite32(reg, gth->base + REG_TSCU_TSUCTRL);
 514}
 515
 516/**
 517 * intel_th_gth_enable() - enable tracing to an output device
 518 * @thdev:      GTH device
 519 * @output:     output device's descriptor
 520 *
 521 * This will configure all masters set to output to this device and
 522 * enable tracing using force storeEn signal.
 523 */
 524static void intel_th_gth_enable(struct intel_th_device *thdev,
 525                                struct intel_th_output *output)
 526{
 527        struct gth_device *gth = dev_get_drvdata(&thdev->dev);
 528        struct intel_th *th = to_intel_th(thdev);
 529        u32 scr = 0xfc0000, scrpd;
 530        int master;
 531
 532        spin_lock(&gth->gth_lock);
 533        for_each_set_bit(master, gth->output[output->port].master,
 534                         TH_CONFIGURABLE_MASTERS + 1) {
 535                gth_master_set(gth, master, output->port);
 536        }
 537
 538        if (output->multiblock)
 539                scr |= 0xff;
 540
 541        output->active = true;
 542        spin_unlock(&gth->gth_lock);
 543
 544        if (INTEL_TH_CAP(th, tscu_enable))
 545                gth_tscu_resync(gth);
 546
 547        scrpd = ioread32(gth->base + REG_GTH_SCRPD0);
 548        scrpd |= output->scratchpad;
 549        iowrite32(scrpd, gth->base + REG_GTH_SCRPD0);
 550
 551        iowrite32(scr, gth->base + REG_GTH_SCR);
 552        iowrite32(0, gth->base + REG_GTH_SCR2);
 553}
 554
 555/**
 556 * intel_th_gth_assign() - assign output device to a GTH output port
 557 * @thdev:      GTH device
 558 * @othdev:     output device
 559 *
 560 * This will match a given output device parameters against present
 561 * output ports on the GTH and fill out relevant bits in output device's
 562 * descriptor.
 563 *
 564 * Return:      0 on success, -errno on error.
 565 */
 566static int intel_th_gth_assign(struct intel_th_device *thdev,
 567                               struct intel_th_device *othdev)
 568{
 569        struct gth_device *gth = dev_get_drvdata(&thdev->dev);
 570        int i, id;
 571
 572        if (thdev->host_mode)
 573                return -EBUSY;
 574
 575        if (othdev->type != INTEL_TH_OUTPUT)
 576                return -EINVAL;
 577
 578        for (i = 0, id = 0; i < TH_POSSIBLE_OUTPUTS; i++) {
 579                if (gth->output[i].port_type != othdev->output.type)
 580                        continue;
 581
 582                if (othdev->id == -1 || othdev->id == id)
 583                        goto found;
 584
 585                id++;
 586        }
 587
 588        return -ENOENT;
 589
 590found:
 591        spin_lock(&gth->gth_lock);
 592        othdev->output.port = i;
 593        othdev->output.active = false;
 594        gth->output[i].output = &othdev->output;
 595        spin_unlock(&gth->gth_lock);
 596
 597        return 0;
 598}
 599
 600/**
 601 * intel_th_gth_unassign() - deassociate an output device from its output port
 602 * @thdev:      GTH device
 603 * @othdev:     output device
 604 */
 605static void intel_th_gth_unassign(struct intel_th_device *thdev,
 606                                  struct intel_th_device *othdev)
 607{
 608        struct gth_device *gth = dev_get_drvdata(&thdev->dev);
 609        int port = othdev->output.port;
 610        int master;
 611
 612        if (thdev->host_mode)
 613                return;
 614
 615        spin_lock(&gth->gth_lock);
 616        othdev->output.port = -1;
 617        othdev->output.active = false;
 618        gth->output[port].output = NULL;
 619        for (master = 0; master <= TH_CONFIGURABLE_MASTERS; master++)
 620                if (gth->master[master] == port)
 621                        gth->master[master] = -1;
 622        spin_unlock(&gth->gth_lock);
 623}
 624
 625static int
 626intel_th_gth_set_output(struct intel_th_device *thdev, unsigned int master)
 627{
 628        struct gth_device *gth = dev_get_drvdata(&thdev->dev);
 629        int port = 0; /* FIXME: make default output configurable */
 630
 631        /*
 632         * everything above TH_CONFIGURABLE_MASTERS is controlled by the
 633         * same register
 634         */
 635        if (master > TH_CONFIGURABLE_MASTERS)
 636                master = TH_CONFIGURABLE_MASTERS;
 637
 638        spin_lock(&gth->gth_lock);
 639        if (gth->master[master] == -1) {
 640                set_bit(master, gth->output[port].master);
 641                gth->master[master] = port;
 642        }
 643        spin_unlock(&gth->gth_lock);
 644
 645        return 0;
 646}
 647
 648static int intel_th_gth_probe(struct intel_th_device *thdev)
 649{
 650        struct device *dev = &thdev->dev;
 651        struct intel_th *th = dev_get_drvdata(dev->parent);
 652        struct gth_device *gth;
 653        struct resource *res;
 654        void __iomem *base;
 655        int i, ret;
 656
 657        res = intel_th_device_get_resource(thdev, IORESOURCE_MEM, 0);
 658        if (!res)
 659                return -ENODEV;
 660
 661        base = devm_ioremap(dev, res->start, resource_size(res));
 662        if (!base)
 663                return -ENOMEM;
 664
 665        gth = devm_kzalloc(dev, sizeof(*gth), GFP_KERNEL);
 666        if (!gth)
 667                return -ENOMEM;
 668
 669        gth->dev = dev;
 670        gth->base = base;
 671        spin_lock_init(&gth->gth_lock);
 672
 673        dev_set_drvdata(dev, gth);
 674
 675        /*
 676         * Host mode can be signalled via SW means or via SCRPD_DEBUGGER_IN_USE
 677         * bit. Either way, don't reset HW in this case, and don't export any
 678         * capture configuration attributes. Also, refuse to assign output
 679         * drivers to ports, see intel_th_gth_assign().
 680         */
 681        if (thdev->host_mode)
 682                return 0;
 683
 684        ret = intel_th_gth_reset(gth);
 685        if (ret) {
 686                if (ret != -EBUSY)
 687                        return ret;
 688
 689                thdev->host_mode = true;
 690
 691                return 0;
 692        }
 693
 694        for (i = 0; i < TH_CONFIGURABLE_MASTERS + 1; i++)
 695                gth->master[i] = -1;
 696
 697        for (i = 0; i < TH_POSSIBLE_OUTPUTS; i++) {
 698                gth->output[i].gth = gth;
 699                gth->output[i].index = i;
 700                gth->output[i].port_type =
 701                        gth_output_parm_get(gth, i, TH_OUTPUT_PARM(port));
 702                if (gth->output[i].port_type == GTH_NONE)
 703                        continue;
 704
 705                ret = intel_th_output_enable(th, gth->output[i].port_type);
 706                /* -ENODEV is ok, we just won't have that device enumerated */
 707                if (ret && ret != -ENODEV)
 708                        return ret;
 709        }
 710
 711        if (intel_th_output_attributes(gth) ||
 712            intel_th_master_attributes(gth)) {
 713                pr_warn("Can't initialize sysfs attributes\n");
 714
 715                if (gth->output_group.attrs)
 716                        sysfs_remove_group(&gth->dev->kobj, &gth->output_group);
 717                return -ENOMEM;
 718        }
 719
 720        return 0;
 721}
 722
 723static void intel_th_gth_remove(struct intel_th_device *thdev)
 724{
 725        struct gth_device *gth = dev_get_drvdata(&thdev->dev);
 726
 727        sysfs_remove_group(&gth->dev->kobj, &gth->output_group);
 728        sysfs_remove_group(&gth->dev->kobj, &gth->master_group);
 729}
 730
 731static struct intel_th_driver intel_th_gth_driver = {
 732        .probe          = intel_th_gth_probe,
 733        .remove         = intel_th_gth_remove,
 734        .assign         = intel_th_gth_assign,
 735        .unassign       = intel_th_gth_unassign,
 736        .set_output     = intel_th_gth_set_output,
 737        .enable         = intel_th_gth_enable,
 738        .disable        = intel_th_gth_disable,
 739        .driver = {
 740                .name   = "gth",
 741                .owner  = THIS_MODULE,
 742        },
 743};
 744
 745module_driver(intel_th_gth_driver,
 746              intel_th_driver_register,
 747              intel_th_driver_unregister);
 748
 749MODULE_ALIAS("intel_th_switch");
 750MODULE_LICENSE("GPL v2");
 751MODULE_DESCRIPTION("Intel(R) Trace Hub Global Trace Hub driver");
 752MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");
 753