Changeset 94e9c29 in mainline
- Timestamp:
- 2018-01-13T00:54:24Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 230ef1c
- Parents:
- 0e7380f
- Location:
- uspace/drv/bus/usb/xhci
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/bus/usb/xhci/hc.c
r0e7380f r94e9c29 220 220 hc->ac64 = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_AC64); 221 221 hc->max_slots = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_MAX_SLOTS); 222 223 struct timeval tv; 224 getuptime(&tv); 225 hc->wrap_time = tv.tv_sec * 1000000 + tv.tv_usec; 222 226 hc->wrap_count = 0; 227 223 228 unsigned ist = XHCI_REG_RD(hc->cap_regs, XHCI_CAP_IST); 224 229 hc->ist = (ist & 0x10 >> 1) * (ist & 0xf); … … 508 513 static int xhci_handle_mfindex_wrap_event(xhci_hc_t *hc, xhci_trb_t *trb) 509 514 { 515 struct timeval tv; 516 getuptime(&tv); 517 hc->wrap_time = ((uint64_t) tv.tv_sec) * 1000000 + ((uint64_t) tv.tv_usec); 510 518 ++hc->wrap_count; 511 519 return EOK; -
uspace/drv/bus/usb/xhci/hc.h
r0e7380f r94e9c29 87 87 unsigned max_slots; 88 88 bool ac64; 89 uint32_t wrap_count; /** Amount of mfindex wraps HC has done */ 89 uint64_t wrap_time; /** The last time when mfindex wrap happened */ 90 uint64_t wrap_count; /** Amount of mfindex wraps HC has done */ 90 91 unsigned ist; /**< IST in microframes */ 91 92 -
uspace/drv/bus/usb/xhci/isoch.c
r0e7380f r94e9c29 80 80 81 81 fibril_timer_clear_locked(isoch->feeding_timer); 82 isoch->last_mf index= -1U;82 isoch->last_mf = -1U; 83 83 usb_log_info("[isoch] Endpoint" XHCI_EP_FMT ": Data flow reset.", XHCI_EP_ARGS(*ep)); 84 84 } … … 195 195 } 196 196 197 /** The number of bits the MFINDEX is stored in at HW */ 198 #define EPOCH_BITS 14 199 /** The delay in usec for the epoch wrap */ 200 #define EPOCH_DELAY 500000 201 /** The amount of microframes the epoch is checked for a delay */ 202 #define EPOCH_LOW_MFINDEX 8 * 100 203 204 static inline uint64_t get_system_time() 205 { 206 struct timeval tv; 207 getuptime(&tv); 208 return ((uint64_t) tv.tv_sec) * 1000000 + ((uint64_t) tv.tv_usec); 209 } 210 211 static inline uint64_t get_current_microframe(const xhci_hc_t *hc) 212 { 213 const uint32_t reg_mfindex = XHCI_REG_RD(hc->rt_regs, XHCI_RT_MFINDEX); 214 /* 215 * If the mfindex is low and the time passed since last mfindex wrap 216 * is too high, we have entered the new epoch already (and haven't received event yet). 217 */ 218 uint64_t epoch = hc->wrap_count; 219 if (reg_mfindex < EPOCH_LOW_MFINDEX && get_system_time() - hc->wrap_time > EPOCH_DELAY) { 220 ++epoch; 221 } 222 return (epoch << EPOCH_BITS) + reg_mfindex; 223 } 224 197 225 static inline void calc_next_mfindex(xhci_endpoint_t *ep, xhci_isoch_transfer_t *it) 198 226 { 199 227 xhci_isoch_t * const isoch = ep->isoch; 200 if (isoch->last_mf index== -1U) {228 if (isoch->last_mf == -1U) { 201 229 const xhci_bus_t *bus = bus_to_xhci_bus(ep->base.device->bus); 202 230 const xhci_hc_t *hc = bus->hc; 203 231 204 /* Choose some number, give us a little time to prepare the 205 * buffers */ 206 it->mfindex = XHCI_REG_RD(hc->rt_regs, XHCI_RT_MFINDEX) + 1 207 + isoch->buffer_count * ep->interval 208 + hc->ist; 232 /* Delay the first frame by some time to fill the buffer, but at most 10 miliseconds. */ 233 const uint64_t delay = min(isoch->buffer_count * ep->interval, 10 * 8); 234 it->mfindex = get_current_microframe(hc) + 1 + delay + hc->ist; 209 235 210 236 // Align to ESIT start boundary … … 212 238 it->mfindex &= ~(ep->interval - 1); 213 239 } else { 214 it->mfindex = (isoch->last_mfindex + ep->interval) % XHCI_MFINDEX_MAX;240 it->mfindex = isoch->last_mf + ep->interval; 215 241 } 216 242 } … … 227 253 typedef struct { 228 254 window_position_t position; 229 uint 32_t offset;255 uint64_t offset; 230 256 } window_decision_t; 231 257 … … 236 262 * uframes it's off. 237 263 */ 238 static inline void window_decide(window_decision_t *res, xhci_hc_t *hc, uint32_t mfindex) 239 { 240 uint32_t current_mfindex = XHCI_REG_RD(hc->rt_regs, XHCI_RT_MFINDEX) + 1; 241 242 /* 243 * In your mind, rotate the clock so the window is at its beginning. 244 * The length of the window is always the same, and by rotating the 245 * mfindex too, we can decide by the value of it easily. 246 */ 247 mfindex = (mfindex - current_mfindex - hc->ist + XHCI_MFINDEX_MAX) % XHCI_MFINDEX_MAX; 248 const uint32_t end = END_FRAME_DELAY - hc->ist; 249 const uint32_t threshold = (XHCI_MFINDEX_MAX + end) / 2; 250 251 if (mfindex <= end) { 264 static inline void window_decide(window_decision_t *res, xhci_hc_t *hc, uint64_t mfindex) 265 { 266 const uint64_t current_mf = get_current_microframe(hc); 267 const uint64_t start = current_mf + hc->ist + 1; 268 const uint64_t end = current_mf + END_FRAME_DELAY; 269 270 if (mfindex < start) { 271 res->position = WINDOW_TOO_LATE; 272 res->offset = start - mfindex; 273 } else if (mfindex <= end) { 252 274 res->position = WINDOW_INSIDE; 253 } else if (mfindex > threshold) {254 res->position = WINDOW_TOO_LATE;255 res->offset = XHCI_MFINDEX_MAX - mfindex;256 275 } else { 257 276 res->position = WINDOW_TOO_SOON; 258 277 res->offset = mfindex - end; 259 278 } 260 /*261 * TODO: The "size" of the clock is too low. We have to scale it a bit262 * to ensure correct scheduling of transfers, that are263 * buffer_count * interval away from now.264 * Maximum interval is 8 seconds, which means we need a size of265 * 16 seconds. The size of MFIINDEX is 2 seconds only.266 *267 * A plan is to create a thin abstraction at HC, which would return268 * a time from 32-bit clock, having its high bits updated by the269 * MFINDEX Wrap Event, and low bits from the MFINDEX register. Using270 * this 32-bit clock, one can plan 6 days ahead.271 */272 279 } 273 280 … … 293 300 bool fed = false; 294 301 295 /* 296 * There might be a case, where no transfer can't be put on the ring immediately 297 * (for endpoints with interval >= 500ms). In that case, the transfer buffers could fill 298 * and the first condition wouldn't be enough to enter the loop. 299 */ 300 while (isoch->hw_enqueue != isoch->enqueue || isoch->transfers[isoch->hw_enqueue].state == ISOCH_FILLED) { 302 while (isoch->transfers[isoch->hw_enqueue].state == ISOCH_FILLED) { 301 303 xhci_isoch_transfer_t * const it = &isoch->transfers[isoch->hw_enqueue]; 302 304 … … 317 319 318 320 case WINDOW_INSIDE: 319 usb_log_debug2("[isoch] feeding buffer %lu at 0x% x",321 usb_log_debug2("[isoch] feeding buffer %lu at 0x%llx", 320 322 it - isoch->transfers, it->mfindex); 321 323 it->error = schedule_isochronous_trb(ep, it); … … 332 334 case WINDOW_TOO_LATE: 333 335 /* Missed the opportunity to schedule. Just mark this transfer as skipped. */ 334 usb_log_debug2("[isoch] missed feeding buffer %lu at 0x% x by %u uframes",336 usb_log_debug2("[isoch] missed feeding buffer %lu at 0x%llx by %llu uframes", 335 337 it - isoch->transfers, it->mfindex, wd.offset); 336 338 it->state = ISOCH_COMPLETE; … … 405 407 406 408 case WINDOW_TOO_LATE: 407 usb_log_debug2("[isoch] missed feeding buffer %lu at 0x% x by %u uframes",409 usb_log_debug2("[isoch] missed feeding buffer %lu at 0x%llx by %llu uframes", 408 410 it - isoch->transfers, it->mfindex, wd.offset); 409 411 /* Missed the opportunity to schedule. Schedule ASAP. */ … … 416 418 case WINDOW_INSIDE: 417 419 isoch->enqueue = (isoch->enqueue + 1) % isoch->buffer_count; 418 isoch->last_mf index= it->mfindex;419 420 usb_log_debug2("[isoch] feeding buffer %lu at 0x% x",420 isoch->last_mf = it->mfindex; 421 422 usb_log_debug2("[isoch] feeding buffer %lu at 0x%llx", 421 423 it - isoch->transfers, it->mfindex); 422 424 … … 503 505 /* Calculate when to schedule next transfer */ 504 506 calc_next_mfindex(ep, it); 505 isoch->last_mf index= it->mfindex;506 usb_log_debug2("[isoch] buffer %zu will be on schedule at 0x% x", it - isoch->transfers, it->mfindex);507 isoch->last_mf = it->mfindex; 508 usb_log_debug2("[isoch] buffer %zu will be on schedule at 0x%llx", it - isoch->transfers, it->mfindex); 507 509 508 510 /* Prepare the transfer. */ -
uspace/drv/bus/usb/xhci/isoch.h
r0e7380f r94e9c29 62 62 63 63 /** Microframe to which to schedule */ 64 uint 32_t mfindex;64 uint64_t mfindex; 65 65 66 66 /** Physical address of enqueued TRB */ … … 87 87 size_t max_size; 88 88 89 /** The MFINDEXat which the last TRB was scheduled. */90 uint 32_t last_mfindex;89 /** The microframe at which the last TRB was scheduled. */ 90 uint64_t last_mf; 91 91 92 92 /** The number of transfer buffers allocated */
Note:
See TracChangeset
for help on using the changeset viewer.