root/drivers/hwtracing/intel_th/core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. intel_th_match
  2. intel_th_child_remove
  3. intel_th_probe
  4. intel_th_remove
  5. intel_th_device_release
  6. intel_th_output_devnode
  7. port_show
  8. intel_th_output_activate
  9. intel_th_output_deactivate
  10. active_show
  11. active_store
  12. intel_th_driver_register
  13. intel_th_driver_unregister
  14. intel_th_device_alloc
  15. intel_th_device_add_resources
  16. intel_th_device_remove
  17. intel_th_device_free
  18. __intel_th_request_hub_module
  19. intel_th_request_hub_module
  20. intel_th_request_hub_module_flush
  21. intel_th_request_hub_module
  22. intel_th_request_hub_module_flush
  23. intel_th_subdevice_alloc
  24. intel_th_output_enable
  25. intel_th_populate
  26. intel_th_output_open
  27. intel_th_irq
  28. intel_th_alloc
  29. intel_th_free
  30. intel_th_trace_enable
  31. intel_th_trace_switch
  32. intel_th_trace_disable
  33. intel_th_set_output
  34. intel_th_init
  35. intel_th_exit

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

/* [<][>][^][v][top][bottom][index][help] */