Annotation of driverkit/notes/KernelDMA, revision 1.1

1.1     ! root        1: Kernel DMA notes
        !             2: 
        !             3: 
        !             4: Questions
        !             5: 
        !             6: * Looks like the low-level interrupt code is going to have to be cognizant
        !             7:   of "is this a DMA interrupt?"....?
        !             8:   -- Need to grab chan_status? No, that can be done at chan_XX_dequeue time.
        !             9:      -- no - not valid for m88k!!!
        !            10:   -- Need to maintain separate 'done queue'? Why? Just scan thru queue of
        !            11:      kern_dma_desc_t's or kern_dma_frame_t's at chan_XX_dequeue time.
        !            12:      
        !            13:   ...so: no way!
        !            14:   
        !            15: * Where are DMA overrun and underrun reported???? Referred to at bottom on 
        !            16:   5-14, can't find the bits.
        !            17:   
        !            18: Notes
        !            19: 
        !            20: * use vm_map_check_protection() in vm/vm_map.c to check access.
        !            21:   pmap_extract() to get physical address.
        !            22:   pmap_enter() to create mapping for dev_{reg,slot,board}_map().
        !            23:   
        !            24: * need another return value from dev_get_type() - 'busy'. When true, the 
        !            25:   specified dev_number is valid, but is already in use by an internal driver.
        !            26:   Don't want to return error in this case, it's nice to be able to see what's
        !            27:   there even if Config can't use it. A dev_port_create on such a busy device
        !            28:   should return a new error (DR_ATTACHED).
        !            29:   
        !            30: * kern_dev_t's - a static array of 8. Need to be able to expand? maybe only at
        !            31:   config time? No, this is too inflexible. Make a linked list, stash the
        !            32:   dev_number in the kern_dev_t. Have to map from dev_number to kern_dev very
        !            33:   seldom (get_dev_type, dev_port_create).
        !            34:   
        !            35:   -- besides, don't know size for static array ar config time - need to include
        !            36:      NextBus boards.
        !            37:   
        !            38: Pseuodocode
        !            39: 
        !            40: chan_dma_enqueue() 
        !            41: {
        !            42:        check access of region, return if error;
        !            43:        return error if dma_id is zero;
        !            44:        check for other errors (channel not attached, etc.);
        !            45:        check for (stream mode && > 1 page && read) error
        !            46:        wire the region via vm_map_pageable();
        !            47:        get a dma_frame_t, init it;
        !            48:        for each page or less in vm region {
        !            49:                pmap_extract the physical address;
        !            50:                if direction == read
        !            51:                        cache_invalidate() the region;
        !            52:                else
        !            53:                        cache_purge() the region;
        !            54:                get a dma_descriptor_t;
        !            55:                set up address, byte_count in the descriptor;
        !            56:                link to desc_tail;
        !            57:                desc_tail = this new descriptor;
        !            58:        }
        !            59:        if(opts & CEO_EOR)
        !            60:                set eor in desc_tail's command;
        !            61:        if(opts & DESC_INTR)
        !            62:                set desc_intr in desc_tail's command;
        !            63:        if(opts & CEO_DESC_CMD) 
        !            64:                write cmd and index to desc_tail; set descCmdValid bit;
        !            65:        add frame to end of frame_queue;
        !            66:        enqueue frame's desc_head on current last_frame's desc_tail
        !            67:                using algorithm defined in DMARaces;
        !            68:        if(opts & CEO_ENABLE_INTR)
        !            69:                enable 'em;
        !            70: }
        !            71: 
        !            72: chan_dma_dequeue()
        !            73: {
        !            74:        check for dumb errors (not attached, frame_queue empty, etc.);
        !            75:        got_a_desc = got_a_frame = FALSE;
        !            76:        do {
        !            77:                this_desc = desc_head of head of frame_queue;
        !            78:                
        !            79:                if this_desc can be dequeued {
        !            80:                        got_a_desc = TRUE;
        !            81:                        unlink it from frame.desc_head;
        !            82:                        add bytes_xfr for this_desc to frame's bytes_xfr;
        !            83:                        if((this is desc_tail for this frame)  ||
        !            84:                            EOR || BUFERR) {
        !            85:                                got_a_frame = TRUE;
        !            86:                                write caller's desc_status, eor from this_desc;
        !            87:                        }
        !            88:                        free this_desc;
        !            89:                        if(got_a_frame) {
        !            90:                                /* 
        !            91:                                 * Frame completely dequeued.
        !            92:                                 */
        !            93:                                write caller's dma_id, bcount;
        !            94:                                unwire frame's vm region;
        !            95:                                dequeue frame from frame_queue, free frame;
        !            96:                        }
        !            97:                }
        !            98:                else {
        !            99:                        /*
        !           100:                         * No available descriptor.
        !           101:                         */
        !           102:                        caller's dma_id = NULL;
        !           103:                }
        !           104:        } while(got_a_desc && !got_a_frame);
        !           105:        return success;
        !           106: }
        !           107: 
        !           108: Can desc_head of head of frame_queue be dequeued?
        !           109: 
        !           110: if list_not_empty {
        !           111:        if(desc_head == hw_current_desc)
        !           112:                desc not complete
        !           113:        else
        !           114:                desc complete
        !           115: }
        !           116: else {
        !           117:        if(desc_head == hw_current_desc) {
        !           118:                if(count register == -1)
        !           119:                        this desc is not complete
        !           120:                else
        !           121:                        this desc is complete
        !           122:        }
        !           123:        else
        !           124:                this desc is complete
        !           125: }
        !           126: else 
        !           127: 
        !           128:  cases:
        !           129:  1. Channel running. Easy case. Can dequeue this_desc as long as it's not
        !           130:     hw_current_desc.
        !           131:  2. Channel not running. 
        !           132:     a. CDO_ALL: any desc can be dequeued.
        !           133:     b. CDO_DONE: how to tell what's done? if this_desc == hw_current_desc, 
        !           134:        is this_desc the last one the TE processed, or the next one (maybe
        !           135:        it's just been enqueued)?
        !           136:        
        !           137:        Can we use the TE count register to see if it's fetched a
        !           138:        descriptor since we last enqueued...?
        !           139:                
        !           140:                eg
        !           141:                
        !           142:                channel not running
        !           143:                chan_dma_enqueue 
        !           144:                        build & enqueue a list (say one descriptor)
        !           145:                        write -1 to count register
        !           146:                driver enables channel & loads descriptor
        !           147:                TE writes count register with something other than -1
        !           148:                DMA complete
        !           149:                chan_dma_dequeue(CDO_DONE)
        !           150:                    if channel not running {
        !           151:                        if(desc_head == hw_current_desc) {
        !           152:                            if(count register == -1)
        !           153:                                this desc is not complete
        !           154:                            else
        !           155:                                this desc is complete
        !           156:                        }
        !           157:                    }
        !           158:                    else
        !           159:                        if(desc_head == hw_current_desc)
        !           160:                                desc not complete
        !           161:                        else
        !           162:                                desc complete
        !           163:                    
        !           164: 
        !           165: Careful - anytime you dequeue a descriptor which is the same as hw_current_desc, have to either NULL out hw_current_desc or write it with desc_head of the next *frame* (NOT the next descriptor in this frame!)
        !           166: 
        !           167: What about dequeueing a whole list of descriptors (in "CDO_DONE mode") and we get to desc == hw_current_desc, and the channel isn't running?
        !           168:   -- if we have NOT done an enqueue since the channel stopped, hw_count != -1
        !           169:      ==> this desc (@ hw_curr_desc) is done! (hw_next_desc should be NULL...)
        !           170:   -- if we HAVE done enqueue since channel stopped, hw_count == -1
        !           171:      ==> this desc is head of h/w's queue. Not done.
        !           172:   

unix.superglobalmegacorp.com

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