1/** 2 * \file 3 * \brief Driver for booting the Xeon Phi Coprocessor card on a Barrelfish Host 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 <virtio/virtio.h> 16#include <virtio/virtqueue.h> 17#include <virtio/virtio_device.h> 18#include <virtio/devices/virtio_block.h> 19 20#include "device.h" 21#include "request.h" 22#include "debug.h" 23 24/** 25 * \brief handles the VirtIO config change interrupt 26 * 27 * \param pointer to the virtio device 28 * 29 * \returns SYS_ERR_OK on success 30 */ 31void vblock_device_config_changed_intr(struct virtio_device *vdev) 32{ 33 struct virtio_device_blk *bdev; 34 35 bdev = virtio_device_get_type_state(vdev); 36 if (bdev == NULL) { 37 return; 38 } 39 40 virtio_block_config_read(bdev); 41} 42 43/** 44 * \brief handles the VirtIO interrupts 45 * 46 * \param arg the argument passed to the virtqueue when allocating it 47 */ 48void vblock_device_virtqueue_intr(void *arg) 49{ 50 errval_t err; 51 52 struct vblock_device *dev = arg; 53 struct virtqueue *vq = dev->blk.vq; 54 55 bool again = true; 56 57 while (again) { 58 err = vblock_request_finish_completed(dev); 59 if (err_is_fail(err)) { 60 /*todo error recovery */ 61 } 62 63 again = !virtio_virtqueue_intr_enable(vq); 64 if (again) { 65 virtio_virtqueue_intr_disable(vq); 66 } 67 } 68} 69 70errval_t vblock_device_init(struct vblock_device *blk, 71 void *dev_regs, 72 size_t reg_size) 73{ 74 errval_t err; 75 76 VBLOCK_DEBUG_DEV("Initializing vblock device [%016lx, %lx]\n", 77 (uintptr_t )dev_regs, 78 (uint64_t )reg_size); 79 80 struct virtqueue_setup vq_setup = { 81 .name = "Request Virtqueue", 82 .vring_ndesc = 16, 83 .vring_align = 4096, 84 .intr_handler = 0, 85 .intr_arg = 0, 86 .max_indirect = 0, 87 .auto_add = 1, 88 .buffer_bits = 10, 89 .header_bits = log2ceil(sizeof(uint8_t) + sizeof(struct virtio_block_reqhdr)) 90 }; 91 92 struct virtio_device_setup setup = { 93 .dev_name = "VirtIO Block Device", 94 .backend = { 95 .type = VBLOCK_DRIVER_BACKEND, 96 .args.mmio = { 97 .dev_base = dev_regs, 98 .dev_size = reg_size 99 } 100 }, 101 .features = VBLOCK_DRIVER_FEATURES, 102 .dev_type = VIRTIO_DEVICE_TYPE_BLOCK, 103 .vq_setup = &vq_setup, 104 .vq_num = 1 105 }; 106 107 err = virtio_block_init_device(&blk->blk, &setup); 108 if (err_is_fail(err)) { 109 return err; 110 } 111 112 err = virtio_virtqueue_get_buf_alloc(blk->blk.vq, &blk->alloc); 113 assert(err_is_ok(err)); 114 115 struct capref vring_cap; 116 lpaddr_t offset; 117 virtio_buffer_alloc_get_cap(blk->alloc, &vring_cap, &offset); 118 119 120 lvaddr_t buf_start; 121 size_t size; 122 virtio_buffer_alloc_get_range(blk->alloc, &buf_start, &size); 123 124 buf_start += size; 125 offset += size; 126 127 err = virtio_buffer_alloc_init_vq(&blk->bf_header, 128 vring_cap, 129 buf_start, 130 offset, 131 sizeof(struct virtio_block_reqhdr), 132 vq_setup.vring_ndesc); 133 134 buf_start += (sizeof(struct virtio_block_reqhdr) * vq_setup.vring_ndesc); 135 offset += (sizeof(struct virtio_block_reqhdr) * vq_setup.vring_ndesc); 136 137 if (err_is_fail(err)) { 138 DEBUG_ERR(err, "failed to initiate the vbuf allocator"); 139 } 140 141 err = virtio_buffer_alloc_init_vq(&blk->bf_status, 142 vring_cap, 143 buf_start, 144 offset, 145 sizeof(uint8_t), 146 vq_setup.vring_ndesc); 147 if (err_is_fail(err)) { 148 DEBUG_ERR(err, "failed to initiate the vbuf allocator"); 149 } 150 151 err = vblock_request_queue_init(blk); 152 if (err_is_fail(err)) { 153 return err; 154 } 155 156 return SYS_ERR_OK; 157} 158