File Index
Files and directories
Sign in
FILE

vsec.c

File preview with syntax highlighting.

linux-6.19.14/drivers/platform/x86/intel/vsec.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Intel Vendor Specific Extended Capabilities auxiliary bus driver
  4 *
  5 * Copyright (c) 2021, Intel Corporation.
  6 * All Rights Reserved.
  7 *
  8 * Author: David E. Box <david.e.box@linux.intel.com>
  9 *
 10 * This driver discovers and creates auxiliary devices for Intel defined PCIe
 11 * "Vendor Specific" and "Designated Vendor Specific" Extended Capabilities,
 12 * VSEC and DVSEC respectively. The driver supports features on specific PCIe
 13 * endpoints that exist primarily to expose them.
 14 */
 15
 16#include <linux/auxiliary_bus.h>
 17#include <linux/bits.h>
 18#include <linux/bitops.h>
 19#include <linux/bug.h>
 20#include <linux/cleanup.h>
 21#include <linux/delay.h>
 22#include <linux/idr.h>
 23#include <linux/log2.h>
 24#include <linux/intel_vsec.h>
 25#include <linux/kernel.h>
 26#include <linux/module.h>
 27#include <linux/pci.h>
 28#include <linux/types.h>
 29
 30#define PMT_XA_START			0
 31#define PMT_XA_MAX			INT_MAX
 32#define PMT_XA_LIMIT			XA_LIMIT(PMT_XA_START, PMT_XA_MAX)
 33
 34static DEFINE_IDA(intel_vsec_ida);
 35static DEFINE_IDA(intel_vsec_sdsi_ida);
 36static DEFINE_XARRAY_ALLOC(auxdev_array);
 37
 38enum vsec_device_state {
 39	STATE_NOT_FOUND,
 40	STATE_REGISTERED,
 41	STATE_SKIP,
 42};
 43
 44struct vsec_priv {
 45	struct intel_vsec_platform_info *info;
 46	struct device *suppliers[VSEC_FEATURE_COUNT];
 47	struct oobmsm_plat_info plat_info;
 48	enum vsec_device_state state[VSEC_FEATURE_COUNT];
 49	unsigned long found_caps;
 50};
 51
 52static const char *intel_vsec_name(enum intel_vsec_id id)
 53{
 54	switch (id) {
 55	case VSEC_ID_TELEMETRY:
 56		return "telemetry";
 57
 58	case VSEC_ID_WATCHER:
 59		return "watcher";
 60
 61	case VSEC_ID_CRASHLOG:
 62		return "crashlog";
 63
 64	case VSEC_ID_SDSI:
 65		return "sdsi";
 66
 67	case VSEC_ID_TPMI:
 68		return "tpmi";
 69
 70	case VSEC_ID_DISCOVERY:
 71		return "discovery";
 72
 73	default:
 74		return NULL;
 75	}
 76}
 77
 78static bool intel_vsec_supported(u16 id, unsigned long caps)
 79{
 80	switch (id) {
 81	case VSEC_ID_TELEMETRY:
 82		return !!(caps & VSEC_CAP_TELEMETRY);
 83	case VSEC_ID_WATCHER:
 84		return !!(caps & VSEC_CAP_WATCHER);
 85	case VSEC_ID_CRASHLOG:
 86		return !!(caps & VSEC_CAP_CRASHLOG);
 87	case VSEC_ID_SDSI:
 88		return !!(caps & VSEC_CAP_SDSI);
 89	case VSEC_ID_TPMI:
 90		return !!(caps & VSEC_CAP_TPMI);
 91	case VSEC_ID_DISCOVERY:
 92		return !!(caps & VSEC_CAP_DISCOVERY);
 93	default:
 94		return false;
 95	}
 96}
 97
 98static void intel_vsec_remove_aux(void *data)
 99{
100	auxiliary_device_delete(data);
101	auxiliary_device_uninit(data);
102}
103
104static void intel_vsec_dev_release(struct device *dev)
105{
106	struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(dev);
107
108	xa_erase(&auxdev_array, intel_vsec_dev->id);
109
110	ida_free(intel_vsec_dev->ida, intel_vsec_dev->auxdev.id);
111
112	kfree(intel_vsec_dev->resource);
113	kfree(intel_vsec_dev);
114}
115
116static const struct vsec_feature_dependency *
117get_consumer_dependencies(struct vsec_priv *priv, int cap_id)
118{
119	const struct vsec_feature_dependency *deps = priv->info->deps;
120	int consumer_id = priv->info->num_deps;
121
122	if (!deps)
123		return NULL;
124
125	while (consumer_id--)
126		if (deps[consumer_id].feature == BIT(cap_id))
127			return &deps[consumer_id];
128
129	return NULL;
130}
131
132static bool vsec_driver_present(int cap_id)
133{
134	unsigned long bit = BIT(cap_id);
135
136	switch (bit) {
137	case VSEC_CAP_TELEMETRY:
138		return IS_ENABLED(CONFIG_INTEL_PMT_TELEMETRY);
139	case VSEC_CAP_WATCHER:
140		return IS_ENABLED(CONFIG_INTEL_PMT_WATCHER);
141	case VSEC_CAP_CRASHLOG:
142		return IS_ENABLED(CONFIG_INTEL_PMT_CRASHLOG);
143	case VSEC_CAP_SDSI:
144		return IS_ENABLED(CONFIG_INTEL_SDSI);
145	case VSEC_CAP_TPMI:
146		return IS_ENABLED(CONFIG_INTEL_TPMI);
147	case VSEC_CAP_DISCOVERY:
148		return IS_ENABLED(CONFIG_INTEL_PMT_DISCOVERY);
149	default:
150		return false;
151	}
152}
153
154/*
155 * Although pci_device_id table is available in the pdev, this prototype is
156 * necessary because the code using it can be called by an exported API that
157 * might pass a different pdev.
158 */
159static const struct pci_device_id intel_vsec_pci_ids[];
160
161static int intel_vsec_link_devices(struct pci_dev *pdev, struct device *dev,
162				   int consumer_id)
163{
164	const struct vsec_feature_dependency *deps;
165	enum vsec_device_state *state;
166	struct device **suppliers;
167	struct vsec_priv *priv;
168	int supplier_id;
169
170	if (!consumer_id)
171		return 0;
172
173	if (!pci_match_id(intel_vsec_pci_ids, pdev))
174		return 0;
175
176	priv = pci_get_drvdata(pdev);
177	state = priv->state;
178	suppliers = priv->suppliers;
179
180	priv->suppliers[consumer_id] = dev;
181
182	deps = get_consumer_dependencies(priv, consumer_id);
183	if (!deps)
184		return 0;
185
186	for_each_set_bit(supplier_id, &deps->supplier_bitmap, VSEC_FEATURE_COUNT) {
187		struct device_link *link;
188
189		if (state[supplier_id] != STATE_REGISTERED ||
190		    !vsec_driver_present(supplier_id))
191			continue;
192
193		if (!suppliers[supplier_id]) {
194			dev_err(dev, "Bad supplier list\n");
195			return -EINVAL;
196		}
197
198		link = device_link_add(dev, suppliers[supplier_id],
199				       DL_FLAG_AUTOPROBE_CONSUMER);
200		if (!link)
201			return -EINVAL;
202	}
203
204	return 0;
205}
206
207int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent,
208		       struct intel_vsec_device *intel_vsec_dev,
209		       const char *name)
210{
211	struct auxiliary_device *auxdev = &intel_vsec_dev->auxdev;
212	int ret, id;
213
214	if (!parent)
215		return -EINVAL;
216
217	ret = xa_alloc(&auxdev_array, &intel_vsec_dev->id, intel_vsec_dev,
218		       PMT_XA_LIMIT, GFP_KERNEL);
219	if (ret < 0) {
220		kfree(intel_vsec_dev->resource);
221		kfree(intel_vsec_dev);
222		return ret;
223	}
224
225	id = ida_alloc(intel_vsec_dev->ida, GFP_KERNEL);
226	if (id < 0) {
227		xa_erase(&auxdev_array, intel_vsec_dev->id);
228		kfree(intel_vsec_dev->resource);
229		kfree(intel_vsec_dev);
230		return id;
231	}
232
233	auxdev->id = id;
234	auxdev->name = name;
235	auxdev->dev.parent = parent;
236	auxdev->dev.release = intel_vsec_dev_release;
237
238	ret = auxiliary_device_init(auxdev);
239	if (ret < 0) {
240		intel_vsec_dev_release(&auxdev->dev);
241		return ret;
242	}
243
244	/*
245	 * Assign a name now to ensure that the device link doesn't contain
246	 * a null string for the consumer name. This is a problem when a supplier
247	 * supplies more than one consumer and can lead to a duplicate name error
248	 * when the link is created in sysfs.
249	 */
250	ret = dev_set_name(&auxdev->dev, "%s.%s.%d", KBUILD_MODNAME, auxdev->name,
251			   auxdev->id);
252	if (ret)
253		goto cleanup_aux;
254
255	ret = intel_vsec_link_devices(pdev, &auxdev->dev, intel_vsec_dev->cap_id);
256	if (ret)
257		goto cleanup_aux;
258
259	ret = auxiliary_device_add(auxdev);
260	if (ret)
261		goto cleanup_aux;
262
263	return devm_add_action_or_reset(parent, intel_vsec_remove_aux,
264				       auxdev);
265
266cleanup_aux:
267	auxiliary_device_uninit(auxdev);
268	return ret;
269}
270EXPORT_SYMBOL_NS_GPL(intel_vsec_add_aux, "INTEL_VSEC");
271
272static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *header,
273			      struct intel_vsec_platform_info *info,
274			      unsigned long cap_id)
275{
276	struct intel_vsec_device __free(kfree) *intel_vsec_dev = NULL;
277	struct resource __free(kfree) *res = NULL;
278	struct resource *tmp;
279	struct device *parent;
280	unsigned long quirks = info->quirks;
281	u64 base_addr;
282	int i;
283
284	if (info->parent)
285		parent = info->parent;
286	else
287		parent = &pdev->dev;
288
289	if (!intel_vsec_supported(header->id, info->caps))
290		return -EINVAL;
291
292	if (!header->num_entries) {
293		dev_dbg(&pdev->dev, "Invalid 0 entry count for header id %d\n", header->id);
294		return -EINVAL;
295	}
296
297	if (!header->entry_size) {
298		dev_dbg(&pdev->dev, "Invalid 0 entry size for header id %d\n", header->id);
299		return -EINVAL;
300	}
301
302	intel_vsec_dev = kzalloc(sizeof(*intel_vsec_dev), GFP_KERNEL);
303	if (!intel_vsec_dev)
304		return -ENOMEM;
305
306	res = kcalloc(header->num_entries, sizeof(*res), GFP_KERNEL);
307	if (!res)
308		return -ENOMEM;
309
310	if (quirks & VSEC_QUIRK_TABLE_SHIFT)
311		header->offset >>= TABLE_OFFSET_SHIFT;
312
313	if (info->base_addr)
314		base_addr = info->base_addr;
315	else
316		base_addr = pdev->resource[header->tbir].start;
317
318	/*
319	 * The DVSEC/VSEC contains the starting offset and count for a block of
320	 * discovery tables. Create a resource array of these tables to the
321	 * auxiliary device driver.
322	 */
323	for (i = 0, tmp = res; i < header->num_entries; i++, tmp++) {
324		tmp->start = base_addr + header->offset + i * (header->entry_size * sizeof(u32));
325		tmp->end = tmp->start + (header->entry_size * sizeof(u32)) - 1;
326		tmp->flags = IORESOURCE_MEM;
327
328		/* Check resource is not in use */
329		if (!request_mem_region(tmp->start, resource_size(tmp), ""))
330			return -EBUSY;
331
332		release_mem_region(tmp->start, resource_size(tmp));
333	}
334
335	intel_vsec_dev->pcidev = pdev;
336	intel_vsec_dev->resource = no_free_ptr(res);
337	intel_vsec_dev->num_resources = header->num_entries;
338	intel_vsec_dev->quirks = info->quirks;
339	intel_vsec_dev->base_addr = info->base_addr;
340	intel_vsec_dev->priv_data = info->priv_data;
341	intel_vsec_dev->cap_id = cap_id;
342
343	if (header->id == VSEC_ID_SDSI)
344		intel_vsec_dev->ida = &intel_vsec_sdsi_ida;
345	else
346		intel_vsec_dev->ida = &intel_vsec_ida;
347
348	/*
349	 * Pass the ownership of intel_vsec_dev and resource within it to
350	 * intel_vsec_add_aux()
351	 */
352	return intel_vsec_add_aux(pdev, parent, no_free_ptr(intel_vsec_dev),
353				  intel_vsec_name(header->id));
354}
355
356static bool suppliers_ready(struct vsec_priv *priv,
357			    const struct vsec_feature_dependency *consumer_deps,
358			    int cap_id)
359{
360	enum vsec_device_state *state = priv->state;
361	int supplier_id;
362
363	if (WARN_ON_ONCE(consumer_deps->feature != BIT(cap_id)))
364		return false;
365
366	/*
367	 * Verify that all required suppliers have been found. Return false
368	 * immediately if any are still missing.
369	 */
370	for_each_set_bit(supplier_id, &consumer_deps->supplier_bitmap, VSEC_FEATURE_COUNT) {
371		if (state[supplier_id] == STATE_SKIP)
372			continue;
373
374		if (state[supplier_id] == STATE_NOT_FOUND)
375			return false;
376	}
377
378	/*
379	 * All suppliers have been found and the consumer is ready to be
380	 * registered.
381	 */
382	return true;
383}
384
385static int get_cap_id(u32 header_id, unsigned long *cap_id)
386{
387	switch (header_id) {
388	case VSEC_ID_TELEMETRY:
389		*cap_id = ilog2(VSEC_CAP_TELEMETRY);
390		break;
391	case VSEC_ID_WATCHER:
392		*cap_id = ilog2(VSEC_CAP_WATCHER);
393		break;
394	case VSEC_ID_CRASHLOG:
395		*cap_id = ilog2(VSEC_CAP_CRASHLOG);
396		break;
397	case VSEC_ID_SDSI:
398		*cap_id = ilog2(VSEC_CAP_SDSI);
399		break;
400	case VSEC_ID_TPMI:
401		*cap_id = ilog2(VSEC_CAP_TPMI);
402		break;
403	case VSEC_ID_DISCOVERY:
404		*cap_id = ilog2(VSEC_CAP_DISCOVERY);
405		break;
406	default:
407		return -EINVAL;
408	}
409
410	return 0;
411}
412
413static int intel_vsec_register_device(struct pci_dev *pdev,
414				      struct intel_vsec_header *header,
415				      struct intel_vsec_platform_info *info)
416{
417	const struct vsec_feature_dependency *consumer_deps;
418	struct vsec_priv *priv;
419	unsigned long cap_id;
420	int ret;
421
422	ret = get_cap_id(header->id, &cap_id);
423	if (ret)
424		return ret;
425
426	/*
427	 * Only track dependencies for devices probed by the VSEC driver.
428	 * For others using the exported APIs, add the device directly.
429	 */
430	if (!pci_match_id(intel_vsec_pci_ids, pdev))
431		return intel_vsec_add_dev(pdev, header, info, cap_id);
432
433	priv = pci_get_drvdata(pdev);
434	if (priv->state[cap_id] == STATE_REGISTERED ||
435	    priv->state[cap_id] == STATE_SKIP)
436		return -EEXIST;
437
438	priv->found_caps |= BIT(cap_id);
439
440	if (!vsec_driver_present(cap_id)) {
441		priv->state[cap_id] = STATE_SKIP;
442		return -ENODEV;
443	}
444
445	consumer_deps = get_consumer_dependencies(priv, cap_id);
446	if (!consumer_deps || suppliers_ready(priv, consumer_deps, cap_id)) {
447		ret = intel_vsec_add_dev(pdev, header, info, cap_id);
448		if (ret)
449			priv->state[cap_id] = STATE_SKIP;
450		else
451			priv->state[cap_id] = STATE_REGISTERED;
452
453		return ret;
454	}
455
456	return -EAGAIN;
457}
458
459static bool intel_vsec_walk_header(struct pci_dev *pdev,
460				   struct intel_vsec_platform_info *info)
461{
462	struct intel_vsec_header **header = info->headers;
463	bool have_devices = false;
464	int ret;
465
466	for ( ; *header; header++) {
467		ret = intel_vsec_register_device(pdev, *header, info);
468		if (!ret)
469			have_devices = true;
470	}
471
472	return have_devices;
473}
474
475static bool intel_vsec_walk_dvsec(struct pci_dev *pdev,
476				  struct intel_vsec_platform_info *info)
477{
478	bool have_devices = false;
479	int pos = 0;
480
481	do {
482		struct intel_vsec_header header;
483		u32 table, hdr;
484		u16 vid;
485		int ret;
486
487		pos = pci_find_next_ext_capability(pdev, pos, PCI_EXT_CAP_ID_DVSEC);
488		if (!pos)
489			break;
490
491		pci_read_config_dword(pdev, pos + PCI_DVSEC_HEADER1, &hdr);
492		vid = PCI_DVSEC_HEADER1_VID(hdr);
493		if (vid != PCI_VENDOR_ID_INTEL)
494			continue;
495
496		/* Support only revision 1 */
497		header.rev = PCI_DVSEC_HEADER1_REV(hdr);
498		if (header.rev != 1) {
499			dev_info(&pdev->dev, "Unsupported DVSEC revision %d\n", header.rev);
500			continue;
501		}
502
503		header.length = PCI_DVSEC_HEADER1_LEN(hdr);
504
505		pci_read_config_byte(pdev, pos + INTEL_DVSEC_ENTRIES, &header.num_entries);
506		pci_read_config_byte(pdev, pos + INTEL_DVSEC_SIZE, &header.entry_size);
507		pci_read_config_dword(pdev, pos + INTEL_DVSEC_TABLE, &table);
508
509		header.tbir = INTEL_DVSEC_TABLE_BAR(table);
510		header.offset = INTEL_DVSEC_TABLE_OFFSET(table);
511
512		pci_read_config_dword(pdev, pos + PCI_DVSEC_HEADER2, &hdr);
513		header.id = PCI_DVSEC_HEADER2_ID(hdr);
514
515		ret = intel_vsec_register_device(pdev, &header, info);
516		if (ret)
517			continue;
518
519		have_devices = true;
520	} while (true);
521
522	return have_devices;
523}
524
525static bool intel_vsec_walk_vsec(struct pci_dev *pdev,
526				 struct intel_vsec_platform_info *info)
527{
528	bool have_devices = false;
529	int pos = 0;
530
531	do {
532		struct intel_vsec_header header;
533		u32 table, hdr;
534		int ret;
535
536		pos = pci_find_next_ext_capability(pdev, pos, PCI_EXT_CAP_ID_VNDR);
537		if (!pos)
538			break;
539
540		pci_read_config_dword(pdev, pos + PCI_VNDR_HEADER, &hdr);
541
542		/* Support only revision 1 */
543		header.rev = PCI_VNDR_HEADER_REV(hdr);
544		if (header.rev != 1) {
545			dev_info(&pdev->dev, "Unsupported VSEC revision %d\n", header.rev);
546			continue;
547		}
548
549		header.id = PCI_VNDR_HEADER_ID(hdr);
550		header.length = PCI_VNDR_HEADER_LEN(hdr);
551
552		/* entry, size, and table offset are the same as DVSEC */
553		pci_read_config_byte(pdev, pos + INTEL_DVSEC_ENTRIES, &header.num_entries);
554		pci_read_config_byte(pdev, pos + INTEL_DVSEC_SIZE, &header.entry_size);
555		pci_read_config_dword(pdev, pos + INTEL_DVSEC_TABLE, &table);
556
557		header.tbir = INTEL_DVSEC_TABLE_BAR(table);
558		header.offset = INTEL_DVSEC_TABLE_OFFSET(table);
559
560		ret = intel_vsec_register_device(pdev, &header, info);
561		if (ret)
562			continue;
563
564		have_devices = true;
565	} while (true);
566
567	return have_devices;
568}
569
570int intel_vsec_register(struct pci_dev *pdev,
571			 struct intel_vsec_platform_info *info)
572{
573	if (!pdev || !info || !info->headers)
574		return -EINVAL;
575
576	if (!intel_vsec_walk_header(pdev, info))
577		return -ENODEV;
578	else
579		return 0;
580}
581EXPORT_SYMBOL_NS_GPL(intel_vsec_register, "INTEL_VSEC");
582
583static bool intel_vsec_get_features(struct pci_dev *pdev,
584				    struct intel_vsec_platform_info *info)
585{
586	bool found = false;
587
588	/*
589	 * Both DVSEC and VSEC capabilities can exist on the same device,
590	 * so both intel_vsec_walk_dvsec() and intel_vsec_walk_vsec() must be
591	 * called independently. Additionally, intel_vsec_walk_header() is
592	 * needed for devices that do not have VSEC/DVSEC but provide the
593	 * information via device_data.
594	 */
595	if (intel_vsec_walk_dvsec(pdev, info))
596		found = true;
597
598	if (intel_vsec_walk_vsec(pdev, info))
599		found = true;
600
601	if (info && (info->quirks & VSEC_QUIRK_NO_DVSEC) &&
602	    intel_vsec_walk_header(pdev, info))
603		found = true;
604
605	return found;
606}
607
608static void intel_vsec_skip_missing_dependencies(struct pci_dev *pdev)
609{
610	struct vsec_priv *priv = pci_get_drvdata(pdev);
611	const struct vsec_feature_dependency *deps = priv->info->deps;
612	int consumer_id = priv->info->num_deps;
613
614	while (consumer_id--) {
615		int supplier_id;
616
617		deps = &priv->info->deps[consumer_id];
618
619		for_each_set_bit(supplier_id, &deps->supplier_bitmap, VSEC_FEATURE_COUNT) {
620			if (!(BIT(supplier_id) & priv->found_caps))
621				priv->state[supplier_id] = STATE_SKIP;
622		}
623	}
624}
625
626static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
627{
628	struct intel_vsec_platform_info *info;
629	struct vsec_priv *priv;
630	int num_caps, ret;
631	int run_once = 0;
632	bool found_any = false;
633
634	ret = pcim_enable_device(pdev);
635	if (ret)
636		return ret;
637
638	pci_save_state(pdev);
639	info = (struct intel_vsec_platform_info *)id->driver_data;
640	if (!info)
641		return -EINVAL;
642
643	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
644	if (!priv)
645		return -ENOMEM;
646
647	priv->info = info;
648	pci_set_drvdata(pdev, priv);
649
650	num_caps = hweight_long(info->caps);
651	while (num_caps--) {
652		found_any |= intel_vsec_get_features(pdev, info);
653
654		if (priv->found_caps == info->caps)
655			break;
656
657		if (!run_once) {
658			intel_vsec_skip_missing_dependencies(pdev);
659			run_once = 1;
660		}
661	}
662
663	if (!found_any)
664		return -ENODEV;
665
666	return 0;
667}
668
669int intel_vsec_set_mapping(struct oobmsm_plat_info *plat_info,
670			   struct intel_vsec_device *vsec_dev)
671{
672	struct vsec_priv *priv;
673
674	priv = pci_get_drvdata(vsec_dev->pcidev);
675	if (!priv)
676		return -EINVAL;
677
678	priv->plat_info = *plat_info;
679
680	return 0;
681}
682EXPORT_SYMBOL_NS_GPL(intel_vsec_set_mapping, "INTEL_VSEC");
683
684struct oobmsm_plat_info *intel_vsec_get_mapping(struct pci_dev *pdev)
685{
686	struct vsec_priv *priv;
687
688	if (!pci_match_id(intel_vsec_pci_ids, pdev))
689		return ERR_PTR(-EINVAL);
690
691	priv = pci_get_drvdata(pdev);
692	if (!priv)
693		return ERR_PTR(-EINVAL);
694
695	return &priv->plat_info;
696}
697EXPORT_SYMBOL_NS_GPL(intel_vsec_get_mapping, "INTEL_VSEC");
698
699/* DG1 info */
700static struct intel_vsec_header dg1_header = {
701	.length = 0x10,
702	.id = 2,
703	.num_entries = 1,
704	.entry_size = 3,
705	.tbir = 0,
706	.offset = 0x466000,
707};
708
709static struct intel_vsec_header *dg1_headers[] = {
710	&dg1_header,
711	NULL
712};
713
714static const struct intel_vsec_platform_info dg1_info = {
715	.caps = VSEC_CAP_TELEMETRY,
716	.headers = dg1_headers,
717	.quirks = VSEC_QUIRK_NO_DVSEC | VSEC_QUIRK_EARLY_HW,
718};
719
720/* MTL info */
721static const struct intel_vsec_platform_info mtl_info = {
722	.caps = VSEC_CAP_TELEMETRY,
723};
724
725static const struct vsec_feature_dependency oobmsm_deps[] = {
726	{
727		.feature = VSEC_CAP_TELEMETRY,
728		.supplier_bitmap = VSEC_CAP_DISCOVERY | VSEC_CAP_TPMI,
729	},
730};
731
732/* OOBMSM info */
733static const struct intel_vsec_platform_info oobmsm_info = {
734	.caps = VSEC_CAP_TELEMETRY | VSEC_CAP_SDSI | VSEC_CAP_TPMI |
735		VSEC_CAP_DISCOVERY,
736	.deps = oobmsm_deps,
737	.num_deps = ARRAY_SIZE(oobmsm_deps),
738};
739
740/* DMR OOBMSM info */
741static const struct intel_vsec_platform_info dmr_oobmsm_info = {
742	.caps = VSEC_CAP_TELEMETRY | VSEC_CAP_TPMI | VSEC_CAP_DISCOVERY,
743	.deps = oobmsm_deps,
744	.num_deps = ARRAY_SIZE(oobmsm_deps),
745};
746
747/* TGL info */
748static const struct intel_vsec_platform_info tgl_info = {
749	.caps = VSEC_CAP_TELEMETRY,
750	.quirks = VSEC_QUIRK_TABLE_SHIFT | VSEC_QUIRK_EARLY_HW,
751};
752
753/* LNL info */
754static const struct intel_vsec_platform_info lnl_info = {
755	.caps = VSEC_CAP_TELEMETRY | VSEC_CAP_WATCHER,
756};
757
758#define PCI_DEVICE_ID_INTEL_VSEC_ADL		0x467d
759#define PCI_DEVICE_ID_INTEL_VSEC_DG1		0x490e
760#define PCI_DEVICE_ID_INTEL_VSEC_MTL_M		0x7d0d
761#define PCI_DEVICE_ID_INTEL_VSEC_MTL_S		0xad0d
762#define PCI_DEVICE_ID_INTEL_VSEC_OOBMSM		0x09a7
763#define PCI_DEVICE_ID_INTEL_VSEC_OOBMSM_DMR	0x09a1
764#define PCI_DEVICE_ID_INTEL_VSEC_RPL		0xa77d
765#define PCI_DEVICE_ID_INTEL_VSEC_TGL		0x9a0d
766#define PCI_DEVICE_ID_INTEL_VSEC_LNL_M		0x647d
767#define PCI_DEVICE_ID_INTEL_VSEC_PTL		0xb07d
768#define PCI_DEVICE_ID_INTEL_VSEC_WCL		0xfd7d
769#define PCI_DEVICE_ID_INTEL_VSEC_NVL		0xd70d
770static const struct pci_device_id intel_vsec_pci_ids[] = {
771	{ PCI_DEVICE_DATA(INTEL, VSEC_ADL, &tgl_info) },
772	{ PCI_DEVICE_DATA(INTEL, VSEC_DG1, &dg1_info) },
773	{ PCI_DEVICE_DATA(INTEL, VSEC_MTL_M, &mtl_info) },
774	{ PCI_DEVICE_DATA(INTEL, VSEC_MTL_S, &mtl_info) },
775	{ PCI_DEVICE_DATA(INTEL, VSEC_OOBMSM, &oobmsm_info) },
776	{ PCI_DEVICE_DATA(INTEL, VSEC_OOBMSM_DMR, &dmr_oobmsm_info) },
777	{ PCI_DEVICE_DATA(INTEL, VSEC_RPL, &tgl_info) },
778	{ PCI_DEVICE_DATA(INTEL, VSEC_TGL, &tgl_info) },
779	{ PCI_DEVICE_DATA(INTEL, VSEC_LNL_M, &lnl_info) },
780	{ PCI_DEVICE_DATA(INTEL, VSEC_PTL, &mtl_info) },
781	{ PCI_DEVICE_DATA(INTEL, VSEC_WCL, &mtl_info) },
782	{ PCI_DEVICE_DATA(INTEL, VSEC_NVL, &mtl_info) },
783	{ }
784};
785MODULE_DEVICE_TABLE(pci, intel_vsec_pci_ids);
786
787static pci_ers_result_t intel_vsec_pci_error_detected(struct pci_dev *pdev,
788						      pci_channel_state_t state)
789{
790	pci_ers_result_t status = PCI_ERS_RESULT_NEED_RESET;
791
792	dev_info(&pdev->dev, "PCI error detected, state %d", state);
793
794	if (state == pci_channel_io_perm_failure)
795		status = PCI_ERS_RESULT_DISCONNECT;
796	else
797		pci_disable_device(pdev);
798
799	return status;
800}
801
802static pci_ers_result_t intel_vsec_pci_slot_reset(struct pci_dev *pdev)
803{
804	struct intel_vsec_device *intel_vsec_dev;
805	pci_ers_result_t status = PCI_ERS_RESULT_DISCONNECT;
806	const struct pci_device_id *pci_dev_id;
807	unsigned long index;
808
809	dev_info(&pdev->dev, "Resetting PCI slot\n");
810
811	msleep(2000);
812	if (pci_enable_device(pdev)) {
813		dev_info(&pdev->dev,
814			 "Failed to re-enable PCI device after reset.\n");
815		goto out;
816	}
817
818	status = PCI_ERS_RESULT_RECOVERED;
819
820	xa_for_each(&auxdev_array, index, intel_vsec_dev) {
821		/* check if pdev doesn't match */
822		if (pdev != intel_vsec_dev->pcidev)
823			continue;
824		devm_release_action(&pdev->dev, intel_vsec_remove_aux,
825				    &intel_vsec_dev->auxdev);
826	}
827	pci_disable_device(pdev);
828	pci_restore_state(pdev);
829	pci_dev_id = pci_match_id(intel_vsec_pci_ids, pdev);
830	intel_vsec_pci_probe(pdev, pci_dev_id);
831
832out:
833	return status;
834}
835
836static void intel_vsec_pci_resume(struct pci_dev *pdev)
837{
838	dev_info(&pdev->dev, "Done resuming PCI device\n");
839}
840
841static const struct pci_error_handlers intel_vsec_pci_err_handlers = {
842	.error_detected = intel_vsec_pci_error_detected,
843	.slot_reset = intel_vsec_pci_slot_reset,
844	.resume = intel_vsec_pci_resume,
845};
846
847static struct pci_driver intel_vsec_pci_driver = {
848	.name = "intel_vsec",
849	.id_table = intel_vsec_pci_ids,
850	.probe = intel_vsec_pci_probe,
851	.err_handler = &intel_vsec_pci_err_handlers,
852};
853module_pci_driver(intel_vsec_pci_driver);
854
855MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
856MODULE_DESCRIPTION("Intel Extended Capabilities auxiliary bus driver");
857MODULE_LICENSE("GPL v2");
~/ Read-only file preview.