- Timestamp:
- 06/10/11 07:06:14 (13 years ago)
- Branches:
- 4.11, 5, master
- Children:
- fa2f4708
- Parents:
- 77199b75
- Location:
- c/src/lib/libbsp/powerpc/mpc55xxevb
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
c/src/lib/libbsp/powerpc/mpc55xxevb/ChangeLog
r77199b75 rcc3929b8 1 2011-06-10 Sebastian Huber <sebastian.huber@embedded-brains.de> 2 3 * network/smsc9218i.c: Optimizations. 4 1 5 2011-06-07 Sebastian Huber <sebastian.huber@embedded-brains.de> 2 6 -
c/src/lib/libbsp/powerpc/mpc55xxevb/network/smsc9218i.c
r77199b75 rcc3929b8 29 29 30 30 #include <errno.h> 31 #include <assert.h> 31 32 #include <stdlib.h> 32 33 #include <stdio.h> … … 58 59 #include <bsp/smsc9218i.h> 59 60 60 #include <rtems/status-checks.h>61 62 61 #if MCLBYTES != 2048 63 62 #warning "unexpected MCLBYTES value" 64 63 #endif 65 64 65 #define ASSERT_SC(sc) assert((sc) == RTEMS_SUCCESSFUL) 66 66 67 #define SMSC9218I_EVENT_TX RTEMS_EVENT_1 67 68 … … 76 77 #define SMSC9218I_EVENT_PHY RTEMS_EVENT_6 77 78 78 #define SMSC9218I_EVENT_ EDMA RTEMS_EVENT_779 80 #define SMSC9218I_EVENT_ EDMA_ERROR RTEMS_EVENT_879 #define SMSC9218I_EVENT_DMA RTEMS_EVENT_7 80 81 #define SMSC9218I_EVENT_DMA_ERROR RTEMS_EVENT_8 81 82 82 83 /* Adjust by two bytes for proper IP header alignment */ 83 84 #define SMSC9218I_RX_DATA_OFFSET 2 84 85 85 #define SMSC9218I_ TX_JOBS 128U86 87 #define SMSC9218I_TX_JOBS _MAX (SMSC9218I_TX_JOBS - 1U)86 #define SMSC9218I_RX_JOBS 32 87 88 #define SMSC9218I_TX_JOBS 64 88 89 89 90 /* Maximum number of fragments per frame, see manual section 3.11.3.2 */ 90 91 #define SMSC9218I_TX_FRAGMENT_MAX 86 91 92 93 #if SMSC9218I_TX_JOBS > SMSC9218I_TX_FRAGMENT_MAX 94 #error "too many TX jobs" 95 #endif 96 92 97 #define SMSC9218I_IRQ_CFG_GLOBAL_ENABLE \ 93 98 (SMSC9218I_IRQ_CFG_IRQ_EN | SMSC9218I_IRQ_CFG_IRQ_TYPE) … … 103 108 #define SMSC9218I_EDMA_TX_CHANNEL 48 104 109 105 #define SMSC9218I_ EDMA_TX_TCD_BMF_LINK 0x10011106 107 #define SMSC9218I_ EDMA_TX_TCD_BMF_INTERRUPT 0x10003108 109 #define SMSC9218I_ EDMA_TX_TCD_BMF_CLEAR 0x10000110 #define SMSC9218I_TCD_BMF_LINK 0x10011 111 112 #define SMSC9218I_TCD_BMF_LAST 0x10003 113 114 #define SMSC9218I_TCD_BMF_CLEAR 0x10000 110 115 111 116 #define SMSC9218I_ERROR_INTERRUPTS \ … … 114 119 | SMSC9218I_INT_RXE \ 115 120 | SMSC9218I_INT_TXE) 121 122 #define SMSC9218I_UNLIKELY(x) __builtin_expect((x), 0) 116 123 117 124 #ifdef DEBUG … … 138 145 mpc55xx_edma_channel_entry edma_receive; 139 146 mpc55xx_edma_channel_entry edma_transmit; 147 unsigned phy_interrupts; 140 148 unsigned received_frames; 149 unsigned receiver_errors; 141 150 unsigned receive_interrupts; 142 unsigned transmitted_frames; 143 unsigned transmit_interrupts; 144 unsigned receiver_errors; 151 unsigned receive_dma_interrupts; 145 152 unsigned receive_too_long_errors; 146 153 unsigned receive_collision_errors; 147 154 unsigned receive_crc_errors; 148 unsigned receive_ edma_errors;155 unsigned receive_dma_errors; 149 156 unsigned receive_drop; 150 157 unsigned receive_watchdog_timeouts; 158 unsigned transmitted_frames; 151 159 unsigned transmitter_errors; 160 unsigned transmit_interrupts; 161 unsigned transmit_dma_interrupts; 152 162 unsigned transmit_status_overflows; 153 163 unsigned transmit_frame_errors; 154 unsigned transmit_ edma_errors;164 unsigned transmit_dma_errors; 155 165 } smsc9218i_driver_entry; 156 166 … … 167 177 struct mbuf *frame; 168 178 struct mbuf *next_fragment; 169 unsignedempty_index;170 unsignedtransfer_index;171 unsignedtransfer_last_index;172 unsignedtodo_index;173 unsignedempty;174 unsignedtransfer;175 unsignedtodo;179 int empty_index; 180 int transfer_index; 181 int transfer_last_index; 182 int todo_index; 183 int empty; 184 int transfer; 185 int todo; 176 186 uint32_t frame_length; 177 187 uint32_t command_b; 178 188 uint16_t tag; 179 189 bool done; 180 unsigned fixme_tiny_fragments; 181 unsigned fixme_too_many; 190 unsigned frame_compact_count; 182 191 } smsc9218i_transmit_job_control; 183 192 184 static void smsc9218i_edma_done( 193 typedef struct { 194 struct tcd_t tcd_table [SMSC9218I_RX_JOBS]; 195 struct mbuf *mbuf_table [SMSC9218I_RX_JOBS]; 196 int consume; 197 int done; 198 int produce; 199 } smsc9218i_receive_job_control; 200 201 static smsc9218i_receive_job_control smsc_rx_jc __attribute__((aligned (32))); 202 203 static void smsc9218i_transmit_dma_done( 204 mpc55xx_edma_channel_entry *channel_entry, 205 uint32_t error_status 206 ); 207 208 static void smsc9218i_receive_dma_done( 185 209 mpc55xx_edma_channel_entry *e, 186 210 uint32_t error_status 187 ) 188 { 189 rtems_event_set event = error_status == 0 ? 190 SMSC9218I_EVENT_EDMA : SMSC9218I_EVENT_EDMA_ERROR; 191 192 SMSC9218I_PRINTK( 193 "edma: id = 0x%08x, error status = 0x%08x\n", 194 e->id, 195 error_status 196 ); 197 198 rtems_event_send(e->id, event); 199 } 211 ); 200 212 201 213 static smsc9218i_driver_entry smsc9218i_driver_data = { … … 205 217 .edma_receive = { 206 218 .channel = SMSC9218I_EDMA_RX_CHANNEL, 207 .done = smsc9218i_ edma_done,219 .done = smsc9218i_receive_dma_done, 208 220 .id = RTEMS_ID_NONE 209 221 }, 210 222 .edma_transmit = { 211 223 .channel = SMSC9218I_EDMA_TX_CHANNEL, 212 .done = smsc9218i_ edma_done,224 .done = smsc9218i_transmit_dma_done, 213 225 .id = RTEMS_ID_NONE 214 226 } … … 357 369 reg = regs->rx_fifo_inf; 358 370 printf( 359 "rx_fifo_inf: 0x%08" PRIx32 " (status u nused = %" PRIu32360 ", data u nused = %" PRIu32 ")\n",371 "rx_fifo_inf: 0x%08" PRIx32 " (status used = %" PRIu32 372 ", data used = %" PRIu32 ")\n", 361 373 SMSC9218I_SWAP(reg), 362 374 SMSC9218I_RX_FIFO_INF_GET_SUSED(reg), … … 426 438 #endif 427 439 440 static void smsc9218i_flush_tcd(struct tcd_t *tcd) 441 { 442 ppc_data_cache_block_store(tcd); 443 } 444 445 static uint32_t smsc9218i_align_up(uint32_t val) 446 { 447 return 4U + ((val - 1U) & ~0x3U); 448 } 449 450 static void smsc9218i_discard_frame( 451 smsc9218i_driver_entry *e, 452 volatile smsc9218i_registers *regs, 453 uint32_t rx_fifo_status, 454 uint32_t frame_length, 455 uint32_t data_length 456 ) 457 { 458 /* Update error counters */ 459 if ((rx_fifo_status & SMSC9218I_RX_STS_ERROR_TOO_LONG) != 0) { 460 ++e->receive_too_long_errors; 461 } 462 if ((rx_fifo_status & SMSC9218I_RX_STS_ERROR_COLLISION) != 0) { 463 ++e->receive_collision_errors; 464 } 465 if ((rx_fifo_status & SMSC9218I_RX_STS_ERROR_CRC) != 0) { 466 ++e->receive_crc_errors; 467 } 468 469 /* Discard frame */ 470 if (frame_length > 16) { 471 /* Fast forward */ 472 regs->rx_dp_ctl = SMSC9218I_RX_DP_CTRL_FFWD; 473 474 while ((regs->rx_dp_ctl & SMSC9218I_RX_DP_CTRL_FFWD) != 0) { 475 /* Wait */ 476 } 477 } else { 478 uint32_t len = data_length / 4; 479 uint32_t i = 0; 480 481 /* Discard data */ 482 for (i = 0; i < len; ++i) { 483 regs->rx_fifo_data; 484 } 485 } 486 } 487 488 static void smsc9218i_setup_receive_dma( 489 smsc9218i_driver_entry *e, 490 volatile smsc9218i_registers *regs, 491 smsc9218i_receive_job_control *jc 492 ) 493 { 494 int c = jc->consume; 495 int p = jc->produce; 496 int np = (p + 1) % SMSC9218I_RX_JOBS; 497 struct tcd_t *first = &jc->tcd_table [p]; 498 struct tcd_t *last = NULL; 499 500 while (np != c) { 501 uint32_t rx_fifo_inf = 0; 502 uint32_t status_used = 0; 503 504 /* Clear FIFO level status */ 505 regs->int_sts = SMSC9218I_INT_RSFL; 506 507 /* Next FIFO status */ 508 rx_fifo_inf = regs->rx_fifo_inf; 509 status_used = SMSC9218I_RX_FIFO_INF_GET_SUSED(rx_fifo_inf); 510 511 if (status_used > 0) { 512 uint32_t status = regs->rx_fifo_status; 513 uint32_t frame_length = SMSC9218I_RX_STS_GET_LENGTH(status); 514 uint32_t data_length = smsc9218i_align_up( 515 SMSC9218I_RX_DATA_OFFSET + frame_length 516 ); 517 bool frame_ok = (status & SMSC9218I_RX_STS_ERROR) == 0; 518 519 if (frame_ok) { 520 struct mbuf *m = jc->mbuf_table [p]; 521 int mbuf_length = (int) frame_length - ETHER_HDR_LEN - ETHER_CRC_LEN; 522 struct tcd_t *current = &jc->tcd_table [p]; 523 524 m->m_len = mbuf_length; 525 m->m_pkthdr.len = mbuf_length; 526 527 current->NBYTES = data_length; 528 smsc9218i_flush_tcd(current); 529 530 last = current; 531 p = np; 532 np = (p + 1) % SMSC9218I_RX_JOBS; 533 } else { 534 smsc9218i_discard_frame(e, regs, status, frame_length, data_length); 535 } 536 } else { 537 break; 538 } 539 } 540 541 jc->produce = p; 542 543 if (last != NULL) { 544 volatile struct tcd_t *channel = &EDMA.TCD [e->edma_receive.channel]; 545 546 /* Setup last TCD */ 547 last->BMF.R = SMSC9218I_TCD_BMF_LAST; 548 smsc9218i_flush_tcd(last); 549 ppc_synchronize_data(); 550 551 /* Start eDMA transfer */ 552 channel->SADDR = first->SADDR; 553 channel->SDF.R = first->SDF.R; 554 channel->NBYTES = first->NBYTES; 555 channel->SLAST = first->SLAST; 556 channel->DADDR = first->DADDR; 557 channel->CDF.R = first->CDF.R; 558 channel->DLAST_SGA = first->DLAST_SGA; 559 channel->BMF.R = SMSC9218I_TCD_BMF_CLEAR; 560 channel->BMF.R = first->BMF.R; 561 } 562 } 563 564 static void smsc9218i_receive_dma_done( 565 mpc55xx_edma_channel_entry *channel_entry, 566 uint32_t error_status 567 ) 568 { 569 rtems_status_code sc = RTEMS_SUCCESSFUL; 570 smsc9218i_driver_entry *e = &smsc9218i_driver_data; 571 volatile smsc9218i_registers *const regs = smsc9218i; 572 smsc9218i_receive_job_control *jc = &smsc_rx_jc; 573 574 SMSC9218I_PRINTK( 575 "edma: id = 0x%08x, error status = 0x%08x\n", 576 channel_entry->id, 577 error_status 578 ); 579 580 ++e->receive_dma_interrupts; 581 if (SMSC9218I_UNLIKELY(error_status != 0)) { 582 ++e->receive_dma_errors; 583 } 584 585 sc = rtems_event_send(channel_entry->id, SMSC9218I_EVENT_DMA); 586 ASSERT_SC(sc); 587 588 jc->done = jc->produce; 589 590 smsc9218i_setup_receive_dma(e, regs, jc); 591 } 592 593 static void smsc9218i_transmit_dma_done( 594 mpc55xx_edma_channel_entry *channel_entry, 595 uint32_t error_status 596 ) 597 { 598 rtems_status_code sc = RTEMS_SUCCESSFUL; 599 smsc9218i_driver_entry *e = &smsc9218i_driver_data; 600 rtems_event_set event = error_status == 0 ? 601 SMSC9218I_EVENT_DMA : SMSC9218I_EVENT_DMA_ERROR; 602 603 SMSC9218I_PRINTK( 604 "edma: id = 0x%08x, error status = 0x%08x\n", 605 channel_entry->id, 606 error_status 607 ); 608 609 ++e->transmit_dma_interrupts; 610 611 sc = rtems_event_send(channel_entry->id, event); 612 ASSERT_SC(sc); 613 } 614 428 615 static void smsc9218i_interrupt_handler(void *arg) 429 616 { 617 rtems_status_code sc = RTEMS_SUCCESSFUL; 430 618 smsc9218i_driver_entry *e = (smsc9218i_driver_entry *) arg; 431 619 volatile smsc9218i_registers *const regs = smsc9218i; 432 rtems_event_set re = 0;433 rtems_event_set te = 0;434 620 uint32_t int_en = regs->int_en; 435 621 uint32_t int_sts = regs->int_sts & int_en; … … 456 642 457 643 /* Error interrupts */ 458 if ( (int_sts & SMSC9218I_ERROR_INTERRUPTS) != 0) {644 if (SMSC9218I_UNLIKELY((int_sts & SMSC9218I_ERROR_INTERRUPTS) != 0)) { 459 645 if ((int_sts & SMSC9218I_INT_TXSO) != 0) { 460 646 ++e->transmit_status_overflows; … … 473 659 /* Check receive interrupts */ 474 660 if ((int_sts & SMSC9218I_INT_RSFL) != 0) { 661 smsc9218i_receive_job_control *jc = &smsc_rx_jc; 662 475 663 int_en &= ~SMSC9218I_INT_RSFL; 476 re = SMSC9218I_EVENT_RX; 664 ++e->receive_interrupts; 665 smsc9218i_setup_receive_dma(e, regs, jc); 477 666 } 478 667 479 668 /* Check PHY interrupts */ 480 if ((int_sts & SMSC9218I_INT_PHY) != 0) { 669 if (SMSC9218I_UNLIKELY((int_sts & SMSC9218I_INT_PHY) != 0)) { 670 SMSC9218I_PRINTK("interrupt: phy\n"); 481 671 int_en &= ~SMSC9218I_INT_PHY; 482 re |= SMSC9218I_EVENT_PHY; 483 } 484 485 /* Send events to receive task */ 486 if (re != 0) { 487 SMSC9218I_PRINTK("interrupt: receive: 0x%08x\n", re); 488 ++e->receive_interrupts; 489 (void) rtems_event_send(e->receive_task, re); 672 ++e->phy_interrupts; 673 sc = rtems_event_send(e->receive_task, SMSC9218I_EVENT_PHY); 674 ASSERT_SC(sc); 490 675 } 491 676 492 677 /* Check transmit interrupts */ 493 678 if ((int_sts & SMSC9218I_INT_TDFA) != 0) { 679 SMSC9218I_PRINTK("interrupt: transmit\n"); 494 680 int_en &= ~SMSC9218I_INT_TDFA; 495 te = SMSC9218I_EVENT_TX;496 }497 498 /* Send events to transmit task */499 if (te != 0) {500 SMSC9218I_PRINTK("interrupt: transmit: 0x%08x\n", te);501 681 ++e->transmit_interrupts; 502 (void) rtems_event_send(e->transmit_task, te); 682 sc = rtems_event_send(e->transmit_task, SMSC9218I_EVENT_TX); 683 ASSERT_SC(sc); 503 684 } 504 685 … … 508 689 /* Enable module interrupts */ 509 690 regs->irq_cfg = SMSC9218I_IRQ_CFG_GLOBAL_ENABLE; 510 }511 512 static void smsc9218i_enable_receive_interrupts(513 volatile smsc9218i_registers *regs514 )515 {516 rtems_interrupt_level level;517 518 rtems_interrupt_disable(level);519 regs->int_en |= SMSC9218I_INT_RSFL;520 rtems_interrupt_enable(level);521 691 } 522 692 … … 581 751 } 582 752 583 static struct mbuf *smsc9218i_new_mbuf(struct ifnet *ifp) 753 static void smsc9218i_new_mbuf( 754 struct ifnet *ifp, 755 smsc9218i_receive_job_control *jc, 756 int i 757 ) 584 758 { 585 759 struct mbuf *m = m_gethdr(M_WAIT, MT_DATA); 760 struct tcd_t *tcd = &jc->tcd_table [i]; 761 char *data = NULL; 586 762 587 763 m->m_pkthdr.rcvif = ifp; 588 764 MCLGET(m, M_WAIT); 589 765 590 return m; 591 } 592 593 static void smsc9218i_receive_task(void *arg) 766 data = mtod(m, char *); 767 m->m_data = data + SMSC9218I_RX_DATA_OFFSET + ETHER_HDR_LEN; 768 769 jc->mbuf_table [i] = m; 770 771 tcd->DADDR = (uint32_t) data; 772 tcd->BMF.R = SMSC9218I_TCD_BMF_LINK; 773 774 /* FIXME: This is maybe a problem in case of a lot of small frames */ 775 rtems_cache_invalidate_multiple_data_lines( 776 data, 777 SMSC9218I_RX_DATA_OFFSET + ETHER_HDR_LEN + ETHERMTU + ETHER_CRC_LEN 778 ); 779 } 780 781 static void smsc9218i_init_receive_jobs( 782 smsc9218i_driver_entry *e, 783 volatile smsc9218i_registers *regs, 784 smsc9218i_receive_job_control *jc 785 ) 594 786 { 595 787 rtems_status_code sc = RTEMS_SUCCESSFUL; 596 rtems_event_set events = 0;597 smsc9218i_driver_entry *e = (smsc9218i_driver_entry *) arg;598 788 struct ifnet *ifp = &e->arpcom.ac_if; 599 volatile smsc9218i_registers *const regs = smsc9218i; 600 volatile struct tcd_t *tcd = &EDMA.TCD [e->edma_receive.channel]; 601 struct tcd_t tcd_init = EDMA_TCD_DEFAULT; 602 uint32_t mac_cr = 0; 603 604 SMSC9218I_PRINTF("%s\n", __func__); 789 int i = 0; 605 790 606 791 /* Obtain receive eDMA channel */ 607 792 e->edma_receive.id = e->receive_task; 608 793 sc = mpc55xx_edma_obtain_channel(&e->edma_receive); 609 RTEMS_CLEANUP_SC(sc, cleanup, "obtain receive eDMA channel"); 610 611 /* Setup receive eDMA channel */ 612 tcd_init.SDF.B.SSIZE = 2; 613 tcd_init.SDF.B.DSIZE = 2; 614 tcd_init.SADDR = (uint32_t) ®s->rx_fifo_data; 615 *tcd = tcd_init; 794 ASSERT_SC(sc); 795 796 for (i = 0; i < SMSC9218I_RX_JOBS; ++i) { 797 struct tcd_t *tcd = &jc->tcd_table [i]; 798 struct tcd_t *next_tcd = &jc->tcd_table [(i + 1) % SMSC9218I_RX_JOBS]; 799 800 tcd->SADDR = (uint32_t) ®s->rx_fifo_data; 801 tcd->SDF.B.SSIZE = 0x2; 802 tcd->SDF.B.DSIZE = 0x2; 803 tcd->CDF.B.CITER = 1; 804 tcd->CDF.B.DOFF = 4; 805 tcd->DLAST_SGA = (int32_t) next_tcd; 806 807 smsc9218i_new_mbuf(ifp, jc, i); 808 } 809 } 810 811 static void smsc9218i_ether_input( 812 smsc9218i_driver_entry *e, 813 volatile smsc9218i_registers *regs, 814 smsc9218i_receive_job_control *jc 815 ) 816 { 817 rtems_interrupt_level level; 818 struct ifnet *ifp = &e->arpcom.ac_if; 819 int c = jc->consume; 820 int d = jc->done; 821 822 while (c != d) { 823 struct mbuf *m = jc->mbuf_table [c]; 824 struct ether_header *eh = (struct ether_header *) 825 (mtod(m, char *) - ETHER_HDR_LEN); 826 827 ++e->received_frames; 828 ether_input(ifp, eh, m); 829 smsc9218i_new_mbuf(ifp, jc, c); 830 831 c = (c + 1) % SMSC9218I_RX_JOBS; 832 } 833 834 jc->consume = c; 835 836 rtems_interrupt_disable(level); 837 /* Enabling the receive interrupts while the DMA is active leads to chaos */ 838 if (c == jc->produce) { 839 regs->int_en |= SMSC9218I_INT_RSFL; 840 } 841 rtems_interrupt_enable(level); 842 } 843 844 static void smsc9218i_receive_task(void *arg) 845 { 846 rtems_status_code sc = RTEMS_SUCCESSFUL; 847 rtems_interrupt_level level; 848 smsc9218i_receive_job_control *jc = &smsc_rx_jc; 849 smsc9218i_driver_entry *e = (smsc9218i_driver_entry *) arg; 850 volatile smsc9218i_registers *const regs = smsc9218i; 851 uint32_t mac_cr = 0; 852 853 smsc9218i_init_receive_jobs(e, regs, jc); 616 854 617 855 /* Configure receiver */ … … 620 858 621 859 /* Enable MAC receiver */ 622 mac_cr = smsc9218i_mac_read(regs, SMSC9218I_MAC_CR) | SMSC9218I_MAC_CR_RXEN; 860 mac_cr = smsc9218i_mac_read(regs, SMSC9218I_MAC_CR); 861 mac_cr |= SMSC9218I_MAC_CR_RXEN; 623 862 smsc9218i_mac_write(regs, SMSC9218I_MAC_CR, mac_cr); 624 863 625 864 /* Enable receive interrupts */ 626 smsc9218i_enable_receive_interrupts(regs); 865 rtems_interrupt_disable(level); 866 regs->int_en |= SMSC9218I_INT_RSFL; 867 rtems_interrupt_enable(level); 627 868 628 869 /* Enable PHY interrupts */ … … 634 875 smsc9218i_enable_phy_interrupts(regs); 635 876 636 SMSC9218I_PRINTF(637 "rx: phy_isr = 0x%08" PRIx32 ", phy_imr = 0x%08" PRIx32 "\n",638 smsc9218i_phy_read(regs, SMSC9218I_PHY_ISR),639 smsc9218i_phy_read(regs, SMSC9218I_PHY_IMR)640 );641 642 /* Main event loop */643 877 while (true) { 644 uint32_t rx_fifo_inf = 0; 645 uint32_t status_used = 0; 646 647 /* Wait for events */ 878 rtems_event_set events; 879 648 880 sc = rtems_bsdnet_event_receive( 649 SMSC9218I_EVENT_ RX| SMSC9218I_EVENT_PHY,881 SMSC9218I_EVENT_DMA | SMSC9218I_EVENT_PHY, 650 882 RTEMS_EVENT_ANY | RTEMS_WAIT, 651 883 RTEMS_NO_TIMEOUT, 652 884 &events 653 885 ); 654 RTEMS_CLEANUP_SC(sc, cleanup, "wait for events"); 886 ASSERT_SC(sc); 887 888 if ((events & SMSC9218I_EVENT_DMA) != 0) { 889 smsc9218i_ether_input(e, regs, jc); 890 } 655 891 656 892 if ((events & SMSC9218I_EVENT_PHY) != 0) { 657 893 smsc9218i_media_status_change(e, regs); 658 894 } 659 660 rx_fifo_inf = regs->rx_fifo_inf; 661 status_used = SMSC9218I_RX_FIFO_INF_GET_SUSED(rx_fifo_inf); 662 663 SMSC9218I_PRINTF( 664 "rx: wake up: events = 0x%08" PRIx32 ", status used = %" PRIu32 "\n", 665 events, 666 status_used 667 ); 668 669 while (status_used > 0) { 670 uint32_t rx_fifo_status = regs->rx_fifo_status; 671 uint32_t frame_length = SMSC9218I_RX_STS_GET_LENGTH(rx_fifo_status); 672 uint32_t data_length = frame_length + SMSC9218I_RX_DATA_OFFSET; 673 uint32_t data_misalign = data_length % 4; 674 675 /* Align data length on four byte boundary */ 676 if (data_misalign > 0) { 677 data_length += 4 - data_misalign; 678 } 679 680 SMSC9218I_PRINTF( 681 "rx: status = 0x%08" PRIx32 ", frame length = %" PRIu32 682 ", data length = %" PRIu32 ", data used = %" PRIu32 "\n", 683 SMSC9218I_SWAP(rx_fifo_status), 684 frame_length, 685 data_length, 686 SMSC9218I_RX_FIFO_INF_GET_DUSED(rx_fifo_inf) 687 ); 688 689 if ((rx_fifo_status & SMSC9218I_RX_STS_ERROR) == 0) { 690 struct mbuf *m = smsc9218i_new_mbuf(ifp); 691 struct ether_header *eh = (struct ether_header *) 692 (mtod(m, char *) + SMSC9218I_RX_DATA_OFFSET); 693 int mbuf_length = (int) frame_length - ETHER_HDR_LEN - ETHER_CRC_LEN; 694 char *data = mtod(m, char *); 695 696 /* Update mbuf */ 697 m->m_len = mbuf_length; 698 m->m_pkthdr.len = mbuf_length; 699 m->m_data = data + ETHER_HDR_LEN + SMSC9218I_RX_DATA_OFFSET; 700 701 /* Invalidate data cache */ 702 rtems_cache_invalidate_multiple_data_lines(data, data_length); 703 704 /* Start eDMA transfer */ 705 tcd->DADDR = (uint32_t) data; 706 tcd->NBYTES = data_length; 707 tcd->CDF.R = SMSC9218I_EDMA_RX_TCD_CDF; 708 tcd->BMF.R = SMSC9218I_EDMA_RX_TCD_BMF; 709 710 /* Wait for eDMA events */ 711 sc = rtems_bsdnet_event_receive( 712 SMSC9218I_EVENT_EDMA | SMSC9218I_EVENT_EDMA_ERROR, 713 RTEMS_EVENT_ANY | RTEMS_WAIT, 714 RTEMS_NO_TIMEOUT, 715 &events 716 ); 717 RTEMS_CHECK_SC_TASK(sc, "wait for eDMA events"); 718 719 if ((events & SMSC9218I_EVENT_EDMA_ERROR) == 0) { 720 /* Hand over */ 721 ether_input(ifp, eh, m); 722 723 /* Increment received frames counter */ 724 ++e->received_frames; 725 } else { 726 /* Increment receive eDMA error counter */ 727 ++e->receive_edma_errors; 728 } 729 730 SMSC9218I_PRINTF("rx: eDMA done\n"); 731 } else { 732 SMSC9218I_PRINTF("rx: error\n"); 733 734 /* Update error counters */ 735 if ((rx_fifo_status & SMSC9218I_RX_STS_ERROR_TOO_LONG) != 0) { 736 ++e->receive_too_long_errors; 737 } 738 if ((rx_fifo_status & SMSC9218I_RX_STS_ERROR_COLLISION) != 0) { 739 ++e->receive_collision_errors; 740 } 741 if ((rx_fifo_status & SMSC9218I_RX_STS_ERROR_CRC) != 0) { 742 ++e->receive_crc_errors; 743 } 744 745 /* Discard frame */ 746 if (frame_length > 16) { 747 /* Fast forward */ 748 regs->rx_dp_ctl = SMSC9218I_RX_DP_CTRL_FFWD; 749 750 while ((regs->rx_dp_ctl & SMSC9218I_RX_DP_CTRL_FFWD) != 0) { 751 /* Wait */ 752 } 753 } else { 754 uint32_t len = data_length / 4; 755 uint32_t i = 0; 756 757 /* Discard data */ 758 for (i = 0; i < len; ++i) { 759 regs->rx_fifo_data; 760 } 761 } 762 } 763 764 /* Clear FIFO level status */ 765 regs->int_sts = SMSC9218I_INT_RSFL; 766 767 /* Next FIFO status */ 768 rx_fifo_inf = regs->rx_fifo_inf; 769 status_used = SMSC9218I_RX_FIFO_INF_GET_SUSED(rx_fifo_inf); 770 } 771 772 SMSC9218I_PRINTF("rx: done\n"); 773 774 /* Nothing to do, enable receive interrupts */ 775 smsc9218i_enable_receive_interrupts(regs); 776 } 777 778 cleanup: 779 780 /* Release network semaphore */ 781 rtems_bsdnet_semaphore_release(); 782 783 /* Terminate self */ 784 (void) rtems_task_delete(RTEMS_SELF); 895 } 785 896 } 786 897 … … 792 903 { 793 904 char out [SMSC9218I_TX_JOBS + 1]; 794 unsignedc = 0;795 unsigneds = 0;905 int c = 0; 906 int s = 0; 796 907 797 908 out [SMSC9218I_TX_JOBS] = '\0'; … … 804 915 out [c] = 'E'; 805 916 --s; 806 if (c < SMSC9218I_TX_JOBS_MAX) { 807 ++c; 808 } else { 809 c = 0; 810 } 917 c = (c + 1) % SMSC9218I_TX_JOBS; 811 918 } 812 919 … … 816 923 out [c] = 'T'; 817 924 --s; 818 if (c < SMSC9218I_TX_JOBS_MAX) { 819 ++c; 820 } else { 821 c = 0; 822 } 925 c = (c + 1) % SMSC9218I_TX_JOBS; 823 926 } 824 927 … … 828 931 out [c] = 'D'; 829 932 --s; 830 if (c < SMSC9218I_TX_JOBS_MAX) { 831 ++c; 832 } else { 833 c = 0; 834 } 933 c = (c + 1) % SMSC9218I_TX_JOBS; 835 934 } 836 935 … … 846 945 #endif /* defined(DEBUG) */ 847 946 947 static struct mbuf *smsc9218i_compact_frame( 948 smsc9218i_transmit_job_control *jc, 949 uint32_t frame_length 950 ) 951 { 952 struct mbuf *old_m = jc->frame; 953 struct mbuf *new_m = m_gethdr(M_WAIT, MT_DATA); 954 char *data = NULL; 955 956 ++jc->frame_compact_count; 957 958 MCLGET(new_m, M_WAIT); 959 data = mtod(new_m, char *); 960 961 new_m->m_len = (int) frame_length; 962 new_m->m_pkthdr.len = (int) frame_length; 963 964 while (old_m != NULL) { 965 size_t len = (size_t) old_m->m_len; 966 memcpy(data, mtod(old_m, void *), len); 967 data += len; 968 old_m = m_free(old_m); 969 } 970 971 jc->frame = new_m; 972 973 return new_m; 974 } 975 848 976 static struct mbuf *smsc9218i_next_transmit_fragment( 849 977 struct ifnet *ifp, … … 868 996 uint32_t frame_length = 0; 869 997 unsigned fragments = 0; 998 bool tiny = false; 870 999 871 1000 /* Calculate frame length and fragment number */ … … 876 1005 ++fragments; 877 1006 frame_length += (uint32_t) len; 878 879 if (len < 4) { 880 ++jc->fixme_tiny_fragments; 881 } 1007 tiny = tiny || len < 4; 882 1008 883 1009 /* Next fragment */ … … 897 1023 } while (n != NULL); 898 1024 899 if (fragments > SMSC9218I_TX_FRAGMENT_MAX) { 900 ++jc->fixme_too_many; 1025 if (SMSC9218I_UNLIKELY(tiny || fragments > SMSC9218I_TX_JOBS)) { 1026 fragments = 1; 1027 m = smsc9218i_compact_frame(jc, frame_length); 901 1028 } 902 1029 … … 911 1038 912 1039 /* Command B */ 913 jc->command_b = SMSC9218I_TX_B_TAG(jc->tag)1040 jc->command_b = ((uint32_t) SMSC9218I_TX_B_TAG(jc->tag)) 914 1041 | SMSC9218I_TX_B_FRAME_LENGTH(jc->frame_length); 915 1042 916 1043 SMSC9218I_PRINTF( 917 "tx: next frame: tag = % u, frame length = %" PRIu321044 "tx: next frame: tag = %i, frame length = %" PRIu32 918 1045 ", fragments = %u\n", 919 (unsigned)jc->tag,1046 jc->tag, 920 1047 frame_length, 921 1048 fragments … … 944 1071 ) 945 1072 { 946 unsignedn = jc->empty;1073 int n = jc->empty; 947 1074 948 1075 if (n > 0) { 949 unsignedc = jc->todo_index;950 unsignedi = 0;1076 int c = jc->todo_index; 1077 int i = 0; 951 1078 952 1079 #ifdef DEBUG … … 998 1125 } 999 1126 1000 if (c < SMSC9218I_TX_JOBS_MAX) { 1001 ++c; 1002 } else { 1003 c = 0; 1004 } 1127 c = (c + 1) % SMSC9218I_TX_JOBS; 1005 1128 } 1006 1129 … … 1032 1155 uint32_t tx_fifo_inf = regs->tx_fifo_inf; 1033 1156 uint32_t data_free = SMSC9218I_TX_FIFO_INF_GET_FREE(tx_fifo_inf); 1034 unsigned c = jc->transfer_index; 1035 unsigned last_index = c; 1036 unsigned i = 0; 1037 unsigned n = jc->todo; 1038 struct tcd_t *p = NULL; 1157 int c = jc->transfer_index; 1158 int last_index = c; 1159 int i = 0; 1160 int n = jc->todo; 1039 1161 1040 1162 #ifdef DEBUG … … 1053 1175 last_index = c; 1054 1176 1055 /* Cache flush for previous data TCD */ 1056 if (p != NULL) { 1057 rtems_cache_flush_multiple_data_lines(p, sizeof(*p)); 1058 } 1177 /* Cache flush for data TCD */ 1178 smsc9218i_flush_tcd(tcd); 1059 1179 } else { 1060 1180 break; 1061 1181 } 1062 1182 1063 p = tcd; 1064 if (c < SMSC9218I_TX_JOBS_MAX) { 1065 ++c; 1066 } else { 1067 c = 0; 1068 } 1183 c = (c + 1) % SMSC9218I_TX_JOBS; 1069 1184 } 1070 1185 … … 1093 1208 1094 1209 /* Enable interrupt for last data TCD */ 1095 last->BMF.R = SMSC9218I_EDMA_TX_TCD_BMF_INTERRUPT; 1096 1097 /* Cache flush for last data TCD */ 1098 rtems_cache_flush_multiple_data_lines(last, sizeof(*last)); 1210 last->BMF.R = SMSC9218I_TCD_BMF_LAST; 1211 smsc9218i_flush_tcd(last); 1099 1212 ppc_synchronize_data(); 1100 1213 … … 1107 1220 channel->CDF.R = start->CDF.R; 1108 1221 channel->DLAST_SGA = start->DLAST_SGA; 1109 channel->BMF.R = SMSC9218I_ EDMA_TX_TCD_BMF_CLEAR;1222 channel->BMF.R = SMSC9218I_TCD_BMF_CLEAR; 1110 1223 channel->BMF.R = start->BMF.R; 1111 1224 … … 1136 1249 uint32_t status_used = SMSC9218I_TX_FIFO_INF_GET_SUSED(tx_fifo_inf); 1137 1250 uint32_t s = 0; 1138 unsignedn = jc->transfer;1251 int n = jc->transfer; 1139 1252 1140 1253 for (s = 0; s < status_used; ++s) { … … 1155 1268 1156 1269 if ( 1157 (events & (SMSC9218I_EVENT_ EDMA | SMSC9218I_EVENT_EDMA_ERROR)) != 01270 (events & (SMSC9218I_EVENT_DMA | SMSC9218I_EVENT_DMA_ERROR)) != 0 1158 1271 && n > 0 1159 1272 ) { 1160 unsignedc = jc->empty_index;1161 unsignedi = 0;1273 int c = jc->empty_index; 1274 int i = 0; 1162 1275 1163 1276 #ifdef DEBUG … … 1165 1278 #endif 1166 1279 1167 if ((events & SMSC9218I_EVENT_ EDMA_ERROR) != 0) {1168 ++e->transmit_ edma_errors;1280 if ((events & SMSC9218I_EVENT_DMA_ERROR) != 0) { 1281 ++e->transmit_dma_errors; 1169 1282 } 1170 1283 1171 1284 /* Restore last data TCD */ 1172 1285 jc->data_tcd_table [jc->transfer_last_index].BMF.R = 1173 SMSC9218I_ EDMA_TX_TCD_BMF_LINK;1286 SMSC9218I_TCD_BMF_LINK; 1174 1287 1175 1288 for (i = 0; i < n; ++i) { … … 1177 1290 m_free(jc->fragment_table [c]); 1178 1291 1179 if (c < SMSC9218I_TX_JOBS_MAX) { 1180 ++c; 1181 } else { 1182 c = 0; 1183 } 1292 c = (c + 1) % SMSC9218I_TX_JOBS; 1184 1293 } 1185 1294 … … 1203 1312 1204 1313 /* FIXME */ 1205 static smsc9218i_transmit_job_control smsc_ jc __attribute__((aligned (32))) = {1314 static smsc9218i_transmit_job_control smsc_tx_jc __attribute__((aligned (32))) = { 1206 1315 .frame = NULL, 1207 1316 .next_fragment = NULL, … … 1226 1335 volatile smsc9218i_registers *const regs = smsc9218i; 1227 1336 uint32_t mac_cr = 0; 1228 smsc9218i_transmit_job_control *jc = &smsc_ jc;1337 smsc9218i_transmit_job_control *jc = &smsc_tx_jc; 1229 1338 unsigned i = 0; 1230 1339 … … 1234 1343 e->edma_transmit.id = e->transmit_task; 1235 1344 sc = mpc55xx_edma_obtain_channel(&e->edma_transmit); 1236 RTEMS_CLEANUP_SC(sc, cleanup, "obtain transmit eDMA channel");1345 ASSERT_SC(sc); 1237 1346 1238 1347 /* Setup transmit eDMA descriptors */ 1239 1348 for (i = 0; i < SMSC9218I_TX_JOBS; ++i) { 1240 unsigned ii = i < SMSC9218I_TX_JOBS_MAX ? i + 1 : 0;1349 unsigned ii = (i + 1) % SMSC9218I_TX_JOBS; 1241 1350 struct tcd_t tcd = EDMA_TCD_DEFAULT; 1242 1351 struct tcd_t *command_tcd = &jc->command_tcd_table [i]; … … 1248 1357 tcd.SDF.B.DSIZE = 2; 1249 1358 tcd.CDF.B.CITER = 1; 1250 tcd.BMF.R = SMSC9218I_ EDMA_TX_TCD_BMF_LINK;1359 tcd.BMF.R = SMSC9218I_TCD_BMF_LINK; 1251 1360 tcd.DADDR = (uint32_t) ®s->tx_fifo_data; 1252 1361 1253 tcd.DLAST_SGA = ( uint32_t) next_command_tcd;1362 tcd.DLAST_SGA = (int32_t) next_command_tcd; 1254 1363 *data_tcd = tcd; 1255 1364 1256 1365 tcd.SADDR = (uint32_t) &jc->command_table [i].a; 1257 1366 tcd.NBYTES = 8; 1258 tcd.DLAST_SGA = ( uint32_t) data_tcd;1367 tcd.DLAST_SGA = (int32_t) data_tcd; 1259 1368 *command_tcd = tcd; 1260 1369 } … … 1282 1391 SMSC9218I_EVENT_TX 1283 1392 | SMSC9218I_EVENT_TX_START 1284 | SMSC9218I_EVENT_ EDMA1285 | SMSC9218I_EVENT_ EDMA_ERROR,1393 | SMSC9218I_EVENT_DMA 1394 | SMSC9218I_EVENT_DMA_ERROR, 1286 1395 RTEMS_EVENT_ANY | RTEMS_WAIT, 1287 1396 RTEMS_NO_TIMEOUT, 1288 1397 &events 1289 1398 ); 1290 RTEMS_CLEANUP_SC(sc, cleanup, "wait for events");1399 ASSERT_SC(sc); 1291 1400 1292 1401 SMSC9218I_PRINTF("tx: wake up: events = 0x%08" PRIx32 "\n", events); … … 1476 1585 e 1477 1586 ); 1478 RTEMS_SYSLOG_ERROR_SC(sc, "install interrupt handler\n");1587 ASSERT_SC(sc); 1479 1588 1480 1589 /* Enable interrupts and use push-pull driver (active low) */ … … 1639 1748 { 1640 1749 volatile smsc9218i_registers *const regs = smsc9218i; 1641 smsc9218i_transmit_job_control *jc = &smsc_ jc;1750 smsc9218i_transmit_job_control *jc = &smsc_tx_jc; 1642 1751 int media = 0; 1643 1752 bool media_ok = smsc9218i_media_status(e, &media); … … 1652 1761 e->receive_drop += SMSC9218I_SWAP(regs->rx_drop); 1653 1762 1763 printf("PHY interrupts: %u\n", e->phy_interrupts); 1654 1764 printf("received frames: %u\n", e->received_frames); 1765 printf("receiver errors: %u\n", e->receiver_errors); 1655 1766 printf("receive interrupts: %u\n", e->receive_interrupts); 1656 printf("transmitted frames: %u\n", e->transmitted_frames); 1657 printf("transmit interrupts: %u\n", e->transmit_interrupts); 1658 printf("receiver errors: %u\n", e->receiver_errors); 1767 printf("receive DMA interrupts: %u\n", e->receive_dma_interrupts); 1659 1768 printf("receive to long errors: %u\n", e->receive_too_long_errors); 1660 1769 printf("receive collision errors: %u\n", e->receive_collision_errors); 1661 1770 printf("receive CRC errors: %u\n", e->receive_crc_errors); 1662 printf("receive eDMA errors: %u\n", e->receive_edma_errors);1771 printf("receive DMA errors: %u\n", e->receive_dma_errors); 1663 1772 printf("receive drops: %u\n", e->receive_drop); 1664 1773 printf("receive watchdog timeouts: %u\n", e->receive_watchdog_timeouts); 1774 printf("transmitted frames: %u\n", e->transmitted_frames); 1665 1775 printf("transmitter errors: %u\n", e->transmitter_errors); 1776 printf("transmit interrupts: %u\n", e->transmit_interrupts); 1777 printf("transmit DMA interrupts: %u\n", e->transmit_dma_interrupts); 1666 1778 printf("transmit status overflows: %u\n", e->transmit_status_overflows); 1667 1779 printf("transmit frame errors: %u\n", e->transmit_frame_errors); 1668 printf("transmit eDMA errors: %u\n", e->transmit_edma_errors); 1669 printf("fixme tiny fragments: %u\n", jc->fixme_tiny_fragments); 1670 printf("fixme too many: %u\n", jc->fixme_too_many); 1780 printf("transmit DMA errors: %u\n", e->transmit_dma_errors); 1781 printf("frame compact count: %u\n", jc->frame_compact_count); 1671 1782 } 1672 1783 … … 1684 1795 case SIOCGIFMEDIA: 1685 1796 case SIOCSIFMEDIA: 1686 rtems_mii_ioctl(&e->mdio, e, (int)command, (int *) data);1797 rtems_mii_ioctl(&e->mdio, e, command, (int *) data); 1687 1798 break; 1688 1799 case SIOCGIFADDR: … … 1719 1830 1720 1831 sc = rtems_event_send(e->transmit_task, SMSC9218I_EVENT_TX_START); 1721 RTEMS_SYSLOG_ERROR_SC(sc, "send transmit start event");1832 ASSERT_SC(sc); 1722 1833 } 1723 1834 … … 1727 1838 } 1728 1839 1729 static intsmsc9218i_attach(struct rtems_bsdnet_ifconfig *config)1840 static void smsc9218i_attach(struct rtems_bsdnet_ifconfig *config) 1730 1841 { 1731 1842 smsc9218i_driver_entry *e = &smsc9218i_driver_data; … … 1735 1846 1736 1847 /* Check parameter */ 1737 if (unit_number < 0) { 1738 RTEMS_SYSLOG_ERROR("parse error for interface name\n"); 1739 return 0; 1740 } 1741 if (unit_number != 0) { 1742 RTEMS_DO_CLEANUP(smsc9218i_attach_cleanup, "unexpected unit number"); 1743 } 1744 if (config->hardware_address == NULL) { 1745 RTEMS_DO_CLEANUP(smsc9218i_attach_cleanup, "MAC address missing"); 1746 } 1747 if (e->state != SMSC9218I_NOT_INITIALIZED) { 1748 RTEMS_DO_CLEANUP(smsc9218i_attach_cleanup, "already attached"); 1749 } 1848 assert(unit_number == 0); 1849 assert(config->hardware_address != NULL); 1850 assert(e->state == SMSC9218I_NOT_INITIALIZED); 1750 1851 1751 1852 /* Interrupt number */ … … 1788 1889 if_attach(ifp); 1789 1890 ether_ifattach(ifp); 1790 1791 return 1;1792 1793 smsc9218i_attach_cleanup:1794 1795 /* FIXME: Type */1796 free(unit_name, (int) 0xdeadbeef);1797 1798 return 0;1799 1891 } 1800 1892 … … 1803 1895 int attaching 1804 1896 ) { 1805 /* FIXME: Return value */1806 1807 1897 if (attaching) { 1808 returnsmsc9218i_attach(config);1898 smsc9218i_attach(config); 1809 1899 } else { 1810 1900 /* TODO */ 1811 return 0; 1812 } 1813 } 1901 } 1902 1903 /* FIXME: Return value */ 1904 return 0; 1905 }
Note: See TracChangeset
for help on using the changeset viewer.