📄 smc91113.c
字号:
static void smc_reset( struct net_device* dev ){ //struct smc_local *lp = (struct smc_local *)dev->priv; unsigned int ioaddr = dev->base_addr; int temp = 0; PRINTK2("%s:smc_reset\n", dev->name); /* This resets the registers mostly to defaults, but doesn't affect EEPROM. That seems unnecessary */ SMC_SELECT_BANK( 0 ); outw( RCR_SOFTRST, ioaddr + RCR_REG ); while(1) // now test the is reset ok?, if not ok, so we just change the status. { temp ++; if ((inw(ioaddr + RCR_REG ) & RCR_SOFTRST) == 0) break; smc_wait_ms (10); /* Delay 10ms, try 5 times*/ if (temp >=5) { outw( (inw(ioaddr + RCR_REG ) & (~RCR_SOFTRST)) , ioaddr + RCR_REG ); break; } } /* Setup the Configuration Register */ /* This is necessary because the CONFIG_REG is not affected */ /* by a soft reset */ SMC_SELECT_BANK( 1 ); outw( CONFIG_DEFAULT, ioaddr + CONFIG_REG); /* Setup for fast accesses if requested */ /* If the card/system can't handle it then there will */ /* be no recovery except for a hard reset or power cycle */ if (dev->dma) outw( inw( ioaddr + CONFIG_REG ) | CONFIG_NO_WAIT, ioaddr + CONFIG_REG );#ifdef POWER_DOWN /* Release from possible power-down state */ /* Configuration register is not affected by Soft Reset */ SMC_SELECT_BANK( 1 ); outw( inw( ioaddr + CONFIG_REG ) | CONFIG_EPH_POWER_EN, ioaddr + CONFIG_REG );#endif SMC_SELECT_BANK( 0 ); /* this should pause enough for the chip to be happy */ mdelay(10); /* Disable transmit and receive functionality */ outw( RCR_CLEAR, ioaddr + RCR_REG ); outw( TCR_CLEAR, ioaddr + TCR_REG ); /* set the control register to automatically release successfully transmitted packets, to make the best use out of our limited memory */ SMC_SELECT_BANK( 1 ); outw( inw( ioaddr + CTL_REG ) | CTL_AUTO_RELEASE , ioaddr + CTL_REG ); /* Reset the MMU */ SMC_SELECT_BANK( 2 ); outw( MC_RESET, ioaddr + MMU_CMD_REG ); /* Note: It doesn't seem that waiting for the MMU busy is needed here, but this is a place where future chipsets _COULD_ break. Be wary of issuing another MMU command right after this */ while ( inw( ioaddr + MMU_CMD_REG ) & MC_BUSY ) /* Qinwei : I add waiting, for safe.*/ mdelay(1); // Wait until not busy /* Disable all interrupts */ outb( 0, ioaddr + IM_REG );}/* . Function: smc_enable . Purpose: let the chip talk to the outside work . Method: . 1. Enable the transmitter . 2. Enable the receiver . 3. Enable interrupts*/static void smc_enable( struct net_device *dev ){ unsigned int ioaddr = dev->base_addr; struct smc_local *lp = (struct smc_local *)dev->priv; PRINTK2("%s:smc_enable\n", dev->name); SMC_SELECT_BANK( 0 ); /* see the header file for options in TCR/RCR DEFAULT*/ outw( lp->tcr_cur_mode, ioaddr + TCR_REG ); outw( lp->rcr_cur_mode, ioaddr + RCR_REG ); /* now, enable interrupts */ SMC_SELECT_BANK( 2 ); outb( SMC_INTERRUPT_MASK, ioaddr + IM_REG );}/* . Function: smc_shutdown . Purpose: closes down the SMC91xxx chip. . Method: . 1. zero the interrupt mask . 2. clear the enable receive flag . 3. clear the enable xmit flags . . TODO: . (1) maybe utilize power down mode. . Why not yet? Because while the chip will go into power down mode, . the manual says that it will wake up in response to any I/O requests . in the register space. Empirical results do not show this working.*/static void smc_shutdown( int ioaddr ){ PRINTK2("CARDNAME:smc_shutdown\n"); /* no more interrupts for me */ SMC_SELECT_BANK( 2 ); outb( 0, ioaddr + IM_REG ); /* and tell the card to stay away from that nasty outside world */ SMC_SELECT_BANK( 0 ); outb( RCR_CLEAR, ioaddr + RCR_REG ); outb( TCR_CLEAR, ioaddr + TCR_REG );#ifdef POWER_DOWN /* finally, shut the chip down */ SMC_SELECT_BANK( 1 ); outw( inw( ioaddr + CONFIG_REG ) & ~CONFIG_EPH_POWER_EN, ioaddr + CONFIG_REG );#endif}/* . Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds ) . Purpose: . This sets the internal hardware table to filter out unwanted multicast . packets before they take up memory. . . The SMC chip uses a hash table where the high 6 bits of the CRC of . address are the offset into the table. If that bit is 1, then the . multicast packet is accepted. Otherwise, it's dropped silently. . . To use the 6 bits as an offset into the table, the high 3 bits are the . number of the 8 bit register, while the low 3 bits are the bit within . that register. . . This routine is based very heavily on the one provided by Peter Cammaert.*/static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs ) { int i; unsigned char multicast_table[ 8 ]; struct dev_mc_list * cur_addr; /* table for flipping the order of 3 bits */ unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 }; PRINTK2("CARDNAME:smc_setmulticast\n"); /* start with a table of all zeros: reject all */ memset( multicast_table, 0, sizeof( multicast_table ) ); cur_addr = addrs; for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next ) { int position; /* do we have a pointer here? */ if ( !cur_addr ) break; /* make sure this is a multicast address - shouldn't this be a given if we have it here ? */ if ( !( *cur_addr->dmi_addr & 1 ) ) continue; /* only use the low order bits */ position = crc32( cur_addr->dmi_addr, 6 ) & 0x3f; /* do some messy swapping to put the bit in the right spot */ multicast_table[invert3[position&7]] |= (1<<invert3[(position>>3)&7]); } /* now, the table can be loaded into the chipset */ SMC_SELECT_BANK( 3 ); for ( i = 0; i < 8 ; i++ ) { outb( multicast_table[i], ioaddr + MCAST_REG1 + i ); }}/* Finds the CRC32 of a set of bytes. Again, from Peter Cammaert's code.*/static int crc32( char * s, int length ) { /* indices */ int perByte; int perBit; /* crc polynomial for Ethernet */ const unsigned long poly = 0xedb88320; /* crc value - preinitialized to all 1's */ unsigned long crc_value = 0xffffffff; for ( perByte = 0; perByte < length; perByte ++ ) { unsigned char c; c = *(s++); for ( perBit = 0; perBit < 8; perBit++ ) { crc_value = (crc_value>>1)^ (((crc_value^c)&0x01)?poly:0); c >>= 1; } } return crc_value;}/* . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct device * ) . Purpose: . Attempt to allocate memory for a packet, if chip-memory is not . available, then tell the card to generate an interrupt when it . is available. . . Algorithm: . . o if the saved_skb is not currently null, then drop this packet . on the floor. This should never happen, because of TBUSY. . o if the saved_skb is null, then replace it with the current packet, . o See if I can sending it now. . o (NO): Enable interrupts and let the interrupt handler deal with it. . o (YES):Send it now.*/static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * dev ){ struct smc_local *lp = (struct smc_local *)dev->priv; unsigned int ioaddr = dev->base_addr; word length; unsigned short numPages; word time_out; word status; PRINTK3("%s:smc_wait_to_send_packet\n", dev->name); if ( lp->saved_skb) { /* THIS SHOULD NEVER HAPPEN. */ lp->stats.tx_aborted_errors++;// printk("%s: sent packet while busy.\n", dev->name); return 1; } lp->saved_skb = skb; length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; /* ** 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 91C113 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 ) { printk("%s: Far too big packet error. \n", dev->name); /* freeing the packet is a good thing here... but should . any packets of this size get down here? */ dev_kfree_skb (skb); lp->saved_skb = NULL; /* this IS an error, but, i don't want the skb saved */ netif_wake_queue(dev); return 0; } /* either way, a packet is waiting now */ lp->packets_waiting++; /* now, try to allocate the memory */ SMC_SELECT_BANK( 2 ); outw( MC_ALLOC | numPages, ioaddr + MMU_CMD_REG ); /* . Performance Hack . . wait a short amount of time.. if I can send a packet now, I send . it now. Otherwise, I enable an interrupt and wait for one to be . available. . . I could have handled this a slightly different way, by checking to . see if any memory was available in the FREE MEMORY register. However, . either way, I need to generate an allocation, and the allocation works . no matter what, so I saw no point in checking free memory. */ time_out = MEMORY_WAIT_TIME; do { status = inb( ioaddr + INT_REG ); if ( status & IM_ALLOC_INT ) { /* acknowledge the interrupt */ outb( IM_ALLOC_INT, ioaddr + INT_REG ); break; } } while ( -- time_out ); if ( !time_out ) { /* oh well, wait until the chip finds memory later */ SMC_ENABLE_INT( IM_ALLOC_INT ); /* Check the status bit one more time just in case */ /* it snuk in between the time we last checked it */ /* and when we set the interrupt bit */ status = inb( ioaddr + INT_REG ); if ( !(status & IM_ALLOC_INT) ) { PRINTK2("%s: memory allocation deferred. \n", dev->name); /* it's deferred, but I'll handle it later */ return 0; } /* Looks like it did sneak in, so disable */ /* the interrupt */ SMC_DISABLE_INT( IM_ALLOC_INT ); } /* or YES! I can send the packet now.. */ smc_hardware_send_packet(dev); netif_wake_queue(dev); return 0;}/* . Function: smc_hardware_send_packet(struct 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 void smc_hardware_send_packet( struct net_device * dev ){ struct smc_local *lp = (struct smc_local *)dev->priv; byte packet_no; struct sk_buff * skb = lp->saved_skb; word length; unsigned int ioaddr; byte * buf; PRINTK3("%s:smc_hardware_send_packet\n", dev->name); ioaddr = dev->base_addr; if ( !skb ) { PRINTK("%s: In XMIT with no packet to send \n", dev->name); return; } length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; buf = skb->data; /* If I get here, I _know_ there is a packet slot waiting for me */ packet_no = inb( ioaddr + AR_REG ); if ( packet_no & AR_FAILED ) { /* or isn't there? BAD CHIP! */ printk(KERN_DEBUG "%s: Memory allocation failed. \n", dev->name); dev_kfree_skb_any (skb); lp->saved_skb = NULL; netif_wake_queue(dev); return; } /* we have a packet address, so tell the card to use it */ outb( packet_no, ioaddr + PN_REG ); /* point to the beginning of the packet */ outw( PTR_AUTOINC , ioaddr + PTR_REG ); PRINTK3("%s: Trying to xmit packet of length %x\n", dev->name, length);#if SMC_DEBUG > 2 printk("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 outl( (length +6 ) << 16 , ioaddr + DATA_REG );#else outw( 0, ioaddr + DATA_REG ); /* send the packet length ( +6 for status words, length, and ctl*//* outb( (length+6) & 0xFF,ioaddr + DATA_REG ); outb( (length+6) >> 8 , ioaddr + DATA_REG );*/ // Qinwei ????? outw( (length+6), ioaddr + 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 outsl(ioaddr + DATA_REG, buf, length >> 2 ); if ( length & 0x2 ) outw(*((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_REG);#else //outsw(ioaddr + DATA_REG , buf, (length ) >> 1); // Qinwei ??? SMC_outsw(ioaddr + DATA_REG,buf,(length ) >> 1);#endif // USE_32_BIT /* Send the last byte, if there is one. */ if ( (length & 1) == 0 ) { outw( 0, ioaddr + DATA_REG ); } else { // Set odd bit in CONTROL BYTE outw( buf[length -1 ] | 0x2000, ioaddr + DATA_REG ); // Qinwei ??? /*outb( buf[length -1 ], ioaddr + DATA_REG ); outb( 0x20, ioaddr + DATA_REG); */ } /* enable the interrupts */ SMC_ENABLE_INT( (IM_TX_INT | IM_TX_EMPTY_INT) ); /* and let the chipset deal with it */ outw( MC_ENQUEUE , ioaddr + MMU_CMD_REG ); PRINTK2("%s: Sent packet of length %d \n", dev->name, length); lp->saved_skb = NULL; dev_kfree_skb_any (skb); dev->trans_start = jiffies; /* we can send another packet */ netif_wake_queue(dev); return;}/*------------------------------------------------------------------------- | | smc_init( struct device * dev ) | Input parameters: | dev->base_addr == 0, try to find all possible locations | dev->base_addr == 1, return failure code | dev->base_addr == 2, always allocate space, and return success | dev->base_addr == <anything else> this is the address to check | | Output: | 0 --> there is a device | anything else, error | ---------------------------------------------------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -