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