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