patch-2.4.10 linux/drivers/net/gmac.c

Next file: linux/drivers/net/gmac.h
Previous file: linux/drivers/net/fealnx.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.9/linux/drivers/net/gmac.c linux/drivers/net/gmac.c
@@ -12,7 +12,10 @@
  * BenH <benh@kernel.crashing.org> - 03/09/2000
  * - Add support for new PHYs
  * - Add some PowerBook sleep code
- * 
+ * BenH <benh@kernel.crashing.org> - ??/??/????
+ *  - PHY updates
+ * BenH <benh@kernel.crashing.org> - 08/08/2001
+ * - Add more PHYs, fixes to sleep code
  */
 
 #include <linux/module.h>
@@ -46,8 +49,8 @@
 
 #define DEBUG_PHY
 
-/* Driver version 1.3, kernel 2.4.x */
-#define GMAC_VERSION	"v1.4k4"
+/* Driver version 1.5, kernel 2.4.x */
+#define GMAC_VERSION	"v1.5k4"
 
 #define DUMMY_BUF_LEN	RX_BUF_ALLOC_SIZE + RX_OFFSET + GMAC_BUFFER_ALIGN
 static unsigned char *dummy_buf;
@@ -213,7 +216,7 @@
 		int		link_100 = 0;
 		int		gigabit = 0;
 #ifdef DEBUG_PHY
-		printk("%s: Link state change, phy_status: 0x%04x\n",
+		printk(KERN_INFO "%s: Link state change, phy_status: 0x%04x\n",
 			gm->dev->name, phy_status);
 #endif
 		gm->phy_status = phy_status;
@@ -228,37 +231,49 @@
 		/* Link ? Check for speed and duplex */
 		if ((phy_status & MII_SR_LKS) && (phy_status & MII_SR_ASSC)) {
 		    int restart = 0;
-		    if (gm->phy_type == PHY_B5201) {
-		    	int aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5201_AUXCTLSTATUS);
+		    int aux_stat, link;
+		    switch (gm->phy_type) {
+		      case PHY_B5201:
+		      case PHY_B5221:
+		    	aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5201_AUXCTLSTATUS);
 #ifdef DEBUG_PHY
-			printk("    Link up ! BCM5201 aux_stat: 0x%04x\n", aux_stat);
+			printk(KERN_INFO "%s:    Link up ! BCM5201/5221 aux_stat: 0x%04x\n",
+				gm->dev->name, aux_stat);
 #endif
 		    	full_duplex = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_DUPLEX) != 0);
 		    	link_100 = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_SPEED) != 0);
-		    } else if (gm->phy_type == PHY_B5400) {
-		    	int aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXSTATUS);
-		    	int link = (aux_stat & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
+		        break;
+		      case PHY_B5400:
+		      case PHY_B5401:
+		      case PHY_B5411:
+		    	aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXSTATUS);
+		    	link = (aux_stat & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
 		    			MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT;
 #ifdef DEBUG_PHY
-			printk("    Link up ! BCM5400 aux_stat: 0x%04x (link mode: %d)\n",
-				aux_stat, link);
+			printk(KERN_INFO "%s:    Link up ! BCM54xx aux_stat: 0x%04x (link mode: %d)\n",
+				gm->dev->name, aux_stat, link);
 #endif
 		    	full_duplex = phy_BCM5400_link_table[link][0];
 		    	link_100 = phy_BCM5400_link_table[link][1];
 		    	gigabit = phy_BCM5400_link_table[link][2];
-		    } else if (gm->phy_type == PHY_LXT971) {
-		    	int stat2 = mii_read(gm, gm->phy_addr, MII_LXT971_STATUS2);
+		    	break;
+		      case PHY_LXT971:
+		    	aux_stat = mii_read(gm, gm->phy_addr, MII_LXT971_STATUS2);
 #ifdef DEBUG_PHY
-			printk("    Link up ! LXT971 stat2: 0x%04x\n", stat2);
+			printk(KERN_INFO "%s:    Link up ! LXT971 stat2: 0x%04x\n",
+				gm->dev->name, aux_stat);
 #endif
-		    	full_duplex = ((stat2 & MII_LXT971_STATUS2_FULLDUPLEX) != 0);
-		    	link_100 = ((stat2 & MII_LXT971_STATUS2_SPEED) != 0);
-		    } else {
+		    	full_duplex = ((aux_stat & MII_LXT971_STATUS2_FULLDUPLEX) != 0);
+		    	link_100 = ((aux_stat & MII_LXT971_STATUS2_SPEED) != 0);
+		    	break;
+		      default:
 		    	full_duplex = (lpar_ability & MII_ANLPA_FDAM) != 0;
 		    	link_100 = (lpar_ability & MII_ANLPA_100M) != 0;
+		    	break;
 		    }
 #ifdef DEBUG_PHY
-		    printk("    full_duplex: %d, speed: %s\n", full_duplex,
+		    printk(KERN_INFO "%s:    Full Duplex: %d, Speed: %s\n",
+		    	gm->dev->name, full_duplex,
 		    	gigabit ? "1000" : (link_100 ? "100" : "10"));
 #endif
                     if (gigabit != gm->gigabit) {
@@ -275,13 +290,15 @@
 			gmac_start_dma(gm);
 		} else if (!(phy_status & MII_SR_LKS)) {
 #ifdef DEBUG_PHY
-		    printk("    Link down !\n");
+		    printk(KERN_INFO "%s:    Link down !\n", gm->dev->name);
 #endif
 		}
 	}
 }
 
 /* Power management: stop PHY chip for suspend mode
+ * 
+ * TODO: This will have to be modified is WOL is to be supported.
  */
 static void
 gmac_suspend(struct gmac* gm)
@@ -290,7 +307,7 @@
 	unsigned long flags;
 	
 	gm->sleeping = 1;
-	netif_stop_queue(gm->dev);
+	netif_device_detach(gm->dev);
 
 
 	spin_lock_irqsave(&gm->lock, flags);
@@ -318,7 +335,7 @@
 	}
 
 	/* Clear interrupts on 5201 */
-	if (gm->phy_type == PHY_B5201)
+	if (gm->phy_type == PHY_B5201 || gm->phy_type == PHY_B5221)
 		mii_write(gm, gm->phy_addr, MII_BCM5201_INTERRUPT, 0);
 		
 	/* Drive MDIO high */
@@ -328,12 +345,6 @@
 	data = mii_read(gm, gm->phy_addr, MII_ANLPA);
 	mii_write(gm, gm->phy_addr, MII_ANLPA, data);
 	
-	/* Put MDIO in sane state */
-	GM_OUT(GM_MIF_CFG, GM_MIF_CFGBB);
-	GM_OUT(GM_MIF_BB_CLOCK, 0);
-	GM_OUT(GM_MIF_BB_DATA, 0);
-	GM_OUT(GM_MIF_BB_OUT_ENABLE, 0);
-	
 	/* Stop everything */
 	GM_OUT(GM_MAC_RX_CONFIG, 0);
 	GM_OUT(GM_MAC_TX_CONFIG, 0);
@@ -341,7 +352,7 @@
 	GM_OUT(GM_TX_CONF, 0);
 	GM_OUT(GM_RX_CONF, 0);
 	
-	/* Set reset state */
+	/* Set MAC in reset state */
 	GM_OUT(GM_RESET, GM_RESET_TX | GM_RESET_RX);
 	for (timeout = 100; timeout > 0; --timeout) {
 		mdelay(10);
@@ -352,11 +363,23 @@
 	GM_OUT(GM_MAC_RX_RESET, GM_MAC_RX_RESET_NOW);
 
 	/* Superisolate PHY */
-	if (gm->phy_type == PHY_B5201)
+	if (gm->phy_type == PHY_B5201 || gm->phy_type == PHY_B5221)
 		mii_write(gm, gm->phy_addr, MII_BCM5201_MULTIPHY,
 			MII_BCM5201_MULTIPHY_SUPERISOLATE);
 
-	/* Unclock chip */
+	/* Put MDIO in sane electric state. According to an obscure
+	 * Apple comment, not doing so may let them drive some current
+	 * during sleep and possibly damage BCM PHYs.
+	 */
+	GM_OUT(GM_MIF_CFG, GM_MIF_CFGBB);
+	GM_OUT(GM_MIF_BB_CLOCK, 0);
+	GM_OUT(GM_MIF_BB_DATA, 0);
+	GM_OUT(GM_MIF_BB_OUT_ENABLE, 0);
+	GM_OUT(GM_MAC_XIF_CONFIG,
+		GM_MAC_XIF_CONF_GMII_MODE|GM_MAC_XIF_CONF_MII_INT_LOOP);
+	(void)GM_IN(GM_MAC_XIF_CONFIG);
+	
+	/* Unclock the GMAC chip */
 	gmac_set_power(gm, 0);
 }
 
@@ -390,7 +413,7 @@
 	mdelay(20);
 	GM_BIS(GM_MAC_RX_CONFIG, GM_MAC_RX_CONF_ENABLE);
 	mdelay(20);
-	if (gm->phy_type == PHY_B5201) {
+	if (gm->phy_type == PHY_B5201 || gm->phy_type == PHY_B5221) {
 		data = mii_read(gm, gm->phy_addr, MII_BCM5201_MULTIPHY);
 		mii_write(gm, gm->phy_addr, MII_BCM5201_MULTIPHY,
 			data & ~MII_BCM5201_MULTIPHY_SUPERISOLATE);
@@ -402,7 +425,7 @@
 		mii_interrupt(gm);
 		/* restart DMA operations */
 		gmac_start_dma(gm);
-		netif_start_queue(gm->dev);
+		netif_device_attach(gm->dev);
 		enable_irq(gm->dev->irq);
 	} else {
 		/* Driver not opened, just leave things off. Note that
@@ -446,11 +469,19 @@
 	return 0;
 }
 
+/* Here's a bunch of configuration routines for
+ * Broadcom PHYs used on various Mac models. Unfortunately,
+ * except for the 5201, Broadcom never sent me any documentation,
+ * so this is from my understanding of Apple's Open Firmware
+ * drivers and Darwin's implementation
+ */
+ 
 static void
 mii_init_BCM5400(struct gmac *gm)
 {
 	int data;
 
+	/* Configure for gigabit full duplex */
 	data = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL);
 	data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
 	mii_write(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL, data);
@@ -460,6 +491,8 @@
 	mii_write(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL, data);
 	
 	mdelay(10);
+
+	/* Reset and configure cascaded 10/100 PHY */
 	mii_do_reset_phy(gm, 0x1f);
 	
 	data = mii_read(gm, 0x1f, MII_BCM5201_MULTIPHY);
@@ -479,7 +512,14 @@
 
 	rev = mii_read(gm, gm->phy_addr, MII_ID1) & 0x000f;
 	if (rev == 0 || rev == 3) {
-		/* A bit of black magic from Apple */
+		/* Some revisions of 5401 appear to need this
+		 * initialisation sequence to disable, according
+		 * to OF, "tap power management"
+		 * 
+		 * WARNING ! OF and Darwin don't agree on the
+		 * register addresses. OF seem to interpret the
+		 * register numbers below as decimal
+		 */
 		mii_write(gm, gm->phy_addr, 0x18, 0x0c20);
 		mii_write(gm, gm->phy_addr, 0x17, 0x0012);
 		mii_write(gm, gm->phy_addr, 0x15, 0x1804);
@@ -493,11 +533,14 @@
 		mii_write(gm, gm->phy_addr, 0x15, 0x0a20);
 	}
 	
+	/* Configure for gigabit full duplex */
 	data = mii_read(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL);
 	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
 	mii_write(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL, data);
 
 	mdelay(10);
+
+	/* Reset and configure cascaded 10/100 PHY */
 	mii_do_reset_phy(gm, 0x1f);
 	
 	data = mii_read(gm, 0x1f, MII_BCM5201_MULTIPHY);
@@ -505,6 +548,34 @@
 	mii_write(gm, 0x1f, MII_BCM5201_MULTIPHY, data);
 }
 
+static void
+mii_init_BCM5411(struct gmac *gm)
+{
+	int data;
+
+	/* Here's some more Apple black magic to setup
+	 * some voltage stuffs.
+	 */
+	mii_write(gm, gm->phy_addr, 0x1c, 0x8c23);
+	mii_write(gm, gm->phy_addr, 0x1c, 0x8ca3);
+	mii_write(gm, gm->phy_addr, 0x1c, 0x8c23);
+
+	/* Here, Apple seems to want to reset it, do
+	 * it as well
+	 */
+	mii_write(gm, gm->phy_addr, MII_CR, MII_CR_RST);
+
+	/* Start autoneg */
+	mii_write(gm, gm->phy_addr, MII_CR,
+			MII_CR_ASSE|MII_CR_FDM|	/* Autospeed, full duplex */
+			MII_CR_RAN|
+			MII_CR_SPEEDSEL2 /* chip specific, gigabit enable ? */);
+
+	data = mii_read(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL);
+	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+	mii_write(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL, data);
+}
+
 static int
 mii_lookup_and_reset(struct gmac *gm)
 {
@@ -536,29 +607,34 @@
 	gm->phy_id = (mii_read(gm, gm->phy_addr, MII_ID0) << 16) |
 		mii_read(gm, gm->phy_addr, MII_ID1);
 #ifdef DEBUG_PHY
-	printk("%s PHY ID: 0x%08x\n", gm->dev->name, gm->phy_id);
+	printk(KERN_INFO "%s: PHY ID: 0x%08x\n", gm->dev->name, gm->phy_id);
 #endif
 	if ((gm->phy_id & MII_BCM5400_MASK) == MII_BCM5400_ID) {
 		gm->phy_type = PHY_B5400;
-		printk(KERN_ERR "%s Found Broadcom BCM5400 PHY (Gigabit)\n",
+		printk(KERN_INFO  "%s: Found Broadcom BCM5400 PHY (Gigabit)\n",
 			gm->dev->name);
 		mii_init_BCM5400(gm);		
 	} else if ((gm->phy_id & MII_BCM5401_MASK) == MII_BCM5401_ID) {
 		gm->phy_type = PHY_B5401;
-		printk(KERN_ERR "%s Found Broadcom BCM5401 PHY (Gigabit)\n",
+		printk(KERN_INFO  "%s: Found Broadcom BCM5401 PHY (Gigabit)\n",
 			gm->dev->name);
 		mii_init_BCM5401(gm);		
+	} else if ((gm->phy_id & MII_BCM5411_MASK) == MII_BCM5411_ID) {
+		gm->phy_type = PHY_B5411;
+		printk(KERN_INFO  "%s: Found Broadcom BCM5411 PHY (Gigabit)\n",
+			gm->dev->name);
+		mii_init_BCM5411(gm);		
 	} else if ((gm->phy_id & MII_BCM5201_MASK) == MII_BCM5201_ID) {
 		gm->phy_type = PHY_B5201;
-		printk(KERN_INFO "%s Found Broadcom BCM5201 PHY\n", gm->dev->name);
+		printk(KERN_INFO "%s: Found Broadcom BCM5201 PHY\n", gm->dev->name);
 	} else if ((gm->phy_id & MII_BCM5221_MASK) == MII_BCM5221_ID) {
-		gm->phy_type = PHY_B5201; /* Same as 5201 for now */
-		printk(KERN_INFO "%s Found Broadcom BCM5221 PHY\n", gm->dev->name);
+		gm->phy_type = PHY_B5221;
+		printk(KERN_INFO "%s: Found Broadcom BCM5221 PHY\n", gm->dev->name);
 	} else if ((gm->phy_id & MII_LXT971_MASK) == MII_LXT971_ID) {
 		gm->phy_type = PHY_LXT971;
-		printk(KERN_INFO "%s Found LevelOne LX971 PHY\n", gm->dev->name);
+		printk(KERN_INFO "%s: Found LevelOne LX971 PHY\n", gm->dev->name);
 	} else {
-		printk(KERN_ERR "%s: Warning ! Unknown PHY ID 0x%08x, using generic mode...\n",
+		printk(KERN_WARNING "%s: Warning ! Unknown PHY ID 0x%08x, using generic mode...\n",
 			gm->dev->name, gm->phy_id);
 	}
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)