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