1/* 2 * Copyright (c) 2014, ETH Zurich. All rights reserved. 3 * 4 * This file is distributed under the terms in the attached LICENSE file. 5 * If you do not find this file, copies can be found by writing to: 6 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group. 7 */ 8/* 9 * 10 * 11 */ 12#include <stdio.h> 13#include <string.h> 14 15#include <barrelfish/barrelfish.h> 16 17#include <pci/devids.h> 18 19#include <dma/dma.h> 20#include <dma/dma_device.h> 21#include <dma/dma_service.h> 22#include <dma/dma_manager_client.h> 23#include <dma/ioat/ioat_dma.h> 24#include <dma/dma_bench.h> 25#include "device.h" 26#include "dma_service.h" 27#include "debug.h" 28 29#include <barrelfish/waitset.h> 30#include <pci/pci_types.h> 31 32#define IOAT_BENCHMARK_CORE 20 33 34#define IOAT_IDLE_COUNTER 0xFFF 35 36static struct dma_service_cb dma_svc_cb = { 37 .connect = dma_svc_connect_cb, 38 .addregion = dma_svc_addregion_cb, 39 .removeregion = dma_svc_removeregion_cb, 40 .memcpy = dma_svc_memcpy_cb 41}; 42 43#if 0 44#define BUFFER_SIZE (1<<22) 45 46static void impl_test_cb(errval_t err, ioat_dma_req_id_t id, void *arg) 47{ 48 debug_printf("impl_test_cb\n"); 49 assert(memcmp(arg, arg + BUFFER_SIZE, BUFFER_SIZE) == 0); 50 debug_printf("test ok\n"); 51} 52 53static void impl_test(void) 54{ 55 errval_t err; 56 57 debug_printf("Doing an implementation test\n"); 58 59 struct capref frame; 60 err = frame_alloc(&frame, 2 * BUFFER_SIZE, NULL); 61 assert(err_is_ok(err)); 62 63 struct frame_identity id; 64 err = invoke_frame_identify(frame, &id); 65 assert(err_is_ok(err)); 66 67 void *buf; 68 err = vspace_map_one_frame(&buf, 1UL << id.bits, frame, NULL, NULL); 69 assert(err_is_ok(err)); 70 71 memset(buf, 0, 1UL << id.bits); 72 memset(buf, 0xA5, BUFFER_SIZE); 73 74 struct ioat_dma_req_setup setup = { 75 .type = IOAT_DMA_REQ_TYPE_MEMCPY, 76 .src = id.base, 77 .dst = id.base + BUFFER_SIZE, 78 .bytes = BUFFER_SIZE, 79 .done_cb = impl_test_cb, 80 .arg = buf 81 }; 82 int reps = 10; 83 do { 84 debug_printf("!!!!!! NEW ROUND\n"); 85 err = ioat_dma_request_memcpy(dma_ctrl.devices, &setup); 86 assert(err_is_ok(err)); 87 88 uint32_t i = 10; 89 while(i--) { 90 ioat_dma_device_poll_channels(dma_ctrl.devices); 91 } 92 }while(reps--); 93} 94#endif 95 96int main(int argc, 97 char *argv[]) 98{ 99 errval_t err; 100 101 debug_printf("I/O AT DMA driver started\n"); 102 103 /* 104 * Parsing of cmdline arguments. 105 * 106 * When started by Kaluga, the last element of the cmdline will contain 107 * the basic PCI information of the device. 108 * VENDORID:DEVICEID:BUS:DEV:FUN 109 */ 110 uint32_t vendor_id, device_id; 111 112 struct pci_addr addr = { 113 .bus = 0, 114 .device = 0, 115 .function = 0 116 }; 117 118 enum device_type devtype = IOAT_DEVICE_INVAL; 119 120 if (argc > 1) { 121 uint32_t parsed = sscanf(argv[argc - 1], 122 "%x:%x:%"SCNx32":%"SCNx32":%"SCNx32, &vendor_id, &device_id, 123 &addr.bus, &addr.device, &addr.function); 124 if (parsed != 5) { 125 DEBUGPRINT("WARNING: cmdline parsing failed. Using PCI Address [0,0,0]"); 126 } else { 127 if (vendor_id != 0x8086) { 128 USER_PANIC("unexpected vendor [%x]", vendor_id); 129 } 130 switch ((device_id & 0xFFF0)) { 131 case PCI_DEVICE_IOAT_IVB0: 132 devtype = IOAT_DEVICE_IVB; 133 break; 134 case PCI_DEVICE_IOAT_HSW0: 135 devtype = IOAT_DEVICE_HSW; 136 break; 137 default: 138 USER_PANIC("unexpected device [%x]", device_id) 139 ; 140 break; 141 } 142 143 DEBUGPRINT("Initializing I/O AT DMA device with PCI address [%u,%u,%u]\n", 144 addr.bus, addr.device, addr.function); 145 } 146 } else { 147 DEBUGPRINT("WARNING: Initializing I/O AT DMA device with unknown PCI address " 148 "[0,0,0]\n"); 149 } 150 151 err = ioat_device_discovery(addr, devtype, IOAT_DMA_OPERATION); 152 if (err_is_fail(err)) { 153 USER_PANIC_ERR(err, "DMA Device discovery failed"); 154 } 155 156#if DMA_BENCH_RUN_BENCHMARK 157 if (disp_get_core_id() < IOAT_BENCHMARK_CORE) { 158 struct ioat_dma_device *dev = ioat_device_get_next(); 159 dma_bench_run_default((struct dma_device *)dev); 160 } 161#endif 162 163#if IOAT_DMA_OPERATION == IOAT_DMA_OPERATION_SERVICE 164 165 iref_t svc_iref; 166 char svc_name[30]; 167 uint8_t numa_node = (disp_get_core_id() >= 20); 168 snprintf(svc_name, 30, "%s.%u", IOAT_DMA_SERVICE_NAME, numa_node); 169 err = dma_service_init_with_name(svc_name, &dma_svc_cb, NULL, &svc_iref); 170 if (err_is_fail(err)) { 171 USER_PANIC_ERR(err, "Failed to start the DMA service"); 172 } 173 174 err = dma_manager_register_driver(0, 1ULL << 40, DMA_DEV_TYPE_IOAT, svc_iref); 175 if (err_is_fail(err)) { 176 USER_PANIC_ERR(err, "Failed to register with the DMA manager\n"); 177 } 178 179 DEBUGPRINT("Driver registered with DMA manager. Serving requests now.\n"); 180 181#endif 182 183#if IOAT_DMA_OPERATION == IOAT_DMA_OPERATION_LIBRARY 184 185#endif 186 187 uint32_t idle_counter = IOAT_IDLE_COUNTER; 188 while (1) { 189 uint8_t idle = 0x1; 190 err = ioat_device_poll(); 191 switch (err_no(err)) { 192 case DMA_ERR_DEVICE_IDLE: 193 break; 194 case SYS_ERR_OK: 195 idle = 0; 196 break; 197 default: 198 debug_printf("I/O AT DMA driver terminated: in poll, %s\n", 199 err_getstring(err)); 200 return err; 201 } 202 err = event_dispatch_non_block(get_default_waitset()); 203 switch (err_no(err)) { 204 case SYS_ERR_OK: 205 idle = 0; 206 break; 207 case LIB_ERR_NO_EVENT: 208 break; 209 default: 210 debug_printf("I/O AT DMA driver terminated in dispatch, %s\n", 211 err_getstring(err)); 212 return err; 213 } 214 if (idle) { 215 idle_counter--; 216 if (idle_counter == 0) { 217 thread_yield(); 218 idle_counter = IOAT_IDLE_COUNTER; 219 } 220 } else { 221 idle_counter = IOAT_IDLE_COUNTER; 222 } 223 } 224 225 debug_printf("I/O AT DMA driver terminated"); 226 227 return 0; 228} 229 230