From 6c66b134e18dc24b3fe8b2d9a9a6954c6bc6840e Mon Sep 17 00:00:00 2001
From: Daniel Hellstrom <daniel@gaisler.com>
Date: Fri, 2 Dec 2011 10:47:58 +0100
Subject: [PR 08] GRETH: performance improvements and one bugfix
GRETH driver updated, 10-15% performance improvements for GBIT MAC,
unnecessary RX interrupts not taken which under heavy load saves approx.
1500 interrupts/s, one task removed saving about 5kb memory and 1 bug
solved.
BUG: RX interrupt was enabled before the RX-daemon was created which could
result in a faulty call to rtems_event_send.
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
---
c/src/libchip/network/greth.c | 497 ++++++++++++++++++++++++++---------------
1 files changed, 317 insertions(+), 180 deletions(-)
diff --git a/c/src/libchip/network/greth.c b/c/src/libchip/network/greth.c
index 05d74c7..aff4d0f 100644
a
|
b
|
extern void ipalign(struct mbuf *m); |
84 | 84 | /* event to send when tx buffers become available */ |
85 | 85 | #define GRETH_TX_WAIT_EVENT RTEMS_EVENT_3 |
86 | 86 | |
87 | | /* suspend when all TX descriptors exhausted */ |
88 | | /* |
89 | | #define GRETH_SUSPEND_NOTXBUF |
90 | | */ |
91 | | |
92 | 87 | #if (MCLBYTES < RBUF_SIZE) |
93 | 88 | # error "Driver must have MCLBYTES > RBUF_SIZE" |
94 | 89 | #endif |
… |
… |
struct greth_softc |
120 | 115 | greth_regs *regs; |
121 | 116 | |
122 | 117 | int acceptBroadcast; |
123 | | rtems_id rxDaemonTid; |
124 | | rtems_id txDaemonTid; |
| 118 | rtems_id daemonTid; |
125 | 119 | |
126 | 120 | unsigned int tx_ptr; |
127 | 121 | unsigned int tx_dptr; |
… |
… |
struct greth_softc |
135 | 129 | struct mbuf **txmbuf; |
136 | 130 | rtems_vector_number vector; |
137 | 131 | |
| 132 | /* TX descriptor interrupt generation */ |
| 133 | int tx_int_gen; |
| 134 | int tx_int_gen_cur; |
| 135 | struct mbuf *next_tx_mbuf; |
| 136 | int max_fragsize; |
| 137 | |
138 | 138 | /*Status*/ |
139 | 139 | struct phy_device_info phydev; |
140 | 140 | int fd; |
… |
… |
struct greth_softc |
167 | 167 | |
168 | 168 | static struct greth_softc greth; |
169 | 169 | |
| 170 | int greth_process_tx_gbit(struct greth_softc *sc); |
| 171 | int greth_process_tx(struct greth_softc *sc); |
| 172 | |
170 | 173 | static char *almalloc(int sz) |
171 | 174 | { |
172 | 175 | char *tmp; |
… |
… |
static char *almalloc(int sz) |
177 | 180 | |
178 | 181 | /* GRETH interrupt handler */ |
179 | 182 | |
180 | | static rtems_isr |
| 183 | rtems_isr |
181 | 184 | greth_interrupt_handler (rtems_vector_number v) |
182 | 185 | { |
183 | 186 | uint32_t status; |
184 | | /* read and clear interrupt cause */ |
| 187 | uint32_t ctrl; |
| 188 | rtems_event_set events = 0; |
185 | 189 | |
| 190 | /* read and clear interrupt cause */ |
186 | 191 | status = greth.regs->status; |
187 | 192 | greth.regs->status = status; |
| 193 | ctrl = greth.regs->ctrl; |
188 | 194 | |
189 | 195 | /* Frame received? */ |
190 | | if (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ)) |
| 196 | if ((ctrl & GRETH_CTRL_RXIRQ) && (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ))) |
191 | 197 | { |
192 | 198 | greth.rxInterrupts++; |
193 | | rtems_event_send (greth.rxDaemonTid, INTERRUPT_EVENT); |
| 199 | /* Stop RX-Error and RX-Packet interrupts */ |
| 200 | ctrl &= ~GRETH_CTRL_RXIRQ; |
| 201 | events |= INTERRUPT_EVENT; |
194 | 202 | } |
195 | | #ifdef GRETH_SUSPEND_NOTXBUF |
196 | | if (status & (GRETH_STATUS_TXERR | GRETH_STATUS_TXIRQ)) |
| 203 | |
| 204 | if ( (ctrl & GRETH_CTRL_TXIRQ) && (status & (GRETH_STATUS_TXERR | GRETH_STATUS_TXIRQ)) ) |
197 | 205 | { |
198 | 206 | greth.txInterrupts++; |
199 | | rtems_event_send (greth.txDaemonTid, GRETH_TX_WAIT_EVENT); |
| 207 | ctrl &= ~GRETH_CTRL_TXIRQ; |
| 208 | events |= GRETH_TX_WAIT_EVENT; |
200 | 209 | } |
201 | | #endif |
202 | | /* |
203 | | #ifdef __leon__ |
204 | | LEON_Clear_interrupt(v-0x10); |
205 | | #endif |
206 | | */ |
| 210 | |
| 211 | /* Clear interrupt sources */ |
| 212 | greth.regs->ctrl = ctrl; |
| 213 | |
| 214 | /* Send the event(s) */ |
| 215 | if ( events ) |
| 216 | rtems_event_send (greth.daemonTid, events); |
207 | 217 | } |
208 | 218 | |
209 | 219 | static uint32_t read_mii(uint32_t phy_addr, uint32_t reg_addr) |
… |
… |
static void write_mii(uint32_t phy_addr, uint32_t reg_addr, uint32_t data) |
230 | 240 | static void print_init_info(struct greth_softc *sc) |
231 | 241 | { |
232 | 242 | printf("greth: driver attached\n"); |
| 243 | if ( sc->auto_neg == -1 ){ |
| 244 | printf("Auto negotiation timed out. Selecting default config\n"); |
| 245 | } |
233 | 246 | printf("**** PHY ****\n"); |
234 | 247 | printf("Vendor: %x Device: %x Revision: %d\n",sc->phydev.vendor, sc->phydev.device, sc->phydev.rev); |
235 | 248 | printf("Current Operating Mode: "); |
… |
… |
greth_initialize_hardware (struct greth_softc *sc) |
268 | 281 | int tmp2; |
269 | 282 | unsigned int msecs; |
270 | 283 | struct timeval tstart, tnow; |
271 | | int anegtout; |
272 | 284 | |
273 | 285 | greth_regs *regs; |
274 | 286 | |
… |
… |
greth_initialize_hardware (struct greth_softc *sc) |
304 | 316 | sc->sp = 0; |
305 | 317 | sc->auto_neg = 0; |
306 | 318 | sc->auto_neg_time = 0; |
307 | | /* the anegtout variable is needed because print cannot be done before mac has |
308 | | been reconfigured due to a possible deadlock situation if rtems |
309 | | is run through the edcl with uart polling (-u)*/ |
310 | | anegtout = 0; |
311 | 319 | if ((phyctrl >> 12) & 1) { |
312 | 320 | /*wait for auto negotiation to complete*/ |
313 | 321 | msecs = 0; |
… |
… |
greth_initialize_hardware (struct greth_softc *sc) |
334 | 342 | msecs = (tnow.tv_sec-tstart.tv_sec)*1000+(tnow.tv_usec-tstart.tv_usec)/1000; |
335 | 343 | if ( msecs > GRETH_AUTONEGO_TIMEOUT_MS ){ |
336 | 344 | sc->auto_neg_time = msecs; |
337 | | anegtout = 1 |
| 345 | sc->auto_neg = -1; /* Failed */ |
338 | 346 | tmp1 = read_mii(phyaddr, 0); |
339 | 347 | sc->gb = ((phyctrl >> 6) & 1) && !((phyctrl >> 13) & 1); |
340 | 348 | sc->sp = !((phyctrl >> 6) & 1) && ((phyctrl >> 13) & 1); |
… |
… |
auto_neg_done: |
383 | 391 | phystatus = read_mii(phyaddr, 1); |
384 | 392 | |
385 | 393 | /*Read out PHY info if extended registers are available */ |
386 | | if (phystatus & 1) { |
| 394 | if (phystatus & 1) { |
387 | 395 | tmp1 = read_mii(phyaddr, 2); |
388 | 396 | tmp2 = read_mii(phyaddr, 3); |
389 | 397 | |
… |
… |
auto_neg_done: |
470 | 478 | mac_addr_lsb |= sc->arpcom.ac_enaddr[5]; |
471 | 479 | regs->mac_addr_lsb = mac_addr_lsb; |
472 | 480 | |
473 | | /* install interrupt vector */ |
474 | | set_vector(greth_interrupt_handler, sc->vector, 1); |
| 481 | if ( sc->rxbufs < 10 ) { |
| 482 | sc->tx_int_gen = sc->tx_int_gen_cur = 1; |
| 483 | }else{ |
| 484 | sc->tx_int_gen = sc->tx_int_gen_cur = sc->txbufs/2; |
| 485 | } |
| 486 | sc->next_tx_mbuf = NULL; |
| 487 | |
| 488 | if ( !sc->gbit_mac ) |
| 489 | sc->max_fragsize = 1; |
475 | 490 | |
476 | 491 | /* clear all pending interrupts */ |
477 | | |
478 | 492 | regs->status = 0xffffffff; |
479 | | |
480 | | #ifdef GRETH_SUSPEND_NOTXBUF |
481 | | regs->ctrl |= GRETH_CTRL_TXIRQ; |
482 | | #endif |
| 493 | |
| 494 | /* install interrupt vector */ |
| 495 | set_vector(greth_interrupt_handler, sc->vector, 1); |
483 | 496 | |
484 | 497 | regs->ctrl |= GRETH_CTRL_RXEN | (sc->fd << 4) | GRETH_CTRL_RXIRQ | (sc->sp << 7) | (sc->gb << 8); |
485 | | |
486 | | if (anegtout) { |
487 | | printk("Auto negotiation timed out. Selecting default config\n\r"); |
488 | | } |
489 | | |
| 498 | |
490 | 499 | print_init_info(sc); |
491 | 500 | } |
492 | 501 | |
493 | | static void |
494 | | greth_rxDaemon (void *arg) |
| 502 | void |
| 503 | greth_Daemon (void *arg) |
495 | 504 | { |
496 | 505 | struct ether_header *eh; |
497 | 506 | struct greth_softc *dp = (struct greth_softc *) &greth; |
… |
… |
greth_rxDaemon (void *arg) |
499 | 508 | struct mbuf *m; |
500 | 509 | unsigned int len, len_status, bad; |
501 | 510 | rtems_event_set events; |
| 511 | rtems_interrupt_level level; |
| 512 | int first; |
502 | 513 | |
503 | 514 | for (;;) |
504 | 515 | { |
505 | | rtems_bsdnet_event_receive (INTERRUPT_EVENT, |
| 516 | rtems_bsdnet_event_receive (INTERRUPT_EVENT | GRETH_TX_WAIT_EVENT, |
506 | 517 | RTEMS_WAIT | RTEMS_EVENT_ANY, |
507 | 518 | RTEMS_NO_TIMEOUT, &events); |
508 | 519 | |
| 520 | if ( events & GRETH_TX_WAIT_EVENT ){ |
| 521 | /* TX interrupt. |
| 522 | * We only end up here when all TX descriptors has been used, |
| 523 | * and |
| 524 | */ |
| 525 | if ( dp->gbit_mac ) |
| 526 | greth_process_tx_gbit(dp); |
| 527 | else |
| 528 | greth_process_tx(dp); |
| 529 | |
| 530 | /* If we didn't get a RX interrupt we don't process it */ |
| 531 | if ( (events & INTERRUPT_EVENT) == 0 ) |
| 532 | continue; |
| 533 | } |
| 534 | |
509 | 535 | #ifdef GRETH_ETH_DEBUG |
510 | 536 | printf ("r\n"); |
511 | 537 | #endif |
| 538 | first=1; |
| 539 | /* Scan for Received packets */ |
| 540 | again: |
512 | 541 | while (!((len_status = |
513 | 542 | dp->rxdesc[dp->rx_ptr].ctrl) & GRETH_RXD_ENABLE)) |
514 | 543 | { |
… |
… |
greth_rxDaemon (void *arg) |
576 | 605 | } else { |
577 | 606 | dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ; |
578 | 607 | } |
| 608 | rtems_interrupt_disable(level); |
579 | 609 | dp->regs->ctrl |= GRETH_CTRL_RXEN; |
| 610 | rtems_interrupt_enable(level); |
580 | 611 | dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs; |
581 | 612 | } |
| 613 | |
| 614 | /* Always scan twice to avoid deadlock */ |
| 615 | if ( first ){ |
| 616 | first=0; |
| 617 | rtems_interrupt_disable(level); |
| 618 | dp->regs->ctrl |= GRETH_CTRL_RXIRQ; |
| 619 | rtems_interrupt_enable(level); |
| 620 | goto again; |
| 621 | } |
| 622 | |
582 | 623 | } |
583 | 624 | |
584 | 625 | } |
585 | 626 | |
586 | 627 | static int inside = 0; |
587 | | static void |
| 628 | static int |
588 | 629 | sendpacket (struct ifnet *ifp, struct mbuf *m) |
589 | 630 | { |
590 | 631 | struct greth_softc *dp = ifp->if_softc; |
591 | 632 | unsigned char *temp; |
592 | 633 | struct mbuf *n; |
593 | 634 | unsigned int len; |
| 635 | rtems_interrupt_level level; |
594 | 636 | |
595 | 637 | /*printf("Send packet entered\n");*/ |
596 | 638 | if (inside) printf ("error: sendpacket re-entered!!\n"); |
597 | 639 | inside = 1; |
| 640 | |
598 | 641 | /* |
599 | | * Waiting for Transmitter ready |
| 642 | * Is there a free descriptor available? |
600 | 643 | */ |
601 | | n = m; |
| 644 | if ( dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE ){ |
| 645 | /* No. */ |
| 646 | inside = 0; |
| 647 | return 1; |
| 648 | } |
602 | 649 | |
603 | | while (dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE) |
604 | | { |
605 | | #ifdef GRETH_SUSPEND_NOTXBUF |
606 | | dp->txdesc[dp->tx_ptr].ctrl |= GRETH_TXD_IRQ; |
607 | | rtems_event_set events; |
608 | | rtems_bsdnet_event_receive (GRETH_TX_WAIT_EVENT, |
609 | | RTEMS_WAIT | RTEMS_EVENT_ANY, |
610 | | TOD_MILLISECONDS_TO_TICKS(500), &events); |
611 | | #endif |
612 | | } |
| 650 | /* Remember head of chain */ |
| 651 | n = m; |
613 | 652 | |
614 | 653 | len = 0; |
615 | 654 | temp = (unsigned char *) dp->txdesc[dp->tx_ptr].addr; |
… |
… |
sendpacket (struct ifnet *ifp, struct mbuf *m) |
644 | 683 | dp->txdesc[dp->tx_ptr].ctrl = |
645 | 684 | GRETH_TXD_WRAP | GRETH_TXD_ENABLE | len; |
646 | 685 | } |
647 | | dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN; |
648 | 686 | dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs; |
| 687 | rtems_interrupt_disable(level); |
| 688 | dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN; |
| 689 | rtems_interrupt_enable(level); |
| 690 | |
649 | 691 | } |
650 | 692 | inside = 0; |
| 693 | |
| 694 | return 0; |
651 | 695 | } |
652 | 696 | |
653 | 697 | |
654 | | static void |
| 698 | int |
655 | 699 | sendpacket_gbit (struct ifnet *ifp, struct mbuf *m) |
656 | 700 | { |
657 | 701 | struct greth_softc *dp = ifp->if_softc; |
658 | 702 | unsigned int len; |
| 703 | |
| 704 | unsigned int ctrl; |
| 705 | int frags; |
| 706 | struct mbuf *mtmp; |
| 707 | int int_en; |
| 708 | rtems_interrupt_level level; |
659 | 709 | |
660 | | /*printf("Send packet entered\n");*/ |
661 | 710 | if (inside) printf ("error: sendpacket re-entered!!\n"); |
662 | 711 | inside = 1; |
663 | | /* |
664 | | * Waiting for Transmitter ready |
665 | | */ |
666 | 712 | |
667 | 713 | len = 0; |
668 | 714 | #ifdef GRETH_DEBUG |
669 | 715 | printf("TXD: 0x%08x\n", (int) m->m_data); |
670 | 716 | #endif |
| 717 | /* Get number of fragments too see if we have enough |
| 718 | * resources. |
| 719 | */ |
| 720 | frags=1; |
| 721 | mtmp=m; |
| 722 | while(mtmp->m_next){ |
| 723 | frags++; |
| 724 | mtmp = mtmp->m_next; |
| 725 | } |
| 726 | |
| 727 | if ( frags > dp->max_fragsize ) |
| 728 | dp->max_fragsize = frags; |
| 729 | |
| 730 | if ( frags > dp->txbufs ){ |
| 731 | inside = 0; |
| 732 | printf("GRETH: MBUF-chain cannot be sent. Increase descriptor count.\n"); |
| 733 | return -1; |
| 734 | } |
| 735 | |
| 736 | if ( frags > (dp->txbufs-dp->tx_cnt) ){ |
| 737 | inside = 0; |
| 738 | /* Return number of fragments */ |
| 739 | return frags; |
| 740 | } |
| 741 | |
| 742 | |
| 743 | /* Enable interrupt from descriptor every tx_int_gen |
| 744 | * descriptor. Typically every 16 descriptor. This |
| 745 | * is only to reduce the number of interrupts during |
| 746 | * heavy load. |
| 747 | */ |
| 748 | dp->tx_int_gen_cur-=frags; |
| 749 | if ( dp->tx_int_gen_cur <= 0 ){ |
| 750 | dp->tx_int_gen_cur = dp->tx_int_gen; |
| 751 | int_en = GRETH_TXD_IRQ; |
| 752 | }else{ |
| 753 | int_en = 0; |
| 754 | } |
| 755 | |
| 756 | /* At this stage we know that enough descriptors are available */ |
671 | 757 | for (;;) |
672 | 758 | { |
673 | | while (dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE) |
674 | | { |
675 | | #ifdef GRETH_SUSPEND_NOTXBUF |
676 | | dp->txdesc[dp->tx_ptr].ctrl |= GRETH_TXD_IRQ; |
677 | | rtems_event_set events; |
678 | | rtems_bsdnet_event_receive (GRETH_TX_WAIT_EVENT, |
679 | | RTEMS_WAIT | RTEMS_EVENT_ANY, |
680 | | TOD_MILLISECONDS_TO_TICKS(500), &events); |
681 | | #endif |
682 | | } |
| 759 | |
683 | 760 | #ifdef GRETH_DEBUG |
684 | | int i; |
685 | | printf("MBUF: 0x%08x, Len: %d : ", (int) m->m_data, m->m_len); |
686 | | for (i=0; i<m->m_len; i++) |
687 | | printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff); |
688 | | printf("\n"); |
| 761 | int i; |
| 762 | printf("MBUF: 0x%08x, Len: %d : ", (int) m->m_data, m->m_len); |
| 763 | for (i=0; i<m->m_len; i++) |
| 764 | printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff); |
| 765 | printf("\n"); |
689 | 766 | #endif |
690 | 767 | len += m->m_len; |
691 | 768 | dp->txdesc[dp->tx_ptr].addr = (uint32_t *)m->m_data; |
| 769 | |
| 770 | /* Wrap around? */ |
692 | 771 | if (dp->tx_ptr < dp->txbufs-1) { |
693 | | if ((m->m_next) == NULL) { |
694 | | dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS | m->m_len; |
695 | | break; |
696 | | } else { |
697 | | dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | GRETH_TXD_MORE | GRETH_TXD_CS | m->m_len; |
698 | | } |
699 | | } else { |
700 | | if ((m->m_next) == NULL) { |
701 | | dp->txdesc[dp->tx_ptr].ctrl = |
702 | | GRETH_TXD_WRAP | GRETH_TXD_ENABLE | GRETH_TXD_CS | m->m_len; |
703 | | break; |
704 | | } else { |
705 | | dp->txdesc[dp->tx_ptr].ctrl = |
706 | | GRETH_TXD_WRAP | GRETH_TXD_ENABLE | GRETH_TXD_MORE | GRETH_TXD_CS | m->m_len; |
707 | | } |
| 772 | ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS; |
| 773 | }else{ |
| 774 | ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS | GRETH_TXD_WRAP; |
708 | 775 | } |
| 776 | |
| 777 | /* Enable Descriptor */ |
| 778 | if ((m->m_next) == NULL) { |
| 779 | dp->txdesc[dp->tx_ptr].ctrl = ctrl | int_en | m->m_len; |
| 780 | break; |
| 781 | }else{ |
| 782 | dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_MORE | ctrl | int_en | m->m_len; |
| 783 | } |
| 784 | |
| 785 | /* Next */ |
709 | 786 | dp->txmbuf[dp->tx_ptr] = m; |
710 | 787 | dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs; |
711 | 788 | dp->tx_cnt++; |
712 | 789 | m = m->m_next; |
713 | | |
714 | | } |
| 790 | } |
715 | 791 | dp->txmbuf[dp->tx_ptr] = m; |
| 792 | dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs; |
716 | 793 | dp->tx_cnt++; |
| 794 | |
| 795 | /* Tell Hardware about newly enabled descriptor */ |
| 796 | rtems_interrupt_disable(level); |
717 | 797 | dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN; |
718 | | dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs; |
| 798 | rtems_interrupt_enable(level); |
| 799 | |
719 | 800 | inside = 0; |
| 801 | |
| 802 | return 0; |
720 | 803 | } |
721 | 804 | |
722 | | /* |
723 | | * Driver transmit daemon |
724 | | */ |
725 | | void |
726 | | greth_txDaemon (void *arg) |
| 805 | int greth_process_tx_gbit(struct greth_softc *sc) |
727 | 806 | { |
728 | | struct greth_softc *sc = (struct greth_softc *) arg; |
729 | 807 | struct ifnet *ifp = &sc->arpcom.ac_if; |
730 | 808 | struct mbuf *m; |
731 | | rtems_event_set events; |
| 809 | rtems_interrupt_level level; |
| 810 | int first=1; |
732 | 811 | |
733 | | for (;;) |
734 | | { |
| 812 | /* |
| 813 | * Send packets till queue is empty |
| 814 | */ |
| 815 | for (;;){ |
| 816 | /* Reap Sent packets */ |
| 817 | while((sc->tx_cnt > 0) && !(sc->txdesc[sc->tx_dptr].ctrl) && !(sc->txdesc[sc->tx_dptr].ctrl & GRETH_TXD_ENABLE)) { |
| 818 | m_free(sc->txmbuf[sc->tx_dptr]); |
| 819 | sc->tx_dptr = (sc->tx_dptr + 1) % sc->txbufs; |
| 820 | sc->tx_cnt--; |
| 821 | } |
| 822 | |
| 823 | if ( sc->next_tx_mbuf ){ |
| 824 | /* Get packet we tried but faild to transmit last time */ |
| 825 | m = sc->next_tx_mbuf; |
| 826 | sc->next_tx_mbuf = NULL; /* Mark packet taken */ |
| 827 | }else{ |
735 | 828 | /* |
736 | | * Wait for packet |
| 829 | * Get the next mbuf chain to transmit from Stack. |
737 | 830 | */ |
| 831 | IF_DEQUEUE (&ifp->if_snd, m); |
| 832 | if (!m){ |
| 833 | /* Hardware has sent all schedule packets, this |
| 834 | * makes the stack enter at greth_start next time |
| 835 | * a packet is to be sent. |
| 836 | */ |
| 837 | ifp->if_flags &= ~IFF_OACTIVE; |
| 838 | break; |
| 839 | } |
| 840 | } |
738 | 841 | |
739 | | rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, |
740 | | RTEMS_EVENT_ANY | RTEMS_WAIT, |
741 | | RTEMS_NO_TIMEOUT, &events); |
742 | | #ifdef GRETH_DEBUG |
743 | | printf ("t\n"); |
744 | | #endif |
| 842 | /* Are there free descriptors available? */ |
| 843 | /* Try to send packet, if it a negative number is returned. */ |
| 844 | if ( (sc->tx_cnt >= sc->txbufs) || sendpacket_gbit(ifp, m) ){ |
| 845 | /* Not enough resources */ |
745 | 846 | |
746 | | /* |
747 | | * Send packets till queue is empty |
| 847 | /* Since we have taken the mbuf out of the "send chain" |
| 848 | * we must remember to use that next time we come back. |
| 849 | * or else we have dropped a packet. |
748 | 850 | */ |
| 851 | sc->next_tx_mbuf = m; |
749 | 852 | |
750 | | |
751 | | for (;;) |
752 | | { |
753 | | /* |
754 | | * Get the next mbuf chain to transmit. |
755 | | */ |
756 | | IF_DEQUEUE (&ifp->if_snd, m); |
757 | | if (!m) |
758 | | break; |
759 | | sendpacket(ifp, m); |
| 853 | /* Not enough resources, enable interrupt for transmissions |
| 854 | * this way we will be informed when more TX-descriptors are |
| 855 | * available. |
| 856 | */ |
| 857 | if ( first ){ |
| 858 | first = 0; |
| 859 | rtems_interrupt_disable(level); |
| 860 | ifp->if_flags |= IFF_OACTIVE; |
| 861 | sc->regs->ctrl |= GRETH_CTRL_TXIRQ; |
| 862 | rtems_interrupt_enable(level); |
| 863 | |
| 864 | /* We must check again to be sure that we didn't |
| 865 | * miss an interrupt (if a packet was sent just before |
| 866 | * enabling interrupts) |
| 867 | */ |
| 868 | continue; |
760 | 869 | } |
761 | | ifp->if_flags &= ~IFF_OACTIVE; |
| 870 | |
| 871 | return -1; |
| 872 | }else{ |
| 873 | /* Sent Ok, proceed to process more packets if available */ |
| 874 | } |
762 | 875 | } |
| 876 | return 0; |
763 | 877 | } |
764 | 878 | |
765 | | /* |
766 | | * Driver transmit daemon |
767 | | */ |
768 | | void |
769 | | greth_txDaemon_gbit (void *arg) |
| 879 | int greth_process_tx(struct greth_softc *sc) |
770 | 880 | { |
771 | | struct greth_softc *sc = (struct greth_softc *) arg; |
772 | 881 | struct ifnet *ifp = &sc->arpcom.ac_if; |
773 | 882 | struct mbuf *m; |
774 | | rtems_event_set events; |
| 883 | rtems_interrupt_level level; |
| 884 | int first=1; |
775 | 885 | |
776 | | for (;;) |
777 | | { |
| 886 | /* |
| 887 | * Send packets till queue is empty |
| 888 | */ |
| 889 | for (;;){ |
| 890 | if ( sc->next_tx_mbuf ){ |
| 891 | /* Get packet we tried but failed to transmit last time */ |
| 892 | m = sc->next_tx_mbuf; |
| 893 | sc->next_tx_mbuf = NULL; /* Mark packet taken */ |
| 894 | }else{ |
778 | 895 | /* |
779 | | * Wait for packet |
| 896 | * Get the next mbuf chain to transmit from Stack. |
780 | 897 | */ |
| 898 | IF_DEQUEUE (&ifp->if_snd, m); |
| 899 | if (!m){ |
| 900 | /* Hardware has sent all schedule packets, this |
| 901 | * makes the stack enter at greth_start next time |
| 902 | * a packet is to be sent. |
| 903 | */ |
| 904 | ifp->if_flags &= ~IFF_OACTIVE; |
| 905 | break; |
| 906 | } |
| 907 | } |
781 | 908 | |
782 | | rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, |
783 | | RTEMS_EVENT_ANY | RTEMS_WAIT, |
784 | | RTEMS_NO_TIMEOUT, &events); |
785 | | #ifdef GRETH_DEBUG |
786 | | printf ("t\n"); |
787 | | #endif |
| 909 | /* Try to send packet, failed if it a non-zero number is returned. */ |
| 910 | if ( sendpacket(ifp, m) ){ |
| 911 | /* Not enough resources */ |
788 | 912 | |
789 | | /* |
790 | | * Send packets till queue is empty |
| 913 | /* Since we have taken the mbuf out of the "send chain" |
| 914 | * we must remember to use that next time we come back. |
| 915 | * or else we have dropped a packet. |
791 | 916 | */ |
792 | | for (;;) |
793 | | { |
794 | | while((sc->tx_cnt > 0) && !(sc->txdesc[sc->tx_dptr].ctrl & GRETH_TXD_ENABLE)) { |
795 | | m_free(sc->txmbuf[sc->tx_dptr]); |
796 | | sc->tx_dptr = (sc->tx_dptr + 1) % sc->txbufs; |
797 | | sc->tx_cnt--; |
798 | | } |
799 | | /* |
800 | | * Get the next mbuf chain to transmit. |
801 | | */ |
802 | | IF_DEQUEUE (&ifp->if_snd, m); |
803 | | if (!m) |
804 | | break; |
805 | | sendpacket_gbit(ifp, m); |
| 917 | sc->next_tx_mbuf = m; |
| 918 | |
| 919 | /* Not enough resources, enable interrupt for transmissions |
| 920 | * this way we will be informed when more TX-descriptors are |
| 921 | * available. |
| 922 | */ |
| 923 | if ( first ){ |
| 924 | first = 0; |
| 925 | rtems_interrupt_disable(level); |
| 926 | ifp->if_flags |= IFF_OACTIVE; |
| 927 | sc->regs->ctrl |= GRETH_CTRL_TXIRQ; |
| 928 | rtems_interrupt_enable(level); |
| 929 | |
| 930 | /* We must check again to be sure that we didn't |
| 931 | * miss an interrupt (if a packet was sent just before |
| 932 | * enabling interrupts) |
| 933 | */ |
| 934 | continue; |
806 | 935 | } |
807 | | ifp->if_flags &= ~IFF_OACTIVE; |
| 936 | |
| 937 | return -1; |
| 938 | }else{ |
| 939 | /* Sent Ok, proceed to process more packets if available */ |
| 940 | } |
808 | 941 | } |
| 942 | return 0; |
809 | 943 | } |
810 | 944 | |
811 | | |
812 | 945 | static void |
813 | 946 | greth_start (struct ifnet *ifp) |
814 | 947 | { |
815 | 948 | struct greth_softc *sc = ifp->if_softc; |
816 | 949 | |
817 | | ifp->if_flags |= IFF_OACTIVE; |
818 | | rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); |
| 950 | if ( ifp->if_flags & IFF_OACTIVE ) |
| 951 | return; |
819 | 952 | |
| 953 | if ( sc->gbit_mac ){ |
| 954 | /* No use trying to handle this if we are waiting on GRETH |
| 955 | * to send the previously scheduled packets. |
| 956 | */ |
| 957 | |
| 958 | greth_process_tx_gbit(sc); |
| 959 | }else{ |
| 960 | greth_process_tx(sc); |
| 961 | } |
820 | 962 | } |
821 | 963 | |
822 | 964 | /* |
… |
… |
greth_init (void *arg) |
828 | 970 | struct greth_softc *sc = arg; |
829 | 971 | struct ifnet *ifp = &sc->arpcom.ac_if; |
830 | 972 | |
831 | | if (sc->txDaemonTid == 0) |
832 | | { |
| 973 | if (sc->daemonTid == 0) { |
833 | 974 | |
834 | | /* |
835 | | * Set up GRETH hardware |
836 | | */ |
837 | | greth_initialize_hardware (sc); |
| 975 | /* |
| 976 | * Start driver tasks |
| 977 | */ |
| 978 | sc->daemonTid = rtems_bsdnet_newproc ("DCrxtx", 4096, |
| 979 | greth_Daemon, sc); |
838 | 980 | |
839 | | /* |
840 | | * Start driver tasks |
841 | | */ |
842 | | sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096, |
843 | | greth_rxDaemon, sc); |
844 | | if (sc->gbit_mac) { |
845 | | sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096, |
846 | | greth_txDaemon_gbit, sc); |
847 | | } else { |
848 | | sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096, |
849 | | greth_txDaemon, sc); |
850 | | } |
| 981 | /* |
| 982 | * Set up GRETH hardware |
| 983 | */ |
| 984 | greth_initialize_hardware (sc); |
851 | 985 | |
852 | | } |
| 986 | } |
853 | 987 | |
854 | 988 | /* |
855 | 989 | * Tell the world that we're running. |
856 | 990 | */ |
857 | 991 | ifp->if_flags |= IFF_RUNNING; |
858 | | |
859 | 992 | } |
860 | 993 | |
861 | 994 | /* |
… |
… |
greth_stop (struct greth_softc *sc) |
871 | 1004 | sc->regs->ctrl = 0; /* RX/TX OFF */ |
872 | 1005 | sc->regs->ctrl = GRETH_CTRL_RST; /* Reset ON */ |
873 | 1006 | sc->regs->ctrl = 0; /* Reset OFF */ |
| 1007 | |
| 1008 | sc->next_tx_mbuf = NULL; |
874 | 1009 | } |
875 | 1010 | |
876 | 1011 | |
… |
… |
greth_stats (struct greth_softc *sc) |
887 | 1022 | printf (" Bad CRC:%-8lu", sc->rxBadCRC); |
888 | 1023 | printf (" Overrun:%-8lu", sc->rxOverrun); |
889 | 1024 | printf (" Tx Interrupts:%-8lu", sc->txInterrupts); |
| 1025 | printf (" Maximal Frags:%-8d", sc->max_fragsize); |
| 1026 | printf (" GBIT MAC:%-8d", sc->gbit_mac); |
890 | 1027 | } |
891 | 1028 | |
892 | 1029 | /* |