📄 smc91111.c
字号:
int time_out; byte status; PRINTK3("%s:smc_hardware_send_packet\n", SMC_DEV_NAME); length = ETH_ZLEN < packet_length ? packet_length : ETH_ZLEN; /* allocate memory ** The MMU wants the number of pages to be the number of 256 bytes ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) ) ** ** The 91C111 ignores the size bits, but the code is left intact ** for backwards and future compatibility. ** ** Pkt size for allocating is data length +6 (for additional status ** words, length and ctl!) ** ** If odd size then last byte is included in this header. */ numPages = ((length & 0xfffe) + 6); numPages >>= 8; // Divide by 256 if (numPages > 7 ) { printf("%s: Far too big packet error. \n", SMC_DEV_NAME); return 0; } /* now, try to allocate the memory */ SMC_SELECT_BANK( 2 ); SMC_outw( MC_ALLOC | numPages, MMU_CMD_REG );again: try++; time_out = MEMORY_WAIT_TIME; do { status = SMC_inb( INT_REG ); if ( status & IM_ALLOC_INT ) { /* acknowledge the interrupt */ SMC_outb( IM_ALLOC_INT, INT_REG ); break; } } while ( -- time_out ); if ( !time_out ) { PRINTK2("%s: memory allocation, try %d failed ...\n", SMC_DEV_NAME, try); if (try < SMC_ALLOC_MAX_TRY) goto again; else return 0; } PRINTK2("%s: memory allocation, try %d succeeded ...\n", SMC_DEV_NAME, try); /* I can send the packet now.. */ ioaddr = SMC_BASE_ADDRESS; buf = (byte *)packet; /* If I get here, I _know_ there is a packet slot waiting for me */ packet_no = SMC_inb( AR_REG ); if ( packet_no & AR_FAILED ) { /* or isn't there? BAD CHIP! */ printf("%s: Memory allocation failed. \n", SMC_DEV_NAME); return 0; } /* we have a packet address, so tell the card to use it */ SMC_outb( packet_no, PN_REG ); /* point to the beginning of the packet */ SMC_outw( PTR_AUTOINC , PTR_REG ); PRINTK3("%s: Trying to xmit packet of length %x\n", SMC_DEV_NAME, length);#if SMC_DEBUG > 2 printf("Transmitting Packet\n"); print_packet( buf, length );#endif /* send the packet length ( +6 for status, length and ctl byte ) and the status word ( set to zeros ) */#ifdef USE_32_BIT SMC_outl( (length +6 ) << 16 , DATA_REG );#else SMC_outw( 0, DATA_REG ); /* send the packet length ( +6 for status words, length, and ctl*/ SMC_outw( (length+6), DATA_REG );#endif /* 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? */#ifdef USE_32_BIT SMC_outsl(DATA_REG, buf, length >> 2 ); if ( length & 0x2 ) SMC_outw(*((word *)(buf + (length & 0xFFFFFFFC))), DATA_REG);#else SMC_outsw(DATA_REG , buf, (length ) >> 1);#endif // USE_32_BIT /* Send the last byte, if there is one. */ if ( (length & 1) == 0 ) { SMC_outw( 0, DATA_REG ); } else { SMC_outw( buf[length -1 ] | 0x2000, DATA_REG ); } /* and let the chipset deal with it */ SMC_outw( MC_ENQUEUE , MMU_CMD_REG ); /* poll for TX INT */ if (poll4int(IM_TX_INT, SMC_TX_TIMEOUT)) { /* sending failed */ PRINTK2("%s: TX timeout, sending failed...\n", SMC_DEV_NAME); /* release packet */ SMC_outw(MC_FREEPKT, MMU_CMD_REG); /* wait for MMU getting ready (low) */ while (SMC_inw(MMU_CMD_REG) & MC_BUSY) { udelay(10); } PRINTK2("MMU ready\n"); return 0; } else { /* ack. int */ SMC_outw(IM_TX_INT, INT_REG); PRINTK2("%s: Sent packet of length %d \n", SMC_DEV_NAME, length); /* release packet */ SMC_outw(MC_FREEPKT, MMU_CMD_REG); /* wait for MMU getting ready (low) */ while (SMC_inw(MMU_CMD_REG) & MC_BUSY) { udelay(10); } PRINTK2("MMU ready\n"); } return length;}/*------------------------------------------------------------------------- | | smc_destructor( struct net_device * dev ) | Input parameters: | dev, pointer to the device structure | | Output: | None. | ---------------------------------------------------------------------------*/void smc_destructor(){ PRINTK2(CARDNAME ":smc_destructor\n");}/* * Open and Initialize the board * * Set up everything, reset the card, etc .. * */static int smc_open(){ int i; /* used to set hw ethernet address */ PRINTK2("%s:smc_open\n", SMC_DEV_NAME); /* reset the hardware */ smc_reset(); smc_enable(); /* Configure the PHY */#ifndef CONFIG_SMC91111_EXT_PHY smc_phy_configure();#endif /* conservative setting (10Mbps, HalfDuplex, no AutoNeg.) */// SMC_SELECT_BANK(0);// SMC_outw(0, RPC_REG); SMC_SELECT_BANK( 1 );#ifdef USE_32_BIT for ( i = 0; i < 6; i += 2 ) { word address; address = smc_mac_addr[ i + 1 ] << 8 ; address |= smc_mac_addr[ i ]; SMC_outw( address, ADDR0_REG + i ); }#else for ( i = 0; i < 6; i ++ ) SMC_outb( smc_mac_addr[i], ADDR0_REG + i );#endif return 0;}#ifdef USE_32_BITvoidinsl32(r,b,l) { int __i ; dword *__b2; __b2 = (dword *) b; for (__i = 0; __i < l; __i++) { *(__b2 + __i) = *(dword *)(r+0x10000300); } }#endif/*------------------------------------------------------------- . . smc_rcv - receive a packet from the card . . There is ( at least ) a packet waiting to be read from . chip-memory. . . o Read the status . o If an error, record it . o otherwise, read in the packet --------------------------------------------------------------*/static int smc_rcv(){ int packet_number; word status; word packet_length; int is_error = 0;#ifdef USE_32_BIT dword stat_len;#endif SMC_SELECT_BANK(2); packet_number = SMC_inw( RXFIFO_REG ); if ( packet_number & RXFIFO_REMPTY ) { return 0; } PRINTK3("%s:smc_rcv\n", SMC_DEV_NAME); /* start reading from the start of the packet */ SMC_outw( PTR_READ | PTR_RCV | PTR_AUTOINC, PTR_REG ); /* First two words are status and packet_length */#ifdef USE_32_BIT stat_len = SMC_inl(DATA_REG); status = stat_len & 0xffff; packet_length = stat_len >> 16;#else status = SMC_inw( DATA_REG ); packet_length = SMC_inw( DATA_REG );#endif packet_length &= 0x07ff; /* mask off top bits */ PRINTK2("RCV: STATUS %4x LENGTH %4x\n", status, packet_length ); if ( !(status & RS_ERRORS ) ){ /* Adjust for having already read the first two words */ packet_length -= 4; //4; // set odd length for bug in LAN91C111, // which never sets RS_ODDFRAME /* TODO ? */#ifdef USE_32_BIT PRINTK3(" Reading %d dwords (and %d bytes) \n", packet_length >> 2, packet_length & 3 ); /* QUESTION: Like in the TX routine, do I want to send the DWORDs or the bytes first, or some mixture. A mixture might improve already slow PIO performance */ SMC_insl( DATA_REG , NetRxPackets[0], packet_length >> 2 ); /* read the left over bytes */ if (packet_length & 3) { int i; byte *tail = NetRxPackets[0] + (packet_length & ~3); dword leftover = SMC_inl(DATA_REG); for (i=0; i<(packet_length & 3); i++) *tail++ = (byte) (leftover >> (8*i)) & 0xff; } #else PRINTK3(" Reading %d words and %d byte(s) \n", (packet_length >> 1 ), packet_length & 1 ); SMC_insw(DATA_REG , NetRxPackets[0], packet_length >> 1);#endif // USE_32_BIT#if SMC_DEBUG > 2 printf("Receiving Packet\n"); print_packet( NetRxPackets[0], packet_length );#endif } else { /* error ... */ /* TODO ? */ is_error = 1; } while ( SMC_inw( MMU_CMD_REG ) & MC_BUSY ) udelay(1); // Wait until not busy /* error or good, tell the card to get rid of this packet */ SMC_outw( MC_RELEASE, MMU_CMD_REG ); while ( SMC_inw( MMU_CMD_REG ) & MC_BUSY ) udelay(1); // Wait until not busy if (!is_error) { /* Pass the packet up to the protocol layers. */ NetReceive(NetRxPackets[0], packet_length); return packet_length; } else { return 0; }}/*---------------------------------------------------- . smc_close . . this makes the board clean up everything that it can . and not talk to the outside world. Caused by . an 'ifconfig ethX down' . -----------------------------------------------------*/static int smc_close(){ PRINTK2("%s:smc_close\n", SMC_DEV_NAME); /* clear everything */ smc_shutdown(); return 0;}#if 0/*------------------------------------------------------------ . Modify a bit in the LAN91C111 register set .-------------------------------------------------------------*/static word smc_modify_regbit(int bank, int ioaddr, int reg, unsigned int bit, int val){ word regval; SMC_SELECT_BANK( bank ); regval = SMC_inw( reg ); if (val) regval |= bit; else regval &= ~bit; SMC_outw( regval, 0 ); return(regval);}/*------------------------------------------------------------ . Retrieve a bit in the LAN91C111 register set .-------------------------------------------------------------*/static int smc_get_regbit(int bank, int ioaddr, int reg, unsigned int bit){ SMC_SELECT_BANK( bank ); if ( SMC_inw( reg ) & bit) return(1); else return(0);}/*------------------------------------------------------------ . Modify a LAN91C111 register (word access only) .-------------------------------------------------------------*/static void smc_modify_reg(int bank, int ioaddr, int reg, word val){ SMC_SELECT_BANK( bank ); SMC_outw( val, reg );}/*------------------------------------------------------------ . Retrieve a LAN91C111 register (word access only) .-------------------------------------------------------------*/static int smc_get_reg(int bank, int ioaddr, int reg){ SMC_SELECT_BANK( bank ); return(SMC_inw( reg ));}#endif /* 0 *///---PHY CONTROL AND CONFIGURATION-----------------------------------------#if (SMC_DEBUG > 2 )/*------------------------------------------------------------ . Debugging function for viewing MII Management serial bitstream .-------------------------------------------------------------*/static void smc_dump_mii_stream(byte* bits, int size){ int i; printf("BIT#:"); for (i = 0; i < size; ++i) { printf("%d", i%10); } printf("\nMDOE:"); for (i = 0; i < size; ++i) { if (bits[i] & MII_MDOE) printf("1"); else printf("0"); } printf("\nMDO :"); for (i = 0; i < size; ++i) { if (bits[i] & MII_MDO)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -