Annotation of driverkit/notes/DMARaces, revision 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.