-2 Removals
+69 Additions
/*-/*-
* Copyright (c) 2001 Wind River Systems * Copyright (c) 2001 Wind River Systems
* Copyright (c) 1997, 1998, 1999, 2001 * Copyright (c) 1997, 1998, 1999, 2001
* Bill Paul <wpaul@windriver.com>. All rights reserved. * Bill Paul <wpaul@windriver.com>. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
* are met: * are met:
* 1. Redistributions of source code must retain the above copyright * 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright * 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software * 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement: * must display the following acknowledgement:
* This product includes software developed by Bill Paul. * This product includes software developed by Bill Paul.
* 4. Neither the name of the author nor the names of any co-contributors * 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software * may be used to endorse or promote products derived from this software
* without specific prior written permission. * without specific prior written permission.
* *
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <sys/cdefs.h>#include <sys/cdefs.h>
__FBSDID("$FreeBSD: stable/11/sys/dev/bge/if_bge.c 301103 2016-06-01 05:15:11Z sephe $");__FBSDID("$FreeBSD$");
/*/*
* Broadcom BCM57xx(x)/BCM590x NetXtreme and NetLink family Ethernet driver * Broadcom BCM57xx(x)/BCM590x NetXtreme and NetLink family Ethernet driver
* *
* The Broadcom BCM5700 is based on technology originally developed by * The Broadcom BCM5700 is based on technology originally developed by
* Alteon Networks as part of the Tigon I and Tigon II Gigabit Ethernet * Alteon Networks as part of the Tigon I and Tigon II Gigabit Ethernet
* MAC chips. The BCM5700, sometimes referred to as the Tigon III, has * MAC chips. The BCM5700, sometimes referred to as the Tigon III, has
* two on-board MIPS R4000 CPUs and can have as much as 16MB of external * two on-board MIPS R4000 CPUs and can have as much as 16MB of external
* SSRAM. The BCM5700 supports TCP, UDP and IP checksum offload, jumbo * SSRAM. The BCM5700 supports TCP, UDP and IP checksum offload, jumbo
* frames, highly configurable RX filtering, and 16 RX and TX queues * frames, highly configurable RX filtering, and 16 RX and TX queues
* (which, along with RX filter rules, can be used for QOS applications). * (which, along with RX filter rules, can be used for QOS applications).
* Other features, such as TCP segmentation, may be available as part * Other features, such as TCP segmentation, may be available as part
* of value-added firmware updates. Unlike the Tigon I and Tigon II, * of value-added firmware updates. Unlike the Tigon I and Tigon II,
* firmware images can be stored in hardware and need not be compiled * firmware images can be stored in hardware and need not be compiled
* into the driver. * into the driver.
* *
* The BCM5700 supports the PCI v2.2 and PCI-X v1.0 standards, and will * The BCM5700 supports the PCI v2.2 and PCI-X v1.0 standards, and will
* function in a 32-bit/64-bit 33/66Mhz bus, or a 64-bit/133Mhz bus. * function in a 32-bit/64-bit 33/66Mhz bus, or a 64-bit/133Mhz bus.
* *
* The BCM5701 is a single-chip solution incorporating both the BCM5700 * The BCM5701 is a single-chip solution incorporating both the BCM5700
* MAC and a BCM5401 10/100/1000 PHY. Unlike the BCM5700, the BCM5701 * MAC and a BCM5401 10/100/1000 PHY. Unlike the BCM5700, the BCM5701
* does not support external SSRAM. * does not support external SSRAM.
* *
* Broadcom also produces a variation of the BCM5700 under the "Altima" * Broadcom also produces a variation of the BCM5700 under the "Altima"
* brand name, which is functionally similar but lacks PCI-X support. * brand name, which is functionally similar but lacks PCI-X support.
* *
* Without external SSRAM, you can only have at most 4 TX rings, * Without external SSRAM, you can only have at most 4 TX rings,
* and the use of the mini RX ring is disabled. This seems to imply * and the use of the mini RX ring is disabled. This seems to imply
* that these features are simply not available on the BCM5701. As a * that these features are simply not available on the BCM5701. As a
* result, this driver does not implement any support for the mini RX * result, this driver does not implement any support for the mini RX
* ring. * ring.
*/ */
#ifdef HAVE_KERNEL_OPTION_HEADERS#ifdef HAVE_KERNEL_OPTION_HEADERS
#include "opt_device_polling.h"#include "opt_device_polling.h"
#endif#endif
#include <sys/param.h>#include <sys/param.h>
#include <sys/endian.h>#include <sys/endian.h>
#include <sys/systm.h>#include <sys/systm.h>
#include <sys/sockio.h>#include <sys/sockio.h>
#include <sys/mbuf.h>#include <sys/mbuf.h>
#include <sys/malloc.h>#include <sys/malloc.h>
#include <sys/kernel.h>#include <sys/kernel.h>
#include <sys/module.h>#include <sys/module.h>
#include <sys/socket.h>#include <sys/socket.h>
#include <sys/sysctl.h>#include <sys/sysctl.h>
#include <sys/taskqueue.h>#include <sys/taskqueue.h>
#include <net/if.h>#include <net/if.h>
#include <net/if_var.h>#include <net/if_var.h>
#include <net/if_arp.h>#include <net/if_arp.h>
#include <net/ethernet.h>#include <net/ethernet.h>
#include <net/if_dl.h>#include <net/if_dl.h>
#include <net/if_media.h>#include <net/if_media.h>
#include <net/bpf.h>#include <net/bpf.h>
#include <net/if_types.h>#include <net/if_types.h>
#include <net/if_vlan_var.h>#include <net/if_vlan_var.h>
#include <netinet/in_systm.h>#include <netinet/in_systm.h>
#include <netinet/in.h>#include <netinet/in.h>
#include <netinet/ip.h>#include <netinet/ip.h>
#include <netinet/tcp.h>#include <netinet/tcp.h>
#include <machine/bus.h>#include <machine/bus.h>
#include <machine/resource.h>#include <machine/resource.h>
#include <sys/bus.h>#include <sys/bus.h>
#include <sys/rman.h>#include <sys/rman.h>
#include <dev/mii/mii.h>#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>#include <dev/mii/miivar.h>
#include "miidevs.h"#include "miidevs.h"
#include <dev/mii/brgphyreg.h>#include <dev/mii/brgphyreg.h>
#ifdef __sparc64__#ifdef __sparc64__
#include <dev/ofw/ofw_bus.h>#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/openfirm.h>#include <dev/ofw/openfirm.h>
#include <machine/ofw_machdep.h>#include <machine/ofw_machdep.h>
#include <machine/ver.h>#include <machine/ver.h>
#endif#endif
#include <dev/pci/pcireg.h>#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>#include <dev/pci/pcivar.h>
#include <dev/bge/if_bgereg.h>#include <dev/bge/if_bgereg.h>
#define BGE_CSUM_FEATURES (CSUM_IP | CSUM_TCP)#define BGE_CSUM_FEATURES (CSUM_IP | CSUM_TCP)
#define ETHER_MIN_NOPAD (ETHER_MIN_LEN - ETHER_CRC_LEN) /* i.e., 60 */#define ETHER_MIN_NOPAD (ETHER_MIN_LEN - ETHER_CRC_LEN) /* i.e., 60 */
MODULE_DEPEND(bge, pci, 1, 1, 1);MODULE_DEPEND(bge, pci, 1, 1, 1);
MODULE_DEPEND(bge, ether, 1, 1, 1);MODULE_DEPEND(bge, ether, 1, 1, 1);
MODULE_DEPEND(bge, miibus, 1, 1, 1);MODULE_DEPEND(bge, miibus, 1, 1, 1);
/* "device miibus" required. See GENERIC if you get errors here. *//* "device miibus" required. See GENERIC if you get errors here. */
#include "miibus_if.h"#include "miibus_if.h"
/*/*
* Various supported device vendors/types and their names. Note: the * Various supported device vendors/types and their names. Note: the
* spec seems to indicate that the hardware still has Alteon's vendor * spec seems to indicate that the hardware still has Alteon's vendor
* ID burned into it, though it will always be overriden by the vendor * ID burned into it, though it will always be overriden by the vendor
* ID in the EEPROM. Just to be safe, we cover all possibilities. * ID in the EEPROM. Just to be safe, we cover all possibilities.
*/ */
static const struct bge_type {static const struct bge_type {
uint16_t bge_vid; uint16_t bge_vid;
uint16_t bge_did; uint16_t bge_did;
} bge_devs[] = {} bge_devs[] = {
{ ALTEON_VENDORID, ALTEON_DEVICEID_BCM5700 }, { ALTEON_VENDORID, ALTEON_DEVICEID_BCM5700 },
{ ALTEON_VENDORID, ALTEON_DEVICEID_BCM5701 }, { ALTEON_VENDORID, ALTEON_DEVICEID_BCM5701 },
{ ALTIMA_VENDORID, ALTIMA_DEVICE_AC1000 }, { ALTIMA_VENDORID, ALTIMA_DEVICE_AC1000 },
{ ALTIMA_VENDORID, ALTIMA_DEVICE_AC1002 }, { ALTIMA_VENDORID, ALTIMA_DEVICE_AC1002 },
{ ALTIMA_VENDORID, ALTIMA_DEVICE_AC9100 }, { ALTIMA_VENDORID, ALTIMA_DEVICE_AC9100 },
{ APPLE_VENDORID, APPLE_DEVICE_BCM5701 }, { APPLE_VENDORID, APPLE_DEVICE_BCM5701 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5700 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5700 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5701 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5701 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5702 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5702 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5702_ALT }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5702_ALT },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5702X }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5702X },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5703 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5703 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5703_ALT }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5703_ALT },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5703X }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5703X },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5704C }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5704C },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5704S }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5704S },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5704S_ALT }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5704S_ALT },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5705 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5705 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5705F }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5705F },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5705K }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5705K },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5705M }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5705M },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5705M_ALT }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5705M_ALT },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5714C }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5714C },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5714S }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5714S },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5715 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5715 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5715S }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5715S },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5717 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5717 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5717C }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5717C },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5718 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5718 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5719 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5719 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5720 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5720 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5721 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5721 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5722 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5722 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5723 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5723 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5725 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5725 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5727 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5727 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5750 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5750 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5750M }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5750M },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5751 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5751 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5751F }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5751F },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5751M }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5751M },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5752 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5752 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5752M }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5752M },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5753 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5753 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5753F }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5753F },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5753M }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5753M },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5754 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5754 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5754M }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5754M },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5755 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5755 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5755M }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5755M },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5756 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5756 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5761 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5761 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5761E }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5761E },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5761S }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5761S },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5761SE }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5761SE },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5762 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5762 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5764 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5764 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5780 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5780 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5780S }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5780S },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5781 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5781 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5782 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5782 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5784 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5784 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5785F }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5785F },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5785G }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5785G },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5786 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5786 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5787 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5787 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5787F }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5787F },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5787M }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5787M },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5788 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5788 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5789 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5789 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5901 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5901 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5901A2 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5901A2 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5903M }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5903M },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5906 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5906 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM5906M }, { BCOM_VENDORID, BCOM_DEVICEID_BCM5906M },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM57760 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM57760 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM57761 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM57761 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM57762 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM57762 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM57764 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM57764 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM57765 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM57765 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM57766 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM57766 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM57767 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM57767 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM57780 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM57780 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM57781 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM57781 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM57782 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM57782 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM57785 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM57785 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM57786 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM57786 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM57787 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM57787 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM57788 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM57788 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM57790 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM57790 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM57791 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM57791 },
{ BCOM_VENDORID, BCOM_DEVICEID_BCM57795 }, { BCOM_VENDORID, BCOM_DEVICEID_BCM57795 },
{ SK_VENDORID, SK_DEVICEID_ALTIMA }, { SK_VENDORID, SK_DEVICEID_ALTIMA },
{ TC_VENDORID, TC_DEVICEID_3C996 }, { TC_VENDORID, TC_DEVICEID_3C996 },
{ FJTSU_VENDORID, FJTSU_DEVICEID_PW008GE4 }, { FJTSU_VENDORID, FJTSU_DEVICEID_PW008GE4 },
{ FJTSU_VENDORID, FJTSU_DEVICEID_PW008GE5 }, { FJTSU_VENDORID, FJTSU_DEVICEID_PW008GE5 },
{ FJTSU_VENDORID, FJTSU_DEVICEID_PP250450 }, { FJTSU_VENDORID, FJTSU_DEVICEID_PP250450 },
{ 0, 0 } { 0, 0 }
};};
static const struct bge_vendor {static const struct bge_vendor {
uint16_t v_id; uint16_t v_id;
const char *v_name; const char *v_name;
} bge_vendors[] = {} bge_vendors[] = {
{ ALTEON_VENDORID, "Alteon" }, { ALTEON_VENDORID, "Alteon" },
{ ALTIMA_VENDORID, "Altima" }, { ALTIMA_VENDORID, "Altima" },
{ APPLE_VENDORID, "Apple" }, { APPLE_VENDORID, "Apple" },
{ BCOM_VENDORID, "Broadcom" }, { BCOM_VENDORID, "Broadcom" },
{ SK_VENDORID, "SysKonnect" }, { SK_VENDORID, "SysKonnect" },
{ TC_VENDORID, "3Com" }, { TC_VENDORID, "3Com" },
{ FJTSU_VENDORID, "Fujitsu" }, { FJTSU_VENDORID, "Fujitsu" },
{ 0, NULL } { 0, NULL }
};};
static const struct bge_revision {static const struct bge_revision {
uint32_t br_chipid; uint32_t br_chipid;
const char *br_name; const char *br_name;
} bge_revisions[] = {} bge_revisions[] = {
{ BGE_CHIPID_BCM5700_A0, "BCM5700 A0" }, { BGE_CHIPID_BCM5700_A0, "BCM5700 A0" },
{ BGE_CHIPID_BCM5700_A1, "BCM5700 A1" }, { BGE_CHIPID_BCM5700_A1, "BCM5700 A1" },
{ BGE_CHIPID_BCM5700_B0, "BCM5700 B0" }, { BGE_CHIPID_BCM5700_B0, "BCM5700 B0" },
{ BGE_CHIPID_BCM5700_B1, "BCM5700 B1" }, { BGE_CHIPID_BCM5700_B1, "BCM5700 B1" },
{ BGE_CHIPID_BCM5700_B2, "BCM5700 B2" }, { BGE_CHIPID_BCM5700_B2, "BCM5700 B2" },
{ BGE_CHIPID_BCM5700_B3, "BCM5700 B3" }, { BGE_CHIPID_BCM5700_B3, "BCM5700 B3" },
{ BGE_CHIPID_BCM5700_ALTIMA, "BCM5700 Altima" }, { BGE_CHIPID_BCM5700_ALTIMA, "BCM5700 Altima" },
{ BGE_CHIPID_BCM5700_C0, "BCM5700 C0" }, { BGE_CHIPID_BCM5700_C0, "BCM5700 C0" },
{ BGE_CHIPID_BCM5701_A0, "BCM5701 A0" }, { BGE_CHIPID_BCM5701_A0, "BCM5701 A0" },
{ BGE_CHIPID_BCM5701_B0, "BCM5701 B0" }, { BGE_CHIPID_BCM5701_B0, "BCM5701 B0" },
{ BGE_CHIPID_BCM5701_B2, "BCM5701 B2" }, { BGE_CHIPID_BCM5701_B2, "BCM5701 B2" },
{ BGE_CHIPID_BCM5701_B5, "BCM5701 B5" }, { BGE_CHIPID_BCM5701_B5, "BCM5701 B5" },
{ BGE_CHIPID_BCM5703_A0, "BCM5703 A0" }, { BGE_CHIPID_BCM5703_A0, "BCM5703 A0" },
{ BGE_CHIPID_BCM5703_A1, "BCM5703 A1" }, { BGE_CHIPID_BCM5703_A1, "BCM5703 A1" },
{ BGE_CHIPID_BCM5703_A2, "BCM5703 A2" }, { BGE_CHIPID_BCM5703_A2, "BCM5703 A2" },
{ BGE_CHIPID_BCM5703_A3, "BCM5703 A3" }, { BGE_CHIPID_BCM5703_A3, "BCM5703 A3" },
{ BGE_CHIPID_BCM5703_B0, "BCM5703 B0" }, { BGE_CHIPID_BCM5703_B0, "BCM5703 B0" },
{ BGE_CHIPID_BCM5704_A0, "BCM5704 A0" }, { BGE_CHIPID_BCM5704_A0, "BCM5704 A0" },
{ BGE_CHIPID_BCM5704_A1, "BCM5704 A1" }, { BGE_CHIPID_BCM5704_A1, "BCM5704 A1" },
{ BGE_CHIPID_BCM5704_A2, "BCM5704 A2" }, { BGE_CHIPID_BCM5704_A2, "BCM5704 A2" },
{ BGE_CHIPID_BCM5704_A3, "BCM5704 A3" }, { BGE_CHIPID_BCM5704_A3, "BCM5704 A3" },
{ BGE_CHIPID_BCM5704_B0, "BCM5704 B0" }, { BGE_CHIPID_BCM5704_B0, "BCM5704 B0" },
{ BGE_CHIPID_BCM5705_A0, "BCM5705 A0" }, { BGE_CHIPID_BCM5705_A0, "BCM5705 A0" },
{ BGE_CHIPID_BCM5705_A1, "BCM5705 A1" }, { BGE_CHIPID_BCM5705_A1, "BCM5705 A1" },
{ BGE_CHIPID_BCM5705_A2, "BCM5705 A2" }, { BGE_CHIPID_BCM5705_A2, "BCM5705 A2" },
{ BGE_CHIPID_BCM5705_A3, "BCM5705 A3" }, { BGE_CHIPID_BCM5705_A3, "BCM5705 A3" },
{ BGE_CHIPID_BCM5750_A0, "BCM5750 A0" }, { BGE_CHIPID_BCM5750_A0, "BCM5750 A0" },
{ BGE_CHIPID_BCM5750_A1, "BCM5750 A1" }, { BGE_CHIPID_BCM5750_A1, "BCM5750 A1" },
{ BGE_CHIPID_BCM5750_A3, "BCM5750 A3" }, { BGE_CHIPID_BCM5750_A3, "BCM5750 A3" },
{ BGE_CHIPID_BCM5750_B0, "BCM5750 B0" }, { BGE_CHIPID_BCM5750_B0, "BCM5750 B0" },
{ BGE_CHIPID_BCM5750_B1, "BCM5750 B1" }, { BGE_CHIPID_BCM5750_B1, "BCM5750 B1" },
{ BGE_CHIPID_BCM5750_C0, "BCM5750 C0" }, { BGE_CHIPID_BCM5750_C0, "BCM5750 C0" },
{ BGE_CHIPID_BCM5750_C1, "BCM5750 C1" }, { BGE_CHIPID_BCM5750_C1, "BCM5750 C1" },
{ BGE_CHIPID_BCM5750_C2, "BCM5750 C2" }, { BGE_CHIPID_BCM5750_C2, "BCM5750 C2" },
{ BGE_CHIPID_BCM5714_A0, "BCM5714 A0" }, { BGE_CHIPID_BCM5714_A0, "BCM5714 A0" },
{ BGE_CHIPID_BCM5752_A0, "BCM5752 A0" }, { BGE_CHIPID_BCM5752_A0, "BCM5752 A0" },
{ BGE_CHIPID_BCM5752_A1, "BCM5752 A1" }, { BGE_CHIPID_BCM5752_A1, "BCM5752 A1" },
{ BGE_CHIPID_BCM5752_A2, "BCM5752 A2" }, { BGE_CHIPID_BCM5752_A2, "BCM5752 A2" },
{ BGE_CHIPID_BCM5714_B0, "BCM5714 B0" }, { BGE_CHIPID_BCM5714_B0, "BCM5714 B0" },
{ BGE_CHIPID_BCM5714_B3, "BCM5714 B3" }, { BGE_CHIPID_BCM5714_B3, "BCM5714 B3" },
{ BGE_CHIPID_BCM5715_A0, "BCM5715 A0" }, { BGE_CHIPID_BCM5715_A0, "BCM5715 A0" },
{ BGE_CHIPID_BCM5715_A1, "BCM5715 A1" }, { BGE_CHIPID_BCM5715_A1, "BCM5715 A1" },
{ BGE_CHIPID_BCM5715_A3, "BCM5715 A3" }, { BGE_CHIPID_BCM5715_A3, "BCM5715 A3" },
{ BGE_CHIPID_BCM5717_A0, "BCM5717 A0" }, { BGE_CHIPID_BCM5717_A0, "BCM5717 A0" },
{ BGE_CHIPID_BCM5717_B0, "BCM5717 B0" }, { BGE_CHIPID_BCM5717_B0, "BCM5717 B0" },
{ BGE_CHIPID_BCM5717_C0, "BCM5717 C0" }, { BGE_CHIPID_BCM5717_C0, "BCM5717 C0" },
{ BGE_CHIPID_BCM5719_A0, "BCM5719 A0" }, { BGE_CHIPID_BCM5719_A0, "BCM5719 A0" },
{ BGE_CHIPID_BCM5720_A0, "BCM5720 A0" }, { BGE_CHIPID_BCM5720_A0, "BCM5720 A0" },
{ BGE_CHIPID_BCM5755_A0, "BCM5755 A0" }, { BGE_CHIPID_BCM5755_A0, "BCM5755 A0" },
{ BGE_CHIPID_BCM5755_A1, "BCM5755 A1" }, { BGE_CHIPID_BCM5755_A1, "BCM5755 A1" },
{ BGE_CHIPID_BCM5755_A2, "BCM5755 A2" }, { BGE_CHIPID_BCM5755_A2, "BCM5755 A2" },
{ BGE_CHIPID_BCM5722_A0, "BCM5722 A0" }, { BGE_CHIPID_BCM5722_A0, "BCM5722 A0" },
{ BGE_CHIPID_BCM5761_A0, "BCM5761 A0" }, { BGE_CHIPID_BCM5761_A0, "BCM5761 A0" },
{ BGE_CHIPID_BCM5761_A1, "BCM5761 A1" }, { BGE_CHIPID_BCM5761_A1, "BCM5761 A1" },
{ BGE_CHIPID_BCM5762_A0, "BCM5762 A0" }, { BGE_CHIPID_BCM5762_A0, "BCM5762 A0" },
{ BGE_CHIPID_BCM5784_A0, "BCM5784 A0" }, { BGE_CHIPID_BCM5784_A0, "BCM5784 A0" },
{ BGE_CHIPID_BCM5784_A1, "BCM5784 A1" }, { BGE_CHIPID_BCM5784_A1, "BCM5784 A1" },
/* 5754 and 5787 share the same ASIC ID */ /* 5754 and 5787 share the same ASIC ID */
{ BGE_CHIPID_BCM5787_A0, "BCM5754/5787 A0" }, { BGE_CHIPID_BCM5787_A0, "BCM5754/5787 A0" },
{ BGE_CHIPID_BCM5787_A1, "BCM5754/5787 A1" }, { BGE_CHIPID_BCM5787_A1, "BCM5754/5787 A1" },
{ BGE_CHIPID_BCM5787_A2, "BCM5754/5787 A2" }, { BGE_CHIPID_BCM5787_A2, "BCM5754/5787 A2" },
{ BGE_CHIPID_BCM5906_A1, "BCM5906 A1" }, { BGE_CHIPID_BCM5906_A1, "BCM5906 A1" },
{ BGE_CHIPID_BCM5906_A2, "BCM5906 A2" }, { BGE_CHIPID_BCM5906_A2, "BCM5906 A2" },
{ BGE_CHIPID_BCM57765_A0, "BCM57765 A0" }, { BGE_CHIPID_BCM57765_A0, "BCM57765 A0" },
{ BGE_CHIPID_BCM57765_B0, "BCM57765 B0" }, { BGE_CHIPID_BCM57765_B0, "BCM57765 B0" },
{ BGE_CHIPID_BCM57780_A0, "BCM57780 A0" }, { BGE_CHIPID_BCM57780_A0, "BCM57780 A0" },
{ BGE_CHIPID_BCM57780_A1, "BCM57780 A1" }, { BGE_CHIPID_BCM57780_A1, "BCM57780 A1" },
{ 0, NULL } { 0, NULL }
};};
/*/*
* Some defaults for major revisions, so that newer steppings * Some defaults for major revisions, so that newer steppings
* that we don't know about have a shot at working. * that we don't know about have a shot at working.
*/ */
static const struct bge_revision bge_majorrevs[] = {static const struct bge_revision bge_majorrevs[] = {
{ BGE_ASICREV_BCM5700, "unknown BCM5700" }, { BGE_ASICREV_BCM5700, "unknown BCM5700" },
{ BGE_ASICREV_BCM5701, "unknown BCM5701" }, { BGE_ASICREV_BCM5701, "unknown BCM5701" },
{ BGE_ASICREV_BCM5703, "unknown BCM5703" }, { BGE_ASICREV_BCM5703, "unknown BCM5703" },
{ BGE_ASICREV_BCM5704, "unknown BCM5704" }, { BGE_ASICREV_BCM5704, "unknown BCM5704" },
{ BGE_ASICREV_BCM5705, "unknown BCM5705" }, { BGE_ASICREV_BCM5705, "unknown BCM5705" },
{ BGE_ASICREV_BCM5750, "unknown BCM5750" }, { BGE_ASICREV_BCM5750, "unknown BCM5750" },
{ BGE_ASICREV_BCM5714_A0, "unknown BCM5714" }, { BGE_ASICREV_BCM5714_A0, "unknown BCM5714" },
{ BGE_ASICREV_BCM5752, "unknown BCM5752" }, { BGE_ASICREV_BCM5752, "unknown BCM5752" },
{ BGE_ASICREV_BCM5780, "unknown BCM5780" }, { BGE_ASICREV_BCM5780, "unknown BCM5780" },
{ BGE_ASICREV_BCM5714, "unknown BCM5714" }, { BGE_ASICREV_BCM5714, "unknown BCM5714" },
{ BGE_ASICREV_BCM5755, "unknown BCM5755" }, { BGE_ASICREV_BCM5755, "unknown BCM5755" },
{ BGE_ASICREV_BCM5761, "unknown BCM5761" }, { BGE_ASICREV_BCM5761, "unknown BCM5761" },
{ BGE_ASICREV_BCM5784, "unknown BCM5784" }, { BGE_ASICREV_BCM5784, "unknown BCM5784" },
{ BGE_ASICREV_BCM5785, "unknown BCM5785" }, { BGE_ASICREV_BCM5785, "unknown BCM5785" },
/* 5754 and 5787 share the same ASIC ID */ /* 5754 and 5787 share the same ASIC ID */
{ BGE_ASICREV_BCM5787, "unknown BCM5754/5787" }, { BGE_ASICREV_BCM5787, "unknown BCM5754/5787" },
{ BGE_ASICREV_BCM5906, "unknown BCM5906" }, { BGE_ASICREV_BCM5906, "unknown BCM5906" },
{ BGE_ASICREV_BCM57765, "unknown BCM57765" }, { BGE_ASICREV_BCM57765, "unknown BCM57765" },
{ BGE_ASICREV_BCM57766, "unknown BCM57766" }, { BGE_ASICREV_BCM57766, "unknown BCM57766" },
{ BGE_ASICREV_BCM57780, "unknown BCM57780" }, { BGE_ASICREV_BCM57780, "unknown BCM57780" },
{ BGE_ASICREV_BCM5717, "unknown BCM5717" }, { BGE_ASICREV_BCM5717, "unknown BCM5717" },
{ BGE_ASICREV_BCM5719, "unknown BCM5719" }, { BGE_ASICREV_BCM5719, "unknown BCM5719" },
{ BGE_ASICREV_BCM5720, "unknown BCM5720" }, { BGE_ASICREV_BCM5720, "unknown BCM5720" },
{ BGE_ASICREV_BCM5762, "unknown BCM5762" }, { BGE_ASICREV_BCM5762, "unknown BCM5762" },
{ 0, NULL } { 0, NULL }
};};
#define BGE_IS_JUMBO_CAPABLE(sc) ((sc)->bge_flags & BGE_FLAG_JUMBO)#define BGE_IS_JUMBO_CAPABLE(sc) ((sc)->bge_flags & BGE_FLAG_JUMBO)
#define BGE_IS_5700_FAMILY(sc) ((sc)->bge_flags & BGE_FLAG_5700_FAMILY)#define BGE_IS_5700_FAMILY(sc) ((sc)->bge_flags & BGE_FLAG_5700_FAMILY)
#define BGE_IS_5705_PLUS(sc) ((sc)->bge_flags & BGE_FLAG_5705_PLUS)#define BGE_IS_5705_PLUS(sc) ((sc)->bge_flags & BGE_FLAG_5705_PLUS)
#define BGE_IS_5714_FAMILY(sc) ((sc)->bge_flags & BGE_FLAG_5714_FAMILY)#define BGE_IS_5714_FAMILY(sc) ((sc)->bge_flags & BGE_FLAG_5714_FAMILY)
#define BGE_IS_575X_PLUS(sc) ((sc)->bge_flags & BGE_FLAG_575X_PLUS)#define BGE_IS_575X_PLUS(sc) ((sc)->bge_flags & BGE_FLAG_575X_PLUS)
#define BGE_IS_5755_PLUS(sc) ((sc)->bge_flags & BGE_FLAG_5755_PLUS)#define BGE_IS_5755_PLUS(sc) ((sc)->bge_flags & BGE_FLAG_5755_PLUS)
#define BGE_IS_5717_PLUS(sc) ((sc)->bge_flags & BGE_FLAG_5717_PLUS)#define BGE_IS_5717_PLUS(sc) ((sc)->bge_flags & BGE_FLAG_5717_PLUS)
#define BGE_IS_57765_PLUS(sc) ((sc)->bge_flags & BGE_FLAG_57765_PLUS)#define BGE_IS_57765_PLUS(sc) ((sc)->bge_flags & BGE_FLAG_57765_PLUS)
static uint32_t bge_chipid(device_t);static uint32_t bge_chipid(device_t);
static const struct bge_vendor * bge_lookup_vendor(uint16_t);static const struct bge_vendor * bge_lookup_vendor(uint16_t);
static const struct bge_revision * bge_lookup_rev(uint32_t);static const struct bge_revision * bge_lookup_rev(uint32_t);
typedef int (*bge_eaddr_fcn_t)(struct bge_softc *, uint8_t[]);typedef int (*bge_eaddr_fcn_t)(struct bge_softc *, uint8_t[]);
static int bge_probe(device_t);static int bge_probe(device_t);
static int bge_attach(device_t);static int bge_attach(device_t);
static int bge_detach(device_t);static int bge_detach(device_t);
static int bge_suspend(device_t);static int bge_suspend(device_t);
static int bge_resume(device_t);static int bge_resume(device_t);
static void bge_release_resources(struct bge_softc *);static void bge_release_resources(struct bge_softc *);
static void bge_dma_map_addr(void *, bus_dma_segment_t *, int, int);static void bge_dma_map_addr(void *, bus_dma_segment_t *, int, int);
static int bge_dma_alloc(struct bge_softc *);static int bge_dma_alloc(struct bge_softc *);
static void bge_dma_free(struct bge_softc *);static void bge_dma_free(struct bge_softc *);
static int bge_dma_ring_alloc(struct bge_softc *, bus_size_t, bus_size_t,static int bge_dma_ring_alloc(struct bge_softc *, bus_size_t, bus_size_t,
bus_dma_tag_t *, uint8_t **, bus_dmamap_t *, bus_addr_t *, const char *); bus_dma_tag_t *, uint8_t **, bus_dmamap_t *, bus_addr_t *, const char *);
static void bge_devinfo(struct bge_softc *);static void bge_devinfo(struct bge_softc *);
static int bge_mbox_reorder(struct bge_softc *);static int bge_mbox_reorder(struct bge_softc *);
static int bge_get_eaddr_fw(struct bge_softc *sc, uint8_t ether_addr[]);static int bge_get_eaddr_fw(struct bge_softc *sc, uint8_t ether_addr[]);
static int bge_get_eaddr_mem(struct bge_softc *, uint8_t[]);static int bge_get_eaddr_mem(struct bge_softc *, uint8_t[]);
static int bge_get_eaddr_nvram(struct bge_softc *, uint8_t[]);static int bge_get_eaddr_nvram(struct bge_softc *, uint8_t[]);
static int bge_get_eaddr_eeprom(struct bge_softc *, uint8_t[]);static int bge_get_eaddr_eeprom(struct bge_softc *, uint8_t[]);
static int bge_get_eaddr(struct bge_softc *, uint8_t[]);static int bge_get_eaddr(struct bge_softc *, uint8_t[]);
static void bge_txeof(struct bge_softc *, uint16_t);static void bge_txeof(struct bge_softc *, uint16_t);
static void bge_rxcsum(struct bge_softc *, struct bge_rx_bd *, struct mbuf *);static void bge_rxcsum(struct bge_softc *, struct bge_rx_bd *, struct mbuf *);
static int bge_rxeof(struct bge_softc *, uint16_t, int);static int bge_rxeof(struct bge_softc *, uint16_t, int);
static void bge_asf_driver_up (struct bge_softc *);static void bge_asf_driver_up (struct bge_softc *);
static void bge_tick(void *);static void bge_tick(void *);
static void bge_stats_clear_regs(struct bge_softc *);static void bge_stats_clear_regs(struct bge_softc *);
static void bge_stats_update(struct bge_softc *);static void bge_stats_update(struct bge_softc *);
static void bge_stats_update_regs(struct bge_softc *);static void bge_stats_update_regs(struct bge_softc *);
static struct mbuf *bge_check_short_dma(struct mbuf *);static struct mbuf *bge_check_short_dma(struct mbuf *);
static struct mbuf *bge_setup_tso(struct bge_softc *, struct mbuf *,static struct mbuf *bge_setup_tso(struct bge_softc *, struct mbuf *,
uint16_t *, uint16_t *); uint16_t *, uint16_t *);
static int bge_encap(struct bge_softc *, struct mbuf **, uint32_t *);static int bge_encap(struct bge_softc *, struct mbuf **, uint32_t *);
static void bge_intr(void *);static void bge_intr(void *);
static int bge_msi_intr(void *);static int bge_msi_intr(void *);
static void bge_intr_task(void *, int);static void bge_intr_task(void *, int);
static void bge_start_locked(if_t);static void bge_start_locked(if_t);
static void bge_start(if_t);static void bge_start(if_t);
static int bge_ioctl(if_t, u_long, caddr_t);static int bge_ioctl(if_t, u_long, caddr_t);
static void bge_init_locked(struct bge_softc *);static void bge_init_locked(struct bge_softc *);
static void bge_init(void *);static void bge_init(void *);
static void bge_stop_block(struct bge_softc *, bus_size_t, uint32_t);static void bge_stop_block(struct bge_softc *, bus_size_t, uint32_t);
static void bge_stop(struct bge_softc *);static void bge_stop(struct bge_softc *);
static void bge_watchdog(struct bge_softc *);static void bge_watchdog(struct bge_softc *);
static int bge_shutdown(device_t);static int bge_shutdown(device_t);
static int bge_ifmedia_upd_locked(if_t);static int bge_ifmedia_upd_locked(if_t);
static int bge_ifmedia_upd(if_t);static int bge_ifmedia_upd(if_t);
static void bge_ifmedia_sts(if_t, struct ifmediareq *);static void bge_ifmedia_sts(if_t, struct ifmediareq *);
static uint64_t bge_get_counter(if_t, ift_counter);static uint64_t bge_get_counter(if_t, ift_counter);
static uint8_t bge_nvram_getbyte(struct bge_softc *, int, uint8_t *);static uint8_t bge_nvram_getbyte(struct bge_softc *, int, uint8_t *);
static int bge_read_nvram(struct bge_softc *, caddr_t, int, int);static int bge_read_nvram(struct bge_softc *, caddr_t, int, int);
static uint8_t bge_eeprom_getbyte(struct bge_softc *, int, uint8_t *);static uint8_t bge_eeprom_getbyte(struct bge_softc *, int, uint8_t *);
static int bge_read_eeprom(struct bge_softc *, caddr_t, int, int);static int bge_read_eeprom(struct bge_softc *, caddr_t, int, int);
static void bge_setpromisc(struct bge_softc *);static void bge_setpromisc(struct bge_softc *);
static void bge_setmulti(struct bge_softc *);static void bge_setmulti(struct bge_softc *);
static void bge_setvlan(struct bge_softc *);static void bge_setvlan(struct bge_softc *);
static __inline void bge_rxreuse_std(struct bge_softc *, int);static __inline void bge_rxreuse_std(struct bge_softc *, int);
static __inline void bge_rxreuse_jumbo(struct bge_softc *, int);static __inline void bge_rxreuse_jumbo(struct bge_softc *, int);
static int bge_newbuf_std(struct bge_softc *, int);static int bge_newbuf_std(struct bge_softc *, int);
static int bge_newbuf_jumbo(struct bge_softc *, int);static int bge_newbuf_jumbo(struct bge_softc *, int);
static int bge_init_rx_ring_std(struct bge_softc *);static int bge_init_rx_ring_std(struct bge_softc *);
static void bge_free_rx_ring_std(struct bge_softc *);static void bge_free_rx_ring_std(struct bge_softc *);
static int bge_init_rx_ring_jumbo(struct bge_softc *);static int bge_init_rx_ring_jumbo(struct bge_softc *);
static void bge_free_rx_ring_jumbo(struct bge_softc *);static void bge_free_rx_ring_jumbo(struct bge_softc *);
static void bge_free_tx_ring(struct bge_softc *);static void bge_free_tx_ring(struct bge_softc *);
static int bge_init_tx_ring(struct bge_softc *);static int bge_init_tx_ring(struct bge_softc *);
static int bge_chipinit(struct bge_softc *);static int bge_chipinit(struct bge_softc *);
static int bge_blockinit(struct bge_softc *);static int bge_blockinit(struct bge_softc *);
static uint32_t bge_dma_swap_options(struct bge_softc *);static uint32_t bge_dma_swap_options(struct bge_softc *);
static int bge_has_eaddr(struct bge_softc *);static int bge_has_eaddr(struct bge_softc *);
static uint32_t bge_readmem_ind(struct bge_softc *, int);static uint32_t bge_readmem_ind(struct bge_softc *, int);
static void bge_writemem_ind(struct bge_softc *, int, int);static void bge_writemem_ind(struct bge_softc *, int, int);
static void bge_writembx(struct bge_softc *, int, int);static void bge_writembx(struct bge_softc *, int, int);
#ifdef notdef#ifdef notdef
static uint32_t bge_readreg_ind(struct bge_softc *, int);static uint32_t bge_readreg_ind(struct bge_softc *, int);
#endif#endif
static void bge_writemem_direct(struct bge_softc *, int, int);static void bge_writemem_direct(struct bge_softc *, int, int);
static void bge_writereg_ind(struct bge_softc *, int, int);static void bge_writereg_ind(struct bge_softc *, int, int);
static int bge_miibus_readreg(device_t, int, int);static int bge_miibus_readreg(device_t, int, int);
static int bge_miibus_writereg(device_t, int, int, int);static int bge_miibus_writereg(device_t, int, int, int);
static void bge_miibus_statchg(device_t);static void bge_miibus_statchg(device_t);
#ifdef DEVICE_POLLING#ifdef DEVICE_POLLING
static int bge_poll(if_t ifp, enum poll_cmd cmd, int count);static int bge_poll(if_t ifp, enum poll_cmd cmd, int count);
#endif#endif
#define BGE_RESET_SHUTDOWN 0#define BGE_RESET_SHUTDOWN 0
#define BGE_RESET_START 1#define BGE_RESET_START 1
#define BGE_RESET_SUSPEND 2#define BGE_RESET_SUSPEND 2
static void bge_sig_post_reset(struct bge_softc *, int);static void bge_sig_post_reset(struct bge_softc *, int);
static void bge_sig_legacy(struct bge_softc *, int);static void bge_sig_legacy(struct bge_softc *, int);
static void bge_sig_pre_reset(struct bge_softc *, int);static void bge_sig_pre_reset(struct bge_softc *, int);
static void bge_stop_fw(struct bge_softc *);static void bge_stop_fw(struct bge_softc *);
static int bge_reset(struct bge_softc *);static int bge_reset(struct bge_softc *);
static void bge_link_upd(struct bge_softc *);static void bge_link_upd(struct bge_softc *);
static void bge_ape_lock_init(struct bge_softc *);static void bge_ape_lock_init(struct bge_softc *);
static void bge_ape_read_fw_ver(struct bge_softc *);static void bge_ape_read_fw_ver(struct bge_softc *);
static int bge_ape_lock(struct bge_softc *, int);static int bge_ape_lock(struct bge_softc *, int);
static void bge_ape_unlock(struct bge_softc *, int);static void bge_ape_unlock(struct bge_softc *, int);
static void bge_ape_send_event(struct bge_softc *, uint32_t);static void bge_ape_send_event(struct bge_softc *, uint32_t);
static void bge_ape_driver_state_change(struct bge_softc *, int);static void bge_ape_driver_state_change(struct bge_softc *, int);
/*/*
* The BGE_REGISTER_DEBUG option is only for low-level debugging. It may * The BGE_REGISTER_DEBUG option is only for low-level debugging. It may
* leak information to untrusted users. It is also known to cause alignment * leak information to untrusted users. It is also known to cause alignment
* traps on certain architectures. * traps on certain architectures.
*/ */
#ifdef BGE_REGISTER_DEBUG#ifdef BGE_REGISTER_DEBUG
static int bge_sysctl_debug_info(SYSCTL_HANDLER_ARGS);static int bge_sysctl_debug_info(SYSCTL_HANDLER_ARGS);
static int bge_sysctl_reg_read(SYSCTL_HANDLER_ARGS);static int bge_sysctl_reg_read(SYSCTL_HANDLER_ARGS);
static int bge_sysctl_ape_read(SYSCTL_HANDLER_ARGS);static int bge_sysctl_ape_read(SYSCTL_HANDLER_ARGS);
static int bge_sysctl_mem_read(SYSCTL_HANDLER_ARGS);static int bge_sysctl_mem_read(SYSCTL_HANDLER_ARGS);
#endif#endif
static void bge_add_sysctls(struct bge_softc *);static void bge_add_sysctls(struct bge_softc *);
static void bge_add_sysctl_stats_regs(struct bge_softc *,static void bge_add_sysctl_stats_regs(struct bge_softc *,
struct sysctl_ctx_list *, struct sysctl_oid_list *); struct sysctl_ctx_list *, struct sysctl_oid_list *);
static void bge_add_sysctl_stats(struct bge_softc *, struct sysctl_ctx_list *,static void bge_add_sysctl_stats(struct bge_softc *, struct sysctl_ctx_list *,
struct sysctl_oid_list *); struct sysctl_oid_list *);
static int bge_sysctl_stats(SYSCTL_HANDLER_ARGS);static int bge_sysctl_stats(SYSCTL_HANDLER_ARGS);
static device_method_t bge_methods[] = {static device_method_t bge_methods[] = {
/* Device interface */ /* Device interface */
DEVMETHOD(device_probe, bge_probe), DEVMETHOD(device_probe, bge_probe),
DEVMETHOD(device_attach, bge_attach), DEVMETHOD(device_attach, bge_attach),
DEVMETHOD(device_detach, bge_detach), DEVMETHOD(device_detach, bge_detach),
DEVMETHOD(device_shutdown, bge_shutdown), DEVMETHOD(device_shutdown, bge_shutdown),
DEVMETHOD(device_suspend, bge_suspend), DEVMETHOD(device_suspend, bge_suspend),
DEVMETHOD(device_resume, bge_resume), DEVMETHOD(device_resume, bge_resume),
/* MII interface */ /* MII interface */
DEVMETHOD(miibus_readreg, bge_miibus_readreg), DEVMETHOD(miibus_readreg, bge_miibus_readreg),
DEVMETHOD(miibus_writereg, bge_miibus_writereg), DEVMETHOD(miibus_writereg, bge_miibus_writereg),
DEVMETHOD(miibus_statchg, bge_miibus_statchg), DEVMETHOD(miibus_statchg, bge_miibus_statchg),
DEVMETHOD_END DEVMETHOD_END
};};
static driver_t bge_driver = {static driver_t bge_driver = {
"bge", "bge",
bge_methods, bge_methods,
sizeof(struct bge_softc) sizeof(struct bge_softc)
};};
static devclass_t bge_devclass;static devclass_t bge_devclass;
DRIVER_MODULE(bge, pci, bge_driver, bge_devclass, 0, 0);DRIVER_MODULE(bge, pci, bge_driver, bge_devclass, 0, 0);
DRIVER_MODULE(miibus, bge, miibus_driver, miibus_devclass, 0, 0);DRIVER_MODULE(miibus, bge, miibus_driver, miibus_devclass, 0, 0);
static int bge_allow_asf = 1;static int bge_allow_asf = 1;
TUNABLE_INT("hw.bge.allow_asf", &bge_allow_asf);
static SYSCTL_NODE(_hw, OID_AUTO, bge, CTLFLAG_RD, 0, "BGE driver parameters");static SYSCTL_NODE(_hw, OID_AUTO, bge, CTLFLAG_RD, 0, "BGE driver parameters");
SYSCTL_INT(_hw_bge, OID_AUTO, allow_asf, CTLFLAG_RDTUN, &bge_allow_asf, 0,SYSCTL_INT(_hw_bge, OID_AUTO, allow_asf, CTLFLAG_RDTUN, &bge_allow_asf, 0,
"Allow ASF mode if available"); "Allow ASF mode if available");
#define SPARC64_BLADE_1500_MODEL "SUNW,Sun-Blade-1500"#define SPARC64_BLADE_1500_MODEL "SUNW,Sun-Blade-1500"
#define SPARC64_BLADE_1500_PATH_BGE "/pci@1f,700000/network@2"#define SPARC64_BLADE_1500_PATH_BGE "/pci@1f,700000/network@2"
#define SPARC64_BLADE_2500_MODEL "SUNW,Sun-Blade-2500"#define SPARC64_BLADE_2500_MODEL "SUNW,Sun-Blade-2500"
#define SPARC64_BLADE_2500_PATH_BGE "/pci@1c,600000/network@3"#define SPARC64_BLADE_2500_PATH_BGE "/pci@1c,600000/network@3"
#define SPARC64_OFW_SUBVENDOR "subsystem-vendor-id"#define SPARC64_OFW_SUBVENDOR "subsystem-vendor-id"
static intstatic int
bge_has_eaddr(struct bge_softc *sc)bge_has_eaddr(struct bge_softc *sc)
{{
#ifdef __sparc64__#ifdef __sparc64__
char buf[sizeof(SPARC64_BLADE_1500_PATH_BGE)]; char buf[sizeof(SPARC64_BLADE_1500_PATH_BGE)];
device_t dev; device_t dev;
uint32_t subvendor; uint32_t subvendor;
dev = sc->bge_dev; dev = sc->bge_dev;
/* /*
* The on-board BGEs found in sun4u machines aren't fitted with * The on-board BGEs found in sun4u machines aren't fitted with
* an EEPROM which means that we have to obtain the MAC address * an EEPROM which means that we have to obtain the MAC address
* via OFW and that some tests will always fail. We distinguish * via OFW and that some tests will always fail. We distinguish
* such BGEs by the subvendor ID, which also has to be obtained * such BGEs by the subvendor ID, which also has to be obtained
* from OFW instead of the PCI configuration space as the latter * from OFW instead of the PCI configuration space as the latter
* indicates Broadcom as the subvendor of the netboot interface. * indicates Broadcom as the subvendor of the netboot interface.
* For early Blade 1500 and 2500 we even have to check the OFW * For early Blade 1500 and 2500 we even have to check the OFW
* device path as the subvendor ID always defaults to Broadcom * device path as the subvendor ID always defaults to Broadcom
* there. * there.
*/ */
if (OF_getprop(ofw_bus_get_node(dev), SPARC64_OFW_SUBVENDOR, if (OF_getprop(ofw_bus_get_node(dev), SPARC64_OFW_SUBVENDOR,
&subvendor, sizeof(subvendor)) == sizeof(subvendor) && &subvendor, sizeof(subvendor)) == sizeof(subvendor) &&
(subvendor == FJTSU_VENDORID || subvendor == SUN_VENDORID)) (subvendor == FJTSU_VENDORID || subvendor == SUN_VENDORID))
return (0); return (0);
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
if (OF_package_to_path(ofw_bus_get_node(dev), buf, sizeof(buf)) > 0) { if (OF_package_to_path(ofw_bus_get_node(dev), buf, sizeof(buf)) > 0) {
if (strcmp(sparc64_model, SPARC64_BLADE_1500_MODEL) == 0 && if (strcmp(sparc64_model, SPARC64_BLADE_1500_MODEL) == 0 &&
strcmp(buf, SPARC64_BLADE_1500_PATH_BGE) == 0) strcmp(buf, SPARC64_BLADE_1500_PATH_BGE) == 0)
return (0); return (0);
if (strcmp(sparc64_model, SPARC64_BLADE_2500_MODEL) == 0 && if (strcmp(sparc64_model, SPARC64_BLADE_2500_MODEL) == 0 &&
strcmp(buf, SPARC64_BLADE_2500_PATH_BGE) == 0) strcmp(buf, SPARC64_BLADE_2500_PATH_BGE) == 0)
return (0); return (0);
} }
#endif#endif
return (1); return (1);
}}
static uint32_tstatic uint32_t
bge_readmem_ind(struct bge_softc *sc, int off)bge_readmem_ind(struct bge_softc *sc, int off)
{{
device_t dev; device_t dev;
uint32_t val; uint32_t val;
if (sc->bge_asicrev == BGE_ASICREV_BCM5906 && if (sc->bge_asicrev == BGE_ASICREV_BCM5906 &&
off >= BGE_STATS_BLOCK && off < BGE_SEND_RING_1_TO_4) off >= BGE_STATS_BLOCK && off < BGE_SEND_RING_1_TO_4)
return (0); return (0);
dev = sc->bge_dev; dev = sc->bge_dev;
pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, off, 4); pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, off, 4);
val = pci_read_config(dev, BGE_PCI_MEMWIN_DATA, 4); val = pci_read_config(dev, BGE_PCI_MEMWIN_DATA, 4);
pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, 0, 4); pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, 0, 4);
return (val); return (val);
}}
static voidstatic void
bge_writemem_ind(struct bge_softc *sc, int off, int val)bge_writemem_ind(struct bge_softc *sc, int off, int val)
{{
device_t dev; device_t dev;
if (sc->bge_asicrev == BGE_ASICREV_BCM5906 && if (sc->bge_asicrev == BGE_ASICREV_BCM5906 &&
off >= BGE_STATS_BLOCK && off < BGE_SEND_RING_1_TO_4) off >= BGE_STATS_BLOCK && off < BGE_SEND_RING_1_TO_4)
return; return;
dev = sc->bge_dev; dev = sc->bge_dev;
pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, off, 4); pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, off, 4);
pci_write_config(dev, BGE_PCI_MEMWIN_DATA, val, 4); pci_write_config(dev, BGE_PCI_MEMWIN_DATA, val, 4);
pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, 0, 4); pci_write_config(dev, BGE_PCI_MEMWIN_BASEADDR, 0, 4);
}}
#ifdef notdef#ifdef notdef
static uint32_tstatic uint32_t
bge_readreg_ind(struct bge_softc *sc, int off)bge_readreg_ind(struct bge_softc *sc, int off)
{{
device_t dev; device_t dev;
dev = sc->bge_dev; dev = sc->bge_dev;
pci_write_config(dev, BGE_PCI_REG_BASEADDR, off, 4); pci_write_config(dev, BGE_PCI_REG_BASEADDR, off, 4);
return (pci_read_config(dev, BGE_PCI_REG_DATA, 4)); return (pci_read_config(dev, BGE_PCI_REG_DATA, 4));
}}
#endif#endif
static voidstatic void
bge_writereg_ind(struct bge_softc *sc, int off, int val)bge_writereg_ind(struct bge_softc *sc, int off, int val)
{{
device_t dev; device_t dev;
dev = sc->bge_dev; dev = sc->bge_dev;
pci_write_config(dev, BGE_PCI_REG_BASEADDR, off, 4); pci_write_config(dev, BGE_PCI_REG_BASEADDR, off, 4);
pci_write_config(dev, BGE_PCI_REG_DATA, val, 4); pci_write_config(dev, BGE_PCI_REG_DATA, val, 4);
}}
static voidstatic void
bge_writemem_direct(struct bge_softc *sc, int off, int val)bge_writemem_direct(struct bge_softc *sc, int off, int val)
{{
CSR_WRITE_4(sc, off, val); CSR_WRITE_4(sc, off, val);
}}
static voidstatic void
bge_writembx(struct bge_softc *sc, int off, int val)bge_writembx(struct bge_softc *sc, int off, int val)
{{
if (sc->bge_asicrev == BGE_ASICREV_BCM5906) if (sc->bge_asicrev == BGE_ASICREV_BCM5906)
off += BGE_LPMBX_IRQ0_HI - BGE_MBX_IRQ0_HI; off += BGE_LPMBX_IRQ0_HI - BGE_MBX_IRQ0_HI;
CSR_WRITE_4(sc, off, val); CSR_WRITE_4(sc, off, val);
if ((sc->bge_flags & BGE_FLAG_MBOX_REORDER) != 0) if ((sc->bge_flags & BGE_FLAG_MBOX_REORDER) != 0)
CSR_READ_4(sc, off); CSR_READ_4(sc, off);
}}
/*/*
* Clear all stale locks and select the lock for this driver instance. * Clear all stale locks and select the lock for this driver instance.
*/ */
static voidstatic void
bge_ape_lock_init(struct bge_softc *sc)bge_ape_lock_init(struct bge_softc *sc)
{{
uint32_t bit, regbase; uint32_t bit, regbase;
int i; int i;
if (sc->bge_asicrev == BGE_ASICREV_BCM5761) if (sc->bge_asicrev == BGE_ASICREV_BCM5761)
regbase = BGE_APE_LOCK_GRANT; regbase = BGE_APE_LOCK_GRANT;
else else
regbase = BGE_APE_PER_LOCK_GRANT; regbase = BGE_APE_PER_LOCK_GRANT;
/* Clear any stale locks. */ /* Clear any stale locks. */
for (i = BGE_APE_LOCK_PHY0; i <= BGE_APE_LOCK_GPIO; i++) { for (i = BGE_APE_LOCK_PHY0; i <= BGE_APE_LOCK_GPIO; i++) {
switch (i) { switch (i) {
case BGE_APE_LOCK_PHY0: case BGE_APE_LOCK_PHY0:
case BGE_APE_LOCK_PHY1: case BGE_APE_LOCK_PHY1:
case BGE_APE_LOCK_PHY2: case BGE_APE_LOCK_PHY2:
case BGE_APE_LOCK_PHY3: case BGE_APE_LOCK_PHY3:
bit = BGE_APE_LOCK_GRANT_DRIVER0; bit = BGE_APE_LOCK_GRANT_DRIVER0;
break; break;
default: default:
if (sc->bge_func_addr == 0) if (sc->bge_func_addr == 0)
bit = BGE_APE_LOCK_GRANT_DRIVER0; bit = BGE_APE_LOCK_GRANT_DRIVER0;
else else
bit = (1 << sc->bge_func_addr); bit = (1 << sc->bge_func_addr);
} }
APE_WRITE_4(sc, regbase + 4 * i, bit); APE_WRITE_4(sc, regbase + 4 * i, bit);
} }
/* Select the PHY lock based on the device's function number. */ /* Select the PHY lock based on the device's function number. */
switch (sc->bge_func_addr) { switch (sc->bge_func_addr) {
case 0: case 0:
sc->bge_phy_ape_lock = BGE_APE_LOCK_PHY0; sc->bge_phy_ape_lock = BGE_APE_LOCK_PHY0;
break; break;
case 1: case 1:
sc->bge_phy_ape_lock = BGE_APE_LOCK_PHY1; sc->bge_phy_ape_lock = BGE_APE_LOCK_PHY1;
break; break;
case 2: case 2:
sc->bge_phy_ape_lock = BGE_APE_LOCK_PHY2; sc->bge_phy_ape_lock = BGE_APE_LOCK_PHY2;
break; break;
case 3: case 3:
sc->bge_phy_ape_lock = BGE_APE_LOCK_PHY3; sc->bge_phy_ape_lock = BGE_APE_LOCK_PHY3;
break; break;
default: default:
device_printf(sc->bge_dev, device_printf(sc->bge_dev,
"PHY lock not supported on this function\n"); "PHY lock not supported on this function\n");
} }
}}
/*/*
* Check for APE firmware, set flags, and print version info. * Check for APE firmware, set flags, and print version info.
*/ */
static voidstatic void
bge_ape_read_fw_ver(struct bge_softc *sc)bge_ape_read_fw_ver(struct bge_softc *sc)
{{
const char *fwtype; const char *fwtype;
uint32_t apedata, features; uint32_t apedata, features;
/* Check for a valid APE signature in shared memory. */ /* Check for a valid APE signature in shared memory. */
apedata = APE_READ_4(sc, BGE_APE_SEG_SIG); apedata = APE_READ_4(sc, BGE_APE_SEG_SIG);
if (apedata != BGE_APE_SEG_SIG_MAGIC) { if (apedata != BGE_APE_SEG_SIG_MAGIC) {
sc->bge_mfw_flags &= ~ BGE_MFW_ON_APE; sc->bge_mfw_flags &= ~ BGE_MFW_ON_APE;
return; return;
} }
/* Check if APE firmware is running. */ /* Check if APE firmware is running. */
apedata = APE_READ_4(sc, BGE_APE_FW_STATUS); apedata = APE_READ_4(sc, BGE_APE_FW_STATUS);
if ((apedata & BGE_APE_FW_STATUS_READY) == 0) { if ((apedata & BGE_APE_FW_STATUS_READY) == 0) {
device_printf(sc->bge_dev, "APE signature found " device_printf(sc->bge_dev, "APE signature found "
"but FW status not ready! 0x%08x\n", apedata); "but FW status not ready! 0x%08x\n", apedata);
return; return;
} }
sc->bge_mfw_flags |= BGE_MFW_ON_APE; sc->bge_mfw_flags |= BGE_MFW_ON_APE;
/* Fetch the APE firwmare type and version. */ /* Fetch the APE firwmare type and version. */
apedata = APE_READ_4(sc, BGE_APE_FW_VERSION); apedata = APE_READ_4(sc, BGE_APE_FW_VERSION);
features = APE_READ_4(sc, BGE_APE_FW_FEATURES); features = APE_READ_4(sc, BGE_APE_FW_FEATURES);
if ((features & BGE_APE_FW_FEATURE_NCSI) != 0) { if ((features & BGE_APE_FW_FEATURE_NCSI) != 0) {
sc->bge_mfw_flags |= BGE_MFW_TYPE_NCSI; sc->bge_mfw_flags |= BGE_MFW_TYPE_NCSI;
fwtype = "NCSI"; fwtype = "NCSI";
} else if ((features & BGE_APE_FW_FEATURE_DASH) != 0) { } else if ((features & BGE_APE_FW_FEATURE_DASH) != 0) {
sc->bge_mfw_flags |= BGE_MFW_TYPE_DASH; sc->bge_mfw_flags |= BGE_MFW_TYPE_DASH;
fwtype = "DASH"; fwtype = "DASH";
} else } else
fwtype = "UNKN"; fwtype = "UNKN";
/* Print the APE firmware version. */ /* Print the APE firmware version. */
device_printf(sc->bge_dev, "APE FW version: %s v%d.%d.%d.%d\n", device_printf(sc->bge_dev, "APE FW version: %s v%d.%d.%d.%d\n",
fwtype, fwtype,
(apedata & BGE_APE_FW_VERSION_MAJMSK) >> BGE_APE_FW_VERSION_MAJSFT, (apedata & BGE_APE_FW_VERSION_MAJMSK) >> BGE_APE_FW_VERSION_MAJSFT,
(apedata & BGE_APE_FW_VERSION_MINMSK) >> BGE_APE_FW_VERSION_MINSFT, (apedata & BGE_APE_FW_VERSION_MINMSK) >> BGE_APE_FW_VERSION_MINSFT,
(apedata & BGE_APE_FW_VERSION_REVMSK) >> BGE_APE_FW_VERSION_REVSFT, (apedata & BGE_APE_FW_VERSION_REVMSK) >> BGE_APE_FW_VERSION_REVSFT,
(apedata & BGE_APE_FW_VERSION_BLDMSK)); (apedata & BGE_APE_FW_VERSION_BLDMSK));
}}
static intstatic int
bge_ape_lock(struct bge_softc *sc, int locknum)bge_ape_lock(struct bge_softc *sc, int locknum)
{{
uint32_t bit, gnt, req, status; uint32_t bit, gnt, req, status;
int i, off; int i, off;
if ((sc->bge_mfw_flags & BGE_MFW_ON_APE) == 0) if ((sc->bge_mfw_flags & BGE_MFW_ON_APE) == 0)
return (0); return (0);
/* Lock request/grant registers have different bases. */ /* Lock request/grant registers have different bases. */
if (sc->bge_asicrev == BGE_ASICREV_BCM5761) { if (sc->bge_asicrev == BGE_ASICREV_BCM5761) {
req = BGE_APE_LOCK_REQ; req = BGE_APE_LOCK_REQ;
gnt = BGE_APE_LOCK_GRANT; gnt = BGE_APE_LOCK_GRANT;
} else { } else {
req = BGE_APE_PER_LOCK_REQ; req = BGE_APE_PER_LOCK_REQ;
gnt = BGE_APE_PER_LOCK_GRANT; gnt = BGE_APE_PER_LOCK_GRANT;
} }
off = 4 * locknum; off = 4 * locknum;
switch (locknum) { switch (locknum) {
case BGE_APE_LOCK_GPIO: case BGE_APE_LOCK_GPIO:
/* Lock required when using GPIO. */ /* Lock required when using GPIO. */
if (sc->bge_asicrev == BGE_ASICREV_BCM5761) if (sc->bge_asicrev == BGE_ASICREV_BCM5761)
return (0); return (0);
if (sc->bge_func_addr == 0) if (sc->bge_func_addr == 0)
bit = BGE_APE_LOCK_REQ_DRIVER0; bit = BGE_APE_LOCK_REQ_DRIVER0;
else else
bit = (1 << sc->bge_func_addr); bit = (1 << sc->bge_func_addr);
break; break;
case BGE_APE_LOCK_GRC: case BGE_APE_LOCK_GRC:
/* Lock required to reset the device. */ /* Lock required to reset the device. */
if (sc->bge_func_addr == 0) if (sc->bge_func_addr == 0)
bit = BGE_APE_LOCK_REQ_DRIVER0; bit = BGE_APE_LOCK_REQ_DRIVER0;
else else
bit = (1 << sc->bge_func_addr); bit = (1 << sc->bge_func_addr);
break; break;
case BGE_APE_LOCK_MEM: case BGE_APE_LOCK_MEM:
/* Lock required when accessing certain APE memory. */ /* Lock required when accessing certain APE memory. */
if (sc->bge_func_addr == 0) if (sc->bge_func_addr == 0)
bit = BGE_APE_LOCK_REQ_DRIVER0; bit = BGE_APE_LOCK_REQ_DRIVER0;
else else
bit = (1 << sc->bge_func_addr); bit = (1 << sc->bge_func_addr);
break; break;
case BGE_APE_LOCK_PHY0: case BGE_APE_LOCK_PHY0:
case BGE_APE_LOCK_PHY1: case BGE_APE_LOCK_PHY1:
case BGE_APE_LOCK_PHY2: case BGE_APE_LOCK_PHY2:
case BGE_APE_LOCK_PHY3: case BGE_APE_LOCK_PHY3:
/* Lock required when accessing PHYs. */ /* Lock required when accessing PHYs. */
bit = BGE_APE_LOCK_REQ_DRIVER0; bit = BGE_APE_LOCK_REQ_DRIVER0;
break; break;
default: default:
return (EINVAL); return (EINVAL);
} }
/* Request a lock. */ /* Request a lock. */
APE_WRITE_4(sc, req + off, bit); APE_WRITE_4(sc, req + off, bit);
/* Wait up to 1 second to acquire lock. */ /* Wait up to 1 second to acquire lock. */
for (i = 0; i < 20000; i++) { for (i = 0; i < 20000; i++) {
status = APE_READ_4(sc, gnt + off); status = APE_READ_4(sc, gnt + off);
if (status == bit) if (status == bit)
break; break;
DELAY(50); DELAY(50);
} }
/* Handle any errors. */ /* Handle any errors. */
if (status != bit) { if (status != bit) {
device_printf(sc->bge_dev, "APE lock %d request failed! " device_printf(sc->bge_dev, "APE lock %d request failed! "
"request = 0x%04x[0x%04x], status = 0x%04x[0x%04x]\n", "request = 0x%04x[0x%04x], status = 0x%04x[0x%04x]\n",
locknum, req + off, bit & 0xFFFF, gnt + off, locknum, req + off, bit & 0xFFFF, gnt + off,
status & 0xFFFF); status & 0xFFFF);
/* Revoke the lock request. */ /* Revoke the lock request. */
APE_WRITE_4(sc, gnt + off, bit); APE_WRITE_4(sc, gnt + off, bit);
return (EBUSY); return (EBUSY);
} }
return (0); return (0);
}}
static voidstatic void
bge_ape_unlock(struct bge_softc *sc, int locknum)bge_ape_unlock(struct bge_softc *sc, int locknum)
{{
uint32_t bit, gnt; uint32_t bit, gnt;
int off; int off;
if ((sc->bge_mfw_flags & BGE_MFW_ON_APE) == 0) if ((sc->bge_mfw_flags & BGE_MFW_ON_APE) == 0)
return; return;
if (sc->bge_asicrev == BGE_ASICREV_BCM5761) if (sc->bge_asicrev == BGE_ASICREV_BCM5761)
gnt = BGE_APE_LOCK_GRANT; gnt = BGE_APE_LOCK_GRANT;
else else
gnt = BGE_APE_PER_LOCK_GRANT; gnt = BGE_APE_PER_LOCK_GRANT;
off = 4 * locknum; off = 4 * locknum;
switch (locknum) { switch (locknum) {
case BGE_APE_LOCK_GPIO: case BGE_APE_LOCK_GPIO:
if (sc->bge_asicrev == BGE_ASICREV_BCM5761) if (sc->bge_asicrev == BGE_ASICREV_BCM5761)
return; return;
if (sc->bge_func_addr == 0) if (sc->bge_func_addr == 0)
bit = BGE_APE_LOCK_GRANT_DRIVER0; bit = BGE_APE_LOCK_GRANT_DRIVER0;
else else
bit = (1 << sc->bge_func_addr); bit = (1 << sc->bge_func_addr);
break; break;
case BGE_APE_LOCK_GRC: case BGE_APE_LOCK_GRC:
if (sc->bge_func_addr == 0) if (sc->bge_func_addr == 0)
bit = BGE_APE_LOCK_GRANT_DRIVER0; bit = BGE_APE_LOCK_GRANT_DRIVER0;
else else
bit = (1 << sc->bge_func_addr); bit = (1 << sc->bge_func_addr);
break; break;
case BGE_APE_LOCK_MEM: case BGE_APE_LOCK_MEM:
if (sc->bge_func_addr == 0) if (sc->bge_func_addr == 0)
bit = BGE_APE_LOCK_GRANT_DRIVER0; bit = BGE_APE_LOCK_GRANT_DRIVER0;
else else
bit = (1 << sc->bge_func_addr); bit = (1 << sc->bge_func_addr);
break; break;
case BGE_APE_LOCK_PHY0: case BGE_APE_LOCK_PHY0:
case BGE_APE_LOCK_PHY1: case BGE_APE_LOCK_PHY1:
case BGE_APE_LOCK_PHY2: case BGE_APE_LOCK_PHY2:
case BGE_APE_LOCK_PHY3: case BGE_APE_LOCK_PHY3:
bit = BGE_APE_LOCK_GRANT_DRIVER0; bit = BGE_APE_LOCK_GRANT_DRIVER0;
break; break;
default: default:
return; return;
} }
APE_WRITE_4(sc, gnt + off, bit); APE_WRITE_4(sc, gnt + off, bit);
}}
/*/*
* Send an event to the APE firmware. * Send an event to the APE firmware.
*/ */
static voidstatic void
bge_ape_send_event(struct bge_softc *sc, uint32_t event)bge_ape_send_event(struct bge_softc *sc, uint32_t event)
{{
uint32_t apedata; uint32_t apedata;
int i; int i;
/* NCSI does not support APE events. */ /* NCSI does not support APE events. */
if ((sc->bge_mfw_flags & BGE_MFW_ON_APE) == 0) if ((sc->bge_mfw_flags & BGE_MFW_ON_APE) == 0)
return; return;
/* Wait up to 1ms for APE to service previous event. */ /* Wait up to 1ms for APE to service previous event. */
for (i = 10; i > 0; i--) { for (i = 10; i > 0; i--) {
if (bge_ape_lock(sc, BGE_APE_LOCK_MEM) != 0) if (bge_ape_lock(sc, BGE_APE_LOCK_MEM) != 0)
break; break;
apedata = APE_READ_4(sc, BGE_APE_EVENT_STATUS); apedata = APE_READ_4(sc, BGE_APE_EVENT_STATUS);
if ((apedata & BGE_APE_EVENT_STATUS_EVENT_PENDING) == 0) { if ((apedata & BGE_APE_EVENT_STATUS_EVENT_PENDING) == 0) {
APE_WRITE_4(sc, BGE_APE_EVENT_STATUS, event | APE_WRITE_4(sc, BGE_APE_EVENT_STATUS, event |
BGE_APE_EVENT_STATUS_EVENT_PENDING); BGE_APE_EVENT_STATUS_EVENT_PENDING);
bge_ape_unlock(sc, BGE_APE_LOCK_MEM); bge_ape_unlock(sc, BGE_APE_LOCK_MEM);
APE_WRITE_4(sc, BGE_APE_EVENT, BGE_APE_EVENT_1); APE_WRITE_4(sc, BGE_APE_EVENT, BGE_APE_EVENT_1);
break; break;
} }
bge_ape_unlock(sc, BGE_APE_LOCK_MEM); bge_ape_unlock(sc, BGE_APE_LOCK_MEM);
DELAY(100); DELAY(100);
} }
if (i == 0) if (i == 0)
device_printf(sc->bge_dev, "APE event 0x%08x send timed out\n", device_printf(sc->bge_dev, "APE event 0x%08x send timed out\n",
event); event);
}}
static voidstatic void
bge_ape_driver_state_change(struct bge_softc *sc, int kind)bge_ape_driver_state_change(struct bge_softc *sc, int kind)
{{
uint32_t apedata, event; uint32_t apedata, event;
if ((sc->bge_mfw_flags & BGE_MFW_ON_APE) == 0) if ((sc->bge_mfw_flags & BGE_MFW_ON_APE) == 0)
return; return;
switch (kind) { switch (kind) {
case BGE_RESET_START: case BGE_RESET_START:
/* If this is the first load, clear the load counter. */ /* If this is the first load, clear the load counter. */
apedata = APE_READ_4(sc, BGE_APE_HOST_SEG_SIG); apedata = APE_READ_4(sc, BGE_APE_HOST_SEG_SIG);
if (apedata != BGE_APE_HOST_SEG_SIG_MAGIC) if (apedata != BGE_APE_HOST_SEG_SIG_MAGIC)
APE_WRITE_4(sc, BGE_APE_HOST_INIT_COUNT, 0); APE_WRITE_4(sc, BGE_APE_HOST_INIT_COUNT, 0);
else { else {
apedata = APE_READ_4(sc, BGE_APE_HOST_INIT_COUNT); apedata = APE_READ_4(sc, BGE_APE_HOST_INIT_COUNT);
APE_WRITE_4(sc, BGE_APE_HOST_INIT_COUNT, ++apedata); APE_WRITE_4(sc, BGE_APE_HOST_INIT_COUNT, ++apedata);
} }
APE_WRITE_4(sc, BGE_APE_HOST_SEG_SIG, APE_WRITE_4(sc, BGE_APE_HOST_SEG_SIG,
BGE_APE_HOST_SEG_SIG_MAGIC); BGE_APE_HOST_SEG_SIG_MAGIC);
APE_WRITE_4(sc, BGE_APE_HOST_SEG_LEN, APE_WRITE_4(sc, BGE_APE_HOST_SEG_LEN,
BGE_APE_HOST_SEG_LEN_MAGIC); BGE_APE_HOST_SEG_LEN_MAGIC);
/* Add some version info if bge(4) supports it. */ /* Add some version info if bge(4) supports it. */
APE_WRITE_4(sc, BGE_APE_HOST_DRIVER_ID, APE_WRITE_4(sc, BGE_APE_HOST_DRIVER_ID,
BGE_APE_HOST_DRIVER_ID_MAGIC(1, 0)); BGE_APE_HOST_DRIVER_ID_MAGIC(1, 0));
APE_WRITE_4(sc, BGE_APE_HOST_BEHAVIOR, APE_WRITE_4(sc, BGE_APE_HOST_BEHAVIOR,
BGE_APE_HOST_BEHAV_NO_PHYLOCK); BGE_APE_HOST_BEHAV_NO_PHYLOCK);
APE_WRITE_4(sc, BGE_APE_HOST_HEARTBEAT_INT_MS, APE_WRITE_4(sc, BGE_APE_HOST_HEARTBEAT_INT_MS,
BGE_APE_HOST_HEARTBEAT_INT_DISABLE); BGE_APE_HOST_HEARTBEAT_INT_DISABLE);
APE_WRITE_4(sc, BGE_APE_HOST_DRVR_STATE, APE_WRITE_4(sc, BGE_APE_HOST_DRVR_STATE,
BGE_APE_HOST_DRVR_STATE_START); BGE_APE_HOST_DRVR_STATE_START);
event = BGE_APE_EVENT_STATUS_STATE_START; event = BGE_APE_EVENT_STATUS_STATE_START;
break; break;
case BGE_RESET_SHUTDOWN: case BGE_RESET_SHUTDOWN:
APE_WRITE_4(sc, BGE_APE_HOST_DRVR_STATE, APE_WRITE_4(sc, BGE_APE_HOST_DRVR_STATE,
BGE_APE_HOST_DRVR_STATE_UNLOAD); BGE_APE_HOST_DRVR_STATE_UNLOAD);
event = BGE_APE_EVENT_STATUS_STATE_UNLOAD; event = BGE_APE_EVENT_STATUS_STATE_UNLOAD;
break; break;
case BGE_RESET_SUSPEND: case BGE_RESET_SUSPEND:
event = BGE_APE_EVENT_STATUS_STATE_SUSPEND; event = BGE_APE_EVENT_STATUS_STATE_SUSPEND;
break; break;
default: default:
return; return;
} }
bge_ape_send_event(sc, event | BGE_APE_EVENT_STATUS_DRIVER_EVNT | bge_ape_send_event(sc, event | BGE_APE_EVENT_STATUS_DRIVER_EVNT |
BGE_APE_EVENT_STATUS_STATE_CHNGE); BGE_APE_EVENT_STATUS_STATE_CHNGE);
}}
/*/*
* Map a single buffer address. * Map a single buffer address.
*/ */
static voidstatic void
bge_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)bge_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{{
struct bge_dmamap_arg *ctx; struct bge_dmamap_arg *ctx;
if (error) if (error)
return; return;
KASSERT(nseg == 1, ("%s: %d segments returned!", __func__, nseg)); KASSERT(nseg == 1, ("%s: %d segments returned!", __func__, nseg));
ctx = arg; ctx = arg;
ctx->bge_busaddr = segs->ds_addr; ctx->bge_busaddr = segs->ds_addr;
}}
static uint8_tstatic uint8_t
bge_nvram_getbyte(struct bge_softc *sc, int addr, uint8_t *dest)bge_nvram_getbyte(struct bge_softc *sc, int addr, uint8_t *dest)
{{
uint32_t access, byte = 0; uint32_t access, byte = 0;
int i; int i;
/* Lock. */ /* Lock. */
CSR_WRITE_4(sc, BGE_NVRAM_SWARB, BGE_NVRAMSWARB_SET1); CSR_WRITE_4(sc, BGE_NVRAM_SWARB, BGE_NVRAMSWARB_SET1);
for (i = 0; i < 8000; i++) { for (i = 0; i < 8000; i++) {
if (CSR_READ_4(sc, BGE_NVRAM_SWARB) & BGE_NVRAMSWARB_GNT1) if (CSR_READ_4(sc, BGE_NVRAM_SWARB) & BGE_NVRAMSWARB_GNT1)
break; break;
DELAY(20); DELAY(20);
} }
if (i == 8000) if (i == 8000)
return (1); return (1);
/* Enable access. */ /* Enable access. */
access = CSR_READ_4(sc, BGE_NVRAM_ACCESS); access = CSR_READ_4(sc, BGE_NVRAM_ACCESS);
CSR_WRITE_4(sc, BGE_NVRAM_ACCESS, access | BGE_NVRAMACC_ENABLE); CSR_WRITE_4(sc, BGE_NVRAM_ACCESS, access | BGE_NVRAMACC_ENABLE);
CSR_WRITE_4(sc, BGE_NVRAM_ADDR, addr & 0xfffffffc); CSR_WRITE_4(sc, BGE_NVRAM_ADDR, addr & 0xfffffffc);
CSR_WRITE_4(sc, BGE_NVRAM_CMD, BGE_NVRAM_READCMD); CSR_WRITE_4(sc, BGE_NVRAM_CMD, BGE_NVRAM_READCMD);
for (i = 0; i < BGE_TIMEOUT * 10; i++) { for (i = 0; i < BGE_TIMEOUT * 10; i++) {
DELAY(10); DELAY(10);
if (CSR_READ_4(sc, BGE_NVRAM_CMD) & BGE_NVRAMCMD_DONE) { if (CSR_READ_4(sc, BGE_NVRAM_CMD) & BGE_NVRAMCMD_DONE) {
DELAY(10); DELAY(10);
break; break;
} }
} }
if (i == BGE_TIMEOUT * 10) { if (i == BGE_TIMEOUT * 10) {
if_printf(sc->bge_ifp, "nvram read timed out\n"); if_printf(sc->bge_ifp, "nvram read timed out\n");
return (1); return (1);
} }
/* Get result. */ /* Get result. */
byte = CSR_READ_4(sc, BGE_NVRAM_RDDATA); byte = CSR_READ_4(sc, BGE_NVRAM_RDDATA);
*dest = (bswap32(byte) >> ((addr % 4) * 8)) & 0xFF; *dest = (bswap32(byte) >> ((addr % 4) * 8)) & 0xFF;
/* Disable access. */ /* Disable access. */
CSR_WRITE_4(sc, BGE_NVRAM_ACCESS, access); CSR_WRITE_4(sc, BGE_NVRAM_ACCESS, access);
/* Unlock. */ /* Unlock. */
CSR_WRITE_4(sc, BGE_NVRAM_SWARB, BGE_NVRAMSWARB_CLR1); CSR_WRITE_4(sc, BGE_NVRAM_SWARB, BGE_NVRAMSWARB_CLR1);
CSR_READ_4(sc, BGE_NVRAM_SWARB); CSR_READ_4(sc, BGE_NVRAM_SWARB);
return (0); return (0);
}}
/*/*
* Read a sequence of bytes from NVRAM. * Read a sequence of bytes from NVRAM.
*/ */
static intstatic int
bge_read_nvram(struct bge_softc *sc, caddr_t dest, int off, int cnt)bge_read_nvram(struct bge_softc *sc, caddr_t dest, int off, int cnt)
{{
int err = 0, i; int err = 0, i;
uint8_t byte = 0; uint8_t byte = 0;
if (sc->bge_asicrev != BGE_ASICREV_BCM5906) if (sc->bge_asicrev != BGE_ASICREV_BCM5906)
return (1); return (1);
for (i = 0; i < cnt; i++) { for (i = 0; i < cnt; i++) {
err = bge_nvram_getbyte(sc, off + i, &byte); err = bge_nvram_getbyte(sc, off + i, &byte);
if (err) if (err)
break; break;
*(dest + i) = byte; *(dest + i) = byte;
} }
return (err ? 1 : 0); return (err ? 1 : 0);
}}
/*/*
* Read a byte of data stored in the EEPROM at address 'addr.' The * Read a byte of data stored in the EEPROM at address 'addr.' The
* BCM570x supports both the traditional bitbang interface and an * BCM570x supports both the traditional bitbang interface and an
* auto access interface for reading the EEPROM. We use the auto * auto access interface for reading the EEPROM. We use the auto
* access method. * access method.
*/ */
static uint8_tstatic uint8_t
bge_eeprom_getbyte(struct bge_softc *sc, int addr, uint8_t *dest)bge_eeprom_getbyte(struct bge_softc *sc, int addr, uint8_t *dest)
{{
int i; int i;
uint32_t byte = 0; uint32_t byte = 0;
/* /*
* Enable use of auto EEPROM access so we can avoid * Enable use of auto EEPROM access so we can avoid
* having to use the bitbang method. * having to use the bitbang method.
*/ */
BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_AUTO_EEPROM); BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_AUTO_EEPROM);
/* Reset the EEPROM, load the clock period. */ /* Reset the EEPROM, load the clock period. */
CSR_WRITE_4(sc, BGE_EE_ADDR, CSR_WRITE_4(sc, BGE_EE_ADDR,
BGE_EEADDR_RESET | BGE_EEHALFCLK(BGE_HALFCLK_384SCL)); BGE_EEADDR_RESET | BGE_EEHALFCLK(BGE_HALFCLK_384SCL));
DELAY(20); DELAY(20);
/* Issue the read EEPROM command. */ /* Issue the read EEPROM command. */
CSR_WRITE_4(sc, BGE_EE_ADDR, BGE_EE_READCMD | addr); CSR_WRITE_4(sc, BGE_EE_ADDR, BGE_EE_READCMD | addr);
/* Wait for completion */ /* Wait for completion */
for(i = 0; i < BGE_TIMEOUT * 10; i++) { for(i = 0; i < BGE_TIMEOUT * 10; i++) {
DELAY(10); DELAY(10);
if (CSR_READ_4(sc, BGE_EE_ADDR) & BGE_EEADDR_DONE) if (CSR_READ_4(sc, BGE_EE_ADDR) & BGE_EEADDR_DONE)
break; break;
} }
if (i == BGE_TIMEOUT * 10) { if (i == BGE_TIMEOUT * 10) {
device_printf(sc->bge_dev, "EEPROM read timed out\n"); device_printf(sc->bge_dev, "EEPROM read timed out\n");
return (1); return (1);
} }
/* Get result. */ /* Get result. */
byte = CSR_READ_4(sc, BGE_EE_DATA); byte = CSR_READ_4(sc, BGE_EE_DATA);
*dest = (byte >> ((addr % 4) * 8)) & 0xFF; *dest = (byte >> ((addr % 4) * 8)) & 0xFF;
return (0); return (0);
}}
/*/*
* Read a sequence of bytes from the EEPROM. * Read a sequence of bytes from the EEPROM.
*/ */
static intstatic int
bge_read_eeprom(struct bge_softc *sc, caddr_t dest, int off, int cnt)bge_read_eeprom(struct bge_softc *sc, caddr_t dest, int off, int cnt)
{{
int i, error = 0; int i, error = 0;
uint8_t byte = 0; uint8_t byte = 0;
for (i = 0; i < cnt; i++) { for (i = 0; i < cnt; i++) {
error = bge_eeprom_getbyte(sc, off + i, &byte); error = bge_eeprom_getbyte(sc, off + i, &byte);
if (error) if (error)
break; break;
*(dest + i) = byte; *(dest + i) = byte;
} }
return (error ? 1 : 0); return (error ? 1 : 0);
}}
static intstatic int
bge_miibus_readreg(device_t dev, int phy, int reg)bge_miibus_readreg(device_t dev, int phy, int reg)
{{
struct bge_softc *sc; struct bge_softc *sc;
uint32_t val; uint32_t val;
int i; int i;
sc = device_get_softc(dev); sc = device_get_softc(dev);
if (bge_ape_lock(sc, sc->bge_phy_ape_lock) != 0) if (bge_ape_lock(sc, sc->bge_phy_ape_lock) != 0)
return (0); return (0);
/* Clear the autopoll bit if set, otherwise may trigger PCI errors. */ /* Clear the autopoll bit if set, otherwise may trigger PCI errors. */
if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) { if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) {
CSR_WRITE_4(sc, BGE_MI_MODE, CSR_WRITE_4(sc, BGE_MI_MODE,
sc->bge_mi_mode & ~BGE_MIMODE_AUTOPOLL); sc->bge_mi_mode & ~BGE_MIMODE_AUTOPOLL);
DELAY(80); DELAY(80);
} }
CSR_WRITE_4(sc, BGE_MI_COMM, BGE_MICMD_READ | BGE_MICOMM_BUSY | CSR_WRITE_4(sc, BGE_MI_COMM, BGE_MICMD_READ | BGE_MICOMM_BUSY |
BGE_MIPHY(phy) | BGE_MIREG(reg)); BGE_MIPHY(phy) | BGE_MIREG(reg));
/* Poll for the PHY register access to complete. */ /* Poll for the PHY register access to complete. */
for (i = 0; i < BGE_TIMEOUT; i++) { for (i = 0; i < BGE_TIMEOUT; i++) {
DELAY(10); DELAY(10);
val = CSR_READ_4(sc, BGE_MI_COMM); val = CSR_READ_4(sc, BGE_MI_COMM);
if ((val & BGE_MICOMM_BUSY) == 0) { if ((val & BGE_MICOMM_BUSY) == 0) {
DELAY(5); DELAY(5);
val = CSR_READ_4(sc, BGE_MI_COMM); val = CSR_READ_4(sc, BGE_MI_COMM);
break; break;
} }
} }
if (i == BGE_TIMEOUT) { if (i == BGE_TIMEOUT) {
device_printf(sc->bge_dev, device_printf(sc->bge_dev,
"PHY read timed out (phy %d, reg %d, val 0x%08x)\n", "PHY read timed out (phy %d, reg %d, val 0x%08x)\n",
phy, reg, val); phy, reg, val);
val = 0; val = 0;
} }
/* Restore the autopoll bit if necessary. */ /* Restore the autopoll bit if necessary. */
if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) { if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) {
CSR_WRITE_4(sc, BGE_MI_MODE, sc->bge_mi_mode); CSR_WRITE_4(sc, BGE_MI_MODE, sc->bge_mi_mode);
DELAY(80); DELAY(80);
} }
bge_ape_unlock(sc, sc->bge_phy_ape_lock); bge_ape_unlock(sc, sc->bge_phy_ape_lock);
if (val & BGE_MICOMM_READFAIL) if (val & BGE_MICOMM_READFAIL)
return (0); return (0);
return (val & 0xFFFF); return (val & 0xFFFF);
}}
static intstatic int
bge_miibus_writereg(device_t dev, int phy, int reg, int val)bge_miibus_writereg(device_t dev, int phy, int reg, int val)
{{
struct bge_softc *sc; struct bge_softc *sc;
int i; int i;
sc = device_get_softc(dev); sc = device_get_softc(dev);
if (sc->bge_asicrev == BGE_ASICREV_BCM5906 && if (sc->bge_asicrev == BGE_ASICREV_BCM5906 &&
(reg == BRGPHY_MII_1000CTL || reg == BRGPHY_MII_AUXCTL)) (reg == BRGPHY_MII_1000CTL || reg == BRGPHY_MII_AUXCTL))
return (0); return (0);
if (bge_ape_lock(sc, sc->bge_phy_ape_lock) != 0) if (bge_ape_lock(sc, sc->bge_phy_ape_lock) != 0)
return (0); return (0);
/* Clear the autopoll bit if set, otherwise may trigger PCI errors. */ /* Clear the autopoll bit if set, otherwise may trigger PCI errors. */
if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) { if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) {
CSR_WRITE_4(sc, BGE_MI_MODE, CSR_WRITE_4(sc, BGE_MI_MODE,
sc->bge_mi_mode & ~BGE_MIMODE_AUTOPOLL); sc->bge_mi_mode & ~BGE_MIMODE_AUTOPOLL);
DELAY(80); DELAY(80);
} }
CSR_WRITE_4(sc, BGE_MI_COMM, BGE_MICMD_WRITE | BGE_MICOMM_BUSY | CSR_WRITE_4(sc, BGE_MI_COMM, BGE_MICMD_WRITE | BGE_MICOMM_BUSY |
BGE_MIPHY(phy) | BGE_MIREG(reg) | val); BGE_MIPHY(phy) | BGE_MIREG(reg) | val);
for (i = 0; i < BGE_TIMEOUT; i++) { for (i = 0; i < BGE_TIMEOUT; i++) {
DELAY(10); DELAY(10);
if (!(CSR_READ_4(sc, BGE_MI_COMM) & BGE_MICOMM_BUSY)) { if (!(CSR_READ_4(sc, BGE_MI_COMM) & BGE_MICOMM_BUSY)) {
DELAY(5); DELAY(5);
CSR_READ_4(sc, BGE_MI_COMM); /* dummy read */ CSR_READ_4(sc, BGE_MI_COMM); /* dummy read */
break; break;
} }
} }
/* Restore the autopoll bit if necessary. */ /* Restore the autopoll bit if necessary. */
if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) { if ((sc->bge_mi_mode & BGE_MIMODE_AUTOPOLL) != 0) {
CSR_WRITE_4(sc, BGE_MI_MODE, sc->bge_mi_mode); CSR_WRITE_4(sc, BGE_MI_MODE, sc->bge_mi_mode);
DELAY(80); DELAY(80);
} }
bge_ape_unlock(sc, sc->bge_phy_ape_lock); bge_ape_unlock(sc, sc->bge_phy_ape_lock);
if (i == BGE_TIMEOUT) if (i == BGE_TIMEOUT)
device_printf(sc->bge_dev, device_printf(sc->bge_dev,
"PHY write timed out (phy %d, reg %d, val 0x%04x)\n", "PHY write timed out (phy %d, reg %d, val 0x%04x)\n",
phy, reg, val); phy, reg, val);
return (0); return (0);
}}
static voidstatic void
bge_miibus_statchg(device_t dev)bge_miibus_statchg(device_t dev)
{{
struct bge_softc *sc; struct bge_softc *sc;
struct mii_data *mii; struct mii_data *mii;
uint32_t mac_mode, rx_mode, tx_mode; uint32_t mac_mode, rx_mode, tx_mode;
sc = device_get_softc(dev); sc = device_get_softc(dev);
if ((if_getdrvflags(sc->bge_ifp) & IFF_DRV_RUNNING) == 0) if ((if_getdrvflags(sc->bge_ifp) & IFF_DRV_RUNNING) == 0)
return; return;
mii = device_get_softc(sc->bge_miibus); mii = device_get_softc(sc->bge_miibus);
if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
(IFM_ACTIVE | IFM_AVALID)) { (IFM_ACTIVE | IFM_AVALID)) {
switch (IFM_SUBTYPE(mii->mii_media_active)) { switch (IFM_SUBTYPE(mii->mii_media_active)) {
case IFM_10_T: case IFM_10_T:
case IFM_100_TX: case IFM_100_TX:
sc->bge_link = 1; sc->bge_link = 1;
break; break;
case IFM_1000_T: case IFM_1000_T:
case IFM_1000_SX: case IFM_1000_SX:
case IFM_2500_SX: case IFM_2500_SX:
if (sc->bge_asicrev != BGE_ASICREV_BCM5906) if (sc->bge_asicrev != BGE_ASICREV_BCM5906)
sc->bge_link = 1; sc->bge_link = 1;
else else
sc->bge_link = 0; sc->bge_link = 0;
break; break;
default: default:
sc->bge_link = 0; sc->bge_link = 0;
break; break;
} }
} else } else
sc->bge_link = 0; sc->bge_link = 0;
if (sc->bge_link == 0) if (sc->bge_link == 0)
return; return;
/* /*
* APE firmware touches these registers to keep the MAC * APE firmware touches these registers to keep the MAC
* connected to the outside world. Try to keep the * connected to the outside world. Try to keep the
* accesses atomic. * accesses atomic.
*/ */
/* Set the port mode (MII/GMII) to match the link speed. */ /* Set the port mode (MII/GMII) to match the link speed. */
mac_mode = CSR_READ_4(sc, BGE_MAC_MODE) & mac_mode = CSR_READ_4(sc, BGE_MAC_MODE) &
~(BGE_MACMODE_PORTMODE | BGE_MACMODE_HALF_DUPLEX); ~(BGE_MACMODE_PORTMODE | BGE_MACMODE_HALF_DUPLEX);
tx_mode = CSR_READ_4(sc, BGE_TX_MODE); tx_mode = CSR_READ_4(sc, BGE_TX_MODE);
rx_mode = CSR_READ_4(sc, BGE_RX_MODE); rx_mode = CSR_READ_4(sc, BGE_RX_MODE);
if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T || if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T ||
IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX)
mac_mode |= BGE_PORTMODE_GMII; mac_mode |= BGE_PORTMODE_GMII;
else else
mac_mode |= BGE_PORTMODE_MII; mac_mode |= BGE_PORTMODE_MII;
/* Set MAC flow control behavior to match link flow control settings. */ /* Set MAC flow control behavior to match link flow control settings. */
tx_mode &= ~BGE_TXMODE_FLOWCTL_ENABLE; tx_mode &= ~BGE_TXMODE_FLOWCTL_ENABLE;
rx_mode &= ~BGE_RXMODE_FLOWCTL_ENABLE; rx_mode &= ~BGE_RXMODE_FLOWCTL_ENABLE;
if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) {
if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0)
tx_mode |= BGE_TXMODE_FLOWCTL_ENABLE; tx_mode |= BGE_TXMODE_FLOWCTL_ENABLE;
if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0)
rx_mode |= BGE_RXMODE_FLOWCTL_ENABLE; rx_mode |= BGE_RXMODE_FLOWCTL_ENABLE;
} else } else
mac_mode |= BGE_MACMODE_HALF_DUPLEX; mac_mode |= BGE_MACMODE_HALF_DUPLEX;
CSR_WRITE_4(sc, BGE_MAC_MODE, mac_mode); CSR_WRITE_4(sc, BGE_MAC_MODE, mac_mode);
DELAY(40); DELAY(40);
CSR_WRITE_4(sc, BGE_TX_MODE, tx_mode); CSR_WRITE_4(sc, BGE_TX_MODE, tx_mode);
CSR_WRITE_4(sc, BGE_RX_MODE, rx_mode); CSR_WRITE_4(sc, BGE_RX_MODE, rx_mode);
}}
/*/*
* Intialize a standard receive ring descriptor. * Intialize a standard receive ring descriptor.
*/ */
static intstatic int
bge_newbuf_std(struct bge_softc *sc, int i)bge_newbuf_std(struct bge_softc *sc, int i)
{{
struct mbuf *m; struct mbuf *m;
struct bge_rx_bd *r; struct bge_rx_bd *r;
bus_dma_segment_t segs[1]; bus_dma_segment_t segs[1];
bus_dmamap_t map; bus_dmamap_t map;
int error, nsegs; int error, nsegs;
if (sc->bge_flags & BGE_FLAG_JUMBO_STD && if (sc->bge_flags & BGE_FLAG_JUMBO_STD &&
(if_getmtu(sc->bge_ifp) + ETHER_HDR_LEN + ETHER_CRC_LEN + (if_getmtu(sc->bge_ifp) + ETHER_HDR_LEN + ETHER_CRC_LEN +
ETHER_VLAN_ENCAP_LEN > (MCLBYTES - ETHER_ALIGN))) { ETHER_VLAN_ENCAP_LEN > (MCLBYTES - ETHER_ALIGN))) {
m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES); m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES);
if (m == NULL) if (m == NULL)
return (ENOBUFS); return (ENOBUFS);
m->m_len = m->m_pkthdr.len = MJUM9BYTES; m->m_len = m->m_pkthdr.len = MJUM9BYTES;
} else { } else {
m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
if (m == NULL) if (m == NULL)
return (ENOBUFS); return (ENOBUFS);
m->m_len = m->m_pkthdr.len = MCLBYTES; m->m_len = m->m_pkthdr.len = MCLBYTES;
} }
if ((sc->bge_flags & BGE_FLAG_RX_ALIGNBUG) == 0) if ((sc->bge_flags & BGE_FLAG_RX_ALIGNBUG) == 0)
m_adj(m, ETHER_ALIGN); m_adj(m, ETHER_ALIGN);
error = bus_dmamap_load_mbuf_sg(sc->bge_cdata.bge_rx_mtag, error = bus_dmamap_load_mbuf_sg(sc->bge_cdata.bge_rx_mtag,
sc->bge_cdata.bge_rx_std_sparemap, m, segs, &nsegs, 0); sc->bge_cdata.bge_rx_std_sparemap, m, segs, &nsegs, 0);
if (error != 0) { if (error != 0) {
m_freem(m); m_freem(m);
return (error); return (error);
} }
if (sc->bge_cdata.bge_rx_std_chain[i] != NULL) { if (sc->bge_cdata.bge_rx_std_chain[i] != NULL) {
bus_dmamap_sync(sc->bge_cdata.bge_rx_mtag, bus_dmamap_sync(sc->bge_cdata.bge_rx_mtag,
sc->bge_cdata.bge_rx_std_dmamap[i], BUS_DMASYNC_POSTREAD); sc->bge_cdata.bge_rx_std_dmamap[i], BUS_DMASYNC_POSTREAD);
bus_dmamap_unload(sc->bge_cdata.bge_rx_mtag, bus_dmamap_unload(sc->bge_cdata.bge_rx_mtag,
sc->bge_cdata.bge_rx_std_dmamap[i]); sc->bge_cdata.bge_rx_std_dmamap[i]);
} }
map = sc->bge_cdata.bge_rx_std_dmamap[i]; map = sc->bge_cdata.bge_rx_std_dmamap[i];
sc->bge_cdata.bge_rx_std_dmamap[i] = sc->bge_cdata.bge_rx_std_sparemap; sc->bge_cdata.bge_rx_std_dmamap[i] = sc->bge_cdata.bge_rx_std_sparemap;
sc->bge_cdata.bge_rx_std_sparemap = map; sc->bge_cdata.bge_rx_std_sparemap = map;
sc->bge_cdata.bge_rx_std_chain[i] = m; sc->bge_cdata.bge_rx_std_chain[i] = m;
sc->bge_cdata.bge_rx_std_seglen[i] = segs[0].ds_len; sc->bge_cdata.bge_rx_std_seglen[i] = segs[0].ds_len;
r = &sc->bge_ldata.bge_rx_std_ring[sc->bge_std]; r = &sc->bge_ldata.bge_rx_std_ring[sc->bge_std];
r->bge_addr.bge_addr_lo = BGE_ADDR_LO(segs[0].ds_addr); r->bge_addr.bge_addr_lo = BGE_ADDR_LO(segs[0].ds_addr);
r->bge_addr.bge_addr_hi = BGE_ADDR_HI(segs[0].ds_addr); r->bge_addr.bge_addr_hi = BGE_ADDR_HI(segs[0].ds_addr);
r->bge_flags = BGE_RXBDFLAG_END; r->bge_flags = BGE_RXBDFLAG_END;
r->bge_len = segs[0].ds_len; r->bge_len = segs[0].ds_len;
r->bge_idx = i; r->bge_idx = i;
bus_dmamap_sync(sc->bge_cdata.bge_rx_mtag, bus_dmamap_sync(sc->bge_cdata.bge_rx_mtag,
sc->bge_cdata.bge_rx_std_dmamap[i], BUS_DMASYNC_PREREAD); sc->bge_cdata.bge_rx_std_dmamap[i], BUS_DMASYNC_PREREAD);
return (0); return (0);
}}
/*/*
* Initialize a jumbo receive ring descriptor. This allocates * Initialize a jumbo receive ring descriptor. This allocates
* a jumbo buffer from the pool managed internally by the driver. * a jumbo buffer from the pool managed internally by the driver.
*/ */
static intstatic int
bge_newbuf_jumbo(struct bge_softc *sc, int i)bge_newbuf_jumbo(struct bge_softc *sc, int i)
{{
bus_dma_segment_t segs[BGE_NSEG_JUMBO]; bus_dma_segment_t segs[BGE_NSEG_JUMBO];
bus_dmamap_t map; bus_dmamap_t map;
struct bge_extrx_bd *r; struct bge_extrx_bd *r;
struct mbuf *m; struct mbuf *m;
int error, nsegs; int error, nsegs;
MGETHDR(m, M_NOWAIT, MT_DATA); MGETHDR(m, M_NOWAIT, MT_DATA);
if (m == NULL) if (m == NULL)
return (ENOBUFS); return (ENOBUFS);
if (m_cljget(m, M_NOWAIT, MJUM9BYTES) == NULL) { if (m_cljget(m, M_NOWAIT, MJUM9BYTES) == NULL) {
m_freem(m); m_freem(m);
return (ENOBUFS); return (ENOBUFS);
} }
m->m_len = m->m_pkthdr.len = MJUM9BYTES; m->m_len = m->m_pkthdr.len = MJUM9BYTES;
if ((sc->bge_flags & BGE_FLAG_RX_ALIGNBUG) == 0) if ((sc->bge_flags & BGE_FLAG_RX_ALIGNBUG) == 0)
m_adj(m, ETHER_ALIGN); m_adj(m, ETHER_ALIGN);
error = bus_dmamap_load_mbuf_sg(sc->bge_cdata.bge_mtag_jumbo, error = bus_dmamap_load_mbuf_sg(sc->bge_cdata.bge_mtag_jumbo,
sc->bge_cdata.bge_rx_jumbo_sparemap, m, segs, &nsegs, 0); sc->bge_cdata.bge_rx_jumbo_sparemap, m, segs, &nsegs, 0);
if (error != 0) { if (error != 0) {
m_freem(m); m_freem(m);
return (error); return (error);
} }
if (sc->bge_cdata.bge_rx_jumbo_chain[i] != NULL) { if (sc->bge_cdata.bge_rx_jumbo_chain[i] != NULL) {
bus_dmamap_sync(sc->bge_cdata.bge_mtag_jumbo, bus_dmamap_sync(sc->bge_cdata.bge_mtag_jumbo,
sc->bge_cdata.bge_rx_jumbo_dmamap[i], BUS_DMASYNC_POSTREAD); sc->bge_cdata.bge_rx_jumbo_dmamap[i], BUS_DMASYNC_POSTREAD);
bus_dmamap_unload(sc->bge_cdata.bge_mtag_jumbo, bus_dmamap_unload(sc->bge_cdata.bge_mtag_jumbo,
sc->bge_cdata.bge_rx_jumbo_dmamap[i]); sc->bge_cdata.bge_rx_jumbo_dmamap[i]);
} }
map = sc->bge_cdata.bge_rx_jumbo_dmamap[i]; map = sc->bge_cdata.bge_rx_jumbo_dmamap[i];
sc->bge_cdata.bge_rx_jumbo_dmamap[i] = sc->bge_cdata.bge_rx_jumbo_dmamap[i] =
sc->bge_cdata.bge_rx_jumbo_sparemap; sc->bge_cdata.bge_rx_jumbo_sparemap;
sc->bge_cdata.bge_rx_jumbo_sparemap = map; sc->bge_cdata.bge_rx_jumbo_sparemap = map;
sc->bge_cdata.bge_rx_jumbo_chain[i] = m; sc->bge_cdata.bge_rx_jumbo_chain[i] = m;
sc->bge_cdata.bge_rx_jumbo_seglen[i][0] = 0; sc->bge_cdata.bge_rx_jumbo_seglen[i][0] = 0;
sc->bge_cdata.bge_rx_jumbo_seglen[i][1] = 0; sc->bge_cdata.bge_rx_jumbo_seglen[i][1] = 0;
sc->bge_cdata.bge_rx_jumbo_seglen[i][2] = 0; sc->bge_cdata.bge_rx_jumbo_seglen[i][2] = 0;
sc->bge_cdata.bge_rx_jumbo_seglen[i][3] = 0; sc->bge_cdata.bge_rx_jumbo_seglen[i][3] = 0;
/* /*
* Fill in the extended RX buffer descriptor. * Fill in the extended RX buffer descriptor.
*/ */
r = &sc->bge_ldata.bge_rx_jumbo_ring[sc->bge_jumbo]; r = &sc->bge_ldata.bge_rx_jumbo_ring[sc->bge_jumbo];
r->bge_flags = BGE_RXBDFLAG_JUMBO_RING | BGE_RXBDFLAG_END; r->bge_flags = BGE_RXBDFLAG_JUMBO_RING | BGE_RXBDFLAG_END;
r->bge_idx = i; r->bge_idx = i;
r->bge_len3 = r->bge_len2 = r->bge_len1 = 0; r->bge_len3 = r->bge_len2 = r->bge_len1 = 0;
switch (nsegs) { switch (nsegs) {
case 4: case 4:
r->bge_addr3.bge_addr_lo = BGE_ADDR_LO(segs[3].ds_addr); r->bge_addr3.bge_addr_lo = BGE_ADDR_LO(segs[3].ds_addr);
r->bge_addr3.bge_addr_hi = BGE_ADDR_HI(segs[3].ds_addr); r->bge_addr3.bge_addr_hi = BGE_ADDR_HI(segs[3].ds_addr);
r->bge_len3 = segs[3].ds_len; r->bge_len3 = segs[3].ds_len;
sc->bge_cdata.bge_rx_jumbo_seglen[i][3] = segs[3].ds_len; sc->bge_cdata.bge_rx_jumbo_seglen[i][3] = segs[3].ds_len;
case 3: case 3:
r->bge_addr2.bge_addr_lo = BGE_ADDR_LO(segs[2].ds_addr); r->bge_addr2.bge_addr_lo = BGE_ADDR_LO(segs[2].ds_addr);
r->bge_addr2.bge_addr_hi = BGE_ADDR_HI(segs[2].ds_addr); r->bge_addr2.bge_addr_hi = BGE_ADDR_HI(segs[2].ds_addr);
r->bge_len2 = segs[2].ds_len; r->bge_len2 = segs[2].ds_len;
sc->bge_cdata.bge_rx_jumbo_seglen[i][2] = segs[2].ds_len; sc->bge_cdata.bge_rx_jumbo_seglen[i][2] = segs[2].ds_len;
case 2: case 2:
r->bge_addr1.bge_addr_lo = BGE_ADDR_LO(segs[1].ds_addr); r->bge_addr1.bge_addr_lo = BGE_ADDR_LO(segs[1].ds_addr);
r->bge_addr1.bge_addr_hi = BGE_ADDR_HI(segs[1].ds_addr); r->bge_addr1.bge_addr_hi = BGE_ADDR_HI(segs[1].ds_addr);
r->bge_len1 = segs[1].ds_len; r->bge_len1 = segs[1].ds_len;
sc->bge_cdata.bge_rx_jumbo_seglen[i][1] = segs[1].ds_len; sc->bge_cdata.bge_rx_jumbo_seglen[i][1] = segs[1].ds_len;
case 1: case 1:
r->bge_addr0.bge_addr_lo = BGE_ADDR_LO(segs[0].ds_addr); r->bge_addr0.bge_addr_lo = BGE_ADDR_LO(segs[0].ds_addr);
r->bge_addr0.bge_addr_hi = BGE_ADDR_HI(segs[0].ds_addr); r->bge_addr0.bge_addr_hi = BGE_ADDR_HI(segs[0].ds_addr);
r->bge_len0 = segs[0].ds_len; r->bge_len0 = segs[0].ds_len;
sc->bge_cdata.bge_rx_jumbo_seglen[i][0] = segs[0].ds_len; sc->bge_cdata.bge_rx_jumbo_seglen[i][0] = segs[0].ds_len;
break; break;
default: default:
panic("%s: %d segments\n", __func__, nsegs); panic("%s: %d segments\n", __func__, nsegs);
} }
bus_dmamap_sync(sc->bge_cdata.bge_mtag_jumbo, bus_dmamap_sync(sc->bge_cdata.bge_mtag_jumbo,
sc->bge_cdata.bge_rx_jumbo_dmamap[i], BUS_DMASYNC_PREREAD); sc->bge_cdata.bge_rx_jumbo_dmamap[i], BUS_DMASYNC_PREREAD);
return (0); return (0);
}}
static intstatic int
bge_init_rx_ring_std(struct bge_softc *sc)bge_init_rx_ring_std(struct bge_softc *sc)
{{
int error, i; int error, i;
bzero(sc->bge_ldata.bge_rx_std_ring, BGE_STD_RX_RING_SZ); bzero(sc->bge_ldata.bge_rx_std_ring, BGE_STD_RX_RING_SZ);
sc->bge_std = 0; sc->bge_std = 0;
for (i = 0; i < BGE_STD_RX_RING_CNT; i++) { for (i = 0; i < BGE_STD_RX_RING_CNT; i++) {
if ((error = bge_newbuf_std(sc, i)) != 0) if ((error = bge_newbuf_std(sc, i)) != 0)
return (error); return (error);
BGE_INC(sc->bge_std, BGE_STD_RX_RING_CNT); BGE_INC(sc->bge_std, BGE_STD_RX_RING_CNT);
} }
bus_dmamap_sync(sc->bge_cdata.bge_rx_std_ring_tag, bus_dmamap_sync(sc->bge_cdata.bge_rx_std_ring_tag,
sc->bge_cdata.bge_rx_std_ring_map, BUS_DMASYNC_PREWRITE); sc->bge_cdata.bge_rx_std_ring_map, BUS_DMASYNC_PREWRITE);
sc->bge_std = 0; sc->bge_std = 0;
bge_writembx(sc, BGE_MBX_RX_STD_PROD_LO, BGE_STD_RX_RING_CNT - 1); bge_writembx(sc, BGE_MBX_RX_STD_PROD_LO, BGE_STD_RX_RING_CNT - 1);
return (0); return (0);
}}
static voidstatic void
bge_free_rx_ring_std(struct bge_softc *sc)bge_free_rx_ring_std(struct bge_softc *sc)
{{
int i; int i;
for (i = 0; i < BGE_STD_RX_RING_CNT; i++) { for (i = 0; i < BGE_STD_RX_RING_CNT; i++) {
if (sc->bge_cdata.bge_rx_std_chain[i] != NULL) { if (sc->bge_cdata.bge_rx_std_chain[i] != NULL) {
bus_dmamap_sync(sc->bge_cdata.bge_rx_mtag, bus_dmamap_sync(sc->bge_cdata.bge_rx_mtag,
sc->bge_cdata.bge_rx_std_dmamap[i], sc->bge_cdata.bge_rx_std_dmamap[i],
BUS_DMASYNC_POSTREAD); BUS_DMASYNC_POSTREAD);
bus_dmamap_unload(sc->bge_cdata.bge_rx_mtag, bus_dmamap_unload(sc->bge_cdata.bge_rx_mtag,
sc->bge_cdata.bge_rx_std_dmamap[i]); sc->bge_cdata.bge_rx_std_dmamap[i]);
m_freem(sc->bge_cdata.bge_rx_std_chain[i]); m_freem(sc->bge_cdata.bge_rx_std_chain[i]);
sc->bge_cdata.bge_rx_std_chain[i] = NULL; sc->bge_cdata.bge_rx_std_chain[i] = NULL;
} }
bzero((char *)&sc->bge_ldata.bge_rx_std_ring[i], bzero((char *)&sc->bge_ldata.bge_rx_std_ring[i],
sizeof(struct bge_rx_bd)); sizeof(struct bge_rx_bd));
} }
}}
static intstatic int
bge_init_rx_ring_jumbo(struct bge_softc *sc)bge_init_rx_ring_jumbo(struct bge_softc *sc)
{{
struct bge_rcb *rcb; struct bge_rcb *rcb;
int error, i; int error, i;
bzero(sc->bge_ldata.bge_rx_jumbo_ring, BGE_JUMBO_RX_RING_SZ); bzero(sc->bge_ldata.bge_rx_jumbo_ring, BGE_JUMBO_RX_RING_SZ);
sc->bge_jumbo = 0; sc->bge_jumbo = 0;
for (i = 0; i < BGE_JUMBO_RX_RING_CNT; i++) { for (i = 0; i < BGE_JUMBO_RX_RING_CNT; i++) {
if ((error = bge_newbuf_jumbo(sc, i)) != 0) if ((error = bge_newbuf_jumbo(sc, i)) != 0)
return (error); return (error);
BGE_INC(sc->bge_jumbo, BGE_JUMBO_RX_RING_CNT); BGE_INC(sc->bge_jumbo, BGE_JUMBO_RX_RING_CNT);
} }
bus_dmamap_sync(sc->bge_cdata.bge_rx_jumbo_ring_tag, bus_dmamap_sync(sc->bge_cdata.bge_rx_jumbo_ring_tag,
sc->bge_cdata.bge_rx_jumbo_ring_map, BUS_DMASYNC_PREWRITE); sc->bge_cdata.bge_rx_jumbo_ring_map, BUS_DMASYNC_PREWRITE);
sc->bge_jumbo = 0; sc->bge_jumbo = 0;
/* Enable the jumbo receive producer ring. */ /* Enable the jumbo receive producer ring. */
rcb = &sc->bge_ldata.bge_info.bge_jumbo_rx_rcb; rcb = &sc->bge_ldata.bge_info.bge_jumbo_rx_rcb;
rcb->bge_maxlen_flags = rcb->bge_maxlen_flags =
BGE_RCB_MAXLEN_FLAGS(0, BGE_RCB_FLAG_USE_EXT_RX_BD); BGE_RCB_MAXLEN_FLAGS(0, BGE_RCB_FLAG_USE_EXT_RX_BD);
CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_MAXLEN_FLAGS, rcb->bge_maxlen_flags); CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_MAXLEN_FLAGS, rcb->bge_maxlen_flags);
bge_writembx(sc, BGE_MBX_RX_JUMBO_PROD_LO, BGE_JUMBO_RX_RING_CNT - 1); bge_writembx(sc, BGE_MBX_RX_JUMBO_PROD_LO, BGE_JUMBO_RX_RING_CNT - 1);
return (0); return (0);
}}
static voidstatic void
bge_free_rx_ring_jumbo(struct bge_softc *sc)bge_free_rx_ring_jumbo(struct bge_softc *sc)
{{
int i; int i;
for (i = 0; i < BGE_JUMBO_RX_RING_CNT; i++) { for (i = 0; i < BGE_JUMBO_RX_RING_CNT; i++) {
if (sc->bge_cdata.bge_rx_jumbo_chain[i] != NULL) { if (sc->bge_cdata.bge_rx_jumbo_chain[i] != NULL) {
bus_dmamap_sync(sc->bge_cdata.bge_mtag_jumbo, bus_dmamap_sync(sc->bge_cdata.bge_mtag_jumbo,
sc->bge_cdata.bge_rx_jumbo_dmamap[i], sc->bge_cdata.bge_rx_jumbo_dmamap[i],
BUS_DMASYNC_POSTREAD); BUS_DMASYNC_POSTREAD);
bus_dmamap_unload(sc->bge_cdata.bge_mtag_jumbo, bus_dmamap_unload(sc->bge_cdata.bge_mtag_jumbo,
sc->bge_cdata.bge_rx_jumbo_dmamap[i]); sc->bge_cdata.bge_rx_jumbo_dmamap[i]);
m_freem(sc->bge_cdata.bge_rx_jumbo_chain[i]); m_freem(sc->bge_cdata.bge_rx_jumbo_chain[i]);
sc->bge_cdata.bge_rx_jumbo_chain[i] = NULL; sc->bge_cdata.bge_rx_jumbo_chain[i] = NULL;
} }
bzero((char *)&sc->bge_ldata.bge_rx_jumbo_ring[i], bzero((char *)&sc->bge_ldata.bge_rx_jumbo_ring[i],
sizeof(struct bge_extrx_bd)); sizeof(struct bge_extrx_bd));
} }
}}
static voidstatic void
bge_free_tx_ring(struct bge_softc *sc)bge_free_tx_ring(struct bge_softc *sc)
{{
int i; int i;
if (sc->bge_ldata.bge_tx_ring == NULL) if (sc->bge_ldata.bge_tx_ring == NULL)
return; return;
for (i = 0; i < BGE_TX_RING_CNT; i++) { for (i = 0; i < BGE_TX_RING_CNT; i++) {
if (sc->bge_cdata.bge_tx_chain[i] != NULL) { if (sc->bge_cdata.bge_tx_chain[i] != NULL) {
bus_dmamap_sync(sc->bge_cdata.bge_tx_mtag, bus_dmamap_sync(sc->bge_cdata.bge_tx_mtag,
sc->bge_cdata.bge_tx_dmamap[i], sc->bge_cdata.bge_tx_dmamap[i],
BUS_DMASYNC_POSTWRITE); BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(sc->bge_cdata.bge_tx_mtag, bus_dmamap_unload(sc->bge_cdata.bge_tx_mtag,
sc->bge_cdata.bge_tx_dmamap[i]); sc->bge_cdata.bge_tx_dmamap[i]);
m_freem(sc->bge_cdata.bge_tx_chain[i]); m_freem(sc->bge_cdata.bge_tx_chain[i]);
sc->bge_cdata.bge_tx_chain[i] = NULL; sc->bge_cdata.bge_tx_chain[i] = NULL;
} }
bzero((char *)&sc->bge_ldata.bge_tx_ring[i], bzero((char *)&sc->bge_ldata.bge_tx_ring[i],
sizeof(struct bge_tx_bd)); sizeof(struct bge_tx_bd));
} }
}}
static intstatic int
bge_init_tx_ring(struct bge_softc *sc)bge_init_tx_ring(struct bge_softc *sc)
{{
sc->bge_txcnt = 0; sc->bge_txcnt = 0;
sc->bge_tx_saved_considx = 0; sc->bge_tx_saved_considx = 0;
bzero(sc->bge_ldata.bge_tx_ring, BGE_TX_RING_SZ); bzero(sc->bge_ldata.bge_tx_ring, BGE_TX_RING_SZ);
bus_dmamap_sync(sc->bge_cdata.bge_tx_ring_tag, bus_dmamap_sync(sc->bge_cdata.bge_tx_ring_tag,
sc->bge_cdata.bge_tx_ring_map, BUS_DMASYNC_PREWRITE); sc->bge_cdata.bge_tx_ring_map, BUS_DMASYNC_PREWRITE);
/* Initialize transmit producer index for host-memory send ring. */ /* Initialize transmit producer index for host-memory send ring. */
sc->bge_tx_prodidx = 0; sc->bge_tx_prodidx = 0;
bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, sc->bge_tx_prodidx); bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, sc->bge_tx_prodidx);
/* 5700 b2 errata */ /* 5700 b2 errata */
if (sc->bge_chiprev == BGE_CHIPREV_5700_BX) if (sc->bge_chiprev == BGE_CHIPREV_5700_BX)
bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, sc->bge_tx_prodidx); bge_writembx(sc, BGE_MBX_TX_HOST_PROD0_LO, sc->bge_tx_prodidx);
/* NIC-memory send ring not used; initialize to zero. */ /* NIC-memory send ring not used; initialize to zero. */
bge_writembx(sc, BGE_MBX_TX_NIC_PROD0_LO, 0); bge_writembx(sc, BGE_MBX_TX_NIC_PROD0_LO, 0);
/* 5700 b2 errata */ /* 5700 b2 errata */
if (sc->bge_chiprev == BGE_CHIPREV_5700_BX) if (sc->bge_chiprev == BGE_CHIPREV_5700_BX)
bge_writembx(sc, BGE_MBX_TX_NIC_PROD0_LO, 0); bge_writembx(sc, BGE_MBX_TX_NIC_PROD0_LO, 0);
return (0); return (0);
}}
static voidstatic void
bge_setpromisc(struct bge_softc *sc)bge_setpromisc(struct bge_softc *sc)
{{
if_t ifp; if_t ifp;
BGE_LOCK_ASSERT(sc); BGE_LOCK_ASSERT(sc);
ifp = sc->bge_ifp; ifp = sc->bge_ifp;
/* Enable or disable promiscuous mode as needed. */ /* Enable or disable promiscuous mode as needed. */
if (if_getflags(ifp) & IFF_PROMISC) if (if_getflags(ifp) & IFF_PROMISC)
BGE_SETBIT(sc, BGE_RX_MODE, BGE_RXMODE_RX_PROMISC); BGE_SETBIT(sc, BGE_RX_MODE, BGE_RXMODE_RX_PROMISC);
else else
BGE_CLRBIT(sc, BGE_RX_MODE, BGE_RXMODE_RX_PROMISC); BGE_CLRBIT(sc, BGE_RX_MODE, BGE_RXMODE_RX_PROMISC);
}}
static voidstatic void
bge_setmulti(struct bge_softc *sc)bge_setmulti(struct bge_softc *sc)
{{
if_t ifp; if_t ifp;
int mc_count = 0; int mc_count = 0;
uint32_t hashes[4] = { 0, 0, 0, 0 }; uint32_t hashes[4] = { 0, 0, 0, 0 };
int h, i, mcnt; int h, i, mcnt;
unsigned char *mta; unsigned char *mta;
BGE_LOCK_ASSERT(sc); BGE_LOCK_ASSERT(sc);
ifp = sc->bge_ifp; ifp = sc->bge_ifp;
mc_count = if_multiaddr_count(ifp, -1); mc_count = if_multiaddr_count(ifp, -1);
mta = malloc(sizeof(unsigned char) * ETHER_ADDR_LEN * mta = malloc(sizeof(unsigned char) * ETHER_ADDR_LEN *
mc_count, M_DEVBUF, M_NOWAIT); mc_count, M_DEVBUF, M_NOWAIT);
if(mta == NULL) { if(mta == NULL) {
device_printf(sc->bge_dev, device_printf(sc->bge_dev,
"Failed to allocated temp mcast list\n"); "Failed to allocated temp mcast list\n");
return; return;
} }
if (if_getflags(ifp) & IFF_ALLMULTI || if_getflags(ifp) & IFF_PROMISC) { if (if_getflags(ifp) & IFF_ALLMULTI || if_getflags(ifp) & IFF_PROMISC) {
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), 0xFFFFFFFF); CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), 0xFFFFFFFF);
free(mta, M_DEVBUF); free(mta, M_DEVBUF);
return; return;
} }
/* First, zot all the existing filters. */ /* First, zot all the existing filters. */
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), 0); CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), 0);
if_multiaddr_array(ifp, mta, &mcnt, mc_count); if_multiaddr_array(ifp, mta, &mcnt, mc_count);
for(i = 0; i < mcnt; i++) { for(i = 0; i < mcnt; i++) {
h = ether_crc32_le(mta + (i * ETHER_ADDR_LEN), h = ether_crc32_le(mta + (i * ETHER_ADDR_LEN),
ETHER_ADDR_LEN) & 0x7F; ETHER_ADDR_LEN) & 0x7F;
hashes[(h & 0x60) >> 5] |= 1 << (h & 0x1F); hashes[(h & 0x60) >> 5] |= 1 << (h & 0x1F);
} }
if_maddr_runlock(ifp);
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), hashes[i]); CSR_WRITE_4(sc, BGE_MAR0 + (i * 4), hashes[i]);
free(mta, M_DEVBUF); free(mta, M_DEVBUF);
}}
static voidstatic void
bge_setvlan(struct bge_softc *sc)bge_setvlan(struct bge_softc *sc)
{{
if_t ifp; if_t ifp;
BGE_LOCK_ASSERT(sc); BGE_LOCK_ASSERT(sc);
ifp = sc->bge_ifp; ifp = sc->bge_ifp;
/* Enable or disable VLAN tag stripping as needed. */ /* Enable or disable VLAN tag stripping as needed. */
if (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) if (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING)
BGE_CLRBIT(sc, BGE_RX_MODE, BGE_RXMODE_RX_KEEP_VLAN_DIAG); BGE_CLRBIT(sc, BGE_RX_MODE, BGE_RXMODE_RX_KEEP_VLAN_DIAG);
else else
BGE_SETBIT(sc, BGE_RX_MODE, BGE_RXMODE_RX_KEEP_VLAN_DIAG); BGE_SETBIT(sc, BGE_RX_MODE, BGE_RXMODE_RX_KEEP_VLAN_DIAG);
}}
static voidstatic void
bge_sig_pre_reset(struct bge_softc *sc, int type)bge_sig_pre_reset(struct bge_softc *sc, int type)
{{
/* /*
* Some chips don't like this so only do this if ASF is enabled * Some chips don't like this so only do this if ASF is enabled
*/ */
if (sc->bge_asf_mode) if (sc->bge_asf_mode)
bge_writemem_ind(sc, BGE_SRAM_FW_MB, BGE_SRAM_FW_MB_MAGIC); bge_writemem_ind(sc, BGE_SRAM_FW_MB, BGE_SRAM_FW_MB_MAGIC);
if (sc->bge_asf_mode & ASF_NEW_HANDSHAKE) { if (sc->bge_asf_mode & ASF_NEW_HANDSHAKE) {
switch (type) { switch (type) {
case BGE_RESET_START: case BGE_RESET_START:
bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB, bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB,
BGE_FW_DRV_STATE_START); BGE_FW_DRV_STATE_START);
break; break;
case BGE_RESET_SHUTDOWN: case BGE_RESET_SHUTDOWN:
bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB, bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB,
BGE_FW_DRV_STATE_UNLOAD); BGE_FW_DRV_STATE_UNLOAD);
break; break;
case BGE_RESET_SUSPEND: case BGE_RESET_SUSPEND:
bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB, bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB,
BGE_FW_DRV_STATE_SUSPEND); BGE_FW_DRV_STATE_SUSPEND);
break; break;
} }
} }
if (type == BGE_RESET_START || type == BGE_RESET_SUSPEND) if (type == BGE_RESET_START || type == BGE_RESET_SUSPEND)
bge_ape_driver_state_change(sc, type); bge_ape_driver_state_change(sc, type);
}}
static voidstatic void
bge_sig_post_reset(struct bge_softc *sc, int type)bge_sig_post_reset(struct bge_softc *sc, int type)
{{
if (sc->bge_asf_mode & ASF_NEW_HANDSHAKE) { if (sc->bge_asf_mode & ASF_NEW_HANDSHAKE) {
switch (type) { switch (type) {
case BGE_RESET_START: case BGE_RESET_START:
bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB, bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB,
BGE_FW_DRV_STATE_START_DONE); BGE_FW_DRV_STATE_START_DONE);
/* START DONE */ /* START DONE */
break; break;
case BGE_RESET_SHUTDOWN: case BGE_RESET_SHUTDOWN:
bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB, bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB,
BGE_FW_DRV_STATE_UNLOAD_DONE); BGE_FW_DRV_STATE_UNLOAD_DONE);
break; break;
} }
} }
if (type == BGE_RESET_SHUTDOWN) if (type == BGE_RESET_SHUTDOWN)
bge_ape_driver_state_change(sc, type); bge_ape_driver_state_change(sc, type);
}}
static voidstatic void
bge_sig_legacy(struct bge_softc *sc, int type)bge_sig_legacy(struct bge_softc *sc, int type)
{{
if (sc->bge_asf_mode) { if (sc->bge_asf_mode) {
switch (type) { switch (type) {
case BGE_RESET_START: case BGE_RESET_START:
bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB, bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB,
BGE_FW_DRV_STATE_START); BGE_FW_DRV_STATE_START);
break; break;
case BGE_RESET_SHUTDOWN: case BGE_RESET_SHUTDOWN:
bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB, bge_writemem_ind(sc, BGE_SRAM_FW_DRV_STATE_MB,
BGE_FW_DRV_STATE_UNLOAD); BGE_FW_DRV_STATE_UNLOAD);
break; break;
} }
} }
}}
static voidstatic void
bge_stop_fw(struct bge_softc *sc)bge_stop_fw(struct bge_softc *sc)
{{
int i; int i;
if (sc->bge_asf_mode) { if (sc->bge_asf_mode) {
bge_writemem_ind(sc, BGE_SRAM_FW_CMD_MB, BGE_FW_CMD_PAUSE); bge_writemem_ind(sc, BGE_SRAM_FW_CMD_MB, BGE_FW_CMD_PAUSE);
CSR_WRITE_4(sc, BGE_RX_CPU_EVENT, CSR_WRITE_4(sc, BGE_RX_CPU_EVENT,
CSR_READ_4(sc, BGE_RX_CPU_EVENT) | BGE_RX_CPU_DRV_EVENT); CSR_READ_4(sc, BGE_RX_CPU_EVENT) | BGE_RX_CPU_DRV_EVENT);
for (i = 0; i < 100; i++ ) { for (i = 0; i < 100; i++ ) {
if (!(CSR_READ_4(sc, BGE_RX_CPU_EVENT) & if (!(CSR_READ_4(sc, BGE_RX_CPU_EVENT) &
BGE_RX_CPU_DRV_EVENT)) BGE_RX_CPU_DRV_EVENT))
break; break;
DELAY(10); DELAY(10);
} }
} }
}}
static uint32_tstatic uint32_t
bge_dma_swap_options(struct bge_softc *sc)bge_dma_swap_options(struct bge_softc *sc)
{{
uint32_t dma_options; uint32_t dma_options;
dma_options = BGE_MODECTL_WORDSWAP_NONFRAME | dma_options = BGE_MODECTL_WORDSWAP_NONFRAME |
BGE_MODECTL_BYTESWAP_DATA | BGE_MODECTL_WORDSWAP_DATA; BGE_MODECTL_BYTESWAP_DATA | BGE_MODECTL_WORDSWAP_DATA;
#if BYTE_ORDER == BIG_ENDIAN#if BYTE_ORDER == BIG_ENDIAN
dma_options |= BGE_MODECTL_BYTESWAP_NONFRAME; dma_options |= BGE_MODECTL_BYTESWAP_NONFRAME;
#endif#endif
if ((sc)->bge_asicrev == BGE_ASICREV_BCM5720)
dma_options |= BGE_MODECTL_BYTESWAP_B2HRX_DATA |
BGE_MODECTL_WORDSWAP_B2HRX_DATA | BGE_MODECTL_B2HRX_ENABLE |
BGE_MODECTL_HTX2B_ENABLE;
return (dma_options); return (dma_options);
}}
/*/*
* Do endian, PCI and DMA initialization. * Do endian, PCI and DMA initialization.
*/ */
static intstatic int
bge_chipinit(struct bge_softc *sc)bge_chipinit(struct bge_softc *sc)
{{
uint32_t dma_rw_ctl, misc_ctl, mode_ctl; uint32_t dma_rw_ctl, misc_ctl, mode_ctl;
uint16_t val; uint16_t val;
int i; int i;
/* Set endianness before we access any non-PCI registers. */ /* Set endianness before we access any non-PCI registers. */
misc_ctl = BGE_INIT; misc_ctl = BGE_INIT;
if (sc->bge_flags & BGE_FLAG_TAGGED_STATUS) if (sc->bge_flags & BGE_FLAG_TAGGED_STATUS)
misc_ctl |= BGE_PCIMISCCTL_TAGGED_STATUS; misc_ctl |= BGE_PCIMISCCTL_TAGGED_STATUS;
pci_write_config(sc->bge_dev, BGE_PCI_MISC_CTL, misc_ctl, 4); pci_write_config(sc->bge_dev, BGE_PCI_MISC_CTL, misc_ctl, 4);
/* /*
* Clear the MAC statistics block in the NIC's * Clear the MAC statistics block in the NIC's
* internal memory. * internal memory.
*/ */
for (i = BGE_STATS_BLOCK; for (i = BGE_STATS_BLOCK;
i < BGE_STATS_BLOCK_END + 1; i += sizeof(uint32_t)) i < BGE_STATS_BLOCK_END + 1; i += sizeof(uint32_t))
BGE_MEMWIN_WRITE(sc, i, 0); BGE_MEMWIN_WRITE(sc, i, 0);
for (i = BGE_STATUS_BLOCK; for (i = BGE_STATUS_BLOCK;
i < BGE_STATUS_BLOCK_END + 1; i += sizeof(uint32_t)) i < BGE_STATUS_BLOCK_END + 1; i += sizeof(uint32_t))
BGE_MEMWIN_WRITE(sc, i, 0); BGE_MEMWIN_WRITE(sc, i, 0);
if (sc->bge_chiprev == BGE_CHIPREV_5704_BX) { if (sc->bge_chiprev == BGE_CHIPREV_5704_BX) {
/* /*
* Fix data corruption caused by non-qword write with WB. * Fix data corruption caused by non-qword write with WB.
* Fix master abort in PCI mode. * Fix master abort in PCI mode.
* Fix PCI latency timer. * Fix PCI latency timer.
*/ */
val = pci_read_config(sc->bge_dev, BGE_PCI_MSI_DATA + 2, 2); val = pci_read_config(sc->bge_dev, BGE_PCI_MSI_DATA + 2, 2);
val |= (1 << 10) | (1 << 12) | (1 << 13); val |= (1 << 10) | (1 << 12) | (1 << 13);
pci_write_config(sc->bge_dev, BGE_PCI_MSI_DATA + 2, val, 2); pci_write_config(sc->bge_dev, BGE_PCI_MSI_DATA + 2, val, 2);
} }
if (sc->bge_asicrev == BGE_ASICREV_BCM57765 || if (sc->bge_asicrev == BGE_ASICREV_BCM57765 ||
sc->bge_asicrev == BGE_ASICREV_BCM57766) { sc->bge_asicrev == BGE_ASICREV_BCM57766) {
/* /*
* For the 57766 and non Ax versions of 57765, bootcode * For the 57766 and non Ax versions of 57765, bootcode
* needs to setup the PCIE Fast Training Sequence (FTS) * needs to setup the PCIE Fast Training Sequence (FTS)
* value to prevent transmit hangs. * value to prevent transmit hangs.
*/ */
if (sc->bge_chiprev != BGE_CHIPREV_57765_AX) { if (sc->bge_chiprev != BGE_CHIPREV_57765_AX) {
CSR_WRITE_4(sc, BGE_CPMU_PADRNG_CTL, CSR_WRITE_4(sc, BGE_CPMU_PADRNG_CTL,
CSR_READ_4(sc, BGE_CPMU_PADRNG_CTL) | CSR_READ_4(sc, BGE_CPMU_PADRNG_CTL) |
BGE_CPMU_PADRNG_CTL_RDIV2); BGE_CPMU_PADRNG_CTL_RDIV2);
} }
} }
/* /*
* Set up the PCI DMA control register. * Set up the PCI DMA control register.
*/ */
dma_rw_ctl = BGE_PCIDMARWCTL_RD_CMD_SHIFT(6) | dma_rw_ctl = BGE_PCIDMARWCTL_RD_CMD_SHIFT(6) |
BGE_PCIDMARWCTL_WR_CMD_SHIFT(7); BGE_PCIDMARWCTL_WR_CMD_SHIFT(7);
if (sc->bge_flags & BGE_FLAG_PCIE) { if (sc->bge_flags & BGE_FLAG_PCIE) {
if (sc->bge_mps >= 256) if (sc->bge_mps >= 256)
dma_rw_ctl |= BGE_PCIDMARWCTL_WR_WAT_SHIFT(7); dma_rw_ctl |= BGE_PCIDMARWCTL_WR_WAT_SHIFT(7);
else else
dma_rw_ctl |= BGE_PCIDMARWCTL_WR_WAT_SHIFT(3); dma_rw_ctl |= BGE_PCIDMARWCTL_WR_WAT_SHIFT(3);
} else if (sc->bge_flags & BGE_FLAG_PCIX) { } else if (sc->bge_flags & BGE_FLAG_PCIX) {
if (BGE_IS_5714_FAMILY(sc)) { if (BGE_IS_5714_FAMILY(sc)) {
/* 256 bytes for read and write. */ /* 256 bytes for read and write. */
dma_rw_ctl |= BGE_PCIDMARWCTL_RD_WAT_SHIFT(2) | dma_rw_ctl |= BGE_PCIDMARWCTL_RD_WAT_SHIFT(2) |
BGE_PCIDMARWCTL_WR_WAT_SHIFT(2); BGE_PCIDMARWCTL_WR_WAT_SHIFT(2);
dma_rw_ctl |= (sc->bge_asicrev == BGE_ASICREV_BCM5780) ? dma_rw_ctl |= (sc->bge_asicrev == BGE_ASICREV_BCM5780) ?
BGE_PCIDMARWCTL_ONEDMA_ATONCE_GLOBAL : BGE_PCIDMARWCTL_ONEDMA_ATONCE_GLOBAL :
BGE_PCIDMARWCTL_ONEDMA_ATONCE_LOCAL; BGE_PCIDMARWCTL_ONEDMA_ATONCE_LOCAL;
} else if (sc->bge_asicrev == BGE_ASICREV_BCM5703) { } else if (sc->bge_asicrev == BGE_ASICREV_BCM5703) {
/* /*
* In the BCM5703, the DMA read watermark should * In the BCM5703, the DMA read watermark should
* be set to less than or equal to the maximum * be set to less than or equal to the maximum
* memory read byte count of the PCI-X command * memory read byte count of the PCI-X command
* register. * register.
*/ */
dma_rw_ctl |= BGE_PCIDMARWCTL_RD_WAT_SHIFT(4) | dma_rw_ctl |= BGE_PCIDMARWCTL_RD_WAT_SHIFT(4) |
BGE_PCIDMARWCTL_WR_WAT_SHIFT(3); BGE_PCIDMARWCTL_WR_WAT_SHIFT(3);
} else if (sc->bge_asicrev == BGE_ASICREV_BCM5704) { } else if (sc->bge_asicrev == BGE_ASICREV_BCM5704) {
/* 1536 bytes for read, 384 bytes for write. */ /* 1536 bytes for read, 384 bytes for write. */
dma_rw_ctl |= BGE_PCIDMARWCTL_RD_WAT_SHIFT(7) | dma_rw_ctl |= BGE_PCIDMARWCTL_RD_WAT_SHIFT(7) |
BGE_PCIDMARWCTL_WR_WAT_SHIFT(3); BGE_PCIDMARWCTL_WR_WAT_SHIFT(3);
} else { } else {
/* 384 bytes for read and write. */ /* 384 bytes for read and write. */
dma_rw_ctl |= BGE_PCIDMARWCTL_RD_WAT_SHIFT(3) | dma_rw_ctl |= BGE_PCIDMARWCTL_RD_WAT_SHIFT(3) |
BGE_PCIDMARWCTL_WR_WAT_SHIFT(3) | BGE_PCIDMARWCTL_WR_WAT_SHIFT(3) |
0x0F; 0x0F;
} }
if (sc->bge_asicrev == BGE_ASICREV_BCM5703 || if (sc->bge_asicrev == BGE_ASICREV_BCM5703 ||
sc->bge_asicrev == BGE_ASICREV_BCM5704) { sc->bge_asicrev == BGE_ASICREV_BCM5704) {
uint32_t tmp; uint32_t tmp;
/* Set ONE_DMA_AT_ONCE for hardware workaround. */ /* Set ONE_DMA_AT_ONCE for hardware workaround. */
tmp = CSR_READ_4(sc, BGE_PCI_CLKCTL) & 0x1F; tmp = CSR_READ_4(sc, BGE_PCI_CLKCTL) & 0x1F;
if (tmp == 6 || tmp == 7) if (tmp == 6 || tmp == 7)
dma_rw_ctl |= dma_rw_ctl |=
BGE_PCIDMARWCTL_ONEDMA_ATONCE_GLOBAL; BGE_PCIDMARWCTL_ONEDMA_ATONCE_GLOBAL;
/* Set PCI-X DMA write workaround. */ /* Set PCI-X DMA write workaround. */
dma_rw_ctl |= BGE_PCIDMARWCTL_ASRT_ALL_BE; dma_rw_ctl |= BGE_PCIDMARWCTL_ASRT_ALL_BE;
} }
} else { } else {
/* Conventional PCI bus: 256 bytes for read and write. */ /* Conventional PCI bus: 256 bytes for read and write. */
dma_rw_ctl |= BGE_PCIDMARWCTL_RD_WAT_SHIFT(7) | dma_rw_ctl |= BGE_PCIDMARWCTL_RD_WAT_SHIFT(7) |
BGE_PCIDMARWCTL_WR_WAT_SHIFT(7); BGE_PCIDMARWCTL_WR_WAT_SHIFT(7);
if (sc->bge_asicrev != BGE_ASICREV_BCM5705 &&