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 <stdio.h>
16#include <string.h>
17#include <barrelfish/barrelfish.h>
18#include <pci/pci.h>
19
20#include "xeon_phi_internal.h"
21#include "interrupts.h"
22
23xeon_phi_irq_t irq_registers;
24
25/**
26 * \brief Initializes the MSI-X Interrupt allocator
27 *
28 * \param alloc pointer to the allocator state struct
29 * \param n     number of vectors to track
30 *
31 * \return true on SUCCESS, false on FAILURE
32 */
33bool msix_allocator_init(struct msix_allocator *alloc, size_t n)
34{
35    alloc->count = n;
36    alloc->state = calloc((n + MSIX_ALLOCATOR_BITS -1 ) / MSIX_ALLOCATOR_BITS,
37                          MSIX_ALLOCATOR_BITS / 8);
38    return (alloc->state != NULL);
39}
40
41
42/**
43 * \brief Destroys a previously allocated MSI-X Interrupt allocator
44 *
45 * \param alloc the allocator to destroy
46 */
47void msix_allocator_destory(struct msix_allocator *alloc)
48{
49    if (alloc->state) {
50        free(alloc->state);
51    }
52    alloc->state = NULL;
53    alloc->count = 0;
54}
55
56/**
57 * \brief Allocates a new MSI-X vector ID
58 *
59 * \param alloc  pointer to the allocator state struct
60 * \param ret_id returned MSI-X vector ID
61 *
62 * \return true on SUCCESS, false on FAILURE (no more vectors left)
63 */
64bool msix_allocator_new(struct msix_allocator *alloc, size_t *ret_id)
65{
66    size_t chunks = (alloc->count + MSIX_ALLOCATOR_BITS - 1) / MSIX_ALLOCATOR_BITS;
67
68    for (uint32_t i = 0; i < chunks; i++) {
69        if (alloc->state[i] != 0xFF) {
70
71            uint32_t idx = 0;
72            for (uint32_t j = i * MSIX_ALLOCATOR_BITS;  j < (i+1) * MSIX_ALLOCATOR_BITS; ++j) {
73                if (!(j < alloc->count)) {
74                    return false;
75                }
76
77                if (!(alloc->state[i] & (0x1 << idx))) {
78                    alloc->state[i] |= (0x1 << idx);
79                    *ret_id = j;
80                    return true;
81                }
82                idx++;
83            }
84        }
85    }
86    return false;
87}
88
89
90/**
91 * \brief Frees a previously allocated id
92 *
93 * \param alloc pointer to the allocator state struct
94 * \param n     number of vectors to track
95 *
96 * \return true on if it was previously allocated, false on if not
97 */
98bool msix_allocator_free(struct msix_allocator *alloc, size_t id)
99{
100    bool result;
101
102    if (id >= alloc->count) {
103        return false;
104    }
105
106    size_t chunk = (id  / MSIX_ALLOCATOR_BITS);
107    size_t shift = id - (chunk * MSIX_ALLOCATOR_BITS);
108    result = alloc->state[chunk] & (0x1 << shift);
109    alloc->state[chunk] &= ~(0x1 << shift);
110
111    return result;
112
113}
114
115/**
116 * \brief enables the MSI-X Interrupts
117 *
118 * \param phi   the xeon phi device data structure
119 *
120 * \return SYS_ERR_OK on success
121 */
122errval_t msix_enable(struct xeon_phi *phi)
123{
124    errval_t err;
125
126    if (!phi->irq->msix_enabled) {
127        return SYS_ERR_OK;
128    }
129    err = pci_msix_enable(&phi->irq->msix_count);
130    if (err_is_fail(err)) {
131        return err;
132    }
133
134    if (!msix_allocator_init(&phi->irq->msix_alloc, phi->irq->msix_count)) {
135        return LIB_ERR_MALLOC_FAIL;
136    }
137
138    // Only support single MSI interrupt for now
139    xeon_phi_irq_msi_vector_t val = xeon_phi_irq_msi_vector_default;
140    val = xeon_phi_irq_msi_vector_dbr_insert(val, xeon_phi_irq_dbr_enable_all);
141    val = xeon_phi_irq_msi_vector_dma_insert(val, xeon_phi_irq_dma_enable_all);
142    xeon_phi_irq_msi_vector_wr(&phi->irq->irq_registers, 0, val);
143
144    phi->irq->msix_enabled = 1;
145
146    return SYS_ERR_OK;
147}
148
149
150
151
152
153
154errval_t interrupts_init(struct xeon_phi *phi)
155{
156    phi->irq = calloc(1, sizeof(struct irq_info));
157    if (phi->irq == NULL) {
158        return LIB_ERR_MALLOC_FAIL;
159    }
160
161    xeon_phi_irq_initialize(&phi->irq->irq_registers, XEON_PHI_MMIO_TO_SBOX(phi));
162
163    return SYS_ERR_OK;
164}
165
166void interrupt_handler(void* arg)
167{
168
169}
170
171