1/**
2 * \file
3 * \brief IOMMU Devices
4 */
5/*
6 * Copyright (c) 2018, ETH Zurich.
7 * All rights reserved.
8 *
9 * This file is distributed under the terms in the attached LICENSE file.
10 * If you do not find this file, copies can be found by writing to:
11 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich.
12 * Attn: Systems Group.
13 */
14
15#include <stdlib.h>
16
17#include <barrelfish/barrelfish.h>
18#include <barrelfish/nameservice_client.h>
19#include <skb/skb.h>
20#include <numa.h>
21
22#include "common.h"
23#include "../intel_vtd/intel_vtd.h"
24
25///< stores the devices
26static struct iommu_device **iommu_devices[IOMMU_BUS_MAX];
27
28
29static errval_t device_put_by_pci(struct iommu_device *dev)
30{
31    assert(dev->addr.pci.segment < IOMMU_SEGMENTS_MAX);
32
33    if (iommu_devices[dev->addr.pci.bus] == NULL) {
34        iommu_devices[dev->addr.pci.bus] = calloc(IOMMU_DEVFUN_MAX,
35                                                  sizeof(void *));
36        if (iommu_devices[dev->addr.pci.bus] == NULL) {
37            return LIB_ERR_MALLOC_FAIL;
38        }
39    }
40
41    uint8_t idx = iommu_devfn_to_idx(dev->addr.pci.device,
42                                     dev->addr.pci.function);
43    if (iommu_devices[dev->addr.pci.bus][idx]) {
44        return IOMMU_ERR_DEV_USED;
45    }
46
47    iommu_devices[dev->addr.pci.bus][idx] = dev;
48
49    return SYS_ERR_OK;
50}
51
52static struct iommu_device *device_get_by_pci(uint16_t seg, uint8_t bus,
53                                              uint8_t dev, uint8_t fun)
54{
55    assert(seg < IOMMU_SEGMENTS_MAX);
56    if (iommu_devices[bus] == NULL) {
57        return NULL;
58    }
59    return iommu_devices[bus][iommu_devfn_to_idx(dev, fun)];
60}
61
62
63
64errval_t iommu_device_create_by_pci(struct iommu *iommu, uint16_t seg,
65                                    uint8_t bus, uint8_t dev, uint8_t fun,
66                                    struct iommu_device **iodev)
67{
68    errval_t err;
69
70    debug_printf("[iommu] create device by pci %u.%u.%u\n", bus, dev, fun);
71
72    struct iommu_device *device;
73
74    /*
75     * check if device already exists
76     */
77
78    device = device_get_by_pci(seg, bus, dev, fun);
79    if (device) {
80        /* XXX: should not create the same device 2*/
81        debug_printf("XXX: created the same device twice: %u.%u.%u.%u\n",
82                     seg, bus, dev, fun);
83
84        assert(!device);
85        return SYS_ERR_OK;
86    }
87
88    debug_printf("[iommu] creating hw specific device.\n");
89
90    /*
91     * call iommu specific device creation function
92     */
93    assert(iommu->f.create_device);
94    err = iommu->f.create_device(iommu, seg, bus, dev, fun, &device);
95    if (err_is_fail(err)) {
96        return err;
97    }
98
99    *iodev = device;
100
101    debug_printf("[iommu] storing device.\n");
102
103    return device_put_by_pci(device);
104}
105
106
107errval_t iommu_device_destroy(struct iommu_device *iodev)
108{
109    USER_PANIC("NYI");
110    return SYS_ERR_OK;
111}
112
113
114
115
116errval_t iommu_device_lookup_by_pci(uint16_t seg, uint8_t bus, uint8_t dev,
117                                    uint8_t fun, struct iommu_device **rdev)
118{
119    debug_printf("[iommu] lookup device by pci %u.%u.%u\n", bus, dev, fun);
120
121    struct iommu_device *d = device_get_by_pci(seg, bus, dev, fun);
122    if (d == NULL) {
123        return IOMMU_ERR_DEV_NOT_FOUND;
124    }
125
126    if (rdev) {
127        *rdev = d;
128    }
129
130    return SYS_ERR_OK;
131}
132
133
134
135
136
137//////////////// TODO Implement
138
139errval_t iommu_device_create_by_address(struct iommu *iommu, uint64_t addr,
140                                        struct iommu_device **iodev)
141{
142    USER_PANIC("[iommu] create by address NYI\n");
143
144    return LIB_ERR_NOT_IMPLEMENTED;
145}
146
147errval_t iommu_device_lookup_iommu_by_address(uint64_t address,
148                                              struct iommu ** iommu)
149{
150    USER_PANIC("[iommu] lookup iommu by address NYI\n");
151
152    return LIB_ERR_NOT_IMPLEMENTED;
153}
154
155errval_t iommu_device_lookup_by_address(uint64_t address,
156                                        struct iommu_device **rdev)
157{
158    USER_PANIC("[iommu] lookup by address NYI\n");
159
160    return LIB_ERR_NOT_IMPLEMENTED;
161}
162