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