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