| @@ -1,786 +1,790 @@ | | | @@ -1,786 +1,790 @@ |
1 | /* $NetBSD: isadma.c,v 1.66 2010/11/13 13:52:03 uebayasi Exp $ */ | | 1 | /* $NetBSD: isadma.c,v 1.66.52.1 2018/06/07 19:39:54 martin Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, | | 8 | * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, |
9 | * NASA Ames Research Center. | | 9 | * NASA Ames Research Center. |
10 | * | | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | | 11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions | | 12 | * modification, are permitted provided that the following conditions |
13 | * are met: | | 13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright | | 14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions and the following disclaimer. | | 15 | * notice, this list of conditions and the following disclaimer. |
16 | * 2. Redistributions in binary form must reproduce the above copyright | | 16 | * 2. Redistributions in binary form must reproduce the above copyright |
17 | * notice, this list of conditions and the following disclaimer in the | | 17 | * notice, this list of conditions and the following disclaimer in the |
18 | * documentation and/or other materials provided with the distribution. | | 18 | * documentation and/or other materials provided with the distribution. |
19 | * | | 19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. | | 30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | /* | | 33 | /* |
34 | * Device driver for the ISA on-board DMA controller. | | 34 | * Device driver for the ISA on-board DMA controller. |
35 | */ | | 35 | */ |
36 | | | 36 | |
37 | #include <sys/cdefs.h> | | 37 | #include <sys/cdefs.h> |
38 | __KERNEL_RCSID(0, "$NetBSD: isadma.c,v 1.66 2010/11/13 13:52:03 uebayasi Exp $"); | | 38 | __KERNEL_RCSID(0, "$NetBSD: isadma.c,v 1.66.52.1 2018/06/07 19:39:54 martin Exp $"); |
39 | | | 39 | |
40 | #include <sys/param.h> | | 40 | #include <sys/param.h> |
41 | #include <sys/systm.h> | | 41 | #include <sys/systm.h> |
42 | #include <sys/proc.h> | | 42 | #include <sys/proc.h> |
43 | #include <sys/device.h> | | 43 | #include <sys/device.h> |
44 | #include <sys/malloc.h> | | 44 | #include <sys/malloc.h> |
45 | | | 45 | |
46 | #include <sys/bus.h> | | 46 | #include <sys/bus.h> |
47 | | | 47 | |
48 | #include <dev/isa/isareg.h> | | 48 | #include <dev/isa/isareg.h> |
49 | #include <dev/isa/isavar.h> | | 49 | #include <dev/isa/isavar.h> |
50 | #include <dev/isa/isadmavar.h> | | 50 | #include <dev/isa/isadmavar.h> |
51 | #include <dev/isa/isadmareg.h> | | 51 | #include <dev/isa/isadmareg.h> |
52 | | | 52 | |
53 | struct isa_mem *isa_mem_head; | | 53 | struct isa_mem *isa_mem_head; |
54 | | | 54 | |
55 | /* | | 55 | /* |
56 | * High byte of DMA address is stored in this DMAPG register for | | 56 | * DMA Channel to Address Page Register offset mapping |
57 | * the Nth DMA channel. | | 57 | * |
| | | 58 | * Offset from IO_DMAPG is stored in this 2D array -- first dimension is |
| | | 59 | * the DMA controller, second dimension is the DMA channel. |
| | | 60 | * |
| | | 61 | * e.g. dmapageport[0][1] gives us the offset for DMA ch 1 on DMA1 |
58 | */ | | 62 | */ |
59 | static int dmapageport[2][4] = { | | 63 | static const int dmapageport[2][4] = { |
60 | {0x7, 0x3, 0x1, 0x2}, | | 64 | {0x6, 0x2, 0x0, 0x1}, |
61 | {0xf, 0xb, 0x9, 0xa} | | 65 | {0xe, 0xa, 0x8, 0x9} |
62 | }; | | 66 | }; |
63 | | | 67 | |
64 | static u_int8_t dmamode[] = { | | 68 | static const u_int8_t dmamode[] = { |
65 | /* write to device/read from device */ | | 69 | /* write to device/read from device */ |
66 | DMA37MD_READ | DMA37MD_SINGLE, | | 70 | DMA37MD_READ | DMA37MD_SINGLE, |
67 | DMA37MD_WRITE | DMA37MD_SINGLE, | | 71 | DMA37MD_WRITE | DMA37MD_SINGLE, |
68 | | | 72 | |
69 | /* write to device/read from device */ | | 73 | /* write to device/read from device */ |
70 | DMA37MD_READ | DMA37MD_DEMAND, | | 74 | DMA37MD_READ | DMA37MD_DEMAND, |
71 | DMA37MD_WRITE | DMA37MD_DEMAND, | | 75 | DMA37MD_WRITE | DMA37MD_DEMAND, |
72 | | | 76 | |
73 | /* write to device/read from device - DMAMODE_LOOP */ | | 77 | /* write to device/read from device - DMAMODE_LOOP */ |
74 | DMA37MD_READ | DMA37MD_SINGLE | DMA37MD_LOOP, | | 78 | DMA37MD_READ | DMA37MD_SINGLE | DMA37MD_LOOP, |
75 | DMA37MD_WRITE | DMA37MD_SINGLE | DMA37MD_LOOP, | | 79 | DMA37MD_WRITE | DMA37MD_SINGLE | DMA37MD_LOOP, |
76 | | | 80 | |
77 | /* write to device/read from device - DMAMODE_LOOPDEMAND */ | | 81 | /* write to device/read from device - DMAMODE_LOOPDEMAND */ |
78 | DMA37MD_READ | DMA37MD_DEMAND | DMA37MD_LOOP, | | 82 | DMA37MD_READ | DMA37MD_DEMAND | DMA37MD_LOOP, |
79 | DMA37MD_WRITE | DMA37MD_DEMAND | DMA37MD_LOOP, | | 83 | DMA37MD_WRITE | DMA37MD_DEMAND | DMA37MD_LOOP, |
80 | }; | | 84 | }; |
81 | | | 85 | |
82 | static inline void _isa_dmaunmask(struct isa_dma_state *, int); | | 86 | static inline void _isa_dmaunmask(struct isa_dma_state *, int); |
83 | static inline void _isa_dmamask(struct isa_dma_state *, int); | | 87 | static inline void _isa_dmamask(struct isa_dma_state *, int); |
84 | | | 88 | |
85 | static inline void | | 89 | static inline void |
86 | _isa_dmaunmask(struct isa_dma_state *ids, int chan) | | 90 | _isa_dmaunmask(struct isa_dma_state *ids, int chan) |
87 | { | | 91 | { |
88 | int ochan = chan & 3; | | 92 | int ochan = chan & 3; |
89 | | | 93 | |
90 | ISA_DMA_MASK_CLR(ids, chan); | | 94 | ISA_DMA_MASK_CLR(ids, chan); |
91 | | | 95 | |
92 | /* | | 96 | /* |
93 | * If DMA is frozen, don't unmask it now. It will be | | 97 | * If DMA is frozen, don't unmask it now. It will be |
94 | * unmasked when DMA is thawed again. | | 98 | * unmasked when DMA is thawed again. |
95 | */ | | 99 | */ |
96 | if (ids->ids_frozen) | | 100 | if (ids->ids_frozen) |
97 | return; | | 101 | return; |
98 | | | 102 | |
99 | /* set dma channel mode, and set dma channel mode */ | | 103 | /* set dma channel mode, and set dma channel mode */ |
100 | if ((chan & 4) == 0) | | 104 | if ((chan & 4) == 0) |
101 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, | | 105 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, |
102 | DMA1_SMSK, ochan | DMA37SM_CLEAR); | | 106 | DMA1_SMSK, ochan | DMA37SM_CLEAR); |
103 | else | | 107 | else |
104 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, | | 108 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, |
105 | DMA2_SMSK, ochan | DMA37SM_CLEAR); | | 109 | DMA2_SMSK, ochan | DMA37SM_CLEAR); |
106 | } | | 110 | } |
107 | | | 111 | |
108 | static inline void | | 112 | static inline void |
109 | _isa_dmamask(struct isa_dma_state *ids, int chan) | | 113 | _isa_dmamask(struct isa_dma_state *ids, int chan) |
110 | { | | 114 | { |
111 | int ochan = chan & 3; | | 115 | int ochan = chan & 3; |
112 | | | 116 | |
113 | ISA_DMA_MASK_SET(ids, chan); | | 117 | ISA_DMA_MASK_SET(ids, chan); |
114 | | | 118 | |
115 | /* | | 119 | /* |
116 | * XXX Should we avoid masking the channel if DMA is | | 120 | * XXX Should we avoid masking the channel if DMA is |
117 | * XXX frozen? It seems like what we're doing should | | 121 | * XXX frozen? It seems like what we're doing should |
118 | * XXX be safe, and we do need to reset FFC... | | 122 | * XXX be safe, and we do need to reset FFC... |
119 | */ | | 123 | */ |
120 | | | 124 | |
121 | /* set dma channel mode, and set dma channel mode */ | | 125 | /* set dma channel mode, and set dma channel mode */ |
122 | if ((chan & 4) == 0) { | | 126 | if ((chan & 4) == 0) { |
123 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, | | 127 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, |
124 | DMA1_SMSK, ochan | DMA37SM_SET); | | 128 | DMA1_SMSK, ochan | DMA37SM_SET); |
125 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, | | 129 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, |
126 | DMA1_FFC, 0); | | 130 | DMA1_FFC, 0); |
127 | } else { | | 131 | } else { |
128 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, | | 132 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, |
129 | DMA2_SMSK, ochan | DMA37SM_SET); | | 133 | DMA2_SMSK, ochan | DMA37SM_SET); |
130 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, | | 134 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, |
131 | DMA2_FFC, 0); | | 135 | DMA2_FFC, 0); |
132 | } | | 136 | } |
133 | } | | 137 | } |
134 | | | 138 | |
135 | /* | | 139 | /* |
136 | * _isa_dmainit(): Initialize the isa_dma_state for this chipset. | | 140 | * _isa_dmainit(): Initialize the isa_dma_state for this chipset. |
137 | */ | | 141 | */ |
138 | void | | 142 | void |
139 | _isa_dmainit(struct isa_dma_state *ids, bus_space_tag_t bst, bus_dma_tag_t dmat, device_t dev) | | 143 | _isa_dmainit(struct isa_dma_state *ids, bus_space_tag_t bst, bus_dma_tag_t dmat, device_t dev) |
140 | { | | 144 | { |
141 | int chan; | | 145 | int chan; |
142 | | | 146 | |
143 | ids->ids_dev = dev; | | 147 | ids->ids_dev = dev; |
144 | | | 148 | |
145 | if (ids->ids_initialized) { | | 149 | if (ids->ids_initialized) { |
146 | /* | | 150 | /* |
147 | * Some systems may have e.g. `ofisa' (OpenFirmware | | 151 | * Some systems may have e.g. `ofisa' (OpenFirmware |
148 | * configuration of ISA bus) and a regular `isa'. | | 152 | * configuration of ISA bus) and a regular `isa'. |
149 | * We allow both to call the initialization function, | | 153 | * We allow both to call the initialization function, |
150 | * and take the device name from the last caller | | 154 | * and take the device name from the last caller |
151 | * (assuming it will be the indirect ISA bus). Since | | 155 | * (assuming it will be the indirect ISA bus). Since |
152 | * `ofisa' and `isa' are the same bus with different | | 156 | * `ofisa' and `isa' are the same bus with different |
153 | * configuration mechanisms, the space and dma tags | | 157 | * configuration mechanisms, the space and dma tags |
154 | * must be the same! | | 158 | * must be the same! |
155 | */ | | 159 | */ |
156 | if (!bus_space_is_equal(ids->ids_bst, bst) || | | 160 | if (!bus_space_is_equal(ids->ids_bst, bst) || |
157 | ids->ids_dmat != dmat) | | 161 | ids->ids_dmat != dmat) |
158 | panic("_isa_dmainit: inconsistent ISA tags"); | | 162 | panic("_isa_dmainit: inconsistent ISA tags"); |
159 | } else { | | 163 | } else { |
160 | ids->ids_bst = bst; | | 164 | ids->ids_bst = bst; |
161 | ids->ids_dmat = dmat; | | 165 | ids->ids_dmat = dmat; |
162 | | | 166 | |
163 | /* | | 167 | /* |
164 | * Map the registers used by the ISA DMA controller. | | 168 | * Map the registers used by the ISA DMA controller. |
165 | */ | | 169 | */ |
166 | if (bus_space_map(ids->ids_bst, IO_DMA1, DMA1_IOSIZE, 0, | | 170 | if (bus_space_map(ids->ids_bst, IO_DMA1, DMA1_IOSIZE, 0, |
167 | &ids->ids_dma1h)) | | 171 | &ids->ids_dma1h)) |
168 | panic("_isa_dmainit: unable to map DMA controller #1"); | | 172 | panic("_isa_dmainit: unable to map DMA controller #1"); |
169 | if (bus_space_map(ids->ids_bst, IO_DMA2, DMA2_IOSIZE, 0, | | 173 | if (bus_space_map(ids->ids_bst, IO_DMA2, DMA2_IOSIZE, 0, |
170 | &ids->ids_dma2h)) | | 174 | &ids->ids_dma2h)) |
171 | panic("_isa_dmainit: unable to map DMA controller #2"); | | 175 | panic("_isa_dmainit: unable to map DMA controller #2"); |
172 | if (bus_space_map(ids->ids_bst, IO_DMAPG, 0xf, 0, | | 176 | if (bus_space_map(ids->ids_bst, IO_DMAPG, DMAPG_IOSIZE, 0, |
173 | &ids->ids_dmapgh)) | | 177 | &ids->ids_dmapgh)) |
174 | panic("_isa_dmainit: unable to map DMA page registers"); | | 178 | panic("_isa_dmainit: unable to map DMA page registers"); |
175 | | | 179 | |
176 | /* | | 180 | /* |
177 | * All 8 DMA channels start out "masked". | | 181 | * All 8 DMA channels start out "masked". |
178 | */ | | 182 | */ |
179 | ids->ids_masked = 0xff; | | 183 | ids->ids_masked = 0xff; |
180 | | | 184 | |
181 | /* | | 185 | /* |
182 | * Initialize the max transfer size for each channel, if | | 186 | * Initialize the max transfer size for each channel, if |
183 | * it is not initialized already (i.e. by a bus-dependent | | 187 | * it is not initialized already (i.e. by a bus-dependent |
184 | * front-end). | | 188 | * front-end). |
185 | */ | | 189 | */ |
186 | for (chan = 0; chan < 8; chan++) { | | 190 | for (chan = 0; chan < 8; chan++) { |
187 | if (ids->ids_maxsize[chan] == 0) | | 191 | if (ids->ids_maxsize[chan] == 0) |
188 | ids->ids_maxsize[chan] = | | 192 | ids->ids_maxsize[chan] = |
189 | ISA_DMA_MAXSIZE_DEFAULT(chan); | | 193 | ISA_DMA_MAXSIZE_DEFAULT(chan); |
190 | } | | 194 | } |
191 | | | 195 | |
192 | ids->ids_initialized = 1; | | 196 | ids->ids_initialized = 1; |
193 | | | 197 | |
194 | /* | | 198 | /* |
195 | * DRQ 4 is used to chain the two 8237s together; make | | 199 | * DRQ 4 is used to chain the two 8237s together; make |
196 | * sure it's always cascaded, and that it will be unmasked | | 200 | * sure it's always cascaded, and that it will be unmasked |
197 | * when DMA is thawed. | | 201 | * when DMA is thawed. |
198 | */ | | 202 | */ |
199 | _isa_dmacascade(ids, 4); | | 203 | _isa_dmacascade(ids, 4); |
200 | } | | 204 | } |
201 | } | | 205 | } |
202 | | | 206 | |
203 | void | | 207 | void |
204 | _isa_dmadestroy(struct isa_dma_state *ids) | | 208 | _isa_dmadestroy(struct isa_dma_state *ids) |
205 | { | | 209 | { |
206 | if (!ids->ids_initialized) | | 210 | if (!ids->ids_initialized) |
207 | return; | | 211 | return; |
208 | | | 212 | |
209 | _isa_dmacascade_stop(ids, 4); | | 213 | _isa_dmacascade_stop(ids, 4); |
210 | | | 214 | |
211 | /* | | 215 | /* |
212 | * Unmap the registers used by the ISA DMA controller. | | 216 | * Unmap the registers used by the ISA DMA controller. |
213 | */ | | 217 | */ |
214 | bus_space_unmap(ids->ids_bst, ids->ids_dmapgh, 0xf); | | 218 | bus_space_unmap(ids->ids_bst, ids->ids_dmapgh, DMAPG_IOSIZE); |
215 | bus_space_unmap(ids->ids_bst, ids->ids_dma2h, DMA2_IOSIZE); | | 219 | bus_space_unmap(ids->ids_bst, ids->ids_dma2h, DMA2_IOSIZE); |
216 | bus_space_unmap(ids->ids_bst, ids->ids_dma1h, DMA1_IOSIZE); | | 220 | bus_space_unmap(ids->ids_bst, ids->ids_dma1h, DMA1_IOSIZE); |
217 | | | 221 | |
218 | ids->ids_initialized = 0; | | 222 | ids->ids_initialized = 0; |
219 | } | | 223 | } |
220 | | | 224 | |
221 | /* | | 225 | /* |
222 | * _isa_dmacascade(): program 8237 DMA controller channel to accept | | 226 | * _isa_dmacascade(): program 8237 DMA controller channel to accept |
223 | * external dma control by a board. | | 227 | * external dma control by a board. |
224 | */ | | 228 | */ |
225 | int | | 229 | int |
226 | _isa_dmacascade(struct isa_dma_state *ids, int chan) | | 230 | _isa_dmacascade(struct isa_dma_state *ids, int chan) |
227 | { | | 231 | { |
228 | int ochan = chan & 3; | | 232 | int ochan = chan & 3; |
229 | | | 233 | |
230 | if (chan < 0 || chan > 7) { | | 234 | if (chan < 0 || chan > 7) { |
231 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); | | 235 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); |
232 | return (EINVAL); | | 236 | return (EINVAL); |
233 | } | | 237 | } |
234 | | | 238 | |
235 | if (!ISA_DMA_DRQ_ISFREE(ids, chan)) { | | 239 | if (!ISA_DMA_DRQ_ISFREE(ids, chan)) { |
236 | printf("%s: DRQ %d is not free\n", device_xname(ids->ids_dev), | | 240 | printf("%s: DRQ %d is not free\n", device_xname(ids->ids_dev), |
237 | chan); | | 241 | chan); |
238 | return (EAGAIN); | | 242 | return (EAGAIN); |
239 | } | | 243 | } |
240 | | | 244 | |
241 | ISA_DMA_DRQ_ALLOC(ids, chan); | | 245 | ISA_DMA_DRQ_ALLOC(ids, chan); |
242 | | | 246 | |
243 | /* set dma channel mode, and set dma channel mode */ | | 247 | /* set dma channel mode, and set dma channel mode */ |
244 | if ((chan & 4) == 0) | | 248 | if ((chan & 4) == 0) |
245 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, | | 249 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, |
246 | DMA1_MODE, ochan | DMA37MD_CASCADE); | | 250 | DMA1_MODE, ochan | DMA37MD_CASCADE); |
247 | else | | 251 | else |
248 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, | | 252 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, |
249 | DMA2_MODE, ochan | DMA37MD_CASCADE); | | 253 | DMA2_MODE, ochan | DMA37MD_CASCADE); |
250 | | | 254 | |
251 | _isa_dmaunmask(ids, chan); | | 255 | _isa_dmaunmask(ids, chan); |
252 | return (0); | | 256 | return (0); |
253 | } | | 257 | } |
254 | | | 258 | |
255 | /* | | 259 | /* |
256 | * _isa_dmacascade_stop(): turn off cascading on the 8237 DMA controller channel | | 260 | * _isa_dmacascade_stop(): turn off cascading on the 8237 DMA controller channel |
257 | * external dma control by a board. | | 261 | * external dma control by a board. |
258 | */ | | 262 | */ |
259 | int | | 263 | int |
260 | _isa_dmacascade_stop(struct isa_dma_state *ids, int chan) | | 264 | _isa_dmacascade_stop(struct isa_dma_state *ids, int chan) |
261 | { | | 265 | { |
262 | if (chan < 0 || chan > 7) { | | 266 | if (chan < 0 || chan > 7) { |
263 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); | | 267 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); |
264 | return EINVAL; | | 268 | return EINVAL; |
265 | } | | 269 | } |
266 | | | 270 | |
267 | if (ISA_DMA_DRQ_ISFREE(ids, chan)) | | 271 | if (ISA_DMA_DRQ_ISFREE(ids, chan)) |
268 | return 0; | | 272 | return 0; |
269 | | | 273 | |
270 | _isa_dmamask(ids, chan); | | 274 | _isa_dmamask(ids, chan); |
271 | | | 275 | |
272 | ISA_DMA_DRQ_FREE(ids, chan); | | 276 | ISA_DMA_DRQ_FREE(ids, chan); |
273 | | | 277 | |
274 | return 0; | | 278 | return 0; |
275 | } | | 279 | } |
276 | | | 280 | |
277 | int | | 281 | int |
278 | _isa_drq_alloc(struct isa_dma_state *ids, int chan) | | 282 | _isa_drq_alloc(struct isa_dma_state *ids, int chan) |
279 | { | | 283 | { |
280 | if (!ISA_DMA_DRQ_ISFREE(ids, chan)) | | 284 | if (!ISA_DMA_DRQ_ISFREE(ids, chan)) |
281 | return EBUSY; | | 285 | return EBUSY; |
282 | ISA_DMA_DRQ_ALLOC(ids, chan); | | 286 | ISA_DMA_DRQ_ALLOC(ids, chan); |
283 | return 0; | | 287 | return 0; |
284 | } | | 288 | } |
285 | | | 289 | |
286 | int | | 290 | int |
287 | _isa_drq_free(struct isa_dma_state *ids, int chan) | | 291 | _isa_drq_free(struct isa_dma_state *ids, int chan) |
288 | { | | 292 | { |
289 | if (ISA_DMA_DRQ_ISFREE(ids, chan)) | | 293 | if (ISA_DMA_DRQ_ISFREE(ids, chan)) |
290 | return EINVAL; | | 294 | return EINVAL; |
291 | ISA_DMA_DRQ_FREE(ids, chan); | | 295 | ISA_DMA_DRQ_FREE(ids, chan); |
292 | return 0; | | 296 | return 0; |
293 | } | | 297 | } |
294 | | | 298 | |
295 | bus_size_t | | 299 | bus_size_t |
296 | _isa_dmamaxsize(struct isa_dma_state *ids, int chan) | | 300 | _isa_dmamaxsize(struct isa_dma_state *ids, int chan) |
297 | { | | 301 | { |
298 | | | 302 | |
299 | if (chan < 0 || chan > 7) { | | 303 | if (chan < 0 || chan > 7) { |
300 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); | | 304 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); |
301 | return (0); | | 305 | return (0); |
302 | } | | 306 | } |
303 | | | 307 | |
304 | return (ids->ids_maxsize[chan]); | | 308 | return (ids->ids_maxsize[chan]); |
305 | } | | 309 | } |
306 | | | 310 | |
307 | int | | 311 | int |
308 | _isa_dmamap_create(struct isa_dma_state *ids, int chan, bus_size_t size, int flags) | | 312 | _isa_dmamap_create(struct isa_dma_state *ids, int chan, bus_size_t size, int flags) |
309 | { | | 313 | { |
310 | int error; | | 314 | int error; |
311 | | | 315 | |
312 | if (chan < 0 || chan > 7) { | | 316 | if (chan < 0 || chan > 7) { |
313 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); | | 317 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); |
314 | return (EINVAL); | | 318 | return (EINVAL); |
315 | } | | 319 | } |
316 | | | 320 | |
317 | if (size > ids->ids_maxsize[chan]) | | 321 | if (size > ids->ids_maxsize[chan]) |
318 | return (EINVAL); | | 322 | return (EINVAL); |
319 | | | 323 | |
320 | error = bus_dmamap_create(ids->ids_dmat, size, 1, size, | | 324 | error = bus_dmamap_create(ids->ids_dmat, size, 1, size, |
321 | ids->ids_maxsize[chan], flags, &ids->ids_dmamaps[chan]); | | 325 | ids->ids_maxsize[chan], flags, &ids->ids_dmamaps[chan]); |
322 | | | 326 | |
323 | return (error); | | 327 | return (error); |
324 | } | | 328 | } |
325 | | | 329 | |
326 | void | | 330 | void |
327 | _isa_dmamap_destroy(struct isa_dma_state *ids, int chan) | | 331 | _isa_dmamap_destroy(struct isa_dma_state *ids, int chan) |
328 | { | | 332 | { |
329 | | | 333 | |
330 | if (chan < 0 || chan > 7) { | | 334 | if (chan < 0 || chan > 7) { |
331 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); | | 335 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); |
332 | goto lose; | | 336 | goto lose; |
333 | } | | 337 | } |
334 | | | 338 | |
335 | bus_dmamap_destroy(ids->ids_dmat, ids->ids_dmamaps[chan]); | | 339 | bus_dmamap_destroy(ids->ids_dmat, ids->ids_dmamaps[chan]); |
336 | return; | | 340 | return; |
337 | | | 341 | |
338 | lose: | | 342 | lose: |
339 | panic("_isa_dmamap_destroy"); | | 343 | panic("_isa_dmamap_destroy"); |
340 | } | | 344 | } |
341 | | | 345 | |
342 | /* | | 346 | /* |
343 | * _isa_dmastart(): program 8237 DMA controller channel and set it | | 347 | * _isa_dmastart(): program 8237 DMA controller channel and set it |
344 | * in motion. | | 348 | * in motion. |
345 | */ | | 349 | */ |
346 | int | | 350 | int |
347 | _isa_dmastart(struct isa_dma_state *ids, int chan, void *addr, bus_size_t nbytes, struct proc *p, int flags, int busdmaflags) | | 351 | _isa_dmastart(struct isa_dma_state *ids, int chan, void *addr, bus_size_t nbytes, struct proc *p, int flags, int busdmaflags) |
348 | { | | 352 | { |
349 | bus_dmamap_t dmam; | | 353 | bus_dmamap_t dmam; |
350 | bus_addr_t dmaaddr; | | 354 | bus_addr_t dmaaddr; |
351 | int waport; | | 355 | int waport; |
352 | int ochan = chan & 3; | | 356 | int ochan = chan & 3; |
353 | int error; | | 357 | int error; |
354 | | | 358 | |
355 | if (chan < 0 || chan > 7) { | | 359 | if (chan < 0 || chan > 7) { |
356 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); | | 360 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); |
357 | goto lose; | | 361 | goto lose; |
358 | } | | 362 | } |
359 | | | 363 | |
360 | #ifdef ISADMA_DEBUG | | 364 | #ifdef ISADMA_DEBUG |
361 | printf("_isa_dmastart: drq %d, addr %p, nbytes 0x%lx, p %p, " | | 365 | printf("_isa_dmastart: drq %d, addr %p, nbytes 0x%lx, p %p, " |
362 | "flags 0x%x, dmaflags 0x%x\n", | | 366 | "flags 0x%x, dmaflags 0x%x\n", |
363 | chan, addr, (u_long)nbytes, p, flags, busdmaflags); | | 367 | chan, addr, (u_long)nbytes, p, flags, busdmaflags); |
364 | #endif | | 368 | #endif |
365 | | | 369 | |
366 | if (ISA_DMA_DRQ_ISFREE(ids, chan)) { | | 370 | if (ISA_DMA_DRQ_ISFREE(ids, chan)) { |
367 | printf("%s: dma start on free channel %d\n", | | 371 | printf("%s: dma start on free channel %d\n", |
368 | device_xname(ids->ids_dev), chan); | | 372 | device_xname(ids->ids_dev), chan); |
369 | goto lose; | | 373 | goto lose; |
370 | } | | 374 | } |
371 | | | 375 | |
372 | if (chan & 4) { | | 376 | if (chan & 4) { |
373 | if (nbytes > (1 << 17) || nbytes & 1 || (u_long)addr & 1) { | | 377 | if (nbytes > (1 << 17) || nbytes & 1 || (u_long)addr & 1) { |
374 | printf("%s: drq %d, nbytes 0x%lx, addr %p\n", | | 378 | printf("%s: drq %d, nbytes 0x%lx, addr %p\n", |
375 | device_xname(ids->ids_dev), chan, | | 379 | device_xname(ids->ids_dev), chan, |
376 | (unsigned long) nbytes, addr); | | 380 | (unsigned long) nbytes, addr); |
377 | goto lose; | | 381 | goto lose; |
378 | } | | 382 | } |
379 | } else { | | 383 | } else { |
380 | if (nbytes > (1 << 16)) { | | 384 | if (nbytes > (1 << 16)) { |
381 | printf("%s: drq %d, nbytes 0x%lx\n", | | 385 | printf("%s: drq %d, nbytes 0x%lx\n", |
382 | device_xname(ids->ids_dev), chan, | | 386 | device_xname(ids->ids_dev), chan, |
383 | (unsigned long) nbytes); | | 387 | (unsigned long) nbytes); |
384 | goto lose; | | 388 | goto lose; |
385 | } | | 389 | } |
386 | } | | 390 | } |
387 | | | 391 | |
388 | dmam = ids->ids_dmamaps[chan]; | | 392 | dmam = ids->ids_dmamaps[chan]; |
389 | if (dmam == NULL) | | 393 | if (dmam == NULL) |
390 | panic("_isa_dmastart: no DMA map for chan %d", chan); | | 394 | panic("_isa_dmastart: no DMA map for chan %d", chan); |
391 | | | 395 | |
392 | error = bus_dmamap_load(ids->ids_dmat, dmam, addr, nbytes, | | 396 | error = bus_dmamap_load(ids->ids_dmat, dmam, addr, nbytes, |
393 | p, busdmaflags | | | 397 | p, busdmaflags | |
394 | ((flags & DMAMODE_READ) ? BUS_DMA_READ : BUS_DMA_WRITE)); | | 398 | ((flags & DMAMODE_READ) ? BUS_DMA_READ : BUS_DMA_WRITE)); |
395 | if (error) | | 399 | if (error) |
396 | return (error); | | 400 | return (error); |
397 | | | 401 | |
398 | #ifdef ISADMA_DEBUG | | 402 | #ifdef ISADMA_DEBUG |
399 | __asm(".globl isa_dmastart_afterload ; isa_dmastart_afterload:"); | | 403 | __asm(".globl isa_dmastart_afterload ; isa_dmastart_afterload:"); |
400 | #endif | | 404 | #endif |
401 | | | 405 | |
402 | if (flags & DMAMODE_READ) { | | 406 | if (flags & DMAMODE_READ) { |
403 | bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize, | | 407 | bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize, |
404 | BUS_DMASYNC_PREREAD); | | 408 | BUS_DMASYNC_PREREAD); |
405 | ids->ids_dmareads |= (1 << chan); | | 409 | ids->ids_dmareads |= (1 << chan); |
406 | } else { | | 410 | } else { |
407 | bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize, | | 411 | bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize, |
408 | BUS_DMASYNC_PREWRITE); | | 412 | BUS_DMASYNC_PREWRITE); |
409 | ids->ids_dmareads &= ~(1 << chan); | | 413 | ids->ids_dmareads &= ~(1 << chan); |
410 | } | | 414 | } |
411 | | | 415 | |
412 | dmaaddr = dmam->dm_segs[0].ds_addr; | | 416 | dmaaddr = dmam->dm_segs[0].ds_addr; |
413 | | | 417 | |
414 | #ifdef ISADMA_DEBUG | | 418 | #ifdef ISADMA_DEBUG |
415 | printf(" dmaaddr %#" PRIxPADDR "\n", dmaaddr); | | 419 | printf(" dmaaddr %#" PRIxPADDR "\n", dmaaddr); |
416 | | | 420 | |
417 | __asm(".globl isa_dmastart_aftersync ; isa_dmastart_aftersync:"); | | 421 | __asm(".globl isa_dmastart_aftersync ; isa_dmastart_aftersync:"); |
418 | #endif | | 422 | #endif |
419 | | | 423 | |
420 | ids->ids_dmalength[chan] = nbytes; | | 424 | ids->ids_dmalength[chan] = nbytes; |
421 | | | 425 | |
422 | _isa_dmamask(ids, chan); | | 426 | _isa_dmamask(ids, chan); |
423 | ids->ids_dmafinished &= ~(1 << chan); | | 427 | ids->ids_dmafinished &= ~(1 << chan); |
424 | | | 428 | |
425 | if ((chan & 4) == 0) { | | 429 | if ((chan & 4) == 0) { |
426 | /* set dma channel mode */ | | 430 | /* set dma channel mode */ |
427 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, DMA1_MODE, | | 431 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, DMA1_MODE, |
428 | ochan | dmamode[flags]); | | 432 | ochan | dmamode[flags]); |
429 | | | 433 | |
430 | /* send start address */ | | 434 | /* send start address */ |
431 | waport = DMA1_CHN(ochan); | | 435 | waport = DMA1_CHN(ochan); |
432 | bus_space_write_1(ids->ids_bst, ids->ids_dmapgh, | | 436 | bus_space_write_1(ids->ids_bst, ids->ids_dmapgh, |
433 | dmapageport[0][ochan], (dmaaddr >> 16) & 0xff); | | 437 | dmapageport[0][ochan], (dmaaddr >> 16) & 0xff); |
434 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport, | | 438 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport, |
435 | dmaaddr & 0xff); | | 439 | dmaaddr & 0xff); |
436 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport, | | 440 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport, |
437 | (dmaaddr >> 8) & 0xff); | | 441 | (dmaaddr >> 8) & 0xff); |
438 | | | 442 | |
439 | /* send count */ | | 443 | /* send count */ |
440 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport + 1, | | 444 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport + 1, |
441 | (--nbytes) & 0xff); | | 445 | (--nbytes) & 0xff); |
442 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport + 1, | | 446 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, waport + 1, |
443 | (nbytes >> 8) & 0xff); | | 447 | (nbytes >> 8) & 0xff); |
444 | } else { | | 448 | } else { |
445 | /* set dma channel mode */ | | 449 | /* set dma channel mode */ |
446 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, DMA2_MODE, | | 450 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, DMA2_MODE, |
447 | ochan | dmamode[flags]); | | 451 | ochan | dmamode[flags]); |
448 | | | 452 | |
449 | /* send start address */ | | 453 | /* send start address */ |
450 | waport = DMA2_CHN(ochan); | | 454 | waport = DMA2_CHN(ochan); |
451 | bus_space_write_1(ids->ids_bst, ids->ids_dmapgh, | | 455 | bus_space_write_1(ids->ids_bst, ids->ids_dmapgh, |
452 | dmapageport[1][ochan], (dmaaddr >> 16) & 0xff); | | 456 | dmapageport[1][ochan], (dmaaddr >> 16) & 0xff); |
453 | dmaaddr >>= 1; | | 457 | dmaaddr >>= 1; |
454 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport, | | 458 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport, |
455 | dmaaddr & 0xff); | | 459 | dmaaddr & 0xff); |
456 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport, | | 460 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport, |
457 | (dmaaddr >> 8) & 0xff); | | 461 | (dmaaddr >> 8) & 0xff); |
458 | | | 462 | |
459 | /* send count */ | | 463 | /* send count */ |
460 | nbytes >>= 1; | | 464 | nbytes >>= 1; |
461 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport + 2, | | 465 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport + 2, |
462 | (--nbytes) & 0xff); | | 466 | (--nbytes) & 0xff); |
463 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport + 2, | | 467 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, waport + 2, |
464 | (nbytes >> 8) & 0xff); | | 468 | (nbytes >> 8) & 0xff); |
465 | } | | 469 | } |
466 | | | 470 | |
467 | _isa_dmaunmask(ids, chan); | | 471 | _isa_dmaunmask(ids, chan); |
468 | return (0); | | 472 | return (0); |
469 | | | 473 | |
470 | lose: | | 474 | lose: |
471 | panic("_isa_dmastart"); | | 475 | panic("_isa_dmastart"); |
472 | } | | 476 | } |
473 | | | 477 | |
474 | void | | 478 | void |
475 | _isa_dmaabort(struct isa_dma_state *ids, int chan) | | 479 | _isa_dmaabort(struct isa_dma_state *ids, int chan) |
476 | { | | 480 | { |
477 | | | 481 | |
478 | if (chan < 0 || chan > 7) { | | 482 | if (chan < 0 || chan > 7) { |
479 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); | | 483 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); |
480 | panic("_isa_dmaabort"); | | 484 | panic("_isa_dmaabort"); |
481 | } | | 485 | } |
482 | | | 486 | |
483 | _isa_dmamask(ids, chan); | | 487 | _isa_dmamask(ids, chan); |
484 | bus_dmamap_unload(ids->ids_dmat, ids->ids_dmamaps[chan]); | | 488 | bus_dmamap_unload(ids->ids_dmat, ids->ids_dmamaps[chan]); |
485 | ids->ids_dmareads &= ~(1 << chan); | | 489 | ids->ids_dmareads &= ~(1 << chan); |
486 | } | | 490 | } |
487 | | | 491 | |
488 | bus_size_t | | 492 | bus_size_t |
489 | _isa_dmacount(struct isa_dma_state *ids, int chan) | | 493 | _isa_dmacount(struct isa_dma_state *ids, int chan) |
490 | { | | 494 | { |
491 | int waport; | | 495 | int waport; |
492 | bus_size_t nbytes; | | 496 | bus_size_t nbytes; |
493 | int ochan = chan & 3; | | 497 | int ochan = chan & 3; |
494 | | | 498 | |
495 | if (chan < 0 || chan > 7) { | | 499 | if (chan < 0 || chan > 7) { |
496 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); | | 500 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); |
497 | panic("isa_dmacount"); | | 501 | panic("isa_dmacount"); |
498 | } | | 502 | } |
499 | | | 503 | |
500 | _isa_dmamask(ids, chan); | | 504 | _isa_dmamask(ids, chan); |
501 | | | 505 | |
502 | /* | | 506 | /* |
503 | * We have to shift the byte count by 1. If we're in auto-initialize | | 507 | * We have to shift the byte count by 1. If we're in auto-initialize |
504 | * mode, the count may have wrapped around to the initial value. We | | 508 | * mode, the count may have wrapped around to the initial value. We |
505 | * can't use the TC bit to check for this case, so instead we compare | | 509 | * can't use the TC bit to check for this case, so instead we compare |
506 | * against the original byte count. | | 510 | * against the original byte count. |
507 | * If we're not in auto-initialize mode, then the count will wrap to | | 511 | * If we're not in auto-initialize mode, then the count will wrap to |
508 | * -1, so we also handle that case. | | 512 | * -1, so we also handle that case. |
509 | */ | | 513 | */ |
510 | if ((chan & 4) == 0) { | | 514 | if ((chan & 4) == 0) { |
511 | waport = DMA1_CHN(ochan); | | 515 | waport = DMA1_CHN(ochan); |
512 | nbytes = bus_space_read_1(ids->ids_bst, ids->ids_dma1h, | | 516 | nbytes = bus_space_read_1(ids->ids_bst, ids->ids_dma1h, |
513 | waport + 1) + 1; | | 517 | waport + 1) + 1; |
514 | nbytes += bus_space_read_1(ids->ids_bst, ids->ids_dma1h, | | 518 | nbytes += bus_space_read_1(ids->ids_bst, ids->ids_dma1h, |
515 | waport + 1) << 8; | | 519 | waport + 1) << 8; |
516 | nbytes &= 0xffff; | | 520 | nbytes &= 0xffff; |
517 | } else { | | 521 | } else { |
518 | waport = DMA2_CHN(ochan); | | 522 | waport = DMA2_CHN(ochan); |
519 | nbytes = bus_space_read_1(ids->ids_bst, ids->ids_dma2h, | | 523 | nbytes = bus_space_read_1(ids->ids_bst, ids->ids_dma2h, |
520 | waport + 2) + 1; | | 524 | waport + 2) + 1; |
521 | nbytes += bus_space_read_1(ids->ids_bst, ids->ids_dma2h, | | 525 | nbytes += bus_space_read_1(ids->ids_bst, ids->ids_dma2h, |
522 | waport + 2) << 8; | | 526 | waport + 2) << 8; |
523 | nbytes <<= 1; | | 527 | nbytes <<= 1; |
524 | nbytes &= 0x1ffff; | | 528 | nbytes &= 0x1ffff; |
525 | } | | 529 | } |
526 | | | 530 | |
527 | if (nbytes == ids->ids_dmalength[chan]) | | 531 | if (nbytes == ids->ids_dmalength[chan]) |
528 | nbytes = 0; | | 532 | nbytes = 0; |
529 | | | 533 | |
530 | _isa_dmaunmask(ids, chan); | | 534 | _isa_dmaunmask(ids, chan); |
531 | return (nbytes); | | 535 | return (nbytes); |
532 | } | | 536 | } |
533 | | | 537 | |
534 | int | | 538 | int |
535 | _isa_dmafinished(struct isa_dma_state *ids, int chan) | | 539 | _isa_dmafinished(struct isa_dma_state *ids, int chan) |
536 | { | | 540 | { |
537 | | | 541 | |
538 | if (chan < 0 || chan > 7) { | | 542 | if (chan < 0 || chan > 7) { |
539 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); | | 543 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); |
540 | panic("_isa_dmafinished"); | | 544 | panic("_isa_dmafinished"); |
541 | } | | 545 | } |
542 | | | 546 | |
543 | /* check that the terminal count was reached */ | | 547 | /* check that the terminal count was reached */ |
544 | if ((chan & 4) == 0) | | 548 | if ((chan & 4) == 0) |
545 | ids->ids_dmafinished |= bus_space_read_1(ids->ids_bst, | | 549 | ids->ids_dmafinished |= bus_space_read_1(ids->ids_bst, |
546 | ids->ids_dma1h, DMA1_SR) & 0x0f; | | 550 | ids->ids_dma1h, DMA1_SR) & 0x0f; |
547 | else | | 551 | else |
548 | ids->ids_dmafinished |= (bus_space_read_1(ids->ids_bst, | | 552 | ids->ids_dmafinished |= (bus_space_read_1(ids->ids_bst, |
549 | ids->ids_dma2h, DMA2_SR) & 0x0f) << 4; | | 553 | ids->ids_dma2h, DMA2_SR) & 0x0f) << 4; |
550 | | | 554 | |
551 | return ((ids->ids_dmafinished & (1 << chan)) != 0); | | 555 | return ((ids->ids_dmafinished & (1 << chan)) != 0); |
552 | } | | 556 | } |
553 | | | 557 | |
554 | void | | 558 | void |
555 | _isa_dmadone(struct isa_dma_state *ids, int chan) | | 559 | _isa_dmadone(struct isa_dma_state *ids, int chan) |
556 | { | | 560 | { |
557 | bus_dmamap_t dmam; | | 561 | bus_dmamap_t dmam; |
558 | | | 562 | |
559 | if (chan < 0 || chan > 7) { | | 563 | if (chan < 0 || chan > 7) { |
560 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); | | 564 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); |
561 | panic("_isa_dmadone"); | | 565 | panic("_isa_dmadone"); |
562 | } | | 566 | } |
563 | | | 567 | |
564 | dmam = ids->ids_dmamaps[chan]; | | 568 | dmam = ids->ids_dmamaps[chan]; |
565 | | | 569 | |
566 | _isa_dmamask(ids, chan); | | 570 | _isa_dmamask(ids, chan); |
567 | | | 571 | |
568 | if (_isa_dmafinished(ids, chan) == 0) | | 572 | if (_isa_dmafinished(ids, chan) == 0) |
569 | printf("%s: _isa_dmadone: channel %d not finished\n", | | 573 | printf("%s: _isa_dmadone: channel %d not finished\n", |
570 | device_xname(ids->ids_dev), chan); | | 574 | device_xname(ids->ids_dev), chan); |
571 | | | 575 | |
572 | bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize, | | 576 | bus_dmamap_sync(ids->ids_dmat, dmam, 0, dmam->dm_mapsize, |
573 | (ids->ids_dmareads & (1 << chan)) ? BUS_DMASYNC_POSTREAD : | | 577 | (ids->ids_dmareads & (1 << chan)) ? BUS_DMASYNC_POSTREAD : |
574 | BUS_DMASYNC_POSTWRITE); | | 578 | BUS_DMASYNC_POSTWRITE); |
575 | | | 579 | |
576 | bus_dmamap_unload(ids->ids_dmat, dmam); | | 580 | bus_dmamap_unload(ids->ids_dmat, dmam); |
577 | ids->ids_dmareads &= ~(1 << chan); | | 581 | ids->ids_dmareads &= ~(1 << chan); |
578 | } | | 582 | } |
579 | | | 583 | |
580 | void | | 584 | void |
581 | _isa_dmafreeze(struct isa_dma_state *ids) | | 585 | _isa_dmafreeze(struct isa_dma_state *ids) |
582 | { | | 586 | { |
583 | int s; | | 587 | int s; |
584 | | | 588 | |
585 | s = splhigh(); | | 589 | s = splhigh(); |
586 | | | 590 | |
587 | if (ids->ids_frozen == 0) { | | 591 | if (ids->ids_frozen == 0) { |
588 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, | | 592 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, |
589 | DMA1_MASK, 0x0f); | | 593 | DMA1_MASK, 0x0f); |
590 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, | | 594 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, |
591 | DMA2_MASK, 0x0f); | | 595 | DMA2_MASK, 0x0f); |
592 | } | | 596 | } |
593 | | | 597 | |
594 | ids->ids_frozen++; | | 598 | ids->ids_frozen++; |
595 | if (ids->ids_frozen < 1) | | 599 | if (ids->ids_frozen < 1) |
596 | panic("_isa_dmafreeze: overflow"); | | 600 | panic("_isa_dmafreeze: overflow"); |
597 | | | 601 | |
598 | splx(s); | | 602 | splx(s); |
599 | } | | 603 | } |
600 | | | 604 | |
601 | void | | 605 | void |
602 | _isa_dmathaw(struct isa_dma_state *ids) | | 606 | _isa_dmathaw(struct isa_dma_state *ids) |
603 | { | | 607 | { |
604 | int s; | | 608 | int s; |
605 | | | 609 | |
606 | s = splhigh(); | | 610 | s = splhigh(); |
607 | | | 611 | |
608 | ids->ids_frozen--; | | 612 | ids->ids_frozen--; |
609 | if (ids->ids_frozen < 0) | | 613 | if (ids->ids_frozen < 0) |
610 | panic("_isa_dmathaw: underflow"); | | 614 | panic("_isa_dmathaw: underflow"); |
611 | | | 615 | |
612 | if (ids->ids_frozen == 0) { | | 616 | if (ids->ids_frozen == 0) { |
613 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, | | 617 | bus_space_write_1(ids->ids_bst, ids->ids_dma1h, |
614 | DMA1_MASK, ids->ids_masked & 0x0f); | | 618 | DMA1_MASK, ids->ids_masked & 0x0f); |
615 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, | | 619 | bus_space_write_1(ids->ids_bst, ids->ids_dma2h, |
616 | DMA2_MASK, (ids->ids_masked >> 4) & 0x0f); | | 620 | DMA2_MASK, (ids->ids_masked >> 4) & 0x0f); |
617 | } | | 621 | } |
618 | | | 622 | |
619 | splx(s); | | 623 | splx(s); |
620 | } | | 624 | } |
621 | | | 625 | |
622 | int | | 626 | int |
623 | _isa_dmamem_alloc(struct isa_dma_state *ids, int chan, bus_size_t size, bus_addr_t *addrp, int flags) | | 627 | _isa_dmamem_alloc(struct isa_dma_state *ids, int chan, bus_size_t size, bus_addr_t *addrp, int flags) |
624 | { | | 628 | { |
625 | bus_dma_segment_t seg; | | 629 | bus_dma_segment_t seg; |
626 | int error, boundary, rsegs; | | 630 | int error, boundary, rsegs; |
627 | | | 631 | |
628 | if (chan < 0 || chan > 7) { | | 632 | if (chan < 0 || chan > 7) { |
629 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); | | 633 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); |
630 | panic("_isa_dmamem_alloc"); | | 634 | panic("_isa_dmamem_alloc"); |
631 | } | | 635 | } |
632 | | | 636 | |
633 | boundary = (chan & 4) ? (1 << 17) : (1 << 16); | | 637 | boundary = (chan & 4) ? (1 << 17) : (1 << 16); |
634 | | | 638 | |
635 | size = round_page(size); | | 639 | size = round_page(size); |
636 | | | 640 | |
637 | error = bus_dmamem_alloc(ids->ids_dmat, size, PAGE_SIZE, boundary, | | 641 | error = bus_dmamem_alloc(ids->ids_dmat, size, PAGE_SIZE, boundary, |
638 | &seg, 1, &rsegs, flags); | | 642 | &seg, 1, &rsegs, flags); |
639 | if (error) | | 643 | if (error) |
640 | return (error); | | 644 | return (error); |
641 | | | 645 | |
642 | *addrp = seg.ds_addr; | | 646 | *addrp = seg.ds_addr; |
643 | return (0); | | 647 | return (0); |
644 | } | | 648 | } |
645 | | | 649 | |
646 | void | | 650 | void |
647 | _isa_dmamem_free(struct isa_dma_state *ids, int chan, bus_addr_t addr, bus_size_t size) | | 651 | _isa_dmamem_free(struct isa_dma_state *ids, int chan, bus_addr_t addr, bus_size_t size) |
648 | { | | 652 | { |
649 | bus_dma_segment_t seg; | | 653 | bus_dma_segment_t seg; |
650 | | | 654 | |
651 | if (chan < 0 || chan > 7) { | | 655 | if (chan < 0 || chan > 7) { |
652 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); | | 656 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); |
653 | panic("_isa_dmamem_free"); | | 657 | panic("_isa_dmamem_free"); |
654 | } | | 658 | } |
655 | | | 659 | |
656 | seg.ds_addr = addr; | | 660 | seg.ds_addr = addr; |
657 | seg.ds_len = size; | | 661 | seg.ds_len = size; |
658 | | | 662 | |
659 | bus_dmamem_free(ids->ids_dmat, &seg, 1); | | 663 | bus_dmamem_free(ids->ids_dmat, &seg, 1); |
660 | } | | 664 | } |
661 | | | 665 | |
662 | int | | 666 | int |
663 | _isa_dmamem_map(struct isa_dma_state *ids, int chan, bus_addr_t addr, bus_size_t size, void **kvap, int flags) | | 667 | _isa_dmamem_map(struct isa_dma_state *ids, int chan, bus_addr_t addr, bus_size_t size, void **kvap, int flags) |
664 | { | | 668 | { |
665 | bus_dma_segment_t seg; | | 669 | bus_dma_segment_t seg; |
666 | | | 670 | |
667 | if (chan < 0 || chan > 7) { | | 671 | if (chan < 0 || chan > 7) { |
668 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); | | 672 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); |
669 | panic("_isa_dmamem_map"); | | 673 | panic("_isa_dmamem_map"); |
670 | } | | 674 | } |
671 | | | 675 | |
672 | seg.ds_addr = addr; | | 676 | seg.ds_addr = addr; |
673 | seg.ds_len = size; | | 677 | seg.ds_len = size; |
674 | | | 678 | |
675 | return (bus_dmamem_map(ids->ids_dmat, &seg, 1, size, kvap, flags)); | | 679 | return (bus_dmamem_map(ids->ids_dmat, &seg, 1, size, kvap, flags)); |
676 | } | | 680 | } |
677 | | | 681 | |
678 | void | | 682 | void |
679 | _isa_dmamem_unmap(struct isa_dma_state *ids, int chan, void *kva, size_t size) | | 683 | _isa_dmamem_unmap(struct isa_dma_state *ids, int chan, void *kva, size_t size) |
680 | { | | 684 | { |
681 | | | 685 | |
682 | if (chan < 0 || chan > 7) { | | 686 | if (chan < 0 || chan > 7) { |
683 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); | | 687 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); |
684 | panic("_isa_dmamem_unmap"); | | 688 | panic("_isa_dmamem_unmap"); |
685 | } | | 689 | } |
686 | | | 690 | |
687 | bus_dmamem_unmap(ids->ids_dmat, kva, size); | | 691 | bus_dmamem_unmap(ids->ids_dmat, kva, size); |
688 | } | | 692 | } |
689 | | | 693 | |
690 | paddr_t | | 694 | paddr_t |
691 | _isa_dmamem_mmap(struct isa_dma_state *ids, int chan, bus_addr_t addr, bus_size_t size, off_t off, int prot, int flags) | | 695 | _isa_dmamem_mmap(struct isa_dma_state *ids, int chan, bus_addr_t addr, bus_size_t size, off_t off, int prot, int flags) |
692 | { | | 696 | { |
693 | bus_dma_segment_t seg; | | 697 | bus_dma_segment_t seg; |
694 | | | 698 | |
695 | if (chan < 0 || chan > 7) { | | 699 | if (chan < 0 || chan > 7) { |
696 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); | | 700 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); |
697 | panic("_isa_dmamem_mmap"); | | 701 | panic("_isa_dmamem_mmap"); |
698 | } | | 702 | } |
699 | | | 703 | |
700 | if (off < 0) | | 704 | if (off < 0) |
701 | return (-1); | | 705 | return (-1); |
702 | | | 706 | |
703 | seg.ds_addr = addr; | | 707 | seg.ds_addr = addr; |
704 | seg.ds_len = size; | | 708 | seg.ds_len = size; |
705 | | | 709 | |
706 | return (bus_dmamem_mmap(ids->ids_dmat, &seg, 1, off, prot, flags)); | | 710 | return (bus_dmamem_mmap(ids->ids_dmat, &seg, 1, off, prot, flags)); |
707 | } | | 711 | } |
708 | | | 712 | |
709 | int | | 713 | int |
710 | _isa_drq_isfree(struct isa_dma_state *ids, int chan) | | 714 | _isa_drq_isfree(struct isa_dma_state *ids, int chan) |
711 | { | | 715 | { |
712 | | | 716 | |
713 | if (chan < 0 || chan > 7) { | | 717 | if (chan < 0 || chan > 7) { |
714 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); | | 718 | printf("%s: bogus drq %d\n", device_xname(ids->ids_dev), chan); |
715 | panic("_isa_drq_isfree"); | | 719 | panic("_isa_drq_isfree"); |
716 | } | | 720 | } |
717 | | | 721 | |
718 | return ISA_DMA_DRQ_ISFREE(ids, chan); | | 722 | return ISA_DMA_DRQ_ISFREE(ids, chan); |
719 | } | | 723 | } |
720 | | | 724 | |
721 | void * | | 725 | void * |
722 | _isa_malloc(struct isa_dma_state *ids, int chan, size_t size, struct malloc_type *pool, int flags) | | 726 | _isa_malloc(struct isa_dma_state *ids, int chan, size_t size, struct malloc_type *pool, int flags) |
723 | { | | 727 | { |
724 | bus_addr_t addr; | | 728 | bus_addr_t addr; |
725 | void *kva; | | 729 | void *kva; |
726 | int bflags; | | 730 | int bflags; |
727 | struct isa_mem *m; | | 731 | struct isa_mem *m; |
728 | | | 732 | |
729 | bflags = flags & M_WAITOK ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT; | | 733 | bflags = flags & M_WAITOK ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT; |
730 | | | 734 | |
731 | if (_isa_dmamem_alloc(ids, chan, size, &addr, bflags)) | | 735 | if (_isa_dmamem_alloc(ids, chan, size, &addr, bflags)) |
732 | return 0; | | 736 | return 0; |
733 | if (_isa_dmamem_map(ids, chan, addr, size, &kva, bflags)) { | | 737 | if (_isa_dmamem_map(ids, chan, addr, size, &kva, bflags)) { |
734 | _isa_dmamem_free(ids, chan, addr, size); | | 738 | _isa_dmamem_free(ids, chan, addr, size); |
735 | return 0; | | 739 | return 0; |
736 | } | | 740 | } |
737 | m = malloc(sizeof(*m), pool, flags); | | 741 | m = malloc(sizeof(*m), pool, flags); |
738 | if (m == 0) { | | 742 | if (m == 0) { |
739 | _isa_dmamem_unmap(ids, chan, kva, size); | | 743 | _isa_dmamem_unmap(ids, chan, kva, size); |
740 | _isa_dmamem_free(ids, chan, addr, size); | | 744 | _isa_dmamem_free(ids, chan, addr, size); |
741 | return 0; | | 745 | return 0; |
742 | } | | 746 | } |
743 | m->ids = ids; | | 747 | m->ids = ids; |
744 | m->chan = chan; | | 748 | m->chan = chan; |
745 | m->size = size; | | 749 | m->size = size; |
746 | m->addr = addr; | | 750 | m->addr = addr; |
747 | m->kva = kva; | | 751 | m->kva = kva; |
748 | m->next = isa_mem_head; | | 752 | m->next = isa_mem_head; |
749 | isa_mem_head = m; | | 753 | isa_mem_head = m; |
750 | return (void *)kva; | | 754 | return (void *)kva; |
751 | } | | 755 | } |
752 | | | 756 | |
753 | void | | 757 | void |
754 | _isa_free(void *addr, struct malloc_type *pool) | | 758 | _isa_free(void *addr, struct malloc_type *pool) |
755 | { | | 759 | { |
756 | struct isa_mem **mp, *m; | | 760 | struct isa_mem **mp, *m; |
757 | void *kva = (void *)addr; | | 761 | void *kva = (void *)addr; |
758 | | | 762 | |
759 | for(mp = &isa_mem_head; *mp && (*mp)->kva != kva; | | 763 | for(mp = &isa_mem_head; *mp && (*mp)->kva != kva; |
760 | mp = &(*mp)->next) | | 764 | mp = &(*mp)->next) |
761 | ; | | 765 | ; |
762 | m = *mp; | | 766 | m = *mp; |
763 | if (!m) { | | 767 | if (!m) { |
764 | printf("_isa_free: freeing unallocted memory\n"); | | 768 | printf("_isa_free: freeing unallocted memory\n"); |
765 | return; | | 769 | return; |
766 | } | | 770 | } |
767 | *mp = m->next; | | 771 | *mp = m->next; |
768 | _isa_dmamem_unmap(m->ids, m->chan, kva, m->size); | | 772 | _isa_dmamem_unmap(m->ids, m->chan, kva, m->size); |
769 | _isa_dmamem_free(m->ids, m->chan, m->addr, m->size); | | 773 | _isa_dmamem_free(m->ids, m->chan, m->addr, m->size); |
770 | free(m, pool); | | 774 | free(m, pool); |
771 | } | | 775 | } |
772 | | | 776 | |
773 | paddr_t | | 777 | paddr_t |
774 | _isa_mappage(void *mem, off_t off, int prot) | | 778 | _isa_mappage(void *mem, off_t off, int prot) |
775 | { | | 779 | { |
776 | struct isa_mem *m; | | 780 | struct isa_mem *m; |
777 | | | 781 | |
778 | for(m = isa_mem_head; m && m->kva != (void *)mem; m = m->next) | | 782 | for(m = isa_mem_head; m && m->kva != (void *)mem; m = m->next) |
779 | ; | | 783 | ; |
780 | if (!m) { | | 784 | if (!m) { |
781 | printf("_isa_mappage: mapping unallocted memory\n"); | | 785 | printf("_isa_mappage: mapping unallocted memory\n"); |
782 | return -1; | | 786 | return -1; |
783 | } | | 787 | } |
784 | return _isa_dmamem_mmap(m->ids, m->chan, m->addr, | | 788 | return _isa_dmamem_mmap(m->ids, m->chan, m->addr, |
785 | m->size, off, prot, BUS_DMA_WAITOK); | | 789 | m->size, off, prot, BUS_DMA_WAITOK); |
786 | } | | 790 | } |