/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __PCI_TSM_H
#define __PCI_TSM_H
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/sockptr.h>

struct pci_tsm;
struct tsm_dev;
struct kvm;
enum pci_tsm_req_scope;


struct pci_tsm_ops {
	
	struct_group_tagged(pci_tsm_link_ops, link_ops,
		struct pci_tsm *(*probe)(struct tsm_dev *tsm_dev,
					 struct pci_dev *pdev);
		void (*remove)(struct pci_tsm *tsm);
		int (*connect)(struct pci_dev *pdev);
		void (*disconnect)(struct pci_dev *pdev);
		struct pci_tdi *(*bind)(struct pci_dev *pdev,
					struct kvm *kvm, u32 tdi_id);
		void (*unbind)(struct pci_tdi *tdi);
		ssize_t (*guest_req)(struct pci_tdi *tdi,
				     enum pci_tsm_req_scope scope,
				     sockptr_t req_in, size_t in_len,
				     sockptr_t req_out, size_t out_len,
				     u64 *tsm_code);
	);

	
	struct_group_tagged(pci_tsm_devsec_ops, devsec_ops,
		struct pci_tsm *(*lock)(struct tsm_dev *tsm_dev,
					struct pci_dev *pdev);
		void (*unlock)(struct pci_tsm *tsm);
	);
};


struct pci_tdi {
	struct pci_dev *pdev;
	struct kvm *kvm;
	u32 tdi_id;
};


struct pci_tsm {
	struct pci_dev *pdev;
	struct pci_dev *dsm_dev;
	struct tsm_dev *tsm_dev;
	struct pci_tdi *tdi;
};


struct pci_tsm_pf0 {
	struct pci_tsm base_tsm;
	struct mutex lock;
	struct pci_doe_mb *doe_mb;
};


static inline bool is_pci_tsm_pf0(struct pci_dev *pdev)
{
	if (!pdev)
		return false;

	if (!pci_is_pcie(pdev))
		return false;

	if (pdev->is_virtfn)
		return false;

	
	switch (pci_pcie_type(pdev)) {
	case PCI_EXP_TYPE_ENDPOINT:
	case PCI_EXP_TYPE_UPSTREAM:
	case PCI_EXP_TYPE_RC_END:
		if (pdev->ide_cap || (pdev->devcap & PCI_EXP_DEVCAP_TEE))
			break;
		fallthrough;
	default:
		return false;
	}

	return PCI_FUNC(pdev->devfn) == 0;
}


enum pci_tsm_req_scope {
	
	PCI_TSM_REQ_INFO = 0,
	
	PCI_TSM_REQ_STATE_CHANGE = 1,
	
	PCI_TSM_REQ_DEBUG_READ = 2,
	
	PCI_TSM_REQ_DEBUG_WRITE = 3,
};

#ifdef CONFIG_PCI_TSM
int pci_tsm_register(struct tsm_dev *tsm_dev);
void pci_tsm_unregister(struct tsm_dev *tsm_dev);
int pci_tsm_link_constructor(struct pci_dev *pdev, struct pci_tsm *tsm,
			     struct tsm_dev *tsm_dev);
int pci_tsm_pf0_constructor(struct pci_dev *pdev, struct pci_tsm_pf0 *tsm,
			    struct tsm_dev *tsm_dev);
void pci_tsm_pf0_destructor(struct pci_tsm_pf0 *tsm);
int pci_tsm_doe_transfer(struct pci_dev *pdev, u8 type, const void *req,
			 size_t req_sz, void *resp, size_t resp_sz);
int pci_tsm_bind(struct pci_dev *pdev, struct kvm *kvm, u32 tdi_id);
void pci_tsm_unbind(struct pci_dev *pdev);
void pci_tsm_tdi_constructor(struct pci_dev *pdev, struct pci_tdi *tdi,
			     struct kvm *kvm, u32 tdi_id);
ssize_t pci_tsm_guest_req(struct pci_dev *pdev, enum pci_tsm_req_scope scope,
			  sockptr_t req_in, size_t in_len, sockptr_t req_out,
			  size_t out_len, u64 *tsm_code);
#else
static inline int pci_tsm_register(struct tsm_dev *tsm_dev)
{
	return 0;
}
static inline void pci_tsm_unregister(struct tsm_dev *tsm_dev)
{
}
static inline int pci_tsm_bind(struct pci_dev *pdev, struct kvm *kvm, u64 tdi_id)
{
	return -ENXIO;
}
static inline void pci_tsm_unbind(struct pci_dev *pdev)
{
}
static inline ssize_t pci_tsm_guest_req(struct pci_dev *pdev,
					enum pci_tsm_req_scope scope,
					sockptr_t req_in, size_t in_len,
					sockptr_t req_out, size_t out_len,
					u64 *tsm_code)
{
	return -ENXIO;
}
#endif
#endif 
