root / hw / ide / pci.c @ 2860e3eb
History | View | Annotate | Download (12.8 kB)
1 | 977e1244 | Gerd Hoffmann | /*
|
---|---|---|---|
2 | 977e1244 | Gerd Hoffmann | * QEMU IDE Emulation: PCI Bus support.
|
3 | 977e1244 | Gerd Hoffmann | *
|
4 | 977e1244 | Gerd Hoffmann | * Copyright (c) 2003 Fabrice Bellard
|
5 | 977e1244 | Gerd Hoffmann | * Copyright (c) 2006 Openedhand Ltd.
|
6 | 977e1244 | Gerd Hoffmann | *
|
7 | 977e1244 | Gerd Hoffmann | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 | 977e1244 | Gerd Hoffmann | * of this software and associated documentation files (the "Software"), to deal
|
9 | 977e1244 | Gerd Hoffmann | * in the Software without restriction, including without limitation the rights
|
10 | 977e1244 | Gerd Hoffmann | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 | 977e1244 | Gerd Hoffmann | * copies of the Software, and to permit persons to whom the Software is
|
12 | 977e1244 | Gerd Hoffmann | * furnished to do so, subject to the following conditions:
|
13 | 977e1244 | Gerd Hoffmann | *
|
14 | 977e1244 | Gerd Hoffmann | * The above copyright notice and this permission notice shall be included in
|
15 | 977e1244 | Gerd Hoffmann | * all copies or substantial portions of the Software.
|
16 | 977e1244 | Gerd Hoffmann | *
|
17 | 977e1244 | Gerd Hoffmann | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 | 977e1244 | Gerd Hoffmann | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 | 977e1244 | Gerd Hoffmann | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
20 | 977e1244 | Gerd Hoffmann | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 | 977e1244 | Gerd Hoffmann | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 | 977e1244 | Gerd Hoffmann | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 | 977e1244 | Gerd Hoffmann | * THE SOFTWARE.
|
24 | 977e1244 | Gerd Hoffmann | */
|
25 | 59f2a787 | Gerd Hoffmann | #include <hw/hw.h> |
26 | 59f2a787 | Gerd Hoffmann | #include <hw/pc.h> |
27 | 59f2a787 | Gerd Hoffmann | #include <hw/pci.h> |
28 | feef3102 | Gerd Hoffmann | #include <hw/isa.h> |
29 | 977e1244 | Gerd Hoffmann | #include "block.h" |
30 | 977e1244 | Gerd Hoffmann | #include "block_int.h" |
31 | 977e1244 | Gerd Hoffmann | #include "dma.h" |
32 | 59f2a787 | Gerd Hoffmann | |
33 | 65c0f135 | Juan Quintela | #include <hw/ide/pci.h> |
34 | 977e1244 | Gerd Hoffmann | |
35 | 40a6238a | Alexander Graf | #define BMDMA_PAGE_SIZE 4096 |
36 | 40a6238a | Alexander Graf | |
37 | 40a6238a | Alexander Graf | static void bmdma_start_dma(IDEDMA *dma, IDEState *s, |
38 | 40a6238a | Alexander Graf | BlockDriverCompletionFunc *dma_cb) |
39 | 40a6238a | Alexander Graf | { |
40 | 40a6238a | Alexander Graf | BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); |
41 | 40a6238a | Alexander Graf | |
42 | 40a6238a | Alexander Graf | bm->unit = s->unit; |
43 | 40a6238a | Alexander Graf | bm->dma_cb = dma_cb; |
44 | 40a6238a | Alexander Graf | bm->cur_prd_last = 0;
|
45 | 40a6238a | Alexander Graf | bm->cur_prd_addr = 0;
|
46 | 40a6238a | Alexander Graf | bm->cur_prd_len = 0;
|
47 | 40a6238a | Alexander Graf | bm->sector_num = ide_get_sector(s); |
48 | 40a6238a | Alexander Graf | bm->nsector = s->nsector; |
49 | 40a6238a | Alexander Graf | |
50 | 40a6238a | Alexander Graf | if (bm->status & BM_STATUS_DMAING) {
|
51 | 40a6238a | Alexander Graf | bm->dma_cb(bmdma_active_if(bm), 0);
|
52 | 40a6238a | Alexander Graf | } |
53 | 40a6238a | Alexander Graf | } |
54 | 40a6238a | Alexander Graf | |
55 | 40a6238a | Alexander Graf | /* return 0 if buffer completed */
|
56 | 40a6238a | Alexander Graf | static int bmdma_prepare_buf(IDEDMA *dma, int is_write) |
57 | 40a6238a | Alexander Graf | { |
58 | 40a6238a | Alexander Graf | BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); |
59 | 40a6238a | Alexander Graf | IDEState *s = bmdma_active_if(bm); |
60 | 40a6238a | Alexander Graf | struct {
|
61 | 40a6238a | Alexander Graf | uint32_t addr; |
62 | 40a6238a | Alexander Graf | uint32_t size; |
63 | 40a6238a | Alexander Graf | } prd; |
64 | 40a6238a | Alexander Graf | int l, len;
|
65 | 40a6238a | Alexander Graf | |
66 | 40a6238a | Alexander Graf | qemu_sglist_init(&s->sg, s->nsector / (BMDMA_PAGE_SIZE / 512) + 1); |
67 | 40a6238a | Alexander Graf | s->io_buffer_size = 0;
|
68 | 40a6238a | Alexander Graf | for(;;) {
|
69 | 40a6238a | Alexander Graf | if (bm->cur_prd_len == 0) { |
70 | 40a6238a | Alexander Graf | /* end of table (with a fail safe of one page) */
|
71 | 40a6238a | Alexander Graf | if (bm->cur_prd_last ||
|
72 | 40a6238a | Alexander Graf | (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) |
73 | 40a6238a | Alexander Graf | return s->io_buffer_size != 0; |
74 | 40a6238a | Alexander Graf | cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8);
|
75 | 40a6238a | Alexander Graf | bm->cur_addr += 8;
|
76 | 40a6238a | Alexander Graf | prd.addr = le32_to_cpu(prd.addr); |
77 | 40a6238a | Alexander Graf | prd.size = le32_to_cpu(prd.size); |
78 | 40a6238a | Alexander Graf | len = prd.size & 0xfffe;
|
79 | 40a6238a | Alexander Graf | if (len == 0) |
80 | 40a6238a | Alexander Graf | len = 0x10000;
|
81 | 40a6238a | Alexander Graf | bm->cur_prd_len = len; |
82 | 40a6238a | Alexander Graf | bm->cur_prd_addr = prd.addr; |
83 | 40a6238a | Alexander Graf | bm->cur_prd_last = (prd.size & 0x80000000);
|
84 | 40a6238a | Alexander Graf | } |
85 | 40a6238a | Alexander Graf | l = bm->cur_prd_len; |
86 | 40a6238a | Alexander Graf | if (l > 0) { |
87 | 40a6238a | Alexander Graf | qemu_sglist_add(&s->sg, bm->cur_prd_addr, l); |
88 | 40a6238a | Alexander Graf | bm->cur_prd_addr += l; |
89 | 40a6238a | Alexander Graf | bm->cur_prd_len -= l; |
90 | 40a6238a | Alexander Graf | s->io_buffer_size += l; |
91 | 40a6238a | Alexander Graf | } |
92 | 40a6238a | Alexander Graf | } |
93 | 40a6238a | Alexander Graf | return 1; |
94 | 40a6238a | Alexander Graf | } |
95 | 40a6238a | Alexander Graf | |
96 | 40a6238a | Alexander Graf | /* return 0 if buffer completed */
|
97 | 40a6238a | Alexander Graf | static int bmdma_rw_buf(IDEDMA *dma, int is_write) |
98 | 40a6238a | Alexander Graf | { |
99 | 40a6238a | Alexander Graf | BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); |
100 | 40a6238a | Alexander Graf | IDEState *s = bmdma_active_if(bm); |
101 | 40a6238a | Alexander Graf | struct {
|
102 | 40a6238a | Alexander Graf | uint32_t addr; |
103 | 40a6238a | Alexander Graf | uint32_t size; |
104 | 40a6238a | Alexander Graf | } prd; |
105 | 40a6238a | Alexander Graf | int l, len;
|
106 | 40a6238a | Alexander Graf | |
107 | 40a6238a | Alexander Graf | for(;;) {
|
108 | 40a6238a | Alexander Graf | l = s->io_buffer_size - s->io_buffer_index; |
109 | 40a6238a | Alexander Graf | if (l <= 0) |
110 | 40a6238a | Alexander Graf | break;
|
111 | 40a6238a | Alexander Graf | if (bm->cur_prd_len == 0) { |
112 | 40a6238a | Alexander Graf | /* end of table (with a fail safe of one page) */
|
113 | 40a6238a | Alexander Graf | if (bm->cur_prd_last ||
|
114 | 40a6238a | Alexander Graf | (bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE) |
115 | 40a6238a | Alexander Graf | return 0; |
116 | 40a6238a | Alexander Graf | cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8);
|
117 | 40a6238a | Alexander Graf | bm->cur_addr += 8;
|
118 | 40a6238a | Alexander Graf | prd.addr = le32_to_cpu(prd.addr); |
119 | 40a6238a | Alexander Graf | prd.size = le32_to_cpu(prd.size); |
120 | 40a6238a | Alexander Graf | len = prd.size & 0xfffe;
|
121 | 40a6238a | Alexander Graf | if (len == 0) |
122 | 40a6238a | Alexander Graf | len = 0x10000;
|
123 | 40a6238a | Alexander Graf | bm->cur_prd_len = len; |
124 | 40a6238a | Alexander Graf | bm->cur_prd_addr = prd.addr; |
125 | 40a6238a | Alexander Graf | bm->cur_prd_last = (prd.size & 0x80000000);
|
126 | 40a6238a | Alexander Graf | } |
127 | 40a6238a | Alexander Graf | if (l > bm->cur_prd_len)
|
128 | 40a6238a | Alexander Graf | l = bm->cur_prd_len; |
129 | 40a6238a | Alexander Graf | if (l > 0) { |
130 | 40a6238a | Alexander Graf | if (is_write) {
|
131 | 40a6238a | Alexander Graf | cpu_physical_memory_write(bm->cur_prd_addr, |
132 | 40a6238a | Alexander Graf | s->io_buffer + s->io_buffer_index, l); |
133 | 40a6238a | Alexander Graf | } else {
|
134 | 40a6238a | Alexander Graf | cpu_physical_memory_read(bm->cur_prd_addr, |
135 | 40a6238a | Alexander Graf | s->io_buffer + s->io_buffer_index, l); |
136 | 40a6238a | Alexander Graf | } |
137 | 40a6238a | Alexander Graf | bm->cur_prd_addr += l; |
138 | 40a6238a | Alexander Graf | bm->cur_prd_len -= l; |
139 | 40a6238a | Alexander Graf | s->io_buffer_index += l; |
140 | 40a6238a | Alexander Graf | } |
141 | 40a6238a | Alexander Graf | } |
142 | 40a6238a | Alexander Graf | return 1; |
143 | 40a6238a | Alexander Graf | } |
144 | 40a6238a | Alexander Graf | |
145 | 40a6238a | Alexander Graf | static int bmdma_set_unit(IDEDMA *dma, int unit) |
146 | 40a6238a | Alexander Graf | { |
147 | 40a6238a | Alexander Graf | BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); |
148 | 40a6238a | Alexander Graf | bm->unit = unit; |
149 | 40a6238a | Alexander Graf | |
150 | 40a6238a | Alexander Graf | return 0; |
151 | 40a6238a | Alexander Graf | } |
152 | 40a6238a | Alexander Graf | |
153 | 40a6238a | Alexander Graf | static int bmdma_add_status(IDEDMA *dma, int status) |
154 | 40a6238a | Alexander Graf | { |
155 | 40a6238a | Alexander Graf | BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); |
156 | 40a6238a | Alexander Graf | bm->status |= status; |
157 | 40a6238a | Alexander Graf | |
158 | 40a6238a | Alexander Graf | return 0; |
159 | 40a6238a | Alexander Graf | } |
160 | 40a6238a | Alexander Graf | |
161 | 40a6238a | Alexander Graf | static int bmdma_set_inactive(IDEDMA *dma) |
162 | 40a6238a | Alexander Graf | { |
163 | 40a6238a | Alexander Graf | BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); |
164 | 40a6238a | Alexander Graf | |
165 | 40a6238a | Alexander Graf | bm->status &= ~BM_STATUS_DMAING; |
166 | 40a6238a | Alexander Graf | bm->dma_cb = NULL;
|
167 | 40a6238a | Alexander Graf | bm->unit = -1;
|
168 | 40a6238a | Alexander Graf | |
169 | 40a6238a | Alexander Graf | return 0; |
170 | 40a6238a | Alexander Graf | } |
171 | 40a6238a | Alexander Graf | |
172 | 40a6238a | Alexander Graf | static void bmdma_restart_dma(BMDMAState *bm, int is_read) |
173 | 40a6238a | Alexander Graf | { |
174 | 40a6238a | Alexander Graf | IDEState *s = bmdma_active_if(bm); |
175 | 40a6238a | Alexander Graf | |
176 | 40a6238a | Alexander Graf | ide_set_sector(s, bm->sector_num); |
177 | 40a6238a | Alexander Graf | s->io_buffer_index = 0;
|
178 | 40a6238a | Alexander Graf | s->io_buffer_size = 0;
|
179 | 40a6238a | Alexander Graf | s->nsector = bm->nsector; |
180 | cd369c46 | Christoph Hellwig | s->is_read = is_read; |
181 | 40a6238a | Alexander Graf | bm->cur_addr = bm->addr; |
182 | cd369c46 | Christoph Hellwig | bm->dma_cb = ide_dma_cb; |
183 | 40a6238a | Alexander Graf | bmdma_start_dma(&bm->dma, s, bm->dma_cb); |
184 | 40a6238a | Alexander Graf | } |
185 | 40a6238a | Alexander Graf | |
186 | 40a6238a | Alexander Graf | static void bmdma_restart_bh(void *opaque) |
187 | 40a6238a | Alexander Graf | { |
188 | 40a6238a | Alexander Graf | BMDMAState *bm = opaque; |
189 | 40a6238a | Alexander Graf | int is_read;
|
190 | 40a6238a | Alexander Graf | |
191 | 40a6238a | Alexander Graf | qemu_bh_delete(bm->bh); |
192 | 40a6238a | Alexander Graf | bm->bh = NULL;
|
193 | 40a6238a | Alexander Graf | |
194 | 40a6238a | Alexander Graf | is_read = !!(bm->status & BM_STATUS_RETRY_READ); |
195 | 40a6238a | Alexander Graf | |
196 | 40a6238a | Alexander Graf | if (bm->status & BM_STATUS_DMA_RETRY) {
|
197 | 40a6238a | Alexander Graf | bm->status &= ~(BM_STATUS_DMA_RETRY | BM_STATUS_RETRY_READ); |
198 | 40a6238a | Alexander Graf | bmdma_restart_dma(bm, is_read); |
199 | 40a6238a | Alexander Graf | } else if (bm->status & BM_STATUS_PIO_RETRY) { |
200 | 40a6238a | Alexander Graf | bm->status &= ~(BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ); |
201 | 40a6238a | Alexander Graf | if (is_read) {
|
202 | 40a6238a | Alexander Graf | ide_sector_read(bmdma_active_if(bm)); |
203 | 40a6238a | Alexander Graf | } else {
|
204 | 40a6238a | Alexander Graf | ide_sector_write(bmdma_active_if(bm)); |
205 | 40a6238a | Alexander Graf | } |
206 | 40a6238a | Alexander Graf | } else if (bm->status & BM_STATUS_RETRY_FLUSH) { |
207 | 40a6238a | Alexander Graf | ide_flush_cache(bmdma_active_if(bm)); |
208 | 40a6238a | Alexander Graf | } |
209 | 40a6238a | Alexander Graf | } |
210 | 40a6238a | Alexander Graf | |
211 | 40a6238a | Alexander Graf | static void bmdma_restart_cb(void *opaque, int running, int reason) |
212 | 40a6238a | Alexander Graf | { |
213 | 40a6238a | Alexander Graf | IDEDMA *dma = opaque; |
214 | 40a6238a | Alexander Graf | BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); |
215 | 40a6238a | Alexander Graf | |
216 | 40a6238a | Alexander Graf | if (!running)
|
217 | 40a6238a | Alexander Graf | return;
|
218 | 40a6238a | Alexander Graf | |
219 | 40a6238a | Alexander Graf | if (!bm->bh) {
|
220 | 40a6238a | Alexander Graf | bm->bh = qemu_bh_new(bmdma_restart_bh, &bm->dma); |
221 | 40a6238a | Alexander Graf | qemu_bh_schedule(bm->bh); |
222 | 40a6238a | Alexander Graf | } |
223 | 40a6238a | Alexander Graf | } |
224 | 40a6238a | Alexander Graf | |
225 | 40a6238a | Alexander Graf | static void bmdma_cancel(BMDMAState *bm) |
226 | 40a6238a | Alexander Graf | { |
227 | 40a6238a | Alexander Graf | if (bm->status & BM_STATUS_DMAING) {
|
228 | 40a6238a | Alexander Graf | /* cancel DMA request */
|
229 | 40a6238a | Alexander Graf | bmdma_set_inactive(&bm->dma); |
230 | 40a6238a | Alexander Graf | } |
231 | 40a6238a | Alexander Graf | } |
232 | 40a6238a | Alexander Graf | |
233 | 40a6238a | Alexander Graf | static int bmdma_reset(IDEDMA *dma) |
234 | 40a6238a | Alexander Graf | { |
235 | 40a6238a | Alexander Graf | BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma); |
236 | 40a6238a | Alexander Graf | |
237 | 40a6238a | Alexander Graf | #ifdef DEBUG_IDE
|
238 | 40a6238a | Alexander Graf | printf("ide: dma_reset\n");
|
239 | 40a6238a | Alexander Graf | #endif
|
240 | 40a6238a | Alexander Graf | bmdma_cancel(bm); |
241 | 40a6238a | Alexander Graf | bm->cmd = 0;
|
242 | 40a6238a | Alexander Graf | bm->status = 0;
|
243 | 40a6238a | Alexander Graf | bm->addr = 0;
|
244 | 40a6238a | Alexander Graf | bm->cur_addr = 0;
|
245 | 40a6238a | Alexander Graf | bm->cur_prd_last = 0;
|
246 | 40a6238a | Alexander Graf | bm->cur_prd_addr = 0;
|
247 | 40a6238a | Alexander Graf | bm->cur_prd_len = 0;
|
248 | 40a6238a | Alexander Graf | bm->sector_num = 0;
|
249 | 40a6238a | Alexander Graf | bm->nsector = 0;
|
250 | 40a6238a | Alexander Graf | |
251 | 40a6238a | Alexander Graf | return 0; |
252 | 40a6238a | Alexander Graf | } |
253 | 40a6238a | Alexander Graf | |
254 | 40a6238a | Alexander Graf | static int bmdma_start_transfer(IDEDMA *dma) |
255 | 40a6238a | Alexander Graf | { |
256 | 40a6238a | Alexander Graf | return 0; |
257 | 40a6238a | Alexander Graf | } |
258 | 40a6238a | Alexander Graf | |
259 | 40a6238a | Alexander Graf | static void bmdma_irq(void *opaque, int n, int level) |
260 | 40a6238a | Alexander Graf | { |
261 | 40a6238a | Alexander Graf | BMDMAState *bm = opaque; |
262 | 40a6238a | Alexander Graf | |
263 | 40a6238a | Alexander Graf | if (!level) {
|
264 | 40a6238a | Alexander Graf | /* pass through lower */
|
265 | 40a6238a | Alexander Graf | qemu_set_irq(bm->irq, level); |
266 | 40a6238a | Alexander Graf | return;
|
267 | 40a6238a | Alexander Graf | } |
268 | 40a6238a | Alexander Graf | |
269 | 1635eecc | Stefan Weil | bm->status |= BM_STATUS_INT; |
270 | 40a6238a | Alexander Graf | |
271 | 40a6238a | Alexander Graf | /* trigger the real irq */
|
272 | 40a6238a | Alexander Graf | qemu_set_irq(bm->irq, level); |
273 | 40a6238a | Alexander Graf | } |
274 | 40a6238a | Alexander Graf | |
275 | 3e7e1558 | Juan Quintela | void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) |
276 | 977e1244 | Gerd Hoffmann | { |
277 | 977e1244 | Gerd Hoffmann | BMDMAState *bm = opaque; |
278 | 977e1244 | Gerd Hoffmann | #ifdef DEBUG_IDE
|
279 | 977e1244 | Gerd Hoffmann | printf("%s: 0x%08x\n", __func__, val);
|
280 | 977e1244 | Gerd Hoffmann | #endif
|
281 | c29947bb | Kevin Wolf | |
282 | c29947bb | Kevin Wolf | /* Ignore writes to SSBM if it keeps the old value */
|
283 | c29947bb | Kevin Wolf | if ((val & BM_CMD_START) != (bm->cmd & BM_CMD_START)) {
|
284 | c29947bb | Kevin Wolf | if (!(val & BM_CMD_START)) {
|
285 | c29947bb | Kevin Wolf | /*
|
286 | c29947bb | Kevin Wolf | * We can't cancel Scatter Gather DMA in the middle of the
|
287 | c29947bb | Kevin Wolf | * operation or a partial (not full) DMA transfer would reach
|
288 | c29947bb | Kevin Wolf | * the storage so we wait for completion instead (we beahve
|
289 | c29947bb | Kevin Wolf | * like if the DMA was completed by the time the guest trying
|
290 | c29947bb | Kevin Wolf | * to cancel dma with bmdma_cmd_writeb with BM_CMD_START not
|
291 | c29947bb | Kevin Wolf | * set).
|
292 | c29947bb | Kevin Wolf | *
|
293 | c29947bb | Kevin Wolf | * In the future we'll be able to safely cancel the I/O if the
|
294 | c29947bb | Kevin Wolf | * whole DMA operation will be submitted to disk with a single
|
295 | c29947bb | Kevin Wolf | * aio operation with preadv/pwritev.
|
296 | c29947bb | Kevin Wolf | */
|
297 | 40a6238a | Alexander Graf | if (bm->bus->dma->aiocb) {
|
298 | c29947bb | Kevin Wolf | qemu_aio_flush(); |
299 | 2860e3eb | Kevin Wolf | assert(bm->bus->dma->aiocb == NULL);
|
300 | 2860e3eb | Kevin Wolf | assert((bm->status & BM_STATUS_DMAING) == 0);
|
301 | c29947bb | Kevin Wolf | } |
302 | c29947bb | Kevin Wolf | } else {
|
303 | b76876e6 | Kevin Wolf | bm->cur_addr = bm->addr; |
304 | c29947bb | Kevin Wolf | if (!(bm->status & BM_STATUS_DMAING)) {
|
305 | c29947bb | Kevin Wolf | bm->status |= BM_STATUS_DMAING; |
306 | c29947bb | Kevin Wolf | /* start dma transfer if possible */
|
307 | c29947bb | Kevin Wolf | if (bm->dma_cb)
|
308 | 40a6238a | Alexander Graf | bm->dma_cb(bmdma_active_if(bm), 0);
|
309 | c29947bb | Kevin Wolf | } |
310 | 953844d1 | Andrea Arcangeli | } |
311 | 977e1244 | Gerd Hoffmann | } |
312 | c29947bb | Kevin Wolf | |
313 | c29947bb | Kevin Wolf | bm->cmd = val & 0x09;
|
314 | 977e1244 | Gerd Hoffmann | } |
315 | 977e1244 | Gerd Hoffmann | |
316 | 9fbef1ac | Avi Kivity | static void bmdma_addr_read(IORange *ioport, uint64_t addr, |
317 | 9fbef1ac | Avi Kivity | unsigned width, uint64_t *data)
|
318 | 977e1244 | Gerd Hoffmann | { |
319 | 9fbef1ac | Avi Kivity | BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport); |
320 | 9fbef1ac | Avi Kivity | uint32_t mask = (1ULL << (width * 8)) - 1; |
321 | 977e1244 | Gerd Hoffmann | |
322 | 9fbef1ac | Avi Kivity | *data = (bm->addr >> (addr * 8)) & mask;
|
323 | 977e1244 | Gerd Hoffmann | #ifdef DEBUG_IDE
|
324 | 9fbef1ac | Avi Kivity | printf("%s: 0x%08x\n", __func__, (unsigned)*data); |
325 | 977e1244 | Gerd Hoffmann | #endif
|
326 | 977e1244 | Gerd Hoffmann | } |
327 | 977e1244 | Gerd Hoffmann | |
328 | 9fbef1ac | Avi Kivity | static void bmdma_addr_write(IORange *ioport, uint64_t addr, |
329 | 9fbef1ac | Avi Kivity | unsigned width, uint64_t data)
|
330 | 977e1244 | Gerd Hoffmann | { |
331 | 9fbef1ac | Avi Kivity | BMDMAState *bm = container_of(ioport, BMDMAState, addr_ioport); |
332 | 9fbef1ac | Avi Kivity | int shift = addr * 8; |
333 | 9fbef1ac | Avi Kivity | uint32_t mask = (1ULL << (width * 8)) - 1; |
334 | 977e1244 | Gerd Hoffmann | |
335 | 977e1244 | Gerd Hoffmann | #ifdef DEBUG_IDE
|
336 | 9fbef1ac | Avi Kivity | printf("%s: 0x%08x\n", __func__, (unsigned)data); |
337 | 977e1244 | Gerd Hoffmann | #endif
|
338 | 9fbef1ac | Avi Kivity | bm->addr &= ~(mask << shift); |
339 | 9fbef1ac | Avi Kivity | bm->addr |= ((data & mask) << shift) & ~3;
|
340 | 977e1244 | Gerd Hoffmann | } |
341 | 977e1244 | Gerd Hoffmann | |
342 | 9fbef1ac | Avi Kivity | const IORangeOps bmdma_addr_ioport_ops = {
|
343 | 9fbef1ac | Avi Kivity | .read = bmdma_addr_read, |
344 | 9fbef1ac | Avi Kivity | .write = bmdma_addr_write, |
345 | 9fbef1ac | Avi Kivity | }; |
346 | 977e1244 | Gerd Hoffmann | |
347 | 5ee84c33 | Juan Quintela | static bool ide_bmdma_current_needed(void *opaque) |
348 | 5ee84c33 | Juan Quintela | { |
349 | 5ee84c33 | Juan Quintela | BMDMAState *bm = opaque; |
350 | 5ee84c33 | Juan Quintela | |
351 | 5ee84c33 | Juan Quintela | return (bm->cur_prd_len != 0); |
352 | 5ee84c33 | Juan Quintela | } |
353 | 5ee84c33 | Juan Quintela | |
354 | 5ee84c33 | Juan Quintela | static const VMStateDescription vmstate_bmdma_current = { |
355 | 5ee84c33 | Juan Quintela | .name = "ide bmdma_current",
|
356 | 5ee84c33 | Juan Quintela | .version_id = 1,
|
357 | 5ee84c33 | Juan Quintela | .minimum_version_id = 1,
|
358 | 5ee84c33 | Juan Quintela | .minimum_version_id_old = 1,
|
359 | 5ee84c33 | Juan Quintela | .fields = (VMStateField []) { |
360 | 5ee84c33 | Juan Quintela | VMSTATE_UINT32(cur_addr, BMDMAState), |
361 | 5ee84c33 | Juan Quintela | VMSTATE_UINT32(cur_prd_last, BMDMAState), |
362 | 5ee84c33 | Juan Quintela | VMSTATE_UINT32(cur_prd_addr, BMDMAState), |
363 | 5ee84c33 | Juan Quintela | VMSTATE_UINT32(cur_prd_len, BMDMAState), |
364 | 5ee84c33 | Juan Quintela | VMSTATE_END_OF_LIST() |
365 | 5ee84c33 | Juan Quintela | } |
366 | 5ee84c33 | Juan Quintela | }; |
367 | 5ee84c33 | Juan Quintela | |
368 | 5ee84c33 | Juan Quintela | |
369 | 407a4f30 | Juan Quintela | static const VMStateDescription vmstate_bmdma = { |
370 | 407a4f30 | Juan Quintela | .name = "ide bmdma",
|
371 | 57338424 | Juan Quintela | .version_id = 3,
|
372 | 407a4f30 | Juan Quintela | .minimum_version_id = 0,
|
373 | 407a4f30 | Juan Quintela | .minimum_version_id_old = 0,
|
374 | 407a4f30 | Juan Quintela | .fields = (VMStateField []) { |
375 | 407a4f30 | Juan Quintela | VMSTATE_UINT8(cmd, BMDMAState), |
376 | 407a4f30 | Juan Quintela | VMSTATE_UINT8(status, BMDMAState), |
377 | 407a4f30 | Juan Quintela | VMSTATE_UINT32(addr, BMDMAState), |
378 | 407a4f30 | Juan Quintela | VMSTATE_INT64(sector_num, BMDMAState), |
379 | 407a4f30 | Juan Quintela | VMSTATE_UINT32(nsector, BMDMAState), |
380 | 407a4f30 | Juan Quintela | VMSTATE_UINT8(unit, BMDMAState), |
381 | 407a4f30 | Juan Quintela | VMSTATE_END_OF_LIST() |
382 | 5ee84c33 | Juan Quintela | }, |
383 | 5ee84c33 | Juan Quintela | .subsections = (VMStateSubsection []) { |
384 | 5ee84c33 | Juan Quintela | { |
385 | 5ee84c33 | Juan Quintela | .vmsd = &vmstate_bmdma_current, |
386 | 5ee84c33 | Juan Quintela | .needed = ide_bmdma_current_needed, |
387 | 5ee84c33 | Juan Quintela | }, { |
388 | 5ee84c33 | Juan Quintela | /* empty */
|
389 | 5ee84c33 | Juan Quintela | } |
390 | 977e1244 | Gerd Hoffmann | } |
391 | 407a4f30 | Juan Quintela | }; |
392 | 977e1244 | Gerd Hoffmann | |
393 | 407a4f30 | Juan Quintela | static int ide_pci_post_load(void *opaque, int version_id) |
394 | 977e1244 | Gerd Hoffmann | { |
395 | 977e1244 | Gerd Hoffmann | PCIIDEState *d = opaque; |
396 | 407a4f30 | Juan Quintela | int i;
|
397 | 977e1244 | Gerd Hoffmann | |
398 | 977e1244 | Gerd Hoffmann | for(i = 0; i < 2; i++) { |
399 | 407a4f30 | Juan Quintela | /* current versions always store 0/1, but older version
|
400 | 407a4f30 | Juan Quintela | stored bigger values. We only need last bit */
|
401 | 407a4f30 | Juan Quintela | d->bmdma[i].unit &= 1;
|
402 | 977e1244 | Gerd Hoffmann | } |
403 | 977e1244 | Gerd Hoffmann | return 0; |
404 | 977e1244 | Gerd Hoffmann | } |
405 | 977e1244 | Gerd Hoffmann | |
406 | 407a4f30 | Juan Quintela | const VMStateDescription vmstate_ide_pci = {
|
407 | 407a4f30 | Juan Quintela | .name = "ide",
|
408 | 57338424 | Juan Quintela | .version_id = 3,
|
409 | 407a4f30 | Juan Quintela | .minimum_version_id = 0,
|
410 | 407a4f30 | Juan Quintela | .minimum_version_id_old = 0,
|
411 | 407a4f30 | Juan Quintela | .post_load = ide_pci_post_load, |
412 | 407a4f30 | Juan Quintela | .fields = (VMStateField []) { |
413 | 407a4f30 | Juan Quintela | VMSTATE_PCI_DEVICE(dev, PCIIDEState), |
414 | 407a4f30 | Juan Quintela | VMSTATE_STRUCT_ARRAY(bmdma, PCIIDEState, 2, 0, |
415 | 407a4f30 | Juan Quintela | vmstate_bmdma, BMDMAState), |
416 | 407a4f30 | Juan Quintela | VMSTATE_IDE_BUS_ARRAY(bus, PCIIDEState, 2),
|
417 | 407a4f30 | Juan Quintela | VMSTATE_IDE_DRIVES(bus[0].ifs, PCIIDEState),
|
418 | 407a4f30 | Juan Quintela | VMSTATE_IDE_DRIVES(bus[1].ifs, PCIIDEState),
|
419 | 407a4f30 | Juan Quintela | VMSTATE_END_OF_LIST() |
420 | 407a4f30 | Juan Quintela | } |
421 | 407a4f30 | Juan Quintela | }; |
422 | 407a4f30 | Juan Quintela | |
423 | 3e7e1558 | Juan Quintela | void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table)
|
424 | feef3102 | Gerd Hoffmann | { |
425 | feef3102 | Gerd Hoffmann | PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev); |
426 | feef3102 | Gerd Hoffmann | static const int bus[4] = { 0, 0, 1, 1 }; |
427 | feef3102 | Gerd Hoffmann | static const int unit[4] = { 0, 1, 0, 1 }; |
428 | feef3102 | Gerd Hoffmann | int i;
|
429 | feef3102 | Gerd Hoffmann | |
430 | feef3102 | Gerd Hoffmann | for (i = 0; i < 4; i++) { |
431 | feef3102 | Gerd Hoffmann | if (hd_table[i] == NULL) |
432 | feef3102 | Gerd Hoffmann | continue;
|
433 | 1f850f10 | Gerd Hoffmann | ide_create_drive(d->bus+bus[i], unit[i], hd_table[i]); |
434 | feef3102 | Gerd Hoffmann | } |
435 | feef3102 | Gerd Hoffmann | } |
436 | 40a6238a | Alexander Graf | |
437 | 40a6238a | Alexander Graf | static const struct IDEDMAOps bmdma_ops = { |
438 | 40a6238a | Alexander Graf | .start_dma = bmdma_start_dma, |
439 | 40a6238a | Alexander Graf | .start_transfer = bmdma_start_transfer, |
440 | 40a6238a | Alexander Graf | .prepare_buf = bmdma_prepare_buf, |
441 | 40a6238a | Alexander Graf | .rw_buf = bmdma_rw_buf, |
442 | 40a6238a | Alexander Graf | .set_unit = bmdma_set_unit, |
443 | 40a6238a | Alexander Graf | .add_status = bmdma_add_status, |
444 | 40a6238a | Alexander Graf | .set_inactive = bmdma_set_inactive, |
445 | 40a6238a | Alexander Graf | .restart_cb = bmdma_restart_cb, |
446 | 40a6238a | Alexander Graf | .reset = bmdma_reset, |
447 | 40a6238a | Alexander Graf | }; |
448 | 40a6238a | Alexander Graf | |
449 | 40a6238a | Alexander Graf | void bmdma_init(IDEBus *bus, BMDMAState *bm)
|
450 | 40a6238a | Alexander Graf | { |
451 | 40a6238a | Alexander Graf | qemu_irq *irq; |
452 | 40a6238a | Alexander Graf | |
453 | 40a6238a | Alexander Graf | if (bus->dma == &bm->dma) {
|
454 | 40a6238a | Alexander Graf | return;
|
455 | 40a6238a | Alexander Graf | } |
456 | 40a6238a | Alexander Graf | |
457 | 40a6238a | Alexander Graf | bm->dma.ops = &bmdma_ops; |
458 | 40a6238a | Alexander Graf | bus->dma = &bm->dma; |
459 | 40a6238a | Alexander Graf | bm->irq = bus->irq; |
460 | 40a6238a | Alexander Graf | irq = qemu_allocate_irqs(bmdma_irq, bm, 1);
|
461 | 40a6238a | Alexander Graf | bus->irq = *irq; |
462 | 40a6238a | Alexander Graf | } |