|
|
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.