?? smc91111.c
字號(hào):
/* . Function: smc_hardware_send_packet(struct net_device * ) . Purpose: . This sends the actual packet to the SMC9xxx chip. . . Algorithm: . First, see if a saved_skb is available. . ( this should NOT be called if there is no 'saved_skb' . 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 . Free the kernel data if I actually sent it.*/static int smc_send_packet (volatile void *packet, int packet_length){ byte packet_no; unsigned long ioaddr; byte *buf; int length; int numPages; int try = 0; int time_out; byte status; byte saved_pnr; word saved_ptr; /* save PTR and PNR registers before manipulation */ SMC_SELECT_BANK (2); saved_pnr = SMC_inb( PN_REG ); saved_ptr = SMC_inw( PTR_REG ); 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); /* FIXME: the ALLOC_INT bit never gets set * * so the following will always give a * * memory allocation error. * * same code works in armboot though * * -ro */again: try++; time_out = MEMORY_WAIT_TIME; do { status = SMC_inb (SMC91111_INT_REG); if (status & IM_ALLOC_INT) { /* acknowledge the interrupt */ SMC_outb (IM_ALLOC_INT, SMC91111_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 */#ifndef CONFIG_XAENIAX SMC_outb (packet_no, PN_REG);#else /* On Xaeniax board, we can't use SMC_outb here because that way * the Allocate MMU command will end up written to the command register * as well, which will lead to a problem. */ SMC_outl (packet_no << 16, 0);#endif /* do not write new ptr value if Write data fifo not empty */ while ( saved_ptr & PTR_NOTEMPTY ) printf ("Write data fifo not empty!\n"); /* 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, SMC91111_DATA_REG);#else SMC_outw (0, SMC91111_DATA_REG); /* send the packet length ( +6 for status words, length, and ctl */ SMC_outw ((length + 6), SMC91111_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 (SMC91111_DATA_REG, buf, length >> 2);#ifndef CONFIG_XAENIAX if (length & 0x2) SMC_outw (*((word *) (buf + (length & 0xFFFFFFFC))), SMC91111_DATA_REG);#else /* On XANEIAX, we can only use 32-bit writes, so we need to handle * unaligned tail part specially. The standard code doesn't work. */ if ((length & 3) == 3) { u16 * ptr = (u16*) &buf[length-3]; SMC_outl((*ptr) | ((0x2000 | buf[length-1]) << 16), SMC91111_DATA_REG); } else if ((length & 2) == 2) { u16 * ptr = (u16*) &buf[length-2]; SMC_outl(*ptr, SMC91111_DATA_REG); } else if (length & 1) { SMC_outl((0x2000 | buf[length-1]), SMC91111_DATA_REG); } else { SMC_outl(0, SMC91111_DATA_REG); }#endif#else SMC_outsw (SMC91111_DATA_REG, buf, (length) >> 1);#endif /* USE_32_BIT */#ifndef CONFIG_XAENIAX /* Send the last byte, if there is one. */ if ((length & 1) == 0) { SMC_outw (0, SMC91111_DATA_REG); } else { SMC_outw (buf[length - 1] | 0x2000, SMC91111_DATA_REG); }#endif /* 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)) { */ /* poll for TX_EMPTY INT - autorelease enabled */ if (poll4int(IM_TX_EMPTY_INT, SMC_TX_TIMEOUT)) { /* sending failed */ PRINTK2 ("%s: TX timeout, sending failed...\n", SMC_DEV_NAME); /* release packet */ /* no need to release, MMU does that now */#ifdef CONFIG_XAENIAX SMC_outw (MC_FREEPKT, MMU_CMD_REG);#endif /* 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_outb (IM_TX_EMPTY_INT, SMC91111_INT_REG); /* SMC_outb (IM_TX_INT, SMC91111_INT_REG); */ PRINTK2 ("%s: Sent packet of length %d \n", SMC_DEV_NAME, length); /* release packet */ /* no need to release, MMU does that now */#ifdef CONFIG_XAENIAX SMC_outw (MC_FREEPKT, MMU_CMD_REG);#endif /* wait for MMU getting ready (low) */ while (SMC_inw (MMU_CMD_REG) & MC_BUSY) { udelay (10); } PRINTK2 ("MMU ready\n"); } /* restore previously saved registers */#ifndef CONFIG_XAENIAX SMC_outb( saved_pnr, PN_REG );#else /* On Xaeniax board, we can't use SMC_outb here because that way * the Allocate MMU command will end up written to the command register * as well, which will lead to a problem. */ SMC_outl(saved_pnr << 16, 0);#endif SMC_outw( saved_ptr, PTR_REG ); 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 (bd_t * bd){ int i, err; 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); err = smc_get_ethaddr (bd); /* set smc_mac_addr, and sync it with u-boot globals */ if (err < 0) { memset (bd->bi_enetaddr, 0, 6); /* hack to make error stick! upper code will abort if not set */ return (-1); /* upper code ignores this, but NOT bi_enetaddr */ }#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;}/*------------------------------------------------------------- . . 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 byte saved_pnr; word saved_ptr; SMC_SELECT_BANK(2); /* save PTR and PTR registers */ saved_pnr = SMC_inb( PN_REG ); saved_ptr = SMC_inw( PTR_REG ); 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(SMC91111_DATA_REG); status = stat_len & 0xffff; packet_length = stat_len >> 16;#else status = SMC_inw( SMC91111_DATA_REG ); packet_length = SMC_inw( SMC91111_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( SMC91111_DATA_REG , NetRxPackets[0], packet_length >> 2 ); /* read the left over bytes */ if (packet_length & 3) { int i; byte *tail = (byte *)(NetRxPackets[0] + (packet_length & ~3)); dword leftover = SMC_inl(SMC91111_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(SMC91111_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 */ /* restore saved registers */#ifndef CONFIG_XAENIAX SMC_outb( saved_pnr, PN_REG );#else /* On Xaeniax board, we can't use SMC_outb here because that way * the Allocate MMU command will end up written to the command register * as well, which will lead to a problem. */ SMC_outl( saved_pnr << 16, 0);#endif SMC_outw( saved_ptr, PTR_REG ); 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
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -