Commit a8303d18e044b9c808c27a9c48888c6e639a321d
1 parent
77b73de6
ETRAX: More DMA context level related fixes.
* When hitting EOL (end of list) at the data descriptor level, the DMA should mark the current context-descriptor as disabled and perform a context-store so software can see whats goin on. * Context loads update RW_SAVED_DATA_BUF, data loads dont. This fixes an issue with ethernet bootstrapping. * Reorder the logic for processing out channels to be more like the one for input channels. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4723 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
70 additions
and
40 deletions
hw/etraxfs_dma.c
... | ... | @@ -267,23 +267,33 @@ static void channel_load_d(struct fs_dma_ctrl *ctrl, int c) |
267 | 267 | target_phys_addr_t addr = channel_reg(ctrl, c, RW_SAVED_DATA); |
268 | 268 | |
269 | 269 | /* Load and decode. FIXME: handle endianness. */ |
270 | - D(printf("%s addr=%x\n", __func__, addr)); | |
270 | + D(printf("%s ch=%d addr=%x\n", __func__, c, addr)); | |
271 | 271 | cpu_physical_memory_read (addr, |
272 | 272 | (void *) &ctrl->channels[c].current_d, |
273 | 273 | sizeof ctrl->channels[c].current_d); |
274 | 274 | |
275 | 275 | D(dump_d(c, &ctrl->channels[c].current_d)); |
276 | 276 | ctrl->channels[c].regs[RW_DATA] = addr; |
277 | - ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = | |
278 | - (uint32_t)ctrl->channels[c].current_d.buf; | |
277 | +} | |
278 | + | |
279 | +static void channel_store_c(struct fs_dma_ctrl *ctrl, int c) | |
280 | +{ | |
281 | + target_phys_addr_t addr = channel_reg(ctrl, c, RW_GROUP_DOWN); | |
282 | + | |
283 | + /* Encode and store. FIXME: handle endianness. */ | |
284 | + D(printf("%s ch=%d addr=%x\n", __func__, c, addr)); | |
285 | + D(dump_d(c, &ctrl->channels[c].current_d)); | |
286 | + cpu_physical_memory_write (addr, | |
287 | + (void *) &ctrl->channels[c].current_c, | |
288 | + sizeof ctrl->channels[c].current_c); | |
279 | 289 | } |
280 | 290 | |
281 | 291 | static void channel_store_d(struct fs_dma_ctrl *ctrl, int c) |
282 | 292 | { |
283 | 293 | target_phys_addr_t addr = channel_reg(ctrl, c, RW_SAVED_DATA); |
284 | 294 | |
285 | - /* Load and decode. FIXME: handle endianness. */ | |
286 | - D(printf("%s addr=%x\n", __func__, addr)); | |
295 | + /* Encode and store. FIXME: handle endianness. */ | |
296 | + D(printf("%s ch=%d addr=%x\n", __func__, c, addr)); | |
287 | 297 | cpu_physical_memory_write (addr, |
288 | 298 | (void *) &ctrl->channels[c].current_d, |
289 | 299 | sizeof ctrl->channels[c].current_d); |
... | ... | @@ -326,20 +336,23 @@ static void channel_continue(struct fs_dma_ctrl *ctrl, int c) |
326 | 336 | /* If the current descriptor cleared the eol flag and we had already |
327 | 337 | reached eol state, do the continue. */ |
328 | 338 | if (!ctrl->channels[c].current_d.eol && ctrl->channels[c].eol) { |
329 | - D(printf("continue %d ok %x\n", c, | |
339 | + D(printf("continue %d ok %p\n", c, | |
330 | 340 | ctrl->channels[c].current_d.next)); |
331 | 341 | ctrl->channels[c].regs[RW_SAVED_DATA] = |
332 | 342 | (uint32_t) ctrl->channels[c].current_d.next; |
333 | 343 | channel_load_d(ctrl, c); |
334 | 344 | channel_start(ctrl, c); |
335 | 345 | } |
346 | + ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = | |
347 | + (uint32_t) ctrl->channels[c].current_d.buf; | |
336 | 348 | } |
337 | 349 | |
338 | 350 | static void channel_stream_cmd(struct fs_dma_ctrl *ctrl, int c, uint32_t v) |
339 | 351 | { |
340 | 352 | unsigned int cmd = v & ((1 << 10) - 1); |
341 | 353 | |
342 | - D(printf("%s cmd=%x\n", __func__, cmd)); | |
354 | + D(printf("%s ch=%d cmd=%x pc=%x\n", | |
355 | + __func__, c, cmd, ctrl->env->pc)); | |
343 | 356 | if (cmd & regk_dma_load_d) { |
344 | 357 | channel_load_d(ctrl, c); |
345 | 358 | if (cmd & regk_dma_burst) |
... | ... | @@ -348,6 +361,7 @@ static void channel_stream_cmd(struct fs_dma_ctrl *ctrl, int c, uint32_t v) |
348 | 361 | |
349 | 362 | if (cmd & regk_dma_load_c) { |
350 | 363 | channel_load_c(ctrl, c); |
364 | + channel_start(ctrl, c); | |
351 | 365 | } |
352 | 366 | } |
353 | 367 | |
... | ... | @@ -382,11 +396,30 @@ static void channel_out_run(struct fs_dma_ctrl *ctrl, int c) |
382 | 396 | |
383 | 397 | saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF); |
384 | 398 | |
385 | - D(printf("buf=%x after=%x saved_data_buf=%x\n", | |
399 | + D(fprintf(logfile, "ch=%d buf=%x after=%x saved_data_buf=%x\n", | |
400 | + c, | |
386 | 401 | (uint32_t)ctrl->channels[c].current_d.buf, |
387 | 402 | (uint32_t)ctrl->channels[c].current_d.after, |
388 | 403 | saved_data_buf)); |
389 | 404 | |
405 | + len = (uint32_t) ctrl->channels[c].current_d.after; | |
406 | + len -= saved_data_buf; | |
407 | + | |
408 | + if (len > sizeof buf) | |
409 | + len = sizeof buf; | |
410 | + cpu_physical_memory_read (saved_data_buf, buf, len); | |
411 | + | |
412 | + D(printf("channel %d pushes %x %u bytes\n", c, | |
413 | + saved_data_buf, len)); | |
414 | + | |
415 | + if (ctrl->channels[c].client->client.push) | |
416 | + ctrl->channels[c].client->client.push( | |
417 | + ctrl->channels[c].client->client.opaque, buf, len); | |
418 | + else | |
419 | + printf("WARNING: DMA ch%d dataloss, no attached client.\n", c); | |
420 | + | |
421 | + saved_data_buf += len; | |
422 | + | |
390 | 423 | if (saved_data_buf == (uint32_t)ctrl->channels[c].current_d.after) { |
391 | 424 | /* Done. Step to next. */ |
392 | 425 | if (ctrl->channels[c].current_d.out_eop) { |
... | ... | @@ -403,36 +436,26 @@ static void channel_out_run(struct fs_dma_ctrl *ctrl, int c) |
403 | 436 | if (ctrl->channels[c].current_d.eol) { |
404 | 437 | D(printf("channel %d EOL\n", c)); |
405 | 438 | ctrl->channels[c].eol = 1; |
439 | + | |
440 | + /* Mark the context as disabled. */ | |
441 | + ctrl->channels[c].current_c.dis = 1; | |
442 | + channel_store_c(ctrl, c); | |
443 | + | |
406 | 444 | channel_stop(ctrl, c); |
407 | 445 | } else { |
408 | 446 | ctrl->channels[c].regs[RW_SAVED_DATA] = |
409 | 447 | (uint32_t) ctrl->channels[c].current_d.next; |
410 | 448 | /* Load new descriptor. */ |
411 | 449 | channel_load_d(ctrl, c); |
450 | + saved_data_buf = (uint32_t) | |
451 | + ctrl->channels[c].current_d.buf; | |
412 | 452 | } |
413 | 453 | |
414 | 454 | channel_store_d(ctrl, c); |
455 | + ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf; | |
415 | 456 | D(dump_d(c, &ctrl->channels[c].current_d)); |
416 | - return; | |
417 | 457 | } |
418 | - | |
419 | - len = (uint32_t) ctrl->channels[c].current_d.after; | |
420 | - len -= saved_data_buf; | |
421 | - | |
422 | - if (len > sizeof buf) | |
423 | - len = sizeof buf; | |
424 | - cpu_physical_memory_read (saved_data_buf, buf, len); | |
425 | - | |
426 | - D(printf("channel %d pushes %x %u bytes\n", c, | |
427 | - saved_data_buf, len)); | |
428 | - /* TODO: Push content. */ | |
429 | - if (ctrl->channels[c].client->client.push) | |
430 | - ctrl->channels[c].client->client.push( | |
431 | - ctrl->channels[c].client->client.opaque, buf, len); | |
432 | - else | |
433 | - printf("WARNING: DMA ch%d dataloss, no attached client.\n", c); | |
434 | - | |
435 | - ctrl->channels[c].regs[RW_SAVED_DATA_BUF] += len; | |
458 | + ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf; | |
436 | 459 | } |
437 | 460 | |
438 | 461 | static int channel_in_process(struct fs_dma_ctrl *ctrl, int c, |
... | ... | @@ -483,14 +506,19 @@ static int channel_in_process(struct fs_dma_ctrl *ctrl, int c, |
483 | 506 | if (ctrl->channels[c].current_d.eol) { |
484 | 507 | D(printf("channel %d EOL\n", c)); |
485 | 508 | ctrl->channels[c].eol = 1; |
509 | + | |
510 | + /* Mark the context as disabled. */ | |
511 | + ctrl->channels[c].current_c.dis = 1; | |
512 | + channel_store_c(ctrl, c); | |
513 | + | |
486 | 514 | channel_stop(ctrl, c); |
487 | 515 | } else { |
488 | 516 | ctrl->channels[c].regs[RW_SAVED_DATA] = |
489 | 517 | (uint32_t) ctrl->channels[c].current_d.next; |
490 | 518 | /* Load new descriptor. */ |
491 | 519 | channel_load_d(ctrl, c); |
492 | - saved_data_buf = | |
493 | - ctrl->channels[c].regs[RW_SAVED_DATA_BUF]; | |
520 | + saved_data_buf = (uint32_t) | |
521 | + ctrl->channels[c].current_d.buf; | |
494 | 522 | } |
495 | 523 | } |
496 | 524 | |
... | ... | @@ -523,21 +551,21 @@ dma_readl (void *opaque, target_phys_addr_t addr) |
523 | 551 | |
524 | 552 | /* Make addr relative to this instances base. */ |
525 | 553 | c = fs_channel(ctrl->base, addr); |
526 | - addr &= 0x1fff; | |
554 | + addr &= 0x1fff; | |
527 | 555 | switch (addr) |
528 | - { | |
556 | + { | |
529 | 557 | case RW_STAT: |
530 | 558 | r = ctrl->channels[c].state & 7; |
531 | 559 | r |= ctrl->channels[c].eol << 5; |
532 | 560 | r |= ctrl->channels[c].stream_cmd_src << 8; |
533 | 561 | break; |
534 | 562 | |
535 | - default: | |
563 | + default: | |
536 | 564 | r = ctrl->channels[c].regs[addr]; |
537 | 565 | D(printf ("%s c=%d addr=%x pc=%x\n", |
538 | - __func__, c, addr, env->pc)); | |
539 | - break; | |
540 | - } | |
566 | + __func__, c, addr, ctrl->env->pc)); | |
567 | + break; | |
568 | + } | |
541 | 569 | return r; |
542 | 570 | } |
543 | 571 | |
... | ... | @@ -560,7 +588,7 @@ dma_writel (void *opaque, target_phys_addr_t addr, uint32_t value) |
560 | 588 | c = fs_channel(ctrl->base, addr); |
561 | 589 | addr &= 0x1fff; |
562 | 590 | switch (addr) |
563 | - { | |
591 | + { | |
564 | 592 | case RW_DATA: |
565 | 593 | ctrl->channels[c].regs[addr] = value; |
566 | 594 | break; |
... | ... | @@ -591,13 +619,15 @@ dma_writel (void *opaque, target_phys_addr_t addr, uint32_t value) |
591 | 619 | |
592 | 620 | case RW_STREAM_CMD: |
593 | 621 | ctrl->channels[c].regs[addr] = value; |
622 | + D(printf("stream_cmd ch=%d pc=%x\n", | |
623 | + c, ctrl->env->pc)); | |
594 | 624 | channel_stream_cmd(ctrl, c, value); |
595 | 625 | break; |
596 | 626 | |
597 | - default: | |
598 | - D(printf ("%s c=%d %x %x pc=%x\n", | |
599 | - __func__, c, addr, value, env->pc)); | |
600 | - break; | |
627 | + default: | |
628 | + D(printf ("%s c=%d %x %x pc=%x\n", | |
629 | + __func__, c, addr, value, ctrl->env->pc)); | |
630 | + break; | |
601 | 631 | } |
602 | 632 | } |
603 | 633 | ... | ... |