Annotation of driverkit/notes/DMARaces, revision 1.1.1.1

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: }      

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.