~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/skiboot/platforms/ibm-fsp/lxvpd.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
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
 
 
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
 
 
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
 
 
154
static struct lxvpd_pci_slot_data *lxvpd_alloc_slots(struct phb *phb,
 
155
                                                     uint8_t count,
 
156
                                                     uint32_t slot_size)
 
157
{
 
158
        struct lxvpd_pci_slot_data *sdata;
 
159
 
 
160
        sdata = zalloc(sizeof(struct lxvpd_pci_slot_data) + count * slot_size);
 
161
        assert(sdata);
 
162
        sdata->num_slots   = count;
 
163
        sdata->entry_size  = slot_size;
 
164
        sdata->slots       = sdata + 1;
 
165
        phb->platform_data = sdata;
 
166
 
 
167
        return sdata;
 
168
}
 
169
 
 
170
static void lxvpd_format_label(char *dst, const char *src, size_t len)
 
171
{
 
172
        int i;
 
173
 
 
174
        memcpy(dst, src, len);
 
175
 
 
176
        /* Remove blank suffix */
 
177
        for (i = strlen(dst) - 1; i >= 0; i--) {
 
178
                if (dst[i] != ' ')
 
179
                        break;
 
180
 
 
181
                dst[i] = 0;
 
182
        }
 
183
}
 
184
 
 
185
static void lxvpd_parse_1004_map(struct phb *phb,
 
186
                                 const uint8_t *sm,
 
187
                                 uint8_t size,
 
188
                                 uint32_t slot_size)
 
189
{
 
190
        struct lxvpd_pci_slot_data *sdata;
 
191
        struct lxvpd_pci_slot *s;
 
192
        const struct pci_slot_entry_1004 *entry;
 
193
        uint8_t num_slots, slot;
 
194
 
 
195
        num_slots = (size / sizeof(struct pci_slot_entry_1004));
 
196
        sdata = lxvpd_alloc_slots(phb, num_slots, slot_size);
 
197
 
 
198
        /* Iterate through the entries in the keyword */
 
199
        entry = (const struct pci_slot_entry_1004 *)sm;
 
200
        for (slot = 0; slot < num_slots; slot++, entry++) {
 
201
                s = sdata->slots + slot * sdata->entry_size;
 
202
 
 
203
                /* Figure out PCI slot info */
 
204
                lxvpd_format_label(s->label, entry->label, 3);
 
205
                s->slot_index     = entry->slot_index;
 
206
                s->switch_id      = entry->pba >> 4;
 
207
                s->vswitch_id     = entry->pba & 0xf;
 
208
                s->dev_id         = entry->sba;
 
209
                s->pluggable      = ((entry->p0.byte & 0x20) == 0);
 
210
                s->power_ctl      = !!(entry->p0.byte & 0x40);
 
211
                s->bus_clock      = entry->p2.bus_clock - 4;
 
212
                s->connector_type = entry->p2.connector_type - 5;
 
213
                s->card_desc      = entry->p3.byte >> 6;
 
214
                if (entry->p3.byte < 0xc0)
 
215
                        s->card_desc -= 4;
 
216
                s->card_mech      = (entry->p3.byte >> 4) & 0x3;
 
217
                s->pwr_led_ctl    = (entry->p3.byte & 0xf) >> 2;
 
218
                s->attn_led_ctl   = entry->p3.byte & 0x3;
 
219
 
 
220
                switch(entry->p1.wired_lanes) {
 
221
                case 1: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIX_32;  break;
 
222
                case 2: /* fall through */
 
223
                case 3: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIX_64;  break;
 
224
                case 4: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X1;  break;
 
225
                case 5: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X4;  break;
 
226
                case 6: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X8;  break;
 
227
                case 7: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X16; break;
 
228
                default:
 
229
                        s->wired_lanes = PCI_SLOT_WIRED_LANES_UNKNOWN;
 
230
                }
 
231
 
 
232
                prlog(PR_DEBUG, "1004 Platform data [%s] %02x %02x on PHB%04x\n",
 
233
                          s->label, s->switch_id, s->dev_id, phb->opal_id);
 
234
        }
 
235
}
 
236
 
 
237
static void lxvpd_parse_1005_map(struct phb *phb,
 
238
                                 const uint8_t *sm,
 
239
                                 uint8_t size,
 
240
                                 uint32_t slot_size)
 
241
{
 
242
        struct lxvpd_pci_slot_data *sdata;
 
243
        struct lxvpd_pci_slot *s;
 
244
        const struct pci_slot_entry_1005 *entry;
 
245
        uint8_t num_slots, slot;
 
246
 
 
247
        num_slots = (size / sizeof(struct pci_slot_entry_1005));
 
248
        sdata = lxvpd_alloc_slots(phb, num_slots, slot_size);
 
249
 
 
250
        /* Iterate through the entries in the keyword */
 
251
        entry = (const struct pci_slot_entry_1005 *)sm;
 
252
        for (slot = 0; slot < num_slots; slot++, entry++) {
 
253
                s = sdata->slots + slot * sdata->entry_size;
 
254
 
 
255
                /* Put slot info into pci device structure */
 
256
                lxvpd_format_label(s->label, entry->label, 8);
 
257
                s->slot_index     = entry->slot_index;
 
258
                s->switch_id      = entry->pba >> 4;
 
259
                s->vswitch_id     = entry->pba & 0xf;
 
260
                s->dev_id         = entry->switch_device_id;
 
261
                s->pluggable      = (entry->p0.pluggable == 0);
 
262
                s->power_ctl      = entry->p0.power_ctl;
 
263
                s->bus_clock      = entry->p2.bus_clock;
 
264
                s->connector_type = entry->p2.connector_type;
 
265
                s->card_desc      = entry->p3.byte >> 6;
 
266
                s->card_mech      = (entry->p3.byte >> 4) & 0x3;
 
267
                s->pwr_led_ctl    = (entry->p3.byte & 0xf) >> 2;
 
268
                s->attn_led_ctl   = entry->p3.byte & 0x3;
 
269
                s->wired_lanes    = entry->p1.wired_lanes;
 
270
                if (s->wired_lanes > PCI_SLOT_WIRED_LANES_PCIE_X32)
 
271
                        s->wired_lanes = PCI_SLOT_WIRED_LANES_UNKNOWN;
 
272
 
 
273
                prlog(PR_DEBUG, "1005 Platform data [%s] %02x %02x on PHB%04x\n",
 
274
                          s->label, s->switch_id, s->dev_id, phb->opal_id);
 
275
        }
 
276
}
 
277
 
 
278
void lxvpd_process_slot_entries(struct phb *phb,
 
279
                                struct dt_node *node,
 
280
                                uint8_t chip_id,
 
281
                                uint8_t index,
 
282
                                uint32_t slot_size)
 
283
{
 
284
        const void *lxvpd;
 
285
        const uint8_t *pr_rec, *pr_end, *sm;
 
286
        size_t lxvpd_size, pr_size;
 
287
        const uint16_t *mf = NULL;
 
288
        char record[5] = "PR00";
 
289
        uint8_t mf_sz, sm_sz;
 
290
        bool found = false;
 
291
 
 
292
        record[2] += chip_id;
 
293
        record[3] += index;
 
294
        record[4] = 0;
 
295
 
 
296
        /* Get LX VPD pointer */
 
297
        lxvpd = dt_prop_get_def_size(node, "ibm,io-vpd", NULL, &lxvpd_size);
 
298
        if (!lxvpd) {
 
299
                prlog(PR_WARNING, "No data found for PHB%04x %s\n",
 
300
                           phb->opal_id, record);
 
301
                return;
 
302
        }
 
303
 
 
304
        pr_rec = vpd_find_record(lxvpd, lxvpd_size, record, &pr_size);
 
305
        if (!pr_rec) {
 
306
                prlog(PR_WARNING, "Record %s not found on PHB%04x\n",
 
307
                           record, phb->opal_id);
 
308
                return;
 
309
        }
 
310
 
 
311
        /* As long as there's still something in the PRxy record */
 
312
        prlog(PR_DEBUG, "PHB%04x record %s has %ld bytes\n",
 
313
                  phb->opal_id, record, pr_size);
 
314
        pr_end = pr_rec + pr_size;
 
315
        while (pr_rec < pr_end) {
 
316
                pr_size = pr_end - pr_rec;
 
317
 
 
318
                /* Find the next MF keyword */
 
319
                mf = vpd_find_keyword(pr_rec, pr_size, "MF", &mf_sz);
 
320
                /* And the corresponding SM */
 
321
                sm = vpd_find_keyword(pr_rec, pr_size, "SM", &sm_sz);
 
322
                if (!mf || !sm) {
 
323
                        if (!found)
 
324
                                prlog(PR_WARNING, "Slot Map keyword %s not found\n",
 
325
                                           record);
 
326
                        return;
 
327
                }
 
328
 
 
329
                prlog(PR_DEBUG, "Found 0x%04x map...\n", *mf);
 
330
                switch (*mf) {
 
331
                case 0x1004:
 
332
                        lxvpd_parse_1004_map(phb, sm + 1, sm_sz - 1, slot_size);
 
333
                        found = true;
 
334
                        break;
 
335
                case 0x1005:
 
336
                        lxvpd_parse_1005_map(phb, sm + 1, sm_sz - 1, slot_size);
 
337
                        found = true;
 
338
                        break;
 
339
                        /* Add support for 0x1006 maps ... */
 
340
                }
 
341
 
 
342
                pr_rec = sm + sm_sz;
 
343
        }
 
344
}
 
345
 
 
346
void lxvpd_add_slot_properties(struct pci_slot *slot,
 
347
                               struct dt_node *np)
 
348
{
 
349
        struct phb *phb = slot->phb;
 
350
        struct lxvpd_pci_slot *s = slot->data;
 
351
        char loc_code[LOC_CODE_SIZE];
 
352
        size_t base_loc_code_len, slot_label_len;
 
353
 
 
354
        /* Check if we have platform specific slot */
 
355
        if (!s || !np)
 
356
                return;
 
357
 
 
358
        /* Check PHB base location code */
 
359
        if (!phb->base_loc_code)
 
360
                return;
 
361
 
 
362
        /* Check location length is valid */
 
363
        base_loc_code_len = strlen(phb->base_loc_code);
 
364
        slot_label_len = strlen(s->label);
 
365
        if ((base_loc_code_len + slot_label_len + 1) >= LOC_CODE_SIZE)
 
366
                return;
 
367
 
 
368
        /* Location code */
 
369
        strcpy(loc_code, phb->base_loc_code);
 
370
        strcat(loc_code, "-");
 
371
        strcat(loc_code, s->label);
 
372
        dt_add_property(np, "ibm,slot-location-code",
 
373
                        loc_code, strlen(loc_code) + 1);
 
374
        dt_add_property_string(np, "ibm,slot-label",
 
375
                               s->label);
 
376
}