[PR 18] GRETH: added support for non-snooping GRETH 10/100 systems
Daniel Hellstrom
daniel at gaisler.com
Mon Feb 6 16:48:54 UTC 2012
On 02/06/2012 05:32 PM, Gedare Bloom wrote:
> 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..
>
Note that it is not me that written this code. I don't remember where it came from but it is available in c/src/libchip/network/sonic.c and c/src/lib/libbsp/lm32/shared/tsmac/tsmac.c. My thoughts are
that it would be best to modify the code as little as possible. The original code is commented out, so that one can see what has been modified.
>> + /* tmp = *first<< 16; */
> Delete this line if it is unnecessary comment.
Ok.
>> + 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)
Ok x2. Good idea.
>> + 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)
Ok.
>> + *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.
Ok, will check this.
>> + unsigned int addr;
> addr probably should have type uintptr_t.
Ok
>> 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
Ok
>> + 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....)
Ok
Thanks for reviewing. I will be back with a PATCH v2 tomorrow.
Daniel
>> 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