core.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. /*
  2. * Intel(R) Trace Hub driver core
  3. *
  4. * Copyright (C) 2014-2015 Intel Corporation.
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms and conditions of the GNU General Public License,
  8. * version 2, as published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope it will be useful, but WITHOUT
  11. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13. * more details.
  14. */
  15. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  16. #include <linux/types.h>
  17. #include <linux/module.h>
  18. #include <linux/device.h>
  19. #include <linux/sysfs.h>
  20. #include <linux/kdev_t.h>
  21. #include <linux/debugfs.h>
  22. #include <linux/idr.h>
  23. #include <linux/pci.h>
  24. #include <linux/dma-mapping.h>
  25. #include "intel_th.h"
  26. #include "debug.h"
  27. static DEFINE_IDA(intel_th_ida);
  28. static int intel_th_match(struct device *dev, struct device_driver *driver)
  29. {
  30. struct intel_th_driver *thdrv = to_intel_th_driver(driver);
  31. struct intel_th_device *thdev = to_intel_th_device(dev);
  32. if (thdev->type == INTEL_TH_SWITCH &&
  33. (!thdrv->enable || !thdrv->disable))
  34. return 0;
  35. return !strcmp(thdev->name, driver->name);
  36. }
  37. static int intel_th_child_remove(struct device *dev, void *data)
  38. {
  39. device_release_driver(dev);
  40. return 0;
  41. }
  42. static int intel_th_probe(struct device *dev)
  43. {
  44. struct intel_th_driver *thdrv = to_intel_th_driver(dev->driver);
  45. struct intel_th_device *thdev = to_intel_th_device(dev);
  46. struct intel_th_driver *hubdrv;
  47. struct intel_th_device *hub = NULL;
  48. int ret;
  49. if (thdev->type == INTEL_TH_SWITCH)
  50. hub = thdev;
  51. else if (dev->parent)
  52. hub = to_intel_th_device(dev->parent);
  53. if (!hub || !hub->dev.driver)
  54. return -EPROBE_DEFER;
  55. hubdrv = to_intel_th_driver(hub->dev.driver);
  56. ret = thdrv->probe(to_intel_th_device(dev));
  57. if (ret)
  58. return ret;
  59. if (thdev->type == INTEL_TH_OUTPUT &&
  60. !intel_th_output_assigned(thdev))
  61. ret = hubdrv->assign(hub, thdev);
  62. return ret;
  63. }
  64. static int intel_th_remove(struct device *dev)
  65. {
  66. struct intel_th_driver *thdrv = to_intel_th_driver(dev->driver);
  67. struct intel_th_device *thdev = to_intel_th_device(dev);
  68. struct intel_th_device *hub = to_intel_th_device(dev->parent);
  69. int err;
  70. if (thdev->type == INTEL_TH_SWITCH) {
  71. err = device_for_each_child(dev, thdev, intel_th_child_remove);
  72. if (err)
  73. return err;
  74. }
  75. thdrv->remove(thdev);
  76. if (intel_th_output_assigned(thdev)) {
  77. struct intel_th_driver *hubdrv =
  78. to_intel_th_driver(dev->parent->driver);
  79. if (hub->dev.driver)
  80. hubdrv->unassign(hub, thdev);
  81. }
  82. return 0;
  83. }
  84. static struct bus_type intel_th_bus = {
  85. .name = "intel_th",
  86. .dev_attrs = NULL,
  87. .match = intel_th_match,
  88. .probe = intel_th_probe,
  89. .remove = intel_th_remove,
  90. };
  91. static void intel_th_device_free(struct intel_th_device *thdev);
  92. static void intel_th_device_release(struct device *dev)
  93. {
  94. intel_th_device_free(to_intel_th_device(dev));
  95. }
  96. static struct device_type intel_th_source_device_type = {
  97. .name = "intel_th_source_device",
  98. .release = intel_th_device_release,
  99. };
  100. static struct intel_th *to_intel_th(struct intel_th_device *thdev)
  101. {
  102. /*
  103. * subdevice tree is flat: if this one is not a switch, its
  104. * parent must be
  105. */
  106. if (thdev->type != INTEL_TH_SWITCH)
  107. thdev = to_intel_th_hub(thdev);
  108. if (WARN_ON_ONCE(!thdev || thdev->type != INTEL_TH_SWITCH))
  109. return NULL;
  110. return dev_get_drvdata(thdev->dev.parent);
  111. }
  112. static char *intel_th_output_devnode(struct device *dev, umode_t *mode,
  113. kuid_t *uid, kgid_t *gid)
  114. {
  115. struct intel_th_device *thdev = to_intel_th_device(dev);
  116. struct intel_th *th = to_intel_th(thdev);
  117. char *node;
  118. if (thdev->id >= 0)
  119. node = kasprintf(GFP_KERNEL, "intel_th%d/%s%d", th->id,
  120. thdev->name, thdev->id);
  121. else
  122. node = kasprintf(GFP_KERNEL, "intel_th%d/%s", th->id,
  123. thdev->name);
  124. return node;
  125. }
  126. static ssize_t port_show(struct device *dev, struct device_attribute *attr,
  127. char *buf)
  128. {
  129. struct intel_th_device *thdev = to_intel_th_device(dev);
  130. if (thdev->output.port >= 0)
  131. return scnprintf(buf, PAGE_SIZE, "%u\n", thdev->output.port);
  132. return scnprintf(buf, PAGE_SIZE, "unassigned\n");
  133. }
  134. static DEVICE_ATTR_RO(port);
  135. static int intel_th_output_activate(struct intel_th_device *thdev)
  136. {
  137. struct intel_th_driver *thdrv = to_intel_th_driver(thdev->dev.driver);
  138. if (thdrv->activate)
  139. return thdrv->activate(thdev);
  140. intel_th_trace_enable(thdev);
  141. return 0;
  142. }
  143. static void intel_th_output_deactivate(struct intel_th_device *thdev)
  144. {
  145. struct intel_th_driver *thdrv = to_intel_th_driver(thdev->dev.driver);
  146. if (thdrv->deactivate)
  147. thdrv->deactivate(thdev);
  148. else
  149. intel_th_trace_disable(thdev);
  150. }
  151. static ssize_t active_show(struct device *dev, struct device_attribute *attr,
  152. char *buf)
  153. {
  154. struct intel_th_device *thdev = to_intel_th_device(dev);
  155. return scnprintf(buf, PAGE_SIZE, "%d\n", thdev->output.active);
  156. }
  157. static ssize_t active_store(struct device *dev, struct device_attribute *attr,
  158. const char *buf, size_t size)
  159. {
  160. struct intel_th_device *thdev = to_intel_th_device(dev);
  161. unsigned long val;
  162. int ret;
  163. ret = kstrtoul(buf, 10, &val);
  164. if (ret)
  165. return ret;
  166. if (!!val != thdev->output.active) {
  167. if (val)
  168. ret = intel_th_output_activate(thdev);
  169. else
  170. intel_th_output_deactivate(thdev);
  171. }
  172. return ret ? ret : size;
  173. }
  174. static DEVICE_ATTR_RW(active);
  175. static struct attribute *intel_th_output_attrs[] = {
  176. &dev_attr_port.attr,
  177. &dev_attr_active.attr,
  178. NULL,
  179. };
  180. ATTRIBUTE_GROUPS(intel_th_output);
  181. static struct device_type intel_th_output_device_type = {
  182. .name = "intel_th_output_device",
  183. .groups = intel_th_output_groups,
  184. .release = intel_th_device_release,
  185. .devnode = intel_th_output_devnode,
  186. };
  187. static struct device_type intel_th_switch_device_type = {
  188. .name = "intel_th_switch_device",
  189. .release = intel_th_device_release,
  190. };
  191. static struct device_type *intel_th_device_type[] = {
  192. [INTEL_TH_SOURCE] = &intel_th_source_device_type,
  193. [INTEL_TH_OUTPUT] = &intel_th_output_device_type,
  194. [INTEL_TH_SWITCH] = &intel_th_switch_device_type,
  195. };
  196. int intel_th_driver_register(struct intel_th_driver *thdrv)
  197. {
  198. if (!thdrv->probe || !thdrv->remove)
  199. return -EINVAL;
  200. thdrv->driver.bus = &intel_th_bus;
  201. return driver_register(&thdrv->driver);
  202. }
  203. EXPORT_SYMBOL_GPL(intel_th_driver_register);
  204. void intel_th_driver_unregister(struct intel_th_driver *thdrv)
  205. {
  206. driver_unregister(&thdrv->driver);
  207. }
  208. EXPORT_SYMBOL_GPL(intel_th_driver_unregister);
  209. static struct intel_th_device *
  210. intel_th_device_alloc(struct intel_th *th, unsigned int type, const char *name,
  211. int id)
  212. {
  213. struct device *parent;
  214. struct intel_th_device *thdev;
  215. if (type == INTEL_TH_SWITCH)
  216. parent = th->dev;
  217. else
  218. parent = &th->hub->dev;
  219. thdev = kzalloc(sizeof(*thdev) + strlen(name) + 1, GFP_KERNEL);
  220. if (!thdev)
  221. return NULL;
  222. thdev->id = id;
  223. thdev->type = type;
  224. strcpy(thdev->name, name);
  225. device_initialize(&thdev->dev);
  226. thdev->dev.bus = &intel_th_bus;
  227. thdev->dev.type = intel_th_device_type[type];
  228. thdev->dev.parent = parent;
  229. thdev->dev.dma_mask = parent->dma_mask;
  230. thdev->dev.dma_parms = parent->dma_parms;
  231. dma_set_coherent_mask(&thdev->dev, parent->coherent_dma_mask);
  232. if (id >= 0)
  233. dev_set_name(&thdev->dev, "%d-%s%d", th->id, name, id);
  234. else
  235. dev_set_name(&thdev->dev, "%d-%s", th->id, name);
  236. return thdev;
  237. }
  238. static int intel_th_device_add_resources(struct intel_th_device *thdev,
  239. struct resource *res, int nres)
  240. {
  241. struct resource *r;
  242. r = kmemdup(res, sizeof(*res) * nres, GFP_KERNEL);
  243. if (!r)
  244. return -ENOMEM;
  245. thdev->resource = r;
  246. thdev->num_resources = nres;
  247. return 0;
  248. }
  249. static void intel_th_device_remove(struct intel_th_device *thdev)
  250. {
  251. device_del(&thdev->dev);
  252. put_device(&thdev->dev);
  253. }
  254. static void intel_th_device_free(struct intel_th_device *thdev)
  255. {
  256. kfree(thdev->resource);
  257. kfree(thdev);
  258. }
  259. /*
  260. * Intel(R) Trace Hub subdevices
  261. */
  262. static struct intel_th_subdevice {
  263. const char *name;
  264. struct resource res[3];
  265. unsigned nres;
  266. unsigned type;
  267. unsigned otype;
  268. unsigned scrpd;
  269. int id;
  270. } intel_th_subdevices[TH_SUBDEVICE_MAX] = {
  271. {
  272. .nres = 1,
  273. .res = {
  274. {
  275. .start = REG_GTH_OFFSET,
  276. .end = REG_GTH_OFFSET + REG_GTH_LENGTH - 1,
  277. .flags = IORESOURCE_MEM,
  278. },
  279. },
  280. .name = "gth",
  281. .type = INTEL_TH_SWITCH,
  282. .id = -1,
  283. },
  284. {
  285. .nres = 2,
  286. .res = {
  287. {
  288. .start = REG_MSU_OFFSET,
  289. .end = REG_MSU_OFFSET + REG_MSU_LENGTH - 1,
  290. .flags = IORESOURCE_MEM,
  291. },
  292. {
  293. .start = BUF_MSU_OFFSET,
  294. .end = BUF_MSU_OFFSET + BUF_MSU_LENGTH - 1,
  295. .flags = IORESOURCE_MEM,
  296. },
  297. },
  298. .name = "msc",
  299. .id = 0,
  300. .type = INTEL_TH_OUTPUT,
  301. .otype = GTH_MSU,
  302. .scrpd = SCRPD_MEM_IS_PRIM_DEST | SCRPD_MSC0_IS_ENABLED,
  303. },
  304. {
  305. .nres = 2,
  306. .res = {
  307. {
  308. .start = REG_MSU_OFFSET,
  309. .end = REG_MSU_OFFSET + REG_MSU_LENGTH - 1,
  310. .flags = IORESOURCE_MEM,
  311. },
  312. {
  313. .start = BUF_MSU_OFFSET,
  314. .end = BUF_MSU_OFFSET + BUF_MSU_LENGTH - 1,
  315. .flags = IORESOURCE_MEM,
  316. },
  317. },
  318. .name = "msc",
  319. .id = 1,
  320. .type = INTEL_TH_OUTPUT,
  321. .otype = GTH_MSU,
  322. .scrpd = SCRPD_MEM_IS_PRIM_DEST | SCRPD_MSC1_IS_ENABLED,
  323. },
  324. {
  325. .nres = 2,
  326. .res = {
  327. {
  328. .start = REG_STH_OFFSET,
  329. .end = REG_STH_OFFSET + REG_STH_LENGTH - 1,
  330. .flags = IORESOURCE_MEM,
  331. },
  332. {
  333. .start = TH_MMIO_SW,
  334. .end = 0,
  335. .flags = IORESOURCE_MEM,
  336. },
  337. },
  338. .id = -1,
  339. .name = "sth",
  340. .type = INTEL_TH_SOURCE,
  341. },
  342. {
  343. .nres = 1,
  344. .res = {
  345. {
  346. .start = REG_PTI_OFFSET,
  347. .end = REG_PTI_OFFSET + REG_PTI_LENGTH - 1,
  348. .flags = IORESOURCE_MEM,
  349. },
  350. },
  351. .id = -1,
  352. .name = "pti",
  353. .type = INTEL_TH_OUTPUT,
  354. .otype = GTH_PTI,
  355. .scrpd = SCRPD_PTI_IS_PRIM_DEST,
  356. },
  357. {
  358. .nres = 1,
  359. .res = {
  360. {
  361. .start = REG_DCIH_OFFSET,
  362. .end = REG_DCIH_OFFSET + REG_DCIH_LENGTH - 1,
  363. .flags = IORESOURCE_MEM,
  364. },
  365. },
  366. .id = -1,
  367. .name = "dcih",
  368. .type = INTEL_TH_OUTPUT,
  369. },
  370. };
  371. static int intel_th_populate(struct intel_th *th, struct resource *devres,
  372. unsigned int ndevres, int irq)
  373. {
  374. struct resource res[3];
  375. unsigned int req = 0;
  376. int i, err;
  377. /* create devices for each intel_th_subdevice */
  378. for (i = 0; i < ARRAY_SIZE(intel_th_subdevices); i++) {
  379. struct intel_th_subdevice *subdev = &intel_th_subdevices[i];
  380. struct intel_th_device *thdev;
  381. int r;
  382. thdev = intel_th_device_alloc(th, subdev->type, subdev->name,
  383. subdev->id);
  384. if (!thdev) {
  385. err = -ENOMEM;
  386. goto kill_subdevs;
  387. }
  388. memcpy(res, subdev->res,
  389. sizeof(struct resource) * subdev->nres);
  390. for (r = 0; r < subdev->nres; r++) {
  391. int bar = TH_MMIO_CONFIG;
  392. /*
  393. * Take .end == 0 to mean 'take the whole bar',
  394. * .start then tells us which bar it is. Default to
  395. * TH_MMIO_CONFIG.
  396. */
  397. if (!res[r].end && res[r].flags == IORESOURCE_MEM) {
  398. bar = res[r].start;
  399. res[r].start = 0;
  400. res[r].end = resource_size(&devres[bar]) - 1;
  401. }
  402. if (res[r].flags & IORESOURCE_MEM) {
  403. res[r].start += devres[bar].start;
  404. res[r].end += devres[bar].start;
  405. dev_dbg(th->dev, "%s:%d @ %pR\n",
  406. subdev->name, r, &res[r]);
  407. } else if (res[r].flags & IORESOURCE_IRQ) {
  408. res[r].start = irq;
  409. }
  410. }
  411. err = intel_th_device_add_resources(thdev, res, subdev->nres);
  412. if (err) {
  413. put_device(&thdev->dev);
  414. goto kill_subdevs;
  415. }
  416. if (subdev->type == INTEL_TH_OUTPUT) {
  417. thdev->dev.devt = MKDEV(th->major, i);
  418. thdev->output.type = subdev->otype;
  419. thdev->output.port = -1;
  420. thdev->output.scratchpad = subdev->scrpd;
  421. }
  422. err = device_add(&thdev->dev);
  423. if (err) {
  424. put_device(&thdev->dev);
  425. goto kill_subdevs;
  426. }
  427. /* need switch driver to be loaded to enumerate the rest */
  428. if (subdev->type == INTEL_TH_SWITCH && !req) {
  429. th->hub = thdev;
  430. err = request_module("intel_th_%s", subdev->name);
  431. if (!err)
  432. req++;
  433. }
  434. th->thdev[i] = thdev;
  435. }
  436. return 0;
  437. kill_subdevs:
  438. for (i-- ; i >= 0; i--)
  439. intel_th_device_remove(th->thdev[i]);
  440. return err;
  441. }
  442. static int match_devt(struct device *dev, void *data)
  443. {
  444. dev_t devt = (dev_t)(unsigned long)data;
  445. return dev->devt == devt;
  446. }
  447. static int intel_th_output_open(struct inode *inode, struct file *file)
  448. {
  449. const struct file_operations *fops;
  450. struct intel_th_driver *thdrv;
  451. struct device *dev;
  452. int err;
  453. dev = bus_find_device(&intel_th_bus, NULL,
  454. (void *)(unsigned long)inode->i_rdev,
  455. match_devt);
  456. if (!dev || !dev->driver)
  457. return -ENODEV;
  458. thdrv = to_intel_th_driver(dev->driver);
  459. fops = fops_get(thdrv->fops);
  460. if (!fops)
  461. return -ENODEV;
  462. replace_fops(file, fops);
  463. file->private_data = to_intel_th_device(dev);
  464. if (file->f_op->open) {
  465. err = file->f_op->open(inode, file);
  466. return err;
  467. }
  468. return 0;
  469. }
  470. static const struct file_operations intel_th_output_fops = {
  471. .open = intel_th_output_open,
  472. .llseek = noop_llseek,
  473. };
  474. /**
  475. * intel_th_alloc() - allocate a new Intel TH device and its subdevices
  476. * @dev: parent device
  477. * @devres: parent's resources
  478. * @ndevres: number of resources
  479. * @irq: irq number
  480. */
  481. struct intel_th *
  482. intel_th_alloc(struct device *dev, struct resource *devres,
  483. unsigned int ndevres, int irq)
  484. {
  485. struct intel_th *th;
  486. int err;
  487. th = kzalloc(sizeof(*th), GFP_KERNEL);
  488. if (!th)
  489. return ERR_PTR(-ENOMEM);
  490. th->id = ida_simple_get(&intel_th_ida, 0, 0, GFP_KERNEL);
  491. if (th->id < 0) {
  492. err = th->id;
  493. goto err_alloc;
  494. }
  495. th->major = __register_chrdev(0, 0, TH_POSSIBLE_OUTPUTS,
  496. "intel_th/output", &intel_th_output_fops);
  497. if (th->major < 0) {
  498. err = th->major;
  499. goto err_ida;
  500. }
  501. th->dev = dev;
  502. dev_set_drvdata(dev, th);
  503. err = intel_th_populate(th, devres, ndevres, irq);
  504. if (err)
  505. goto err_chrdev;
  506. return th;
  507. err_chrdev:
  508. __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS,
  509. "intel_th/output");
  510. err_ida:
  511. ida_simple_remove(&intel_th_ida, th->id);
  512. err_alloc:
  513. kfree(th);
  514. return ERR_PTR(err);
  515. }
  516. EXPORT_SYMBOL_GPL(intel_th_alloc);
  517. void intel_th_free(struct intel_th *th)
  518. {
  519. int i;
  520. for (i = 0; i < TH_SUBDEVICE_MAX; i++)
  521. if (th->thdev[i] != th->hub)
  522. intel_th_device_remove(th->thdev[i]);
  523. intel_th_device_remove(th->hub);
  524. __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS,
  525. "intel_th/output");
  526. ida_simple_remove(&intel_th_ida, th->id);
  527. kfree(th);
  528. }
  529. EXPORT_SYMBOL_GPL(intel_th_free);
  530. /**
  531. * intel_th_trace_enable() - enable tracing for an output device
  532. * @thdev: output device that requests tracing be enabled
  533. */
  534. int intel_th_trace_enable(struct intel_th_device *thdev)
  535. {
  536. struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent);
  537. struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
  538. if (WARN_ON_ONCE(hub->type != INTEL_TH_SWITCH))
  539. return -EINVAL;
  540. if (WARN_ON_ONCE(thdev->type != INTEL_TH_OUTPUT))
  541. return -EINVAL;
  542. hubdrv->enable(hub, &thdev->output);
  543. return 0;
  544. }
  545. EXPORT_SYMBOL_GPL(intel_th_trace_enable);
  546. /**
  547. * intel_th_trace_disable() - disable tracing for an output device
  548. * @thdev: output device that requests tracing be disabled
  549. */
  550. int intel_th_trace_disable(struct intel_th_device *thdev)
  551. {
  552. struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent);
  553. struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
  554. WARN_ON_ONCE(hub->type != INTEL_TH_SWITCH);
  555. if (WARN_ON_ONCE(thdev->type != INTEL_TH_OUTPUT))
  556. return -EINVAL;
  557. hubdrv->disable(hub, &thdev->output);
  558. return 0;
  559. }
  560. EXPORT_SYMBOL_GPL(intel_th_trace_disable);
  561. int intel_th_set_output(struct intel_th_device *thdev,
  562. unsigned int master)
  563. {
  564. struct intel_th_device *hub = to_intel_th_device(thdev->dev.parent);
  565. struct intel_th_driver *hubdrv = to_intel_th_driver(hub->dev.driver);
  566. if (!hubdrv->set_output)
  567. return -ENOTSUPP;
  568. return hubdrv->set_output(hub, master);
  569. }
  570. EXPORT_SYMBOL_GPL(intel_th_set_output);
  571. static int __init intel_th_init(void)
  572. {
  573. intel_th_debug_init();
  574. return bus_register(&intel_th_bus);
  575. }
  576. subsys_initcall(intel_th_init);
  577. static void __exit intel_th_exit(void)
  578. {
  579. intel_th_debug_done();
  580. bus_unregister(&intel_th_bus);
  581. }
  582. module_exit(intel_th_exit);
  583. MODULE_LICENSE("GPL v2");
  584. MODULE_DESCRIPTION("Intel(R) Trace Hub controller driver");
  585. MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>");