Ticket #1404: pr1404.diff

File pr1404.diff, 57.4 KB (added by Joel Sherrill, on Aug 8, 2010 at 9:42:34 PM)

Attempt to merge against head`

  • c/src/lib/libcpu/powerpc/ppc403/include/ppc405ex.h

    ? c/src/lib/libbsp/powerpc/haleakala/include/mmu_405.h
    RCS file: /usr1/CVS/rtems/c/src/lib/libcpu/powerpc/ppc403/include/ppc405ex.h,v
    retrieving revision 1.2
    diff -u -r1.2 ppc405ex.h
     
    7979};
    8080
    8181enum {
     82        SDR0_PINSTP = 0x40,
    8283        SDR0_UART0      = 0x120,
    8384        SDR0_UART1  = 0x121,
    8485        SDR0_C405       = 0x180,
     86        SDR0_SRST0  = 0x200,
    8587        SDR0_MALTBL = 0x280,
    8688        SDR0_MALRBL = 0x2A0,
    8789        SDR0_MALTBS = 0x2C0,
    88         SDR0_MALRBS = 0x2E0
     90        SDR0_MALRBS = 0x2E0,
     91        SDR0_PFC2   = 0x4102,
     92        SDR0_MFR    = 0x4300,
     93        SDR0_EMAC0RXST = 0x4301,
     94        SDR0_HSF    = 0x4400
    8995};
    9096
     97enum {
     98        CPR0_CLKUPD = 0x20,
     99        CPR0_PLLC = 0x40,
     100        CPR0_PLLD = 0x60,
     101        CPR0_CPUD = 0x80,
     102        CPR0_PLBD = 0xA0,
     103        CPR0_OPBD = 0xC0,
     104        CPR0_PERD = 0xE0,
     105        CPR0_AHBD = 0x100,
     106        CPR0_ICFG = 0x140
     107};
    91108
    92109/* Memory-mapped registers */
    93110
    94111
    95112/*======================= Ethernet =================== */
    96113
    97 
    98 typedef struct EthernetRegisters_EX {
    99         uint32_t mode0;
    100         uint32_t mode1;
    101         uint32_t xmtMode0;
    102         uint32_t xmtMode1;
    103         uint32_t rcvMode;
    104         uint32_t intStatus;
    105         uint32_t intEnable;
    106         uint32_t addrHi;
    107         uint32_t addrLo;
    108         uint32_t VLANTPID;
    109         uint32_t VLANTCI;
    110         uint32_t pauseTimer;
    111         uint32_t multicastAddr[2];
    112         uint32_t multicastMask[2];
    113         uint32_t unused[4];
    114         uint32_t lastSrcLo;
    115         uint32_t lastSrcHi;
    116         uint32_t IPGap;
    117         uint32_t STAcontrol;
    118         uint32_t xmtReqThreshold;
    119         uint32_t rcvWatermark;
    120         uint32_t bytesXmtd;
    121         uint32_t bytesRcvd;
    122         uint32_t unused2;
    123         uint32_t revID;
    124         uint32_t unused3[2];
    125         uint32_t indivHash[8];
    126         uint32_t groupHash[8];
    127         uint32_t xmtPause;
    128 } EthernetRegisters_EX;
    129 
    130114enum {
    131         EMAC0Address = 0xEF600900,
    132         EMAC1Address = 0xEF600A00
     115        EMAC0EXAddress = 0xEF600900,
     116        EMAC1EXAddress = 0xEF600A00,
     117       
     118        /* 405EX-specific bits in EMAC_MR1 */
     119        keEMAC1000Mbps = 0x00800000,
     120        keEMAC16KRxFIFO = 0x00280000,
     121        keEMAC8KRxFIFO  = 0x00200000,
     122        keEMAC4KRxFIFO  = 0x00180000,
     123        keEMAC2KRxFIFO  = 0x00100000,
     124        keEMAC1KRxFIFO  = 0x00080000,
     125        keEMAC16KTxFIFO = 0x00050000,
     126        keEMAC8KTxFIFO  = 0x00040000,
     127        keEMAC4KTxFIFO  = 0x00030000,
     128        keEMAC2KTxFIFO  = 0x00020000,
     129        keEMAC1KTxFIFO  = 0x00010000,
     130        keEMACJumbo         = 0x00000800,
     131        keEMACIPHYAddr4 = 0x180,
     132        keEMACOPB50MHz  = 0x00,
     133        keEMACOPB66MHz  = 0x08,
     134        keEMACOPB83MHz  = 0x10,
     135        keEMACOPB100MHz = 0x18,
     136        keEMACOPBGt100  = 0x20,
     137       
     138        /* 405EX-specific bits in MAL0_CFG */
     139        keMALRdMaxBurst4  = 0,
     140        keMALRdMaxBurst8  = 0x00100000,
     141        keMALRdMaxBurst16 = 0x00200000,
     142        keMALRdMaxBurst32 = 0x00300000,
     143       
     144        keMALWrLowPriority    = 0,
     145        keMALWrMedLowPriority = 0x00040000,
     146        keMALWrMedHiPriority  = 0x00080000,
     147        keMALWrHighPriority   = 0x000C0000,
     148
     149        keMALWrMaxBurst4  = 0,
     150        keMALWrMaxBurst8  = 0x00010000,
     151        keMALWrMaxBurst16 = 0x00020000,
     152        keMALWrMaxBurst32 = 0x00030000,
     153       
     154        /* 405EX-specific STA bits */
     155        keSTARun          = 0x8000,
     156        keSTADirectRd = 0x1000,
     157        keSTADirectWr = 0x0800,
     158        keSTAIndirAddr = 0x2000,
     159        keSTAIndirRd  = 0x3000,
     160        keSTAIndirWr  = 0x2800
    133161};
    134162
    135 
    136163typedef struct GPIORegisters {
    137164        uint32_t OR;
    138165        uint32_t GPIO_TCR;              /* Note that TCR is defined as a DCR name */
     
    156183
    157184enum { GPIOAddress = 0xEF600800 };
    158185
     186typedef struct RGMIIRegisters {
     187        uint32_t FER;
     188        uint32_t SSR;
     189} RGMIIRegisters;
     190
     191enum { RGMIIAddress = 0xEF600B00 };
     192
  • c/src/lib/libcpu/powerpc/ppc403/include/ppc405gp.h

    RCS file: /usr1/CVS/rtems/c/src/lib/libcpu/powerpc/ppc403/include/ppc405gp.h,v
    retrieving revision 1.2
    diff -u -r1.2 ppc405gp.h
     
    3737        EBC0_CFG        =       0x23
    3838};
    3939
     40/* MAL DCRs, have to be #defines */
     41#define MAL0_CFG                0x180
     42#define MAL0_ESR                0x181
     43#define MAL0_IER                0x182
     44#define MAL0_TXCASR             0x184
     45#define MAL0_TXCARR             0x185
     46#define MAL0_TXEOBISR   0x186
     47#define MAL0_TXDEIR             0x187
     48#define MAL0_RXCASR             0x190
     49#define MAL0_RXCARR             0x191
     50#define MAL0_RXEOBISR   0x192
     51#define MAL0_RXDEIR             0x193
     52#define MAL0_TXCTP0R    0x1A0
     53#define MAL0_TXCTP1R    0x1A1
     54#define MAL0_RXCTP0R    0x1C0
     55#define MAL0_RXCTP1R    0x1C1
     56#define MAL0_RCBS0              0x1E0
     57#define MAL0_RCBS1              0x1E1
     58
    4059/* Memory-mapped registers */
    4160
    4261typedef struct EthernetRegisters_GP {
     
    5271        uint32_t VLANTPID;
    5372        uint32_t VLANTCI;
    5473        uint32_t pauseTimer;
    55         uint32_t indivHash[4];
    56         uint32_t groupHash[4];
     74        uint32_t g_indivHash[4];  /* EX non-IP multicast addr/mask */
     75        uint32_t g_groupHash[4];
    5776        uint32_t lastSrcLo;
    5877        uint32_t lastSrcHi;
    5978        uint32_t IPGap;
    6079        uint32_t STAcontrol;
    6180        uint32_t xmtReqThreshold;
    62         uint32_t rcvWatermark;
     81        uint32_t rcvWatermarks;
    6382        uint32_t bytesXmtd;
    6483        uint32_t bytesRcvd;
     84        uint32_t e_unused2;
     85        uint32_t e_revID;
     86        uint32_t e_unused3[2];
     87        uint32_t e_indivHash[8];
     88        uint32_t e_groupHash[8];
     89        uint32_t e_xmtPause;
    6590} EthernetRegisters_GP;
    6691
     92typedef struct EthernetRegisters_GP EthernetRegisters_EX;
     93
    6794enum { EMACAddress = 0xEF600800 };
     95enum { EMAC0GPAddress = 0xEF600800 };
    6896
    6997enum {
    7098        // Mode 0 bits
     
    76104
    77105        // Mode 1 bits
    78106        kEMACFullDuplex = 0x80000000,
     107        kEMACDoFlowControl = 0x10000000,
    79108        kEMACIgnoreSQE  = 0x01000000,
    80109        kEMAC100MBbps    = 0x00400000,
    81110        kEMAC4KRxFIFO   = 0x00300000,
    82111        kEMAC2KTxFIFO    = 0x00080000,
    83112        kEMACTx0Multi    = 0x00008000,
    84113        kEMACTxDependent= 0x00014000,
     114        kEMAC100Mbps     = 0x00400000,
     115        kgEMAC4KRxFIFO   = 0x00300000,
     116        kgEMAC2KTxFIFO   = 0x00080000,
     117        kgEMACTx0Multi   = 0x00008000,
     118        kgEMACTxDependent= 0x00014000,
     119
    85120
    86121        // Tx mode bits
    87122        kEMACNewPacket0 = 0x80000000,
     
    99134        kEMACHashRcv            = 0x00200000,
    100135        kEMACBrcastRcv          = 0x00100000,
    101136        kEMACMultcastRcv        = 0x00080000,
     137        keEMACNonIPMultcast = 0x00040000,
     138        keEMACRxFIFOAFMax   = 7,
     139       
     140        // EMAC_STACR bits
     141        kgSTAComplete   = 0x8000,
     142        kSTAErr         = 0x4000,
     143       
     144        // Interrupt status bits
     145        kEMACIOverrun = 0x02000000,
     146        kEMACIPause   = 0x01000000,
     147        kEMACIBadPkt  = 0x00800000,
     148        kEMACIRuntPkt = 0x00400000,
     149        kEMACIShortEvt= 0x00200000,
     150        kEMACIAlignErr= 0x00100000,
     151        kEMACIBadFCS  = 0x00080000,
     152        kEMACIOverSize= 0x00040000,
     153        kEMACILLCRange= 0x00020000,
     154        kEMACISQEErr  = 0x00000080,
     155        kEMACITxErr   = 0x00000040,
    102156
    103157        // Buffer descriptor control bits
    104158        kMALTxReady                     = 0x8000,
     
    109163        kMALRxFirst                     = 0x0800,
    110164        kMALInterrupt           = 0x0400,
    111165
     166        kMALReset                       = 0x80000000,
     167        kMALLowPriority    = 0,
     168        kMALMedLowPriority = 0x00400000,
     169        kMALMedHiPriority  = 0x00800000,
     170        kMALHighPriority   = 0x00C00000,
     171        kMALLatency8       = 0x00040000,
     172        kMALLockErr         = 0x8000,
     173        kMALCanBurst    = 0x4000,
     174        kMALLocksOPB    = 0x80,
     175        kMALLocksErrs   = 0x2,
     176       
     177        // MAL channel masks
     178        kMALChannel0 = 0x80000000,
     179        kMALChannel1 = 0x40000000,
     180
    112181        // EMAC Tx descriptor bits sent
    113182        kEMACGenFCS                     = 0x200,
    114183        kEMACGenPad                     = 0x100,
  • c/src/lib/libbsp/powerpc/haleakala/Makefile.am

    RCS file: /usr1/CVS/rtems/c/src/lib/libbsp/powerpc/haleakala/Makefile.am,v
    retrieving revision 1.15
    diff -u -r1.15 Makefile.am
     
    1111dist_project_lib_DATA = bsp_specs
    1212
    1313include_HEADERS = include/bsp.h
     14include_HEADERS = include/mmu_405.h
    1415include_HEADERS += ../../shared/include/tm27.h
    1516
    1617nodist_include_HEADERS = include/bspopts.h
     
    3435    startup/bspstart.c ../../shared/bootcard.c \
    3536    ../../shared/bsppredriverhook.c ../../shared/bspgetworkarea.c \
    3637    ../../shared/bsppretaskinghook.c ../../shared/sbrk.c \
    37     ../../shared/gnatinstallhandler.c
     38    ../../shared/gnatinstallhandler.c mmu/mmu_405.c mmu/mmu_405asm.S
    3839
    3940# dlentry
    4041libbsp_a_SOURCES += dlentry/dlentry.S
     
    5152# irq
    5253libbsp_a_SOURCES += irq/irq_init.c irq/irq.c
    5354
     55if HAS_NETWORKING
     56network_CPPFLAGS = -D__INSIDE_RTEMS_BSD_TCPIP_STACK__
     57noinst_PROGRAMS = network.rel
     58network_rel_SOURCES = network/network.c
     59network_rel_CPPFLAGS = $(AM_CPPFLAGS) $(network_CPPFLAGS)
     60network_rel_LDFLAGS = $(RTEMS_RELLDFLAGS)
     61endif
     62
    5463libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/@exceptions@/rtems-cpu.rel \
    5564    ../../../libcpu/@RTEMS_CPU@/@exceptions@/exc_bspsupport.rel \
    5665    ../../../libcpu/@RTEMS_CPU@/@exceptions@/irq_bspsupport.rel \
     
    5968    ../../../libcpu/@RTEMS_CPU@/ppc403/clock.rel \
    6069    ../../../libcpu/@RTEMS_CPU@/ppc403/timer.rel
    6170
     71if HAS_NETWORKING
     72libbsp_a_LIBADD += network.rel
     73endif
     74
     75
    6276EXTRA_DIST = times
    6377
    6478include $(srcdir)/preinstall.am
  • c/src/lib/libbsp/powerpc/haleakala/configure.ac

    RCS file: /usr1/CVS/rtems/c/src/lib/libbsp/powerpc/haleakala/configure.ac,v
    retrieving revision 1.9
    diff -u -r1.9 configure.ac
     
    1616RTEMS_PROG_CCAS
    1717
    1818RTEMS_CHECK_NETWORKING
    19 
    2019AM_CONDITIONAL(HAS_NETWORKING,test "$HAS_NETWORKING" = "yes")
    2120
    2221RTEMS_BSPOPTS_SET([PPC_USE_SPRG],[*],[1])
  • c/src/lib/libbsp/powerpc/haleakala/preinstall.am

    RCS file: /usr1/CVS/rtems/c/src/lib/libbsp/powerpc/haleakala/preinstall.am,v
    retrieving revision 1.4
    diff -u -r1.4 preinstall.am
     
    4141        $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp.h
    4242PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp.h
    4343
     44$(PROJECT_INCLUDE)/mmu_405.h: include/mmu_405.h $(PROJECT_INCLUDE)/$(dirstamp)
     45        $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/mmu_405.h
     46PREINSTALL_FILES += $(PROJECT_INCLUDE)/mmu_405.h
     47
    4448$(PROJECT_INCLUDE)/tm27.h: ../../shared/include/tm27.h $(PROJECT_INCLUDE)/$(dirstamp)
    4549        $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/tm27.h
    4650PREINSTALL_FILES += $(PROJECT_INCLUDE)/tm27.h
  • new file c/src/lib/libbsp/powerpc/haleakala/mmu/mmu_405.c

    RCS file: c/src/lib/libbsp/powerpc/haleakala/mmu/mmu_405.c
    diff -N c/src/lib/libbsp/powerpc/haleakala/mmu/mmu_405.c
    - +  
     1/*
     2 *  Simple interface to the PowerPC 405 MMU
     3 *
     4 *   Michael Hamel ADInstruments 2008
     5 *
     6  */
     7
     8
     9#include <bsp.h>
     10#include <libcpu/powerpc-utility.h>
     11#include "mmu_405.h"
     12
     13/* #define qLogTLB */
     14/* #define qLogTLBDetails */
     15
     16
     17/*--------------------------------- TLB handling ------------------------------------- */
     18/* The following are in assembler in mmu_405asm.S  */
     19extern  void MMU_GetTLBEntry(uint8_t index, uint32_t* tagword, uint32_t* dataword, uint8_t* pid);
     20extern  void MMU_SetTLBEntry(uint8_t index, uint32_t hiword, uint32_t loword, uint8_t pid);
     21extern  void MMU_ClearTLBs();
     22extern  int16_t MMU_FindTLBEntry(uint32_t address);
     23
     24
     25enum { kNTLBs = 64 };           /* for 403GCX and 405 */
     26
     27static bool             sFreeTLBs[kNTLBs];
     28static uint8_t  sLastIndex = 0;
     29static int              sNInUse = 0;
     30
     31static void MMUFault(const char* what)
     32/* Used for all setup faults; these can't really be ignored */
     33{
     34        printk("\n>>>MMU fatal error %s\n",what);
     35        rtems_fatal_error_occurred(RTEMS_INTERNAL_ERROR);
     36}
     37
     38static uint8_t AllocTLB()
     39{
     40        uint8_t index;
     41       
     42        index = sLastIndex;
     43        do {
     44                index++;
     45                if (index == kNTLBs)
     46                        index = 0;
     47                if (index == sLastIndex)
     48                        MMUFault("TLB table full");
     49        } while (! sFreeTLBs[index]);
     50        sFreeTLBs[index] = false;
     51        sLastIndex = index;
     52        sNInUse++;
     53        return index;
     54}
     55
     56static void FreeTLB(uint8_t index)
     57{
     58        MMU_SetTLBEntry(index,0,0,0);
     59        sFreeTLBs[index] = true;
     60        sLastIndex = index-1;
     61        sNInUse--;
     62}
     63
     64
     65/*---------------------------- MMU operations ---------------------------------- */
     66
     67int DataMissException(BSP_Exception_frame *f, unsigned int vector);
     68int InstructionMissException(BSP_Exception_frame *f, unsigned int vector);
     69int InstructionFetchException(BSP_Exception_frame *f, unsigned int vector);
     70
     71void
     72mmu_initialise()
     73/* Clear the TLBs and set up exception handlers for the MMU miss handlers */
     74{
     75        int i;
     76       
     77        MMU_ClearTLBs();
     78        for (i=0; i<kNTLBs; i++) {
     79                sFreeTLBs[i] = true;
     80                MMU_SetTLBEntry(i,0,0,0xFF);
     81        }
     82        ppc_exc_set_handler(ASM_ISI_VECTOR ,InstructionFetchException);
     83        ppc_exc_set_handler(ASM_BOOKE_ITLBMISS_VECTOR ,DataMissException);
     84        ppc_exc_set_handler(ASM_BOOKE_DTLBMISS_VECTOR ,InstructionMissException);
     85}
     86
     87static void
     88MakeTLBEntries(uint32_t startAt, uint32_t nBytes, bool EX, bool WR, bool I, uint8_t PID)
     89{
     90        uint32_t mask, options, tagWord, dataWord;
     91        uint8_t  index, sizeCode, pid;
     92       
     93        if ((startAt & 0x3FF) != 0)
     94                MMUFault("TLB entry not on 1K boundary");
     95        if ((nBytes & 0x3FF) != 0)
     96                MMUFault("TLB size not on 1K boundary");
     97               
     98        options = 0;
     99        if (EX) options += 0x200;
     100        if (WR) options += 0x100;
     101        if (I) options += 5;
     102       
     103        #ifdef qLogTLB
     104                printk("TLB: make entries for $%X bytes from $%X..$%X PID %d",nBytes, startAt, startAt+nBytes-1, PID);
     105                if (EX) printk(" EX");
     106                if (WR) printk(" WR");
     107                if (I) printk(" I");
     108                printk("\n");
     109        #endif
     110       
     111        while (nBytes > 0) {
     112                /* Find the largest block we can base on this address */
     113                mask = 0x3FF;
     114                sizeCode = 0;
     115                while (mask < nBytes && ((startAt & mask)==0) && sizeCode < 8) {
     116                        mask = (mask<<2) + 3;
     117                        sizeCode++;
     118                }
     119                mask >>= 2;
     120                sizeCode--;
     121               
     122                /* Make a TLB entry describing this, ZSEL=0 */
     123                tagWord = startAt | (sizeCode<<7) | 0x40;
     124                dataWord = startAt | options;
     125                index = AllocTLB();
     126                MMU_SetTLBEntry( index , tagWord, dataWord, PID);
     127               
     128                {
     129                        /* Paranoia: check that we can read that back... */
     130                        uint8_t tdex, oldpid;
     131                       
     132                        oldpid = mmu_current_processID();
     133                        mmu_set_processID(PID);
     134                        tdex = MMU_FindTLBEntry(startAt);
     135                        mmu_set_processID(oldpid);
     136                       
     137                        if (tdex != index) {
     138                                printk(" Add TLB %d: At %X for $%X sizecode %d tagWord $%X  ",index, startAt, mask+1,sizeCode,tagWord);
     139                                printk(" -- find failed, %d/%d!\n",tdex,index);
     140                                MMU_GetTLBEntry(index, &tagWord, &dataWord, &pid);
     141                                printk(" -- reads back $%X : $%X, PID %d\n",tagWord,dataWord,pid);
     142                        } else {
     143                                #ifdef qLogTLBDetails
     144                                printk(" Add TLB %d: At %X for $%X sizecode %d tagWord $%X\n",index, startAt, mask+1,sizeCode,tagWord);
     145                                #endif
     146                        }
     147                }
     148       
     149                /* Subtract block from startAddr and nBytes */
     150                mask++;         /* Convert to a byte count */
     151                startAt += mask;
     152                nBytes -= mask;
     153        }
     154        #ifdef qLogTLB
     155                printk(" %d in use\n",sNInUse);
     156        #endif
     157}
     158
     159void
     160mmu_remove_space(uint32_t startAt, uint32_t endAt)
     161{
     162        int16_t index;
     163        int32_t size;
     164        uint32_t tagword, dataword, nBytes;
     165        uint8_t  pid, sCode;
     166       
     167        nBytes = endAt - startAt;
     168       
     169        #ifdef qLogTLB
     170        printk("TLB: delete entries for $%X bytes from $%X\n",nBytes,startAt);
     171        #endif
     172       
     173        while (nBytes > 0) {
     174                index = MMU_FindTLBEntry( (uint32_t)startAt );
     175                size = 1024;
     176                if (index >= 0) {
     177                        MMU_GetTLBEntry(index, &tagword, &dataword, &pid);
     178                        if ((tagword & 0x40) == 0)
     179                                MMUFault("Undefine failed: redundant entries?");
     180                        if ((tagword & 0xFFFFFC00) != (uint32_t)startAt)
     181                                MMUFault("Undefine not on TLB boundary");
     182                        FreeTLB(index);
     183                        sCode = (tagword >> 7) & 7;
     184                        while (sCode > 0) {
     185                                size <<= 2;
     186                                sCode--;
     187                        }
     188                        #ifdef qLogTLBDetails
     189                        printk(" Free TLB %d: At %X for $%X\n",index, startAt, size);
     190                        #endif
     191                }
     192                startAt += size;
     193                nBytes -= size;
     194        }
     195}
     196
     197void
     198mmu_add_space(uint32_t startAddr, uint32_t endAddr, MMUAccessType permissions, uint8_t processID)
     199/* Convert accesstype to write-enable, executable, and cache-inhibit bits */
     200{
     201        bool EX, WR, I;
     202       
     203        EX = false;
     204        WR = false;
     205        I = false;
     206        switch (permissions) {
     207                case executable                 : EX = true;  break;
     208                case readOnlyData               : break;
     209                case readOnlyNoCache    : I = true; break;
     210                case readWriteData              : WR = true; break;
     211                case readWriteNoCache   : WR = true; I= true; break;
     212                case readWriteExecutable: WR = true; EX = true; break;
     213        }
     214        MakeTLBEntries( (uint32_t)startAddr, (uint32_t)(endAddr-startAddr+1), EX, WR, I, processID);
     215}
     216
     217int
     218mmu_get_tlb_count()
     219{
     220        return sNInUse;
     221}
     222
     223/*---------------------------- CPU process ID handling ----------------------------------
     224 * Really dumb system where we just hand out sequential numbers and eventually fail
     225 * As long as we only use 8-9 processes this isn't a problem */
     226
     227static uint8_t sNextPID = 1;
     228
     229#define SPR_PID         0x3B1
     230
     231uint8_t mmu_new_processID()
     232{
     233        return sNextPID++;
     234}
     235
     236void mmu_free_processID(uint8_t freeThis)
     237{
     238}
     239
     240uint8_t mmu_current_processID()
     241{
     242        return PPC_SPECIAL_PURPOSE_REGISTER(SPR_PID);
     243}
     244
     245uint8_t mmu_set_processID(uint8_t newID)
     246{
     247        uint8_t prev = mmu_current_processID();
     248        PPC_SET_SPECIAL_PURPOSE_REGISTER(SPR_PID,newID);
     249        return prev;
     250}
     251
     252
     253/* ------------------ Fault handlers ------------------ */
     254
     255#define SPR_ESR         0x3D4
     256#define SPR_DEAR        0x3D5
     257
     258enum { kESR_DST = 0x00800000 };
     259
     260int DataMissException(BSP_Exception_frame *f, unsigned int vector)
     261{
     262        uint32_t addr, excSyn;
     263       
     264        addr = PPC_SPECIAL_PURPOSE_REGISTER(SPR_DEAR);
     265        excSyn  = PPC_SPECIAL_PURPOSE_REGISTER(SPR_ESR);
     266        if (excSyn & kESR_DST) printk("\n---Data write to $%X attempted at $%X\n",addr,f->EXC_SRR0);
     267                                          else printk("\n---Data read from $%X attempted at $%X\n",addr,f->EXC_SRR0);
     268        return -1;
     269}
     270
     271int InstructionMissException(BSP_Exception_frame *f, unsigned int vector)
     272{
     273        printk("\n---Instruction fetch attempted from $%X, no TLB exists\n",f->EXC_SRR0);
     274        return -1;
     275}
     276
     277int InstructionFetchException(BSP_Exception_frame *f, unsigned int vector)
     278{
     279        printk("\n---Instruction fetch attempted from $%X, TLB is no-execute\n",f->EXC_SRR0);
     280        return -1;
     281}
  • new file c/src/lib/libbsp/powerpc/haleakala/mmu/mmu_405asm.S

    RCS file: c/src/lib/libbsp/powerpc/haleakala/mmu/mmu_405asm.S
    diff -N c/src/lib/libbsp/powerpc/haleakala/mmu/mmu_405asm.S
    - +  
     1/*
     2
     3Low-level interface to the PPC405 MMU
     4
     5M.Hamel ADInstruments 2008
     6
     7*/
     8
     9#include <rtems/asm.h>
     10
     11/* Useful MMU SPR values */
     12
     13#define SPR_ZPR         0x3B0
     14#define SPR_PID         0x3B1
     15
     16                        .text
     17
     18/* void MMU_ClearTLBs(); */
     19                        PUBLIC_VAR(MMU_ClearTLBs)
     20SYM (MMU_ClearTLBs):
     21                        tlbia
     22                        isync
     23                        lis             r3,0x5555               // *** Gratuitous fiddle of ZPR to 0101010101 to take it out of
     24                        mtspr   SPR_ZPR,r3              // the picture
     25                        blr
     26                       
     27/* void MMU_SetTLBEntry(UInt8 index, UInt32 tagword, UInt32 dataword, UInt8 SPR_PID) */
     28                        PUBLIC_VAR(MMU_SetTLBEntry)
     29SYM (MMU_SetTLBEntry):
     30                        mfspr   r7,SPR_PID              // Save the current SPR_PID
     31                        mtspr   SPR_PID,r6              // Write to SPR_PID
     32                        tlbwehi r4,r3                   // Write hiword
     33                        mtspr   SPR_PID,r7              // Restore the SPR_PID
     34                        tlbwelo r5,r3                   // Write loword
     35                        isync
     36                        blr
     37
     38/* void MMU_GetTLBEntry(UInt8 index, UInt32& tagword, UInt32& dataword, UInt8& SPR_PID) */
     39                        PUBLIC_VAR(MMU_GetTLBEntry)
     40SYM (MMU_GetTLBEntry):         
     41                        mfspr   r7,SPR_PID              // Save the current SPR_PID
     42                        tlbrehi r8,r3                   // Read hiword & SPR_PID
     43                        mfspr   r9,SPR_PID              // Copy the SPR_PID
     44                        mtspr   SPR_PID,r7              // Restore original SPR_PID so we can proceed
     45                        stw             r8,0(r4)                // Write to r4 pointer
     46                        stb             r9,0(r6)                // Write to r6 pointer
     47                        tlbrelo r8,r3                   // Read loword
     48                        stw             r8,0(r5)                // Write to r5 pointer
     49                        blr
     50                       
     51/* SInt16 MMU_FindTLBEntry(UInt32 address) */
     52/* Returns index of covering TLB entry (0..63), or -1 if there isn't one */
     53                        PUBLIC_VAR(MMU_FindTLBEntry)
     54SYM (MMU_FindTLBEntry):         
     55                        tlbsx.  r3,0,r3
     56                        beqlr
     57                        li              r3,0xFFFFFFFF
     58                        blr
     59
     60/* bool         mmu_enable_code(bool enable); */
     61                        PUBLIC_VAR(mmu_enable_code)
     62SYM (mmu_enable_code): 
     63                        li              r5,0x20 // IR bit
     64                        b               msrbits
     65                       
     66/* bool         mmu_enable_data(bool enable); */
     67                        PUBLIC_VAR(mmu_enable_data)
     68SYM (mmu_enable_data): 
     69                        li              r5,0x10         // DR bit
     70msrbits:        cmpwi   r3,0                    // Common code: parameter 0?
     71                        mfmsr   r4                              // r4 = MSR state
     72                        beq             clrBit
     73                        or              r6,r4,r5                // If 1, r6 = MSR with bit set
     74                        b               setmsr
     75clrBit:         andc    r6,r4,r5                // If 0 r6 = MSR with bit clear
     76setmsr:         mtmsr   r6                              // Write new MSR
     77                        and.    r3,r4,r5                // Result = old MSR bit
     78                        beqlr                                           // If zero return zero
     79                        li              r3,0xFF         // If nonzero return byte -1
     80                        blr
     81       
     82                       
     83                       
  • new file c/src/lib/libbsp/powerpc/haleakala/network/network.c

    RCS file: c/src/lib/libbsp/powerpc/haleakala/network/network.c
    diff -N c/src/lib/libbsp/powerpc/haleakala/network/network.c
    - +  
     1/*
     2 *  network.c
     3 *  RTEMS_490
     4 *
     5 *  Created by Michael Hamel on 18/11/08.
     6 *
     7 * This code is for the PPC405EX, 405EXr on the Haleakala board with an
     8 * 88E1111 PHY.
     9 * Its has some adaptations for the 405GP, and 405GPr (untested).
     10 *
     11 * It should handle dual interfaces correctly, but has not been tested.
     12 *
     13 */
     14
     15#include <bsp.h>
     16#include <stdio.h>
     17#include <errno.h>
     18#include <rtems/error.h>
     19#include <rtems/rtems_bsdnet.h>
     20#include <rtems/rtems_mii_ioctl.h>
     21
     22#include <sys/param.h>
     23#include <sys/mbuf.h>
     24#include <sys/socket.h>
     25#include <sys/sockio.h>
     26
     27#include <net/if.h>
     28
     29#include <netinet/in.h>
     30
     31#include <netinet/if_ether.h>
     32#include <bsp/irq.h>
     33
     34#include <sys/types.h>
     35#include <sys/socket.h>
     36#include <arpa/inet.h>
     37
     38#include <ppc4xx/ppc405gp.h>
     39#include <ppc4xx/ppc405ex.h>
     40
     41#define qDebug          /* General printf debugging */
     42/* #define qMultiDebug */       /* Debugging for the multicast hardware filter */
     43
     44/*---------------------------- Hardware definitions -------------------------- */
     45
     46/* PHY addresses for Kilauea & Haleakala; defined by hardware */
     47enum {
     48        kPHY0 = 1,
     49        kPHY1 = 2,
     50        kMaxEMACs = 2
     51};
     52
     53enum {
     54        kMaxRxBuffers = 256,
     55        kNXmtDescriptors = 256, /* May as well use all of them */
     56        kNoXmtBusy = 666                /* Arbitrary flag value outside 0..kNXmtDescriptors */
     57};
     58
     59
     60/*----------------------- Local variables for the driver -------------------------- */
     61
     62typedef struct MALDescriptor {
     63        uint16_t ctrlBits;
     64        uint16_t adrDataSize;   /* 4 bits of high address, 12 bits of length */
     65        uint8_t* ptr;
     66} MALDescriptor;
     67
     68typedef struct EMACLocals {
     69    struct arpcom  arpcom;
     70
     71        /* Pointer to memory-mapped hardware */
     72        volatile EthernetRegisters_GP*  EMAC;
     73       
     74    /* Transmit and receive task references */
     75    rtems_id            rxDaemonTid;
     76        rtems_id                txDaemonTid;
     77        int                             nRxBuffers;
     78        int                             xmtFreeIndex;
     79        int                             xmtBusyIndex;
     80        MALDescriptor*  xmtDescTable;
     81        MALDescriptor*  rcvDescTable;
     82       
     83        struct mbuf* rxMBufs[kMaxRxBuffers];
     84        struct mbuf* txMBufs[kNXmtDescriptors];
     85       
     86        int                     phyAddr,        /* PHY address */
     87                                phyState,       /* Last link state */
     88                                phyOUI,         /* Cached PHY type info */
     89                                phyModel,
     90                                phyRev;
     91
     92        /* Statistics */
     93        uint32_t   rxInterrupts;
     94        uint32_t   rxOverrun;
     95        uint32_t   rxRunt;
     96        uint32_t   rxBadCRC;
     97        uint32_t   rxNonOctet;
     98        uint32_t   rxGiant;
     99       
     100        uint32_t        txInterrupts;
     101       
     102        uint32_t        txLostCarrier;
     103        uint32_t        txDeferred;
     104        uint32_t        txOneCollision;
     105        uint32_t        txMultiCollision;
     106        uint32_t        txTooManyCollision;
     107        uint32_t        txLateCollision;
     108        uint32_t        txUnderrun;
     109        uint32_t        txPoorSignal;
     110} EMACLocals;
     111
     112
     113EMACLocals gEmacs[kMaxEMACs];
     114
     115/*----------------------------------- Globals --------------------------------------*/
     116
     117/*
     118   Pointers to the buffer descriptor tables used by the MAL. Tricky because they are both
     119   read and written to by the MAL, which is unaware of the CPU data cache. As four 8-byte
     120   descriptors fit into a single cache line this makes managing them in cached memory difficult.
     121   Best solution is to label them as uncached using the MMU. This code assumes an appropriate
     122   sized block stating at _enet_bdesc_base has been reserved by linkcmds and has been set up
     123   with uncached MMU attrributes in bspstart.c */
     124
     125LINKER_SYMBOL(_enet_bdesc_start);               /* start of buffer descriptor space, from linkcmds */
     126LINKER_SYMBOL(_enet_bdesc_end);                 /* top limit, from linkcmds */
     127
     128static MALDescriptor* gTx0Descs = NULL;
     129static MALDescriptor* gRx0Descs = NULL;
     130static MALDescriptor* gTx1Descs = NULL;
     131static MALDescriptor* gRx1Descs = NULL;
     132
     133/*------------------------------------------------------------*/
     134
     135
     136/*
     137 * RTEMS event used by interrupt handler to signal driver tasks.
     138 * This must not be any of the events used by the network task synchronization.
     139 */
     140#define INTERRUPT_EVENT                 RTEMS_EVENT_1
     141
     142/*
     143 * RTEMS event used to start transmit daemon.
     144 * This must not be the same as INTERRUPT_EVENT.
     145 */
     146#define START_TRANSMIT_EVENT    RTEMS_EVENT_2
     147
     148#define _sync    __asm__ volatile ("sync\n"::)
     149
     150#define kCacheLineMask  (PPC_CACHE_ALIGNMENT - 1)
     151
     152
     153/*----------------------- IRQ handler glue -----------------------*/
     154
     155static void InstallIRQHandler(rtems_irq_number id,
     156                                                          rtems_irq_hdl handler,
     157                                                          rtems_irq_enable turnOn,
     158                                                          rtems_irq_disable turnOff)
     159{
     160        rtems_irq_connect_data params;
     161       
     162        params.name = id;
     163        params.hdl = handler;
     164        params.on = turnOn;
     165        params.off = turnOff;
     166        params.isOn = NULL;
     167        params.handle = NULL;
     168        if (! BSP_install_rtems_irq_handler(&params))
     169                rtems_panic ("Can't install interrupt handler");
     170}
     171
     172static void
     173NoAction(const rtems_irq_connect_data* unused)
     174{
     175        /* printf("NoAction %d\n",unused->name); */
     176}
     177
     178
     179/*------------------------ PHY interface -------------------------- */
     180/* This code recognises and works with the 88E1111 only. Other PHYs
     181   will require appropriate adaptations to this code */
     182   
     183enum {
     184        kPHYControl = 0,
     185         kPHYReset = 0x8000,
     186        kPHYStatus = 1,
     187         kPHYLinkStatus = 0x0004,
     188        kPHYID1 = 2,
     189        kPHYID2 = 3,
     190        kPHYAutoNegExp = 6,
     191        kPHY1000BaseTCtl = 9,
     192        kPHYExtStatus = 15,
     193       
     194        /* 88E1111 identification */
     195        kMarvellOUI = 0x5043,
     196        k88E1111Part = 0x0C,
     197
     198        /* 88E1111 register addresses */
     199        k8PHYSpecStatus = 17,
     200                k8PHYSpeedShift = 14,
     201                k8PHYDuplex    = 0x2000,
     202                k8PHYResolved  = 0x0800,
     203                k8PHYLinkUp    = 0x0400,
     204        k8IntStatus = 19,
     205        k8IntEnable = 18,
     206         k8AutoNegComplete = 0x0800,
     207         k8LinkStateChanged = 0x0400,
     208        k8ExtCtlReg = 20,
     209                k8RcvTimingDelay = 0x0080,
     210                k8XmtTimingDelay = 0x0002,
     211                k8XmtEnable      = 0x0001,
     212        k8LEDCtlReg = 24,
     213        k8ExtStatusReg = 27,
     214};
     215
     216
     217static uint16_t ReadPHY(EMACLocals* ep, uint8_t reg)
     218{
     219        int n = 0;
     220        uint32_t t;
     221       
     222        reg &= 0x1F;
     223       
     224        /* 405EX-specific! */
     225        while ((ep->EMAC->STAcontrol & keSTARun) != 0)
     226                { ; }
     227        ep->EMAC->STAcontrol = keSTADirectRd + (ep->phyAddr<<5) + reg;
     228        ep->EMAC->STAcontrol |= keSTARun;
     229        /* Wait for the read to complete, should take ~25usec */
     230        do {
     231                t = ep->EMAC->STAcontrol;
     232                if (++n > 200000)
     233                        rtems_panic("PHY read timed out");
     234        } while ((t & keSTARun) != 0);
     235       
     236        if (t & kSTAErr)
     237                rtems_panic("PHY read failed");
     238        return t >> 16;
     239}
     240
     241static void WritePHY(EMACLocals* ep, uint8_t reg, uint16_t value)
     242{
     243
     244        reg &= 0x1F;
     245       
     246        /* 405EX-specific */
     247        while ((ep->EMAC->STAcontrol & keSTARun) != 0)
     248                { ; }
     249        ep->EMAC->STAcontrol = (value<<16) | keSTADirectWr | (ep->phyAddr<<5) | reg;
     250        ep->EMAC->STAcontrol |= keSTARun;
     251}
     252
     253static void ResetPHY(EMACLocals* ep)
     254{
     255        int n;
     256       
     257        n = ReadPHY(ep, kPHYControl);
     258        n |= kPHYReset;
     259        WritePHY(ep, kPHYControl, n);
     260        do {
     261                rtems_task_wake_after( (rtems_bsdnet_ticks_per_second/20) + 1 );
     262                n = ReadPHY(ep, kPHYControl);
     263        } while ((n & kPHYReset)!=0);
     264}
     265
     266enum {
     267        kELinkUp = 0x80,
     268        kELinkFullDuplex = 0x40,
     269        kELinkSpeed10 = 0,
     270        kELinkSpeed100 = 1,
     271        kELinkSpeed1000 = 2,
     272        kELinkSpeedMask = 3
     273};
     274
     275static int GetPHYLinkState(EMACLocals* ep)
     276/* Return link state (up/speed/duplex) as a set of flags */
     277{
     278        int state, result;
     279       
     280        /* if (ep->phyOUI==kMarvellOUI) */
     281        result = 0;
     282        state = ReadPHY(ep,k8PHYSpecStatus);
     283        if ((state & k8PHYLinkUp) && (state & k8PHYResolved)) {
     284                result |= kELinkUp;
     285                if (state & k8PHYDuplex) result |= kELinkFullDuplex;
     286                result |= ((state >> k8PHYSpeedShift) & 3);
     287        }
     288        return result;
     289}
     290
     291/*---------------------- PHY setup ------------------------*/
     292
     293
     294static void InitPHY(EMACLocals* ep)
     295{
     296        int id,id2,n;
     297       
     298        id = ReadPHY(ep,kPHYID1);
     299        id2 = ReadPHY(ep,kPHYID2);
     300        ep->phyOUI = (id<<6) + (id2>>10);
     301        ep->phyModel = (id2>>4) & 0x1F;
     302        ep->phyRev = id2 & 0xF;
     303       
     304        #ifdef qDebug
     305                printf("PHY %d maker $%X model %d revision %d\n",ep->phyAddr,ep->phyOUI,ep->phyModel,ep->phyRev);
     306        #endif
     307       
     308        /* Test for PHYs that we understand; insert new PHY types initialisation here */
     309        if (ep->phyOUI == kMarvellOUI || ep->phyModel == k88E1111Part) {
     310                /* 88E111-specific: Enable RxTx timing control, enable transmitter */
     311                n = ReadPHY(ep, k8ExtCtlReg);
     312                n |= k8RcvTimingDelay + k8XmtTimingDelay + k8XmtEnable;         
     313                WritePHY(ep, k8ExtCtlReg, n);
     314               
     315                /* Set LED mode; Haleakala has LINK10 and TX LEDs only. Set up to do 100/1000 and link up/active*/
     316                WritePHY(ep, k8LEDCtlReg, 0x4109);
     317               
     318                /* Need to do a reset after fiddling with registers*/
     319                ResetPHY(ep);
     320        } else
     321                rtems_panic("Unknown PHY type");
     322}
     323
     324
     325/*--------------------- Interrupt handlers for the MAL ----------------------------- */
     326
     327static void
     328MALTXDone_handler(rtems_irq_hdl_param param)
     329{
     330        int n;
     331       
     332        n = PPC_DEVICE_CONTROL_REGISTER(MAL0_TXEOBISR);
     333        if (n & kMALChannel0) {
     334                gEmacs[0].txInterrupts++;
     335                rtems_event_send (gEmacs[0].txDaemonTid, INTERRUPT_EVENT);
     336        }
     337        if (n & kMALChannel1) {
     338                gEmacs[1].txInterrupts++;
     339                rtems_event_send (gEmacs[1].txDaemonTid, INTERRUPT_EVENT);
     340        }
     341        PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_TXEOBISR,n);
     342}
     343
     344static void
     345MALRXDone_handler (rtems_irq_hdl_param param)
     346{
     347        int n;
     348       
     349        n = PPC_DEVICE_CONTROL_REGISTER(MAL0_RXEOBISR);
     350        if (n & kMALChannel0) {
     351                gEmacs[0].rxInterrupts++;
     352                rtems_event_send (gEmacs[0].rxDaemonTid, INTERRUPT_EVENT);
     353        }
     354        if (n & kMALChannel1) {
     355                gEmacs[1].rxInterrupts++;
     356                rtems_event_send (gEmacs[1].rxDaemonTid, INTERRUPT_EVENT);
     357        }
     358        PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_RXEOBISR,n);       /* Write back to clear interrupt */
     359}
     360
     361/* These handlers are useful for debugging, but we don't actually need to process these interrupts */
     362
     363static void
     364MALErr_handler (rtems_irq_hdl_param param)
     365{
     366        uint32_t errCause;
     367       
     368        errCause = PPC_DEVICE_CONTROL_REGISTER(MAL0_ESR);
     369        /* Clear the error */
     370        PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_ESR,errCause);
     371}
     372       
     373static void
     374EMAC0Err_handler (rtems_irq_hdl_param param)
     375{
     376        uint32_t errCause;
     377       
     378        errCause = gEmacs[0].EMAC->intStatus;
     379        /* Clear error by writing back */
     380        gEmacs[0].EMAC->intStatus = errCause;
     381}
     382
     383static void
     384EMAC1Err_handler (rtems_irq_hdl_param param)
     385{
     386        uint32_t errCause;
     387       
     388        errCause = gEmacs[1].EMAC->intStatus;
     389        /* Clear error by writing back */
     390        gEmacs[1].EMAC->intStatus = errCause;
     391}
     392
     393
     394/*--------------------- Low-level hardware initialisation ----------------------------- */
     395
     396
     397
     398static void
     399mal_initialise(void)
     400{       
     401        uint32_t bdescbase;
     402        int nBytes, ntables;
     403       
     404        /*------------------- Initialise the MAL for both channels ---------------------- */
     405                       
     406        PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_CFG,kMALReset);
     407        PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_TXCARR, kMALChannel0 | kMALChannel1);
     408        PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_RXCARR, kMALChannel0 | kMALChannel1);
     409
     410        /* Acquire MAL interrupts */
     411        InstallIRQHandler(BSP_UIC_MALTXEOB, MALTXDone_handler, NoAction, NoAction);
     412        InstallIRQHandler(BSP_UIC_MALRXEOB, MALRXDone_handler, NoAction, NoAction);
     413        InstallIRQHandler(BSP_UIC_MALSERR, MALErr_handler, NoAction, NoAction);
     414               
     415        /* Set up the buffer descriptor tables */
     416        bdescbase = (uint32_t)(_enet_bdesc_start);
     417        nBytes = sizeof(MALDescriptor) * 256;
     418        ntables = 4;
     419        if (get_ppc_cpu_type() != PPC_405EX) {
     420                /* The 405GP/GPr requires table bases to be 4K-aligned and can use two tx channels on one EMAC */
     421                nBytes = (nBytes + 0x0FFF) & ~0x0FFF;
     422                bdescbase = (bdescbase + 0x0FFF) & ~0x0FFF;
     423                ntables = 3;
     424        }
     425       
     426        /* printf("Buffer descriptors at $%X..$%X, code from $%X\n",bdescbase, bdescbase + nBytes*ntables - 1,(uint32_t)&_text_start); */
     427       
     428        /* Check that we have been given enough space and the buffers don't run past the enet_bdesc_end address */
     429        if (bdescbase + nBytes*ntables > (uint32_t)_enet_bdesc_end)
     430                rtems_panic("Ethernet descriptor space insufficient!");
     431               
     432        gTx0Descs = (MALDescriptor*)bdescbase;
     433        gTx1Descs = (MALDescriptor*)(bdescbase + nBytes);
     434        gRx0Descs = (MALDescriptor*)(bdescbase + nBytes*2);
     435        /* Clear the buffer descriptor tables */
     436        memset(gTx0Descs, 0, sizeof(MALDescriptor)*256);
     437        memset(gTx1Descs, 0, sizeof(MALDescriptor)*256);
     438        memset(gRx0Descs, 0, sizeof(MALDescriptor)*256);
     439        if (get_ppc_cpu_type() == PPC_405EX) {
     440                gRx1Descs = (MALDescriptor*)(bdescbase + nBytes*3);
     441                memset(gRx1Descs, 0, sizeof(MALDescriptor)*256);
     442        }
     443       
     444        /* Set up the MAL registers */
     445        PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_TXCTP0R,gTx0Descs);
     446        PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_TXCTP1R,gTx1Descs);
     447        PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_RXCTP0R,gRx0Descs);
     448        PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_RCBS0, (MCLBYTES-16)>>4);          /* The hardware writes directly to the mbuf clusters, so it can write MCLBYTES */
     449        if (get_ppc_cpu_type() == PPC_405EX) {
     450                PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_CFG,kMALMedHiPriority + keMALRdMaxBurst32 + keMALWrMedHiPriority + keMALWrMaxBurst32 +
     451                                                                                         kMALLocksOPB + kMALLocksErrs + kMALCanBurst);
     452                PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_RXCTP1R,gRx1Descs);
     453                PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_RCBS1, (MCLBYTES-16)>>4);
     454                PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_IER,0xF7);         /* Enable all MAL interrupts */
     455        } else {
     456                PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_CFG,kMALMedHiPriority + kMALLocksOPB + kMALLocksErrs + kMALCanBurst + kMALLatency8);
     457                PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_IER,0x1F);         /* Enable all MAL interrupts */
     458        }
     459}
     460
     461
     462
     463#ifdef qDebug
     464static void printaddr(uint8_t* enetaddr)
     465{
     466        printf("%02X.%02X.%02X.%02X.%02X.%02X",enetaddr[0],enetaddr[1],enetaddr[2],enetaddr[3],enetaddr[4],enetaddr[5]);
     467}
     468#endif
     469
     470static bool gMALInited = FALSE;
     471       
     472static void
     473ppc405_emac_initialize_hardware(EMACLocals* ep)
     474{
     475
     476        int  n,mfr;
     477        int  unitnum = ep->arpcom.ac_if.if_unit;
     478       
     479        if (get_ppc_cpu_type() == PPC_405EX) {
     480                /* PPC405EX: configure the RGMII bridge and clocks */
     481                RGMIIRegisters* rgmp = (RGMIIRegisters*)RGMIIAddress;
     482                rgmp->FER = 0x00080055; /* Both EMACs RGMII */
     483                rgmp->SSR = 0x00000044; /* Both EMACs 1000Mbps */
     484                /* Configure the TX clock to be external */
     485                mfsdr(SDR0_MFR,mfr);
     486                mfr &= ~0x0C000000;             /* Switches both PHYs */
     487                mtsdr(SDR0_MFR,mfr);
     488        }
     489       
     490        /* Reset the EMAC */
     491        n = 0;
     492        ep->EMAC->mode0 = kEMACSoftRst;                                                 
     493        while ((ep->EMAC->mode0 & kEMACSoftRst) != 0)
     494                n++;            /* Wait for it to complete */
     495       
     496        /* Set up so we can talk to the PHY */
     497        ep->EMAC->mode1 = keEMACIPHYAddr4 |  keEMACOPB100MHz;
     498       
     499        /* Initialise the PHY  */
     500        InitPHY(ep);
     501       
     502        /* Initialise the MAL (once only) */
     503        if ( ! gMALInited) {
     504                mal_initialise();
     505                gMALInited = TRUE;
     506        }
     507
     508        /* Set up IRQ handlers and enable the MAL channels for this port */
     509        if (unitnum==0) {
     510                ep->xmtDescTable = gTx0Descs;
     511                ep->rcvDescTable = gRx0Descs;
     512                InstallIRQHandler(BSP_UIC_EMAC0, EMAC0Err_handler, NoAction, NoAction);
     513                PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_TXCASR,kMALChannel0);
     514                PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_RXCASR,kMALChannel0);
     515        } else {
     516                ep->xmtDescTable = gTx1Descs;
     517                ep->rcvDescTable = gRx1Descs;
     518                InstallIRQHandler(BSP_UIC_EMAC1, EMAC1Err_handler, NoAction, NoAction);
     519                PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_TXCASR,kMALChannel1);
     520                PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_RXCASR,kMALChannel1);
     521        }
     522       
     523        /* The rest of the EMAC initialisation is done in emac_phy_adapt
     524           when we know what the characteristics of the link are */
     525}
     526
     527
     528/* EMAC second stage initialisation; talks to the PHY to find out how to do it.
     529   Resets the EMAC if the PHY parameters need to be changed */
     530 
     531int ppc405_emac_phy_adapt(EMACLocals* ep)
     532{
     533        int linkState = GetPHYLinkState(ep);
     534        int spd;
     535       
     536        if ((linkState & kELinkUp) && (linkState != ep->phyState)) {
     537                /* Reset the EMAC and set registers according to PHY state */
     538                int i,n = 0;
     539                uint32_t mode, rmode;
     540               
     541                ep->EMAC->mode0 = kEMACSoftRst;                                                 
     542                while ((ep->EMAC->mode0 & kEMACSoftRst) != 0)
     543                        n++;            /* Wait for it to complete */
     544                spd = linkState & kELinkSpeedMask;
     545                mode = (spd<<22) | kgEMACTx0Multi;
     546                if (get_ppc_cpu_type() == PPC_405EX)
     547                        mode |= (keEMAC16KRxFIFO | keEMAC16KTxFIFO | keEMACIPHYAddr4 | keEMACOPB100MHz );
     548                else
     549                        mode |= (kgEMAC4KRxFIFO | kgEMAC2KTxFIFO);
     550                if (linkState & kELinkFullDuplex)
     551                        mode |= kEMACFullDuplex + kEMACDoFlowControl;
     552                if ( (linkState & kELinkFullDuplex) || (spd > kELinkSpeed10) )
     553                        mode |= kEMACIgnoreSQE;
     554       
     555               
     556                if (spd==kELinkSpeed1000) {
     557                        /* Gigabit, so we support jumbo frames. Take appropriate measures: adjust the if_mtu */
     558                        /* Note that we do this here because changing it later doesn't work very well : see
     559                           the SIOCSIFMTU discussion below */
     560                        struct ifnet* ifp = &ep->arpcom.ac_if;
     561                        ifp->if_mtu = ETHERMTU_JUMBO;
     562                        mode |= keEMACJumbo;
     563                }
     564               
     565               
     566                ep->phyState = linkState;
     567                ep->EMAC->mode1 = mode;
     568               
     569                /* Install 48-bit hardware address that we have been given */
     570                ep->EMAC->addrHi = (ep->arpcom.ac_enaddr[0]<<8) + ep->arpcom.ac_enaddr[1];
     571                ep->EMAC->addrLo = (ep->arpcom.ac_enaddr[2]<<24) + (ep->arpcom.ac_enaddr[3]<<16)
     572                                                + (ep->arpcom.ac_enaddr[4]<<8) + (ep->arpcom.ac_enaddr[5] );
     573               
     574                /* Set receive mode appropriately */
     575                rmode = kEMACStripPadding + kEMACStripFCS + kEMACBrcastRcv;
     576               
     577                if (ep->arpcom.ac_if.if_flags & IFF_PROMISC) rmode |= kEMACPromiscRcv;
     578                                                                                                else rmode |= kEMACIndivRcv;
     579                if (get_ppc_cpu_type() == PPC_405EX)
     580                        rmode |= keEMACRxFIFOAFMax;     
     581                if ((ep->arpcom.ac_if.if_flags & IFF_ALLMULTI) != 0)
     582                        rmode |= kEMACPromMultRcv;
     583                else if ((ep->arpcom.ac_if.if_flags & IFF_MULTICAST) != 0)
     584                        rmode |= kEMACMultcastRcv;
     585               
     586                ep->EMAC->rcvMode = rmode;
     587
     588                if (get_ppc_cpu_type() == PPC_405EX)
     589                        for (i=0; i<8; i++)
     590                                ep->EMAC->e_groupHash[i] = 0;
     591                else
     592                        for (i=0; i<4; i++)
     593                                ep->EMAC->g_groupHash[i] = 0;
     594
     595                if (get_ppc_cpu_type() == PPC_405EX) {
     596                        /* Rcv low watermark, must be < mode1 Rcv FIFO size and > MAL burst length (default 64x4 bytes), 16-byte units
     597                           High watermark must be > low and < RcvFIFO size */
     598                        ep->EMAC->rcvWatermarks = (16<<22) + (768<<6);
     599                        /* Xmt low request must be >= 17 FIFO entries, Xmt urgent must be > low */
     600                        ep->EMAC->xmtMode1 = (17<<27) + (68<<14);                       /* TLR = 17, TUR = 68 */
     601                        /* Xmt partial packet request threshold */
     602                        ep->EMAC->xmtReqThreshold = ((1000>>2)-1) << 24;        /* TRTR[TRT] = 1000 FIFO entries */
     603                } else {
     604                        ep->EMAC->rcvWatermarks = (15<<24) + (32<<8);
     605                        ep->EMAC->xmtReqThreshold = ((1448>>6)-1) << 26;        /* TRT = 1024b */
     606                        ep->EMAC->xmtMode1 = 0x40200000;                                        /* TLR = 8w=32b, TUR=32w=128b */
     607                }
     608                       
     609                ep->EMAC->IPGap = 8;
     610               
     611                /* Want EMAC interrupts for error logging & statistics */
     612                ep->EMAC->intEnable = kEMACIOverrun + kEMACIPause + kEMACIBadPkt + kEMACIRuntPkt + kEMACIShortEvt
     613                                                        + kEMACIAlignErr + kEMACIBadFCS + kEMACIOverSize + kEMACILLCRange + kEMACISQEErr
     614                                                        + kEMACITxErr;
     615                                               
     616                /* Start it running */
     617                ep->EMAC->mode0 = kEMACRxEnable + kEMACTxEnable;               
     618                return 0;
     619        } else
     620                return -1;
     621}
     622
     623
     624static void
     625ppc405_emac_disable(EMACLocals* ep)
     626/* Disable the EMAC channels so we stop running and processing interrupts */
     627{
     628        ep->EMAC->mode0 = 0;
     629}
     630
     631static void
     632ppc405_emac_startxmt(EMACLocals* ep)
     633/* Start the transmitter: set TMR0[GNP] */
     634{
     635        ep->EMAC->xmtMode0 = kEMACNewPacket0 + 7;               /* *** TFAE value for EX */
     636}
     637
     638static void ppc405_emac_watchdog(struct ifnet* ifp)
     639/* Called if a transmit stalls or when the interface is down. Check the PHY
     640   until we get a valid link */
     641{
     642        EMACLocals* ep = ifp->if_softc;
     643       
     644        if (ppc405_emac_phy_adapt(ep)==0) {
     645                ep->arpcom.ac_if.if_flags |= IFF_RUNNING;
     646                ifp->if_timer = 0;              /* No longer needed */
     647        } else
     648                ifp->if_timer = 1;              /* reschedule, once a second */
     649}
     650
     651
     652
     653/*----------------------- The transmit daemon/task -------------------------- */
     654
     655
     656static void
     657FreeTxDescriptors(EMACLocals* ep)
     658/* Make descriptors and mbufs at xmtBusyIndex available for re-use if the packet that they */
     659/* point at has all gone */
     660{
     661        uint16_t scan, status;
     662       
     663        if (ep->xmtBusyIndex != kNoXmtBusy) {
     664                scan = ep->xmtBusyIndex;
     665                while (TRUE) {
     666                        /* Scan forward through the descriptors */
     667                        status = ep->xmtDescTable[scan].ctrlBits;
     668                        if (++scan >= kNXmtDescriptors)
     669                                scan = 0;
     670                        /* If we find a ready (i.e not-yet-sent) descriptor, stop */
     671                        if ((status & kMALTxReady) != 0)
     672                                break;
     673                        /* If we find a last descriptor, we can free all the buffers up to and including it */
     674                        if ((status & kMALLast) != 0) {
     675                                /* End of packet and it has been sent or abandoned; advance xmtBusyIndex to  */
     676                                /* the next buffer and free buffers. */
     677                                if ((status & kEMACErrMask) != 0) {
     678                                        /* Transmit error of some kind */
     679                                       
     680                                        if ((status & kEMACDeferred) != 0)
     681                                                ep->txDeferred++;
     682                                        if ((status & kEMACLostCarrier) != 0)
     683                                                ep->txLostCarrier++;    /* *** Perhaps more serious reaction needed... */
     684                                       
     685                                        if ((status & kEMACLateColl) != 0)
     686                                                ep->txLateCollision++;
     687                                        if ((status & kEMACOneColl) != 0)
     688                                                ep->txOneCollision++;
     689                                        if ((status & kEMACMultColl) != 0)
     690                                                ep->txMultiCollision++;
     691                                        if ((status & kEMACCollFail) != 0)
     692                                                ep->txTooManyCollision++;
     693                                       
     694                                        if ((status & kEMACSQEFail) != 0)
     695                                                ep->txPoorSignal++;
     696                                        if ((status & kEMACUnderrun) != 0)
     697                                                ep->txUnderrun++;
     698                                }
     699                                while (ep->xmtBusyIndex != scan) {
     700                                        m_free(ep->txMBufs[ep->xmtBusyIndex]);
     701                                        if (++ep->xmtBusyIndex >= kNXmtDescriptors) ep->xmtBusyIndex = 0;
     702                                }
     703                                if (ep->xmtBusyIndex == ep->xmtFreeIndex) {
     704                                        /* Nothing is busy */
     705                                        ep->xmtBusyIndex = kNoXmtBusy;
     706                                        break;
     707                                }
     708                        }
     709                }
     710        }
     711}
     712
     713
     714static void
     715SendPacket (EMACLocals* ep, struct ifnet *ifp, struct mbuf *m)
     716/* Given a chain of mbufs, set up a transmit description and fire it off */
     717{
     718        int nAdded, index, lastidx, totalbytes;
     719        uint16_t status;
     720        struct mbuf* lastAdded;
     721       
     722        nAdded = 0;
     723        totalbytes = 0;
     724        lastAdded = NULL;
     725        index = ep->xmtFreeIndex;
     726       
     727        /* Go through the chain of mbufs setting up descriptors for each */
     728        while (m != NULL) {
     729                                       
     730                if (m->m_len == 0) {
     731                        /* Can be empty: dispose and unlink from chain */
     732                        m = m_free(m);
     733                        if (lastAdded!=NULL) lastAdded->m_next = m;
     734                } else {
     735                        /* Make sure the mbuf has been written to memory */
     736                        rtems_cache_flush_multiple_data_lines(mtod (m, void *), m->m_len);
     737                        /* If there are no descriptors available wait until there are */
     738                        while (index == ep->xmtBusyIndex) {
     739                                rtems_event_set events;
     740                                ifp->if_timer = 2;
     741                                /* Then check for free descriptors, followed by: */
     742                                rtems_bsdnet_event_receive (INTERRUPT_EVENT, RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &events);
     743                                FreeTxDescriptors(ep);
     744                        }
     745                               
     746                        /* Fill in a descriptor for this mbuf and record it */
     747                        ep->txMBufs[index] = m;
     748                        ep->xmtDescTable[index].ptr = mtod (m, void *);
     749                        ep->xmtDescTable[index].adrDataSize = m->m_len;
     750                        /* Fill in ctrlBits as we go but don't mark the first one as ready yet */
     751                        status = kEMACGenFCS + kEMACGenPad + kEMACRepSrcAddr;
     752                        if (nAdded > 0)
     753                                status |= kMALTxReady;
     754                        if (index==kNXmtDescriptors-1)
     755                                status |= kMALWrap;
     756                        ep->xmtDescTable[index].ctrlBits = status;
     757                        lastidx = index;
     758                                       
     759                        totalbytes += m->m_len;
     760                        lastAdded = m;
     761                        m = m->m_next;
     762                        nAdded++;
     763                       
     764                        index += 1;
     765                        if (index==kNXmtDescriptors)
     766                                index = 0;
     767                       
     768                        if (nAdded==kNXmtDescriptors)
     769                                rtems_fatal_error_occurred(RTEMS_INTERNAL_ERROR);               /* This is impossible, of course... */
     770                }
     771        }
     772       
     773        if (nAdded > 0) {
     774                /* Done and we added some buffers */
     775                /* Label the last buffer and ask for an interrupt */
     776                ep->xmtDescTable[lastidx].ctrlBits |= kMALLast + kMALInterrupt;
     777                /* Finally set the ready bit on the first buffer */
     778                ep->xmtDescTable[ep->xmtFreeIndex].ctrlBits |= kMALTxReady;
     779                /* Make sure this has been written */
     780                _sync;
     781                if (ep->xmtBusyIndex == kNoXmtBusy)
     782                        ep->xmtBusyIndex = ep->xmtFreeIndex;
     783                ep->xmtFreeIndex = index;
     784                /* Poke the EMAC to get it started (which may not be needed if its already running */
     785                ppc405_emac_startxmt(ep);
     786                ifp->if_timer = 2;
     787        }
     788}
     789
     790static void
     791ppc405_emac_txDaemon (void* param)
     792{
     793        EMACLocals* ep = param;
     794        struct ifnet *ifp = &ep->arpcom.ac_if;
     795        struct mbuf *m;
     796        rtems_event_set events;
     797
     798        ep->xmtFreeIndex = 0;
     799        ep->xmtBusyIndex = kNoXmtBusy;
     800        while (TRUE) {
     801                /* Wait for someone wanting to transmit */
     802                rtems_bsdnet_event_receive (START_TRANSMIT_EVENT | INTERRUPT_EVENT,
     803                                                                        RTEMS_EVENT_ANY | RTEMS_WAIT,
     804                                                                        RTEMS_NO_TIMEOUT,
     805                                                                        &events);
     806                if (events & INTERRUPT_EVENT)
     807                        ifp->if_timer = 0;
     808                /* Grab packets and send until empty */
     809                /* Note that this doesn't (at the time of writing, RTEMS 4.9.1), ever get asked to send more than
     810                   one header mbuf and one data mbuf cluster, regardless of the MTU. This is because sosend() in the FreeBSD
     811                   stack only passes one mbuf at a time across to tcp_send, which immediately sends it */
     812                while (TRUE) {
     813                        FreeTxDescriptors(ep);
     814                        IF_DEQUEUE(&ifp->if_snd, m);
     815                        if (m == NULL)
     816                                break;
     817                        SendPacket (ep, ifp, m);
     818                }
     819                ifp->if_flags &= ~IFF_OACTIVE;
     820        }
     821}
     822
     823/*----------------------- The receive daemon/task -------------------------- */
     824
     825static void
     826MakeRxBuffer(EMACLocals* ep, int index)
     827{
     828        struct mbuf*    m;
     829       
     830        /* Allocate an mbuf, wait if necessary, label as dynamic data, start of record */
     831        MGETHDR (m, M_WAIT, MT_DATA);
     832        /* Allocate a cluster buffer to this mbuf, waiting if necessary */
     833        MCLGET (m, M_WAIT);
     834        /* Set up reference to the interface the packet will be received on */
     835        m->m_pkthdr.rcvif = &ep->arpcom.ac_if;
     836        ep->rxMBufs[index] = m;
     837        ep->rcvDescTable[index].ptr = mtod (m, uint8_t*);
     838        ep->rcvDescTable[index].adrDataSize = 0x0EEE;           /* Precaution */
     839        if (index==ep->nRxBuffers-1)
     840                ep->rcvDescTable[index].ctrlBits = kMALRxEmpty + kMALInterrupt + kMALWrap;
     841        else
     842                ep->rcvDescTable[index].ctrlBits = kMALRxEmpty + kMALInterrupt;
     843}
     844
     845
     846
     847static void
     848ppc405_emac_rxDaemon (void* param)
     849{
     850        EMACLocals* ep = param;
     851        int             index,n,mdex;
     852        struct mbuf*    m;
     853        struct mbuf*    mstart = NULL;
     854        struct mbuf*    mlast = NULL;
     855        struct ifnet*   ifp;
     856        struct ether_header* eh = NULL;
     857        rtems_event_set events;
     858       
     859        /* Startup : allocate a bunch of receive buffers and point the descriptor table entries at them */
     860        ifp = &ep->arpcom.ac_if;
     861        index = 0;
     862        while (index < ep->nRxBuffers) {
     863                MakeRxBuffer(ep,index);
     864                index += 1;
     865        }
     866        index = 0;
     867        mdex = 0;
     868       
     869        /* Loop waiting for frames to arrive */
     870        while (TRUE) {
     871                rtems_bsdnet_event_receive (INTERRUPT_EVENT,
     872                                                                                        RTEMS_WAIT | RTEMS_EVENT_ANY,
     873                                                                                        RTEMS_NO_TIMEOUT,
     874                                                                                        &events);
     875                while ((ep->rcvDescTable[index].ctrlBits & kMALRxEmpty) == 0) {
     876                        /* Got a frame */
     877                        uint16_t flags = ep->rcvDescTable[index].ctrlBits;
     878                        if ((flags & kEMACErrMask) != 0) {
     879                                /* It has errors. Update statistics */
     880                                if ((flags & kEMACOverrun) != 0)
     881                                        ep->rxOverrun++;
     882                                if ((flags & kEMACRuntPkt) != 0)
     883                                        ep->rxRunt++;
     884                                if ((flags & kEMACBadFCS) != 0)
     885                                        ep->rxBadCRC++;
     886                                if ((flags & kEMACAlignErr) != 0)
     887                                        ep->rxNonOctet++;
     888                                if ((flags & kEMACPktLong) != 0)
     889                                        ep->rxGiant++;
     890                                /* and reset descriptor to empty */
     891                               
     892                                /* No need to get new mbufs, just reset */
     893                                ep->rcvDescTable[index].adrDataSize = 0x0EEE;
     894                                if (index==ep->nRxBuffers-1)
     895                                        ep->rcvDescTable[index].ctrlBits = kMALRxEmpty + kMALInterrupt + kMALWrap;
     896                                else
     897                                        ep->rcvDescTable[index].ctrlBits = kMALRxEmpty + kMALInterrupt;
     898                               
     899                        } else {
     900                                /* Seems to be OK. Invalidate cache over the size we received */
     901                                n = ep->rcvDescTable[index].adrDataSize & 0x0FFF;
     902                                m = ep->rxMBufs[index];
     903                                rtems_cache_invalidate_multiple_data_lines(m->m_data, (n + kCacheLineMask) & ~kCacheLineMask);
     904                               
     905                                /* Consider copying small packets out of the cluster into m_pktdat to save clusters? */
     906                                m->m_len = n;
     907                                       
     908                                /* Jumbo packets will span multiple mbufs; chain them together and submit when we get the last one */
     909                                if (flags & kMALRxFirst) {
     910                                        /* First mbuf in the packet */
     911                                        if (mstart!=NULL)
     912                                                rtems_panic("first, no last");
     913                                       
     914                                        /* Adjust the mbuf pointers to skip the header and set eh to point to it */
     915                                        m->m_len -= sizeof(struct ether_header);
     916                                        m->m_pkthdr.len = m->m_len;
     917                                        eh = mtod (m, struct ether_header *);
     918                                        m->m_data += sizeof(struct ether_header);
     919                                        mstart = m;
     920                                        mlast = m;
     921                                        mdex = index;
     922                                } else {
     923                                        /* Chain onto mstart: add length to pkthdr.len */
     924                                        if (mstart == NULL)
     925                                                rtems_panic("last, no first");
     926                                       
     927                                        mstart->m_pkthdr.len += n;
     928                                        m->m_flags &= ~M_PKTHDR;
     929                                        mlast->m_next = m;
     930                                        mlast = m;
     931                                }
     932                               
     933                                if (flags & kMALLast) {
     934                                        /* Last mbuf in the packet: pass base of the chain to a higher level */
     935                                        ether_input (ifp, eh, mstart);
     936                                       
     937                                        /* ether_input took the chain, set up new mbufs in the slots we used */
     938                                        mdex -= 1;
     939                                        do {
     940                                                if (++mdex==ep->nRxBuffers) mdex = 0;
     941                                                MakeRxBuffer(ep,mdex);
     942                                        } while (mdex != index);
     943                                        mstart = NULL;
     944                                        mlast = NULL;
     945                                        eh = NULL;
     946                                }
     947                        }
     948                        index += 1;
     949                        if (index == ep->nRxBuffers) index = 0;
     950                }
     951        }
     952}
     953
     954/*----------- Vectored routines called through the driver struct ------------------ */
     955
     956static void ppc405_emac_init (void* p)
     957/* Initialise the hardware, create and start the transmit and receive tasks */
     958{
     959        char txName[] = "ETx0";
     960        char rxName[] = "ERx0";
     961       
     962        EMACLocals* ep = (EMACLocals*)p;
     963        if (ep->txDaemonTid == 0) {
     964                ppc405_emac_initialize_hardware(ep);
     965                rxName[3] += ep->phyAddr;
     966                ep->rxDaemonTid = rtems_bsdnet_newproc (rxName, 4096, ppc405_emac_rxDaemon, ep);
     967                txName[3] += ep->phyAddr;
     968                ep->txDaemonTid = rtems_bsdnet_newproc (txName, 4096, ppc405_emac_txDaemon, ep);
     969        }
     970        /* Only set IFF_RUNNING if the PHY is ready. If not set the watchdog timer running so we check it */
     971        if ( GetPHYLinkState(ep) & kELinkUp )
     972                ep->arpcom.ac_if.if_flags |= IFF_RUNNING;
     973        else
     974                ep->arpcom.ac_if.if_timer = 1;
     975}
     976
     977static void ppc405_emac_start(struct ifnet *ifp)
     978/* Send a packet: send an event to the transmit task, waking it up */
     979{
     980        EMACLocals* ep = ifp->if_softc;
     981        rtems_event_send (ep->txDaemonTid, START_TRANSMIT_EVENT);
     982        ifp->if_flags |= IFF_OACTIVE;
     983}
     984
     985static void ppc405_emac_stop (EMACLocals* ep)
     986{
     987        uint32_t mask;
     988       
     989        mask = 0x80000000 >> ep->arpcom.ac_if.if_unit;
     990        PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_TXCARR,mask);
     991        PPC_SET_DEVICE_CONTROL_REGISTER(MAL0_RXCARR,mask);
     992        ppc405_emac_disable(ep);
     993        /* *** delete daemons, or do they exit themselves? */
     994        ep->arpcom.ac_if.if_flags &= ~IFF_RUNNING;
     995}
     996
     997#ifdef qDebug
     998static void ppc405_emac_stats (EMACLocals* ep)
     999{
     1000
     1001        printf ("  Rx Interrupts:%-8lu", ep->rxInterrupts);
     1002        printf ("          Giant:%-8lu", ep->rxGiant);
     1003        printf ("           Runt:%-8lu\n", ep->rxRunt);
     1004        printf ("      Non-octet:%-8lu", ep->rxNonOctet);
     1005        printf ("        Bad CRC:%-8lu", ep->rxBadCRC);
     1006        printf ("        Overrun:%-8lu\n", ep->rxOverrun);
     1007
     1008        printf ("    Tx Interrupts:%-8lu", ep->txInterrupts);
     1009        printf ("    Long deferral:%-8lu", ep->txDeferred);
     1010        printf ("       No Carrier:%-8lu\n", ep->txLostCarrier);
     1011        printf ("   Late collision:%-8lu", ep->txLateCollision);
     1012        printf ("    One collision:%-8lu", ep->txOneCollision);
     1013        printf ("  Many collisions:%-8lu\n", ep->txMultiCollision);
     1014        printf ("Excess collisions:%-8lu", ep->txTooManyCollision);
     1015        printf ("         Underrun:%-8lu", ep->txUnderrun);
     1016        printf ("      Poor signal:%-8lu\n", ep->txPoorSignal);
     1017}
     1018#endif
     1019
     1020static int UpdateMulticast(EMACLocals* ep)
     1021{
     1022        /* Traverse list of multicast addresses and update hardware hash filter. This is just a work-reduction */
     1023        /* step; the filter uses a hash of the hardware address and therefore doesn't catch all unwanted packets */
     1024        /* We have to do other checks in software. */
     1025        /* 405GP/GPr has 4x16-bit hash registers, 405EX/EXr has 8x32-bit */
     1026       
     1027        struct ether_multi* enm;
     1028        struct ether_multistep step;
     1029        uint32_t hash;
     1030       
     1031        #ifdef qMultiDebug
     1032                printf("\nMulticast etheraddrs:\n");
     1033        #endif
     1034       
     1035        ETHER_FIRST_MULTI(step, &ep->arpcom, enm);
     1036        while (enm != NULL) {
     1037               
     1038                /* *** Doesn't implement ranges */
     1039                               
     1040                hash = ether_crc32_be( (uint8_t*)&enm->enm_addrlo, sizeof(enm->enm_addrlo) );
     1041                if (get_ppc_cpu_type() == PPC_405EX) {
     1042                        hash >>= 24;    /* Upper 8 bits, split 3/5 */
     1043                        /* This has been experimentally verified against the hardware */
     1044                        ep->EMAC->e_groupHash[7-(hash>>5)] |= (1 << (hash & 0x1F));
     1045                } else {
     1046                        hash >>= 26;    /* Upper 6 bits, split 2/4 */
     1047                        /* This has not been checked */
     1048                        ep->EMAC->g_groupHash[3-(hash>>6)] |= (1 << (hash & 0xF));
     1049                }
     1050               
     1051                #ifdef qMultiDebug
     1052                        printf("  ");
     1053                        printaddr(enm->enm_addrlo);
     1054                        printf(" = bit %d",hash);
     1055                        if (memcmp(&enm->enm_addrlo, &enm->enm_addrhi, 6) != 0) {
     1056                                printf(" - ");
     1057                                printaddr(enm->enm_addrhi);
     1058                                printf(" [not supported]");
     1059                        }
     1060                        printf("\n");
     1061                #endif
     1062               
     1063                ETHER_NEXT_MULTI(step, enm);
     1064        }
     1065        #ifdef qMultiDebug
     1066        {
     1067                int i;
     1068                printf(" Grouphash is ");
     1069                for (i=0; i<8; i++)
     1070                        printf("%08X:",(int)ep->EMAC->e_groupHash[i]);
     1071                printf("\n");
     1072        }
     1073        #endif
     1074        return 0;
     1075}
     1076
     1077
     1078static int ppc405_emac_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data)
     1079{
     1080        int error = 0;
     1081        EMACLocals* ep = ifp->if_softc;
     1082        struct ifreq* reqP = (struct ifreq *) data;
     1083               
     1084        switch (command) {
     1085       
     1086                case SIOCSIFFLAGS:
     1087                        switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
     1088                                case IFF_RUNNING:
     1089                                        ppc405_emac_stop(ep);
     1090                                        break;
     1091               
     1092                                case IFF_UP:
     1093                                        ppc405_emac_init(ep);
     1094                                        break;
     1095               
     1096                                case IFF_UP | IFF_RUNNING:
     1097                                        ppc405_emac_stop(ep);
     1098                                        ppc405_emac_init(ep);
     1099                                        break;
     1100               
     1101                                default:
     1102                                        break;
     1103                        }
     1104                        break;
     1105       
     1106                case SIOCADDMULTI: {
     1107                                error = ether_addmulti( reqP, &ep->arpcom);
     1108                                if (error==ENETRESET)
     1109                                        error = UpdateMulticast(ep);
     1110                        } break;
     1111                       
     1112                case SIOCDELMULTI:
     1113                        error = ether_delmulti( (struct ifreq *) data, &ep->arpcom);
     1114                        if (error==ENETRESET)
     1115                                error = UpdateMulticast(ep);
     1116                        break;
     1117                       
     1118                case SIOCSIFMTU: {
     1119                                /* Note that this may not do what you want; setting the interface MTU doesn't touch the route MTUs,
     1120                                   and new routes are sometimes made by cloning old ones. So this won't change the MTU to known hosts
     1121                                   and may not change the MTU to new ones either... */
     1122                                int max;
     1123                                if ( get_ppc_cpu_type() == PPC_405EX && (ep->EMAC->mode1 & keEMACJumbo) != 0 )
     1124                                        max = ETHER_MAX_LEN_JUMBO;
     1125                                else
     1126                                        max = ETHER_MAX_LEN;
     1127                                if (reqP->ifr_mtu > max - ETHER_HDR_LEN - ETHER_CRC_LEN)
     1128                                        error = EINVAL;
     1129                                else
     1130                                        ifp->if_mtu = reqP->ifr_mtu;
     1131                        } break;
     1132                       
     1133                case SIO_RTEMS_SHOW_STATS:
     1134                        #ifdef qDebug
     1135                                ppc405_emac_stats(ep);
     1136                        #endif
     1137                        break;
     1138                       
     1139                default:
     1140                        /* Not handled here, pass to generic */
     1141                        error = ether_ioctl(ifp,command,data);
     1142                        break;
     1143        }
     1144       
     1145        #ifdef qDebug
     1146        if (error != 0)
     1147                printf("--- Ethernet ioctl %d failed %d\n",(int)command,error);
     1148        #endif
     1149       
     1150        return error;
     1151}
     1152
     1153       
     1154/*----------------------- External attach function --------------------------
     1155 * 
     1156 * This is the one function we are required to define in here: declared in bsp.h
     1157 * as RTEMS_BSP_NETWORK_DRIVER_ATTACH and called from rtems_bsdnet_attach
     1158 *
     1159*/
     1160
     1161int
     1162rtems_emac_driver_attach(struct rtems_bsdnet_ifconfig* config, int attaching)
     1163{
     1164        int     unitNumber, nUnits;
     1165        char*   unitName;
     1166        struct  ifnet* ifp;
     1167        EMACLocals* ep;
     1168       
     1169        if (attaching==0) {
     1170                printk ("EMAC: driver cannot be detached.\n");
     1171                return 0;
     1172        }
     1173       
     1174        nUnits = 1;
     1175        if (get_ppc_cpu_type()==PPC_405EX && get_ppc_cpu_revision() > 0x1474)
     1176                nUnits = 2;     /* PPC405EX has two interfaces, EXr has one */
     1177       
     1178        unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName);
     1179    if (unitNumber < 0 || unitNumber > nUnits-1) {
     1180                printk ("EMAC: bad unit number %d.\n",unitNumber);
     1181                return 0;
     1182        }
     1183       
     1184        ep = &gEmacs[unitNumber];
     1185       
     1186        if (get_ppc_cpu_type()==PPC_405EX) {
     1187                if (unitNumber==0) ep->EMAC = (EthernetRegisters_EX*)EMAC0EXAddress;
     1188                                          else ep->EMAC = (EthernetRegisters_GP*)EMAC1EXAddress;
     1189        } else
     1190                ep->EMAC = (EthernetRegisters_GP*)EMAC0GPAddress;
     1191               
     1192        ifp = &ep->arpcom.ac_if;
     1193        if (ifp->if_softc != NULL) {
     1194                printk ("EMAC: driver already in use.\n");
     1195                return 0;
     1196        }
     1197        ifp->if_softc = ep;
     1198       
     1199        if (config->hardware_address == 0)
     1200                rtems_panic("No Ethernet MAC address specified!");
     1201        memcpy (ep->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
     1202       
     1203        ifp->if_name = unitName;
     1204        ifp->if_unit = unitNumber;
     1205       
     1206        if (config->mtu != 0)
     1207                ifp->if_mtu = config->mtu;
     1208        else
     1209                ifp->if_mtu = ETHERMTU;         /* May be adjusted later by ppc405_emac_phy_adapt() */
     1210               
     1211        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
     1212        if (ifp->if_snd.ifq_maxlen == 0)
     1213                ifp->if_snd.ifq_maxlen = ifqmaxlen;
     1214        ifp->if_init = &ppc405_emac_init;
     1215        ifp->if_ioctl = ppc405_emac_ioctl;
     1216        ifp->if_start = ppc405_emac_start;
     1217        ifp->if_output = ether_output;
     1218        ifp->if_watchdog = ppc405_emac_watchdog;
     1219        ifp->if_timer    = 0;
     1220       
     1221        if (config->rbuf_count != 0) {
     1222                if (config->rbuf_count > 256) ep->nRxBuffers = 256;
     1223                                                                 else ep->nRxBuffers = config->rbuf_count;
     1224        } else
     1225                ep->nRxBuffers = nmbclusters/2;
     1226               
     1227        ep->phyAddr = unitNumber+1;
     1228        ep->phyState = 0;
     1229       
     1230        #ifdef qDebug
     1231                printf("\n  Setting up EMAC %d of %d\n",unitNumber+1,nUnits);
     1232                printf("  MAC address is ");
     1233                printaddr(ep->arpcom.ac_enaddr);
     1234                printf("  MHLEN = %d, MINCLSIZE = %d MCLBYTES = %d\n",MHLEN,MINCLSIZE,MCLBYTES);
     1235                printf("  ticks/sec = %d, usec/tick = %d\n", rtems_bsdnet_ticks_per_second, rtems_bsdnet_microseconds_per_tick);
     1236        #endif
     1237       
     1238        if_attach (ifp);
     1239        ether_ifattach (ifp);
     1240
     1241        return 1;
     1242}
     1243