patch-2.1.101 linux/drivers/net/sunhme.c

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

diff -u --recursive --new-file v2.1.100/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
@@ -58,6 +58,70 @@
 #undef SXDEBUG
 #undef RXDEBUG
 #undef TXDEBUG
+#undef TXLOGGING
+
+#ifdef TXLOGGING
+struct hme_tx_logent {
+	unsigned int tstamp;
+	int tx_new, tx_old;
+	unsigned int action;
+#define TXLOG_ACTION_IRQ	0x01
+#define TXLOG_ACTION_TXMIT	0x02
+#define TXLOG_ACTION_TBUSY	0x04
+#define TXLOG_ACTION_NBUFS	0x08
+	unsigned int status;
+};
+#define TX_LOG_LEN	128
+static struct hme_tx_logent tx_log[TX_LOG_LEN];
+static int txlog_cur_entry = 0;
+static __inline__ void tx_add_log(struct happy_meal *hp, unsigned int a, unsigned int s)
+{
+	struct hme_tx_logent *tlp;
+	unsigned long flags;
+
+	save_and_cli(flags);
+	tlp = &tx_log[txlog_cur_entry];
+	tlp->tstamp = (unsigned int)jiffies;
+	tlp->tx_new = hp->tx_new;
+	tlp->tx_old = hp->tx_old;
+	tlp->action = a;
+	tlp->status = s;
+	txlog_cur_entry = (txlog_cur_entry + 1) & (TX_LOG_LEN - 1);
+	restore_flags(flags);
+}
+static __inline__ void tx_dump_log(void)
+{
+	int i, this;
+
+	this = txlog_cur_entry;
+	for(i = 0; i < TX_LOG_LEN; i++) {
+		printk("TXLOG[%d]: j[%08x] tx[N(%d)O(%d)] action[%08x] stat[%08x]\n", i,
+		       tx_log[this].tstamp,
+		       tx_log[this].tx_new, tx_log[this].tx_old,
+		       tx_log[this].action, tx_log[this].status);
+		this = (this + 1) & (TX_LOG_LEN - 1);
+	}
+}
+static __inline__ void tx_dump_ring(struct happy_meal *hp)
+{
+	struct hmeal_init_block *hb = hp->happy_block;
+	struct happy_meal_txd *tp = &hb->happy_meal_txd[0];
+	int i;
+
+	for(i = 0; i < TX_RING_SIZE; i+=4) {
+		printk("TXD[%d..%d]: [%08x:%08x] [%08x:%08x] [%08x:%08x] [%08x:%08x]\n",
+		       i, i + 4,
+		       le32_to_cpu(tp[i].tx_flags), le32_to_cpu(tp[i].tx_addr),
+		       le32_to_cpu(tp[i + 1].tx_flags), le32_to_cpu(tp[i + 1].tx_addr),
+		       le32_to_cpu(tp[i + 2].tx_flags), le32_to_cpu(tp[i + 2].tx_addr),
+		       le32_to_cpu(tp[i + 3].tx_flags), le32_to_cpu(tp[i + 3].tx_addr));
+	}
+}
+#else
+#define tx_add_log(hp, a, s)		do { } while(0)
+#define tx_dump_log()			do { } while(0)
+#define tx_dump_ring(hp)		do { } while(0)
+#endif
 
 #ifdef HMEDEBUG
 #define HMD(x)  printk x
@@ -73,7 +137,7 @@
 #define ASD(x)
 #endif
 
-#define DEFAULT_IPG0      32 /* For lance-mode only */
+#define DEFAULT_IPG0      16 /* For lance-mode only */
 #define DEFAULT_IPG1       8 /* For all modes */
 #define DEFAULT_IPG2       4 /* For all modes */
 #define DEFAULT_JAMSIZE    4 /* Toe jam */
@@ -376,18 +440,33 @@
 			full = 0;
 	}
 
-	/* XXX This may not be enough, we may need to reinit the entire
-	 * XXX Happy Meal front end for this to work every time.
+	/* Before changing other bits in the tx_cfg register, and in
+	 * general any of other the TX config registers too, you
+	 * must:
+	 * 1) Clear Enable
+	 * 2) Poll with reads until that bit reads back as zero
+	 * 3) Make TX configuration changes
+	 * 4) Set Enable once more
 	 */
-	if(full)
+	hme_write32(hp, &hp->bigmacregs->tx_cfg,
+		    hme_read32(hp, &hp->bigmacregs->tx_cfg) &
+		    ~(BIGMAC_TXCFG_ENABLE));
+	while(hme_read32(hp, &hp->bigmacregs->tx_cfg) & BIGMAC_TXCFG_ENABLE)
+		barrier();
+	if(full) {
+		hp->happy_flags |= HFLAG_FULL;
 		hme_write32(hp, &hp->bigmacregs->tx_cfg,
 			    hme_read32(hp, &hp->bigmacregs->tx_cfg) |
 			    BIGMAC_TXCFG_FULLDPLX);
-	else
+	} else {
+		hp->happy_flags &= ~(HFLAG_FULL);
 		hme_write32(hp, &hp->bigmacregs->tx_cfg,
 			    hme_read32(hp, &hp->bigmacregs->tx_cfg) &
 			    ~(BIGMAC_TXCFG_FULLDPLX));
-
+	}
+	hme_write32(hp, &hp->bigmacregs->tx_cfg,
+		    hme_read32(hp, &hp->bigmacregs->tx_cfg) |
+		    BIGMAC_TXCFG_ENABLE);
 	return 0;
 no_response:
 	return 1;
@@ -1220,8 +1299,8 @@
 	/* Load up the MAC address and random seed. */
 	HMD(("rseed/macaddr, "));
 
-	/* XXX use something less deterministic... */
-	hme_write32(hp, &bregs->rand_seed, 0xbd);
+	/* The docs recommend to use the 10LSB of our MAC here. */
+	hme_write32(hp, &bregs->rand_seed, ((e[5] | e[4]<<8)&0x3ff));
 
 	hme_write32(hp, &bregs->mac_addr2, ((e[4] << 8) | e[5]));
 	hme_write32(hp, &bregs->mac_addr1, ((e[2] << 8) | e[3]));
@@ -2013,7 +2092,7 @@
 		hp->dev->tbusy = 0;
 		mark_bh(NET_BH);
 	}
-
+	tx_add_log(hp, TXLOG_ACTION_IRQ, happy_status);
 	dev->interrupt = 0;
 	HMD(("done\n"));
 }
@@ -2154,29 +2233,29 @@
 	struct happy_meal *hp = (struct happy_meal *) dev->priv;
 	int len, entry;
 
-	if(dev->tbusy) {
+	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
 		int tickssofar = jiffies - dev->trans_start;
 	    
-		if (tickssofar < 40) {
-			return 1;
-		} else {
+		if (tickssofar >= 40) {
 			printk ("%s: transmit timed out, resetting\n", dev->name);
 			hp->net_stats.tx_errors++;
+			tx_dump_log();
+			printk ("%s: Happy Status %08x TX[%08x:%08x]\n", dev->name,
+				hme_read32(hp, &hp->gregs->stat),
+				hme_read32(hp, &hp->etxregs->cfg),
+				hme_read32(hp, &hp->bigmacregs->tx_cfg));
 			happy_meal_init(hp, 0);
 			dev->tbusy = 0;
 			dev->trans_start = jiffies;
-			return 0;
-		}
-	}
-
-	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
-		printk("happy meal: Transmitter access conflict.\n");
+		} else
+			tx_add_log(hp, TXLOG_ACTION_TXMIT|TXLOG_ACTION_TBUSY, 0);
 		return 1;
 	}
 
-	if(!TX_BUFFS_AVAIL(hp))
+	if(!TX_BUFFS_AVAIL(hp)) {
+		tx_add_log(hp, TXLOG_ACTION_TXMIT|TXLOG_ACTION_NBUFS, 0);
 		return 1;
-
+	}
 	len = skb->len;
 	entry = hp->tx_new;
 
@@ -2194,6 +2273,7 @@
 	if(TX_BUFFS_AVAIL(hp))
 		dev->tbusy = 0;
 
+	tx_add_log(hp, TXLOG_ACTION_TXMIT, 0);
 	return 0;
 }
 
@@ -2203,29 +2283,32 @@
 	struct happy_meal *hp = (struct happy_meal *) dev->priv;
 	int len, entry;
 
-	if(dev->tbusy) {
+	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
 		int tickssofar = jiffies - dev->trans_start;
 	    
-		if (tickssofar < 40) {
-			return 1;
-		} else {
+		if (tickssofar >= 40) {
+			unsigned long flags;
+
 			printk ("%s: transmit timed out, resetting\n", dev->name);
+
+			save_and_cli(flags);
+			tx_dump_log();
+			tx_dump_ring(hp);
+			restore_flags(flags);
+
 			hp->net_stats.tx_errors++;
 			happy_meal_init(hp, 0);
 			dev->tbusy = 0;
 			dev->trans_start = jiffies;
-			return 0;
-		}
-	}
-
-	if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
-		printk("happy meal: Transmitter access conflict.\n");
+		} else
+			tx_add_log(hp, TXLOG_ACTION_TXMIT|TXLOG_ACTION_TBUSY, 0);
 		return 1;
 	}
 
-	if(!TX_BUFFS_AVAIL(hp))
+	if(!TX_BUFFS_AVAIL(hp)) {
+		tx_add_log(hp, TXLOG_ACTION_TXMIT|TXLOG_ACTION_NBUFS, 0);
 		return 1;
-
+	}
 	len = skb->len;
 	entry = hp->tx_new;
 
@@ -2243,6 +2326,7 @@
 	if(TX_BUFFS_AVAIL(hp))
 		dev->tbusy = 0;
 
+	tx_add_log(hp, TXLOG_ACTION_TXMIT, 0);
 	return 0;
 }
 #endif
@@ -2629,6 +2713,11 @@
 	pcibios_write_config_word(pdev->bus->number,
 				  pdev->devfn,
 				  PCI_COMMAND, pci_command);
+
+	/* Set the latency timer as well, PROM leaves it at zero. */
+	pcibios_write_config_byte(pdev->bus->number,
+				  pdev->devfn,
+				  PCI_LATENCY_TIMER, 240);
 
 #ifdef MODULE
 	/* We are home free at this point, link us in to the happy

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov