Changeset 00aece0 in mainline for uspace/drv/bus/usb/uhci/hc.c
- Timestamp:
- 2012-02-18T16:47:38Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 4449c6c
- Parents:
- bd5f3b7 (diff), f943dd3 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/uhci/hc.c
rbd5f3b7 r00aece0 41 41 42 42 #include "hc.h" 43 #include "uhci_batch.h" 43 44 44 45 #define UHCI_INTR_ALLOW_INTERRUPTS \ … … 47 48 (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT) 48 49 49 static const irq_cmd_t uhci_irq_commands[] = 50 { 50 static const irq_pio_range_t uhci_irq_pio_ranges[] = { 51 { 52 .base = 0, /* filled later */ 53 .size = sizeof(uhci_regs_t) 54 } 55 }; 56 57 static const irq_cmd_t uhci_irq_commands[] = { 51 58 { .cmd = CMD_PIO_READ_16, .dstarg = 1, .addr = NULL/*filled later*/}, 52 59 { .cmd = CMD_BTEST, .srcarg = 1, .dstarg = 2, … … 57 64 }; 58 65 66 static void hc_init_hw(const hc_t *instance); 67 static int hc_init_mem_structures(hc_t *instance); 59 68 static int hc_init_transfer_lists(hc_t *instance); 60 static int hc_init_mem_structures(hc_t *instance); 61 static void hc_init_hw(hc_t *instance); 69 static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch); 62 70 63 71 static int hc_interrupt_emulator(void *arg); … … 65 73 66 74 /*----------------------------------------------------------------------------*/ 75 /** Get number of PIO ranges used in IRQ code. 76 * @return Number of ranges. 77 */ 78 size_t hc_irq_pio_range_count(void) 79 { 80 return sizeof(uhci_irq_pio_ranges) / sizeof(irq_pio_range_t); 81 } 82 /*----------------------------------------------------------------------------*/ 67 83 /** Get number of commands used in IRQ code. 68 84 * @return Number of commands. … … 73 89 } 74 90 /*----------------------------------------------------------------------------*/ 75 /** Generate IRQ code commands. 76 * @param[out] cmds Place to store the commands. 77 * @param[in] cmd_size Size of the place (bytes). 91 /** Generate IRQ code. 92 * @param[out] ranges PIO ranges buffer. 93 * @param[in] ranges_size Size of the ranges buffer (bytes). 94 * @param[out] cmds Commands buffer. 95 * @param[in] cmds_size Size of the commands buffer (bytes). 78 96 * @param[in] regs Physical address of device's registers. 79 97 * @param[in] reg_size Size of the register area (bytes). … … 81 99 * @return Error code. 82 100 */ 83 int hc_get_irq_commands( 84 irq_cmd_t cmds[], size_t cmd_size, uintptr_t regs, size_t reg_size) 85 { 86 if (cmd_size < sizeof(uhci_irq_commands) 87 || reg_size < sizeof(uhci_regs_t)) 101 int 102 hc_get_irq_code(irq_pio_range_t ranges[], size_t ranges_size, irq_cmd_t cmds[], 103 size_t cmds_size, uintptr_t regs, size_t reg_size) 104 { 105 if ((ranges_size < sizeof(uhci_irq_pio_ranges)) || 106 (cmds_size < sizeof(uhci_irq_commands)) || 107 (reg_size < sizeof(uhci_regs_t))) 88 108 return EOVERFLOW; 89 109 90 uhci_regs_t *registers = (uhci_regs_t*)regs; 110 memcpy(ranges, uhci_irq_pio_ranges, sizeof(uhci_irq_pio_ranges)); 111 ranges[0].base = regs; 91 112 92 113 memcpy(cmds, uhci_irq_commands, sizeof(uhci_irq_commands)); 93 94 cmds[0].addr = (void*)®isters->usbsts; 95 cmds[3].addr = (void*)®isters->usbsts; 96 return EOK; 114 uhci_regs_t *registers = (uhci_regs_t *) regs; 115 cmds[0].addr = ®isters->usbsts; 116 cmds[3].addr = ®isters->usbsts; 117 118 return EOK; 119 } 120 /*----------------------------------------------------------------------------*/ 121 /** Take action based on the interrupt cause. 122 * 123 * @param[in] instance UHCI structure to use. 124 * @param[in] status Value of the status register at the time of interrupt. 125 * 126 * Interrupt might indicate: 127 * - transaction completed, either by triggering IOC, SPD, or an error 128 * - some kind of device error 129 * - resume from suspend state (not implemented) 130 */ 131 void hc_interrupt(hc_t *instance, uint16_t status) 132 { 133 assert(instance); 134 /* Lower 2 bits are transaction error and transaction complete */ 135 if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) { 136 LIST_INITIALIZE(done); 137 transfer_list_remove_finished( 138 &instance->transfers_interrupt, &done); 139 transfer_list_remove_finished( 140 &instance->transfers_control_slow, &done); 141 transfer_list_remove_finished( 142 &instance->transfers_control_full, &done); 143 transfer_list_remove_finished( 144 &instance->transfers_bulk_full, &done); 145 146 while (!list_empty(&done)) { 147 link_t *item = list_first(&done); 148 list_remove(item); 149 uhci_transfer_batch_t *batch = 150 uhci_transfer_batch_from_link(item); 151 uhci_transfer_batch_finish_dispose(batch); 152 } 153 } 154 /* Resume interrupts are not supported */ 155 if (status & UHCI_STATUS_RESUME) { 156 usb_log_error("Resume interrupt!\n"); 157 } 158 159 /* Bits 4 and 5 indicate hc error */ 160 if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) { 161 usb_log_error("UHCI hardware failure!.\n"); 162 ++instance->hw_failures; 163 transfer_list_abort_all(&instance->transfers_interrupt); 164 transfer_list_abort_all(&instance->transfers_control_slow); 165 transfer_list_abort_all(&instance->transfers_control_full); 166 transfer_list_abort_all(&instance->transfers_bulk_full); 167 168 if (instance->hw_failures < UHCI_ALLOWED_HW_FAIL) { 169 /* reinitialize hw, this triggers virtual disconnect*/ 170 hc_init_hw(instance); 171 } else { 172 usb_log_fatal("Too many UHCI hardware failures!.\n"); 173 hc_fini(instance); 174 } 175 } 97 176 } 98 177 /*----------------------------------------------------------------------------*/ … … 137 216 str_error(ret)); 138 217 218 #undef CHECK_RET_RETURN 219 220 hcd_init(&instance->generic, USB_SPEED_FULL, 221 BANDWIDTH_AVAILABLE_USB11, bandwidth_count_usb11); 222 223 instance->generic.private_data = instance; 224 instance->generic.schedule = hc_schedule; 225 instance->generic.ep_add_hook = NULL; 226 139 227 hc_init_hw(instance); 140 228 if (!interrupts) { … … 146 234 147 235 return EOK; 148 #undef CHECK_RET_DEST_FUN_RETURN149 236 } 150 237 /*----------------------------------------------------------------------------*/ … … 154 241 * For magic values see UHCI Design Guide 155 242 */ 156 void hc_init_hw( hc_t *instance)243 void hc_init_hw(const hc_t *instance) 157 244 { 158 245 assert(instance); … … 198 285 * 199 286 * Structures: 200 * - interrupt code (I/O addressses are customized per instance)201 287 * - transfer lists (queue heads need to be accessible by the hw) 202 288 * - frame list page (needs to be one UHCI hw accessible 4K page) … … 205 291 { 206 292 assert(instance); 207 #define CHECK_RET_RETURN(ret, message...) \ 208 if (ret != EOK) { \ 209 usb_log_error(message); \ 210 return ret; \ 211 } else (void) 0 293 294 /* Init USB frame list page */ 295 instance->frame_list = get_page(); 296 if (!instance->frame_list) { 297 return ENOMEM; 298 } 299 usb_log_debug("Initialized frame list at %p.\n", instance->frame_list); 212 300 213 301 /* Init transfer lists */ 214 302 int ret = hc_init_transfer_lists(instance); 215 CHECK_RET_RETURN(ret, "Failed to initialize transfer lists.\n"); 303 if (ret != EOK) { 304 usb_log_error("Failed to initialize transfer lists.\n"); 305 return_page(instance->frame_list); 306 return ENOMEM; 307 } 216 308 usb_log_debug("Initialized transfer lists.\n"); 217 309 218 /* Init device keeper */219 usb_device_keeper_init(&instance->manager);220 usb_log_debug("Initialized device keeper.\n");221 222 ret = usb_endpoint_manager_init(&instance->ep_manager,223 BANDWIDTH_AVAILABLE_USB11);224 CHECK_RET_RETURN(ret, "Failed to initialize endpoint manager: %s.\n",225 str_error(ret));226 227 /* Init USB frame list page*/228 instance->frame_list = get_page();229 if (!instance->frame_list) {230 usb_log_error("Failed to get frame list page.\n");231 usb_endpoint_manager_destroy(&instance->ep_manager);232 return ENOMEM;233 }234 usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);235 310 236 311 /* Set all frames to point to the first queue head */ 237 312 const uint32_t queue = LINK_POINTER_QH( 238 313 addr_to_phys(instance->transfers_interrupt.queue_head)); 239 unsigned i = 0; 240 for (; i < UHCI_FRAME_LIST_COUNT; ++i) {314 315 for (unsigned i = 0; i < UHCI_FRAME_LIST_COUNT; ++i) { 241 316 instance->frame_list[i] = queue; 242 317 } 243 318 244 319 return EOK; 245 #undef CHECK_RET_RETURN246 320 } 247 321 /*----------------------------------------------------------------------------*/ … … 316 390 * Checks for bandwidth availability and appends the batch to the proper queue. 317 391 */ 318 int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch) 319 { 392 int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch) 393 { 394 assert(hcd); 395 hc_t *instance = hcd->private_data; 320 396 assert(instance); 321 397 assert(batch); 398 uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch); 399 if (!uhci_batch) { 400 usb_log_error("Failed to create UHCI transfer structures.\n"); 401 return ENOMEM; 402 } 322 403 323 404 transfer_list_t *list = 324 405 instance->transfers[batch->ep->speed][batch->ep->transfer_type]; 325 406 assert(list); 326 transfer_list_add_batch(list, batch); 327 328 return EOK; 329 } 330 /*----------------------------------------------------------------------------*/ 331 /** Take action based on the interrupt cause. 332 * 333 * @param[in] instance UHCI structure to use. 334 * @param[in] status Value of the status register at the time of interrupt. 335 * 336 * Interrupt might indicate: 337 * - transaction completed, either by triggering IOC, SPD, or an error 338 * - some kind of device error 339 * - resume from suspend state (not implemented) 340 */ 341 void hc_interrupt(hc_t *instance, uint16_t status) 342 { 343 assert(instance); 344 /* Lower 2 bits are transaction error and transaction complete */ 345 if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) { 346 LIST_INITIALIZE(done); 347 transfer_list_remove_finished( 348 &instance->transfers_interrupt, &done); 349 transfer_list_remove_finished( 350 &instance->transfers_control_slow, &done); 351 transfer_list_remove_finished( 352 &instance->transfers_control_full, &done); 353 transfer_list_remove_finished( 354 &instance->transfers_bulk_full, &done); 355 356 while (!list_empty(&done)) { 357 link_t *item = list_first(&done); 358 list_remove(item); 359 usb_transfer_batch_t *batch = 360 list_get_instance(item, usb_transfer_batch_t, link); 361 usb_transfer_batch_finish(batch); 362 } 363 } 364 /* Resume interrupts are not supported */ 365 if (status & UHCI_STATUS_RESUME) { 366 usb_log_error("Resume interrupt!\n"); 367 } 368 369 /* Bits 4 and 5 indicate hc error */ 370 if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) { 371 usb_log_error("UHCI hardware failure!.\n"); 372 ++instance->hw_failures; 373 transfer_list_abort_all(&instance->transfers_interrupt); 374 transfer_list_abort_all(&instance->transfers_control_slow); 375 transfer_list_abort_all(&instance->transfers_control_full); 376 transfer_list_abort_all(&instance->transfers_bulk_full); 377 378 if (instance->hw_failures < UHCI_ALLOWED_HW_FAIL) { 379 /* reinitialize hw, this triggers virtual disconnect*/ 380 hc_init_hw(instance); 381 } else { 382 usb_log_fatal("Too many UHCI hardware failures!.\n"); 383 hc_fini(instance); 384 } 385 } 407 transfer_list_add_batch(list, uhci_batch); 408 409 return EOK; 386 410 } 387 411 /*----------------------------------------------------------------------------*/ … … 403 427 if (status != 0) 404 428 usb_log_debug2("UHCI status: %x.\n", status); 405 // Qemu fails to report stalled communication406 // see https://bugs.launchpad.net/qemu/+bug/757654407 // This is a simple workaround to force queue processing every time408 // status |= 1;409 429 hc_interrupt(instance, status); 410 430 async_usleep(UHCI_INT_EMULATOR_TIMEOUT); … … 412 432 return EOK; 413 433 } 414 /*--------------------------------------------------------------------------- */434 /*----------------------------------------------------------------------------*/ 415 435 /** Debug function, checks consistency of memory structures. 416 436 *
Note:
See TracChangeset
for help on using the changeset viewer.