Annotation of driverkit/notes/DMADequeue, revision 1.1

1.1     ! root        1:                        DMA Dequeue algorithm
        !             2:                        
        !             3: Definitions: 
        !             4: 
        !             5: * a descriptor is "completed" (as far as the kernel is concerned) if at least one byte moved between the device and the descriptor. A descriptor can be "completed" even if it was aborted because of any error. A descriptor 'n' is NOT completed if a device-level error occurred while processing data from descriptor 'n-1', even of the TE fetched one or two buffers worth of data from descriptor 'n'.
        !             6: 
        !             7: * DMA read: transfer from device to memory
        !             8: 
        !             9: * DMA write: transfer from memory to device
        !            10: 
        !            11: Notes:
        !            12: 
        !            13: * We write -1 to a descriptor's rem_byte_count field when it is enqueued.
        !            14: * We write -1000 (or some magic number less than -(max buffer size)) to the
        !            15:   hw_count register every time we write the hw_curr_desc register.
        !            16: * Once chan_dma_dequeue() is called with DEQUEUE_ALL, further calls specifying
        !            17:   only DEQUEUE_COMPLETED are not guaranteed to return only completed frames.
        !            18:   
        !            19:   
        !            20: chan_dma_dequeue(dequeue_spec_t dequeue_spec) {
        !            21: 
        !            22:        desc = head of software's descriptor chain;
        !            23:        if(direction == DMA_READ) {
        !            24:                if(desc->rem_byte_count != -1) {
        !            25:                        /*
        !            26:                         * Easy case; TE has written the rem_byte_count field, 
        !            27:                         * indicating completion. 
        !            28:                         */
        !            29:                        dequeue_ok = TRUE;
        !            30:                        goto got_one;
        !            31:                }
        !            32:                
        !            33:                /*
        !            34:                 * Continue - this descriptor could still be complete
        !            35:                 * if EOR was not here.
        !            36:                 */
        !            37:        }
        !            38:        if(desc_list_not_empty) {
        !            39:                /*
        !            40:                 * Channel running; another easy case. This descriptor is
        !            41:                 * complete as long as it's not the current descriptor.
        !            42:                 */
        !            43:                if(desc != hw_curr_desc)
        !            44:                        dequeue_ok = TRUE;
        !            45:                else
        !            46:                        dequeue_ok = FALSE;                     
        !            47:        }
        !            48:        else {
        !            49:                /*
        !            50:                 * Channel idle.
        !            51:                 */
        !            52:                if(desc != hw_curr_desc) {
        !            53:                        /*
        !            54:                         * Not current, must be completed.
        !            55:                         */
        !            56:                        dequeue_ok = TRUE;
        !            57:                }
        !            58:                else {  
        !            59:                        /*
        !            60:                         * This descriptor was either the last descriptor
        !            61:                         * serviced by the TE or the next one to be serviced.
        !            62:                         *
        !            63:                         * We write -1000 to hw_count every time we write
        !            64:                         * hw_curr_desc, so if it's still -1000, we know
        !            65:                         * the TE hasn't gotten to this one yet.
        !            66:                         */
        !            67:                        if(hw_count == -1000) {
        !            68:                                dequeue_ok = FALSE;
        !            69:                        }
        !            70:                        else {
        !            71:                                /*
        !            72:                                 * Tricky case. The TE at least started to work
        !            73:                                 * on this descriptor, but we don't know if
        !            74:                                 * any data from this descriptor moved to/from
        !            75:                                 * the device. We have to examine the amount
        !            76:                                 * of data moved from memory and the state of
        !            77:                                 * the TE buffers...
        !            78:                                 */
        !            79:                                if(hw_count between 0 and -(max buffer size)) {
        !            80:                                        /*
        !            81:                                         * This implies completion by the TE.
        !            82:                                         */
        !            83:                                        dequeue_ok = TRUE;
        !            84:                                } 
        !            85:                                else {
        !            86:                                        bytes_moved = desc->count - hw_count;
        !            87:                                                                                                
        !            88:                                        if(direction == DMA_READ) {
        !            89:                                            /*
        !            90:                                             * For data in, any bytes 
        !            91:                                             * transferred
        !            92:                                             * means that the descriptor is
        !            93:                                             * complete.
        !            94:                                             */
        !            95:                                            if(bytes_moved == 0) {
        !            96:                                                got_a_desc = FALSE;
        !            97:                                            }
        !            98:                                            else {
        !            99:                                                got_a_desc = TRUE;
        !           100:                                            }
        !           101:                                            goto got_one;
        !           102:                                        }
        !           103: 
        !           104:                                        if(bytes_moved > (2 * buffer size)) {
        !           105:                                                /*
        !           106:                                                 * some had to move to the
        !           107:                                                 * device.
        !           108:                                                 */
        !           109:                                                dequeue_ok = TRUE;
        !           110:                                        }
        !           111:                                        else if(bytes_moved == 0) {
        !           112:                                                /*
        !           113:                                                 * We haven't touched this 
        !           114:                                                 * descriptor's data.
        !           115:                                                 */
        !           116:                                                dequeue_ok = FALSE;
        !           117:                                        }
        !           118:                                        else if(bytes_moved == 1 buffer) {
        !           119:                                            if(either "buffer full" flag set) {
        !           120:                                                /*
        !           121:                                                 * We couldn't have moved data
        !           122:                                                 * to or from the device.
        !           123:                                                 */
        !           124:                                                dequeue_ok = FALSE;
        !           125:                                            }
        !           126:                                            else {
        !           127:                                                dequeue_ok = TRUE;
        !           128:                                            }
        !           129:                                        }
        !           130:                                        else  {
        !           131:                                            /*
        !           132:                                             * bytes_moved == 2 buffers.
        !           133:                                             */
        !           134:                                            if(BOTH "buffer full" flags set) {
        !           135:                                                dequeue_ok = FALSE;
        !           136:                                            }
        !           137:                                            else {
        !           138:                                                /*
        !           139:                                                 * We moved 2 buffers from 
        !           140:                                                 * memory but at least one
        !           141:                                                 * of the buffers is not full, 
        !           142:                                                 * so some data must have 
        !           143:                                                 * moved to the device.
        !           144:                                                 */
        !           145:                                                dequeue_ok = TRUE;
        !           146:                                            }
        !           147:                                        }
        !           148:                                }
        !           149:                        }
        !           150:                } /* desc == hw_curr */
        !           151:        }         /* channel idle */
        !           152:        
        !           153: got_one:
        !           154: 
        !           155:        /*
        !           156:         * Even if dequeue_ok is FALSE, we can still dequeue if the channel
        !           157:         * isn't running and the caller said they wanted all descriptors.
        !           158:         */
        !           159:        if(!dequeue_ok && 
        !           160:           (channel not running) && 
        !           161:           (dequeue_spec == DEQUEUE_ALL)) {
        !           162:                dequeue_ok = TRUE;
        !           163:        }
        !           164:        if(dequeue_ok) {
        !           165:                grab this desc from s/w chain; 
        !           166:                if this is the last descriptor of a frame {
        !           167:                        dequeue the frame;
        !           168:                        get return parameters from last descriptor;
        !           169:                        unlock the VM associated with this frame;
        !           170:                        free all descriptors and the frame;
        !           171:                }
        !           172:        }
        !           173: }

unix.superglobalmegacorp.com

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