From eb4b0a37eef110359736a01fe9cdb03e38bb1db9 Mon Sep 17 00:00:00 2001
From: Daniel Hellstrom <daniel@gaisler.com>
Date: Fri, 2 Dec 2011 10:53:35 +0100
Subject: [PATCH 1/1] GRETH: added support for non-snooping GRETH 10/100 systems
When data cache snooping is not present the cache needs
flushing, the SPARC LEON CPUs does not have to ability
to flush individual cache rows and flushing all cache is
expensive. Instead the LDA instruction is used to force
cache miss on individual loads during the IP-align copy
operation required anyway.
GRETH GBIT non-snooping systems are still unsupported,
since it use zero-copy (can deal with unaligned DMA).
Let the bsp.h select if the GRETH driver is supported.
Currently only the LEON2/LEON3 platforms BSPs builds the
driver.
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
---
c/src/lib/libbsp/sparc/leon2/include/bsp.h | 4 ++
c/src/lib/libbsp/sparc/leon2/include/leon.h | 8 +++
c/src/lib/libbsp/sparc/leon3/include/bsp.h | 4 ++
c/src/lib/libbsp/sparc/leon3/include/leon.h | 8 +++
c/src/libchip/network/greth.c | 68 ++++++++++++++++++++++++---
5 files changed, 85 insertions(+), 7 deletions(-)
diff --git a/c/src/lib/libbsp/sparc/leon2/include/bsp.h b/c/src/lib/libbsp/sparc/leon2/include/bsp.h
index b855347..0784ba4 100644
a
|
b
|
extern int rtems_smc91111_driver_attach_leon2( |
60 | 60 | |
61 | 61 | #define HAS_SMC91111 |
62 | 62 | |
| 63 | /* Configure GRETH driver */ |
| 64 | #define GRETH_SUPPORTED |
| 65 | #define GRETH_MEM_LOAD(addr) leon_r32_no_cache(addr) |
| 66 | |
63 | 67 | /* |
64 | 68 | * The synchronous trap is an arbitrarily chosen software trap. |
65 | 69 | */ |
diff --git a/c/src/lib/libbsp/sparc/leon2/include/leon.h b/c/src/lib/libbsp/sparc/leon2/include/leon.h
index 168ebe5..c183c90 100644
a
|
b
|
extern LEON_Register_Map LEON_REG; |
369 | 369 | #define LEON_REG_TIMER_COUNTER_DEFINED_MASK 0x00000003 |
370 | 370 | #define LEON_REG_TIMER_COUNTER_CURRENT_MODE_MASK 0x00000003 |
371 | 371 | |
| 372 | /* Load 32-bit word by forcing a cache-miss */ |
| 373 | static inline unsigned int leon_r32_no_cache(uintptr_t addr) |
| 374 | { |
| 375 | unsigned int tmp; |
| 376 | asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr)); |
| 377 | return tmp; |
| 378 | } |
| 379 | |
372 | 380 | #endif /* !ASM */ |
373 | 381 | |
374 | 382 | #ifdef __cplusplus |
diff --git a/c/src/lib/libbsp/sparc/leon3/include/bsp.h b/c/src/lib/libbsp/sparc/leon3/include/bsp.h
index 2286ad6..e47ddda 100644
a
|
b
|
extern int rtems_leon_greth_driver_attach( |
73 | 73 | |
74 | 74 | #define HAS_SMC91111 |
75 | 75 | |
| 76 | /* Configure GRETH driver */ |
| 77 | #define GRETH_SUPPORTED |
| 78 | #define GRETH_MEM_LOAD(addr) leon_r32_no_cache(addr) |
| 79 | |
76 | 80 | extern int CPU_SPARC_HAS_SNOOPING; |
77 | 81 | |
78 | 82 | |
diff --git a/c/src/lib/libbsp/sparc/leon3/include/leon.h b/c/src/lib/libbsp/sparc/leon3/include/leon.h
index b953e59..cd50629 100644
a
|
b
|
extern int LEON3_Cpu_Index; |
326 | 326 | #define LEON_REG_TIMER_COUNTER_DEFINED_MASK 0x00000003 |
327 | 327 | #define LEON_REG_TIMER_COUNTER_CURRENT_MODE_MASK 0x00000003 |
328 | 328 | |
| 329 | /* Load 32-bit word by forcing a cache-miss */ |
| 330 | static inline unsigned int leon_r32_no_cache(uintptr_t addr) |
| 331 | { |
| 332 | unsigned int tmp; |
| 333 | asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr)); |
| 334 | return tmp; |
| 335 | } |
| 336 | |
329 | 337 | #endif /* !ASM */ |
330 | 338 | |
331 | 339 | #ifdef __cplusplus |
diff --git a/c/src/libchip/network/greth.c b/c/src/libchip/network/greth.c
index aff4d0f..df3c143 100644
a
|
b
|
|
12 | 12 | */ |
13 | 13 | |
14 | 14 | #include <rtems.h> |
15 | | |
16 | | #define GRETH_SUPPORTED |
17 | 15 | #include <bsp.h> |
18 | 16 | |
| 17 | #ifdef GRETH_SUPPORTED |
| 18 | |
19 | 19 | #include <inttypes.h> |
20 | 20 | #include <errno.h> |
21 | 21 | #include <rtems/bspIo.h> |
… |
… |
extern rtems_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int ); |
57 | 57 | extern void ipalign(struct mbuf *m); |
58 | 58 | #endif |
59 | 59 | |
| 60 | /* Used when reading from memory written by GRETH DMA unit */ |
| 61 | #ifndef GRETH_MEM_LOAD |
| 62 | #define GRETH_MEM_LOAD(addr) (*(volatile unsigned int *)(addr)) |
| 63 | #endif |
| 64 | |
60 | 65 | /* |
61 | 66 | * Number of OCs supported by this driver |
62 | 67 | */ |
… |
… |
auto_neg_done: |
499 | 504 | print_init_info(sc); |
500 | 505 | } |
501 | 506 | |
| 507 | #ifdef CPU_U32_FIX |
| 508 | |
| 509 | /* |
| 510 | * Routine to align the received packet so that the ip header |
| 511 | * is on a 32-bit boundary. Necessary for cpu's that do not |
| 512 | * allow unaligned loads and stores and when the 32-bit DMA |
| 513 | * mode is used. |
| 514 | * |
| 515 | * Transfers are done on word basis to avoid possibly slow byte |
| 516 | * and half-word writes. |
| 517 | */ |
| 518 | |
| 519 | void ipalign(struct mbuf *m) |
| 520 | { |
| 521 | unsigned int *first, *last, data; |
| 522 | unsigned int tmp; |
| 523 | |
| 524 | if ((((int) m->m_data) & 2) && (m->m_len)) { |
| 525 | last = (unsigned int *) ((((int) m->m_data) + m->m_len + 8) & ~3); |
| 526 | first = (unsigned int *) (((int) m->m_data) & ~3); |
| 527 | tmp = GRETH_MEM_LOAD(first); |
| 528 | tmp = tmp << 16; |
| 529 | first++; |
| 530 | do { |
| 531 | /* When snooping is not available the LDA instruction must be used |
| 532 | * to avoid the cache to return an illegal value. |
| 533 | * Load with forced cache miss |
| 534 | */ |
| 535 | data = GRETH_MEM_LOAD(first); |
| 536 | *first = tmp | (data >> 16); |
| 537 | tmp = data << 16; |
| 538 | first++; |
| 539 | } while (first <= last); |
| 540 | |
| 541 | m->m_data = (caddr_t)(((int) m->m_data) + 2); |
| 542 | } |
| 543 | } |
| 544 | #endif |
| 545 | |
502 | 546 | void |
503 | 547 | greth_Daemon (void *arg) |
504 | 548 | { |
… |
… |
greth_Daemon (void *arg) |
510 | 554 | rtems_event_set events; |
511 | 555 | rtems_interrupt_level level; |
512 | 556 | int first; |
| 557 | unsigned int tmp; |
513 | 558 | |
514 | 559 | for (;;) |
515 | 560 | { |
… |
… |
greth_Daemon (void *arg) |
539 | 584 | /* Scan for Received packets */ |
540 | 585 | again: |
541 | 586 | while (!((len_status = |
542 | | dp->rxdesc[dp->rx_ptr].ctrl) & GRETH_RXD_ENABLE)) |
| 587 | GRETH_MEM_LOAD(&dp->rxdesc[dp->rx_ptr].ctrl)) & GRETH_RXD_ENABLE)) |
543 | 588 | { |
544 | 589 | bad = 0; |
545 | 590 | if (len_status & GRETH_RXD_TOOLONG) |
… |
… |
again: |
583 | 628 | len - sizeof (struct ether_header); |
584 | 629 | |
585 | 630 | eh = mtod (m, struct ether_header *); |
| 631 | |
586 | 632 | m->m_data += sizeof (struct ether_header); |
587 | 633 | #ifdef CPU_U32_FIX |
588 | | if(!(dp->gbit_mac)) |
| 634 | if(!dp->gbit_mac) { |
| 635 | /* OVERRIDE CACHED ETHERNET HEADER FOR NON-SNOOPING SYSTEMS */ |
| 636 | tmp = GRETH_MEM_LOAD((uintptr_t)eh); |
| 637 | tmp = GRETH_MEM_LOAD(4+(uintptr_t)eh); |
| 638 | tmp = GRETH_MEM_LOAD(8+(uintptr_t)eh); |
| 639 | tmp = GRETH_MEM_LOAD(12+(uintptr_t)eh); |
| 640 | |
589 | 641 | ipalign(m); /* Align packet on 32-bit boundary */ |
| 642 | } |
590 | 643 | #endif |
591 | 644 | |
592 | 645 | ether_input (ifp, eh, m); |
… |
… |
sendpacket (struct ifnet *ifp, struct mbuf *m) |
641 | 694 | /* |
642 | 695 | * Is there a free descriptor available? |
643 | 696 | */ |
644 | | if ( dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE ){ |
| 697 | if (GRETH_MEM_LOAD(&dp->txdesc[dp->tx_ptr].ctrl) & GRETH_TXD_ENABLE){ |
645 | 698 | /* No. */ |
646 | 699 | inside = 0; |
647 | 700 | return 1; |
… |
… |
sendpacket (struct ifnet *ifp, struct mbuf *m) |
651 | 704 | n = m; |
652 | 705 | |
653 | 706 | len = 0; |
654 | | temp = (unsigned char *) dp->txdesc[dp->tx_ptr].addr; |
| 707 | temp = (unsigned char *) GRETH_MEM_LOAD(&dp->txdesc[dp->tx_ptr].addr); |
655 | 708 | #ifdef GRETH_DEBUG |
656 | 709 | printf("TXD: 0x%08x : BUF: 0x%08x\n", (int) m->m_data, (int) temp); |
657 | 710 | #endif |
… |
… |
int greth_process_tx_gbit(struct greth_softc *sc) |
814 | 867 | */ |
815 | 868 | for (;;){ |
816 | 869 | /* Reap Sent packets */ |
817 | | while((sc->tx_cnt > 0) && !(sc->txdesc[sc->tx_dptr].ctrl) && !(sc->txdesc[sc->tx_dptr].ctrl & GRETH_TXD_ENABLE)) { |
| 870 | while((sc->tx_cnt > 0) && !(GRETH_MEM_LOAD(&sc->txdesc[sc->tx_dptr].ctrl) & GRETH_TXD_ENABLE)) { |
818 | 871 | m_free(sc->txmbuf[sc->tx_dptr]); |
819 | 872 | sc->tx_dptr = (sc->tx_dptr + 1) % sc->txbufs; |
820 | 873 | sc->tx_cnt--; |
… |
… |
rtems_greth_driver_attach (struct rtems_bsdnet_ifconfig *config, |
1146 | 1199 | return 1; |
1147 | 1200 | }; |
1148 | 1201 | |
| 1202 | #endif |