1/** 2 * \file 3 * \brief Driver module example template. 4 * 5 * In summary, every driver (struct bfdriver) shall implement the five 6 * life-cycle functions init/set_sleep_level/attach/detach/destroy 7 * (along with additional IRQ handler functions etc.). 8 * 9 * A driver module is linked with a driver domain (see main.c in this directory). 10 * At runtime, a driver domain will instantiate a driver instance (struct bfdriver_instance) 11 * of a given module (or class if you want) using the `init` function. During the lifetime 12 * of a driver instance it may be `detached` from and re-`attach`-ed to the 13 * device, set in different sleep levels, and finally it can be `destroy`-ed. 14 * 15 * For every driver instance (i.e., struct bfdriver_instance), a corresponding 16 * control interface created and exported. The interface is defined in dcontrol.if, 17 * the corresponding code is located in the driverkit library (dcontrol_service.c). 18 * 19 * \note For more information about driver domains check the main.c file in this 20 * directory. 21 */ 22/* 23 * Copyright (c) 2016, ETH Zurich. 24 * All rights reserved. 25 * 26 * This file is distributed under the terms in the attached LICENSE file. 27 * If you do not find this file, copies can be found by writing to: 28 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 29 */ 30 31#include <stdlib.h> 32#include <stdio.h> 33#include <string.h> 34#include <assert.h> 35 36#include <barrelfish/barrelfish.h> 37#include <driverkit/driverkit.h> 38#include <driverkit/iommu.h> 39#include <driverkit/hwmodel.h> 40 41#include <xeon_phi/xeon_phi.h> 42#include <xeon_phi/xeon_phi_manager_client.h> 43 44#include <skb/skb.h> 45 46#include "xeon_phi_internal.h" 47#include "smpt.h" 48#include "dma_service.h" 49#include "service.h" 50#include "xphi_service.h" 51#include "interphi.h" 52#include "domain.h" 53#include "sysmem_caps.h" 54 55 56 57extern uint8_t xeon_phi_dma_enabled; 58extern char *xeon_phi_mod_uri; 59extern char *xeon_phi_mod_list; 60extern struct xeon_phi *phis; 61 62bool started = false; 63uint8_t num_xphi = 0; 64 65 66static errval_t add_xeon_phi_model_nodes(int32_t nodeid, int32_t *newnodeid) { 67 HWMODEL_QUERY_DEBUG( 68 "state_get(S)," 69 "replace_with_xeon_phi(S, %"PRIi32", E1, NewS)," 70 "writeln(E1)," 71 "state_set(NewS)", 72 nodeid); 73 errval_t err = skb_execute_query( 74 "state_get(S)," 75 "replace_with_xeon_phi(S, %"PRIi32", E1, NewS)," 76 "writeln(E1)," 77 "state_set(NewS)", 78 nodeid); 79 if(err_is_fail(err)){ 80 DEBUG_SKB_ERR(err, "add_pci"); 81 return err; 82 } 83 debug_printf("[knc] Allocated model node=%s, for Xeon Phi device.\n", 84 skb_get_output()); 85 86 if(newnodeid != NULL){ 87 skb_read_output("%d", newnodeid); 88 } 89 return err; 90} 91 92 93/** 94 * Driver initialization function. This function is called by the driver domain 95 * (see also 'create_handler' in ddomain_service.c). 96 * Typically through a request from the device manager. 97 * 98 * The init function is supposed to set `dev` to the exported service iref. 99 * The init function may use `bfi->dstate` to store additional state about the device. 100 * 101 * \param[in] bfi The instance of this driver. 102 * \param[in] name The name of this driver instance. 103 * \param[in] flags Additional flags (The exact flags supported is device/driver specific). 104 * \param[in] c Capabilities (for registers etc.) as provided by the device manager. 105 * The exact layout of the `c` is device specific. 106 * \param[out] dev The service iref over which the device can be contacted. 107 * 108 * \retval SYS_ERR_OK Device initialized successfully. 109 * \retval LIB_ERR_MALLOC_FAIL Unable to allocate memory for the driver. 110 */ 111static errval_t init(struct bfdriver_instance *bfi, uint64_t flags, iref_t* dev) { 112 113 errval_t err; 114 // 1. Initialize the device: 115 116 debug_printf("[knc] attaching new co-processor\n"); 117 if (started) { 118 debug_printf("[knc] skipping initialization of second knc\n"); 119 return SYS_ERR_OK; 120 } 121#if defined(XEON_PHI_USE_HW_MODEL) 122 // TODO HW model 123 started = true; 124#endif 125 126 /* allocate the Xeon Phi state */ 127 struct xeon_phi *xphi = calloc(1, sizeof(*xphi)); 128 if (xphi == NULL) { 129 return LIB_ERR_MALLOC_FAIL; 130 } 131 xphi->id = num_xphi; 132 num_xphi++; 133 134 struct capref iommuep; 135 136 if (driverkit_iommu_present(xphi->iommu_client)) { 137 err = driverkit_get_iommu_cap(bfi, &iommuep); 138 if (err_is_fail(err)) { 139 goto err_out; 140 } 141 142 err = driverkit_iommu_client_init_cl(iommuep, &xphi->iommu_client); 143 if (err_is_fail(err)) { 144 goto err_out; 145 } 146 147 int32_t init_nodeid = driverkit_iommu_get_nodeid(xphi->iommu_client); 148 debug_printf("[knc] adding xeon phi model nodes...\n"); 149 err = add_xeon_phi_model_nodes(init_nodeid, &xphi->nodeid); 150 debug_printf("[knc] addded xeon phi model nodes: init_nodeid=%"PRIi32", xphi nodeid=%"PRIi32"\n", 151 init_nodeid, xphi->nodeid); 152 if (err_is_fail(err)) { 153 DEBUG_ERR(err, "add model nodes"); 154 goto err_out2; 155 } 156 } else { 157 xphi->iommu_client = NULL; 158 } 159 debug_printf("[knc] iommu is %s.\n", 160 driverkit_iommu_present(xphi->iommu_client) ? "on" : "off"); 161 162 /* set the client flag to false */ 163 xphi->is_client = XEON_PHI_IS_CLIENT; 164 xphi->state = XEON_PHI_STATE_NULL; 165 166 debug_printf("[knc] obtaining the bar caps.\n"); 167 168 struct capref mmio; 169 err = driverkit_get_bar_cap(bfi, 1, &mmio); 170 if (err_is_fail(err)) { 171 goto err_out2; 172 } 173 174 struct capref apt; 175 err = driverkit_get_bar_cap(bfi, 0, &apt); 176 if (err_is_fail(err)) { 177 goto err_out2; 178 } 179 180 debug_printf("[knc] initialize the xeon phi\n"); 181 182 err = xeon_phi_init(xphi, mmio, apt); 183 if (err_is_fail(err)) { 184 DEBUG_ERR(err, "could not do the card initialization\n"); 185 goto err_out2; 186 } 187 188 debug_printf("[knc] booting it.\n"); 189 190 err = xeon_phi_boot(xphi, xeon_phi_mod_uri, xeon_phi_mod_list); 191 if (err_is_fail(err)) { 192 DEBUG_ERR(err, "could not boot the card\n"); 193 goto err_out2; 194 } 195 196#if 0 197 err = service_init(xphi); 198 if (err_is_fail(err)) { 199 USER_PANIC_ERR(err, "could not start the driver service\n"); 200 } 201 202 uint8_t num; 203 iref_t *irefs; 204 err = xeon_phi_manager_client_register(xphi.iref, &xphi.id, &num, &irefs); 205 if (err_is_fail(err)) { 206 USER_PANIC_ERR(err, "could not register with the Xeon Phi manager\n"); 207 } 208 209#endif 210 211 debug_printf("[knc] waiting for the client to connect"); 212 interphi_wait_for_client(xphi); 213 214#if 0 215 err = service_register(&xphi, irefs, num); 216 if (err_is_fail(err)) { 217 USER_PANIC_ERR(err, "could not register with the other drivers"); 218 } 219 220#endif 221 222 err = xdma_service_init(xphi); 223 if (err_is_fail(err)) { 224 USER_PANIC_ERR(err, "could not initialize the DMA engine\n"); 225 } 226 227 err = xeon_phi_service_init(xphi); 228 if (err_is_fail(err)) { 229 USER_PANIC_ERR(err, "could not initialize the messaging service"); 230 } 231 232 #if 0 233 /* 234 * in case there are more than one Xeon Phi present in the system, indicated 235 * by an id > 0, the driver will register itself with the other Xeon Phi 236 * driver instances running in the system and initializes the inter-Phi 237 * messaging frame 238 */ 239 if (xphi.id != 0) { 240 XDEBUG("Doing Intra Xeon Phi setup with %u other instances\n", xphi.id); 241 for (uint32_t i = 0; i < xphi.id; ++i) { 242 /* initialize the messaging frame */ 243 err = interphi_init_xphi(i, &xphi, NULL_CAP, XEON_PHI_IS_CLIENT); 244 if (err_is_fail(err)) { 245 XDEBUG("Could not initialize messaging\n"); 246 continue; 247 } 248 } 249 } 250 #endif 251 252 char buf[20]; 253 snprintf(buf, 20, "xeon_phi.%u.ready", xphi->id); 254 255 XDEBUG("registering ready\n"); 256 err = domain_register(buf, 0xcafebabe); 257 assert(err_is_ok(err)); 258 259 /* signal for the test */ 260 debug_printf("Xeon Phi operational: %s\n", buf); 261 262 263 // 2. Export service to talk to the device: 264 265 // 3. Set iref of your exported service (this is reported back to Kaluga) 266 *dev = 0x0; 267 268 struct xeon_phi *tmp = phis; 269 if (phis == NULL) { 270 phis = xphi; 271 } else { 272 while(tmp->next != NULL) { 273 tmp = tmp->next; 274 } 275 tmp->next = xphi; 276 } 277 278 XDEBUG("initialization done. \n"); 279 return SYS_ERR_OK; 280err_out2: 281 driverkit_iommu_client_disconnect_cl(xphi->iommu_client); 282err_out: 283 free(xphi); 284 return err; 285} 286 287/** 288 * Instructs driver to attach to the device. 289 * This function is only called if the driver has previously detached 290 * from the device (see also detach). 291 * 292 * \note After detachment the driver can not assume anything about the 293 * configuration of the device. 294 * 295 * \param[in] bfi The instance of this driver. 296 * \retval SYS_ERR_OK Device initialized successfully. 297 */ 298static errval_t attach(struct bfdriver_instance* bfi) { 299 300 return SYS_ERR_OK; 301} 302 303/** 304 * Instructs driver to detach from the device. 305 * The driver must yield any control over to the device after this function returns. 306 * The device may be left in any state. 307 * 308 * \param[in] bfi The instance of this driver. 309 * \retval SYS_ERR_OK Device initialized successfully. 310 */ 311static errval_t detach(struct bfdriver_instance* bfi) { 312 313 return SYS_ERR_OK; 314} 315 316/** 317 * Instructs the driver to go in a particular sleep state. 318 * Supported states are platform/device specific. 319 * 320 * \param[in] bfi The instance of this driver. 321 * \retval SYS_ERR_OK Device initialized successfully. 322 */ 323static errval_t set_sleep_level(struct bfdriver_instance* bfi, uint32_t level) { 324 325 return SYS_ERR_OK; 326} 327 328/** 329 * Destroys this driver instance. The driver will yield any 330 * control over the device and free any state allocated. 331 * 332 * \param[in] bfi The instance of this driver. 333 * \retval SYS_ERR_OK Device initialized successfully. 334 */ 335static errval_t destroy(struct bfdriver_instance* bfi) { 336 337 // XXX: Tear-down the service 338 bfi->device = 0x0; 339 340 return SYS_ERR_OK; 341} 342 343static errval_t get_ep(struct bfdriver_instance* bfi, bool lmp, struct capref* ret_cap) 344{ 345 return SYS_ERR_OK; 346} 347 348/** 349 * Registers the driver module with the system. 350 * 351 * To link this particular module in your driver domain, 352 * add it to the addModules list in the Hakefile. 353 */ 354DEFINE_MODULE(knc_module, init, attach, detach, set_sleep_level, destroy, get_ep); 355