bootloader: bumped the version to 2.1
[nios2ecos.git] / eth_ocm / HAL / src / ins_eth_ocm.c
blob1d555f3cbd5326f02afa70bca8a0e20182a0317a
1 #ifdef ALT_INICHE
3 #include "ins_eth_ocm.h"
5 /**
6 * Function for obtaining MAC address. Located externally in application code.
8 * @param net NET interface (Interniche typedef)
9 * @param mac_addr Character array into which MAC address should be written.
11 * @return zero on success, nonzero otherwise.
12 */
13 extern int get_mac_addr(NET net, unsigned char mac_addr[6]);
15 /**
16 * Performs PHY initialization and determines link duplex.
17 * This is fully vendor specific depending on the PHY you are using.
19 * @param dev Pointer to eth_ocm_dev struct which contains needed base address
20 * @return 1 if Link is established in Full duplex.
21 * 0 if Link is established in Half duplex.
23 extern int eth_ocm_phy_init(eth_ocm_dev *dev);
25 static void eth_ocm_isr(void *context, alt_u32 id);
26 static int eth_ocm_read_init(eth_ocm_dev *dev);
27 #ifndef ETH_OCM_SYNC_TX
28 static int eth_ocm_pkt_send(PACKET pkt);
29 static int eth_ocm_low_send(NET net, char *data, unsigned data_bytes);
30 static void eth_ocm_tx_isr(eth_ocm_dev *dev);
31 #else
32 static int eth_ocm_raw_send(NET net, char *data, unsigned data_bytes);
33 #endif // else ifndef ETH_OCM_SYNC_TX
34 static int eth_ocm_rx_isr(eth_ocm_dev *dev);
36 /**
37 * Prepare ethernet MAC.
39 * @param ins_dev Pointer to associated alt_iniche_dev struct
40 * @return
42 error_t eth_ocm_prep(alt_iniche_dev *ins_dev){
43 NET ifp;
44 int index;
45 eth_ocm_dev *dev;
47 index = ins_dev->if_num;
48 dev = (eth_ocm_dev *)ins_dev;
50 #if (ETH_OCM_DBG_LVL >= 1)
51 //Status message
52 dprintf("eth_ocm_prep\n");
53 #endif // if ETH_OCM_DBG_LVL
55 //create eth_ocm_info struct
56 dev->info = (eth_ocm_info *)malloc(sizeof(eth_ocm_info));
57 dev->info->sem = 0; //initialize semaphore
58 dev->info->rx_pkts = (PACKET *)(malloc(sizeof(PACKET) * ETH_OCM_RX_DESC_COUNT));
61 ifp = nets[index];
62 ifp->n_mib->ifAdminStatus = ETH_OCM_STATUS_DOWN;
63 ifp->n_mib->ifOperStatus = ETH_OCM_STATUS_DOWN;
64 ifp->n_mib->ifLastChange = cticks * (100/TPS); //timestamp
65 ifp->n_mib->ifPhysAddress = (u_char*)dev->info->mac_addr;
66 ifp->n_mib->ifDescr = (u_char*)"Opencores 10/100 ethernet MAC";
67 ifp->n_lnh = ETHHDR_SIZE; /* ethernet header size. */
68 ifp->n_hal = ETH_OCM_MAC_ADDR_LEN; /* MAC address length */
69 ifp->n_mib->ifType = ETHERNET; /* device type */
70 ifp->n_mtu = ETH_OCM_MAX_MTU; /* max frame size */
72 /* install our hardware driver routines */
73 ifp->n_init = eth_ocm_init;
74 #ifndef ETH_OCM_SYNC_TX
75 ifp->pkt_send = eth_ocm_pkt_send;
76 ifp->raw_send = NULL;
77 #else
78 ifp->pkt_send = NULL;
79 ifp->raw_send = eth_ocm_raw_send;
80 #endif // ifndef ETH_OCM_SYNC_TX
81 ifp->n_close = eth_ocm_close;
82 ifp->n_stats = eth_ocm_stats;
84 #ifdef IP_V6
85 ifp->n_flags |= (NF_NBPROT | NF_IPV6);
86 #else
87 ifp->n_flags |= NF_NBPROT;
88 #endif
90 /* set cross-pointers between iface and eth_ocm structs */
91 dev->info->netp = ifp;
92 ifp->n_local = (void*)(dev);
94 /* get the MAC address. */
95 get_mac_addr(ifp, dev->info->mac_addr);
97 index++;
98 return index;
100 //End of function eth_ocm_prep
103 * Initializes the Opencores ethernet MAC. Called by InterNiche stack
105 * @param
107 int eth_ocm_init(int iface){
108 int status = SUCCESS;
109 int duplex;
110 int temp;
111 NET ifp;
112 eth_ocm_dev *dev;
113 eth_ocm_info *info;
114 eth_ocm_regs *regs;
116 #if (ETH_OCM_DBG_LVL >= 1)
117 dprintf("[eth_ocm_init]\n");
118 #endif
119 //get the ifp first
120 ifp = nets[iface];
121 //now get the info pointer
122 dev = (eth_ocm_dev *)ifp->n_local;
123 info = dev->info;
124 regs = dev->regs;
126 //Reset Descriptors (supposedly this can be done while in reset)
127 for(temp=ETH_OCM_DESC_START;temp<ETH_OCM_DESC_END;temp++)
128 IOWR(dev->base, temp, 0);
130 //Let's disable the MAC until everything else is set up
131 regs->moder = 0;
133 //Determine the number of RX descriptors
134 regs->tx_bd_num = ETH_OCM_TX_DESC_COUNT; //Set TX descriptor count in MAC
135 info->cur_tx_desc = 0;
136 info->cur_rx_desc = 0;
137 #ifndef ETH_OCM_SYNC_TX
138 info->next_tx_desc = 0;
139 info->next_tx_desc_rdy = 1;
140 //Initialize queues
141 dev->info->tosend.q_head = dev->info->tosend.q_tail = NULL;
142 dev->info->tosend.q_max = dev->info->tosend.q_min = dev->info->tosend.q_len = 0;
143 dev->info->sending.q_head = dev->info->sending.q_tail = NULL;
144 dev->info->sending.q_max = dev->info->sending.q_min = dev->info->sending.q_len = 0;
145 #endif
147 /* perform any necessary PHY setup */
148 //Let's set the MDIO interface up to run at 4MHz.
149 temp = (ALT_CPU_FREQ / 1000000);
150 temp += 2;
151 temp &= 0xFFFFFFFE; //only even numbers allowed)
152 regs->miimoder = temp;
153 regs->miicommand = 0;
154 //Find out if we should run in duplex or not
155 duplex = eth_ocm_phy_init(dev);
157 if(duplex)
158 duplex = ETH_OCM_MODER_FULLD_MSK;
160 // Configure MAC options
161 // Interrupt sources
162 regs->int_mask = ETH_OCM_DEFAULT_INTERRUPT_MASK; //Interrupt on receive
163 // Clear any existing interrupts
164 regs->int_source = 0xFFFFFFFF;
166 // Inter-packet gap
167 if(duplex)
168 regs->ipgt = ETH_OCM_FULL_DUPLEX_IPGT;
169 else
170 regs->ipgt = ETH_OCM_HALF_DUPLEX_IPGT;
172 //Let's set the defaults just because they've bitten us before
173 regs->ipgr2 = 0x0000000C;
174 regs->ipgr2 = 0x00000012;
175 regs->packetlen = 0x00400600; //Min and Max frame sizes
176 regs->collconf = 0x000F003F;
177 regs->ctrlmoder = 0x00000000;
179 #if (ETH_OCM_DBG_LVL >= 1)
180 dprintf("[eth_ocm_init] Configuring MAC address "
181 "%02x:%02x:%02x:%02x:%02x:%02x\n",
182 info->mac_addr[0],info->mac_addr[1],info->mac_addr[2],
183 info->mac_addr[3],info->mac_addr[4],info->mac_addr[5]);
184 #endif // if ETH_OCM_DBG_LVL
185 //Configure the MAC address
186 regs->mac_addr0 =
187 ( ((int)info->mac_addr[5]) |
188 (((int)info->mac_addr[4]) << 8) |
189 (((int)info->mac_addr[3]) << 16) |
190 (((int)info->mac_addr[2]) << 24) );
192 regs->mac_addr1 =
193 ( ((int)((unsigned char)info->mac_addr[1])) |
194 (((int)((unsigned char)info->mac_addr[0])) << 8) );
197 //Enable MAC
198 regs->moder = (
199 ETH_OCM_MODER_PAD_MSK | //Enable padding of small packets
200 ETH_OCM_MODER_CRCEN_MSK | //Append CRC to TX packets
201 ETH_OCM_MODER_RXEN_MSK | //Enable receive
202 ETH_OCM_MODER_TXEN_MSK | //Enable transmit
203 duplex //Discovered duplex
206 #if (ETH_OCM_DBG_LVL >= 1)
207 dprintf("\nOpencores MAC post-init: MODER = 0x%08x\n", (int)regs->moder);
208 #endif // if ETH_OCM_DBG
210 /* status = UP */
211 nets[iface]->n_mib->ifAdminStatus = ETH_OCM_STATUS_UP;
212 nets[iface]->n_mib->ifOperStatus = ETH_OCM_STATUS_UP;
214 //register ISR interrupt handler
215 temp = alt_irq_register(dev->irq, dev, eth_ocm_isr);
216 if(temp)
217 dprintf("[eth_ocm_init] Failed to register RX ISR\n");
218 //Setup the first read transfer
219 eth_ocm_read_init(dev);
221 return status; //MAC is ready to rock and roll
223 //End of eth_ocm_init function
226 #ifndef ETH_OCM_SYNC_TX
227 int eth_ocm_pkt_send(PACKET pkt){
228 eth_ocm_dev *dev;
229 eth_ocm_info *info;
230 eth_ocm_regs *regs;
231 int result;
232 #ifdef UCOS_II
233 int cpu_sr;
234 #endif
236 dev = (eth_ocm_dev *)pkt->net->n_local;
237 info = dev->info;
238 regs = dev->regs;
239 result = SUCCESS;
241 OS_ENTER_CRITICAL(); //disable interrupts
243 putq(&info->tosend, (qp)pkt);
244 eth_ocm_tx_isr(dev);
246 //If there is an available descriptor, and it's not busy
247 if(info->next_tx_desc_rdy && (info->sending.q_len < ETH_OCM_TX_DESC_COUNT)){//!(regs->txdescs[info->next_tx_desc].ctrl & ETH_OCM_TXDESC_READY_MSK)){
248 result = eth_ocm_low_send(pkt->net, pkt->nb_prot, pkt->nb_plen);
249 //If setup failed, free the packet and move on.
250 if(result != SUCCESS){
251 pkt->net->n_mib->ifOutDiscards++; //increment TX discard counter
252 pk_free(pkt);
253 return result;
255 else{ //Transfer was successfully setup
256 info->next_tx_desc++;
257 if(info->next_tx_desc == ETH_OCM_TX_DESC_COUNT)
258 info->next_tx_desc = 0;
259 //See if all descriptor are in use
260 if(info->next_tx_desc == info->cur_tx_desc)
261 info->next_tx_desc_rdy = 0;
262 //Put the packet in the sending queue
263 putq(&info->sending, (qp)pkt);
266 else{ //Unable to send packet right now so queue it
267 putq(&info->tosend, (qp)pkt);
271 OS_EXIT_CRITICAL(); //reenable interrupts
272 return SUCCESS;
275 /** This is the asynchronous raw send function. It sets up a transfer
276 * but does not wait for it to conclude. It sets the MAC to interrupt
277 * when the transfer has finished. This is not threadsafe.
279 * @param NET
280 * @param data
281 * @param data_bytes
283 * @return 0 if Successful, negative otherwise
285 int eth_ocm_low_send(NET net, char *data, unsigned data_bytes){
286 int result;
287 unsigned len;
288 eth_ocm_dev *dev;
289 eth_ocm_info *info;
290 eth_ocm_regs *regs;
291 alt_u8 *buf;
293 dev = (eth_ocm_dev *)net->n_local;
294 info = dev->info;
295 regs = dev->regs;
296 len = data_bytes - ETHHDR_BIAS;
297 result = SUCCESS;
299 //Check to see if someone is nesting send calls (BAD!)
300 if(info->sem){
301 dprintf("[eth_ocm_low_send] ERROR: Nested low send call\n");
302 return ENP_RESOURCE;
304 //Grab the semaphore
305 info->sem = 1;
306 // clear bit-31 before passing it to SGDMA Driver
307 buf = (alt_u8 *)alt_remap_cached( (volatile void *)data, 4);
308 //advance the pointer beyond the header bias
309 buf = (alt_u8 *)((unsigned int)buf + ETHHDR_BIAS);
311 //Some error checks first
312 if(len < ETH_OCM_MIN_MTU)
313 result = -1; //packet too small
314 if(len > ETH_OCM_MAX_MTU)
315 result = -EFBIG; //packet too big
316 if(regs->txdescs[info->next_tx_desc].ctrl & ETH_OCM_TXDESC_READY_MSK)
317 result = -EBUSY; //DMA not available
319 if(result == SUCCESS){
320 //Write pointer to descriptor
321 regs->txdescs[info->next_tx_desc].ptr = (unsigned int)buf;
322 //Write length and setup transfer
323 result = ((len << ETH_OCM_TXDESC_LEN_OFST) |
324 ETH_OCM_TXDESC_READY_MSK |
325 ETH_OCM_TXDESC_IRQ_MSK |
326 ETH_OCM_TXDESC_PAD_MSK |
327 ETH_OCM_TXDESC_CRC_MSK);
328 //See if wrap flag should be set
329 if(info->next_tx_desc == (ETH_OCM_TX_DESC_COUNT - 1))
330 result |= ETH_OCM_TXDESC_WRAP_MSK;
331 //Write descriptor
332 regs->txdescs[info->next_tx_desc].ctrl = result;
333 result = SUCCESS;
336 info->sem = 0;
337 return result;
340 void eth_ocm_tx_isr(eth_ocm_dev *dev){
341 eth_ocm_info *info;
342 eth_ocm_regs *regs;
343 int result;
344 PACKET pkt;
346 info = dev->info;
347 regs = dev->regs;
349 //First we need to process all finished descriptors
350 while( info->sending.q_len>0
351 && ((info->cur_tx_desc != info->next_tx_desc) || !info->next_tx_desc_rdy)
352 && !(regs->txdescs[info->cur_tx_desc].ctrl & ETH_OCM_TXDESC_READY_MSK)){
354 //Get the packet
355 pkt = (PACKET)getq(&info->sending);
357 //Get transmit result from descriptor
358 result = regs->txdescs[info->cur_tx_desc].ctrl;
360 //Check for errors
361 if(result &
362 (ETH_OCM_TXDESC_UR_MSK |
363 ETH_OCM_TXDESC_RL_MSK |
364 ETH_OCM_TXDESC_LC_MSK |
365 ETH_OCM_TXDESC_CS_MSK)){
366 #if (ETH_OCM_DBG_LVL >= 2)
367 dprintf("[eth_ocm_tx_isr] Transmit error 0x%x\n", result);
368 #endif // if ETH_OCM_DBG_LVL
369 pkt->net->n_mib->ifOutDiscards++; //increment TX discard counter
371 else{
372 #if (ETH_OCM_DBG_LVL >= 5)
373 if(result & ETH_OCM_TXDESC_RTRY_MSK)
374 dprintf("[eth_ocm_tx_isr] Transmit retries: %d\n", (result & ETH_OCM_TXDESC_RTRY_MSK)>>ETH_OCM_TXDESC_RTRY_OFST);
375 #endif
376 pkt->net->n_mib->ifOutOctets += pkt->nb_plen;
377 pkt->net->n_mib->ifOutUcastPkts++;
378 result = 0;
381 //free the packet
382 pk_free(pkt);
384 //Increment the current descriptor pointer
385 info->cur_tx_desc++;
386 if(info->cur_tx_desc == ETH_OCM_TX_DESC_COUNT)
387 info->cur_tx_desc = 0;
388 //Whatever the next descriptor is it's ready now
389 info->next_tx_desc_rdy = 1;
392 //Now we can send any queued packets
393 while( info->next_tx_desc_rdy
394 && info->tosend.q_len>0
395 && !(regs->txdescs[info->next_tx_desc].ctrl & ETH_OCM_TXDESC_READY_MSK) ){
397 //Get the packet to be send
398 pkt = (PACKET)getq(&info->tosend);
400 result = eth_ocm_low_send(pkt->net, pkt->nb_prot, pkt->nb_plen);
401 //If setup failed, free the packet and move on.
402 if(result != SUCCESS){
403 pkt->net->n_mib->ifOutDiscards++;
404 pk_free(pkt);
406 else{ //Transfer was successfully setup
407 info->next_tx_desc++;
408 if(info->next_tx_desc == ETH_OCM_TX_DESC_COUNT)
409 info->next_tx_desc = 0;
410 //See if all descriptor are in use
411 if(info->next_tx_desc == info->cur_tx_desc)
412 info->next_tx_desc_rdy = 0;
413 //Put the packet in the sending queue
414 putq(&info->sending, (qp)pkt);
419 #endif // ifndef ETH_OCM_SYNC_TX
422 #ifdef ETH_OCM_SYNC_TX
424 * Raw send function to initiate a transfer to the mac
426 * @param net - NET structure associated with the Opencores MAC instance
427 * @param data - pointer to the data payload
429 * @return SUCCESS if success, else a negative value
431 int eth_ocm_raw_send(NET net, char * data, unsigned data_bytes){
432 int result;
433 int i;
434 unsigned len;
435 eth_ocm_dev *dev;
436 eth_ocm_info *info;
437 eth_ocm_regs *regs;
438 alt_u8 *buf;
439 #ifdef UCOS_II
440 int cpu_sr;
441 #endif
443 OS_ENTER_CRITICAL(); //disable interrupts
445 dev = (eth_ocm_dev *)net->n_local;
446 info = dev->info;
447 regs = dev->regs;
448 len = data_bytes - ETHHDR_BIAS;
449 result = 0;
451 //Check to see if someone is nesting send calls (BAD!)
452 if(info->sem){
453 dprintf("[eth_ocm_raw_send] ERROR: Nested raw send call\n");
454 OS_EXIT_CRITICAL();
455 return ENP_RESOURCE;
458 //Grab the semaphore
459 info->sem = 1;
460 // clear bit-31 before passing it to SGDMA Driver
461 buf = (alt_u8 *)alt_remap_cached( (volatile void *)data, 4);
462 //advance the pointer beyond the header bias
463 buf = (alt_u8 *)((unsigned int)buf + ETHHDR_BIAS);
465 //Some error checks first
466 if(len < ETH_OCM_MIN_MTU)
467 result = -1; //packet too small
468 if(len > ETH_OCM_MAX_MTU)
469 result = -EFBIG; //packet too big
470 if(regs->txdescs[0].ctrl & ETH_OCM_TXDESC_READY_MSK)
471 result = -EBUSY; //DMA not available
473 if(!result){
474 //Write pointer to descriptor
475 regs->txdescs[0].ptr = (unsigned int)buf;
476 //Write length and setup transfer
477 regs->txdescs[0].ctrl =
478 ((len << ETH_OCM_TXDESC_LEN_OFST) |
479 ETH_OCM_TXDESC_READY_MSK |
480 ETH_OCM_TXDESC_WRAP_MSK |
481 ETH_OCM_TXDESC_PAD_MSK |
482 ETH_OCM_TXDESC_CRC_MSK);
483 //Wait for transfer to complete
484 i=0;
486 result = regs->txdescs[0].ctrl;
487 i++;
488 }while((result & ETH_OCM_TXDESC_READY_MSK) && i<ETH_OCM_TRANSMIT_TIMEOUT);
489 //Make sure no timeout occurred
490 if(i<ETH_OCM_TRANSMIT_TIMEOUT){
491 if(result &
492 (ETH_OCM_TXDESC_UR_MSK |
493 ETH_OCM_TXDESC_RL_MSK |
494 ETH_OCM_TXDESC_LC_MSK |
495 ETH_OCM_TXDESC_CS_MSK)){
496 #if (ETH_OCM_DBG_LVL >= 2)
497 dprintf("[eth_ocm_raw_send] Transmit error 0x%x\n", result);
498 #endif // if ETH_OCM_DBG_LVL
499 result = -EIO; //Some error occured
501 else{
502 #if (ETH_OCM_DBG_LVL >= 5)
503 if(result & ETH_OCM_TXDESC_RTRY_MSK)
504 dprintf("[eth_ocm_raw_send] Transmit retries: %d\n", (result & ETH_OCM_TXDESC_RTRY_MSK)>>ETH_OCM_TXDESC_RTRY_OFST);
505 #endif
506 result = 0;
509 else{ //Timeout
510 result = -ETIMEDOUT;
512 } //End of if(!result) Transmit branch
514 //Check final result
515 if(!result){ //Successfull transfer
516 net->n_mib->ifOutOctets += data_bytes; //Increment TX data counter
517 // we dont know whether it was unicast or not, we count both in <ifOutUcastPkts>
518 net->n_mib->ifOutUcastPkts++;
519 result = SUCCESS;
521 else{ //Failed transfer
522 #if (ETH_OCM_DBG_LVL >= 2)
523 dprintf("[eth_ocm_raw_send] Transmit failed, "
524 "ret=%u, len=%d\n",
525 result,
526 len);
527 #endif // if ETH_OCM_DBG_LVL
528 net->n_mib->ifOutDiscards++; //increment TX discard counter
529 result = SEND_DROPPED; // ENP_RESOURCE and SEND_DROPPED have the same value!
532 info->sem = 0; //release semaphore
533 OS_EXIT_CRITICAL(); //reenable interrupts
534 return result; //success
536 //End of function eth_ocm_raw_send
537 #endif // ifdef ETH_OCM_SYNC_TX
541 * Receive ISR (interrupt service routine)
543 * @param context - context of the Opencores MAC instance
544 * @param id - IRQ number
546 void eth_ocm_isr(void *context, alt_u32 id){
547 eth_ocm_dev *dev;
548 eth_ocm_regs *regs;
549 int result;
551 dev = (eth_ocm_dev *)context;
552 regs = dev->regs;
554 //Read the interrupt source
555 result = regs->int_source;
556 while(result){
557 //Clear interrupt flags immediately. Only clear the ones that
558 //have been set. We do this in case another one has occured since
559 //we read it.
560 regs->int_source = result; //clear interrupts
562 //Check for receive flags
563 if(result & (ETH_OCM_INT_MASK_RXB_MSK | ETH_OCM_INT_MASK_RXE_MSK)){
564 //Call the receive function. This will set up a new transfer
565 eth_ocm_rx_isr(dev);
566 //Check to see if there is something in the stack's received queue
567 if ((rcvdq.q_len) > 0){
568 SignalPktDemux();
572 //Check for busy flag
573 if(result & ETH_OCM_INT_MASK_BUSY_MSK){
574 #if (ETH_OCM_DBG_LVL >= 3)
575 dprintf("Frame dropped: too busy to receive\n");
576 #endif
577 dev->info->netp->n_mib->ifInDiscards++;
580 #ifndef ETH_OCM_SYNC_TX
581 //Check for transmit flags
582 if(result & (ETH_OCM_INT_MASK_TXE_MSK | ETH_OCM_INT_MASK_TXB_MSK)){
583 eth_ocm_tx_isr(dev);
585 #endif //ifndef ETH_OCM_SYNC_TX
588 //See if any interrupts have been set
589 result = regs->int_source;
595 * Set up the first receive transfer
597 static int eth_ocm_read_init(eth_ocm_dev *dev){
598 eth_ocm_info *info;
599 eth_ocm_regs *regs;
600 alt_u8 *buf_ptr;
601 PACKET *pkts;
602 alt_u32 temp;
603 int i;
605 info = dev->info;
606 regs = dev->regs;
607 pkts = info->rx_pkts;
610 //allocate a packet for every descriptor
611 for(i=0;i<ETH_OCM_RX_DESC_COUNT;i++){
612 pkts[i] = pk_alloc(ETH_OCM_BUF_ALLOC_SIZE);
613 if (!pkts[i]){ // couldn't get a free buffer for rx
614 dprintf("[eth_ocm_read_init] Fatal error: Unable to allocte ETH_OCM_RX_DESC_COUNT buffers\n");
615 return ENP_NOBUFFER;
618 // ensure bit-31 of pkt_array[i]->nb_buff is clear before passing
619 buf_ptr = (alt_u8*)alt_remap_cached ((volatile void*) pkts[i]->nb_buff, 4);
620 //shift the actual write location over by ETHHDR_BIAS (see ipport.h)
621 buf_ptr = (alt_u8*)(((unsigned int)buf_ptr) + ETHHDR_BIAS);
623 if(!(regs->rxdescs[i].ctrl & ETH_OCM_RXDESC_EMPTY_MSK)){
624 //Write pointer
625 regs->rxdescs[i].ptr = (alt_u32)buf_ptr;
626 //Write the control register to start the transfer
627 temp = ETH_OCM_RXDESC_EMPTY_MSK | ETH_OCM_RXDESC_IRQ_MSK;
628 if(i == (ETH_OCM_RX_DESC_COUNT - 1))
629 temp |= ETH_OCM_RXDESC_WRAP_MSK;
630 regs->rxdescs[i].ctrl = temp;
632 else{
633 dprintf("[eth_ocm_read_init] Fatal error: RX descriptor unavailable.\n");
634 dprintf("[eth_ocm_read_init] Descriptor %u = 0x%08x\n", i, (int)regs->rxdescs[i].ctrl);
635 return ENP_RESOURCE;
639 return SUCCESS;
641 //End of function eth_ocm_read_init
645 * Receive operation. Checks the status of the received frame.
646 * Attempt to obtain a new buffer from the InterNiche stack.
647 * Schedules another RX transfer
649 * @return SUCCESS on success
651 static int eth_ocm_rx_isr(eth_ocm_dev *dev)
653 eth_ocm_info *info;
654 eth_ocm_regs *regs;
655 struct ethhdr *eth;
656 int pklen;
657 alt_u32 stat;
658 alt_u8 cur;
659 PACKET pkt;
660 PACKET *pkts;
661 alt_u8 *buf_ptr;
663 info = dev->info;
664 regs = dev->regs;
665 pkts = info->rx_pkts;
666 cur = info->cur_rx_desc;
668 stat = regs->rxdescs[cur].ctrl;
670 //We'll process as many descriptors as are ready
671 while(!(stat & ETH_OCM_RXDESC_EMPTY_MSK)){
672 pklen = stat & ETH_OCM_RXDESC_LEN_MSK;
673 pklen = pklen >> ETH_OCM_RXDESC_LEN_OFST;
675 //Increment received byte count
676 info->netp->n_mib->ifInOctets += (u_long)pklen;
678 pkts[cur]->nb_prot = pkts[cur]->nb_buff + ETHHDR_SIZE;
679 pkts[cur]->nb_plen = pklen - (14 + 4); //Packet length minus (header + CRC)
680 pkts[cur]->nb_tstamp = cticks;
681 pkts[cur]->net = info->netp;
683 // set packet type for demux routine
684 eth = (struct ethhdr *)(pkts[cur]->nb_buff + ETHHDR_BIAS);
685 pkts[cur]->type = eth->e_type;
687 if (!(stat & ETH_OCM_RXDESC_ERROR_MSK)){
688 pkt = pk_alloc(ETH_OCM_BUF_ALLOC_SIZE);
689 if (!pkt){ // couldn't get a free buffer for rx
690 #if (ETH_OCM_DBG_LVL >= 4)
691 dprintf("[eth_ocm_rx_isr] No free RX buffers (Swamping the NicheStack)\n");
692 #endif // if ETH_OCM_DBG_LVL
693 info->netp->n_mib->ifInDiscards++;
695 else{
696 putq(&rcvdq, pkts[cur]);
697 pkts[cur] = pkt;
700 else{
701 #if (ETH_OCM_DBG_LVL >= 3)
702 dprintf("[eth_ocm_rx_isr] Frame discarded due to errors: 0x%08x!\n", (unsigned)stat);
703 #endif // if ETH_OCM_DBG_LVL
704 info->netp->n_mib->ifInDiscards++;
707 // ensure bit-31 of pkt_array[]->nb_buff is clear before passing
708 // to DMA Driver
709 buf_ptr = (alt_u8*)alt_remap_cached ((volatile void*) pkts[cur]->nb_buff, 4);
710 //shift the actual write location over by ETHHDR_BIAS (see ipport.h)
711 buf_ptr = (alt_u8*)((unsigned int)buf_ptr + ETHHDR_BIAS);
713 //Write pointer
714 regs->rxdescs[cur].ptr = (unsigned int)buf_ptr;
715 //Write the control register to start the transfer
716 stat = ETH_OCM_RXDESC_EMPTY_MSK | ETH_OCM_RXDESC_IRQ_MSK;
717 if(cur == (ETH_OCM_RX_DESC_COUNT - 1))
718 stat |= ETH_OCM_RXDESC_WRAP_MSK;
719 regs->rxdescs[cur].ctrl = stat;
721 //increment current descriptor counter
722 cur++;
723 if(cur == ETH_OCM_RX_DESC_COUNT)
724 cur = 0;
725 //get new descriptors status
726 stat = regs->rxdescs[cur].ctrl;
728 info->cur_rx_desc = cur;
730 return SUCCESS;
733 void eth_ocm_stats(void *pio, int iface) {
734 NET ifp;
735 eth_ocm_dev *dev;
736 eth_ocm_regs *regs;
737 int i;
739 //get the ifp first
740 ifp = nets[iface];
741 dev = (eth_ocm_dev *)ifp->n_local;
742 regs = dev->regs;
744 #ifndef ETH_OCM_SYNC_TX
745 ns_printf(pio, "ToSend queue: max:%d, current:%d\n",
746 dev->info->tosend.q_max,
747 dev->info->tosend.q_len);
749 ns_printf(pio, "Sendng queue: max:%d, current:%d\n",
750 dev->info->sending.q_max,
751 dev->info->sending.q_len);
752 #endif //ifndef ETH_OCM_SYNC_TX
754 ns_printf(pio, "TX Descriptor status:\n");
755 for(i=0;i<ETH_OCM_TX_DESC_COUNT;i++){
756 ns_printf(pio," %3d: 0x%08x\n", i, regs->txdescs[i].ctrl);
759 ns_printf(pio, "RX Descriptor status:\n");
760 for(i=0;i<ETH_OCM_RX_DESC_COUNT;i++){
761 ns_printf(pio," %3d: 0x%08x\n", i, regs->rxdescs[i].ctrl);
768 * Closes the opencores mac interface
770 * @param iface index of the NET interface associated with the Opencores MAC.
771 * @return SUCCESS
773 int eth_ocm_close(int iface)
775 int err;
776 NET ifp;
777 eth_ocm_dev *dev;
779 /* status = down */
780 ifp = nets[iface];
781 dev = (eth_ocm_dev *)ifp->n_local;
783 ifp->n_mib->ifAdminStatus = ETH_OCM_STATUS_DOWN;
785 /* disable the interrupt in the OS*/
786 err = alt_irq_register (dev->irq, 0, NULL);
787 if (err){
788 dprintf("[eth_ocm_close] Could not unregister interrupt, error = %d\n",err);
789 return err;
792 // Shut down the MAC
793 IOWR_ETH_OCM_MODER(dev->base, 0);
795 /* status = down */
796 ifp->n_mib->ifOperStatus = ETH_OCM_STATUS_DOWN;
797 //deallocate memory for the eth_ocm_info struct allocated in eth_ocm_prep
798 free(dev->info->rx_pkts);
799 free(dev->info);
801 return SUCCESS;
804 #endif // ifdef ALT_INICHE
805 //End of file ins_eth_ocm.h