Changeset 26e7d6d in mainline for uspace/drv/bus/usb/uhci/hc.c
- Timestamp:
- 2011-09-19T16:31:00Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- a347a11
- Parents:
- 3842a955 (diff), 086290d (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 moved
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/uhci/hc.c
r3842a955 r26e7d6d 41 41 42 42 #include "hc.h" 43 #include "uhci_batch.h" 43 44 44 45 #define UHCI_INTR_ALLOW_INTERRUPTS \ … … 48 49 49 50 51 static const irq_cmd_t uhci_irq_commands[] = 52 { 53 { .cmd = CMD_PIO_READ_16, .dstarg = 1, .addr = NULL/*filled later*/}, 54 { .cmd = CMD_BTEST, .srcarg = 1, .dstarg = 2, 55 .value = UHCI_STATUS_USED_INTERRUPTS | UHCI_STATUS_NM_INTERRUPTS }, 56 { .cmd = CMD_PREDICATE, .srcarg = 2, .value = 2 }, 57 { .cmd = CMD_PIO_WRITE_A_16, .srcarg = 1, .addr = NULL/*filled later*/}, 58 { .cmd = CMD_ACCEPT }, 59 }; 60 61 static void hc_init_hw(const hc_t *instance); 62 static int hc_init_mem_structures(hc_t *instance); 50 63 static int hc_init_transfer_lists(hc_t *instance); 51 static int hc_init_mem_structures(hc_t *instance); 52 static void hc_init_hw(hc_t *instance); 64 static int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch); 53 65 54 66 static int hc_interrupt_emulator(void *arg); 55 67 static int hc_debug_checker(void *arg); 68 69 /*----------------------------------------------------------------------------*/ 70 /** Get number of commands used in IRQ code. 71 * @return Number of commands. 72 */ 73 size_t hc_irq_cmd_count(void) 74 { 75 return sizeof(uhci_irq_commands) / sizeof(irq_cmd_t); 76 } 77 /*----------------------------------------------------------------------------*/ 78 /** Generate IRQ code commands. 79 * @param[out] cmds Place to store the commands. 80 * @param[in] cmd_size Size of the place (bytes). 81 * @param[in] regs Physical address of device's registers. 82 * @param[in] reg_size Size of the register area (bytes). 83 * 84 * @return Error code. 85 */ 86 int hc_get_irq_commands( 87 irq_cmd_t cmds[], size_t cmd_size, uintptr_t regs, size_t reg_size) 88 { 89 if (cmd_size < sizeof(uhci_irq_commands) 90 || reg_size < sizeof(uhci_regs_t)) 91 return EOVERFLOW; 92 93 uhci_regs_t *registers = (uhci_regs_t*)regs; 94 95 memcpy(cmds, uhci_irq_commands, sizeof(uhci_irq_commands)); 96 97 cmds[0].addr = (void*)®isters->usbsts; 98 cmds[3].addr = (void*)®isters->usbsts; 99 return EOK; 100 } 101 /*----------------------------------------------------------------------------*/ 102 /** Take action based on the interrupt cause. 103 * 104 * @param[in] instance UHCI structure to use. 105 * @param[in] status Value of the status register at the time of interrupt. 106 * 107 * Interrupt might indicate: 108 * - transaction completed, either by triggering IOC, SPD, or an error 109 * - some kind of device error 110 * - resume from suspend state (not implemented) 111 */ 112 void hc_interrupt(hc_t *instance, uint16_t status) 113 { 114 assert(instance); 115 /* Lower 2 bits are transaction error and transaction complete */ 116 if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) { 117 LIST_INITIALIZE(done); 118 transfer_list_remove_finished( 119 &instance->transfers_interrupt, &done); 120 transfer_list_remove_finished( 121 &instance->transfers_control_slow, &done); 122 transfer_list_remove_finished( 123 &instance->transfers_control_full, &done); 124 transfer_list_remove_finished( 125 &instance->transfers_bulk_full, &done); 126 127 while (!list_empty(&done)) { 128 link_t *item = list_first(&done); 129 list_remove(item); 130 uhci_transfer_batch_t *batch = 131 uhci_transfer_batch_from_link(item); 132 uhci_transfer_batch_call_dispose(batch); 133 } 134 } 135 /* Resume interrupts are not supported */ 136 if (status & UHCI_STATUS_RESUME) { 137 usb_log_error("Resume interrupt!\n"); 138 } 139 140 /* Bits 4 and 5 indicate hc error */ 141 if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) { 142 usb_log_error("UHCI hardware failure!.\n"); 143 ++instance->hw_failures; 144 transfer_list_abort_all(&instance->transfers_interrupt); 145 transfer_list_abort_all(&instance->transfers_control_slow); 146 transfer_list_abort_all(&instance->transfers_control_full); 147 transfer_list_abort_all(&instance->transfers_bulk_full); 148 149 if (instance->hw_failures < UHCI_ALLOWED_HW_FAIL) { 150 /* reinitialize hw, this triggers virtual disconnect*/ 151 hc_init_hw(instance); 152 } else { 153 usb_log_fatal("Too many UHCI hardware failures!.\n"); 154 hc_fini(instance); 155 } 156 } 157 } 56 158 /*----------------------------------------------------------------------------*/ 57 159 /** Initialize UHCI hc driver structure … … 69 171 int hc_init(hc_t *instance, void *regs, size_t reg_size, bool interrupts) 70 172 { 71 assert(reg_size >= sizeof( regs_t));173 assert(reg_size >= sizeof(uhci_regs_t)); 72 174 int ret; 73 175 … … 82 184 83 185 /* allow access to hc control registers */ 84 regs_t *io;186 uhci_regs_t *io; 85 187 ret = pio_enable(regs, reg_size, (void **)&io); 86 CHECK_RET_RETURN(ret, 87 "Failed(%d) to gain access to registers at %p: %s.\n", 88 ret, io, str_error(ret)); 188 CHECK_RET_RETURN(ret, "Failed to gain access to registers at %p: %s.\n", 189 io, str_error(ret)); 89 190 instance->registers = io; 90 usb_log_debug("Device registers at %p (%zuB) accessible.\n", 91 io, reg_size); 191 usb_log_debug( 192 "Device registers at %p (%zuB) accessible.\n", io, reg_size); 193 194 ret = hcd_init(&instance->generic, BANDWIDTH_AVAILABLE_USB11, 195 bandwidth_count_usb11); 196 CHECK_RET_RETURN(ret, "Failed to initialize HCD generic driver: %s.\n", 197 str_error(ret)); 198 199 instance->generic.private_data = instance; 200 instance->generic.schedule = hc_schedule; 201 instance->generic.ep_add_hook = NULL; 202 203 #undef CHECK_RET_DEST_FUN_RETURN 92 204 93 205 ret = hc_init_mem_structures(instance); 94 CHECK_RET_RETURN(ret, 95 "Failed(%d) to initialize UHCI memory structures: %s.\n", 96 ret, str_error(ret)); 206 if (ret != EOK) { 207 usb_log_error( 208 "Failed to initialize UHCI memory structures: %s.\n", 209 str_error(ret)); 210 hcd_destroy(&instance->generic); 211 return ret; 212 } 97 213 98 214 hc_init_hw(instance); … … 105 221 106 222 return EOK; 107 #undef CHECK_RET_DEST_FUN_RETURN108 223 } 109 224 /*----------------------------------------------------------------------------*/ … … 113 228 * For magic values see UHCI Design Guide 114 229 */ 115 void hc_init_hw( hc_t *instance)116 { 117 assert(instance); 118 regs_t *registers = instance->registers;230 void hc_init_hw(const hc_t *instance) 231 { 232 assert(instance); 233 uhci_regs_t *registers = instance->registers; 119 234 120 235 /* Reset everything, who knows what touched it before us */ 121 236 pio_write_16(®isters->usbcmd, UHCI_CMD_GLOBAL_RESET); 122 async_usleep( 10000); /* 10ms according to USB spec*/237 async_usleep(50000); /* 50ms according to USB spec(root hub reset) */ 123 238 pio_write_16(®isters->usbcmd, 0); 124 239 125 /* Reset hc, all states and counters */240 /* Reset hc, all states and counters. Hope that hw is not broken */ 126 241 pio_write_16(®isters->usbcmd, UHCI_CMD_HCRESET); 127 242 do { async_usleep(10); } … … 141 256 } 142 257 143 const uint16_t status= pio_read_16(®isters->usbcmd);144 if ( status!= 0)145 usb_log_warning("Previous command value: %x.\n", status);258 const uint16_t cmd = pio_read_16(®isters->usbcmd); 259 if (cmd != 0) 260 usb_log_warning("Previous command value: %x.\n", cmd); 146 261 147 262 /* Start the hc with large(64B) packet FSBR */ … … 157 272 * 158 273 * Structures: 159 * - interrupt code (I/O addressses are customized per instance)160 274 * - transfer lists (queue heads need to be accessible by the hw) 161 275 * - frame list page (needs to be one UHCI hw accessible 4K page) … … 164 278 { 165 279 assert(instance); 166 #define CHECK_RET_RETURN(ret, message...) \ 167 if (ret != EOK) { \ 168 usb_log_error(message); \ 169 return ret; \ 170 } else (void) 0 171 172 /* Init interrupt code */ 173 instance->interrupt_code.cmds = instance->interrupt_commands; 174 { 175 /* Read status register */ 176 instance->interrupt_commands[0].cmd = CMD_PIO_READ_16; 177 instance->interrupt_commands[0].dstarg = 1; 178 instance->interrupt_commands[0].addr = 179 &instance->registers->usbsts; 180 181 /* Test whether we are the interrupt cause */ 182 instance->interrupt_commands[1].cmd = CMD_BTEST; 183 instance->interrupt_commands[1].value = 184 UHCI_STATUS_USED_INTERRUPTS | UHCI_STATUS_NM_INTERRUPTS; 185 instance->interrupt_commands[1].srcarg = 1; 186 instance->interrupt_commands[1].dstarg = 2; 187 188 /* Predicate cleaning and accepting */ 189 instance->interrupt_commands[2].cmd = CMD_PREDICATE; 190 instance->interrupt_commands[2].value = 2; 191 instance->interrupt_commands[2].srcarg = 2; 192 193 /* Write clean status register */ 194 instance->interrupt_commands[3].cmd = CMD_PIO_WRITE_A_16; 195 instance->interrupt_commands[3].srcarg = 1; 196 instance->interrupt_commands[3].addr = 197 &instance->registers->usbsts; 198 199 /* Accept interrupt */ 200 instance->interrupt_commands[4].cmd = CMD_ACCEPT; 201 202 instance->interrupt_code.cmdcount = UHCI_NEEDED_IRQ_COMMANDS; 203 } 280 281 /* Init USB frame list page */ 282 instance->frame_list = get_page(); 283 if (!instance->frame_list) { 284 return ENOMEM; 285 } 286 usb_log_debug("Initialized frame list at %p.\n", instance->frame_list); 204 287 205 288 /* Init transfer lists */ 206 289 int ret = hc_init_transfer_lists(instance); 207 CHECK_RET_RETURN(ret, "Failed to init transfer lists.\n"); 290 if (ret != EOK) { 291 usb_log_error("Failed to initialize transfer lists.\n"); 292 return_page(instance->frame_list); 293 return ENOMEM; 294 } 208 295 usb_log_debug("Initialized transfer lists.\n"); 209 296 210 /* Init USB frame list page*/211 instance->frame_list = get_page();212 ret = instance->frame_list ? EOK : ENOMEM;213 CHECK_RET_RETURN(ret, "Failed to get frame list page.\n");214 usb_log_debug("Initialized frame list at %p.\n", instance->frame_list);215 297 216 298 /* Set all frames to point to the first queue head */ 217 299 const uint32_t queue = LINK_POINTER_QH( 218 300 addr_to_phys(instance->transfers_interrupt.queue_head)); 219 220 301 unsigned i = 0; 221 302 for(; i < UHCI_FRAME_LIST_COUNT; ++i) { … … 223 304 } 224 305 225 /* Init device keeper */ 226 usb_device_keeper_init(&instance->manager); 227 usb_log_debug("Initialized device manager.\n"); 228 229 ret = usb_endpoint_manager_init(&instance->ep_manager, 230 BANDWIDTH_AVAILABLE_USB11); 231 CHECK_RET_RETURN(ret, "Failed to initialize endpoint manager: %s.\n", 232 str_error(ret)); 233 234 return EOK; 235 #undef CHECK_RET_RETURN 306 return EOK; 236 307 } 237 308 /*----------------------------------------------------------------------------*/ … … 252 323 int ret = transfer_list_init(&instance->transfers_##type, name); \ 253 324 if (ret != EOK) { \ 254 usb_log_error("Failed (%d)to setup %s transfer list: %s.\n", \255 ret,name, str_error(ret)); \325 usb_log_error("Failed to setup %s transfer list: %s.\n", \ 326 name, str_error(ret)); \ 256 327 transfer_list_fini(&instance->transfers_bulk_full); \ 257 328 transfer_list_fini(&instance->transfers_control_full); \ … … 306 377 * Checks for bandwidth availability and appends the batch to the proper queue. 307 378 */ 308 int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch) 309 { 379 int hc_schedule(hcd_t *hcd, usb_transfer_batch_t *batch) 380 { 381 assert(hcd); 382 hc_t *instance = hcd->private_data; 310 383 assert(instance); 311 384 assert(batch); 385 uhci_transfer_batch_t *uhci_batch = uhci_transfer_batch_get(batch); 386 if (!uhci_batch) { 387 usb_log_error("Failed to create UHCI transfer structures.\n"); 388 return ENOMEM; 389 } 312 390 313 391 transfer_list_t *list = 314 392 instance->transfers[batch->ep->speed][batch->ep->transfer_type]; 315 393 assert(list); 316 transfer_list_add_batch(list, batch); 317 318 return EOK; 319 } 320 /*----------------------------------------------------------------------------*/ 321 /** Take action based on the interrupt cause. 322 * 323 * @param[in] instance UHCI structure to use. 324 * @param[in] status Value of the status register at the time of interrupt. 325 * 326 * Interrupt might indicate: 327 * - transaction completed, either by triggering IOC, SPD, or an error 328 * - some kind of device error 329 * - resume from suspend state (not implemented) 330 */ 331 void hc_interrupt(hc_t *instance, uint16_t status) 332 { 333 assert(instance); 334 /* Lower 2 bits are transaction error and transaction complete */ 335 if (status & (UHCI_STATUS_INTERRUPT | UHCI_STATUS_ERROR_INTERRUPT)) { 336 LIST_INITIALIZE(done); 337 transfer_list_remove_finished( 338 &instance->transfers_interrupt, &done); 339 transfer_list_remove_finished( 340 &instance->transfers_control_slow, &done); 341 transfer_list_remove_finished( 342 &instance->transfers_control_full, &done); 343 transfer_list_remove_finished( 344 &instance->transfers_bulk_full, &done); 345 346 while (!list_empty(&done)) { 347 link_t *item = list_first(&done); 348 list_remove(item); 349 usb_transfer_batch_t *batch = 350 list_get_instance(item, usb_transfer_batch_t, link); 351 usb_transfer_batch_finish(batch); 352 } 353 } 354 /* Resume interrupts are not supported */ 355 if (status & UHCI_STATUS_RESUME) { 356 usb_log_error("Resume interrupt!\n"); 357 } 358 359 /* Bits 4 and 5 indicate hc error */ 360 if (status & (UHCI_STATUS_PROCESS_ERROR | UHCI_STATUS_SYSTEM_ERROR)) { 361 usb_log_error("UHCI hardware failure!.\n"); 362 ++instance->hw_failures; 363 transfer_list_abort_all(&instance->transfers_interrupt); 364 transfer_list_abort_all(&instance->transfers_control_slow); 365 transfer_list_abort_all(&instance->transfers_control_full); 366 transfer_list_abort_all(&instance->transfers_bulk_full); 367 368 if (instance->hw_failures < UHCI_ALLOWED_HW_FAIL) { 369 /* reinitialize hw, this triggers virtual disconnect*/ 370 hc_init_hw(instance); 371 } else { 372 usb_log_fatal("Too many UHCI hardware failures!.\n"); 373 hc_fini(instance); 374 } 375 } 394 transfer_list_add_batch(list, uhci_batch); 395 396 return EOK; 376 397 } 377 398 /*----------------------------------------------------------------------------*/ … … 393 414 if (status != 0) 394 415 usb_log_debug2("UHCI status: %x.\n", status); 395 // Qemu fails to report stalled communication396 // see https://bugs.launchpad.net/qemu/+bug/757654397 // This is a simple workaround to force queue processing every time398 // status |= 1;399 416 hc_interrupt(instance, status); 400 417 async_usleep(UHCI_INT_EMULATOR_TIMEOUT); … … 402 419 return EOK; 403 420 } 404 /*--------------------------------------------------------------------------- */421 /*----------------------------------------------------------------------------*/ 405 422 /** Debug function, checks consistency of memory structures. 406 423 *
Note:
See TracChangeset
for help on using the changeset viewer.