📄 enetlib.c
字号:
rtn = ( in16(ENET_IO_ADDR + MII_REG) & MII_MDI ) >> 1; nsdelay(200); out16(ENET_IO_ADDR + MII_REG, MII_MGMTval); nsdelay(200); wData |= ( rtn << i ); } out16(ENET_IO_ADDR + MII_REG, MII_MGMTval); out16(ENET_IO_ADDR + MII_REG, MII_MGMTval | MII_MCLK | MII_MDOE | MII_MDO ); nsdelay(200); out16(ENET_IO_ADDR + MII_REG, MII_MGMTval); nsdelay(200); nsdelay(1000*1000); // delay 1ms#ifdef DEBUG_MSG_PHYREAD s1printf("phy_readreg: phyaddr=%x phyreg=%x phydata=%x\n", PHYAddr, RegAdd, wData);#endif return (wData);}// YYDstatic int enet_alloc_page(int length){ unsigned int numPages, mask; int timeout; // s1printf("Alloc page\n"); // calcualte num pages (256) bytes required length = ENET_MINPACKET < length ? length : ENET_MINPACKET; numPages = ((length & 0xfffffffe) + 6); numPages >>= 8; // Divide by 256, the actual page is numPages+1 if(numPages > ENET_MAX_MTU/256) { s1printf("SMC91111 Error: alloc_page: Packet size %d too big!\n", length); return -1; } /* now, try to allocate the memory */ out16( ENET_IO_ADDR + BANK_SELECT, 0x02 ); out16( ENET_IO_ADDR + MMU_CMD_REG, MC_ALLOC | numPages ); // enable the ALLOC int mask = in16( ENET_IO_ADDR + INT_REG)&0xff00; timeout = ALLOC_TIMEOUT; while(!(in16( ENET_IO_ADDR + INT_REG) & IM_ALLOC_INT) && timeout > 0) { timeout--; nsdelay(1000*1000); } if(in16( ENET_IO_ADDR + INT_REG) & IM_ALLOC_INT) { // ack the int signal out16( ENET_IO_ADDR + INT_REG, mask | IM_ALLOC_INT); } else { s1printf("SMC91111 Error: alloc_page: Failed to alloc page!\n", length); return -1; } return 0;}/*-----------------------------------------------------------------------------+| EnetSend.+-----------------------------------------------------------------------------*/int enetSend(char *p, int len, int *parmp){ struct enet_frame *e_frame=(struct enet_frame *)outframe; struct arp_frame *a_frame; unsigned char *datap=e_frame->enet_data; unsigned long msr; struct ip *ip_ptr=(struct ip *)p; unsigned long target_address=ip_ptr->ip_dst.s_addr; unsigned long fake_length;#ifdef DEBUG_MSG_ENETSEND s1printf("%s: ENETSEND: Entered....\n", dev.name);#endif /*--------------------------------------------------------------------------+ | Disable interrupts. +--------------------------------------------------------------------------*/ msr=ppcAndMsr(~ppcMsrEE); if (outframe_len!=0) { (void)s1printf("%s: ENETSEND: hold frame collision, outbound frame.\n",dev.name); outframe_len=0; } e_frame->type=ENET_IPTYPE; out16( ENET_IO_ADDR + BANK_SELECT, 0x02 ); if(!(in16( ENET_IO_ADDR + INT_REG) & IM_ALLOC_INT)) { if(enet_alloc_page(len)) { return -1; } } /*--------------------------------------------------------------------------+ | Destination is a broadcast address. +--------------------------------------------------------------------------*/ if (target_address==0xFFFFFFFF) { (void)memset(e_frame->dest_addr, 0xFF, ENET_ADDR_LENGTH); } else { if (enetarp_resolve(target_address, (char *)e_frame->dest_addr)==0) { unsigned char outbarp[ENET_MINPACKET]; /*--------------------------------------------------------------------+ | Build arp packet and send it instead of data packet. +--------------------------------------------------------------------*/ e_frame=(struct enet_frame *)outbarp; (void)memset(e_frame->dest_addr, 0xFF, ENET_ADDR_LENGTH); e_frame->type=ENET_ARPTYPE; a_frame=(struct arp_frame *)e_frame->enet_data; (void)memset(a_frame, 0x00, sizeof(struct arp_frame)); a_frame->ar_hrd=1; a_frame->ar_pro=0x800; a_frame->ar_hln=6; a_frame->ar_pln=4; (void)memcpy(a_frame->ar_tpa, &target_address, a_frame->ar_pln); (void)memcpy(a_frame->ar_sha, hwd_addr, a_frame->ar_hln); (void)memcpy(a_frame->ar_spa, ip_addr, a_frame->ar_pln); a_frame->ar_op=ARP_REQUEST; /*--------------------------------------------------------------------+ | Stack current frame in holding pen (-2 for XLC sizeof). +--------------------------------------------------------------------*/ outframe_len=len+ sizeof(struct enet_frame)- 2; (void)memcpy(datap, p, len); if (enet_send_macframe((char *)outbarp, sizeof(outbarp))) { (void)s1printf("%s: ENETSEND: send frame error.\n",dev.name); } (void)ppcMtmsr(msr); #if 0 // YYD, timeout delay { int timeout = 30000; int len = outframe_len; while(outframe_len > 0 && timeout > 0) { nsdelay(100*1000); // 100 us delay timeout --; } if(outframe_len ==0) return len; }#endif return(-1); } } (void)memcpy(datap, p, len); fake_length=len+ sizeof(struct enet_frame)- 2; if (fake_length<ENET_MINPACKET) { fake_length=ENET_MINPACKET; } if (enet_send_macframe((char *)outframe, fake_length)) { (void)s1printf("%s: ENETSEND: send frame error.\n",dev.name); (void)ppcMtmsr(msr); return(-1); } (void)ppcMtmsr(msr); return(len+ sizeof(struct enet_frame)- 2);}/*-----------------------------------------------------------------------------+ . Function: Enet_send_macframe . . Purpose: . This sends the actual packet to the SMC9xxx chip. . . Algorithm: . First, see if a buf is available. . Now, find the packet number that the chip allocated . Point the data pointers at it in memory . Set the length word in the chip's memory . Dump the packet to chip memory . Check if a last byte is needed ( odd length packet ) . if so, set the control flag right . Tell the card to send it . Enable the transmit interrupt, so I know if it failed+-----------------------------------------------------------------------------*/int enet_send_macframe(char * frame, int frame_len){ struct enet_frame *ef_ptr=(struct enet_frame *)frame; char packet_no; unsigned int length; char *buf; char mask;#ifdef DEBUG_MSG_MACFRAME s1printf("%s: SEND_MACFRAME: Entered...\n", dev.name);#endif /*--------------------------------------------------------------------------+ | Copy in our address into the frame. +--------------------------------------------------------------------------*/ (void)memcpy(ef_ptr->source_addr, hwd_addr, ENET_ADDR_LENGTH); /*--------------------------------------------------------------------------+ | If frame is too long or too short, modify length. +--------------------------------------------------------------------------*/ if (frame_len>ENET_MAX_MTU) { frame_len=ENET_MAX_MTU; } else if (frame_len<ENET_MINPACKET) { frame_len=ENET_MINPACKET; } if ( !frame_len ) { s1printf("%s: SEND_MACFRAME: In XMIT with no packet to send \n", dev.name); return(1); } length = frame_len; buf = frame; /* If I get here, I _know_ there is a packet slot waiting for me */ packet_no = in16( ENET_IO_ADDR + PN_REG )>>8; // YYD if ( packet_no & AR_FAILED ) { /* or isn't there? BAD CHIP! */ s1printf("%s: SEND_MACFRAME: Memory allocation failed. \n", dev.name); dev.tbusy = 0; return(1); }// s1printf("Send pkt no = %x\n", packet_no); /* we have a packet address, so tell the card to use it */ out16( ENET_IO_ADDR + PN_REG, packet_no ); /* point to the beginning of the packet */ out16( ENET_IO_ADDR + PTR_REG, PTR_AUTOINC);#ifdef DEBUG_MSG_MACFRAME s1printf("%s: SEND_MACFRAME: Trying to xmit packet of length 0x%x\n", dev.name, length); dump( buf, length );#endif /* send the packet length ( +6 for status, length and ctl byte ) and the status word ( set to zeros ) */ out16( ENET_IO_ADDR + DATA_REG, 0x00 ); /* send the packet length ( +6 for status words, length, and ctl*/ out16( ENET_IO_ADDR + DATA_REG, (length+6) ); /* send the actual data . I _think_ it's faster to send the longs first, and then . mop up by sending the last word. It depends heavily . on alignment, at least on the 486. Maybe it would be . a good idea to check which is optimal? But that could take . almost as much time as is saved? */ outsw(ENET_IO_ADDR + DATA_REG, buf, (length ) >> 1); /* Send the last byte, if there is one. */ if ( (length & 1) == 0 ) { out16( ENET_IO_ADDR + DATA_REG, 0x00); } else { out16( ENET_IO_ADDR + DATA_REG, 0x2000 | buf[length -1 ]); // Set odd bit in CONTROL BYTE } /* enable the interrupts */ out16( ENET_IO_ADDR + BANK_SELECT, 0x02 ); mask = in16( ENET_IO_ADDR + INT_REG )>>8; mask |= IM_TX_INT | IM_TX_EMPTY_INT; out16( ENET_IO_ADDR + INT_REG, (mask<<8) ); // YYD, IM_TX_EMPTY_INT// out16( ENET_IO_ADDR + INT_REG, IM_TX_EMPTY_INT ); /* and let the chipset deal with it */ out16( ENET_IO_ADDR + MMU_CMD_REG, MC_ENQUEUE); nsdelay(1000); // YYD wait for status update// out16( ENET_IO_ADDR + INT_REG, (mask<<8) ); // YYD, IM_TX_EMPTY_INT#ifdef DEBUG_MSG_MACFRAME s1printf("%s: SEND_MACFRAME: Sent packet of length 0x%x \n", dev.name, length);#endif /* we can send another packet */ dev.tbusy = 0; return(0);}/************************************************************************* . phy_interrupt . . Purpose: Handle interrupts relating to PHY register 18. This is . called from the "hard" interrupt handler. . ************************************************************************/static void phy_interrupt(){ char phyaddr = dev.phyaddr; unsigned int phy18;#ifdef DEBUG_MSG_PHYINT s1printf("%s: phy_interrupt\n", dev.name);#endif while (1) { // Read PHY Register 18, Status Output phy18 = phy_readreg(phyaddr, PHY_INT_REG); // Exit if not more changes if (phy18 == dev.lastPhy18) break;#if (PHY_DEBUG > 1 ) s1printf("%s: phy18=0x%x\n", dev.name, phy18); s1printf("%s: lastPhy18=0x%x\n", dev.name, dev.lastPhy18); // Handle events if ((phy18 & PHY_INT_LNKFAIL) != (dev.lastPhy18 & PHY_INT_LNKFAIL)) { s1printf("%s: PHY Link Fail=%x\n", dev.name, phy18 & PHY_INT_LNKFAIL); } if ((phy18 & PHY_INT_LOSSSYNC) != (dev.lastPhy18 & PHY_INT_LOSSSYNC)) { s1printf("%s: PHY LOSS SYNC=%x\n", dev.name, phy18 & PHY_INT_LOSSSYNC); } if ((phy18 & PHY_INT_CWRD) != (dev.lastPhy18 & PHY_INT_CWRD)) { s1printf("%s: PHY INVALID 4B5B code=%x\n", dev.name, phy18 & PHY_INT_CWRD); } if ((phy18 & PHY_INT_SSD) != (dev.lastPhy18 & PHY_INT_SSD)) { s1printf("%s: PHY No Start Of Stream=%x\n", dev.name, phy18 & PHY_INT_SSD); } if ((phy18 & PHY_INT_ESD) != (dev.lastPhy18 & PHY_INT_ESD)) { s1printf("%s: PHY No End Of Stream=%x\n", dev.name, phy18 & PHY_INT_ESD); } if ((phy18 & PHY_INT_RPOL) != (dev.lastPhy18 & PHY_INT_RPOL)) { s1printf("%s: PHY Reverse Polarity Detected=%x\n", dev.name, phy18 & PHY_INT_RPOL); } if ((phy18 & PHY_INT_JAB) != (dev.lastPhy18 & PHY_INT_JAB)) { s1printf("%s: PHY Jabber Detected=%x\n", dev.name,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -