1/* 2 * Copyright (c) 2007-2013 ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <stdlib.h> 11#include <stdio.h> 12#include <string.h> 13#include <barrelfish/barrelfish.h> 14 15#include <usb/usb.h> 16 17#include <usb_memory.h> 18 19#include <usb_controller.h> 20#include "usb_ehci.h" 21#include "usb_ehci_memory.h" 22 23/// which version of data structures we have to use 24static usb_ds_size_t ds_size = USB_EHCI_DS_32BIT; 25 26/* 27 * the free lists 28 */ 29static struct usb_ehci_itd *free_itd = NULL; 30static struct usb_ehci_sitd *free_sitd = NULL; 31static struct usb_ehci_qtd *free_qtd = NULL; 32static struct usb_ehci_qh *free_qh = NULL; 33 34static struct usb_page *used_pages = NULL; 35static struct usb_page *free_pages = NULL; 36 37/** 38 * \brief this function sets the used ehci data structure size 39 * to 32 bit or 64 bit 40 */ 41void usb_ehci_set_datastruct_size(usb_ds_size_t size) 42{ 43 switch (size) { 44 case USB_EHCI_DS_32BIT: 45 ds_size = size; 46 break; 47 case USB_EHCI_DS_64BIT: 48 //ds_size = size; 49 assert( !"NYI: Support of 64 bit data structures " 50 "not yet supported\n"); 51 break; 52 default: 53 debug_printf("ERROR: Unknown data structure size\n"); 54 break; 55 } 56} 57 58/* 59 * \brief prints out the sizes of the used data structures 60 */ 61void usb_ehci_print_datastruct_sizes(void) 62{ 63 printf("sizeof(struct usb_ehci_itd) = %zu\n", sizeof(struct usb_ehci_itd)); 64 printf("sizeof(struct usb_ehci_sitd) = %zu\n", sizeof(struct usb_ehci_sitd)); 65 printf("sizeof(struct usb_ehci_qh) = %zu\n", sizeof(struct usb_ehci_qh)); 66 printf("sizeof(struct usb_ehci_qtd) = %zu\n", sizeof(struct usb_ehci_qtd)); 67 printf("sizeof(struct usb_ehci_fstn) = %zu\n", sizeof(struct usb_ehci_fstn)); 68} 69 70/* 71 * \brief allocates an empty queue head descriptors without buffer pages 72 * 73 * \return pointer to a correctly aligned queue head pointer 74 */ 75struct usb_ehci_qh *usb_ehci_qh_alloc(void) 76{ 77 usb_ehci_qh_t *qh; 78 79 /* 80 * we have a free queue head left, so we can use it 81 */ 82 if (free_qh != NULL) { 83 qh = free_qh; 84 free_qh = qh->obj_next; 85 return (qh); 86 } 87 88 struct usb_page *page; 89 90 /* get a free page or allocate a new one*/ 91 if (free_pages == NULL) { 92 page = usb_mem_page_alloc(); 93 } else { 94 page = free_pages; 95 free_pages = page->next; 96 } 97 98 uint32_t size_qh = sizeof(struct usb_ehci_qh); 99 uint32_t num_qh = page->free.size / size_qh; 100 101 /* initiate the variables with the start addresses */ 102 qh = page->free.buffer; 103 usb_paddr_t qh_self = page->free.phys_addr; 104 105 for (uint32_t i = 0; i < num_qh; i++) { 106 assert(!(qh_self % USB_EHCI_QH_ALIGN)); 107 USB_DEBUG_MEM(" Allocating QH: vaddr=%p, phys=%p (%x) [%x] (%u of %u)\n", qh, 108 qh_self, qh_self % USB_EHCI_QH_ALIGN, size_qh, i, num_qh); 109 /* reset memory */ 110 memset(qh, 0, size_qh); 111 112 /* set the physical address */ 113 qh->qh_self = qh_self; 114 115 /* put it into the free list */ 116 qh->obj_next = free_qh; 117 free_qh = qh; 118 119 qh++; 120 qh_self += size_qh; 121 } 122 123 /* update free information */ 124 page->free.size -= (num_qh * size_qh); 125 page->free.buffer += (num_qh * size_qh); 126 page->free.phys_addr += (num_qh * size_qh); 127 128 /* put page into free list */ 129 page->next = used_pages; 130 used_pages = page; 131 132 /* return a fresh qh */ 133 qh = free_qh; 134 free_qh = qh->obj_next; 135 136 return (qh); 137} 138 139/** 140 * \brief frees up a queue head descriptor but keeps the associated 141 * buffer pages 142 * 143 * \param qh the queue head to be freed 144 */ 145void usb_ehci_qh_free(struct usb_ehci_qh *qh) 146{ 147 /* 148 * clear out all physical fields of this queue head 149 * and set the link address to terminated 150 */ 151 memset(qh, 0, 0x1B); 152 qh->qh_link |= USB_EHCI_LINK_TERMINATE; 153 qh->qh_alt_next_qtd |= USB_EHCI_LINK_TERMINATE; 154 qh->qh_next_qtd |= USB_EHCI_LINK_TERMINATE; 155 156 qh->bp_list[0].bp &= 0xFFFFF000; 157 qh->bp_list[1].bp &= 0xFFFFF000; 158 qh->bp_list[2].bp &= 0xFFFFF000; 159 qh->bp_list[3].bp &= 0xFFFFF000; 160 qh->bp_list[4].bp &= 0xFFFFF000; 161 162 /* 163 * clear out virtual pointers and add it to the free list 164 */ 165 qh->next = NULL; 166 qh->prev = NULL; 167 qh->obj_next = free_qh; 168 free_qh = qh; 169} 170 171struct usb_ehci_qtd *usb_ehci_qtd_alloc(void) 172{ 173 usb_ehci_qtd_t *qtd; 174 175 /* 176 * we have a free queue transfer descriptor left, so we can use it 177 */ 178 if (free_qtd != NULL) { 179 qtd = free_qtd; 180 free_qtd = qtd->obj_next; 181 return (qtd); 182 } 183 184 /* 185 * we have to populate our free queue element transfer descriptor 186 */ 187 struct usb_page *page; 188 189 if (free_pages == NULL) { 190 page = usb_mem_page_alloc(); 191 } else { 192 page = free_pages; 193 free_pages = page->next; 194 } 195 196 uint32_t size_qtd = sizeof(struct usb_ehci_qtd); 197 uint32_t num_qtd = page->free.size / size_qtd; 198 199 qtd = page->free.buffer; 200 usb_paddr_t qtd_self = page->free.phys_addr; 201 202 for (uint32_t i = 0; i < num_qtd; i++) { 203 assert(!(qtd_self % USB_EHCI_QTD_ALIGN)); 204 USB_DEBUG_MEM(" Allocating QTD: vaddr=%p, phys=%p (%x) [%x]\n", qtd, 205 qtd_self, qtd_self % USB_EHCI_QTD_ALIGN, size_qtd); 206 memset(qtd, 0, size_qtd); 207 qtd->qtd_self = qtd_self; 208 qtd->obj_next = free_qtd; 209 free_qtd = qtd; 210 211 qtd++; 212 qtd_self += size_qtd; 213 } 214 215 page->free.size -= (num_qtd * size_qtd); 216 page->free.buffer += (num_qtd * size_qtd); 217 page->free.phys_addr += (num_qtd * size_qtd); 218 219 page->next = used_pages; 220 used_pages = page; 221 222 qtd = free_qtd; 223 free_qtd = qtd->obj_next; 224 225 return (qtd); 226 227} 228 229void usb_ehci_qtd_free(struct usb_ehci_qtd *qtd) 230{ 231 /* 232 * clear out all physical fields except the buffer pointers 233 */ 234 memset(qtd, 0, 0xB); 235 qtd->qtd_alt_next |= USB_EHCI_LINK_TERMINATE; 236 qtd->qtd_next |= USB_EHCI_LINK_TERMINATE; 237 qtd->qtd_bp[0].address &= 0xFFFFF000; 238 qtd->qtd_bp[1].address &= 0xFFFFF000; 239 qtd->qtd_bp[2].address &= 0xFFFFF000; 240 qtd->qtd_bp[3].address &= 0xFFFFF000; 241 qtd->qtd_bp[4].address &= 0xFFFFF000; 242 243 /* 244 * clear out all virtual information 245 */ 246 qtd->len = 0; 247 qtd->alt_next = NULL; 248 249 qtd->obj_next = free_qtd; 250 free_qtd = qtd; 251} 252 253struct usb_ehci_sitd *usb_ehci_sitd_alloc(void) 254{ 255 usb_ehci_sitd_t *sitd; 256 257 /* 258 * we have a free queue transfer descriptor left, so we can use it 259 */ 260 if (free_sitd != NULL) { 261 sitd = free_sitd; 262 free_sitd = sitd->obj_next; 263 return (sitd); 264 } 265 266 /* 267 * we have to populate our free queue element transfer descriptor 268 */ 269 struct usb_page *page; 270 271 if (free_pages == NULL) { 272 page = usb_mem_page_alloc(); 273 } else { 274 page = free_pages; 275 free_pages = page->next; 276 } 277 278 uint32_t size_sitd = sizeof(struct usb_ehci_sitd); 279 uint32_t num_sitd = page->free.size / size_sitd; 280 281 sitd = page->free.buffer; 282 usb_paddr_t sitd_self = page->free.phys_addr; 283 284 for (uint32_t i = 0; i < num_sitd; i++) { 285 assert(!(sitd_self % USB_EHCI_SITD_ALIGN)); 286 USB_DEBUG_MEM(" Allocating SITD: vaddr=%p, phys=%p (%x) [%x]\n", sitd, 287 sitd_self, sitd_self % USB_EHCI_SITD_ALIGN, size_sitd); 288 memset(sitd, 0, size_sitd); 289 sitd->sitd_self = sitd_self; 290 sitd->obj_next = free_sitd; 291 free_sitd = sitd; 292 293 sitd++; 294 sitd_self += size_sitd; 295 } 296 297 page->free.size -= (num_sitd * size_sitd); 298 page->free.buffer += (num_sitd * size_sitd); 299 page->free.phys_addr += (num_sitd * size_sitd); 300 301 page->next = used_pages; 302 used_pages = page; 303 304 sitd = free_sitd; 305 free_sitd = sitd->obj_next; 306 307 return (sitd); 308} 309void usb_ehci_sitd_free(struct usb_ehci_sitd *sitd) 310{ 311 memset(sitd, 0, 0xF); 312 sitd->sitd_next |= USB_EHCI_LINK_TERMINATE; 313 sitd->sitd_bp[0].address &= 0xFFFFF000; 314 sitd->sitd_bp[0].address &= 0xFFFFF000; 315 sitd->sitd_back_link |= USB_EHCI_LINK_TERMINATE; 316 317 sitd->prev = NULL; 318 sitd->next = NULL; 319 320 sitd->obj_next = free_sitd; 321 free_sitd = sitd; 322} 323 324struct usb_ehci_itd *usb_ehci_itd_alloc(void) 325{ 326 usb_ehci_itd_t *itd; 327 328 /* 329 * we have a free queue transfer descriptor left, so we can use it 330 */ 331 if (free_itd != NULL) { 332 itd = free_itd; 333 free_itd = itd->obj_next; 334 return (itd); 335 } 336 337 /* 338 * we have to populate our free queue element transfer descriptor 339 */ 340 struct usb_page *page; 341 342 if (free_pages == NULL) { 343 page = usb_mem_page_alloc(); 344 } else { 345 page = free_pages; 346 free_pages = page->next; 347 } 348 349 uint32_t size_itd = sizeof(struct usb_ehci_itd); 350 uint32_t num_itd = page->free.size / size_itd; 351 352 itd = page->free.buffer; 353 usb_paddr_t itd_self = page->free.phys_addr; 354 355 for (uint32_t i = 0; i < num_itd; i++) { 356 USB_DEBUG_MEM(" Allocating ITD: vaddr=%p, phys=%p (%x) [%x]\n", itd, 357 itd_self, itd_self % USB_EHCI_ITD_ALIGN, size_itd); 358 assert(!(itd_self % USB_EHCI_ITD_ALIGN)); 359 memset(itd, 0, size_itd); 360 itd->itd_self = itd_self; 361 itd->obj_next = free_itd; 362 free_itd = itd; 363 364 itd++; 365 itd_self += size_itd; 366 } 367 368 page->free.size -= (num_itd * size_itd); 369 page->free.buffer += (num_itd * size_itd); 370 page->free.phys_addr += (num_itd * size_itd); 371 372 page->next = used_pages; 373 used_pages = page; 374 375 itd = free_itd; 376 free_itd = itd->obj_next; 377 378 return (itd); 379} 380 381void usb_ehci_itd_free(struct usb_ehci_itd *itd) 382{ 383 memset(itd, 0, 0x23); 384 itd->itd_next |= USB_EHCI_LINK_TERMINATE; 385 itd->itd_bp[0].address &= 0xFFFFF000; 386 itd->itd_bp[1].address &= 0xFFFFF000; 387 itd->itd_bp[2].address &= 0xFFFFF000; 388 itd->itd_bp[3].address &= 0xFFFFF000; 389 itd->itd_bp[4].address &= 0xFFFFF000; 390 itd->itd_bp[5].address &= 0xFFFFF000; 391 itd->itd_bp[6].address &= 0xFFFFF000; 392 393 itd->next = NULL; 394 itd->prev = NULL; 395 396 itd->obj_next = free_itd; 397 free_itd = itd; 398} 399 400usb_paddr_t usb_ehci_buffer_page_alloc(void) 401{ 402 struct usb_page *page; 403 if (free_pages != NULL) { 404 /* get the free apge */ 405 page = free_pages; 406 free_pages = page->next; 407 408 /* put it into the used page */ 409 page->next = used_pages; 410 used_pages = page; 411 412 /* return address */ 413 return (page->page.phys_addr); 414 } 415 416 page = usb_mem_page_alloc(); 417 418 // page has to be 4k aligned 419 assert(!(page->page.phys_addr & 0xFFF)); 420 421 page->next = used_pages; 422 used_pages = page; 423 424 return (page->page.phys_addr); 425} 426 427void usb_ehci_buffer_page_free(usb_paddr_t buf) 428{ 429 struct usb_page *page = used_pages; 430 struct usb_page *prev = page; 431 while (page->next != NULL) { 432 if (page->page.phys_addr == buf) { 433 break; 434 } 435 prev = page; 436 page = page->next; 437 } 438 439 if (page->page.phys_addr != buf) { 440 /* page not found */ 441 debug_printf("WARNING: freeing up a page that was not allocated"); 442 return; 443 } 444 445 if (prev == page) { 446 used_pages = page->next; 447 } else { 448 prev->next = page->next; 449 } 450 451 page->next = free_pages; 452 free_pages = page; 453} 454 455void usb_ehci_pframes_alloc(usb_ehci_hc_t *hc) 456{ 457 struct usb_page *page; 458 459 page = usb_mem_page_alloc(); 460 461 assert(!(page->page.phys_addr % USB_EHCI_FRAMELIST_ALIGN)); 462 463 hc->pframes = page->page.buffer; 464 hc->pframes_phys = page->page.phys_addr; 465 466 page->next = used_pages; 467 used_pages = page; 468} 469 470