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
--- 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
*/