File Index
Files and directories
Sign in
FILE

tsm.c

File preview with syntax highlighting.

linux-6.19.14/drivers/pci/tsm.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Interface with platform TEE Security Manager (TSM) objects as defined by
  4 * PCIe r7.0 section 11 TEE Device Interface Security Protocol (TDISP)
  5 *
  6 * Copyright(c) 2024-2025 Intel Corporation. All rights reserved.
  7 */
  8
  9#define dev_fmt(fmt) "PCI/TSM: " fmt
 10
 11#include <linux/bitfield.h>
 12#include <linux/pci.h>
 13#include <linux/pci-doe.h>
 14#include <linux/pci-tsm.h>
 15#include <linux/sysfs.h>
 16#include <linux/tsm.h>
 17#include <linux/xarray.h>
 18#include "pci.h"
 19
 20/*
 21 * Provide a read/write lock against the init / exit of pdev tsm
 22 * capabilities and arrival/departure of a TSM instance
 23 */
 24static DECLARE_RWSEM(pci_tsm_rwsem);
 25
 26/*
 27 * Count of TSMs registered that support physical link operations vs device
 28 * security state management.
 29 */
 30static int pci_tsm_link_count;
 31static int pci_tsm_devsec_count;
 32
 33static const struct pci_tsm_ops *to_pci_tsm_ops(struct pci_tsm *tsm)
 34{
 35	return tsm->tsm_dev->pci_ops;
 36}
 37
 38static inline bool is_dsm(struct pci_dev *pdev)
 39{
 40	return pdev->tsm && pdev->tsm->dsm_dev == pdev;
 41}
 42
 43static inline bool has_tee(struct pci_dev *pdev)
 44{
 45	return pdev->devcap & PCI_EXP_DEVCAP_TEE;
 46}
 47
 48/* 'struct pci_tsm_pf0' wraps 'struct pci_tsm' when ->dsm_dev == ->pdev (self) */
 49static struct pci_tsm_pf0 *to_pci_tsm_pf0(struct pci_tsm *tsm)
 50{
 51	/*
 52	 * All "link" TSM contexts reference the device that hosts the DSM
 53	 * interface for a set of devices. Walk to the DSM device and cast its
 54	 * ->tsm context to a 'struct pci_tsm_pf0 *'.
 55	 */
 56	struct pci_dev *pf0 = tsm->dsm_dev;
 57
 58	if (!is_pci_tsm_pf0(pf0) || !is_dsm(pf0)) {
 59		pci_WARN_ONCE(tsm->pdev, 1, "invalid context object\n");
 60		return NULL;
 61	}
 62
 63	return container_of(pf0->tsm, struct pci_tsm_pf0, base_tsm);
 64}
 65
 66static void tsm_remove(struct pci_tsm *tsm)
 67{
 68	struct pci_dev *pdev;
 69
 70	if (!tsm)
 71		return;
 72
 73	pdev = tsm->pdev;
 74	to_pci_tsm_ops(tsm)->remove(tsm);
 75	pdev->tsm = NULL;
 76}
 77DEFINE_FREE(tsm_remove, struct pci_tsm *, if (_T) tsm_remove(_T))
 78
 79static void pci_tsm_walk_fns(struct pci_dev *pdev,
 80			     int (*cb)(struct pci_dev *pdev, void *data),
 81			     void *data)
 82{
 83	/* Walk subordinate physical functions */
 84	for (int i = 0; i < 8; i++) {
 85		struct pci_dev *pf __free(pci_dev_put) = pci_get_slot(
 86			pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), i));
 87
 88		if (!pf)
 89			continue;
 90
 91		/* on entry function 0 has already run @cb */
 92		if (i > 0)
 93			cb(pf, data);
 94
 95		/* walk virtual functions of each pf */
 96		for (int j = 0; j < pci_num_vf(pf); j++) {
 97			struct pci_dev *vf __free(pci_dev_put) =
 98				pci_get_domain_bus_and_slot(
 99					pci_domain_nr(pf->bus),
100					pci_iov_virtfn_bus(pf, j),
101					pci_iov_virtfn_devfn(pf, j));
102
103			if (!vf)
104				continue;
105
106			cb(vf, data);
107		}
108	}
109
110	/*
111	 * Walk downstream devices, assumes that an upstream DSM is
112	 * limited to downstream physical functions
113	 */
114	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_UPSTREAM && is_dsm(pdev))
115		pci_walk_bus(pdev->subordinate, cb, data);
116}
117
118static void pci_tsm_walk_fns_reverse(struct pci_dev *pdev,
119				     int (*cb)(struct pci_dev *pdev,
120					       void *data),
121				     void *data)
122{
123	/* Reverse walk downstream devices */
124	if (pci_pcie_type(pdev) == PCI_EXP_TYPE_UPSTREAM && is_dsm(pdev))
125		pci_walk_bus_reverse(pdev->subordinate, cb, data);
126
127	/* Reverse walk subordinate physical functions */
128	for (int i = 7; i >= 0; i--) {
129		struct pci_dev *pf __free(pci_dev_put) = pci_get_slot(
130			pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), i));
131
132		if (!pf)
133			continue;
134
135		/* reverse walk virtual functions */
136		for (int j = pci_num_vf(pf) - 1; j >= 0; j--) {
137			struct pci_dev *vf __free(pci_dev_put) =
138				pci_get_domain_bus_and_slot(
139					pci_domain_nr(pf->bus),
140					pci_iov_virtfn_bus(pf, j),
141					pci_iov_virtfn_devfn(pf, j));
142
143			if (!vf)
144				continue;
145			cb(vf, data);
146		}
147
148		/* on exit, caller will run @cb on function 0 */
149		if (i > 0)
150			cb(pf, data);
151	}
152}
153
154static void link_sysfs_disable(struct pci_dev *pdev)
155{
156	sysfs_update_group(&pdev->dev.kobj, &pci_tsm_auth_attr_group);
157	sysfs_update_group(&pdev->dev.kobj, &pci_tsm_attr_group);
158}
159
160static void link_sysfs_enable(struct pci_dev *pdev)
161{
162	bool tee = has_tee(pdev);
163
164	pci_dbg(pdev, "%s Security Manager detected (%s%s%s)\n",
165		pdev->tsm ? "Device" : "Platform TEE",
166		pdev->ide_cap ? "IDE" : "", pdev->ide_cap && tee ? " " : "",
167		tee ? "TEE" : "");
168
169	sysfs_update_group(&pdev->dev.kobj, &pci_tsm_auth_attr_group);
170	sysfs_update_group(&pdev->dev.kobj, &pci_tsm_attr_group);
171}
172
173static int probe_fn(struct pci_dev *pdev, void *dsm)
174{
175	struct pci_dev *dsm_dev = dsm;
176	const struct pci_tsm_ops *ops = to_pci_tsm_ops(dsm_dev->tsm);
177
178	pdev->tsm = ops->probe(dsm_dev->tsm->tsm_dev, pdev);
179	pci_dbg(pdev, "setup TSM context: DSM: %s status: %s\n",
180		pci_name(dsm_dev), pdev->tsm ? "success" : "failed");
181	if (pdev->tsm)
182		link_sysfs_enable(pdev);
183	return 0;
184}
185
186static int pci_tsm_connect(struct pci_dev *pdev, struct tsm_dev *tsm_dev)
187{
188	int rc;
189	struct pci_tsm_pf0 *tsm_pf0;
190	const struct pci_tsm_ops *ops = tsm_dev->pci_ops;
191	struct pci_tsm *pci_tsm __free(tsm_remove) = ops->probe(tsm_dev, pdev);
192
193	/* connect() mutually exclusive with subfunction pci_tsm_init() */
194	lockdep_assert_held_write(&pci_tsm_rwsem);
195
196	if (!pci_tsm)
197		return -ENXIO;
198
199	pdev->tsm = pci_tsm;
200	tsm_pf0 = to_pci_tsm_pf0(pdev->tsm);
201
202	/* mutex_intr assumes connect() is always sysfs/user driven */
203	ACQUIRE(mutex_intr, lock)(&tsm_pf0->lock);
204	if ((rc = ACQUIRE_ERR(mutex_intr, &lock)))
205		return rc;
206
207	rc = ops->connect(pdev);
208	if (rc)
209		return rc;
210
211	pdev->tsm = no_free_ptr(pci_tsm);
212
213	/*
214	 * Now that the DSM is established, probe() all the potential
215	 * dependent functions. Failure to probe a function is not fatal
216	 * to connect(), it just disables subsequent security operations
217	 * for that function.
218	 *
219	 * Note this is done unconditionally, without regard to finding
220	 * PCI_EXP_DEVCAP_TEE on the dependent function, for robustness. The DSM
221	 * is the ultimate arbiter of security state relative to a given
222	 * interface id, and if it says it can manage TDISP state of a function,
223	 * let it.
224	 */
225	if (has_tee(pdev))
226		pci_tsm_walk_fns(pdev, probe_fn, pdev);
227	return 0;
228}
229
230static ssize_t connect_show(struct device *dev, struct device_attribute *attr,
231			    char *buf)
232{
233	struct pci_dev *pdev = to_pci_dev(dev);
234	struct tsm_dev *tsm_dev;
235	int rc;
236
237	ACQUIRE(rwsem_read_intr, lock)(&pci_tsm_rwsem);
238	if ((rc = ACQUIRE_ERR(rwsem_read_intr, &lock)))
239		return rc;
240
241	if (!pdev->tsm)
242		return sysfs_emit(buf, "\n");
243
244	tsm_dev = pdev->tsm->tsm_dev;
245	return sysfs_emit(buf, "%s\n", dev_name(&tsm_dev->dev));
246}
247
248/* Is @tsm_dev managing physical link / session properties... */
249static bool is_link_tsm(struct tsm_dev *tsm_dev)
250{
251	return tsm_dev && tsm_dev->pci_ops && tsm_dev->pci_ops->link_ops.probe;
252}
253
254/* ...or is @tsm_dev managing device security state ? */
255static bool is_devsec_tsm(struct tsm_dev *tsm_dev)
256{
257	return tsm_dev && tsm_dev->pci_ops && tsm_dev->pci_ops->devsec_ops.lock;
258}
259
260static ssize_t connect_store(struct device *dev, struct device_attribute *attr,
261			     const char *buf, size_t len)
262{
263	struct pci_dev *pdev = to_pci_dev(dev);
264	int rc, id;
265
266	rc = sscanf(buf, "tsm%d\n", &id);
267	if (rc != 1)
268		return -EINVAL;
269
270	ACQUIRE(rwsem_write_kill, lock)(&pci_tsm_rwsem);
271	if ((rc = ACQUIRE_ERR(rwsem_write_kill, &lock)))
272		return rc;
273
274	if (pdev->tsm)
275		return -EBUSY;
276
277	struct tsm_dev *tsm_dev __free(put_tsm_dev) = find_tsm_dev(id);
278	if (!is_link_tsm(tsm_dev))
279		return -ENXIO;
280
281	rc = pci_tsm_connect(pdev, tsm_dev);
282	if (rc)
283		return rc;
284	return len;
285}
286static DEVICE_ATTR_RW(connect);
287
288static int remove_fn(struct pci_dev *pdev, void *data)
289{
290	tsm_remove(pdev->tsm);
291	link_sysfs_disable(pdev);
292	return 0;
293}
294
295/*
296 * Note, this helper only returns an error code and takes an argument for
297 * compatibility with the pci_walk_bus() callback prototype. pci_tsm_unbind()
298 * always succeeds.
299 */
300static int __pci_tsm_unbind(struct pci_dev *pdev, void *data)
301{
302	struct pci_tdi *tdi;
303	struct pci_tsm_pf0 *tsm_pf0;
304
305	lockdep_assert_held(&pci_tsm_rwsem);
306
307	if (!pdev->tsm)
308		return 0;
309
310	tsm_pf0 = to_pci_tsm_pf0(pdev->tsm);
311	guard(mutex)(&tsm_pf0->lock);
312
313	tdi = pdev->tsm->tdi;
314	if (!tdi)
315		return 0;
316
317	to_pci_tsm_ops(pdev->tsm)->unbind(tdi);
318	pdev->tsm->tdi = NULL;
319
320	return 0;
321}
322
323void pci_tsm_unbind(struct pci_dev *pdev)
324{
325	guard(rwsem_read)(&pci_tsm_rwsem);
326	__pci_tsm_unbind(pdev, NULL);
327}
328EXPORT_SYMBOL_GPL(pci_tsm_unbind);
329
330/**
331 * pci_tsm_bind() - Bind @pdev as a TDI for @kvm
332 * @pdev: PCI device function to bind
333 * @kvm: Private memory attach context
334 * @tdi_id: Identifier (virtual BDF) for the TDI as referenced by the TSM and DSM
335 *
336 * Returns 0 on success, or a negative error code on failure.
337 *
338 * Context: Caller is responsible for constraining the bind lifetime to the
339 * registered state of the device. For example, pci_tsm_bind() /
340 * pci_tsm_unbind() limited to the VFIO driver bound state of the device.
341 */
342int pci_tsm_bind(struct pci_dev *pdev, struct kvm *kvm, u32 tdi_id)
343{
344	struct pci_tsm_pf0 *tsm_pf0;
345	struct pci_tdi *tdi;
346
347	if (!kvm)
348		return -EINVAL;
349
350	guard(rwsem_read)(&pci_tsm_rwsem);
351
352	if (!pdev->tsm)
353		return -EINVAL;
354
355	if (!is_link_tsm(pdev->tsm->tsm_dev))
356		return -ENXIO;
357
358	tsm_pf0 = to_pci_tsm_pf0(pdev->tsm);
359	guard(mutex)(&tsm_pf0->lock);
360
361	/* Resolve races to bind a TDI */
362	if (pdev->tsm->tdi) {
363		if (pdev->tsm->tdi->kvm != kvm)
364			return -EBUSY;
365		return 0;
366	}
367
368	tdi = to_pci_tsm_ops(pdev->tsm)->bind(pdev, kvm, tdi_id);
369	if (IS_ERR(tdi))
370		return PTR_ERR(tdi);
371
372	pdev->tsm->tdi = tdi;
373
374	return 0;
375}
376EXPORT_SYMBOL_GPL(pci_tsm_bind);
377
378/**
379 * pci_tsm_guest_req() - helper to marshal guest requests to the TSM driver
380 * @pdev: @pdev representing a bound tdi
381 * @scope: caller asserts this passthrough request is limited to TDISP operations
382 * @req_in: Input payload forwarded from the guest
383 * @in_len: Length of @req_in
384 * @req_out: Output payload buffer response to the guest
385 * @out_len: Length of @req_out on input, bytes filled in @req_out on output
386 * @tsm_code: Optional TSM arch specific result code for the guest TSM
387 *
388 * This is a common entry point for requests triggered by userspace KVM-exit
389 * service handlers responding to TDI information or state change requests. The
390 * scope parameter limits requests to TDISP state management, or limited debug.
391 * This path is only suitable for commands and results that are the host kernel
392 * has no use, the host is only facilitating guest to TSM communication.
393 *
394 * Returns 0 on success and -error on failure and positive "residue" on success
395 * but @req_out is filled with less then @out_len, or @req_out is NULL and a
396 * residue number of bytes were not consumed from @req_in.  On success or
397 * failure @tsm_code may be populated with a TSM implementation specific result
398 * code for the guest to consume.
399 *
400 * Context: Caller is responsible for calling this within the pci_tsm_bind()
401 * state of the TDI.
402 */
403ssize_t pci_tsm_guest_req(struct pci_dev *pdev, enum pci_tsm_req_scope scope,
404			  sockptr_t req_in, size_t in_len, sockptr_t req_out,
405			  size_t out_len, u64 *tsm_code)
406{
407	struct pci_tsm_pf0 *tsm_pf0;
408	struct pci_tdi *tdi;
409	int rc;
410
411	/* Forbid requests that are not directly related to TDISP operations */
412	if (scope > PCI_TSM_REQ_STATE_CHANGE)
413		return -EINVAL;
414
415	ACQUIRE(rwsem_read_intr, lock)(&pci_tsm_rwsem);
416	if ((rc = ACQUIRE_ERR(rwsem_read_intr, &lock)))
417		return rc;
418
419	if (!pdev->tsm)
420		return -ENXIO;
421
422	if (!is_link_tsm(pdev->tsm->tsm_dev))
423		return -ENXIO;
424
425	tsm_pf0 = to_pci_tsm_pf0(pdev->tsm);
426	ACQUIRE(mutex_intr, ops_lock)(&tsm_pf0->lock);
427	if ((rc = ACQUIRE_ERR(mutex_intr, &ops_lock)))
428		return rc;
429
430	tdi = pdev->tsm->tdi;
431	if (!tdi)
432		return -ENXIO;
433	return to_pci_tsm_ops(pdev->tsm)->guest_req(tdi, scope, req_in, in_len,
434						    req_out, out_len, tsm_code);
435}
436EXPORT_SYMBOL_GPL(pci_tsm_guest_req);
437
438static void pci_tsm_unbind_all(struct pci_dev *pdev)
439{
440	pci_tsm_walk_fns_reverse(pdev, __pci_tsm_unbind, NULL);
441	__pci_tsm_unbind(pdev, NULL);
442}
443
444static void __pci_tsm_disconnect(struct pci_dev *pdev)
445{
446	struct pci_tsm_pf0 *tsm_pf0 = to_pci_tsm_pf0(pdev->tsm);
447	const struct pci_tsm_ops *ops = to_pci_tsm_ops(pdev->tsm);
448
449	/* disconnect() mutually exclusive with subfunction pci_tsm_init() */
450	lockdep_assert_held_write(&pci_tsm_rwsem);
451
452	pci_tsm_unbind_all(pdev);
453
454	/*
455	 * disconnect() is uninterruptible as it may be called for device
456	 * teardown
457	 */
458	guard(mutex)(&tsm_pf0->lock);
459	pci_tsm_walk_fns_reverse(pdev, remove_fn, NULL);
460	ops->disconnect(pdev);
461}
462
463static void pci_tsm_disconnect(struct pci_dev *pdev)
464{
465	__pci_tsm_disconnect(pdev);
466	tsm_remove(pdev->tsm);
467}
468
469static ssize_t disconnect_store(struct device *dev,
470				struct device_attribute *attr, const char *buf,
471				size_t len)
472{
473	struct pci_dev *pdev = to_pci_dev(dev);
474	struct tsm_dev *tsm_dev;
475	int rc;
476
477	ACQUIRE(rwsem_write_kill, lock)(&pci_tsm_rwsem);
478	if ((rc = ACQUIRE_ERR(rwsem_write_kill, &lock)))
479		return rc;
480
481	if (!pdev->tsm)
482		return -ENXIO;
483
484	tsm_dev = pdev->tsm->tsm_dev;
485	if (!sysfs_streq(buf, dev_name(&tsm_dev->dev)))
486		return -EINVAL;
487
488	pci_tsm_disconnect(pdev);
489	return len;
490}
491static DEVICE_ATTR_WO(disconnect);
492
493static ssize_t bound_show(struct device *dev,
494			  struct device_attribute *attr, char *buf)
495{
496	struct pci_dev *pdev = to_pci_dev(dev);
497	struct pci_tsm_pf0 *tsm_pf0;
498	struct pci_tsm *tsm;
499	int rc;
500
501	ACQUIRE(rwsem_read_intr, lock)(&pci_tsm_rwsem);
502	if ((rc = ACQUIRE_ERR(rwsem_read_intr, &lock)))
503		return rc;
504
505	tsm = pdev->tsm;
506	if (!tsm)
507		return sysfs_emit(buf, "\n");
508	tsm_pf0 = to_pci_tsm_pf0(tsm);
509
510	ACQUIRE(mutex_intr, ops_lock)(&tsm_pf0->lock);
511	if ((rc = ACQUIRE_ERR(mutex_intr, &ops_lock)))
512		return rc;
513
514	if (!tsm->tdi)
515		return sysfs_emit(buf, "\n");
516	return sysfs_emit(buf, "%s\n", dev_name(&tsm->tsm_dev->dev));
517}
518static DEVICE_ATTR_RO(bound);
519
520static ssize_t dsm_show(struct device *dev, struct device_attribute *attr,
521			char *buf)
522{
523	struct pci_dev *pdev = to_pci_dev(dev);
524	struct pci_tsm *tsm;
525	int rc;
526
527	ACQUIRE(rwsem_read_intr, lock)(&pci_tsm_rwsem);
528	if ((rc = ACQUIRE_ERR(rwsem_read_intr, &lock)))
529		return rc;
530
531	tsm = pdev->tsm;
532	if (!tsm)
533		return sysfs_emit(buf, "\n");
534
535	return sysfs_emit(buf, "%s\n", pci_name(tsm->dsm_dev));
536}
537static DEVICE_ATTR_RO(dsm);
538
539/* The 'authenticated' attribute is exclusive to the presence of a 'link' TSM */
540static bool pci_tsm_link_group_visible(struct kobject *kobj)
541{
542	struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
543
544	if (!pci_tsm_link_count)
545		return false;
546
547	if (!pci_is_pcie(pdev))
548		return false;
549
550	if (is_pci_tsm_pf0(pdev))
551		return true;
552
553	/*
554	 * Show 'authenticated' and other attributes for the managed
555	 * sub-functions of a DSM.
556	 */
557	if (pdev->tsm)
558		return true;
559
560	return false;
561}
562DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(pci_tsm_link);
563
564/*
565 * 'link' and 'devsec' TSMs share the same 'tsm/' sysfs group, so the TSM type
566 * specific attributes need individual visibility checks.
567 */
568static umode_t pci_tsm_attr_visible(struct kobject *kobj,
569				    struct attribute *attr, int n)
570{
571	if (pci_tsm_link_group_visible(kobj)) {
572		struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
573
574		if (attr == &dev_attr_bound.attr) {
575			if (is_pci_tsm_pf0(pdev) && has_tee(pdev))
576				return attr->mode;
577			if (pdev->tsm && has_tee(pdev->tsm->dsm_dev))
578				return attr->mode;
579		}
580
581		if (attr == &dev_attr_dsm.attr) {
582			if (is_pci_tsm_pf0(pdev))
583				return attr->mode;
584			if (pdev->tsm && has_tee(pdev->tsm->dsm_dev))
585				return attr->mode;
586		}
587
588		if (attr == &dev_attr_connect.attr ||
589		    attr == &dev_attr_disconnect.attr) {
590			if (is_pci_tsm_pf0(pdev))
591				return attr->mode;
592		}
593	}
594
595	return 0;
596}
597
598static bool pci_tsm_group_visible(struct kobject *kobj)
599{
600	return pci_tsm_link_group_visible(kobj);
601}
602DEFINE_SYSFS_GROUP_VISIBLE(pci_tsm);
603
604static struct attribute *pci_tsm_attrs[] = {
605	&dev_attr_connect.attr,
606	&dev_attr_disconnect.attr,
607	&dev_attr_bound.attr,
608	&dev_attr_dsm.attr,
609	NULL
610};
611
612const struct attribute_group pci_tsm_attr_group = {
613	.name = "tsm",
614	.attrs = pci_tsm_attrs,
615	.is_visible = SYSFS_GROUP_VISIBLE(pci_tsm),
616};
617
618static ssize_t authenticated_show(struct device *dev,
619				  struct device_attribute *attr, char *buf)
620{
621	/*
622	 * When the SPDM session established via TSM the 'authenticated' state
623	 * of the device is identical to the connect state.
624	 */
625	return connect_show(dev, attr, buf);
626}
627static DEVICE_ATTR_RO(authenticated);
628
629static struct attribute *pci_tsm_auth_attrs[] = {
630	&dev_attr_authenticated.attr,
631	NULL
632};
633
634const struct attribute_group pci_tsm_auth_attr_group = {
635	.attrs = pci_tsm_auth_attrs,
636	.is_visible = SYSFS_GROUP_VISIBLE(pci_tsm_link),
637};
638
639/*
640 * Retrieve physical function0 device whether it has TEE capability or not
641 */
642static struct pci_dev *pf0_dev_get(struct pci_dev *pdev)
643{
644	struct pci_dev *pf_dev = pci_physfn(pdev);
645
646	if (PCI_FUNC(pf_dev->devfn) == 0)
647		return pci_dev_get(pf_dev);
648
649	return pci_get_slot(pf_dev->bus,
650			    pf_dev->devfn - PCI_FUNC(pf_dev->devfn));
651}
652
653/*
654 * Find the PCI Device instance that serves as the Device Security Manager (DSM)
655 * for @pdev. Note that no additional reference is held for the resulting device
656 * because that resulting object always has a registered lifetime
657 * greater-than-or-equal to that of the @pdev argument. This is by virtue of
658 * @pdev being a descendant of, or identical to, the returned DSM device.
659 */
660static struct pci_dev *find_dsm_dev(struct pci_dev *pdev)
661{
662	struct device *grandparent;
663	struct pci_dev *uport;
664
665	if (is_pci_tsm_pf0(pdev))
666		return pdev;
667
668	struct pci_dev *pf0 __free(pci_dev_put) = pf0_dev_get(pdev);
669	if (!pf0)
670		return NULL;
671
672	if (is_dsm(pf0))
673		return pf0;
674
675	/*
676	 * For cases where a switch may be hosting TDISP services on behalf of
677	 * downstream devices, check the first upstream port relative to this
678	 * endpoint.
679	 */
680	if (!pdev->dev.parent)
681		return NULL;
682	grandparent = pdev->dev.parent->parent;
683	if (!grandparent)
684		return NULL;
685	if (!dev_is_pci(grandparent))
686		return NULL;
687	uport = to_pci_dev(grandparent);
688	if (!pci_is_pcie(uport) ||
689	    pci_pcie_type(uport) != PCI_EXP_TYPE_UPSTREAM)
690		return NULL;
691
692	if (is_dsm(uport))
693		return uport;
694	return NULL;
695}
696
697/**
698 * pci_tsm_tdi_constructor() - base 'struct pci_tdi' initialization for link TSMs
699 * @pdev: PCI device function representing the TDI
700 * @tdi: context to initialize
701 * @kvm: Private memory attach context
702 * @tdi_id: Identifier (virtual BDF) for the TDI as referenced by the TSM and DSM
703 */
704void pci_tsm_tdi_constructor(struct pci_dev *pdev, struct pci_tdi *tdi,
705			     struct kvm *kvm, u32 tdi_id)
706{
707	tdi->pdev = pdev;
708	tdi->kvm = kvm;
709	tdi->tdi_id = tdi_id;
710}
711EXPORT_SYMBOL_GPL(pci_tsm_tdi_constructor);
712
713/**
714 * pci_tsm_link_constructor() - base 'struct pci_tsm' initialization for link TSMs
715 * @pdev: The PCI device
716 * @tsm: context to initialize
717 * @tsm_dev: Platform TEE Security Manager, initiator of security operations
718 */
719int pci_tsm_link_constructor(struct pci_dev *pdev, struct pci_tsm *tsm,
720			     struct tsm_dev *tsm_dev)
721{
722	if (!is_link_tsm(tsm_dev))
723		return -EINVAL;
724
725	tsm->dsm_dev = find_dsm_dev(pdev);
726	if (!tsm->dsm_dev) {
727		pci_warn(pdev, "failed to find Device Security Manager\n");
728		return -ENXIO;
729	}
730	tsm->pdev = pdev;
731	tsm->tsm_dev = tsm_dev;
732
733	return 0;
734}
735EXPORT_SYMBOL_GPL(pci_tsm_link_constructor);
736
737/**
738 * pci_tsm_pf0_constructor() - common 'struct pci_tsm_pf0' (DSM) initialization
739 * @pdev: Physical Function 0 PCI device (as indicated by is_pci_tsm_pf0())
740 * @tsm: context to initialize
741 * @tsm_dev: Platform TEE Security Manager, initiator of security operations
742 */
743int pci_tsm_pf0_constructor(struct pci_dev *pdev, struct pci_tsm_pf0 *tsm,
744			    struct tsm_dev *tsm_dev)
745{
746	mutex_init(&tsm->lock);
747	tsm->doe_mb = pci_find_doe_mailbox(pdev, PCI_VENDOR_ID_PCI_SIG,
748					   PCI_DOE_FEATURE_CMA);
749	if (!tsm->doe_mb) {
750		pci_warn(pdev, "TSM init failure, no CMA mailbox\n");
751		return -ENODEV;
752	}
753
754	return pci_tsm_link_constructor(pdev, &tsm->base_tsm, tsm_dev);
755}
756EXPORT_SYMBOL_GPL(pci_tsm_pf0_constructor);
757
758void pci_tsm_pf0_destructor(struct pci_tsm_pf0 *pf0_tsm)
759{
760	mutex_destroy(&pf0_tsm->lock);
761}
762EXPORT_SYMBOL_GPL(pci_tsm_pf0_destructor);
763
764int pci_tsm_register(struct tsm_dev *tsm_dev)
765{
766	struct pci_dev *pdev = NULL;
767
768	if (!tsm_dev)
769		return -EINVAL;
770
771	/* The TSM device must only implement one of link_ops or devsec_ops */
772	if (!is_link_tsm(tsm_dev) && !is_devsec_tsm(tsm_dev))
773		return -EINVAL;
774
775	if (is_link_tsm(tsm_dev) && is_devsec_tsm(tsm_dev))
776		return -EINVAL;
777
778	guard(rwsem_write)(&pci_tsm_rwsem);
779
780	/* On first enable, update sysfs groups */
781	if (is_link_tsm(tsm_dev) && pci_tsm_link_count++ == 0) {
782		for_each_pci_dev(pdev)
783			if (is_pci_tsm_pf0(pdev))
784				link_sysfs_enable(pdev);
785	} else if (is_devsec_tsm(tsm_dev)) {
786		pci_tsm_devsec_count++;
787	}
788
789	return 0;
790}
791
792static void pci_tsm_fn_exit(struct pci_dev *pdev)
793{
794	__pci_tsm_unbind(pdev, NULL);
795	tsm_remove(pdev->tsm);
796}
797
798/**
799 * __pci_tsm_destroy() - destroy the TSM context for @pdev
800 * @pdev: device to cleanup
801 * @tsm_dev: the TSM device being removed, or NULL if @pdev is being removed.
802 *
803 * At device removal or TSM unregistration all established context
804 * with the TSM is torn down. Additionally, if there are no more TSMs
805 * registered, the PCI tsm/ sysfs attributes are hidden.
806 */
807static void __pci_tsm_destroy(struct pci_dev *pdev, struct tsm_dev *tsm_dev)
808{
809	struct pci_tsm *tsm = pdev->tsm;
810
811	lockdep_assert_held_write(&pci_tsm_rwsem);
812
813	/*
814	 * First, handle the TSM removal case to shutdown @pdev sysfs, this is
815	 * skipped if the device itself is being removed since sysfs goes away
816	 * naturally at that point
817	 */
818	if (is_link_tsm(tsm_dev) && is_pci_tsm_pf0(pdev) && !pci_tsm_link_count)
819		link_sysfs_disable(pdev);
820
821	/* Nothing else to do if this device never attached to the departing TSM */
822	if (!tsm)
823		return;
824
825	/* Now lookup the tsm_dev to destroy TSM context */
826	if (!tsm_dev)
827		tsm_dev = tsm->tsm_dev;
828	else if (tsm_dev != tsm->tsm_dev)
829		return;
830
831	if (is_link_tsm(tsm_dev) && is_pci_tsm_pf0(pdev))
832		pci_tsm_disconnect(pdev);
833	else
834		pci_tsm_fn_exit(pdev);
835}
836
837void pci_tsm_destroy(struct pci_dev *pdev)
838{
839	guard(rwsem_write)(&pci_tsm_rwsem);
840	__pci_tsm_destroy(pdev, NULL);
841}
842
843void pci_tsm_init(struct pci_dev *pdev)
844{
845	guard(rwsem_read)(&pci_tsm_rwsem);
846
847	/*
848	 * Subfunctions are either probed synchronous with connect() or later
849	 * when either the SR-IOV configuration is changed, or, unlikely,
850	 * connect() raced initial bus scanning.
851	 */
852	if (pdev->tsm)
853		return;
854
855	if (pci_tsm_link_count) {
856		struct pci_dev *dsm = find_dsm_dev(pdev);
857
858		if (!dsm)
859			return;
860
861		/*
862		 * The only path to init a Device Security Manager capable
863		 * device is via connect().
864		 */
865		if (!dsm->tsm)
866			return;
867
868		probe_fn(pdev, dsm);
869	}
870}
871
872void pci_tsm_unregister(struct tsm_dev *tsm_dev)
873{
874	struct pci_dev *pdev = NULL;
875
876	guard(rwsem_write)(&pci_tsm_rwsem);
877	if (is_link_tsm(tsm_dev))
878		pci_tsm_link_count--;
879	if (is_devsec_tsm(tsm_dev))
880		pci_tsm_devsec_count--;
881	for_each_pci_dev_reverse(pdev)
882		__pci_tsm_destroy(pdev, tsm_dev);
883}
884
885int pci_tsm_doe_transfer(struct pci_dev *pdev, u8 type, const void *req,
886			 size_t req_sz, void *resp, size_t resp_sz)
887{
888	struct pci_tsm_pf0 *tsm;
889
890	if (!pdev->tsm || !is_pci_tsm_pf0(pdev))
891		return -ENXIO;
892
893	tsm = to_pci_tsm_pf0(pdev->tsm);
894	if (!tsm->doe_mb)
895		return -ENXIO;
896
897	return pci_doe(tsm->doe_mb, PCI_VENDOR_ID_PCI_SIG, type, req, req_sz,
898		       resp, resp_sz);
899}
900EXPORT_SYMBOL_GPL(pci_tsm_doe_transfer);
~/ Read-only file preview.