|
|
1.1 ! root 1: DMA enqueue race condition handling ! 2: ! 3: hw_next_desc = nextDescriptor hw register ! 4: hw_curr_desc = currentDescriptor hw register ! 5: count_reg = 'Count' hw register ! 6: frame_queue = queue of kern_dma_frame_t (one per channel) ! 7: desc_queue = queue of kern_dma_desc_t's (one per dma_frame_t) ! 8: last_frame = end of frame_queue ! 9: last_desc = end of last_frame's desc_queue ! 10: ! 11: enqueue new_frame ! 12: { ! 13: ! 14: save current last_desc in old_tail; ! 15: create chain for new_frame; ! 16: link new_frame's chain onto old_tail; ! 17: link new_frame onto frame_queue; ! 18: if(hw_next_desc != NULL) ! 19: done; ! 20: else one of three cases: ! 21: 1. Missed update, channel still working on old_tail. ! 22: 2. Missed update, channel stopped. ! 23: 3. Update OK, channel working on new last_frame from ! 24: (new_frame). ! 25: if(hw_curr_desc != old_tail) ! 26: return OK - case 3; ! 27: ! 28: /* ! 29: * try to catch update in h/w. ! 30: */ ! 31: hw_next_desc = new_frame; ! 32: ! 33: /* ! 34: * reading count register guarantees we avoid this race condition: ! 35: * ! 36: * -- TE finishes last desc, next_descriptor null, sends "clear ! 37: * descriptorListNotEmpty" packet to device. ! 38: * -- Kernel reads descriptorListNotEmpty, it's still 1 because the ! 39: * packet just sent to the device is NOT atomic and can be ! 40: * interrupted by a kernel access (ONCE). ! 41: * Thus reading count does two things: ! 42: * -- guarantees that descriptorListNotEmpty will be valid ! 43: * (i.e., 0) when kernel reads it in case of underrun, and ! 44: * -- also tells kernel than channel is OK (running) if count is ! 45: * non-zero, since TE clears it before sending the "clear ! 46: * descriptorListNotEmpty" packet to the device. ! 47: */ ! 48: if((count != 0) || channel's descriptorListNotEmpty) ! 49: return OK - case 1, did h/w update in time; ! 50: if(hw_curr_desc == new last_desc) ! 51: return OK - h/w update in time, and new_frame is already done ! 52: ! 53: /* ! 54: * case 3. Return error and prepare channel for restart. ! 55: */ ! 56: hw_curr_desc = new_frame; ! 57: return(missed error); ! 58: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.