1/**
2 * \file
3 * \brief Card Configuration
4 */
5
6/*
7 * Copyright (c) 2014 ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdio.h>
16#include <string.h>
17#include <barrelfish/barrelfish.h>
18#include <pci/pci.h>
19
20#include <dev/xeon_phi/xeon_phi_boot_dev.h>
21
22#include "xeon_phi_internal.h"
23#include "interrupts.h"
24#include "sleep.h"
25#include "smpt.h"
26#include "sysmem_caps.h"
27
28#define XEON_PHI_RESET_TIME 3000
29#define XEON_PHI_RESET_TIME_UNIT 100
30
31
32/// PCI Vendor ID of Intel
33#define PCI_VENDOR_ID_INTEL     0x8086
34
35#define PCI_SUBSYSTEM_DEVICE    0x2500
36
37#define PCI_SUBSYSTEM_VENDOR    0x8086
38
39/*
40 * These are the possible device IDs of the Xeon PHi according to the
41 * Intel MPSS implementation.
42 *
43 * Querying the host with lspci -nn | grep "8086:225" gives the actual
44 * device ID of the built in cards to be the last one.
45 *
46 * 07:00.0 Co-processor [0b40]: Intel Corporation Device [8086:225e] (rev 11)
47 * 82:00.0 Co-processor [0b40]: Intel Corporation Device [8086:225e] (rev 11)
48 */
49#define PCI_DEVICE_KNC_2250 0x2250
50#define PCI_DEVICE_KNC_2251 0x2251
51#define PCI_DEVICE_KNC_2252 0x2252
52#define PCI_DEVICE_KNC_2253 0x2253
53#define PCI_DEVICE_KNC_2254 0x2254
54#define PCI_DEVICE_KNC_2255 0x2255
55#define PCI_DEVICE_KNC_2256 0x2256
56#define PCI_DEVICE_KNC_2257 0x2257
57#define PCI_DEVICE_KNC_2258 0x2258
58#define PCI_DEVICE_KNC_2259 0x2259
59#define PCI_DEVICE_KNC_225a 0x225a
60#define PCI_DEVICE_KNC_225b 0x225b
61#define PCI_DEVICE_KNC_225c 0x225c
62#define PCI_DEVICE_KNC_225d 0x225d
63#define PCI_DEVICE_KNC_225e 0x225e
64
65#define XEON_PHI_APT_BAR 0
66#define XEON_PHI_MMIO_BAR 1
67#define XEON_PHI_MMIO_BAR_SIZE (128*1024)
68#define XEON_PHI_APT_BAR_SIZE (8ULL << 30)
69#define XEON_PHI_BAR_TYPE 0
70
71static void device_init(struct xeon_phi *phi)
72{
73
74#if 0
75    scratch13 = SBOX_READ(mic_ctx->mmio.va, SBOX_SCRATCH13);
76    mic_ctx->bi_stepping = SCRATCH13_STEP_ID(scratch13);
77    mic_ctx->bi_substepping = SCRATCH13_SUB_STEP(scratch13);
78#ifdef MIC_IS_EMULATION
79    mic_ctx->bi_platform = PLATFORM_EMULATOR;
80#else
81    mic_ctx->bi_platform = SCRATCH13_PLATFORM_ID(scratch13);
82#endif
83    mic_enable_msi_interrupts(mic_ctx);
84    mic_enable_interrupts(mic_ctx);
85
86    mic_reg_irqhandler(mic_ctx, 1, "MIC SHUTDOWN DoorBell 1",
87                    mic_shutdown_host_doorbell_intr_handler);
88
89#endif
90}
91
92
93#if 0
94static void pci_init_card(void *arg, struct device_mem* bar_info,
95                          int bar_count)
96{
97    errval_t err;
98
99    if (initialized) {
100        debug_printf("WARNING > Device already initialized\n");
101        return;
102    }
103
104    printf("Got: %i bars\n", bar_count);
105    for (int i = 0; i < bar_count; ++i) {
106        printf("> Bar[%i]: {type=%i, paddr=0x%lx, size=%u}\n", i, bar_info[i].type, bar_info[i].paddr, (uint32_t)(bar_info[i].bytes/1024));
107    }
108
109    if (bar_count != 2) {
110        USER_PANIC("There is something wrong. The Card should have 2 MBARs.");
111    }
112
113
114    /*
115     * TODO> install some checks that we got the correct caps
116     */
117    assert(bar_info[XEON_PHI_MMIO_BAR].bytes == XEON_PHI_MMIO_BAR_SIZE);
118    assert(bar_info[XEON_PHI_APT_BAR].bytes >= XEON_PHI_APT_BAR_SIZE);
119    assert(bar_info[XEON_PHI_MMIO_BAR].type == XEON_PHI_BAR_TYPE);
120    assert(bar_info[XEON_PHI_APT_BAR].type == XEON_PHI_BAR_TYPE);
121
122    struct frame_identity id;
123    assert(!capref_is_null(bar_info[XEON_PHI_APT_BAR].frame_cap));
124    card->apt.cap = bar_info[XEON_PHI_APT_BAR].frame_cap;
125    err = frame_identify(card->apt.cap, &id);
126    if (err_is_fail(err)) {
127        USER_PANIC_ERR(err, "failed to identify the aperture cap");
128    }
129    card->apt.length = id.bytes;
130    card->apt.pbase = id.base;
131    card->apt.bytes = bar_info[XEON_PHI_APT_BAR].bytes;
132
133    assert(!capref_is_null(bar_info[XEON_PHI_MMIO_BAR].frame_cap));
134    card->mmio.cap = bar_info[XEON_PHI_MMIO_BAR].frame_cap;
135
136    err = frame_identify(card->mmio.cap, &id);
137    if (err_is_fail(err)) {
138        USER_PANIC_ERR(err, "failed to identify the aperture cap");
139    }
140    card->mmio.length = id.bytes;
141    card->mmio.pbase = id.base;
142    card->mmio.bytes = bar_info[XEON_PHI_MMIO_BAR].bytes;
143
144    err = xeon_phi_map_aperture(card, XEON_PHI_APERTURE_INIT_SIZE);
145    if (err_is_fail(err)) {
146        USER_PANIC_ERR(err, "Failed to map aperture range");
147    }
148
149    err = sysmem_cap_manager_init(card->apt.cap);
150    if (err_is_fail(err)) {
151        USER_PANIC_ERR(err, "could not initialize the cap manager");
152    }
153
154    err = map_device(&bar_info[XEON_PHI_MMIO_BAR]);
155    if (err_is_fail(err)) {
156        USER_PANIC_ERR(err, "Failed to map MMIO range");
157    }
158
159    card->mmio.vbase = (lvaddr_t) bar_info[XEON_PHI_MMIO_BAR].vaddr;
160    card->mmio.length = bar_info[XEON_PHI_MMIO_BAR].bytes;
161
162    card->state = XEON_PHI_STATE_PCI_OK;
163}
164
165
166static void pci_register(struct xeon_phi *phi, uint32_t bus, uint32_t dev, uint32_t fun)
167{
168    errval_t err;
169
170    err = pci_client_connect();
171    if (err_is_fail(err)) {
172        USER_PANIC_ERR(err, "Could not connect to PCI\n");
173    }
174
175    err = pci_register_driver_irq(pci_init_card, NULL,
176                                  PCI_DONT_CARE,
177                                  PCI_DONT_CARE,
178                                  PCI_DONT_CARE,
179                                  PCI_VENDOR_ID_INTEL,
180                                  PCI_DEVICE_KNC_225e,
181                                  bus,
182                                  dev,
183                                  fun,
184                                  interrupt_handler,
185                                  phi);
186
187    if (err_is_fail(err)) {
188        USER_PANIC_ERR(err, "Could not register the PCI device");
189    }
190}
191#endif
192
193
194static errval_t xeon_phi_init_with_caps(struct xeon_phi *card, struct capref mmio,
195                                        struct capref apt)
196{
197    errval_t err;
198
199    struct frame_identity id;
200    assert(!capref_is_null(apt));
201    card->apt.cap = apt;
202    err = frame_identify(card->apt.cap, &id);
203    if (err_is_fail(err)) {
204        return err_push(err, LIB_ERR_FRAME_IDENTIFY);
205    }
206
207    card->apt.pbase = id.base;
208    card->apt.bytes = id.bytes;
209
210    assert(!capref_is_null(mmio));
211    card->mmio.cap = mmio;
212
213    err = frame_identify(card->mmio.cap, &id);
214    if (err_is_fail(err)) {
215        return err_push(err, LIB_ERR_FRAME_IDENTIFY);
216    }
217
218    card->mmio.pbase = id.base;
219    card->mmio.bytes = id.bytes;
220
221
222    err = xeon_phi_map_aperture(card, XEON_PHI_APERTURE_INIT_SIZE);
223    if (err_is_fail(err)) {
224        return err;
225    }
226
227    err = sysmem_cap_manager_init(card->apt.cap);
228    if (err_is_fail(err)) {
229        return err;
230    }
231
232    err = vspace_map_one_frame_attr((void **)&card->mmio.vbase, card->mmio.bytes,
233                                    card->mmio.cap, VREGION_FLAGS_READ_WRITE_NOCACHE,
234                                    NULL, NULL);
235    if (err_is_fail(err)) {
236        return err_push(err, LIB_ERR_VSPACE_MAP);
237    }
238
239    card->state = XEON_PHI_STATE_PCI_OK;
240
241    return SYS_ERR_OK;
242}
243
244/**
245 * \brief initializes the coprocessor card
246 *
247 * \param phi pointer to the information structure
248 */
249errval_t xeon_phi_init(struct xeon_phi *phi, struct capref mmio, struct capref apt)
250{
251    errval_t err;
252
253    #if 0
254    pci_register(phi, bus,  dev,  fun);
255    #endif
256
257    err = xeon_phi_init_with_caps(phi, mmio, apt);
258    if (err_is_fail(err)) {
259        return err;
260    }
261
262    xeon_phi_reset(phi);
263
264    interrupts_init(phi);
265
266    device_init(phi);
267
268    smpt_init(phi);
269
270    xeon_phi_serial_init(phi);
271
272    return SYS_ERR_OK;
273}
274
275/**
276 * \brief performs a soft reset of the card
277 *
278 * \param phi   pointer to the card information
279 */
280errval_t xeon_phi_reset(struct xeon_phi *phi)
281{
282    if (phi->state == XEON_PHI_STATE_NULL) {
283        return SYS_ERR_ILLEGAL_INVOCATION;
284    }
285
286    phi->state = XEON_PHI_STATE_RESET;
287
288    xeon_phi_boot_t boot_registers;
289
290    xeon_phi_boot_initialize(&boot_registers,
291                             XEON_PHI_MMIO_TO_SBOX(phi),
292                             XEON_PHI_MMIO_TO_DBOX(phi));
293
294    // clearing the download status register before rest.
295    xeon_phi_boot_download_wr(&boot_registers, 0x0);
296
297    // perform the actual reset sequence
298    xeon_phi_boot_reset_t res = xeon_phi_boot_reset_rd(&boot_registers);
299    res = xeon_phi_boot_reset_reset_insert(res, 0x1);
300    xeon_phi_boot_reset_wr(&boot_registers, res);
301
302    // wait a bit to prevent potential problems
303    milli_sleep(1000);
304
305    xeon_phi_boot_postcode_t postcode;
306    xeon_phi_boot_postcodes_t pc, pc_prev = 0;
307    for (uint32_t time = 0; time < XEON_PHI_RESET_TIME; ++time) {
308        postcode = xeon_phi_boot_postcode_rd(&boot_registers);
309        pc = xeon_phi_boot_postcode_code_extract(postcode);
310        if (pc_prev != pc) {
311            debug_printf("Resetting: %s\n", xeon_phi_boot_postcodes_describe(pc));
312            }
313        if (postcode == xeon_phi_boot_postcode_invalid || postcode
314                        == xeon_phi_boot_postcode_fatal
315            || pc == xeon_phi_boot_postcode_memtf
316            || pc == xeon_phi_boot_postcode_mempf) {
317            break;
318        }
319
320        if (xeon_phi_boot_download_status_rdf(&boot_registers)) {
321            phi->state = XEON_PHI_STATE_READY;
322            debug_printf("Reset successful\n");
323            /*
324             * XXX; Maybe we should re-enable the IRQ if they were enabled beforehand
325             * if (mic_ctx->msie)
326             mic_enable_msi_interrupts(mic_ctx);
327             mic_enable_interrupts(mic_ctx);
328             mic_smpt_restore(mic_ctx);
329             micscif_start(mic_ctx);
330             */
331            return SYS_ERR_OK;
332        }
333
334        pc_prev = pc;
335        milli_sleep(XEON_PHI_RESET_TIME_UNIT);
336    }
337
338    if (phi->state != XEON_PHI_STATE_READY) {
339        debug_printf("Reset Failed; %s\n", xeon_phi_boot_postcodes_describe(pc));
340        XBOOT_DEBUG("Reset Failed (Post Code %c%c)\n",
341                    xeon_phi_boot_postcode_raw_code0_extract(postcode),
342                    xeon_phi_boot_postcode_raw_code1_extract(postcode));
343
344        return 1; // todo> error code
345    }
346
347#if 0
348#define ENABLE_MIC_INTERRUPTS(mmio) { \
349    uint32_t sboxSice0reg = SBOX_READ((mmio), SBOX_SICE0); \
350    sboxSice0reg |= SBOX_SICE0_DBR_BITS(0xf) | SBOX_SICE0_DMA_BITS(0xff); \
351    SBOX_WRITE(sboxSice0reg, (mmio), SBOX_SICE0); }
352#endif
353    return SYS_ERR_OK;
354}
355
356
357/**
358 * \brief maps the aperture memory range of the Xeon Phi into the drivers
359 *        vspace to be able to load the coprocessor OS onto the card
360 *
361 * \param phi   pointer to the Xeon Phi structure holding aperture information
362 * \param range how much bytes to map
363 *
364 * \returns SYS_ERR_OK on success
365 */
366errval_t xeon_phi_map_aperture(struct xeon_phi *phi,
367                               size_t range)
368{
369    if (phi->apt.vbase != 0) {
370        return SYS_ERR_VM_ALREADY_MAPPED;
371    }
372
373    errval_t err;
374    void *addr;
375    err = vspace_map_one_frame(&addr, range, phi->apt.cap, NULL, NULL);
376    if (err_is_fail(err)) {
377        DEBUG_ERR(err, "vspace_map_one_frame failed for the apt mbar");
378        return err_push(err, LIB_ERR_VSPACE_MAP);
379    }
380
381    phi->apt.vbase = (lvaddr_t)addr;
382
383    return SYS_ERR_OK;
384}
385
386/**
387 * \brief unmaps the previously mapped aperture range when the programming
388 *        completes.
389 *
390 * \param phi pointer to the Xeon Phi structure holiding mapping information
391 *
392 * \return SYS_ERR_OK on success
393 */
394errval_t xeon_phi_unmap_aperture(struct xeon_phi *phi)
395{
396    errval_t err;
397
398    if (phi->apt.vbase == 0) {
399        return SYS_ERR_OK;
400    }
401
402    err = vspace_unmap((void *)phi->apt.vbase);
403    if (err_is_fail(err)) {
404        DEBUG_ERR(err, "vspace_map_one_frame failed for the apt mbar");
405        return err_push(err, LIB_ERR_VSPACE_MAP);
406    }
407
408    phi->apt.vbase = 0;
409
410    return SYS_ERR_OK;
411}
412