Added: Xeon Phi Manager
[barrelfish] / usr / drivers / xeon_phi / xeon_phi.c
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.h"
23 #include "interrupts.h"
24 #include "sleep.h"
25 #include "dma.h"
26
27 static uint32_t initialized = 0;
28
29 #define XEON_PHI_RESET_TIME 300
30
31 static struct xeon_phi *card;
32
33 static uint32_t pci_bus = PCI_DONT_CARE;
34 static uint32_t pci_device = PCI_DONT_CARE;
35 static uint32_t pci_function = PCI_DONT_CARE;
36
37 /// PCI Vendor ID of Intel
38 #define PCI_VENDOR_ID_INTEL     0x8086
39
40 #define PCI_SUBSYSTEM_DEVICE    0x2500
41
42 #define PCI_SUBSYSTEM_VENDOR    0x8086
43 /*
44  * These are the possible device IDs of the Xeon PHi according to the
45  * Intel MPSS implementation.
46  *
47  * Querying the host with lspci -nn | grep "8086:225" gives the actual
48  * device ID of the built in cards to be the last one.
49  *
50  * 07:00.0 Co-processor [0b40]: Intel Corporation Device [8086:225e] (rev 11)
51  * 82:00.0 Co-processor [0b40]: Intel Corporation Device [8086:225e] (rev 11)
52  */
53 #define PCI_DEVICE_KNC_2250 0x2250
54 #define PCI_DEVICE_KNC_2251 0x2251
55 #define PCI_DEVICE_KNC_2252 0x2252
56 #define PCI_DEVICE_KNC_2253 0x2253
57 #define PCI_DEVICE_KNC_2254 0x2254
58 #define PCI_DEVICE_KNC_2255 0x2255
59 #define PCI_DEVICE_KNC_2256 0x2256
60 #define PCI_DEVICE_KNC_2257 0x2257
61 #define PCI_DEVICE_KNC_2258 0x2258
62 #define PCI_DEVICE_KNC_2259 0x2259
63 #define PCI_DEVICE_KNC_225a 0x225a
64 #define PCI_DEVICE_KNC_225b 0x225b
65 #define PCI_DEVICE_KNC_225c 0x225c
66 #define PCI_DEVICE_KNC_225d 0x225d
67 #define PCI_DEVICE_KNC_225e 0x225e
68
69 #define XEON_PHI_APT_BAR 0
70 #define XEON_PHI_MMIO_BAR 4
71
72 static void device_init(struct xeon_phi *phi)
73 {
74
75 #if 0
76     scratch13 = SBOX_READ(mic_ctx->mmio.va, SBOX_SCRATCH13);
77     mic_ctx->bi_stepping = SCRATCH13_STEP_ID(scratch13);
78     mic_ctx->bi_substepping = SCRATCH13_SUB_STEP(scratch13);
79 #ifdef MIC_IS_EMULATION
80     mic_ctx->bi_platform = PLATFORM_EMULATOR;
81 #else
82     mic_ctx->bi_platform = SCRATCH13_PLATFORM_ID(scratch13);
83 #endif
84     mic_enable_msi_interrupts(mic_ctx);
85     mic_enable_interrupts(mic_ctx);
86
87     mic_reg_irqhandler(mic_ctx, 1, "MIC SHUTDOWN DoorBell 1",
88                     mic_shutdown_host_doorbell_intr_handler);
89
90 #endif
91
92     initialized = true;
93 }
94
95 static void pci_init_card(struct device_mem* bar_info,
96                           int bar_count)
97 {
98     errval_t err;
99
100     if (initialized) {
101         debug_printf("WARNING> Device already initialized\n");
102         return;
103     }
104
105     // ok may be 5
106     if (bar_count != 5) {
107         USER_PANIC("There is something wrong. The Card should have 2 MBARs.");
108     }
109
110     err = map_device(&bar_info[XEON_PHI_APT_BAR]);
111     if (err_is_fail(err)) {
112         USER_PANIC_ERR(err, "Failed to map aperture range");
113     }
114
115     err = map_device(&bar_info[XEON_PHI_MMIO_BAR]);
116     if (err_is_fail(err)) {
117         USER_PANIC_ERR(err, "Failed to map MMIO range");
118     }
119
120     card->apt.vbase = (lvaddr_t) bar_info[XEON_PHI_APT_BAR].vaddr;
121     card->apt.length = bar_info[XEON_PHI_APT_BAR].bytes;
122     card->apt.pbase = (lpaddr_t) bar_info[XEON_PHI_APT_BAR].paddr;
123     card->mmio.vbase = (lvaddr_t) bar_info[XEON_PHI_MMIO_BAR].vaddr;
124     card->mmio.length = bar_info[XEON_PHI_MMIO_BAR].bytes;
125     card->mmio.pbase = (lpaddr_t) bar_info[XEON_PHI_MMIO_BAR].paddr;
126
127     card->state = XEON_PHI_STATE_PCI_OK;
128 }
129
130 static void pci_register(struct xeon_phi *phi)
131 {
132     errval_t err;
133
134     err = pci_client_connect();
135     if (err_is_fail(err)) {
136         USER_PANIC_ERR(err, "Could not connect to PCI\n");
137     }
138
139     err = pci_register_driver_irq(pci_init_card,
140                                   PCI_DONT_CARE,
141                                   PCI_DONT_CARE,
142                                   PCI_DONT_CARE,
143                                   PCI_VENDOR_ID_INTEL,
144                                   PCI_DEVICE_KNC_225e,
145                                   pci_bus,
146                                   pci_device,
147                                   pci_function,
148                                   interrupt_handler,
149                                   phi);
150
151     if (err_is_fail(err)) {
152         USER_PANIC_ERR(err, "Could not register the PCI device");
153     }
154 }
155
156 /**
157  * \brief initializes the coprocessor card
158  *
159  * \param phi pointer to the information structure
160  */
161 errval_t xeon_phi_init(struct xeon_phi *phi)
162 {
163     card = phi;
164
165     pci_register(phi);
166
167     xeon_phi_reset(phi);
168
169     interrupts_init(phi);
170
171     device_init(phi);
172
173     dma_init(phi);
174
175     return SYS_ERR_OK;
176 }
177
178 /**
179  * \brief performs a soft reset of the card
180  *
181  * \param phi   pointer to the card information
182  */
183 errval_t xeon_phi_reset(struct xeon_phi *phi)
184 {
185     if (phi->state == XEON_PHI_STATE_NULL) {
186         return SYS_ERR_ILLEGAL_INVOCATION;
187     }
188
189     phi->state = XEON_PHI_STATE_RESET;
190
191     xeon_phi_boot_t boot_registers;
192
193     xeon_phi_boot_initialize(&boot_registers,
194                              XEON_PHI_MMIO_TO_SBOX(phi),
195                              XEON_PHI_MMIO_TO_DBOX(phi));
196
197     // clearing the download status register before rest.
198     xeon_phi_boot_download_wr(&boot_registers, 0x0);
199
200     // perform the actual reset sequence
201     xeon_phi_boot_reset_t res = xeon_phi_boot_reset_rd(&boot_registers);
202     res = xeon_phi_boot_reset_reset_insert(res, 0x1);
203     xeon_phi_boot_reset_wr(&boot_registers, res);
204
205     // wait a bit to prevent potential problems
206     milli_sleep(1000);
207
208     xeon_phi_boot_postcode_t postcode;
209     xeon_phi_boot_postcodes_t pc;
210     for (uint32_t time = 0; time < XEON_PHI_RESET_TIME; ++time) {
211         postcode = xeon_phi_boot_postcode_rd(&boot_registers);
212         pc = xeon_phi_boot_postcode_code_extract(postcode);
213         debug_printf("Resetting; %s\n", xeon_phi_boot_postcodes_describe(pc));
214         XBOOT_DEBUG("Resetting (Post Code %c%c)\n",
215                     xeon_phi_boot_postcode_raw_code0_extract(postcode),
216                     xeon_phi_boot_postcode_raw_code1_extract(postcode));
217
218         if (postcode == xeon_phi_boot_postcode_invalid || postcode
219                         == xeon_phi_boot_postcode_fatal
220             || pc == xeon_phi_boot_postcode_memtf
221             || pc == xeon_phi_boot_postcode_mempf) {
222             break;
223         }
224
225         if (xeon_phi_boot_download_status_rdf(&boot_registers)) {
226             phi->state = XEON_PHI_STATE_READY;
227             debug_printf("Reset successful\n");
228             /*
229              * XXX; Maybe we should re-enable the IRQ if they were enabled beforehand
230              * if (mic_ctx->msie)
231              mic_enable_msi_interrupts(mic_ctx);
232              mic_enable_interrupts(mic_ctx);
233              mic_smpt_restore(mic_ctx);
234              micscif_start(mic_ctx);
235              */
236             return SYS_ERR_OK;
237         }
238
239         milli_sleep(1000);
240     }
241
242     if (phi->state != XEON_PHI_STATE_READY) {
243         debug_printf("Reset Failed; %s\n", xeon_phi_boot_postcodes_describe(pc));
244         XBOOT_DEBUG("Reset Failed (Post Code %c%c)\n",
245                     xeon_phi_boot_postcode_raw_code0_extract(postcode),
246                     xeon_phi_boot_postcode_raw_code1_extract(postcode));
247
248         return 1;
249     }
250
251     return SYS_ERR_OK;
252 }
253