[PR 18] GRETH: added support for non-snooping GRETH 10/100 systems

Gedare Bloom gedare at rtems.org
Mon Feb 6 16:32:36 UTC 2012


On Mon, Feb 6, 2012 at 9:15 AM, Daniel Hellstrom <daniel at gaisler.com> wrote:
> 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).
>
> Also, made the GRETH driver only built on LEON2/LEON3
> platforms.
>
> Signed-off-by: Daniel Hellstrom <daniel at gaisler.com>
> ---
>  c/src/libchip/network/greth.c |   80 +++++++++++++++++++++++++++++++++++++---
>  1 files changed, 74 insertions(+), 6 deletions(-)
>
> diff --git a/c/src/libchip/network/greth.c b/c/src/libchip/network/greth.c
> index b0e70b4..6af5283 100644
> --- a/c/src/libchip/network/greth.c
> +++ b/c/src/libchip/network/greth.c
> @@ -12,10 +12,15 @@
>  */
>
>  #include <rtems.h>
> -
> -#define GRETH_SUPPORTED
>  #include <bsp.h>
>
> +/* This driver is only supported by the LEON BSPs */
> +#if defined(LEON3) || defined(LEON2)
> +  #define GRETH_SUPPORTED
> +#endif
> +
> +#ifdef GRETH_SUPPORTED
> +
>  #include <inttypes.h>
>  #include <errno.h>
>  #include <rtems/bspIo.h>
> @@ -57,6 +62,14 @@ extern rtems_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
>  extern void ipalign(struct mbuf *m);
>  #endif
>
> +static inline unsigned int sparc_load_no_cache(unsigned int addr)
> +{
> +       unsigned int tmp;
> +       asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
> +       return tmp;
> +}
> +#define NO_CACHE_LOAD(addr) sparc_load_no_cache(addr)
> +
>  /*
>  * Number of OCs supported by this driver
>  */
> @@ -499,6 +512,47 @@ auto_neg_done:
>     print_init_info(sc);
>  }
>
> +#ifdef CPU_U32_FIX
> +
> +/*
> + * Routine to align the received packet so that the ip header
> + * is on a 32-bit boundary. Necessary for cpu's that do not
> + * allow unaligned loads and stores and when the 32-bit DMA
> + * mode is used.
> + *
> + * Transfers are done on word basis to avoid possibly slow byte
> + * and half-word writes.
> + */
> +
> +void ipalign(struct mbuf *m)
> +{
> +  unsigned int *first, *last, data;
> +  unsigned int tmp = 0;
> +
> +  if ((((int) m->m_data) & 2) && (m->m_len)) {
> +    last = (unsigned int *) ((((int) m->m_data) + m->m_len + 8) & ~3);
> +    first = (unsigned int *) (((int) m->m_data) & ~3);
We should really have some generic alignment macros to make reading
this type of code easier..

> +               /* tmp = *first << 16; */
Delete this line if it is unnecessary comment.

> +               asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(first) );
Fix whitespace, and can we use here the inline function?
tmp = NO_CACHE_LOAD(first)

> +               tmp = tmp << 16;
> +    first++;
> +    do {
> +      /* When snooping is not available the LDA instruction must be used
> +       * to avoid the cache to return an illegal value.
> +       * Load with forced cache miss
> +       * data = *first;
> +       */
> +      asm volatile (" lda [%1] 1, %0\n" : "=r"(data) : "r"(first) );
Can use here? data = NO_CACHE_LOAD(first)

> +      *first = tmp | (data >> 16);
> +      tmp = data << 16;
> +      first++;
> +    } while (first <= last);
> +
> +    m->m_data = (caddr_t)(((int) m->m_data) + 2);
> +  }
> +}
> +#endif
> +
>  void
>  greth_Daemon (void *arg)
>  {
> @@ -510,6 +564,8 @@ greth_Daemon (void *arg)
>     rtems_event_set events;
>     rtems_interrupt_level level;
>     int first;
> +    int tmp;
tmp probably should be unsigned int (just for type matching); though
the variable may be unnecessary if the NO_CACHE_LOAD macro/inline
function is used.

> +    unsigned int addr;
addr probably should have type uintptr_t.

>
>     for (;;)
>       {
> @@ -539,7 +595,7 @@ greth_Daemon (void *arg)
>     /* Scan for Received packets */
>  again:
>     while (!((len_status =
> -                   dp->rxdesc[dp->rx_ptr].ctrl) & GRETH_RXD_ENABLE))
> +                   NO_CACHE_LOAD(&dp->rxdesc[dp->rx_ptr].ctrl)) & GRETH_RXD_ENABLE))
>            {
>                     bad = 0;
>                     if (len_status & GRETH_RXD_TOOLONG)
> @@ -583,6 +639,17 @@ again:
>                                     len - sizeof (struct ether_header);
>
>                             eh = mtod (m, struct ether_header *);
> +
> +                            /* OVERRIDE CACHED ETHERNET HEADER FOR NON-SNOOPING SYSTEMS */
> +                            addr = (unsigned int)eh;
cast to uintptr_t
> +                            asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
> +                            addr+=4;
> +                            asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
> +                            addr+=4;
> +                            asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
> +                            addr+=4;
> +                            asm volatile (" lda [%1] 1, %0\n" : "=r"(tmp) : "r"(addr) );
> +
Can we use here:
NO_CACHE_LOAD(addr);
NO_CACHE_LOAD(addr+4);
NO_CACHE_LOAD(addr+8);
NO_CACHE_LOAD(addr+12);
addr +=12 (if necessary for correctness....)

>                             m->m_data += sizeof (struct ether_header);
>  #ifdef CPU_U32_FIX
>                             if(!(dp->gbit_mac))
> @@ -641,7 +708,7 @@ sendpacket (struct ifnet *ifp, struct mbuf *m)
>     /*
>      * Is there a free descriptor available?
>      */
> -    if ( dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE ){
> +    if ( NO_CACHE_LOAD(&dp->txdesc[dp->tx_ptr].ctrl) & GRETH_TXD_ENABLE ){
>             /* No. */
>             inside = 0;
>             return 1;
> @@ -651,7 +718,7 @@ sendpacket (struct ifnet *ifp, struct mbuf *m)
>     n = m;
>
>     len = 0;
> -    temp = (unsigned char *) dp->txdesc[dp->tx_ptr].addr;
> +    temp = (unsigned char *) NO_CACHE_LOAD(&dp->txdesc[dp->tx_ptr].addr);
>  #ifdef GRETH_DEBUG
>     printf("TXD: 0x%08x : BUF: 0x%08x\n", (int) m->m_data, (int) temp);
>  #endif
> @@ -814,7 +881,7 @@ int greth_process_tx_gbit(struct greth_softc *sc)
>      */
>     for (;;){
>         /* Reap Sent packets */
> -        while((sc->tx_cnt > 0) && !(sc->txdesc[sc->tx_dptr].ctrl) && !(sc->txdesc[sc->tx_dptr].ctrl & GRETH_TXD_ENABLE)) {
> +        while((sc->tx_cnt > 0) && !(NO_CACHE_LOAD(&sc->txdesc[sc->tx_dptr].ctrl) & GRETH_TXD_ENABLE)) {
>             m_free(sc->txmbuf[sc->tx_dptr]);
>             sc->tx_dptr = (sc->tx_dptr + 1) % sc->txbufs;
>             sc->tx_cnt--;
> @@ -1146,3 +1213,4 @@ rtems_greth_driver_attach (struct rtems_bsdnet_ifconfig *config,
>     return 1;
>  };
>
> +#endif
> --
> 1.7.0.4
>
> _______________________________________________
> rtems-devel mailing list
> rtems-devel at rtems.org
> http://www.rtems.org/mailman/listinfo/rtems-devel




More information about the devel mailing list