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,23 +267,33 @@ static void channel_load_d(struct fs_dma_ctrl *ctrl, int c) | ||
| 267 | target_phys_addr_t addr = channel_reg(ctrl, c, RW_SAVED_DATA); | 267 | target_phys_addr_t addr = channel_reg(ctrl, c, RW_SAVED_DATA); |
| 268 | 268 | ||
| 269 | /* Load and decode. FIXME: handle endianness. */ | 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 | cpu_physical_memory_read (addr, | 271 | cpu_physical_memory_read (addr, |
| 272 | (void *) &ctrl->channels[c].current_d, | 272 | (void *) &ctrl->channels[c].current_d, |
| 273 | sizeof ctrl->channels[c].current_d); | 273 | sizeof ctrl->channels[c].current_d); |
| 274 | 274 | ||
| 275 | D(dump_d(c, &ctrl->channels[c].current_d)); | 275 | D(dump_d(c, &ctrl->channels[c].current_d)); |
| 276 | ctrl->channels[c].regs[RW_DATA] = addr; | 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 | static void channel_store_d(struct fs_dma_ctrl *ctrl, int c) | 291 | static void channel_store_d(struct fs_dma_ctrl *ctrl, int c) |
| 282 | { | 292 | { |
| 283 | target_phys_addr_t addr = channel_reg(ctrl, c, RW_SAVED_DATA); | 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 | cpu_physical_memory_write (addr, | 297 | cpu_physical_memory_write (addr, |
| 288 | (void *) &ctrl->channels[c].current_d, | 298 | (void *) &ctrl->channels[c].current_d, |
| 289 | sizeof ctrl->channels[c].current_d); | 299 | sizeof ctrl->channels[c].current_d); |
| @@ -326,20 +336,23 @@ static void channel_continue(struct fs_dma_ctrl *ctrl, int c) | @@ -326,20 +336,23 @@ static void channel_continue(struct fs_dma_ctrl *ctrl, int c) | ||
| 326 | /* If the current descriptor cleared the eol flag and we had already | 336 | /* If the current descriptor cleared the eol flag and we had already |
| 327 | reached eol state, do the continue. */ | 337 | reached eol state, do the continue. */ |
| 328 | if (!ctrl->channels[c].current_d.eol && ctrl->channels[c].eol) { | 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 | ctrl->channels[c].current_d.next)); | 340 | ctrl->channels[c].current_d.next)); |
| 331 | ctrl->channels[c].regs[RW_SAVED_DATA] = | 341 | ctrl->channels[c].regs[RW_SAVED_DATA] = |
| 332 | (uint32_t) ctrl->channels[c].current_d.next; | 342 | (uint32_t) ctrl->channels[c].current_d.next; |
| 333 | channel_load_d(ctrl, c); | 343 | channel_load_d(ctrl, c); |
| 334 | channel_start(ctrl, c); | 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 | static void channel_stream_cmd(struct fs_dma_ctrl *ctrl, int c, uint32_t v) | 350 | static void channel_stream_cmd(struct fs_dma_ctrl *ctrl, int c, uint32_t v) |
| 339 | { | 351 | { |
| 340 | unsigned int cmd = v & ((1 << 10) - 1); | 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 | if (cmd & regk_dma_load_d) { | 356 | if (cmd & regk_dma_load_d) { |
| 344 | channel_load_d(ctrl, c); | 357 | channel_load_d(ctrl, c); |
| 345 | if (cmd & regk_dma_burst) | 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,6 +361,7 @@ static void channel_stream_cmd(struct fs_dma_ctrl *ctrl, int c, uint32_t v) | ||
| 348 | 361 | ||
| 349 | if (cmd & regk_dma_load_c) { | 362 | if (cmd & regk_dma_load_c) { |
| 350 | channel_load_c(ctrl, c); | 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,11 +396,30 @@ static void channel_out_run(struct fs_dma_ctrl *ctrl, int c) | ||
| 382 | 396 | ||
| 383 | saved_data_buf = channel_reg(ctrl, c, RW_SAVED_DATA_BUF); | 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 | (uint32_t)ctrl->channels[c].current_d.buf, | 401 | (uint32_t)ctrl->channels[c].current_d.buf, |
| 387 | (uint32_t)ctrl->channels[c].current_d.after, | 402 | (uint32_t)ctrl->channels[c].current_d.after, |
| 388 | saved_data_buf)); | 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 | if (saved_data_buf == (uint32_t)ctrl->channels[c].current_d.after) { | 423 | if (saved_data_buf == (uint32_t)ctrl->channels[c].current_d.after) { |
| 391 | /* Done. Step to next. */ | 424 | /* Done. Step to next. */ |
| 392 | if (ctrl->channels[c].current_d.out_eop) { | 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,36 +436,26 @@ static void channel_out_run(struct fs_dma_ctrl *ctrl, int c) | ||
| 403 | if (ctrl->channels[c].current_d.eol) { | 436 | if (ctrl->channels[c].current_d.eol) { |
| 404 | D(printf("channel %d EOL\n", c)); | 437 | D(printf("channel %d EOL\n", c)); |
| 405 | ctrl->channels[c].eol = 1; | 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 | channel_stop(ctrl, c); | 444 | channel_stop(ctrl, c); |
| 407 | } else { | 445 | } else { |
| 408 | ctrl->channels[c].regs[RW_SAVED_DATA] = | 446 | ctrl->channels[c].regs[RW_SAVED_DATA] = |
| 409 | (uint32_t) ctrl->channels[c].current_d.next; | 447 | (uint32_t) ctrl->channels[c].current_d.next; |
| 410 | /* Load new descriptor. */ | 448 | /* Load new descriptor. */ |
| 411 | channel_load_d(ctrl, c); | 449 | channel_load_d(ctrl, c); |
| 450 | + saved_data_buf = (uint32_t) | ||
| 451 | + ctrl->channels[c].current_d.buf; | ||
| 412 | } | 452 | } |
| 413 | 453 | ||
| 414 | channel_store_d(ctrl, c); | 454 | channel_store_d(ctrl, c); |
| 455 | + ctrl->channels[c].regs[RW_SAVED_DATA_BUF] = saved_data_buf; | ||
| 415 | D(dump_d(c, &ctrl->channels[c].current_d)); | 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 | static int channel_in_process(struct fs_dma_ctrl *ctrl, int c, | 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,14 +506,19 @@ static int channel_in_process(struct fs_dma_ctrl *ctrl, int c, | ||
| 483 | if (ctrl->channels[c].current_d.eol) { | 506 | if (ctrl->channels[c].current_d.eol) { |
| 484 | D(printf("channel %d EOL\n", c)); | 507 | D(printf("channel %d EOL\n", c)); |
| 485 | ctrl->channels[c].eol = 1; | 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 | channel_stop(ctrl, c); | 514 | channel_stop(ctrl, c); |
| 487 | } else { | 515 | } else { |
| 488 | ctrl->channels[c].regs[RW_SAVED_DATA] = | 516 | ctrl->channels[c].regs[RW_SAVED_DATA] = |
| 489 | (uint32_t) ctrl->channels[c].current_d.next; | 517 | (uint32_t) ctrl->channels[c].current_d.next; |
| 490 | /* Load new descriptor. */ | 518 | /* Load new descriptor. */ |
| 491 | channel_load_d(ctrl, c); | 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,21 +551,21 @@ dma_readl (void *opaque, target_phys_addr_t addr) | ||
| 523 | 551 | ||
| 524 | /* Make addr relative to this instances base. */ | 552 | /* Make addr relative to this instances base. */ |
| 525 | c = fs_channel(ctrl->base, addr); | 553 | c = fs_channel(ctrl->base, addr); |
| 526 | - addr &= 0x1fff; | 554 | + addr &= 0x1fff; |
| 527 | switch (addr) | 555 | switch (addr) |
| 528 | - { | 556 | + { |
| 529 | case RW_STAT: | 557 | case RW_STAT: |
| 530 | r = ctrl->channels[c].state & 7; | 558 | r = ctrl->channels[c].state & 7; |
| 531 | r |= ctrl->channels[c].eol << 5; | 559 | r |= ctrl->channels[c].eol << 5; |
| 532 | r |= ctrl->channels[c].stream_cmd_src << 8; | 560 | r |= ctrl->channels[c].stream_cmd_src << 8; |
| 533 | break; | 561 | break; |
| 534 | 562 | ||
| 535 | - default: | 563 | + default: |
| 536 | r = ctrl->channels[c].regs[addr]; | 564 | r = ctrl->channels[c].regs[addr]; |
| 537 | D(printf ("%s c=%d addr=%x pc=%x\n", | 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 | return r; | 569 | return r; |
| 542 | } | 570 | } |
| 543 | 571 | ||
| @@ -560,7 +588,7 @@ dma_writel (void *opaque, target_phys_addr_t addr, uint32_t value) | @@ -560,7 +588,7 @@ dma_writel (void *opaque, target_phys_addr_t addr, uint32_t value) | ||
| 560 | c = fs_channel(ctrl->base, addr); | 588 | c = fs_channel(ctrl->base, addr); |
| 561 | addr &= 0x1fff; | 589 | addr &= 0x1fff; |
| 562 | switch (addr) | 590 | switch (addr) |
| 563 | - { | 591 | + { |
| 564 | case RW_DATA: | 592 | case RW_DATA: |
| 565 | ctrl->channels[c].regs[addr] = value; | 593 | ctrl->channels[c].regs[addr] = value; |
| 566 | break; | 594 | break; |
| @@ -591,13 +619,15 @@ dma_writel (void *opaque, target_phys_addr_t addr, uint32_t value) | @@ -591,13 +619,15 @@ dma_writel (void *opaque, target_phys_addr_t addr, uint32_t value) | ||
| 591 | 619 | ||
| 592 | case RW_STREAM_CMD: | 620 | case RW_STREAM_CMD: |
| 593 | ctrl->channels[c].regs[addr] = value; | 621 | ctrl->channels[c].regs[addr] = value; |
| 622 | + D(printf("stream_cmd ch=%d pc=%x\n", | ||
| 623 | + c, ctrl->env->pc)); | ||
| 594 | channel_stream_cmd(ctrl, c, value); | 624 | channel_stream_cmd(ctrl, c, value); |
| 595 | break; | 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 |