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