1 /*
2  * Copyright (C) 2021-2022 Intel Corporation.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <errno.h>
9 #include <string.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <sys/queue.h>
13 
14 #include "pcireg.h"
15 #include "pciaccess.h"
16 #include "pci_core.h"
17 #include "ptm.h"
18 #include "passthru.h"
19 #include "pci_util.h"
20 #include "vmmapi.h"
21 #include "acrn_common.h"
22 
23 #define PTM_ROOT_PORT_VENDOR           0x8086U
24 #define PTM_ROOT_PORT_DEVICE           0x9d14U
25 
26 /* PTM capability register ID*/
27 #define PCIZ_PTM    0x1fU
28 
29 /* PTM register Definitions */
30 /* PTM capability register */
31 #define PCIR_PTM_CAP				0x04U
32 	#define PCIM_PTM_CAP_REQ		0x01U	/* Requestor capable */
33 	#define PCIM_PTM_CAP_ROOT		0x4U	/* Root capable */
34 	#define PCIM_PTM_GRANULARITY	0xFF00	/* Clock granularity */
35 /* PTM control register */
36 #define PCIR_PTM_CTRL				0x08U
37 	#define PCIM_PTM_CTRL_ENABLE	0x1U	/* PTM enable */
38 	#define PCIM_PTM_CTRL_ROOT_SELECT	0x2U	/* Root select */
39 
40 /* virtual root port secondary bus */
41 static int ptm_root_port_secondary_bus;
42 
43 /* get ptm capability register value */
44 static int
get_ptm_reg_value(struct pci_device * pdev,int reg)45 get_ptm_reg_value(struct pci_device *pdev, int reg)
46 {
47 	int pos;
48 	uint32_t reg_val;
49 
50 	pos = pci_find_ext_cap(pdev, PCIZ_PTM);
51 
52 	if (!pos) {
53 		return 0;
54 	}
55 
56 	pci_device_cfg_read_u32(pdev, &reg_val, pos + reg);
57 
58 	pr_notice("<PTM>-%s: device [%x:%x.%x]: ptm pos=0x%x, ptm reg val=0x%x.\n",
59 				__func__, pdev->bus, pdev->dev, pdev->func, pos, reg_val);
60 
61 	return reg_val;
62 }
63 
64 /* add virtual root port to hv */
65 static int
add_vroot_port(struct vmctx * ctx,struct passthru_dev * ptdev,struct pci_device * root_port,int ptm_cap_offset)66 add_vroot_port(struct vmctx *ctx, struct passthru_dev *ptdev, struct pci_device *root_port, int ptm_cap_offset)
67 {
68 	int error = 0;
69 	int offset = 0;
70 	uint32_t dev_cap = 0;
71 
72 	struct acrn_vdev rp_vdev = {};
73 	struct vrp_config *rp_priv = (struct vrp_config *)&rp_vdev.args;
74 
75 	rp_vdev.id.fields.vendor = PTM_ROOT_PORT_VENDOR;
76 	rp_vdev.id.fields.device = PTM_ROOT_PORT_DEVICE;
77 
78 	// virtual root port takes bdf from its downstream device
79 	rp_vdev.slot = PCI_BDF(ptdev->dev->bus, ptdev->dev->slot, ptdev->dev->func);
80 
81 	rp_priv->phy_bdf = PCI_BDF(root_port->bus, root_port->dev, root_port->func);
82 
83 	rp_priv->primary_bus = ptdev->dev->bus;
84 
85 	rp_priv->secondary_bus = ++ptm_root_port_secondary_bus;
86 
87 	// only passthru device is connected to virtual root port
88 	rp_priv->subordinate_bus = rp_priv->secondary_bus;
89 
90 	rp_priv->ptm_capable = 1;
91 
92 	rp_priv->ptm_cap_offset = ptm_cap_offset;
93 
94 	/* It seems important that passthru device's max payload settings match
95 	 * the settings on the native device otherwise passthru device may not work.
96 	 * So we have to set vrp's max payload capacity the same as native root port
97 	 * otherwise we may accidentally change passthru device's max payload since
98 	 * during guest OS's pci enumeration, pass-thru device will renegotiate
99 	 * its max payload's setting with vrp.
100 	 */
101 	offset = pci_find_cap(root_port, PCIY_EXPRESS);
102 	pci_device_cfg_read_u32(root_port, &dev_cap, offset + PCIER_DEVICE_CAP);
103 	rp_priv->max_payload = dev_cap & PCIEM_CAP_MAX_PAYLOAD;
104 	pr_info("%s: virtual root port info: vbdf=0x%x, phy_bdf=0x%x, prim_bus=%x, sec_bus=%x, sub_bus=%x, ptm_cpa_offset=0x%x, max_payload=0x%x.\n",
105 		 __func__, rp_vdev.slot, rp_priv->phy_bdf, rp_priv->primary_bus, rp_priv->secondary_bus, rp_priv->subordinate_bus,
106 		 rp_priv->ptm_cap_offset, rp_priv->max_payload);
107 
108 	error = vm_add_hv_vdev(ctx, &rp_vdev);
109 	if (error) {
110 		pr_err("failed to add virtual root.\n");
111 		return -1;
112 	} else
113 		return rp_priv->secondary_bus;
114 }
115 
116 /* Probe whether device and its root port support PTM */
ptm_probe(struct vmctx * ctx,struct passthru_dev * ptdev,int * vrp_sec_bus)117 int ptm_probe(struct vmctx *ctx, struct passthru_dev *ptdev, int *vrp_sec_bus)
118 {
119 	int pos, pcie_type, cap, rp_ptm_offset;
120 	struct pci_device *phys_dev = ptdev->phys_dev;
121 	struct pci_device *rp;
122 
123 	*vrp_sec_bus = 0;
124 
125 	if (!ptdev->pcie_cap) {
126 		pr_err("%s Error: %x:%x.%x is not a pci-e device.\n", __func__,
127 				phys_dev->bus, phys_dev->dev, phys_dev->func);
128 		return -EINVAL;
129 	}
130 
131 	pos = pci_find_ext_cap(phys_dev, PCIZ_PTM);
132 	if (!pos) {
133 		pr_err("%s Error: %x:%x.%x doesn't support ptm.\n", __func__,
134 				phys_dev->bus, phys_dev->dev, phys_dev->func);
135 		return -EINVAL;
136 	}
137 
138 	pcie_type = pci_get_pcie_type(phys_dev);
139 
140 	/* The following sanity checks are based on these assumptions:
141 	 * 1. PTM requestor can be enabled on pci ep or rcie.
142 	 * 2. HW implements this simple PTM hierarchy: PTM requestor (EP) is
143 	 * directly connected to PTM root (root port), or requestor itself is RCIE.
144 	 * 3. There is no intermediate nodes (such as switch) in between the PTM
145 	 * root and PTM requestor.
146 	 * 4. HW only implements one PCI domain in the system and only one PTM
147 	 * domain implemented in this PCI domain
148 	 */
149 	if (pcie_type == PCIEM_TYPE_ENDPOINT) {
150 		cap = get_ptm_reg_value(phys_dev, PCIR_PTM_CAP);
151 		if (!(cap & PCIM_PTM_CAP_REQ)) {
152 			pr_err("%s Error: %x:%x.%x must be PTM requestor.\n", __func__,
153 					phys_dev->bus, phys_dev->dev, phys_dev->func);
154 			return -EINVAL;
155 		}
156 
157 		/* Do not support switch */
158 		rp = pci_device_get_parent_bridge(phys_dev);
159 		if ((rp == NULL) || !is_root_port(rp)) {
160 			pr_err("%s Error: Cannot find root port of %x:%x.%x.\n", __func__,
161 					phys_dev->bus, phys_dev->dev, phys_dev->func);
162 			return -ENODEV;
163 		}
164 
165 		/* check whether root port is PTM root-capable */
166 		cap = get_ptm_reg_value(rp, PCIR_PTM_CAP);
167 		if (!(cap & PCIM_PTM_CAP_ROOT)) {
168 			pr_err("%s Error: root port %x:%x.%x of %x:%x.%x is not PTM root capable.\n",
169 				__func__, rp->bus, rp->dev, rp->func,
170 				phys_dev->bus, phys_dev->dev, phys_dev->func);
171 			return -EINVAL;
172 		}
173 
174 		/* TODO: Support multiple PFs device later as it needs to consider to prevent P2P
175 		 * attack through ACS or passthrough all PFs together.
176 		 */
177 		if (is_mfdev(phys_dev)) {
178 			pr_err("%s: Failed to enable PTM on root port [%x:%x.%x], multi-func dev is not supported.\n",
179 					__func__, rp->bus, rp->dev, rp->func);
180 			return -EINVAL;
181 		}
182 
183 		/* hv is responsible to ensure that PTM is enabled on hw root port if
184 		 * root port is PTM root-capable.  If PTM root is not enabled already in physical
185 		 * root port before guest launch, guest OS can only enable it in root port's virtual
186 		 * config space and PTM may not function as desired so we are not going to allow user
187 		 * to enable PTM on pass-thru device.
188 		 */
189 		cap = get_ptm_reg_value(rp, PCIR_PTM_CTRL);
190 		if (!(cap & PCIM_PTM_CTRL_ENABLE) || !(cap & PCIM_PTM_CTRL_ROOT_SELECT)) {
191 			pr_err("%s Warning: guest is not allowed to enable PTM on root port %x:%x.%x.\n",
192 				__func__, rp->bus, rp->dev, rp->func);
193 
194 			return -EINVAL;
195 		}
196 
197 		rp_ptm_offset = pci_find_ext_cap(rp, PCIZ_PTM);
198 
199 		/* add virtual root port */
200 		*vrp_sec_bus = add_vroot_port(ctx, ptdev, rp, rp_ptm_offset);
201 	} else if (pcie_type == PCIEM_TYPE_ROOT_INT_EP) {
202 		/* Do NOT emulate root port if ptm requestor is RCIE */
203 		pr_notice("%s: ptm requestor is root complex integrated device.\n", __func__);
204 	} else {
205 		pr_err("%s Error: PTM can only be enabled on pci root complex integrated device or endpoint device.\n",
206 					__func__);
207 		return -EINVAL;
208 	}
209 
210 	return 0;
211 }
212