1 /* Copyright 2013-2014 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 #define pr_fmt(fmt) "LXVPD: " fmt
17 
18 #include <skiboot.h>
19 #include <device.h>
20 #include <vpd.h>
21 #include <pci.h>
22 #include <pci-cfg.h>
23 #include <pci-slot.h>
24 
25 #include "lxvpd.h"
26 
27 /*
28  * Currently, the lxvpd PCI slot struct is shared by multiple
29  * platforms (Apollo and Firenze), but each slot still has
30  * platform specific features. In order for unified data structs,
31  * "struct lxvpd_slot" is expected to be embedded in platform
32  * PCI slot struct. "entry_size" indicates the size of platform
33  * specific PCI slot instance.
34  */
35 struct lxvpd_pci_slot_data {
36 	uint8_t		num_slots;
37 	int32_t		entry_size;	/* Size of platform PCI slot  */
38 	void		*slots;		/* Data of platform PCI slots */
39 };
40 
lxvpd_supported_slot(struct phb * phb,struct pci_device * pd)41 static bool lxvpd_supported_slot(struct phb *phb, struct pci_device *pd)
42 {
43 	/* PHB should always be valid */
44 	if (!phb)
45 		return false;
46 
47 	/* We expect platform slot for root complex */
48 	if (!pd)
49 		return true;
50 
51 	/* We support the root complex at the top level */
52 	if (pd->dev_type == PCIE_TYPE_ROOT_PORT && !pd->parent)
53 		return true;
54 
55 	/* We support an upstream switch port below the root complex */
56 	if (pd->dev_type == PCIE_TYPE_SWITCH_UPPORT &&
57 	    pd->parent && pd->parent->dev_type == PCIE_TYPE_ROOT_PORT &&
58 	    !pd->parent->parent)
59 		return true;
60 
61 	/* We support a downstream switch port below an upstream port
62 	 * below the root complex
63 	 */
64 	if (pd->dev_type == PCIE_TYPE_SWITCH_DNPORT &&
65 	    pd->parent && pd->parent->dev_type == PCIE_TYPE_SWITCH_UPPORT &&
66 	    pd->parent->parent &&
67 	    pd->parent->parent->dev_type == PCIE_TYPE_ROOT_PORT &&
68 	    !pd->parent->parent->parent)
69 		return true;
70 
71 	/* Anything else, bail */
72 	return false;
73 }
74 
lxvpd_get_slot(struct pci_slot * slot)75 void *lxvpd_get_slot(struct pci_slot *slot)
76 {
77 	struct phb *phb = slot->phb;
78 	struct pci_device *pd = slot->pd;
79 	struct lxvpd_pci_slot_data *sdata = phb->platform_data;
80 	struct lxvpd_pci_slot *s = NULL;
81 	uint8_t slot_num = pd ? ((pd->bdfn >> 3) & 0x1f) : 0xff;
82 	bool is_phb = (pd && pd->parent) ? false : true;
83 	uint8_t index;
84 
85 	/* Check if we have slot info */
86 	if (!sdata) {
87 		prlog(PR_DEBUG, "PHB%04x not have VPD data\n",
88 			  phb->opal_id);
89 		return NULL;
90 	}
91 
92 	/* Platform slot attached ? */
93 	s = slot->data;
94 	if (s) {
95 		prlog(PR_DEBUG, "Slot %016llx had platform data [%s]\n",
96 			  slot->id, s->label);
97 		return s;
98 	}
99 
100 	/*
101 	 * This code only handles PHBs and PCIe switches at the
102 	 * top level. We do not handle any other switch nor any
103 	 * other type of PCI/PCI-X bridge. Generally, we have
104 	 * more strict rules to support slot than PCI core.
105 	 */
106 	if (!lxvpd_supported_slot(phb, pd)) {
107 		prlog(PR_DEBUG, "Slot %016llx not supported\n",
108 			  slot->id);
109 		return NULL;
110 	}
111 
112 	/* Iterate the platform slot array */
113 	for (index = 0; index < sdata->num_slots; index++) {
114 		s = sdata->slots + (index * sdata->entry_size);
115 
116 		/* Match PHB with switch_id == 0 */
117 		if (is_phb && s->switch_id == 0) {
118 			slot->data = s;
119 			s->pci_slot = slot;
120 			prlog(PR_DEBUG, "Found [%s] for PHB slot %016llx\n",
121 				  s->label, slot->id);
122 
123 			return s;
124 		}
125 
126 		/* Match switch port with switch_id != 0 */
127 		if (!is_phb && s->switch_id != 0 && s->dev_id == slot_num) {
128 			slot->data = s;
129 			s->pci_slot = slot;
130 			prlog(PR_DEBUG, "Found [%s] for slot %016llx\n",
131 				  s->label, slot->id);
132 
133 			return s;
134 		}
135 	}
136 
137 	prlog(PR_DEBUG, "No data found for %sslot %016llx\n",
138 		  is_phb ? "PHB " : " ", slot->id);
139 	return NULL;
140 }
141 
lxvpd_extract_info(struct pci_slot * slot,struct lxvpd_pci_slot * s)142 void lxvpd_extract_info(struct pci_slot *slot, struct lxvpd_pci_slot *s)
143 {
144 	slot->pluggable      = s->pluggable ? 1 : 0;
145 	slot->power_ctl      = s->power_ctl ? 1 : 0;
146 	slot->power_led_ctl  = s->pwr_led_ctl;
147 	slot->attn_led_ctl   = s->attn_led_ctl;
148 	slot->connector_type = s->connector_type;
149 	slot->card_desc      = s->card_desc;
150 	slot->card_mech      = s->card_mech;
151 	slot->wired_lanes    = s->wired_lanes;
152 
153 	prlog(PR_DEBUG, "[%s]: pluggable: %d power_ctrl: %d\n",
154 		s->label, (int) s->pluggable, (int) s->power_ctl);
155 }
156 
lxvpd_alloc_slots(struct phb * phb,uint8_t count,uint32_t slot_size)157 static struct lxvpd_pci_slot_data *lxvpd_alloc_slots(struct phb *phb,
158 						     uint8_t count,
159 						     uint32_t slot_size)
160 {
161 	struct lxvpd_pci_slot_data *sdata;
162 
163 	sdata = zalloc(sizeof(struct lxvpd_pci_slot_data) + count * slot_size);
164 	assert(sdata);
165 	sdata->num_slots   = count;
166 	sdata->entry_size  = slot_size;
167 	sdata->slots       = sdata + 1;
168 	phb->platform_data = sdata;
169 
170 	return sdata;
171 }
172 
lxvpd_format_label(char * dst,const char * src,size_t len)173 static void lxvpd_format_label(char *dst, const char *src, size_t len)
174 {
175 	int i;
176 
177 	memcpy(dst, src, len);
178 
179 	/* Remove blank suffix */
180 	for (i = strlen(dst) - 1; i >= 0; i--) {
181 		if (dst[i] != ' ')
182 			break;
183 
184 		dst[i] = 0;
185 	}
186 }
187 
lxvpd_parse_1004_map(struct phb * phb,const uint8_t * sm,uint8_t size,uint32_t slot_size)188 static void lxvpd_parse_1004_map(struct phb *phb,
189 				 const uint8_t *sm,
190 				 uint8_t size,
191 				 uint32_t slot_size)
192 {
193 	struct lxvpd_pci_slot_data *sdata;
194 	struct lxvpd_pci_slot *s;
195 	const struct pci_slot_entry_1004 *entry;
196 	uint8_t num_slots, slot;
197 
198 	num_slots = (size / sizeof(struct pci_slot_entry_1004));
199 	sdata = lxvpd_alloc_slots(phb, num_slots, slot_size);
200 
201 	/* Iterate through the entries in the keyword */
202 	entry = (const struct pci_slot_entry_1004 *)sm;
203 	for (slot = 0; slot < num_slots; slot++, entry++) {
204 		s = sdata->slots + slot * sdata->entry_size;
205 
206 		/* Figure out PCI slot info */
207 		lxvpd_format_label(s->label, entry->label, 3);
208 		s->slot_index     = entry->slot_index;
209 		s->switch_id      = entry->pba >> 4;
210 		s->vswitch_id     = entry->pba & 0xf;
211 		s->dev_id         = entry->sba;
212 		s->pluggable      = ((entry->p0.byte & 0x20) == 0);
213 		s->power_ctl      = !!(entry->p0.byte & 0x40);
214 		s->bus_clock      = entry->p2.bus_clock - 4;
215 		s->connector_type = entry->p2.connector_type - 5;
216 		s->card_desc      = entry->p3.byte >> 6;
217 		if (entry->p3.byte < 0xc0)
218 			s->card_desc -= 4;
219 		s->card_mech      = (entry->p3.byte >> 4) & 0x3;
220 		s->pwr_led_ctl    = (entry->p3.byte & 0xf) >> 2;
221 		s->attn_led_ctl   = entry->p3.byte & 0x3;
222 
223 		switch(entry->p1.wired_lanes) {
224 		case 1: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIX_32;  break;
225 		case 2: /* fall through */
226 		case 3: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIX_64;  break;
227 		case 4: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X1;  break;
228 		case 5: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X4;  break;
229 		case 6: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X8;  break;
230 		case 7: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X16; break;
231 		default:
232 			s->wired_lanes = PCI_SLOT_WIRED_LANES_UNKNOWN;
233 		}
234 
235 		prlog(PR_DEBUG, "1004 Platform data [%s] %02x %02x on PHB%04x\n",
236 			  s->label, s->switch_id, s->dev_id, phb->opal_id);
237 	}
238 }
239 
lxvpd_parse_1005_map(struct phb * phb,const uint8_t * sm,uint8_t size,uint32_t slot_size)240 static void lxvpd_parse_1005_map(struct phb *phb,
241 				 const uint8_t *sm,
242 				 uint8_t size,
243 				 uint32_t slot_size)
244 {
245 	struct lxvpd_pci_slot_data *sdata;
246 	struct lxvpd_pci_slot *s;
247 	const struct pci_slot_entry_1005 *entry;
248 	uint8_t num_slots, slot;
249 
250 	num_slots = (size / sizeof(struct pci_slot_entry_1005));
251 	sdata = lxvpd_alloc_slots(phb, num_slots, slot_size);
252 
253 	/* Iterate through the entries in the keyword */
254 	entry = (const struct pci_slot_entry_1005 *)sm;
255 	for (slot = 0; slot < num_slots; slot++, entry++) {
256 		s = sdata->slots + slot * sdata->entry_size;
257 
258 		/* Put slot info into pci device structure */
259 		lxvpd_format_label(s->label, entry->label, 8);
260 		s->slot_index     = entry->slot_index;
261 		s->switch_id      = entry->pba >> 4;
262 		s->vswitch_id     = entry->pba & 0xf;
263 		s->dev_id         = entry->switch_device_id;
264 		s->pluggable      = (entry->p0.pluggable == 0);
265 		s->power_ctl      = entry->p0.power_ctl;
266 		s->bus_clock      = entry->p2.bus_clock;
267 		s->connector_type = entry->p2.connector_type;
268 		s->card_desc      = entry->p3.byte >> 6;
269 		s->card_mech      = (entry->p3.byte >> 4) & 0x3;
270 		s->pwr_led_ctl    = (entry->p3.byte & 0xf) >> 2;
271 		s->attn_led_ctl   = entry->p3.byte & 0x3;
272 		s->wired_lanes    = entry->p1.wired_lanes;
273 		if (s->wired_lanes > PCI_SLOT_WIRED_LANES_PCIE_X32)
274 			s->wired_lanes = PCI_SLOT_WIRED_LANES_UNKNOWN;
275 
276 		prlog(PR_DEBUG, "1005 Platform data [%s] %02x %02x on PHB%04x\n",
277 			  s->label, s->switch_id, s->dev_id, phb->opal_id);
278 	}
279 }
280 
lxvpd_process_slot_entries(struct phb * phb,struct dt_node * node,uint8_t chip_id,uint8_t index,uint32_t slot_size)281 void lxvpd_process_slot_entries(struct phb *phb,
282 				struct dt_node *node,
283 				uint8_t chip_id,
284 				uint8_t index,
285 				uint32_t slot_size)
286 {
287 	const void *lxvpd;
288 	const uint8_t *pr_rec, *pr_end, *sm;
289 	size_t lxvpd_size, pr_size;
290 	const uint16_t *mf = NULL;
291 	char record[5] = "PR00";
292 	uint8_t mf_sz, sm_sz;
293 	bool found = false;
294 
295 	record[2] += chip_id;
296 	record[3] += index;
297 	record[4] = 0;
298 
299 	/* Get LX VPD pointer */
300 	lxvpd = dt_prop_get_def_size(node, "ibm,io-vpd", NULL, &lxvpd_size);
301 	if (!lxvpd) {
302 		prlog(PR_WARNING, "No data found for PHB%04x %s\n",
303 			   phb->opal_id, record);
304 		return;
305 	}
306 
307 	pr_rec = vpd_find_record(lxvpd, lxvpd_size, record, &pr_size);
308 	if (!pr_rec) {
309 		prlog(PR_WARNING, "Record %s not found on PHB%04x\n",
310 			   record, phb->opal_id);
311 		return;
312 	}
313 
314 	/* As long as there's still something in the PRxy record */
315 	prlog(PR_DEBUG, "PHB%04x record %s has %ld bytes\n",
316 		  phb->opal_id, record, pr_size);
317 	pr_end = pr_rec + pr_size;
318 	while (pr_rec < pr_end) {
319 		pr_size = pr_end - pr_rec;
320 
321 		/* Find the next MF keyword */
322 		mf = vpd_find_keyword(pr_rec, pr_size, "MF", &mf_sz);
323 		/* And the corresponding SM */
324 		sm = vpd_find_keyword(pr_rec, pr_size, "SM", &sm_sz);
325 		if (!mf || !sm) {
326 			if (!found)
327 				prlog(PR_WARNING, "Slot Map keyword %s not found\n",
328 					   record);
329 			return;
330 		}
331 
332 		prlog(PR_DEBUG, "Found 0x%04x map...\n", *mf);
333 		switch (*mf) {
334 		case 0x1004:
335 			lxvpd_parse_1004_map(phb, sm + 1, sm_sz - 1, slot_size);
336 			found = true;
337 			break;
338 		case 0x1005:
339 			lxvpd_parse_1005_map(phb, sm + 1, sm_sz - 1, slot_size);
340 			found = true;
341 			break;
342 			/* Add support for 0x1006 maps ... */
343 		}
344 
345 		pr_rec = sm + sm_sz;
346 	}
347 }
348 
lxvpd_add_slot_properties(struct pci_slot * slot,struct dt_node * np)349 void lxvpd_add_slot_properties(struct pci_slot *slot,
350 			       struct dt_node *np)
351 {
352 	struct phb *phb = slot->phb;
353 	struct lxvpd_pci_slot *s = slot->data;
354 	char loc_code[LOC_CODE_SIZE];
355 	size_t base_loc_code_len, slot_label_len;
356 
357 	/* Check if we have platform specific slot */
358 	if (!s || !np)
359 		return;
360 
361 	/* Check PHB base location code */
362 	if (!phb->base_loc_code)
363 		return;
364 
365 	/* Check location length is valid */
366 	base_loc_code_len = strlen(phb->base_loc_code);
367 	slot_label_len = strlen(s->label);
368 	if ((base_loc_code_len + slot_label_len + 1) >= LOC_CODE_SIZE)
369 		return;
370 
371 	/* Location code */
372 	strcpy(loc_code, phb->base_loc_code);
373 	strcat(loc_code, "-");
374 	strcat(loc_code, s->label);
375 	dt_add_property(np, "ibm,slot-location-code",
376 			loc_code, strlen(loc_code) + 1);
377 	dt_add_property_string(np, "ibm,slot-label",
378 			       s->label);
379 }
380