discovery.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Intel Platform Monitory Technology Discovery driver
  4. *
  5. * Copyright (c) 2025, Intel Corporation.
  6. * All Rights Reserved.
  7. */
  8. #include <linux/auxiliary_bus.h>
  9. #include <linux/bitfield.h>
  10. #include <linux/bits.h>
  11. #include <linux/bug.h>
  12. #include <linux/cleanup.h>
  13. #include <linux/container_of.h>
  14. #include <linux/device.h>
  15. #include <linux/err.h>
  16. #include <linux/io.h>
  17. #include <linux/ioport.h>
  18. #include <linux/kdev_t.h>
  19. #include <linux/kobject.h>
  20. #include <linux/list.h>
  21. #include <linux/module.h>
  22. #include <linux/mutex.h>
  23. #include <linux/overflow.h>
  24. #include <linux/pci.h>
  25. #include <linux/slab.h>
  26. #include <linux/string_choices.h>
  27. #include <linux/sysfs.h>
  28. #include <linux/types.h>
  29. #include <linux/uaccess.h>
  30. #include <linux/intel_pmt_features.h>
  31. #include <linux/intel_vsec.h>
  32. #include "class.h"
  33. #define MAX_FEATURE_VERSION 0
  34. #define DT_TBIR GENMASK(2, 0)
  35. #define FEAT_ATTR_SIZE(x) ((x) * sizeof(u32))
  36. #define PMT_GUID_SIZE(x) ((x) * sizeof(u32))
  37. #define PMT_ACCESS_TYPE_RSVD 0xF
  38. #define SKIP_FEATURE 1
  39. struct feature_discovery_table {
  40. u32 access_type:4;
  41. u32 version:8;
  42. u32 size:16;
  43. u32 reserved:4;
  44. u32 id;
  45. u32 offset;
  46. u32 reserved2;
  47. };
  48. /* Common feature table header */
  49. struct feature_header {
  50. u32 attr_size:8;
  51. u32 num_guids:8;
  52. u32 reserved:16;
  53. };
  54. /* Feature attribute fields */
  55. struct caps {
  56. u32 caps;
  57. };
  58. struct command {
  59. u32 max_stream_size:16;
  60. u32 max_command_size:16;
  61. };
  62. struct watcher {
  63. u32 reserved:21;
  64. u32 period:11;
  65. struct command command;
  66. };
  67. struct rmid {
  68. u32 num_rmids:16; /* Number of Resource Monitoring IDs */
  69. u32 reserved:16;
  70. struct watcher watcher;
  71. };
  72. struct feature_table {
  73. struct feature_header header;
  74. struct caps caps;
  75. union {
  76. struct command command;
  77. struct watcher watcher;
  78. struct rmid rmid;
  79. };
  80. u32 *guids;
  81. };
  82. /* For backreference in struct feature */
  83. struct pmt_features_priv;
  84. struct feature {
  85. struct feature_table table;
  86. struct kobject kobj;
  87. struct pmt_features_priv *priv;
  88. struct list_head list;
  89. const struct attribute_group *attr_group;
  90. enum pmt_feature_id id;
  91. };
  92. struct pmt_features_priv {
  93. struct device *parent;
  94. struct device *dev;
  95. int count;
  96. u32 mask;
  97. struct feature feature[];
  98. };
  99. static LIST_HEAD(pmt_feature_list);
  100. static DEFINE_MUTEX(feature_list_lock);
  101. #define to_pmt_feature(x) container_of(x, struct feature, kobj)
  102. static void pmt_feature_release(struct kobject *kobj)
  103. {
  104. }
  105. static ssize_t caps_show(struct kobject *kobj, struct kobj_attribute *attr,
  106. char *buf)
  107. {
  108. struct feature *feature = to_pmt_feature(kobj);
  109. struct pmt_cap **pmt_caps;
  110. u32 caps = feature->table.caps.caps;
  111. ssize_t ret = 0;
  112. switch (feature->id) {
  113. case FEATURE_PER_CORE_PERF_TELEM:
  114. pmt_caps = pmt_caps_pcpt;
  115. break;
  116. case FEATURE_PER_CORE_ENV_TELEM:
  117. pmt_caps = pmt_caps_pcet;
  118. break;
  119. case FEATURE_PER_RMID_PERF_TELEM:
  120. pmt_caps = pmt_caps_rmid_perf;
  121. break;
  122. case FEATURE_ACCEL_TELEM:
  123. pmt_caps = pmt_caps_accel;
  124. break;
  125. case FEATURE_UNCORE_TELEM:
  126. pmt_caps = pmt_caps_uncore;
  127. break;
  128. case FEATURE_CRASH_LOG:
  129. pmt_caps = pmt_caps_crashlog;
  130. break;
  131. case FEATURE_PETE_LOG:
  132. pmt_caps = pmt_caps_pete;
  133. break;
  134. case FEATURE_TPMI_CTRL:
  135. pmt_caps = pmt_caps_tpmi;
  136. break;
  137. case FEATURE_TRACING:
  138. pmt_caps = pmt_caps_tracing;
  139. break;
  140. case FEATURE_PER_RMID_ENERGY_TELEM:
  141. pmt_caps = pmt_caps_rmid_energy;
  142. break;
  143. default:
  144. return -EINVAL;
  145. }
  146. while (*pmt_caps) {
  147. struct pmt_cap *pmt_cap = *pmt_caps;
  148. while (pmt_cap->name) {
  149. ret += sysfs_emit_at(buf, ret, "%-40s Available: %s\n", pmt_cap->name,
  150. str_yes_no(pmt_cap->mask & caps));
  151. pmt_cap++;
  152. }
  153. pmt_caps++;
  154. }
  155. return ret;
  156. }
  157. static struct kobj_attribute caps_attribute = __ATTR_RO(caps);
  158. static struct watcher *get_watcher(struct feature *feature)
  159. {
  160. switch (feature_layout[feature->id]) {
  161. case LAYOUT_RMID:
  162. return &feature->table.rmid.watcher;
  163. case LAYOUT_WATCHER:
  164. return &feature->table.watcher;
  165. default:
  166. return ERR_PTR(-EINVAL);
  167. }
  168. }
  169. static struct command *get_command(struct feature *feature)
  170. {
  171. switch (feature_layout[feature->id]) {
  172. case LAYOUT_RMID:
  173. return &feature->table.rmid.watcher.command;
  174. case LAYOUT_WATCHER:
  175. return &feature->table.watcher.command;
  176. case LAYOUT_COMMAND:
  177. return &feature->table.command;
  178. default:
  179. return ERR_PTR(-EINVAL);
  180. }
  181. }
  182. static ssize_t num_rmids_show(struct kobject *kobj,
  183. struct kobj_attribute *attr, char *buf)
  184. {
  185. struct feature *feature = to_pmt_feature(kobj);
  186. return sysfs_emit(buf, "%u\n", feature->table.rmid.num_rmids);
  187. }
  188. static struct kobj_attribute num_rmids_attribute = __ATTR_RO(num_rmids);
  189. static ssize_t min_watcher_period_ms_show(struct kobject *kobj,
  190. struct kobj_attribute *attr, char *buf)
  191. {
  192. struct feature *feature = to_pmt_feature(kobj);
  193. struct watcher *watcher = get_watcher(feature);
  194. if (IS_ERR(watcher))
  195. return PTR_ERR(watcher);
  196. return sysfs_emit(buf, "%u\n", watcher->period);
  197. }
  198. static struct kobj_attribute min_watcher_period_ms_attribute =
  199. __ATTR_RO(min_watcher_period_ms);
  200. static ssize_t max_stream_size_show(struct kobject *kobj,
  201. struct kobj_attribute *attr, char *buf)
  202. {
  203. struct feature *feature = to_pmt_feature(kobj);
  204. struct command *command = get_command(feature);
  205. if (IS_ERR(command))
  206. return PTR_ERR(command);
  207. return sysfs_emit(buf, "%u\n", command->max_stream_size);
  208. }
  209. static struct kobj_attribute max_stream_size_attribute =
  210. __ATTR_RO(max_stream_size);
  211. static ssize_t max_command_size_show(struct kobject *kobj,
  212. struct kobj_attribute *attr, char *buf)
  213. {
  214. struct feature *feature = to_pmt_feature(kobj);
  215. struct command *command = get_command(feature);
  216. if (IS_ERR(command))
  217. return PTR_ERR(command);
  218. return sysfs_emit(buf, "%u\n", command->max_command_size);
  219. }
  220. static struct kobj_attribute max_command_size_attribute =
  221. __ATTR_RO(max_command_size);
  222. static ssize_t guids_show(struct kobject *kobj, struct kobj_attribute *attr,
  223. char *buf)
  224. {
  225. struct feature *feature = to_pmt_feature(kobj);
  226. int i, count = 0;
  227. for (i = 0; i < feature->table.header.num_guids; i++)
  228. count += sysfs_emit_at(buf, count, "0x%x\n",
  229. feature->table.guids[i]);
  230. return count;
  231. }
  232. static struct kobj_attribute guids_attribute = __ATTR_RO(guids);
  233. static struct attribute *pmt_feature_rmid_attrs[] = {
  234. &caps_attribute.attr,
  235. &num_rmids_attribute.attr,
  236. &min_watcher_period_ms_attribute.attr,
  237. &max_stream_size_attribute.attr,
  238. &max_command_size_attribute.attr,
  239. &guids_attribute.attr,
  240. NULL
  241. };
  242. ATTRIBUTE_GROUPS(pmt_feature_rmid);
  243. static const struct kobj_type pmt_feature_rmid_ktype = {
  244. .sysfs_ops = &kobj_sysfs_ops,
  245. .release = pmt_feature_release,
  246. .default_groups = pmt_feature_rmid_groups,
  247. };
  248. static struct attribute *pmt_feature_watcher_attrs[] = {
  249. &caps_attribute.attr,
  250. &min_watcher_period_ms_attribute.attr,
  251. &max_stream_size_attribute.attr,
  252. &max_command_size_attribute.attr,
  253. &guids_attribute.attr,
  254. NULL
  255. };
  256. ATTRIBUTE_GROUPS(pmt_feature_watcher);
  257. static const struct kobj_type pmt_feature_watcher_ktype = {
  258. .sysfs_ops = &kobj_sysfs_ops,
  259. .release = pmt_feature_release,
  260. .default_groups = pmt_feature_watcher_groups,
  261. };
  262. static struct attribute *pmt_feature_command_attrs[] = {
  263. &caps_attribute.attr,
  264. &max_stream_size_attribute.attr,
  265. &max_command_size_attribute.attr,
  266. &guids_attribute.attr,
  267. NULL
  268. };
  269. ATTRIBUTE_GROUPS(pmt_feature_command);
  270. static const struct kobj_type pmt_feature_command_ktype = {
  271. .sysfs_ops = &kobj_sysfs_ops,
  272. .release = pmt_feature_release,
  273. .default_groups = pmt_feature_command_groups,
  274. };
  275. static struct attribute *pmt_feature_guids_attrs[] = {
  276. &caps_attribute.attr,
  277. &guids_attribute.attr,
  278. NULL
  279. };
  280. ATTRIBUTE_GROUPS(pmt_feature_guids);
  281. static const struct kobj_type pmt_feature_guids_ktype = {
  282. .sysfs_ops = &kobj_sysfs_ops,
  283. .release = pmt_feature_release,
  284. .default_groups = pmt_feature_guids_groups,
  285. };
  286. static int
  287. pmt_feature_get_disc_table(struct pmt_features_priv *priv,
  288. struct resource *disc_res,
  289. struct feature_discovery_table *disc_tbl)
  290. {
  291. void __iomem *disc_base;
  292. disc_base = devm_ioremap_resource(priv->dev, disc_res);
  293. if (IS_ERR(disc_base))
  294. return PTR_ERR(disc_base);
  295. memcpy_fromio(disc_tbl, disc_base, sizeof(*disc_tbl));
  296. devm_iounmap(priv->dev, disc_base);
  297. if (priv->mask & BIT(disc_tbl->id))
  298. return dev_err_probe(priv->dev, -EINVAL, "Duplicate feature: %s\n",
  299. pmt_feature_names[disc_tbl->id]);
  300. /*
  301. * Some devices may expose non-functioning entries that are
  302. * reserved for future use. They have zero size. Do not fail
  303. * probe for these. Just ignore them.
  304. */
  305. if (disc_tbl->size == 0 || disc_tbl->access_type == PMT_ACCESS_TYPE_RSVD)
  306. return SKIP_FEATURE;
  307. if (disc_tbl->version > MAX_FEATURE_VERSION)
  308. return SKIP_FEATURE;
  309. if (!pmt_feature_id_is_valid(disc_tbl->id))
  310. return SKIP_FEATURE;
  311. priv->mask |= BIT(disc_tbl->id);
  312. return 0;
  313. }
  314. static int
  315. pmt_feature_get_feature_table(struct pmt_features_priv *priv,
  316. struct feature *feature,
  317. struct feature_discovery_table *disc_tbl,
  318. struct resource *disc_res)
  319. {
  320. struct feature_table *feat_tbl = &feature->table;
  321. struct feature_header *header;
  322. struct resource res = {};
  323. resource_size_t res_size;
  324. void __iomem *feat_base, *feat_offset;
  325. void *tbl_offset;
  326. size_t size;
  327. u32 *guids;
  328. u8 tbir;
  329. tbir = FIELD_GET(DT_TBIR, disc_tbl->offset);
  330. switch (disc_tbl->access_type) {
  331. case ACCESS_LOCAL:
  332. if (tbir)
  333. return dev_err_probe(priv->dev, -EINVAL,
  334. "Unsupported BAR index %u for access type %u\n",
  335. tbir, disc_tbl->access_type);
  336. /*
  337. * For access_type LOCAL, the base address is as follows:
  338. * base address = end of discovery region + base offset + 1
  339. */
  340. res = DEFINE_RES_MEM(disc_res->end + disc_tbl->offset + 1,
  341. disc_tbl->size * sizeof(u32));
  342. break;
  343. default:
  344. return dev_err_probe(priv->dev, -EINVAL, "Unrecognized access_type %u\n",
  345. disc_tbl->access_type);
  346. }
  347. feature->id = disc_tbl->id;
  348. /* Get the feature table */
  349. feat_base = devm_ioremap_resource(priv->dev, &res);
  350. if (IS_ERR(feat_base))
  351. return PTR_ERR(feat_base);
  352. feat_offset = feat_base;
  353. tbl_offset = feat_tbl;
  354. /* Get the header */
  355. header = &feat_tbl->header;
  356. memcpy_fromio(header, feat_offset, sizeof(*header));
  357. /* Validate fields fit within mapped resource */
  358. size = sizeof(*header) + FEAT_ATTR_SIZE(header->attr_size) +
  359. PMT_GUID_SIZE(header->num_guids);
  360. res_size = resource_size(&res);
  361. if (WARN(size > res_size, "Bad table size %zu > %pa", size, &res_size))
  362. return -EINVAL;
  363. /* Get the feature attributes, including capability fields */
  364. tbl_offset += sizeof(*header);
  365. feat_offset += sizeof(*header);
  366. memcpy_fromio(tbl_offset, feat_offset, FEAT_ATTR_SIZE(header->attr_size));
  367. /* Finally, get the guids */
  368. guids = devm_kmalloc(priv->dev, PMT_GUID_SIZE(header->num_guids), GFP_KERNEL);
  369. if (!guids)
  370. return -ENOMEM;
  371. feat_offset += FEAT_ATTR_SIZE(header->attr_size);
  372. memcpy_fromio(guids, feat_offset, PMT_GUID_SIZE(header->num_guids));
  373. feat_tbl->guids = guids;
  374. devm_iounmap(priv->dev, feat_base);
  375. return 0;
  376. }
  377. static void pmt_features_add_feat(struct feature *feature)
  378. {
  379. guard(mutex)(&feature_list_lock);
  380. list_add(&feature->list, &pmt_feature_list);
  381. }
  382. static void pmt_features_remove_feat(struct feature *feature)
  383. {
  384. guard(mutex)(&feature_list_lock);
  385. list_del(&feature->list);
  386. }
  387. /* Get the discovery table and use it to get the feature table */
  388. static int pmt_features_discovery(struct pmt_features_priv *priv,
  389. struct feature *feature,
  390. struct intel_vsec_device *ivdev,
  391. int idx)
  392. {
  393. struct feature_discovery_table disc_tbl = {}; /* Avoid false warning */
  394. struct resource *disc_res = &ivdev->resource[idx];
  395. const struct kobj_type *ktype;
  396. int ret;
  397. ret = pmt_feature_get_disc_table(priv, disc_res, &disc_tbl);
  398. if (ret)
  399. return ret;
  400. ret = pmt_feature_get_feature_table(priv, feature, &disc_tbl, disc_res);
  401. if (ret)
  402. return ret;
  403. switch (feature_layout[feature->id]) {
  404. case LAYOUT_RMID:
  405. ktype = &pmt_feature_rmid_ktype;
  406. feature->attr_group = &pmt_feature_rmid_group;
  407. break;
  408. case LAYOUT_WATCHER:
  409. ktype = &pmt_feature_watcher_ktype;
  410. feature->attr_group = &pmt_feature_watcher_group;
  411. break;
  412. case LAYOUT_COMMAND:
  413. ktype = &pmt_feature_command_ktype;
  414. feature->attr_group = &pmt_feature_command_group;
  415. break;
  416. case LAYOUT_CAPS_ONLY:
  417. ktype = &pmt_feature_guids_ktype;
  418. feature->attr_group = &pmt_feature_guids_group;
  419. break;
  420. default:
  421. return -EINVAL;
  422. }
  423. ret = kobject_init_and_add(&feature->kobj, ktype, &priv->dev->kobj,
  424. "%s", pmt_feature_names[feature->id]);
  425. if (ret) {
  426. kobject_put(&feature->kobj);
  427. return ret;
  428. }
  429. kobject_uevent(&feature->kobj, KOBJ_ADD);
  430. pmt_features_add_feat(feature);
  431. return 0;
  432. }
  433. static void pmt_features_remove(struct auxiliary_device *auxdev)
  434. {
  435. struct pmt_features_priv *priv = auxiliary_get_drvdata(auxdev);
  436. int i;
  437. for (i = 0; i < priv->count; i++) {
  438. struct feature *feature = &priv->feature[i];
  439. pmt_features_remove_feat(feature);
  440. sysfs_remove_group(&feature->kobj, feature->attr_group);
  441. kobject_put(&feature->kobj);
  442. }
  443. device_unregister(priv->dev);
  444. }
  445. static int pmt_features_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id)
  446. {
  447. struct intel_vsec_device *ivdev = auxdev_to_ivdev(auxdev);
  448. struct pmt_features_priv *priv;
  449. size_t size;
  450. int ret, i;
  451. size = struct_size(priv, feature, ivdev->num_resources);
  452. priv = devm_kzalloc(&auxdev->dev, size, GFP_KERNEL);
  453. if (!priv)
  454. return -ENOMEM;
  455. priv->parent = &ivdev->pcidev->dev;
  456. auxiliary_set_drvdata(auxdev, priv);
  457. priv->dev = device_create(&intel_pmt_class, &auxdev->dev, MKDEV(0, 0), priv,
  458. "%s-%s", "features", dev_name(priv->parent));
  459. if (IS_ERR(priv->dev))
  460. return dev_err_probe(&auxdev->dev, PTR_ERR(priv->dev),
  461. "Could not create %s-%s device node\n",
  462. "features", dev_name(priv->parent));
  463. /* Initialize each feature */
  464. for (i = 0; i < ivdev->num_resources; i++) {
  465. struct feature *feature = &priv->feature[priv->count];
  466. ret = pmt_features_discovery(priv, feature, ivdev, i);
  467. if (ret == SKIP_FEATURE)
  468. continue;
  469. if (ret != 0)
  470. goto abort_probe;
  471. feature->priv = priv;
  472. priv->count++;
  473. }
  474. return 0;
  475. abort_probe:
  476. /*
  477. * Only fully initialized features are tracked in priv->count, which is
  478. * incremented only after a feature is completely set up (i.e., after
  479. * discovery and sysfs registration). If feature initialization fails,
  480. * the failing feature's state is local and does not require rollback.
  481. *
  482. * Therefore, on error, we can safely call the driver's remove() routine
  483. * pmt_features_remove() to clean up only those features that were
  484. * fully initialized and counted. All other resources are device-managed
  485. * and will be cleaned up automatically during device_unregister().
  486. */
  487. pmt_features_remove(auxdev);
  488. return ret;
  489. }
  490. static void pmt_get_features(struct intel_pmt_entry *entry, struct feature *f)
  491. {
  492. int num_guids = f->table.header.num_guids;
  493. int i;
  494. for (i = 0; i < num_guids; i++) {
  495. if (f->table.guids[i] != entry->guid)
  496. continue;
  497. entry->feature_flags |= BIT(f->id);
  498. if (feature_layout[f->id] == LAYOUT_RMID)
  499. entry->num_rmids = f->table.rmid.num_rmids;
  500. else
  501. entry->num_rmids = 0; /* entry is kzalloc but set anyway */
  502. }
  503. }
  504. void intel_pmt_get_features(struct intel_pmt_entry *entry)
  505. {
  506. struct feature *feature;
  507. mutex_lock(&feature_list_lock);
  508. list_for_each_entry(feature, &pmt_feature_list, list) {
  509. if (feature->priv->parent != &entry->ep->pcidev->dev)
  510. continue;
  511. pmt_get_features(entry, feature);
  512. }
  513. mutex_unlock(&feature_list_lock);
  514. }
  515. EXPORT_SYMBOL_NS_GPL(intel_pmt_get_features, "INTEL_PMT");
  516. static const struct auxiliary_device_id pmt_features_id_table[] = {
  517. { .name = "intel_vsec.discovery" },
  518. {}
  519. };
  520. MODULE_DEVICE_TABLE(auxiliary, pmt_features_id_table);
  521. static struct auxiliary_driver pmt_features_aux_driver = {
  522. .id_table = pmt_features_id_table,
  523. .remove = pmt_features_remove,
  524. .probe = pmt_features_probe,
  525. };
  526. module_auxiliary_driver(pmt_features_aux_driver);
  527. MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
  528. MODULE_DESCRIPTION("Intel PMT Discovery driver");
  529. MODULE_LICENSE("GPL");
  530. MODULE_IMPORT_NS("INTEL_PMT");