2005-04-17 02:20:36 +04:00
/*
drivers / net / tulip / pnic2 . c
2006-09-08 22:15:34 +04:00
Maintained by Valerie Henson < val_henson @ linux . intel . com >
2005-04-17 02:20:36 +04:00
Copyright 2000 , 2001 The Linux Kernel Team
Written / copyright 1994 - 2001 by Donald Becker .
Modified to hep support PNIC_II by Kevin B . Hendricks
This software may be used and distributed according to the terms
of the GNU General Public License , incorporated herein by reference .
Please refer to Documentation / DocBook / tulip - user . { pdf , ps , html }
for more information on this driver , or visit the project
Web page at http : //sourceforge.net/projects/tulip/
*/
/* Understanding the PNIC_II - everything is this file is based
* on the PNIC_II_PDF datasheet which is sorely lacking in detail
*
* As I understand things , here are the registers and bits that
* explain the masks and constants used in this file that are
* either different from the 21142 / 3 or important for basic operation .
*
*
* CSR 6 ( mask = 0xfe3bd1fd of bits not to change )
* - - - - -
* Bit 24 - SCR
* Bit 23 - PCS
* Bit 22 - TTM ( Trasmit Threshold Mode )
* Bit 18 - Port Select
* Bit 13 - Start - 1 , Stop - 0 Transmissions
* Bit 11 : 10 - Loop Back Operation Mode
* Bit 9 - Full Duplex mode ( Advertise 10 BaseT - FD is CSR14 < 7 > is set )
* Bit 1 - Start - 1 , Stop - 0 Receive
*
*
* CSR 14 ( mask = 0xfff0ee39 of bits not to change )
* - - - - - -
* Bit 19 - PAUSE - Pause
* Bit 18 - Advertise T4
* Bit 17 - Advertise 100 baseTx - FD
* Bit 16 - Advertise 100 baseTx - HD
* Bit 12 - LTE - Link Test Enable
* Bit 7 - ANE - Auto Negotiate Enable
* Bit 6 - HDE - Advertise 10 baseT - HD
* Bit 2 - Reset to Power down - kept as 1 for normal operation
* Bit 1 - Loop Back enable for 10 baseT MCC
*
*
* CSR 12
* - - - - - -
* Bit 25 - Partner can do T4
* Bit 24 - Partner can do 100 baseTx - FD
* Bit 23 - Partner can do 100 baseTx - HD
* Bit 22 - Partner can do 10 baseT - FD
* Bit 21 - Partner can do 10 baseT - HD
* Bit 15 - LPN is 1 if all above bits are valid other wise 0
* Bit 14 : 12 - autonegotiation state ( write 001 to start autonegotiate )
* Bit 3 - Autopolarity state
* Bit 2 - LS10B - link state of 10 baseT 0 - good , 1 - failed
* Bit 1 - LS100B - link state of 100 baseT 0 - good , 1 - faild
*
*
* Data Port Selection Info
* - - - - - - - - - - - - - - - - - - - - - - - - -
*
* CSR14 < 7 > CSR6 < 18 > CSR6 < 22 > CSR6 < 23 > CSR6 < 24 > MODE / PORT
* 1 0 0 ( X ) 0 ( X ) 1 NWAY
* 0 0 1 0 ( X ) 0 10 baseT
* 0 1 0 1 1 ( X ) 100 baseT
*
*
*/
# include <linux/pci.h>
# include "tulip.h"
# include <linux/delay.h>
void pnic2_timer ( unsigned long data )
{
struct net_device * dev = ( struct net_device * ) data ;
struct tulip_private * tp = netdev_priv ( dev ) ;
void __iomem * ioaddr = tp - > base_addr ;
int next_tick = 60 * HZ ;
if ( tulip_debug > 3 )
printk ( KERN_INFO " %s: PNIC2 negotiation status %8.8x. \n " ,
dev - > name , ioread32 ( ioaddr + CSR12 ) ) ;
if ( next_tick ) {
mod_timer ( & tp - > timer , RUN_AT ( next_tick ) ) ;
}
}
void pnic2_start_nway ( struct net_device * dev )
{
struct tulip_private * tp = netdev_priv ( dev ) ;
void __iomem * ioaddr = tp - > base_addr ;
int csr14 ;
int csr12 ;
/* set up what to advertise during the negotiation */
/* load in csr14 and mask off bits not to touch
* comment at top of file explains mask value
*/
csr14 = ( ioread32 ( ioaddr + CSR14 ) & 0xfff0ee39 ) ;
/* bit 17 - advetise 100baseTx-FD */
if ( tp - > sym_advertise & 0x0100 ) csr14 | = 0x00020000 ;
/* bit 16 - advertise 100baseTx-HD */
if ( tp - > sym_advertise & 0x0080 ) csr14 | = 0x00010000 ;
/* bit 6 - advertise 10baseT-HD */
if ( tp - > sym_advertise & 0x0020 ) csr14 | = 0x00000040 ;
/* Now set bit 12 Link Test Enable, Bit 7 Autonegotiation Enable
* and bit 0 Don ' t PowerDown 10 baseT
*/
csr14 | = 0x00001184 ;
if ( tulip_debug > 1 )
printk ( KERN_DEBUG " %s: Restarting PNIC2 autonegotiation, "
" csr14=%8.8x. \n " , dev - > name , csr14 ) ;
/* tell pnic2_lnk_change we are doing an nway negotiation */
dev - > if_port = 0 ;
tp - > nway = tp - > mediasense = 1 ;
tp - > nwayset = tp - > lpar = 0 ;
/* now we have to set up csr6 for NWAY state */
tp - > csr6 = ioread32 ( ioaddr + CSR6 ) ;
if ( tulip_debug > 1 )
printk ( KERN_DEBUG " %s: On Entry to Nway, "
" csr6=%8.8x. \n " , dev - > name , tp - > csr6 ) ;
/* mask off any bits not to touch
* comment at top of file explains mask value
*/
tp - > csr6 = tp - > csr6 & 0xfe3bd1fd ;
/* don't forget that bit 9 is also used for advertising */
/* advertise 10baseT-FD for the negotiation (bit 9) */
if ( tp - > sym_advertise & 0x0040 ) tp - > csr6 | = 0x00000200 ;
/* set bit 24 for nway negotiation mode ...
* see Data Port Selection comment at top of file
* and " Stop " - reset both Transmit ( bit 13 ) and Receive ( bit 1 )
*/
tp - > csr6 | = 0x01000000 ;
iowrite32 ( csr14 , ioaddr + CSR14 ) ;
iowrite32 ( tp - > csr6 , ioaddr + CSR6 ) ;
udelay ( 100 ) ;
/* all set up so now force the negotiation to begin */
/* read in current values and mask off all but the
* Autonegotiation bits 14 : 12. Writing a 001 to those bits
* should start the autonegotiation
*/
csr12 = ( ioread32 ( ioaddr + CSR12 ) & 0xffff8fff ) ;
csr12 | = 0x1000 ;
iowrite32 ( csr12 , ioaddr + CSR12 ) ;
}
void pnic2_lnk_change ( struct net_device * dev , int csr5 )
{
struct tulip_private * tp = netdev_priv ( dev ) ;
void __iomem * ioaddr = tp - > base_addr ;
int csr14 ;
/* read the staus register to find out what is up */
int csr12 = ioread32 ( ioaddr + CSR12 ) ;
if ( tulip_debug > 1 )
printk ( KERN_INFO " %s: PNIC2 link status interrupt %8.8x, "
" CSR5 %x, %8.8x. \n " , dev - > name , csr12 ,
csr5 , ioread32 ( ioaddr + CSR14 ) ) ;
/* If NWay finished and we have a negotiated partner capability.
* check bits 14 : 12 for bit pattern 101 - all is good
*/
if ( tp - > nway & & ! tp - > nwayset ) {
/* we did an auto negotiation */
if ( ( csr12 & 0x7000 ) = = 0x5000 ) {
/* negotiation ended successfully */
/* get the link partners reply and mask out all but
2006-03-28 13:56:53 +04:00
* bits 24 - 21 which show the partners capabilities
2005-04-17 02:20:36 +04:00
* and match those to what we advertised
*
* then begin to interpret the results of the negotiation .
* Always go in this order : ( we are ignoring T4 for now )
* 100 baseTx - FD , 100 baseTx - HD , 10 baseT - FD , 10 baseT - HD
*/
int negotiated = ( ( csr12 > > 16 ) & 0x01E0 ) & tp - > sym_advertise ;
tp - > lpar = ( csr12 > > 16 ) ;
tp - > nwayset = 1 ;
if ( negotiated & 0x0100 ) dev - > if_port = 5 ;
else if ( negotiated & 0x0080 ) dev - > if_port = 3 ;
else if ( negotiated & 0x0040 ) dev - > if_port = 4 ;
else if ( negotiated & 0x0020 ) dev - > if_port = 0 ;
else {
if ( tulip_debug > 1 )
printk ( KERN_INFO " %s: funny autonegotiate result "
" csr12 %8.8x advertising %4.4x \n " ,
dev - > name , csr12 , tp - > sym_advertise ) ;
tp - > nwayset = 0 ;
/* so check if 100baseTx link state is okay */
if ( ( csr12 & 2 ) = = 0 & & ( tp - > sym_advertise & 0x0180 ) )
dev - > if_port = 3 ;
}
/* now record the duplex that was negotiated */
tp - > full_duplex = 0 ;
if ( ( dev - > if_port = = 4 ) | | ( dev - > if_port = = 5 ) )
tp - > full_duplex = 1 ;
if ( tulip_debug > 1 ) {
if ( tp - > nwayset )
printk ( KERN_INFO " %s: Switching to %s based on link "
" negotiation %4.4x & %4.4x = %4.4x. \n " ,
dev - > name , medianame [ dev - > if_port ] ,
tp - > sym_advertise , tp - > lpar , negotiated ) ;
}
/* remember to turn off bit 7 - autonegotiate
* enable so we can properly end nway mode and
* set duplex ( ie . use csr6 < 9 > again )
*/
csr14 = ( ioread32 ( ioaddr + CSR14 ) & 0xffffff7f ) ;
iowrite32 ( csr14 , ioaddr + CSR14 ) ;
/* now set the data port and operating mode
* ( see the Data Port Selection comments at
* the top of the file
*/
/* get current csr6 and mask off bits not to touch */
/* see comment at top of file */
tp - > csr6 = ( ioread32 ( ioaddr + CSR6 ) & 0xfe3bd1fd ) ;
/* so if using if_port 3 or 5 then select the 100baseT
* port else select the 10 baseT port .
* See the Data Port Selection table at the top
* of the file which was taken from the PNIC_II . PDF
* datasheet
*/
if ( dev - > if_port & 1 ) tp - > csr6 | = 0x01840000 ;
else tp - > csr6 | = 0x00400000 ;
/* now set the full duplex bit appropriately */
if ( tp - > full_duplex ) tp - > csr6 | = 0x00000200 ;
iowrite32 ( 1 , ioaddr + CSR13 ) ;
if ( tulip_debug > 2 )
printk ( KERN_DEBUG " %s: Setting CSR6 %8.8x/%x CSR12 "
" %8.8x. \n " , dev - > name , tp - > csr6 ,
ioread32 ( ioaddr + CSR6 ) , ioread32 ( ioaddr + CSR12 ) ) ;
/* now the following actually writes out the
* new csr6 values
*/
tulip_start_rxtx ( tp ) ;
return ;
} else {
printk ( KERN_INFO " %s: Autonegotiation failed, "
" using %s, link beat status %4.4x. \n " ,
dev - > name , medianame [ dev - > if_port ] , csr12 ) ;
/* remember to turn off bit 7 - autonegotiate
* enable so we don ' t forget
*/
csr14 = ( ioread32 ( ioaddr + CSR14 ) & 0xffffff7f ) ;
iowrite32 ( csr14 , ioaddr + CSR14 ) ;
/* what should we do when autonegotiate fails?
* should we try again or default to baseline
* case . I just don ' t know .
*
* for now default to some baseline case
*/
dev - > if_port = 0 ;
tp - > nway = 0 ;
tp - > nwayset = 1 ;
/* set to 10baseTx-HD - see Data Port Selection
* comment given at the top of the file
*/
tp - > csr6 = ( ioread32 ( ioaddr + CSR6 ) & 0xfe3bd1fd ) ;
tp - > csr6 | = 0x00400000 ;
tulip_restart_rxtx ( tp ) ;
return ;
}
}
if ( ( tp - > nwayset & & ( csr5 & 0x08000000 )
& & ( dev - > if_port = = 3 | | dev - > if_port = = 5 )
& & ( csr12 & 2 ) = = 2 ) | | ( tp - > nway & & ( csr5 & ( TPLnkFail ) ) ) ) {
/* Link blew? Maybe restart NWay. */
if ( tulip_debug > 2 )
printk ( KERN_DEBUG " %s: Ugh! Link blew? \n " , dev - > name ) ;
del_timer_sync ( & tp - > timer ) ;
pnic2_start_nway ( dev ) ;
tp - > timer . expires = RUN_AT ( 3 * HZ ) ;
add_timer ( & tp - > timer ) ;
return ;
}
if ( dev - > if_port = = 3 | | dev - > if_port = = 5 ) {
/* we are at 100mb and a potential link change occurred */
if ( tulip_debug > 1 )
printk ( KERN_INFO " %s: PNIC2 %s link beat %s. \n " ,
dev - > name , medianame [ dev - > if_port ] ,
( csr12 & 2 ) ? " failed " : " good " ) ;
/* check 100 link beat */
tp - > nway = 0 ;
tp - > nwayset = 1 ;
/* if failed then try doing an nway to get in sync */
if ( ( csr12 & 2 ) & & ! tp - > medialock ) {
del_timer_sync ( & tp - > timer ) ;
pnic2_start_nway ( dev ) ;
tp - > timer . expires = RUN_AT ( 3 * HZ ) ;
add_timer ( & tp - > timer ) ;
}
return ;
}
if ( dev - > if_port = = 0 | | dev - > if_port = = 4 ) {
/* we are at 10mb and a potential link change occurred */
if ( tulip_debug > 1 )
printk ( KERN_INFO " %s: PNIC2 %s link beat %s. \n " ,
dev - > name , medianame [ dev - > if_port ] ,
( csr12 & 4 ) ? " failed " : " good " ) ;
tp - > nway = 0 ;
tp - > nwayset = 1 ;
/* if failed, try doing an nway to get in sync */
if ( ( csr12 & 4 ) & & ! tp - > medialock ) {
del_timer_sync ( & tp - > timer ) ;
pnic2_start_nway ( dev ) ;
tp - > timer . expires = RUN_AT ( 3 * HZ ) ;
add_timer ( & tp - > timer ) ;
}
return ;
}
if ( tulip_debug > 1 )
printk ( KERN_INFO " %s: PNIC2 Link Change Default? \n " , dev - > name ) ;
/* if all else fails default to trying 10baseT-HD */
dev - > if_port = 0 ;
/* make sure autonegotiate enable is off */
csr14 = ( ioread32 ( ioaddr + CSR14 ) & 0xffffff7f ) ;
iowrite32 ( csr14 , ioaddr + CSR14 ) ;
/* set to 10baseTx-HD - see Data Port Selection
* comment given at the top of the file
*/
tp - > csr6 = ( ioread32 ( ioaddr + CSR6 ) & 0xfe3bd1fd ) ;
tp - > csr6 | = 0x00400000 ;
tulip_restart_rxtx ( tp ) ;
}