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