|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.