1 /* Copyright 2013-2016 IBM Corp.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12  * implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <skiboot.h>
18 #include <pci.h>
19 #include <pci-virt.h>
20 
pci_virt_cfg_read_raw(struct pci_virt_device * pvd,uint32_t space,uint32_t offset,uint32_t size,uint32_t * data)21 void pci_virt_cfg_read_raw(struct pci_virt_device *pvd,
22 			   uint32_t space, uint32_t offset,
23 			   uint32_t size, uint32_t *data)
24 {
25 	uint32_t i;
26 
27 	if (space >= PCI_VIRT_CFG_MAX || !pvd->config[space])
28 		return;
29 
30 	for (*data = 0, i = 0; i < size; i++)
31 		*data |= ((uint32_t)(pvd->config[space][offset + i]) << (i * 8));
32 }
33 
pci_virt_cfg_write_raw(struct pci_virt_device * pvd,uint32_t space,uint32_t offset,uint32_t size,uint32_t data)34 void pci_virt_cfg_write_raw(struct pci_virt_device *pvd,
35 			    uint32_t space, uint32_t offset,
36 			    uint32_t size, uint32_t data)
37 {
38 	int i;
39 
40 	if (space >= PCI_VIRT_CFG_MAX || !pvd->config[space])
41 		return;
42 
43 	for (i = 0; i < size; i++) {
44 		pvd->config[space][offset + i] = data;
45 		data = (data >> 8);
46 	}
47 }
48 
pci_virt_find_filter(struct pci_virt_device * pvd,uint32_t start,uint32_t len)49 static struct pci_cfg_reg_filter *pci_virt_find_filter(
50 					struct pci_virt_device *pvd,
51 					uint32_t start, uint32_t len)
52 {
53 	struct pci_cfg_reg_filter *pcrf;
54 
55 	if (!pvd || !len || start >= pvd->cfg_size)
56 		return NULL;
57 
58 	/* Return filter if there is overlapped region. We don't
59 	 * require strict matching for more flexibility. It also
60 	 * means the associated handler should validate the register
61 	 * offset and length.
62 	 */
63 	list_for_each(&pvd->pcrf, pcrf, link) {
64 		if (start < (pcrf->start + pcrf->len) &&
65 		    (start + len) > pcrf->start)
66 			return pcrf;
67 	}
68 
69 	return NULL;
70 }
71 
pci_virt_add_filter(struct pci_virt_device * pvd,uint32_t start,uint32_t len,uint32_t flags,pci_cfg_reg_func func,void * data)72 struct pci_cfg_reg_filter *pci_virt_add_filter(struct pci_virt_device *pvd,
73 					       uint32_t start,
74 					       uint32_t len,
75 					       uint32_t flags,
76 					       pci_cfg_reg_func func,
77 					       void *data)
78 {
79 	struct pci_cfg_reg_filter *pcrf;
80 
81 	if (!pvd || !len || (start + len) >= pvd->cfg_size)
82 		return NULL;
83 	if (!(flags & PCI_REG_FLAG_MASK))
84 		return NULL;
85 
86 	pcrf = pci_virt_find_filter(pvd, start, len);
87 	if (pcrf) {
88 		prlog(PR_ERR, "%s: Filter [%x, %x] overlapped with [%x, %x]\n",
89 		      __func__, start, len, pcrf->start, pcrf->len);
90 		return NULL;
91 	}
92 
93 	pcrf = zalloc(sizeof(*pcrf));
94 	if (!pcrf) {
95 		prlog(PR_ERR, "%s: Out of memory!\n", __func__);
96 		return NULL;
97 	}
98 
99 	pcrf->start = start;
100 	pcrf->len   = len;
101 	pcrf->flags = flags;
102 	pcrf->func  = func;
103 	pcrf->data  = data;
104 	list_add_tail(&pvd->pcrf, &pcrf->link);
105 
106 	return pcrf;
107 }
108 
pci_virt_find_device(struct phb * phb,uint32_t bdfn)109 struct pci_virt_device *pci_virt_find_device(struct phb *phb,
110 					     uint32_t bdfn)
111 {
112 	struct pci_virt_device *pvd;
113 
114 	list_for_each(&phb->virt_devices, pvd, node) {
115 		if (pvd->bdfn == bdfn)
116 			return pvd;
117 	}
118 
119 	return NULL;
120 }
121 
pci_virt_cfg_valid(struct pci_virt_device * pvd,uint32_t offset,uint32_t size)122 static inline bool pci_virt_cfg_valid(struct pci_virt_device *pvd,
123 				      uint32_t offset, uint32_t size)
124 {
125 	if ((offset + size) > pvd->cfg_size)
126 		return false;
127 
128 	if (!size || (size > 4))
129 		return false;
130 
131 	if ((size & (size - 1)) || (offset & (size - 1)))
132 		return false;
133 
134 	return true;
135 }
136 
pci_virt_cfg_read(struct phb * phb,uint32_t bdfn,uint32_t offset,uint32_t size,uint32_t * data)137 int64_t pci_virt_cfg_read(struct phb *phb, uint32_t bdfn,
138 			  uint32_t offset, uint32_t size,
139 			  uint32_t *data)
140 {
141 	struct pci_virt_device *pvd;
142 	struct pci_cfg_reg_filter *pcrf;
143 	int64_t ret = OPAL_SUCCESS;
144 
145 	*data = 0xffffffff;
146 
147 	/* Search for PCI virtual device */
148 	pvd = pci_virt_find_device(phb, bdfn);
149 	if (!pvd)
150 		return OPAL_PARAMETER;
151 
152 	/* Check if config address is valid or not */
153 	if (!pci_virt_cfg_valid(pvd, offset, size))
154 		return OPAL_PARAMETER;
155 
156 	/* The value is fetched from the normal config space when the
157 	 * trap handler returns OPAL_PARTIAL. Otherwise, the trap handler
158 	 * should provide the return value.
159 	 */
160 	pcrf = pci_virt_find_filter(pvd, offset, size);
161 	if (!pcrf || !pcrf->func || !(pcrf->flags & PCI_REG_FLAG_READ))
162 		goto out;
163 
164 	ret = pcrf->func(pvd, pcrf, offset, size, data, false);
165 	if (ret != OPAL_PARTIAL)
166 		return ret;
167 out:
168 	pci_virt_cfg_read_raw(pvd, PCI_VIRT_CFG_NORMAL, offset, size, data);
169 	return OPAL_SUCCESS;
170 }
171 
pci_virt_cfg_write(struct phb * phb,uint32_t bdfn,uint32_t offset,uint32_t size,uint32_t data)172 int64_t pci_virt_cfg_write(struct phb *phb, uint32_t bdfn,
173 			   uint32_t offset, uint32_t size,
174 			   uint32_t data)
175 {
176 	struct pci_virt_device *pvd;
177 	struct pci_cfg_reg_filter *pcrf;
178 	uint32_t val, v, r, c, i;
179 	int64_t ret = OPAL_SUCCESS;
180 
181 	/* Search for PCI virtual device */
182 	pvd = pci_virt_find_device(phb, bdfn);
183 	if (!pvd)
184 		return OPAL_PARAMETER;
185 
186 	/* Check if config address is valid or not */
187 	if (!pci_virt_cfg_valid(pvd, offset, size))
188 		return OPAL_PARAMETER;
189 
190 	/* The value is written to the config space if the trap handler
191 	 * returns OPAL_PARTIAL. Otherwise, the value to be written is
192 	 * dropped.
193 	 */
194 	pcrf = pci_virt_find_filter(pvd, offset, size);
195 	if (!pcrf || !pcrf->func || !(pcrf->flags & PCI_REG_FLAG_WRITE))
196 		goto out;
197 
198 	ret = pcrf->func(pvd, pcrf, offset, size, &data, true);
199 	if (ret != OPAL_PARTIAL)
200 		return ret;
201 out:
202 	val = data;
203 	for (i = 0; i < size; i++) {
204 		PCI_VIRT_CFG_NORMAL_RD(pvd, offset + i, 1, &v);
205 		PCI_VIRT_CFG_RDONLY_RD(pvd, offset + i, 1, &r);
206 		PCI_VIRT_CFG_W1CLR_RD(pvd, offset + i, 1, &c);
207 
208 		/* Drop read-only bits */
209 		val &= ~(r << (i * 8));
210 		val |= (r & v) << (i * 8);
211 
212 		/* Drop W1C bits */
213 		val &= ~(val & ((c & v) << (i * 8)));
214 	}
215 
216 	PCI_VIRT_CFG_NORMAL_WR(pvd, offset, size, val);
217 	return OPAL_SUCCESS;
218 }
219 
pci_virt_add_device(struct phb * phb,uint32_t bdfn,uint32_t cfg_size,void * data)220 struct pci_virt_device *pci_virt_add_device(struct phb *phb, uint32_t bdfn,
221 					    uint32_t cfg_size, void *data)
222 {
223 	struct pci_virt_device *pvd;
224 	uint8_t *cfg;
225 	uint32_t i;
226 
227 	/* The standard config header size is 64 bytes */
228 	if (!phb || (bdfn & 0xffff0000) || (cfg_size < 64))
229 		return NULL;
230 
231 	/* Check if the bdfn is available */
232 	pvd = pci_virt_find_device(phb, bdfn);
233 	if (pvd) {
234 		prlog(PR_ERR, "%s: bdfn 0x%x was reserved\n",
235 		      __func__, bdfn);
236 		return NULL;
237 	}
238 
239 	/* Populate the PCI virtual device */
240 	pvd = zalloc(sizeof(*pvd));
241 	if (!pvd) {
242 		prlog(PR_ERR, "%s: Cannot alloate PCI virtual device (0x%x)\n",
243 		      __func__, bdfn);
244 		return NULL;
245 	}
246 
247 	cfg = zalloc(cfg_size * PCI_VIRT_CFG_MAX);
248 	if (!cfg) {
249 		prlog(PR_ERR, "%s: Cannot allocate config space (0x%x)\n",
250 		      __func__, bdfn);
251 		free(pvd);
252 		return NULL;
253 	}
254 
255 	for (i = 0; i < PCI_VIRT_CFG_MAX; i++, cfg += cfg_size)
256 		pvd->config[i] = cfg;
257 
258 	pvd->bdfn     = bdfn;
259 	pvd->cfg_size = cfg_size;
260 	pvd->data     = data;
261 	list_head_init(&pvd->pcrf);
262 	list_add_tail(&phb->virt_devices, &pvd->node);
263 
264 	return pvd;
265 }
266