1#include <barrelfish/barrelfish.h> 2#include <assert.h> 3#include <devif/queue_interface.h> 4#include <devif/queue_interface_backend.h> 5#include <devif/backends/blk/ahci_devq.h> 6 7#include "blk_ahci.h" 8#include "ahci_dev.h" // TODO: get rid of this include 9#include "../dma_mem/dma_mem.h" 10#include "../blk_debug.h" 11 12struct ahci_queue { 13 struct devq q; 14 struct ahci_port* port; 15 struct dma_mem buffers[MAX_BUFFERS]; 16 struct dev_queue_request requests[MAX_REQUESTS]; 17}; 18 19 20static bool is_valid_buffer(struct ahci_queue* dq, size_t slot) 21{ 22 return !capref_is_null(dq->buffers[slot].frame); 23} 24 25static errval_t request_slot_alloc(struct ahci_queue* dq, size_t* slot) 26{ 27 assert(dq->port->ncs <= MAX_REQUESTS); 28 29 for (size_t i=0; i < dq->port->ncs; i++) { 30 struct dev_queue_request *dqr = &dq->requests[i]; 31 if (dqr->status == RequestStatus_Unused) { 32 dqr->status = RequestStatus_InProgress; 33 *slot = i; 34 return SYS_ERR_OK; 35 } 36 } 37 38 return DEVQ_ERR_QUEUE_FULL; 39} 40 41static errval_t get_port(struct ahci_disk* hba, size_t port_num, struct ahci_port** p) { 42 assert(hba != NULL); 43 assert(port_num < MAX_AHCI_PORTS); 44 errval_t err = SYS_ERR_OK; 45 46 struct ahci_port* port = &hba->ports[port_num]; 47 if (!port->is_initialized) { 48 return err_push(err, DEVQ_ERR_INIT_QUEUE); 49 } 50 51 *p = port; 52 return SYS_ERR_OK; 53} 54 55static errval_t init_queue(struct ahci_queue** dq) { 56 struct ahci_queue* queue = calloc(1, sizeof(struct ahci_queue)); 57 if (dq == NULL) { 58 return LIB_ERR_MALLOC_FAIL; 59 } 60 61 for (size_t i = 0; i< MAX_BUFFERS; i++) { 62 queue->buffers[i].frame = NULL_CAP; 63 } 64 65 *dq = queue; 66 return SYS_ERR_OK; 67} 68 69static bool slice_is_in_range(struct dma_mem *mem, genpaddr_t offset, size_t length) 70{ 71 // do not have to check lower bound since it is unsigned 72 bool upper_bound = (mem->bytes >= length); 73 bool upper_bound2 = (mem->paddr + offset + length) <= (mem->paddr + mem->bytes); 74 // printf("mem->paddr %lx, mem->bytes %lx, offset %lx, length %lx \n", 75 // mem->paddr, mem->bytes, offset, length); 76 return upper_bound2 && upper_bound; 77} 78 79static uint64_t flags_get_block(uint64_t flags) 80{ 81 return flags & ((1ULL<<49) - 1); 82} 83 84static bool flags_is_write(uint64_t flags) { 85 return (flags & (1ULL << 63)) > 0; 86} 87 88void ahci_interrupt_handler(void* q) 89{ 90 if (q == NULL) { 91 BLK_DEBUG("Ignored interrupt, device not yet initialized?\n"); 92 return; 93 } 94 struct ahci_queue *queue = q; 95 struct ahci_port *port = queue->port; 96 97 assert(port->interrupt != NULL); 98 port->interrupt(port, queue->requests, port->ncs); 99} 100 101static errval_t ahci_destroy(struct devq *queue) 102{ 103 // TODO: Wait for stuff to finish...! 104 105 struct ahci_queue *q = (struct ahci_queue*) queue; 106 // Clean-up memory: 107 for (size_t i = 0; i< MAX_BUFFERS; i++) { 108 dma_mem_free(&q->buffers[i]); 109 } 110 free(q); 111 return SYS_ERR_OK; 112} 113 114static errval_t ahci_enqueue(struct devq *q, 115 regionid_t region_id, 116 genoffset_t offset, 117 genoffset_t length, 118 genoffset_t valid_data, 119 genoffset_t valid_length, 120 uint64_t flags) 121{ 122 struct ahci_queue *queue = (struct ahci_queue*) q; 123 124 assert(is_valid_buffer(queue, (region_id % MAX_BUFFERS))); 125 assert(length >= 512); 126 127 struct dma_mem* mem = &queue->buffers[(region_id % MAX_BUFFERS)]; 128 129 if (!slice_is_in_range(mem, offset, length)) { 130 return DEVQ_ERR_INVALID_BUFFER_ARGS; 131 } 132 133 size_t slot = 0; 134 135 errval_t err = request_slot_alloc(queue, &slot); 136 if (err_is_fail(err)) { 137 return err; 138 } 139 140 struct dev_queue_request *dqr = &queue->requests[slot]; 141 dqr->status = RequestStatus_InProgress; 142 dqr->region_id = region_id; 143 dqr->offset = offset; 144 dqr->length = length; 145 dqr->valid_data = valid_data; 146 dqr->valid_length = valid_length; 147 dqr->command_slot = slot; 148 149 uint64_t block = flags_get_block(flags); 150 bool write = flags_is_write(flags); 151 152 err = blk_ahci_port_dma_async(queue->port, slot, block, mem->paddr+offset, 153 length, write); 154 return err; 155} 156 157static errval_t ahci_dequeue(struct devq* q, 158 regionid_t* region_id, 159 genoffset_t* offset, 160 genoffset_t* length, 161 genoffset_t* valid_data, 162 genoffset_t* valid_length, 163 uint64_t* misc_flags) 164{ 165 assert(q != NULL); 166 assert(region_id != NULL); 167 assert(offset != NULL); 168 assert(valid_data != NULL); 169 assert(valid_length != NULL); 170 assert(length != NULL); 171 172 struct ahci_queue *queue = (struct ahci_queue*) q; 173 174 for (size_t i=0; i < queue->port->ncs; i++) { 175 struct dev_queue_request *dqr = &queue->requests[i]; 176 if (dqr->status == RequestStatus_Done) { 177 *region_id = dqr->region_id; 178 *offset = dqr->offset; 179 *length = dqr->length; 180 *valid_data = dqr->valid_data; 181 *valid_length = dqr->valid_length; 182 dqr->status = RequestStatus_Unused; 183 return dqr->error; 184 } 185 } 186 187 return DEVQ_ERR_QUEUE_EMPTY; 188} 189 190static errval_t ahci_register(struct devq *q, 191 struct capref cap, 192 regionid_t region_id) 193{ 194 195 errval_t err = DEVQ_ERR_REGISTER_REGION; 196 assert(!capref_is_null(cap)); 197 struct ahci_queue *queue = (struct ahci_queue*) q; 198 199 for (size_t i=0; i<MAX_BUFFERS; i++) { 200 uint16_t slot = ((region_id+i) % MAX_BUFFERS); 201 202 if (is_valid_buffer(queue, slot)) { 203 printf("Don't overwrite existing buffer\n"); 204 continue; 205 } 206 207 queue->buffers[slot].frame = cap; 208 209 struct dma_mem* mem = &queue->buffers[slot]; 210 err = dma_mem_from_capref(cap, mem); 211 if (err_is_fail(err)) { 212 DEBUG_ERR(err, "call failed"); 213 return err_push(err, DEVQ_ERR_REGISTER_REGION); 214 } 215 return SYS_ERR_OK; 216 } 217 218 return err; 219} 220 221static errval_t ahci_deregister(struct devq *q, regionid_t region_id) 222{ 223 assert(q != NULL); 224 struct ahci_queue *queue = (struct ahci_queue*) q; 225 226 struct dma_mem* mem = &queue->buffers[(region_id % MAX_BUFFERS)]; 227 assert(!capref_is_null(mem->frame)); 228 229 return dma_mem_free(mem); 230} 231 232static errval_t ahci_notify(struct devq *q) 233{ 234 return SYS_ERR_OK; 235} 236 237static errval_t ahci_control(struct devq *q, uint64_t request, uint64_t value, 238 uint64_t *result) 239{ 240 return SYS_ERR_OK; 241} 242 243errval_t ahci_create(struct ahci_queue** q, void* st, uint64_t flags) 244{ 245 errval_t err = SYS_ERR_OK; 246 247 struct ahci_port* port = NULL; 248 err = get_port(st, flags, &port); 249 if (err_is_fail(err)) { 250 return err; 251 } 252 253 struct ahci_queue *dq; 254 err = init_queue(&dq); 255 if (err_is_fail(err)) { 256 return err; 257 } 258 259 dq->port = port; 260 261 dq->q.f.enq = ahci_enqueue; 262 dq->q.f.deq = ahci_dequeue; 263 dq->q.f.reg = ahci_register; 264 dq->q.f.dereg = ahci_deregister; 265 dq->q.f.ctrl = ahci_control; 266 dq->q.f.notify = ahci_notify; 267 dq->q.f.destroy = ahci_destroy; 268 269 err = devq_init(&dq->q, false); 270 if (err_is_fail(err)) { 271 return err; 272 } 273 274 *q = dq; 275 276 return err; 277} 278