6424735 bge driver should support relaxed ordering
authorzh199473
Wed, 28 Mar 2007 00:46:13 -0700
changeset 3907 06a70d1289cb
parent 3906 6bf378350201
child 3908 211a66d0821f
6424735 bge driver should support relaxed ordering 6426339 boston bge hardware reporting critical issue through fma. 6462563 Broadcom 5703 needs to be added to /etc/driver_aliases & /kernel/drv/bge.conf for GRUB with HP BL20p
usr/src/uts/common/io/bge/bge.conf
usr/src/uts/common/io/bge/bge_chip2.c
usr/src/uts/common/io/bge/bge_hw.h
usr/src/uts/common/io/bge/bge_impl.h
usr/src/uts/common/io/bge/bge_kstats.c
usr/src/uts/common/io/bge/bge_main2.c
--- a/usr/src/uts/common/io/bge/bge.conf	Tue Mar 27 22:00:10 2007 -0700
+++ b/usr/src/uts/common/io/bge/bge.conf	Wed Mar 28 00:46:13 2007 -0700
@@ -2,9 +2,8 @@
 # CDDL HEADER START
 #
 # The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
 #
 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 # or http://www.opensolaris.org/os/licensing.
@@ -21,7 +20,7 @@
 #
 #########################################################################
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -165,6 +164,7 @@
 			  0x10280109,
 			  0x1028865d,
 			  0x0e11005a,
+			  0x0e1100cb,
 			  0x103c12bc;
 #########################################################################
 #
--- a/usr/src/uts/common/io/bge/bge_chip2.c	Tue Mar 27 22:00:10 2007 -0700
+++ b/usr/src/uts/common/io/bge/bge_chip2.c	Wed Mar 28 00:46:13 2007 -0700
@@ -52,6 +52,11 @@
 #endif
 
 /*
+ * PCI-X/PCI-E relaxed ordering tunable for OS/Nexus driver
+ */
+boolean_t bge_relaxed_ordering = B_TRUE;
+
+/*
  * Property names
  */
 static char knownids_propname[] = "bge-known-subsystems";
@@ -3212,7 +3217,7 @@
 	/* Enable MSI code */
 	if (bgep->intr_type == DDI_INTR_TYPE_MSI)
 		bge_reg_set32(bgep, MSI_MODE_REG,
-		    MSI_PRI_HIGHEST|MSI_MSI_ENABLE);
+		    MSI_PRI_HIGHEST|MSI_MSI_ENABLE|MSI_ERROR_ATTENTION);
 
 	/*
 	 * On the first time through, save the factory-set MAC address
@@ -3835,7 +3840,7 @@
 	bge_t *bgep = (bge_t *)arg1;		/* private device info	*/
 	bge_status_t *bsp;
 	uint64_t flags;
-	uint32_t mlcr = 0;
+	uint32_t regval;
 	uint_t result;
 	int retval;
 
@@ -3848,158 +3853,169 @@
 	 */
 	ASSERT(bgep->progress & PROGRESS_HWINT);
 
-	/*
-	 * Check whether chip's says it's asserting #INTA;
-	 * if not, don't process or claim the interrupt.
-	 *
-	 * Note that the PCI signal is active low, so the
-	 * bit is *zero* when the interrupt is asserted.
-	 */
 	result = DDI_INTR_UNCLAIMED;
 	mutex_enter(bgep->genlock);
 
-	if (bgep->intr_type == DDI_INTR_TYPE_FIXED)
-		mlcr = bge_reg_get32(bgep, MISC_LOCAL_CONTROL_REG);
-
-	BGE_DEBUG(("bge_intr($%p) ($%p) mlcr 0x%08x", arg1, arg2, mlcr));
-
-	if ((mlcr & MLCR_INTA_STATE) == 0) {
+	if (bgep->intr_type == DDI_INTR_TYPE_FIXED) {
 		/*
-		 * Block further PCI interrupts ...
+		 * Check whether chip's says it's asserting #INTA;
+		 * if not, don't process or claim the interrupt.
+		 *
+		 * Note that the PCI signal is active low, so the
+		 * bit is *zero* when the interrupt is asserted.
 		 */
-		result = DDI_INTR_CLAIMED;
-
-		if (bgep->intr_type == DDI_INTR_TYPE_FIXED) {
-			bge_reg_set32(bgep, PCI_CONF_BGE_MHCR,
-				MHCR_MASK_PCI_INT_OUTPUT);
-			if (bge_check_acc_handle(bgep, bgep->cfg_handle) !=
-			    DDI_FM_OK)
+		regval = bge_reg_get32(bgep, MISC_LOCAL_CONTROL_REG);
+		if (regval & MLCR_INTA_STATE) {
+			if (bge_check_acc_handle(bgep, bgep->io_handle)
+			    != DDI_FM_OK)
 				goto chip_stop;
+			mutex_exit(bgep->genlock);
+			return (result);
 		}
 
 		/*
-		 * Sync the status block and grab the flags-n-tag from it.
-		 * We count the number of interrupts where there doesn't
-		 * seem to have been a DMA update of the status block; if
-		 * it *has* been updated, the counter will be cleared in
-		 * the while() loop below ...
+		 * Block further PCI interrupts ...
+		 */
+		bge_reg_set32(bgep, PCI_CONF_BGE_MHCR,
+		    MHCR_MASK_PCI_INT_OUTPUT);
+
+	} else {
+		/*
+		 * Check MSI status
 		 */
-		bgep->missed_dmas += 1;
-		bsp = DMA_VPTR(bgep->status_block);
-		for (;;) {
-			if (bgep->bge_chip_state != BGE_CHIP_RUNNING) {
-				/*
-				 * bge_chip_stop() may have freed dma area etc
-				 * while we were in this interrupt handler -
-				 * better not call bge_status_sync()
-				 */
-				(void) bge_check_acc_handle(bgep,
-				    bgep->io_handle);
-				mutex_exit(bgep->genlock);
-				return (DDI_INTR_CLAIMED);
-			}
-			retval = bge_status_sync(bgep, STATUS_FLAG_UPDATED,
-			    &flags);
-			if (retval != DDI_FM_OK) {
-				bgep->bge_dma_error = B_TRUE;
-				goto chip_stop;
-			}
-
-			if (!(flags & STATUS_FLAG_UPDATED))
-				break;
-
+		regval = bge_reg_get32(bgep, MSI_STATUS_REG);
+		if (regval & MSI_ERROR_ATTENTION) {
+			BGE_REPORT((bgep, "msi error attention,"
+			    " status=0x%x", regval));
+			bge_reg_put32(bgep, MSI_STATUS_REG, regval);
+		}
+	}
+
+	result = DDI_INTR_CLAIMED;
+
+	BGE_DEBUG(("bge_intr($%p) ($%p) regval 0x%08x", arg1, arg2, regval));
+
+	/*
+	 * Sync the status block and grab the flags-n-tag from it.
+	 * We count the number of interrupts where there doesn't
+	 * seem to have been a DMA update of the status block; if
+	 * it *has* been updated, the counter will be cleared in
+	 * the while() loop below ...
+	 */
+	bgep->missed_dmas += 1;
+	bsp = DMA_VPTR(bgep->status_block);
+	for (;;) {
+		if (bgep->bge_chip_state != BGE_CHIP_RUNNING) {
 			/*
-			 * Tell the chip that we're processing the interrupt
+			 * bge_chip_stop() may have freed dma area etc
+			 * while we were in this interrupt handler -
+			 * better not call bge_status_sync()
 			 */
-			bge_mbx_put(bgep, INTERRUPT_MBOX_0_REG,
-				INTERRUPT_MBOX_DISABLE(flags));
-			if (bge_check_acc_handle(bgep, bgep->io_handle) !=
-			    DDI_FM_OK)
-				goto chip_stop;
-
-			/*
-			 * Drop the mutex while we:
-			 * 	Receive any newly-arrived packets
-			 *	Recycle any newly-finished send buffers
-			 */
-			bgep->bge_intr_running = B_TRUE;
+			(void) bge_check_acc_handle(bgep,
+			    bgep->io_handle);
 			mutex_exit(bgep->genlock);
-			bge_receive(bgep, bsp);
-			bge_recycle(bgep, bsp);
-			mutex_enter(bgep->genlock);
-			bgep->bge_intr_running = B_FALSE;
-
-			/*
-			 * Tell the chip we've finished processing, and
-			 * give it the tag that we got from the status
-			 * block earlier, so that it knows just how far
-			 * we've gone.  If it's got more for us to do,
-			 * it will now update the status block and try
-			 * to assert an interrupt (but we've got the
-			 * #INTA blocked at present).  If we see the
-			 * update, we'll loop around to do some more.
-			 * Eventually we'll get out of here ...
-			 */
-			bge_mbx_put(bgep, INTERRUPT_MBOX_0_REG,
-				INTERRUPT_MBOX_ENABLE(flags));
-			bgep->missed_dmas = 0;
+			return (DDI_INTR_CLAIMED);
+		}
+		retval = bge_status_sync(bgep, STATUS_FLAG_UPDATED,
+		    &flags);
+		if (retval != DDI_FM_OK) {
+			bgep->bge_dma_error = B_TRUE;
+			goto chip_stop;
 		}
 
+		if (!(flags & STATUS_FLAG_UPDATED))
+			break;
+
+		/*
+		 * Tell the chip that we're processing the interrupt
+		 */
+		bge_mbx_put(bgep, INTERRUPT_MBOX_0_REG,
+		    INTERRUPT_MBOX_DISABLE(flags));
+		if (bge_check_acc_handle(bgep, bgep->io_handle) !=
+		    DDI_FM_OK)
+			goto chip_stop;
+
 		/*
-		 * Check for exceptional conditions that we need to handle
-		 *
-		 * Link status changed
-		 * Status block not updated
+		 * Drop the mutex while we:
+		 * 	Receive any newly-arrived packets
+		 *	Recycle any newly-finished send buffers
 		 */
-		if (flags & STATUS_FLAG_LINK_CHANGED)
-			bge_wake_factotum(bgep);
-
-		if (bgep->missed_dmas) {
-			/*
-			 * Probably due to the internal status tag not
-			 * being reset.  Force a status block update now;
-			 * this should ensure that we get an update and
-			 * a new interrupt.  After that, we should be in
-			 * sync again ...
-			 */
-			BGE_REPORT((bgep, "interrupt: flags 0x%llx - "
-				"not updated?", flags));
-			bge_reg_set32(bgep, HOST_COALESCE_MODE_REG,
-				COALESCE_NOW);
-
-			if (bgep->missed_dmas >= bge_dma_miss_limit) {
-				/*
-				 * If this happens multiple times in a row,
-				 * it means DMA is just not working.  Maybe
-				 * the chip's failed, or maybe there's a
-				 * problem on the PCI bus or in the host-PCI
-				 * bridge (Tomatillo).
-				 *
-				 * At all events, we want to stop further
-				 * interrupts and let the recovery code take
-				 * over to see whether anything can be done
-				 * about it ...
-				 */
-				bge_fm_ereport(bgep,
-				    DDI_FM_DEVICE_BADINT_LIMIT);
-				goto chip_stop;
-			}
-		}
+		bgep->bge_intr_running = B_TRUE;
+		mutex_exit(bgep->genlock);
+		bge_receive(bgep, bsp);
+		bge_recycle(bgep, bsp);
+		mutex_enter(bgep->genlock);
+		bgep->bge_intr_running = B_FALSE;
 
 		/*
-		 * Reenable assertion of #INTA, unless there's a DMA fault
+		 * Tell the chip we've finished processing, and
+		 * give it the tag that we got from the status
+		 * block earlier, so that it knows just how far
+		 * we've gone.  If it's got more for us to do,
+		 * it will now update the status block and try
+		 * to assert an interrupt (but we've got the
+		 * #INTA blocked at present).  If we see the
+		 * update, we'll loop around to do some more.
+		 * Eventually we'll get out of here ...
+		 */
+		bge_mbx_put(bgep, INTERRUPT_MBOX_0_REG,
+		    INTERRUPT_MBOX_ENABLE(flags));
+		bgep->missed_dmas = 0;
+	}
+
+	/*
+	 * Check for exceptional conditions that we need to handle
+	 *
+	 * Link status changed
+	 * Status block not updated
+	 */
+	if (flags & STATUS_FLAG_LINK_CHANGED)
+		bge_wake_factotum(bgep);
+
+	if (bgep->missed_dmas) {
+		/*
+		 * Probably due to the internal status tag not
+		 * being reset.  Force a status block update now;
+		 * this should ensure that we get an update and
+		 * a new interrupt.  After that, we should be in
+		 * sync again ...
 		 */
-		if (result == DDI_INTR_CLAIMED) {
-			if (bgep->intr_type == DDI_INTR_TYPE_FIXED) {
-				bge_reg_clr32(bgep, PCI_CONF_BGE_MHCR,
-					MHCR_MASK_PCI_INT_OUTPUT);
-				if (bge_check_acc_handle(bgep,
-				    bgep->cfg_handle) != DDI_FM_OK)
-					goto chip_stop;
-			}
+		BGE_REPORT((bgep, "interrupt: flags 0x%llx - "
+		    "not updated?", flags));
+		bgep->missed_updates++;
+		bge_reg_set32(bgep, HOST_COALESCE_MODE_REG,
+		    COALESCE_NOW);
+
+		if (bgep->missed_dmas >= bge_dma_miss_limit) {
+			/*
+			 * If this happens multiple times in a row,
+			 * it means DMA is just not working.  Maybe
+			 * the chip's failed, or maybe there's a
+			 * problem on the PCI bus or in the host-PCI
+			 * bridge (Tomatillo).
+			 *
+			 * At all events, we want to stop further
+			 * interrupts and let the recovery code take
+			 * over to see whether anything can be done
+			 * about it ...
+			 */
+			bge_fm_ereport(bgep,
+			    DDI_FM_DEVICE_BADINT_LIMIT);
+			goto chip_stop;
 		}
 	}
 
+	/*
+	 * Reenable assertion of #INTA, unless there's a DMA fault
+	 */
+	if (bgep->intr_type == DDI_INTR_TYPE_FIXED) {
+		bge_reg_clr32(bgep, PCI_CONF_BGE_MHCR,
+		    MHCR_MASK_PCI_INT_OUTPUT);
+		if (bge_check_acc_handle(bgep, bgep->cfg_handle) !=
+		    DDI_FM_OK)
+			goto chip_stop;
+	}
+
 	if (bge_check_acc_handle(bgep, bgep->io_handle) != DDI_FM_OK)
 		goto chip_stop;
 
--- a/usr/src/uts/common/io/bge/bge_hw.h	Tue Mar 27 22:00:10 2007 -0700
+++ b/usr/src/uts/common/io/bge/bge_hw.h	Wed Mar 28 00:46:13 2007 -0700
@@ -1065,6 +1065,9 @@
 #define	MSI_MODE_REG			0x6000
 #define	MSI_PRI_HIGHEST			0xc0000000
 #define	MSI_MSI_ENABLE			0x00000002
+#define	MSI_ERROR_ATTENTION		0x0000001c
+
+#define	MSI_STATUS_REG			0x6004
 
 #define	MODE_CONTROL_REG		0x6800
 #define	MODE_ROUTE_MCAST_TO_RX_RISC	0x40000000
--- a/usr/src/uts/common/io/bge/bge_impl.h	Tue Mar 27 22:00:10 2007 -0700
+++ b/usr/src/uts/common/io/bge/bge_impl.h	Wed Mar 28 00:46:13 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -924,6 +924,7 @@
 	 */
 	uint64_t		chip_resets;	/* # of chip RESETs	*/
 	uint64_t		missed_dmas;	/* # of missed DMAs	*/
+	uint64_t		missed_updates;	/* # of missed updates	*/
 	enum bge_mac_state	bge_mac_state;	/* definitions above	*/
 	enum bge_chip_state	bge_chip_state;	/* definitions above	*/
 	boolean_t		send_hw_tcp_csum;
@@ -1234,6 +1235,8 @@
 extern uint32_t bge_rx_count_norm;
 extern uint32_t bge_tx_count_norm;
 extern boolean_t bge_jumbo_enable;
+extern boolean_t bge_relaxed_ordering;
+
 void   bge_chip_msi_trig(bge_t *bgep);
 
 /* bge_kstats.c */
--- a/usr/src/uts/common/io/bge/bge_kstats.c	Tue Mar 27 22:00:10 2007 -0700
+++ b/usr/src/uts/common/io/bge/bge_kstats.c	Wed Mar 28 00:46:13 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -404,13 +404,14 @@
 	{ 18,				"watchdog"		},
 	{ 19,				"chip_resets"		},
 	{ 20,				"dma_misses"		},
+	{ 21,				"update_misses"		},
 
-	{ 21,				"misc_host_config"	},
-	{ 22,				"dma_rw_control"	},
-	{ 23,				"pci_bus_info"		},
+	{ 22,				"misc_host_config"	},
+	{ 23,				"dma_rw_control"	},
+	{ 24,				"pci_bus_info"		},
 
-	{ 24,				"buff_mgr_status"	},
-	{ 25,				"rcv_init_status"	},
+	{ 25,				"buff_mgr_status"	},
+	{ 26,				"rcv_init_status"	},
 
 	{ -1,				NULL 			}
 };
@@ -455,6 +456,7 @@
 	(knp++)->value.ui64 = bgep->watchdog;
 	(knp++)->value.ui64 = bgep->chip_resets;
 	(knp++)->value.ui64 = bgep->missed_dmas;
+	(knp++)->value.ui64 = bgep->missed_updates;
 
 	/*
 	 * Hold the mutex while accessing the chip registers
--- a/usr/src/uts/common/io/bge/bge_main2.c	Tue Mar 27 22:00:10 2007 -0700
+++ b/usr/src/uts/common/io/bge/bge_main2.c	Wed Mar 28 00:46:13 2007 -0700
@@ -33,7 +33,7 @@
  * This is the string displayed by modinfo, etc.
  * Make sure you keep the version ID up to date!
  */
-static char bge_ident[] = "Broadcom Gb Ethernet v0.55";
+static char bge_ident[] = "Broadcom Gb Ethernet v0.56";
 
 /*
  * Property names
@@ -1975,6 +1975,12 @@
 	txdescsize += BGE_STATUS_PADDING;
 
 	/*
+	 * Enable PCI relaxed ordering only for RX/TX data buffers
+	 */
+	if (bge_relaxed_ordering)
+		dma_attr.dma_attr_flags |= DDI_DMA_RELAXED_ORDERING;
+
+	/*
 	 * Allocate memory & handles for RX buffers
 	 */
 	ASSERT((rxbuffsize % BGE_SPLIT) == 0);
@@ -1998,6 +2004,8 @@
 			return (DDI_FAILURE);
 	}
 
+	dma_attr.dma_attr_flags &= ~DDI_DMA_RELAXED_ORDERING;
+
 	/*
 	 * Allocate memory & handles for receive return rings
 	 */