summaryrefslogtreecommitdiffstats
path: root/cfe/cfe/dev
diff options
context:
space:
mode:
Diffstat (limited to 'cfe/cfe/dev')
-rw-r--r--cfe/cfe/dev/SIBYTE_PRIVATE_FILES6
-rw-r--r--cfe/cfe/dev/bcm5700.h1007
-rw-r--r--cfe/cfe/dev/bcm5821.h278
-rw-r--r--cfe/cfe/dev/dc21143.h588
-rw-r--r--cfe/cfe/dev/dev_atapi.c222
-rw-r--r--cfe/cfe/dev/dev_bcm1250.c275
-rw-r--r--cfe/cfe/dev/dev_bcm5700.c2557
-rw-r--r--cfe/cfe/dev/dev_bcm5821.c1592
-rw-r--r--cfe/cfe/dev/dev_dc21143.c2388
-rw-r--r--cfe/cfe/dev/dev_dp83815.c2290
-rw-r--r--cfe/cfe/dev/dev_ds17887clock.c422
-rw-r--r--cfe/cfe/dev/dev_flash.c1367
-rw-r--r--cfe/cfe/dev/dev_ht7520.c167
-rw-r--r--cfe/cfe/dev/dev_ide_common.c1249
-rw-r--r--cfe/cfe/dev/dev_ide_pci.c358
-rw-r--r--cfe/cfe/dev/dev_newflash.c1428
-rw-r--r--cfe/cfe/dev/dev_ns16550.c255
-rw-r--r--cfe/cfe/dev/dev_ns16550_pci.c114
-rw-r--r--cfe/cfe/dev/dev_null.c142
-rw-r--r--cfe/cfe/dev/dev_promice.c402
-rw-r--r--cfe/cfe/dev/dev_sp1011.c151
-rw-r--r--cfe/cfe/dev/dev_tulip.c2985
-rw-r--r--cfe/cfe/dev/dp83815.h559
-rw-r--r--cfe/cfe/dev/ns16550.h143
-rw-r--r--cfe/cfe/dev/pci_devs.c79
25 files changed, 21024 insertions, 0 deletions
diff --git a/cfe/cfe/dev/SIBYTE_PRIVATE_FILES b/cfe/cfe/dev/SIBYTE_PRIVATE_FILES
new file mode 100644
index 0000000..eae0411
--- /dev/null
+++ b/cfe/cfe/dev/SIBYTE_PRIVATE_FILES
@@ -0,0 +1,6 @@
+dev_ptflash.c
+bcm5700.h
+dev_bcm5700.c
+bcm5821.h
+dev_bcm5821.c
+
diff --git a/cfe/cfe/dev/bcm5700.h b/cfe/cfe/dev/bcm5700.h
new file mode 100644
index 0000000..76aa3ea
--- /dev/null
+++ b/cfe/cfe/dev/bcm5700.h
@@ -0,0 +1,1007 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * BCM5700 (10/100/1K EthernetMAC) registers File: bcm5700.c
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+#ifndef _BCM5700_H_
+#define _BCM5700_H_
+
+/*
+ * Register and bit definitions for the Broadcom BCM570X family (aka
+ * Tigon3) of Integrated MACs.
+ *
+ * References:
+ *
+ * Host Programmer Interface Specification for the BCM570X Family
+ * of Highly-Integrated Media Access Controllers, 570X-PG106-R.
+ * Broadcom Corp., 16215 Alton Parkway, Irvine CA, 09/27/02
+ *
+ * Simplified Programmer Interface Specification for the BCM570X Family
+ * of Highly Integrated Media Access Controllers, 570X-PG202-R.
+ * Broadcom Corp., 16215 Alton Parkway, Irvine CA, 10/14/02
+ */
+
+#define K_PCI_VENDOR_BROADCOM 0x14e4
+#define K_PCI_ID_BCM5700 0x1644
+#define K_PCI_ID_BCM5701 0x1645
+#define K_PCI_ID_BCM5702 0x16A6
+#define K_PCI_ID_BCM5703 0x16A7
+#define K_PCI_ID_BCM5704C 0x1648
+#define K_PCI_ID_BCM5704S 0x16A8
+#define K_PCI_ID_BCM5705 0x1653
+
+#define _DD_MAKEMASK1(n) (1 << (n))
+#define _DD_MAKEMASK(v,n) ((((1)<<(v))-1) << (n))
+#define _DD_MAKEVALUE(v,n) ((v) << (n))
+#define _DD_GETVALUE(v,n,m) (((v) & (m)) >> (n))
+
+
+/* Registers 0x0000 - 0x00FF are PCI Configuration registers (shadow) */
+
+#define PCI_PCIX_CMD_REG 0x40
+#define PCI_PCIX_STAT_REG 0x44
+
+#define PCI_PMC_REG 0x48
+#define PCI_PMCSR_REG 0x4C
+
+#define R_MISC_HOST_CTRL 0x0068
+#define R_DMA_RW_CTRL 0x006C
+#define R_PCI_STATE 0x0070
+#define R_PCI_CLK_CTRL 0x0074
+#define R_REG_BASE_ADDR 0x0078
+#define R_MEMWIN_BASE_ADDR 0x007C
+#define R_REG_DATA 0x0080
+#define R_MEMWIN_DATA 0x0084
+/* For 5700 and 5701, 0x0088-0x0090 shadow 0x6800-0x6808 */
+#define R_INT_MBOX0 0x0B0 /* 8 bytes, shadows R_INT_MBOX(0) */
+
+/* Registers 0x0200 - 0x03FF are High Priority Mailbox registers */
+
+#define R_INT_MBOX(n) (0x0200 + 8*(n)) /* 0 <= n < 4 */
+#define R_GEN_MBOX(n) (0x0220 + 8*(n)-8) /* 1 <= n <= 8 */
+#define R_RELOAD_STATS_MBOX 0x0260
+#define R_RCV_BD_STD_PI 0x0268
+#define R_RCV_BD_JUMBO_PI 0x0270
+#define R_RCV_BD_MINI_PI 0x0278
+#define R_RCV_BD_RTN_CI(n) (0x0280 + 8*(n)-8) /* 1 <= n <= 16 */
+#define R_SND_BD_PI(n) (0x0300 + 8*(n)-8) /* 1 <= n <= 16 */
+#define R_SND_BD_NIC_PI(n) (0x0380 + 8*(n)-8) /* 1 <= n <= 16 */
+
+/* Registers 0x0400 - 0x0BFF are MAC Control registers */
+
+#define R_MAC_MODE 0x0400
+#define R_MAC_STATUS 0x0404
+#define R_MAC_EVENT_ENB 0x0408
+#define R_MAC_LED_CTRL 0x040C
+
+#define R_MAC_ADDR1_HIGH 0x0410
+#define R_MAC_ADDR1_LOW 0x0414
+#define R_MAC_ADDR2_HIGH 0x0418
+#define R_MAC_ADDR2_LOW 0x041C
+#define R_MAC_ADDR3_HIGH 0x0420
+#define R_MAC_ADDR3_LOW 0x0424
+#define R_MAC_ADDR4_HIGH 0x0428
+#define R_MAC_ADDR4_LOW 0x042C
+
+#define R_WOL_PATTERN_PTR 0x0430
+#define R_WOL_PATTERN_CFG 0x0434
+#define R_TX_BACKOFF 0x0438
+#define R_RX_MTU 0x043C
+#define R_PCS_TEST 0x0440
+#define R_TX_AUTONEG 0x0444
+#define R_RX_AUTONEG 0x0448
+
+#define R_MI_COMM 0x044C
+#define R_MI_STATUS 0x0450
+#define R_MI_MODE 0x0454
+
+#define R_AUTOPOLL_STAT 0x0458
+#define R_TX_MODE 0x045C
+#define R_TX_STAT 0x0460
+#define R_TX_LENS 0x0464
+#define R_RX_MODE 0x0468
+#define R_RX_STAT 0x046C
+
+#define R_MAC_HASH(n) (0x0470 + 4*(n)) /* 0 <= n < 4 */
+
+#define R_RX_BD_RULES_CTRL(n) (0x0480 + 8*(n)) /* 0 <= n < 16 */
+#define R_RX_BD_RULES_MASK(n) (0x0484 + 8*(n))
+
+#define R_RX_RULES_CFG 0x0500
+#define R_RX_FRAMES_LOW 0x0504
+#define R_MAC_HASH_EXT(n) (0x0520 + 4*(n)) /* 0 <= n < 4 */
+#define R_MAC_ADDR_EXT(n) (0x0530 + 8*(n)) /* 0 <= n < 12 */
+#define R_SERDES_CTRL 0x0590
+#define R_SERDES_STAT 0x0594
+#define R_RX_STATS_MEM 0x0800
+#define R_TX_STATS_MEM 0x0880
+
+
+/*
+ * Note on Buffer Descriptor (BD) Ring indices:
+ * Numbering follows Broadcom literature, which uses indices 1-16.
+ * PI = producer index, CI = consumer index.
+ */
+
+/* Registers 0x0C00 - 0x0FFF are Send Data Initiator Control registers */
+
+#define R_SND_DATA_MODE 0x0C00
+#define R_SND_DATA_STAT 0x0C04
+#define R_SND_DATA_STATS_CTRL 0x0C08
+#define R_SND_DATA_STATS_ENB 0x0C0C
+#define R_SND_DATA_STATS_INCR 0x0C10
+
+#define R_STATS_CTR_SND_COS(n) (0x0C80 + 4*(n)-4) /* 1 <= n <= 16 */
+#define R_STATS_DMA_RDQ_FULL 0x0CC0
+#define R_STATS_DMA_HP_RDQ_FULL 0x0CC4
+#define R_STATS_SDCQ_FULL 0x0CC8
+#define R_STATS_NIC_SET_SND_PI 0x0CCC
+#define R_STATS_STAT_UPDATED 0x0CD0
+#define R_STATS_IRQS 0x0CD4
+#define R_STATS_IRQS_AVOIDED 0x0CD8
+#define R_STATS_SND_THRSH_HIT 0x0CDC
+
+/* Registers 0x1000 - 0x13FF are Send Data Completion Control registers */
+
+#define R_SND_DATA_COMP_MODE 0x1000
+
+/* Registers 0x1400 - 0x17FF are Send BD Ring Selection Control registers */
+
+#define R_SND_BD_SEL_MODE 0x1400
+#define R_SND_BD_SEL_STAT 0x1404
+#define R_SND_BD_DIAG 0x1408
+#define R_SND_BD_SEL_CI(n) (0x1440 + 4*(n)-4) /* 1 <= n <= 16 */
+
+/* Registers 0x1800 - 0x1BFF are Send BD Initiator Control registers */
+
+#define R_SND_BD_INIT_MODE 0x1800
+#define R_SND_BD_INIT_STAT 0x1804
+#define R_SND_BD_INIT_PI(n) (0x1808 + 4*(n)-4) /* 1 <= n <= 16 */
+
+/* Registers 0x1C00 - 0x1FFF are Send BD Completion Control registers */
+
+#define R_SND_BD_COMP_MODE 0x1C00
+
+/* Registers 0x2000 - 0x23FF are Receive List Placement Control registers */
+
+#define R_RCV_LIST_MODE 0x2000
+#define R_RCV_LIST_STAT 0x2004
+#define R_RCV_LIST_LOCK 0x2008
+#define R_RCV_NONEMPTY_BITS 0x200C
+#define R_RCV_LIST_CFG 0x2010
+#define R_RCV_LIST_STATS_CTRL 0x2014
+#define R_RCV_LIST_STATS_ENB 0x2018
+#define R_RCV_LIST_STATS_INC 0x201C
+#define R_RCV_LIST_HEAD(n) (0x2100 + 16*(n)-16) /* 1 <= n <= 16 */
+#define R_RCV_LIST_TAIL(n) (0x2104 + 16*(n)-16)
+#define R_RCV_LIST_CNT(n) (0x2108 + 16*(n)-16)
+#define R_STATS_CTR_RCV_COS(n) (0x2200 + 4*(n)-4) /* 1 <= n <= 16 */
+#define R_STATS_FILT_DROP 0x2240
+#define R_STATS_DMA_WRQ_FULL 0x2244
+#define R_STATS_DMA_HP_WRQ_FULL 0x2248
+#define R_STATS_NO_RCV_BDS 0x224C
+#define R_STATS_IN_DISCARDS 0x2250
+#define R_STATS_IN_ERRORS 0x2254
+#define R_STATS_RCV_THRSH_HIT 0x2258
+
+/* Registers 0x2400 - 0x27FF are Receive Data/BD Initiator Control registers */
+
+#define R_RCV_DATA_INIT_MODE 0x2400
+#define R_RCV_DATA_INIT_STAT 0x2404
+#define R_JUMBO_RCV_BD_RCB 0x2440 /* 16 bytes */
+#define R_STD_RCV_BD_RCB 0x2450 /* 16 bytes */
+#define R_MINI_RCV_BD_RCB 0x2460 /* 16 bytes */
+#define R_RCV_BD_INIT_JUMBO_CI 0x2470
+#define R_RCV_BD_INIT_STD_CI 0x2474
+#define R_RCV_BD_INIT_MINI_CI 0x2478
+#define R_RCV_BD_INIT_RTN_PI(n) (0x2480 + 4*(n)-4) /* 1 <= n <= 16 */
+#define R_RCV_BD_INIT_DIAG 0x24C0
+
+/* Registers 0x2800 - 0x2BFF are Receive Data Completion Control registers */
+
+#define R_RCV_COMP_MODE 0x2800
+
+/* Registers 0x2C00 - 0x2FFF are Receive BD Initiator Control registers */
+
+#define R_RCV_BD_INIT_MODE 0x2C00
+#define R_RCV_BD_INIT_STAT 0x2C04
+#define R_RCV_BD_INIT_JUMBO_PI 0x2C08
+#define R_RCV_BD_INIT_STD_PI 0x2C0C
+#define R_RCV_BD_INIT_MINI_PI 0x2C10
+#define R_MINI_RCV_BD_THRESH 0x2C14
+#define R_STD_RCV_BD_THRESH 0x2C18
+#define R_JUMBO_RCV_BD_THRESH 0x2C1C
+
+/* Registers 0x3000 - 0x33FF are Receive BD Completion Control registers */
+
+#define R_RCV_BD_COMP_MODE 0x3000
+#define R_RCV_BD_COMP_STAT 0x3004
+#define R_NIC_JUMBO_RCV_BD_PI 0x3008
+#define R_NIC_STD_RCV_BD_PI 0x300C
+#define R_NIC_MINI_RCV_BD_PI 0x3010
+
+/* Registers 0x3400 - 0x37FF are Receive List Selector Control registers */
+
+#define R_RCV_LIST_SEL_MODE 0x3400
+#define R_RCV_LIST_SEL_STATUS 0x3404
+
+/* Registers 0x3800 - 0x3BFF are Mbuf Cluster Free registers */
+
+#define R_MBUF_FREE_MODE 0x3800
+#define R_MBUF_FREE_STATUS 0x3804
+
+/* Registers 0x3C00 - 0x3FFF are Host Coalescing Control registers */
+
+#define R_HOST_COAL_MODE 0x3C00
+#define R_HOST_COAL_STAT 0x3C04
+#define R_RCV_COAL_TICKS 0x3C08
+#define R_SND_COAL_TICKS 0x3C0C
+#define R_RCV_COAL_MAX_CNT 0x3C10
+#define R_SND_COAL_MAX_CNT 0x3C14
+#define R_RCV_COAL_INT_TICKS 0x3C18
+#define R_SND_COAL_INT_TICKS 0x3C1C
+#define R_RCV_COAL_INT_CNT 0x3C20
+#define R_SND_COAL_INT_CNT 0x3C24
+#define R_STATS_TICKS 0x3C28
+#define R_STATS_HOST_ADDR 0x3C30 /* 8 bytes */
+#define R_STATUS_HOST_ADDR 0x3C38 /* 8 bytes */
+#define R_STATS_BASE_ADDR 0x3C40
+#define R_STATUS_BASE_ADDR 0x3C44
+#define R_FLOW_ATTN 0x3C48
+#define R_NIC_JUMBO_RCV_BD_CI 0x3C50
+#define R_NIC_STD_RCV_BD_CI 0x3C54
+#define R_NIC_MINI_RCV_BD_CI 0x3C58
+#define R_NIC_RTN_PI(n) (0x3C80 + 4*(n)-4) /* 1 <= n <= 16 */
+#define R_NIC_SND_BD_CD(n) (0x3CC0 + 4*(n)-4) /* 1 <= n <= 16 */
+
+/* Registers 0x4000 - 0x43FF are Memory Arbiter registers */
+
+#define R_MEM_MODE 0x4000
+#define R_MEM_STATUS 0x4004
+#define R_MEM_TRAP_LOW 0x4008
+#define R_MEM_TRAP_HIGH 0x400C
+
+
+/* Registers 0x4400 - 0x47FF are Buffer Manager Control registers */
+
+#define R_BMGR_MODE 0x4400
+#define R_BMGR_STATUS 0x4404
+#define R_BMGR_MBUF_BASE 0x4408
+#define R_BMGR_MBUF_LEN 0x440C
+#define R_BMGR_MBUF_DMA_LOW 0x4410
+#define R_BMGR_MBUF_RX_LOW 0x4414
+#define R_BMGR_MBUF_HIGH 0x4418
+
+#define R_BMGR_DMA_BASE 0x442C
+#define R_BMGR_DMA_LEN 0x4430
+#define R_BMGR_DMA_LOW 0x4434
+#define R_BMGR_DMA_HIGH 0x4438
+
+#define R_BMGR_DIAG1 0x444C
+#define R_BMGR_DIAG2 0x4450
+#define R_BMGR_DIAG3 0x4454
+#define R_BMGR_RCV_FLOW_THRESH 0x4458
+
+/* Registers 0x4800 - 0x4BFF are Read DMA Control registers */
+
+#define R_RD_DMA_MODE 0x4800
+#define R_RD_DMA_STAT 0x4804
+
+/* Registers 0x4C00 - 0x4FFF are Write DMA Control registers */
+
+#define R_WR_DMA_MODE 0x4C00
+#define R_WR_DMA_STAT 0x4C04
+
+/* Registers 0x5000 - 0x53FF are RX RISC registers */
+
+#define R_RX_RISC_MODE 0x5000
+#define R_RX_RISC_STATE 0x5004
+#define R_RX_RISC_PC 0x501C
+
+/* Registers 0x5400 - 0x57FF are TX RISC registers */
+
+#define R_TX_RISC_MODE 0x5400
+#define R_TX_RISC_STATE 0x5404
+#define R_TX_RISC_PC 0x541C
+
+/* Registers 0x5800 - 0x5BFF are Low Priority Mailbox registers (8 bytes) */
+
+#define R_LP_INT_MBOX(n) (0x5800 + 8*(n)) /* 0 <= n < 4 */
+#define R_LP_GEN_MBOX(n) (0x5820 + 8*(n)-8) /* 1 <= n <= 8 */
+#define R_LP_RELOAD_STATS_MBOX 0x5860
+#define R_LP_RCV_BD_STD_PI 0x5868
+#define R_LP_RCV_BD_JUMBO_PI 0x5870
+#define R_LP_RCV_BD_MINI_PI 0x5878
+#define R_LP_RCV_BD_RTN_CI(n) (0x5880 + 8*(n)-8) /* 1 <= n <= 16 */
+#define R_LP_SND_BD_PI(n) (0x5900 + 8*(n)-8) /* 1 <= n <= 16 */
+
+/* Registers 0x5C00 - 0x5C03 are Flow Through Queues */
+
+#define R_FTQ_RESET 0x5C00
+
+/* Registers 0x6000 - 0x63FF are Message Signaled Interrupt registers */
+
+/* Registers 0x6400 - 0x67FF are DMA Completion registers */
+
+#define R_DMA_COMP_MODE 0x6400
+
+/* Registers 0x6800 - 0x68ff are General Control registers */
+
+#define R_MODE_CTRL 0x6800
+#define R_MISC_CFG 0x6804
+#define R_MISC_LOCAL_CTRL 0x6808
+#define R_TIMER 0x680C
+#define R_MEM_PWRUP 0x6030 /* 8 bytes */
+#define R_EEPROM_ADDR 0x6838
+#define R_EEPROM_DATA 0x683C
+#define R_EEPROM_CTRL 0x6840
+#define R_MDI_CTRL 0x6844
+#define R_EEPROM_DELAY 0x6848
+
+/* Registers 0x6C00 - 0x6CFF are ASF Support registers (NYI) */
+
+/* Registers 0x7000 - 0x7024 are NVM Interface registers (NYI) */
+
+
+/* PCI Capability registers (should be moved to PCI headers) */
+
+/* PCI-X Capability and Command Register (0x40) */
+
+#define PCIX_CMD_DPREC_ENABLE 0x00010000
+#define PCIX_CMD_RLXORDER_ENABLE 0x00020000
+#define PCIX_CMD_RD_CNT_SHIFT 18
+#define PCIX_CMD_RD_CNT_MASK 0x000C0000
+#define PCIX_CMD_MAX_SPLIT_SHIFT 20
+#define PCIX_CMD_MAX_SPLIT_MASK 0x00700000
+
+/* PCI-X Status Register (0x44) */
+
+
+/* Generic bit fields shared by most MODE and STATUS registers */
+
+#define M_MODE_RESET _DD_MAKEMASK1(0)
+#define M_MODE_ENABLE _DD_MAKEMASK1(1)
+#define M_MODE_ATTNENABLE _DD_MAKEMASK1(2)
+
+#define M_STAT_ERROR _DD_MAKEMASK1(1)
+
+/* Generic bit fields shared by STATS_CTRL registers */
+
+#define M_STATS_ENABLE _DD_MAKEMASK1(0)
+#define M_STATS_FASTUPDATE _DD_MAKEMASK1(1)
+#define M_STATS_CLEAR _DD_MAKEMASK1(2)
+#define M_STATS_FLUSH _DD_MAKEMASK1(3)
+#define M_STATS_ZERO _DD_MAKEMASK1(4)
+
+/* Private PCI Configuration registers (p 335) */
+
+/* MHC: Miscellaneous Host Control Register (0x68) */
+
+#define M_MHC_CLEARINTA _DD_MAKEMASK1(0)
+#define M_MHC_MASKPCIINT _DD_MAKEMASK1(1)
+#define M_MHC_ENBYTESWAP _DD_MAKEMASK1(2)
+#define M_MHC_ENWORDSWAP _DD_MAKEMASK1(3)
+#define M_MHC_ENPCISTATERW _DD_MAKEMASK1(4)
+#define M_MHC_ENCLKCTRLRW _DD_MAKEMASK1(5)
+#define M_MHC_ENREGWORDSWAP _DD_MAKEMASK1(6)
+#define M_MHC_ENINDIRECT _DD_MAKEMASK1(7)
+#define S_MHC_ASICREV 16
+#define M_MHC_ASICREV _DD_MAKEMASK(16,S_MHC_ASICREV)
+#define G_MHC_ASICREV(x) _DD_GETVALUE(x,S_MHC_ASICREV,M_MHC_ASICREV)
+
+/* DMAC: DMA Read/Write Control Register (0x6c) */
+
+#define S_DMAC_MINDMA 0
+#define M_DMAC_MINDMA _DD_MAKEMASK(8,S_DMAC_MINDMA)
+#define V_DMAC_MINDMA(x) _DD_MAKEVALUE(x,S_DMAC_MINDMA)
+#define G_DMAC_MINDMA(x) _DD_GETVALUE(x,S_DMAC_MINDMA,M_DMAC_MINDMA)
+
+#define M_DMAC_MEMRDMULT _DD_MAKEMASK1(22) /* 570{0,1} only */
+#define M_DMAC_BEALL _DD_MAKEMASK1(23) /* 570{0,1} only */
+
+#define S_DMAC_RDCMD 24 /* 570{0,1} only */
+#define M_DMAC_RDCMD _DD_MAKEMASK(4,S_DMAC_RDCMD)
+#define V_DMAC_RDCMD(x) _DD_MAKEVALUE(x,S_DMAC_RDCMD)
+#define G_DMAC_RDCMD(x) _DD_GETVALUE(x,S_DMAC_RDCMD,M_DMAC_RDCMD)
+#define K_PCI_MEMRD 0x6
+
+#define S_DMAC_WRCMD 28
+#define M_DMAC_WRCMD _DD_MAKEMASK(4,S_DMAC_WRCMD)
+#define V_DMAC_WRCMD(x) _DD_MAKEVALUE(x,S_DMAC_WRCMD)
+#define G_DMAC_WRCMD(x) _DD_GETVALUE(x,S_DMAC_WRCMD,M_DMAC_WRCMD)
+#define K_PCI_MEMWR 0x7
+
+/* PCIS: PCI State Register (0x70) */
+
+#define M_PCIS_RESET _DD_MAKEMASK1(0)
+#define M_PCIS_INT _DD_MAKEMASK1(1)
+#define M_PCIS_MODE _DD_MAKEMASK1(2)
+#define M_PCIS_33MHZ _DD_MAKEMASK1(3)
+#define M_PCIS_32BIT _DD_MAKEMASK1(4)
+#define M_PCIS_ROMEN _DD_MAKEMASK1(5)
+#define M_PCIS_ROMRETRY _DD_MAKEMASK1(6)
+#define M_PCIS_FLATVIEW _DD_MAKEMASK1(8)
+/* ... more ... */
+
+/* PCI Clock Control Register (0x74) */
+
+/* Register Base Address Register (0x78) */
+
+/* Memory Window Base Address Register (0x7c) */
+
+
+/* High Priority Mailboxes (p 323) */
+
+
+/* Ethernet MAC Control registers (p 358) */
+
+/* MACM: Ethernet MAC Mode Register (0x400) */
+
+#define M_MACM_GLBRESET _DD_MAKEMASK1(0)
+#define M_MACM_HALFDUPLEX _DD_MAKEMASK1(1)
+
+#define S_MACM_PORTMODE 2
+#define M_MACM_PORTMODE _DD_MAKEMASK(2,S_MACM_PORTMODE)
+#define V_MACM_PORTMODE(x) _DD_MAKEVALUE(x,S_MACM_PORTMODE)
+#define G_MACM_PORTMODE(x) _DD_GETVALUE(x,S_MACM_PORTMODE,M_MACM_PORTMODE)
+#define K_MACM_PORTMODE_NONE 0x0
+#define K_MACM_PORTMODE_MII 0x1
+#define K_MACM_PORTMODE_GMII 0x2
+#define K_MACM_PORTMODE_TBI 0x3
+
+#define M_MACM_LOOPBACK _DD_MAKEMASK1(4)
+#define M_MACM_TAGGEDMAC _DD_MAKEMASK1(7)
+#define M_MACM_TXBURST _DD_MAKEMASK1(8)
+#define M_MACM_MAXDEFER _DD_MAKEMASK1(9)
+#define M_MACM_LINKPOLARITY _DD_MAKEMASK1(10)
+#define M_MACM_RXSTATSENB _DD_MAKEMASK1(11)
+#define M_MACM_RXSTATSCLR _DD_MAKEMASK1(12)
+#define M_MACM_RXSTATSFLUSH _DD_MAKEMASK1(13)
+#define M_MACM_TXSTATSENB _DD_MAKEMASK1(14)
+#define M_MACM_TXSTATSCLR _DD_MAKEMASK1(15)
+#define M_MACM_TXSTATSFLUSH _DD_MAKEMASK1(16)
+#define M_MACM_SENDCFGS _DD_MAKEMASK1(17)
+#define M_MACM_MAGICPKT _DD_MAKEMASK1(18)
+#define M_MACM_ACPI _DD_MAKEMASK1(19)
+#define M_MACM_MIPENB _DD_MAKEMASK1(20)
+#define M_MACM_TDEENB _DD_MAKEMASK1(21)
+#define M_MACM_RDEENB _DD_MAKEMASK1(22)
+#define M_MACM_FHDEENB _DD_MAKEMASK1(23)
+
+/* MACSTAT: Ethernet MAC Status Register (0x404) */
+/* MACEVNT: Ethernet MAC Event Enable Register (0x408) */
+
+/* Status Register only */
+#define M_MACSTAT_PCSSYNC _DD_MAKEMASK1(0)
+#define M_MACSTAT_SIGDET _DD_MAKEMASK1(1)
+#define M_MACSTAT_RCVCFG _DD_MAKEMASK1(2)
+#define M_MACSTAT_CFGCHNG _DD_MAKEMASK1(3)
+#define M_MACSTAT_SYNCCHNG _DD_MAKEMASK1(4)
+/* Status and Enable Registers */
+#define M_EVT_PORTERR _DD_MAKEMASK1(10)
+#define M_EVT_LINKCHNG _DD_MAKEMASK1(12)
+#define M_EVT_MICOMPLETE _DD_MAKEMASK1(22)
+#define M_EVT_MIINT _DD_MAKEMASK1(23)
+#define M_EVT_APERR _DD_MAKEMASK1(24)
+#define M_EVT_ODIERR _DD_MAKEMASK1(25)
+#define M_EVT_RXSTATOVRUN _DD_MAKEMASK1(26)
+#define M_EVT_TXSTATOVRUN _DD_MAKEMASK1(27)
+
+/* MICOMM: MI Communication Register (0x44c) */
+
+#define S_MICOMM_DATA 0
+#define M_MICOMM_DATA _DD_MAKEMASK(16,S_MICOMM_DATA)
+#define V_MICOMM_DATA(x) _DD_MAKEVALUE(x,S_MICOMM_DATA)
+#define G_MICOMM_DATA(x) _DD_GETVALUE(x,S_MICOMM_DATA,M_MICOMM_DATA)
+
+#define S_MICOMM_REG 16
+#define M_MICOMM_REG _DD_MAKEMASK(5,S_MICOMM_REG)
+#define V_MICOMM_REG(x) _DD_MAKEVALUE(x,S_MICOMM_REG)
+#define G_MICOMM_REG(x) _DD_GETVALUE(x,S_MICOMM_REG,M_MICOMM_REG)
+
+#define S_MICOMM_PHY 21
+#define M_MICOMM_PHY _DD_MAKEMASK(5,S_MICOMM_PHY)
+#define V_MICOMM_PHY(x) _DD_MAKEVALUE(x,S_MICOMM_PHY)
+#define G_MICOMM_PHY(x) _DD_GETVALUE(x,S_MICOMM_PHY,M_MICOMM_PHY)
+
+#define S_MICOMM_CMD 26
+#define M_MICOMM_CMD _DD_MAKEMASK(2,S_MICOMM_CMD)
+#define V_MICOMM_CMD(x) _DD_MAKEVALUE(x,S_MICOMM_CMD)
+#define G_MICOMM_CMD(x) _DD_GETVALUE(x,S_MICOMM_CMD,M_MICOMM_CMD)
+#define K_MICOMM_CMD_WR 0x1
+#define K_MICOMM_CMD_RD 0x2
+#define V_MICOMM_CMD_WR V_MICOMM_CMD(K_MICOMM_CMD_WR)
+#define V_MICOMM_CMD_RD V_MICOMM_CMD(K_MICOMM_CMD_RD)
+
+#define M_MICOMM_RDFAIL _DD_MAKEMASK1(28)
+#define M_MICOMM_BUSY _DD_MAKEMASK1(29)
+
+/* MISTAT: MI Status Register (0x450) */
+
+#define M_MISTAT_LINKED _DD_MAKEMASK1(0)
+#define M_MISTAT_10MBPS _DD_MAKEMASK1(1)
+
+/* MIMODE: MI Mode Register (0x454) */
+
+#define M_MIMODE_SHORTPREAMBLE _DD_MAKEMASK1(1)
+#define M_MIMODE_POLLING _DD_MAKEMASK1(4)
+
+#define S_MIMODE_CLKCNT 16
+#define M_MIMODE_CLKCNT _DD_MAKEMASK(5,S_MIMODE_CLKCNT)
+#define V_MIMODE_CLKCNT(x) _DD_MAKEVALUE(x,S_MIMODE_CLKCNT)
+#define G_MIMODE_CLKCNT(x) _DD_GETVALUE(x,S_MIMODE_CLKCNT,M_MIMODE_CLKCNT)
+
+/* TXLEN: Transmit MAC Lengths Register (0x464) */
+
+#define S_TXLEN_SLOT 0
+#define M_TXLEN_SLOT _DD_MAKEMASK(8,S_TXLEN_SLOT)
+#define V_TXLEN_SLOT(x) _DD_MAKEVALUE(x,S_TXLEN_SLOT)
+#define G_TXLEN_SLOT(x) _DD_GETVALUE(x,S_TXLEN_SLOT,M_TXLEN_SLOT)
+
+#define S_TXLEN_IPG 8
+#define M_TXLEN_IPG _DD_MAKEMASK(4,S_TXLEN_IPG)
+#define V_TXLEN_IPG(x) _DD_MAKEVALUE(x,S_TXLEN_IPG)
+#define G_TXLEN_IPG(x) _DD_GETVALUE(x,S_TXLEN_IPG,M_TXLEN_IPG)
+
+#define S_TXLEN_IPGCRS 12
+#define M_TXLEN_IPGCRS _DD_MAKEMASK(2,S_TXLEN_IPGCRS)
+#define V_TXLEN_IPGCRS(x) _DD_MAKEVALUE(x,S_TXLEN_IPGCRS)
+#define G_TXLEN_IPGCRS(x) _DD_GETVALUE(x,S_TXLEN_IPGCRS,M_TXLEN_IPGCRS)
+
+/* RULESCFG: Receive Rules Configuration Register (0x500) */
+
+#define S_RULESCFG_DEFAULT 3
+#define M_RULESCFG_DEFAULT _DD_MAKEMASK(5,S_RULESCFG_DEFAULT)
+#define V_RULESCFG_DEFAULT(x) _DD_MAKEVALUE(x,S_RULESCFG_DEFAULT)
+#define G_RULESCFG_DEFAULT(x) _DD_GETVALUE(x,S_RULESCFG_DEFAULT,M_RULESCFG_DEFAULT)
+
+
+/* Send Data Initiator Control Registers (p 383) */
+/* Send BD Ring Selector Control Registers (p 387) */
+/* Send BD Initiator Control Registers (p 389) */
+
+
+/* Receive List Placement Control Registers (p 392) */
+
+/* LISTCFG: Receive List Placement Configuration Register (0x2010) */
+
+#define S_LISTCFG_GROUP 0
+#define M_LISTCFG_GROUP _DD_MAKEMASK(3,S_LISTCFG_GROUP)
+#define V_LISTCFG_GROUP(x) _DD_MAKEVALUE(x,S_LISTCFG_GROUP)
+#define G_LISTCFG_GROUP(x) _DD_GETVALUE(x,S_LISTCFG_GROUP,M_LISTCFG_GROUP)
+
+#define S_LISTCFG_ACTIVE 3
+#define M_LISTCFG_ACTIVE _DD_MAKEMASK(5,S_LISTCFG_ACTIVE)
+#define V_LISTCFG_ACTIVE(x) _DD_MAKEVALUE(x,S_LISTCFG_ACTIVE)
+#define G_LISTCFG_ACTIVE(x) _DD_GETVALUE(x,S_LISTCFG_ACTIVE,M_LISTCFG_ACTIVE)
+
+#define S_LISTCFG_BAD 8
+#define M_LISTCFG_BAD _DD_MAKEMASK(5,S_LISTCFG_BAD)
+#define V_LISTCFG_BAD(x) _DD_MAKEVALUE(x,S_LISTCFG_BAD)
+#define G_LISTCFG_BAD(x) _DD_GETVALUE(x,S_LISTCFG_BAD,M_LISTCFG_BAD)
+
+#define S_LISTCFG_DEFAULT 13
+#define M_LISTCFG_DEFAULT _DD_MAKEMASK(2,S_LISTCFG_DEFAULT)
+#define V_LISTCFG_DEFAULT(x) _DD_MAKEVALUE(x,S_LISTCFG_DEFAULT)
+#define G_LISTCFG_DEFAULT(x) _DD_GETVALUE(x,S_LISTCFG_DEFAULT,M_LISTCFG_DEFAULT)
+
+
+/* Receive Data and Receive BD Initiator Control Registers (p 399) */
+
+/* RCVINITMODE: Receive Data and Receive BD Initiator Mode Register (0x2400) */
+
+#define M_RCVINITMODE_JUMBO _DD_MAKEMASK1(2)
+#define M_RCVINITMODE_FRMSIZE _DD_MAKEMASK1(3)
+#define M_RCVINITMODE_RTNSIZE _DD_MAKEMASK1(4)
+
+
+/* Receive Initiator Control Registers (p 404) */
+/* Receive BD Completion Control Registers (p 406) */
+/* Receive List Selector Control Registers (p 408) */
+/* Mbuf Cluster Free Registers (p 409) */
+
+
+/* Host Coalescing Control registers (p 410) */
+
+/* HCM: Host Coalescing Mode Register (0x3C00) */
+
+#define M_HCM_RESET _DD_MAKEMASK1(0)
+#define M_HCM_ENABLE _DD_MAKEMASK1(1)
+#define M_HCM_ATTN _DD_MAKEMASK1(2)
+#define M_HCM_COAL_NOW _DD_MAKEMASK1(3)
+
+#define S_HCM_MSIBITS 4
+#define M_HCM_MSIBITS _DD_MAKEMASK(3,S_HCM_MSIBITS)
+#define V_HCM_MSIBITS(x) _DD_MAKEVALUE(x,S_HCM_MSIBITS)
+#define G_HCM_MSIBITS _DD_GETVALUE(x,S_HCM_MSIBITS,M_HCM_MSIBITS)
+
+#define S_HCM_SBSIZE 7
+#define M_HCM_SBSIZE _DD_MAKEMASK(2,S_HCM_SBSIZE)
+#define V_HCM_SBSIZE(x) _DD_MAKEVALUE(x,S_HCM_SBSIZE)
+#define G_HCM_SBSIZE _DD_GETVALUE(x,S_HCM_SBSIZE,M_HCM_SBSIZE)
+#define K_HCM_SBSIZE_80 0x0
+#define K_HCM_SBSIZE_64 0x1
+#define K_HCM_SBSIZE_32 0x2
+/* ... more ... */
+
+
+/* Memory Arbiter Registers (p 420) */
+
+/* MAM: Memory Arbiter Mode Register (0x4000) */
+
+#define M_MAM_RESET _DD_MAKEMASK1(0)
+#define M_MAM_ENABLE _DD_MAKEMASK1(1)
+
+/* Memory Arbiter Status Register (0x4004) */
+
+/* Memory Arbiter Trap Low and Trap High Registers (0x4008, 0x400C) */
+
+
+/* Buffer Manager Control Registers (p 424) */
+
+/* BMODE: Buffer Manager Control Register (0x4400) */
+
+#define M_BMODE_RESET _DD_MAKEMASK1(0)
+#define M_BMODE_ENABLE _DD_MAKEMASK1(1)
+#define M_BMODE_ATTN _DD_MAKEMASK1(2)
+#define M_BMODE_TEST _DD_MAKEMASK1(3)
+#define M_BMODE_MBUFLOWATTN _DD_MAKEMASK1(4)
+
+
+/* Read DMA Control Registers (p 428) */
+/* Write DMA Control Registers (p 431) */
+
+/* Bit fields shared by DMA_MODE and DMA_STATUS registers */
+
+#define M_ATTN_TGTABORT _DD_MAKEMASK1(2)
+#define M_ATTN_MSTRABORT _DD_MAKEMASK1(3)
+#define M_ATTN_PERR _DD_MAKEMASK1(4)
+#define M_ATTN_ADDROVFL _DD_MAKEMASK1(5)
+#define M_ATTN_FIFOOVFL _DD_MAKEMASK1(6)
+#define M_ATTN_FIFOUNFL _DD_MAKEMASK1(7)
+#define M_ATTN_FIFOREAD _DD_MAKEMASK1(8)
+#define M_ATTN_LENERR _DD_MAKEMASK1(9)
+#define M_ATTN_ALL (M_ATTN_TGTABORT | M_ATTN_MSTRABORT | \
+ M_ATTN_PERR | M_ATTN_ADDROVFL | \
+ M_ATTN_FIFOOVFL | M_ATTN_FIFOUNFL | \
+ M_ATTN_FIFOREAD | M_ATTN_LENERR)
+
+/* Read DMA Mode Register (0x4800) */
+/* Write DMA Mode Register (0x4C00) */
+
+/* Read DMA Status Register (0x4804) */
+/* Write DMA Status Register (0x4C04) */
+
+
+/* RX RISC Registers (p 433) */
+/* TX RISC Registers (p 437) */
+/* Low Priority Mailboxes (p 441) */
+/* Flow Through Queues (p 445) */
+/* Message Signaled Interrupt Registers (p 447) */
+/* DMA Completion Registers (p 449) */
+
+
+/* General Control registers (p 450) */
+
+/* MCTL: Miscellaneous Host Control Register (0x6800) */
+
+#define M_MCTL_UPDATE _DD_MAKEMASK1(0)
+#define M_MCTL_BSWAPCTRL _DD_MAKEMASK1(1)
+#define M_MCTL_WSWAPCTRL _DD_MAKEMASK1(2)
+#define M_MCTL_BSWAPDATA _DD_MAKEMASK1(4)
+#define M_MCTL_WSWAPDATA _DD_MAKEMASK1(5)
+#define M_MCTL_NOCRACK _DD_MAKEMASK1(9)
+#define M_MCTL_NOCRC _DD_MAKEMASK1(10)
+#define M_MCTL_ACCEPTBAD _DD_MAKEMASK1(11)
+#define M_MCTL_NOTXINT _DD_MAKEMASK1(13)
+#define M_MCTL_NORTRNINT _DD_MAKEMASK1(14)
+#define M_MCTL_PCI32 _DD_MAKEMASK1(15)
+#define M_MCTL_HOSTUP _DD_MAKEMASK1(16)
+#define M_MCTL_HOSTBDS _DD_MAKEMASK1(17)
+#define M_MCTL_NOTXPHSUM _DD_MAKEMASK1(20)
+#define M_MCTL_NORXPHSUM _DD_MAKEMASK1(23)
+#define M_MCTL_TXINT _DD_MAKEMASK1(24)
+#define M_MCTL_RXINT _DD_MAKEMASK1(25)
+#define M_MCTL_MACINT _DD_MAKEMASK1(26)
+#define M_MCTL_DMAINT _DD_MAKEMASK1(27)
+#define M_MCTL_FLOWINT _DD_MAKEMASK1(28)
+#define M_MCTL_4XRINGS _DD_MAKEMASK1(29)
+#define M_MCTL_MCASTEN _DD_MAKEMASK1(30)
+
+/* MCFG: Miscellaneous Configuration Register (0x6804) */
+
+#define M_MCFG_CORERESET _DD_MAKEMASK1(0)
+#define S_MCFG_PRESCALER 1
+#define M_MCFG_PRESCALER _DD_MAKEMASK(7,S_MCFG_PRESCALER)
+#define V_MCFG_PRESCALER(x) _DD_MAKEVALUE(x,S_MCFG_PRESCALER)
+#define G_MCFG_PRESCALER(x) _DD_GETVALUE(x,S_MCFG_PRESCALER,M_MCFG_PRESCALER)
+
+/* MLCTL: Miscellaneous Local Control Register (0x6808) */
+
+#define M_MLCTL_INTSTATE _DD_MAKEMASK1(0)
+#define M_MLCTL_INTCLR _DD_MAKEMASK1(1)
+#define M_MLCTL_INTSET _DD_MAKEMASK1(2)
+#define M_MLCTL_INTATTN _DD_MAKEMASK1(3)
+/* ... */
+#define M_MLCTL_EPAUTOACCESS _DD_MAKEMASK1(24)
+
+/* EPADDR: Serial EEPROM Address Register (0x6838) */
+
+#define S_EPADDR_ADDR 0
+#define M_EPADDR_ADDR (_DD_MAKEMASK(16,S_EPADDR_ADDR) & ~3)
+#define V_EPADDR_ADDR(x) _DD_MAKEVALUE(x,S_EPADDR_ADDR)
+#define G_EPADDR_ADDR(x) _DD_GETVALUE(x,S_EPADDR_ADDR,M_EPADDR_ADDR)
+
+#define S_EPADDR_HPERIOD 16
+#define M_EPADDR_HPERIOD _DD_MAKEMASK(9,S_EPADDR_HPERIOD)
+#define V_EPADDR_HPERIOD(x) _DD_MAKEVALUE(x,S_EPADDR_HPERIOD)
+#define G_EPADDR_HPERIOD(x) _DD_GETVALUE(x,S_EPADDR_HPERIOD,M_EPADDR_HPERIOD)
+
+#define M_EPADDR_START _DD_MAKEMASK1(25)
+
+#define S_EPADDR_DEVID 26
+#define M_EPADDR_DEVID _DD_MAKEMASK(3,S_EPADDR_DEVID)
+#define V_EPADDR_DEVID(x) _DD_MAKEVALUE(x,S_EPADDR_DEVID)
+#define G_EPADDR_DEVID(x) _DD_GETVALUE(x,S_EPADDR_DEVID,M_EPADDR_DEVID)
+
+#define M_EPADDR_RESET _DD_MAKEMASK1(29)
+#define M_EPADDR_COMPLETE _DD_MAKEMASK1(30)
+#define M_EPADDR_RW _DD_MAKEMASK1(31)
+
+/* EPDATA: Serial EEPROM Data Register (0x683C) */
+
+/* EPCTL: Serial EEPROM Control Register (0x6840) */
+
+#define M_EPCTL_CLOCKTS0 _DD_MAKEMASK1(0)
+#define M_EPCTL_CLOCKO _DD_MAKEMASK1(1)
+#define M_EPCTL_CLOCKI _DD_MAKEMASK1(2)
+#define M_EPCTL_DATATSO _DD_MAKEMASK1(3)
+#define M_EPCTL_DATAO _DD_MAKEMASK1(4)
+#define M_EPCTL_DATAI _DD_MAKEMASK1(5)
+
+/* MDCTL: MDI Control Register (0x6844) */
+
+#define M_MDCTL_DATA _DD_MAKEMASK1(0)
+#define M_MDCTL_ENABLE _DD_MAKEMASK1(1)
+#define M_MDCTL_SELECT _DD_MAKEMASK1(2)
+#define M_MDCTL_CLOCK _DD_MAKEMASK1(3)
+
+
+/* Ring Control Blocks (p 97) */
+
+#define RCB_HOST_ADDR_HIGH 0x0
+#define RCB_HOST_ADDR_LOW 0x4
+#define RCB_CTRL 0x8
+#define RCB_NIC_ADDR 0xC
+
+#define RCB_SIZE 0x10
+
+#define RCB_FLAG_USE_EXT_RCV_BD _DD_MAKEMASK1(0)
+#define RCB_FLAG_RING_DISABLED _DD_MAKEMASK1(1)
+
+#define S_RCB_MAXLEN 16
+#define M_RCB_MAXLEN _DD_MAKEMASK(16,S_RCB_MAXLEN)
+#define V_RCB_MAXLEN(x) _DD_MAKEVALUE(x,S_RCB_MAXLEN)
+#define G_RCB_MAXLEN(x) _DD_GETVALUE(x,S_RCB_MAXLEN,M_RCB_MAXLEN)
+
+
+/* On-chip Memory Map (Tables 70 and 71, pp 178-179) This is the map
+ for the 5700 with no external SRAM, the 5701, 5702 and 5703. The
+ 5705 does not fully implement some ranges and maps the buffer pool
+ differently. */
+
+/* Locations 0x0000 - 0x00FF are Page Zero */
+
+/* Locations 0x0100 - 0x01FF are Send Producer Ring RCBs */
+
+#define A_SND_RCBS 0x0100
+#define L_SND_RCBS (16*RCB_SIZE)
+#define A_SND_RCB(n) (A_SND_RCBS + ((n)-1)*RCB_SIZE)
+
+/* Locations 0x0200 - 0x02FF are Receive Return Ring RCBs */
+
+#define A_RTN_RCBS 0x0200
+#define L_RTN_RCBS (16*RCB_SIZE)
+#define A_RTN_RCB(n) (A_RTN_RCBS + ((n)-1)*RCB_SIZE)
+
+/* Locations 0x0300 - 0x0AFF are Statistics Block */
+
+#define A_MAC_STATS 0x0300
+#define L_MAC_STATS (0x0B00-A_MAC_STATS)
+
+/* Locations 0x0B00 - 0x0B4F are Status Block */
+
+#define A_MAC_STATUS 0x0B00
+#define L_MAC_STATUS (0x0B50-A_MAC_STATUS)
+
+/* Locations 0x0B50 - 0x0FFF are Software General Communication */
+
+#define A_PXE_MAILBOX 0x0B50
+#define T3_MAGIC_NUMBER 0x4B657654
+
+/* Locations 0x1000 - 0x1FFF are unmapped */
+
+/* Locations 0x2000 - 0x3FFF are DMA Descriptors */
+
+#define A_DMA_DESCS 0x2000
+#define L_DMA_DESCS (0x4000-A_DMA_DESCS)
+
+/* Locations 0x4000 - 0x5FFF are Send Rings 1-4 */
+
+#define A_SND_RINGS 0x4000
+#define L_SND_RINGS (0x6000-A_SND_RINGS)
+
+/* Locations 0x6000 - 0x6FFF are Standard Receive Rings */
+
+#define A_STD_RCV_RINGS 0x6000
+#define L_STD_RCV_RINGS (0x7000-A_STD_RCV_RINGS)
+
+/* Locations 0x7000 - 0x7FFF are Jumbo Receive Rings */
+
+#define A_JUMBO_RCV_RINGS 0x7000
+#define L_JUMBO_RCV_RINGS (0x8000-A_JUMBO_RCV_RINGS)
+
+/* Locations 0x08000 - 0x0FFFF are Buffer Pool 1 */
+/* Locations 0x10000 - 0x17FFF are Buffer Pool 2 */
+/* Locations 0x18000 - 0x1FFFF are Buffer Pool 3 */
+
+#define A_BUFFER_POOL 0x08000
+#define L_BUFFER_POOL (0x20000-A_BUFFER_POOL)
+
+/* Locations 0x08000 - 0x09FFF are TXMBUF (5705) */
+/* Locations 0x10000 - 0x1DFFF are RXMBUF (5705) */
+
+#define A_TXMBUF 0x080000
+#define L_TXMBUF (0x0A000-A_TXMBUF)
+#define A_RXMBUF 0x100000
+#define L_RXMBUF (0x1E000-A_RXMBUF)
+
+
+/* Indices of (8-byte) counters in the Statistics Block. */
+
+#define ifHCInOctets 32
+#define etherStatsFragments 34
+#define ifHCInUcastPkts 35
+#define ifHCInMulticastPkts 36
+#define ifHCInBroadcastPkts 37
+#define dot3StatsFCSErrors 38
+#define dot3StatsAlignmentErrors 39
+#define xonPauseFramesReceived 40
+#define xoffPauseFramesReceived 41
+#define macControlFramesReceived 42
+#define xoffSateEntered 43
+#define dot3StatsFrameTooLongs 44
+#define etherStatsJabbers 45
+#define etherStatsUndersizePkts 46
+#define inRangeLengthError 47
+#define outRangeLengthError 48
+#define etherStatsPkts64Octets 49
+#define etherStatsPkts65to127Octets 50
+#define etherStatsPkts128to255Octets 51
+#define etherStatsPkts256to511Octets 52
+#define etherStatsPkts512to1023Octets 53
+#define etherStatsPkts1024to1522Octets 54
+#define etherStatsPkts1523to2047Octets 55
+#define etherStatsPkts2048to4095Octets 56
+#define etherStatsPkts4096to8191Octets 57
+#define etherStatsPkts8192to9022Octets 58
+
+#define ifHCOutOctets 96
+#define etherStatsCollisions 98
+#define outXonSent 99
+#define outXoffSent 100
+#define flowControlDone 101
+#define dot3StatsInternalMacTransmitErrors 102
+#define dot3StatsSingleCollisionFrames 103
+#define dot3StatsMultipleCollisionFrames 104
+#define dot3StatsDeferredTransmissions 105
+#define dot3StatsExcessiveCollisions 107
+#define dot3StatsLateCollisions 108
+#define dot3Collided2Times 109
+#define dot3Collided3Times 110
+#define dot3Collided4Times 111
+#define dot3Collided5Times 112
+#define dot3Collided6Times 113
+#define dot3Collided7Times 114
+#define dot3Collided8Times 115
+#define dot3Collided9Times 116
+#define dot3Collided10Times 117
+#define dot3Collided11Times 118
+#define dot3Collided12Times 119
+#define dot3Collided13Times 120
+#define dot3Collided14Times 121
+#define dot3Collided15Times 122
+#define ifHCOutUcastPkts 123
+#define ifHCOutMulticastPkts 124
+#define ifHCOutBroadcastPkts 125
+#define dot3StatsCarrierSenseErrors 126
+#define ifOutDiscards 127
+#define ifOutErrors 128
+
+#define COSifHCInPkts1 160
+#define COSifHCInPkts2 161
+#define COSifHCInPkts3 162
+#define COSifHCInPkts4 163
+#define COSifHCInPkts5 164
+#define COSifHCInPkts6 165
+#define COSifHCInPkts7 166
+#define COSifHCInPkts8 167
+#define COSifHCInPkts9 168
+#define COSifHCInPkts10 169
+#define COSifHCInPkts11 170
+#define COSifHCInPkts12 171
+#define COSifHCInPkts13 172
+#define COSifHCInPkts14 173
+#define COSifHCInPkts15 174
+#define COSifHCInPkts16 175
+#define COSFramesDroppedDueToFilters 176
+#define nicDmaWriteQueueFull 177
+#define nicDmaWriteHighPriQueueFull 178
+#define nicNoMoreRxBDs 179
+#define ifInDiscards 180
+#define ifInErrors 181
+#define nicRecvThresholdHit 182
+
+#define COSifHCOutPkts1 192
+#define COSifHCOutPkts2 193
+#define COSifHCOutPkts3 194
+#define COSifHCOutPkts4 195
+#define COSifHCOutPkts5 196
+#define COSifHCOutPkts6 197
+#define COSifHCOutPkts7 198
+#define COSifHCOutPkts8 199
+#define COSifHCOutPkts9 200
+#define COSifHCOutPkts10 201
+#define COSifHCOutPkts11 202
+#define COSifHCOutPkts12 203
+#define COSifHCOutPkts13 204
+#define COSifHCOutPkts14 205
+#define COSifHCOutPkts15 206
+#define COSifHCOutPkts16 207
+#define nicDmaReadQueueFull 208
+#define nicDmaReadHighPriQueueFull 209
+#define nicSendDataCompQueueFull 210
+#define nicRingSetSendProdIndex 211
+#define nicRingStatusUpdate 212
+#define nicInterrupts 213
+#define nicAvoidedInterrupts 214
+#define nicSendThresholdHit 215
+
+#endif /* _BCM_5700_H_ */
diff --git a/cfe/cfe/dev/bcm5821.h b/cfe/cfe/dev/bcm5821.h
new file mode 100644
index 0000000..29ece60
--- /dev/null
+++ b/cfe/cfe/dev/bcm5821.h
@@ -0,0 +1,278 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * BCM5821 cryptoaccelerator File: bcm5821.h
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+#ifndef _BCM5821_H_
+#define _BCM5821_H_
+
+/* Register and field definitions for the Broadcom BCM5821 crypto
+ accelerator. The BCM5820 implements a compatible (modulo bugs)
+ subset of the BCM5821. */
+
+#define K_PCI_VENDOR_BROADCOM 0x14e4
+#define K_PCI_ID_BCM5820 0x5820
+#define K_PCI_ID_BCM5821 0x5821
+
+#define _DD_MAKEMASK1(n) (1 << (n))
+#define _DD_MAKEMASK(v,n) ((((1)<<(v))-1) << (n))
+#define _DD_MAKEVALUE(v,n) ((v) << (n))
+#define _DD_GETVALUE(v,n,m) (((v) & (m)) >> (n))
+
+
+/* DMA Control and Status Register offsets */
+
+#define R_MCR1 0x00
+#define R_DMA_CTRL 0x04
+#define R_DMA_STAT 0x08
+#define R_DMA_ERR 0x0C
+#define R_MCR2 0x10
+
+
+/* 0x00 MCR1@: Master Command Record 1 Address */
+/* 0x10 MCR2@: Master Command Record 2 Address */
+
+
+/* 0x04 DMA Control */
+
+#define M_DMA_CTRL_WR_BURST _DD_MAKEMASK1(16) /* Not 5820 */
+
+#define K_DMA_WR_BURST_128 0
+#define K_DMA_WR_BURST_240 M_DMA_CRTL_WR_BURST
+
+#define M_DMA_CTRL_MOD_NORM _DD_MAKEMASK1(22)
+#define M_DMA_CTRL_RNG_MODE _DD_MAKEMASK1(23)
+#define M_DMA_CTRL_DMAERR_EN _DD_MAKEMASK1(25)
+#define M_DMA_CTRL_NORM_PCI _DD_MAKEMASK1(26) /* Not 5820 */
+#define M_DMA_CTRL_LE_CRYPTO _DD_MAKEMASK1(27) /* Not 5820 */
+#define M_DMA_CTRL_MCR1_INT_EN _DD_MAKEMASK1(29)
+#define M_DMA_CTRL_MCR2_INT_EN _DD_MAKEMASK1(30)
+#define M_DMA_CTRL_RESET _DD_MAKEMASK1(31)
+
+
+/* 0x08 DMA Status */
+
+#define M_DMA_STAT_MCR2_EMPTY _DD_MAKEMASK1(24) /* Not 5820 */
+#define M_DMA_STAT_MCR1_EMPTY _DD_MAKEMASK1(25) /* Not 5820 */
+#define M_DMA_STAT_MCR2_INTR _DD_MAKEMASK1(26)
+#define M_DMA_STAT_MCR2_FULL _DD_MAKEMASK1(27)
+#define M_DMA_STAT_DMAERR_INTR _DD_MAKEMASK1(28)
+#define M_DMA_STAT_MCR1_INTR _DD_MAKEMASK1(29)
+#define M_DMA_STAT_MCR1_FULL _DD_MAKEMASK1(30)
+#define M_DMA_STAT_MSTR_ACCESS _DD_MAKEMASK1(31)
+
+/* 0x0C DMA Error Address */
+
+#define M_DMA_ERR_RD_FAULT _DD_MAKEMASK1(1)
+#define M_DMA_ERR_ADDR 0xFFFFFFFC
+
+
+/* Master Command Record Header Format */
+
+#define S_MCR_NUM_PACKETS 0
+#define M_MCR_NUM_PACKETS _DD_MAKEMASK(16,S_MCR_NUM_PACKETS)
+#define V_MCR_NUM_PACKETS(x) _DD_MAKEVALUE(x,S_MCR_NUM_PACKETS)
+#define G_MCR_NUM_PACKETS(x) _DD_GETVALUE(x,S_MCR_NUM_PACKETS,M_MCR_NUM_PACKETS)
+
+/* Input flags */
+
+#define M_MCR_SUPPRESS_INTR _DD_MAKEMASK1(31)
+
+/* Output flags */
+
+#define M_MCR_DONE _DD_MAKEMASK1(16)
+#define M_MCR_ERROR _DD_MAKEMASK1(17)
+
+#define S_MCR_ERROR_CODE 24
+#define M_MCR_ERROR_CODE _DD_MAKEMASK(8,S_MCR_ERROR_CODE)
+#define V_MCR_ERROR_CODE(x) _DD_MAKEVALUE(x,S_MCR_ERROR_CODE)
+#define G_MCR_ERROR_CODE(x) _DD_GETVALUE(x,S_MCR_ERROR_CODE,M_MCR_ERROR_CODE)
+#define K_MCR_ERROR_OK 0
+#define K_MCR_ERROR_UNKNOWN_OP 1
+#define K_MCR_ERROR_DSA_SHORT 2
+#define K_MCR_ERROR_PKI_SHORT 3
+#define K_MCR_ERROR_PKO_SHORT 4 /* Not 5820 */
+#define K_MCR_ERROR_CHAIN_SHORT 5 /* Not 5820 */
+#define K_MCR_ERROR_FIFO 6 /* Not 5820 */
+
+/* In both cases, the header word is followed by an array of N PD entries:
+ commandContext[0]
+ dataBuffer[0]
+ pktLen[0]
+ outputBuffer[0]
+ ...
+ commandContext[n-1]
+ dataBuffer[n-1]
+ pktLen[n-1]
+ outputBuffer[n-1]
+*/
+
+#define MCR_WORDS(n) (1+8*(n))
+#define MCR_BYTES(n) ((1+8*(n))*4)
+
+
+/* Data Buffer Chain Entry Offsets */
+
+#define DBC_ADDR 0
+#define DBC_NEXT 4
+#define DBC_LEN 8
+
+#define CHAIN_WORDS 3
+
+#define S_DBC_DATA_LEN 0
+#define M_DBC_DATA_LEN _DD_MAKEMASK(16,S_DBC_DATA_LEN)
+#define V_DBC_DATA_LEN(x) _DD_MAKEVALUE(x,S_DBC_DATA_LEN)
+#define G_DBC_DATA_LEN(x) _DD_GETVALUE(x,S_DBC_DATA_LEN,M_DBC_DATA_LEN)
+
+/* Packet Descriptor Offsets */
+
+#define PD_CC_ADDR 0
+#define PD_INPUT_FRAG 4
+#define PD_INPUT_FRAG_ADDR (PD_INPUT_FRAG+DBC_ADDR)
+#define PD_INPUT_FRAG_NEXT (PD_INPUT_FRAG+DBC_NEXT)
+#define PD_INPUT_FRAG_LEN (PD_INPUT_FRAG+DBC_LEN)
+#define PD_PKT_LEN 16
+#define PD_OUTPUT_FRAG 20
+#define PD_OUTPUT_FRAG_ADDR (PD_OUTPUT_FRAG+DBC_ADDR)
+#define PD_OUTPUT_FRAG_NEXT (PD_OUTPUT_FRAG+DBC_NEXT)
+#define PD_OUTPUT_FRAG_LEN (PD_OUTPUT_FRAG+DBC_LEN)
+
+#define PD_SIZE 32
+
+#define S_PD_PKT_LEN 16
+#define M_PD_PKT_LEN _DD_MAKEMASK(16,S_PD_PKT_LEN)
+#define V_PD_PKT_LEN(x) _DD_MAKEVALUE(x,S_PD_PKT_LEN)
+#define G_PD_PKT_LEN(x) _DD_GETVALUE(x,S_PD_PKT_LEN,M_PD_PKT_LEN)
+
+
+/* Crypotographic Operations */
+
+/* MCR1 only (symmetric) */
+#define K_IPSEC_3DES 0x0000 /* Not 5820 */
+#define K_SSL_MAC 0x0001
+#define K_TLS_HMAC 0x0002
+#define K_SSL_3DES 0x0003
+#define K_ARC4 0x0004
+#define K_HASH 0x0005
+
+/* MCR2 only (asymmetric) */
+#define K_DH_PK_GEN 0x0001
+#define K_DH_SK_GEN 0x0002
+#define K_RSA_PK_OP 0x0003
+#define K_RSA_SK_OP 0x0004
+#define K_DSA_SIGN 0x0005
+#define K_DSA_VERIF 0x0006
+#define K_RNG_DIRECT 0x0041
+#define K_RNG_SHA1 0x0042
+#define K_MOD_ADD 0x0043
+#define K_MOD_SUB 0x0044
+#define K_MOD_MUL 0x0045
+#define K_MOD_REDUCE 0x0046
+#define K_MOD_EXP 0x0047
+#define K_MOD_INV 0x0048 /* Not 5821 */
+#define K_MOD_2EXP 0x0049 /* Not 5820 */
+
+
+/* Command Context Header */
+
+/* Word 0 */
+
+#define S_CC_OPCODE 16
+#define M_CC_OPCODE _DD_MAKEMASK(16,S_CC_OPCODE)
+#define V_CC_OPCODE(x) _DD_MAKEVALUE(x,S_CC_OPCODE)
+#define G_CC_OPCODE(x) _DD_GETVALUE(x,S_CC_OPCODE,M_CC_OPCODE)
+
+#define S_CC_LEN 0
+#define M_CC_LEN _DD_MAKEMASK(16,S_CC_LEN)
+#define V_CC_LEN(x) _DD_MAKEVALUE(x,S_CC_LEN)
+#define G_CC_LEN(x) _DD_GETVALUE(x,S_CC_LEN,M_CC_LEN)
+
+/* Word 1 */
+
+#define S_CC_FLAGS 12
+#define M_CC_FLAGS _DD_MAKEMASK(4,S_CC_FLAGS)
+#define V_CC_FLAGS(x) _DD_MAKEVALUE(x,S_CC_FLAGS)
+#define G_CC_FLAGS(x) _DD_GETVALUE(x,S_CC_OPCODE,M_CC_OPCODE)
+
+/* The remaining command context fields depend on the opcode. */
+
+/* IPSEC 3DES (K_IPSEC_3DES) */
+
+/* SSL MAC (K_SSL_MAC) */
+/* TLS HMAC (K_TLS_HMAC) */
+/* Pure MD5/SHA-1 Hash (K_HASH) */
+
+#define K_HASH_FLAGS_MD5 1
+#define K_HASH_FLAGS_SHA1 2
+
+/* SSL MAC (K_SSL_MAC) */
+
+#define SSL_MAC_CMD_WORDS 22
+
+/* TLS HMAC (K_TLS_HMAC) */
+
+#define TLS_HMAC_CMD_WORDS 16
+
+/* Pure MD5/SHA-1 Hash (K_HASH) */
+
+/* SSL/TLS DES/3DES (K_SSL_3DES) */
+
+/* ARCFOUR (K_ARC4) */
+
+#define ARC4_STATE_WORDS (1 + 256/4)
+#define ARC4_CMD_WORDS (2 + ARC4_STATE_WORDS)
+
+#define M_ARC4_FLAGS_KEY _DD_MAKEMASK1(10)
+#define M_ARC4_FLAGS_WRITEBACK _DD_MAKEMASK1(11)
+#define M_ARC4_FLAGS_NULLDATA _DD_MAKEMASK1(12)
+
+
+/* Random number generation (K_RNG_DIRECT, K_RNG_SHA1) */
+
+/* Modular arithmetic (K_MOD_ADD, K_MOD_SUB, K_MOD_MUL) */
+
+/* Modular Remainder (K_MOD_REDUCE) */
+
+/* Modular Exponentiation (K_MOD_EXP) */
+
+/* Double Modular Exponentiation (K_MOD_2EXP) */
+
+
+#endif /* _BCM_5821_H_ */
diff --git a/cfe/cfe/dev/dc21143.h b/cfe/cfe/dev/dc21143.h
new file mode 100644
index 0000000..65f3255
--- /dev/null
+++ b/cfe/cfe/dev/dc21143.h
@@ -0,0 +1,588 @@
+/*
+ * Register and bit definitions for the DEC/Intel 21143 Ethernet controller,
+ * part of the Tulip family of 10 and 10/100 controllers.
+ * Reference:
+ * 21143 PCI/CardBus 10/100 Mb/s Ethernet LAN Controller,
+ * Hardware Reference Manual, Revision 1.0.
+ * Document No. 278074-001
+ * Intel Corp., October 1998
+ * Includes extensions/alternatives for the DEC 21040, 21041 and 21140(A)
+ * Ethernet controllers.
+ */
+#ifndef _DC21143_H_
+#define _DC21143_H_
+
+#define _DD_MAKEMASK1(n) (1 << (n))
+#define _DD_MAKEMASK(v,n) ((((1)<<(v))-1) << (n))
+#define _DD_MAKEVALUE(v,n) ((v) << (n))
+#define _DD_GETVALUE(v,n,m) (((v) & (m)) >> (n))
+
+
+/* *********************************************************************
+ * PCI Configuration Register offsets (Tulip nomenclature)
+ ********************************************************************* */
+
+#define R_CFG_CFID PCI_ID_REG
+#define K_PCI_VENDOR_DEC 0x1011
+#define K_PCI_ID_DC21040 0x0002
+#define K_PCI_ID_DC21041 0x0014
+#define K_PCI_ID_DC21140 0x0009
+#define K_PCI_ID_DC21143 0x0019
+
+#define R_CFG_CFRV PCI_CLASS_REG
+
+#define R_CFG_CBIO PCI_MAPREG(0)
+#define R_CFG_CBMA PCI_MAPREG(1)
+
+#define R_CFG_CFIT PCI_BPARAM_INTERRUPT_REG
+
+/* Tulip extensions */
+#define R_CFG_CFDD 0x40
+
+#define M_CFDD_SLEEP __DD_MAKEMASK1(31)
+#define M_CFDD_SNOOZE __DD_MAKEMASK1(30)
+
+#define R_CFG_CPMS 0xE0
+
+
+/* *********************************************************************
+ * CSRs: offsets
+ ********************************************************************* */
+
+#define R_CSR_BUSMODE 0x00
+#define R_CSR_TXPOLL 0x08
+#define R_CSR_RXPOLL 0x10
+#define R_CSR_RXRING 0x18
+#define R_CSR_TXRING 0x20
+#define R_CSR_STATUS 0x28
+#define R_CSR_OPMODE 0x30
+#define R_CSR_INTMASK 0x38
+#define R_CSR_MISSEDFRAME 0x40
+#define R_CSR_ROM_MII 0x48
+#define R_CSR_BOOTROM_ADRR 0x50
+#define R_CSR_GENTIMER 0x58
+
+/* The following registers are specific to the 21040 */
+
+#define R_CSR_FDUPLEX 0x58
+
+/* The following registers are specific to the 21040/21041 and 21142/21143 */
+
+#define R_CSR_SIASTATUS 0x60
+#define R_CSR_SIAMODE0 0x68
+#define R_CSR_SIAMODE1 0x70
+#define R_CSR_SIAMODE2 0x78
+
+/* The following registers are specific to the 21140/21140A */
+
+#define R_CSR_GENPORT 0x60
+#define R_CSR_WATCHDOG_TIMER 0x78
+
+
+/* CSR0: Bus Mode register */
+
+#define M_CSR0_SWRESET _DD_MAKEMASK1(0)
+#define M_CSR0_BUSARB _DD_MAKEMASK1(1)
+
+#define S_CSR0_SKIPLEN 2
+#define M_CSR0_SKIPLEN _DD_MAKEMASK(5,S_CSR0_SKIPLEN)
+#define V_CSR0_SKIPLEN(x) _DD_MAKEVALUE(x,S_CSR0_SKIPLEN)
+#define G_CSR0_SKIPLEN(x) _DD_GETVALUE(x,S_CSR0_SKIPLEN,M_CSR0_SKIPLEN)
+
+#define M_CSR0_BIGENDIAN _DD_MAKEMASK1(7)
+
+#define S_CSR0_BURSTLEN 8
+#define M_CSR0_BURSTLEN _DD_MAKEMASK(6,S_CSR0_BURSTLEN)
+#define V_CSR0_BURSTLEN(x) _DD_MAKEVALUE(x,S_CSR0_BURSTLEN)
+#define G_CSR0_BURSTLEN(x) _DD_GETVALUE(x,S_CSR0_BURSTLEN,M_CSR0_BURSTLEN)
+
+#define S_CSR0_CACHEALIGN 14
+#define M_CSR0_CACHEALIGN _DD_MAKEMASK(2,S_CSR0_CACHEALIGN)
+#define V_CSR0_CACHEALIGN(x) _DD_MAKEVALUE(x,S_CSR0_CACHEALIGN)
+#define G_CSR0_CACHEALIGN(x) _DD_GETVALUE(x,S_CSR0_CACHEALIGN,M_CSR0_CACHEALIGN)
+
+#define S_CSR0_TXAUTOPOLL 17
+#define M_CSR0_TXAUTOPOLL _DD_MAKEMASK(3,S_CSR0_AUTOPOLL)
+#define V_CSR0_TXAUTOPOLL(x) _DD_MAKEVALUE(x,S_CSR0_TXAUTOPOLL)
+#define G_CSR0_TXAUTOPOLL(x) _DD_GETVALUE(x,S_CSR0_TXAUTOPOLL,M_CSR0_TXAUTOPOLL)
+
+#define M_CSR0_DESCBYTEORDER _DD_MAKEMASK1(20) /* not 21040 */
+#define M_CSR0_READMULTENAB _DD_MAKEMASK1(21) /* not 2104{0,1} */
+#define M_CSR0_READLINEENAB _DD_MAKEMASK1(23) /* not 2104{0,1} */
+#define M_CSR0_WRITEINVALENAB _DD_MAKEMASK1(24) /* not 2104{0,1} */
+
+#define K_CSR0_TAPDISABLED 0x00
+#define K_CSR0_TAP200US 0x01
+#define K_CSR0_TAP800US 0x02
+#define K_CSR0_TAP1600US 0x03
+
+#define K_CSR0_ALIGNNONE 0
+#define K_CSR0_ALIGN32 1
+#define K_CSR0_ALIGN64 2
+#define K_CSR0_ALIGN128 3
+
+#define K_CSR0_BURST32 32
+#define K_CSR0_BURST16 16
+#define K_CSR0_BURST8 8
+#define K_CSR0_BURST4 4
+#define K_CSR0_BURST2 2
+#define K_CSR0_BURST1 1
+
+
+#define M_CSR3_RXDSCRADDR 0xFFFFFFFC
+#define M_CSR4_TXDSCRADDR 0xFFFFFFFC
+
+
+/* CSR5: Status register */
+
+#define M_CSR5_TXINT _DD_MAKEMASK1(0)
+#define M_CSR5_TXSTOP _DD_MAKEMASK1(1)
+#define M_CSR5_TXBUFUNAVAIL _DD_MAKEMASK1(2)
+#define M_CSR5_TXJABTIMEOUT _DD_MAKEMASK1(3)
+#define M_CSR5_LINKPASS _DD_MAKEMASK1(4) /* not 21040 */
+#define M_CSR5_TXUNDERFLOW _DD_MAKEMASK1(5)
+#define M_CSR5_RXINT _DD_MAKEMASK1(6)
+#define M_CSR5_RXBUFUNAVAIL _DD_MAKEMASK1(7)
+#define M_CSR5_RXSTOPPED _DD_MAKEMASK1(8)
+#define M_CSR5_RXWDOGTIMEOUT _DD_MAKEMASK1(9)
+#define M_CSR5_AUITPPIN _DD_MAKEMASK1(10) /* 21040 only */
+#define M_CSR5_TXEARLYINT _DD_MAKEMASK1(10) /* not 2104{0,1} */
+#define M_CSR5_FDSHORTFRAME _DD_MAKEMASK1(11) /* 21040 only */
+#define M_CSR5_GPTIMEREXPIRE _DD_MAKEMASK1(11) /* not 21040 */
+#define M_CSR5_LINKFAIL _DD_MAKEMASK1(12)
+#define M_CSR5_FATALBUSERROR _DD_MAKEMASK1(13)
+#define M_CSR5_RXEARLYINT _DD_MAKEMASK1(14) /* not 21040 */
+#define M_CSR5_ABNORMALINT _DD_MAKEMASK1(15)
+#define M_CSR5_NORMALINT _DD_MAKEMASK1(16)
+
+#define S_CSR5_RXPROCSTATE 17
+#define M_CSR5_RXPROCSTATE _DD_MAKEMASK(3,S_CSR5_RXPROCSTATE)
+#define V_CSR5_RXPROCSTATE(x) _DD_MAKEVALUE(x,S_CSR5_RXPROCSTATE)
+#define G_CSR5_RXPROCSTATE(x) _DD_GETVALUE(x,S_CSR5_RXPROCSTATE,M_CSR5_RXPROCSTATE)
+
+#define K_CSR5_RXSTOPPED 0x00 /* RESET or STOP command */
+#define K_CSR5_RXFETCH 0x01 /* fetching rx desc */
+#define K_CSR5_RXCHECK 0x02 /* checking end of rx pkt */
+#define K_CSR5_RXWAIT 0x03 /* waiting for rx pkt */
+#define K_CSR5_RXSUSPEND 0x04 /* unavailable rx buffer */
+#define K_CSR5_RXCLOSE 0x05 /* closing rx desc */
+#define K_CSR5_RXFLUSH 0x06 /* flushing rx frame */
+#define K_CSR5_RXQUEUE 0x07 /* reading rx frame from FIFO */
+
+#define S_CSR5_TXPROCSTATE 20
+#define M_CSR5_TXPROCSTATE _DD_MAKEMASK(3,S_CSR5_TXPROCSTATE)
+#define V_CSR5_TXPROCSTATE(x) _DD_MAKEVALUE(x,S_CSR5_TXPROCSTATE)
+#define G_CSR5_TXPROCSTATE(x) _DD_GETVALUE(x,S_CSR5_TXPROCSTATE,M_CSR5_TXPROCSTATE)
+
+#define K_CSR5_TXSTOPPED 0x00 /* RESET or STOP command */
+#define K_CSR5_TXFETCH 0x01 /* fetching tx desc */
+#define K_CSR5_TXWAIT 0x02 /* waiting for end of tx */
+#define K_CSR5_TXREAD 0x03 /* reading buffer into FIFO */
+#define K_CSR5_TXSETUP 0x05 /* setup packet */
+#define K_CSR5_TXSUSPEND 0x06 /* tx underflow or no tx desc */
+#define K_CSR5_TXCLOSE 0x07 /* closing tx desc */
+
+#define S_CSR5_ERRORBITS 23
+#define M_CSR5_ERRORBITS _DD_MAKEMASK(3,S_CSR5_ERRORBITS)
+#define V_CSR5_ERRORBITS(x) _DD_MAKEVALUE(x,S_CSR5_ERRORBITS)
+#define G_CSR5_ERRORBITS(x) _DD_GETVALUE(x,S_CSR5_ERRORBITS,M_CSR5_ERRORBITS)
+
+#define K_CSR5_FBE_PARITY 0x00
+#define K_CSR5_FBE_MABORT 0x01
+#define K_CSR5_FBE_TABORT 0x02
+
+#define M_CSR5_GPPORTINT _DD_MAKEMASK1(26) /* not 2104{0,1} */
+#define M_CSR5_LINKCHANGED _DD_MAKEMASK1(27) /* not 2104{0,1} */
+
+
+/* CSR6: Operating Mode register */
+
+#define M_CSR6_RXHASHFILT _DD_MAKEMASK1(0)
+#define M_CSR6_RXSTART _DD_MAKEMASK1(1)
+#define M_CSR6_HASHONLY _DD_MAKEMASK1(2)
+#define M_CSR6_PASSBADFRAMES _DD_MAKEMASK1(3)
+#define M_CSR6_INVERSEFILT _DD_MAKEMASK1(4)
+#define M_CSR6_STOPBACKOFF _DD_MAKEMASK1(5)
+#define M_CSR6_PROMISCUOUS _DD_MAKEMASK1(6)
+#define M_CSR6_PASSALLMULTI _DD_MAKEMASK1(7)
+#define M_CSR6_FULLDUPLEX _DD_MAKEMASK1(9)
+
+#define M_CSR6_INTLOOPBACK _DD_MAKEMASK1(10)
+#define M_CSR6_EXTLOOPBACK _DD_MAKEMASK1(11)
+
+#define S_CSR6_OPMODE 10
+#define M_CSR6_OPMODE _DD_MAKEMASK(2,S_CSR6_OPMODE)
+#define V_CSR6_OPMODE(x) _DD_MAKEVALUE(x,S_CSR6_OPMODE)
+#define G_CSR6_OPMODE(x) _DD_GETVALUE(x,S_CSR6_OPMODE,M_CSR6_OPMODE)
+
+#define M_CSR6_FORCECOLL _DD_MAKEMASK1(12)
+#define M_CSR6_TXSTART _DD_MAKEMASK1(13)
+
+#define S_CSR6_THRESHCONTROL 14
+#define M_CSR6_THRESHCONTROL _DD_MAKEMASK(2,S_CSR6_THRESHCONTROL)
+#define V_CSR6_THRESHCONTROL(x) _DD_MAKEVALUE(x,S_CSR6_THRESHCONTROL)
+#define G_CSR6_THRESHCONTROL(x) _DD_GETVALUE(x,S_CSR6_THRESHCONTROL,M_CSR6_THRESHCONTROL)
+
+#define M_CSR6_BACKPRESSURE _DD_MAKEMASK1(16) /* 21040 only */
+#define M_CSR6_CAPTUREEFFECT _DD_MAKEMASK1(17)
+
+#define M_CSR6_PORTSEL _DD_MAKEMASK1(18) /* not 2104{0,1} */
+#define M_CSR6_HBDISABLE _DD_MAKEMASK1(19) /* not 2104{0,1} */
+#define M_CSR6_STOREFWD _DD_MAKEMASK1(21) /* not 2104{0,1} */
+#define M_CSR6_TXTHRESH _DD_MAKEMASK1(22) /* not 2104{0,1} */
+#define M_CSR6_PCSFUNC _DD_MAKEMASK1(23) /* not 2104{0,1} */
+#define M_CSR6_SCRAMMODE _DD_MAKEMASK1(24) /* not 2104{0,1} */
+#define M_CSR6_MBO _DD_MAKEMASK1(25) /* not 2104{0,1} */
+#define M_CSR6_RXALL _DD_MAKEMASK1(30) /* not 2104{0,1} */
+
+#define M_CSR6_SPECCAP _DD_MAKEMASK1(31) /* not 21040 */
+
+#define K_CSR6_TXTHRES_128_72 0x00
+#define K_CSR6_TXTHRES_256_96 0x01
+#define K_CSR6_TXTHRES_512_128 0x02
+#define K_CSR6_TXTHRES_1024_160 0x03
+
+
+#define M_CSR6_SPEED_10 (M_CSR6_TXTHRESH)
+
+#define M_CSR6_SPEED_100 (M_CSR6_HBDISABLE | \
+ M_CSR6_SCRAMMODE | \
+ M_CSR6_PCSFUNC | \
+ M_CSR6_PORTSEL)
+
+#define M_CSR6_SPEED_10_MII (M_CSR6_TXTHRESH | \
+ M_CSR6_PORTSEL)
+
+#define M_CSR6_SPEED_100_MII (M_CSR6_HBDISABLE | \
+ M_CSR6_PORTSEL)
+
+
+/* CSR7: Interrupt mask register */
+
+#define M_CSR7_TXINT _DD_MAKEMASK1(0)
+#define M_CSR7_TXSTOP _DD_MAKEMASK1(1)
+#define M_CSR7_TXBUFUNAVAIL _DD_MAKEMASK1(2)
+#define M_CSR7_TXJABTIMEOUT _DD_MAKEMASK1(3)
+#define M_CSR7_LINKPASS _DD_MAKEMASK1(4) /* not 21040 */
+#define M_CSR7_TXUNDERFLOW _DD_MAKEMASK1(5)
+#define M_CSR7_RXINT _DD_MAKEMASK1(6)
+#define M_CSR7_RXBUFUNAVAIL _DD_MAKEMASK1(7)
+#define M_CSR7_RXSTOPPED _DD_MAKEMASK1(8)
+#define M_CSR7_RXWDOGTIMEOUT _DD_MAKEMASK1(9)
+#define M_CSR7_AUITPSW _DD_MAKEMASK1(10) /* 21040 only */
+#define M_CSR7_TXEARLY _DD_MAKEMASK1(10) /* not 2104{0,1} */
+#define M_CSR7_FD _DD_MAKEMASK1(11) /* 21040 only */
+#define M_CSR7_GPTIMER _DD_MAKEMASK1(11) /* not 21040 */
+#define M_CSR7_LINKFAIL _DD_MAKEMASK1(12)
+#define M_CSR7_FATALBUSERROR _DD_MAKEMASK1(13)
+#define M_CSR7_RXEARLY _DD_MAKEMASK1(14) /* not 21040 */
+#define M_CSR7_ABNORMALINT _DD_MAKEMASK1(15)
+#define M_CSR7_NORMALINT _DD_MAKEMASK1(16)
+#define M_CSR7_GPPORT _DD_MAKEMASK1(26) /* not 2104{0,1} */
+#define M_CSR7_LINKCHANGED _DD_MAKEMASK1(27) /* not 2104{0,1} */
+
+
+/* CSR8: Missed Frame register */
+
+#define M_CSR8_RXOVER_WRAP _DD_MAKEMASK1(28) /* not 2104{0,1} */
+#define S_CSR8_RXOVER 17
+#define M_CSR8_RXOVER _DD_MAKEMASK(11,S_CSR8_RXOVER) /* not 2104{0,1} */
+#define V_CSR8_RXOVER(x) _DD_MAKEVALUE(x,S_CSR8_RXOVER)
+#define G_CSR8_RXOVER(x) _DD_GETVALUE(x,S_CSR8_RXOVER,M_CSR8_RXOVER)
+
+#define M_CSR8_MISSEDWRAP _DD_MAKEMASK1(16)
+#define S_CSR8_MISSED 0
+#define M_CSR8_MISSED _DD_MAKEMASK(16,S_CSR8_MISSED)
+#define V_CSR8_MISSED(x) _DD_MAKEVALUE(x,S_CSR8_MISSED)
+#define G_CSR8_MISSED(x) _DD_GETVALUE(x,S_CSR8_MISSED,M_CSR8_MISSED)
+
+
+/* CSR9: ROM and MII register */
+
+#define S_CSR9_ROMDATA 0
+#define M_CSR9_ROMDATA _DD_MAKEMASK(8,S_CSR9_ROMDATA)
+#define V_CSR9_ROMDATA(x) _DD_MAKEVALUE(x,S_CSR9_ROMDATA)
+#define G_CSR9_ROMDATA(x) _DD_GETVALUE(x,S_CSR9_ROMDATA,M_CSR9_ROMDATA)
+
+#define M_CSR9_SROMCHIPSEL _DD_MAKEMASK1(0) /* not 21040 */
+#define M_CSR9_SROMCLOCK _DD_MAKEMASK1(1) /* not 21040 */
+#define M_CSR9_SROMDATAIN _DD_MAKEMASK1(2) /* not 21040 */
+#define M_CSR9_SROMDATAOUT _DD_MAKEMASK1(3) /* not 21040 */
+
+#define M_CSR9_REGSELECT _DD_MAKEMASK1(10) /* not 21040 */
+#define M_CSR9_SERROMSEL _DD_MAKEMASK1(11) /* not 21040 */
+#define M_CSR9_ROMSEL _DD_MAKEMASK1(12) /* not 21040 */
+#define M_CSR9_ROMWRITE _DD_MAKEMASK1(13) /* not 21040 */
+#define M_CSR9_ROMREAD _DD_MAKEMASK1(14) /* not 21040 */
+#define M_CSR9_MODESEL _DD_MAKEMASK1(15) /* 21041 only */
+#define M_CSR9_MDC _DD_MAKEMASK1(16) /* not 2104{0,1} */
+#define M_CSR9_MDO _DD_MAKEMASK1(17) /* not 2104{0,1} */
+#define M_CSR9_MIIMODE _DD_MAKEMASK1(18) /* not 2104{0,1} */
+#define M_CSR9_MDI _DD_MAKEMASK1(19) /* not 2104{0,1} */
+
+#define M_CSR9_DATANOTVALID _DD_MAKEMASK1(31) /* 21040 only */
+
+#define M_CSR10_BOOTROMADDR _DD_MAKEMASK(18,0) /* not 21040 */
+
+
+/* CSR11 General Purpose Timer register */
+
+#define S_CSR11_GPTIMER 0 /* not 21040 */
+#define M_CSR11_GPTIMER _DD_MAKEMASK(16,S_CSR11_GPTIMER)
+#define V_CSR11_GPTIMER(x) _DD_MAKEVALUE(x,S_CSR11_GPTIMER)
+#define G_CSR11_GPTIMER(x) _DD_GETVALUE(x,S_CSR11_GPTIMER,M_CSR11_GPTIMER)
+
+
+#define M_CSR11_GPTIMERCONT _DD_MAKEMASK1(16) /* not 21040 */
+
+#define S_CSR11_FDAUTOCONF 0 /* 21040 only */
+#define M_CSR11_FDAUTOCONF _DD_MAKEMASK(16,S_CSR11_FDAUTOCONF)
+#define V_CSR11_FDAUTOCONF(x) _DD_MAKEVALUE(x,S_CSR11_FDAUTOCONF)
+#define G_CSR11_FRAUTOCONF(x) _DD_GETVALUE(x,S_CSR11_FDAUTOCONF,M_CSR11_AUTOCONF)
+
+
+/* CSR12: SIA Status register (21143) */
+
+#define M_CSR12_MIIRPA _DD_MAKEMASK1(0)
+#define M_CSR12_100MBLINK _DD_MAKEMASK1(1)
+#define M_CSR12_10MBLINK _DD_MAKEMASK1(2)
+#define M_CSR12_AUTOPOLSTATE _DD_MAKEMASK1(3)
+
+#define M_CSR12_RXAUIACT _DD_MAKEMASK1(8)
+#define M_CSR12_RX10BASETACT _DD_MAKEMASK1(9)
+#define M_CSR12_NLPDETECT _DD_MAKEMASK1(10)
+#define M_CSR12_TXREMFAULT _DD_MAKEMASK1(11)
+
+#define S_CSR12_AUTONEGARBIT 12
+#define M_CSR12_AUTONEGARBIT _DD_MAKEMASK(3,S_CSR12_AUTONEGARBIT)
+#define V_CSR12_AUTONEGARBIT(x) _DD_MAKEVALUE(x,S_CSR12_AUTONEGARBIT)
+#define G_CSR12_AUTONEGARBIT(x) _DD_GETVALUE(x,S_CSR12_AUTONEGARBIT,M_CSR12_AUTONEGARBIT)
+
+#define M_CSR12_LINKPARTNEG _DD_MAKEMASK1(15)
+
+#define S_CSR12_LINKPARTCODE 16
+#define M_CSR12_LINKPARTCODE _DD_MAKEMASK(16,S_CSR12_LINKPARTCODE)
+#define V_CSR12_LINKPARTCODE(x) _DD_MAKEVALUE(x,S_CSR12_LINKPARTCODE)
+#define G_CSR12_LINKPARTCODE(x) _DD_GETVALUE(x,S_CSR12_LINKPARTCODE,M_CSR12_LINKPARTCODE)
+
+
+/* CSR12: SIA Status register (21041, also 31:12, 3:3 as for 21143) */
+
+#define M_CSR12_NETCONNERR _DD_MAKEMASK1(1)
+#define M_CSR12_LINKFAIL _DD_MAKEMASK1(2)
+#define M_CSR12_SELPORTACT _DD_MAKEMASK1(8)
+#define M_CSR12_NONSELPORTACT _DD_MAKEMASK1(9)
+#define M_CSR12_AUTONEGRESTART _DD_MAKEMASK1(10)
+#define M_CSR12_UNSTABLENLP _DD_MAKEMASK1(11)
+
+
+/* CSR12: General Purpose Port register (21140) */
+
+#define S_CSR12_DATA 0
+#define M_CSR12_DATA _DD_MAKEMASK(8,S_CSR12_DATA)
+#define V_CSR12_DATA _DD_MAKEVALUE(x,S_CSR12_DATA,M_CSR12_DATA)
+#define G_CSR12_DATA(x) _DD_GETVALUE(x,S_CSR12_DATA,M_CSR12_DATA)
+
+#define M_CSR12_CONTROL _DD_MAKEMASK1(8)
+
+
+/* CSR13: SIA Mode 0 register (21143 and 21041) */
+
+#define M_CSR13_CONN_NOT_RESET _DD_MAKEMASK1(0)
+#define M_CSR13_CONN_CSR_AUTO _DD_MAKEMAKS1(2) /* 21041 only */
+#define M_CSR13_CONN_AUI_10BT _DD_MAKEMASK1(3)
+
+
+/* CSR14: SIA Mode 1 register (21143 and 21041) */
+
+#define M_CSR14_ENCODER _DD_MAKEMASK1(0)
+#define M_CSR14_LOOPBACK _DD_MAKEMASK1(1)
+#define M_CSR14_DRIVER _DD_MAKEMASK1(2)
+#define M_CSR14_LINKPULSE _DD_MAKEMASK1(3)
+
+#define S_CSR14_COMPENSATE 4
+#define M_CSR14_COMPENSATE _DD_MAKEMASK(2,S_CSR14_COMPENSATE)
+#define V_CSR15_COMPENSATE(x) _DD_MAKEVALUE(x,S_CSR15_COMPENSATE)
+#define G_CSR15_COMPENSATE(x) _DD_GETVALUE(x,S_CSR15_COMPENSATE,M_CSR15_COMPENSATE)
+
+#define M_CSR14_HALFDUPLEX10BASET _DD_MAKEMASK1(6)
+#define M_CSR14_AUTONEGOTIATE _DD_MAKEMASK1(7)
+#define M_CSR14_RXSQUELCH _DD_MAKEMASK1(8)
+#define M_CSR14_COLLSQUELCH _DD_MAKEMASK1(9)
+#define M_CSR14_COLLDETECT _DD_MAKEMASK1(10)
+#define M_CSR14_SIGQUALGEN _DD_MAKEMASK1(11)
+#define M_CSR14_LINKTEST _DD_MAKEMASK1(12)
+#define M_CSR14_AUTOPOLARITY _DD_MAKEMASK1(13)
+#define M_CSR14_SETPOLARITY _DD_MAKEMASK1(14)
+#define M_CSR14_10BASETAUIAUTO _DD_MAKEMASK1(15)
+#define M_CSR14_100BASETHALFDUP _DD_MAKEMASK1(16) /* not 21041 */
+#define M_CSR14_100BASETFULLDUP _DD_MAKEMASK1(17) /* not 21041 */
+#define M_CSR14_100BASET4 _DD_MAKEMASK1(18) /* not 21041 */
+
+#define M_CSR14_10BT_HD 0x7F3F
+#define M_CSR14_10BT_FD 0x7F3D
+
+
+/* CSR15: SIA Mode 2 register (21143 and 21041) */
+
+#define M_CSR15_GP_JABBERDIS _DD_MAKEMASK1(0) /* 21041 only */
+#define M_CSR15_GP_HOSTUNJAB _DD_MAKEMASK1(1)
+#define M_CSR15_GP_JABBERCLK _DD_MAKEMASK1(2)
+#define M_CSR15_GP_AUIBNC _DD_MAKEMASK1(3)
+#define M_CSR15_GP_RXWATCHDIS _DD_MAKEMASK1(4)
+#define M_CSR15_GP_RXWATCHREL _DD_MAKEMASK1(5)
+
+/* (CSR15: 21143 only) */
+
+#define S_CSR15_GP_GPDATA 16
+#define M_CSR15_GP_GPDATA _DD_MAKEMASK(4,S_CSR15_GP_GPDATA)
+#define V_CSR15_GP_GPDATA(x) _DD_MAKEVALUE(x,S_CSR15_GP_GPDATA)
+#define G_CSR15_GP_GPDATA(x) _DD_GETVALUE(x,S_CSR15_GP_GPDATA,M_CSR15_GP_GPDATA)
+
+#define M_CSR15_GP_LED0 _DD_MAKEMASK1(20)
+#define M_CSR15_GP_LED1 _DD_MAKEMASK1(21)
+#define M_CSR15_GP_LED2 _DD_MAKEMASK1(22)
+#define M_CSR15_GP_LED3 _DD_MAKEMASK1(23)
+#define M_CSR15_GP_INTPORT0 _DD_MAKEMASK1(24)
+#define M_CSR15_GP_INTPORT1 _DD_MAKEMASK1(25)
+#define M_CSR15_GP_RXMATCH _DD_MAKEMASK1(26)
+#define M_CSR15_GP_CONTROLWRITE _DD_MAKEMASK1(27)
+#define M_CSR15_GP_GPINT0 _DD_MAKEMASK1(28)
+#define M_CSR15_GP_GPINT1 _DD_MAKEMASK1(29)
+#define M_CSR15_GP_RXMATCHINT _DD_MAKEMASK1(30)
+
+#define M_CSR15_DEFAULT_VALUE 0x00050008
+#define M_CSR15_CONFIG_GEPS_LEDS 0x08af0000
+
+/* (CSR15: 21041 only) */
+
+#define M_CSR15_GP_LED1ENB _DD_MAKEMASK1(6)
+#define M_CSR15_GP_LED1VALUE _DD_MAKEMASK1(7)
+#define M_CSR15_GP_TSTCLK _DD_MAKEMASK1(8)
+#define M_CSR15_GP_FORCEUNSQ _DD_MAKEMASK1(9)
+#define M_CSR15_GP_FORCEFAIL _DD_MAKEMASK1(10)
+#define M_CSR15_GP_LEDSTRDIS _DD_MAKEMASK1(11)
+#define M_CSR15_GP_PLLTEST _DD_MAKEMASK1(12)
+#define M_CSR15_GP_FORCERXLOW _DD_MAKEMASK1(13)
+#define M_CSR15_GP_LED2ENB _DD_MAKEMASK1(14)
+#define M_CSR15_GP_LED2VALUE _DD_MAKEMASK1(15)
+
+
+/* CSR15: Watchdog Timer register (21140) */
+
+#define M_CSR15_WT_JABBER _DD_MAKEMASK1(0)
+#define M_CSR15_WT_HOSTUNJAB _DD_MAKEMASK1(1)
+#define M_CSR15_WT_JABBERCLK _DD_MAKEMASK1(2)
+#define M_CSR15_WT_RXWATCHDIS _DD_MAKEMASK1(4)
+#define M_CSR15_WT_RXWATCHREL _DD_MAKEMASK1(5)
+
+
+/* *********************************************************************
+ * Receive Descriptors
+ ********************************************************************* */
+
+#define M_RDES0_OWNSYS 0
+#define M_RDES0_OWNADAP _DD_MAKEMASK1(31)
+
+#define S_RDES0_FRAMELEN 16
+#define M_RDES0_FRAMELEN _DD_MAKEMASK(14,S_RDES0_FRAMELEN)
+#define V_RDES0_FRAMELEN(x) _DD_MAKEVALUE(x,S_RDES0_FRAMELEN)
+#define G_RDES0_FRAMELEN(x) _DD_GETVALUE(x,S_RDES0_FRAMELEN,M_RDES0_FRAMELEN)
+
+#define M_RDES0_ZERO _DD_MAKEMASK1(0)
+#define M_RDES0_OVFL _DD_MAKEMAKS1(0) /* 21041 only */
+#define M_RDES0_CRCERR _DD_MAKEMASK1(1)
+#define M_RDES0_DRIBBLE _DD_MAKEMASK1(2)
+#define M_RDES0_MIIERROR _DD_MAKEMASK1(3) /* not 21041 */
+#define M_RDES0_WDOGTIMER _DD_MAKEMASK1(4)
+#define M_RDES0_FRAMETYPE _DD_MAKEMASK1(5)
+#define M_RDES0_COLLSEEN _DD_MAKEMASK1(6)
+#define M_RDES0_FRAMETOOLONG _DD_MAKEMASK1(7)
+#define M_RDES0_LASTDES _DD_MAKEMASK1(8)
+#define M_RDES0_FIRSTDES _DD_MAKEMASK1(9)
+#define M_RDES0_MCASTFRAME _DD_MAKEMASK1(10)
+#define M_RDES0_RUNTFRAME _DD_MAKEMASK1(11)
+
+#define S_RDES0_DATATYPE 12
+#define M_RDES0_DATATYPE _DD_MAKEMASK(2,S_RDES0_DATATYPE)
+#define V_RDES0_DATATYPE(x) _DD_MAKEVALUE(x,S_RDES0_DATATYPE)
+#define G_RDES0_DATATYPE(x) _DD_GETVALUE(x,S_RDES0_DATATYPE,M_RDES0_DATATYPE)
+
+#define M_RDES0_ERROR _DD_MAKEMASK1(14)
+#define M_RDES0_ERRORSUM _DD_MAKEMASK1(15)
+#define M_RDES0_FILTFAIL _DD_MAKEMASK1(30) /* not 21041 */
+
+#define S_RDES1_BUF1SIZE 0
+#define M_RDES1_BUF1SIZE _DD_MAKEMASK(11,S_TDES1_BUF1SIZE)
+#define V_RDES1_BUF1SIZE(x) _DD_MAKEVALUE(x,S_RDES1_BUF1SIZE)
+#define G_RDES1_BUF1SIZE(x) _DD_GETVALUE(x,S_RDES1_BUF1SIZE,M_RDES1_BUF1SIZE)
+
+#define S_RDES1_BUF2SIZE 11
+#define M_RDES1_BUF2SIZE _DD_MAKEMASK(11,S_TDES2_BUF2SIZE)
+#define V_RDES1_BUF2SIZE(x) _DD_MAKEVALUE(x,S_RDES1_BUF2SIZE)
+#define G_RDES1_BUF2SIZE(x) _DD_GETVALUE(x,S_RDES1_BUF2SIZE,M_RDES1_BUF2SIZE)
+
+#define M_RDES1_CHAINED _DD_MAKEMASK1(24)
+#define M_RDES1_ENDOFRING _DD_MAKEMASK1(25)
+
+#define M_RDES2_BUFADDR 0xFFFFFFFF
+#define M_RDES3_BUFADDR 0xFFFFFFFF
+
+/* *********************************************************************
+ * Transmit Descriptors
+ ********************************************************************* */
+
+#define M_TDES0_OWNSYS 0
+#define M_TDES0_OWNADAP _DD_MAKEMASK1(31)
+
+#define M_TDES0_DEFERRED _DD_MAKEMASK1(0)
+#define M_TDES0_UNDERFLOW _DD_MAKEMASK1(1)
+#define M_TDES0_LINK_FAIL _DD_MAKEMASK1(2)
+
+#define S_TDES0_COLLCOUNT 3
+#define M_TDES0_COLLCOUNT _DD_MAKEMASK(4,S_TDES0_COLLCOUNT)
+#define V_TDES0_COLLCOUNT(x) _DD_MAKEVALUE(x,S_TDES0_COLLCOUNT)
+#define G_TDES0_COLLCOUNT(x) _DD_GETVALUE(x,S_TDES0_COLLCOUNT,M_TDES0_COLLCOUNT)
+
+#define M_TDES0_HEARTBEAT_FAIL _DD_MAKEMASK1(7)
+#define M_TDES0_EXCESSIVE_COLLISIONS _DD_MAKEMASK1(8)
+#define M_TDES0_LATE_COLLISION _DD_MAKEMASK1(9)
+#define M_TDES0_NO_CARRIER _DD_MAKEMASK1(10)
+#define M_TDES0_LOSS_OF_CARRIER _DD_MAKEMASK1(11)
+#define M_TDES0_TX_JABBER_TIMEOUT _DD_MAKEMASK1(14)
+#define M_TDES0_ERROR_SUMMARY _DD_MAKEMASK1(15)
+#define M_TDES0_OWN_BIT _DD_MAKEMASK1(31)
+
+#define S_TDES1_BUF1SIZE 0
+#define M_TDES1_BUF1SIZE _DD_MAKEMASK(11,S_TDES1_BUF1SIZE)
+#define V_TDES1_BUF1SIZE(x) _DD_MAKEVALUE(x,S_TDES1_BUF1SIZE)
+#define G_TDES1_BUF1SIZE(x) _DD_GETVALUE(x,S_TDES1_BUF1SIZE,M_TDES1_BUF1SIZE)
+
+#define S_TDES1_BUF2SIZE 11
+#define M_TDES1_BUF2SIZE _DD_MAKEMASK(11,S_TDES2_BUF2SIZE)
+#define V_TDES1_BUF2SIZE(x) _DD_MAKEVALUE(x,S_TDES1_BUF2SIZE)
+#define G_TDES1_BUF2SIZE(x) _DD_GETVALUE(x,S_TDES1_BUF2SIZE,M_TDES1_BUF2SIZE)
+
+#define M_TDES1_FT0 _DD_MAKEMASK1(22)
+#define M_TDES1_NOPADDING _DD_MAKEMASK1(23)
+#define M_TDES1_CHAINED _DD_MAKEMASK1(24)
+#define M_TDES1_ENDOFRING _DD_MAKEMASK1(25)
+#define M_TDES1_NOADDCRC _DD_MAKEMASK1(26)
+#define M_TDES1_SETUP _DD_MAKEMASK1(27)
+#define M_TDES1_FT1 _DD_MAKEMASK1(28)
+#define M_TDES1_FIRSTSEG _DD_MAKEMASK1(29)
+#define M_TDES1_LASTSEG _DD_MAKEMASK1(30)
+#define M_TDES1_INTERRUPT _DD_MAKEMASK1(31)
+
+#define M_TDES2_BUFADDR 0xFFFFFFFF
+#define M_TDES3_BUFADDR 0xFFFFFFFF
+
+
+/* CAM */
+
+#define CAM_HASH_THRESHOLD 14
+#define CAM_PERFECT_ENTRIES 16
+
+#define CAM_SETUP_BUFFER_SIZE 192
+
+#endif /* _DC21143_H_ */
diff --git a/cfe/cfe/dev/dev_atapi.c b/cfe/cfe/dev/dev_atapi.c
new file mode 100644
index 0000000..b5f4d9a
--- /dev/null
+++ b/cfe/cfe/dev/dev_atapi.c
@@ -0,0 +1,222 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * ATAPI device driver File: dev_atapi.c
+ *
+ * This is a simple driver for ATAPI devices. The disks
+ * are expected to be connected to the generic bus (this
+ * driver doesn't support PCI).
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include "sbmips.h"
+#include "lib_types.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+#include "lib_string.h"
+#include "cfe_timer.h"
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "cfe_ioctl.h"
+
+#include "dev_ide_common.h"
+
+/* *********************************************************************
+ * Macros
+ ********************************************************************* */
+
+#define GETWORD_LE(buf,wordidx) (((unsigned int) (buf)[(wordidx)*2]) + \
+ (((unsigned int) (buf)[(wordidx)*2+1]) << 8))
+
+
+/* *********************************************************************
+ * Forward declarations
+ ********************************************************************* */
+
+extern void _wbflush(void);
+static void atapidrv_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+
+const static cfe_devdisp_t atapidrv_dispatch = {
+ idecommon_open,
+ idecommon_read,
+ idecommon_inpstat,
+ idecommon_write,
+ idecommon_ioctl,
+ idecommon_close,
+ NULL,
+ NULL
+};
+
+const cfe_driver_t atapidrv = {
+ "ATAPI device",
+ "atapi",
+ CFE_DEV_DISK,
+ &atapidrv_dispatch,
+ atapidrv_probe
+};
+
+
+
+/* *********************************************************************
+ * Port I/O routines
+ *
+ * These routines are called back from the common code to do
+ * I/O cycles to the IDE disk. We provide routines for
+ * reading and writing bytes, words, and strings of words.
+ ********************************************************************* */
+
+static uint8_t atapidrv_inb(idecommon_dispatch_t *disp,uint32_t reg)
+{
+ return *((volatile uint8_t *) PHYS_TO_K1(reg+disp->baseaddr));
+}
+
+static uint16_t atapidrv_inw(idecommon_dispatch_t *disp,uint32_t reg)
+{
+ return *((volatile uint16_t *) PHYS_TO_K1((reg+disp->baseaddr)));
+}
+
+static void atapidrv_ins(idecommon_dispatch_t *disp,uint32_t reg,uint8_t *buf,int len)
+{
+ uint16_t data;
+
+ while (len > 0) {
+ data = *((volatile uint16_t *) PHYS_TO_K1(reg+disp->baseaddr));
+
+#ifdef _BYTESWAP_
+ *buf++ = (data >> 8) & 0xFF;
+ *buf++ = (data & 0xFF);
+#else
+ *buf++ = (data & 0xFF);
+ *buf++ = (data >> 8) & 0xFF;
+#endif
+ len--;
+ len--;
+ }
+
+}
+
+static void atapidrv_outb(idecommon_dispatch_t *disp,uint32_t reg,uint8_t val)
+{
+ *((volatile uint8_t *) PHYS_TO_K1(reg+disp->baseaddr)) = val;
+ _wbflush();
+}
+
+static void atapidrv_outw(idecommon_dispatch_t *disp,uint32_t reg,uint16_t val)
+{
+ *((volatile uint16_t *) PHYS_TO_K1(reg+disp->baseaddr)) = val;
+ _wbflush();
+}
+
+static void atapidrv_outs(idecommon_dispatch_t *disp,uint32_t reg,uint8_t *buf,int len)
+{
+ uint16_t data;
+
+ while (len > 0) {
+#ifdef _BYTESWAP_
+ data = (uint16_t) buf[1] + ((uint16_t) buf[0] << 8);
+#else
+ data = (uint16_t) buf[0] + ((uint16_t) buf[1] << 8);
+#endif
+
+ *((volatile uint16_t *) PHYS_TO_K1(reg+disp->baseaddr)) = data;
+ _wbflush();
+
+ buf++;
+ buf++;
+ len--;
+ len--;
+ }
+}
+
+
+
+static void atapidrv_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ idecommon_t *softc;
+ idecommon_dispatch_t *disp;
+ char descr[80];
+ char unitstr[50];
+ int res;
+
+ /*
+ * probe_a is the IDE base address
+ * probe_b is the unit number and other flags
+ * probe_ptr is unused.
+ */
+
+ softc = (idecommon_t *) KMALLOC(sizeof(idecommon_t),0);
+ disp = (idecommon_dispatch_t *) KMALLOC(sizeof(idecommon_dispatch_t),0);
+
+ if (softc && disp) {
+ softc->idecommon_addr = probe_a;
+ softc->idecommon_unit = probe_b;
+
+ disp->ref = softc;
+ disp->baseaddr = softc->idecommon_addr;
+ softc->idecommon_dispatch = disp;
+
+ disp->outb = atapidrv_outb;
+ disp->outw = atapidrv_outw;
+ disp->outs = atapidrv_outs;
+
+ disp->inb = atapidrv_inb;
+ disp->inw = atapidrv_inw;
+ disp->ins = atapidrv_ins;
+
+ res = idecommon_devprobe(softc);
+ if (res < 0) {
+ KFREE(softc);
+ KFREE(disp);
+ return;
+ }
+
+ xsprintf(descr,"%s unit %d at %08X",drv->drv_description,probe_b,probe_a);
+ xsprintf(unitstr,"%d",probe_b);
+ cfe_attach(drv,softc,unitstr,descr);
+ }
+}
+
+
diff --git a/cfe/cfe/dev/dev_bcm1250.c b/cfe/cfe/dev/dev_bcm1250.c
new file mode 100644
index 0000000..8343a46
--- /dev/null
+++ b/cfe/cfe/dev/dev_bcm1250.c
@@ -0,0 +1,275 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * BCM1250 (BCM1250 as PCI device) driver File: dev_bcm1250.c
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include "sbmips.h"
+
+#ifndef _SB_MAKE64
+#define _SB_MAKE64(x) ((uint64_t)(x))
+#endif
+#ifndef _SB_MAKEMASK1
+#define _SB_MAKEMASK1(n) (_SB_MAKE64(1) << _SB_MAKE64(n))
+#endif
+
+#include "lib_types.h"
+#include "lib_hssubr.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+
+#include "cfe_iocb.h"
+#include "cfe_error.h"
+#include "cfe_device.h"
+
+#include "pcivar.h"
+#include "pcireg.h"
+
+#include "bsp_config.h"
+
+/* Note that PHYSADDR only works with 32-bit addresses */
+#define PHYSADDR(x) (K0_TO_PHYS((uint32_t)(uintptr_t)(x)))
+
+
+static void bcm1250_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+static int bcm1250_open(cfe_devctx_t *ctx);
+static int bcm1250_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int bcm1250_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
+static int bcm1250_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int bcm1250_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int bcm1250_close(cfe_devctx_t *ctx);
+
+const static cfe_devdisp_t bcm1250_dispatch = {
+ bcm1250_open,
+ bcm1250_read,
+ bcm1250_inpstat,
+ bcm1250_write,
+ bcm1250_ioctl,
+ bcm1250_close,
+ NULL,
+ NULL
+};
+
+const cfe_driver_t bcm1250drv = {
+ "BCM1250",
+ "widget",
+ CFE_DEV_OTHER,
+ &bcm1250_dispatch,
+ bcm1250_probe
+};
+
+
+typedef struct bcm1250_s {
+ uint64_t mailbox;
+ uint64_t mem_base;
+ uint8_t irq; /* interrupt mapping */
+ pcitag_t tag; /* tag for configuration register */
+
+ int downloaded; /* code has already been downloaded. */
+} bcm1250_t;
+
+
+/*
+ * BCM1250_PROBE
+ * probe_a, probe_b and probe_ptr all unused
+ */
+
+static void
+bcm1250_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ int index;
+
+ index = 0;
+ for (;;) {
+ pcitag_t tag;
+
+ if (pci_find_device(0x166d, 0x0001, index, &tag) != 0)
+ break;
+
+ if (tag != 0x00000000) { /* don't configure ourselves */
+ bcm1250_t *softc;
+ char descr[80];
+ phys_addr_t pa;
+
+ softc = (bcm1250_t *) KMALLOC(sizeof(bcm1250_t), 0);
+ if (softc == NULL) {
+ xprintf("BCM1250: No memory to complete probe\n");
+ break;
+ }
+
+ softc->tag = tag;
+
+ pci_map_mem(tag, PCI_MAPREG(0), PCI_MATCH_BYTES, &pa);
+ xsprintf(descr, "%s at 0x%X", drv->drv_description, (uint32_t)pa);
+ softc->mem_base = PHYS_TO_XKSEG_UNCACHED(pa);
+
+ /* Map the CPU0 mailbox registers of the device 1250.
+ Note that our BAR2 space maps to its "alias" mailbox
+ registers. Set bit 3 for mbox_set; clear bit 3 for
+ reading. Address bits 15-4 are don't cares. */
+ pci_map_mem(tag, PCI_MAPREG(2), PCI_MATCH_BYTES, &pa);
+ softc->mailbox = PHYS_TO_XKSEG_UNCACHED(pa);
+
+ softc->downloaded = 0;
+
+ cfe_attach(drv, softc, NULL, descr);
+ }
+ index++;
+ }
+}
+
+
+#include "elf.h"
+
+static int
+elf_header (const uint8_t *hdr)
+{
+ return (hdr[EI_MAG0] == ELFMAG0 &&
+ hdr[EI_MAG1] == ELFMAG1 &&
+ hdr[EI_MAG2] == ELFMAG2 &&
+ hdr[EI_MAG3] == ELFMAG3);
+}
+
+
+#include "cfe_timer.h"
+
+typedef struct {
+ uint32_t addr; /* source address, in device's PCI space */
+ uint32_t len; /* length of this chunk */
+} chunk_desc;
+
+
+#define MBOX_SET_BIT 0x8
+
+extern void download_start(void), download_end(void);
+
+static int
+bcm1250_open(cfe_devctx_t *ctx)
+{
+ bcm1250_t *softc = ctx->dev_softc;
+ uint64_t cmd_p = softc->mailbox + 4;
+
+ if (softc->downloaded) {
+ xprintf("bcm1250_open: Warning: Device previously downloaded\n");
+ softc->downloaded = 0;
+ }
+
+ if (hs_read32(cmd_p) != 0) {
+ xprintf("bcm1250_open: Device not in initial state\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+bcm1250_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ return -1;
+}
+
+static int
+bcm1250_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat)
+{
+ return -1;
+}
+
+static int
+bcm1250_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ bcm1250_t *softc = ctx->dev_softc;
+ uint64_t arg_p = softc->mailbox + 0;
+ uint64_t cmd_p = softc->mailbox + 4;
+ chunk_desc code;
+ uint32_t cmd;
+ int64_t timer;
+ int res;
+
+ /* Note: This code assumes that PHYSADDR gives a PCI memory space
+ address that is accessible via our BAR4 or BAR5 */
+
+ code.addr = PHYSADDR((uint8_t *)buffer->buf_ptr);
+ code.len = buffer->buf_length;
+
+ cmd = 0x1; /* load */
+ if (!elf_header((uint8_t *)buffer->buf_ptr)) {
+ /* No recognizable elf seal, so assume compressed. */
+ cmd |= 0x2;
+ }
+
+ hs_write32(arg_p | MBOX_SET_BIT, PHYSADDR(&code));
+ hs_write32(cmd_p | MBOX_SET_BIT, cmd); /* load */
+
+ /* Wait for handshake */
+
+ res = CFE_ERR_TIMEOUT;
+ TIMER_SET(timer, 5*CFE_HZ);
+ while (!TIMER_EXPIRED(timer)) {
+ if ((hs_read32(cmd_p) & 0x3) == 0) {
+ softc->downloaded = 1;
+ buffer->buf_retlen = 0; /* XXX check this */
+ /* Note that the result code need not be translated only
+ because we are assuming a CFE in the device that is
+ compatible with us. */
+ res = (int)hs_read32(arg_p);
+ break;
+ }
+ POLL();
+ }
+
+ return res;
+}
+
+static int
+bcm1250_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ return -1;
+}
+
+static int
+bcm1250_close(cfe_devctx_t *ctx)
+{
+ return 0;
+}
diff --git a/cfe/cfe/dev/dev_bcm5700.c b/cfe/cfe/dev/dev_bcm5700.c
new file mode 100644
index 0000000..a7bef89
--- /dev/null
+++ b/cfe/cfe/dev/dev_bcm5700.c
@@ -0,0 +1,2557 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * BCM5700/Tigon3 (10/100/1000 EthernetMAC) driver File: dev_bcm5700.c
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+#include "sbmips.h"
+
+#ifndef _SB_MAKE64
+#define _SB_MAKE64(x) ((uint64_t)(x))
+#endif
+#ifndef _SB_MAKEMASK1
+#define _SB_MAKEMASK1(n) (_SB_MAKE64(1) << _SB_MAKE64(n))
+#endif
+
+#include "lib_types.h"
+#include "lib_hssubr.h"
+#include "lib_malloc.h"
+#include "lib_string.h"
+#define blockcopy memcpy
+#include "lib_printf.h"
+#include "lib_queue.h"
+
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "cfe_ioctl.h"
+#include "cfe_timer.h"
+#include "cfe_error.h"
+#include "cfe_irq.h"
+
+#include "pcivar.h"
+#include "pcireg.h"
+
+#include "bcm5700.h"
+#include "mii.h"
+
+/* This is a driver for the Broadcom 570x ("Tigon 3") 10/100/1000 MAC.
+ Currently, only the 5700, 5701 and 5705 have been tested. The 5704
+ dual MAC is not supported, nor is any device with a SerDes PHY.
+
+ Reference:
+ Host Programmer Interface Specification for the BCM570X Family
+ of Highly-Integrated Media Access Controllers, 570X-PG106-R.
+ Broadcom Corp., 16215 Alton Parkway, Irvine CA, 09/27/02
+
+ This BCM1250 version takes advantage of DMA coherence and uses
+ "preserve bit lanes" addresses for all accesses that cross the
+ ZBbus-PCI bridge.
+
+ Note that the 5705 does not fully map all address ranges. Per
+ the manual, reads and writes of the unmapped regions are permitted
+ and do not fault; however, it apparently has some poisoned registers,
+ at least in early revs, that should not be touched. See the
+ conditionals in the code. */
+
+/* PIOSWAP controls whether word-swapping takes place for transactions
+ in which the 570x is the target device. In theory, either value
+ should work (with access macros adjusted as below) and it should be
+ set to be consistent with the settings for 570x as initiator.
+ Empirically, however, some combinations work with the bit clear:
+
+ SWAP=0 SWAP=1
+ 5700 32 PCI OK OK
+ 5700 64 Sturgeon OK OK
+ 5701-32 32 PCI OK OK
+ 5701-32 64 Sturgeon OK OK
+ 5701-32 64 Golem OK OK
+ 5701-64 64 Sturgeon OK OK
+ 5701-64 64 Golem OK FAIL
+ 5705 32 PCI OK OK
+ 5705 64 Sturgeon (OK)* FAIL
+ 5705 64 Golem OK OK
+
+ * PCI status/interrupt ordering problem under load. */
+
+#define PIOSWAP 0
+
+#ifndef T3_DEBUG
+#define T3_DEBUG 0
+#endif
+
+#ifndef T3_BRINGUP
+#define T3_BRINGUP 0
+#endif
+
+/* Broadcom recommends using PHY interrupts instead of autopolling,
+ but I haven't made it work yet. */
+#define T3_AUTOPOLL 1
+
+/* Set IPOLL to drive processing through the pseudo-interrupt
+ dispatcher. Set XPOLL to drive processing by an external polling
+ agent. One must be set; setting both is ok. */
+
+#ifndef IPOLL
+#define IPOLL 0
+#endif
+#ifndef XPOLL
+#define XPOLL 1
+#endif
+
+#define ENET_ADDR_LEN 6 /* size of an ethernet address */
+#define MIN_ETHER_PACK 64 /* min size of a packet */
+#define MAX_ETHER_PACK 1518 /* max size of a packet */
+#define VLAN_TAG_LEN 4 /* VLAN type plus tag */
+#define CRC_SIZE 4 /* size of CRC field */
+
+/* Packet buffers. For the Tigon 3, packet buffer alignment is
+ arbitrary and can be to any byte boundary. We would like it
+ aligned to a cache line boundary for performance, although there is
+ a trade-off with IP/TCP header alignment. */
+
+#define ETH_PKTBUF_LEN (((MAX_ETHER_PACK+31)/32)*32)
+
+#if __long64
+typedef struct eth_pkt_s {
+ queue_t next; /* 16 */
+ uint8_t *buffer; /* 8 */
+ uint32_t flags; /* 4 */
+ int32_t length; /* 4 */
+ uint8_t data[ETH_PKTBUF_LEN];
+} eth_pkt_t;
+#else
+typedef struct eth_pkt_s {
+ queue_t next; /* 8 */
+ uint8_t *buffer; /* 4 */
+ uint32_t flags; /* 4 */
+ int32_t length; /* 4 */
+ uint32_t unused[3]; /* 12 */
+ uint8_t data[ETH_PKTBUF_LEN];
+} eth_pkt_t;
+#endif
+
+#define CACHE_ALIGN 32
+#define ETH_PKTBUF_LINES ((sizeof(eth_pkt_t) + (CACHE_ALIGN-1))/CACHE_ALIGN)
+#define ETH_PKTBUF_SIZE (ETH_PKTBUF_LINES*CACHE_ALIGN)
+#define ETH_PKTBUF_OFFSET (offsetof(eth_pkt_t, data))
+
+#define ETH_PKT_BASE(data) ((eth_pkt_t *)((data) - ETH_PKTBUF_OFFSET))
+
+static void
+show_packet(char c, eth_pkt_t *pkt)
+{
+ int i;
+ int n = (pkt->length < 32 ? pkt->length : 32);
+
+ xprintf("%c[%4d]:", c, pkt->length);
+ for (i = 0; i < n; i++) {
+ if (i % 4 == 0)
+ xprintf(" ");
+ xprintf("%02x", pkt->buffer[i]);
+ }
+ xprintf("\n");
+}
+
+
+static void t3_ether_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+
+/* BCM570X Hardware Common Data Structures
+ XXX These work for 1250 big endian. Need endian testing.
+ XXX Should they move to the header file? */
+
+/* Chip documentation numbers the rings with 1-origin. */
+
+#define RI(n) ((n)-1)
+
+/* BCM570x Ring Sizes (no external memory). Pages 97-98 */
+
+#define TXP_MAX_RINGS 16
+#define TXP_INTERNAL_RINGS 4
+#define TXP_RING_ENTRIES 512
+
+#define RXP_STD_ENTRIES 512
+
+#define RXR_MAX_RINGS 16
+#define RXR_RING_ENTRIES 1024
+
+#define RXR_MAX_RINGS_05 1
+#define RXR_RING_ENTRIES_05 512
+
+
+/* BCM570x Send Buffer Descriptors as a struct. Pages 100-101 */
+
+typedef struct t3_snd_bd_s {
+ uint32_t bufptr_hi;
+ uint32_t bufptr_lo;
+#ifdef __MIPSEB
+ uint16_t length;
+ uint16_t flags;
+ uint16_t pad;
+ uint16_t vlan_tag;
+#elif __MIPSEL
+ uint16_t flags;
+ uint16_t length;
+ uint16_t vlan_tag;
+ uint16_t pad;
+#else
+#error "bcm5700: endian not set"
+#endif
+} t3_snd_bd_t;
+
+#define SND_BD_SIZE 16
+
+#define TX_FLAG_TCP_CKSUM 0x0001
+#define TX_FLAG_IP_CKSUM 0x0002
+#define TX_FLAG_PACKET_END 0x0004
+#define TX_FLAG_IP_FRAG 0x0008
+#define TX_FLAG_IP_FRAG_END 0x0010
+#define TX_FLAG_VLAN_TAG 0x0040
+#define TX_FLAG_COAL_NOW 0x0080
+#define TX_FLAG_CPU_PRE_DMA 0x0100
+#define TX_FLAG_CPU_POST_DMA 0x0200
+#define TX_FLAG_ADD_SRC 0x1000
+#define TX_FLAG_SRC_ADDR_SEL 0x6000
+#define TX_FLAG_NO_CRC 0x8000
+
+/* BCM570x Receive Buffer Descriptors as a struct. Pages 105-107 */
+
+typedef struct t3_rcv_bd_s {
+ uint32_t bufptr_hi;
+ uint32_t bufptr_lo;
+#ifdef __MIPSEB
+ uint16_t index;
+ uint16_t length;
+ uint16_t type;
+ uint16_t flags;
+ uint16_t ip_cksum;
+ uint16_t tcp_cksum;
+ uint16_t error_flag;
+ uint16_t vlan_tag;
+#elif __MIPSEL
+ uint16_t length;
+ uint16_t index;
+ uint16_t flags;
+ uint16_t type;
+ uint16_t tcp_cksum;
+ uint16_t ip_cksum;
+ uint16_t vlan_tag;
+ uint16_t error_flag;
+#else
+#error "bcm5700: endian not set"
+#endif
+ uint32_t pad;
+ uint32_t opaque;
+} t3_rcv_bd_t;
+
+#define RCV_BD_SIZE 32
+
+#define RX_FLAG_PACKET_END 0x0004
+#define RX_FLAG_JUMBO_RING 0x0020
+#define RX_FLAG_VLAN_TAG 0x0040
+#define RX_FLAG_ERROR 0x0400
+#define RX_FLAG_MINI_RING 0x0800
+#define RX_FLAG_IP_CKSUM 0x1000
+#define RX_FLAG_TCP_CKSUM 0x2000
+#define RX_FLAG_IS_TCP 0x4000
+
+#define RX_ERR_BAD_CRC 0x0001
+#define RX_ERR_COLL_DETECT 0x0002
+#define RX_ERR_LINK_LOST 0x0004
+#define RX_ERR_PHY_DECODE 0x0008
+#define RX_ERR_DRIBBLE 0x0010
+#define RX_ERR_MAC_ABORT 0x0020
+#define RX_ERR_SHORT_PKT 0x0040
+#define RX_ERR_TRUNC_NO_RES 0x0080
+#define RX_ERR_GIANT_PKT 0x0100
+
+/* BCM570x Status Block format as a struct (not BCM5705). Pages 110-111. */
+
+typedef struct t3_status_s {
+ uint32_t status;
+ uint32_t tag;
+#ifdef __MIPSEB
+ uint16_t rxc_std_index;
+ uint16_t rxc_jumbo_index;
+ uint16_t reserved2;
+ uint16_t rxc_mini_index;
+ struct {
+ uint16_t send_c;
+ uint16_t return_p;
+ } index [16];
+#elif __MIPSEL
+ uint16_t rxc_jumbo_index;
+ uint16_t rxc_std_index;
+ uint16_t rxc_mini_index;
+ uint16_t reserved2;
+ struct {
+ uint16_t return_p;
+ uint16_t send_c;
+ } index [16];
+#else
+#error "bcm5700: endian not set"
+#endif
+} t3_status_t;
+
+#define M_STATUS_UPDATED 0x00000001
+#define M_STATUS_LINKCHNG 0x00000002
+#define M_STATUS_ERROR 0x00000004
+
+/* BCM570x Statistics Block format as a struct. Pages 112-120 */
+
+typedef struct t3_stats_s {
+ uint64_t stats[L_MAC_STATS/sizeof(uint64_t)];
+} t3_stats_t;
+
+/* End of 570X defined data structures */
+
+
+typedef enum {
+ eth_state_uninit,
+ eth_state_off,
+ eth_state_on,
+} eth_state_t;
+
+typedef struct t3_ether_s {
+ /* status block */
+ volatile t3_status_t *status; /* should be cache-aligned */
+
+ /* PCI access information */
+ uint32_t regbase;
+ uint32_t membase;
+ uint8_t irq;
+ pcitag_t tag; /* tag for configuration registers */
+
+ uint8_t hwaddr[6];
+ uint16_t device; /* chip device code */
+ uint8_t revision; /* chip revision */
+
+ eth_state_t state; /* current state */
+ uint32_t intmask; /* interrupt mask */
+
+ /* packet lists */
+ queue_t freelist;
+ uint8_t *pktpool;
+ queue_t rxqueue;
+
+ /* rings */
+ /* For now, support only the standard Rx Producer Ring */
+ t3_rcv_bd_t *rxp_std; /* Standard Rx Producer Ring */
+ uint32_t rxp_std_index;
+ uint32_t prev_rxp_std_index;
+
+ /* For now, support only 1 priority */
+ uint32_t rxr_entries;
+ t3_rcv_bd_t *rxr_1; /* Rx Return Ring 1 */
+ uint32_t rxr_1_index;
+ t3_snd_bd_t *txp_1; /* Send Ring 1 */
+ uint32_t txp_1_index;
+ uint32_t txc_1_index;
+
+ cfe_devctx_t *devctx;
+
+ /* PHY access */
+ int phy_addr;
+ uint16_t phy_status;
+ uint16_t phy_ability;
+ uint16_t phy_xability;
+
+ /* MII polling control */
+ int phy_change;
+ int mii_polling;
+
+ /* statistics block */
+ t3_stats_t *stats; /* should be cache-aligned */
+
+ /* additional driver statistics */
+ uint32_t rx_interrupts;
+ uint32_t tx_interrupts;
+ uint32_t bogus_interrupts;
+} t3_ether_t;
+
+
+/* Address mapping macros */
+
+#define PTR_TO_PHYS(x) (K0_TO_PHYS((uintptr_t)(x)))
+#define PHYS_TO_PTR(a) ((uint8_t *)PHYS_TO_K0(a))
+
+/* All mappings through the PCI host bridge use match bits mode. */
+#define PHYS_TO_PCI(a) ((uint32_t) (a) | 0x20000000)
+#define PCI_TO_PHYS(a) ((uint32_t) (a) & 0x1FFFFFFF)
+
+#define PCI_TO_PTR(a) (PHYS_TO_PTR(PCI_TO_PHYS(a)))
+#define PTR_TO_PCI(x) (PHYS_TO_PCI(PTR_TO_PHYS(x)))
+
+
+/* Chip access macros */
+
+/* These macros attempt to be compatible with match-bits mode,
+ which may put the data and byte masks into the wrong 32-bit word
+ for 64-bit accesses. See the comment above on PIOSWAP.
+ Externally mastered DMA (control and data) uses match-bits and does
+ specify word-swaps when operating big endian. */
+
+/* Most registers are 32 bits wide and are accessed by 32-bit
+ transactions. The mailbox registers and on-chip RAM are 64-bits
+ wide but are generally accessed by 32-bit transactions.
+ Furthermore, the documentation is ambiguous about which 32-bits of
+ the mailbox is significant. To localize the potential confusions,
+ we define macros for the 3 different cases. */
+
+#if __long64
+#define READCSR(sc,csr) \
+ (*((volatile uint32_t *) \
+ (PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr)))))
+
+#define WRITECSR(sc,csr,val) \
+ (*((volatile uint32_t *) \
+ (PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr)))) = (val))
+
+#if PIOSWAP
+#define READMBOX(sc,csr) \
+ (*((volatile uint32_t *) \
+ (PHYS_TO_XKSEG_UNCACHED((sc)->regbase+((csr)+4)))))
+
+#define WRITEMBOX(sc,csr,val) \
+ (*((volatile uint32_t *) \
+ (PHYS_TO_XKSEG_UNCACHED((sc)->regbase+((csr)+4)))) = (val))
+
+#define READMEM(sc,csr) \
+ (*((volatile uint32_t *) \
+ (PHYS_TO_XKSEG_UNCACHED((sc)->membase+(csr)))))
+
+#define WRITEMEM(sc,csr,val) \
+ (*((volatile uint32_t *) \
+ (PHYS_TO_XKSEG_UNCACHED((sc)->membase+(csr)))) = (val))
+
+#else
+#define READMBOX(sc,csr) \
+ (*((volatile uint32_t *) \
+ (PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr)))))
+
+#define WRITEMBOX(sc,csr,val) \
+ (*((volatile uint32_t *) \
+ (PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr)))) = (val))
+
+#define READMEM(sc,csr) \
+ (*((volatile uint32_t *) \
+ (PHYS_TO_XKSEG_UNCACHED((sc)->membase+((csr) ^ 4)))))
+
+#define WRITEMEM(sc,csr,val) \
+ (*((volatile uint32_t *) \
+ (PHYS_TO_XKSEG_UNCACHED((sc)->membase+((csr) ^ 4)))) = (val))
+
+#endif
+#else
+#define READCSR(sc,csr) \
+ (hs_read32(PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr))))
+
+#define WRITECSR(sc,csr,val) \
+ (hs_write32(PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr), (val))))
+
+#define READMBOX(sc,csr) \
+ (hs_read32(PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr)))))
+
+#define WRITEMBOX(sc,csr,val) \
+ (hs_write32(PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr)))) = (val))
+
+#define READMEM(sc,csr) \
+ (hs_read32(PHYS_TO_XKSEG_UNCACHED((sc)->membase+(csr))))
+
+#define WRITEMEM(sc,csr,val) \
+ (hs_write32(PHYS_TO_XKSEG_UNCACHED((sc)->membase+(csr), (val))))
+
+#endif
+
+
+/* Entry to and exit from critical sections (currently relative to
+ interrupts only, not SMP) */
+
+#if CFG_INTERRUPTS
+#define CS_ENTER(sc) cfe_disable_irq(sc->irq)
+#define CS_EXIT(sc) cfe_enable_irq(sc->irq)
+#else
+#define CS_ENTER(sc) ((void)0)
+#define CS_EXIT(sc) ((void)0)
+#endif
+
+
+static void
+dumpseq(t3_ether_t *sc, int start, int next)
+{
+ int offset, i, j;
+ int columns = 4;
+ int lines = (((next - start)/4 + 1) + 3)/columns;
+ int step = lines*4;
+
+ offset = start;
+ for (i = 0; i < lines; i++) {
+ xprintf("\nCSR");
+ for (j = 0; j < columns; j++) {
+ if (offset + j*step < next)
+ xprintf(" %04X: %08X ",
+ offset+j*step, READCSR(sc, offset+j*step));
+ }
+ offset += 4;
+ }
+ xprintf("\n");
+}
+
+static void
+dumpcsrs(t3_ether_t *sc, const char *legend)
+{
+ xprintf("%s:\n", legend);
+
+ /* Some device-specific PCI configuration registers */
+ xprintf("-----PCI-----");
+ dumpseq(sc, 0x68, 0x78);
+
+ /* Some general control registers */
+ xprintf("---General---");
+ dumpseq(sc, 0x6800, 0x6810);
+
+ xprintf("-------------\n");
+}
+
+
+/* Packet management */
+
+#define ETH_PKTPOOL_SIZE 64
+#define MIN_RXP_STD_BDS 32
+
+
+static eth_pkt_t *
+eth_alloc_pkt(t3_ether_t *sc)
+{
+ eth_pkt_t *pkt;
+
+ CS_ENTER(sc);
+ pkt = (eth_pkt_t *) q_deqnext(&sc->freelist);
+ CS_EXIT(sc);
+ if (!pkt) return NULL;
+
+ pkt->buffer = pkt->data;
+ pkt->length = ETH_PKTBUF_LEN;
+ pkt->flags = 0;
+
+ return pkt;
+}
+
+
+static void
+eth_free_pkt(t3_ether_t *sc, eth_pkt_t *pkt)
+{
+ CS_ENTER(sc);
+ q_enqueue(&sc->freelist, &pkt->next);
+ CS_EXIT(sc);
+}
+
+static void
+eth_initfreelist(t3_ether_t *sc)
+{
+ int idx;
+ uint8_t *ptr;
+ eth_pkt_t *pkt;
+
+ q_init(&sc->freelist);
+
+ ptr = sc->pktpool;
+ for (idx = 0; idx < ETH_PKTPOOL_SIZE; idx++) {
+ pkt = (eth_pkt_t *) ptr;
+ eth_free_pkt(sc, pkt);
+ ptr += ETH_PKTBUF_SIZE;
+ }
+}
+
+
+/* Utilities */
+
+static const char *
+t3_devname(t3_ether_t *sc)
+{
+ return (sc->devctx != NULL ? cfe_device_name(sc->devctx) : "eth?");
+}
+
+
+/* CRCs */
+
+#define IEEE_CRC32_POLY 0xEDB88320UL /* CRC-32 Poly -- either endian */
+
+uint32_t eth_crc32(const uint8_t *databuf, unsigned int datalen);
+/*static*/ uint32_t
+eth_crc32(const uint8_t *databuf, unsigned int datalen)
+{
+ unsigned int idx, bit, data;
+ uint32_t crc;
+
+ crc = 0xFFFFFFFFUL;
+ for (idx = 0; idx < datalen; idx++)
+ for (data = *databuf++, bit = 0; bit < 8; bit++, data >>= 1)
+ crc = (crc >> 1) ^ (((crc ^ data) & 1) ? IEEE_CRC32_POLY : 0);
+ return crc;
+}
+
+
+/* Descriptor ring management */
+
+static int
+t3_add_rcvbuf(t3_ether_t *sc, eth_pkt_t *pkt)
+{
+ t3_rcv_bd_t *rxp;
+
+ rxp = &(sc->rxp_std[sc->rxp_std_index]);
+ rxp->bufptr_lo = PTR_TO_PCI(pkt->buffer);
+ rxp->length = ETH_PKTBUF_LEN;
+ sc->rxp_std_index++;
+ if (sc->rxp_std_index == RXP_STD_ENTRIES)
+ sc->rxp_std_index = 0;
+ return 0;
+}
+
+static void
+t3_fillrxring(t3_ether_t *sc)
+{
+ eth_pkt_t *pkt;
+ unsigned rxp_ci, rxp_onring;
+
+ rxp_ci = sc->status->rxc_std_index; /* Get a snapshot */
+
+ if (sc->rxp_std_index >= rxp_ci)
+ rxp_onring = sc->rxp_std_index - rxp_ci;
+ else
+ rxp_onring = (sc->rxp_std_index + RXP_STD_ENTRIES) - rxp_ci;
+
+ while (rxp_onring < MIN_RXP_STD_BDS) {
+ pkt = eth_alloc_pkt(sc);
+ if (pkt == NULL) {
+ /* could not allocate a buffer */
+ break;
+ }
+ if (t3_add_rcvbuf(sc, pkt) != 0) {
+ /* could not add buffer to ring */
+ eth_free_pkt(sc, pkt);
+ break;
+ }
+ rxp_onring++;
+ }
+}
+
+static void
+t3_rx_callback(t3_ether_t *sc, eth_pkt_t *pkt)
+{
+ if (T3_DEBUG) show_packet('>', pkt); /* debug */
+
+ CS_ENTER(sc);
+ q_enqueue(&sc->rxqueue, &pkt->next);
+ CS_EXIT(sc);
+}
+
+static void
+t3_procrxring(t3_ether_t *sc)
+{
+ eth_pkt_t *pkt;
+ t3_rcv_bd_t *rxc;
+ volatile t3_status_t *status = sc->status;
+
+ rxc = &(sc->rxr_1[sc->rxr_1_index]);
+ do {
+ pkt = ETH_PKT_BASE(PCI_TO_PTR(rxc->bufptr_lo));
+ pkt->length = rxc->length;
+ if ((rxc->flags & RX_FLAG_ERROR) == 0)
+ t3_rx_callback(sc, pkt);
+ else {
+#if T3_BRINGUP
+ xprintf("%s: rx error %04X\n", t3_devname(sc), rxc->error_flag);
+#endif
+ eth_free_pkt(sc, pkt); /* Could optimize */
+ }
+ sc->rxr_1_index++;
+ rxc++;
+ if (sc->rxr_1_index == sc->rxr_entries) {
+ sc->rxr_1_index = 0;
+ rxc = &(sc->rxr_1[0]);
+ }
+ } while (status->index[RI(1)].return_p != sc->rxr_1_index);
+
+ /* Update the return ring */
+ WRITEMBOX(sc, R_RCV_BD_RTN_CI(1), sc->rxr_1_index);
+
+ /* Refill the producer ring */
+ t3_fillrxring(sc);
+}
+
+
+static int
+t3_transmit(t3_ether_t *sc, eth_pkt_t *pkt)
+{
+ t3_snd_bd_t *txp;
+
+ if (T3_DEBUG) show_packet('<', pkt); /* debug */
+
+ txp = &(sc->txp_1[sc->txp_1_index]);
+ txp->bufptr_hi = 0;
+ txp->bufptr_lo = PTR_TO_PCI(pkt->buffer);
+ txp->length = pkt->length;
+ txp->flags = TX_FLAG_PACKET_END;
+
+ sc->txp_1_index++;
+ if (sc->txp_1_index == TXP_RING_ENTRIES)
+ sc->txp_1_index = 0;
+
+ WRITEMBOX(sc, R_SND_BD_PI(1), sc->txp_1_index);
+
+ return 0;
+}
+
+
+static void
+t3_proctxring(t3_ether_t *sc)
+{
+ eth_pkt_t *pkt;
+ t3_snd_bd_t *txc;
+ volatile t3_status_t *status = sc->status;
+
+ txc = &(sc->txp_1[sc->txc_1_index]);
+ do {
+ pkt = ETH_PKT_BASE(PCI_TO_PTR(txc->bufptr_lo));
+ eth_free_pkt(sc, pkt);
+ sc->txc_1_index++;
+ txc++;
+ if (sc->txc_1_index == TXP_RING_ENTRIES) {
+ sc->txc_1_index = 0;
+ txc = &(sc->txp_1[0]);
+ }
+ } while (status->index[RI(1)].send_c != sc->txc_1_index);
+}
+
+
+static void
+t3_initrings(t3_ether_t *sc)
+{
+ int i;
+ t3_rcv_bd_t *rxp;
+ volatile t3_status_t *status = sc->status;
+
+ /* Clear all Producer BDs */
+ rxp = &(sc->rxp_std[0]);
+ for (i = 0; i < RXP_STD_ENTRIES; i++) {
+ rxp->bufptr_hi = rxp->bufptr_lo = 0;
+ rxp->length = 0;
+ rxp->index = i;
+ rxp->flags = 0;
+ rxp->type = 0;
+ rxp->ip_cksum = rxp->tcp_cksum = 0;
+ rxp++;
+ }
+
+ /* Init the ring pointers */
+
+ sc->rxp_std_index = 0; status->rxc_std_index = 0;
+ sc->rxr_1_index = 0; status->index[RI(1)].return_p = 0;
+ sc->txp_1_index = 0; status->index[RI(1)].send_c = 0;
+
+ /* Allocate some initial buffers for the Producer BD ring */
+ sc->prev_rxp_std_index = 0;
+ t3_fillrxring(sc);
+
+ /* Nothing consumed yet */
+ sc->txc_1_index = 0;
+}
+
+static void
+t3_init(t3_ether_t *sc)
+{
+ /* Allocate buffer pool */
+ sc->pktpool = KMALLOC(ETH_PKTPOOL_SIZE*ETH_PKTBUF_SIZE, CACHE_ALIGN);
+ eth_initfreelist(sc);
+ q_init(&sc->rxqueue);
+
+ t3_initrings(sc);
+}
+
+static void
+t3_reinit(t3_ether_t *sc)
+{
+ eth_initfreelist(sc);
+ q_init(&sc->rxqueue);
+
+ t3_initrings(sc);
+}
+
+
+/* Byte swap utilities. */
+
+#define SWAP4(x) \
+ ((((x) & 0x00FF) << 24) | \
+ (((x) & 0xFF00) << 8) | \
+ (((x) >> 8) & 0xFF00) | \
+ (((x) >> 24) & 0x00FF))
+
+static uint32_t
+swap4(uint32_t x)
+{
+ uint32_t t;
+
+ t = ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8);
+ return (t >> 16) | ((t & 0xFFFF) << 16);
+}
+
+
+/* EEPROM access functions (BCM5700 and BCM5701 version) */
+
+/* The 570x chips support multiple access methods. We use "Auto Access",
+ which requires that
+ Miscellaneous_Local_Control.Auto_SEEPROM_Access be set,
+ Serial_EEprom.Address.HalfClock be programmed for <= 400 Hz.
+ (both done by initialization code) */
+
+#define EP_MAX_RETRIES 500
+#define EP_DEVICE_ID 0x00 /* default ATMEL device ID */
+
+static void
+eeprom_access_init(t3_ether_t *sc)
+{
+ uint32_t mlctl;
+
+ WRITECSR(sc, R_EEPROM_ADDR, M_EPADDR_RESET | V_EPADDR_HPERIOD(0x60));
+
+ mlctl = READCSR(sc, R_MISC_LOCAL_CTRL);
+ mlctl |= M_MLCTL_EPAUTOACCESS;
+ WRITECSR(sc, R_MISC_LOCAL_CTRL, mlctl);
+}
+
+
+static uint32_t
+eeprom_read_word(t3_ether_t *sc, unsigned int offset)
+{
+ /* Assumes that SEEPROM is already set up for auto access. */
+ uint32_t epaddr, epdata;
+ volatile uint32_t temp;
+ int i;
+
+ epaddr = READCSR(sc, R_EEPROM_ADDR);
+ epaddr &= M_EPADDR_HPERIOD;
+ epaddr |= (V_EPADDR_ADDR(offset) | V_EPADDR_DEVID(EP_DEVICE_ID)
+ | M_EPADDR_RW | M_EPADDR_START | M_EPADDR_COMPLETE);
+ WRITECSR(sc, R_EEPROM_ADDR, epaddr);
+ temp = READCSR(sc, R_EEPROM_ADDR); /* push */
+
+ for (i = 0; i < EP_MAX_RETRIES; i++) {
+ temp = READCSR(sc, R_EEPROM_ADDR);
+ if ((temp & M_EPADDR_COMPLETE) != 0)
+ break;
+ cfe_usleep(10);
+ }
+ if (i == EP_MAX_RETRIES)
+ xprintf("%s: eeprom_read_word: no SEEPROM response @ %x\n",
+ t3_devname(sc), offset);
+
+ epdata = READCSR(sc, R_EEPROM_DATA); /* little endian */
+#ifdef __MIPSEB
+ return swap4(epdata);
+#else
+ return epdata;
+#endif
+}
+
+static int
+eeprom_read_range(t3_ether_t *sc, unsigned int offset, unsigned int len,
+ uint32_t buf[])
+{
+ int index;
+
+ offset &= ~3; len &= ~3; /* 4-byte words only */
+ index = 0;
+
+ while (len > 0) {
+ buf[index++] = eeprom_read_word(sc, offset);
+ offset += 4; len -= 4;
+ }
+
+ return index;
+}
+
+static void
+eeprom_dump_range(const char *label,
+ uint32_t buf[], unsigned int offset, unsigned int len)
+{
+ int index;
+
+ xprintf("EEPROM: %s", label);
+
+ offset &= ~3; len &= ~3; /* 4-byte words only */
+ index = 0;
+
+ for (index = 0; len > 0; index++) {
+ if (index % 8 == 0)
+ xprintf("\n %04x: ", offset);
+ xprintf(" %08x", buf[offset/4]);
+ offset += 4; len -= 4;
+ }
+ xprintf("\n");
+}
+
+
+/* MII access functions. */
+
+/* BCM5401 device specific registers */
+
+#define MII_ISR 0x1A /* Interrupt Status Register */
+#define MII_IMR 0x1B /* Interrupt Mask Register */
+
+#define M_INT_LINKCHNG 0x0002
+
+
+/* The 570x chips support multiple access methods. We use "Auto
+ Access", which requires that MDI_Control_Register.MDI_Select be
+ clear (done by initialization code) */
+
+#define MII_MAX_RETRIES 5000
+
+static void
+mii_access_init(t3_ether_t *sc)
+{
+ WRITECSR(sc, R_MDI_CTRL, 0); /* here for now */
+#if !T3_AUTOPOLL
+ WRITECSR(sc, R_MI_MODE, V_MIMODE_CLKCNT(0x1F)); /* max divider */
+#endif
+}
+
+/* XXX Autopolling should be disabled during reads and writes per the
+ manual, but doing so currently generates recurvise LINKCHNG
+ attentions. */
+
+static uint16_t
+mii_read_register(t3_ether_t *sc, int phy, int index)
+{
+ uint32_t mode;
+ uint32_t comm, val;
+ int i;
+
+ mode = READCSR(sc, R_MI_MODE);
+#if 0 /* for now */
+ if (mode & M_MIMODE_POLLING) {
+ WRITECSR(sc, R_MI_MODE, mode & ~M_MIMODE_POLLING);
+ cfe_usleep(40);
+ }
+#endif
+
+ comm = (V_MICOMM_CMD_RD | V_MICOMM_PHY(phy) | V_MICOMM_REG(index)
+ | M_MICOMM_BUSY);
+ WRITECSR(sc, R_MI_COMM, comm);
+
+ for (i = 0; i < MII_MAX_RETRIES; i++) {
+ val = READCSR(sc, R_MI_COMM);
+ if ((val & M_MICOMM_BUSY) == 0)
+ break;
+ }
+ if (i == MII_MAX_RETRIES)
+ xprintf("%s: mii_read_register: MII always busy\n", t3_devname(sc));
+
+#if 0
+ if (mode & M_MIMODE_POLLING)
+ WRITECSR(sc, R_MI_MODE, mode);
+#endif
+
+ return G_MICOMM_DATA(val);
+}
+
+/* Register reads occasionally return spurious 0's. Verify a zero by
+ doing a second read, or spinning when a zero is "impossible". */
+static uint16_t
+mii_read_register_v(t3_ether_t *sc, int phy, int index, int spin)
+{
+ uint32_t val;
+
+ val = mii_read_register(sc, phy, index);
+ if (val == 0) {
+ do {
+ val = mii_read_register(sc, phy, index);
+ } while (spin && val == 0);
+ }
+ return val;
+}
+
+static void
+mii_write_register(t3_ether_t *sc, int phy, int index, uint16_t value)
+{
+ uint32_t mode;
+ uint32_t comm, val;
+ int i;
+
+ mode = READCSR(sc, R_MI_MODE);
+#if 0 /* for now */
+ if (mode & M_MIMODE_POLLING) {
+ WRITECSR(sc, R_MI_MODE, mode & ~M_MIMODE_POLLING);
+ cfe_usleep(40);
+ }
+#endif
+
+ comm = (V_MICOMM_CMD_WR | V_MICOMM_PHY(phy) | V_MICOMM_REG(index)
+ | V_MICOMM_DATA(value) | M_MICOMM_BUSY);
+ WRITECSR(sc, R_MI_COMM, comm);
+
+ for (i = 0; i < MII_MAX_RETRIES; i++) {
+ val = READCSR(sc, R_MI_COMM);
+ if ((val & M_MICOMM_BUSY) == 0)
+ break;
+ }
+ if (i == MII_MAX_RETRIES)
+ xprintf("%s: mii_write_register: MII always busy\n", t3_devname(sc));
+
+#if 0
+ if (mode & M_MIMODE_POLLING)
+ WRITECSR(sc, R_MI_MODE, mode);
+#endif
+}
+
+static int
+mii_probe(t3_ether_t *sc)
+{
+#if T3_AUTOPOLL /* With autopolling, the code below is not reliable. */
+ return 1; /* Guaranteed for integrated PHYs */
+#else
+ int i;
+ uint16_t id1, id2;
+
+ for (i = 0; i < 32; i++) {
+ id1 = mii_read_register(sc, i, MII_PHYIDR1);
+ id2 = mii_read_register(sc, i, MII_PHYIDR2);
+ if ((id1 != 0x0000 && id1 != 0xFFFF) ||
+ (id2 != 0x0000 && id2 != 0xFFFF)) {
+ if (id1 != id2) return i;
+ }
+ }
+ return -1;
+#endif
+}
+
+#if T3_DEBUG
+#define OUI_BCM 0x001018
+#define IDR_BCM 0x000818
+/* 5400: 4, 5401: 5, 5411: 6, 5421: e, 5701: 11 */
+
+static void
+mii_dump(t3_ether_t *sc, const char *label)
+{
+ int i;
+ uint16_t r;
+ uint32_t idr, part;
+
+ xprintf("%s, MII:\n", label);
+ idr = part = 0;
+
+ /* Required registers */
+ for (i = 0x0; i <= 0x6; ++i) {
+ r = mii_read_register(sc, sc->phy_addr, i);
+ xprintf(" REG%02X: %04X", i, r);
+ if (i == 3 || i == 6)
+ xprintf("\n");
+ if (i == MII_PHYIDR1) {
+ idr |= r << 6;
+ }
+ else if (i == MII_PHYIDR2) {
+ idr |= (r >> 10) & 0x3F;
+ part = (r >> 4) & 0x3F;
+ }
+ }
+
+ /* GMII extensions */
+ for (i = 0x9; i <= 0xA; ++i) {
+ r = mii_read_register(sc, sc->phy_addr, i);
+ xprintf(" REG%02X: %04X", i, r);
+ }
+ r = mii_read_register(sc, sc->phy_addr, 0xF);
+ xprintf(" REG%02X: %04X\n", 0xF, r);
+
+ /* Broadcom extensions (54xx family) */
+ if (idr == IDR_BCM) {
+ for (i = 0x10; i <= 0x14; i++) {
+ r = mii_read_register(sc, sc->phy_addr, i);
+ xprintf(" REG%02X: %04X", i, r);
+ }
+ xprintf("\n");
+ for (i = 0x18; i <= 0x1A; i++) {
+ r = mii_read_register(sc, sc->phy_addr, i);
+ xprintf(" REG%02X: %04X", i, r);
+ }
+ xprintf("\n");
+ }
+}
+#else
+#define mii_dump(sc,label)
+#endif
+
+static void
+mii_enable_interrupts(t3_ether_t *sc)
+{
+ mii_write_register(sc, sc->phy_addr, MII_IMR, ~M_INT_LINKCHNG);
+}
+
+
+/* For 5700/5701, LINKCHNG is read-only in the status register and
+ cleared by writing to CFGCHNG | SYNCCHNG. For the 5705
+ (empirically), LINKCHNG is cleared by writing a one, while CFGCHNG
+ and SYNCCHNG are unimplemented. Thus we can safely clear the
+ interrupt by writing ones to all the above bits. */
+
+#define M_LINKCHNG_CLR \
+ (M_EVT_LINKCHNG | M_MACSTAT_CFGCHNG | M_MACSTAT_SYNCCHNG)
+
+static int
+mii_poll(t3_ether_t *sc)
+{
+ uint32_t macstat;
+ uint16_t status, ability, xability;
+ uint16_t isr;
+
+ macstat = READCSR(sc, R_MAC_STATUS);
+ if ((macstat & (M_EVT_LINKCHNG | M_EVT_MIINT)) != 0)
+ WRITECSR(sc, R_MAC_STATUS, M_LINKCHNG_CLR);
+
+ /* BMSR has read-to-clear bits; read twice. */
+
+ status = mii_read_register(sc, sc->phy_addr, MII_BMSR);
+ status = mii_read_register_v(sc, sc->phy_addr, MII_BMSR, 1);
+ ability = mii_read_register_v(sc, sc->phy_addr, MII_ANLPAR, 0);
+ if (status & BMSR_1000BT_XSR)
+ xability = mii_read_register_v(sc, sc->phy_addr, MII_K1STSR, 0);
+ else
+ xability = 0;
+ isr = mii_read_register(sc, sc->phy_addr, MII_ISR);
+
+ if (status != sc->phy_status
+ || ability != sc->phy_ability || xability != sc->phy_xability) {
+#if T3_DEBUG
+ xprintf("[%04x]", isr);
+ xprintf((macstat & (M_EVT_LINKCHNG | M_EVT_MIINT)) != 0 ? "+" : "-");
+
+ if (status != sc->phy_status)
+ xprintf(" ST: %04x %04x", sc->phy_status, status);
+ if (ability != sc->phy_ability)
+ xprintf(" AB: %04x %04x", sc->phy_ability, ability);
+ if (xability != sc->phy_xability)
+ xprintf(" XA: %04x %04x", sc->phy_xability, xability);
+ xprintf("\n");
+#endif
+ sc->phy_status = status;
+ sc->phy_ability = ability;
+ sc->phy_xability = xability;
+ return 1;
+ }
+ else if ((macstat & (M_EVT_LINKCHNG | M_EVT_MIINT)) != 0) {
+ isr = mii_read_register(sc, sc->phy_addr, MII_ISR);
+ }
+ return 0;
+}
+
+static void
+mii_set_speed(t3_ether_t *sc, int speed)
+{
+ uint16_t control;
+
+ control = mii_read_register(sc, sc->phy_addr, MII_BMCR);
+
+ control &= ~(BMCR_ANENABLE | BMCR_RESTARTAN);
+ mii_write_register(sc, sc->phy_addr, MII_BMCR, control);
+ control &= ~(BMCR_SPEED0 | BMCR_SPEED1 | BMCR_DUPLEX);
+
+ switch (speed) {
+ case ETHER_SPEED_10HDX:
+ default:
+ break;
+ case ETHER_SPEED_10FDX:
+ control |= BMCR_DUPLEX;
+ break;
+ case ETHER_SPEED_100HDX:
+ control |= BMCR_SPEED100;
+ break;
+ case ETHER_SPEED_100FDX:
+ control |= BMCR_SPEED100 | BMCR_DUPLEX ;
+ break;
+ }
+
+ mii_write_register(sc, sc->phy_addr, MII_BMCR, control);
+}
+
+static void
+mii_autonegotiate(t3_ether_t *sc)
+{
+ uint16_t control, status, remote, xremote;
+ unsigned int timeout;
+ int linkspeed;
+ uint32_t mode;
+
+ linkspeed = ETHER_SPEED_UNKNOWN;
+
+ /* Read twice to clear latching bits */
+ status = mii_read_register(sc, sc->phy_addr, MII_BMSR);
+ status = mii_read_register_v(sc, sc->phy_addr, MII_BMSR, 1);
+ mii_dump(sc, "query PHY");
+
+ if ((status & (BMSR_AUTONEG | BMSR_LINKSTAT)) ==
+ (BMSR_AUTONEG | BMSR_LINKSTAT))
+ control = mii_read_register(sc, sc->phy_addr, MII_BMCR);
+ else {
+ for (timeout = 4*CFE_HZ; timeout > 0; timeout -= CFE_HZ/2) {
+ status = mii_read_register(sc, sc->phy_addr, MII_BMSR);
+ if ((status & BMSR_ANCOMPLETE) != 0 || timeout <= 0)
+ break;
+ cfe_sleep(CFE_HZ/2);
+ }
+ }
+
+ remote = mii_read_register_v(sc, sc->phy_addr, MII_ANLPAR, 0);
+
+ /* XXX Empirically, it appears best to set/keep PortMode non-null to
+ get STATUS_LINKCHNG assertions. */
+ mode = READCSR(sc, R_MAC_MODE);
+
+ xprintf("%s: Link speed: ", t3_devname(sc));
+ if ((status & BMSR_ANCOMPLETE) != 0) {
+ /* A link partner was negogiated... */
+
+ if (status & BMSR_1000BT_XSR)
+ xremote = mii_read_register_v(sc, sc->phy_addr, MII_K1STSR, 0);
+ else
+ xremote = 0;
+
+ mode &= ~(M_MACM_PORTMODE | M_MACM_HALFDUPLEX);
+
+ if ((xremote & K1STSR_LP1KFD) != 0) {
+ xprintf("1000BaseT FDX\n");
+ linkspeed = ETHER_SPEED_1000FDX;
+ mode |= V_MACM_PORTMODE(K_MACM_PORTMODE_GMII);
+ }
+ else if ((xremote & K1STSR_LP1KHD) != 0) {
+ xprintf("1000BaseT HDX\n");
+ linkspeed = ETHER_SPEED_1000HDX;
+ mode |= V_MACM_PORTMODE(K_MACM_PORTMODE_GMII) | M_MACM_HALFDUPLEX;
+ }
+ else if ((remote & ANLPAR_TXFD) != 0) {
+ xprintf("100BaseT FDX\n");
+ linkspeed = ETHER_SPEED_100FDX;
+ mode |= V_MACM_PORTMODE(K_MACM_PORTMODE_MII);
+ }
+ else if ((remote & ANLPAR_TXHD) != 0) {
+ xprintf("100BaseT HDX\n");
+ linkspeed = ETHER_SPEED_100HDX;
+ mode |= V_MACM_PORTMODE(K_MACM_PORTMODE_MII) | M_MACM_HALFDUPLEX;
+ }
+ else if ((remote & ANLPAR_10FD) != 0) {
+ xprintf("10BaseT FDX\n");
+ linkspeed = ETHER_SPEED_10FDX;
+ mode |= V_MACM_PORTMODE(K_MACM_PORTMODE_MII);
+ }
+ else if ((remote & ANLPAR_10HD) != 0) {
+ xprintf("10BaseT HDX\n");
+ linkspeed = ETHER_SPEED_10HDX;
+ mode |= V_MACM_PORTMODE(K_MACM_PORTMODE_MII) | M_MACM_HALFDUPLEX;
+ }
+
+ WRITECSR(sc, R_MAC_MODE, mode);
+ }
+ else {
+ /* no link partner convergence */
+ xprintf("Unknown\n");
+ linkspeed = ETHER_SPEED_UNKNOWN;
+ remote = xremote = 0;
+ if (G_MACM_PORTMODE(mode) == K_MACM_PORTMODE_NONE) {
+ /* Keep any previous port mode as the one most likely to reappear.
+ Otherwise, choose one, and 10/100FDX is more likely. */
+ mode |= V_MACM_PORTMODE(K_MACM_PORTMODE_MII);
+ WRITECSR(sc, R_MAC_MODE, mode);
+ }
+ }
+
+ /* clear latching bits, XXX fix flakey reads */
+ status = mii_read_register_v(sc, sc->phy_addr, MII_BMSR, 1);
+ (void)mii_read_register(sc, sc->phy_addr, MII_ISR);
+
+ sc->phy_status = status;
+ sc->phy_ability = remote;
+ sc->phy_xability = xremote;
+
+ mii_dump(sc, "final PHY");
+}
+
+
+static void
+t3_clear(t3_ether_t *sc, unsigned reg, uint32_t mask)
+{
+ uint32_t val;
+ int timeout;
+
+ val = READCSR(sc, reg);
+ val &= ~mask;
+ WRITECSR(sc, reg, val);
+ val = READCSR(sc, reg);
+
+ for (timeout = 4000; (val & mask) != 0 && timeout > 0; timeout -= 100) {
+ cfe_usleep(100);
+ val = READCSR(sc, reg);
+ }
+ if (timeout <= 0)
+ xprintf("%s: cannot clear %04X/%08X\n", t3_devname(sc), reg, mask);
+}
+
+
+/* The following functions collectively implement the recommended
+ BCM5700 Initialization Procedure (Section 8: Device Control) */
+
+static int
+t3_coldreset(t3_ether_t *sc)
+{
+ pcireg_t cmd;
+ pcireg_t bhlc, subsysid;
+ pcireg_t bar0, bar1;
+ pcireg_t cmdx;
+ uint32_t mhc, mcr, mcfg;
+ uint32_t mode;
+ int timeout;
+
+ /* Steps 1-18 */
+ /* Enable memory, also clear R/WC status bits (1) */
+ cmd = pci_conf_read(sc->tag, PCI_COMMAND_STATUS_REG);
+ cmd |= PCI_COMMAND_MEM_ENABLE | PCI_COMMAND_MASTER_ENABLE;
+ pci_conf_write(sc->tag, PCI_COMMAND_STATUS_REG, cmd);
+
+ /* Clear and disable INTA output. (2) */
+ mhc = READCSR(sc, R_MISC_HOST_CTRL);
+ mhc |= M_MHC_MASKPCIINT | M_MHC_CLEARINTA;
+ WRITECSR(sc, R_MISC_HOST_CTRL, mhc);
+
+ /* Save some config registers modified by core clock reset (3). */
+ bhlc = pci_conf_read(sc->tag, PCI_BHLC_REG);
+ subsysid = pci_conf_read(sc->tag, PCI_SUBSYS_ID_REG);
+ /* Empirically, these are clobbered too. */
+ bar0 = pci_conf_read(sc->tag, PCI_MAPREG(0));
+ bar1 = pci_conf_read(sc->tag, PCI_MAPREG(1));
+
+ /* Reset the core clocks (4, 5). */
+ mcfg = READCSR(sc, R_MISC_CFG);
+ mcfg |= M_MCFG_CORERESET;
+ WRITECSR(sc, R_MISC_CFG, mcfg);
+ cfe_usleep(100); /* 100 usec delay */
+
+ /* NB: Until the BARs are restored and reenabled, only PCI
+ configuration reads and writes will succeed. */
+
+ /* Reenable MAC memory (7) */
+ pci_conf_write(sc->tag, PCI_MAPREG(0), bar0);
+ pci_conf_write(sc->tag, PCI_MAPREG(1), bar1);
+ (void)pci_conf_read(sc->tag, PCI_MAPREG(1)); /* push */
+ pci_conf_write(sc->tag, PCI_COMMAND_STATUS_REG, cmd);
+ (void)pci_conf_read(sc->tag, PCI_COMMAND_STATUS_REG); /* push */
+
+ /* Undo some of the resets (6) */
+ mhc = READCSR(sc, R_MISC_HOST_CTRL);
+ mhc |= M_MHC_MASKPCIINT;
+ WRITECSR(sc, R_MISC_HOST_CTRL, mhc);
+
+ /* Verify that core clock resets completed and autocleared. */
+ mcfg = READCSR(sc, R_MISC_CFG);
+ if ((mcfg & M_MCFG_CORERESET) != 0) {
+ xprintf("bcm5700: core clocks stuck in reset\n");
+ }
+
+ /* Configure PCI-X (8) */
+ if (sc->device != K_PCI_ID_BCM5705) {
+ cmdx = pci_conf_read(sc->tag, PCI_PCIX_CMD_REG);
+ cmdx &= ~PCIX_CMD_RLXORDER_ENABLE;
+ pci_conf_write(sc->tag, PCI_PCIX_CMD_REG, cmdx);
+ }
+
+ /* Enable memory arbiter (9) */
+ mode = READCSR(sc, R_MEM_MODE);
+ mode |= M_MAM_ENABLE; /* enable memory arbiter */
+ WRITECSR(sc, R_MEM_MODE, mode);
+
+ /* Assume no external SRAM for now (10) */
+
+ /* Set up MHC for endianness and write enables (11-15) */
+ mhc = READCSR(sc, R_MISC_HOST_CTRL);
+#ifdef __MIPSEL
+ mhc |= M_MHC_ENWORDSWAP; /* XXX check this */
+#endif
+#ifdef __MIPSEB
+ /* Since we use match-bits for Direct PCI access, don't swap bytes. */
+#if PIOSWAP
+ mhc |= M_MHC_ENWORDSWAP;
+#endif
+#endif
+ mhc |= M_MHC_ENINDIRECT | M_MHC_ENPCISTATERW | M_MHC_ENCLKCTRLRW;
+ WRITECSR(sc, R_MISC_HOST_CTRL, mhc);
+
+ /* Set byte swapping (16, 17) */
+ mcr = READCSR(sc, R_MODE_CTRL);
+#ifdef __MIPSEL
+ mcr &= ~M_MCTL_BSWAPDATA;
+ mcr |= M_MCTL_WSWAPCTRL | M_MCTL_WSWAPDATA; /* XXX check this */
+#endif
+#ifdef __MIPSEB
+ mcr &= ~(M_MCTL_BSWAPCTRL | M_MCTL_BSWAPDATA);
+ mcr |= M_MCTL_WSWAPCTRL | M_MCTL_WSWAPDATA;
+#endif
+ WRITECSR(sc, R_MODE_CTRL, mcr);
+
+ /* Disable PXE restart, wait for firmware (18, 19) */
+ if (READMEM(sc, A_PXE_MAILBOX) != T3_MAGIC_NUMBER) {
+ /* Apparently, if the magic number is already set, firmware
+ ignores this attempted handshake. */
+ WRITEMEM(sc, A_PXE_MAILBOX, T3_MAGIC_NUMBER);
+ for (timeout = CFE_HZ; timeout > 0; timeout -= CFE_HZ/10) {
+ if (READMEM(sc, A_PXE_MAILBOX) == ~T3_MAGIC_NUMBER)
+ break;
+ cfe_sleep(CFE_HZ/10);
+ }
+ if (READMEM(sc, A_PXE_MAILBOX) != ~T3_MAGIC_NUMBER)
+ xprintf("bcm5700: no firmware PXE rendevous\n");
+ }
+ else
+ xprintf("bcm5700: PXE magic number already set\n");
+
+ /* Clear Ethernet MAC Mode (20) */
+ WRITECSR(sc, R_MAC_MODE, 0x00000000);
+
+ /* Restore remaining config registers (21) */
+ pci_conf_write(sc->tag, PCI_BHLC_REG, bhlc);
+ pci_conf_write(sc->tag, PCI_SUBSYS_ID_REG, subsysid);
+
+ return 0;
+}
+
+/* XXX Not clear that the following is useful. */
+static int
+t3_warmreset(t3_ether_t *sc)
+{
+ uint32_t mode;
+
+ /* Enable memory arbiter (9) */
+ mode = READCSR(sc, R_MEM_MODE);
+ mode |= M_MAM_ENABLE; /* enable memory arbiter */
+ WRITECSR(sc, R_MEM_MODE, mode);
+
+ /* Clear Ethernet MAC Mode (20) */
+ WRITECSR(sc, R_MAC_MODE, 0x00000000);
+
+ return 0;
+}
+
+
+static int
+t3_init_registers(t3_ether_t *sc)
+{
+ unsigned offset;
+ uint32_t dmac, mcr, mcfg;
+
+ /* Steps 22-29 */
+
+ /* Clear MAC statistics block (22) */
+ for (offset = A_MAC_STATS; offset < A_MAC_STATS+L_MAC_STATS; offset += 4) {
+ WRITEMEM(sc, offset, 0);
+ }
+
+ /* Clear driver status memory region (23) */
+ /* ASSERT (sizeof(t3_status_t) == L_MAC_STATUS) */
+ memset((uint8_t *)sc->status, 0, sizeof(t3_status_t));
+
+ /* Set up PCI DMA control (24) */
+ dmac = READCSR(sc, R_DMA_RW_CTRL);
+ dmac &= ~(M_DMAC_RDCMD | M_DMAC_WRCMD | M_DMAC_MINDMA);
+ dmac |= V_DMAC_RDCMD(K_PCI_MEMRD) | V_DMAC_WRCMD(K_PCI_MEMWR);
+ switch (sc->device) {
+ case K_PCI_ID_BCM5700:
+ case K_PCI_ID_BCM5701:
+ case K_PCI_ID_BCM5702:
+ dmac |= V_DMAC_MINDMA(0xF); /* "Recommended" */
+ break;
+ default:
+ dmac |= V_DMAC_MINDMA(0x0);
+ break;
+ }
+ WRITECSR(sc, R_DMA_RW_CTRL, dmac);
+
+ /* Set DMA byte swapping (25) - XXX repeat of (17) */
+ mcr = READCSR(sc, R_MODE_CTRL);
+#ifdef __MIPSEL
+ mcr &= ~M_MCTL_BSWAPDATA;
+ mcr |= M_MCTL_WSWAPCTRL | M_MCTL_WSWAPDATA; /* XXX check this */
+#endif
+#ifdef __MIPSEB
+ mcr &= ~(M_MCTL_BSWAPCTRL | M_MCTL_BSWAPDATA);
+ mcr |= M_MCTL_WSWAPCTRL | M_MCTL_WSWAPDATA;
+#endif
+ WRITECSR(sc, R_MODE_CTRL, mcr);
+
+ /* Configure host rings (26) */
+ mcr |= M_MCTL_HOSTBDS;
+ WRITECSR(sc, R_MODE_CTRL, mcr);
+
+ /* Indicate driver ready, disable checksums (27, 28) */
+ mcr |= M_MCTL_HOSTUP;
+ mcr |= (M_MCTL_NOTXPHSUM | M_MCTL_NORXPHSUM);
+ WRITECSR(sc, R_MODE_CTRL, mcr);
+
+ /* Configure timer (29) */
+ mcfg = READCSR(sc, R_MISC_CFG);
+ mcfg &= ~M_MCFG_PRESCALER;
+ mcfg |= V_MCFG_PRESCALER(66-1); /* 66 MHz */
+ WRITECSR(sc, R_MISC_CFG, mcfg);
+
+ return 0;
+}
+
+static int
+t3_init_pools(t3_ether_t *sc)
+{
+ uint32_t mode;
+ int timeout;
+
+ /* Steps 30-36. These use "recommended" settings (p 150) */
+
+ /* Configure the MAC memory pool (30) */
+ if (sc->device != K_PCI_ID_BCM5705) {
+ WRITECSR(sc, R_BMGR_MBUF_BASE, A_BUFFER_POOL);
+ WRITECSR(sc, R_BMGR_MBUF_LEN, L_BUFFER_POOL);
+ }
+ else {
+ /* Note: manual appears to recommend not even writing these (?) */
+ /* WRITECSR(sc, R_BMGR_MBUF_BASE, A_RXMBUF); */
+ /* WRITECSR(sc, R_BMGR_MBUF_LEN, 0x8000); */
+ }
+
+ /* Configure the MAC DMA resource pool (31) */
+ WRITECSR(sc, R_BMGR_DMA_BASE, A_DMA_DESCS);
+ WRITECSR(sc, R_BMGR_DMA_LEN, L_DMA_DESCS);
+
+ /* Configure the MAC memory watermarks (32) */
+ WRITECSR(sc, R_BMGR_MBUF_DMA_LOW, 0x50);
+ WRITECSR(sc, R_BMGR_MBUF_RX_LOW, 0x20);
+ WRITECSR(sc, R_BMGR_MBUF_HIGH, 0x60);
+
+ /* Configure the DMA resource watermarks (33) */
+ WRITECSR(sc, R_BMGR_DMA_LOW, 5);
+ WRITECSR(sc, R_BMGR_DMA_HIGH, 10);
+
+ /* Enable the buffer manager (34, 35) */
+ mode = READCSR(sc, R_BMGR_MODE);
+ mode |= (M_BMODE_ENABLE | M_BMODE_MBUFLOWATTN);
+ WRITECSR(sc, R_BMGR_MODE, mode);
+ for (timeout = CFE_HZ/2; timeout > 0; timeout -= CFE_HZ/10) {
+ mode = READCSR(sc, R_BMGR_MODE);
+ if ((mode & M_BMODE_ENABLE) != 0)
+ break;
+ cfe_sleep(CFE_HZ/10);
+ }
+ if ((mode & M_BMODE_ENABLE) == 0)
+ xprintf("bcm5700: buffer manager not enabled\n");
+
+ /* Enable internal queues (36) */
+ WRITECSR(sc, R_FTQ_RESET, 0xFFFFFFFF);
+ (void)READCSR(sc, R_FTQ_RESET); /* push */
+ cfe_sleep(1);
+ WRITECSR(sc, R_FTQ_RESET, 0x00000000);
+
+ return 0;
+}
+
+static int
+t3_init_rings(t3_ether_t *sc)
+{
+ unsigned rcbp;
+ int i;
+
+ /* Steps 37-46 */
+
+ /* Initialize RCBs for Standard Receive Buffer Ring (37) */
+ WRITECSR(sc, R_STD_RCV_BD_RCB+RCB_HOST_ADDR_HIGH, 0);
+ WRITECSR(sc, R_STD_RCV_BD_RCB+RCB_HOST_ADDR_LOW, PTR_TO_PCI(sc->rxp_std));
+ WRITECSR(sc, R_STD_RCV_BD_RCB+RCB_CTRL, V_RCB_MAXLEN(ETH_PKTBUF_LEN));
+ WRITECSR(sc, R_STD_RCV_BD_RCB+RCB_NIC_ADDR, A_STD_RCV_RINGS);
+
+ /* Disable RCBs for Jumbo and Mini Receive Buffer Rings (38,39) */
+ WRITECSR(sc, R_JUMBO_RCV_BD_RCB+RCB_CTRL,
+ RCB_FLAG_USE_EXT_RCV_BD | RCB_FLAG_RING_DISABLED);
+ WRITECSR(sc, R_JUMBO_RCV_BD_RCB+RCB_NIC_ADDR, A_JUMBO_RCV_RINGS);
+ WRITECSR(sc, R_MINI_RCV_BD_RCB+RCB_CTRL, RCB_FLAG_RING_DISABLED);
+ WRITECSR(sc, R_MINI_RCV_BD_RCB+RCB_NIC_ADDR, 0xe000);
+
+ /* Set BD ring replenish thresholds (40) */
+ WRITECSR(sc, R_MINI_RCV_BD_THRESH, 128);
+#if T3_BRINGUP
+ WRITECSR(sc, R_STD_RCV_BD_THRESH, 1);
+#else
+ WRITECSR(sc, R_STD_RCV_BD_THRESH, 25);
+#endif
+ WRITECSR(sc, R_JUMBO_RCV_BD_THRESH, 16);
+
+ /* Disable unused send producer rings 2-16 (41) */
+ for (rcbp = A_SND_RCB(1); rcbp <= A_SND_RCB(16); rcbp += RCB_SIZE)
+ WRITEMEM(sc, rcbp+RCB_CTRL, RCB_FLAG_RING_DISABLED);
+
+ /* Initialize send producer index registers (42) */
+ for (i = 1; i <= TXP_MAX_RINGS; i++) {
+ WRITEMBOX(sc, R_SND_BD_PI(i), 0);
+ WRITEMBOX(sc, R_SND_BD_NIC_PI(i), 0);
+ }
+
+ /* Initialize send producer ring 1 (43) */
+ WRITEMEM(sc, A_SND_RCB(1)+RCB_HOST_ADDR_HIGH, 0);
+ WRITEMEM(sc, A_SND_RCB(1)+RCB_HOST_ADDR_LOW, PTR_TO_PCI(sc->txp_1));
+ WRITEMEM(sc, A_SND_RCB(1)+RCB_CTRL, V_RCB_MAXLEN(TXP_RING_ENTRIES));
+ WRITEMEM(sc, A_SND_RCB(1)+RCB_NIC_ADDR, A_SND_RINGS);
+
+ /* Disable unused receive return rings (44) */
+ for (rcbp = A_RTN_RCB(1); rcbp <= A_RTN_RCB(16); rcbp += RCB_SIZE)
+ WRITEMEM(sc, rcbp+RCB_CTRL, RCB_FLAG_RING_DISABLED);
+
+ /* Initialize receive return ring 1 (45) */
+ WRITEMEM(sc, A_RTN_RCB(1)+RCB_HOST_ADDR_HIGH, 0);
+ WRITEMEM(sc, A_RTN_RCB(1)+RCB_HOST_ADDR_LOW, PTR_TO_PCI(sc->rxr_1));
+ WRITEMEM(sc, A_RTN_RCB(1)+RCB_CTRL, V_RCB_MAXLEN(sc->rxr_entries));
+ WRITEMEM(sc, A_RTN_RCB(1)+RCB_NIC_ADDR, 0x0000);
+
+ /* Initialize receive producer ring mailboxes (46) */
+ WRITEMBOX(sc, R_RCV_BD_STD_PI, 0);
+ WRITEMBOX(sc, R_RCV_BD_JUMBO_PI, 0);
+ WRITEMBOX(sc, R_RCV_BD_MINI_PI, 0);
+
+ return 0;
+}
+
+static int
+t3_configure_mac(t3_ether_t *sc)
+{
+ uint32_t low, high;
+ uint32_t seed;
+ int i;
+
+ /* Steps 47-52 */
+
+ /* Configure the MAC unicast address (47) */
+ high = (sc->hwaddr[0] << 8) | (sc->hwaddr[1]);
+ low = ((sc->hwaddr[2] << 24) | (sc->hwaddr[3] << 16)
+ | (sc->hwaddr[4] << 8) | sc->hwaddr[5]);
+ /* For now, use a single MAC address */
+ WRITECSR(sc, R_MAC_ADDR1_HIGH, high); WRITECSR(sc, R_MAC_ADDR1_LOW, low);
+ WRITECSR(sc, R_MAC_ADDR2_HIGH, high); WRITECSR(sc, R_MAC_ADDR2_LOW, low);
+ WRITECSR(sc, R_MAC_ADDR3_HIGH, high); WRITECSR(sc, R_MAC_ADDR3_LOW, low);
+ WRITECSR(sc, R_MAC_ADDR4_HIGH, high); WRITECSR(sc, R_MAC_ADDR4_LOW, low);
+
+ /* Configure the random backoff seed (48) */
+ seed = 0;
+ for (i = 0; i < 6; i++)
+ seed += sc->hwaddr[i];
+ seed &= 0x3FF;
+ WRITECSR(sc, R_TX_BACKOFF, seed);
+
+ /* Configure the MTU (49) */
+ WRITECSR(sc, R_RX_MTU, MAX_ETHER_PACK+VLAN_TAG_LEN);
+
+ /* Configure the tx IPG (50) */
+ WRITECSR(sc, R_TX_LENS,
+ V_TXLEN_SLOT(0x20) | V_TXLEN_IPG(0x6) | V_TXLEN_IPGCRS(0x2));
+
+ /* Configure the default rx return ring 1 (51) */
+ WRITECSR(sc, R_RX_RULES_CFG, V_RULESCFG_DEFAULT(1));
+
+ /* Configure the receive lists and enable statistics (52) */
+ WRITECSR(sc, R_RCV_LIST_CFG,
+ V_LISTCFG_GROUP(1) | V_LISTCFG_ACTIVE(1) | V_LISTCFG_BAD(1));
+ /* was V_LISTCFG_DEFAULT(1) | V_LISTCFG_ACTIVE(16) | V_LISTCFG_BAD(1) */
+
+ return 0;
+}
+
+static int
+t3_enable_stats(t3_ether_t *sc)
+{
+ uint32_t ctrl;
+
+ /* Steps 53-56 */
+
+ /* Enable rx stats (53,54) */
+ WRITECSR(sc, R_RCV_LIST_STATS_ENB, 0xFFFFFF);
+ ctrl = READCSR(sc, R_RCV_LIST_STATS_CTRL);
+ ctrl |= M_STATS_ENABLE;
+ WRITECSR(sc, R_RCV_LIST_STATS_CTRL, ctrl);
+
+ /* Enable tx stats (55,56) */
+ WRITECSR(sc, R_SND_DATA_STATS_ENB, 0xFFFFFF);
+ ctrl = READCSR(sc, R_SND_DATA_STATS_CTRL);
+ ctrl |= (M_STATS_ENABLE | M_STATS_FASTUPDATE);
+ WRITECSR(sc, R_SND_DATA_STATS_CTRL, ctrl);
+
+ return 0;
+}
+
+static int
+t3_init_coalescing(t3_ether_t *sc)
+{
+ uint32_t mode;
+ int timeout;
+
+ /* Steps 57-68 */
+
+ /* Disable the host coalescing engine (57, 58) */
+ WRITECSR(sc, R_HOST_COAL_MODE, 0);
+ for (timeout = CFE_HZ/2; timeout > 0; timeout -= CFE_HZ/10) {
+ mode = READCSR(sc, R_HOST_COAL_MODE);
+ if (mode == 0)
+ break;
+ cfe_sleep(CFE_HZ/10);
+ }
+ if (mode != 0)
+ xprintf("bcm5700: coalescing engine not disabled\n");
+
+ /* Set coalescing parameters (59-62) */
+#if T3_BRINGUP
+ WRITECSR(sc, R_RCV_COAL_TICKS, 0);
+ WRITECSR(sc, R_RCV_COAL_MAX_CNT, 1);
+#else
+ WRITECSR(sc, R_RCV_COAL_TICKS, 150);
+ WRITECSR(sc, R_RCV_COAL_MAX_CNT, 10);
+#endif
+ WRITECSR(sc, R_RCV_COAL_INT_TICKS, 0);
+ WRITECSR(sc, R_RCV_COAL_INT_CNT, 0);
+#if T3_BRINGUP
+ WRITECSR(sc, R_SND_COAL_TICKS, 0);
+ WRITECSR(sc, R_SND_COAL_MAX_CNT, 1);
+#else
+ WRITECSR(sc, R_SND_COAL_TICKS, 150);
+ WRITECSR(sc, R_SND_COAL_MAX_CNT, 10);
+#endif
+ WRITECSR(sc, R_SND_COAL_INT_TICKS, 0);
+ WRITECSR(sc, R_SND_COAL_INT_CNT, 0);
+
+ /* Initialize host status block address (63) */
+ WRITECSR(sc, R_STATUS_HOST_ADDR, 0);
+ WRITECSR(sc, R_STATUS_HOST_ADDR+4, PTR_TO_PCI(sc->status));
+
+ /* Initialize host statistics block address (64) */
+ WRITECSR(sc, R_STATS_HOST_ADDR, 0);
+ WRITECSR(sc, R_STATS_HOST_ADDR+4, PTR_TO_PCI(sc->stats));
+
+ /* Set statistics block NIC address and tick count (65, 66) */
+ WRITECSR(sc, R_STATS_TICKS, 1000000);
+ WRITECSR(sc, R_STATS_BASE_ADDR, A_MAC_STATS);
+
+ /* Set status block NIC address (67) */
+ WRITECSR(sc, R_STATUS_BASE_ADDR, A_MAC_STATUS);
+
+ /* Enable the host coalescing engine (68) */
+ WRITECSR(sc, R_HOST_COAL_MODE, M_HCM_ENABLE);
+
+ return 0;
+}
+
+static int
+t3_init_dma(t3_ether_t *sc)
+{
+ uint32_t mode;
+
+ /* Steps 69-87 */
+
+ /* Enable receive BD completion, placement, and selector blocks (69-71) */
+ WRITECSR(sc, R_RCV_BD_COMP_MODE, M_MODE_ENABLE | M_MODE_ATTNENABLE);
+ WRITECSR(sc, R_RCV_LIST_MODE, M_MODE_ENABLE);
+ if (sc->device != K_PCI_ID_BCM5705) {
+ WRITECSR(sc, R_RCV_LIST_SEL_MODE, M_MODE_ENABLE | M_MODE_ATTNENABLE);
+ }
+
+ /* Enable DMA engines, enable and clear statistics (72, 73) */
+ mode = READCSR(sc, R_MAC_MODE);
+ mode |= (M_MACM_FHDEENB | M_MACM_RDEENB | M_MACM_TDEENB |
+ M_MACM_RXSTATSENB | M_MACM_RXSTATSCLR |
+ M_MACM_TXSTATSENB | M_MACM_TXSTATSCLR);
+#if T3_AUTOPOLL
+ mode |= V_MACM_PORTMODE(K_MACM_PORTMODE_MII);
+#endif
+
+ WRITECSR(sc, R_MAC_MODE, mode);
+
+#if T3_AUTOPOLL
+ WRITECSR(sc, R_MISC_LOCAL_CTRL, M_MLCTL_INTATTN);
+#endif
+
+ /* Configure GPIOs (74) - skipped */
+
+ /* Clear interrupt mailbox (75) */
+ WRITEMBOX(sc, R_INT_MBOX(0), 0);
+
+ /* Enable DMA completion block (76) */
+ if (sc->device != K_PCI_ID_BCM5705) {
+ WRITECSR(sc, R_DMA_COMP_MODE, M_MODE_ENABLE);
+ }
+
+ /* Configure write and read DMA modes (77, 78) */
+ WRITECSR(sc, R_WR_DMA_MODE, M_MODE_ENABLE | M_ATTN_ALL);
+ WRITECSR(sc, R_RD_DMA_MODE, M_MODE_ENABLE | M_ATTN_ALL);
+
+ return 0;
+}
+
+static int
+t3_init_enable(t3_ether_t *sc)
+{
+ uint32_t mhc;
+ uint32_t pmcs;
+#if T3_AUTOPOLL
+ uint32_t mode, mask;
+#else
+ int i;
+#endif
+
+ /* Steps 79-97 */
+
+ /* Enable completion functional blocks (79-82) */
+ WRITECSR(sc, R_RCV_COMP_MODE, M_MODE_ENABLE | M_MODE_ATTNENABLE);
+ if (sc->device != K_PCI_ID_BCM5705) {
+ WRITECSR(sc, R_MBUF_FREE_MODE, M_MODE_ENABLE);
+ }
+ WRITECSR(sc, R_SND_DATA_COMP_MODE, M_MODE_ENABLE);
+ WRITECSR(sc, R_SND_BD_COMP_MODE, M_MODE_ENABLE | M_MODE_ATTNENABLE);
+
+ /* Enable initiator functional blocks (83-86) */
+ WRITECSR(sc, R_RCV_BD_INIT_MODE, M_MODE_ENABLE | M_MODE_ATTNENABLE);
+ WRITECSR(sc, R_RCV_DATA_INIT_MODE, M_MODE_ENABLE | M_RCVINITMODE_RTNSIZE);
+ WRITECSR(sc, R_SND_DATA_MODE, M_MODE_ENABLE);
+ WRITECSR(sc, R_SND_BD_INIT_MODE, M_MODE_ENABLE | M_MODE_ATTNENABLE);
+
+ /* Enable the send BD selector (87) */
+ WRITECSR(sc, R_SND_BD_SEL_MODE, M_MODE_ENABLE | M_MODE_ATTNENABLE);
+
+ /* Download firmware (88) - skipped */
+
+ /* Enable the MAC (89,90) */
+ WRITECSR(sc, R_TX_MODE, M_MODE_ENABLE); /* optional flow control */
+ WRITECSR(sc, R_RX_MODE, M_MODE_ENABLE); /* other options */
+
+ /* Disable auto-polling (91) */
+ mii_access_init(sc);
+
+ /* Configure power state (92) */
+ pmcs = READCSR(sc, PCI_PMCSR_REG);
+ pmcs &= ~PCI_PMCSR_STATE_MASK;
+ pmcs |= PCI_PMCSR_STATE_D0;
+ WRITECSR(sc, PCI_PMCSR_REG, pmcs);
+
+#if T3_AUTOPOLL
+ /* Program hardware LED control (93) */
+ WRITECSR(sc, R_MAC_LED_CTRL, 0x00); /* LEDs at PHY layer */
+#endif
+
+#if T3_AUTOPOLL
+ /* Ack/clear link change events */
+ WRITECSR(sc, R_MAC_STATUS, M_LINKCHNG_CLR);
+ WRITECSR(sc, R_MI_STATUS, 0);
+
+ /* Enable autopolling */
+ mode = READCSR(sc, R_MI_MODE);
+ mode |= M_MIMODE_POLLING | 0x000c000;
+ WRITECSR(sc, R_MI_MODE, mode);
+
+ /* Enable link state attentions */
+ mask = READCSR(sc, R_MAC_EVENT_ENB);
+ mask |= M_EVT_LINKCHNG;
+ WRITECSR(sc, R_MAC_EVENT_ENB, mask);
+#else
+ /* Initialize link (94) */
+ WRITECSR(sc, R_MI_STATUS, M_MISTAT_LINKED);
+
+ /* Start autonegotiation (95) - see t3_initlink below */
+
+ /* Setup multicast filters (96) */
+ for (i = 0; i < 4; i++)
+ WRITECSR(sc, R_MAC_HASH(i), 0);
+#endif /* T3_AUTOPOLL */
+
+ /* Enable interrupts (97) */
+ mhc = READCSR(sc, R_MISC_HOST_CTRL);
+ mhc &= ~M_MHC_MASKPCIINT;
+ WRITECSR(sc, R_MISC_HOST_CTRL, mhc);
+
+ return 0;
+}
+
+
+static void
+t3_initlink(t3_ether_t *sc)
+{
+ uint32_t mcr;
+
+ sc->phy_addr = mii_probe(sc);
+ if (sc->phy_addr < 0) {
+ xprintf("%s: no PHY found\n", t3_devname(sc));
+ return;
+ }
+#if T3_DEBUG
+ xprintf("%s: PHY addr %d\n", t3_devname(sc), sc->phy_addr);
+#endif
+ if (1) /* XXX Support only autonegotiation for now */
+ mii_autonegotiate(sc);
+ else
+ mii_set_speed(sc, ETHER_SPEED_10HDX);
+
+ mii_enable_interrupts(sc);
+
+ mcr = READCSR(sc, R_MODE_CTRL);
+ mcr |= M_MCTL_MACINT;
+ WRITECSR(sc, R_MODE_CTRL, mcr);
+
+ sc->mii_polling = 0;
+ sc->phy_change = 0;
+}
+
+static void
+t3_shutdownlink(t3_ether_t *sc)
+{
+ uint32_t mcr;
+
+ mcr = READCSR(sc, R_MODE_CTRL);
+ mcr &= ~M_MCTL_MACINT;
+ WRITECSR(sc, R_MODE_CTRL, mcr);
+
+ WRITECSR(sc, R_MAC_EVENT_ENB, 0);
+
+ /* The manual is fuzzy about what to do with the PHY at this
+ point. Empirically, resetting the 5705 PHY (but not others)
+ will cause it to get stuck in 10/100 MII mode. */
+ if (sc->device != K_PCI_ID_BCM5705)
+ mii_write_register(sc, sc->phy_addr, MII_BMCR, BMCR_RESET);
+
+ sc->mii_polling = 0;
+ sc->phy_change = 0;
+}
+
+
+static void
+t3_hwinit(t3_ether_t *sc)
+{
+ if (sc->state != eth_state_on) {
+
+ if (sc->state == eth_state_uninit) {
+ WRITECSR(sc, R_MEMWIN_BASE_ADDR, 0); /* Default memory window */
+ t3_coldreset(sc);
+ }
+ else
+ t3_warmreset(sc);
+
+ t3_init_registers(sc);
+ t3_init_pools(sc);
+ t3_init_rings(sc);
+ t3_configure_mac(sc);
+ t3_enable_stats(sc);
+ t3_init_coalescing(sc);
+ t3_init_dma(sc);
+ t3_init_enable(sc);
+#if T3_DEBUG
+ dumpcsrs(sc, "end init");
+#else
+ (void)dumpcsrs;
+#endif
+
+ eeprom_access_init(sc);
+#if T3_DEBUG
+ {
+ uint32_t eeprom[0x100/4];
+ int i;
+
+ cfe_sleep(1);
+ /* XXX Apparently a few reads can be required to get the
+ AutoAccess logic into a good state. ??? */
+ for (i = 0; i < 4; i++) {
+ eeprom_read_range(sc, 0, 4, eeprom);
+ }
+
+ eeprom_read_range(sc, 0, sizeof(eeprom), eeprom);
+ eeprom_dump_range("Boot Strap", eeprom, 0x00, 20);
+ eeprom_dump_range("Manufacturing Info", eeprom, 0x74, 140);
+ }
+#else
+ (void)eeprom_read_range;
+ (void)eeprom_dump_range;
+#endif
+
+ t3_initlink(sc);
+
+ sc->state = eth_state_off;
+ }
+}
+
+static void
+t3_hwshutdown(t3_ether_t *sc)
+{
+ /* Receive path shutdown */
+ t3_clear(sc, R_RX_MODE, M_MODE_ENABLE);
+ t3_clear(sc, R_RCV_BD_INIT_MODE, M_MODE_ENABLE);
+ t3_clear(sc, R_RCV_LIST_MODE, M_MODE_ENABLE);
+ if (sc->device != K_PCI_ID_BCM5705) {
+ t3_clear(sc, R_RCV_LIST_SEL_MODE, M_MODE_ENABLE);
+ }
+ t3_clear(sc, R_RCV_DATA_INIT_MODE, M_MODE_ENABLE);
+ t3_clear(sc, R_RCV_COMP_MODE, M_MODE_ENABLE);
+ t3_clear(sc, R_RCV_BD_COMP_MODE, M_MODE_ENABLE);
+
+ /* Transmit path shutdown */
+ t3_clear(sc, R_SND_BD_SEL_MODE, M_MODE_ENABLE);
+ t3_clear(sc, R_SND_BD_INIT_MODE, M_MODE_ENABLE);
+ t3_clear(sc, R_SND_DATA_MODE, M_MODE_ENABLE);
+ t3_clear(sc, R_RD_DMA_MODE, M_MODE_ENABLE);
+ t3_clear(sc, R_SND_DATA_COMP_MODE, M_MODE_ENABLE);
+ if (sc->device != K_PCI_ID_BCM5705) {
+ t3_clear(sc, R_DMA_COMP_MODE, M_MODE_ENABLE);
+ }
+ t3_clear(sc, R_SND_BD_COMP_MODE, M_MODE_ENABLE);
+ t3_clear(sc, R_TX_MODE, M_MODE_ENABLE);
+
+ /* Memory shutdown */
+ t3_clear(sc, R_HOST_COAL_MODE, M_HCM_ENABLE);
+ t3_clear(sc, R_WR_DMA_MODE, M_MODE_ENABLE);
+ if (sc->device != K_PCI_ID_BCM5705) {
+ t3_clear(sc, R_MBUF_FREE_MODE, M_MODE_ENABLE);
+ }
+ WRITECSR(sc, R_FTQ_RESET, 0xFFFFFFFF);
+ cfe_sleep(1);
+ WRITECSR(sc, R_FTQ_RESET, 0x00000000);
+ t3_clear(sc, R_BMGR_MODE, M_BMODE_ENABLE);
+ t3_clear(sc, R_MEM_MODE, M_MAM_ENABLE);
+
+ t3_shutdownlink(sc);
+
+ WRITECSR(sc, R_MEMWIN_BASE_ADDR, 0); /* Default memory window */
+ t3_coldreset(sc);
+
+ sc->state = eth_state_uninit;
+}
+
+
+static void
+t3_isr(void *arg)
+{
+ t3_ether_t *sc = (t3_ether_t *)arg;
+ volatile t3_status_t *status = sc->status;
+ uint32_t mac_status;
+ int handled;
+
+ do {
+ WRITEMBOX(sc, R_INT_MBOX(0), 1);
+
+ handled = 0;
+ mac_status = READCSR(sc, R_MAC_STATUS); /* force ordering */
+ status->status &= ~M_STATUS_UPDATED;
+
+ if (status->index[RI(1)].return_p != sc->rxr_1_index) {
+ handled = 1;
+ if (IPOLL) sc->rx_interrupts++;
+ t3_procrxring(sc);
+ }
+
+ if (status->index[RI(1)].send_c != sc->txc_1_index) {
+ handled = 1;
+ if (IPOLL) sc->tx_interrupts++;
+ t3_proctxring(sc);
+ }
+
+ if ((status->status & M_STATUS_LINKCHNG) != 0) {
+ handled = 1;
+#if T3_AUTOPOLL
+ WRITECSR(sc, R_MAC_STATUS, M_LINKCHNG_CLR);
+#endif
+ WRITECSR(sc, R_MAC_STATUS, M_EVT_MICOMPLETE);
+
+ status->status &= ~M_STATUS_LINKCHNG;
+ sc->phy_change = 1;
+ }
+
+ WRITEMBOX(sc, R_INT_MBOX(0), 0);
+ (void)READMBOX(sc, R_INT_MBOX(0)); /* push */
+
+#if (!XPOLL)
+ if (!handled)
+ sc->bogus_interrupts++;
+#endif
+
+ } while ((status->status & M_STATUS_UPDATED) != 0);
+
+ if (sc->rxp_std_index != sc->prev_rxp_std_index) {
+ sc->prev_rxp_std_index = sc->rxp_std_index;
+ WRITEMBOX(sc, R_RCV_BD_STD_PI, sc->rxp_std_index);
+ }
+}
+
+
+static void
+t3_start(t3_ether_t *sc)
+{
+ t3_hwinit(sc);
+
+ sc->intmask = 0;
+
+#if IPOLL
+ cfe_request_irq(sc->irq, t3_isr, sc, CFE_IRQ_FLAGS_SHARED, 0);
+
+#if T3_AUTOPOLL
+ sc->intmask |= M_EVT_LINKCHNG;
+#else
+ sc->intmask |= M_EVT_LINKCHNG | M_EVT_MIINT;
+#endif
+ WRITECSR(sc, R_MAC_EVENT_ENB, sc->intmask);
+#endif
+
+ /* Post some Rcv Producer buffers */
+ sc->prev_rxp_std_index = sc->rxp_std_index;
+ WRITEMBOX(sc, R_RCV_BD_STD_PI, sc->rxp_std_index);
+
+ sc->state = eth_state_on;
+}
+
+static void
+t3_stop(t3_ether_t *sc)
+{
+ WRITECSR(sc, R_MAC_EVENT_ENB, 0);
+ sc->intmask = 0;
+#if IPOLL
+ cfe_free_irq(sc->irq, 0);
+#endif
+
+ if (sc->state == eth_state_on) {
+ sc->state = eth_state_off;
+ t3_hwshutdown(sc);
+ t3_reinit(sc);
+ }
+}
+
+
+static int t3_ether_open(cfe_devctx_t *ctx);
+static int t3_ether_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int t3_ether_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
+static int t3_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int t3_ether_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int t3_ether_close(cfe_devctx_t *ctx);
+static void t3_ether_poll(cfe_devctx_t *ctx, int64_t ticks);
+static void t3_ether_reset(void *softc);
+
+const static cfe_devdisp_t t3_ether_dispatch = {
+ t3_ether_open,
+ t3_ether_read,
+ t3_ether_inpstat,
+ t3_ether_write,
+ t3_ether_ioctl,
+ t3_ether_close,
+ t3_ether_poll,
+ t3_ether_reset
+};
+
+cfe_driver_t bcm5700drv = {
+ "BCM570x Ethernet",
+ "eth",
+ CFE_DEV_NETWORK,
+ &t3_ether_dispatch,
+ t3_ether_probe
+};
+
+
+static void
+t3_delete_sc(t3_ether_t *sc)
+{
+ xprintf("BCM570x attach: No memory to complete probe\n");
+ if (sc != NULL) {
+ if (sc->txp_1 != NULL)
+ KFREE(sc->txp_1);
+ if (sc->rxr_1 != NULL)
+ KFREE(sc->rxr_1);
+ if (sc->rxp_std != NULL)
+ KFREE(sc->rxp_std);
+ if (sc->stats != NULL)
+ KFREE(sc->stats);
+ if (sc->status != NULL)
+ KFREE((t3_ether_t *)sc->status);
+ KFREE(sc);
+ }
+}
+
+static int
+t3_ether_attach(cfe_driver_t *drv, pcitag_t tag, int index)
+{
+ t3_ether_t *sc;
+ char descr[80];
+ phys_addr_t pa;
+ uint32_t base;
+ uint32_t pcictrl;
+ uint32_t addr;
+ pcireg_t device, class;
+ const char *devname;
+ int i;
+
+ pci_map_mem(tag, PCI_MAPREG(0), PCI_MATCH_BITS, &pa);
+ base = (uint32_t)pa;
+
+ sc = (t3_ether_t *) KMALLOC(sizeof(t3_ether_t), 0);
+ if (sc == NULL) {
+ t3_delete_sc(sc);
+ return 0;
+ }
+
+ memset(sc, 0, sizeof(*sc));
+
+ sc->status = NULL;
+ sc->stats = NULL;
+
+ device = pci_conf_read(tag, PCI_ID_REG);
+ class = pci_conf_read(tag, PCI_CLASS_REG);
+ sc->tag = tag;
+ sc->device = PCI_PRODUCT(device);
+ sc->revision = PCI_REVISION(class);
+
+ sc->status = (t3_status_t *) KMALLOC(sizeof(t3_status_t), CACHE_ALIGN);
+ if (sc->status == NULL) {
+ t3_delete_sc(sc);
+ return 0;
+ }
+
+ sc->stats = (t3_stats_t *) KMALLOC(sizeof(t3_stats_t), CACHE_ALIGN);
+ if (sc->stats == NULL) {
+ t3_delete_sc(sc);
+ return 0;
+ }
+
+ if (sc->device == K_PCI_ID_BCM5705)
+ sc->rxr_entries = RXR_RING_ENTRIES_05;
+ else
+ sc->rxr_entries = RXR_RING_ENTRIES;
+
+ sc->rxp_std =
+ (t3_rcv_bd_t *) KMALLOC(RXP_STD_ENTRIES*RCV_BD_SIZE, CACHE_ALIGN);
+ sc->rxr_1 =
+ (t3_rcv_bd_t *) KMALLOC(sc->rxr_entries*RCV_BD_SIZE, CACHE_ALIGN);
+ sc->txp_1 =
+ (t3_snd_bd_t *) KMALLOC(TXP_RING_ENTRIES*SND_BD_SIZE, CACHE_ALIGN);
+ if (sc->rxp_std == NULL || sc->rxr_1 == NULL || sc->txp_1 == NULL) {
+ t3_delete_sc(sc);
+ return 0;
+ }
+
+ sc->regbase = base;
+
+ /* NB: the relative base of memory depends on the access model */
+ pcictrl = pci_conf_read(tag, R_PCI_STATE);
+#if 0 /* XXX This gets spontaneously reset somehow! */
+ if ((pcictrl & M_PCIS_FLATVIEW) != 0)
+ sc->membase = base + 0x01000000; /* Flat mode */
+ else
+#endif
+ sc->membase = base + 0x8000; /* Normal mode: 32K window */
+
+ sc->irq = pci_conf_read(tag, PCI_BPARAM_INTERRUPT_REG) & 0xFF;
+
+ sc->devctx = NULL;
+
+ /* Assume on-chip firmware has initialized the MAC address. */
+ addr = READCSR(sc, R_MAC_ADDR1_HIGH);
+ for (i = 0; i < 2; i++)
+ sc->hwaddr[i] = (addr >> (8*(1-i))) & 0xff;
+ addr = READCSR(sc, R_MAC_ADDR1_LOW);
+ for (i = 0; i < 4; i++)
+ sc->hwaddr[2+i] = (addr >> (8*(3-i))) & 0xff;
+
+ t3_init(sc);
+
+ sc->state = eth_state_uninit;
+
+ switch (sc->device) {
+ case K_PCI_ID_BCM5700:
+ devname = "BCM5700"; break;
+ case K_PCI_ID_BCM5701:
+ devname = "BCM5701"; break;
+ case K_PCI_ID_BCM5702:
+ devname = "BCM5702"; break;
+ case K_PCI_ID_BCM5703:
+ devname = "BCM5703"; break;
+ case K_PCI_ID_BCM5705:
+ devname = "BCM5705"; break;
+ default:
+ devname = "BCM570x"; break;
+ }
+ xsprintf(descr, "%s Ethernet at 0x%X (%02X-%02X-%02X-%02X-%02X-%02X)",
+ devname, sc->regbase,
+ sc->hwaddr[0], sc->hwaddr[1], sc->hwaddr[2],
+ sc->hwaddr[3], sc->hwaddr[4], sc->hwaddr[5]);
+
+ cfe_attach(drv, sc, NULL, descr);
+ return 1;
+}
+
+static void
+t3_ether_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ int index;
+ int n;
+
+ n = 0;
+ index = 0;
+ for (;;) {
+ pcitag_t tag;
+ pcireg_t device;
+
+ if (pci_find_class(PCI_CLASS_NETWORK, index, &tag) != 0)
+ break;
+
+ index++;
+
+ device = pci_conf_read(tag, PCI_ID_REG);
+ if (PCI_VENDOR(device) == K_PCI_VENDOR_BROADCOM) {
+ switch (PCI_PRODUCT(device)) {
+ case K_PCI_ID_BCM5700:
+ case K_PCI_ID_BCM5701:
+ case K_PCI_ID_BCM5702:
+ case K_PCI_ID_BCM5703:
+ case K_PCI_ID_BCM5705:
+ t3_ether_attach(drv, tag, n);
+ n++;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+
+/* The functions below are called via the dispatch vector for the Tigon 3 */
+
+static int
+t3_ether_open(cfe_devctx_t *ctx)
+{
+ t3_ether_t *sc = ctx->dev_softc;
+ t3_stats_t *stats = sc->stats;
+ int i;
+
+ if (sc->state == eth_state_on)
+ t3_stop(sc);
+
+ sc->devctx = ctx;
+
+ sc->rx_interrupts = sc->tx_interrupts = sc->bogus_interrupts = 0;
+ for (i = 0; i < L_MAC_STATS/sizeof(uint64_t); i++)
+ stats->stats[i] = 0;
+
+ t3_start(sc);
+
+ if (XPOLL) t3_isr(sc);
+ return 0;
+}
+
+static int
+t3_ether_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ t3_ether_t *sc = ctx->dev_softc;
+ eth_pkt_t *pkt;
+ int blen;
+
+ if (XPOLL) t3_isr(sc);
+
+ if (sc->state != eth_state_on) return -1;
+
+ CS_ENTER(sc);
+ pkt = (eth_pkt_t *) q_deqnext(&(sc->rxqueue));
+ CS_EXIT(sc);
+
+ if (pkt == NULL) {
+ buffer->buf_retlen = 0;
+ return 0;
+ }
+
+ blen = buffer->buf_length;
+ if (blen > pkt->length) blen = pkt->length;
+
+ blockcopy(buffer->buf_ptr, pkt->buffer, blen);
+ buffer->buf_retlen = blen;
+
+ eth_free_pkt(sc, pkt);
+
+ if (XPOLL) t3_isr(sc);
+ return 0;
+}
+
+static int
+t3_ether_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat)
+{
+ t3_ether_t *sc = ctx->dev_softc;
+
+ if (XPOLL) t3_isr(sc);
+
+ if (sc->state != eth_state_on) return -1;
+
+ /* We avoid an interlock here because the result is a hint and an
+ interrupt cannot turn a non-empty queue into an empty one. */
+ inpstat->inp_status = (q_isempty(&(sc->rxqueue))) ? 0 : 1;
+
+ return 0;
+}
+
+static int
+t3_ether_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ t3_ether_t *sc = ctx->dev_softc;
+ eth_pkt_t *pkt;
+ int blen;
+
+ if (XPOLL) t3_isr(sc);
+
+ if (sc->state != eth_state_on) return -1;
+
+ pkt = eth_alloc_pkt(sc);
+ if (!pkt) return CFE_ERR_NOMEM;
+
+ blen = buffer->buf_length;
+ if (blen > pkt->length) blen = pkt->length;
+
+ blockcopy(pkt->buffer, buffer->buf_ptr, blen);
+ pkt->length = blen;
+
+ if (t3_transmit(sc, pkt) != 0) {
+ eth_free_pkt(sc,pkt);
+ return CFE_ERR_IOERR;
+ }
+
+ if (XPOLL) t3_isr(sc);
+ return 0;
+}
+
+static int
+t3_ether_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ t3_ether_t *sc = ctx->dev_softc;
+
+ switch ((int)buffer->buf_ioctlcmd) {
+ case IOCTL_ETHER_GETHWADDR:
+ memcpy(buffer->buf_ptr, sc->hwaddr, sizeof(sc->hwaddr));
+ return 0;
+
+ default:
+ return -1;
+ }
+}
+
+static int
+t3_ether_close(cfe_devctx_t *ctx)
+{
+ t3_ether_t *sc = ctx->dev_softc;
+ t3_stats_t *stats = sc->stats;
+ uint32_t inpkts, outpkts, interrupts;
+ int i;
+
+ t3_stop(sc);
+
+#if T3_BRINGUP
+ for (i = 0; i < L_MAC_STATS/sizeof(uint64_t); i++) {
+ if (stats->stats[i] != 0)
+ xprintf(" stats[%d] = %8lld\n", i, stats->stats[i]);
+ }
+#else
+ (void) i;
+#endif
+
+ inpkts = stats->stats[ifHCInUcastPkts]
+ + stats->stats[ifHCInMulticastPkts]
+ + stats->stats[ifHCInBroadcastPkts];
+ outpkts = stats->stats[ifHCOutUcastPkts]
+ + stats->stats[ifHCOutMulticastPkts]
+ + stats->stats[ifHCOutBroadcastPkts];
+ interrupts = stats->stats[nicInterrupts];
+
+ /* Empirically, counters on the 5705 are always zero. */
+ if (sc->device != K_PCI_ID_BCM5705) {
+ xprintf("%s: %d sent, %d received, %d interrupts\n",
+ t3_devname(sc), outpkts, inpkts, interrupts);
+ if (IPOLL) {
+ xprintf(" %d rx interrupts, %d tx interrupts",
+ sc->rx_interrupts, sc->tx_interrupts);
+ if (sc->bogus_interrupts != 0)
+ xprintf(", %d bogus interrupts", sc->bogus_interrupts);
+ xprintf("\n");
+ }
+ }
+
+ sc->devctx = NULL;
+ return 0;
+}
+
+static void
+t3_ether_poll(cfe_devctx_t *ctx, int64_t ticks)
+{
+ t3_ether_t *sc = ctx->dev_softc;
+ int changed;
+
+ if (sc->phy_change && sc->state != eth_state_uninit && !sc->mii_polling) {
+ uint32_t mask;
+
+ sc->mii_polling++;
+ mask = READCSR(sc, R_MAC_EVENT_ENB);
+ WRITECSR(sc, R_MAC_EVENT_ENB, 0);
+
+ changed = mii_poll(sc);
+ if (changed) {
+ mii_autonegotiate(sc);
+ }
+ sc->phy_change = 0;
+ sc->mii_polling--;
+
+ WRITECSR(sc, R_MAC_EVENT_ENB, mask);
+ }
+}
+
+static void
+t3_ether_reset(void *softc)
+{
+ t3_ether_t *sc = (t3_ether_t *)softc;
+
+ /* Turn off the Ethernet interface. */
+
+ if (sc->state == eth_state_on)
+ t3_stop(sc);
+
+ sc->state = eth_state_uninit;
+}
diff --git a/cfe/cfe/dev/dev_bcm5821.c b/cfe/cfe/dev/dev_bcm5821.c
new file mode 100644
index 0000000..3dede0f
--- /dev/null
+++ b/cfe/cfe/dev/dev_bcm5821.c
@@ -0,0 +1,1592 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * BC5821 crypto accelerator driver File: dev_bcm5821.c
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+/*
+ CFE Driver plus test programs for the BCM5820 and BCM5821 crypto
+ coprocessor chips.
+ Reference:
+ BCM5821 Super-eCommerce Processor
+ Data Sheet 5821-DS105-D1 (draft, 7/26/02)
+ Broadcom Corp., 16215 Alton Parkway, Irvine, CA.
+*/
+
+/* The performance counter usage assumes a BCM11xx or BCM1250 part */
+#ifndef _SB14XX_
+
+#include "sbmips.h"
+#include "sb1250_defs.h"
+#include "sb1250_regs.h"
+
+#ifndef _SB_MAKE64
+#define _SB_MAKE64(x) ((uint64_t)(x))
+#endif
+#ifndef _SB_MAKEMASK1
+#define _SB_MAKEMASK1(n) (_SB_MAKE64(1) << _SB_MAKE64(n))
+#endif
+
+#include "lib_types.h"
+#include "lib_hssubr.h"
+#include "lib_malloc.h"
+#include "lib_string.h"
+#include "lib_printf.h"
+#include "lib_queue.h"
+
+#include "addrspace.h"
+
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "cfe_timer.h"
+#include "cfe_devfuncs.h"
+#include "cfe_irq.h"
+
+#include "pcivar.h"
+#include "pcireg.h"
+
+#include "bcm5821.h"
+
+/* The version that works by polling the CPU's Cause register doesn't
+ do handshakes or checks to detect merged interrupts. It currently
+ works when the 5821 is on the direct PCI bus but can behave
+ erratically when the 5821 is behind an LDT-to-PCI bridge that does
+ interrupt mapping and relies on EOI. */
+
+extern int32_t _getcause(void); /* return value of CP0 CAUSE */
+
+#define IMR_POINTER(cpu,reg) \
+ ((volatile uint64_t *)(PHYS_TO_K1(A_IMR_REGISTER(cpu,reg))))
+
+#define CACHE_LINE_SIZE 32
+
+static void bcm5821_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+typedef struct bcm5821_state_s {
+ uint32_t regbase;
+ uint8_t irq;
+ pcitag_t tag; /* tag for configuration registers */
+
+ uint16_t device; /* chip device code */
+ uint8_t revision; /* chip revision */
+
+} bcm5821_state_t;
+
+
+/* Address mapping macros */
+
+/* Note that PTR_TO_PHYS only works with 32-bit addresses, but then
+ so does the bcm528x. */
+#define PTR_TO_PHYS(x) (K0_TO_PHYS((uintptr_t)(x)))
+#define PHYS_TO_PTR(a) ((void *)PHYS_TO_K0(a))
+
+/* For the 5821, all mappings through the PCI host bridge use match
+ bits mode. This works because the NORM_PCI bit in DMA Control is
+ clear. The 5820 does not have such a bit, so pointers to data byte
+ sequences use match bytes, but control blocks use match bits. */
+#define PHYS_TO_PCI(a) ((uint32_t) (a) | 0x20000000)
+#define PHYS_TO_PCI_D(a) (a)
+#define PCI_TO_PHYS(a) ((uint32_t) (a) & 0x1FFFFFFF)
+
+#if __long64
+#define READCSR(sc,csr) \
+ (*((volatile uint32_t *) \
+ (PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr)))))
+
+#define WRITECSR(sc,csr,val) \
+ (*((volatile uint32_t *) \
+ (PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr)))) = (val))
+#else
+#define READCSR(sc,csr) \
+ (hs_read32(PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr))))
+
+#define WRITECSR(sc,csr,val) \
+ (hs_write32(PHYS_TO_XKSEG_UNCACHED((sc)->regbase+(csr)), (val)))
+#endif
+
+static void
+dumpcsrs(bcm5821_state_t *sc, const char *legend)
+{
+ xprintf("%s:\n", legend);
+ xprintf("---DMA---\n");
+ /* DMA control and status registers */
+ xprintf("MCR1: %08X CTRL: %08X STAT: %08X ERR: %08X\n",
+ READCSR(sc, R_MCR1), READCSR(sc, R_DMA_CTRL),
+ READCSR(sc, R_DMA_STAT), READCSR(sc, R_DMA_ERR));
+ xprintf("MCR2: %08X\n", READCSR(sc, R_MCR2));
+ xprintf("-------------\n");
+}
+
+
+static void
+bcm5821_init(bcm5821_state_t *sc)
+{
+}
+
+static void
+bcm5821_hwinit(bcm5821_state_t *sc)
+{
+ uint32_t ctrl;
+ uint32_t status;
+
+ ctrl = (M_DMA_CTRL_MCR1_INT_EN | M_DMA_CTRL_MCR2_INT_EN |
+ M_DMA_CTRL_DMAERR_EN);
+ if (sc->device == K_PCI_ID_BCM5820)
+ ctrl |= (M_DMA_CTRL_NORM_PCI | M_DMA_CTRL_LE_CRYPTO);
+ /* Note for 5821: M_DMA_CTRL_NORM_PCI, M_DMA_CTRL_LE_CRYPTO not set. */
+#if 0 /* Empirically, this reduces performance. */
+ if (sc->device != K_PCI_ID_BCM5820)
+ ctrl |= M_DMA_CTRL_WR_BURST;
+#endif
+ WRITECSR(sc, R_DMA_CTRL, ctrl);
+
+ status = READCSR(sc, R_DMA_STAT);
+ WRITECSR(sc, R_DMA_STAT, status); /* reset write-to-clear bits */
+ status = READCSR(sc, R_DMA_STAT);
+
+ dumpcsrs(sc, "init");
+}
+
+
+static void
+bcm5821_start(bcm5821_state_t *sc)
+{
+ bcm5821_hwinit(sc);
+}
+
+static void
+bcm5821_stop(bcm5821_state_t *sc)
+{
+ WRITECSR(sc, R_DMA_CTRL, 0);
+}
+
+
+static int bcm5821_open(cfe_devctx_t *ctx);
+static int bcm5821_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int bcm5821_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
+static int bcm5821_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int bcm5821_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int bcm5821_close(cfe_devctx_t *ctx);
+
+const static cfe_devdisp_t bcm5821_dispatch = {
+ bcm5821_open,
+ bcm5821_read,
+ bcm5821_inpstat,
+ bcm5821_write,
+ bcm5821_ioctl,
+ bcm5821_close,
+ NULL,
+ NULL
+};
+
+cfe_driver_t bcm5821drv = {
+ "BCM582x crypto",
+ "crypt",
+ CFE_DEV_OTHER,
+ &bcm5821_dispatch,
+ bcm5821_probe
+};
+
+
+static int
+bcm5821_attach(cfe_driver_t *drv, pcitag_t tag, int index)
+{
+ bcm5821_state_t *sc;
+ char descr[80];
+ phys_addr_t pa;
+ uint32_t base;
+ pcireg_t device, class;
+
+ pci_map_mem(tag, PCI_MAPREG(0), PCI_MATCH_BITS, &pa);
+ base = (uint32_t)pa;
+
+ sc = (bcm5821_state_t *) KMALLOC(sizeof(bcm5821_state_t),0);
+ if (sc == NULL) {
+ xprintf("BCM5821: No memory to complete probe\n");
+ return 0;
+ }
+
+ memset(sc, 0, sizeof(*sc));
+
+ sc->regbase = base;
+
+ sc->irq = pci_conf_read(tag, PCI_BPARAM_INTERRUPT_REG) & 0xFF;
+
+ device = pci_conf_read(tag, PCI_ID_REG);
+ class = pci_conf_read(tag, PCI_CLASS_REG);
+
+ sc->tag = tag;
+ sc->device = PCI_PRODUCT(device);
+ sc->revision = PCI_REVISION(class);
+
+ bcm5821_init(sc);
+
+ xsprintf(descr, "BCM%04X Crypto at 0x%08X", sc->device, base);
+ cfe_attach(drv, sc, NULL, descr);
+
+ return 1;
+}
+
+static void
+bcm5821_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ int index;
+ int n;
+
+ n = 0;
+ index = 0;
+ for (;;) {
+ pcitag_t tag;
+ pcireg_t device;
+
+ if (pci_find_class(PCI_CLASS_PROCESSOR, index, &tag) != 0)
+ break;
+
+ index++;
+
+ device = pci_conf_read(tag, PCI_ID_REG);
+ if (PCI_VENDOR(device) == K_PCI_VENDOR_BROADCOM) {
+ if (PCI_PRODUCT(device) == K_PCI_ID_BCM5820 ||
+ PCI_PRODUCT(device) == K_PCI_ID_BCM5821) {
+ bcm5821_attach(drv, tag, n);
+ n++;
+ }
+ }
+ }
+}
+
+
+/* The functions below are called via the dispatch vector for the 5821 */
+
+static int
+bcm5821_open(cfe_devctx_t *ctx)
+{
+ bcm5821_state_t *sc = ctx->dev_softc;
+
+ bcm5821_start(sc);
+ return 0;
+}
+
+static int
+bcm5821_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ return -1;
+}
+
+static int
+bcm5821_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat)
+{
+ return 0;
+}
+
+static int
+bcm5821_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ return -1;
+}
+
+static int
+bcm5821_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ return -1;
+}
+
+static int
+bcm5821_close(cfe_devctx_t *ctx)
+{
+ bcm5821_state_t *sc = ctx->dev_softc;
+
+ bcm5821_stop(sc);
+ return 0;
+}
+
+
+/* Additional hooks for testing. */
+
+static int
+bcm5821_dump_cc1 (uint32_t *cc)
+{
+ int i;
+ unsigned op = G_CC_OPCODE(cc[0]);
+ unsigned cc_words = G_CC_LEN(cc[0])/4;
+ int chain_out; /* Whether the output is chained or fixed */
+
+ chain_out = 1; /* default */
+
+ switch (op) {
+
+ case K_SSL_MAC:
+ xprintf("(SSL_MAC)\n");
+ for (i = 0; i < SSL_MAC_CMD_WORDS; i++)
+ xprintf(" %2d: %08x\n", i, cc[i]);
+ chain_out = 0;
+ break;
+
+ case K_ARC4:
+ xprintf("(ARCFOUR)\n");
+ for (i = 0; i < 3; i++)
+ xprintf(" %2d: %08x\n", i, cc[i]);
+ for (i = 0; i < 256/4; i += 4)
+ xprintf(" %2d: %08x %08x %08x %08x\n",
+ i+3, cc[i+3], cc[i+4], cc[i+5], cc[i+6]);
+ break;
+
+ case K_HASH:
+ xprintf("(HASH)\n");
+ for (i = 0; i < 2; i++)
+ xprintf(" %2d: %08x\n", i, cc[i]);
+ chain_out = 0;
+ break;
+
+ case K_TLS_HMAC:
+ chain_out = 0;
+ /* fall through */
+
+ default: /* NYI: K_IPSEC_3DES (5821 only), K_SSL_3DES */
+ xprintf("\n");
+ for (i = 0; i < cc_words; i++)
+ xprintf(" %2d: %08x\n", i, cc[i]);
+ break;
+ }
+
+ return chain_out;
+}
+
+static int
+bcm5821_dump_cc2 (uint32_t *cc)
+{
+ int i;
+ unsigned op = G_CC_OPCODE(cc[0]);
+ unsigned cc_words = G_CC_LEN(cc[0])/4;
+ int chain_out; /* Whether the output is chained or fixed */
+
+ chain_out = 1; /* default */
+
+ switch (op) {
+
+ case K_RNG_DIRECT:
+ xprintf(" RNG_DIRECT\n");
+ chain_out = 0;
+ for (i = 0; i < 1; i++)
+ xprintf(" %2d: %08x\n", i, cc[i]);
+ break;
+
+ case K_RNG_SHA1:
+ xprintf(" RNG_SHA1\n");
+ chain_out = 0;
+ for (i = 0; i < 1; i++)
+ xprintf(" %2d: %08x\n", i, cc[i]);
+ break;
+
+ default: /* NYI: K_DH_*_GEN, K_RSA_*_OP, K_DSA_*, K_MOD_* */
+ xprintf(" %04x\n", op);
+ for (i = 0; i < cc_words; i++)
+ xprintf(" %2d: %08x\n", i, cc[i]);
+ break;
+ }
+ return chain_out;
+}
+
+static void
+bcm5821_dump_pkt (uint32_t *pkt, int port)
+{
+ uint32_t *cc = PHYS_TO_PTR(PCI_TO_PHYS(pkt[0]));
+ uint32_t *chain;
+ int chain_out;
+ int i, j;
+
+ xprintf(" %2d: %08x ", 0, pkt[0]);
+ chain_out = (port == 1 ? bcm5821_dump_cc1 : bcm5821_dump_cc2)(cc);
+
+ for (i = 1; i < PD_SIZE/4; i++) {
+ xprintf(" %2d: %08x\n", i, pkt[i]);
+
+ if (pkt[i] != 0) {
+ switch (i) {
+ case 2:
+ chain = PHYS_TO_PTR(PCI_TO_PHYS(pkt[i]));
+ for (j = 0; j < CHAIN_WORDS; j++)
+ xprintf(" %2d: %08x\n", j, chain[j]);
+ break;
+ case 6:
+ if (chain_out) {
+ chain = PHYS_TO_PTR(PCI_TO_PHYS(pkt[i]));
+ for (j = 0; j < CHAIN_WORDS; j++)
+ xprintf(" %2d: %08x\n", j, chain[j]);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+static void
+bcm5821_dump_mcr (uint32_t mcr[], int port)
+{
+ unsigned i;
+ unsigned npkts = G_MCR_NUM_PACKETS(mcr[0]);
+
+ xprintf("MCR header %08x at %p:\n", mcr[0], mcr);
+ for (i = 0; i < npkts; i++) {
+ xprintf(" packet %d:\n", i+1);
+ bcm5821_dump_pkt(&mcr[1 + i*(PD_SIZE/4)], port);
+ }
+}
+
+
+static void
+bcm5821_show_pkt1 (uint32_t *pkt)
+{
+ uint32_t *cc = PHYS_TO_PTR(PCI_TO_PHYS(pkt[0]));
+ unsigned op = G_CC_OPCODE(cc[0]);
+ int i;
+
+ switch (op) {
+ case K_SSL_MAC:
+ {
+ uint32_t *hash = PHYS_TO_PTR(PCI_TO_PHYS(pkt[6]));
+ xprintf("SSL_MAC hash:\n");
+ xprintf(" %08x %08x %08x %08x\n",
+ hash[0], hash[1], hash[2], hash[3]);
+ xprintf(" %08x\n", hash[4]);
+ }
+ break;
+ case K_TLS_HMAC:
+ {
+ uint32_t *hash = PHYS_TO_PTR(PCI_TO_PHYS(pkt[7]));
+ xprintf("TLS_HMAC hash:\n");
+ xprintf(" %08x %08x %08x %08x\n",
+ hash[0], hash[1], hash[2], hash[3]);
+ xprintf(" %08x\n", hash[4]);
+ }
+ break;
+ case K_ARC4:
+ {
+ uint32_t *output = PHYS_TO_PTR(PCI_TO_PHYS(pkt[5]));
+ uint32_t *chain = PHYS_TO_PTR(PCI_TO_PHYS(pkt[6]));
+ uint32_t *update = PHYS_TO_PTR(PCI_TO_PHYS(chain[0]));
+
+ xprintf("ARCFOUR output\n");
+ for (i = 0; i < 64; i += 4)
+ xprintf (" %08x %08x %08x %08x\n",
+ output[i+0], output[i+1], output[i+2], output[i+3]);
+ xprintf("ARCFOUR update\n");
+ xprintf(" %08x\n", update[0]);
+ for (i = 0; i < 256/4; i += 4)
+ xprintf (" %08x %08x %08x %08x\n",
+ update[i+1], update[i+2], update[i+3], update[i+4]);
+ }
+ break;
+ case K_HASH:
+ {
+ uint8_t *digest = PHYS_TO_PTR(PCI_TO_PHYS(pkt[6]));
+
+ xprintf("HASH digest ");
+ for (i = 0; i < 16; i++)
+ xprintf("%02x", digest[i]);
+ xprintf("\n");
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+bcm5821_show_pkt2 (uint32_t *pkt)
+{
+ uint32_t *cc = PHYS_TO_PTR(PCI_TO_PHYS(pkt[0]));
+ unsigned op = G_CC_OPCODE(cc[0]);
+ int i;
+
+ switch (op) {
+ case K_RNG_DIRECT:
+ case K_RNG_SHA1:
+ {
+ uint32_t *output = PHYS_TO_PTR(PCI_TO_PHYS(pkt[5]));
+ size_t len = V_DBC_DATA_LEN(pkt[7])/sizeof(uint32_t);
+
+ xprintf("RNG output\n");
+ for (i = 0; i < len; i += 4)
+ xprintf (" %08x %08x %08x %08x\n",
+ output[i+0], output[i+1], output[i+2], output[i+3]);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+bcm5821_show_mcr (uint32_t mcr[], int port)
+{
+ unsigned i;
+ unsigned npkts = G_MCR_NUM_PACKETS(mcr[0]);
+
+ xprintf("MCR at %p:\n", mcr);
+ for (i = 0; i < npkts; i++) {
+ xprintf("packet %d:\n", i+1);
+ if (port == 1)
+ bcm5821_show_pkt1(&mcr[1 + i*(PD_SIZE/4)]);
+ else
+ bcm5821_show_pkt2(&mcr[1 + i*(PD_SIZE/4)]);
+ }
+}
+
+
+static uint32_t *
+bcm5821_alloc_hash (const uint8_t *msg, size_t msg_len, int swap)
+{
+ uint32_t *mcr;
+ uint32_t *cmd; /* always reads at least 64 bytes */
+ uint8_t *message;
+ uint8_t *digest;
+ int i;
+
+ message = KMALLOC(msg_len, CACHE_LINE_SIZE);
+ for (i = 0; i < msg_len; i++)
+ message[i] = msg[i];
+
+ digest = KMALLOC(16, CACHE_LINE_SIZE);
+ for (i = 0; i < 16; i++)
+ digest[i] = 0;
+
+ mcr = KMALLOC(MCR_WORDS(1)*4, CACHE_LINE_SIZE);
+ mcr[0] = V_MCR_NUM_PACKETS(1);
+
+ cmd = KMALLOC(64, CACHE_LINE_SIZE); /* Always allocate >= 64 bytes */
+ cmd[0] = V_CC_OPCODE(K_HASH) | V_CC_LEN(8);
+ cmd[1] = V_CC_FLAGS(K_HASH_FLAGS_MD5);
+
+ mcr[1] = PHYS_TO_PCI(PTR_TO_PHYS(cmd));
+
+ /* input fragment */
+ mcr[2] = swap ? PHYS_TO_PCI_D(PTR_TO_PHYS(message))
+ : PHYS_TO_PCI(PTR_TO_PHYS(message));
+ mcr[3] = 0;
+ mcr[4] = V_DBC_DATA_LEN(msg_len);
+
+ mcr[5] = V_PD_PKT_LEN(msg_len);
+
+ mcr[6] = 0;
+ mcr[7] = swap ? PHYS_TO_PCI_D(PTR_TO_PHYS(digest))
+ : PHYS_TO_PCI(PTR_TO_PHYS(digest));
+ mcr[8] = 0;
+
+ return mcr;
+}
+
+static void
+bcm5821_free_hash (uint32_t mcr[])
+{
+ KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[1])));
+ KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[2])));
+ KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[7])));
+
+ KFREE(mcr);
+}
+
+
+static uint32_t *
+bcm5821_alloc_hmac (const char *key, int key_len,
+ const char *msg, int msg_len,
+ int swap)
+{
+ uint32_t *message;
+ uint32_t *cmd;
+ uint32_t *mcr;
+ uint32_t *hash;
+ int i;
+
+ message = KMALLOC(msg_len, CACHE_LINE_SIZE);
+ memcpy((uint8_t *)message, msg, msg_len);
+
+ mcr = KMALLOC(MCR_WORDS(1)*4, CACHE_LINE_SIZE);
+ mcr[0] = V_MCR_NUM_PACKETS(1);
+
+ /* packet 1 */
+
+ cmd = KMALLOC(TLS_HMAC_CMD_WORDS*4, CACHE_LINE_SIZE);
+ cmd[0] = V_CC_OPCODE(K_TLS_HMAC) | V_CC_LEN(TLS_HMAC_CMD_WORDS*4);
+ cmd[1] = V_CC_FLAGS(K_HASH_FLAGS_MD5);
+
+ /* XXX This is not correct. The key is used to compute the inner
+ and outer states. */
+ for (i = 2; i < 7; i++)
+ cmd[i] = 0x36363636; /* XXX MAC write secret */
+ cmd[6] = 0x00000000; /* must be zero for SSL */
+ for (i = 8; i < 13; i++)
+ cmd[i] = 0x5c5c5c5c;
+ cmd[13] = 0; /* seq num */
+ cmd[14] = 1;
+ cmd[15] = 0x03000000 | (msg_len << 8); /* XXX type/len/rsvd */
+
+ mcr[1] = PHYS_TO_PCI(PTR_TO_PHYS(cmd));
+
+ /* input fragment */
+ mcr[2] = swap ? PHYS_TO_PCI_D(PTR_TO_PHYS(message))
+ : PHYS_TO_PCI(PTR_TO_PHYS(message));
+ mcr[3] = 0;
+ mcr[4] = V_DBC_DATA_LEN(msg_len);
+
+ mcr[5] = V_PD_PKT_LEN(msg_len);
+
+ hash = KMALLOC(5*4, CACHE_LINE_SIZE);
+ for (i = 0; i < 5; i++)
+ hash[i] = 0;
+
+ mcr[6] = 0;
+ mcr[7] = swap ? PHYS_TO_PCI_D(PTR_TO_PHYS(hash))
+ : PHYS_TO_PCI(PTR_TO_PHYS(hash));
+ mcr[8] = 0;
+
+ return mcr;
+}
+
+static void
+bcm5821_free_hmac (uint32_t mcr[])
+{
+ KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[1])));
+ KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[2])));
+ KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[7])));
+
+ KFREE(mcr);
+}
+
+
+static int test_init = 0;
+
+/* Timing */
+
+/* For Pass 1, dedicate an SCD peformance counter to use as a counter
+ of ZBbus cycles. */
+#include "sb1250_scd.h"
+#define ZCTR_MODULUS 0x10000000000LL
+
+/* The counter is a shared resource that must be reset periodically
+ since it doesn't roll over. Furthermore, there is a pass one bug
+ that makes the interrupt unreliable and the final value either all
+ ones or all zeros. We therefore reset the count when it exceeds
+ half the modulus. We also assume that intervals of interest
+ are much less than half the modulus and attempt to adjust for
+ the reset in zclk_elapsed. */
+
+static void
+zclk_init(uint64_t val)
+{
+ *((volatile uint64_t *) UNCADDR(A_SCD_PERF_CNT_0)) = val;
+ *((volatile uint64_t *) UNCADDR(A_SCD_PERF_CNT_CFG)) =
+ V_SPC_CFG_SRC0(1) | M_SPC_CFG_ENABLE;
+}
+
+static uint64_t
+zclk_get(void)
+{
+ uint64_t ticks;
+
+ ticks = *((volatile uint64_t *) UNCADDR(A_SCD_PERF_CNT_0));
+ if (ticks == 0 || ticks == ZCTR_MODULUS-1) {
+ ticks = 0;
+ zclk_init(ticks);
+ }
+ else if (ticks >= ZCTR_MODULUS/2) {
+ ticks -= ZCTR_MODULUS/2;
+ zclk_init(ticks); /* Ignore the fudge and lose a few ticks */
+ }
+ return ticks;
+}
+
+static uint64_t
+zclk_elapsed(uint64_t stop, uint64_t start)
+{
+ return ((stop >= start) ? stop : stop + ZCTR_MODULUS/2) - start;
+}
+
+
+/* Auxiliary functions */
+
+static uint32_t *
+bcm5821_alloc_composite(int input_size)
+{
+ uint32_t *input, *output;
+ uint32_t *cmd;
+ uint32_t *chain;
+ uint32_t *mcr;
+ uint32_t *hash;
+ uint32_t *update;
+ uint8_t *arc4_state;
+ int i;
+
+ input = KMALLOC(input_size, CACHE_LINE_SIZE);
+ for (i = 0; i < input_size; i++)
+ ((uint8_t *)input)[i] = i & 0xFF;
+ output = KMALLOC(input_size + 16, CACHE_LINE_SIZE);
+ for (i = 0; i < input_size + 16; i++)
+ ((uint8_t *)output)[i] = 0xFF;
+
+ mcr = KMALLOC(MCR_WORDS(2)*4, CACHE_LINE_SIZE);
+ mcr[0] = V_MCR_NUM_PACKETS(2);
+
+ /* packet 1 */
+
+ cmd = KMALLOC(SSL_MAC_CMD_WORDS*4, CACHE_LINE_SIZE);
+ cmd[0] = V_CC_OPCODE(K_SSL_MAC) | V_CC_LEN(SSL_MAC_CMD_WORDS*4);
+ cmd[1] = V_CC_FLAGS(K_HASH_FLAGS_MD5);
+ for (i = 2; i < 6; i++)
+ cmd[i] = 0x01020304; /* XXX MAC write secret */
+ cmd[6] = 0x00000000; /* must be zero for SSL */
+ for (i = 7; i < 19; i++)
+ cmd[i] = 0x36363636;
+ cmd[19] = 0; /* seq num */
+ cmd[20] = 1;
+ cmd[21] = 0x03000000 | (input_size << 8); /* type/len/rsvd */
+
+ mcr[1] = PHYS_TO_PCI(PTR_TO_PHYS(cmd));
+
+ /* input fragment */
+ mcr[2] = PHYS_TO_PCI(PTR_TO_PHYS(input));
+ mcr[3] = 0;
+ mcr[4] = V_DBC_DATA_LEN(input_size);
+
+ mcr[5] = V_PD_PKT_LEN(input_size);
+
+ hash = KMALLOC(5*4, CACHE_LINE_SIZE);
+ for (i = 0; i < 5; i++)
+ hash[i] = 0;
+
+ mcr[6] = 0;
+ mcr[7] = PHYS_TO_PCI(PTR_TO_PHYS(hash));
+ mcr[8] = 0;
+
+ /* packet 2 */
+
+ cmd = KMALLOC(ARC4_CMD_WORDS*4, CACHE_LINE_SIZE);
+ cmd[0] = V_CC_OPCODE(K_ARC4) | V_CC_LEN(ARC4_CMD_WORDS*4);
+ cmd[1] = M_ARC4_FLAGS_WRITEBACK;
+ cmd[2] = 0x000100F3;
+ arc4_state = (uint8_t *)&cmd[3];
+ for (i = 0; i < 256; i++)
+ arc4_state[i] = i;
+
+ mcr[8+1] = PHYS_TO_PCI(PTR_TO_PHYS(cmd));
+
+ /* input fragment */
+ chain = KMALLOC(CHAIN_WORDS*4, CACHE_LINE_SIZE);
+
+ mcr[8+2] = PHYS_TO_PCI(PTR_TO_PHYS(input));
+ mcr[8+3] = PHYS_TO_PCI(PTR_TO_PHYS(chain));
+ mcr[8+4] = V_DBC_DATA_LEN(input_size);
+
+ /* MAC fragment */
+ chain[0] = PHYS_TO_PCI(PTR_TO_PHYS(hash));
+ chain[1] = 0;
+ chain[2] = V_DBC_DATA_LEN(16);
+
+ mcr[8+5] = V_PD_PKT_LEN(input_size + 16);
+
+ /* output fragment */
+ chain = KMALLOC(CHAIN_WORDS*4, CACHE_LINE_SIZE);
+
+ mcr[8+6] = PHYS_TO_PCI(PTR_TO_PHYS(output));
+ mcr[8+7] = PHYS_TO_PCI(PTR_TO_PHYS(chain));
+ mcr[8+8] = V_DBC_DATA_LEN(input_size + 16);
+
+ update = KMALLOC(ARC4_STATE_WORDS*4, CACHE_LINE_SIZE);
+ for (i = 0; i < ARC4_STATE_WORDS; i++)
+ update[i] = 0xFFFFFFFF;
+
+ /* output update */
+ chain[0] = PHYS_TO_PCI(PTR_TO_PHYS(update));
+ chain[1] = 0;
+ chain[2] = V_DBC_DATA_LEN(ARC4_STATE_WORDS*4); /* not actually used */
+
+ return mcr;
+}
+
+static void
+bcm5821_free_composite (uint32_t mcr[])
+{
+ uint32_t *chain;
+
+ /* packet 1 */
+
+ KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[1])));
+ KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[2])));
+ KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[7])));
+
+ /* packet 2 */
+ KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[8+1])));
+ /* mcr[8+2] already freed */
+ chain = PHYS_TO_PTR(PCI_TO_PHYS(mcr[8+3]));
+ KFREE(PHYS_TO_PTR(PCI_TO_PHYS(chain[0]))); KFREE(chain);
+ KFREE(PHYS_TO_PTR(PCI_TO_PHYS(mcr[8+6])));
+ chain = PHYS_TO_PTR(PCI_TO_PHYS(mcr[8+7]));
+ KFREE(PHYS_TO_PTR(PCI_TO_PHYS(chain[0]))); KFREE(chain);
+
+ KFREE(mcr);
+}
+
+
+static void
+flush_l2(void)
+{
+ /* Temporary hack: churn through all of L2 */
+ volatile uint64_t *lomem;
+ uint64_t t;
+ int i;
+
+ lomem = (uint64_t *)(0xFFFFFFFF80000000LL); /* kseg0 @ 0 */
+ t = 0;
+ for (i = 0; i < (512/8)*1024; i++)
+ t ^= lomem[i];
+}
+
+#ifdef IRQ
+static void
+bcm5821_interrupt(void *ctx)
+{
+}
+#endif
+
+
+#define POOL_SIZE 4
+#define MCR_QUEUE_DEPTH 2
+
+static int
+bcm5821_composite (bcm5821_state_t *sc, size_t len, int trials)
+{
+ uint32_t *mcr[POOL_SIZE];
+ uint32_t status;
+ uint64_t start, stop, ticks;
+ uint64_t tpb, Mbs;
+ int i;
+ int next, last, run;
+
+ for (i = 0; i < POOL_SIZE; i++)
+ mcr[i] = bcm5821_alloc_composite(len);
+
+ (void)bcm5821_dump_mcr; /*bcm5821_dump_mcr(mcr[0], 1);*/
+
+ next = last = 0;
+ run = 0;
+
+ /* Force all descriptors and buffers out of L1 */
+ cfe_flushcache(CFE_CACHE_FLUSH_D);
+ (void)flush_l2; /* XXX for now */
+
+ status = READCSR(sc, R_DMA_STAT);
+ WRITECSR(sc, R_DMA_STAT, status); /* clear pending bits */
+ status = READCSR(sc, R_DMA_STAT);
+
+ for (i = 0; i < 1000; i++) {
+ status = READCSR(sc, R_DMA_STAT);
+ if ((status & M_DMA_STAT_MCR1_FULL) == 0)
+ break;
+ cfe_sleep(1);
+ }
+ if (i == 1000) {
+ dumpcsrs(sc, "bcm5821: full bit never clears");
+ return -1;
+ }
+
+#ifdef IRQ
+ /* Enable interrupt polling, but the handler is never called. */
+ cfe_request_irq(sc->irq, bcm5821_interrupt, NULL, 0, 0);
+#endif
+
+ zclk_init(0); /* Time origin is arbitrary. */
+ start = zclk_get();
+
+ /* MCR ports are double buffered. */
+ for (i = 0; i < MCR_QUEUE_DEPTH; i++) {
+ while ((READCSR(sc, R_DMA_STAT) & M_DMA_STAT_MCR1_FULL) != 0)
+ continue;
+ WRITECSR(sc, R_MCR1, PHYS_TO_PCI(PTR_TO_PHYS(mcr[next])));
+ next = (next + 1) % POOL_SIZE;
+ }
+
+ while (1) {
+#ifdef IRQ
+ while ((_getcause() & M_CAUSE_IP2) == 0)
+ continue;
+
+ status = READCSR(sc, R_DMA_STAT);
+ if ((status & M_DMA_STAT_MCR1_INTR) == 0) {
+ /* This apparently is MCR1_ALL_EMPTY, timing of which is unclear. */
+ WRITECSR(sc, R_DMA_STAT,
+ M_DMA_STAT_DMAERR_INTR | M_DMA_STAT_MCR1_INTR);
+ continue;
+ }
+
+ stop = zclk_get();
+ WRITECSR(sc, R_DMA_STAT,
+ M_DMA_STAT_DMAERR_INTR | M_DMA_STAT_MCR1_INTR);
+#else
+ volatile uint32_t *last_mcr = mcr[last];
+
+ while ((*last_mcr & M_MCR_DONE) == 0)
+ continue;
+
+ stop = zclk_get();
+#endif
+
+ run++;
+ if (run == trials)
+ break;
+
+ while ((READCSR(sc, R_DMA_STAT) & M_DMA_STAT_MCR1_FULL) != 0)
+ continue;
+ WRITECSR(sc, R_MCR1, PHYS_TO_PCI(PTR_TO_PHYS(mcr[next])));
+ next = (next + 1) % POOL_SIZE;
+
+ /* Clear the DONE and ERROR bits. This will bring one line of
+ the MCR back into L1. Flush? */
+ mcr[last][0] = V_MCR_NUM_PACKETS(2);
+ last = (last + 1) % POOL_SIZE;
+ }
+
+#ifdef IRQ
+ status = READCSR(sc, R_DMA_STAT);
+ WRITECSR(sc, R_DMA_STAT, status); /* clear pending bits */
+ cfe_free_irq(sc->irq, 0);
+#endif
+
+ ticks = zclk_elapsed(stop, start) / trials;
+ xprintf("bcm5821: Composite %lld ticks for %d bytes, %d packets\n",
+ ticks, len, trials);
+ /* Scaling for two decimal places. */
+ tpb = (ticks*100) / len;
+ Mbs = (2000*100)*100 / tpb;
+ xprintf(" rate %lld.%02lld Mbps\n", Mbs/100, Mbs % 100);
+
+ if (trials == 1)
+ {
+ bcm5821_show_mcr(mcr[0], 1);
+ }
+
+ for (i = 0; i < POOL_SIZE; i++)
+ bcm5821_free_composite(mcr[i]);
+
+ return 0;
+}
+
+
+/* The following code depends on having a separate interrupt per
+ device, and there are only 4 PCI interrupts. */
+#define MAX_DEVICES 4
+
+struct dev_info {
+ bcm5821_state_t *sc;
+ uint64_t irq_mask;
+ int index[MCR_QUEUE_DEPTH];
+};
+
+
+#define N_DEVICES 2
+
+static int
+bcm5821_composite2 (bcm5821_state_t *sc0, bcm5821_state_t *sc1,
+ size_t len, int trials)
+{
+ uint32_t *mcr[POOL_SIZE];
+ uint32_t ring[POOL_SIZE];
+ uint32_t status;
+ uint64_t start, stop, ticks;
+ uint64_t tpb, Mbs;
+ int i;
+ int next, last;
+ int started, run;
+ int d;
+ struct dev_info dev[N_DEVICES];
+ uint64_t masks;
+ bcm5821_state_t *sc;
+#ifdef IRQ
+ volatile uint64_t *irqstat = IMR_POINTER(0, R_IMR_INTERRUPT_SOURCE_STATUS);
+#endif
+ uint64_t pending;
+
+ dev[0].sc = sc0; dev[1].sc = sc1;
+
+ for (i = 0; i < POOL_SIZE; i++)
+ mcr[i] = bcm5821_alloc_composite(len);
+ for (i = 0; i < POOL_SIZE; i++)
+ ring[i] = i;
+ next = last = 0;
+
+ (void)bcm5821_dump_mcr; /*bcm5821_dump_mcr(mcr[0], 1);*/
+
+ started = run = 0;
+
+ /* Force all descriptors and buffers out of L1 */
+ cfe_flushcache(CFE_CACHE_FLUSH_D);
+ (void)flush_l2; /* XXX for now */
+
+ masks = 0;
+ for (d = 0; d < N_DEVICES; d++) {
+ sc = dev[d].sc;
+ dev[d].irq_mask = 1LL << (sc->irq);
+ masks |= dev[d].irq_mask;
+
+ status = READCSR(sc, R_DMA_STAT);
+ WRITECSR(sc, R_DMA_STAT, status); /* clear pending bits */
+ status = READCSR(sc, R_DMA_STAT);
+
+ for (i = 0; i < 1000; i++) {
+ status = READCSR(sc, R_DMA_STAT);
+ if ((status & M_DMA_STAT_MCR1_FULL) == 0)
+ break;
+ cfe_sleep(1);
+ }
+
+ if (i == 1000) {
+ dumpcsrs(sc, "bcm5821: full bit never clears");
+ return -1;
+ }
+
+#ifdef IRQ
+ /* Enable interrupt polling, but the handler is never called. */
+ cfe_request_irq(sc->irq, bcm5821_interrupt, NULL, 0, 0);
+#endif
+ }
+
+ stop = 0; /* Keep compiler happy */
+ zclk_init(0); /* Time origin is arbitrary. */
+ start = zclk_get();
+
+ for (d = 0; d < N_DEVICES; d++) {
+ sc = dev[d].sc;
+
+ /* MCR ports are double buffered. */
+ for (i = 0; i < 2; i++) {
+ int index = ring[next];
+ while ((READCSR(sc, R_DMA_STAT) & M_DMA_STAT_MCR1_FULL) != 0)
+ continue;
+ WRITECSR(sc, R_MCR1, PHYS_TO_PCI(PTR_TO_PHYS(mcr[index])));
+ dev[d].index[i] = index;
+ next = (next + 1) % POOL_SIZE;
+ started++;
+ }
+ }
+
+ while (trials == 0 || run != trials) {
+#ifdef IRQ
+ while ((_getcause() & M_CAUSE_IP2) == 0)
+ continue;
+
+ pending = *irqstat;
+#else
+ pending = 0;
+ while (pending == 0) {
+ for (d = 0; d < N_DEVICES; d++) {
+ volatile uint32_t *last_mcr = mcr[dev[d].index[0]];
+
+ if ((*last_mcr & M_MCR_DONE) != 0)
+ pending |= dev[d].irq_mask;
+ }
+ }
+#endif
+
+ stop = zclk_get();
+
+ for (d = 0; d < N_DEVICES; d++) {
+ if ((dev[d].irq_mask & pending) != 0) {
+ sc = dev[d].sc;
+
+#ifdef IRQ
+ status = READCSR(sc, R_DMA_STAT);
+ if ((status & M_DMA_STAT_MCR1_INTR) == 0) {
+ /* Apparently MCR1_ALL_EMPTY, timing of which is unclear. */
+ WRITECSR(sc, R_DMA_STAT,
+ M_DMA_STAT_DMAERR_INTR | M_DMA_STAT_MCR1_INTR);
+ continue;
+ }
+ WRITECSR(sc, R_DMA_STAT,
+ M_DMA_STAT_DMAERR_INTR | M_DMA_STAT_MCR1_INTR);
+#endif
+ ring[last] = dev[d].index[0];
+ /* Clear the DONE and ERROR bits. This will bring one line of
+ the MCR back into L1. Flush? */
+ mcr[ring[last]][0] = V_MCR_NUM_PACKETS(2);
+ last = (last + 1) % POOL_SIZE;
+
+ run++;
+ if (run == trials)
+ break;
+
+ dev[d].index[0] = dev[d].index[1];
+ if (trials == 0 || started < trials) {
+ int index = ring[next];
+ while ((READCSR(sc, R_DMA_STAT) & M_DMA_STAT_MCR1_FULL) != 0)
+ continue;
+ WRITECSR(sc, R_MCR1, PHYS_TO_PCI(PTR_TO_PHYS(mcr[index])));
+ dev[d].index[1] = index;
+ next = (next + 1) % POOL_SIZE;
+ started++;
+ }
+ }
+ }
+ }
+
+ for (d = 0; d < N_DEVICES; d++) {
+ sc = dev[d].sc;
+ status = READCSR(sc, R_DMA_STAT);
+ WRITECSR(sc, R_DMA_STAT, status); /* clear pending bits */
+#ifdef IRQ
+ cfe_free_irq(sc->irq, 0);
+#endif
+ }
+
+ ticks = zclk_elapsed(stop, start) / trials;
+ xprintf("bcm5821: Composite %lld ticks for %d bytes, %d packets\n",
+ ticks, len, trials);
+ /* Scaling for two decimal places. */
+ tpb = (ticks*100) / len;
+ Mbs = (2000*100)*100 / tpb;
+ xprintf(" rate %lld.%02lld Mbps\n", Mbs/100, Mbs % 100);
+
+ for (i = 0; i < POOL_SIZE; i++)
+ bcm5821_free_composite(mcr[i]);
+
+ return 0;
+}
+
+
+extern cfe_devctx_t *cfe_handle_table[];
+
+int bcm5821_test (int device, int trials);
+int
+bcm5821_test (int device, int trials)
+{
+ cfe_devctx_t *ctx = cfe_handle_table[device];
+ bcm5821_state_t *sc = ctx->dev_softc;
+
+ if (!test_init) {
+ zclk_init(0); /* Time origin is arbitrary */
+ test_init = 1;
+ }
+
+ bcm5821_composite(sc, 1472, trials);
+
+ return 0;
+}
+
+int bcm5821_test2 (int device0, int device2, int trials);
+int
+bcm5821_test2 (int device0, int device1, int trials)
+{
+ cfe_devctx_t *ctx0 = cfe_handle_table[device0];
+ cfe_devctx_t *ctx1 = cfe_handle_table[device1];
+ bcm5821_state_t *sc0 = ctx0->dev_softc;
+ bcm5821_state_t *sc1 = ctx1->dev_softc;
+
+ if (!test_init) {
+ zclk_init(0); /* Time origin is arbitrary */
+ test_init = 1;
+ }
+
+ bcm5821_composite2(sc0, sc1, 1472, trials);
+
+ return 0;
+}
+
+
+static int
+bcm5821_hash_md5 (bcm5821_state_t *sc, const char *msg)
+{
+ size_t len = strlen(msg);
+ uint32_t *mcr;
+ uint32_t status;
+ int i;
+ int swap = (sc->device == K_PCI_ID_BCM5820);
+
+ mcr = bcm5821_alloc_hash(msg, len, swap);
+
+ /* bcm5821_dump_mcr(mcr, 1); */
+
+ status = READCSR(sc, R_DMA_STAT);
+ WRITECSR(sc, R_DMA_STAT, status); /* clear pending bits */
+ status = READCSR(sc, R_DMA_STAT);
+
+ for (i = 0; i < 1000; i++) {
+ status = READCSR(sc, R_DMA_STAT);
+ if ((status & M_DMA_STAT_MCR1_FULL) == 0)
+ break;
+ cfe_sleep(1);
+ }
+ if (i == 1000) {
+ dumpcsrs(sc, "bcm5821: full bit never clears");
+ return -1;
+ }
+
+ WRITECSR(sc, R_MCR1, PHYS_TO_PCI(PTR_TO_PHYS(mcr)));
+
+ for (i = 0; i < 1000; i++) {
+#ifdef IRQ
+ status = READCSR(sc, R_DMA_STAT);
+ if ((status & M_DMA_STAT_MCR1_INTR) != 0)
+ break;
+#else
+ if ((mcr[0] & M_MCR_DONE) != 0)
+ break;
+#endif
+ cfe_sleep(1);
+ }
+ if (i == 1000) {
+ dumpcsrs(sc, "bcm5821: done bit never sets");
+ /*return -1;*/
+ }
+
+ status = READCSR(sc, R_DMA_STAT);
+ WRITECSR(sc, R_DMA_STAT, status); /* clear pending bits */
+
+ /* bcm5821_dump_mcr(mcr, 1); */
+
+ bcm5821_show_mcr(mcr, 1);
+
+ bcm5821_free_hash(mcr);
+
+ return 0;
+}
+
+
+static int
+bcm5821_hmac_md5 (bcm5821_state_t *sc,
+ const uint8_t key[], size_t key_len,
+ const uint8_t data[], size_t data_len)
+{
+ uint32_t *mcr;
+ uint32_t status;
+ int i;
+ int swap = (sc->device == K_PCI_ID_BCM5820);
+
+ mcr = bcm5821_alloc_hmac(key, key_len, data, data_len, swap);
+
+ status = READCSR(sc, R_DMA_STAT);
+ WRITECSR(sc, R_DMA_STAT, status); /* clear pending bits */
+ status = READCSR(sc, R_DMA_STAT);
+
+ for (i = 0; i < 1000; i++) {
+ status = READCSR(sc, R_DMA_STAT);
+ if ((status & M_DMA_STAT_MCR1_FULL) == 0)
+ break;
+ cfe_sleep(1);
+ }
+ if (i == 1000) {
+ dumpcsrs(sc, "bcm5821: full bit never clears");
+ return -1;
+ }
+#if 0 /* disable: work in progress */
+
+ while ((READCSR(sc, R_DMA_STAT) & M_DMA_STAT_MCR1_FULL) != 0)
+ continue;
+ WRITECSR(sc, R_MCR1, PHYS_TO_PCI(PTR_TO_PHYS(mcr)));
+
+ for (i = 0; i < 1000; i++) {
+ if ((mcr[0] & M_MCR_DONE) != 0)
+ break;
+ cfe_sleep(1);
+ }
+ if (i == 1000) {
+ dumpcsrs(sc, "bcm5821: done bit never sets");
+ return -1;
+ }
+
+ status = READCSR(sc, R_DMA_STAT);
+ WRITECSR(sc, R_DMA_STAT, status); /* clear pending bits */
+
+ bcm5821_show_mcr(mcr, 1);
+#endif
+
+ bcm5821_free_hmac(mcr);
+ return 0;
+}
+
+/* Sanity check on the implementation using RFC test suites. */
+
+int bcm5821_check (int device);
+int
+bcm5821_check (int device)
+{
+ static unsigned char k1[16] = {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
+ };
+ static unsigned char m1[] = "Hi There";
+
+ static unsigned char k2[] = "Jefe";
+ static unsigned char m2[] = "what do ya want for nothing?";
+
+ static unsigned char k3[16] = {
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA
+ };
+ static unsigned char m3[50] = {
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD
+ };
+
+ cfe_devctx_t *ctx = cfe_handle_table[device];
+ bcm5821_state_t *sc = ctx->dev_softc;
+
+ if (!test_init) {
+ zclk_init(0); /* Time origin is arbitrary */
+ test_init = 1;
+ }
+
+#if 0 /* 5821 cannot handle 0-length fragments (see Appendix B) */
+ bcm5821_hash_md5(sc, "");
+#endif
+ bcm5821_hash_md5(sc, "a");
+ bcm5821_hash_md5(sc, "abc");
+ bcm5821_hash_md5(sc, "message digest");
+ bcm5821_hash_md5(sc, "abcdefghijklmnopqrstuvwxyz");
+ bcm5821_hash_md5(sc, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+ bcm5821_hash_md5(sc, "12345678901234567890123456789012345678901234567890123456789012345678901234567890");
+
+ bcm5821_hmac_md5(sc, k1, sizeof(k1), m1, strlen(m1));
+ bcm5821_hmac_md5(sc, k2, strlen(k2), m2, strlen(m2));
+ bcm5821_hmac_md5(sc, k3, sizeof(k3), m3, sizeof(m3));
+
+ return 0;
+}
+
+/* Output of md5 test suite (md5 -x)
+
+MD5 test suite:
+MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
+MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
+MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
+MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
+MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
+MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = d174ab98d277d9f5a5611c2c9f419d9f
+MD5 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = 57edf4a22be3c955ac49da2e2107b67a
+
+*/
+
+/* HMAC-MD5 test suite
+
+Test Vectors (Trailing '\0' of a character string not included in test):
+
+ key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+ key_len = 16 bytes
+ data = "Hi There"
+ data_len = 8 bytes
+ digest = 0x9294727a3638bb1c13f48ef8158bfc9d
+
+ key = "Jefe"
+ data = "what do ya want for nothing?"
+ data_len = 28 bytes
+ digest = 0x750c783e6ab0b503eaa86e310a5db738
+
+ key = 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ key_len 16 bytes
+ data = 0xDDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD
+ data_len = 50 bytes
+ digest = 0x56be34521d144c88dbb8c733f0e8b3f6
+
+*/
+#endif /* !_BCM14XX_ */
+
+
+#if 0 /* ---------- XXX still under construction XXX ---------- */
+
+static uint32_t *
+bcm5821_alloc_rng (int output_size)
+{
+ uint32_t *output;
+ uint32_t *mcr;
+ uint32_t *cmd;
+ int i;
+
+ output = (uint32_t *)KMALLOC(output_size, CACHE_LINE_SIZE);
+ for (i = 0; i < output_size/sizeof(uint32_t); i++)
+ output[i] = 0xDEADBEEF;
+
+ mcr = KMALLOC(MCR_WORDS(1)*4, CACHE_LINE_SIZE);
+ mcr[0] = V_MCR_NUM_PACKETS(1);
+
+ cmd = KMALLOC(16, CACHE_LINE_SIZE); /* Always allocate >= 64 bytes */
+ cmd[0] = V_CC_OPCODE(K_RNG_DIRECT) | V_CC_LEN(4);
+
+ mcr[1] = PHYS_TO_PCI(PTR_TO_PHYS(cmd));
+
+ /* input fragment */
+ mcr[2] = 0;
+ mcr[3] = 0;
+ mcr[4] = V_DBC_DATA_LEN(0);
+
+ mcr[5] = V_PD_PKT_LEN(output_size);
+
+ /* output fragment */
+ mcr[6] = PHYS_TO_PCI(PTR_TO_PHYS(output));
+ mcr[7] = 0;
+ mcr[8] = V_DBC_DATA_LEN(sizeof(output));
+
+ return mcr;
+}
+
+
+static uint32_t *
+bcm5821_alloc_ssl_mac (int msg_size)
+{
+ uint32_t *message;
+ uint32_t *cmd;
+ uint32_t *mcr;
+ uint32_t *hash;
+ int i;
+
+ message = KMALLOC(msg_size, CACHE_LINE_SIZE);
+ for (i = 0; i < msg_size; i++)
+ ((uint8_t *)message)[i] = i & 0xFF; /* was 0xDEADBEEF */
+
+ mcr = KMALLOC(MCR_WORDS(1)*4, CACHE_LINE_SIZE);
+ mcr[0] = V_MCR_NUM_PACKETS(1);
+
+ /* packet 1 */
+
+ cmd = KMALLOC(SSL_MAC_CMD_WORDS*4, CACHE_LINE_SIZE);
+ cmd[0] = V_CC_OPCODE(K_SSL_MAC) | V_CC_LEN(SSL_MAC_CMD_WORDS*4);
+ cmd[1] = V_CC_FLAGS(K_HASH_FLAGS_MD5);
+ for (i = 2; i < 6; i++)
+ cmd[i] = 0x01020304; /* XXX MAC write secret */
+ cmd[6] = 0x00000000; /* must be zero for SSL */
+ for (i = 7; i < 19; i++)
+ cmd[i] = 0x36363636;
+ cmd[19] = 0; /* seq num */
+ cmd[20] = 1;
+ cmd[21] = 0x03000000 | (msg_size << 8); /* type/len/rsvd */
+
+ mcr[1] = PHYS_TO_PCI(PTR_TO_PHYS(cmd));
+
+ /* input fragment */
+ mcr[2] = PHYS_TO_PCI(PTR_TO_PHYS(message));
+ mcr[3] = 0;
+ mcr[4] = V_DBC_DATA_LEN(msg_size);
+
+ mcr[5] = V_PD_PKT_LEN(msg_size);
+
+ hash = KMALLOC(5*4, CACHE_LINE_SIZE);
+ for (i = 0; i < 5; i++)
+ hash[i] = 0;
+
+ mcr[6] = 0;
+ mcr[7] = PHYS_TO_PCI(PTR_TO_PHYS(hash));
+ mcr[8] = 0;
+
+ return mcr;
+}
+
+static uint32_t *
+bcm5821_alloc_arc4 (int input_size)
+{
+ uint32_t *mcr;
+ uint32_t cmd[3 + 256/4];
+ uint32_t input[64], output[64];
+ uint32_t chain[3];
+ uint32_t update[1 + 256/4];
+ uint32_t status;
+ uint8_t *arc4_state;
+ int i;
+
+ xprintf("\nARC4\n");
+
+ status = READCSR(sc, R_DMA_STAT);
+ WRITECSR(sc, R_DMA_STAT, status); /* clear pending bits */
+ status = READCSR(sc, R_DMA_STAT);
+
+ for (i = 0; i < 64; i++)
+#if 0
+ input[i] = (i << 24) | ((i+1) << 16) | ((i+2) << 8) | (i+3);
+#else
+ input[i] = 0x5555AAAA;
+#endif
+ for (i = 0; i < 64; i++)
+ output[i] = 0xDEADBEEF;
+ for (i = 0; i < 1 + 256/4; i++)
+ update[i] = 0xFEEDFACE;
+
+ cmd[0] = V_CC_OPCODE(K_ARC4) | V_CC_LEN(sizeof(cmd));
+ cmd[1] = M_ARC4_FLAGS_WRITEBACK;
+#if 0
+ cmd[2] = 0x000100F3;
+#else
+ cmd[2] = 0x00000000;
+#endif
+ arc4_state = (uint8_t *)&cmd[3];
+ for (i = 0; i < 256; i++)
+ arc4_state[i] = i;
+
+ mcr[0] = V_MCR_NUM_PACKETS(1);
+
+ /* packet 1 */
+ mcr[1] = PHYS_TO_PCI(PTR_TO_PHYS(cmd));
+
+ /* input fragment */
+ mcr[2] = PHYS_TO_PCI(PTR_TO_PHYS(input));
+ mcr[3] = 0;
+ mcr[4] = V_DBC_DATA_LEN(sizeof(input));
+
+ mcr[5] = V_PD_PKT_LEN(sizeof(input));
+
+ /* output fragment */
+ mcr[6] = PHYS_TO_PCI(PTR_TO_PHYS(output));
+ mcr[7] = PHYS_TO_PCI(PTR_TO_PHYS(chain));
+ mcr[8] = V_DBC_DATA_LEN(sizeof(output));
+
+ /* output update */
+ chain[0] = PHYS_TO_PCI(PTR_TO_PHYS(update));
+ chain[1] = 0;
+ chain[2] = V_DBC_DATA_LEN(sizeof(update)); /* not actually used */
+
+ return mcr;
+}
+#endif /* 0 */
diff --git a/cfe/cfe/dev/dev_dc21143.c b/cfe/cfe/dev/dev_dc21143.c
new file mode 100644
index 0000000..f133cbb
--- /dev/null
+++ b/cfe/cfe/dev/dev_dc21143.c
@@ -0,0 +1,2388 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * DC2114x Ethernet Driver File: dev_dc21143.c
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+#include "sbmips.h"
+
+#ifndef _SB_MAKE64
+#define _SB_MAKE64(x) ((uint64_t)(x))
+#endif
+#ifndef _SB_MAKEMASK1
+#define _SB_MAKEMASK1(n) (_SB_MAKE64(1) << _SB_MAKE64(n))
+#endif
+
+#include "lib_types.h"
+#include "lib_hssubr.h"
+#include "lib_malloc.h"
+#include "lib_string.h"
+#include "lib_printf.h"
+#include "lib_queue.h"
+
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "cfe_ioctl.h"
+#include "cfe_timer.h"
+#include "cfe_irq.h"
+
+#include "pcivar.h"
+#include "pcireg.h"
+
+#include "dc21143.h"
+#include "mii.h"
+
+/* This is a driver for specific configurations of the DC21041,
+ DC21140A and DC21143, not a generic Tulip driver. The prefix
+ "tulip_" is used to indicate generic Tulip functions, while
+ "dc21041_", "dc21140_" or "dc21143_" indicates functions specific
+ to a chip variant.
+
+ The 21041 driver assumes a 10BT HD interface, since autonegotiation
+ is known to be broken in the early revisons of that chip. Example
+ cards come from DEC.
+
+ The 21140 driver assumes that the PHY uses a standard MII interface
+ for both 100BT and 10BT. Example cards come from DEC (National DP83840
+ Twister PHY) and Netgear (Level One PHY).
+
+ The 21143 driver assumes that the PHY uses the SYM ("5 wire") interface
+ for 100BT with pass-through for 10BT. Example cards come from DEC
+ (MicroLinear ML6694 PHY) and Znyx (Kendin KS8761 PHY). There is no
+ support for MII or AUI interfaces.
+
+ This SB1250 version takes advantage of DMA coherence and uses
+ "preserve bit lanes" addresses for all accesses that cross the
+ ZBbus-PCI bridge. */
+
+#ifndef TULIP_DEBUG
+#define TULIP_DEBUG 0
+#endif
+
+#ifndef TULIP_TUNE
+#define TULIP_TUNE 1
+#endif
+
+#define ENET_ADDR_LEN 6 /* size of an ethernet address */
+#define MAX_ETHER_PACK 1518 /* max size of a packet */
+#define CRC_SIZE 4 /* size of CRC field */
+
+/* The following must be a multiple of 4. In late versions of the
+ tulip, the rx DMA engine also apparently writes beyond 1520 bytes
+ for received packets > 1516 bytes (WriteInvalidate only?). */
+#define ETH_BUFFER_SIZE 1536
+
+typedef struct eth_pkt_s {
+ queue_t next;
+ void *devctx;
+ unsigned char *buffer;
+ unsigned int flags;
+ int length;
+ /* packet data goes here, should always be longword aligned */
+} eth_pkt_t;
+
+/* packet flags */
+#define ETH_TX_SETUP 1
+
+static void
+show_packet(eth_pkt_t *pkt)
+{
+ int i;
+ int n = (pkt->length < 32 ? pkt->length : 32);
+
+ xprintf("[%4d]:", pkt->length);
+ for (i = 0; i < n; i++) {
+ if (i % 4 == 0)
+ xprintf(" ");
+ xprintf("%02x", pkt->buffer[i]);
+ }
+ xprintf("\n");
+}
+
+
+/* Descriptor structures */
+
+typedef struct rx_dscr {
+ uint32_t rxd_flags;
+ uint32_t rxd_bufsize;
+ uint32_t rxd_bufaddr1;
+ uint32_t rxd_bufaddr2;
+} rx_dscr;
+
+typedef struct tx_dscr {
+ uint32_t txd_flags;
+ uint32_t txd_bufsize;
+ uint32_t txd_bufaddr1;
+ uint32_t txd_bufaddr2;
+} tx_dscr;
+
+/* CAM structure */
+
+typedef union {
+ struct {
+ uint32_t physical[CAM_PERFECT_ENTRIES][3];
+ } p;
+ struct {
+ uint32_t hash[32];
+ uint32_t mbz[7];
+ uint32_t physical[3];
+ } h;
+} tulip_cam;
+
+
+typedef enum {
+ eth_state_uninit,
+ eth_state_setup,
+ eth_state_off,
+ eth_state_on,
+ eth_state_broken
+} eth_state_t;
+
+#define ETH_PKTPOOL_SIZE 20
+#define ETH_PKTBUF_SIZE (sizeof(eth_pkt_t) + ((ETH_BUFFER_SIZE+7)&~7))
+
+typedef struct tulip_softc {
+ uint32_t membase;
+ uint8_t irq; /* interrupt mapping (not currently used) */
+ pcitag_t tag; /* tag for configuration registers */
+
+ uint8_t hwaddr[ENET_ADDR_LEN];
+ uint16_t device; /* chip device code */
+ uint8_t revision; /* chip revision and step (Table 3-7) */
+
+ /* current state */
+ eth_state_t state;
+ int bus_errors;
+
+ /* These fields are the chip startup values. */
+// uint16_t media; /* media type */
+ uint32_t opmode; /* operating mode */
+ uint32_t intmask; /* interrupt mask */
+
+ /* This field is set before calling dc2114x_hwinit */
+ int linkspeed; /* encoding from cfe_ioctl */
+
+ /* Packet free list */
+ queue_t freelist;
+ uint8_t *pktpool;
+ queue_t rxqueue;
+
+ /* The descriptor tables */
+ uint8_t *rxdscrmem; /* receive descriptors */
+ uint8_t *txdscrmem; /* transmit descriptors */
+
+ eth_pkt_t **rxdscrinfo;
+ eth_pkt_t **txdscrinfo;
+
+ /* These fields keep track of where we are in tx/rx processing */
+ volatile rx_dscr *rxdscr_start; /* beginning of ring */
+ volatile rx_dscr *rxdscr_end; /* end of ring */
+ volatile rx_dscr *rxdscr_remove; /* next one we expect tulip to use */
+ volatile rx_dscr *rxdscr_add; /* next place to put a buffer */
+ int rxdscr_onring;
+
+ volatile tx_dscr *txdscr_start; /* beginning of ring */
+ volatile tx_dscr *txdscr_end; /* end of ring */
+ volatile tx_dscr *txdscr_remove; /* next one we will use for tx */
+ volatile tx_dscr *txdscr_add; /* next place to put a buffer */
+
+ /* These fields describe the PHY */
+ int mii_addr;
+
+} tulip_softc;
+
+
+/* Driver parameterization */
+
+#define MAXRXDSCR 16
+#define MAXTXDSCR 16
+#define MINRXRING 8
+
+#define MEDIA_UNKNOWN 0
+#define MEDIA_AUI 1
+#define MEDIA_BNC 2
+#define MEDIA_UTP_FULL_DUPLEX 3
+#define MEDIA_UTP_NO_LINK_TEST 4
+#define MEDIA_UTP 5
+
+/* Prototypes */
+
+static void tulip_ether_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+
+/* Address mapping macros */
+
+/* Note that PHYSADDR only works with 32-bit addresses, but the
+ so does the Tulip. */
+#define PHYSADDR(sc,x) (K0_TO_PHYS((uintptr_t)(x)))
+
+#define PCIADDR(a,b) ((uint32_t) (b))
+#define PCIADDRX(a,b) ((uint32_t) (b) | 0x20000000)
+#define PCI_TO_CPU(a) (a)
+
+#if __long64
+#define READCSR(sc,csr) \
+ (*((volatile uint32_t *) \
+ (PHYS_TO_XKSEG_UNCACHED(PCI_TO_CPU((sc)->membase)+(csr)))))
+
+#define WRITECSR(sc,csr,val) \
+ (*((volatile uint32_t *) \
+ (PHYS_TO_XKSEG_UNCACHED(PCI_TO_CPU((sc)->membase)+(csr)))) = (val))
+
+#else
+#define READCSR(sc,csr) \
+ (hs_read32(PHYS_TO_XKSEG_UNCACHED(PCI_TO_CPU((sc)->membase)+(csr))))
+
+#define WRITECSR(sc,csr,val) \
+ (hs_write32(PHYS_TO_XKSEG_UNCACHED(PCI_TO_CPU((sc)->membase)+(csr)), \
+ (val)))
+
+#endif
+
+
+#define RESET_ADAPTER(sc) \
+ { \
+ WRITECSR((sc), R_CSR_BUSMODE, M_CSR0_SWRESET); \
+ cfe_sleep(CFE_HZ/10); \
+ }
+
+
+/* Debugging */
+
+static void
+dumpstat(tulip_softc *sc)
+{
+ xprintf("-- CSR 5 = %08X CSR 6 = %08x\n",
+ READCSR(sc, R_CSR_STATUS), READCSR(sc, R_CSR_OPMODE));
+}
+
+static void
+dumpcsrs(tulip_softc *sc)
+{
+ int idx;
+
+ xprintf("-------------\n");
+ for (idx = 0; idx < 16; idx++) {
+ xprintf("CSR %2d = %08X\n", idx, READCSR(sc, idx*8));
+ }
+ xprintf("-------------\n");
+}
+
+
+/* Packet management */
+
+/* *********************************************************************
+ * ETH_ALLOC_PKT(s)
+ *
+ * Allocate a packet from the free list.
+ *
+ * Input parameters:
+ * s - eth structure
+ *
+ * Return value:
+ * pointer to packet structure, or NULL if none available
+ ********************************************************************* */
+#define ETHPKT_ALIGN ((uintptr_t) 4)
+
+static eth_pkt_t *
+eth_alloc_pkt(tulip_softc *s)
+{
+ uintptr_t addr;
+ eth_pkt_t *pkt;
+
+ pkt = (eth_pkt_t *) q_deqnext(&s->freelist);
+ if (!pkt) return NULL;
+
+ addr = (uintptr_t) (pkt+1);
+ if (addr & (ETHPKT_ALIGN-1)) {
+ addr = (addr + ETHPKT_ALIGN) & ~(ETHPKT_ALIGN-1);
+ }
+
+ pkt->buffer = (uint8_t *) addr;
+ pkt->length = ETH_BUFFER_SIZE;
+ pkt->flags = 0;
+
+ return pkt;
+}
+
+
+/* *********************************************************************
+ * ETH_FREE_PKT(s,pkt)
+ *
+ * Return a packet to the free list
+ *
+ * Input parameters:
+ * s - sbmac structure
+ * pkt - packet to return
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void
+eth_free_pkt(tulip_softc *s, eth_pkt_t *pkt)
+{
+ q_enqueue(&s->freelist, &pkt->next);
+}
+
+
+/* *********************************************************************
+ * ETH_INITFREELIST(s)
+ *
+ * Initialize the buffer free list for this mac. The memory
+ * allocated to the free list is carved up and placed on a linked
+ * list of buffers for use by the mac.
+ *
+ * Input parameters:
+ * s - eth structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void
+eth_initfreelist(tulip_softc *s)
+{
+ int idx;
+ unsigned char *ptr;
+ eth_pkt_t *pkt;
+
+ q_init(&s->freelist);
+
+ ptr = s->pktpool;
+ for (idx = 0; idx < ETH_PKTPOOL_SIZE; idx++) {
+ pkt = (eth_pkt_t *) ptr;
+ eth_free_pkt(s, pkt);
+ ptr += ETH_PKTBUF_SIZE;
+ }
+}
+
+
+/* Descriptor ring management */
+
+static int
+tulip_add_rcvbuf(tulip_softc *sc, eth_pkt_t *pkt)
+{
+ volatile rx_dscr *rxd;
+ volatile rx_dscr *nextrxd;
+ int idx;
+ uint32_t flags = 0;
+
+ rxd = sc->rxdscr_add;
+
+ /* Figure out where the next descriptor will go */
+ nextrxd = rxd+1;
+ if (nextrxd == sc->rxdscr_end) {
+ nextrxd = sc->rxdscr_start;
+ flags = M_RDES1_ENDOFRING;
+ }
+
+ /*
+ * If the next one is the same as our remove pointer,
+ * the ring is considered full. (it actually has room for
+ * one more, but we reserve the remove == add case for "empty")
+ */
+ if (nextrxd == sc->rxdscr_remove) return -1;
+
+ /* Save this packet pointer. */
+ idx = rxd - sc->rxdscr_start;
+ sc->rxdscrinfo[idx] = pkt;
+
+ rxd->rxd_bufsize = V_RDES1_BUF1SIZE(ETH_BUFFER_SIZE) | flags;
+ rxd->rxd_bufaddr1 = PCIADDRX(sc, PHYSADDR(sc, pkt->buffer));
+ rxd->rxd_bufaddr2 = 0;
+ rxd->rxd_flags = M_RDES0_OWNADAP;
+
+ /* success, advance the pointer */
+ sc->rxdscr_add = nextrxd;
+ sc->rxdscr_onring++;
+
+ return 0;
+}
+
+static void
+tulip_fillrxring(tulip_softc *sc)
+{
+ eth_pkt_t *pkt;
+
+ while (sc->rxdscr_onring < MINRXRING) {
+ pkt = eth_alloc_pkt(sc);
+ if (pkt == NULL) {
+ /* could not allocate a buffer */
+ break;
+ }
+ if (tulip_add_rcvbuf(sc, pkt) != 0) {
+ /* could not add buffer to ring */
+ eth_free_pkt(sc, pkt);
+ break;
+ }
+ }
+}
+
+
+/* *********************************************************************
+ * TULIP_RX_CALLBACK(sc, pkt)
+ *
+ * Receive callback routine. This routine is invoked when a
+ * buffer queued for receives is filled. In this simple driver,
+ * all we do is add the packet to a per-MAC queue for later
+ * processing, and try to put a new packet in the place of the one
+ * that was removed from the queue.
+ *
+ * Input parameters:
+ * sc - interface
+ * ptk - packet context (sbeth_pkt structure)
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void
+tulip_rx_callback(tulip_softc *sc, eth_pkt_t *pkt)
+{
+ if (TULIP_DEBUG) show_packet(pkt); /* debug */
+
+ q_enqueue(&sc->rxqueue, &pkt->next);
+
+ tulip_fillrxring(sc);
+}
+
+
+static void
+tulip_procrxring(tulip_softc *sc)
+{
+ volatile rx_dscr *rxd;
+ eth_pkt_t *pkt;
+ eth_pkt_t *newpkt;
+ int idx;
+ uint32_t flags;
+
+ for (;;) {
+ rxd = (volatile rx_dscr *) sc->rxdscr_remove;
+ idx = rxd - sc->rxdscr_start;
+
+ flags = rxd->rxd_flags;
+
+ if (flags & M_RDES0_OWNADAP) {
+ /* end of ring, no more packets */
+ break;
+ }
+
+ pkt = sc->rxdscrinfo[idx];
+
+ /* Drop error packets */
+ if (flags & M_RDES0_ERRORSUM) {
+ xprintf("DC2114x: rx error %04X\n", flags & 0xFFFF);
+ tulip_add_rcvbuf(sc, pkt);
+ goto next;
+ }
+
+ /* Pass up the packet */
+ pkt->length = G_RDES0_FRAMELEN(flags) - CRC_SIZE;
+ tulip_rx_callback(sc, pkt);
+
+ /* put a buffer back on the ring to replace this one */
+ newpkt = eth_alloc_pkt(sc);
+ if (newpkt) tulip_add_rcvbuf(sc, newpkt);
+
+next:
+ /* update the pointer, accounting for buffer wrap. */
+ rxd++;
+ if (rxd == sc->rxdscr_end)
+ rxd = sc->rxdscr_start;
+
+ sc->rxdscr_remove = (rx_dscr *) rxd;
+ sc->rxdscr_onring--;
+ }
+}
+
+
+static int
+tulip_add_txbuf(tulip_softc *sc, eth_pkt_t *pkt)
+{
+ volatile tx_dscr *txd;
+ volatile tx_dscr *nexttxd;
+ int idx;
+ uint32_t bufsize = 0;
+
+ txd = sc->txdscr_add;
+
+ /* Figure out where the next descriptor will go */
+ nexttxd = (txd+1);
+ if (nexttxd == sc->txdscr_end) {
+ nexttxd = sc->txdscr_start;
+ bufsize = M_TDES1_ENDOFRING;
+ }
+
+ /* If the next one is the same as our remove pointer,
+ the ring is considered full. (it actually has room for
+ one more, but we reserve the remove == add case for "empty") */
+
+ if (nexttxd == sc->txdscr_remove) return -1;
+
+ /* Save this packet pointer. */
+ idx = txd - sc->txdscr_start;
+ sc->txdscrinfo[idx] = pkt;
+
+ bufsize |= V_TDES1_BUF1SIZE(pkt->length) |
+ M_TDES1_FIRSTSEG | M_TDES1_LASTSEG | M_TDES1_INTERRUPT;
+ if (pkt->flags & ETH_TX_SETUP) {
+ /* For a setup packet, FIRSTSEG and LASTSEG should be clear (!) */
+ bufsize ^= M_TDES1_SETUP | M_TDES1_FIRSTSEG | M_TDES1_LASTSEG;
+ }
+ txd->txd_bufsize = bufsize;
+ txd->txd_bufaddr1 = PCIADDRX(sc, PHYSADDR(sc, pkt->buffer));
+ txd->txd_bufaddr2 = 0;
+ txd->txd_flags = M_TDES0_OWNADAP;
+
+ /* success, advance the pointer */
+ sc->txdscr_add = nexttxd;
+
+ return 0;
+}
+
+
+static int
+tulip_transmit(tulip_softc *sc,eth_pkt_t *pkt)
+{
+ tulip_add_txbuf(sc, pkt);
+
+ WRITECSR(sc, R_CSR_TXPOLL, 1);
+ return 0;
+}
+
+
+static void
+tulip_proctxring(tulip_softc *sc)
+{
+ volatile tx_dscr *txd;
+ eth_pkt_t *pkt;
+ int idx;
+ uint32_t flags;
+
+ for (;;) {
+ txd = (volatile tx_dscr *) sc->txdscr_remove;
+ idx = txd - sc->txdscr_start;
+
+ flags = txd->txd_flags;
+
+ if (txd == sc->txdscr_add) {
+ /* ring is empty, no buffers to process */
+ break;
+ }
+
+ if (flags & M_RDES0_OWNADAP) {
+ /* Reached a packet still being transmitted */
+ break;
+ }
+
+ /* Check for a completed setup packet */
+ pkt = sc->txdscrinfo[idx];
+ if (pkt->flags & ETH_TX_SETUP) {
+ if (sc->state == eth_state_setup) {
+ /* check flag bits */
+ sc->state = eth_state_on;
+ }
+ pkt->flags &=~ ETH_TX_SETUP;
+ }
+
+ /* Just free the packet */
+ eth_free_pkt(sc, pkt);
+
+ /* update the pointer, accounting for buffer wrap. */
+ txd++;
+ if (txd == sc->txdscr_end)
+ txd = sc->txdscr_start;
+
+ sc->txdscr_remove = (tx_dscr *) txd;
+ }
+}
+
+
+static void
+tulip_initrings(tulip_softc *sc)
+{
+ volatile tx_dscr *txd;
+ volatile rx_dscr *rxd;
+
+ /* Claim ownership of all transmit descriptors */
+
+ for (txd = sc->txdscr_start; txd != sc->txdscr_end; txd++)
+ txd->txd_flags = 0;
+ for (rxd = sc->rxdscr_start; rxd != sc->rxdscr_end; rxd++)
+ rxd->rxd_flags = 0;
+
+ /* Init the ring pointers */
+
+ sc->txdscr_add = sc->txdscr_remove = sc->txdscr_start;
+ sc->rxdscr_add = sc->rxdscr_remove = sc->rxdscr_start;
+ sc->rxdscr_onring = 0;
+
+ /* Add stuff to the receive ring */
+
+ tulip_fillrxring(sc);
+}
+
+
+static int
+tulip_init(tulip_softc *sc)
+{
+ /* Allocate descriptor rings and lookaside lists */
+ sc->rxdscrmem = KMALLOC(MAXRXDSCR*sizeof(rx_dscr),sizeof(rx_dscr));
+ sc->txdscrmem = KMALLOC(MAXTXDSCR*sizeof(tx_dscr),sizeof(tx_dscr));
+ sc->rxdscrinfo = KMALLOC(MAXRXDSCR*sizeof(eth_pkt_t *),sizeof(eth_pkt_t));
+ sc->txdscrinfo = KMALLOC(MAXTXDSCR*sizeof(eth_pkt_t *),sizeof(eth_pkt_t));
+
+ /* Allocate buffer pool */
+ sc->pktpool = KMALLOC(ETH_PKTPOOL_SIZE*ETH_PKTBUF_SIZE, 0);
+ eth_initfreelist(sc);
+ q_init(&sc->rxqueue);
+
+ /* Fill in pointers to the rings */
+ sc->rxdscr_start = (rx_dscr *) (sc->rxdscrmem);
+ sc->rxdscr_end = sc->rxdscr_start + MAXRXDSCR;
+ sc->rxdscr_add = sc->rxdscr_start;
+ sc->rxdscr_remove = sc->rxdscr_start;
+ sc->rxdscr_onring = 0;
+
+ sc->txdscr_start = (tx_dscr *) (sc->txdscrmem);
+ sc->txdscr_end = sc->txdscr_start + MAXTXDSCR;
+ sc->txdscr_add = sc->txdscr_start;
+ sc->txdscr_remove = sc->txdscr_start;
+
+ tulip_initrings(sc);
+
+ return 0;
+}
+
+
+static void
+tulip_resetrings(tulip_softc *sc)
+{
+ volatile tx_dscr *txd;
+ volatile rx_dscr *rxd;
+ int idx;
+
+ /* Free already-sent descriptors and buffers */
+ tulip_proctxring(sc);
+
+ /* Free any pending but unsent */
+ txd = (volatile tx_dscr *) sc->txdscr_remove;
+ while (txd != sc->txdscr_add) {
+ idx = txd - sc->txdscr_start;
+ eth_free_pkt(sc, sc->txdscrinfo[idx]);
+ txd->txd_flags &=~ M_TDES0_OWNADAP;
+
+ txd++;
+ if (txd == sc->txdscr_end)
+ txd = sc->txdscr_start;
+ }
+ sc->txdscr_add = sc->txdscr_remove;
+
+ /* Discard any received packets as well as all free buffers */
+ rxd = (volatile rx_dscr *) sc->rxdscr_remove;
+ while (rxd != sc->rxdscr_add) {
+ idx = rxd - sc->rxdscr_start;
+ eth_free_pkt(sc, sc->rxdscrinfo[idx]);
+ rxd->rxd_flags &=~ M_RDES0_OWNADAP;
+
+ rxd++;
+ if (rxd == sc->rxdscr_end)
+ rxd = sc->rxdscr_start;
+ sc->rxdscr_onring--;
+ }
+
+ /* Reestablish the initial state. */
+ tulip_initrings(sc);
+}
+
+
+/* CRCs */
+
+#define IEEE_CRC32_POLY 0xEDB88320UL /* CRC-32 Poly -- either endian */
+
+static uint32_t
+tulip_crc32(const uint8_t *databuf, unsigned int datalen)
+{
+ unsigned int idx, bit, data;
+ uint32_t crc;
+
+ crc = 0xFFFFFFFFUL;
+ for (idx = 0; idx < datalen; idx++)
+ for (data = *databuf++, bit = 0; bit < 8; bit++, data >>= 1)
+ crc = (crc >> 1) ^ (((crc ^ data) & 1) ? IEEE_CRC32_POLY : 0);
+ return crc;
+}
+
+#define tulip_mchash(mca) (tulip_crc32((mca), 6) & 0x1FF)
+
+
+/* Serial ROM access */
+
+/****************************************************************************
+ * tulip_spin(sc, ns)
+ *
+ * Spin for a short interval (nominally in nanoseconds)
+ *
+ * Input Parameters: ns - minimum required nsec.
+ *
+ * The delay loop uses uncached PCI reads, each of which requires
+ * at least 3 PCI bus clocks (45 ns at 66 MHz) to complete. The
+ * actual delay will be longer (much longer if preempted).
+ ***************************************************************************/
+
+#define PCI_MIN_DELAY 45
+
+static void
+tulip_spin(tulip_softc *sc, long nanoseconds)
+{
+ long delay;
+ volatile uint32_t t;
+
+ for (delay = nanoseconds; delay > 0; delay -= PCI_MIN_DELAY)
+ t = READCSR(sc, R_CSR_BUSMODE);
+}
+
+
+/*
+ * Delays below are chosen to meet specs for NS93C64 (slow M variant).
+ * Current parts are faster.
+ * Reference: NS Memory Data Book, 1994
+ */
+
+#define SROM_SIZE 128
+#define SROM_MAX_CYCLES 32
+
+#define SROM_CMD_BITS 3
+#define SROM_ADDR_BITS 6
+
+#define K_SROM_READ_CMD 06
+#define K_SROM_WRITE_CMD 05
+
+#define SROM_ADDR_OFFSET 0x14
+#define SROM_CRC_OFFSET (SROM_SIZE-2)
+
+
+static void
+srom_idle_state(tulip_softc *sc)
+{
+ uint32_t csr9;
+ unsigned int i;
+
+ csr9 = READCSR(sc, R_CSR_ROM_MII);
+
+ csr9 |= M_CSR9_SROMCHIPSEL;
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 100); /* CS setup (Tcss=100) */
+
+ /* Run the clock through the maximum number of pending read cycles */
+ for (i = 0; i < SROM_MAX_CYCLES*2; i++) {
+ csr9 ^= M_CSR9_SROMCLOCK;
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 1000); /* SK period (Fsk=0.5MHz) */
+ }
+
+ /* Deassert SROM Chip Select */
+ csr9 &=~ M_CSR9_SROMCHIPSEL;
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 50); /* CS recovery (Tsks=50) */
+}
+
+static void
+srom_send_command_bit(tulip_softc *sc, unsigned int data)
+{
+ uint32_t csr9;
+
+ csr9 = READCSR(sc, R_CSR_ROM_MII);
+
+ /* Place the data bit on the bus */
+ if (data == 1)
+ csr9 |= M_CSR9_SROMDATAIN;
+ else
+ csr9 &=~ M_CSR9_SROMDATAIN;
+
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 360); /* setup: Tdis=200 */
+
+ /* Now clock the data into the SROM */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_SROMCLOCK);
+ tulip_spin(sc, 900); /* clock high, Tskh=500 */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 450); /* clock low, Tskl=250 */
+
+ /* Now clear the data bit */
+ csr9 &=~ M_CSR9_SROMDATAIN; /* data invalid, Tidh=20 for SK^ */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 270); /* min cycle, 1/Fsk=2000 */
+}
+
+static uint16_t
+srom_read_bit(tulip_softc *sc)
+{
+ uint32_t csr9;
+
+ csr9 = READCSR(sc, R_CSR_ROM_MII);
+
+ /* Generate a clock cycle before doing a read */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_SROMCLOCK); /* rising edge */
+ tulip_spin(sc, 1000); /* clock high, Tskh=500, Tpd=1000 */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9); /* falling edge */
+ tulip_spin(sc, 1000); /* clock low, 1/Fsk=2000 */
+
+ csr9 = READCSR(sc, R_CSR_ROM_MII);
+ return ((csr9 & M_CSR9_SROMDATAOUT) != 0 ? 1 : 0);
+}
+
+#define CMD_BIT_MASK (1 << (SROM_CMD_BITS+SROM_ADDR_BITS-1))
+
+static uint16_t
+srom_read_word(tulip_softc *sc, unsigned int index)
+{
+ uint16_t command, word;
+ uint32_t csr9;
+ unsigned int i;
+
+ csr9 = READCSR(sc, R_CSR_ROM_MII) | M_CSR9_SROMCHIPSEL;
+
+ /* Assert the SROM CS line */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 100); /* CS setup, Tcss = 100 */
+
+ /* Send the read command to the SROM */
+ command = (K_SROM_READ_CMD << SROM_ADDR_BITS) | index;
+ for (i = 0; i < SROM_CMD_BITS+SROM_ADDR_BITS; i++) {
+ srom_send_command_bit(sc, (command & CMD_BIT_MASK) != 0 ? 1 : 0);
+ command <<= 1;
+ }
+
+ /* Now read the bits from the SROM (MSB first) */
+ word = 0;
+ for (i = 0; i < 16; ++i) {
+ word <<= 1;
+ word |= srom_read_bit(sc);
+ }
+
+ /* Clear the SROM CS Line, CS hold, Tcsh = 0 */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9 &~ M_CSR9_SROMCHIPSEL);
+
+ return word;
+}
+
+
+/****************************************************************************
+ * srom_calc_crc()
+ *
+ * Calculate the CRC of the SROM and return it. We compute the
+ * CRC per Appendix A of the 21140A ROM/external register data
+ * sheet (EC-QPQWA-TE).
+ ***************************************************************************/
+
+static uint16_t
+srom_calc_crc(tulip_softc *sc, uint8_t srom[], int length)
+{
+ uint32_t crc = tulip_crc32(srom, length) ^ 0xffffffff;
+
+ return (uint16_t)(crc & 0xffff);
+}
+
+/****************************************************************************
+ * srom_read_all(sc, uint8_t dest)
+ *
+ * Read the entire SROM into the srom array
+ *
+ * Input parameters:
+ * sc - tulip state
+ ***************************************************************************/
+
+#define STORED_CRC(rom) \
+ ((rom)[SROM_CRC_OFFSET] | ((rom)[SROM_CRC_OFFSET+1] << 8))
+
+static int
+srom_read_all(tulip_softc *sc, uint8_t dest[])
+{
+ int i;
+ uint16_t crc, temp;
+
+ WRITECSR(sc, R_CSR_ROM_MII, M_CSR9_SERROMSEL|M_CSR9_ROMREAD);
+
+ srom_idle_state(sc);
+
+ for (i = 0; i < SROM_SIZE/2; i++) {
+ temp = srom_read_word(sc, i);
+ dest[2*i] = temp & 0xff;
+ dest[2*i+1] =temp >> 8;
+ }
+
+ WRITECSR(sc, R_CSR_ROM_MII, 0); /* CS hold, Tcsh=0 */
+
+ crc = srom_calc_crc(sc, dest, SROM_CRC_OFFSET);
+ if (crc != STORED_CRC(dest)) {
+ crc = srom_calc_crc(sc, dest, 94); /* "alternative" */
+ if (crc != STORED_CRC(dest)) {
+ xprintf("DC2114x: Invalid SROM CRC, calc %04x, stored %04x\n",
+ crc, STORED_CRC(dest));
+ return 0/*-1*/;
+ }
+ }
+ return 0;
+}
+
+static int
+srom_read_addr(tulip_softc *sc, uint8_t buf[])
+{
+ uint8_t srom[SROM_SIZE];
+
+ if (srom_read_all(sc, srom) == 0) {
+ memcpy(buf, &srom[SROM_ADDR_OFFSET], ENET_ADDR_LEN);
+ return 0;
+ }
+
+ return -1;
+}
+
+
+/****************************************************************************
+ * MII access utility routines
+ ***************************************************************************/
+
+/* MII clock limited to 2.5 MHz, transactions end with MDIO tristated */
+
+static void
+mii_write_bits(tulip_softc *sc, uint32_t data, unsigned int count)
+{
+ uint32_t csr9;
+ uint32_t bitmask;
+
+ csr9 = READCSR(sc, R_CSR_ROM_MII) &~ (M_CSR9_MDC | M_CSR9_MIIMODE);
+
+ for (bitmask = 1 << (count-1); bitmask != 0; bitmask >>= 1) {
+ csr9 &=~ M_CSR9_MDO;
+ if ((data & bitmask) != 0) csr9 |= M_CSR9_MDO;
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+
+ tulip_spin(sc, 2000); /* setup */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_MDC);
+ tulip_spin(sc, 2000); /* hold */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ }
+}
+
+static void
+mii_turnaround(tulip_softc *sc)
+{
+ uint32_t csr9;
+
+ csr9 = READCSR(sc, R_CSR_ROM_MII) | M_CSR9_MIIMODE;
+
+ /* stop driving data */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 2000); /* setup */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_MDC);
+ tulip_spin(sc, 2000); /* clock high */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+
+ /* read back and check for 0 here? */
+}
+
+/****************************************************************************
+ * mii_read_register
+ *
+ * This routine reads a register from the PHY chip using the MII
+ * serial management interface.
+ *
+ * Input parameters:
+ * index - index of register to read (0-31)
+ *
+ * Return value:
+ * word read from register
+ ***************************************************************************/
+
+static uint16_t
+mii_read_register(tulip_softc *sc, unsigned int index)
+{
+ /* Send the command and address to the PHY. The sequence is
+ a synchronization sequence (32 1 bits)
+ a "start" command (2 bits)
+ a "read" command (2 bits)
+ the PHY addr (5 bits)
+ the register index (5 bits)
+ */
+ uint32_t csr9;
+ uint16_t word;
+ int i;
+
+ mii_write_bits(sc, 0xff, 8);
+ mii_write_bits(sc, 0xffffffff, 32);
+ mii_write_bits(sc, MII_COMMAND_START, 2);
+ mii_write_bits(sc, MII_COMMAND_READ, 2);
+ mii_write_bits(sc, sc->mii_addr /* XXX sc->phy.index */, 5);
+ mii_write_bits(sc, index, 5);
+
+ mii_turnaround(sc);
+
+ csr9 = (READCSR(sc, R_CSR_ROM_MII) &~ M_CSR9_MDC) | M_CSR9_MIIMODE;
+ word = 0;
+
+ for (i = 0; i < 16; i++) {
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 2000); /* clock width low */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_MDC);
+ tulip_spin(sc, 2000); /* clock width high */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 1000); /* output delay */
+ word <<= 1;
+ if ((READCSR(sc, R_CSR_ROM_MII) & M_CSR9_MDI) != 0)
+ word |= 0x0001;
+ }
+
+ return word;
+
+ /* reset to output mode? */
+}
+
+/****************************************************************************
+ * mii_write_register
+ *
+ * This routine writes a register in the PHY chip using the MII
+ * serial management interface.
+ *
+ * Input parameters:
+ * index - index of register to write (0-31)
+ * value - word to write
+ ***************************************************************************/
+
+static void
+mii_write_register(tulip_softc *sc, unsigned int index, uint16_t value)
+{
+ mii_write_bits(sc, 0xff, 8);
+ mii_write_bits(sc, 0xffffffff, 32);
+ mii_write_bits(sc, MII_COMMAND_START, 2);
+ mii_write_bits(sc, MII_COMMAND_WRITE, 2);
+ mii_write_bits(sc, sc->mii_addr /* XXX sc->phy.index */, 5);
+ mii_write_bits(sc, index, 5);
+ mii_write_bits(sc, MII_COMMAND_ACK, 2);
+ mii_write_bits(sc, value, 16);
+
+ /* reset to input mode? */
+}
+
+
+static int
+mii_probe(tulip_softc *sc)
+{
+ int i;
+ uint16_t id1, id2;
+
+ for (i = 0; i < 32; i++) {
+ sc->mii_addr = i;
+ id1 = mii_read_register(sc, MII_PHYIDR1);
+ id2 = mii_read_register(sc, MII_PHYIDR2);
+ if ((id1 != 0xffff || id2 != 0xffff) &&
+ (id1 != 0x0000 || id2 != 0x0000)) {
+ return 0;
+ }
+ }
+ return -1;
+}
+
+#if 0
+static void
+mii_dump(tulip_softc *sc)
+{
+ int i;
+ uint16_t r;
+
+ for (i = 0; i <=6; ++i) {
+ r = mii_read_register(sc, i);
+ if (r != 0) xprintf("MII_REG%02x: %04x\n", i, r);
+ }
+ for (i = 21; i <= 25; ++i) {
+ r = mii_read_register(sc, i);
+ if (r != 0) printf("MII_REG%02x: %04x\n", i, r);
+ }
+}
+#else
+#define mii_dump(sc)
+#endif
+
+
+#if 0
+static void
+tulip_getaddr(tulip_softc *sc, uint8_t *buf)
+{
+ memcpy(buf, sc->hwaddr, ENET_ADDR_LEN);
+}
+#endif
+
+
+/* Chip specific code */
+
+static void
+dc21143_set_speed(tulip_softc *sc, int speed)
+{
+ uint32_t opmode = 0;
+
+ WRITECSR(sc, R_CSR_SIAMODE0, 0);
+
+ switch (speed) {
+ case ETHER_SPEED_AUTO:
+ break;
+ case ETHER_SPEED_10HDX:
+ default:
+ WRITECSR(sc, R_CSR_SIAMODE1, M_CSR14_10BT_HD);
+ WRITECSR(sc, R_CSR_SIAMODE2, M_CSR15_DEFAULT_VALUE);
+ opmode = M_CSR6_SPEED_10;
+ break;
+ case ETHER_SPEED_10FDX:
+ WRITECSR(sc, R_CSR_SIAMODE1, M_CSR14_10BT_FD);
+ WRITECSR(sc, R_CSR_SIAMODE2, M_CSR15_DEFAULT_VALUE);
+ opmode = M_CSR6_SPEED_10 | M_CSR6_FULLDUPLEX;
+ break;
+ case ETHER_SPEED_100HDX:
+ WRITECSR(sc, R_CSR_SIAMODE1, 0);
+ WRITECSR(sc, R_CSR_SIAMODE2, M_CSR15_DEFAULT_VALUE);
+ opmode = M_CSR6_SPEED_100;
+ break;
+ case ETHER_SPEED_100FDX:
+ WRITECSR(sc, R_CSR_SIAMODE1, 0);
+ WRITECSR(sc, R_CSR_SIAMODE2, M_CSR15_DEFAULT_VALUE);
+ opmode = M_CSR6_SPEED_100 | M_CSR6_FULLDUPLEX;
+ break;
+ }
+
+ WRITECSR(sc, R_CSR_SIAMODE0, M_CSR13_CONN_NOT_RESET);
+
+ opmode |= M_CSR6_MBO;
+#if TULIP_TUNE
+ opmode |= V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72);
+#else
+ opmode |= M_CSR6_STOREFWD;
+#endif
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+}
+
+static void
+dc21143_autonegotiate(tulip_softc *sc)
+{
+ uint32_t opmode;
+ uint32_t tempword;
+ int count;
+ int linkspeed;
+
+ linkspeed = ETHER_SPEED_UNKNOWN;
+
+ /* Program the media setup into the CSRs. */
+ /* reset SIA */
+ WRITECSR(sc, R_CSR_SIAMODE0, 0);
+
+ /* set to speed_10, fullduplex to start_nway */
+ opmode =
+ M_CSR6_SPEED_10 |
+ M_CSR6_FULLDUPLEX |
+ M_CSR6_MBO;
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+
+ /* Choose advertised capabilities */
+ tempword =
+ M_CSR14_100BASETHALFDUP |
+ M_CSR14_100BASETFULLDUP |
+ M_CSR14_HALFDUPLEX10BASET;
+ WRITECSR(sc, R_CSR_SIAMODE1, tempword);
+
+ /* Enable autonegotiation */
+ tempword |= M_CSR14_AUTONEGOTIATE | 0xffff;
+ WRITECSR(sc, R_CSR_SIAMODE1, tempword);
+ WRITECSR(sc, R_CSR_SIAMODE2, M_CSR15_DEFAULT_VALUE);
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+ WRITECSR(sc, R_CSR_SIAMODE0, M_CSR13_CONN_NOT_RESET);
+
+ /* STATE check nway, poll until a valid 10/100mbs signal seen */
+ WRITECSR(sc, R_CSR_STATUS, M_CSR5_LINKPASS); /* try to clear this... */
+
+ /* (Re)start negotiation */
+ tempword = READCSR(sc, R_CSR_SIASTATUS);
+ tempword &=~ M_CSR12_AUTONEGARBIT;
+ tempword |= V_CSR12_AUTONEGARBIT(0x1);
+
+ for (count = 0; count <= 130; count++) {
+ tempword = READCSR(sc, R_CSR_STATUS);
+ if (tempword & M_CSR5_LINKPASS)
+ break;
+ cfe_sleep(CFE_HZ/100);
+ }
+
+ if (count > 130)
+ xprintf("DC21143: Link autonegotiation failed\n");
+
+ /* STATE configure nway, check to see if any abilities common to us.
+ If they do, set to highest mode, if not, we will see if the partner
+ will do 100mb or 10mb - then set it */
+
+ tempword = READCSR(sc, R_CSR_SIASTATUS);
+ /* clear the autonegogiate complete bit */
+ WRITECSR(sc, R_CSR_STATUS, M_CSR5_LINKPASS);
+
+ if (tempword & M_CSR12_LINKPARTNEG) {
+ /* A link partner was negogiated... */
+
+ xprintf("DC21143: Negotiated ");
+ if (tempword & 0x01000000) { /* 100FD */
+ xprintf("100Mb/s FDX");
+ linkspeed = ETHER_SPEED_100FDX;
+ }
+ else if (tempword & 0x00800000) { /* 100HD */
+ xprintf("100Mb/s HDX");
+ linkspeed = ETHER_SPEED_100HDX;
+ }
+ else if (tempword & 0x00400000) { /* 10FD */
+ xprintf("10Mb/s FDX");
+ linkspeed = ETHER_SPEED_10FDX;
+ }
+ else if (tempword & 0x00200000) { /* 10HD */
+ xprintf("10Mb/s HDX");
+ linkspeed = ETHER_SPEED_10HDX;
+ }
+ xprintf("\n");
+ }
+ else {
+ /* no link partner negotiation */
+ /* disable link for 1.3 seconds to break any existing connections */
+
+ /* xprintf("Disabling link, setting to 10mb half duplex\n"); */
+ dc21143_set_speed(sc, ETHER_SPEED_10HDX);
+ cfe_sleep(CFE_HZ/8);
+
+ tempword = READCSR(sc, R_CSR_SIASTATUS);
+
+ if ((tempword & 0x02) == 0) {
+ /* 100 mb signal present set to 100mb */
+ xprintf("No link partner... setting to 100mb/s HDX\n");
+ linkspeed = ETHER_SPEED_100HDX;
+ }
+ else if ((tempword & 0x04) == 0) {
+ /* 10 mb signal present */
+ xprintf("No link partner... setting to 10mb/s HDX\n");
+ linkspeed = ETHER_SPEED_10HDX;
+ }
+ else {
+ /* couldn't determine line speed, so set to 10mbs */
+ xprintf("Unknown; defaulting to 10Mb/s HDX\n");
+ linkspeed = ETHER_SPEED_10HDX;
+ }
+ }
+
+ dc21143_set_speed(sc, linkspeed);
+}
+
+static void
+dc21143_set_loopback(tulip_softc *sc, int mode)
+{
+ uint32_t v;
+
+ WRITECSR(sc, R_CSR_SIAMODE0, 0);
+ if (mode == ETHER_LOOPBACK_EXT) {
+ /* deal with CSRs 13-15 */
+ }
+ cfe_sleep(CFE_HZ/10); /* check this */
+
+ /* Update the SIA registers */
+ v = READCSR(sc, R_CSR_SIAMODE0);
+ WRITECSR(sc, R_CSR_SIAMODE0, v &~ 0xFFFF);
+ v = READCSR(sc, R_CSR_SIAMODE1);
+ WRITECSR(sc, R_CSR_SIAMODE1, v &~ 0xFFFF);
+ v = READCSR(sc, R_CSR_SIAMODE2);
+ WRITECSR(sc, R_CSR_SIAMODE2, v | 0xC000); /* WC of HCKR, RMP */
+ WRITECSR(sc, R_CSR_SIAMODE2, (v &~ 0xFFFF) | M_CSR15_GP_AUIBNC);
+
+ WRITECSR(sc, R_CSR_SIAMODE0, M_CSR13_CONN_NOT_RESET);
+}
+
+static void
+dc21143_hwinit(tulip_softc *sc)
+{
+ uint32_t v;
+ uint32_t csr6word, csr14word;
+
+ /* CSR0 - bus mode */
+ WRITECSR(sc, R_CSR_SIAMODE2, M_CSR15_CONFIG_GEPS_LEDS);
+#if TULIP_TUNE
+ v = V_CSR0_SKIPLEN(0) |
+ V_CSR0_CACHEALIGN(K_CSR0_ALIGN32) |
+ M_CSR0_READMULTENAB | M_CSR0_READLINEENAB |
+ M_CSR0_WRITEINVALENAB |
+ V_CSR0_BURSTLEN(K_CSR0_BURST32);
+#else
+ v = V_CSR0_SKIPLEN(0) |
+ V_CSR0_CACHEALIGN(K_CSR0_ALIGN128) |
+ V_CSR0_BURSTLEN(K_CSR0_BURST32);
+#endif
+#ifdef __MIPSEB
+ v |= M_CSR0_BIGENDIAN; /* big-endian data serialization */
+#endif
+ WRITECSR(sc, R_CSR_BUSMODE, v);
+
+ /* CSR6 - operation mode */
+ v = M_CSR6_PORTSEL |
+#if TULIP_TUNE
+ V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72) |
+#else
+ M_CSR6_STOREFWD |
+#endif
+ M_CSR6_MBO |
+ M_CSR6_PCSFUNC |
+ M_CSR6_SCRAMMODE;
+ WRITECSR(sc, R_CSR_OPMODE, v);
+
+ /* About to muck the SIA, reset it.(?) */
+ /* WRITECSR(sc, R_CSR_SIASTATUS, 1); */
+
+ /* Must shut off all transmit/receive in order to attempt to
+ achieve Full Duplex */
+ csr6word = READCSR(sc, R_CSR_OPMODE);
+ WRITECSR(sc, R_CSR_OPMODE, csr6word &~ (M_CSR6_TXSTART | M_CSR6_RXSTART));
+ csr6word = READCSR(sc, R_CSR_OPMODE);
+
+ WRITECSR(sc, R_CSR_RXRING, PCIADDRX(sc, PHYSADDR(sc, sc->rxdscr_start)));
+ WRITECSR(sc, R_CSR_TXRING, PCIADDRX(sc, PHYSADDR(sc, sc->txdscr_start)));
+
+ if (sc->linkspeed == ETHER_SPEED_AUTO) {
+ dc21143_autonegotiate(sc);
+ }
+ else {
+ /* disable autonegotiate so we can set full duplex to on */
+ WRITECSR(sc, R_CSR_SIAMODE0, 0);
+ csr14word = READCSR(sc, R_CSR_SIAMODE1);
+ csr14word &=~ M_CSR14_AUTONEGOTIATE;
+ WRITECSR(sc, R_CSR_SIAMODE1, csr14word);
+ WRITECSR(sc, R_CSR_SIAMODE0, M_CSR13_CONN_NOT_RESET);
+
+ dc21143_set_speed(sc, sc->linkspeed);
+ }
+}
+
+
+static void
+dc21140_set_speed(tulip_softc *sc, int speed, int autoneg)
+{
+ uint16_t control;
+ uint16_t pcr;
+ uint32_t opmode = 0;
+
+ pcr = mii_read_register(sc, 0x17);
+ pcr |= (0x400|0x100|0x40|0x20);
+ mii_write_register(sc, 0x17, pcr);
+
+ control = mii_read_register(sc, MII_BMCR);
+
+ if (!autoneg) {
+ control &=~ (BMCR_ANENABLE | BMCR_RESTARTAN);
+ mii_write_register(sc, MII_BMCR, control);
+ control &=~ (BMCR_SPEED0 | BMCR_SPEED1 | BMCR_DUPLEX);
+ }
+
+ switch (speed) {
+ case ETHER_SPEED_10HDX:
+ default:
+ opmode = M_CSR6_SPEED_10_MII;
+ break;
+ case ETHER_SPEED_10FDX:
+ control |= BMCR_DUPLEX;
+ opmode = M_CSR6_SPEED_10_MII | M_CSR6_FULLDUPLEX;
+ break;
+ case ETHER_SPEED_100HDX:
+ control |= BMCR_SPEED100;
+ opmode = M_CSR6_SPEED_100_MII;
+ break;
+ case ETHER_SPEED_100FDX:
+ control |= BMCR_SPEED100 | BMCR_DUPLEX ;
+ opmode = M_CSR6_SPEED_100_MII | M_CSR6_FULLDUPLEX;
+ break;
+ }
+
+ if (!autoneg)
+ mii_write_register(sc, MII_BMCR, control);
+
+ opmode |= M_CSR6_MBO;
+#if TULIP_TUNE
+ opmode |= V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72);
+#else
+ opmode |= M_CSR6_STOREFWD;
+#endif
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+#if 0
+ xprintf("setspeed PHY\n"); mii_dump(sc);
+#endif
+}
+
+static void
+dc21140_autonegotiate(tulip_softc *sc)
+{
+ uint16_t control, status, cap;
+ unsigned int timeout;
+ int linkspeed;
+ int autoneg;
+
+ linkspeed = ETHER_SPEED_UNKNOWN;
+
+ /* Read twice to clear latching bits */
+ status = mii_read_register(sc, MII_BMSR);
+ status = mii_read_register(sc, MII_BMSR);
+#if 0
+ xprintf("query PHY\n"); mii_dump(sc);
+#endif
+
+ if ((status & (BMSR_AUTONEG | BMSR_LINKSTAT)) ==
+ (BMSR_AUTONEG | BMSR_LINKSTAT))
+ control = mii_read_register(sc, MII_BMCR);
+ else {
+ /* reset the PHY */
+ mii_write_register(sc, MII_BMCR, BMCR_RESET);
+ timeout = 3000;
+ for (;;) {
+ control = mii_read_register(sc, MII_BMCR);
+ if ((control && BMCR_RESET) == 0) break;
+ cfe_sleep(CFE_HZ/2);
+ timeout -= 500;
+ if (timeout <= 0) break;
+ }
+ if ((control & BMCR_RESET) != 0) {
+ xprintf("DC21140: PHY reset failed\n");
+ return;
+ }
+
+ status = mii_read_register(sc, MII_BMSR);
+ cap = ((status >> 6) & (ANAR_TXFD | ANAR_TXHD | ANAR_10FD | ANAR_10HD))
+ | PSB_802_3;
+ mii_write_register(sc, MII_ANAR, cap);
+ control |= (BMCR_ANENABLE | BMCR_RESTARTAN);
+ mii_write_register(sc, MII_BMCR, control);
+
+ timeout = 3000;
+ for (;;) {
+ status = mii_read_register(sc, MII_BMSR);
+ if ((status & BMSR_ANCOMPLETE) != 0) break;
+ cfe_sleep(CFE_HZ/2);
+ timeout -= 500;
+ if (timeout <= 0) break;
+ }
+#if 0
+ xprintf("done PHY\n"); mii_dump(sc);
+#endif
+ }
+
+ if ((status & BMSR_ANCOMPLETE) != 0) {
+ /* A link partner was negogiated... */
+
+ uint16_t remote = mii_read_register(sc, MII_ANLPAR);
+
+ autoneg = 1;
+ xprintf("DC21140: Negotiated ");
+ if ((remote & ANLPAR_TXFD) != 0) {
+ xprintf("100Mb/s FDX");
+ linkspeed = ETHER_SPEED_100FDX;
+ }
+ else if ((remote & ANLPAR_TXHD) != 0) {
+ xprintf("100Mb/s HDX");
+ linkspeed = ETHER_SPEED_100HDX;
+ }
+ else if ((remote & ANLPAR_10FD) != 0) {
+ xprintf("10Mb/s FDX");
+ linkspeed = ETHER_SPEED_10FDX;
+ }
+ else if ((remote & ANLPAR_10HD) != 0) {
+ xprintf("10Mb/s HDX");
+ linkspeed = ETHER_SPEED_10HDX;
+ }
+ xprintf("\n");
+ }
+ else {
+ /* no link partner negotiation */
+
+ autoneg = 0;
+ xprintf("DC21140: MII negotiation failed, assuming 10BT\n");
+ control &=~ (BMCR_ANENABLE | BMCR_RESTARTAN);
+ mii_write_register(sc, MII_BMCR, control);
+ linkspeed = ETHER_SPEED_10HDX;
+ }
+
+ if ((status & BMSR_LINKSTAT) == 0)
+ mii_write_register(sc, MII_BMCR, control);
+ dc21140_set_speed(sc, linkspeed, autoneg);
+
+ status = mii_read_register(sc, MII_BMSR); /* clear latching bits */
+#if 0
+ xprintf("final PHY\n"); mii_dump(sc);
+#endif
+}
+
+static void
+dc21140_set_loopback(tulip_softc *sc, int mode)
+{
+ if (mode == ETHER_LOOPBACK_EXT)
+ xprintf("DC21140: external loopback mode NYI\n");
+}
+
+static void
+dc21140_hwinit(tulip_softc *sc)
+{
+ uint32_t v;
+ uint32_t csr6word;
+
+ /* The following assume GP port bits wired per the DEC reference design.
+ XXX Interpret the srom initialization strings instead */
+ WRITECSR(sc, R_CSR_GENPORT, M_CSR12_CONTROL | 0x1F);
+ WRITECSR(sc, R_CSR_GENPORT, 0); /* release PHY reset */
+
+ /* Select MII interface */
+ WRITECSR(sc, R_CSR_OPMODE, M_CSR6_PORTSEL);
+ RESET_ADAPTER(sc);
+
+ mii_probe(sc);
+
+ /* CSR0 - bus mode */
+#if TULIP_TUNE
+ v = V_CSR0_SKIPLEN(0) |
+ V_CSR0_CACHEALIGN(K_CSR0_ALIGN32) |
+ M_CSR0_READMULTENAB | M_CSR0_READLINEENAB |
+ M_CSR0_WRITEINVALENAB |
+ V_CSR0_BURSTLEN(K_CSR0_BURST32);
+#else
+ v = V_CSR0_SKIPLEN(0) |
+ V_CSR0_CACHEALIGN(K_CSR0_ALIGN128) |
+ V_CSR0_BURSTLEN(K_CSR0_BURST32);
+#endif
+#ifdef __MIPSEB
+ v |= M_CSR0_BIGENDIAN; /* big-endian data serialization */
+#endif
+ WRITECSR(sc, R_CSR_BUSMODE, v);
+
+ /* CSR6 - operation mode */
+ v = M_CSR6_PORTSEL |
+#if TULIP_TUNE
+ V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72) |
+#else
+ M_CSR6_STOREFWD |
+#endif
+ M_CSR6_MBO;
+ WRITECSR(sc, R_CSR_OPMODE, v);
+
+ /* Must shut off all transmit/receive in order to attempt to
+ achieve Full Duplex */
+ csr6word = READCSR(sc, R_CSR_OPMODE);
+ WRITECSR(sc, R_CSR_OPMODE, csr6word &~ (M_CSR6_TXSTART | M_CSR6_RXSTART));
+ csr6word = READCSR(sc, R_CSR_OPMODE);
+
+ WRITECSR(sc, R_CSR_RXRING, PCIADDRX(sc, PHYSADDR(sc, sc->rxdscr_start)));
+ WRITECSR(sc, R_CSR_TXRING, PCIADDRX(sc, PHYSADDR(sc, sc->txdscr_start)));
+
+ if (sc->linkspeed == ETHER_SPEED_AUTO) {
+ dc21140_autonegotiate(sc);
+ }
+ else {
+ dc21140_set_speed(sc, sc->linkspeed, 0);
+ }
+}
+
+
+static void
+dc21041_set_loopback(tulip_softc *sc, int mode)
+{
+ uint32_t v;
+
+ WRITECSR(sc, R_CSR_SIAMODE0, 0);
+ if (mode == ETHER_LOOPBACK_EXT) {
+ /* deal with CSRs 13-15 */
+ }
+ cfe_sleep(CFE_HZ/10); /* check this */
+
+ /* Update the SIA registers */
+ v = READCSR(sc, R_CSR_SIAMODE0);
+ WRITECSR(sc, R_CSR_SIAMODE0, v &~ 0xFFFF);
+ WRITECSR(sc, R_CSR_SIAMODE1, 0x7A3F);
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x0008);
+
+ WRITECSR(sc, R_CSR_SIAMODE0, 0xEF01);
+}
+
+static void
+dc21041_hwinit(tulip_softc *sc)
+{
+ uint32_t v;
+ uint32_t opmode;
+
+ /* CSR0 - bus mode */
+ v = V_CSR0_SKIPLEN(0) |
+ V_CSR0_CACHEALIGN(K_CSR0_ALIGN128) |
+ V_CSR0_BURSTLEN(K_CSR0_BURST32);
+#ifdef __MIPSEB
+ v |= M_CSR0_BIGENDIAN; /* big-endian data serialization */
+#endif
+ WRITECSR(sc, R_CSR_BUSMODE, v);
+
+ /* set initial interrupt mask here? */
+
+ WRITECSR(sc, R_CSR_RXRING, PCIADDRX(sc, PHYSADDR(sc, sc->rxdscr_start)));
+ WRITECSR(sc, R_CSR_TXRING, PCIADDRX(sc, PHYSADDR(sc, sc->txdscr_start)));
+
+ WRITECSR(sc, R_CSR_SIAMODE0, 0);
+
+ /* For now, always force 10BT, HDX */
+ WRITECSR(sc, R_CSR_SIAMODE1, 0x7F3F);
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x0008);
+ opmode = M_CSR6_SPEED_10;
+
+ WRITECSR(sc, R_CSR_SIAMODE0, 0xEF01);
+ cfe_sleep(CFE_HZ/10);
+
+ opmode |= V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72);
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+}
+
+
+static void
+tulip_hwinit(tulip_softc *sc)
+{
+ if (sc->state == eth_state_uninit) {
+ RESET_ADAPTER(sc);
+ sc->state = eth_state_off;
+ sc->bus_errors = 0;
+
+ switch (sc->device) {
+ case K_PCI_ID_DC21041:
+ dc21041_hwinit(sc);
+ break;
+ case K_PCI_ID_DC21140:
+ dc21140_hwinit(sc);
+ break;
+ case K_PCI_ID_DC21143:
+ dc21143_hwinit(sc);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+
+static void
+tulip_isr(tulip_softc *sc)
+{
+ uint32_t status;
+ uint32_t csr5;
+
+ for (;;) {
+
+ /* Read the interrupt status. */
+ csr5 = READCSR(sc, R_CSR_STATUS);
+// status &= sc->intmask; /* keep only the bits we like. */
+ status = csr5 & (
+ M_CSR5_RXINT | M_CSR5_RXBUFUNAVAIL |
+ M_CSR5_TXINT | M_CSR5_TXUNDERFLOW |
+ M_CSR5_FATALBUSERROR);
+
+ /* if there are no more interrupts, leave now. */
+ if (status == 0) break;
+
+ /* Clear the pending interrupt. */
+ WRITECSR(sc, R_CSR_STATUS, status);
+
+ /* Now, test each unmasked bit in the interrupt register and
+ handle each interrupt type appropriately. */
+
+ if (status & M_CSR5_FATALBUSERROR) {
+ xprintf("DC21143: bus error %02x\n", G_CSR5_ERRORBITS(csr5));
+ dumpstat(sc);
+ sc->bus_errors++;
+ if (sc->bus_errors >= 2) {
+ dumpcsrs(sc);
+ RESET_ADAPTER(sc);
+ sc->state = eth_state_off;
+ sc->bus_errors = 0;
+ }
+ }
+
+ if (status & M_CSR5_RXINT) {
+ tulip_procrxring(sc);
+ }
+
+ if (status & M_CSR5_TXINT) {
+ tulip_proctxring(sc);
+ }
+
+ if (status & (M_CSR5_TXUNDERFLOW | M_CSR5_RXBUFUNAVAIL)) {
+ if (status & M_CSR5_TXUNDERFLOW) {
+ xprintf("DC21143: tx underrun, %08x\n", csr5);
+ /* Try to restart */
+ WRITECSR(sc, R_CSR_TXPOLL, 1);
+ }
+ if (status & M_CSR5_RXBUFUNAVAIL) {
+ /* Try to restart */
+ WRITECSR(sc, R_CSR_RXPOLL, 1);
+ }
+ }
+ }
+}
+
+
+static void
+tulip_start(tulip_softc *sc)
+{
+ uint32_t opmode;
+ int idx;
+ tulip_cam *cam;
+ eth_pkt_t *pkt;
+
+ tulip_hwinit(sc);
+
+ WRITECSR(sc, R_CSR_RXRING, PCIADDRX(sc, PHYSADDR(sc, sc->rxdscr_start)));
+ WRITECSR(sc, R_CSR_TXRING, PCIADDRX(sc, PHYSADDR(sc, sc->txdscr_start)));
+
+ opmode = READCSR(sc, R_CSR_OPMODE);
+ opmode &=~ M_CSR6_OPMODE; /* no loopback */
+ opmode |= (M_CSR6_TXSTART | M_CSR6_RXSTART);
+
+ sc->intmask = 0;
+ WRITECSR(sc, R_CSR_INTMASK, 0); /* no interrupts */
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+
+ pkt = eth_alloc_pkt(sc);
+ if (pkt) {
+ pkt->length = CAM_SETUP_BUFFER_SIZE;
+ cam = (tulip_cam *) pkt->buffer;
+
+#ifdef __MIPSEB
+ cam->p.physical[0][0] = (((uint32_t) sc->hwaddr[0] << 8) |
+ (uint32_t) sc->hwaddr[1]) << 16;
+ cam->p.physical[0][1] = (((uint32_t) sc->hwaddr[2] << 8) |
+ (uint32_t) sc->hwaddr[3]) << 16;
+ cam->p.physical[0][2] = (((uint32_t) sc->hwaddr[4] << 8) |
+ (uint32_t) sc->hwaddr[5]) << 16;
+ for (idx = 1; idx < CAM_PERFECT_ENTRIES; idx++) {
+ cam->p.physical[idx][0] = 0xFFFF0000;
+ cam->p.physical[idx][1] = 0xFFFF0000;
+ cam->p.physical[idx][2] = 0xFFFF0000;
+ }
+#else
+ cam->p.physical[0][0] = ((uint32_t) sc->hwaddr[0]) |
+ (((uint32_t) sc->hwaddr[1]) << 8);
+ cam->p.physical[0][1] = ((uint32_t) sc->hwaddr[2]) |
+ (((uint32_t) sc->hwaddr[3]) << 8);
+ cam->p.physical[0][2] = ((uint32_t) sc->hwaddr[4]) |
+ (((uint32_t) sc->hwaddr[5]) << 8);
+ for (idx = 1; idx < CAM_PERFECT_ENTRIES; idx++) {
+ cam->p.physical[idx][0] = 0x0000FFFF;
+ cam->p.physical[idx][1] = 0x0000FFFF;
+ cam->p.physical[idx][2] = 0x0000FFFF;
+ }
+#endif
+
+ pkt->flags |= ETH_TX_SETUP;
+ if (tulip_transmit(sc, pkt) != 0) {
+ xprintf("DC21143: failed setup\n");
+ dumpstat(sc);
+ eth_free_pkt(sc, pkt);
+ return;
+ }
+ sc->state = eth_state_setup;
+ }
+}
+
+static void
+tulip_stop(tulip_softc *sc)
+{
+ uint32_t opmode;
+ uint32_t status;
+ int count;
+
+ WRITECSR(sc, R_CSR_INTMASK, 0);
+ sc->intmask = 0;
+
+ opmode = READCSR(sc, R_CSR_OPMODE);
+ opmode &=~ (M_CSR6_TXSTART | M_CSR6_RXSTART);
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+
+ /* wait for any DMA activity to terminate */
+ for (count = 0; count <= 130; count++) {
+ status = READCSR(sc, R_CSR_STATUS);
+ if ((status & (M_CSR5_RXPROCSTATE | M_CSR5_TXPROCSTATE)) == 0)
+ break;
+ cfe_sleep(CFE_HZ/10);
+ }
+ if (count > 130) {
+ xprintf("DC21143: idle state not achieved\n");
+ dumpstat(sc);
+ }
+}
+
+
+static void
+tulip_start_loopback(tulip_softc *sc, int mode)
+{
+ uint32_t opmode;
+
+ opmode = READCSR(sc, R_CSR_OPMODE);
+
+ switch (sc->device) {
+ case K_PCI_ID_DC21041:
+ dc21041_set_loopback(sc, mode);
+ break;
+ case K_PCI_ID_DC21140:
+ dc21140_set_loopback(sc, mode);
+ break;
+ case K_PCI_ID_DC21143:
+ dc21143_set_loopback(sc, mode);
+ break;
+ default:
+ break;
+ }
+ cfe_sleep(CFE_HZ/10);
+
+ WRITECSR(sc, R_CSR_RXRING, PCIADDRX(sc, PHYSADDR(sc, sc->rxdscr_start)));
+ WRITECSR(sc, R_CSR_TXRING, PCIADDRX(sc, PHYSADDR(sc, sc->txdscr_start)));
+
+ sc->intmask = 0; /* no interrupts */
+ WRITECSR(sc, R_CSR_INTMASK, 0);
+
+ opmode &=~ (M_CSR6_OPMODE | M_CSR6_FULLDUPLEX);
+ opmode |= M_CSR6_PORTSEL;
+ if (mode == ETHER_LOOPBACK_EXT)
+ opmode |= M_CSR6_EXTLOOPBACK;
+ else
+ opmode |= M_CSR6_INTLOOPBACK;
+ opmode |= M_CSR6_TXSTART | M_CSR6_RXSTART;
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+}
+
+
+/* *********************************************************************
+ * ETH_PARSE_XDIGIT(c)
+ *
+ * Parse a hex digit, returning its value
+ *
+ * Input parameters:
+ * c - character
+ *
+ * Return value:
+ * hex value, or -1 if invalid
+ ********************************************************************* */
+static int
+eth_parse_xdigit(char c)
+{
+ int digit;
+
+ if ((c >= '0') && (c <= '9')) digit = c - '0';
+ else if ((c >= 'a') && (c <= 'f')) digit = c - 'a' + 10;
+ else if ((c >= 'A') && (c <= 'F')) digit = c - 'A' + 10;
+ else digit = -1;
+
+ return digit;
+}
+
+/* *********************************************************************
+ * ETH_PARSE_HWADDR(str,hwaddr)
+ *
+ * Convert a string in the form xx:xx:xx:xx:xx:xx into a 6-byte
+ * Ethernet address.
+ *
+ * Input parameters:
+ * str - string
+ * hwaddr - pointer to hardware address
+ *
+ * Return value:
+ * 0 if ok, else -1
+ ********************************************************************* */
+static int
+eth_parse_hwaddr(char *str, uint8_t *hwaddr)
+{
+ int digit1, digit2;
+ int idx = ENET_ADDR_LEN;
+
+ while (*str && (idx > 0)) {
+ digit1 = eth_parse_xdigit(*str);
+ if (digit1 < 0) return -1;
+ str++;
+ if (!*str) return -1;
+
+ if ((*str == ':') || (*str == '-')) {
+ digit2 = digit1;
+ digit1 = 0;
+ }
+ else {
+ digit2 = eth_parse_xdigit(*str);
+ if (digit2 < 0) return -1;
+ str++;
+ }
+
+ *hwaddr++ = (digit1 << 4) | digit2;
+ idx--;
+
+ if ((*str == ':') || (*str == '-'))
+ str++;
+ }
+ return 0;
+}
+
+/* *********************************************************************
+ * ETH_INCR_HWADDR(hwaddr,incr)
+ *
+ * Increment a 6-byte Ethernet hardware address, with carries
+ *
+ * Input parameters:
+ * hwaddr - pointer to hardware address
+ * incr - desired increment
+ *
+ * Return value:
+ * none
+ ********************************************************************* */
+static void
+eth_incr_hwaddr(uint8_t *hwaddr, unsigned incr)
+{
+ int idx;
+ int carry;
+
+ idx = 5;
+ carry = incr;
+ while (idx >= 0 && carry != 0) {
+ unsigned sum = hwaddr[idx] + carry;
+
+ hwaddr[idx] = sum & 0xff;
+ carry = sum >> 8;
+ idx--;
+ }
+}
+
+
+/* *********************************************************************
+ * Declarations for CFE Device Driver Interface routines
+ ********************************************************************* */
+
+static int tulip_ether_open(cfe_devctx_t *ctx);
+static int tulip_ether_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int tulip_ether_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
+static int tulip_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int tulip_ether_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int tulip_ether_close(cfe_devctx_t *ctx);
+
+/* *********************************************************************
+ * CFE Device Driver dispatch structure
+ ********************************************************************* */
+
+const static cfe_devdisp_t tulip_ether_dispatch = {
+ tulip_ether_open,
+ tulip_ether_read,
+ tulip_ether_inpstat,
+ tulip_ether_write,
+ tulip_ether_ioctl,
+ tulip_ether_close,
+ NULL,
+ NULL
+};
+
+/* *********************************************************************
+ * CFE Device Driver descriptor
+ ********************************************************************* */
+
+const cfe_driver_t dc21143drv = {
+ "DC2114x Ethernet",
+ "eth",
+ CFE_DEV_NETWORK,
+ &tulip_ether_dispatch,
+ tulip_ether_probe
+};
+
+
+static int
+tulip_ether_attach(cfe_driver_t *drv,
+ pcitag_t tag, int index, uint8_t hwaddr[], int host)
+{
+ tulip_softc *softc;
+ uint32_t device;
+ uint32_t class;
+ uint32_t reg;
+ phys_addr_t pa;
+ char descr[100];
+ uint8_t romaddr[ENET_ADDR_LEN];
+#if 0 /* temporary */
+ int i;
+ uint8_t srom[SROM_SIZE];
+#endif
+
+ device = pci_conf_read(tag, R_CFG_CFID);
+
+ class = pci_conf_read(tag, R_CFG_CFRV);
+
+ reg = pci_conf_read(tag, R_CFG_CPMS);
+
+ reg = pci_conf_read(tag, R_CFG_CFDD);
+ pci_conf_write(tag, R_CFG_CFDD, 0);
+ reg = pci_conf_read(tag, R_CFG_CFDD);
+
+#if 1
+ /* Use memory space for the CSRs */
+ pci_map_mem(tag, R_CFG_CBMA, PCI_MATCH_BITS, &pa);
+#else
+ /* Use i/o space for the CSRs */
+ pci_map_io(tag, R_CFG_CBIO, PCI_MATCH_BITS, &pa);
+#endif
+
+ softc = (tulip_softc *) KMALLOC(sizeof(tulip_softc), 0);
+ if (softc == NULL) {
+ xprintf("DC2114x: No memory to complete probe\n");
+ return 0;
+ }
+
+ memset(softc, 0, sizeof(*softc));
+
+ softc->membase = (uint32_t)pa;
+
+ /* If we are in Host mode, we can receive interrupts. Otherwise,
+ we can see the CSRs but our CPU will not get interrupts. */
+ if (host)
+ softc->irq = pci_conf_read(tag, R_CFG_CFIT) & 0xFF;
+ else
+ softc->irq = 0xFF;
+
+ softc->tag = tag;
+ softc->device = PCI_PRODUCT(device);
+ softc->revision = PCI_REVISION(class);
+#if 1
+ softc->linkspeed = ETHER_SPEED_AUTO; /* select autonegotiation */
+#else
+ softc->linkspeed = ETHER_SPEED_100HDX; /* 100 Mbps, full duplex */
+#endif
+ memcpy(softc->hwaddr, hwaddr, ENET_ADDR_LEN);
+
+ tulip_init(softc);
+
+ /* Prefer address in srom */
+ if (srom_read_addr(softc, romaddr) == 0)
+ memcpy(softc->hwaddr, romaddr, ENET_ADDR_LEN);
+
+ softc->state = eth_state_uninit;
+
+ xsprintf(descr, "%s at 0x%X (%02x-%02x-%02x-%02x-%02x-%02x)",
+ drv->drv_description, softc->membase,
+ softc->hwaddr[0], softc->hwaddr[1], softc->hwaddr[2],
+ softc->hwaddr[3], softc->hwaddr[4], softc->hwaddr[5]);
+ cfe_attach(drv, softc, NULL, descr);
+ return 1;
+}
+
+
+/* *********************************************************************
+ * TULIP_ETHER_PROBE(drv,probe_a,probe_b,probe_ptr)
+ *
+ * Probe and install drivers for all DC2114x Ethernet controllers.
+ * For each, creates a context structure and attaches to the
+ * specified MAC devices.
+ *
+ * Input parameters:
+ * drv - driver descriptor
+ * probe_a - not used
+ * probe_b - not used
+ * probe_ptr - string pointer to hardware address for the first
+ * MAC, in the form xx:xx:xx:xx:xx:xx
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void
+tulip_ether_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ int index;
+ int n;
+ uint8_t hwaddr[ENET_ADDR_LEN];
+
+ if (probe_ptr)
+ eth_parse_hwaddr((char *) probe_ptr, hwaddr);
+ else {
+ /* use default address 40-00-00-10-11-11 */
+ hwaddr[0] = 0x40; hwaddr[1] = 0x00;
+ hwaddr[2] = 0x00; hwaddr[3] = 0x10;
+ hwaddr[4] = 0x11; hwaddr[5] = 0x11;
+ }
+
+ n = 0;
+ index = 0;
+ for (;;) {
+ pcitag_t tag;
+ pcireg_t device;
+
+ if (pci_find_class(PCI_CLASS_NETWORK, index, &tag) != 0)
+ break;
+
+ index++;
+
+ device = pci_conf_read(tag, R_CFG_CFID);
+ if (PCI_VENDOR(device) != K_PCI_VENDOR_DEC)
+ continue;
+ switch (PCI_PRODUCT(device)) {
+ case K_PCI_ID_DC21041:
+ break;
+ case K_PCI_ID_DC21140:
+ break;
+ case K_PCI_ID_DC21143:
+ break;
+ default:
+ continue;
+ }
+
+ tulip_ether_attach(drv, tag, index, hwaddr, 1);
+
+ n++;
+ eth_incr_hwaddr(hwaddr, 1);
+ }
+}
+
+
+/* The functions below are called via the dispatch vector for the 2114x. */
+
+/* *********************************************************************
+ * TULIP_ETHER_OPEN(ctx)
+ *
+ * Open the Ethernet device. The MAC is reset, initialized, and
+ * prepared to receive and send packets.
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ *
+ * Return value:
+ * status, 0 = ok
+ ********************************************************************* */
+static int
+tulip_ether_open(cfe_devctx_t *ctx)
+{
+ tulip_softc *softc = ctx->dev_softc;
+
+ if (softc->state == eth_state_on)
+ tulip_stop(softc);
+
+ tulip_start(softc);
+ softc->state = eth_state_on;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * TULIP_ETHER_READ(ctx,buffer)
+ *
+ * Read a packet from the Ethernet device. If no packets are
+ * available, the read will succeed but return 0 bytes.
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ * buffer - pointer to buffer descriptor.
+ *
+ * Return value:
+ * status, 0 = ok
+ ********************************************************************* */
+static int
+tulip_ether_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ tulip_softc *softc = ctx->dev_softc;
+ eth_pkt_t *pkt;
+ int blen;
+
+ if (softc->state != eth_state_on) return -1;
+
+ tulip_isr(softc);
+
+ pkt = (eth_pkt_t *) q_deqnext(&(softc->rxqueue));
+
+ if (pkt == NULL) {
+ buffer->buf_retlen = 0;
+ return 0;
+ }
+
+ blen = buffer->buf_length;
+ if (blen > pkt->length) blen = pkt->length;
+
+ memcpy(buffer->buf_ptr, pkt->buffer, blen);
+ buffer->buf_retlen = blen;
+
+ eth_free_pkt(softc,pkt);
+ tulip_fillrxring(softc);
+ tulip_isr(softc);
+
+ return 0;
+}
+
+/* *********************************************************************
+ * TULIP_ETHER_INPSTAT(ctx,inpstat)
+ *
+ * Check for received packets on the Ethernet device
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ * inpstat - pointer to input status structure
+ *
+ * Return value:
+ * status, 0 = ok
+ ********************************************************************* */
+static int
+tulip_ether_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat)
+{
+ tulip_softc *softc = ctx->dev_softc;
+
+ if (softc->state != eth_state_on) return -1;
+
+ tulip_isr(softc);
+
+ inpstat->inp_status = (q_isempty(&(softc->rxqueue))) ? 0 : 1;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * TULIP_ETHER_WRITE(ctx,buffer)
+ *
+ * Write a packet to the Ethernet device.
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ * buffer - pointer to buffer descriptor.
+ *
+ * Return value:
+ * status, 0 = ok
+ ********************************************************************* */
+static int
+tulip_ether_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ tulip_softc *softc = ctx->dev_softc;
+ eth_pkt_t *pkt;
+ int blen;
+
+ if (softc->state != eth_state_on) return -1;
+
+ pkt = eth_alloc_pkt(softc);
+ if (!pkt) return -1;
+
+ blen = buffer->buf_length;
+ if (blen > pkt->length) blen = pkt->length;
+
+ memcpy(pkt->buffer, buffer->buf_ptr, blen);
+ pkt->length = blen;
+
+ tulip_isr(softc);
+
+ if (tulip_transmit(softc, pkt) != 0) {
+ eth_free_pkt(softc,pkt);
+ return -1;
+ }
+
+ tulip_isr(softc);
+
+ return 0;
+}
+
+/* *********************************************************************
+ * TULIP_ETHER_IOCTL(ctx,buffer)
+ *
+ * Do device-specific I/O control operations for the device
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ * buffer - pointer to buffer descriptor.
+ *
+ * Return value:
+ * status, 0 = ok
+ ********************************************************************* */
+static int
+tulip_ether_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ tulip_softc *softc = ctx->dev_softc;
+ int mode;
+
+ switch ((int)buffer->buf_ioctlcmd) {
+ case IOCTL_ETHER_GETHWADDR:
+ memcpy(buffer->buf_ptr, softc->hwaddr, sizeof(softc->hwaddr));
+ return 0;
+
+ case IOCTL_ETHER_SETHWADDR:
+ return -1; /* need to do this carefully */
+
+ /* XXX IOCTLs to set speed, etc.? */
+
+ case IOCTL_ETHER_GETLOOPBACK:
+ *((int *) buffer) = 0; /* XXX place holder */
+ return 0;
+
+ case IOCTL_ETHER_SETLOOPBACK:
+ tulip_stop(softc);
+ tulip_resetrings(softc);
+ mode = *((int *) buffer->buf_ptr);
+ if (mode == ETHER_LOOPBACK_INT || mode == ETHER_LOOPBACK_EXT) {
+ tulip_start_loopback(softc, mode);
+ }
+ else if (mode == ETHER_LOOPBACK_OFF) {
+ tulip_start(softc);
+ }
+ softc->state = eth_state_on;
+ return 0;
+
+ default:
+ return -1;
+ }
+}
+
+/* *********************************************************************
+ * TULIP_ETHER_CLOSE(ctx)
+ *
+ * Close the Ethernet device.
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ *
+ * Return value:
+ * status, 0 = ok
+ ********************************************************************* */
+static int
+tulip_ether_close(cfe_devctx_t *ctx)
+{
+ tulip_softc *softc = ctx->dev_softc;
+
+ tulip_stop(softc);
+ softc->state = eth_state_off;
+
+ /* resynchronize descriptor rings */
+ tulip_resetrings(softc);
+
+ return 0;
+}
diff --git a/cfe/cfe/dev/dev_dp83815.c b/cfe/cfe/dev/dev_dp83815.c
new file mode 100644
index 0000000..b9fb644
--- /dev/null
+++ b/cfe/cfe/dev/dev_dp83815.c
@@ -0,0 +1,2290 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * NS DP83815 Ethernet Driver File: dev_dp83815.c
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+#include "sbmips.h"
+
+#ifndef _SB_MAKE64
+#define _SB_MAKE64(x) ((uint64_t)(x))
+#endif
+#ifndef _SB_MAKEMASK1
+#define _SB_MAKEMASK1(n) (_SB_MAKE64(1) << _SB_MAKE64(n))
+#endif
+
+#include "lib_types.h"
+#include "lib_hssubr.h"
+#include "lib_malloc.h"
+#include "lib_string.h"
+#define blockcopy memcpy
+#include "lib_printf.h"
+#include "lib_queue.h"
+
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "cfe_ioctl.h"
+#include "cfe_timer.h"
+#include "cfe_error.h"
+#include "cfe_irq.h"
+
+#include "pcivar.h"
+#include "pcireg.h"
+
+#include "dp83815.h"
+#include "mii.h"
+
+/* This is a driver for the National Semiconductor DP83815 (MacPhyter)
+ 10/100 MAC with integrated PHY.
+
+ The current version has been developed for the Netgear FA311 and
+ FA312 NICs. These include an EEPROM with automatically loaded
+ setup information that includes station address filtering.
+ Operation without such an EEPROM has not been tested.
+
+ This SB1250 version takes advantage of DMA coherence and uses
+ "preserve bit lanes" addresses for all accesses that cross the
+ ZBbus-PCI bridge. */
+
+#ifndef MACPHYTER_DEBUG
+#define MACPHYTER_DEBUG 0
+#endif
+#ifndef MACPHYTER_TEST
+#define MACPHYTER_TEST 0
+#endif
+
+/* Set IPOLL to drive processing through the pseudo-interrupt
+ dispatcher. Set XPOLL to drive processing by an external polling
+ agent. Setting both is ok. */
+
+#ifndef IPOLL
+#define IPOLL 0
+#endif
+#ifndef XPOLL
+#define XPOLL 1
+#endif
+
+#define ENET_ADDR_LEN 6 /* size of an ethernet address */
+#define MIN_ETHER_PACK 64 /* min size of a packet */
+#define MAX_ETHER_PACK 1518 /* max size of a packet */
+#define CRC_SIZE 4 /* size of CRC field */
+
+/* Packet buffers. For the DP83815, an rx packet must be aligned to a
+ 32-bit word boundary, and we would like it aligned to a cache line
+ boundary for performance. Also, the buffers "should" be allocated
+ in 32 byte multiples (5.3.2). */
+
+#define ETH_PKTBUF_LEN (((MAX_ETHER_PACK+31)/32)*32)
+
+#if __long64
+typedef struct eth_pkt_s {
+ queue_t next; /* 16 */
+ uint8_t *buffer; /* 8 */
+ uint32_t flags; /* 4 */
+ int32_t length; /* 4 */
+ uint8_t data[ETH_PKTBUF_LEN];
+} eth_pkt_t;
+#else
+typedef struct eth_pkt_s {
+ queue_t next; /* 8 */
+ uint8_t *buffer; /* 4 */
+ uint32_t flags; /* 4 */
+ int32_t length; /* 4 */
+ uint32_t unused[3]; /* 12 */
+ uint8_t data[ETH_PKTBUF_LEN];
+} eth_pkt_t;
+#endif
+
+#define CACHE_ALIGN 32
+#define ETH_PKTBUF_LINES ((sizeof(eth_pkt_t) + (CACHE_ALIGN-1))/CACHE_ALIGN)
+#define ETH_PKTBUF_SIZE (ETH_PKTBUF_LINES*CACHE_ALIGN)
+#define ETH_PKTBUF_OFFSET (offsetof(eth_pkt_t, data))
+
+#define ETH_PKT_BASE(data) ((eth_pkt_t *)((data) - ETH_PKTBUF_OFFSET))
+
+/* packet flags */
+#define ETH_TX_SETUP 1 /* assumes Perfect Filtering format */
+
+static void
+show_packet(char c, eth_pkt_t *pkt)
+{
+ int i;
+ int n = (pkt->length < 32 ? pkt->length : 32);
+
+ xprintf("%c[%4d]:", c, pkt->length);
+ for (i = 0; i < n; i++) {
+ if (i % 4 == 0)
+ xprintf(" ");
+ xprintf("%02x", pkt->buffer[i]);
+ }
+ xprintf("\n");
+}
+
+
+/* Descriptor structures. NOTE: To avoid having descriptors straddle
+ cache lines, we append a pad word, ignored by DMA, to each. */
+
+typedef struct rx_dscr {
+ pci_addr_t rxd_link;
+ uint32_t rxd_cmdsts;
+ pci_addr_t rxd_bufptr;
+ uint32_t rxd_pad;
+} rx_dscr;
+
+typedef struct tx_dscr {
+ pci_addr_t txd_link;
+ uint32_t txd_cmdsts;
+ pci_addr_t txd_bufptr;
+ uint32_t txd_pad;
+} tx_dscr;
+
+
+/* Driver data structures */
+
+typedef enum {
+ eth_state_uninit,
+ eth_state_off,
+ eth_state_on,
+ eth_state_broken
+} eth_state_t;
+
+#define ETH_PKTPOOL_SIZE 32
+
+typedef struct dp83815_softc {
+ uint32_t membase;
+ uint8_t irq; /* interrupt mapping (used if IPOLL) */
+ pcitag_t tag; /* tag for configuration registers */
+
+ uint8_t hwaddr[ENET_ADDR_LEN];
+ uint16_t device; /* chip device code */
+ uint8_t revision; /* chip revision and step */
+
+ eth_state_t state; /* current state */
+ uint32_t intmask; /* interrupt mask */
+
+ /* These fields are set before calling dp83815_hwinit */
+ int linkspeed; /* encodings from cfe_ioctl */
+ int loopback;
+
+ /* Packet free list */
+ queue_t freelist;
+ uint8_t *pktpool;
+ queue_t rxqueue;
+
+ /* The descriptor tables */
+ uint8_t *rxdscrmem; /* receive descriptors */
+ uint8_t *txdscrmem; /* transmit descriptors */
+
+ /* These fields keep track of where we are in tx/rx processing */
+ volatile rx_dscr *rxdscr_start; /* beginning of ring */
+ volatile rx_dscr *rxdscr_end; /* end of ring */
+ volatile rx_dscr *rxdscr_remove; /* next one we expect DMA to use */
+ volatile rx_dscr *rxdscr_add; /* next place to put a buffer */
+ int rxdscr_onring;
+
+ volatile tx_dscr *txdscr_start; /* beginning of ring */
+ volatile tx_dscr *txdscr_end; /* end of ring */
+ volatile tx_dscr *txdscr_remove; /* next one we will use for tx */
+ volatile tx_dscr *txdscr_add; /* next place to put a buffer */
+
+ cfe_devctx_t *devctx;
+
+ /* These fields describe the PHY */
+ int phy_addr;
+ int phy_check;
+ uint32_t phy_status;
+
+ /* Statistics */
+ uint32_t inpkts;
+ uint32_t outpkts;
+ uint32_t interrupts;
+ uint32_t rx_interrupts;
+ uint32_t tx_interrupts;
+ uint32_t bus_errors;
+} dp83815_softc;
+
+
+/* Entry to and exit from critical sections (currently relative to
+ interrupts only, not SMP) */
+
+#if CFG_INTERRUPTS
+#define CS_ENTER(sc) cfe_disable_irq(sc->irq)
+#define CS_EXIT(sc) cfe_enable_irq(sc->irq)
+#else
+#define CS_ENTER(sc) ((void)0)
+#define CS_EXIT(sc) ((void)0)
+#endif
+
+
+/* Driver parameterization */
+
+#define MAXRXDSCR 32
+#define MAXTXDSCR 32
+#define MINRXRING 8
+
+
+/* Prototypes */
+
+static void dp83815_ether_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+
+/* Address mapping macros */
+
+/* Note that PTR_TO_PHYS only works with 32-bit addresses, but then
+ so does the dp83815. */
+#define PTR_TO_PHYS(x) (K0_TO_PHYS((uintptr_t)(x)))
+#define PHYS_TO_PTR(a) ((uint8_t *)PHYS_TO_K0(a))
+
+/* All mappings through the PCI host bridge use match bits mode. */
+#define PHYS_TO_PCI(a) ((uint32_t) (a) | 0x20000000)
+#define PCI_TO_PHYS(a) ((uint32_t) (a) & 0x1FFFFFFF)
+
+#define PCI_TO_PTR(a) (PHYS_TO_PTR(PCI_TO_PHYS(a)))
+#define PTR_TO_PCI(x) (PHYS_TO_PCI(PTR_TO_PHYS(x)))
+
+#if __long64
+#define READCSR(sc,csr) \
+ (*((volatile uint32_t *) (PHYS_TO_XKSEG_UNCACHED((sc)->membase + (csr)))))
+
+#define WRITECSR(sc,csr,val) \
+ (*((volatile uint32_t *) \
+ (PHYS_TO_XKSEG_UNCACHED((sc)->membase + (csr)))) = (val))
+
+#else
+#define READCSR(sc,csr) \
+ (hs_read32(PHYS_TO_XKSEG_UNCACHED((sc)->membase + (csr))))
+
+#define WRITECSR(sc,csr,val) \
+ (hs_write32(PHYS_TO_XKSEG_UNCACHED((sc)->membase + (csr)), (val)))
+
+#endif
+
+#define RESET_ADAPTER(sc) \
+ { \
+ /* XXX */ \
+ }
+
+
+/* Debugging */
+
+static void
+dumpstat(dp83815_softc *sc)
+{
+ xprintf("-- CR = %08X CFG = %08x\n",
+ READCSR(sc, R_CR), READCSR(sc, R_CFG));
+}
+
+static void
+dumpcsrs(dp83815_softc *sc)
+{
+ int reg;
+
+ xprintf("-------------\n");
+ for (reg = 0; reg < R_MIBC; reg += 4) {
+ xprintf("CSR %02X = %08X\n", reg, READCSR(sc, reg));
+ }
+ xprintf("-------------\n");
+}
+
+
+/* Packet management */
+
+/* *********************************************************************
+ * ETH_ALLOC_PKT(sc)
+ *
+ * Allocate a packet from the free list.
+ *
+ * Input parameters:
+ * sc - eth structure
+ *
+ * Return value:
+ * pointer to packet structure, or NULL if none available
+ ********************************************************************* */
+static eth_pkt_t *
+eth_alloc_pkt(dp83815_softc *sc)
+{
+ eth_pkt_t *pkt;
+
+ CS_ENTER(sc);
+ pkt = (eth_pkt_t *) q_deqnext(&sc->freelist);
+ CS_EXIT(sc);
+ if (!pkt) return NULL;
+
+ pkt->buffer = pkt->data;
+ pkt->length = ETH_PKTBUF_LEN;
+ pkt->flags = 0;
+
+ return pkt;
+}
+
+
+/* *********************************************************************
+ * ETH_FREE_PKT(sc,pkt)
+ *
+ * Return a packet to the free list
+ *
+ * Input parameters:
+ * sc - sbmac structure
+ * pkt - packet to return
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void
+eth_free_pkt(dp83815_softc *sc, eth_pkt_t *pkt)
+{
+ CS_ENTER(sc);
+ q_enqueue(&sc->freelist, &pkt->next);
+ CS_EXIT(sc);
+}
+
+
+/* *********************************************************************
+ * ETH_INITFREELIST(sc)
+ *
+ * Initialize the buffer free list for this mac. The memory
+ * allocated to the free list is carved up and placed on a linked
+ * list of buffers for use by the mac.
+ *
+ * Input parameters:
+ * sc - eth structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void
+eth_initfreelist(dp83815_softc *sc)
+{
+ int idx;
+ uint8_t *ptr;
+ eth_pkt_t *pkt;
+
+ q_init(&sc->freelist);
+
+ ptr = sc->pktpool;
+ for (idx = 0; idx < ETH_PKTPOOL_SIZE; idx++) {
+ pkt = (eth_pkt_t *) ptr;
+ eth_free_pkt(sc, pkt);
+ ptr += ETH_PKTBUF_SIZE;
+ }
+}
+
+
+/* Utilities */
+
+static const char *
+dp83815_devname(dp83815_softc *sc)
+{
+ return (sc->devctx != NULL ? cfe_device_name(sc->devctx) : "eth?");
+}
+
+
+/* Descriptor ring management */
+
+static int
+dp83815_add_rcvbuf(dp83815_softc *sc, eth_pkt_t *pkt)
+{
+ volatile rx_dscr *rxd;
+ volatile rx_dscr *nextrxd;
+
+ rxd = sc->rxdscr_add;
+
+ /* Figure out where the next descriptor will go */
+ nextrxd = rxd+1;
+ if (nextrxd == sc->rxdscr_end) {
+ nextrxd = sc->rxdscr_start;
+ }
+
+ /*
+ * If the next one is the same as our remove pointer,
+ * the ring is considered full. (it actually has room for
+ * one more, but we reserve the remove == add case for "empty")
+ */
+ if (nextrxd == sc->rxdscr_remove) return -1;
+
+ rxd->rxd_bufptr = PTR_TO_PCI(pkt->buffer);
+ rxd->rxd_cmdsts = M_DES1_INTR | V_DES1_SIZE(ETH_PKTBUF_LEN);
+
+ /* success, advance the pointer */
+ sc->rxdscr_add = nextrxd;
+ CS_ENTER(sc);
+ sc->rxdscr_onring++;
+ CS_EXIT(sc);
+
+ return 0;
+}
+
+static void
+dp83815_fillrxring(dp83815_softc *sc)
+{
+ eth_pkt_t *pkt;
+
+ while (1) {
+ CS_ENTER(sc);
+ if (sc->rxdscr_onring >= MINRXRING) {
+ CS_EXIT(sc);
+ break;
+ }
+ CS_EXIT(sc);
+ pkt = eth_alloc_pkt(sc);
+ if (pkt == NULL) {
+ /* could not allocate a buffer */
+ break;
+ }
+ if (dp83815_add_rcvbuf(sc, pkt) != 0) {
+ /* could not add buffer to ring */
+ eth_free_pkt(sc, pkt);
+ break;
+ }
+ }
+}
+
+
+/* *********************************************************************
+ * DP83815_RX_CALLBACK(sc, pkt)
+ *
+ * Receive callback routine. This routine is invoked when a
+ * buffer queued for receives is filled. In this simple driver,
+ * all we do is add the packet to a per-MAC queue for later
+ * processing, and try to put a new packet in the place of the one
+ * that was removed from the queue.
+ *
+ * Input parameters:
+ * sc - interface
+ * ptk - packet context (eth_pkt structure)
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void
+dp83815_rx_callback(dp83815_softc *sc, eth_pkt_t *pkt)
+{
+ if (MACPHYTER_DEBUG) show_packet('>', pkt); /* debug */
+
+ CS_ENTER(sc);
+ q_enqueue(&sc->rxqueue, &pkt->next);
+ CS_EXIT(sc);
+ sc->inpkts++;
+
+ dp83815_fillrxring(sc);
+}
+
+
+static void
+dp83815_procrxring(dp83815_softc *sc)
+{
+ volatile rx_dscr *rxd;
+ eth_pkt_t *pkt;
+ eth_pkt_t *newpkt;
+ uint32_t cmdsts;
+
+ for (;;) {
+ rxd = (volatile rx_dscr *) sc->rxdscr_remove;
+
+ cmdsts = rxd->rxd_cmdsts;
+ if ((cmdsts & M_DES1_OWN) == 0) {
+ /* end of ring, no more packets */
+ break;
+ }
+
+ pkt = ETH_PKT_BASE(PCI_TO_PTR(rxd->rxd_bufptr));
+ pkt->length = G_DES1_SIZE(cmdsts) - CRC_SIZE;
+
+ /* Drop error packets */
+ if (cmdsts & M_DES1_RX_ERRORS) {
+#if MACPHYTER_DEBUG
+ if (pkt->length >= MIN_ETHER_PACK - CRC_SIZE)
+ xprintf("%s: rx error %08X\n", dp83815_devname(sc), cmdsts);
+#endif
+ dp83815_add_rcvbuf(sc, pkt);
+ goto next;
+ }
+
+ /* Pass up the packet */
+ dp83815_rx_callback(sc, pkt);
+
+ /* put a buffer back on the ring to replace this one */
+ newpkt = eth_alloc_pkt(sc);
+ if (newpkt) dp83815_add_rcvbuf(sc, newpkt);
+
+next:
+ /* update the pointer, accounting for buffer wrap. */
+ rxd++;
+ if (rxd == sc->rxdscr_end)
+ rxd = sc->rxdscr_start;
+
+ sc->rxdscr_remove = (rx_dscr *) rxd;
+ CS_ENTER(sc);
+ sc->rxdscr_onring--;
+ CS_EXIT(sc);
+ }
+}
+
+
+static int
+dp83815_add_txbuf(dp83815_softc *sc, eth_pkt_t *pkt)
+{
+ volatile tx_dscr *txd;
+ volatile tx_dscr *nexttxd;
+
+ txd = sc->txdscr_add;
+
+ /* Figure out where the next descriptor will go */
+ nexttxd = (txd+1);
+ if (nexttxd == sc->txdscr_end) {
+ nexttxd = sc->txdscr_start;
+ }
+
+ /* If the next one is the same as our remove pointer,
+ the ring is considered full. (it actually has room for
+ one more, but we reserve the remove == add case for "empty") */
+
+ if (nexttxd == sc->txdscr_remove) return -1;
+
+ txd->txd_bufptr = PTR_TO_PCI(pkt->buffer);
+ txd->txd_cmdsts = M_DES1_INTR | M_DES1_OWN | V_DES1_SIZE(pkt->length);
+
+ /* success, advance the pointer */
+ sc->txdscr_add = nexttxd;
+
+ return 0;
+}
+
+
+static int
+dp83815_transmit(dp83815_softc *sc,eth_pkt_t *pkt)
+{
+ int rv;
+
+ if (MACPHYTER_DEBUG) show_packet('<', pkt); /* debug */
+
+ rv = dp83815_add_txbuf(sc, pkt);
+ sc->outpkts++;
+
+ WRITECSR(sc, R_CR, M_CR_TXE | M_CR_RXE);
+ return rv;
+}
+
+
+static void
+dp83815_proctxring(dp83815_softc *sc)
+{
+ volatile tx_dscr *txd;
+ eth_pkt_t *pkt;
+ uint32_t cmdsts;
+
+ for (;;) {
+ txd = (volatile tx_dscr *) sc->txdscr_remove;
+
+ if (txd == sc->txdscr_add) {
+ /* ring is empty, no buffers to process */
+ break;
+ }
+
+ cmdsts = txd->txd_cmdsts;
+ if (cmdsts & M_DES1_OWN) {
+ /* Reached a packet still being transmitted */
+ break;
+ }
+
+ /* Just free the packet */
+ pkt = ETH_PKT_BASE(PCI_TO_PTR(txd->txd_bufptr));
+ eth_free_pkt(sc, pkt);
+
+ /* update the pointer, accounting for buffer wrap. */
+ txd++;
+ if (txd == sc->txdscr_end)
+ txd = sc->txdscr_start;
+
+ sc->txdscr_remove = (tx_dscr *) txd;
+ }
+}
+
+
+static void
+dp83815_initrings(dp83815_softc *sc)
+{
+ volatile tx_dscr *txd, *txn;
+ volatile rx_dscr *rxd, *rxn;
+
+ /* Claim ownership of all descriptors for the driver */
+
+ for (txd = sc->txdscr_start; txd != sc->txdscr_end; txd++) {
+ txn = txd + 1;
+ if (txn == sc->txdscr_end) txn = sc->txdscr_start;
+ txd->txd_link = PTR_TO_PCI(txn);
+ txd->txd_cmdsts = 0;
+ txd->txd_pad = 0;
+ }
+ for (rxd = sc->rxdscr_start; rxd != sc->rxdscr_end; rxd++) {
+ rxn = rxd + 1;
+ if (rxn == sc->rxdscr_end) rxn = sc->rxdscr_start;
+ rxd->rxd_link = PTR_TO_PCI(rxn);
+ rxd->rxd_cmdsts = M_DES1_OWN;
+ rxd->rxd_pad = 0;
+ }
+
+ /* Init the ring pointers */
+
+ sc->txdscr_add = sc->txdscr_remove = sc->txdscr_start;
+ sc->rxdscr_add = sc->rxdscr_remove = sc->rxdscr_start;
+ sc->rxdscr_onring = 0;
+
+ /* Add stuff to the receive ring */
+
+ dp83815_fillrxring(sc);
+}
+
+
+static int
+dp83815_init(dp83815_softc *sc)
+{
+ /* Allocate descriptor rings */
+ sc->rxdscrmem = KMALLOC(MAXRXDSCR*sizeof(rx_dscr), sizeof(rx_dscr));
+ sc->txdscrmem = KMALLOC(MAXTXDSCR*sizeof(tx_dscr), sizeof(tx_dscr));
+
+ /* Allocate buffer pool */
+ sc->pktpool = KMALLOC(ETH_PKTPOOL_SIZE*ETH_PKTBUF_SIZE, CACHE_ALIGN);
+ eth_initfreelist(sc);
+ q_init(&sc->rxqueue);
+
+ /* Fill in pointers to the rings */
+ sc->rxdscr_start = (rx_dscr *) (sc->rxdscrmem);
+ sc->rxdscr_end = sc->rxdscr_start + MAXRXDSCR;
+ sc->rxdscr_add = sc->rxdscr_start;
+ sc->rxdscr_remove = sc->rxdscr_start;
+ sc->rxdscr_onring = 0;
+
+ sc->txdscr_start = (tx_dscr *) (sc->txdscrmem);
+ sc->txdscr_end = sc->txdscr_start + MAXTXDSCR;
+ sc->txdscr_add = sc->txdscr_start;
+ sc->txdscr_remove = sc->txdscr_start;
+
+ dp83815_initrings(sc);
+
+ return 0;
+}
+
+
+static void
+dp83815_resetrings(dp83815_softc *sc)
+{
+ volatile tx_dscr *txd;
+ volatile rx_dscr *rxd;
+ eth_pkt_t *pkt;
+
+ /* Free already-sent descriptors and buffers */
+ dp83815_proctxring(sc);
+
+ /* Free any pending but unsent */
+ txd = (volatile tx_dscr *) sc->txdscr_remove;
+ while (txd != sc->txdscr_add) {
+ txd->txd_cmdsts &=~ M_DES1_OWN;
+ pkt = ETH_PKT_BASE(PCI_TO_PTR(txd->txd_bufptr));
+ eth_free_pkt(sc, pkt);
+
+ txd++;
+ if (txd == sc->txdscr_end)
+ txd = sc->txdscr_start;
+ }
+ sc->txdscr_add = sc->txdscr_remove;
+
+ /* Discard any received packets as well as all free buffers */
+ rxd = (volatile rx_dscr *) sc->rxdscr_remove;
+ while (rxd != sc->rxdscr_add) {
+ rxd->rxd_cmdsts |= M_DES1_OWN;
+ pkt = ETH_PKT_BASE(PCI_TO_PTR(rxd->rxd_bufptr));
+ eth_free_pkt(sc, pkt);
+
+ rxd++;
+ if (rxd == sc->rxdscr_end)
+ rxd = sc->rxdscr_start;
+ CS_ENTER(sc);
+ sc->rxdscr_onring--;
+ CS_EXIT(sc);
+ }
+
+ /* Reestablish the initial state. */
+ dp83815_initrings(sc);
+}
+
+
+#if 0 /* XXX Multicast filtering not yet implemented. */
+/* CRCs */
+
+#define IEEE_CRC32_POLY 0xEDB88320UL /* CRC-32 Poly -- either endian */
+
+static uint32_t
+dp83815_crc32(const uint8_t *databuf, unsigned int datalen)
+{
+ unsigned int idx, bit, data;
+ uint32_t crc;
+
+ crc = 0xFFFFFFFFUL;
+ for (idx = 0; idx < datalen; idx++)
+ for (data = *databuf++, bit = 0; bit < 8; bit++, data >>= 1)
+ crc = (crc >> 1) ^ (((crc ^ data) & 1) ? IEEE_CRC32_POLY : 0);
+ return crc;
+}
+
+#define dp83815_mchash(mca) (dp83815_crc32((mca), 6) & 0x1FF)
+#endif
+
+
+#if MACPHYTER_TEST
+/* EEPROM access */
+
+/* Current NICs use the EEPROM auto-load feature and there is no need
+ for explicit EEPROM access. The following routines are included
+ for future applications and have been tested (Netgear FA311). */
+
+/****************************************************************************
+ * dp83815_spin(sc, ns)
+ *
+ * Spin for a short interval (nominally in nanoseconds)
+ *
+ * Input Parameters: ns - minimum required nsec.
+ *
+ * The delay loop uses uncached PCI reads, each of which requires
+ * at least 3 PCI bus clocks (45 ns at 66 MHz) to complete. The
+ * actual delay will be longer (much longer if preempted).
+ ***************************************************************************/
+
+#define PCI_MIN_DELAY 45
+
+static void
+dp83815_spin(dp83815_softc *sc, long nanoseconds)
+{
+ long delay;
+ volatile uint32_t t;
+
+ for (delay = nanoseconds; delay > 0; delay -= PCI_MIN_DELAY)
+ t = READCSR(sc, R_SRR);
+}
+
+
+/*
+ * The recommended EEPROM is the NM9306.
+ * Delays below are chosen to meet specs for NS93C64 (slow M variant).
+ * Current parts are faster.
+ * Reference: NS Memory Data Book, 1994
+ */
+
+#define EEPROM_SIZE (2*0x0C)
+#define EEPROM_MAX_CYCLES 32
+
+#define EEPROM_CMD_BITS 3
+#define EEPROM_ADDR_BITS 6
+
+#define K_EEPROM_READ_CMD 06
+#define K_EEPROM_WRITE_CMD 05
+
+#define EEPROM_CRC_INDEX (EEPROM_SIZE-2)
+
+#define EEPROM_WORD(rom,offset) ((rom)[offset] | ((rom)[offset+1] << 8))
+
+static void
+eeprom_idle_state(dp83815_softc *sc)
+{
+ uint32_t ctrl;
+ unsigned int i;
+
+ ctrl = READCSR(sc, R_MEAR);
+
+ ctrl |= M_MEAR_EESEL;
+ WRITECSR(sc, R_MEAR, ctrl);
+ dp83815_spin(sc, 100); /* CS setup (Tcss=100) */
+
+ /* Run the clock through the maximum number of pending read cycles */
+ for (i = 0; i < EEPROM_MAX_CYCLES*2; i++) {
+ ctrl ^= M_MEAR_EECLK;
+ WRITECSR(sc, R_MEAR, ctrl);
+ dp83815_spin(sc, 1000); /* SK period (Fsk=0.5MHz) */
+ }
+
+ /* Deassert EEPROM Chip Select */
+ ctrl &=~ M_MEAR_EESEL;
+ WRITECSR(sc, R_MEAR, ctrl);
+ dp83815_spin(sc, 50); /* CS recovery (Tsks=50) */
+}
+
+static void
+eeprom_send_command_bit(dp83815_softc *sc, unsigned int data)
+{
+ uint32_t ctrl;
+
+ ctrl = READCSR(sc, R_MEAR);
+
+ /* Place the data bit on the bus */
+ if (data == 1)
+ ctrl |= M_MEAR_EEDI;
+ else
+ ctrl &=~ M_MEAR_EEDI;
+
+ WRITECSR(sc, R_MEAR, ctrl);
+ dp83815_spin(sc, 360); /* setup: Tdis=200 */
+
+ /* Now clock the data into the EEPROM */
+ WRITECSR(sc, R_MEAR, ctrl | M_MEAR_EECLK);
+ dp83815_spin(sc, 900); /* clock high, Tskh=500 */
+ WRITECSR(sc, R_MEAR, ctrl);
+ dp83815_spin(sc, 450); /* clock low, Tskl=250 */
+
+ /* Now clear the data bit */
+ ctrl &=~ M_MEAR_EEDI; /* data invalid, Tidh=20 for SK^ */
+ WRITECSR(sc, R_MEAR, ctrl);
+ dp83815_spin(sc, 270); /* min cycle, 1/Fsk=2000 */
+}
+
+static uint16_t
+eeprom_read_bit(dp83815_softc *sc)
+{
+ uint32_t ctrl;
+
+ ctrl = READCSR(sc, R_MEAR);
+
+ /* Generate a clock cycle before doing a read */
+ WRITECSR(sc, R_MEAR, ctrl | M_MEAR_EECLK); /* rising edge */
+ dp83815_spin(sc, 1000); /* clock high, Tskh=500, Tpd=1000 */
+ WRITECSR(sc, R_MEAR, ctrl); /* falling edge */
+ dp83815_spin(sc, 1000); /* clock low, 1/Fsk=2000 */
+
+ ctrl = READCSR(sc, R_MEAR);
+ return ((ctrl & M_MEAR_EEDO) != 0 ? 1 : 0);
+}
+
+#define CMD_BIT_MASK (1 << (EEPROM_CMD_BITS+EEPROM_ADDR_BITS-1))
+
+static uint16_t
+eeprom_read_word(dp83815_softc *sc, unsigned int index)
+{
+ uint16_t command, word;
+ uint32_t ctrl;
+ unsigned int i;
+
+ ctrl = READCSR(sc, R_MEAR) | M_MEAR_EESEL;
+
+ /* Assert the EEPROM CS line */
+ WRITECSR(sc, R_MEAR, ctrl);
+ dp83815_spin(sc, 100); /* CS setup, Tcss = 100 */
+
+ /* Send the read command to the EEPROM */
+ command = (K_EEPROM_READ_CMD << EEPROM_ADDR_BITS) | index;
+ for (i = 0; i < EEPROM_CMD_BITS+EEPROM_ADDR_BITS; i++) {
+ eeprom_send_command_bit(sc, (command & CMD_BIT_MASK) != 0 ? 1 : 0);
+ command <<= 1;
+ }
+
+ /* Now read the bits from the EEPROM (MSB first) */
+ word = 0;
+ for (i = 0; i < 16; ++i) {
+ word <<= 1;
+ word |= eeprom_read_bit(sc);
+ }
+
+ /* Clear the EEPROM CS Line, CS hold, Tcsh = 0 */
+ WRITECSR(sc, R_MEAR, ctrl &~ M_MEAR_EESEL);
+
+ return word;
+}
+
+
+/****************************************************************************
+ * eeprom_checksum()
+ *
+ * Calculate the checksum of the EEPROM and return it. See Section
+ * 4.2.4 for the algorithm.
+ ***************************************************************************/
+
+static uint16_t
+eeprom_checksum(const uint8_t rom[])
+{
+ uint16_t sum;
+ int i;
+
+ sum = 0;
+ for (i = 0; i < EEPROM_SIZE-1; i++)
+ sum += rom[i];
+ sum ^= 0xFF;
+ return (((sum + 1) & 0xFF) << 8) | 0x55;
+}
+
+
+/****************************************************************************
+ * eeprom_read_all(sc, uint8_t dest)
+ *
+ * Read the entire EEPROM into the srom array
+ *
+ * Input parameters:
+ * sc - dp83815 state
+ ***************************************************************************/
+
+static int
+eeprom_read_all(dp83815_softc *sc, uint8_t dest[])
+{
+ int i;
+ uint16_t cksum, temp;
+
+ WRITECSR(sc, R_MEAR, M_MEAR_EESEL);
+
+ eeprom_idle_state(sc);
+
+ for (i = 0; i < EEPROM_SIZE/2; i++) {
+ temp = eeprom_read_word(sc, i);
+ dest[2*i] = temp & 0xFF;
+ dest[2*i+1] = temp >> 8;
+ }
+
+ WRITECSR(sc, R_MEAR, 0); /* CS hold, Tcsh=0 */
+
+ cksum = eeprom_checksum(dest);;
+ if (cksum != EEPROM_WORD(dest, EEPROM_CRC_INDEX)) {
+ xprintf("%s: Invalid EEPROM CHECKSUM, calc %04x, stored %04x\n",
+ dp83815_devname(sc),
+ cksum, EEPROM_WORD(dest, EEPROM_CRC_INDEX));
+ return 0/*-1*/;
+ }
+ return 0;
+}
+
+static int
+eeprom_read_addr(const uint8_t rom[], uint8_t buf[])
+{
+ uint16_t s;
+ unsigned offset, mask;
+ int i, j;
+
+ if (eeprom_checksum(rom) != EEPROM_WORD(rom, EEPROM_SIZE-2))
+ return -1;
+
+ s = 0;
+ offset = 2*6; mask = 0x1;
+ i = j = 0;
+ do {
+ s >>= 1;
+ if ((EEPROM_WORD(rom, offset) & mask) != 0) s |= 0x8000;
+ mask >>= 1;
+ if (mask == 0) {
+ offset +=2; mask = 0x8000;
+ }
+ i++;
+ if (i % 16 == 0) {
+ buf[j++] = s & 0xFF;
+ buf[j++] = s >> 8;
+ s = 0;
+ }
+ } while (i < ENET_ADDR_LEN*8);
+
+ return 0;
+}
+#endif /* MACPHYTER_TEST */
+
+#if 0
+static void
+eeprom_dump(uint8_t srom[])
+{
+ int i;
+
+ xprintf("DP83815: EEPROM data:");
+ for (i = 0; i < EEPROM_SIZE; i++) {
+ if (i % 16 == 0)
+ xprintf("\n %02x: ", i);
+ xprintf(" %02x", srom[i]);
+ }
+ xprintf("\n");
+}
+#else
+#define eeprom_dump(srom)
+#endif
+
+
+static int
+dp83815_get_pm_addr(dp83815_softc *sc, uint8_t buf[])
+{
+ uint32_t rfcr;
+ unsigned rfaddr;
+ unsigned i;
+ uint32_t rfdata;
+
+ rfcr = READCSR(sc, R_RFCR);
+ rfaddr = K_RFCR_PMATCH_ADDR;
+
+ for (i = 0; i < ENET_ADDR_LEN/2; i++) {
+ rfcr &=~ M_RFCR_RFADDR;
+ rfcr |= V_RFCR_RFADDR(rfaddr);
+ WRITECSR(sc, R_RFCR, rfcr);
+ rfdata = READCSR(sc, R_RFDR);
+ buf[2*i] = rfdata & 0xFF;
+ buf[2*i+1] = (rfdata >> 8) & 0xFF;
+ rfaddr += 2;
+ }
+
+ return 0;
+}
+
+
+#if MACPHYTER_TEST
+/* MII access */
+
+/* Current NICs use the internal PHY, which can be accessed more
+ simply via internal registers. The following routines are
+ primarily for management access to an external PHY and are retained
+ for future applications. They have been tested on a Netgear FA311. */
+
+/****************************************************************************
+ * MII access utility routines
+ ***************************************************************************/
+
+/* MII clock limited to 2.5 MHz (DP83815 allows 25 MHz), transactions
+ end with MDIO tristated */
+
+static void
+mii_write_bits(dp83815_softc *sc, uint32_t data, unsigned int count)
+{
+ uint32_t ctrl;
+ uint32_t bitmask;
+
+ ctrl = READCSR(sc, R_MEAR) & ~M_MEAR_MDC;
+ ctrl |= M_MEAR_MDDIR;
+
+ for (bitmask = 1 << (count-1); bitmask != 0; bitmask >>= 1) {
+ ctrl &=~ M_MEAR_MDIO;
+ if ((data & bitmask) != 0) ctrl |= M_MEAR_MDIO;
+ WRITECSR(sc, R_MEAR, ctrl);
+
+ dp83815_spin(sc, 2000); /* setup */
+ WRITECSR(sc, R_MEAR, ctrl | M_MEAR_MDC);
+ dp83815_spin(sc, 2000); /* hold */
+ WRITECSR(sc, R_MEAR, ctrl);
+ }
+}
+
+static void
+mii_turnaround(dp83815_softc *sc)
+{
+ uint32_t ctrl;
+
+ ctrl = READCSR(sc, R_MEAR) &~ M_MEAR_MDDIR;
+
+ /* stop driving data */
+ WRITECSR(sc, R_MEAR, ctrl);
+ dp83815_spin(sc, 2000); /* setup */
+ WRITECSR(sc, R_MEAR, ctrl | M_MEAR_MDC);
+ dp83815_spin(sc, 2000); /* clock high */
+ WRITECSR(sc, R_MEAR, ctrl);
+
+ /* read back and check for 0 here? */
+}
+
+/****************************************************************************
+ * mii_read_register
+ *
+ * This routine reads a register from the PHY chip using the MII
+ * serial management interface.
+ *
+ * Input parameters:
+ * index - index of register to read (0-31)
+ *
+ * Return value:
+ * word read from register
+ ***************************************************************************/
+
+static uint16_t
+mii_read_register(dp83815_softc *sc, unsigned int index)
+{
+ /* Send the command and address to the PHY. The sequence is
+ a synchronization sequence (32 1 bits)
+ a "start" command (2 bits)
+ a "read" command (2 bits)
+ the PHY addr (5 bits)
+ the register index (5 bits)
+ */
+ uint32_t ctrl;
+ uint16_t word;
+ int i;
+
+ mii_write_bits(sc, 0xFF, 8);
+ mii_write_bits(sc, 0xFFFFFFFF, 32);
+ mii_write_bits(sc, MII_COMMAND_START, 2);
+ mii_write_bits(sc, MII_COMMAND_READ, 2);
+ mii_write_bits(sc, sc->phy_addr, 5);
+ mii_write_bits(sc, index, 5);
+
+ mii_turnaround(sc);
+
+ ctrl = READCSR(sc, R_MEAR) &~ (M_MEAR_MDC | M_MEAR_MDDIR);
+ word = 0;
+
+ for (i = 0; i < 16; i++) {
+ WRITECSR(sc, R_MEAR, ctrl);
+ dp83815_spin(sc, 2000); /* clock width low */
+ WRITECSR(sc, R_MEAR, ctrl | M_MEAR_MDC);
+ dp83815_spin(sc, 2000); /* clock width high */
+ WRITECSR(sc, R_MEAR, ctrl);
+ dp83815_spin(sc, 1000); /* output delay */
+ word <<= 1;
+ if ((READCSR(sc, R_MEAR) & M_MEAR_MDIO) != 0)
+ word |= 0x0001;
+ }
+
+ return word;
+
+ /* reset to output mode? */
+}
+
+/****************************************************************************
+ * mii_write_register
+ *
+ * This routine writes a register in the PHY chip using the MII
+ * serial management interface.
+ *
+ * Input parameters:
+ * index - index of register to write (0-31)
+ * value - word to write
+ ***************************************************************************/
+
+static void
+mii_write_register(dp83815_softc *sc, unsigned int index, uint16_t value)
+{
+ mii_write_bits(sc, 0xFF, 8);
+ mii_write_bits(sc, 0xFFFFFFFF, 32);
+ mii_write_bits(sc, MII_COMMAND_START, 2);
+ mii_write_bits(sc, MII_COMMAND_WRITE, 2);
+ mii_write_bits(sc, sc->phy_addr, 5);
+ mii_write_bits(sc, index, 5);
+ mii_write_bits(sc, MII_COMMAND_ACK, 2);
+ mii_write_bits(sc, value, 16);
+
+ /* reset to input mode? */
+}
+
+
+static int
+mii_probe(dp83815_softc *sc)
+{
+ int i;
+ uint16_t id1, id2;
+
+ /* Empirically, bit-banged access will return register 0 of the
+ integrated PHY for all registers of all unpopulated PHY
+ addresses. */
+ for (i = 0; i < 32; i++) {
+ sc->phy_addr = i;
+ id1 = mii_read_register(sc, MII_PHYIDR1);
+ id2 = mii_read_register(sc, MII_PHYIDR2);
+ if ((id1 != 0x0000 && id1 != 0xFFFF) ||
+ (id2 != 0x0000 && id2 != 0xFFFF)) {
+ if (id1 != id2) return 0;
+ }
+ }
+ return -1;
+}
+
+#if 0
+#define OUI_NAT_SEMI 0x080017
+#define IDR_NAT_SEMI 0x080017 /* NSC does not bit-reverse each byte */
+#define PART_83815 0x02
+
+static void
+mii_dump(dp83815_softc *sc, const char *label)
+{
+ int i;
+ uint16_t r;
+ uint32_t idr, part;
+
+ xprintf("%s\n", label);
+ idr = 0;
+ for (i = 0; i <= 6; ++i) {
+ r = mii_read_register(sc, i);
+ xprintf("MII_REG%02x: %04x\n", i, r);
+ if (i == MII_PHYIDR1) {
+ idr |= r << 6;
+ }
+ else if (i == MII_PHYIDR2) {
+ idr |= (r >> 10) & 0x3F;
+ part = (r >> 4) & 0x3F;
+ }
+ }
+ if (idr == IDR_NAT_SEMI && part == PART_83815) {
+ r = mii_read_register(sc, 7);
+ xprintf("MII_REG%02x: %04x\n", i, r);
+ for (i = 0x10; i <= 0x16; ++i) {
+ r = mii_read_register(sc, i);
+ xprintf("MII_REG%02x: %04x\n", i, r);
+ }
+ for (i = 0x19; i <= 0x1A; ++i) {
+ r = mii_read_register(sc, i);
+ xprintf("MII_REG%02x: %04x\n", i, r);
+ }
+ }
+}
+#else
+#define mii_dump(sc,label)
+#endif
+
+
+/* The following functions are suitable for explicit MII access. */
+
+static void
+mii_set_speed(dp83815_softc *sc, int speed)
+{
+ uint16_t control;
+
+ control = mii_read_register(sc, MII_BMCR);
+
+ control &=~ (BMCR_ANENABLE | BMCR_RESTARTAN);
+ mii_write_register(sc, MII_BMCR, control);
+ control &=~ (BMCR_SPEED0 | BMCR_SPEED1 | BMCR_DUPLEX);
+
+ switch (speed) {
+ case ETHER_SPEED_10HDX:
+ default:
+ break;
+ case ETHER_SPEED_10FDX:
+ control |= BMCR_DUPLEX;
+ break;
+ case ETHER_SPEED_100HDX:
+ control |= BMCR_SPEED100;
+ break;
+ case ETHER_SPEED_100FDX:
+ control |= BMCR_SPEED100 | BMCR_DUPLEX ;
+ break;
+ }
+
+ mii_write_register(sc, MII_BMCR, control);
+}
+
+static void
+mii_autonegotiate(dp83815_softc *sc)
+{
+ uint16_t control, status, cap;
+ int timeout;
+ int linkspeed;
+
+ linkspeed = ETHER_SPEED_UNKNOWN;
+
+ /* Read twice to clear latching bits */
+ status = mii_read_register(sc, MII_BMSR);
+ status = mii_read_register(sc, MII_BMSR);
+ mii_dump(sc, "query PHY");
+
+ if ((status & (BMSR_AUTONEG | BMSR_LINKSTAT)) ==
+ (BMSR_AUTONEG | BMSR_LINKSTAT))
+ control = mii_read_register(sc, MII_BMCR);
+ else {
+ /* reset the PHY */
+ mii_write_register(sc, MII_BMCR, BMCR_RESET);
+ timeout = 3*CFE_HZ;
+ for (;;) {
+ control = mii_read_register(sc, MII_BMCR);
+ if ((control && BMCR_RESET) == 0 || timeout <= 0)
+ break;
+ cfe_sleep(CFE_HZ/2);
+ timeout -= CFE_HZ/2;
+ }
+ if ((control & BMCR_RESET) != 0) {
+ xprintf("%s: PHY reset failed\n", dp83815_devname(sc));
+ return;
+ }
+
+ status = mii_read_register(sc, MII_BMSR);
+ cap = ((status >> 6) & (ANAR_TXFD | ANAR_TXHD | ANAR_10FD | ANAR_10HD))
+ | PSB_802_3;
+ mii_write_register(sc, MII_ANAR, cap);
+ control |= (BMCR_ANENABLE | BMCR_RESTARTAN);
+ mii_write_register(sc, MII_BMCR, control);
+
+ timeout = 3*CFE_HZ;
+ for (;;) {
+ status = mii_read_register(sc, MII_BMSR);
+ if ((status & BMSR_ANCOMPLETE) != 0 || timeout <= 0)
+ break;
+ cfe_sleep(CFE_HZ/2);
+ timeout -= CFE_HZ/2;
+ }
+ mii_dump(sc, "done PHY");
+ }
+
+ xprintf("%s: Link speed: ", dp83815_devname(sc));
+ if ((status & BMSR_ANCOMPLETE) != 0) {
+ /* A link partner was negogiated... */
+
+ uint16_t remote = mii_read_register(sc, MII_ANLPAR);
+
+ if ((remote & ANLPAR_TXFD) != 0) {
+ xprintf("100BaseT FDX\n");
+ linkspeed = ETHER_SPEED_100FDX;
+ }
+ else if ((remote & ANLPAR_TXHD) != 0) {
+ xprintf("100BaseT HDX\n");
+ linkspeed = ETHER_SPEED_100HDX;
+ }
+ else if ((remote & ANLPAR_10FD) != 0) {
+ xprintf("10BaseT FDX\n");
+ linkspeed = ETHER_SPEED_10FDX;
+ }
+ else if ((remote & ANLPAR_10HD) != 0) {
+ xprintf("10BaseT HDX\n");
+ linkspeed = ETHER_SPEED_10HDX;
+ }
+ }
+ else {
+ /* no link partner negotiation */
+ control &=~ (BMCR_ANENABLE | BMCR_RESTARTAN);
+ mii_write_register(sc, MII_BMCR, control);
+ xprintf("10BaseT HDX (assumed)\n");
+ linkspeed = ETHER_SPEED_10HDX;
+ if ((status & BMSR_LINKSTAT) == 0)
+ mii_write_register(sc, MII_BMCR, control);
+ mii_set_speed(sc, linkspeed);
+ }
+
+ status = mii_read_register(sc, MII_BMSR); /* clear latching bits */
+ mii_dump(sc, "final PHY");
+}
+#endif /* MACPHYTER_TEST */
+
+
+static void
+dp83815_phyupdate(dp83815_softc *sc, uint32_t status)
+{
+ xprintf("%s: Link speed: ", dp83815_devname(sc));
+ if ((status & M_CFG_LNKSTS) != 0) {
+ switch (status & (M_CFG_SPEED100 | M_CFG_FDUP)) {
+ case (M_CFG_SPEED100 | M_CFG_FDUP):
+ sc->linkspeed = ETHER_SPEED_100FDX;
+ xprintf("100BaseT FDX\n");
+ break;
+ case (M_CFG_SPEED100):
+ sc->linkspeed = ETHER_SPEED_100HDX;
+ xprintf("100BaseT HDX\n");
+ break;
+ case (M_CFG_FDUP):
+ sc->linkspeed = ETHER_SPEED_10FDX;
+ xprintf("10BaseT FDX\n");
+ break;
+ default:
+ sc->linkspeed = ETHER_SPEED_10HDX;
+ xprintf("10BaseT HDX\n");
+ break;
+ }
+ if ((status & M_CFG_SPEED100) != 0) {
+ uint32_t t;
+
+ /* This is a reputed fix that improves 100BT rx
+ performance on short cables with "a small number"
+ of DP83815 chips. It comes from Bruce at NatSemi
+ via the Soekris support web page (see appended
+ note). */
+
+ WRITECSR(sc, R_PGSEL, 0x0001);
+ (void)READCSR(sc, R_PGSEL); /* push */
+ t = READCSR(sc, R_DSPCFG);
+ WRITECSR(sc, R_DSPCFG, (t & 0xFFF) | 0x1000);
+ cfe_sleep(1);
+ t = READCSR(sc, R_TSTDAT) & 0xFF;
+ if ((t & 0x0080) == 0 || ((t > 0x00D8) && (t <= 0x00FF))) {
+ WRITECSR(sc, R_TSTDAT, 0x00E8);
+ t = READCSR(sc, R_DSPCFG);
+ WRITECSR(sc, R_DSPCFG, t | 0x0020);
+ }
+ WRITECSR(sc, R_PGSEL, 0);
+ }
+ if ((status & M_CFG_FDUP) != (sc->phy_status & M_CFG_FDUP)) {
+ uint32_t txcfg;
+
+ txcfg = READCSR(sc, R_TXCFG);
+ if (status & M_CFG_FDUP)
+ txcfg |= M_TXCFG_CSI;
+ else
+ txcfg &= ~M_TXCFG_CSI;
+ WRITECSR(sc, R_RXCFG, txcfg);
+ }
+ }
+ else {
+ xprintf("Unknown\n");
+ }
+
+ sc->phy_status = status;
+}
+
+static void
+dp83815_hwinit(dp83815_softc *sc)
+{
+ if (sc->state == eth_state_uninit) {
+ uint32_t cfg;
+ uint32_t txcfg, rxcfg;
+ uint32_t ready;
+ int timeout;
+
+ /* RESET_ADAPTER(sc); */
+ sc->state = eth_state_off;
+ sc->bus_errors = 0;
+
+ cfg = READCSR(sc, R_CFG);
+ cfg |= M_CFG_BEM; /* We will use match bits */
+ WRITECSR(sc, R_CFG, cfg);
+
+ sc->phy_status = 0;
+ dp83815_phyupdate(sc, cfg & M_CFG_LNKSUMMARY);
+
+ txcfg = READCSR(sc, R_TXCFG);
+ txcfg |= M_TXCFG_ATP;
+ /* XXX fix up FLTH, DRTH? */
+ WRITECSR(sc, R_TXCFG, txcfg);
+
+ rxcfg = READCSR(sc, R_RXCFG);
+ /* Set an aggressive rx drain threshhold of 16 (2*8) bytes */
+ rxcfg &= ~M_RXCFG_DRTH;
+ rxcfg |= V_RXCFG_DRTH(2);
+ WRITECSR(sc, R_RXCFG, rxcfg);
+
+#if MACPHYTER_TEST
+ {
+ uint8_t srom[EEPROM_SIZE];
+ uint8_t addr[ENET_ADDR_LEN];
+
+ eeprom_read_all(sc, srom);
+ eeprom_dump(srom);
+ xprintf(" checksum %04x\n", eeprom_checksum(srom));
+ if (eeprom_read_addr(srom, addr) == 0)
+ xprintf(" addr: %02x-%02x-%02x-%02x-%02x-%02x\n",
+ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+
+ mii_probe(sc);
+ xprintf("MII address %02x\n", sc->phy_addr);
+ mii_dump(sc, "DP83815 PHY:");
+ (void)mii_autonegotiate;
+ }
+#endif /* MACPHYTER_TEST */
+
+ /* XXX fix up rx filtering here. We are relying on the EEPROM. */
+
+ /* XXX This is inappropriate on a restart. */
+ timeout = 2*CFE_HZ;
+ ready = 0;
+ for (;;) {
+ ready |= READCSR(sc, R_ISR);
+ if ((ready & (M_INT_TXRCMP | M_INT_RXRCMP))
+ == (M_INT_TXRCMP | M_INT_RXRCMP) || timeout <= 0)
+ break;
+ cfe_sleep(CFE_HZ/10);
+ timeout -= CFE_HZ/10;
+ }
+ if ((ready & M_INT_TXRCMP) == 0)
+ xprintf("%s: tx reset failed\n", dp83815_devname(sc));
+ if ((ready & M_INT_RXRCMP) == 0)
+ xprintf("%s: rx reset failed\n", dp83815_devname(sc));
+ }
+}
+
+static void
+dp83815_setspeed(dp83815_softc *sc, int speed)
+{
+ /* XXX Not yet implemented - autonegotiation only. */
+}
+
+static void
+dp83815_setloopback(dp83815_softc *sc, int mode)
+{
+ /* XXX Not yet implemented. */
+}
+
+
+static void
+dp83815_isr(void *arg)
+{
+ dp83815_softc *sc = (dp83815_softc *)arg;
+ uint32_t status;
+ uint32_t isr;
+
+#if IPOLL
+ sc->interrupts++;
+#endif
+
+ for (;;) {
+
+ /* Read (and clear) the interrupt status. */
+ isr = READCSR(sc, R_ISR);
+ status = isr & sc->intmask;
+
+ /* if there are no more interrupts, leave now. */
+ if (status == 0) break;
+
+ /* Now, test each unmasked bit in the interrupt register and
+ handle each interrupt type appropriately. */
+
+ if (status & (M_INT_RTABT | M_INT_RMABT)) {
+ WRITECSR(sc, R_IER, 0);
+
+ xprintf("%s: bus error\n", dp83815_devname(sc));
+ dumpstat(sc);
+ sc->bus_errors++;
+ if (sc->bus_errors >= 2) {
+ dumpcsrs(sc);
+ RESET_ADAPTER(sc);
+ sc->state = eth_state_off;
+ sc->bus_errors = 0;
+ }
+#if IPOLL
+ else
+ WRITECSR(sc, R_IMR, sc->intmask);
+#endif
+ }
+
+ if (status & M_INT_RXDESC) {
+#if IPOLL
+ sc->rx_interrupts++;
+#endif
+ dp83815_procrxring(sc);
+ }
+
+ if (status & M_INT_TXDESC) {
+#if IPOLL
+ sc->tx_interrupts++;
+#endif
+ dp83815_proctxring(sc);
+ }
+
+ if (status & (M_INT_TXURN | M_INT_RXORN)) {
+ if (status & M_INT_TXURN) {
+ xprintf("%s: tx underrun, %08x\n", dp83815_devname(sc), isr);
+ /* XXX Try to restart */
+ }
+ if (status & M_INT_RXORN) {
+ xprintf("%s: tx overrun, %08x\n", dp83815_devname(sc), isr);
+ /* XXX Try to restart */
+ }
+ }
+
+ if (status & M_INT_PHY) {
+ sc->intmask &= ~ M_INT_PHY;
+ WRITECSR(sc, R_IMR, sc->intmask);
+ (void)READCSR(sc, R_MISR); /* Clear at PHY */
+ sc->phy_check = 1;
+ }
+
+ }
+}
+
+static void
+dp83815_checkphy(dp83815_softc *sc)
+{
+ uint32_t cfg;
+ uint32_t status;
+
+ (void)READCSR(sc, R_MISR); /* Clear at PHY */
+ cfg = READCSR(sc, R_CFG);
+ status = cfg & M_CFG_LNKSUMMARY;
+ if (status != sc->phy_status) {
+ /* XXX Can we really do the phy update with active rx and tx? */
+ dp83815_phyupdate(sc, status);
+ }
+
+ sc->intmask |= M_INT_PHY;
+ WRITECSR(sc, R_IMR, sc->intmask);
+}
+
+
+static void
+dp83815_start(dp83815_softc *sc)
+{
+ dp83815_hwinit(sc);
+
+ /* Set up loopback here */
+
+ sc->intmask = 0;
+ WRITECSR(sc, R_IER, 0); /* no interrupts */
+ WRITECSR(sc, R_IMR, 0);
+ (void)READCSR(sc, R_ISR); /* clear any pending */
+
+ sc->phy_status = READCSR(sc, R_CFG) & M_CFG_LNKSUMMARY;
+ sc->phy_check = 0;
+
+ sc->intmask = M_INT_RXDESC | M_INT_TXDESC;
+ sc->intmask |= M_INT_RTABT | M_INT_RMABT | M_INT_RXORN | M_INT_TXURN;
+ sc->intmask |= M_INT_PHY;
+
+#if IPOLL
+ cfe_request_irq(sc->irq, dp83815_isr, sc, CFE_IRQ_FLAGS_SHARED, 0);
+ WRITECSR(sc, R_IMR, sc->intmask);
+ WRITECSR(sc, R_IER, M_IER_IE);
+#endif
+
+ (void)READCSR(sc, R_MISR); /* clear any pending */
+ WRITECSR(sc, R_MISR, MISR_MSKJAB | MISR_MSKRF | MISR_MSKFHF | MISR_MSKRHF);
+ WRITECSR(sc, R_MICR, MICR_INTEN);
+
+ WRITECSR(sc, R_TXDP, PTR_TO_PCI(sc->txdscr_start));
+ WRITECSR(sc, R_RXDP, PTR_TO_PCI(sc->rxdscr_start));
+
+ WRITECSR(sc, R_MIBC, M_MIBC_ACLR); /* zero hw MIB counters */
+
+ WRITECSR(sc, R_CR, M_CR_TXE | M_CR_RXE);
+ sc->state = eth_state_on;
+}
+
+static void
+dp83815_stop(dp83815_softc *sc)
+{
+ uint32_t status;
+ int count;
+
+ /* Make sure that no further interrutps will be processed. */
+ sc->intmask = 0;
+ WRITECSR(sc, R_IER, 0);
+ WRITECSR(sc, R_IMR, 0);
+
+#if IPOLL
+ (void)READCSR(sc, R_IER); /* Push */
+ cfe_free_irq(sc->irq, 0);
+#endif
+
+ WRITECSR(sc, R_CR, M_CR_TXD | M_CR_RXD);
+
+ /* wait for any DMA activity to terminate */
+ for (count = 0; count <= 13; count++) {
+ status = READCSR(sc, R_CR);
+ if ((status & (M_CR_TXE | M_CR_RXE)) == 0)
+ break;
+ cfe_sleep(CFE_HZ/10);
+ }
+ if (count > 13) {
+ xprintf("%s: idle state not achieved\n", dp83815_devname(sc));
+ dumpstat(sc);
+ RESET_ADAPTER(sc);
+ sc->state = eth_state_uninit;
+#if 1
+ sc->linkspeed = ETHER_SPEED_AUTO;
+#endif
+ }
+#if 0 /* XXX Not yet implemented. */
+ else if (sc->loopback != ETHER_LOOPBACK_OFF) {
+ dp83815_setloopback(sc, ETHER_LOOPBACK_OFF);
+ }
+#endif
+
+ (void)READCSR(sc, R_ISR); /* Clear any stragglers. */
+}
+
+
+/* *********************************************************************
+ * ETH_PARSE_XDIGIT(c)
+ *
+ * Parse a hex digit, returning its value
+ *
+ * Input parameters:
+ * c - character
+ *
+ * Return value:
+ * hex value, or -1 if invalid
+ ********************************************************************* */
+static int
+eth_parse_xdigit(char c)
+{
+ int digit;
+
+ if ((c >= '0') && (c <= '9')) digit = c - '0';
+ else if ((c >= 'a') && (c <= 'f')) digit = c - 'a' + 10;
+ else if ((c >= 'A') && (c <= 'F')) digit = c - 'A' + 10;
+ else digit = -1;
+
+ return digit;
+}
+
+/* *********************************************************************
+ * ETH_PARSE_HWADDR(str,hwaddr)
+ *
+ * Convert a string in the form xx:xx:xx:xx:xx:xx into a 6-byte
+ * Ethernet address.
+ *
+ * Input parameters:
+ * str - string
+ * hwaddr - pointer to hardware address
+ *
+ * Return value:
+ * 0 if ok, else -1
+ ********************************************************************* */
+static int
+eth_parse_hwaddr(char *str, uint8_t *hwaddr)
+{
+ int digit1, digit2;
+ int idx = ENET_ADDR_LEN;
+
+ while (*str && (idx > 0)) {
+ digit1 = eth_parse_xdigit(*str);
+ if (digit1 < 0) return -1;
+ str++;
+ if (!*str) return -1;
+
+ if ((*str == ':') || (*str == '-')) {
+ digit2 = digit1;
+ digit1 = 0;
+ }
+ else {
+ digit2 = eth_parse_xdigit(*str);
+ if (digit2 < 0) return -1;
+ str++;
+ }
+
+ *hwaddr++ = (digit1 << 4) | digit2;
+ idx--;
+
+ if ((*str == ':') || (*str == '-'))
+ str++;
+ }
+ return 0;
+}
+
+/* *********************************************************************
+ * ETH_INCR_HWADDR(hwaddr,incr)
+ *
+ * Increment a 6-byte Ethernet hardware address, with carries
+ *
+ * Input parameters:
+ * hwaddr - pointer to hardware address
+ * incr - desired increment
+ *
+ * Return value:
+ * none
+ ********************************************************************* */
+static void
+eth_incr_hwaddr(uint8_t *hwaddr, unsigned incr)
+{
+ int idx;
+ int carry;
+
+ idx = 5;
+ carry = incr;
+ while (idx >= 0 && carry != 0) {
+ unsigned sum = hwaddr[idx] + carry;
+
+ hwaddr[idx] = sum & 0xFF;
+ carry = sum >> 8;
+ idx--;
+ }
+}
+
+
+/* *********************************************************************
+ * Declarations for CFE Device Driver Interface routines
+ ********************************************************************* */
+
+static int dp83815_ether_open(cfe_devctx_t *ctx);
+static int dp83815_ether_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int dp83815_ether_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
+static int dp83815_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int dp83815_ether_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int dp83815_ether_close(cfe_devctx_t *ctx);
+static void dp83815_ether_poll(cfe_devctx_t *ctx, int64_t ticks);
+static void dp83815_ether_reset(void *softc);
+
+/* *********************************************************************
+ * CFE Device Driver dispatch structure
+ ********************************************************************* */
+
+const static cfe_devdisp_t dp83815_ether_dispatch = {
+ dp83815_ether_open,
+ dp83815_ether_read,
+ dp83815_ether_inpstat,
+ dp83815_ether_write,
+ dp83815_ether_ioctl,
+ dp83815_ether_close,
+ dp83815_ether_poll,
+ dp83815_ether_reset
+};
+
+/* *********************************************************************
+ * CFE Device Driver descriptor
+ ********************************************************************* */
+
+const cfe_driver_t dp83815drv = {
+ "DP83815 Ethernet",
+ "eth",
+ CFE_DEV_NETWORK,
+ &dp83815_ether_dispatch,
+ dp83815_ether_probe
+};
+
+
+static int
+dp83815_ether_attach(cfe_driver_t *drv,
+ pcitag_t tag, int index, uint8_t hwaddr[])
+{
+ dp83815_softc *sc;
+ uint32_t device;
+ uint32_t class;
+ phys_addr_t pa;
+ uint8_t promaddr[ENET_ADDR_LEN];
+ char descr[100];
+ uint32_t srr;
+
+ device = pci_conf_read(tag, R_CFGID);
+ class = pci_conf_read(tag, R_CFGRID);
+
+#if 1
+ /* Use memory space for the CSRs */
+ pci_map_mem(tag, R_CFGMA, PCI_MATCH_BITS, &pa);
+#else
+ /* Use i/o space for the CSRs */
+ pci_map_io(tag, R_CFGIOA, PCI_MATCH_BITS, &pa);
+#endif
+
+ sc = (dp83815_softc *) KMALLOC(sizeof(dp83815_softc), 0);
+
+ if (sc == NULL) {
+ xprintf("DP83815: No memory to complete probe\n");
+ return 0;
+ }
+ memset(sc, 0, sizeof(*sc));
+
+ sc->membase = (uint32_t)pa;
+ sc->irq = pci_conf_read(tag, R_CFGINT) & 0xFF;
+ sc->tag = tag;
+ sc->device = PCI_PRODUCT(device);
+ sc->revision = PCI_REVISION(class);
+ sc->devctx = NULL;
+
+#if 1
+ sc->linkspeed = ETHER_SPEED_AUTO; /* select autonegotiation */
+#else
+ sc->linkspeed = ETHER_SPEED_100FDX; /* 100 Mbps, full duplex */
+#endif
+ sc->loopback = ETHER_LOOPBACK_OFF;
+ memcpy(sc->hwaddr, hwaddr, ENET_ADDR_LEN);
+
+ srr = READCSR(sc, R_SRR);
+#if 0
+ /* The NS data sheet recommends the following for "optimal
+ performance" of CVNG parts. Tested on a sample of one CVNG
+ part on an NS "Macphyter Demo II" eval board, it seemed to
+ produce slightly less reliable initial behavior. */
+ if (G_SRR_REV(srr) == K_REV_CVNG) {
+ /* Update PHY DSP registers per data sheet. */
+ WRITECSR(sc, R_PGSEL, 0x0001);
+ (void)READCSR(sc, R_PGSEL); /* push */
+ WRITECSR(sc, R_PMDCSR, 0x189C);
+ WRITECSR(sc, R_TSTDAT, 0x0000);
+ WRITECSR(sc, R_DSPCFG, 0x5040);
+ WRITECSR(sc, R_SDCFG, 0x008C);
+ }
+#endif
+
+ dp83815_init(sc);
+
+ /* Prefer the address in EEPROM. This will be read into the
+ PMATCH register upon power up. Unfortunately, how to test for
+ completion of the auto-load (but see PTSCR_EELOAD_EN). */
+ if (dp83815_get_pm_addr(sc, promaddr) == 0) {
+ memcpy(sc->hwaddr, promaddr, ENET_ADDR_LEN);
+ }
+
+ sc->state = eth_state_uninit;
+
+ xsprintf(descr, "%s at 0x%X (%02x-%02x-%02x-%02x-%02x-%02x)",
+ drv->drv_description, sc->membase,
+ sc->hwaddr[0], sc->hwaddr[1], sc->hwaddr[2],
+ sc->hwaddr[3], sc->hwaddr[4], sc->hwaddr[5]);
+
+ cfe_attach(drv, sc, NULL, descr);
+ return 1;
+}
+
+
+/* *********************************************************************
+ * DP83815_ETHER_PROBE(drv,probe_a,probe_b,probe_ptr)
+ *
+ * Probe and install drivers for all dp83815 Ethernet controllers.
+ * For each, create a context structure and attach to the
+ * specified network device.
+ *
+ * Input parameters:
+ * drv - driver descriptor
+ * probe_a - not used
+ * probe_b - not used
+ * probe_ptr - string pointer to hardware address for the first
+ * MAC, in the form xx:xx:xx:xx:xx:xx
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void
+dp83815_ether_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ int n;
+ uint8_t hwaddr[ENET_ADDR_LEN];
+
+ if (probe_ptr)
+ eth_parse_hwaddr((char *) probe_ptr, hwaddr);
+ else {
+ /* use default address 02-00-00-10-0B-00 */
+ hwaddr[0] = 0x02; hwaddr[1] = 0x00; hwaddr[2] = 0x00;
+ hwaddr[3] = 0x10; hwaddr[4] = 0x0B; hwaddr[5] = 0x00;
+ }
+
+ n = 0;
+ for (;;) {
+ pcitag_t tag;
+
+ if (pci_find_device(K_PCI_VENDOR_NSC, K_PCI_ID_DP83815, n, &tag) != 0)
+ break;
+ dp83815_ether_attach(drv, tag, n, hwaddr);
+ n++;
+ eth_incr_hwaddr(hwaddr, 1);
+ }
+}
+
+
+/* The functions below are called via the dispatch vector for the 83815. */
+
+/* *********************************************************************
+ * DP83815_ETHER_OPEN(ctx)
+ *
+ * Open the Ethernet device. The MAC is reset, initialized, and
+ * prepared to receive and send packets.
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ *
+ * Return value:
+ * status, 0 = ok
+ ********************************************************************* */
+static int
+dp83815_ether_open(cfe_devctx_t *ctx)
+{
+ dp83815_softc *sc = ctx->dev_softc;
+
+ if (sc->state == eth_state_on)
+ dp83815_stop(sc);
+
+ sc->devctx = ctx;
+
+ sc->inpkts = sc->outpkts = 0;
+ sc->interrupts = 0;
+ sc->rx_interrupts = sc->tx_interrupts = 0;
+
+ dp83815_start(sc);
+
+#if XPOLL
+ dp83815_isr(sc);
+#endif
+
+ return 0;
+}
+
+/* *********************************************************************
+ * DP83815_ETHER_READ(ctx,buffer)
+ *
+ * Read a packet from the Ethernet device. If no packets are
+ * available, the read will succeed but return 0 bytes.
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ * buffer - pointer to buffer descriptor.
+ *
+ * Return value:
+ * status, 0 = ok
+ ********************************************************************* */
+static int
+dp83815_ether_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ dp83815_softc *sc = ctx->dev_softc;
+ eth_pkt_t *pkt;
+ int blen;
+
+#if XPOLL
+ dp83815_isr(sc);
+#endif
+
+ if (sc->state != eth_state_on) return -1;
+
+ CS_ENTER(sc);
+ pkt = (eth_pkt_t *) q_deqnext(&(sc->rxqueue));
+ CS_EXIT(sc);
+
+ if (pkt == NULL) {
+ buffer->buf_retlen = 0;
+ return 0;
+ }
+
+ blen = buffer->buf_length;
+ if (blen > pkt->length) blen = pkt->length;
+
+ blockcopy(buffer->buf_ptr, pkt->buffer, blen);
+ buffer->buf_retlen = blen;
+
+ eth_free_pkt(sc, pkt);
+ dp83815_fillrxring(sc);
+
+#if XPOLL
+ dp83815_isr(sc);
+#endif
+
+ return 0;
+}
+
+/* *********************************************************************
+ * DP83815_ETHER_INPSTAT(ctx,inpstat)
+ *
+ * Check for received packets on the Ethernet device
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ * inpstat - pointer to input status structure
+ *
+ * Return value:
+ * status, 0 = ok
+ ********************************************************************* */
+static int
+dp83815_ether_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat)
+{
+ dp83815_softc *sc = ctx->dev_softc;
+
+#if XPOLL
+ dp83815_isr(sc);
+#endif
+
+ if (sc->state != eth_state_on) return -1;
+
+ /* We avoid an interlock here because the result is a hint and an
+ interrupt cannot turn a non-empty queue into an empty one. */
+ inpstat->inp_status = (q_isempty(&(sc->rxqueue))) ? 0 : 1;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * DP83815_ETHER_WRITE(ctx,buffer)
+ *
+ * Write a packet to the Ethernet device.
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ * buffer - pointer to buffer descriptor.
+ *
+ * Return value:
+ * status, 0 = ok
+ ********************************************************************* */
+static int
+dp83815_ether_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ dp83815_softc *sc = ctx->dev_softc;
+ eth_pkt_t *pkt;
+ int blen;
+
+#if XPOLL
+ dp83815_isr(sc);
+#endif
+
+ if (sc->state != eth_state_on) return -1;
+
+ pkt = eth_alloc_pkt(sc);
+ if (!pkt) return CFE_ERR_NOMEM;
+
+ blen = buffer->buf_length;
+ if (blen > pkt->length) blen = pkt->length;
+
+ blockcopy(pkt->buffer, buffer->buf_ptr, blen);
+ pkt->length = blen;
+
+ if (dp83815_transmit(sc, pkt) != 0) {
+ eth_free_pkt(sc,pkt);
+ return CFE_ERR_IOERR;
+ }
+
+#if XPOLL
+ dp83815_isr(sc);
+#endif
+
+ return 0;
+}
+
+/* *********************************************************************
+ * DP83815_ETHER_IOCTL(ctx,buffer)
+ *
+ * Do device-specific I/O control operations for the device
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ * buffer - pointer to buffer descriptor.
+ *
+ * Return value:
+ * status, 0 = ok
+ ********************************************************************* */
+static int
+dp83815_ether_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ dp83815_softc *sc = ctx->dev_softc;
+ int *argp;
+ int mode;
+ int speed;
+
+ switch ((int)buffer->buf_ioctlcmd) {
+ case IOCTL_ETHER_GETHWADDR:
+ memcpy(buffer->buf_ptr, sc->hwaddr, sizeof(sc->hwaddr));
+ return 0;
+
+ case IOCTL_ETHER_SETHWADDR:
+ return -1; /* not supported */
+
+ case IOCTL_ETHER_GETSPEED:
+ argp = (int *) buffer->buf_ptr;
+ *argp = sc->linkspeed;
+ return 0;
+
+ case IOCTL_ETHER_SETSPEED:
+ dp83815_stop(sc);
+ dp83815_resetrings(sc);
+ speed = *((int *) buffer->buf_ptr);
+ dp83815_setspeed(sc, speed);
+ dp83815_start(sc);
+ sc->state = eth_state_on;
+ return 0;
+
+ case IOCTL_ETHER_GETLINK:
+ argp = (int *) buffer->buf_ptr;
+ *argp = sc->linkspeed;
+ return 0;
+
+ case IOCTL_ETHER_GETLOOPBACK:
+ *((int *) buffer) = sc->loopback;
+ return 0;
+
+ case IOCTL_ETHER_SETLOOPBACK:
+ dp83815_stop(sc);
+ dp83815_resetrings(sc);
+ mode = *((int *) buffer->buf_ptr);
+ sc->loopback = ETHER_LOOPBACK_OFF; /* default */
+ if (mode == ETHER_LOOPBACK_INT || mode == ETHER_LOOPBACK_EXT) {
+ dp83815_setloopback(sc, mode);
+ }
+ dp83815_start(sc);
+ sc->state = eth_state_on;
+ return 0;
+
+ default:
+ return -1;
+ }
+}
+
+/* *********************************************************************
+ * DP83815_ETHER_CLOSE(ctx)
+ *
+ * Close the Ethernet device.
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ *
+ * Return value:
+ * status, 0 = ok
+ ********************************************************************* */
+static int
+dp83815_ether_close(cfe_devctx_t *ctx)
+{
+ dp83815_softc *sc = ctx->dev_softc;
+
+ sc->state = eth_state_off;
+ dp83815_stop(sc);
+
+ /* resynchronize descriptor rings */
+ dp83815_resetrings(sc);
+
+ xprintf("%s: %d sent, %d received, %d interrupts\n",
+ dp83815_devname(sc), sc->outpkts, sc->inpkts, sc->interrupts);
+ xprintf(" %d rx interrupts, %d tx interrupts\n",
+ sc->rx_interrupts, sc->tx_interrupts);
+
+ sc->devctx = NULL;
+ return 0;
+}
+
+
+/* *********************************************************************
+ * DP83815_ETHER_POLL(ctx,ticks)
+ *
+ * TBD
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ * ticks- current time in ticks
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void
+dp83815_ether_poll(cfe_devctx_t *ctx, int64_t ticks)
+{
+ dp83815_softc *sc = ctx->dev_softc;
+
+ if (sc->phy_check) {
+ sc->phy_check = 0;
+ dp83815_checkphy(sc);
+ }
+}
+
+
+/* *********************************************************************
+ * DP83815_ETHER_RESET(softc)
+ *
+ * This routine is called when CFE is restarted after a
+ * program exits. We can clean up pending I/Os here.
+ *
+ * Input parameters:
+ * softc - pointer to dp83815_softc
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void
+dp83815_ether_reset(void *softc)
+{
+ dp83815_softc *sc = (dp83815_softc *)softc;
+
+ /* Turn off the Ethernet interface. */
+
+ /* RESET_ADAPTER(sc); */
+
+ sc->state = eth_state_uninit;
+}
diff --git a/cfe/cfe/dev/dev_ds17887clock.c b/cfe/cfe/dev/dev_ds17887clock.c
new file mode 100644
index 0000000..2ee82a3
--- /dev/null
+++ b/cfe/cfe/dev/dev_ds17887clock.c
@@ -0,0 +1,422 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * DS17887-3 RTC driver File: dev_sb1250_ds17887clock.c
+ *
+ * This module contains a CFE driver for a DS17887-3 generic bus
+ * real-time-clock.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+#include "lib_types.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "cfe_ioctl.h"
+
+#include "lib_physio.h"
+
+
+/* *********************************************************************
+ * Constants
+ ********************************************************************* */
+
+/*
+ * Register bits
+ */
+
+#define DS17887REGA_UIP 0x80 /* Update-in-progress */
+#define DS17887REGA_DV2 0x40 /* Countdown chain */
+#define DS17887REGA_DV1 0x20 /* Oscillator enable */
+#define DS17887REGA_DV0 0x10 /* Bank Select */
+#define DS17887REGA_RS3 0x08 /* Rate-selection bits */
+#define DS17887REGA_RS2 0x04
+#define DS17887REGA_RS1 0x02
+#define DS17887REGA_RS0 0x01
+
+#define DS17887REGB_SET 0x80 /* Set bit */
+#define DS17887REGB_PIE 0x40 /* Periodic Interrupt Enable */
+#define DS17887REGB_AIE 0x20 /* Alarm Interrupt Enable */
+#define DS17887REGB_UIE 0x10 /* Update-ended Interrupt Enable */
+#define DS17887REGB_SQWE 0x08 /* Square-wave Enable */
+#define DS17887REGB_DM 0x04 /* Data Mode (binary) */
+#define DS17887REGB_24 0x02 /* 24-hour mode control bit */
+#define DS17887REGB_DSE 0x01 /* Daylight Savings Enable */
+
+#define DS17887REGC_IRQF 0x80 /* Interrupt request flag */
+#define DS17887REGC_PF 0x40 /* Periodic interrupt flag */
+#define DS17887REGC_AF 0x20 /* Alarm interrupt flag */
+#define DS17887REGC_UF 0x10 /* Update ended interrupt flag */
+
+#define DS17887REGD_VRT 0x80 /* Valid RAM and time */
+
+/*
+ * Register numbers
+ */
+
+#define DS17887REG_SC 0x00 /* seconds */
+#define DS17887REG_SCA 0x01 /* seconds alarm */
+#define DS17887REG_MN 0x02 /* minutes */
+#define DS17887REG_MNA 0x03 /* minutes alarm */
+#define DS17887REG_HR 0x04 /* hours */
+#define DS17887REG_HRA 0x05 /* hours alarm */
+#define DS17887REG_DW 0x06 /* day of week */
+#define DS17887REG_DM 0x07 /* day of month */
+#define DS17887REG_MO 0x08 /* month */
+#define DS17887REG_YR 0x09 /* year */
+#define DS17887REG_A 0x0A /* register A */
+#define DS17887REG_B 0x0B /* register B */
+#define DS17887REG_C 0x0C /* register C */
+#define DS17887REG_D 0x0D /* register D */
+
+#define DS17887REG_CE 0x48 /* century (bank 1 only) */
+
+#define BCD(x) (((x) % 10) + (((x) / 10) << 4))
+#define SET_TIME 0x00
+#define SET_DATE 0x01
+
+#define WRITECSR(p,v) phys_write8((p),(v))
+#define READCSR(p) phys_read8((p))
+
+/* *********************************************************************
+ * Forward declarations
+ ********************************************************************* */
+
+static void ds17887_clock_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+static int ds17887_clock_open(cfe_devctx_t *ctx);
+static int ds17887_clock_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int ds17887_clock_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
+static int ds17887_clock_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int ds17887_clock_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int ds17887_clock_close(cfe_devctx_t *ctx);
+
+
+/* *********************************************************************
+ * Device dispatch
+ ********************************************************************* */
+
+const static cfe_devdisp_t ds17887_clock_dispatch = {
+ ds17887_clock_open,
+ ds17887_clock_read,
+ ds17887_clock_inpstat,
+ ds17887_clock_write,
+ ds17887_clock_ioctl,
+ ds17887_clock_close,
+ NULL,
+ NULL
+};
+
+const cfe_driver_t ds17887_clock = {
+ "DS17887 RTC",
+ "clock",
+ CFE_DEV_CLOCK,
+ &ds17887_clock_dispatch,
+ ds17887_clock_probe
+};
+
+
+/* *********************************************************************
+ * Structures
+ ********************************************************************* */
+typedef struct ds17887_clock_s {
+ physaddr_t clock_base;
+} ds17887_clock_t;
+
+/* *********************************************************************
+ * ds17887_clock_probe(drv,a,b,ptr)
+ *
+ * Probe routine for this driver. This routine creates the
+ * local device context and attaches it to the driver list
+ * within CFE.
+ *
+ * Input parameters:
+ * drv - driver handle
+ * a,b - probe hints (longs)
+ * ptr - probe hint (pointer)
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void ds17887_clock_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ ds17887_clock_t *softc;
+ char descr[80];
+
+ softc = (ds17887_clock_t *) KMALLOC(sizeof(ds17887_clock_t),0);
+
+ /*
+ * Probe_a is the clock base address
+ * Probe_b is unused.
+ * Probe_ptr is unused.
+ */
+
+ softc->clock_base = probe_a;
+
+ xsprintf(descr,"%s at 0x%X",
+ drv->drv_description,(uint32_t)probe_a);
+ cfe_attach(drv,softc,NULL,descr);
+
+}
+
+/* *********************************************************************
+ * ds17887_clock_open(ctx)
+ *
+ * Open this device. For the DS17887, we do a quick test
+ * read to be sure the device is out there.
+ *
+ * Input parameters:
+ * ctx - device context (can obtain our softc here)
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int ds17887_clock_open(cfe_devctx_t *ctx)
+{
+ ds17887_clock_t *softc = ctx->dev_softc;
+ uint8_t byte;
+ physaddr_t clockbase;
+
+ clockbase = softc->clock_base;
+
+ /* Make sure battery is still good and RTC valid */
+ if ( !(READCSR(clockbase+DS17887REG_D) & DS17887REGD_VRT) ) {
+ printf("Warning: Battery has failed. Clock setting is not accurate.\n");
+ }
+
+ /* Switch to bank 1. Mainly for century byte */
+ byte = (uint8_t) (READCSR(clockbase+DS17887REG_A) & 0xFF);
+ WRITECSR(clockbase+DS17887REG_A,DS17887REGA_DV0 | DS17887REGA_DV1 | byte);
+
+ /* Set data mode to BCD, 24-hour mode, and enable daylight savings */
+ byte = (uint8_t) (READCSR(clockbase+DS17887REG_B) & 0xFF);
+ byte &= (~DS17887REGB_DM & ~DS17887REGB_AIE);
+ WRITECSR(clockbase+DS17887REG_B, DS17887REGB_24 | DS17887REGB_DSE | byte );
+
+ return 0;
+}
+
+/* *********************************************************************
+ * ds17887_clock_read(ctx,buffer)
+ *
+ * Read time/date from the RTC. Read a total of 8 bytes in this format:
+ * hour-minute-second-month-day-year1-year2
+ *
+ * Input parameters:
+ * ctx - device context (can obtain our softc here)
+ * buffer - buffer descriptor (target buffer, length, offset)
+ *
+ * Return value:
+ * number of bytes read
+ * -1 if an error occured
+ ********************************************************************* */
+
+static int ds17887_clock_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+
+ ds17887_clock_t *softc = ctx->dev_softc;
+ unsigned char *bptr;
+ physaddr_t clockbase;
+
+ clockbase = softc->clock_base;
+
+ bptr = buffer->buf_ptr;
+
+ *bptr++ = READCSR(clockbase+DS17887REG_HR);
+ *bptr++ = READCSR(clockbase+DS17887REG_MN);
+ *bptr++ = READCSR(clockbase+DS17887REG_SC);
+ *bptr++ = READCSR(clockbase+DS17887REG_MO);
+ *bptr++ = READCSR(clockbase+DS17887REG_DM);
+ *bptr++ = READCSR(clockbase+DS17887REG_YR);
+ *bptr++ = READCSR(clockbase+DS17887REG_CE);
+
+ buffer->buf_retlen = 8;
+ return 0;
+}
+
+/* *********************************************************************
+ * ds17887_clock_write(ctx,buffer)
+ *
+ * Write time/date to the RTC. Write in this format:
+ * hour-minute-second-month-day-year1-year2-(time/date flag)
+ *
+ * Input parameters:
+ * ctx - device context (can obtain our softc here)
+ * buffer - buffer descriptor (target buffer, length, offset)
+ *
+ * Return value:
+ * number of bytes written
+ * -1 if an error occured
+ ********************************************************************* */
+
+static int ds17887_clock_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ ds17887_clock_t *softc = ctx->dev_softc;
+ uint8_t byte;
+ unsigned char *bptr;
+ uint8_t hr,min,sec;
+ uint8_t mo,day,yr,y2k;
+ uint8_t timeDateFlag;
+ physaddr_t clockbase;
+
+ clockbase = softc->clock_base;
+
+ bptr = buffer->buf_ptr;
+
+ /* Set SET bit */
+ byte = (uint8_t) (READCSR(clockbase+DS17887REG_B) & 0xFF);
+ WRITECSR(clockbase+DS17887REG_B,DS17887REGB_SET | byte);
+
+ timeDateFlag = *(bptr + 7);
+
+ /* write time or date */
+ if(timeDateFlag == SET_TIME) {
+
+ hr = (uint8_t) *bptr;
+ WRITECSR(clockbase+DS17887REG_HR,BCD(hr));
+
+ min = (uint8_t) *(bptr+1);
+ WRITECSR(clockbase+DS17887REG_MN,BCD(min));
+
+ sec = (uint8_t) *(bptr+2);
+ WRITECSR(clockbase+DS17887REG_SC,BCD(sec));
+
+ buffer->buf_retlen = 3;
+ }
+ else if(timeDateFlag == SET_DATE) {
+
+ mo = (uint8_t) *(bptr+3);
+ WRITECSR(clockbase+DS17887REG_MO,BCD(mo));
+
+ day = (uint8_t) *(bptr+4);
+ WRITECSR(clockbase+DS17887REG_DM,BCD(day));
+
+ yr = (uint8_t) *(bptr+5);
+ WRITECSR(clockbase+DS17887REG_YR,BCD(yr));
+
+ y2k = (uint8_t) *(bptr+6);
+ WRITECSR(clockbase+DS17887REG_CE,y2k);
+
+ buffer->buf_retlen = 4;
+ }
+ else {
+ return -1;
+ }
+
+ /* clear SET bit */
+ byte = (uint8_t) (READCSR(clockbase+DS17887REG_B) & 0xFF);
+ WRITECSR(clockbase+DS17887REG_B,~DS17887REGB_SET & byte);
+
+ return 0;
+}
+
+/* *********************************************************************
+ * ds17887_clock_inpstat(ctx,inpstat)
+ *
+ * Test input (read) status for the device
+ *
+ * Input parameters:
+ * ctx - device context (can obtain our softc here)
+ * inpstat - input status descriptor to receive value
+ *
+ * Return value:
+ * 0 if ok
+ * -1 if an error occured
+ ********************************************************************* */
+
+static int ds17887_clock_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
+{
+ inpstat->inp_status = 1;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * ds17887_clock_ioctl(ctx,buffer)
+ *
+ * Perform miscellaneous I/O control operations on the device.
+ *
+ * Input parameters:
+ * ctx - device context (can obtain our softc here)
+ * buffer - buffer descriptor (target buffer, length, offset)
+ *
+ * Return value:
+ * number of bytes read
+ * -1 if an error occured
+ ********************************************************************* */
+
+static int ds17887_clock_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ return 0;
+}
+
+/* *********************************************************************
+ * ds17887_clock_close(ctx,buffer)
+ *
+ * Close the device.
+ *
+ * Input parameters:
+ * ctx - device context (can obtain our softc here)
+ *
+ * Return value:
+ * 0 if ok
+ * -1 if an error occured
+ ********************************************************************* */
+
+static int ds17887_clock_close(cfe_devctx_t *ctx)
+{
+ return 0;
+}
+
+
+
+
+
+
+
+
diff --git a/cfe/cfe/dev/dev_flash.c b/cfe/cfe/dev/dev_flash.c
new file mode 100644
index 0000000..98ad3e7
--- /dev/null
+++ b/cfe/cfe/dev/dev_flash.c
@@ -0,0 +1,1367 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Flash device driver File: dev_flash.c
+ *
+ * This driver supports various types of flash
+ * parts. You can also put the environment storage in
+ * the flash - the top sector is reserved for that purpose.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include "lib_types.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+#include "lib_string.h"
+#include "addrspace.h"
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "cfe_ioctl.h"
+#include "cfe_error.h"
+
+#include "dev_flash.h"
+
+/* *********************************************************************
+ * Macros
+ ********************************************************************* */
+
+#define FLASHCMD(sc,x,y) *((volatile unsigned char *)(sc->flashdrv_cmdaddr+ \
+ ((x)<<(sc)->flashdrv_widemode))) = (y)
+#define FLASHSTATUS(sc,x) *((volatile unsigned char *)(sc->flashdrv_cmdaddr+ \
+ ((x)<<(sc)->flashdrv_widemode)))
+
+#define WRITEFLASH_K1(sc,x,y) *((volatile unsigned char *)(sc->flashdrv_cmdaddr+(x))) = (y)
+#define READFLASH_K1(sc,x) *((volatile unsigned char *)(sc->flashdrv_cmdaddr+(x)))
+
+#define WRITEFLASH_K1W(sc,x,y) *((volatile unsigned short *)(sc->flashdrv_cmdaddr+(x))) = (y)
+#define READFLASH_K1W(sc,x) *((volatile unsigned short *)(sc->flashdrv_cmdaddr+(x)))
+
+
+#define GETCFIBYTE(softc,offset) READFLASH_K1(softc,((offset) << (softc->flashdrv_widemode)))
+
+/* *********************************************************************
+ * Forward declarations
+ ********************************************************************* */
+
+
+static void flashdrv_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+
+static int flashdrv_open(cfe_devctx_t *ctx);
+static int flashdrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int flashdrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
+static int flashdrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int flashdrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int flashdrv_close(cfe_devctx_t *ctx);
+
+/* *********************************************************************
+ * Device dispatch
+ ********************************************************************* */
+
+const static cfe_devdisp_t flashdrv_dispatch = {
+ flashdrv_open,
+ flashdrv_read,
+ flashdrv_inpstat,
+ flashdrv_write,
+ flashdrv_ioctl,
+ flashdrv_close,
+ NULL,
+ NULL
+};
+
+const cfe_driver_t flashdrv = {
+ "CFI flash",
+ "flash",
+ CFE_DEV_FLASH,
+ &flashdrv_dispatch,
+ flashdrv_probe
+};
+
+
+/* *********************************************************************
+ * Structures
+ ********************************************************************* */
+
+typedef struct flash_cfidata_s {
+ unsigned int cfidata_cmdset; /* ID of primary command set */
+ unsigned int cfidata_devif; /* device interface byte */
+ unsigned int cfidata_size; /* probed device size */
+} flash_cfidata_t;
+
+typedef struct flashops_s flashops_t;
+
+typedef struct flashdrv_s {
+ flash_probe_t flashdrv_probe; /* data from probe */
+ int flashdrv_devsize; /* size reported by driver */
+ unsigned char *flashdrv_cmdaddr; /* virtual address (K1) */
+ int flashdrv_widemode; /* 1=wide flash in byte mode, 0=narrow flash */
+ int flashdrv_initialized; /* true if we've probed already */
+ flash_info_t flashdrv_info;
+ int flashdrv_nvram_ok; /* true if we can use as NVRAM */
+ int flashdrv_unlocked; /* true if we can r/w past devsize */
+ nvram_info_t flashdrv_nvraminfo;
+ flashops_t *flashdrv_ops;
+ flash_cfidata_t flashdrv_cfidata;
+} flashdrv_t;
+
+struct flashops_s {
+ int (*erasesector)(flashdrv_t *f,int offset);
+ int (*writeblk)(flashdrv_t *f,int offset,void *buf,int len);
+};
+
+/* *********************************************************************
+ * Macros
+ ********************************************************************* */
+
+#define FLASHOP_ERASE_SECTOR(softc,sect) (*((softc)->flashdrv_ops->erasesector))((softc),(sect))
+#define FLASHOP_WRITE_BLOCK(softc,off,buf,len) (*((softc)->flashdrv_ops->writeblk))((softc),(off),(buf),(len))
+
+/* *********************************************************************
+ * forward declarations
+ ********************************************************************* */
+
+
+static int flash_sector_query(flashdrv_t *softc,flash_sector_t *sector);
+
+static int amd_flash_write_block(flashdrv_t *softc,int offset,void *buf,int len);
+static int amd_flash_erase_sector(flashdrv_t *softc,int offset);
+
+static int intel_flash_write_block(flashdrv_t *softc,int offset,void *buf,int len);
+static int intel_flash_erase_sector(flashdrv_t *softc,int offset);
+
+static flashops_t amd_flashops = {
+ amd_flash_erase_sector,
+ amd_flash_write_block,
+};
+
+static flashops_t intel_flashops = {
+ intel_flash_erase_sector,
+ intel_flash_write_block,
+};
+
+#define FLASHOPS_DEFAULT amd_flashops
+
+
+
+/* *********************************************************************
+ * Externs
+ ********************************************************************* */
+
+extern void *flash_write_all_ptr;
+extern int flash_write_all_len;
+
+extern void _cfe_flushcache(int);
+
+
+#if 0
+/* *********************************************************************
+ * jedec_flash_maufacturer(softc)
+ *
+ * Return the manufacturer ID for this flash part.
+ *
+ * Input parameters:
+ * softc - flash context
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static unsigned int jedec_flash_manufacturer(flashdrv_t *softc)
+{
+ unsigned int res;
+
+ /* Do an "unlock write" sequence */
+ FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1);
+ FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2);
+ FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_AUTOSEL);
+
+ res = FLASHSTATUS(softc,FLASH_JEDEC_OFFSET_MFR) & 0xFF;
+
+ FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_RESET);
+
+ return res;
+}
+
+/* *********************************************************************
+ * jedec_flash_type(softc)
+ *
+ * Return the manufacturer's type for the flash
+ *
+ * Input parameters:
+ * softc - flash context
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static unsigned int jedec_flash_type(flashdrv_t *softc)
+{
+ unsigned int res;
+
+ /* Do an "unlock write" sequence */
+ FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1);
+ FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2);
+ FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_AUTOSEL);
+
+ res = FLASHSTATUS(softc,FLASH_JEDEC_OFFSET_DEV) & 0xFF;
+
+ FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_RESET);
+
+ return res;
+}
+
+#endif
+
+/* *********************************************************************
+ * amd_flash_write_byte(softc,offset,val)
+ *
+ * Write a single byte to the flash. The sector that the flash
+ * byte is in should have been previously erased, or else this
+ * routine may hang.
+ *
+ * Input parameters:
+ * softc - flash context
+ * offset - distance in bytes into the flash
+ * val - byte to write
+ *
+ * Return value:
+ * 0 if ok
+ * else if flash could not be written
+ ********************************************************************* */
+static inline int amd_flash_write_byte(flashdrv_t *softc,int offset, unsigned char val)
+{
+ unsigned int value;
+
+ /* Do an "unlock write" sequence */
+ FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1);
+ FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2);
+
+ /* Send a program command */
+ FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_PROGRAM);
+
+ /* Write a byte */
+ WRITEFLASH_K1(softc,offset,val);
+
+ for (;;) {
+ value = READFLASH_K1(softc,offset) & 0xFF;
+
+ if ((value & 0x80) == (val & 0x80)) {
+ return 0;
+ }
+ if ((value & 0x20) != 0x20) {
+ continue;
+ }
+
+ if ((READFLASH_K1(softc,offset) & 0x80) == (val & 0x80)) {
+ return 0;
+ }
+ else {
+ return -1;
+ }
+ }
+}
+
+
+/* *********************************************************************
+ * amd_flash_write_block(softc,offset,val)
+ *
+ * Write a single byte to the flash. The sector that the flash
+ * byte is in should have been previously erased, or else this
+ * routine may hang.
+ *
+ * Input parameters:
+ * softc - flash context
+ * offset - distance in bytes into the flash
+ * buf - buffer of bytes to write
+ * len - number of bytes to write
+ *
+ * Return value:
+ * number of bytes written
+ ********************************************************************* */
+static int amd_flash_write_block(flashdrv_t *softc,int offset,void *buf,int len)
+{
+ unsigned char *ptr;
+
+ ptr = buf;
+
+ while (len) {
+ if (amd_flash_write_byte(softc,offset,*ptr) < 0) break;
+ len--;
+ ptr++;
+ offset++;
+
+ }
+
+ return (ptr - (unsigned char *)buf);
+}
+
+
+/* *********************************************************************
+ * amd_flash_erase_sector(softc,offset)
+ *
+ * Erase a single sector in the flash device
+ *
+ * Input parameters:
+ * softc - device context
+ * offset - offset in flash of sector to erase
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+static int amd_flash_erase_sector(flashdrv_t *softc,int offset)
+{
+ /* Do an "unlock write" sequence */
+ FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1); /* cycles 1-2 */
+ FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2);
+
+ /* send the erase command */
+ FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_ERASE_3); /* cycle 3 */
+
+ /* Do an "unlock write" sequence */
+ FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_1,AMD_FLASH_MAGIC_1); /* cycles 4-5 */
+ FLASHCMD(softc,AMD_FLASH_MAGIC_ADDR_2,AMD_FLASH_MAGIC_2);
+
+ /*
+ * Send the "erase sector" qualifier - don't use FLASHCMD
+ * because it changes the offset.
+ */
+ WRITEFLASH_K1(softc,offset,AMD_FLASH_ERASE_SEC_6);
+
+ while ((READFLASH_K1(softc,offset) & 0x80) != 0x80) {
+ /* NULL LOOP */
+ }
+
+ return 0;
+}
+
+
+
+/* *********************************************************************
+ * intel_flash_write_byte(softc,offset,val)
+ *
+ * Write a single byte to the flash. The sector that the flash
+ * byte is in should have been previously erased, or else this
+ * routine may hang.
+ *
+ * Input parameters:
+ * softc - flash context
+ * offset - distance in bytes into the flash
+ * val - byte to write
+ *
+ * Return value:
+ * 0 if ok
+ * else if flash could not be written
+ ********************************************************************* */
+static inline int intel_flash_write_byte(flashdrv_t *softc,
+ int offset, unsigned char val)
+{
+ unsigned int value;
+
+ /* Send a program command */
+ WRITEFLASH_K1(softc,offset,INTEL_FLASH_PROGRAM);
+
+ /* Write a byte */
+ WRITEFLASH_K1(softc,offset,val);
+
+
+ while ((READFLASH_K1(softc,offset) & 0x80) != 0x80) {
+ /* NULL LOOP */
+ }
+
+ value = READFLASH_K1(softc,offset) & 0xFF;
+
+ if (value & (0x01|0x08|0x10)) return -1;
+ return 0;
+}
+
+/* *********************************************************************
+ * intel_flash_write_word(softc,offset,val)
+ *
+ * Write a single word to the flash. The sector that the flash
+ * byte is in should have been previously erased, or else this
+ * routine may hang.
+ *
+ * Input parameters:
+ * softc - flash context
+ * offset - distance in bytes into the flash
+ * val - word to write
+ *
+ * Return value:
+ * 0 if ok
+ * else if flash could not be written
+ ********************************************************************* */
+static inline int intel_flash_write_word(flashdrv_t *softc,
+ int offset, unsigned short val)
+{
+ unsigned int value;
+
+
+ /* Send a program command */
+ WRITEFLASH_K1W(softc,offset,INTEL_FLASH_PROGRAM);
+
+ /* Write a byte */
+ WRITEFLASH_K1W(softc,offset,val);
+
+
+ while ((READFLASH_K1W(softc,offset) & 0x80) != 0x80) {
+ /* NULL LOOP */
+ }
+
+ value = READFLASH_K1W(softc,offset) & 0xFF;
+
+ if (value & (0x01|0x08|0x10)) return -1;
+ return 0;
+}
+
+/* *********************************************************************
+ * intel_flash_write_block(softc,offset,val)
+ *
+ * Write a single byte to the flash. The sector that the flash
+ * byte is in should have been previously erased, or else this
+ * routine may hang.
+ *
+ * Input parameters:
+ * softc - flash context
+ * offset - distance in bytes into the flash
+ * buf - buffer of bytes to write
+ * len - number of bytes to write
+ *
+ * Return value:
+ * number of bytes written
+ ********************************************************************* */
+static int intel_flash_write_block(flashdrv_t *softc,int offset,void *buf,int len)
+{
+ unsigned char *ptr;
+ unsigned short *ptrw;
+
+ if (softc->flashdrv_probe.flash_flags & FLASH_FLG_16BIT) {
+ ptrw = buf;
+ offset &= ~1; /* offset must be even */
+ while (len > 0) {
+ if (intel_flash_write_word(softc,offset,*ptrw) < 0) break;
+ len-=2;
+ ptrw++;
+ offset+=2;
+ }
+ WRITEFLASH_K1(softc,offset,INTEL_FLASH_READ_MODE);
+ return ((unsigned char *) ptrw - (unsigned char *)buf);
+ }
+ else {
+ ptr = buf;
+ while (len) {
+ if (intel_flash_write_byte(softc,offset,*ptr) < 0) break;
+ len--;
+ ptr++;
+ offset++;
+ }
+ WRITEFLASH_K1(softc,offset,INTEL_FLASH_READ_MODE);
+ return (ptr - (unsigned char *)buf);
+ }
+
+}
+
+
+/* *********************************************************************
+ * intel_flash_erase_sector(softc,offset)
+ *
+ * Erase a single sector on the flash device
+ *
+ * Input parameters:
+ * softc - device context
+ * offset - offset in flash of sector to erase
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+static int intel_flash_erase_sector(flashdrv_t *softc,int offset)
+{
+ WRITEFLASH_K1(softc,offset,INTEL_FLASH_ERASE_BLOCK);
+ WRITEFLASH_K1(softc,offset,INTEL_FLASH_ERASE_CONFIRM);
+
+ while ((READFLASH_K1(softc,offset) & 0x80) != 0x80) {
+ /* NULL LOOP */
+ }
+ WRITEFLASH_K1(softc,offset,INTEL_FLASH_READ_MODE);
+
+ return 0;
+}
+
+
+
+
+
+/* *********************************************************************
+ * FLASH_ERASE_RANGE(softc,range)
+ *
+ * Erase a range of sectors
+ *
+ * Input parameters:
+ * softc - our flash
+ * range - range structure
+ *
+ * Return value:
+ * 0 if ok
+ * else error
+ ********************************************************************* */
+
+static int flash_erase_range(flashdrv_t *softc,flash_range_t *range)
+{
+ flash_sector_t sector;
+ int res;
+
+ if (softc->flashdrv_info.flash_type != FLASH_TYPE_FLASH) {
+ return CFE_ERR_UNSUPPORTED;
+ }
+
+
+ if (range->range_base+range->range_length > softc->flashdrv_devsize) {
+ return CFE_ERR_INV_PARAM;
+ }
+
+ res = 0;
+
+ sector.flash_sector_idx = 0;
+
+ for (;;) {
+ res = flash_sector_query(softc,&sector);
+ if (res != 0) break;
+ if (sector.flash_sector_status == FLASH_SECTOR_INVALID) {
+ break;
+ }
+
+ if ((sector.flash_sector_offset >= range->range_base) &&
+ (sector.flash_sector_offset <
+ (range->range_base+range->range_length-1))) {
+
+ if (softc->flashdrv_nvram_ok &&
+ (sector.flash_sector_offset >= softc->flashdrv_nvraminfo.nvram_offset)) {
+ break;
+ }
+ res = FLASHOP_ERASE_SECTOR(softc,sector.flash_sector_offset);
+ if (res != 0) break;
+ }
+ sector.flash_sector_idx++;
+ }
+
+ return res;
+
+}
+
+/* *********************************************************************
+ * FLASH_ERASE_ALL(softc)
+ *
+ * Erase the entire flash device, except the NVRAM area,
+ * sector-by-sector.
+ *
+ * Input parameters:
+ * softc - our flash
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int flash_erase_all(flashdrv_t *softc)
+{
+ flash_range_t range;
+
+ range.range_base = 0;
+ range.range_length = softc->flashdrv_devsize;
+
+ return flash_erase_range(softc,&range);
+}
+
+/* *********************************************************************
+ * FLASH_CFI_GETSECTORS(softc)
+ *
+ * Query the CFI information and store the sector info in our
+ * private probe structure.
+ *
+ * Input parameters:
+ * softc - our flash info
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int flash_cfi_getsectors(flashdrv_t *softc)
+{
+ int idx;
+ int regcnt;
+ int nblks;
+ int blksiz;
+
+ regcnt = GETCFIBYTE(softc,FLASH_CFI_REGION_COUNT);
+
+ softc->flashdrv_probe.flash_nsectors = regcnt;
+
+ for (idx = 0; idx < regcnt; idx++) {
+ nblks = ((int)GETCFIBYTE(softc,FLASH_CFI_REGION_TABLE+0+idx*4) +
+ (int)(GETCFIBYTE(softc,FLASH_CFI_REGION_TABLE+1+idx*4)<<8)) + 1;
+ blksiz = ((int)GETCFIBYTE(softc,FLASH_CFI_REGION_TABLE+2+idx*4) +
+ (int)(GETCFIBYTE(softc,FLASH_CFI_REGION_TABLE+3+idx*4)<<8)) * 256;
+ softc->flashdrv_probe.flash_sectors[idx] =
+ FLASH_SECTOR_RANGE(nblks,blksiz);
+ }
+
+
+ return 0;
+}
+
+/* *********************************************************************
+ * FLASH_SECTOR_QUERY(softc,sector)
+ *
+ * Query the sector information about a particular sector. You can
+ * call this iteratively to find out about all of the sectors.
+ *
+ * Input parameters:
+ * softc - our flash info
+ * sector - structure to receive sector information
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int flash_sector_query(flashdrv_t *softc,flash_sector_t *sector)
+{
+ int idx;
+ int nblks;
+ int blksiz;
+ unsigned int offset;
+ int curblk;
+
+ if (softc->flashdrv_info.flash_type != FLASH_TYPE_FLASH) {
+ return CFE_ERR_UNSUPPORTED;
+ }
+
+ if (softc->flashdrv_probe.flash_nsectors == 0) {
+ return CFE_ERR_UNSUPPORTED;
+ }
+
+ offset = 0;
+ curblk = 0;
+ for (idx = 0; idx < softc->flashdrv_probe.flash_nsectors; idx++) {
+ nblks = FLASH_SECTOR_NBLKS(softc->flashdrv_probe.flash_sectors[idx]);
+ blksiz = FLASH_SECTOR_SIZE(softc->flashdrv_probe.flash_sectors[idx]);
+ if (sector->flash_sector_idx < curblk+nblks) {
+ sector->flash_sector_status = FLASH_SECTOR_OK;
+ sector->flash_sector_offset =
+ offset + (sector->flash_sector_idx-curblk)*blksiz;
+ sector->flash_sector_size = blksiz;
+ break;
+ }
+
+ offset += (nblks)*blksiz;
+ curblk += nblks;
+ }
+
+
+ if (idx == softc->flashdrv_probe.flash_nsectors) {
+ sector->flash_sector_status = FLASH_SECTOR_INVALID;
+ }
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * FLASH_SET_CMDSET(softc,cmdset)
+ *
+ * Set the command-set that we'll honor for this flash.
+ *
+ * Input parameters:
+ * softc - our flash
+ * cmdset - FLASH_CFI_CMDSET_xxx
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void flash_set_cmdset(flashdrv_t *softc,int cmdset)
+{
+ switch (cmdset) {
+ case FLASH_CFI_CMDSET_INTEL_ECS:
+ case FLASH_CFI_CMDSET_INTEL_STD:
+ softc->flashdrv_ops = &intel_flashops;
+ /* XXX: Intel flashes don't have the "a-1" line. Yay. */
+ softc->flashdrv_widemode = 0;
+ break;
+ case FLASH_CFI_CMDSET_AMD_STD:
+ case FLASH_CFI_CMDSET_AMD_ECS:
+ softc->flashdrv_ops = &amd_flashops;
+ break;
+ default:
+ /* we don't understand the command set - treat it like ROM */
+ softc->flashdrv_info.flash_type = FLASH_TYPE_ROM;
+ }
+}
+
+
+/* *********************************************************************
+ * FLASH_CFI_PROBE(softc)
+ *
+ * Try to do a CFI query on this device. If we find the m
+ * magic signature, extract some useful information from the
+ * query structure.
+ *
+ * Input parameters:
+ * softc - out flash
+ *
+ * Return value:
+ * 0 if successful, <0 if error
+ ********************************************************************* */
+static int flash_cfi_probe(flashdrv_t *softc)
+{
+ FLASHCMD(softc,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_MODE);
+
+ if (!((GETCFIBYTE(softc,FLASH_CFI_SIGNATURE+0) == 'Q') &&
+ (GETCFIBYTE(softc,FLASH_CFI_SIGNATURE+1) == 'R') &&
+ (GETCFIBYTE(softc,FLASH_CFI_SIGNATURE+2) == 'Y'))) {
+
+ FLASHCMD(softc,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_EXIT);
+ return CFE_ERR_UNSUPPORTED;
+ }
+
+ /*
+ * Gather info from flash
+ */
+
+ softc->flashdrv_cfidata.cfidata_cmdset =
+ ((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_COMMAND_SET))) +
+ (((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_COMMAND_SET+1))) << 8);
+
+ softc->flashdrv_cfidata.cfidata_devif =
+ ((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_DEVICE_INTERFACE))) +
+ (((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_DEVICE_INTERFACE+1))) << 8);
+
+ softc->flashdrv_cfidata.cfidata_size =
+ 1 << ((unsigned int) (GETCFIBYTE(softc,FLASH_CFI_DEVICE_SIZE)));
+
+ flash_cfi_getsectors(softc);
+
+ /*
+ * Don't need to be in query mode anymore.
+ */
+
+ FLASHCMD(softc,FLASH_CFI_QUERY_ADDR,FLASH_CFI_QUERY_EXIT);
+
+ softc->flashdrv_info.flash_type = FLASH_TYPE_FLASH;
+
+ flash_set_cmdset(softc,softc->flashdrv_cfidata.cfidata_cmdset);
+
+ return 0;
+
+}
+
+/* *********************************************************************
+ * FLASH_GETWIDTH(softc,info)
+ *
+ * Try to determine the width of the flash. This is needed for
+ * management purposes, since some 16-bit flash parts in 8-bit mode
+ * have an "A-1" (address line -1) wire to select bytes within
+ * a 16-bit word. When this is present, the flash commands
+ * will have different offsets.
+ *
+ * Input parameters:
+ * softc - our flash
+ * info - flash info structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void flash_getwidth(flashdrv_t *softc,flash_info_t *info)
+{
+ softc->flashdrv_widemode = 0; /* first try narrow */
+
+ if (flash_cfi_probe(softc) == 0) {
+ return;
+ }
+
+ softc->flashdrv_widemode = 1; /* then wide */
+
+ if (flash_cfi_probe(softc) == 0) {
+ return;
+ }
+
+ /* Just return, assume not wide if no CFI interface */
+ softc->flashdrv_widemode = 0;
+
+ softc->flashdrv_info.flash_type = FLASH_TYPE_ROM; /* no CFI: treat as ROM */
+}
+
+/* *********************************************************************
+ * flash_getinfo(softc)
+ *
+ * Try to determine if the specified region is flash, ROM, SRAM,
+ * or something else.
+ *
+ * Input parameters:
+ * softc - our context
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void flash_getinfo(flashdrv_t *softc)
+{
+ uint8_t save0,save1;
+ volatile uint8_t *ptr;
+ flash_info_t *info = &(softc->flashdrv_info);
+
+ /*
+ * Set up some defaults based on the probe data
+ */
+
+ softc->flashdrv_widemode = 0;
+ info->flash_base = softc->flashdrv_probe.flash_phys;
+ info->flash_size = softc->flashdrv_probe.flash_size;
+ softc->flashdrv_devsize = softc->flashdrv_probe.flash_size;
+ info->flash_type = FLASH_TYPE_UNKNOWN;
+ info->flash_flags = 0;
+
+ /*
+ * If we've been told not to try probing, just assume
+ * we're a flash part.
+ */
+
+ if (softc->flashdrv_probe.flash_flags & FLASH_FLG_MANUAL) {
+ info->flash_type = FLASH_TYPE_FLASH;
+ if (softc->flashdrv_probe.flash_flags & FLASH_FLG_WIDE) {
+ softc->flashdrv_widemode = TRUE;
+ }
+ if (softc->flashdrv_probe.flash_cmdset) {
+ flash_set_cmdset(softc,softc->flashdrv_probe.flash_cmdset);
+ }
+ return;
+ }
+
+ /*
+ * Attempt to read/write byte zero. If it is changable,
+ * this is SRAM (or maybe a ROM emulator with the write line hooked up)
+ */
+
+ ptr = (volatile uint8_t *) UNCADDR(softc->flashdrv_probe.flash_phys);
+ save0 = *ptr; /* save old value */
+ save1 = *(ptr+1); /* save old value */
+ *(ptr) = 0x55;
+ if ((*ptr) == 0x55) {
+ *(ptr) = 0xAA;
+ if ((*ptr) == 0xAA) {
+ info->flash_type = FLASH_TYPE_SRAM;
+ }
+ }
+
+ if (*ptr == save0) info->flash_type = FLASH_TYPE_ROM;
+ else (*ptr) = save0; /* restore old value */
+
+ /*
+ * If we thought it was ROM, try doing a CFI query
+ * to see if it was flash. This check is kind of kludgey
+ * but should work.
+ */
+
+ if (info->flash_type == FLASH_TYPE_ROM) {
+ flash_getwidth(softc,info);
+ if (info->flash_type == FLASH_TYPE_FLASH) {
+ }
+ }
+}
+
+/* *********************************************************************
+ * flashdrv_setup_nvram(softc)
+ *
+ * If we're going to be using a sector of the flash for NVRAM,
+ * go find that sector and set it up.
+ *
+ * Input parameters:
+ * softc - our flash
+ *
+ * Return value:
+ * nothing. flashdrv_nvram_ok might change though.
+ ********************************************************************* */
+
+static void flashdrv_setup_nvram(flashdrv_t *softc)
+{
+ flash_sector_t sector;
+ int res;
+
+ softc->flashdrv_nvram_ok = FALSE;
+
+ if (softc->flashdrv_info.flash_type != FLASH_TYPE_FLASH) {
+ return;
+ }
+
+ sector.flash_sector_idx = 0;
+ for (;;) {
+ res = flash_sector_query(softc,&sector);
+ if (res == CFE_ERR_UNSUPPORTED) break;
+ if (res == 0) {
+ if (sector.flash_sector_status != FLASH_SECTOR_INVALID) {
+ sector.flash_sector_idx++;
+ continue;
+ }
+ }
+ break;
+ }
+
+ /* The sector offset will still contain the value at the end
+ of the last successful call. That's the last sector, so
+ we can now use this to fill in the NVRAM info structure */
+
+ if (res != CFE_ERR_UNSUPPORTED) {
+ softc->flashdrv_nvraminfo.nvram_offset = sector.flash_sector_offset;
+ softc->flashdrv_nvraminfo.nvram_size = sector.flash_sector_size;
+ softc->flashdrv_nvraminfo.nvram_eraseflg = TRUE; /* needs erase */
+ softc->flashdrv_nvram_ok = TRUE;
+ /*
+ * Set the flash's size as reported in the flash_info structure
+ * to be the size without the NVRAM sector at the end.
+ */
+ softc->flashdrv_info.flash_size = sector.flash_sector_offset;
+ softc->flashdrv_devsize = sector.flash_sector_offset;
+ }
+
+}
+
+
+/* *********************************************************************
+ * flashdrv_probe(drv,probe_a,probe_b,probe_ptr)
+ *
+ * Device probe routine. Attach the flash device to
+ * CFE's device table.
+ *
+ * Input parameters:
+ * drv - driver descriptor
+ * probe_a - physical address of flash
+ * probe_b - size of flash (bytes)
+ * probe_ptr - unused
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void flashdrv_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ flashdrv_t *softc;
+ flash_probe_t *probe;
+ char descr[80];
+
+ probe = (flash_probe_t *) probe_ptr;
+
+ /*
+ * probe_a is the flash base address
+ * probe_b is the size of the flash
+ * probe_ptr is unused.
+ */
+
+ softc = (flashdrv_t *) KMALLOC(sizeof(flashdrv_t),0);
+ if (softc) {
+ memset(softc,0,sizeof(flashdrv_t));
+
+ if (probe) {
+ /* Passed probe structure, do fancy stuff */
+ memcpy(&(softc->flashdrv_probe),probe,sizeof(flash_probe_t));
+ if (softc->flashdrv_probe.flash_prog_phys == 0) {
+ softc->flashdrv_probe.flash_prog_phys =
+ softc->flashdrv_probe.flash_phys;
+ }
+ }
+ else {
+ /* Didn't pass probe structure, do the compatible thing */
+ softc->flashdrv_probe.flash_phys = probe_a;
+ softc->flashdrv_probe.flash_prog_phys = probe_a;
+ softc->flashdrv_probe.flash_size = probe_b;
+ softc->flashdrv_probe.flash_flags = FLASH_FLG_NVRAM;
+ }
+
+ softc->flashdrv_cmdaddr = (char *) UNCADDR(softc->flashdrv_probe.flash_prog_phys);
+ softc->flashdrv_initialized = 0;
+ softc->flashdrv_ops = &FLASHOPS_DEFAULT;
+ xsprintf(descr,"%s at %08X size %uKB",drv->drv_description,
+ softc->flashdrv_probe.flash_phys,
+ softc->flashdrv_probe.flash_size/1024);
+ cfe_attach(drv,softc,NULL,descr);
+ }
+
+}
+
+
+/* *********************************************************************
+ * flashdrv_open(ctx)
+ *
+ * Called when the flash device is opened.
+ *
+ * Input parameters:
+ * ctx - device context
+ *
+ * Return value:
+ * 0 if ok else error code
+ ********************************************************************* */
+
+static int flashdrv_open(cfe_devctx_t *ctx)
+{
+ flashdrv_t *softc = ctx->dev_softc;
+
+ /*
+ * do initialization
+ */
+
+ if (!softc->flashdrv_initialized) {
+
+ /*
+ * Assume it's not an NVRAM-capable flash
+ */
+
+ softc->flashdrv_nvram_ok = FALSE;
+
+ /*
+ * Probe flash for geometry
+ */
+ flash_getinfo(softc);
+
+ /*
+ * Find the last sector if in NVRAM mode
+ */
+
+ if (softc->flashdrv_probe.flash_flags & FLASH_FLG_NVRAM) {
+ flashdrv_setup_nvram(softc);
+ }
+
+ softc->flashdrv_initialized = TRUE;
+ }
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * flashdrv_read(ctx,buffer)
+ *
+ * Read data from the flash device. The flash device is
+ * considered to be like a disk (you need to specify the offset).
+ *
+ * Input parameters:
+ * ctx - device context
+ * buffer - buffer descriptor
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+static int flashdrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ flashdrv_t *softc = ctx->dev_softc;
+ unsigned char *bptr;
+ unsigned char *flashbase;
+ int offset;
+ int blen;
+
+ /*
+ * For now, read the flash from K1 (always). Eventually
+ * we need to flush the cache after a write.
+ */
+
+ flashbase = (unsigned char *) UNCADDR(softc->flashdrv_probe.flash_phys);
+
+ bptr = buffer->buf_ptr;
+ blen = buffer->buf_length;
+ offset = (int) buffer->buf_offset;
+
+ if (!(softc->flashdrv_unlocked)) {
+ if ((offset + blen) > softc->flashdrv_devsize) {
+ blen = softc->flashdrv_devsize - offset;
+ }
+ }
+
+#ifdef _FLASH_BROKEN_BYTEREAD_
+ /*
+ * BCM1250 users: don't worry about this. This hack is for
+ * something else and should not be used with the BCM1250.
+ */
+ if (softc->flashdrv_probe.flash_flags & FLASH_FLG_16BIT) {
+ uint16_t *src;
+ int len = blen;
+ int idx = 0;
+ union {
+ uint16_t x;
+ char b[2];
+ } u;
+
+ src = (uint16_t *) flashbase;
+ while (len > 0) {
+ u.x = src[(idx+offset)>>1];
+ *bptr++ = u.b[(idx+offset)&1];
+ len--;
+ idx++;
+ }
+ }
+ else {
+ memcpy(bptr,flashbase + offset, blen);
+ }
+#else
+ memcpy(bptr,flashbase + offset, blen);
+#endif
+
+ buffer->buf_retlen = blen;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * flashdrv_inpstat(ctx,inpstat)
+ *
+ * Return "input status". For flash devices, we always return true.
+ *
+ * Input parameters:
+ * ctx - device context
+ * inpstat - input status structure
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+static int flashdrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
+{
+ /* flashdrv_t *softc = ctx->dev_softc; */
+
+ inpstat->inp_status = 1;
+ return 0;
+}
+
+
+/* *********************************************************************
+ * flash_writeall(softc,buffer)
+ *
+ * Write the entire flash and reboot. This is a special case
+ * used for when the flash currently being used for CFE's
+ * execution is updated. A small assembly routine is relocated
+ * to DRAM to do the update (so that the programming routine is
+ * not erased while we're running it), and then the update
+ * is done. When completed, CFE is restarted.
+ *
+ * (we could get really sleazy here and touch the routine first
+ * so it will stay in the cache, thereby eliminating the need
+ * to relocate it, but that's dangerous)
+ *
+ * Input parameters:
+ * softc - our context
+ * buffer - buffer descriptor
+ *
+ * Return value:
+ * does not return
+ ********************************************************************* */
+
+static int flash_writeall(flashdrv_t *softc,iocb_buffer_t *buffer)
+{
+ void *rptr;
+ void (*routine)(unsigned char *data,unsigned int flashbase,
+ unsigned int size,unsigned int secsize);
+
+ rptr = KMALLOC(flash_write_all_len,0);
+
+ if (!rptr) return CFE_ERR_NOMEM;
+
+ memcpy(rptr,flash_write_all_ptr,flash_write_all_len);
+
+ _cfe_flushcache(0);
+
+ routine = rptr;
+
+ (*routine)(buffer->buf_ptr,
+ softc->flashdrv_probe.flash_phys,
+ buffer->buf_length,
+ 65536);
+
+ return -1;
+}
+
+
+/* *********************************************************************
+ * flashdrv_write(ctx,buffer)
+ *
+ * Write data to the flash device. The flash device is
+ * considered to be like a disk (you need to specify the offset).
+ *
+ * Input parameters:
+ * ctx - device context
+ * buffer - buffer descriptor
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+static int flashdrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ flashdrv_t *softc = ctx->dev_softc;
+ unsigned char *bptr;
+ int offset;
+ int blen;
+ int res;
+
+ bptr = buffer->buf_ptr;
+ blen = buffer->buf_length;
+ offset = (int) buffer->buf_offset;
+
+ if (!(softc->flashdrv_unlocked)) {
+ if ((offset + blen) > softc->flashdrv_devsize) {
+ blen = softc->flashdrv_devsize - offset;
+ }
+ }
+
+ res = FLASHOP_WRITE_BLOCK(softc,offset,bptr,blen);
+
+ buffer->buf_retlen = res;
+
+ /* XXX flush the cache here? */
+
+ return (res == blen) ? 0 : CFE_ERR_IOERR;
+}
+
+/* *********************************************************************
+ * flashdrv_ioctl(ctx,buffer)
+ *
+ * Handle special IOCTL functions for the flash. Flash devices
+ * support NVRAM information, sector and chip erase, and a
+ * special IOCTL for updating the running copy of CFE.
+ *
+ * Input parameters:
+ * ctx - device context
+ * buffer - descriptor for IOCTL parameters
+ *
+ * Return value:
+ * 0 if ok else error
+ ********************************************************************* */
+static int flashdrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ flashdrv_t *softc = ctx->dev_softc;
+ nvram_info_t *info;
+ int offset;
+
+ /*
+ * If using flash to store environment, only the last sector
+ * is used for environment stuff.
+ */
+
+ switch ((int)buffer->buf_ioctlcmd) {
+ case IOCTL_NVRAM_ERASE:
+ if (softc->flashdrv_nvram_ok == FALSE) return CFE_ERR_UNSUPPORTED;
+ FLASHOP_ERASE_SECTOR(softc,softc->flashdrv_nvraminfo.nvram_offset);
+ return 0;
+
+ case IOCTL_NVRAM_GETINFO:
+ info = (nvram_info_t *) buffer->buf_ptr;
+ if (buffer->buf_length != sizeof(nvram_info_t)) return CFE_ERR_INV_PARAM;
+ if (softc->flashdrv_nvram_ok == FALSE) return CFE_ERR_UNSUPPORTED;
+ info->nvram_offset = softc->flashdrv_nvraminfo.nvram_offset;
+ info->nvram_size = softc->flashdrv_nvraminfo.nvram_size;
+ info->nvram_eraseflg = softc->flashdrv_nvraminfo.nvram_eraseflg;
+ buffer->buf_retlen = sizeof(nvram_info_t);
+ return 0;
+
+ case IOCTL_FLASH_ERASE_SECTOR:
+ offset = (int) buffer->buf_offset;
+ if (!(softc->flashdrv_unlocked)) {
+ if (offset >= softc->flashdrv_devsize) return -1;
+ }
+ FLASHOP_ERASE_SECTOR(softc,offset);
+ return 0;
+
+ case IOCTL_FLASH_ERASE_ALL:
+ offset = (int) buffer->buf_offset;
+ if (offset != 0) return -1;
+ flash_erase_all(softc);
+ return 0;
+
+ case IOCTL_FLASH_WRITE_ALL:
+ flash_writeall(softc,buffer);
+ return -1; /* should not return */
+
+ case IOCTL_FLASH_GETINFO:
+ memcpy(buffer->buf_ptr,&(softc->flashdrv_info),sizeof(flash_info_t));
+ return 0;
+
+ case IOCTL_FLASH_GETSECTORS:
+ return flash_sector_query(softc,(flash_sector_t *) buffer->buf_ptr);
+
+
+ case IOCTL_FLASH_ERASE_RANGE:
+ return flash_erase_range(softc,(flash_range_t *) buffer->buf_ptr);
+
+ case IOCTL_NVRAM_UNLOCK:
+ softc->flashdrv_unlocked = TRUE;
+ break;
+
+ default:
+ return -1;
+ }
+
+ return -1;
+}
+
+
+/* *********************************************************************
+ * flashdrv_close(ctx)
+ *
+ * Close the flash device.
+ *
+ * Input parameters:
+ * ctx - device context
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+static int flashdrv_close(cfe_devctx_t *ctx)
+{
+ /* flashdrv_t *softc = ctx->dev_softc; */
+
+ /* XXX Invalidate the cache */
+
+ return 0;
+}
+
+
diff --git a/cfe/cfe/dev/dev_ht7520.c b/cfe/cfe/dev/dev_ht7520.c
new file mode 100644
index 0000000..8e64971
--- /dev/null
+++ b/cfe/cfe/dev/dev_ht7520.c
@@ -0,0 +1,167 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * HT7520 (Golem) Bridge Support File: dev_ht7520.c
+ *
+ *********************************************************************
+ *
+ * Copyright 2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+#include "lib_types.h"
+#include "lib_physio.h"
+
+#include "pcireg.h"
+#include "pcivar.h"
+
+extern int eoi_implemented;
+
+void ht7520apic_preset (pcitag_t tag);
+void ht7520apic_setup (pcitag_t tag);
+
+
+/* PLX HT7520 (LDT to PCI-X bridge + APIC) specific definitions */
+
+#define PCI_VENDOR_AMD 0x1022
+#define PCI_PRODUCT_PLX_HT7520 0x7450
+#define PCI_PRODUCT_PLX_HT7520_APIC 0x7451
+
+/* HT7520 specific registers */
+
+/* APIC configuration registers */
+
+#define APIC_CONTROL_REG 0x0044
+
+#define APIC_CONTROL_OSVISBAR (1 << 0)
+#define APIC_CONTROL_IOAEN (1 << 1)
+
+#define APIC_BASE_ADDR_REG 0x0048
+
+/* APIC registers in BAR0 memory space */
+
+#define HT7520_APIC_INDEX_REG 0x0000
+#define HT7520_APIC_DATA_REG 0x0010
+
+#define APIC_ID_INDEX 0x00
+#define APIC_VERSION_INDEX 0x01
+#define APIC_ARBID_INDEX 0x02
+#define APIC_RDR_BASE_INDEX 0x10
+#define APIC_RDR_LO_INDEX(n) (APIC_RDR_BASE_INDEX + 2*(n))
+#define APIC_RDR_HI_INDEX(n) (APIC_RDR_BASE_INDEX + 2*(n) + 1)
+
+#define RDR_HI_DEST_SHIFT (56-32)
+#define RDR_HI_DEST_MASK (0xff << RDR_HI_DEST_SHIFT)
+#define RDR_LO_IM (1 << 16)
+#define RDR_LO_TM (1 << 15)
+#define RDR_LO_IRR (1 << 14)
+#define RDR_LO_POL (1 << 13)
+#define RDR_LO_DS (1 << 12)
+#define RDR_LO_DM (1 << 11)
+#define RDR_LO_MT_SHIFT 8
+#define RDR_LO_MT_MASK (3 << RDR_LO_MT_SHIFT)
+#define RDR_LO_IV_SHIFT 0
+#define RDR_LO_IV_MASK (0xff << RDR_LO_IV_SHIFT)
+
+void
+ht7520apic_preset (pcitag_t tag)
+{
+ pcireg_t ctrl;
+
+ /* For some reason, BAR0 (necessary for setting the interrupt
+ mapping) is hidden by default; the following makes it
+ visible. */
+ ctrl = pci_conf_read(tag, APIC_CONTROL_REG);
+ ctrl |= APIC_CONTROL_IOAEN | APIC_CONTROL_OSVISBAR;
+ pci_conf_write(tag, APIC_CONTROL_REG, ctrl);
+ ctrl = pci_conf_read(tag, APIC_CONTROL_REG); /* push */
+}
+
+void
+ht7520apic_setup (pcitag_t tag)
+{
+ int bus, device, function;
+ pcitag_t br_tag;
+ int secondary;
+ struct pci_bus *pb;
+ unsigned offset;
+ phys_addr_t apic_addr;
+ uint32_t rdrh, rdrl;
+ int i;
+
+ /* The HT7520 splits the bridge and APIC functionality between two
+ functions. The following code depends upon a known
+ relationship between the bridge and APIC tags, with a temporary
+ fudge for the simulator. NB: We assume that the bridge
+ function has already been initialized. */
+
+ pci_break_tag(tag, &bus, &device, &function);
+
+#ifdef _FUNCSIM_
+ br_tag = pci_make_tag(bus, device-2, 0);
+#else
+ br_tag = pci_make_tag(bus, device, function-1);
+#endif
+ secondary = (pci_conf_read(br_tag, PPB_BUSINFO_REG) >> 8) & 0xff;
+ pb = &_pci_bus[secondary];
+
+ /* Set up interrupt mappings. */
+ pci_map_mem(tag, PCI_MAPREG(0), PCI_MATCH_BITS, &apic_addr);
+
+ offset = pb->inta_shift % 4;
+ for (i = 0; i < 4; i++) {
+ phys_write32(apic_addr + HT7520_APIC_INDEX_REG, APIC_RDR_HI_INDEX(i));
+ rdrh = 0x03 << RDR_HI_DEST_SHIFT; /* CPU 0 + CPU 1 */
+ phys_write32(apic_addr + HT7520_APIC_DATA_REG, rdrh);
+ rdrh = phys_read32(apic_addr + HT7520_APIC_DATA_REG); /* push */
+
+ phys_write32(apic_addr + HT7520_APIC_INDEX_REG, APIC_RDR_LO_INDEX(i));
+ if (eoi_implemented) {
+ /* Passes >=2 have working EOI. Trigger=Level */
+ rdrl = (RDR_LO_TM | /* Level */
+ RDR_LO_POL | /* Active Low */
+ RDR_LO_DM | /* Logical */
+ 0x0 << RDR_LO_MT_SHIFT | /* Fixed */
+ (56+offset) << RDR_LO_IV_SHIFT); /* Vector */
+ } else {
+ /* Pass 1 lacks working EOI. Trigger=Edge. Note that
+ LO_POL appears mis-documented for edges. */
+ rdrl = (RDR_LO_DM | /* Logical */
+ 0x0 << RDR_LO_MT_SHIFT | /* Fixed */
+ (56+offset) << RDR_LO_IV_SHIFT); /* Vector */
+ }
+ phys_write32(apic_addr + HT7520_APIC_DATA_REG, rdrl);
+ offset = (offset + 1) % 4;
+ }
+}
diff --git a/cfe/cfe/dev/dev_ide_common.c b/cfe/cfe/dev/dev_ide_common.c
new file mode 100644
index 0000000..e15ac8a
--- /dev/null
+++ b/cfe/cfe/dev/dev_ide_common.c
@@ -0,0 +1,1249 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Generic IDE disk driver File: dev_ide_common.c
+ *
+ * This is a simple driver for IDE hard disks. The mechanics
+ * of talking to the I/O ports are abstracted sufficiently to make
+ * this driver usable for various bus interfaces.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include "lib_types.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+#include "lib_string.h"
+#include "cfe_timer.h"
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "cfe_ioctl.h"
+#include "cfe_error.h"
+
+#include "dev_ide_common.h"
+
+#include "dev_ide.h"
+
+/* *********************************************************************
+ * Macros
+ ********************************************************************* */
+
+#define DISK_MASTER 0
+#define DISK_SLAVE 1
+
+#define IDE_WRITEREG8(ide,reg,val) IDEDISP_WRITEREG8(ide->idecommon_dispatch,reg,val)
+#define IDE_WRITEREG16(ide,reg,val) IDEDISP_WRITEREG8(ide->idecommon_dispatch,reg,val)
+#define IDE_WRITEBUF(ide,reg,buf,len) IDEDISP_WRITEBUF(ide->idecommon_dispatch,reg,buf,len)
+#define IDE_READREG8(ide,reg) IDEDISP_READREG8(ide->idecommon_dispatch,reg)
+#define IDE_READREG16(ide,reg) IDEDISP_READREG16(ide->idecommon_dispatch,reg)
+#define IDE_READBUF(ide,reg,buf,len) IDEDISP_READBUF(ide->idecommon_dispatch,reg,buf,len)
+
+#define GETWORD_LE(buf,wordidx) (((unsigned int) (buf)[(wordidx)*2]) + \
+ (((unsigned int) (buf)[(wordidx)*2+1]) << 8))
+
+#define _IDE_DEBUG_
+
+
+static void idecommon_testdrq(idecommon_t *ide);
+
+/* *********************************************************************
+ * idecommon_sectorshift(size)
+ *
+ * Given a sector size, return log2(size). We cheat; this is
+ * only needed for 2048 and 512-byte sectors.
+ * Explicitly using shifts and masks in sector number calculations
+ * helps on 32-bit-only platforms, since we probably won't need
+ * a helper library.
+ *
+ * Input parameters:
+ * size - sector size
+ *
+ * Return value:
+ * # of bits to shift
+ ********************************************************************* */
+
+#define idecommon_sectorshift(size) (((size)==2048)?11:9)
+
+/* *********************************************************************
+ * idecommon_waitnotbusy(ide)
+ *
+ * Wait for an IDE device to report "not busy"
+ *
+ * Input parameters:
+ * ide - IDE interface
+ *
+ * Return value:
+ * 0 if ok, else -1 if timeout
+ ********************************************************************* */
+
+static int idecommon_waitnotbusy(idecommon_t *ide)
+{
+ int32_t timer;
+ uint8_t status;
+
+ TIMER_SET(timer,10*CFE_HZ);
+
+ while (!TIMER_EXPIRED(timer)) {
+ status = IDE_READREG8(ide,IDE_REG_STATUS);
+ if (!(status & IDE_STS_BSY) && (status & IDE_STS_DRQ)) {
+ idecommon_testdrq(ide);
+ continue;
+ }
+ if ((status & (IDE_STS_BSY | IDE_STS_DRQ )) == 0) return 0;
+ POLL();
+ }
+
+#ifdef _IDE_DEBUG_
+ xprintf("Device did not become unbusy\n");
+#endif
+ return -1;
+}
+
+#if 0
+/* *********************************************************************
+ * idecommon_waitready(ide)
+ *
+ * Wait for the specified device to become ready.
+ *
+ * Input parameters:
+ * ide - IDE interface
+ *
+ * Return value:
+ * 0 if device became ready
+ * -1 if device did not become ready
+ ********************************************************************* */
+
+static int idecommon_waitready(idecommon_t *ide)
+{
+ int32_t timer;
+ uint8_t status;
+
+ TIMER_SET(timer,10*CFE_HZ);
+
+ while (!TIMER_EXPIRED(timer)) {
+ status = IDE_READREG8(ide,IDE_REG_STATUS);
+ if (status & IDE_STS_RDY) return 0;
+ POLL();
+ }
+
+#ifdef _IDE_DEBUG_
+ xprintf("Disk did not become ready\n");
+#endif
+
+ return -1;
+}
+#endif
+
+/* *********************************************************************
+ * idecommon_waitbusy(idx)
+ *
+ * Wait for an IDE disk to start processing a command, or at
+ * least long enough to indicate that it is doing so.
+ * The code below looks suspiciously like a timing loop.
+ * unfortunately, that's what it is, determined empirically
+ * for certain ATA flash cards. Without this many reads to the
+ * ALTSTAT register, the PCMCIA controller deasserts the
+ * card detect pins briefly. Anyone have any clues?
+ *
+ * Input parameters:
+ * ide - IDE interface
+ *
+ * Return value:
+ * void
+ ********************************************************************* */
+
+static void idecommon_waitbusy(idecommon_t *ide)
+{
+ int idx;
+
+ for (idx = 0; idx < 10; idx++) {
+ IDE_READREG8(ide,IDE_REG_ALTSTAT);
+ IDE_READREG8(ide,IDE_REG_ALTSTAT);
+ IDE_READREG8(ide,IDE_REG_ALTSTAT);
+ IDE_READREG8(ide,IDE_REG_ALTSTAT);
+ }
+}
+
+
+/* *********************************************************************
+ * idecommon_wait_drq(ide)
+ *
+ * Wait for the BUSY bit to be clear and the DRQ bit to be set.
+ * This is usually the indication that it's time to transfer data.
+ *
+ * Input parameters:
+ * ide - IDE interface
+ * 0 if DRQ is set
+ * -1 if timeout occured
+ ********************************************************************* */
+
+static int idecommon_wait_drq(idecommon_t *ide)
+{
+ int32_t timer;
+ uint8_t status;
+
+ TIMER_SET(timer,10*CFE_HZ);
+
+ while (!TIMER_EXPIRED(timer)) {
+ POLL();
+ status = IDE_READREG8(ide,IDE_REG_STATUS);
+ if (!(status & IDE_STS_BSY) && (status & IDE_STS_ERR)) {
+ xprintf("Drive status: %02X error %02X\n",status,
+ IDE_READREG8(ide,IDE_REG_ERROR));
+ return -1;
+ }
+ if (!(status & IDE_STS_BSY) && (status & IDE_STS_DRQ)) return 0;
+ }
+
+#ifdef _IDE_DEBUG_
+ xprintf("Timeout waiting for disk\n");
+#endif
+
+ return -1;
+}
+
+/* *********************************************************************
+ * idecommon_testdrq(ide)
+ *
+ * Debug routine. Check the DRQ bit. If it's set, it is not
+ * supposed to be, so transfer data until it clears and report
+ * how much we had to transfer.
+ *
+ * Input parameters:
+ * ide - IDE interface
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+#ifdef _IDE_DEBUG_
+static void idecommon_testdrq(idecommon_t *ide)
+{
+ uint8_t status;
+ uint16_t data;
+ int idx;
+
+ status = IDE_READREG8(ide,IDE_REG_STATUS);
+ if (status & IDE_STS_DRQ) {
+ xprintf("Error: DRQ should be zero\n");
+ idx = 0;
+ while (status & IDE_STS_DRQ) {
+ data = IDE_READREG16(ide,IDE_REG_DATA);
+ idx++;
+ status = IDE_READREG8(ide,IDE_REG_STATUS);
+ }
+ xprintf("Had to read data %d times to clear DRQ\n",idx);
+ }
+}
+#else
+#define idecommon_testdrq(ide)
+#endif
+
+
+/* *********************************************************************
+ * idecommon_dumpregs(ide)
+ *
+ * Dump out the IDE registers. (debug routine)
+ *
+ * Input parameters:
+ * ide - ide disk
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void idecommon_dumpregs(idecommon_t *ide)
+{
+#if 0
+ uint8_t reg = 0;
+
+ reg = IDE_READREG8(ide,IDE_REG_STATUS);
+ xprintf("Status:%02X ",reg);
+
+ reg = IDE_READREG8(ide,IDE_REG_DRVHD);
+ xprintf("DrvHd:%02X ",reg);
+
+ reg = IDE_READREG8(ide,IDE_REG_CYLLSB);
+ xprintf("CylLSB:%02X ",reg);
+
+ reg = IDE_READREG8(ide,IDE_REG_CYLMSB);
+ xprintf("CylMSB:%02X ",reg);
+
+ reg = IDE_READREG8(ide,IDE_REG_SECNUM);
+ xprintf("SecNum:%02X ",reg);
+
+ reg = IDE_READREG8(ide,IDE_REG_SECCNT);
+ xprintf("SecCnt:%02X ",reg);
+
+ xprintf("\n");
+#endif
+}
+
+
+/* *********************************************************************
+ * idecommon_reset(ide)
+ *
+ * Reset the IDE interface.
+ *
+ * Input parameters:
+ * ide - IDE interface
+ *
+ * Return value:
+ * 0 if ok, else -1 if a timeout occured
+ ********************************************************************* */
+
+static int idecommon_reset(idecommon_t *ide)
+{
+ return 0;
+}
+
+/* *********************************************************************
+ * idecommon_identify(ide,buffer)
+ *
+ * Execute an IDENTIFY command to get information about the disk.
+ *
+ * Input parameters:
+ * ide - IDE interface
+ * buffer - pointer to 512 byte buffer
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int idecommon_identify(idecommon_t *ide,unsigned char *buffer)
+{
+
+ /* Device Select Protocol; see ATAPI-4 sect 9.6 */
+
+ if (idecommon_waitnotbusy(ide) < 0) return -1;
+ IDE_WRITEREG8(ide,IDE_REG_DRVHD,(ide->idecommon_unit<<4)|0);
+ if (idecommon_waitnotbusy(ide) < 0) return -1;
+
+ /* Set device registers */
+
+ IDE_WRITEREG8(ide,IDE_REG_CYLLSB,0);
+ IDE_WRITEREG8(ide,IDE_REG_CYLMSB,0);
+ IDE_WRITEREG8(ide,IDE_REG_SECNUM,1);
+ IDE_WRITEREG8(ide,IDE_REG_SECCNT,1);
+
+ idecommon_testdrq(ide);
+
+ /* Issue command, then read ALT STATUS (9.7) */
+
+ if (ide->idecommon_atapi) {
+ IDE_WRITEREG8(ide,IDE_REG_COMMAND,IDE_CMD_ATAPI_IDENTIFY);
+ }
+ else {
+ IDE_WRITEREG8(ide,IDE_REG_COMMAND,IDE_CMD_DRIVE_INFO);
+ }
+
+ IDE_READREG8(ide,IDE_REG_ALTSTAT);
+ idecommon_waitbusy(ide); /* should not be necessary */
+
+ /* Wait BSY=0 && DRQ=1, then read buffer, see sect 9.7 */
+
+ if (idecommon_wait_drq(ide) < 0) return -1;
+ IDE_READBUF(ide,IDE_REG_DATA,buffer,DISK_SECTORSIZE);
+
+ idecommon_testdrq(ide);
+
+ return 0;
+}
+
+/* *********************************************************************
+ * idecommon_packet(ide,packet,pktlen,databuf,datalen)
+ *
+ * Process an IDE "packet" command, for ATAPI devices
+ *
+ * Input parameters:
+ * ide - IDE interface
+ * packet,pktlen - command packet
+ * databuf,datalen - data buffer
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int idecommon_packet(idecommon_t *ide,
+ uint8_t *packet,int pktlen,
+ uint8_t *databuf,int datalen)
+{
+ uint8_t status;
+
+ /*
+ * Not valid on non-ATAPI disks
+ */
+
+ if (!ide->idecommon_atapi) return -1;
+
+ /*
+ * Set up the standard IDE registers for an ATAPI PACKET command
+ */
+
+ /* Device Select Protocol */
+ if (idecommon_waitnotbusy(ide) < 0) return -1;
+ IDE_WRITEREG8(ide,IDE_REG_DRVHD,(ide->idecommon_unit<<4));
+ if (idecommon_waitnotbusy(ide) < 0) return -1;
+
+ /* Device Registers */
+ IDE_WRITEREG8(ide,IDE_REG_BCLSB,(datalen & 0xFF));
+ IDE_WRITEREG8(ide,IDE_REG_BCMSB,((datalen >> 8) & 0xFF));
+ IDE_WRITEREG8(ide,IDE_REG_SECNUM,0);
+ IDE_WRITEREG8(ide,IDE_REG_SECCNT,0);
+ IDE_WRITEREG8(ide,IDE_REG_COMMAND,IDE_CMD_ATAPI_PACKET);
+
+ /*
+ * Wait for the DRQ bit to indicate that we should send
+ * the packet.
+ */
+
+ if (idecommon_wait_drq(ide) < 0) return -1;
+
+ status = IDE_READREG8(ide,IDE_REG_IR);
+
+ /*
+ * Send the packet to the device
+ */
+
+ IDE_WRITEBUF(ide,IDE_REG_DATA,packet,pktlen);
+
+ /*
+ * Wait for BSY to be cleared and DRQ to be set.
+ */
+
+ if (idecommon_wait_drq(ide) < 0) return -1;
+ status = IDE_READREG8(ide,IDE_REG_ALTSTAT);
+ if (idecommon_wait_drq(ide) < 0) return -1;
+ status = IDE_READREG8(ide,IDE_REG_IR);
+
+
+ /*
+ * Transfer data, if necessary. The direction will depend
+ * on what the drive says. If this is a non-data command,
+ * passing databuf == NULL can avoid all this.
+ */
+
+ if (databuf) {
+ status = IDE_READREG8(ide,IDE_REG_IR);
+ if (status & IDE_IR_CD) {
+ xprintf("Error: Command/data should be zero\n");
+ }
+
+ if (status & IDE_IR_IO) { /* from device (READ) */
+ IDE_READBUF(ide,IDE_REG_DATA,databuf,datalen);
+ }
+ else { /* to device (WRITE) */
+ IDE_WRITEBUF(ide,IDE_REG_DATA,databuf,datalen);
+ }
+
+ }
+
+
+ idecommon_testdrq(ide);
+
+ return 0;
+
+}
+
+
+/* *********************************************************************
+ * idecommon_request_sense(ide)
+ *
+ * Request sense data. This also clears a UNIT_ATTENTION condition
+ *
+ * Input parameters:
+ * ide - IDE interface
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+static int idecommon_request_sense(idecommon_t *ide)
+{
+ uint8_t cdb[12];
+ uint8_t sensedata[32];
+ int res;
+ int numbytes;
+
+ numbytes = sizeof(sensedata);
+
+ cdb[0] = CDB_CMD_REQSENSE;
+ cdb[1] = 0;
+ cdb[2] = 0;
+ cdb[3] = 0;
+ cdb[4] = sizeof(sensedata);
+ cdb[5] = 0;
+ cdb[6] = 0;
+ cdb[7] = 0;
+ cdb[8] = 0;
+ cdb[9] = 0;
+ cdb[10] = 0;
+ cdb[11] = 0;
+
+ memset(sensedata,0,sizeof(sensedata));
+
+ res = idecommon_packet(ide,cdb,sizeof(cdb),sensedata,numbytes);
+
+#if 0
+ xprintf("Sense data: ");
+ xprintf("Err:%02X ",sensedata[0]);
+ xprintf("Key:%02X ",sensedata[1]);
+ xprintf("Information:%02X%02X ",sensedata[2],sensedata[3]);
+ xprintf("ASC:%02X ASCQ:%02X ",sensedata[12],sensedata[13]);
+ xprintf("\n");
+#endif
+
+ idecommon_testdrq(ide);
+
+ return res;
+}
+
+
+/* *********************************************************************
+ * idecommon_read_atapi(ide,lba,numsec,buffer)
+ *
+ * Read sector(s) from the device. This version is for ATAPI devs.
+ *
+ * Input parameters:
+ * ide - IDE interface
+ * lba - logical block address
+ * numsec - number of sectors
+ * buffer - buffer address
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int idecommon_read_atapi(idecommon_t *ide,uint64_t lba,
+ int numsec,unsigned char *buffer)
+{
+ uint8_t cdb[12];
+ int res = 0;
+ int numbytes;
+ int idx;
+
+ numbytes = numsec << idecommon_sectorshift(ide->idecommon_sectorsize);
+
+ cdb[0] = CDB_CMD_READ;
+ cdb[1] = 0;
+ cdb[2] = ((lba >> 24) & 0xFF);
+ cdb[3] = ((lba >> 16) & 0xFF);
+ cdb[4] = ((lba >> 8) & 0xFF);
+ cdb[5] = ((lba >> 0) & 0xFF);
+ cdb[6] = 0;
+ cdb[7] = ((numsec >> 8) & 0xFF);
+ cdb[8] = ((numsec >> 0) & 0xFF);
+ cdb[9] = 0;
+ cdb[10] = 0;
+ cdb[11] = 0;
+
+ for (idx = 0; idx < 4; idx++) {
+ res = idecommon_packet(ide,cdb,sizeof(cdb),buffer,numbytes);
+ if (res < 0) {
+ idecommon_request_sense(ide);
+ continue;
+ }
+ break;
+ }
+
+ return res;
+}
+
+
+/* *********************************************************************
+ * idecommon_write_atapi(ide,lba,numsec,buffer)
+ *
+ * Write sector(s) to the device. This version is for ATAPI disks
+ *
+ * Input parameters:
+ * ide - IDE interface
+ * lba - logical block address
+ * numsec - number of sectors
+ * buffer - buffer address
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int idecommon_write_atapi(idecommon_t *ide,uint64_t lba,
+ int numsec,unsigned char *buffer)
+{
+ uint8_t cdb[12];
+ int res;
+ int numbytes;
+
+ numbytes = numsec << idecommon_sectorshift(ide->idecommon_sectorsize);
+
+ cdb[0] = CDB_CMD_WRITE;
+ cdb[1] = 0;
+ cdb[2] = ((lba >> 24) & 0xFF);
+ cdb[3] = ((lba >> 16) & 0xFF);
+ cdb[4] = ((lba >> 8) & 0xFF);
+ cdb[5] = ((lba >> 0) & 0xFF);
+ cdb[6] = 0;
+ cdb[7] = ((numsec >> 8) & 0xFF);
+ cdb[8] = ((numsec >> 0) & 0xFF);
+ cdb[9] = 0;
+ cdb[10] = 0;
+ cdb[11] = 0;
+
+ res = idecommon_packet(ide,cdb,sizeof(cdb),buffer,numbytes);
+
+ return res;
+}
+
+
+/* *********************************************************************
+ * idecommon_read_lba(ide,lba,numsec,buffer)
+ *
+ * Read sector(s) from the device.
+ *
+ * Input parameters:
+ * ide - IDE interface
+ * lba - logical block address
+ * numsec - number of sectors
+ * buffer - buffer address
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int idecommon_read_lba(idecommon_t *ide,uint64_t lba,int numsec,unsigned char *buffer)
+{
+ int secidx;
+ unsigned char *ptr;
+
+ if (idecommon_waitnotbusy(ide) < 0) return -1;
+ IDE_WRITEREG8(ide,IDE_REG_DRVHD,(ide->idecommon_unit<<4) | ((lba >> 24) & 0x0F) | 0x40);
+ if (idecommon_waitnotbusy(ide) < 0) return -1;
+
+ IDE_WRITEREG8(ide,IDE_REG_CYLMSB,((lba >> 16) & 0xFF));
+ IDE_WRITEREG8(ide,IDE_REG_CYLLSB,((lba >> 8) & 0xFF));
+ IDE_WRITEREG8(ide,IDE_REG_SECNUM,(lba & 0xFF));
+ IDE_WRITEREG8(ide,IDE_REG_SECCNT,numsec);
+
+ idecommon_testdrq(ide);
+
+ IDE_WRITEREG8(ide,IDE_REG_COMMAND,IDE_CMD_READ);
+
+ idecommon_waitbusy(ide);
+ if (idecommon_wait_drq(ide) < 0) return -1;
+
+ ptr = buffer;
+
+ for (secidx = 0; secidx < numsec; secidx++) {
+ IDE_READBUF(ide,IDE_REG_DATA,ptr,ide->idecommon_sectorsize);
+ ptr += ide->idecommon_sectorsize;
+ }
+
+ idecommon_testdrq(ide);
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * idecommon_write_lba(ide,lba,numsec,buffer)
+ *
+ * Write sector(s) from the device.
+ *
+ * Input parameters:
+ * ide - IDE interface
+ * lba - logical block address
+ * numsec - number of sectors
+ * buffer - buffer address
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int idecommon_write_lba(idecommon_t *ide,uint64_t lba,int numsec,unsigned char *buffer)
+{
+ int secidx;
+ uint8_t *ptr;
+
+ if (idecommon_waitnotbusy(ide) < 0) return -1;
+ IDE_WRITEREG8(ide,IDE_REG_DRVHD,(ide->idecommon_unit<<4) | ((lba >> 24) & 0x0F) | 0x40);
+ if (idecommon_waitnotbusy(ide) < 0) return -1;
+
+ IDE_WRITEREG8(ide,IDE_REG_CYLMSB,((lba >> 16) & 0xFF));
+ IDE_WRITEREG8(ide,IDE_REG_CYLLSB,((lba >> 8) & 0xFF));
+ IDE_WRITEREG8(ide,IDE_REG_SECNUM,(lba & 0xFF));
+ IDE_WRITEREG8(ide,IDE_REG_SECCNT,numsec);
+
+ IDE_WRITEREG8(ide,IDE_REG_COMMAND,IDE_CMD_WRITE);
+
+ if (idecommon_wait_drq(ide) < 0) return -1;
+
+ ptr = buffer;
+
+ for (secidx = 0; secidx < numsec; secidx++) {
+ IDE_WRITEBUF(ide,IDE_REG_DATA,ptr,ide->idecommon_sectorsize);
+ ptr += ide->idecommon_sectorsize;
+ }
+
+ idecommon_testdrq(ide);
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * idecommon_diagnostic(ide)
+ *
+ * run the device diagnostics on the IDE device. This also
+ * helps us determine if it's an IDE or ATAPI disk, since the
+ * diagnostic will leave a signature in the registers.
+ *
+ * Input parameters:
+ * softc - IDE interface
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int idecommon_diagnostic(idecommon_t *softc)
+{
+ if (idecommon_waitnotbusy(softc) < 0) return -1;
+ IDE_WRITEREG8(softc,IDE_REG_DRVHD,(softc->idecommon_unit<<4));
+ if (idecommon_waitnotbusy(softc) < 0) return -1;
+
+ IDE_WRITEREG8(softc,IDE_REG_COMMAND,IDE_CMD_DIAGNOSTIC);
+ if (idecommon_waitnotbusy(softc) < 0) return -1;
+
+ cfe_sleep(CFE_HZ/2);
+ idecommon_dumpregs(softc);
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * idecommon_getmodel(buffer,model)
+ *
+ * Get the ASCII model name out of an IDE identify buffer. some
+ * byte swapping is involved here. The trailing blanks are trimmed.
+ *
+ * Input parameters:
+ * buffer - 512-byte buffer from IDENTIFY command
+ * model - 41-byte string (max) for model name
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void idecommon_getmodel(uint8_t *buffer,char *model)
+{
+ uint16_t w;
+ int idx;
+
+ for (idx = 0; idx < 20; idx++) {
+ w = GETWORD_LE(buffer,27+idx);
+ model[idx*2] = w >> 8;
+ model[idx*2+1] = w & 0xFF;
+ }
+ for (idx = 39; idx > 0; idx--) {
+ if (model[idx] != ' ') {
+ model[idx+1] = '\0';
+ break;
+ }
+ }
+
+}
+
+/* *********************************************************************
+ * idecommon_devprobe(softc)
+ *
+ * Probe the IDE device, to determine if it's actually present
+ * or not. If present, determine if it's IDE or ATAPI and
+ * get the device size. Init our internal structures so we know
+ * how to talk to the device.
+ *
+ * Input parameters:
+ * softc - IDE structure
+ * noisy - display stuff as we probe
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+int idecommon_devprobe(idecommon_t *softc,int noisy)
+{
+ int res;
+ int atapi;
+ unsigned char buffer[DISK_SECTORSIZE];
+ unsigned char model[41];
+ uint64_t ttlsect;
+ int devtype;
+ uint16_t w;
+ char *typename;
+
+ /*
+ * Reset the drive
+ */
+
+ res = idecommon_reset(softc);
+ if (res < 0) return -1;
+
+ /*
+ * Run diagnostic to get the signature.
+ */
+
+ res = idecommon_diagnostic(softc);
+ if (res < 0) return res;
+
+ /*
+ * Test signature
+ */
+
+ atapi = 0;
+ if ((IDE_READREG8(softc,IDE_REG_CYLLSB) == ATAPI_SIG_LSB) &&
+ (IDE_READREG8(softc,IDE_REG_CYLMSB) == ATAPI_SIG_MSB)) {
+ atapi = 1;
+ }
+
+ if (noisy) {
+ if (atapi) xprintf("ATAPI: ");
+ else xprintf("IDE: ");
+ }
+
+ /*
+ * Do tha appropriate IDENTIFY command to get device information
+ */
+
+ softc->idecommon_atapi = atapi;
+ res = idecommon_identify(softc,buffer);
+ if (res < 0) return -1;
+
+ /*
+ * Using that information, determine our device type
+ */
+
+ if (!atapi) {
+ devtype = IDE_DEVTYPE_DISK;
+ typename = "Disk";
+ }
+ else {
+ w = GETWORD_LE(buffer,0);
+ switch ((w >> 8) & 31) {
+ case 5: /* CD-ROM */
+ devtype = IDE_DEVTYPE_CDROM;
+ typename = "CD-ROM";
+ break;
+ default:
+ devtype = IDE_DEVTYPE_ATAPIDISK;
+ typename = "Disk";
+ break;
+ }
+ }
+
+ /*
+ * Say nice things about the device.
+ */
+
+ idecommon_getmodel(buffer,model);
+ if (noisy) xprintf("%s, \"%s\"",typename,model);
+
+
+#ifdef _IDE_DEBUG_
+ if (!softc->idecommon_atapi) {
+ ttlsect = (GETWORD_LE(buffer,57) + (GETWORD_LE(buffer,58) << 16));
+ if (noisy) xprintf(", Sectors: %llu (%lld MB)",ttlsect,
+ (uint64_t) (ttlsect/2048));
+ }
+ else {
+ ttlsect = 0;
+ }
+#endif
+ if (noisy) xprintf("\n");
+
+ /*
+ * Initialize internal structure info, especially pointers to the
+ * read/write routines and the sector size.
+ */
+
+ softc->idecommon_ttlsect = ttlsect;
+ idecommon_init(softc,devtype);
+
+ return res;
+}
+
+/* *********************************************************************
+ * idecommon_open(ctx)
+ *
+ * Process the CFE OPEN call for this device. For IDE disks,
+ * the device is reset and identified, and the geometry is
+ * determined.
+ *
+ * Input parameters:
+ * ctx - device context
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+
+int idecommon_open(cfe_devctx_t *ctx)
+{
+ idecommon_t *softc = ctx->dev_softc;
+ int res;
+
+ if (softc->idecommon_deferprobe) {
+ res = idecommon_devprobe(softc,0);
+ if (res < 0) return res;
+ }
+
+ return 0;
+}
+
+/* *********************************************************************
+ * idecommon_read(ctx,buffer)
+ *
+ * Process a CFE READ command for the IDE device. This is
+ * more complex than it looks, since CFE offsets are byte offsets
+ * and we may need to read partial sectors.
+ *
+ * Input parameters:
+ * ctx - device context
+ * buffer - buffer descriptor
+ *
+ * Return value:
+ * number of bytes read, or <0 if an error occured
+ ********************************************************************* */
+
+int idecommon_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ idecommon_t *softc = ctx->dev_softc;
+ unsigned char *bptr;
+ int blen;
+ int numsec;
+ int res = 0;
+ int amtcopy;
+ uint64_t lba;
+ uint64_t offset;
+ unsigned char sector[MAX_SECTORSIZE];
+ int sectorshift;
+
+ sectorshift = idecommon_sectorshift(softc->idecommon_sectorsize);
+
+ bptr = buffer->buf_ptr;
+ blen = buffer->buf_length;
+ offset = buffer->buf_offset;
+ numsec = (blen + softc->idecommon_sectorsize - 1) >> sectorshift;
+
+ if (offset & (softc->idecommon_sectorsize-1)) {
+ lba = (offset >> sectorshift);
+ res = (*softc->idecommon_readfunc)(softc,lba,1,sector);
+ if (res < 0) goto out;
+ amtcopy = softc->idecommon_sectorsize - (offset & (softc->idecommon_sectorsize-1));
+ if (amtcopy > blen) amtcopy = blen;
+ memcpy(bptr,&sector[offset & (softc->idecommon_sectorsize-1)],amtcopy);
+ bptr += amtcopy;
+ offset += amtcopy;
+ blen -= amtcopy;
+ }
+
+ while (blen >= softc->idecommon_sectorsize) {
+ lba = (offset >> sectorshift);
+ amtcopy = softc->idecommon_sectorsize;
+ res = (*softc->idecommon_readfunc)(softc,lba,1,bptr);
+ if (res < 0) goto out;
+ bptr += amtcopy;
+ offset += amtcopy;
+ blen -= amtcopy;
+ }
+
+ if (blen) {
+ lba = (offset >> sectorshift);
+ res = (*softc->idecommon_readfunc)(softc,lba,1,sector);
+ if (res < 0) goto out;
+ amtcopy = blen;
+ memcpy(bptr,sector,amtcopy);
+ bptr += amtcopy;
+ offset += amtcopy;
+ blen -= amtcopy;
+ }
+
+out:
+ buffer->buf_retlen = bptr - buffer->buf_ptr;
+
+ return res;
+}
+
+/* *********************************************************************
+ * idecommon_inpstat(ctx,inpstat)
+ *
+ * Test input status for the IDE disk. Disks are always ready
+ * to read.
+ *
+ * Input parameters:
+ * ctx - device context
+ * inpstat - input status structure
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+int idecommon_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
+{
+ /* idecommon_t *softc = ctx->dev_softc; */
+
+ inpstat->inp_status = 1;
+ return 0;
+}
+
+/* *********************************************************************
+ * idecommon_write(ctx,buffer)
+ *
+ * Process a CFE WRITE command for the IDE device. If the write
+ * involves partial sectors, the affected sectors are read first
+ * and the changes are merged in.
+ *
+ * Input parameters:
+ * ctx - device context
+ * buffer - buffer descriptor
+ *
+ * Return value:
+ * number of bytes write, or <0 if an error occured
+ ********************************************************************* */
+
+int idecommon_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ idecommon_t *softc = ctx->dev_softc;
+ unsigned char *bptr;
+ int blen;
+ int numsec;
+ int res = 0;
+ int amtcopy;
+ uint64_t offset;
+ uint64_t lba;
+ unsigned char sector[MAX_SECTORSIZE];
+ int sectorshift;
+
+ sectorshift = (softc->idecommon_sectorsize == 2048) ? 11 : 9;
+
+ bptr = buffer->buf_ptr;
+ blen = buffer->buf_length;
+ offset = buffer->buf_offset;
+ numsec = (blen + softc->idecommon_sectorsize - 1) >> sectorshift;
+
+ if (offset & (softc->idecommon_sectorsize-1)) {
+ lba = (offset >> sectorshift);
+ res = (*softc->idecommon_readfunc)(softc,lba,1,sector);
+ if (res < 0) goto out;
+ amtcopy = softc->idecommon_sectorsize - (offset & (softc->idecommon_sectorsize-1));
+ if (amtcopy > blen) amtcopy = blen;
+ memcpy(&sector[offset & (softc->idecommon_sectorsize-1)],bptr,amtcopy);
+ res = (*softc->idecommon_writefunc)(softc,lba,1,sector);
+ if (res < 0) goto out;
+ bptr += amtcopy;
+ offset += amtcopy;
+ blen -= amtcopy;
+ }
+
+ while (blen >= softc->idecommon_sectorsize) {
+ amtcopy = softc->idecommon_sectorsize;
+ lba = (offset >> sectorshift);
+ res = (*softc->idecommon_writefunc)(softc,lba,1,bptr);
+ if (res < 0) goto out;
+ bptr += amtcopy;
+ offset += amtcopy;
+ blen -= amtcopy;
+ }
+
+ if (blen) {
+ lba = (offset >> sectorshift);
+ res = (*softc->idecommon_readfunc)(softc,lba,1,sector);
+ if (res < 0) goto out;
+ amtcopy = blen;
+ memcpy(sector,bptr,amtcopy);
+ res = (*softc->idecommon_writefunc)(softc,lba,1,sector);
+ if (res < 0) goto out;
+ bptr += amtcopy;
+ offset += amtcopy;
+ blen -= amtcopy;
+ }
+
+out:
+ buffer->buf_retlen = bptr - buffer->buf_ptr;
+
+ return res;
+}
+
+
+/* *********************************************************************
+ * idecommon_ioctl(ctx,buffer)
+ *
+ * Process device I/O control requests for the IDE device.
+ *
+ * Input parameters:
+ * ctx - device context
+ * buffer - buffer descriptor
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+int idecommon_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ idecommon_t *softc = ctx->dev_softc;
+ unsigned int *info = (unsigned int *) buffer->buf_ptr;
+ unsigned long long *linfo = (unsigned long long *) buffer->buf_ptr;
+ blockdev_info_t *devinfo;
+
+ switch ((int)buffer->buf_ioctlcmd) {
+ case IOCTL_BLOCK_GETBLOCKSIZE:
+ *info = softc->idecommon_sectorsize;
+ break;
+ case IOCTL_BLOCK_GETTOTALBLOCKS:
+ *linfo = softc->idecommon_ttlsect;
+ break;
+ case IOCTL_BLOCK_GETDEVTYPE:
+ devinfo = (blockdev_info_t *) buffer->buf_ptr;
+ devinfo->blkdev_totalblocks = softc->idecommon_ttlsect;
+ devinfo->blkdev_blocksize = softc->idecommon_sectorsize;
+ devinfo->blkdev_devtype = (softc->idecommon_devtype == IDE_DEVTYPE_CDROM) ?
+ BLOCK_DEVTYPE_CDROM : BLOCK_DEVTYPE_DISK;
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+/* *********************************************************************
+ * idecommon_close(ctx)
+ *
+ * Close the I/O device.
+ *
+ * Input parameters:
+ * ctx - device context
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+int idecommon_close(cfe_devctx_t *ctx)
+{
+ /* idecommon_t *softc = ctx->dev_softc; */
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * idecommon_init(ide,devtype)
+ *
+ * Set up internal values based on the device type
+ *
+ * Input parameters:
+ * ide - IDE interface
+ * devtype - device type
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+void idecommon_init(idecommon_t *ide,int devtype)
+{
+
+ ide->idecommon_devtype = devtype;
+
+ switch (ide->idecommon_devtype) {
+ case IDE_DEVTYPE_DISK:
+ ide->idecommon_atapi = FALSE;
+ ide->idecommon_sectorsize = DISK_SECTORSIZE;
+ break;
+ case IDE_DEVTYPE_CDROM:
+ ide->idecommon_atapi = TRUE;
+ ide->idecommon_sectorsize = CDROM_SECTORSIZE;
+ break;
+ case IDE_DEVTYPE_ATAPIDISK:
+ ide->idecommon_atapi = TRUE;
+ ide->idecommon_sectorsize = DISK_SECTORSIZE;
+ break;
+ default:
+ ide->idecommon_atapi = FALSE;
+ ide->idecommon_sectorsize = DISK_SECTORSIZE;
+ break;
+ }
+
+ if (ide->idecommon_atapi) {
+ ide->idecommon_readfunc = idecommon_read_atapi;
+ ide->idecommon_writefunc = idecommon_write_atapi;
+ }
+ else {
+ ide->idecommon_readfunc = idecommon_read_lba;
+ ide->idecommon_writefunc = idecommon_write_lba;
+ }
+}
+
+/* *********************************************************************
+ * idecommon_attach(devdisp)
+ *
+ * Set up a cfe_devdisp structure that points at the idecommon
+ * structures.
+ *
+ * Input parameters:
+ * devdisp - cfe_devdisp_t structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+void idecommon_attach(cfe_devdisp_t *disp)
+{
+ disp->dev_open = idecommon_open;
+ disp->dev_read = idecommon_read;
+ disp->dev_inpstat = idecommon_inpstat;
+ disp->dev_write = idecommon_write;
+ disp->dev_ioctl = idecommon_ioctl;
+ disp->dev_close = idecommon_close;
+ disp->dev_poll = NULL;
+ disp->dev_reset = NULL;
+}
diff --git a/cfe/cfe/dev/dev_ide_pci.c b/cfe/cfe/dev/dev_ide_pci.c
new file mode 100644
index 0000000..ecf4c2a
--- /dev/null
+++ b/cfe/cfe/dev/dev_ide_pci.c
@@ -0,0 +1,358 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * PCI IDE disk driver File: dev_ide_pci.c
+ *
+ * This is a simple driver for IDE hard disks that are connected
+ * to PCI IDE controllers, such as a Promise UltraXX.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include "lib_types.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+#include "lib_string.h"
+#include "cfe_timer.h"
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "cfe_ioctl.h"
+
+#include "dev_ide_common.h"
+
+#include "dev_ide.h"
+
+#include "pcivar.h"
+#include "pcireg.h"
+
+/* *********************************************************************
+ * Macros
+ ********************************************************************* */
+
+#define _BYTESWAP_ /* don't byteswap these disks */
+
+#define OUTB(x,y) outb(x,y)
+#define OUTW(x,y) outw(x,y)
+#define INB(x) inb(x)
+#define INW(x) inw(x)
+
+/* *********************************************************************
+ * Forward declarations
+ ********************************************************************* */
+
+extern void _wbflush(void);
+
+static void idedrv_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+/* *********************************************************************
+ * Device Dispatch
+ ********************************************************************* */
+
+static cfe_devdisp_t idedrv_dispatch = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+const cfe_driver_t pciidedrv = {
+ "PCI IDE disk",
+ "ide",
+ CFE_DEV_DISK,
+ &idedrv_dispatch,
+ idedrv_probe
+};
+
+const cfe_driver_t pciatapidrv = {
+ "PCI ATAPI device",
+ "atapi",
+ CFE_DEV_DISK,
+ &idedrv_dispatch,
+ idedrv_probe
+};
+
+/* *********************************************************************
+ * Supported PCI devices
+ ********************************************************************* */
+
+#define DEVID(vid,pid) (((pid)<<16)|(vid))
+
+static uint32_t pciidedrv_devlist[] = {
+ DEVID(0x105a,0x4d33), /* Promise Ultra33 */
+ DEVID(0x1095,0x0649), /* CMD PCI0649 */
+ DEVID(0x1095,0x0648), /* CMD PCI0648 */
+ 0xFFFFFFFF
+};
+
+
+/* *********************************************************************
+ * Port I/O routines
+ *
+ * These routines are called back from the common code to do
+ * I/O cycles to the IDE disk. We provide routines for
+ * reading and writing bytes, words, and strings of words.
+ ********************************************************************* */
+
+static uint8_t idedrv_inb(idecommon_dispatch_t *disp,uint32_t reg)
+{
+ return INB(reg+disp->baseaddr);
+}
+
+static uint16_t idedrv_inw(idecommon_dispatch_t *disp,uint32_t reg)
+{
+ return INW(reg+disp->baseaddr);
+}
+
+static void idedrv_ins(idecommon_dispatch_t *disp,uint32_t reg,uint8_t *buf,int len)
+{
+ uint16_t data;
+
+ while (len > 0) {
+ data = INW(reg+disp->baseaddr);
+
+#ifdef _BYTESWAP_
+ *buf++ = (data >> 8) & 0xFF;
+ *buf++ = (data & 0xFF);
+#else
+ *buf++ = (data & 0xFF);
+ *buf++ = (data >> 8) & 0xFF;
+#endif
+ len--;
+ len--;
+ }
+
+}
+
+static void idedrv_outb(idecommon_dispatch_t *disp,uint32_t reg,uint8_t val)
+{
+ OUTB(reg+disp->baseaddr,val);
+}
+
+static void idedrv_outw(idecommon_dispatch_t *disp,uint32_t reg,uint16_t val)
+{
+ OUTW(reg+disp->baseaddr,val);
+}
+
+static void idedrv_outs(idecommon_dispatch_t *disp,uint32_t reg,uint8_t *buf,int len)
+{
+ uint16_t data;
+
+ while (len > 0) {
+#ifdef _BYTESWAP_
+ data = (uint16_t) buf[1] + ((uint16_t) buf[0] << 8);
+#else
+ data = (uint16_t) buf[0] + ((uint16_t) buf[1] << 8);
+#endif
+
+ OUTW(reg+disp->baseaddr,data);
+
+ buf++;
+ buf++;
+ len--;
+ len--;
+ }
+}
+
+
+/* *********************************************************************
+ * pciidedrv_find(devid,list)
+ *
+ * Find a particular product ID on the list. Return >= 0 if
+ * the ID is valid.
+ *
+ * Input parameters:
+ * devid - product and device ID we have
+ * list - list of product and device IDs we're looking for
+ *
+ * Return value:
+ * index into table, or -1 if not found
+ ********************************************************************* */
+static int pciidedrv_find(uint32_t devid,uint32_t *list)
+{
+ int idx = 0;
+
+ while (list[idx] != 0xFFFFFFFF) {
+ if (list[idx] == devid) return idx;
+ idx++;
+ }
+
+ return -1;
+}
+
+
+/* *********************************************************************
+ * idedrv_probe(drv,probe_a,probe_b,probe_ptr)
+ *
+ * Our probe routine. Attach an IDE device to the firmware.
+ *
+ * Input parameters:
+ * drv - driver structure
+ * probe_a - physical address of IDE registers
+ * probe_b - unit number
+ * probe_ptr - not used
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void idedrv_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ idecommon_t *softc;
+ idecommon_dispatch_t *disp;
+ char descr[80];
+ char unitstr[50];
+ pcitag_t tag;
+ int index;
+ uint32_t devid;
+ uint32_t reg;
+ int res;
+ int unit;
+ cfe_driver_t *realdrv;
+ int attached = 0;
+
+ /*
+ * probe_a is unused
+ * probe_b is unused
+ * probe_ptr is unused.
+ */
+
+ index = 0;
+
+ for (;;) {
+ if (pci_find_class(PCI_CLASS_MASS_STORAGE,index,&tag) != 0) break;
+ index++;
+ devid = pci_conf_read(tag,PCI_ID_REG);
+
+ if (pciidedrv_find(devid,pciidedrv_devlist) < 0) {
+ continue;
+ }
+
+
+ reg = pci_conf_read(tag,PCI_MAPREG(0));
+
+ if (PCI_MAPREG_TYPE(reg) != PCI_MAPREG_TYPE_IO) {
+ xprintf("Skipping this IDE device, we don't do memory mapped IDE yet\n");
+ continue;
+ }
+
+ reg &= ~PCI_MAPREG_TYPE_MASK;
+
+ for (unit = 0; unit < 2; unit++) {
+
+ /*
+ * If we've deliberately disabled probing of this
+ * device, then skip it.
+ */
+
+ if (IDE_PROBE_GET_TYPE(probe_b,unit) == IDE_DEVTYPE_NOPROBE) {
+ continue;
+ }
+
+ softc = (idecommon_t *) KMALLOC(sizeof(idecommon_t),0);
+ disp = (idecommon_dispatch_t *) KMALLOC(sizeof(idecommon_dispatch_t),0);
+
+ if (!softc || !disp) {
+ if (softc) KFREE(softc);
+ if (disp) KFREE(disp);
+ return; /* out of memory, stop here */
+ }
+
+
+ softc->idecommon_addr = reg;
+ disp->ref = softc;
+ disp->baseaddr = softc->idecommon_addr;
+ softc->idecommon_deferprobe = 0;
+ softc->idecommon_dispatch = disp;
+ softc->idecommon_unit = unit;
+
+ disp->outb = idedrv_outb;
+ disp->outw = idedrv_outw;
+ disp->outs = idedrv_outs;
+
+ disp->inb = idedrv_inb;
+ disp->inw = idedrv_inw;
+ disp->ins = idedrv_ins;
+
+ /*
+ * If we're autoprobing, do it now. Loop back if we have
+ * trouble finding the device.
+ *
+ * If not autoprobing, assume the device is there and set the
+ * common routines to double check later.
+ */
+
+ if (IDE_PROBE_GET_TYPE(probe_b,unit) == IDE_DEVTYPE_AUTO) {
+ res = idecommon_devprobe(softc,1);
+ if (res < 0) {
+ KFREE(softc);
+ KFREE(disp);
+ continue;
+ }
+ }
+ else {
+ idecommon_init(softc,IDE_PROBE_GET_TYPE(probe_b,unit));
+ softc->idecommon_deferprobe = 1;
+ }
+
+ xsprintf(descr,"%s unit %d at I/O %04X",drv->drv_description,
+ softc->idecommon_unit,softc->idecommon_addr);
+ xsprintf(unitstr,"%d",unit);
+
+ realdrv = (cfe_driver_t *) (softc->idecommon_atapi ? &pciatapidrv : &pciidedrv);
+
+ idecommon_attach(&idedrv_dispatch);
+ cfe_attach(realdrv,softc,unitstr,descr);
+ attached++;
+ }
+
+ }
+
+ xprintf("PCIIDE: %d controllers found\n",attached);
+}
+
+
diff --git a/cfe/cfe/dev/dev_newflash.c b/cfe/cfe/dev/dev_newflash.c
new file mode 100644
index 0000000..d196e92
--- /dev/null
+++ b/cfe/cfe/dev/dev_newflash.c
@@ -0,0 +1,1428 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * "New" Flash device driver File: dev_newflash.c
+ *
+ * This driver supports various types of flash
+ * parts.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include "lib_types.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+#include "lib_string.h"
+#include "addrspace.h"
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "cfe_ioctl.h"
+#include "cfe_error.h"
+
+#include "bsp_config.h"
+#include "dev_newflash.h"
+
+/* *********************************************************************
+ * Macros
+ ********************************************************************* */
+
+#define GETCFIBYTE(arr,x) (arr[(x)*2])
+
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#define max(a,b) ((a) > (b) ? (a) : (b))
+
+/*
+ * Get the address of the flash sector buffer from the
+ * config file. Addresses are PHYSICAL.
+ */
+
+#ifndef CFG_FLASH_SECTOR_BUFFER_ADDR
+#define CFG_FLASH_SECTOR_BUFFER_ADDR (100*1024*1024-128*1024)
+#endif
+
+#ifndef CFG_FLASH_SECTOR_BUFFER_SIZE
+#define CFG_FLASH_SECTOR_BUFFER_SIZE (128*1024)
+#endif
+
+
+/*#define _NEWFLASH_DEBUG_ */
+
+/* *********************************************************************
+ * Forward declarations
+ ********************************************************************* */
+
+
+static void flashdrv_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+
+static int flashdrv_open(cfe_devctx_t *ctx);
+static int flashdrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int flashdrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
+static int flashdrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int flashdrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int flashdrv_close(cfe_devctx_t *ctx);
+
+/* *********************************************************************
+ * Device dispatch
+ ********************************************************************* */
+
+const static cfe_devdisp_t flashdrv_dispatch = {
+ flashdrv_open,
+ flashdrv_read,
+ flashdrv_inpstat,
+ flashdrv_write,
+ flashdrv_ioctl,
+ flashdrv_close,
+ NULL,
+ NULL
+};
+
+const cfe_driver_t newflashdrv = {
+ "New CFI flash",
+ "flash",
+ CFE_DEV_FLASH,
+ &flashdrv_dispatch,
+ flashdrv_probe
+};
+
+
+
+/* *********************************************************************
+ * Externs
+ ********************************************************************* */
+
+extern void *flashop_engine_ptr;
+extern int flashop_engine_len;
+
+extern void _cfe_flushcache(int);
+
+static int flash_sector_query(flashdev_t *softc,flash_sector_t *sector);
+
+/* *********************************************************************
+ * Globals
+ ********************************************************************* */
+
+/*
+ * This is a pointer to a DRAM version of our flash subroutines.
+ * We make a global here so that it doesn't get copied multiple
+ * times for each flash we instantiate.
+ */
+
+static int (*flashop_engine_ram)(flashinstr_t *prog) = NULL;
+static uint8_t *flash_sector_buffer = NULL;
+
+/* *********************************************************************
+ * FLASH_OP_BEGIN(softc)
+ *
+ * Reset the pointer to the flash operations so that we can
+ * begin filling in new instructions to execute
+ *
+ * Input parameters:
+ * softc - our softc.
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+#define flash_op_begin(softc) softc->fd_iptr = 0;
+
+/* *********************************************************************
+ * FLASH_OP_ADD(softc,op,dest,src,cnt)
+ *
+ * Add an instruction to the flashop table
+ *
+ * Input parameters:
+ * softc - our flash
+ * op,dest,src,cnt - data for the opcode
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void flash_op_add(flashdev_t *softc,long base,long op,long dest,long src,long cnt)
+{
+ flashinstr_t *fi = &(softc->fd_inst[softc->fd_iptr]);
+
+ fi->fi_op = op;
+ fi->fi_base = base;
+ fi->fi_dest = dest;
+ fi->fi_src = src;
+ fi->fi_cnt = cnt;
+
+ softc->fd_iptr++;
+}
+
+
+/* *********************************************************************
+ * FLASH_OP_EXECUTE(softc)
+ *
+ * Execute the stored "flash operations"
+ *
+ * Input parameters:
+ * softc - our flash
+ *
+ * Return value:
+ * 0 if ok, else # of failures (less than zero)
+ ********************************************************************* */
+
+static int flash_op_execute(flashdev_t *softc)
+{
+ flash_op_add(softc,softc->fd_probe.flash_phys,FEOP_RETURN,0,0,0);
+
+#ifdef _NEWFLASH_DEBUG_
+ if (1) {
+ int idx;
+ printf("---------------\nCalling engine @ %08X\n",flashop_engine_ram);
+ for (idx = 0; idx < softc->fd_iptr; idx++) {
+ printf("%2d %08X %08X %08X %08X\n",
+ softc->fd_inst[idx].fi_op,
+ softc->fd_inst[idx].fi_base,
+ softc->fd_inst[idx].fi_dest,
+ softc->fd_inst[idx].fi_src,
+ softc->fd_inst[idx].fi_cnt);
+ }
+ }
+#endif
+
+ /*
+ * If someone hooked the flashop engine, call the hook.
+ */
+ if (softc->fd_probe.flash_engine_hook) {
+ return (*(softc->fd_probe.flash_engine_hook))(&(softc->fd_inst[0]));
+ }
+
+ /*
+ * Otherwise, call the standard one.
+ */
+ if (!flashop_engine_ram) return CFE_ERR_UNSUPPORTED;
+ return (*flashop_engine_ram)(&(softc->fd_inst[0]));
+}
+
+
+/* *********************************************************************
+ * FLASH_SETUP_ENGINE()
+ *
+ * Set up the "flash engine", copying the routine to DRAM
+ * and flushing the cache so we can call it.
+ *
+ * Input parameters:
+ * nothing
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void flash_setup_engine(void)
+{
+#if ((CFG_RAMAPP) || (CFG_EMBEDDED_PIC))
+ /* CFE is relocated, no need to copy flash engine to heap */
+ flashop_engine_ram = (void *) flashop_engine_ptr;
+#else
+ /* Copy flash engine to heap */
+ uint32_t *dst,*src;
+ int idx;
+
+ if (flashop_engine_ram) return; /* already done */
+
+ /*
+ * Allocate space for engine
+ */
+
+ flashop_engine_ram = (void *) KMALLOC(flashop_engine_len,0);
+ if (!flashop_engine_ram) return;
+
+ /*
+ * Copy engine to RAM - do it 32-bits at a time to avoid
+ * a certain platform with broken byte reads (no, not the 1250)
+ */
+
+ dst = (uint32_t *) flashop_engine_ram;
+ src = (uint32_t *) flashop_engine_ptr;
+ for (idx = 0; idx < flashop_engine_len/sizeof(uint32_t); idx++) {
+ *dst++ = *src++;
+ }
+
+ /*
+ * Flush the d-cache, invalidate the I-cache.
+ */
+
+ _cfe_flushcache(1);
+ _cfe_flushcache(2);
+#endif
+}
+
+/* *********************************************************************
+ * FLASH_ERASE_RANGE(softc,range)
+ *
+ * Erase a range of sectors
+ *
+ * Input parameters:
+ * softc - our flash
+ * range - range structure
+ *
+ * Return value:
+ * 0 if ok
+ * else error
+ ********************************************************************* */
+
+static int flash_erase_range(flashdev_t *softc,flash_range_t *range)
+{
+ flash_sector_t sector;
+ int res;
+
+ if (softc->fd_probe.flash_type != FLASH_TYPE_FLASH) {
+ return CFE_ERR_UNSUPPORTED;
+ }
+
+ if (range->range_base+range->range_length > softc->fd_probe.flash_size) {
+ return CFE_ERR_INV_PARAM;
+ }
+
+ res = 0;
+
+ sector.flash_sector_idx = 0;
+
+ for (;;) {
+ res = flash_sector_query(softc,&sector);
+ if (res != 0) break;
+ if (sector.flash_sector_status == FLASH_SECTOR_INVALID) {
+ break;
+ }
+
+ if ((sector.flash_sector_offset >= range->range_base) &&
+ (sector.flash_sector_offset <
+ (range->range_base+range->range_length-1))) {
+
+ flash_op_begin(softc);
+ flash_op_add(softc,softc->fd_probe.flash_phys,
+ softc->fd_erasefunc,
+ sector.flash_sector_offset,
+ 0,0);
+ res = flash_op_execute(softc);
+
+ if (res != 0) break;
+ }
+ sector.flash_sector_idx++;
+ }
+
+ return res;
+
+}
+
+/* *********************************************************************
+ * FLASH_ERASE_ALL(softc)
+ *
+ * Erase the entire flash device, except the NVRAM area,
+ * sector-by-sector.
+ *
+ * Input parameters:
+ * softc - our flash
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int flash_erase_all(flashdev_t *softc)
+{
+ flash_range_t range;
+
+ range.range_base = 0;
+ range.range_length = softc->fd_probe.flash_size *
+ softc->fd_probe.flash_nchips;
+
+ return flash_erase_range(softc,&range);
+}
+
+
+/* *********************************************************************
+ * flash_range_intersection(sector,inrange,outrange)
+ *
+ * Compute the intersection between a flash range and a
+ * sector.
+ *
+ * Input parameters:
+ * sector - sector to examine
+ * range - range we are checking
+ * outrange - where to put resulting intersection range
+ *
+ * Return value:
+ * 1 - range is an entire sector
+ * 0 - range is a partial sector
+ * -1 - range has no intersection
+ ********************************************************************* */
+
+static int flash_range_intersection(flash_sector_t *sector,
+ flash_range_t *inrange,
+ flash_range_t *outrange)
+{
+ int start,end;
+
+ /*
+ * compute the start and end pointers
+ */
+
+ start = (int) (max(sector->flash_sector_offset,
+ inrange->range_base));
+
+ end = (int) (min((sector->flash_sector_offset+sector->flash_sector_size),
+ (inrange->range_base+inrange->range_length)));
+
+ /*
+ * if the end is in the right place wrt the start,
+ * there is an intersection.
+ */
+
+ if (end > start) {
+ outrange->range_base = (unsigned int) start;
+ outrange->range_length = (unsigned int) (end-start);
+
+ if ((sector->flash_sector_offset == outrange->range_base) &&
+ (sector->flash_sector_size == outrange->range_length)) {
+ return 1; /* instersection: entire sector */
+ }
+ else {
+ return 0; /* intersection: partial sector */
+ }
+ }
+ else {
+ outrange->range_base = (unsigned int) start;
+ outrange->range_length = 0;
+ return -1; /* intersection: none */
+ }
+}
+
+
+/* *********************************************************************
+ * FLASH_SECTOR_QUERY(softc,sector)
+ *
+ * Query the sector information about a particular sector. You can
+ * call this iteratively to find out about all of the sectors.
+ *
+ * Input parameters:
+ * softc - our flash info
+ * sector - structure to receive sector information
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int flash_sector_query(flashdev_t *softc,flash_sector_t *sector)
+{
+ int idx;
+ int nblks;
+ int blksiz;
+ unsigned int offset;
+ int whichchip;
+ int secidx;
+ int curblk;
+
+ if (softc->fd_probe.flash_type != FLASH_TYPE_FLASH) {
+ return CFE_ERR_UNSUPPORTED;
+ }
+
+ if (softc->fd_probe.flash_nsectors == 0) {
+ return CFE_ERR_UNSUPPORTED;
+ }
+
+ /* Figure out which chip */
+ whichchip = sector->flash_sector_idx / softc->fd_ttlsect;
+ if (whichchip >= softc->fd_probe.flash_nchips) {
+ sector->flash_sector_status = FLASH_SECTOR_INVALID;
+ return 0;
+ }
+
+ /* Within that chip, get sector info */
+ offset = softc->fd_probe.flash_size * whichchip;
+ secidx = sector->flash_sector_idx % softc->fd_ttlsect;
+ curblk = 0;
+
+ for (idx = 0; idx < softc->fd_probe.flash_nsectors; idx++) {
+ nblks = FLASH_SECTOR_NBLKS(softc->fd_probe.flash_sectors[idx]);
+ blksiz = FLASH_SECTOR_SIZE(softc->fd_probe.flash_sectors[idx]);
+ if (secidx < curblk+nblks) {
+ sector->flash_sector_status = FLASH_SECTOR_OK;
+ sector->flash_sector_offset =
+ offset + (secidx-curblk)*blksiz;
+ sector->flash_sector_size = blksiz;
+ break;
+ }
+
+ offset += (nblks)*blksiz;
+ curblk += nblks;
+ }
+
+
+ if (idx == softc->fd_probe.flash_nsectors) {
+ sector->flash_sector_status = FLASH_SECTOR_INVALID;
+ }
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * FLASH_SET_CMDSET(softc,cmdset,bus16,dev16)
+ *
+ * Set the command-set that we'll honor for this flash.
+ *
+ * Input parameters:
+ * softc - our flash
+ * cmdset - FLASH_CFI_CMDSET_xxx
+ * bus16 - true if bus is 16 bits wide
+ * dev16 - true if device supports 16-bit operation
+ *
+ * So: bus16 && dev16 -> 16-bit commands
+ * !bus16 && dev16 -> 8-bit commands to 16-bit flash with BYTE#
+ * !bus16 && !dev16 -> 8-bit commands
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void flash_set_cmdset(flashdev_t *softc,int cmdset,int bus16,int dev16)
+{
+ switch (cmdset) {
+#if (FLASH_DRIVERS & FLASH_DRIVER_INTEL)
+ case FLASH_CFI_CMDSET_INTEL_ECS:
+ case FLASH_CFI_CMDSET_INTEL_STD:
+ if (bus16) {
+ softc->fd_erasefunc = FEOP_INTEL_ERASE16;
+ softc->fd_pgmfunc = FEOP_INTEL_PGM16;
+ softc->fd_readfunc = FEOP_READ16;
+ }
+ else {
+ softc->fd_erasefunc = FEOP_INTEL_ERASE8;
+ softc->fd_pgmfunc = FEOP_INTEL_PGM8;
+ softc->fd_readfunc = FEOP_READ8;
+ }
+ break;
+#endif
+#if (FLASH_DRIVERS & FLASH_DRIVER_AMD)
+ case FLASH_CFI_CMDSET_AMD_STD:
+ case FLASH_CFI_CMDSET_AMD_ECS:
+ if (!bus16 && !dev16) { /* 8-bit bus, 8-bit flash */
+ softc->fd_erasefunc = FEOP_AMD_ERASE8;
+ softc->fd_pgmfunc = FEOP_AMD_PGM8;
+ softc->fd_readfunc = FEOP_READ8;
+ }
+ else if (bus16 && dev16) { /* 16-bit bus, 16-bit flash */
+ softc->fd_erasefunc = FEOP_AMD_ERASE16;
+ softc->fd_pgmfunc = FEOP_AMD_PGM16;
+ softc->fd_readfunc = FEOP_READ16;
+ }
+ else { /* 8-bit bus, 16-bit flash w/BYTE# */
+ softc->fd_erasefunc = FEOP_AMD_ERASE16B;
+ softc->fd_pgmfunc = FEOP_AMD_PGM16B;
+ softc->fd_readfunc = FEOP_READ8;
+ }
+ break;
+#endif
+ default:
+ /* we don't understand the command set - treat it like ROM */
+ softc->fd_erasefunc = FEOP_RETURN;
+ softc->fd_pgmfunc = FEOP_RETURN;
+ softc->fd_readfunc = bus16 ? FEOP_READ16 : FEOP_READ8;
+ break;
+ }
+}
+
+#if (FLASH_DRIVERS & FLASH_DRIVER_CFI)
+/* *********************************************************************
+ * FLASH_CFI_PROBE(softc)
+ *
+ * Try to do a CFI query on this device. If we find the m
+ * magic signature, extract some useful information from the
+ * query structure.
+ *
+ * Input parameters:
+ * softc - out flash
+ *
+ * Return value:
+ * 0 if successful, <0 if error
+ ********************************************************************* */
+static int flash_cfi_probe(flashdev_t *softc)
+{
+ uint8_t cfidata[FLASH_MAX_CFIDATA];
+ unsigned int cmdset;
+ unsigned int devif;
+ int bus16 = 0;
+ int dev16 = 0;
+ int idx;
+ int found = 0;
+ int regcnt;
+ int nblks;
+ int blksiz;
+ int insane = 0;
+ uint8_t insaner = 0;
+
+ if (softc->fd_probe.flash_flags & FLASH_FLG_BUS16) {
+ bus16 = 1;
+ }
+
+ /*
+ * Do a CFI query (16-bit)
+ */
+
+ idx = FEOP_CFIQUERY8;
+ if (softc->fd_probe.flash_flags & FLASH_FLG_DEV16) {
+ idx = (softc->fd_probe.flash_flags & FLASH_FLG_BUS16) ?
+ FEOP_CFIQUERY16 : FEOP_CFIQUERY16B;
+ }
+
+ flash_op_begin(softc);
+ flash_op_add(softc,softc->fd_probe.flash_phys,
+ idx,(long)cfidata,0,FLASH_MAX_CFIDATA);
+ flash_op_execute(softc);
+
+ /*
+ * Look for signature.
+ */
+
+
+ if ((GETCFIBYTE(cfidata,FLASH_CFI_SIGNATURE+0) == 'Q') &&
+ (GETCFIBYTE(cfidata,FLASH_CFI_SIGNATURE+1) == 'R') &&
+ (GETCFIBYTE(cfidata,FLASH_CFI_SIGNATURE+2) == 'Y')) {
+ found = 1;
+ }
+
+
+ /*
+ * No CFI, bail. First, set the command set to an invalid
+ * value so that we'll use default routines to read but not do programming
+ */
+
+ if (!found) {
+ flash_set_cmdset(softc,-1,bus16,dev16);
+ return CFE_ERR_UNSUPPORTED;
+ }
+
+ softc->fd_probe.flash_type = FLASH_TYPE_FLASH;
+
+ /*
+ * Gather info from flash
+ */
+
+ cmdset = ((unsigned int) (GETCFIBYTE(cfidata,FLASH_CFI_COMMAND_SET))) +
+ (((unsigned int) (GETCFIBYTE(cfidata,FLASH_CFI_COMMAND_SET+1))) << 8);
+
+
+ devif = ((unsigned int) (GETCFIBYTE(cfidata,FLASH_CFI_DEVICE_INTERFACE))) +
+ (((unsigned int) (GETCFIBYTE(cfidata,FLASH_CFI_DEVICE_INTERFACE+1))) << 8);
+
+
+ softc->fd_probe.flash_size = (1 << (unsigned int)(GETCFIBYTE(cfidata,FLASH_CFI_DEVICE_SIZE)));
+
+ /*
+ * It's a 16-bit device if it is either always 16 bits or can be.
+ * we'll use "bus16" to decide if the BYTE# pin was strapped
+ */
+
+ dev16 = 0;
+ if ((devif == FLASH_CFI_DEVIF_X16) || (devif == FLASH_CFI_DEVIF_X8X16)) dev16 = 1;
+
+ regcnt = GETCFIBYTE(cfidata,FLASH_CFI_REGION_COUNT);
+
+ softc->fd_probe.flash_nsectors = regcnt;
+
+#if 1
+ /*
+ * Hiss! Some AMD top-boot flash parts have broken CFI tables - they are backwards!
+ * Do some extra probing to find it.
+ */
+
+ if (cmdset == FLASH_CFI_CMDSET_AMD_STD) {
+ idx = FEOP_AMD_DEVCODE8;
+ if (softc->fd_probe.flash_flags & FLASH_FLG_DEV16) {
+ idx = (softc->fd_probe.flash_flags & FLASH_FLG_BUS16) ?
+ FEOP_AMD_DEVCODE16 : FEOP_AMD_DEVCODE16B;
+ }
+
+ flash_op_begin(softc);
+ flash_op_add(softc,softc->fd_probe.flash_phys,
+ idx,(long)&insaner,0,0);
+ flash_op_execute(softc);
+#ifdef _NEWFLASH_DEBUG_
+ xprintf("Insaner = 0x%x\n", insaner);
+#endif /* _NEWFLASH_DEBUG_ */
+ if(((insaner & 0xFF) == 0xC4)||((insaner & 0xFF) == 0xF6)){
+ insane = 1;
+#ifdef _NEWFLASH_DEBUG_
+ xprintf("Warning: insane AMD part, backwards CFI table!\n");
+#endif /* _NEWFLASH_DEBUG_ */
+ }
+ }
+#else
+ insane = insaner = 1;
+#endif /* 0 */
+
+
+ for (idx = 0; idx < regcnt; idx++) {
+ nblks = ((int)GETCFIBYTE(cfidata,FLASH_CFI_REGION_TABLE+0+idx*4) +
+ (int)(GETCFIBYTE(cfidata,FLASH_CFI_REGION_TABLE+1+idx*4)<<8)) + 1;
+ blksiz = ((int)GETCFIBYTE(cfidata,FLASH_CFI_REGION_TABLE+2+idx*4) +
+ (int)(GETCFIBYTE(cfidata,FLASH_CFI_REGION_TABLE+3+idx*4)<<8)) * 256;
+
+ if (insane) {
+ /* Insane */
+ softc->fd_probe.flash_sectors[((regcnt-1)-idx)] =
+ FLASH_SECTOR_RANGE(nblks,blksiz);
+ }
+ else {
+ /* Sane */
+ softc->fd_probe.flash_sectors[idx] =
+ FLASH_SECTOR_RANGE(nblks,blksiz);
+ }
+ }
+
+ /*
+ * Set the command set we're going to use.
+ */
+
+ flash_set_cmdset(softc,cmdset,bus16,dev16);
+
+ return 0;
+
+}
+
+
+
+/* *********************************************************************
+ * FLASH_DO_PROBE(softc)
+ *
+ * Probe to see if we're ROM or RAM. If ROM, see if we're flash.
+ * If flash, do CFI query.
+ *
+ * Input parameters:
+ * softc - our structure
+ *
+ * Return value:
+ * FLASH_TYPE_xxx
+ ********************************************************************* */
+static int flash_do_probe(flashdev_t *softc)
+{
+ uint8_t test_byte0,test_byte1;
+ uint8_t save0,save1;
+ volatile uint8_t *ptr;
+
+ /*
+ * flash_do_probe is called before we open the device, so we
+ * need to allocate space for instructions so the flashop
+ * engine will work.
+ */
+
+ softc->fd_inst = KMALLOC(FLASH_MAX_INST*sizeof(flashinstr_t),0);
+ if (!softc->fd_inst) return FLASH_TYPE_ROM;
+
+ /*
+ * Attempt to read/write byte zero. If it is changable,
+ * this is SRAM (or maybe a ROM emulator with the write line hooked up)
+ */
+
+ ptr = (volatile uint8_t *) UNCADDR(softc->fd_probe.flash_phys);
+ save0 = *ptr; /* save old value */
+ save1 = *(ptr+1); /* save old value */
+
+ test_byte0 = (save0 != 0x88) ? 0x88 : 0x89;
+ test_byte1 = (save1 != 0x99) ? 0x99 : 0x91;
+
+ *(ptr) = test_byte0;
+ *(ptr+1) = test_byte1;
+
+ if ((*ptr == test_byte0) && (*(ptr+1) == test_byte1)) {
+ softc->fd_probe.flash_type = FLASH_TYPE_SRAM;
+
+ /*Only write back saved values if it's RAM*/
+ *(ptr) = save0;
+ *(ptr+1) = save1;
+
+#ifdef _NEWFLASH_DEBUG_
+ xprintf("Flash type SRAM\n");
+#endif
+
+ }
+ else {
+ softc->fd_probe.flash_type = FLASH_TYPE_ROM;
+
+#ifdef _NEWFLASH_DEBUG_
+ xprintf("Flash type ROM\n");
+#endif
+
+ }
+
+ /*
+ * If we thought it was ROM, try doing a CFI query
+ * to see if it was flash. This check is kind of kludgey
+ * but should work.
+ */
+
+ if (softc->fd_probe.flash_type == FLASH_TYPE_ROM) {
+ flash_cfi_probe(softc);
+ }
+
+
+ KFREE(softc->fd_inst);
+ softc->fd_inst = NULL;
+
+ return softc->fd_probe.flash_type;
+}
+
+#endif /* (FLASH_DRIVERS & FLASH_DRIVER_CFI) */
+
+
+/* *********************************************************************
+ * flash_do_parts(probe,parts)
+ *
+ * Partition the flash into the sizes specified. We use
+ * the sizes in the table to generate a table of {offset,size}
+ * pairs that eventually become partitions.
+ *
+ * The only thing magical about this is that size "0" means
+ * "fill to max" and that partitions beyond the "0" are aligned
+ * to the top of the flash. Therefore, if you had a 4MB
+ * flash and listed four partitions, 512K, 0, 512K, 512K,
+ * then there would be a 2.5M partition in the middle and two
+ * 512K partitions at the top.
+ *
+ * Input parameters:
+ * probe - flash probe data (user-supplied table)
+ * parts - our partition table (output)
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void flash_do_parts(flashdev_t *softc)
+{
+ int idx;
+ int middlepart = -1;
+ int lobound = 0;
+ newflash_probe_t *probe = &(softc->fd_probe);
+ flashpart_t *parts = &(softc->fd_parts[0]);
+ int hibound = probe->flash_size*probe->flash_nchips;
+
+ for (idx = 0; idx < probe->flash_nparts; idx++) {
+ if (probe->flash_parts[idx].fp_size == 0) {
+ middlepart = idx;
+ break;
+ }
+ parts[idx].fp_offset = lobound;
+ parts[idx].fp_size = probe->flash_parts[idx].fp_size;
+ lobound += probe->flash_parts[idx].fp_size;
+ }
+
+ if (idx != probe->flash_nparts) {
+ for (idx = probe->flash_nparts - 1; idx > middlepart;
+ idx--) {
+ parts[idx].fp_size = probe->flash_parts[idx].fp_size;
+ hibound -= probe->flash_parts[idx].fp_size;
+ parts[idx].fp_offset = hibound;
+ }
+ }
+
+ if (middlepart != -1) {
+ parts[middlepart].fp_offset = lobound;
+ parts[middlepart].fp_size = hibound - lobound;
+ }
+
+#ifdef _NEWFLASH_DEBUG_
+ printf("Partition information:\n");
+ for (idx = 0; idx < probe->flash_nparts;idx++) {
+ printf("#%02d %08X -> %08X (%d)\n",idx,
+ parts[idx].fp_offset,parts[idx].fp_offset+parts[idx].fp_size-1,
+ parts[idx].fp_size);
+ }
+#endif
+}
+
+
+/* *********************************************************************
+ * flashdrv_allocbuf(dev)
+ *
+ * Allocate sector buffer for flash programming. Use a global
+ * buffer for all devices.
+ *
+ * Input parameters:
+ * dev - our device
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void flashdrv_allocbuf(flashdev_t *softc)
+{
+ if (!flash_sector_buffer) {
+#if CFG_FLASH_ALLOC_SECTOR_BUFFER
+ flash_sector_buffer = KMALLOC(CFG_FLASH_SECTOR_BUFFER_SIZE,0);
+ if (!flash_sector_buffer) {
+ printf("FLASH: Could not allocate sector buffer, using default\n");
+ flash_sector_buffer = (uint8_t *) KERNADDR(CFG_FLASH_SECTOR_BUFFER_SIZE);
+ }
+#else
+ flash_sector_buffer = (uint8_t *) KERNADDR(CFG_FLASH_SECTOR_BUFFER_ADDR);
+#endif
+ }
+
+ softc->fd_sectorbuffer = flash_sector_buffer;
+}
+
+/* *********************************************************************
+ * flashdrv_probe(drv,probe_a,probe_b,probe_ptr)
+ *
+ * Device probe routine. Attach the flash device to
+ * CFE's device table.
+ *
+ * Input parameters:
+ * drv - driver descriptor
+ * probe_a - physical address of flash
+ * probe_b - size of flash (bytes)
+ * probe_ptr - unused
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void flashdrv_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ flashdev_t *softc;
+ newflash_probe_t *probe;
+ int idx;
+ char descr[80];
+ static int flashidx = 0;
+ char *x;
+
+ /*
+ * First thing to do is configure the flashop engine
+ * if not already done. Basically we copy a bit of
+ * position-independent code into the DRAM.
+ */
+
+ flash_setup_engine();
+
+ /*
+ * Now, on with the probing.
+ */
+
+ probe = (newflash_probe_t *) probe_ptr;
+
+ /*
+ * probe_a is the flash base address
+ * probe_b is the size of the flash
+ * probe_ptr is unused.
+ */
+
+ softc = (flashdev_t *) KMALLOC(sizeof(flashdev_t),0);
+ if (softc) {
+ memset(softc,0,sizeof(flashdev_t));
+
+ flashdrv_allocbuf(softc);
+
+ if (probe) {
+ /*
+ * Passed probe structure, do fancy stuff
+ */
+ memcpy(&(softc->fd_probe),probe,sizeof(newflash_probe_t));
+ if (softc->fd_probe.flash_nchips == 0) {
+ softc->fd_probe.flash_nchips = 1;
+ }
+ }
+ else {
+ /* Didn't pass probe structure, do the compatible thing */
+ softc->fd_probe.flash_phys = probe_a;
+ softc->fd_probe.flash_size = (probe_b & FLASH_SIZE_MASK);
+ softc->fd_probe.flash_flags = (probe_b & FLASH_FLG_MASK);
+ softc->fd_probe.flash_nchips = 1;
+ }
+
+ if (softc->fd_probe.flash_flags & FLASH_FLG_MANUAL) {
+ /* Manual probing, just set the command set. */
+ flash_set_cmdset(softc,softc->fd_probe.flash_cmdset,
+ ((softc->fd_probe.flash_flags & FLASH_FLG_BUS16) ? 1 : 0),
+ ((softc->fd_probe.flash_flags & FLASH_FLG_DEV16) ? 1 : 0));
+ }
+ else {
+ /* Do automatic probing */
+#if (FLASH_DRIVERS & FLASH_DRIVER_CFI)
+ flash_do_probe(softc);
+#else
+ return; /* No automatic probing, bail! */
+#endif
+ }
+
+ /* Remember total size of all devices */
+ softc->fd_ttlsize = softc->fd_probe.flash_nchips * softc->fd_probe.flash_size;
+
+ /* Set description */
+ x = descr;
+ x += xsprintf(x,"%s at %08X size %uKB",drv->drv_description,
+ softc->fd_probe.flash_phys,
+ softc->fd_ttlsize/1024);
+ if (softc->fd_probe.flash_nchips > 1) {
+ xsprintf(x," (%d chips)",softc->fd_probe.flash_nchips);
+ }
+
+ /*
+ * If flash is not partitioned, just instantiate one
+ * device. Otherwise, instantiate multiple flashes
+ * to cover the entire device.
+ */
+
+ if (softc->fd_probe.flash_nparts == 0) {
+ softc->fd_parts[0].fp_dev = softc;
+ softc->fd_parts[0].fp_offset = 0;
+ softc->fd_parts[0].fp_size = softc->fd_probe.flash_size;
+ cfe_attach(drv,&(softc->fd_parts[0]),NULL,descr);
+ }
+ else {
+ /*
+ * Partition flash into chunks
+ */
+ flash_do_parts(softc);
+
+ /*
+ * Instantiate devices for each piece
+ */
+
+ for (idx = 0; idx < softc->fd_probe.flash_nparts; idx++) {
+ char name[32];
+ char *nptr;
+
+ xsprintf(descr,"%s at %08X offset %08X size %uKB",
+ drv->drv_description,
+ softc->fd_probe.flash_phys,
+ softc->fd_parts[idx].fp_offset,
+ (softc->fd_parts[idx].fp_size+1023)/1024);
+
+ softc->fd_parts[idx].fp_dev = softc;
+ if (softc->fd_probe.flash_parts[idx].fp_name == NULL) {
+ sprintf(name,"%d",idx);
+ nptr = name;
+ }
+ else {
+ nptr = softc->fd_probe.flash_parts[idx].fp_name;
+ }
+ cfe_attach_idx(drv,
+ flashidx,
+ &(softc->fd_parts[idx]),
+ nptr,
+ descr);
+ }
+ }
+
+ flashidx++;
+
+ /* Count total sectors on the device */
+
+ softc->fd_ttlsect = 0;
+ for (idx = 0; idx < softc->fd_probe.flash_nsectors; idx++) {
+ softc->fd_ttlsect += FLASH_SECTOR_NBLKS(softc->fd_probe.flash_sectors[idx]);
+ }
+
+ }
+
+}
+
+
+/* *********************************************************************
+ * flashdrv_open(ctx)
+ *
+ * Called when the flash device is opened.
+ *
+ * Input parameters:
+ * ctx - device context
+ *
+ * Return value:
+ * 0 if ok else error code
+ ********************************************************************* */
+
+static int flashdrv_open(cfe_devctx_t *ctx)
+{
+ flashpart_t *part = ctx->dev_softc;
+ flashdev_t *softc = part->fp_dev;
+ int ttlsect = softc->fd_ttlsect;
+
+ /*
+ * Calculate number of flashop instructions we'll need at most.
+ * This will be two for each sector plus two more for the first
+ * and last sectors, plus two extra
+ */
+
+ ttlsect = (ttlsect * 2 * softc->fd_probe.flash_nchips) + 6;
+
+ /*
+ * Allocate memory for instructions.
+ */
+
+#ifdef _NEWFLASH_DEBUG_
+ printf("%s: allocating %d instructions\n",cfe_device_name(ctx),ttlsect);
+#endif
+
+ softc->fd_inst = KMALLOC(ttlsect*sizeof(flashinstr_t),0);
+ if (!softc->fd_inst) return CFE_ERR_NOMEM;
+
+ return 0;
+}
+
+
+/* *********************************************************************
+ * flashdrv_read(ctx,buffer)
+ *
+ * Read data from the flash device. The flash device is
+ * considered to be like a disk (you need to specify the offset).
+ *
+ * Input parameters:
+ * ctx - device context
+ * buffer - buffer descriptor
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+static int flashdrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ flashpart_t *part = ctx->dev_softc;
+ flashdev_t *softc = part->fp_dev;
+ int blen;
+ int offset;
+
+ blen = buffer->buf_length;
+ offset = (long)buffer->buf_offset;
+
+ if ((offset + blen) > part->fp_size) {
+ blen = part->fp_size - offset;
+ }
+
+ offset += part->fp_offset;
+
+ if (blen > 0) {
+ flash_op_begin(softc);
+ flash_op_add(softc,softc->fd_probe.flash_phys,
+ softc->fd_readfunc,(long)buffer->buf_ptr,offset,blen);
+ flash_op_execute(softc);
+ }
+
+ buffer->buf_retlen = blen;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * flashdrv_inpstat(ctx,inpstat)
+ *
+ * Return "input status". For flash devices, we always return true.
+ *
+ * Input parameters:
+ * ctx - device context
+ * inpstat - input status structure
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+static int flashdrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
+{
+ inpstat->inp_status = 1;
+ return 0;
+}
+
+
+/* *********************************************************************
+ * flashdrv_write(ctx,buffer)
+ *
+ * Write data to the flash device. The flash device is
+ * considered to be like a disk (you need to specify the offset).
+ *
+ * Input parameters:
+ * ctx - device context
+ * buffer - buffer descriptor
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+
+static int flashdrv_write2(cfe_devctx_t *ctx,iocb_buffer_t *buffer,int reboot)
+{
+ flashpart_t *part = ctx->dev_softc;
+ flashdev_t *softc = part->fp_dev;
+ int blen;
+ int res;
+ int offset;
+ int whichchip;
+ long chipbase;
+ flash_range_t outrange;
+ flash_range_t inrange;
+ flash_sector_t sector;
+
+ blen = buffer->buf_length;
+ offset = (long)buffer->buf_offset;
+
+ /* Compute range within physical flash */
+
+ if ((offset + blen) > part->fp_size) {
+ blen = part->fp_size - offset;
+ }
+
+ offset += part->fp_offset;
+
+ /* Handle case of writing nothing */
+
+ if (blen == 0) {
+ buffer->buf_retlen = blen;
+ return (buffer->buf_length == blen) ? 0 : CFE_ERR_IOERR;
+ }
+
+ /* now, offset/blen forms the range we want to write to. */
+
+ inrange.range_base = offset;
+ inrange.range_length = blen;
+
+ sector.flash_sector_idx = 0;
+
+ flash_op_begin(softc);
+
+ for (;;) {
+ res = flash_sector_query(softc,&sector);
+ if (res != 0) break;
+ if (sector.flash_sector_status == FLASH_SECTOR_INVALID) {
+ break;
+ }
+
+ whichchip = sector.flash_sector_idx / softc->fd_ttlsect;
+ chipbase = softc->fd_probe.flash_phys +
+ (long) (whichchip * softc->fd_probe.flash_size);
+
+ res = flash_range_intersection(&sector,&inrange,&outrange);
+
+ switch (res) {
+ case 1: /* Erease/program entire sector */
+ flash_op_add(softc,chipbase,
+ softc->fd_erasefunc,
+ sector.flash_sector_offset,
+ 0,0);
+ flash_op_add(softc,chipbase,
+ softc->fd_pgmfunc,
+ outrange.range_base,
+ ((long)buffer->buf_ptr)+(outrange.range_base-inrange.range_base),
+ outrange.range_length);
+ break;
+
+ case 0: /* Erase/reprogram partial sector */
+ /* Save old sector */
+ flash_op_add(softc,chipbase,
+ softc->fd_readfunc,
+ (long)(softc->fd_sectorbuffer),
+ sector.flash_sector_offset,
+ sector.flash_sector_size);
+ /* Copy in new stuff */
+ flash_op_add(softc,chipbase,
+ FEOP_MEMCPY,
+ ((long)(softc->fd_sectorbuffer))+(outrange.range_base-sector.flash_sector_offset),
+ ((long)buffer->buf_ptr)+(outrange.range_base-inrange.range_base),
+ outrange.range_length);
+ /* Erase sector */
+ flash_op_add(softc,chipbase,
+ softc->fd_erasefunc,
+ sector.flash_sector_offset,
+ 0,0);
+ /* Program sector */
+ flash_op_add(softc,chipbase,
+ softc->fd_pgmfunc,
+ sector.flash_sector_offset,
+ (long)(softc->fd_sectorbuffer),
+ sector.flash_sector_size);
+ break;
+
+ case -1: /* No intersection */
+ break;
+ }
+
+ sector.flash_sector_idx++;
+
+ }
+
+ if (reboot) {
+ flash_op_add(softc,softc->fd_probe.flash_phys,FEOP_REBOOT,0,0,0);
+ }
+
+ res = flash_op_execute(softc);
+
+ buffer->buf_retlen = blen;
+
+ return (res == 0) ? 0 : CFE_ERR_IOERR;
+}
+
+static int flashdrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ return flashdrv_write2(ctx,buffer,0);
+}
+
+
+/* *********************************************************************
+ * flashdrv_ioctl(ctx,buffer)
+ *
+ * Handle special IOCTL functions for the flash. Flash devices
+ * support NVRAM information, sector and chip erase, and a
+ * special IOCTL for updating the running copy of CFE.
+ *
+ * Input parameters:
+ * ctx - device context
+ * buffer - descriptor for IOCTL parameters
+ *
+ * Return value:
+ * 0 if ok else error
+ ********************************************************************* */
+static int flashdrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ flashpart_t *part = ctx->dev_softc;
+ flashdev_t *softc = part->fp_dev;
+ nvram_info_t *nvinfo;
+ flash_info_t *info;
+ flash_range_t range;
+ int offset;
+
+ switch ((int)buffer->buf_ioctlcmd) {
+ case IOCTL_NVRAM_GETINFO:
+ /*
+ * We only support NVRAM on flashes that have been partitioned
+ * into at least two partitions. Every partition supports
+ * being an NVRAM in that case, but we'll only attach one
+ * of them to the environment subsystem.
+ */
+ if (softc->fd_probe.flash_nparts <= 1) {
+ return CFE_ERR_UNSUPPORTED;
+ }
+ nvinfo = (nvram_info_t *) buffer->buf_ptr;
+ if (buffer->buf_length != sizeof(nvram_info_t)) return CFE_ERR_INV_PARAM;
+
+ nvinfo->nvram_offset = 0;
+ nvinfo->nvram_size = part->fp_size;
+ nvinfo->nvram_eraseflg = 1;
+ buffer->buf_retlen = sizeof(nvram_info_t);
+ return 0;
+ break;
+
+ case IOCTL_FLASH_ERASE_SECTOR:
+ offset = (int) buffer->buf_offset;
+ offset += part->fp_offset;
+ if (offset >= softc->fd_probe.flash_size) return -1;
+
+ flash_op_begin(softc);
+ flash_op_add(softc,
+ softc->fd_probe.flash_phys,
+ softc->fd_erasefunc,
+ offset,
+ 0,0);
+ flash_op_execute(softc);
+ return 0;
+
+ case IOCTL_FLASH_ERASE_ALL:
+ offset = (int) buffer->buf_offset;
+ if (offset != 0) return -1;
+ flash_erase_all(softc);
+ return 0;
+
+ case IOCTL_FLASH_WRITE_ALL:
+ /* Write file and reboot */
+ flashdrv_write2(ctx,buffer,1);
+ return -1; /* should not return */
+
+ case IOCTL_FLASH_GETINFO:
+ info = (flash_info_t *) buffer->buf_ptr;
+ info->flash_base = softc->fd_probe.flash_phys;
+ info->flash_size = softc->fd_probe.flash_size;
+ info->flash_type = softc->fd_probe.flash_type;
+ info->flash_flags = FLASH_FLAG_NOERASE;
+ return 0;
+
+ case IOCTL_FLASH_GETSECTORS:
+ return flash_sector_query(softc,(flash_sector_t *) buffer->buf_ptr);
+
+ case IOCTL_FLASH_ERASE_RANGE:
+ memcpy(&range,buffer->buf_ptr,sizeof(flash_range_t));
+ range.range_base += part->fp_offset;
+ if (range.range_length > part->fp_size) {
+ range.range_length = part->fp_size;
+ }
+ return flash_erase_range(softc,&range);
+
+ default:
+ /* Call hook if present. */
+ if (softc->fd_probe.flash_ioctl_hook) {
+ return (*(softc->fd_probe.flash_ioctl_hook))(ctx,buffer);
+ }
+ return -1;
+ }
+
+ return -1;
+}
+
+
+/* *********************************************************************
+ * flashdrv_close(ctx)
+ *
+ * Close the flash device.
+ *
+ * Input parameters:
+ * ctx - device context
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+static int flashdrv_close(cfe_devctx_t *ctx)
+{
+ flashpart_t *part = ctx->dev_softc;
+ flashdev_t *softc = part->fp_dev;
+
+ if (softc->fd_inst) {
+ KFREE(softc->fd_inst);
+ }
+
+ softc->fd_inst = NULL;
+
+ /* XXX Invalidate the cache ?!?! */
+
+ return 0;
+}
+
+
diff --git a/cfe/cfe/dev/dev_ns16550.c b/cfe/cfe/dev/dev_ns16550.c
new file mode 100644
index 0000000..a70eecf
--- /dev/null
+++ b/cfe/cfe/dev/dev_ns16550.c
@@ -0,0 +1,255 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * NS16550 UART driver File: dev_ns16550.c
+ *
+ * This is a console device driver for an NS16550 UART, either
+ * on-board or as a PCI-device. In the case of a PCI device,
+ * our probe routine is called from the PCI probe code
+ * over in dev_ns16550_pci.c
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include "lib_types.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "cfe_ioctl.h"
+
+#include "lib_physio.h"
+
+#include "bsp_config.h"
+
+#include "ns16550.h"
+
+#define WRITECSR(p,v) phys_write8((p),(v))
+#define READCSR(p) phys_read8((p))
+
+static int ns16550_uart_open(cfe_devctx_t *ctx);
+static int ns16550_uart_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int ns16550_uart_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
+static int ns16550_uart_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int ns16550_uart_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int ns16550_uart_close(cfe_devctx_t *ctx);
+
+void ns16550_uart_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+
+const cfe_devdisp_t ns16550_uart_dispatch = {
+ ns16550_uart_open,
+ ns16550_uart_read,
+ ns16550_uart_inpstat,
+ ns16550_uart_write,
+ ns16550_uart_ioctl,
+ ns16550_uart_close,
+ NULL,
+ NULL
+};
+
+const cfe_driver_t ns16550_uart = {
+ "NS16550 UART",
+ "uart",
+ CFE_DEV_SERIAL,
+ &ns16550_uart_dispatch,
+ ns16550_uart_probe
+};
+
+typedef struct ns16550_uart_s {
+ physaddr_t uart_base;
+ int uart_flowcontrol;
+ int uart_speed;
+} ns16550_uart_t;
+
+
+/*
+ * NS16550-compatible UART.
+ * probe_a: physical address of UART
+ */
+
+void ns16550_uart_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ ns16550_uart_t *softc;
+ char descr[80];
+
+ softc = (ns16550_uart_t *) KMALLOC(sizeof(ns16550_uart_t),0);
+ if (softc) {
+ softc->uart_base = probe_a;
+ softc->uart_speed = CFG_SERIAL_BAUD_RATE;
+ softc->uart_flowcontrol = SERIAL_FLOW_NONE;
+ xsprintf(descr, "%s at 0x%X", drv->drv_description, (uint32_t)probe_a);
+
+ cfe_attach(drv, softc, NULL, descr);
+ }
+}
+
+#define DELAY(n) delay(n)
+extern int32_t _getticks(void);
+static void delay(int ticks)
+{
+ int32_t t;
+
+ t = _getticks() + ticks;
+ while (_getticks() < t)
+ ; /* NULL LOOP */
+}
+
+static void ns16550_uart_setflow(ns16550_uart_t *softc)
+{
+ /* noop for now */
+}
+
+
+static int ns16550_uart_open(cfe_devctx_t *ctx)
+{
+ ns16550_uart_t *softc = ctx->dev_softc;
+ int baudrate = CFG_SERIAL_BAUD_RATE;
+ unsigned int brtc;
+
+ brtc = BRTC(baudrate);
+
+ WRITECSR(softc->uart_base+R_UART_CFCR,CFCR_DLAB);
+ WRITECSR(softc->uart_base+R_UART_DATA,brtc & 0xFF);
+ WRITECSR(softc->uart_base+R_UART_IER,brtc>>8);
+ WRITECSR(softc->uart_base+R_UART_CFCR,CFCR_8BITS);
+ WRITECSR(softc->uart_base+R_UART_MCR,MCR_DTR | MCR_RTS | MCR_IENABLE);
+ WRITECSR(softc->uart_base+R_UART_IER,0);
+
+ WRITECSR(softc->uart_base+R_UART_FIFO,FIFO_ENABLE);
+ DELAY(100);
+ WRITECSR(softc->uart_base+R_UART_FIFO,
+ FIFO_ENABLE | FIFO_RCV_RST | FIFO_XMT_RST | FIFO_TRIGGER_1);
+ DELAY(100);
+
+ if ((READCSR(softc->uart_base+R_UART_IIR) & IIR_FIFO_MASK) != IIR_FIFO_MASK) {
+ WRITECSR(softc->uart_base+R_UART_FIFO,0);
+ }
+ ns16550_uart_setflow(softc);
+
+ return 0;
+}
+
+static int ns16550_uart_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ ns16550_uart_t *softc = ctx->dev_softc;
+ unsigned char *bptr;
+ int blen;
+
+ bptr = buffer->buf_ptr;
+ blen = buffer->buf_length;
+
+ while ((blen > 0) && (READCSR(softc->uart_base+R_UART_LSR) & LSR_RXRDY)) {
+ *bptr++ = (READCSR(softc->uart_base+R_UART_DATA) & 0xFF);
+ blen--;
+ }
+
+ buffer->buf_retlen = buffer->buf_length - blen;
+ return 0;
+}
+
+static int ns16550_uart_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat)
+{
+ ns16550_uart_t *softc = ctx->dev_softc;
+
+ inpstat->inp_status = (READCSR(softc->uart_base+R_UART_LSR) & LSR_RXRDY) ? 1 : 0;
+
+ return 0;
+}
+
+static int ns16550_uart_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ ns16550_uart_t *softc = ctx->dev_softc;
+ unsigned char *bptr;
+ int blen;
+
+ bptr = buffer->buf_ptr;
+ blen = buffer->buf_length;
+ while ((blen > 0) && (READCSR(softc->uart_base+R_UART_LSR) & LSR_TXRDY)) {
+ WRITECSR(softc->uart_base+R_UART_DATA, *bptr++);
+ blen--;
+ }
+
+ buffer->buf_retlen = buffer->buf_length - blen;
+ return 0;
+}
+
+static int ns16550_uart_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ ns16550_uart_t *softc = ctx->dev_softc;
+
+ unsigned int *info = (unsigned int *) buffer->buf_ptr;
+
+ switch ((int)buffer->buf_ioctlcmd) {
+ case IOCTL_SERIAL_GETSPEED:
+ *info = softc->uart_speed;
+ break;
+ case IOCTL_SERIAL_SETSPEED:
+ softc->uart_speed = *info;
+ /* NYI */
+ break;
+ case IOCTL_SERIAL_GETFLOW:
+ *info = softc->uart_flowcontrol;
+ break;
+ case IOCTL_SERIAL_SETFLOW:
+ softc->uart_flowcontrol = *info;
+ ns16550_uart_setflow(softc);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ns16550_uart_close(cfe_devctx_t *ctx)
+{
+ ns16550_uart_t *softc = ctx->dev_softc;
+
+ WRITECSR(softc->uart_base+R_UART_MCR,0);
+
+ return 0;
+}
+
+
diff --git a/cfe/cfe/dev/dev_ns16550_pci.c b/cfe/cfe/dev/dev_ns16550_pci.c
new file mode 100644
index 0000000..021f34c
--- /dev/null
+++ b/cfe/cfe/dev/dev_ns16550_pci.c
@@ -0,0 +1,114 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * NS16550 UART driver (PCI) File: dev_ns16550_pci.c
+ *
+ * This is a console device driver for a PCI NS16550 UART
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#include "lib_types.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "cfe_ioctl.h"
+
+#include "pcivar.h"
+#include "pcireg.h"
+
+
+/* Probe routine for real UART driver */
+extern void ns16550_uart_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+/* Probe routine for this UART driver. */
+static void ns16550pci_uart_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+/* We just glom onto the dispatch table in the real driver */
+extern const cfe_devdisp_t ns16550_uart_dispatch;
+
+const cfe_driver_t ns16550pci_uart = {
+ "PCI NS16550 UART",
+ "uart",
+ CFE_DEV_SERIAL,
+ &ns16550_uart_dispatch,
+ ns16550pci_uart_probe
+};
+
+
+static void ns16550pci_uart_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ phys_addr_t pa;
+ pcitag_t tag;
+ int index = 0;
+
+ /*
+ * NS16550-compatible UART on the PCI bus
+ * probe_a, probe_b and probe_ptr are unused.
+ */
+
+ /*
+ * This is for a SIIG card. Should probably do a little
+ * vendor ID table like we did for the IDE driver so
+ * we can spport other cards.
+ */
+
+ for (;;) {
+
+ if (pci_find_device(0x131f,0x2000,index,&tag) != 0) {
+ break;
+ }
+
+ pci_map_io(tag, PCI_MAPREG(0), PCI_MATCH_BYTES, &pa);
+ xprintf("NS16550PCI: I/O mapped registers start at %08X", (uint32_t)pa);
+
+ ns16550_uart_probe(drv,pa,0,NULL);
+
+ index++;
+ }
+}
+
diff --git a/cfe/cfe/dev/dev_null.c b/cfe/cfe/dev/dev_null.c
new file mode 100644
index 0000000..d995919
--- /dev/null
+++ b/cfe/cfe/dev/dev_null.c
@@ -0,0 +1,142 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * Null console device File: dev_null.c
+ *
+ * This is a null console device, useful for console-less
+ * operation, or when using chip simulators.
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+
+#include "lib_types.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+
+static void nulldrv_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+
+static int nulldrv_open(cfe_devctx_t *ctx);
+static int nulldrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int nulldrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
+static int nulldrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int nulldrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int nulldrv_close(cfe_devctx_t *ctx);
+
+const static cfe_devdisp_t nulldrv_dispatch = {
+ nulldrv_open,
+ nulldrv_read,
+ nulldrv_inpstat,
+ nulldrv_write,
+ nulldrv_ioctl,
+ nulldrv_close,
+ NULL,
+ NULL
+};
+
+const cfe_driver_t nulldrv = {
+ "Null console device",
+ "null",
+ CFE_DEV_SERIAL,
+ &nulldrv_dispatch,
+ nulldrv_probe
+};
+
+
+static void nulldrv_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ cfe_attach(drv,NULL,NULL,drv->drv_description);
+}
+
+
+static int nulldrv_open(cfe_devctx_t *ctx)
+{
+/* nulldrv_t *softc = ctx->dev_softc; */
+
+ return 0;
+}
+
+static int nulldrv_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+/* nulldrv_t *softc = ctx->dev_softc; */
+
+ buffer->buf_retlen = buffer->buf_length;
+ return 0;
+}
+
+static int nulldrv_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
+{
+/* nulldrv_t *softc = ctx->dev_softc; */
+
+ inpstat->inp_status = 0;
+
+ return 0;
+}
+
+static int nulldrv_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+/* nulldrv_t *softc = ctx->dev_softc; */
+
+ buffer->buf_retlen = buffer->buf_length;
+ return 0;
+}
+
+static int nulldrv_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+/* nulldrv_t *softc = ctx->dev_softc;*/
+
+ return -1;
+}
+
+static int nulldrv_close(cfe_devctx_t *ctx)
+{
+/* nulldrv_t *softc = ctx->dev_softc; */
+
+ return 0;
+}
+
+
diff --git a/cfe/cfe/dev/dev_promice.c b/cfe/cfe/dev/dev_promice.c
new file mode 100644
index 0000000..fe79086
--- /dev/null
+++ b/cfe/cfe/dev/dev_promice.c
@@ -0,0 +1,402 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * PromICE console device File: dev_promice.c
+ *
+ * This device driver supports Grammar Engine's PromICE AI2
+ * serial communications options. With this console, you can
+ * communicate with the firmware using only uncached reads in the
+ * boot ROM space. See Grammar Engine's PromICE manuals
+ * for more information at http://www.gei.com
+ *
+ * Author: Mitch Lichtenberg (mpl@broadcom.com)
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+/*
+ * Example PromICE initialization file:
+ *
+ * -----------------------
+ * output=com1
+ * pponly=lpt1
+ * rom=27040
+ * word=8
+ * file=cfe.srec
+ * ailoc 7FC00,9600
+ * -----------------------
+ *
+ * The offset specified in the 'ailoc' line must be the location where you
+ * will configure the AI2 serial port. In this example, the ROM is assumed
+ * to be 512KB, and the AI2 serial port is at 511KB, or offset 0x7FC00.
+ * This area is filled with 0xCC to detect AI2's initialization sequence
+ * properly (see the PromICE manual). You should connect your
+ * PromICE's serial port up to the PC and run a terminal emulator on it.
+ * The parallel port will be used for downloading data to the PromICE.
+ *
+ * If you have connected the write line to the PromICE, then you can
+ * define the _AIDIRT_ symbol to increase performance.
+ */
+
+
+
+#include "lib_types.h"
+#include "lib_malloc.h"
+#include "lib_printf.h"
+#include "lib_string.h"
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "addrspace.h"
+
+#define _AIDIRT_
+
+/* *********************************************************************
+ * Prototypes
+ ********************************************************************* */
+
+static void promice_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+
+static int promice_open(cfe_devctx_t *ctx);
+static int promice_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int promice_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
+static int promice_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int promice_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int promice_close(cfe_devctx_t *ctx);
+
+/* *********************************************************************
+ * Device dispatch table
+ ********************************************************************* */
+
+const static cfe_devdisp_t promice_dispatch = {
+ promice_open,
+ promice_read,
+ promice_inpstat,
+ promice_write,
+ promice_ioctl,
+ promice_close,
+ NULL,
+ NULL
+};
+
+/* *********************************************************************
+ * Device descriptor
+ ********************************************************************* */
+
+const cfe_driver_t promice_uart = {
+ "PromICE AI2 Serial Port",
+ "promice",
+ CFE_DEV_SERIAL,
+ &promice_dispatch,
+ promice_probe
+};
+
+/* *********************************************************************
+ * Local constants and structures
+ ********************************************************************* */
+
+/*
+ * If your PromICE is connected to a 32-bit host (emulating four
+ * flash ROMs) and the SB1250 is set to boot from that host, define
+ * the PROMICE_32BITS symbol to make sure the AI2 interface is
+ * configured correctly.
+ */
+
+/*#define PROMICE_32BITS*/
+
+#ifdef PROMICE_32BITS
+#define WORDSIZE 4
+#define WORDTYPE uint32_t
+#else
+#define WORDSIZE 1
+#define WORDTYPE uint8_t
+#endif
+
+
+#define ZERO_OFFSET (0)
+#define ONE_OFFSET (1)
+#define DATA_OFFSET (2)
+#define STATUS_OFFSET (3)
+
+#define TDA 0x01 /* Target data available */
+#define HDA 0x02 /* Host data available */
+#define OVR 0x04 /* Host data overflow */
+
+typedef struct promice_s {
+ unsigned long ai2_addr;
+ unsigned int ai2_wordsize;
+ volatile WORDTYPE *zero;
+ volatile WORDTYPE *one;
+ volatile WORDTYPE *data;
+ volatile WORDTYPE *status;
+} promice_t;
+
+
+/* *********************************************************************
+ * promice_probe(drv,probe_a,probe_b,probe_ptr)
+ *
+ * Device "Probe" routine. This routine creates the soft
+ * context for the device and calls the attach routine.
+ *
+ * Input parameters:
+ * drv - driver structure
+ * probe_a,probe_b,probe_ptr - probe args
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+
+static void promice_probe(cfe_driver_t *drv,
+ unsigned long probe_a,
+ unsigned long probe_b,
+ void *probe_ptr)
+{
+ promice_t *softc;
+ char descr[80];
+
+ /*
+ * probe_a is the address in the ROM of the AI2 interface
+ * on the PromICE.
+ * probe_b is the word size (1,2,4)
+ */
+
+ softc = (promice_t *) KMALLOC(sizeof(promice_t),0);
+ if (softc) {
+ softc->ai2_addr = probe_a;
+ if (probe_b) softc->ai2_wordsize = probe_b;
+ else softc->ai2_wordsize = WORDSIZE;
+ xsprintf(descr,"%s at 0x%X",drv->drv_description,probe_a);
+ cfe_attach(drv,softc,NULL,descr);
+ }
+}
+
+
+
+/* *********************************************************************
+ * promice_open(ctx)
+ *
+ * Open the device
+ *
+ * Input parameters:
+ * ctx - device context
+ *
+ * Return value:
+ * 0 if ok, else error code
+ ********************************************************************* */
+static int promice_open(cfe_devctx_t *ctx)
+{
+ promice_t *softc = ctx->dev_softc;
+ uint8_t dummy;
+
+ softc->zero = (volatile WORDTYPE *)
+ UNCADDR(softc->ai2_addr + (ZERO_OFFSET*softc->ai2_wordsize));
+ softc->one = (volatile WORDTYPE *)
+ UNCADDR(softc->ai2_addr + (ONE_OFFSET*softc->ai2_wordsize));
+ softc->data = (volatile WORDTYPE *)
+ UNCADDR(softc->ai2_addr + (DATA_OFFSET*softc->ai2_wordsize));
+ softc->status = (volatile WORDTYPE *)
+ UNCADDR(softc->ai2_addr + (STATUS_OFFSET*softc->ai2_wordsize));
+
+ /*
+ * Wait for bit 3 to clear so we know the interface is ready.
+ */
+
+ while (*(softc->status) == 0xCC) ; /* NULL LOOP */
+
+ /*
+ * a dummy read is required to clear out the interface.
+ */
+
+ dummy = *(softc->data);
+
+ return 0;
+}
+
+/* *********************************************************************
+ * promice_read(ctx,buffer)
+ *
+ * Read data from the device
+ *
+ * Input parameters:
+ * ctx - device context
+ * buffer - I/O buffer descriptor
+ *
+ * Return value:
+ * number of bytes transferred, or <0 if error
+ ********************************************************************* */
+static int promice_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ promice_t *softc = ctx->dev_softc;
+ unsigned char *bptr;
+ int blen;
+
+ bptr = buffer->buf_ptr;
+ blen = buffer->buf_length;
+
+ while ((blen > 0) && (*(softc->status) & HDA)) {
+ *bptr++ = *(softc->data);
+ blen--;
+ }
+
+ buffer->buf_retlen = buffer->buf_length - blen;
+ return 0;
+}
+
+/* *********************************************************************
+ * promice_inpstat(ctx,inpstat)
+ *
+ * Determine if read data is available
+ *
+ * Input parameters:
+ * ctx - device context
+ * inpstat - input status structure
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int promice_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
+{
+ promice_t *softc = ctx->dev_softc;
+
+ inpstat->inp_status = (*(softc->status) & HDA) ? 1 : 0;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * promice_write(ctx,buffer)
+ *
+ * Write data to the device
+ *
+ * Input parameters:
+ * ctx - device context
+ * buffer - I/O buffer descriptor
+ *
+ * Return value:
+ * number of bytes transferred, or <0 if error
+ ********************************************************************* */
+static int promice_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ promice_t *softc = ctx->dev_softc;
+ unsigned char *bptr;
+ int blen;
+ uint8_t data;
+#ifndef _AIDIRT_
+ uint8_t dummy;
+ int count;
+#endif
+
+ bptr = buffer->buf_ptr;
+ blen = buffer->buf_length;
+
+
+ /*
+ * The AI2 interface requires you to transmit characters
+ * one bit at a time. First a '1' start bit,
+ * then 8 data bits (lsb first) then another '1' stop bit.
+ *
+ * Just reference the right memory location to transmit a bit.
+ */
+
+ while ((blen > 0) && !(*(softc->status) & TDA)) {
+
+#ifdef _AIDIRT_
+ data = *bptr++;
+ *(softc->zero) = data;
+#else
+ dummy = *(softc->one); /* send start bit */
+
+ data = *bptr++;
+
+ for (count = 0; count < 8; count++) {
+ if (data & 1) dummy = *(softc->one);
+ else dummy = *(softc->zero);
+ data >>= 1; /* shift in next bit */
+ }
+
+ dummy = *(softc->one); /* send stop bit */
+#endif
+
+ blen--;
+ }
+
+ buffer->buf_retlen = buffer->buf_length - blen;
+ return 0;
+}
+
+/* *********************************************************************
+ * promice_ioctl(ctx,buffer)
+ *
+ * Do I/O control operations
+ *
+ * Input parameters:
+ * ctx - device context
+ * buffer - I/O control args
+ *
+ * Return value:
+ * 0 if ok
+ * else error code
+ ********************************************************************* */
+
+static int promice_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
+{
+ return -1;
+}
+
+/* *********************************************************************
+ * promice_close(ctx)
+ *
+ * Close the device.
+ *
+ * Input parameters:
+ * ctx - device context
+ *
+ * Return value:
+ * 0
+ ********************************************************************* */
+
+static int promice_close(cfe_devctx_t *ctx)
+{
+ return 0;
+}
+
+
diff --git a/cfe/cfe/dev/dev_sp1011.c b/cfe/cfe/dev/dev_sp1011.c
new file mode 100644
index 0000000..8e0d16b
--- /dev/null
+++ b/cfe/cfe/dev/dev_sp1011.c
@@ -0,0 +1,151 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * SP1011 (Sturgeon) Support File: dev_sp1011.c
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+#include "lib_types.h"
+
+#include "pcireg.h"
+#include "pcivar.h"
+
+extern int eoi_implemented;
+
+void sturgeon_setup (pcitag_t tag, pci_flags_t flags);
+
+
+/* Sturgeon LDT-to-PCI bridge (LPB) specific definitions. */
+
+#define PCI_VENDOR_API 0x14d9
+#define PCI_PRODUCT_API_STURGEON 0x0010
+
+/* Sturgeon specific registers */
+#define LPB_READ_CTRL_REG 0x60
+#define LPB_READ_CTRL_MASK 0xffffff
+
+#define LPB_READ_CTRL_PREF_EN (1 << 0)
+#define LPB_READ_CTRL_RD_PREF_EN (1 << 1)
+#define LPB_READ_CTRL_MULT_PREF_SHIFT 2
+#define LPB_READ_CTRL_MULT_PREF_MASK (7 << LPB_READ_CTRL_MULT_PREF_SHIFT)
+#define LPB_READ_CTRL_LINE_PREF_SHIFT 5
+#define LPB_READ_CTRL_LINE_PREF_MASK (7 << LPB_READ_CTRL_LINE_PREF_SHIFT)
+#define LPB_READ_CTRL_DEL_REQ_SHIFT 8
+#define LPB_READ_CTRL_DEL_REQ_MASK (3 << LPB_READ_CTRL_DEL_REQ_SHIFT)
+
+#define LPB_INT_CTRL_BASE 0xa0
+
+#define LPB_INT_CTRL_ENABLE (1 << 15)
+#define LPB_INT_CTRL_DESTMODE (1 << 14)
+#define LPB_INT_CTRL_DEST_SHIFT 6
+#define LPB_INT_CTRL_DEST_MASK (0xff << LPB_INT_CTRL_DEST_SHIFT)
+#define LPB_INT_CTRL_MSGTYPE_SHIFT 4
+#define LPB_INT_CTRL_MSGTYPE_MASK (0x3 << LPB_INT_CTRL_MSGTYPE_SHIFT)
+#define LPB_INT_CTRL_POLARITY (1 << 3)
+#define LPB_INT_CTRL_TRIGGERMODE (1 << 2)
+#define LPB_INT_CTRL_VECTOR_SHIFT 0
+#define LPB_INT_CTRL_VECTOR_MASK (0x3 << 0)
+
+#define LPB_INT_BLOCK1_REG 0xc4
+
+void
+sturgeon_setup (pcitag_t tag, pci_flags_t flags)
+{
+ int bus, device, function;
+ int secondary;
+ struct pci_bus *pb;
+ unsigned offset;
+ pcireg_t t, ctrl, intmap;
+
+ pci_break_tag(tag, &bus, &device, &function);
+
+ secondary = (pci_conf_read(tag, PPB_BUSINFO_REG) >> 8) & 0xff;
+ pb = &_pci_bus[secondary];
+
+ /* set up READ CONTROL register for selected prefetch option */
+ ctrl = pci_conf_read(tag, LPB_READ_CTRL_REG) & ~LPB_READ_CTRL_MASK;
+ if ((flags & PCI_FLG_LDT_PREFETCH) != 0) {
+ /* Prefetch enable: all cycle types, 2 delayed requests,
+ 4 lines of fetch ahead for MemRdMult */
+ ctrl |= (LPB_READ_CTRL_PREF_EN
+ | LPB_READ_CTRL_RD_PREF_EN
+ | (3 << LPB_READ_CTRL_MULT_PREF_SHIFT)
+ | (1 << LPB_READ_CTRL_DEL_REQ_SHIFT));
+ } else {
+ /* No prefetch */
+ ctrl |= 0;
+ }
+ pci_conf_write(tag, LPB_READ_CTRL_REG, ctrl);
+
+ /* It's apparently not possible for software to distinguish
+ the CSWARM's debug Sturgeon (which has floating interrupt
+ inputs), so we route interrupts only if there are secondary
+ devices. */
+ if (pb->ndev > 0) {
+ /* Setup interrupt mapping for Block 1:
+ Enabled, Dest=Logical (CPU 0 + CPU 1), Type=Fixed */
+ intmap = (LPB_INT_CTRL_ENABLE |
+ LPB_INT_CTRL_DESTMODE | /* Logical */
+ (0x3 << LPB_INT_CTRL_DEST_SHIFT) | /* CPU 0+1 */
+ (0x0 << LPB_INT_CTRL_MSGTYPE_SHIFT)); /* Fixed */
+ if (eoi_implemented) {
+ /* Passes >=2 have working EOI. Trigger=Level */
+ intmap |= LPB_INT_CTRL_TRIGGERMODE; /* Level */
+ } else {
+ /* Pass 1 lacks working EOI. Trigger=Edge */
+ intmap |= 0; /* Edge */
+ }
+
+ offset = pb->inta_shift % 4;
+ t = (intmap + offset);
+ offset = (offset+1) % 4;
+ t |= (intmap + offset) << 16;
+ pci_conf_write(tag, LPB_INT_CTRL_BASE + 8, t);
+
+ offset = (offset+1) % 4;
+ t = (intmap + offset);
+ offset = (offset+1) % 4;
+ t |= (intmap + offset) << 16;
+ pci_conf_write(tag, LPB_INT_CTRL_BASE + 12, t);
+
+ t = pci_conf_read(tag, LPB_INT_BLOCK1_REG);
+ t &= 0xffffff00;
+ t |= (0x40 | (56 >> 2));
+ pci_conf_write(tag, LPB_INT_BLOCK1_REG, t);
+ }
+}
diff --git a/cfe/cfe/dev/dev_tulip.c b/cfe/cfe/dev/dev_tulip.c
new file mode 100644
index 0000000..dec6b56
--- /dev/null
+++ b/cfe/cfe/dev/dev_tulip.c
@@ -0,0 +1,2985 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * DC21x4x Ethernet Driver File: dev_tulip.c
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+#include "sbmips.h"
+
+#ifndef _SB_MAKE64
+#define _SB_MAKE64(x) ((uint64_t)(x))
+#endif
+#ifndef _SB_MAKEMASK1
+#define _SB_MAKEMASK1(n) (_SB_MAKE64(1) << _SB_MAKE64(n))
+#endif
+
+#include "lib_types.h"
+#include "lib_hssubr.h"
+#include "lib_malloc.h"
+#include "lib_string.h"
+#define blockcopy memcpy
+#include "lib_printf.h"
+#include "lib_queue.h"
+
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "cfe_ioctl.h"
+#include "cfe_timer.h"
+#include "cfe_error.h"
+#include "cfe_irq.h"
+
+#include "pcivar.h"
+#include "pcireg.h"
+
+#include "dc21143.h"
+#include "mii.h"
+
+/* This is a driver for specific configurations of the DC21040, DC21041,
+ DC21140A and DC21143, not a generic Tulip driver. The prefix
+ "tulip_" is used to indicate generic Tulip functions, while
+ "dc21040_", "dc21041_", "dc21140_" or "dc21143_" indicates functions
+ specific to a chip variant.
+
+ The 21041 driver assumes a 10BT HD interface, since autonegotiation
+ is known to be broken in the early revisons of that chip. Example
+ cards come from DEC and SMC. Essentially the same driver is used
+ for 21040 cards.
+
+ The 21140 driver assumes that the PHY uses a standard MII interface
+ for both 100BT and 10BT. Example cards come from DEC (National DP83840
+ plus Twister PHY) and Netgear (Level One PHY).
+
+ Some early 21140 boards are exceptions and use SYM plus SRL
+ with different PHY chips for 10 and 100 (limited support).
+
+ The 21143 driver assumes by default that the PHY uses the SYM ("5
+ wire") interface for 100BT with pass-through for 10BT. Example
+ cards come from DEC (MicroLinear ML6694 PHY) and Znyx (QS6611 or
+ Kendin KS8761 PHY). It also supports an MII interface for
+ recognized adapters. An example card comes from Adaptec (National
+ DP83840A and Twister PHY). There is no support for AUI interfaces.
+
+ This SB1250 version takes advantage of DMA coherence and uses
+ "preserve bit lanes" addresses for all accesses that cross the
+ ZBbus-PCI bridge. */
+
+#ifndef TULIP_DEBUG
+#define TULIP_DEBUG 0
+#endif
+
+#ifndef TULIP_TUNE
+#define TULIP_TUNE 1
+#endif
+
+/* Set IPOLL to drive processing through the pseudo-interrupt
+ dispatcher. Set XPOLL to drive processing by an external polling
+ agent. Setting both is ok. */
+
+#ifndef IPOLL
+#define IPOLL 0
+#endif
+#ifndef XPOLL
+#define XPOLL 1
+#endif
+
+#define ENET_ADDR_LEN 6 /* size of an ethernet address */
+#define MAX_ETHER_PACK 1518 /* max size of a packet */
+#define CRC_SIZE 4 /* size of CRC field */
+
+/* Packet buffers. For tulip, the packet must be aligned to a 32-bit
+ word boundary, and we would like it aligned to a cache line
+ boundary for performance. */
+
+#define CACHE_ALIGN 32
+
+#if __long64
+typedef struct eth_pkt_s {
+ queue_t next; /* 16 */
+ uint8_t *buffer; /* 8 */
+ uint32_t flags; /* 4 */
+ int32_t length; /* 4 */
+ uint8_t data[MAX_ETHER_PACK];
+} eth_pkt_t;
+#else
+typedef struct eth_pkt_s {
+ queue_t next; /* 8 */
+ uint8_t *buffer; /* 4 */
+ uint32_t flags; /* 4 */
+ int32_t length; /* 4 */
+ uint32_t unused[3]; /* 12 */
+ uint8_t data[MAX_ETHER_PACK];
+} eth_pkt_t;
+#endif
+
+#define ETH_PKTBUF_LINES ((sizeof(eth_pkt_t) + (CACHE_ALIGN-1))/CACHE_ALIGN)
+#define ETH_PKTBUF_SIZE (ETH_PKTBUF_LINES*CACHE_ALIGN)
+#define ETH_PKTBUF_OFFSET (offsetof(eth_pkt_t, data))
+
+#define ETH_PKT_BASE(data) ((eth_pkt_t *)((data) - ETH_PKTBUF_OFFSET))
+
+/* packet flags */
+#define ETH_TX_SETUP 1 /* assumes Perfect Filtering format */
+
+static void
+show_packet(char c, eth_pkt_t *pkt)
+{
+ int i;
+ int n = (pkt->length < 32 ? pkt->length : 32);
+
+ xprintf("%c[%4d]:", c, pkt->length);
+ for (i = 0; i < n; i++) {
+ if (i % 4 == 0)
+ xprintf(" ");
+ xprintf("%02x", pkt->buffer[i]);
+ }
+ xprintf("\n");
+}
+
+
+/* Descriptor structures */
+
+typedef struct rx_dscr {
+ uint32_t rxd_flags;
+ uint32_t rxd_bufsize;
+ pci_addr_t rxd_bufaddr1;
+ pci_addr_t rxd_bufaddr2;
+} rx_dscr;
+
+typedef struct tx_dscr {
+ uint32_t txd_flags;
+ uint32_t txd_bufsize;
+ pci_addr_t txd_bufaddr1;
+ pci_addr_t txd_bufaddr2;
+} tx_dscr;
+
+/* CAM structure */
+
+typedef union {
+ struct {
+ uint32_t physical[CAM_PERFECT_ENTRIES][3];
+ } p;
+ struct {
+ uint32_t hash[32];
+ uint32_t mbz[7];
+ uint32_t physical[3];
+ } h;
+} tulip_cam;
+
+
+/* Driver data structures */
+
+typedef enum {
+ eth_state_uninit,
+ eth_state_setup,
+ eth_state_off,
+ eth_state_on,
+ eth_state_broken
+} eth_state_t;
+
+#define ETH_PKTPOOL_SIZE 32
+#define ETH_PKT_SIZE MAX_ETHER_PACK
+
+typedef struct tulip_softc {
+ uint32_t membase;
+ uint8_t irq; /* interrupt mapping (used if IPOLL) */
+ pcitag_t tag; /* tag for configuration registers */
+
+ uint8_t hwaddr[ENET_ADDR_LEN];
+ uint16_t device; /* chip device code */
+ uint8_t revision; /* chip revision and step (Table 3-7) */
+
+ /* current state */
+ eth_state_t state;
+
+ /* These fields are the chip startup values. */
+// uint16_t media; /* media type */
+ uint32_t opmode; /* operating mode */
+ uint32_t intmask; /* interrupt mask */
+ uint32_t gpdata; /* output bits for csr15 (21143) */
+
+ /* These fields are set before calling dc21x4x_hwinit */
+ int linkspeed; /* encodings from cfe_ioctl */
+ int loopback;
+
+ /* Packet free list */
+ queue_t freelist;
+ uint8_t *pktpool;
+ queue_t rxqueue;
+
+ /* The descriptor tables */
+ uint8_t *rxdscrmem; /* receive descriptors */
+ uint8_t *txdscrmem; /* transmit descriptors */
+
+ /* These fields keep track of where we are in tx/rx processing */
+ volatile rx_dscr *rxdscr_start; /* beginning of ring */
+ volatile rx_dscr *rxdscr_end; /* end of ring */
+ volatile rx_dscr *rxdscr_remove; /* next one we expect tulip to use */
+ volatile rx_dscr *rxdscr_add; /* next place to put a buffer */
+ int rxdscr_onring;
+
+ volatile tx_dscr *txdscr_start; /* beginning of ring */
+ volatile tx_dscr *txdscr_end; /* end of ring */
+ volatile tx_dscr *txdscr_remove; /* next one we will use for tx */
+ volatile tx_dscr *txdscr_add; /* next place to put a buffer */
+
+ cfe_devctx_t *devctx;
+
+ /* These fields describe the PHY */
+ enum {SRL, MII, SYM} phy_type;
+ int mii_addr;
+
+ /* Statistics */
+ uint32_t inpkts;
+ uint32_t outpkts;
+ uint32_t interrupts;
+ uint32_t rx_interrupts;
+ uint32_t tx_interrupts;
+ uint32_t bus_errors;
+} tulip_softc;
+
+
+/* Entry to and exit from critical sections (currently relative to
+ interrupts only, not SMP) */
+
+#if CFG_INTERRUPTS
+#define CS_ENTER(sc) cfe_disable_irq(sc->irq)
+#define CS_EXIT(sc) cfe_enable_irq(sc->irq)
+#else
+#define CS_ENTER(sc) ((void)0)
+#define CS_EXIT(sc) ((void)0)
+#endif
+
+
+/* Driver parameterization */
+
+#define MAXRXDSCR 32
+#define MAXTXDSCR 32
+#define MINRXRING 8
+
+#define MEDIA_UNKNOWN 0
+#define MEDIA_AUI 1
+#define MEDIA_BNC 2
+#define MEDIA_UTP_FULL_DUPLEX 3
+#define MEDIA_UTP_NO_LINK_TEST 4
+#define MEDIA_UTP 5
+
+/* Prototypes */
+
+static void tulip_ether_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr);
+
+
+/* Address mapping macros */
+
+/* Note that PTR_TO_PHYS only works with 32-bit addresses, but then
+ so does the Tulip. */
+#define PTR_TO_PHYS(x) (K0_TO_PHYS((uintptr_t)(x)))
+#define PHYS_TO_PTR(a) ((uint8_t *)PHYS_TO_K0(a))
+
+/* All mappings through the PCI host bridge use match bits mode. */
+#define PHYS_TO_PCI(a) ((uint32_t) (a) | 0x20000000)
+#define PCI_TO_PHYS(a) ((uint32_t) (a) & 0x1FFFFFFF)
+
+#define PCI_TO_PTR(a) (PHYS_TO_PTR(PCI_TO_PHYS(a)))
+#define PTR_TO_PCI(x) (PHYS_TO_PCI(PTR_TO_PHYS(x)))
+
+#if __long64
+#define READCSR(sc,csr) \
+ (*((volatile uint32_t *) (PHYS_TO_XKSEG_UNCACHED((sc)->membase + (csr)))))
+
+#define WRITECSR(sc,csr,val) \
+ (*((volatile uint32_t *) \
+ (PHYS_TO_XKSEG_UNCACHED((sc)->membase + (csr)))) = (val))
+
+#else
+#define READCSR(sc,csr) \
+ (hs_read32(PHYS_TO_XKSEG_UNCACHED((sc)->membase + (csr))))
+
+#define WRITECSR(sc,csr,val) \
+ (hs_write32(PHYS_TO_XKSEG_UNCACHED((sc)->membase + (csr)), (val)))
+
+#endif
+
+#define RESET_ADAPTER(sc) \
+ { \
+ WRITECSR((sc), R_CSR_BUSMODE, M_CSR0_SWRESET); \
+ cfe_sleep(CFE_HZ/10); \
+ }
+
+
+/* Debugging */
+
+static void
+dumpstat(tulip_softc *sc)
+{
+ xprintf("-- CSR 5 = %08X CSR 6 = %08x\n",
+ READCSR(sc, R_CSR_STATUS), READCSR(sc, R_CSR_OPMODE));
+}
+
+static void
+dumpcsrs(tulip_softc *sc)
+{
+ int idx;
+
+ xprintf("-------------\n");
+ for (idx = 0; idx < 16; idx++) {
+ xprintf("CSR %2d = %08X\n", idx, READCSR(sc, idx*8));
+ }
+ xprintf("-------------\n");
+}
+
+
+/* Packet management */
+
+/* *********************************************************************
+ * ETH_ALLOC_PKT(sc)
+ *
+ * Allocate a packet from the free list.
+ *
+ * Input parameters:
+ * sc - eth structure
+ *
+ * Return value:
+ * pointer to packet structure, or NULL if none available
+ ********************************************************************* */
+static eth_pkt_t *
+eth_alloc_pkt(tulip_softc *sc)
+{
+ eth_pkt_t *pkt;
+
+ CS_ENTER(sc);
+ pkt = (eth_pkt_t *) q_deqnext(&sc->freelist);
+ CS_EXIT(sc);
+ if (!pkt) return NULL;
+
+ pkt->buffer = pkt->data;
+ pkt->length = ETH_PKT_SIZE;
+ pkt->flags = 0;
+
+ return pkt;
+}
+
+
+/* *********************************************************************
+ * ETH_FREE_PKT(sc,pkt)
+ *
+ * Return a packet to the free list
+ *
+ * Input parameters:
+ * sc - sbmac structure
+ * pkt - packet to return
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void
+eth_free_pkt(tulip_softc *sc, eth_pkt_t *pkt)
+{
+ CS_ENTER(sc);
+ q_enqueue(&sc->freelist, &pkt->next);
+ CS_EXIT(sc);
+}
+
+
+/* *********************************************************************
+ * ETH_INITFREELIST(sc)
+ *
+ * Initialize the buffer free list for this mac. The memory
+ * allocated to the free list is carved up and placed on a linked
+ * list of buffers for use by the mac.
+ *
+ * Input parameters:
+ * sc - eth structure
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void
+eth_initfreelist(tulip_softc *sc)
+{
+ int idx;
+ uint8_t *ptr;
+ eth_pkt_t *pkt;
+
+ q_init(&sc->freelist);
+
+ ptr = sc->pktpool;
+ for (idx = 0; idx < ETH_PKTPOOL_SIZE; idx++) {
+ pkt = (eth_pkt_t *) ptr;
+ eth_free_pkt(sc, pkt);
+ ptr += ETH_PKTBUF_SIZE;
+ }
+}
+
+
+/* Utilities */
+
+static const char *
+tulip_devname(tulip_softc *sc)
+{
+ return (sc->devctx != NULL ? cfe_device_name(sc->devctx) : "eth?");
+}
+
+
+/* Descriptor ring management */
+
+static int
+tulip_add_rcvbuf(tulip_softc *sc, eth_pkt_t *pkt)
+{
+ volatile rx_dscr *rxd;
+ volatile rx_dscr *nextrxd;
+ uint32_t flags = 0;
+
+ rxd = sc->rxdscr_add;
+
+ /* Figure out where the next descriptor will go */
+ nextrxd = rxd+1;
+ if (nextrxd == sc->rxdscr_end) {
+ nextrxd = sc->rxdscr_start;
+ flags = M_RDES1_ENDOFRING;
+ }
+
+ /*
+ * If the next one is the same as our remove pointer,
+ * the ring is considered full. (it actually has room for
+ * one more, but we reserve the remove == add case for "empty")
+ */
+ if (nextrxd == sc->rxdscr_remove) return -1;
+
+ rxd->rxd_bufsize = V_RDES1_BUF1SIZE(1520) | flags;
+ rxd->rxd_bufaddr1 = PTR_TO_PCI(pkt->buffer);
+ rxd->rxd_bufaddr2 = 0;
+ rxd->rxd_flags = M_RDES0_OWNADAP;
+
+ /* success, advance the pointer */
+ sc->rxdscr_add = nextrxd;
+ CS_ENTER(sc);
+ sc->rxdscr_onring++;
+ CS_EXIT(sc);
+
+ return 0;
+}
+
+static void
+tulip_fillrxring(tulip_softc *sc)
+{
+ eth_pkt_t *pkt;
+
+ while (1) {
+ CS_ENTER(sc);
+ if (sc->rxdscr_onring >= MINRXRING) {
+ CS_EXIT(sc);
+ break;
+ }
+ CS_EXIT(sc);
+ pkt = eth_alloc_pkt(sc);
+ if (pkt == NULL) {
+ /* could not allocate a buffer */
+ break;
+ }
+ if (tulip_add_rcvbuf(sc, pkt) != 0) {
+ /* could not add buffer to ring */
+ eth_free_pkt(sc, pkt);
+ break;
+ }
+ }
+}
+
+
+/* *********************************************************************
+ * TULIP_RX_CALLBACK(sc, pkt)
+ *
+ * Receive callback routine. This routine is invoked when a
+ * buffer queued for receives is filled. In this simple driver,
+ * all we do is add the packet to a per-MAC queue for later
+ * processing, and try to put a new packet in the place of the one
+ * that was removed from the queue.
+ *
+ * Input parameters:
+ * sc - interface
+ * ptk - packet context (eth_pkt structure)
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void
+tulip_rx_callback(tulip_softc *sc, eth_pkt_t *pkt)
+{
+ if (TULIP_DEBUG) show_packet('>', pkt); /* debug */
+
+ CS_ENTER(sc);
+ q_enqueue(&sc->rxqueue, &pkt->next);
+ CS_EXIT(sc);
+ sc->inpkts++;
+
+ tulip_fillrxring(sc);
+}
+
+
+static void
+tulip_procrxring(tulip_softc *sc)
+{
+ volatile rx_dscr *rxd;
+ eth_pkt_t *pkt;
+ eth_pkt_t *newpkt;
+ uint32_t flags;
+
+ for (;;) {
+ rxd = (volatile rx_dscr *) sc->rxdscr_remove;
+
+ flags = rxd->rxd_flags;
+ if (flags & M_RDES0_OWNADAP) {
+ /* end of ring, no more packets */
+ break;
+ }
+
+ pkt = ETH_PKT_BASE(PCI_TO_PTR(rxd->rxd_bufaddr1));
+
+ /* Drop error packets */
+ if (flags & M_RDES0_ERRORSUM) {
+ xprintf("%s: rx error %04X\n", tulip_devname(sc), flags & 0xFFFF);
+ tulip_add_rcvbuf(sc, pkt);
+ goto next;
+ }
+
+ /* Pass up the packet */
+ pkt->length = G_RDES0_FRAMELEN(flags) - CRC_SIZE;
+ tulip_rx_callback(sc, pkt);
+
+ /* put a buffer back on the ring to replace this one */
+ newpkt = eth_alloc_pkt(sc);
+ if (newpkt) tulip_add_rcvbuf(sc, newpkt);
+
+next:
+ /* update the pointer, accounting for buffer wrap. */
+ rxd++;
+ if (rxd == sc->rxdscr_end)
+ rxd = sc->rxdscr_start;
+
+ sc->rxdscr_remove = (rx_dscr *) rxd;
+ CS_ENTER(sc);
+ sc->rxdscr_onring--;
+ CS_EXIT(sc);
+ }
+}
+
+
+static int
+tulip_add_txbuf(tulip_softc *sc, eth_pkt_t *pkt)
+{
+ volatile tx_dscr *txd;
+ volatile tx_dscr *nexttxd;
+ uint32_t bufsize = 0;
+
+ txd = sc->txdscr_add;
+
+ /* Figure out where the next descriptor will go */
+ nexttxd = (txd+1);
+ if (nexttxd == sc->txdscr_end) {
+ nexttxd = sc->txdscr_start;
+ bufsize = M_TDES1_ENDOFRING;
+ }
+
+ /* If the next one is the same as our remove pointer,
+ the ring is considered full. (it actually has room for
+ one more, but we reserve the remove == add case for "empty") */
+
+ if (nexttxd == sc->txdscr_remove) return -1;
+
+ bufsize |= V_TDES1_BUF1SIZE(pkt->length) |
+ M_TDES1_FIRSTSEG | M_TDES1_LASTSEG | M_TDES1_INTERRUPT;
+ if (pkt->flags & ETH_TX_SETUP) {
+ /* For a setup packet, FIRSTSEG and LASTSEG should be clear (!) */
+ bufsize ^= M_TDES1_SETUP | M_TDES1_FIRSTSEG | M_TDES1_LASTSEG;
+ }
+ txd->txd_bufsize = bufsize;
+ txd->txd_bufaddr1 = PTR_TO_PCI(pkt->buffer);
+ txd->txd_bufaddr2 = 0;
+ txd->txd_flags = M_TDES0_OWNADAP;
+
+ /* success, advance the pointer */
+ sc->txdscr_add = nexttxd;
+
+ return 0;
+}
+
+
+static int
+tulip_transmit(tulip_softc *sc,eth_pkt_t *pkt)
+{
+ int rv;
+
+ if (TULIP_DEBUG) show_packet('<', pkt); /* debug */
+
+ rv = tulip_add_txbuf(sc, pkt);
+ sc->outpkts++;
+
+ WRITECSR(sc, R_CSR_TXPOLL, 1);
+ return rv;
+}
+
+
+static void
+tulip_proctxring(tulip_softc *sc)
+{
+ volatile tx_dscr *txd;
+ eth_pkt_t *pkt;
+ uint32_t flags;
+
+ for (;;) {
+ txd = (volatile tx_dscr *) sc->txdscr_remove;
+
+ if (txd == sc->txdscr_add) {
+ /* ring is empty, no buffers to process */
+ break;
+ }
+
+ flags = txd->txd_flags;
+ if (flags & M_TDES0_OWNADAP) {
+ /* Reached a packet still being transmitted */
+ break;
+ }
+
+ /* Check for a completed setup packet */
+ pkt = ETH_PKT_BASE(PCI_TO_PTR(txd->txd_bufaddr1));
+ if (pkt->flags & ETH_TX_SETUP) {
+ if (sc->state == eth_state_setup) {
+ uint32_t opmode;
+
+ /* check flag bits */
+ opmode = READCSR(sc, R_CSR_OPMODE);
+ opmode |= M_CSR6_RXSTART;
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+ sc->inpkts = sc->outpkts = 0;
+ sc->state =eth_state_on;
+ }
+ pkt->flags &=~ ETH_TX_SETUP;
+ }
+
+ /* Just free the packet */
+ eth_free_pkt(sc, pkt);
+
+ /* update the pointer, accounting for buffer wrap. */
+ txd++;
+ if (txd == sc->txdscr_end)
+ txd = sc->txdscr_start;
+
+ sc->txdscr_remove = (tx_dscr *) txd;
+ }
+}
+
+
+static void
+tulip_initrings(tulip_softc *sc)
+{
+ volatile tx_dscr *txd;
+ volatile rx_dscr *rxd;
+
+ /* Claim ownership of all descriptors for the driver */
+
+ for (txd = sc->txdscr_start; txd != sc->txdscr_end; txd++)
+ txd->txd_flags = 0;
+ for (rxd = sc->rxdscr_start; rxd != sc->rxdscr_end; rxd++)
+ rxd->rxd_flags = 0;
+
+ /* Init the ring pointers */
+
+ sc->txdscr_add = sc->txdscr_remove = sc->txdscr_start;
+ sc->rxdscr_add = sc->rxdscr_remove = sc->rxdscr_start;
+ sc->rxdscr_onring = 0;
+
+ /* Add stuff to the receive ring */
+
+ tulip_fillrxring(sc);
+}
+
+
+static int
+tulip_init(tulip_softc *sc)
+{
+ /* Allocate descriptor rings */
+ sc->rxdscrmem = KMALLOC(MAXRXDSCR*sizeof(rx_dscr), sizeof(rx_dscr));
+ sc->txdscrmem = KMALLOC(MAXTXDSCR*sizeof(tx_dscr), sizeof(tx_dscr));
+
+ /* Allocate buffer pool */
+ sc->pktpool = KMALLOC(ETH_PKTPOOL_SIZE*ETH_PKTBUF_SIZE, CACHE_ALIGN);
+ eth_initfreelist(sc);
+ q_init(&sc->rxqueue);
+
+ /* Fill in pointers to the rings */
+ sc->rxdscr_start = (rx_dscr *) (sc->rxdscrmem);
+ sc->rxdscr_end = sc->rxdscr_start + MAXRXDSCR;
+ sc->rxdscr_add = sc->rxdscr_start;
+ sc->rxdscr_remove = sc->rxdscr_start;
+ sc->rxdscr_onring = 0;
+
+ sc->txdscr_start = (tx_dscr *) (sc->txdscrmem);
+ sc->txdscr_end = sc->txdscr_start + MAXTXDSCR;
+ sc->txdscr_add = sc->txdscr_start;
+ sc->txdscr_remove = sc->txdscr_start;
+
+ tulip_initrings(sc);
+
+ return 0;
+}
+
+
+static void
+tulip_resetrings(tulip_softc *sc)
+{
+ volatile tx_dscr *txd;
+ volatile rx_dscr *rxd;
+ eth_pkt_t *pkt;
+
+ /* Free already-sent descriptors and buffers */
+ tulip_proctxring(sc);
+
+ /* Free any pending but unsent */
+ txd = (volatile tx_dscr *) sc->txdscr_remove;
+ while (txd != sc->txdscr_add) {
+ txd->txd_flags &=~ M_TDES0_OWNADAP;
+ pkt = ETH_PKT_BASE(PCI_TO_PTR(txd->txd_bufaddr1));
+ eth_free_pkt(sc, pkt);
+
+ txd++;
+ if (txd == sc->txdscr_end)
+ txd = sc->txdscr_start;
+ }
+ sc->txdscr_add = sc->txdscr_remove;
+
+ /* Discard any received packets as well as all free buffers */
+ rxd = (volatile rx_dscr *) sc->rxdscr_remove;
+ while (rxd != sc->rxdscr_add) {
+ rxd->rxd_flags &=~ M_RDES0_OWNADAP;
+ pkt = ETH_PKT_BASE(PCI_TO_PTR(rxd->rxd_bufaddr1));
+ eth_free_pkt(sc, pkt);
+
+ rxd++;
+ if (rxd == sc->rxdscr_end)
+ rxd = sc->rxdscr_start;
+ CS_ENTER(sc);
+ sc->rxdscr_onring--;
+ CS_EXIT(sc);
+ }
+
+ /* Reestablish the initial state. */
+ tulip_initrings(sc);
+}
+
+
+/* CRCs */
+
+#define IEEE_CRC32_POLY 0xEDB88320UL /* CRC-32 Poly -- either endian */
+
+static uint32_t
+tulip_crc32(const uint8_t *databuf, unsigned int datalen)
+{
+ unsigned int idx, bit, data;
+ uint32_t crc;
+
+ crc = 0xFFFFFFFFUL;
+ for (idx = 0; idx < datalen; idx++)
+ for (data = *databuf++, bit = 0; bit < 8; bit++, data >>= 1)
+ crc = (crc >> 1) ^ (((crc ^ data) & 1) ? IEEE_CRC32_POLY : 0);
+ return crc;
+}
+
+#define tulip_mchash(mca) (tulip_crc32((mca), 6) & 0x1FF)
+
+
+/* Serial ROM access */
+
+/****************************************************************************
+ * tulip_spin(sc, ns)
+ *
+ * Spin for a short interval (nominally in nanoseconds)
+ *
+ * Input Parameters: ns - minimum required nsec.
+ *
+ * The delay loop uses uncached PCI reads, each of which requires
+ * at least 3 PCI bus clocks (45 ns at 66 MHz) to complete. The
+ * actual delay will be longer (much longer if preempted).
+ ***************************************************************************/
+
+#define PCI_MIN_DELAY 45
+
+static void
+tulip_spin(tulip_softc *sc, long nanoseconds)
+{
+ long delay;
+ volatile uint32_t t;
+
+ for (delay = nanoseconds; delay > 0; delay -= PCI_MIN_DELAY)
+ t = READCSR(sc, R_CSR_BUSMODE);
+}
+
+
+/*
+ * Delays below are chosen to meet specs for NS93C64 (slow M variant).
+ * Current parts are faster.
+ * Reference: NS Memory Data Book, 1994
+ */
+
+#define SROM_SIZE 128
+#define SROM_MAX_CYCLES 32
+
+#define SROM_CMD_BITS 3
+#define SROM_ADDR_BITS 6
+
+#define K_SROM_READ_CMD 06
+#define K_SROM_WRITE_CMD 05
+
+#define SROM_VENDOR_INDEX 0x00
+#define SROM_FORMAT_INDEX 0x12
+#define SROM_ADDR_INDEX 0x14
+
+#define SROM_DEVICE0_INDEX 0x1A
+#define SROM_LEAF0_OFFSET_INDEX 0x1B
+
+#define SROM_CRC_INDEX (SROM_SIZE-2)
+/* Note recent chips supporting wake-on-lan have CRC in bytes 94, 95 */
+
+#define SROM_WORD(rom,offset) ((rom)[offset] | ((rom)[offset+1] << 8))
+
+static void
+srom_idle_state(tulip_softc *sc)
+{
+ uint32_t csr9;
+ unsigned int i;
+
+ csr9 = READCSR(sc, R_CSR_ROM_MII);
+
+ csr9 |= M_CSR9_SROMCHIPSEL;
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 100); /* CS setup (Tcss=100) */
+
+ /* Run the clock through the maximum number of pending read cycles */
+ for (i = 0; i < SROM_MAX_CYCLES*2; i++) {
+ csr9 ^= M_CSR9_SROMCLOCK;
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 1000); /* SK period (Fsk=0.5MHz) */
+ }
+
+ /* Deassert SROM Chip Select */
+ csr9 &=~ M_CSR9_SROMCHIPSEL;
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 50); /* CS recovery (Tsks=50) */
+}
+
+static void
+srom_send_command_bit(tulip_softc *sc, unsigned int data)
+{
+ uint32_t csr9;
+
+ csr9 = READCSR(sc, R_CSR_ROM_MII);
+
+ /* Place the data bit on the bus */
+ if (data == 1)
+ csr9 |= M_CSR9_SROMDATAIN;
+ else
+ csr9 &=~ M_CSR9_SROMDATAIN;
+
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 360); /* setup: Tdis=200 */
+
+ /* Now clock the data into the SROM */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_SROMCLOCK);
+ tulip_spin(sc, 900); /* clock high, Tskh=500 */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 450); /* clock low, Tskl=250 */
+
+ /* Now clear the data bit */
+ csr9 &=~ M_CSR9_SROMDATAIN; /* data invalid, Tidh=20 for SK^ */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 270); /* min cycle, 1/Fsk=2000 */
+}
+
+static uint16_t
+srom_read_bit(tulip_softc *sc)
+{
+ uint32_t csr9;
+
+ csr9 = READCSR(sc, R_CSR_ROM_MII);
+
+ /* Generate a clock cycle before doing a read */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_SROMCLOCK); /* rising edge */
+ tulip_spin(sc, 1000); /* clock high, Tskh=500, Tpd=1000 */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9); /* falling edge */
+ tulip_spin(sc, 1000); /* clock low, 1/Fsk=2000 */
+
+ csr9 = READCSR(sc, R_CSR_ROM_MII);
+ return ((csr9 & M_CSR9_SROMDATAOUT) != 0 ? 1 : 0);
+}
+
+#define CMD_BIT_MASK (1 << (SROM_CMD_BITS+SROM_ADDR_BITS-1))
+
+static uint16_t
+srom_read_word(tulip_softc *sc, unsigned int index)
+{
+ uint16_t command, word;
+ uint32_t csr9;
+ unsigned int i;
+
+ csr9 = READCSR(sc, R_CSR_ROM_MII) | M_CSR9_SROMCHIPSEL;
+
+ /* Assert the SROM CS line */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 100); /* CS setup, Tcss = 100 */
+
+ /* Send the read command to the SROM */
+ command = (K_SROM_READ_CMD << SROM_ADDR_BITS) | index;
+ for (i = 0; i < SROM_CMD_BITS+SROM_ADDR_BITS; i++) {
+ srom_send_command_bit(sc, (command & CMD_BIT_MASK) != 0 ? 1 : 0);
+ command <<= 1;
+ }
+
+ /* Now read the bits from the SROM (MSB first) */
+ word = 0;
+ for (i = 0; i < 16; ++i) {
+ word <<= 1;
+ word |= srom_read_bit(sc);
+ }
+
+ /* Clear the SROM CS Line, CS hold, Tcsh = 0 */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9 &~ M_CSR9_SROMCHIPSEL);
+
+ return word;
+}
+
+
+/****************************************************************************
+ * srom_calc_crc()
+ *
+ * Calculate the CRC of the SROM and return it. We compute the
+ * CRC per Appendix A of the 21140A ROM/external register data
+ * sheet (EC-QPQWA-TE).
+ ***************************************************************************/
+
+static uint16_t
+srom_calc_crc(tulip_softc *sc, uint8_t srom[], int length)
+{
+ uint32_t crc = tulip_crc32(srom, length) ^ 0xFFFFFFFF;
+
+ return (uint16_t)(crc & 0xFFFF);
+}
+
+/****************************************************************************
+ * srom_read_all(sc, uint8_t dest)
+ *
+ * Read the entire SROM into the srom array
+ *
+ * Input parameters:
+ * sc - tulip state
+ ***************************************************************************/
+
+static int
+srom_read_all(tulip_softc *sc, uint8_t dest[])
+{
+ int i;
+ uint16_t crc, temp;
+
+ WRITECSR(sc, R_CSR_ROM_MII, M_CSR9_SERROMSEL|M_CSR9_ROMREAD);
+
+ srom_idle_state(sc);
+
+ for (i = 0; i < SROM_SIZE/2; i++) {
+ temp = srom_read_word(sc, i);
+ dest[2*i] = temp & 0xFF;
+ dest[2*i+1] =temp >> 8;
+ }
+
+ WRITECSR(sc, R_CSR_ROM_MII, 0); /* CS hold, Tcsh=0 */
+
+ crc = srom_calc_crc(sc, dest, SROM_CRC_INDEX);
+ if (crc != SROM_WORD(dest, SROM_CRC_INDEX)) {
+ crc = srom_calc_crc(sc, dest, 94); /* "alternative" */
+ if (crc != SROM_WORD(dest, 94)) {
+ xprintf("%s: Invalid SROM CRC, calc %04x, stored %04x\n",
+ tulip_devname(sc), crc, SROM_WORD(dest, 94));
+ return 0/*-1*/;
+ }
+ }
+ return 0;
+}
+
+static int
+srom_read_addr(tulip_softc *sc, uint8_t buf[])
+{
+ uint8_t srom[SROM_SIZE];
+
+ if (srom_read_all(sc, srom) == 0) {
+ memcpy(buf, &srom[SROM_ADDR_INDEX], ENET_ADDR_LEN);
+ return 0;
+ }
+
+ return -1;
+}
+
+
+/****************************************************************************
+ * earom_read_all(sc, uint8_t dest)
+ *
+ * Read the entire Ethernet address ROM into the srom array (21040 only)
+ *
+ * Input parameters:
+ * sc - tulip state
+ ***************************************************************************/
+
+static int
+earom_read_all(tulip_softc *sc, uint8_t dest[])
+{
+ int i;
+ uint32_t csr9;
+
+ WRITECSR(sc, R_CSR_ROM_MII, 0); /* reset pointer */
+
+ for (i = 0; i < SROM_SIZE; i++) {
+ for (;;) {
+ csr9 = READCSR(sc, R_CSR_ROM_MII);
+ if ((csr9 & M_CSR9_DATANOTVALID) == 0)
+ break;
+ POLL(); /* XXX need a timeout */
+ }
+ dest[i] = G_CSR9_ROMDATA(csr9);
+ }
+
+ return 0;
+}
+
+static int
+earom_read_addr(tulip_softc *sc, uint8_t buf[])
+{
+ uint8_t srom[SROM_SIZE];
+
+ if (earom_read_all(sc, srom) == 0) {
+ memcpy(buf, &srom[0], ENET_ADDR_LEN);
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int
+rom_read_all(tulip_softc *sc, uint8_t buf[])
+{
+ if (sc->device == K_PCI_ID_DC21040)
+ return earom_read_all(sc, buf);
+ else
+ return srom_read_all(sc, buf);
+}
+
+static int
+rom_read_addr(tulip_softc *sc, uint8_t buf[])
+{
+ if (sc->device == K_PCI_ID_DC21040)
+ return earom_read_addr(sc, buf);
+ else
+ return srom_read_addr(sc, buf);
+}
+
+#if 0
+static void
+rom_dump(uint8_t srom[])
+{
+ int i;
+
+ xprintf("DC21x4x: SROM data:");
+ for (i = 0; i < SROM_SIZE; i++) {
+ if (i % 16 == 0)
+ xprintf("\n %02x: ", i);
+ xprintf(" %02x", srom[i]);
+ }
+ xprintf("\n");
+}
+#else
+#define rom_dump(srom)
+#endif
+
+
+/****************************************************************************
+ * MII access utility routines
+ ***************************************************************************/
+
+/* MII clock limited to 2.5 MHz, transactions end with MDIO tristated */
+
+static void
+mii_write_bits(tulip_softc *sc, uint32_t data, unsigned int count)
+{
+ uint32_t csr9;
+ uint32_t bitmask;
+
+ csr9 = READCSR(sc, R_CSR_ROM_MII) &~ (M_CSR9_MDC | M_CSR9_MIIMODE);
+
+ for (bitmask = 1 << (count-1); bitmask != 0; bitmask >>= 1) {
+ csr9 &=~ M_CSR9_MDO;
+ if ((data & bitmask) != 0) csr9 |= M_CSR9_MDO;
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+
+ tulip_spin(sc, 2000); /* setup */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_MDC);
+ tulip_spin(sc, 2000); /* hold */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ }
+}
+
+static void
+mii_turnaround(tulip_softc *sc)
+{
+ uint32_t csr9;
+
+ csr9 = READCSR(sc, R_CSR_ROM_MII) | M_CSR9_MIIMODE;
+
+ /* stop driving data */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 2000); /* setup */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_MDC);
+ tulip_spin(sc, 2000); /* clock high */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+
+ /* read back and check for 0 here? */
+}
+
+/****************************************************************************
+ * mii_read_register
+ *
+ * This routine reads a register from the PHY chip using the MII
+ * serial management interface.
+ *
+ * Input parameters:
+ * index - index of register to read (0-31)
+ *
+ * Return value:
+ * word read from register
+ ***************************************************************************/
+
+static uint16_t
+mii_read_register(tulip_softc *sc, unsigned int index)
+{
+ /* Send the command and address to the PHY. The sequence is
+ a synchronization sequence (32 1 bits)
+ a "start" command (2 bits)
+ a "read" command (2 bits)
+ the PHY addr (5 bits)
+ the register index (5 bits)
+ */
+ uint32_t csr9;
+ uint16_t word;
+ int i;
+
+ mii_write_bits(sc, 0xFF, 8);
+ mii_write_bits(sc, 0xFFFFFFFF, 32);
+ mii_write_bits(sc, MII_COMMAND_START, 2);
+ mii_write_bits(sc, MII_COMMAND_READ, 2);
+ mii_write_bits(sc, sc->mii_addr, 5);
+ mii_write_bits(sc, index, 5);
+
+ mii_turnaround(sc);
+
+ csr9 = (READCSR(sc, R_CSR_ROM_MII) &~ M_CSR9_MDC) | M_CSR9_MIIMODE;
+ word = 0;
+
+ for (i = 0; i < 16; i++) {
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 2000); /* clock width low */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9 | M_CSR9_MDC);
+ tulip_spin(sc, 2000); /* clock width high */
+ WRITECSR(sc, R_CSR_ROM_MII, csr9);
+ tulip_spin(sc, 1000); /* output delay */
+ word <<= 1;
+ if ((READCSR(sc, R_CSR_ROM_MII) & M_CSR9_MDI) != 0)
+ word |= 0x0001;
+ }
+
+ return word;
+
+ /* reset to output mode? */
+}
+
+/****************************************************************************
+ * mii_write_register
+ *
+ * This routine writes a register in the PHY chip using the MII
+ * serial management interface.
+ *
+ * Input parameters:
+ * index - index of register to write (0-31)
+ * value - word to write
+ ***************************************************************************/
+
+static void
+mii_write_register(tulip_softc *sc, unsigned int index, uint16_t value)
+{
+ mii_write_bits(sc, 0xFF, 8);
+ mii_write_bits(sc, 0xFFFFFFFF, 32);
+ mii_write_bits(sc, MII_COMMAND_START, 2);
+ mii_write_bits(sc, MII_COMMAND_WRITE, 2);
+ mii_write_bits(sc, sc->mii_addr, 5);
+ mii_write_bits(sc, index, 5);
+ mii_write_bits(sc, MII_COMMAND_ACK, 2);
+ mii_write_bits(sc, value, 16);
+
+ /* reset to input mode? */
+}
+
+
+static int
+mii_probe(tulip_softc *sc)
+{
+ int i;
+ uint16_t id1, id2;
+
+ for (i = 0; i < 32; i++) {
+ sc->mii_addr = i;
+ id1 = mii_read_register(sc, MII_PHYIDR1);
+ id2 = mii_read_register(sc, MII_PHYIDR2);
+ if ((id1 != 0x0000 && id1 != 0xFFFF) ||
+ (id2 != 0x0000 && id2 != 0xFFFF)) {
+ return 0;
+ }
+ }
+ return -1;
+}
+
+#if 0
+#define OUI_NAT_SEMI 0x080017
+#define OUI_LEVEL_ONE 0x1E0400 /* 0x00207B, bit reversed and truncated */
+
+static void
+mii_dump(tulip_softc *sc, const char *label)
+{
+ int i;
+ uint16_t r;
+ uint32_t oui, part;
+
+ xprintf("%s\n", label);
+ oui = 0;
+ for (i = 0; i <= 6; ++i) {
+ r = mii_read_register(sc, i);
+ if (r != 0) xprintf("MII_REG%02x: %04x\n", i, r);
+ if (i == MII_PHYIDR1) {
+ oui = r << 6;
+ }
+ else if (i == MII_PHYIDR2) {
+ oui |= (r >> 10) & 0x3F;
+ part = (r >> 4) & 0x3F;
+ }
+ }
+ if (oui == OUI_NAT_SEMI) { /* DP83840, DP83840A */
+ for (i = 0x15; i <= 0x19; ++i) {
+ r = mii_read_register(sc, i);
+ if (r != 0) xprintf("MII_REG%02x: %04x\n", i, r);
+ }
+ }
+ else if (oui == OUI_LEVEL_ONE) { /* LXT970, etc. */
+ for (i = 0x10; i <= 0x14; ++i) {
+ r = mii_read_register(sc, i);
+ if (r != 0) xprintf("MII_REG%02x: %04x\n", i, r);
+ }
+ }
+}
+#else
+#define mii_dump(sc,label)
+#endif
+
+
+/* The following functions are suitable for all tulips with MII
+ interfaces. */
+
+static void
+mii_set_speed(tulip_softc *sc, int speed, int autoneg)
+{
+ uint16_t control;
+ uint16_t pcr;
+ uint32_t opmode = 0;
+
+ /* This is really just for NS DP83840/A. Needed? */
+ pcr = mii_read_register(sc, 0x17);
+ pcr |= (0x400|0x100|0x40|0x20);
+ mii_write_register(sc, 0x17, pcr);
+
+ control = mii_read_register(sc, MII_BMCR);
+
+ if (!autoneg) {
+ control &=~ (BMCR_ANENABLE | BMCR_RESTARTAN);
+ mii_write_register(sc, MII_BMCR, control);
+ control &=~ (BMCR_SPEED0 | BMCR_SPEED1 | BMCR_DUPLEX);
+ }
+
+ switch (speed) {
+ case ETHER_SPEED_10HDX:
+ default:
+ opmode = M_CSR6_SPEED_10_MII;
+ break;
+ case ETHER_SPEED_10FDX:
+ control |= BMCR_DUPLEX;
+ opmode = M_CSR6_SPEED_10_MII | M_CSR6_FULLDUPLEX;
+ break;
+ case ETHER_SPEED_100HDX:
+ control |= BMCR_SPEED100;
+ opmode = M_CSR6_SPEED_100_MII;
+ break;
+ case ETHER_SPEED_100FDX:
+ control |= BMCR_SPEED100 | BMCR_DUPLEX ;
+ opmode = M_CSR6_SPEED_100_MII | M_CSR6_FULLDUPLEX;
+ break;
+ }
+
+ if (!autoneg)
+ mii_write_register(sc, MII_BMCR, control);
+
+ opmode |= M_CSR6_MBO;
+#if TULIP_TUNE
+ opmode |= V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72);
+#else
+ opmode |= M_CSR6_STOREFWD;
+#endif
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+ mii_dump(sc, "setspeed PHY");
+}
+
+static void
+mii_autonegotiate(tulip_softc *sc)
+{
+ uint16_t control, status, cap;
+ unsigned int timeout;
+ int linkspeed;
+ int autoneg;
+
+ linkspeed = ETHER_SPEED_UNKNOWN;
+
+ /* Read twice to clear latching bits */
+ status = mii_read_register(sc, MII_BMSR);
+ status = mii_read_register(sc, MII_BMSR);
+ mii_dump(sc, "query PHY");
+
+ if ((status & (BMSR_AUTONEG | BMSR_LINKSTAT)) ==
+ (BMSR_AUTONEG | BMSR_LINKSTAT))
+ control = mii_read_register(sc, MII_BMCR);
+ else {
+ /* reset the PHY */
+ mii_write_register(sc, MII_BMCR, BMCR_RESET);
+ timeout = 3000;
+ for (;;) {
+ control = mii_read_register(sc, MII_BMCR);
+ if ((control && BMCR_RESET) == 0) break;
+ cfe_sleep(CFE_HZ/2);
+ timeout -= 500;
+ if (timeout <= 0) break;
+ }
+ if ((control & BMCR_RESET) != 0) {
+ xprintf("%s: PHY reset failed\n", tulip_devname(sc));
+ return;
+ }
+
+ status = mii_read_register(sc, MII_BMSR);
+ cap = ((status >> 6) & (ANAR_TXFD | ANAR_TXHD | ANAR_10FD | ANAR_10HD))
+ | PSB_802_3;
+ mii_write_register(sc, MII_ANAR, cap);
+ control |= (BMCR_ANENABLE | BMCR_RESTARTAN);
+ mii_write_register(sc, MII_BMCR, control);
+
+ timeout = 3000;
+ for (;;) {
+ status = mii_read_register(sc, MII_BMSR);
+ if ((status & BMSR_ANCOMPLETE) != 0) break;
+ cfe_sleep(CFE_HZ/2);
+ timeout -= 500;
+ if (timeout <= 0) break;
+ }
+ mii_dump(sc, "done PHY");
+ }
+
+ xprintf("%s: Link speed: ", tulip_devname(sc));
+ if ((status & BMSR_ANCOMPLETE) != 0) {
+ /* A link partner was negogiated... */
+
+ uint16_t remote = mii_read_register(sc, MII_ANLPAR);
+
+ autoneg = 1;
+ if ((remote & ANLPAR_TXFD) != 0) {
+ xprintf("100BaseT FDX");
+ linkspeed = ETHER_SPEED_100FDX;
+ }
+ else if ((remote & ANLPAR_TXHD) != 0) {
+ xprintf("100BaseT HDX");
+ linkspeed = ETHER_SPEED_100HDX;
+ }
+ else if ((remote & ANLPAR_10FD) != 0) {
+ xprintf("10BaseT FDX");
+ linkspeed = ETHER_SPEED_10FDX;
+ }
+ else if ((remote & ANLPAR_10HD) != 0) {
+ xprintf("10BaseT HDX");
+ linkspeed = ETHER_SPEED_10HDX;
+ }
+ xprintf("\n");
+ }
+ else {
+ /* no link partner negotiation */
+
+ autoneg = 0;
+ xprintf("Unknown, assuming 10BaseT\n");
+ control &=~ (BMCR_ANENABLE | BMCR_RESTARTAN);
+ mii_write_register(sc, MII_BMCR, control);
+ linkspeed = ETHER_SPEED_10HDX;
+ }
+
+ if ((status & BMSR_LINKSTAT) == 0)
+ mii_write_register(sc, MII_BMCR, control);
+ mii_set_speed(sc, linkspeed, autoneg);
+
+ status = mii_read_register(sc, MII_BMSR); /* clear latching bits */
+ mii_dump(sc, "final PHY");
+}
+
+
+/* Chip specific code */
+
+static void
+dc21143_set_speed(tulip_softc *sc, int speed)
+{
+ uint32_t opmode = 0;
+
+ WRITECSR(sc, R_CSR_SIAMODE0, 0);
+
+ switch (speed) {
+ case ETHER_SPEED_AUTO:
+ break;
+ case ETHER_SPEED_10HDX:
+ default:
+ WRITECSR(sc, R_CSR_SIAMODE1, M_CSR14_10BT_HD);
+ WRITECSR(sc, R_CSR_SIAMODE2, sc->gpdata);
+ opmode = M_CSR6_SPEED_10;
+ break;
+ case ETHER_SPEED_10FDX:
+ WRITECSR(sc, R_CSR_SIAMODE1, M_CSR14_10BT_FD);
+ WRITECSR(sc, R_CSR_SIAMODE2, sc->gpdata);
+ opmode = M_CSR6_SPEED_10 | M_CSR6_FULLDUPLEX;
+ break;
+ case ETHER_SPEED_100HDX:
+ WRITECSR(sc, R_CSR_SIAMODE1, 0);
+ WRITECSR(sc, R_CSR_SIAMODE2, sc->gpdata);
+ opmode = M_CSR6_SPEED_100;
+ break;
+ case ETHER_SPEED_100FDX:
+ WRITECSR(sc, R_CSR_SIAMODE1, 0);
+ WRITECSR(sc, R_CSR_SIAMODE2, sc->gpdata);
+ opmode = M_CSR6_SPEED_100 | M_CSR6_FULLDUPLEX;
+ break;
+ }
+
+ WRITECSR(sc, R_CSR_SIAMODE0, M_CSR13_CONN_NOT_RESET);
+
+ opmode |= M_CSR6_MBO;
+#if TULIP_TUNE
+ opmode |= V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72);
+#else
+ opmode |= M_CSR6_STOREFWD;
+#endif
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+}
+
+static void
+dc21143_autonegotiate(tulip_softc *sc)
+{
+ uint32_t opmode;
+ uint32_t tempword;
+ int count;
+ int linkspeed;
+
+ linkspeed = ETHER_SPEED_UNKNOWN;
+
+ /* Program the media setup into the CSRs. */
+ /* reset SIA */
+ WRITECSR(sc, R_CSR_SIAMODE0, 0);
+
+ /* set to speed_10, fullduplex to start_nway */
+ opmode =
+ M_CSR6_SPEED_10 |
+ M_CSR6_FULLDUPLEX |
+ M_CSR6_MBO;
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+
+ /* Choose advertised capabilities */
+ tempword =
+ M_CSR14_100BASETHALFDUP |
+ M_CSR14_100BASETFULLDUP |
+ M_CSR14_HALFDUPLEX10BASET;
+ WRITECSR(sc, R_CSR_SIAMODE1, tempword);
+
+ /* Enable autonegotiation */
+ tempword |= M_CSR14_AUTONEGOTIATE | 0xFFFF;
+ WRITECSR(sc, R_CSR_SIAMODE1, tempword);
+ WRITECSR(sc, R_CSR_SIAMODE2, sc->gpdata);
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+ WRITECSR(sc, R_CSR_SIAMODE0, M_CSR13_CONN_NOT_RESET);
+
+ /* STATE check nway, poll until a valid 10/100mbs signal seen */
+ WRITECSR(sc, R_CSR_STATUS, M_CSR5_LINKPASS); /* try to clear this... */
+
+ /* (Re)start negotiation */
+ tempword = READCSR(sc, R_CSR_SIASTATUS);
+ tempword &=~ M_CSR12_AUTONEGARBIT;
+ tempword |= V_CSR12_AUTONEGARBIT(0x1);
+
+ for (count = 0; count <= 13; count++) {
+ tempword = READCSR(sc, R_CSR_STATUS);
+ if (tempword & M_CSR5_LINKPASS)
+ break;
+ cfe_sleep(CFE_HZ/10);
+ }
+
+ if (count > 13)
+ xprintf("%s: Link autonegotiation failed\n", tulip_devname(sc));
+
+ /* STATE configure nway, check to see if any abilities common to us.
+ If they do, set to highest mode, if not, we will see if the partner
+ will do 100mb or 10mb - then set it */
+
+ tempword = READCSR(sc, R_CSR_SIASTATUS);
+ /* clear the autonegogiate complete bit */
+ WRITECSR(sc, R_CSR_STATUS, M_CSR5_LINKPASS);
+
+ if (tempword & M_CSR12_LINKPARTNEG) {
+ /* A link partner was negogiated... */
+
+ xprintf("%s: Link speed: ", tulip_devname(sc));
+ if (tempword & 0x01000000) { /* 100FD */
+ xprintf("100BaseT FDX");
+ linkspeed = ETHER_SPEED_100FDX;
+ }
+ else if (tempword & 0x00800000) { /* 100HD */
+ xprintf("100BaseT HDX");
+ linkspeed = ETHER_SPEED_100HDX;
+ }
+ else if (tempword & 0x00400000) { /* 10FD */
+ xprintf("10BaseT FDX");
+ linkspeed = ETHER_SPEED_10FDX;
+ }
+ else if (tempword & 0x00200000) { /* 10HD */
+ xprintf("10BaseT HDX");
+ linkspeed = ETHER_SPEED_10HDX;
+ }
+ xprintf("\n");
+ }
+ else {
+ /* no link partner negotiation */
+ /* disable link for 1.3 seconds to break any existing connections */
+
+ xprintf("%s: ", tulip_devname(sc));
+ dc21143_set_speed(sc, ETHER_SPEED_10HDX);
+ cfe_sleep(CFE_HZ/8);
+
+ tempword = READCSR(sc, R_CSR_SIASTATUS);
+
+ if ((tempword & 0x02) == 0) {
+ /* 100 mb signal present set to 100mb */
+ xprintf("No link partner... setting to 100BaseT HDX\n");
+ linkspeed = ETHER_SPEED_100HDX;
+ }
+ else if ((tempword & 0x04) == 0) {
+ /* 10 mb signal present */
+ xprintf("No link partner... setting to 10BaseT HDX\n");
+ linkspeed = ETHER_SPEED_10HDX;
+ }
+ else {
+ /* couldn't determine line speed, so set to 10mbs */
+ xprintf("Unknown; defaulting to 10BaseT HDX\n");
+ linkspeed = ETHER_SPEED_10HDX;
+ }
+ }
+
+ dc21143_set_speed(sc, linkspeed);
+}
+
+static void
+dc21143_set_loopback(tulip_softc *sc, int mode)
+{
+ uint32_t v;
+
+ WRITECSR(sc, R_CSR_SIAMODE0, 0);
+ if (mode == ETHER_LOOPBACK_EXT) {
+ /* deal with CSRs 13-15 */
+ }
+ cfe_sleep(CFE_HZ/10); /* check this */
+
+ /* Update the SIA registers */
+ v = READCSR(sc, R_CSR_SIAMODE0);
+ WRITECSR(sc, R_CSR_SIAMODE0, v &~ 0xFFFF);
+ v = READCSR(sc, R_CSR_SIAMODE1);
+ WRITECSR(sc, R_CSR_SIAMODE1, v &~ 0xFFFF);
+ v = READCSR(sc, R_CSR_SIAMODE2);
+ WRITECSR(sc, R_CSR_SIAMODE2, v | 0xC000); /* WC of HCKR, RMP */
+ if (mode == ETHER_LOOPBACK_OFF)
+ WRITECSR(sc, R_CSR_SIAMODE2, sc->gpdata);
+ else
+ WRITECSR(sc, R_CSR_SIAMODE2, (v &~ 0xFFFF) | M_CSR15_GP_AUIBNC);
+
+ WRITECSR(sc, R_CSR_SIAMODE0, M_CSR13_CONN_NOT_RESET);
+
+ sc->loopback = mode;
+}
+
+/* Known vendors with cards requiring special initialization. */
+#define K_PCI_VENDOR_COGENT 0x1109 /* inherited by Adaptec */
+#define K_PCI_VENDOR_PHOBOS 0x13D8
+#define K_PCI_VENDOR_ZNYZ 0x110D
+#define K_PCI_VENDOR_KINGSTON 0x2646
+
+static void
+dc21143_hwinit(tulip_softc *sc, uint8_t srom[])
+{
+ uint32_t v;
+ uint32_t csr6word, csr14word;
+
+ if (SROM_WORD(srom, SROM_VENDOR_INDEX) == K_PCI_VENDOR_COGENT) {
+ /* Cogent/Adaptec MII (ANA-6911A). */
+ sc->phy_type = MII;
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x0821 << 16);
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x0001 << 16);
+ cfe_sleep(CFE_HZ/10);
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x0000 << 16);
+ cfe_sleep(CFE_HZ/2);
+ sc->gpdata = 0;
+ }
+ else if (SROM_WORD(srom, SROM_VENDOR_INDEX) == K_PCI_VENDOR_ZNYZ) {
+ /* Znyz 34xQ adapters */
+ sc->phy_type = SYM;
+
+ /* The ZX345Q with wake-on-LAN enabled apparently clears ANE and
+ TAS on power up (but not cold reset) */
+ WRITECSR(sc, R_CSR_SIAMODE1, 0xFFFFFFFF);
+
+ /* The following is a reset workaround for QS/Kendin PHYs
+ as suggested by an Intel app note. Bit 0x40000 is the PHY
+ reset (low true) on Znyx cards. */
+ WRITECSR(sc, R_CSR_SIAMODE2,
+ M_CSR15_GP_CONTROLWRITE |
+ 0xF0000 | /* all outputs */
+ M_CSR15_GP_LED1 |
+ M_CSR15_GP_AUIBNC);
+ cfe_sleep(CFE_HZ/5);
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x40000); /* release reset */
+ cfe_sleep(CFE_HZ/5);
+ sc->gpdata = 0x40000 | M_CSR15_GP_AUIBNC;
+ }
+ else if (SROM_WORD(srom, SROM_VENDOR_INDEX) == K_PCI_VENDOR_KINGSTON) {
+ /* Kingston KNE100TX */
+ sc->phy_type = MII;
+ sc->gpdata = 0;
+ }
+ else if (SROM_WORD(srom, SROM_VENDOR_INDEX) == K_PCI_VENDOR_PHOBOS) {
+ /* Phobos 430TX quad card */
+ sc->phy_type = MII;
+#if 0 /* per EEPROM */
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x080E << 16);
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x000E << 16);
+ cfe_sleep(CFE_HZ/10);
+ sc->gpdata = 0x0E;
+#else /* following Adaptec 21143 with MII interface */
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x0821 << 16);
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x0001 << 16);
+ cfe_sleep(CFE_HZ/10);
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x0000 << 16);
+ cfe_sleep(CFE_HZ/2);
+ sc->gpdata = 0;
+#endif
+ }
+ else {
+ /* Most 21143 cards use the SYM interface. */
+ sc->phy_type = SYM;
+ WRITECSR(sc, R_CSR_SIAMODE2, M_CSR15_CONFIG_GEPS_LEDS);
+ sc->gpdata = M_CSR15_DEFAULT_VALUE;
+ }
+
+ if (sc->phy_type == MII) {
+ mii_probe(sc);
+ }
+
+ /* CSR0 - bus mode */
+#if TULIP_TUNE
+ v = V_CSR0_SKIPLEN(0) |
+ V_CSR0_CACHEALIGN(K_CSR0_ALIGN32) |
+ M_CSR0_READMULTENAB | M_CSR0_READLINEENAB |
+ M_CSR0_WRITEINVALENAB |
+ V_CSR0_BURSTLEN(K_CSR0_BURST32);
+#else
+ v = V_CSR0_SKIPLEN(0) |
+ V_CSR0_CACHEALIGN(K_CSR0_ALIGN32) |
+ V_CSR0_BURSTLEN(K_CSR0_BURST32);
+#endif
+#ifdef __MIPSEB
+ v |= M_CSR0_BIGENDIAN; /* big-endian data serialization */
+#endif
+ WRITECSR(sc, R_CSR_BUSMODE, v);
+
+ /* CSR6 - operation mode */
+ v = M_CSR6_PORTSEL |
+#if TULIP_TUNE
+ V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72) |
+#else
+ M_CSR6_STOREFWD |
+#endif
+ M_CSR6_MBO;
+ if (sc->phy_type == SYM)
+ v |= M_CSR6_PCSFUNC |M_CSR6_SCRAMMODE;
+ WRITECSR(sc, R_CSR_OPMODE, v);
+
+ /* About to muck with the SIA, reset it.(?) */
+ /* WRITECSR(sc, R_CSR_SIASTATUS, 0); */
+
+ /* Must shut off all transmit/receive in order to attempt to
+ achieve Full Duplex */
+ csr6word = READCSR(sc, R_CSR_OPMODE);
+ WRITECSR(sc, R_CSR_OPMODE, csr6word &~ (M_CSR6_TXSTART | M_CSR6_RXSTART));
+ csr6word = READCSR(sc, R_CSR_OPMODE);
+
+ WRITECSR(sc, R_CSR_RXRING, PTR_TO_PCI(sc->rxdscr_start));
+ WRITECSR(sc, R_CSR_TXRING, PTR_TO_PCI(sc->txdscr_start));
+
+ if (sc->phy_type == MII) {
+ if (sc->linkspeed == ETHER_SPEED_AUTO)
+ mii_autonegotiate(sc);
+ else
+ mii_set_speed(sc, sc->linkspeed, 0);
+ }
+ else {
+ if (sc->linkspeed == ETHER_SPEED_AUTO) {
+ dc21143_autonegotiate(sc);
+ }
+ else {
+ /* disable autonegotiate so we can set full duplex to on */
+ WRITECSR(sc, R_CSR_SIAMODE0, 0);
+ csr14word = READCSR(sc, R_CSR_SIAMODE1);
+ csr14word &=~ M_CSR14_AUTONEGOTIATE;
+ WRITECSR(sc, R_CSR_SIAMODE1, csr14word);
+ WRITECSR(sc, R_CSR_SIAMODE0, M_CSR13_CONN_NOT_RESET);
+
+ dc21143_set_speed(sc, sc->linkspeed);
+ }
+ }
+}
+
+
+static void
+dc21140_set_speed(tulip_softc *sc, int speed, int autoneg)
+{
+ mii_set_speed(sc, speed, autoneg);
+}
+
+static void
+dc21140_set_loopback(tulip_softc *sc, int mode)
+{
+ if (mode == ETHER_LOOPBACK_EXT) {
+ xprintf("%s: external loopback mode NYI\n", tulip_devname(sc));
+ mode = ETHER_LOOPBACK_OFF;
+ }
+ else if (mode != ETHER_LOOPBACK_INT)
+ mode = ETHER_LOOPBACK_OFF;
+
+ sc->loopback = mode;
+}
+
+static void
+dc21140_hwinit(tulip_softc *sc, uint8_t srom[])
+{
+ uint16_t leaf;
+ uint8_t gpr_control, gpr_data;
+ uint32_t v;
+ uint32_t opmode;
+
+ if (srom[SROM_FORMAT_INDEX] == 0 || srom[SROM_FORMAT_INDEX] > 4) {
+ gpr_control = 0x1F;
+ gpr_data = 0x00;
+ sc->phy_type = MII; /* Most 21140 cards use MII */
+ }
+ else {
+ leaf = SROM_WORD(srom, SROM_LEAF0_OFFSET_INDEX);
+ gpr_control = srom[leaf+2];
+ /* XXX We should parse and check all the leaf info */
+ if ((srom[leaf+4] & 0x80) == 0) {
+ gpr_data = 0x85; /* SYM, 100 Mb/s */
+ sc->phy_type = SYM;
+ }
+ else {
+ gpr_data = 0x00; /* MII */
+ sc->phy_type = MII;
+ }
+ }
+
+ /* Assume that we will use MII or SYM interface */
+ WRITECSR(sc, R_CSR_OPMODE, M_CSR6_PORTSEL);
+ RESET_ADAPTER(sc);
+
+ WRITECSR(sc, R_CSR_GENPORT, M_CSR12_CONTROL | gpr_control);
+ WRITECSR(sc, R_CSR_GENPORT, gpr_data); /* setup PHY */
+
+ if (sc->phy_type == MII) {
+ mii_probe(sc);
+ }
+
+ /* CSR0 - bus mode */
+#if TULIP_TUNE
+ v = V_CSR0_SKIPLEN(0) |
+ V_CSR0_CACHEALIGN(K_CSR0_ALIGN32) |
+ M_CSR0_READMULTENAB | M_CSR0_READLINEENAB |
+ M_CSR0_WRITEINVALENAB |
+ V_CSR0_BURSTLEN(K_CSR0_BURST32);
+#else
+ v = V_CSR0_SKIPLEN(0) |
+ V_CSR0_CACHEALIGN(K_CSR0_ALIGN32) |
+ V_CSR0_BURSTLEN(K_CSR0_BURST32);
+#endif
+#ifdef __MIPSEB
+ v |= M_CSR0_BIGENDIAN; /* big-endian data serialization */
+#endif
+ WRITECSR(sc, R_CSR_BUSMODE, v);
+
+ /* CSR6 - operation mode */
+ v = M_CSR6_PORTSEL |
+#if TULIP_TUNE
+ V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72) |
+#else
+ M_CSR6_STOREFWD |
+#endif
+ M_CSR6_MBO;
+ WRITECSR(sc, R_CSR_OPMODE, v);
+
+ /* Must shut off all transmit/receive in order to attempt to
+ achieve Full Duplex */
+ opmode = READCSR(sc, R_CSR_OPMODE);
+ WRITECSR(sc, R_CSR_OPMODE, opmode &~ (M_CSR6_TXSTART | M_CSR6_RXSTART));
+ opmode = READCSR(sc, R_CSR_OPMODE);
+
+ WRITECSR(sc, R_CSR_RXRING, PTR_TO_PCI(sc->rxdscr_start));
+ WRITECSR(sc, R_CSR_TXRING, PTR_TO_PCI(sc->txdscr_start));
+
+ if (sc->phy_type == MII) {
+ if (sc->linkspeed == ETHER_SPEED_AUTO)
+ mii_autonegotiate(sc);
+ else
+ mii_set_speed(sc, sc->linkspeed, 0);
+ }
+ else {
+ /* XXX The 21140 requires a soft reset after changing PORTSEL.
+ For now, remain committed to the SYM port (100 Mb/s) */
+ switch (sc->linkspeed) {
+ default:
+ sc->linkspeed = ETHER_SPEED_100HDX; /* for now */
+ /* fall through */
+ case ETHER_SPEED_100HDX:
+ opmode |= M_CSR6_SPEED_100;
+ break;
+ case ETHER_SPEED_100FDX:
+ opmode |= M_CSR6_SPEED_100 | M_CSR6_FULLDUPLEX;
+ break;
+ }
+
+ /* XXX Need to reset and reinitialize if we choose SPEED_10 above */
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+ }
+}
+
+
+static void
+dc21041_set_speed(tulip_softc *sc, int speed)
+{
+ uint32_t opmode = 0;
+
+ WRITECSR(sc, R_CSR_SIAMODE0, 0);
+
+ /* For now, always force 10BT, HDX (21041, Table 3-62) */
+ switch (speed) {
+ case ETHER_SPEED_10HDX:
+ default:
+ WRITECSR(sc, R_CSR_SIAMODE1, 0x7F3F);
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x0008);
+ opmode = M_CSR6_SPEED_10;
+ break;
+ }
+
+ WRITECSR(sc, R_CSR_SIAMODE0, 0xEF00 | M_CSR13_CONN_NOT_RESET);
+ cfe_sleep(CFE_HZ/10);
+
+ opmode |= V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72);
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+}
+
+static void
+dc21041_set_loopback(tulip_softc *sc, int mode)
+{
+ /* For now, always assume 10BT */
+ uint32_t mode0;
+
+ WRITECSR(sc, R_CSR_SIAMODE0, 0);
+ cfe_sleep(CFE_HZ/10); /* check this */
+
+ /* Update the SIA registers */
+ if (mode == ETHER_LOOPBACK_EXT) {
+ /* NB: this is really just internal but through the 10BT endec */
+ WRITECSR(sc, R_CSR_SIAMODE1, 0x7A3F);
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x0008);
+ mode0 = 0;
+ }
+ else if (mode == ETHER_LOOPBACK_INT) {
+ /* MAC internal loopback, no SIA */
+ WRITECSR(sc, R_CSR_SIAMODE1, 0x0000);
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x000E);
+ mode0 = M_CSR13_CONN_AUI_10BT;
+ }
+ else {
+ mode = ETHER_LOOPBACK_OFF;
+ WRITECSR(sc, R_CSR_SIAMODE1, 0x7F3F);
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x0008);
+ mode0 = 0;
+ }
+
+ WRITECSR(sc, R_CSR_SIAMODE0, 0xEF00 | mode0 | M_CSR13_CONN_NOT_RESET );
+
+ sc->loopback = mode;
+}
+
+static void
+dc21041_hwinit(tulip_softc *sc, uint8_t srom[])
+{
+ uint32_t v;
+
+ sc->phy_type = SRL;
+
+ /* CSR0 - bus mode */
+ v = V_CSR0_SKIPLEN(0) |
+ V_CSR0_CACHEALIGN(K_CSR0_ALIGN32) |
+ V_CSR0_BURSTLEN(K_CSR0_BURST32);
+#ifdef __MIPSEB
+ v |= M_CSR0_BIGENDIAN; /* big-endian data serialization */
+#endif
+ WRITECSR(sc, R_CSR_BUSMODE, v);
+
+ WRITECSR(sc, R_CSR_INTMASK, 0);
+
+ WRITECSR(sc, R_CSR_RXRING, PTR_TO_PCI(sc->rxdscr_start));
+ WRITECSR(sc, R_CSR_TXRING, PTR_TO_PCI(sc->txdscr_start));
+
+ /* For now, always force 10BT, HDX (21041, Table 3-62) */
+ dc21041_set_speed(sc, ETHER_SPEED_10HDX);
+}
+
+
+static void
+dc21040_set_speed(tulip_softc *sc, int speed)
+{
+ uint32_t opmode = 0;
+
+ WRITECSR(sc, R_CSR_SIAMODE0, 0);
+
+ /* For now, force 10BT, HDX unless FDX requested (21040, Table 3-53) */
+ switch (speed) {
+ case ETHER_SPEED_10HDX:
+ default:
+ WRITECSR(sc, R_CSR_SIAMODE1, 0xFFFF);
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x0000);
+ opmode = 0;
+ break;
+ case ETHER_SPEED_10FDX:
+ WRITECSR(sc, R_CSR_SIAMODE1, 0xFFFD);
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x0000);
+ opmode = M_CSR6_FULLDUPLEX;
+ break;
+ }
+
+ WRITECSR(sc, R_CSR_SIAMODE0, 0xEF00 | M_CSR13_CONN_NOT_RESET);
+ cfe_sleep(CFE_HZ/10);
+
+ opmode |= V_CSR6_THRESHCONTROL(K_CSR6_TXTHRES_128_72);
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+}
+
+static void
+dc21040_set_loopback(tulip_softc *sc, int mode)
+{
+ WRITECSR(sc, R_CSR_SIAMODE0, 0);
+ cfe_sleep(CFE_HZ/10); /* check this */
+
+ /* Update the SIA registers */
+ if (mode == ETHER_LOOPBACK_EXT) {
+ /* NB: this is on-chip loopback through the 10BT endec */
+ WRITECSR(sc, R_CSR_SIAMODE1, 0xFEFB);
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x0008);
+ }
+ else if (mode == ETHER_LOOPBACK_INT) {
+ /* MAC internal loopback, no SIA */
+ WRITECSR(sc, R_CSR_SIAMODE1, 0x0000);
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x0000);
+ }
+ else {
+ mode = ETHER_LOOPBACK_OFF;
+ WRITECSR(sc, R_CSR_SIAMODE1, 0xFFFF);
+ WRITECSR(sc, R_CSR_SIAMODE2, 0x0000);
+ }
+
+ WRITECSR(sc, R_CSR_SIAMODE0, 0x8F00 | M_CSR13_CONN_NOT_RESET );
+
+ sc->loopback = mode;
+}
+
+static void
+dc21040_hwinit(tulip_softc *sc, uint8_t srom[])
+{
+ uint32_t v;
+
+ sc->phy_type = SRL;
+
+ /* CSR0 - bus mode */
+ v = V_CSR0_SKIPLEN(0) |
+ V_CSR0_CACHEALIGN(K_CSR0_ALIGN32) |
+ V_CSR0_BURSTLEN(K_CSR0_BURST32);
+#ifdef __MIPSEB
+ v |= M_CSR0_BIGENDIAN; /* big-endian data serialization */
+#endif
+ WRITECSR(sc, R_CSR_BUSMODE, v);
+
+ WRITECSR(sc, R_CSR_INTMASK, 0);
+
+ dc21040_set_speed(sc, sc->linkspeed);
+}
+
+
+static void
+tulip_hwinit(tulip_softc *sc)
+{
+ if (sc->state == eth_state_uninit) {
+ uint8_t srom[SROM_SIZE];
+
+ /* Wake-on-LAN apparently powers up with PORTSEL = 1 */
+ WRITECSR(sc, R_CSR_OPMODE,
+ READCSR(sc, R_CSR_OPMODE) &~ M_CSR6_PORTSEL);
+
+ RESET_ADAPTER(sc);
+ sc->state = eth_state_off;
+ sc->bus_errors = 0;
+
+ rom_read_all(sc, srom); /* XXX read just once? */
+ rom_dump(srom);
+
+ switch (sc->device) {
+ case K_PCI_ID_DC21040:
+ dc21040_hwinit(sc, srom);
+ break;
+ case K_PCI_ID_DC21041:
+ dc21041_hwinit(sc, srom);
+ break;
+ case K_PCI_ID_DC21140:
+ dc21140_hwinit(sc, srom);
+ break;
+ case K_PCI_ID_DC21143:
+ dc21143_hwinit(sc, srom);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void
+tulip_setaddr(tulip_softc *sc)
+{
+ int idx;
+ tulip_cam *cam;
+ eth_pkt_t *pkt;
+
+ pkt = eth_alloc_pkt(sc);
+ if (pkt) {
+ pkt->length = CAM_SETUP_BUFFER_SIZE;
+ cam = (tulip_cam *) pkt->buffer;
+
+#ifdef __MIPSEB
+ cam->p.physical[0][0] = (((uint32_t) sc->hwaddr[0] << 8) |
+ (uint32_t) sc->hwaddr[1]) << 16;
+ cam->p.physical[0][1] = (((uint32_t) sc->hwaddr[2] << 8) |
+ (uint32_t) sc->hwaddr[3]) << 16;
+ cam->p.physical[0][2] = (((uint32_t) sc->hwaddr[4] << 8) |
+ (uint32_t) sc->hwaddr[5]) << 16;
+ for (idx = 1; idx < CAM_PERFECT_ENTRIES; idx++) {
+ cam->p.physical[idx][0] = 0xFFFF0000;
+ cam->p.physical[idx][1] = 0xFFFF0000;
+ cam->p.physical[idx][2] = 0xFFFF0000;
+ }
+#else
+ cam->p.physical[0][0] = ((uint32_t) sc->hwaddr[0]) |
+ (((uint32_t) sc->hwaddr[1]) << 8);
+ cam->p.physical[0][1] = ((uint32_t) sc->hwaddr[2]) |
+ (((uint32_t) sc->hwaddr[3]) << 8);
+ cam->p.physical[0][2] = ((uint32_t) sc->hwaddr[4]) |
+ (((uint32_t) sc->hwaddr[5]) << 8);
+ for (idx = 1; idx < CAM_PERFECT_ENTRIES; idx++) {
+ cam->p.physical[idx][0] = 0x0000FFFF;
+ cam->p.physical[idx][1] = 0x0000FFFF;
+ cam->p.physical[idx][2] = 0x0000FFFF;
+ }
+#endif
+
+ pkt->flags |= ETH_TX_SETUP;
+ sc->state = eth_state_setup;
+ if (tulip_transmit(sc, pkt) != 0) {
+ xprintf("%s: failed setup\n", tulip_devname(sc));
+ dumpstat(sc);
+ eth_free_pkt(sc, pkt);
+ }
+ }
+}
+
+static void
+tulip_setspeed(tulip_softc *sc, int speed)
+{
+ switch (sc->device) {
+ case K_PCI_ID_DC21040:
+ dc21040_set_speed(sc, speed);
+ break;
+ case K_PCI_ID_DC21041:
+ dc21041_set_speed(sc, speed);
+ break;
+ case K_PCI_ID_DC21140:
+ dc21140_set_speed(sc, speed, 0);
+ break;
+ case K_PCI_ID_DC21143:
+ dc21143_set_speed(sc, speed);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+tulip_setloopback(tulip_softc *sc, int mode)
+{
+ switch (sc->device) {
+ case K_PCI_ID_DC21040:
+ dc21040_set_loopback(sc, mode);
+ break;
+ case K_PCI_ID_DC21041:
+ dc21041_set_loopback(sc, mode);
+ break;
+ case K_PCI_ID_DC21140:
+ dc21140_set_loopback(sc, mode);
+ break;
+ case K_PCI_ID_DC21143:
+ dc21143_set_loopback(sc, mode);
+ break;
+ default:
+ break;
+ }
+ cfe_sleep(CFE_HZ/10);
+}
+
+
+static void
+tulip_isr(void *arg)
+{
+ uint32_t status;
+ uint32_t csr5;
+ tulip_softc *sc = (tulip_softc *)arg;
+
+#if IPOLL
+ sc->interrupts++;
+#endif
+
+ for (;;) {
+
+ /* Read the interrupt status. */
+ csr5 = READCSR(sc, R_CSR_STATUS);
+ status = csr5 & (
+ M_CSR5_RXINT | M_CSR5_RXBUFUNAVAIL |
+ M_CSR5_TXINT | M_CSR5_TXUNDERFLOW |
+ M_CSR5_FATALBUSERROR);
+
+ /* if there are no more interrupts, leave now. */
+ if (status == 0) break;
+
+ /* Clear the pending interrupt. */
+ WRITECSR(sc, R_CSR_STATUS, status);
+
+ /* Now, test each unmasked bit in the interrupt register and
+ handle each interrupt type appropriately. */
+
+ if (status & M_CSR5_FATALBUSERROR) {
+ WRITECSR(sc, R_CSR_INTMASK, 0);
+
+ xprintf("%s: bus error %02x\n",
+ tulip_devname(sc), G_CSR5_ERRORBITS(csr5));
+ dumpstat(sc);
+ sc->bus_errors++;
+ if (sc->bus_errors >= 2) {
+ dumpcsrs(sc);
+ RESET_ADAPTER(sc);
+ sc->state = eth_state_off;
+ sc->bus_errors = 0;
+ }
+#if IPOLL
+ else
+ WRITECSR(sc, R_CSR_INTMASK, sc->intmask);
+#endif
+ }
+
+ if (status & M_CSR5_RXINT) {
+#if IPOLL
+ sc->rx_interrupts++;
+#endif
+ tulip_procrxring(sc);
+ }
+
+ if (status & M_CSR5_TXINT) {
+#if IPOLL
+ sc->tx_interrupts++;
+#endif
+ tulip_proctxring(sc);
+ }
+
+ if (status & (M_CSR5_TXUNDERFLOW | M_CSR5_RXBUFUNAVAIL)) {
+ if (status & M_CSR5_TXUNDERFLOW) {
+ xprintf("%s: tx underrun, %08x\n", tulip_devname(sc), csr5);
+ /* Try to restart */
+ WRITECSR(sc, R_CSR_TXPOLL, 1);
+ }
+ if (status & M_CSR5_RXBUFUNAVAIL) {
+ /* Try to restart */
+ WRITECSR(sc, R_CSR_RXPOLL, 1);
+ }
+ }
+ }
+}
+
+
+static void
+tulip_start(tulip_softc *sc)
+{
+ uint32_t opmode;
+
+ tulip_hwinit(sc);
+
+ WRITECSR(sc, R_CSR_RXRING, PTR_TO_PCI(sc->rxdscr_start));
+ WRITECSR(sc, R_CSR_TXRING, PTR_TO_PCI(sc->txdscr_start));
+
+ opmode = READCSR(sc, R_CSR_OPMODE);
+ opmode &=~ M_CSR6_OPMODE; /* no loopback */
+ if (sc->loopback != ETHER_LOOPBACK_OFF) {
+ opmode &=~ M_CSR6_FULLDUPLEX;
+ opmode |= M_CSR6_PORTSEL;
+ if (sc->loopback == ETHER_LOOPBACK_EXT)
+ opmode |= M_CSR6_EXTLOOPBACK;
+ else
+ opmode |= M_CSR6_INTLOOPBACK;
+ }
+
+ sc->intmask = 0;
+ WRITECSR(sc, R_CSR_INTMASK, 0); /* no interrupts */
+ WRITECSR(sc, R_CSR_STATUS, 0x1FFFF); /* clear any pending */
+ READCSR(sc, R_CSR_STATUS); /* push the write */
+
+ sc->interrupts = 0;
+ sc->rx_interrupts = sc->tx_interrupts = 0;
+
+#if IPOLL
+ cfe_request_irq(sc->irq, tulip_isr, sc, CFE_IRQ_FLAGS_SHARED, 0);
+
+ sc->intmask = M_CSR7_RXINT | M_CSR7_TXINT |
+ M_CSR7_NORMALINT;
+ sc->intmask |= M_CSR7_FATALBUSERROR | M_CSR7_TXUNDERFLOW |
+ M_CSR7_ABNORMALINT;
+ WRITECSR(sc, R_CSR_INTMASK, sc->intmask);
+#endif
+
+ if (sc->loopback == ETHER_LOOPBACK_OFF) {
+ opmode |= M_CSR6_TXSTART;
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+ tulip_setaddr(sc);
+ }
+ else {
+ opmode |= M_CSR6_TXSTART | M_CSR6_RXSTART;
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+ }
+}
+
+static void
+tulip_stop(tulip_softc *sc)
+{
+ uint32_t opmode;
+ uint32_t status;
+ int count;
+
+ WRITECSR(sc, R_CSR_INTMASK, 0);
+ sc->intmask = 0;
+#if IPOLL
+ cfe_free_irq(sc->irq, 0);
+#endif
+ WRITECSR(sc, R_CSR_STATUS, 0x1FFFF);
+ opmode = READCSR(sc, R_CSR_OPMODE);
+ opmode &=~ (M_CSR6_TXSTART | M_CSR6_RXSTART);
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+
+ /* wait for any DMA activity to terminate */
+ for (count = 0; count <= 13; count++) {
+ status = READCSR(sc, R_CSR_STATUS);
+ if ((status & (M_CSR5_RXPROCSTATE | M_CSR5_TXPROCSTATE)) == 0)
+ break;
+ cfe_sleep(CFE_HZ/10);
+ }
+ if (count > 13) {
+ xprintf("%s: idle state not achieved\n", tulip_devname(sc));
+ dumpstat(sc);
+ RESET_ADAPTER(sc);
+ sc->state = eth_state_uninit;
+#if 1
+ sc->linkspeed = ETHER_SPEED_AUTO;
+#endif
+ }
+ else if (sc->loopback != ETHER_LOOPBACK_OFF) {
+ tulip_setloopback(sc, ETHER_LOOPBACK_OFF);
+ opmode &=~ M_CSR6_OPMODE;
+ WRITECSR(sc, R_CSR_OPMODE, opmode);
+ }
+
+ if (sc->outpkts > 1) {
+ /* heuristic: suppress stats for initial mode changes */
+ xprintf("%s: %d sent, %d received, %d interrupts\n",
+ tulip_devname(sc), sc->outpkts, sc->inpkts, sc->interrupts);
+ xprintf(" %d rx interrupts, %d tx interrupts\n",
+ sc->rx_interrupts, sc->tx_interrupts);
+ }
+}
+
+
+/* *********************************************************************
+ * ETH_PARSE_XDIGIT(c)
+ *
+ * Parse a hex digit, returning its value
+ *
+ * Input parameters:
+ * c - character
+ *
+ * Return value:
+ * hex value, or -1 if invalid
+ ********************************************************************* */
+static int
+eth_parse_xdigit(char c)
+{
+ int digit;
+
+ if ((c >= '0') && (c <= '9')) digit = c - '0';
+ else if ((c >= 'a') && (c <= 'f')) digit = c - 'a' + 10;
+ else if ((c >= 'A') && (c <= 'F')) digit = c - 'A' + 10;
+ else digit = -1;
+
+ return digit;
+}
+
+/* *********************************************************************
+ * ETH_PARSE_HWADDR(str,hwaddr)
+ *
+ * Convert a string in the form xx:xx:xx:xx:xx:xx into a 6-byte
+ * Ethernet address.
+ *
+ * Input parameters:
+ * str - string
+ * hwaddr - pointer to hardware address
+ *
+ * Return value:
+ * 0 if ok, else -1
+ ********************************************************************* */
+static int
+eth_parse_hwaddr(char *str, uint8_t *hwaddr)
+{
+ int digit1, digit2;
+ int idx = ENET_ADDR_LEN;
+
+ while (*str && (idx > 0)) {
+ digit1 = eth_parse_xdigit(*str);
+ if (digit1 < 0) return -1;
+ str++;
+ if (!*str) return -1;
+
+ if ((*str == ':') || (*str == '-')) {
+ digit2 = digit1;
+ digit1 = 0;
+ }
+ else {
+ digit2 = eth_parse_xdigit(*str);
+ if (digit2 < 0) return -1;
+ str++;
+ }
+
+ *hwaddr++ = (digit1 << 4) | digit2;
+ idx--;
+
+ if ((*str == ':') || (*str == '-'))
+ str++;
+ }
+ return 0;
+}
+
+/* *********************************************************************
+ * ETH_INCR_HWADDR(hwaddr,incr)
+ *
+ * Increment a 6-byte Ethernet hardware address, with carries
+ *
+ * Input parameters:
+ * hwaddr - pointer to hardware address
+ * incr - desired increment
+ *
+ * Return value:
+ * none
+ ********************************************************************* */
+static void
+eth_incr_hwaddr(uint8_t *hwaddr, unsigned incr)
+{
+ int idx;
+ int carry;
+
+ idx = 5;
+ carry = incr;
+ while (idx >= 0 && carry != 0) {
+ unsigned sum = hwaddr[idx] + carry;
+
+ hwaddr[idx] = sum & 0xFF;
+ carry = sum >> 8;
+ idx--;
+ }
+}
+
+
+/* *********************************************************************
+ * Declarations for CFE Device Driver Interface routines
+ ********************************************************************* */
+
+static int tulip_ether_open(cfe_devctx_t *ctx);
+static int tulip_ether_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int tulip_ether_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
+static int tulip_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int tulip_ether_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
+static int tulip_ether_close(cfe_devctx_t *ctx);
+#if 0
+static void tulip_ether_reset(void *softc);
+#endif
+
+/* *********************************************************************
+ * CFE Device Driver dispatch structure
+ ********************************************************************* */
+
+const static cfe_devdisp_t tulip_ether_dispatch = {
+ tulip_ether_open,
+ tulip_ether_read,
+ tulip_ether_inpstat,
+ tulip_ether_write,
+ tulip_ether_ioctl,
+ tulip_ether_close,
+ NULL, /* tulip_ether_poll */
+ NULL /* tulip_ether_reset */
+};
+
+/* *********************************************************************
+ * CFE Device Driver descriptor
+ ********************************************************************* */
+
+const cfe_driver_t dc21143drv = {
+ "DC21x4x Ethernet",
+ "eth",
+ CFE_DEV_NETWORK,
+ &tulip_ether_dispatch,
+ tulip_ether_probe
+};
+
+
+static int
+tulip_ether_attach(cfe_driver_t *drv,
+ pcitag_t tag, int index, uint8_t hwaddr[])
+{
+ tulip_softc *softc;
+ uint32_t device;
+ uint32_t class;
+ uint32_t reg;
+ phys_addr_t pa;
+ const char *devname;
+ char descr[100];
+ uint8_t romaddr[ENET_ADDR_LEN];
+
+ device = pci_conf_read(tag, R_CFG_CFID);
+ class = pci_conf_read(tag, R_CFG_CFRV);
+
+ reg = pci_conf_read(tag, R_CFG_CPMS);
+
+ reg = pci_conf_read(tag, R_CFG_CFDD);
+ pci_conf_write(tag, R_CFG_CFDD, 0);
+ reg = pci_conf_read(tag, R_CFG_CFDD);
+
+#if 1
+ /* Use memory space for the CSRs */
+ pci_map_mem(tag, R_CFG_CBMA, PCI_MATCH_BITS, &pa);
+#else
+ /* Use i/o space for the CSRs */
+ pci_map_io(tag, R_CFG_CBIO, PCI_MATCH_BITS, &pa);
+#endif
+
+ softc = (tulip_softc *) KMALLOC(sizeof(tulip_softc), 0);
+ if (softc == NULL) {
+ xprintf("DC21x4x: No memory to complete probe\n");
+ return 0;
+ }
+ memset(softc, 0, sizeof(*softc));
+
+ softc->membase = (uint32_t)pa;
+ softc->irq = pci_conf_read(tag, R_CFG_CFIT) & 0xFF;
+
+ softc->tag = tag;
+ softc->device = PCI_PRODUCT(device);
+ softc->revision = PCI_REVISION(class);
+ softc->devctx = NULL;
+
+#if 1
+ softc->linkspeed = ETHER_SPEED_AUTO; /* select autonegotiation */
+#else
+ softc->linkspeed = ETHER_SPEED_100FDX; /* 100 Mbps, full duplex */
+#endif
+ softc->loopback = ETHER_LOOPBACK_OFF;
+ memcpy(softc->hwaddr, hwaddr, ENET_ADDR_LEN);
+
+ tulip_init(softc);
+
+ /* Prefer address in srom */
+ if (rom_read_addr(softc, romaddr) == 0) {
+ memcpy(softc->hwaddr, romaddr, ENET_ADDR_LEN);
+ }
+
+ softc->state = eth_state_uninit;
+
+ switch (PCI_PRODUCT(device)) {
+ case K_PCI_ID_DC21040:
+ devname = "DC21040"; break;
+ case K_PCI_ID_DC21041:
+ devname = "DC21041"; break;
+ case K_PCI_ID_DC21140:
+ devname = "DC21140"; break;
+ case K_PCI_ID_DC21143:
+ devname = "DC21143"; break;
+ default:
+ devname = "DC21x4x"; break;
+ }
+
+ xsprintf(descr, "%s Ethernet at 0x%X (%02X-%02X-%02X-%02X-%02X-%02X)",
+ devname, softc->membase,
+ softc->hwaddr[0], softc->hwaddr[1], softc->hwaddr[2],
+ softc->hwaddr[3], softc->hwaddr[4], softc->hwaddr[5]);
+
+ cfe_attach(drv, softc, NULL, descr);
+ return 1;
+}
+
+
+/* *********************************************************************
+ * TULIP_ETHER_PROBE(drv,probe_a,probe_b,probe_ptr)
+ *
+ * Probe and install drivers for all DC21x4x Ethernet controllers.
+ * For each, create a context structure and attach to the
+ * specified network device.
+ *
+ * Input parameters:
+ * drv - driver descriptor
+ * probe_a - not used
+ * probe_b - not used
+ * probe_ptr - string pointer to hardware address for the first
+ * MAC, in the form xx:xx:xx:xx:xx:xx
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void
+tulip_ether_probe(cfe_driver_t *drv,
+ unsigned long probe_a, unsigned long probe_b,
+ void *probe_ptr)
+{
+ int index;
+ int n;
+ uint8_t hwaddr[ENET_ADDR_LEN];
+
+ if (probe_ptr)
+ eth_parse_hwaddr((char *) probe_ptr, hwaddr);
+ else {
+ /* use default address 40-00-00-10-11-11 */
+ hwaddr[0] = 0x40; hwaddr[1] = 0x00; hwaddr[2] = 0x00;
+ hwaddr[3] = 0x10; hwaddr[4] = 0x11; hwaddr[5] = 0x11;
+ }
+
+ n = 0;
+ index = 0;
+ for (;;) {
+ pcitag_t tag;
+ pcireg_t device;
+
+ if (pci_find_class(PCI_CLASS_NETWORK, index, &tag) != 0)
+ break;
+
+ index++;
+
+ device = pci_conf_read(tag, R_CFG_CFID);
+ if (PCI_VENDOR(device) == K_PCI_VENDOR_DEC) {
+#if 0 /* this currently (2.1.1) generates a bad code in PIC mode */
+ switch (PCI_PRODUCT(device)) {
+ case K_PCI_ID_DC21040:
+ case K_PCI_ID_DC21041:
+ case K_PCI_ID_DC21140:
+ case K_PCI_ID_DC21143:
+ tulip_ether_attach(drv, tag, n, hwaddr);
+ n++;
+ eth_incr_hwaddr(hwaddr, 1);
+ break;
+ default:
+ break;
+ }
+#else
+ if (PCI_PRODUCT(device) == K_PCI_ID_DC21040 ||
+ PCI_PRODUCT(device) == K_PCI_ID_DC21041 ||
+ PCI_PRODUCT(device) == K_PCI_ID_DC21140 ||
+ PCI_PRODUCT(device) == K_PCI_ID_DC21143) {
+
+ tulip_ether_attach(drv, tag, n, hwaddr);
+ n++;
+ eth_incr_hwaddr(hwaddr, 1);
+ }
+#endif
+ }
+ }
+}
+
+
+/* The functions below are called via the dispatch vector for the 21x4x. */
+
+/* *********************************************************************
+ * TULIP_ETHER_OPEN(ctx)
+ *
+ * Open the Ethernet device. The MAC is reset, initialized, and
+ * prepared to receive and send packets.
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ *
+ * Return value:
+ * status, 0 = ok
+ ********************************************************************* */
+static int
+tulip_ether_open(cfe_devctx_t *ctx)
+{
+ tulip_softc *softc = ctx->dev_softc;
+
+ if (softc->state == eth_state_on)
+ tulip_stop(softc);
+
+ softc->devctx = ctx;
+ tulip_start(softc);
+
+#if XPOLL
+ tulip_isr(softc);
+#endif
+
+ return 0;
+}
+
+/* *********************************************************************
+ * TULIP_ETHER_READ(ctx,buffer)
+ *
+ * Read a packet from the Ethernet device. If no packets are
+ * available, the read will succeed but return 0 bytes.
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ * buffer - pointer to buffer descriptor.
+ *
+ * Return value:
+ * status, 0 = ok
+ ********************************************************************* */
+static int
+tulip_ether_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ tulip_softc *softc = ctx->dev_softc;
+ eth_pkt_t *pkt;
+ int blen;
+
+#if XPOLL
+ tulip_isr(softc);
+#endif
+
+ if (softc->state != eth_state_on) return -1;
+
+ CS_ENTER(softc);
+ pkt = (eth_pkt_t *) q_deqnext(&(softc->rxqueue));
+ CS_EXIT(softc);
+
+ if (pkt == NULL) {
+ buffer->buf_retlen = 0;
+ return 0;
+ }
+
+ blen = buffer->buf_length;
+ if (blen > pkt->length) blen = pkt->length;
+
+ blockcopy(buffer->buf_ptr, pkt->buffer, blen);
+ buffer->buf_retlen = blen;
+
+ eth_free_pkt(softc, pkt);
+ tulip_fillrxring(softc);
+
+#if XPOLL
+ tulip_isr(softc);
+#endif
+
+ return 0;
+}
+
+/* *********************************************************************
+ * TULIP_ETHER_INPSTAT(ctx,inpstat)
+ *
+ * Check for received packets on the Ethernet device
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ * inpstat - pointer to input status structure
+ *
+ * Return value:
+ * status, 0 = ok
+ ********************************************************************* */
+static int
+tulip_ether_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat)
+{
+ tulip_softc *softc = ctx->dev_softc;
+
+#if XPOLL
+ tulip_isr(softc);
+#endif
+
+ if (softc->state != eth_state_on) return -1;
+
+ /* We avoid an interlock here because the result is a hint and an
+ interrupt cannot turn a non-empty queue into an empty one. */
+ inpstat->inp_status = (q_isempty(&(softc->rxqueue))) ? 0 : 1;
+
+ return 0;
+}
+
+/* *********************************************************************
+ * TULIP_ETHER_WRITE(ctx,buffer)
+ *
+ * Write a packet to the Ethernet device.
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ * buffer - pointer to buffer descriptor.
+ *
+ * Return value:
+ * status, 0 = ok
+ ********************************************************************* */
+static int
+tulip_ether_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ tulip_softc *softc = ctx->dev_softc;
+ eth_pkt_t *pkt;
+ int blen;
+
+#if XPOLL
+ tulip_isr(softc);
+#endif
+
+ if (softc->state != eth_state_on) return -1;
+
+ pkt = eth_alloc_pkt(softc);
+ if (!pkt) return CFE_ERR_NOMEM;
+
+ blen = buffer->buf_length;
+ if (blen > pkt->length) blen = pkt->length;
+
+ blockcopy(pkt->buffer, buffer->buf_ptr, blen);
+ pkt->length = blen;
+
+ if (tulip_transmit(softc, pkt) != 0) {
+ eth_free_pkt(softc,pkt);
+ return CFE_ERR_IOERR;
+ }
+
+#if XPOLL
+ tulip_isr(softc);
+#endif
+
+ return 0;
+}
+
+/* *********************************************************************
+ * TULIP_ETHER_IOCTL(ctx,buffer)
+ *
+ * Do device-specific I/O control operations for the device
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ * buffer - pointer to buffer descriptor.
+ *
+ * Return value:
+ * status, 0 = ok
+ ********************************************************************* */
+static int
+tulip_ether_ioctl(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
+{
+ tulip_softc *softc = ctx->dev_softc;
+ int *argp;
+ int mode;
+ int speed;
+
+ switch ((int)buffer->buf_ioctlcmd) {
+ case IOCTL_ETHER_GETHWADDR:
+ memcpy(buffer->buf_ptr, softc->hwaddr, sizeof(softc->hwaddr));
+ return 0;
+
+ case IOCTL_ETHER_SETHWADDR:
+ return -1; /* not supported */
+
+ case IOCTL_ETHER_GETSPEED:
+ argp = (int *) buffer->buf_ptr;
+ *argp = softc->linkspeed;
+ return 0;
+
+ case IOCTL_ETHER_SETSPEED:
+ tulip_stop(softc);
+ tulip_resetrings(softc);
+ speed = *((int *) buffer->buf_ptr);
+ tulip_setspeed(softc, speed);
+ tulip_start(softc);
+ softc->state = eth_state_on;
+ return 0;
+
+ case IOCTL_ETHER_GETLINK:
+ argp = (int *) buffer->buf_ptr;
+ *argp = softc->linkspeed;
+ return 0;
+
+ case IOCTL_ETHER_GETLOOPBACK:
+ *((int *) buffer) = softc->loopback;
+ return 0;
+
+ case IOCTL_ETHER_SETLOOPBACK:
+ tulip_stop(softc);
+ tulip_resetrings(softc);
+ mode = *((int *) buffer->buf_ptr);
+ softc->loopback = ETHER_LOOPBACK_OFF; /* default */
+ if (mode == ETHER_LOOPBACK_INT || mode == ETHER_LOOPBACK_EXT) {
+ tulip_setloopback(softc, mode);
+ }
+ tulip_start(softc);
+ softc->state = eth_state_on;
+ return 0;
+
+ default:
+ return -1;
+ }
+}
+
+/* *********************************************************************
+ * TULIP_ETHER_CLOSE(ctx)
+ *
+ * Close the Ethernet device.
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ *
+ * Return value:
+ * status, 0 = ok
+ ********************************************************************* */
+static int
+tulip_ether_close(cfe_devctx_t *ctx)
+{
+ tulip_softc *softc = ctx->dev_softc;
+
+ softc->state = eth_state_off;
+ tulip_stop(softc);
+
+ /* resynchronize descriptor rings */
+ tulip_resetrings(softc);
+
+ softc->devctx = NULL;
+ return 0;
+}
+
+
+#if 0
+/* *********************************************************************
+ * TULIP_ETHER_POLL(ctx,ticks)
+ *
+ * TBD
+ *
+ * Input parameters:
+ * ctx - device context (includes ptr to our softc)
+ * ticks- current time in ticks
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void
+tulip_ether_poll(cfe_devctx_t *ctx, int64_t ticks)
+{
+}
+
+/* *********************************************************************
+ * TULIP_ETHER_RESET(softc)
+ *
+ * This routine is called when CFE is restarted after a
+ * program exits. We can clean up pending I/Os here.
+ *
+ * Input parameters:
+ * softc - pointer to tulip_softc
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+
+static void
+tulip_ether_reset(void *softc)
+{
+ tulip_softc *sc = (tulip_softc *)softc;
+
+ /* Turn off the Ethernet interface. */
+
+ RESET_ADAPTER(sc);
+}
+#endif
diff --git a/cfe/cfe/dev/dp83815.h b/cfe/cfe/dev/dp83815.h
new file mode 100644
index 0000000..1d50422
--- /dev/null
+++ b/cfe/cfe/dev/dp83815.h
@@ -0,0 +1,559 @@
+/*
+ * Register and bit definitions for the National Semiconductor
+ * DP83815 10/100 Integrated Ethernet MAC and PHY.
+ * Reference:
+ * DP83815 10/100 Mb/s Integrated PCI Ethernet Media Access
+ * Controller and Physical Layer (MacPhyter)
+ * Hardware Reference Manual, Revision 1.0.
+ * National Semiconductor Corp., December 2000
+ */
+#ifndef _DP83815_H_
+#define _DP83815_H_
+
+#define _DD_MAKEMASK1(n) (1 << (n))
+#define _DD_MAKEMASK(v,n) ((((1)<<(v))-1) << (n))
+#define _DD_MAKEVALUE(v,n) ((v) << (n))
+#define _DD_GETVALUE(v,n,m) (((v) & (m)) >> (n))
+
+
+/* PCI Configuration Register offsets (MacPhyter nomenclature) */
+
+#define R_CFGID PCI_ID_REG
+#define K_PCI_VENDOR_NSC 0x100B
+#define K_PCI_ID_DP83815 0x0020
+
+#define R_CFGCS PCI_COMMAND_STATUS_REG
+#define R_CFGRID PCI_CLASS_REG
+#define R_CFGLAT PCI_BHLC_REG
+
+#define R_CFGIOA PCI_MAPREG(0)
+#define R_CFGMA PCI_MAPREG(1)
+
+#define R_CFGSID PCI_SUBSYS_ID_REG
+#define R_CFGROM PCI_MAPREG_ROM
+#define R_CAPPTR PCI_CAPLISTPTR_REG
+#define R_CFGINT PCI_BPARAM_INTERRUPT_REG
+
+/* Power management capability */
+#define R_PMCAP 0x40
+#define R_PMCSR 0x44
+
+
+/* MacPhyter Operational Register offsets */
+
+#define R_CR 0x00
+#define R_CFG 0x04
+#define R_MEAR 0x08
+#define R_PTSCR 0x0C
+#define R_ISR 0x10
+#define R_IMR 0x14
+#define R_IER 0x18
+#define R_TXDP 0x20
+#define R_TXCFG 0x24
+#define R_RXDP 0x30
+#define R_RXCFG 0x34
+#define R_CCSR 0x3C
+#define R_WCSR 0x40
+#define R_PCR 0x44
+#define R_RFCR 0x48
+#define R_RFDR 0x4C
+#define R_BRAR 0x50
+#define R_BRDR 0x54
+#define R_SRR 0x58
+#define R_MIBC 0x5C
+#define R_MIB(n) (0x60+4*(n))
+
+/* MacPhyter MIB Registers */
+
+#define R_MIB_RXErroredPkts R_MIB(0)
+#define R_MIB_RXFCSErrors R_MIB(1)
+#define R_MIB_RXMsdPktErrors R_MIB(2)
+#define R_MIB_RXFAErrors R_MIB(3)
+#define R_MIB_RXSymbolErrors R_MIB(4)
+#define R_MIB_RXFrameTooLong R_MIB(5)
+#define R_MIB_TXSQEErrors R_MIB(6)
+
+#define N_MIB_REGISTERS 7
+
+
+/* MacPhyter Internal PHY Register offsets */
+
+#define R_BMCR 0x80
+#define R_BMSR 0x84
+#define R_PHYIDR1 0x88
+#define R_PHYIDR2 0x8C
+#define R_ANAR 0x90
+#define R_ANLPAR 0x94
+#define R_ANER 0x98
+#define R_ANNPTR 0x9C
+#define R_PHYSTS 0xC0
+#define R_MICR 0xC4
+#define R_MISR 0xC8
+#define R_FCSCR 0xD0
+#define R_RECR 0xD4
+#define R_PHYCR 0xE4
+#define R_TBTSCR 0xE8
+
+/* Undocumented, updated for CVNG (SRR=0x0302) parts */
+
+#define R_PGSEL 0xCC
+#define R_PMDCSR 0xE4 /* R_PHYCR */
+#define R_DSPCFG 0xF4
+#define R_SDCFG 0xF8
+#define R_TSTDAT 0xFC
+
+
+/* 0x00 CR: Command Register */
+
+#define M_CR_TXE _DD_MAKEMASK1(0)
+#define M_CR_TXD _DD_MAKEMASK1(1)
+#define M_CR_RXE _DD_MAKEMASK1(2)
+#define M_CR_RXD _DD_MAKEMASK1(3)
+#define M_CR_TXR _DD_MAKEMASK1(4)
+#define M_CR_RXR _DD_MAKEMASK1(5)
+#define M_CR_SWI _DD_MAKEMASK1(7)
+#define M_CR_RST _DD_MAKEMASK1(8)
+
+
+/* 0x04 CFG: Configuration and Media Status Register */
+
+#define M_CFG_BEM _DD_MAKEMASK1(0)
+#define M_CFG_BROM_DIS _DD_MAKEMASK1(2)
+#define M_CFG_PESEL _DD_MAKEMASK1(3)
+#define M_CFG_EXD _DD_MAKEMASK1(4)
+#define M_CFG_POW _DD_MAKEMASK1(5)
+#define M_CFG_SB _DD_MAKEMASK1(6)
+#define M_CFG_REQALG _DD_MAKEMASK1(7)
+#define M_CFG_EUPHCOMP _DD_MAKEMASK1(8)
+#define M_CFG_PHY_DIS _DD_MAKEMASK1(9)
+#define M_CFG_PHY_RST _DD_MAKEMASK1(10)
+#define M_CFG_EXT_PHY _DD_MAKEMASK1(12)
+
+#define S_CFG_ANEG_SEL 13
+#define M_CFG_ANEG_SEL _DD_MAKEMASK(3,S_CFG_ANEG_SEL)
+#define V_CFG_ANEG_SEL(x) _DD_MAKEVALUE(x,S_CFG_ANEG_SEL)
+#define G_CFG_ANEG_SEL(x) _DD_GETVALUE(x,S_CFG_ANEG_SEL,M_CFG_ANEG_SEL)
+
+#define K_ANEG_10H 0x0
+#define K_ANEG_100H 0x2
+#define K_ANEG_10F 0x4
+#define K_ANEG_100F 0x6
+#define K_ANEG_10HF 0x1
+#define K_ANEG_10H_100H 0x3
+#define K_ANEG_100HF 0x5
+#define K_ANEG_10HF_100HF 0x7
+#define K_ANEG_ALL 0x7
+
+#define M_CFG_PAUSE_ADV _DD_MAKEMASK1(16)
+#define M_CFG_PINT_ACEN _DD_MAKEMASK1(17)
+
+#define S_CFG_PHY_CFG 18
+#define M_CFG_PHY_CFG _DD_MAKEMASK(6,S_CFG_PHY_CFG)
+
+#define M_CFG_ANEG_DN _DD_MAKEMASK1(27)
+#define M_CFG_POL _DD_MAKEMASK1(28)
+#define M_CFG_FDUP _DD_MAKEMASK1(29)
+#define M_CFG_SPEED100 _DD_MAKEMASK1(30)
+#define M_CFG_LNKSTS _DD_MAKEMASK1(31)
+#define M_CFG_LNKSUMMARY (M_CFG_LNKSTS | M_CFG_SPEED100 | M_CFG_FDUP)
+
+
+/* 0x08 MEAR: EEPROM Access Register (see 4.2.4 for EEPROM Map) */
+
+#define M_MEAR_EEDI _DD_MAKEMASK1(0)
+#define M_MEAR_EEDO _DD_MAKEMASK1(1)
+#define M_MEAR_EECLK _DD_MAKEMASK1(2)
+#define M_MEAR_EESEL _DD_MAKEMASK1(3)
+#define M_MEAR_MDIO _DD_MAKEMASK1(4)
+#define M_MEAR_MDDIR _DD_MAKEMASK1(5)
+#define M_MEAR_MDC _DD_MAKEMASK1(6)
+
+
+/* 0x0C PTSCR: PCI Test Control Register */
+
+#define M_PTSCR_EEBIST_FAIL _DD_MAKEMASK1(0)
+#define M_PTSCR_EEBIST_EN _DD_MAKEMASK1(1)
+#define M_PTSCR_EELOAD_EN _DD_MAKEMASK1(2)
+#define M_PTSCR_RBIST_RXFFAIL _DD_MAKEMASK1(3)
+#define M_PTSCR_RBIST_TXFAIL _DD_MAKEMASK1(4)
+#define M_PTSCR_RBIST_RXFAIL _DD_MAKEMASK1(5)
+#define M_PTSCR_RBIST_DONE _DD_MAKEMASK1(6)
+#define M_PTSCR_RBIST_EN _DD_MAKEMASK1(7)
+#define M_PTSCR_MBZ8 _DD_MAKEMASK1(8)
+#define M_PTSCR_MBZ9 _DD_MAKEMASK1(9)
+#define M_PTSCR_RBIST_RST _DD_MAKEMASK1(10)
+#define M_PTSCR_MBZ12 _DD_MAKEMASK1(12)
+
+
+/* 0x10 ISR: Interrupt Status Register */
+/* 0x14 IMR: Interrupt Mask Register */
+
+#define M_INT_RXOK _DD_MAKEMASK1(0)
+#define M_INT_RXDESC _DD_MAKEMASK1(1)
+#define M_INT_RXERR _DD_MAKEMASK1(2)
+#define M_INT_RXEARLY _DD_MAKEMASK1(3)
+#define M_INT_RXIDLE _DD_MAKEMASK1(4)
+#define M_INT_RXORN _DD_MAKEMASK1(5)
+#define M_INT_TXOK _DD_MAKEMASK1(6)
+#define M_INT_TXDESC _DD_MAKEMASK1(7)
+#define M_INT_TXERR _DD_MAKEMASK1(8)
+#define M_INT_TXIDLE _DD_MAKEMASK1(9)
+#define M_INT_TXURN _DD_MAKEMASK1(10)
+#define M_INT_MIB _DD_MAKEMASK1(11)
+#define M_INT_SWI _DD_MAKEMASK1(12)
+#define M_INT_PME _DD_MAKEMASK1(13)
+#define M_INT_PHY _DD_MAKEMASK1(14)
+#define M_INT_HIBERR _DD_MAKEMASK1(15)
+#define M_INT_RXSOVR _DD_MAKEMASK1(16)
+#define M_INT_RTABT _DD_MAKEMASK1(20)
+#define M_INT_RMABT _DD_MAKEMASK1(21)
+#define M_INT_SSERR _DD_MAKEMASK1(22)
+#define M_INT_DPERR _DD_MAKEMASK1(23)
+#define M_INT_RXRCMP _DD_MAKEMASK1(24)
+#define M_INT_TXRCMP _DD_MAKEMASK1(25)
+
+
+/* 0x18 IER: Interrupt Enable Register */
+
+#define M_IER_IE _DD_MAKEMASK1(0)
+
+
+/* 0x20 TXDP: Transmit Descriptor Pointer Register */
+
+
+/* 0x24 TXCFG: Transmit Configuration Register */
+
+#define S_TXCFG_DRTH 0
+#define M_TXCFG_DRTH _DD_MAKEMASK(6,S_TXCFG_DRTH)
+#define V_TXCFG_DRTH(x) _DD_MAKEVALUE(x,S_TXCFG_DRTH)
+#define G_TXCFG_DRTH(x) _DD_GETVALUE(x,S_TXCFG_DRTH,M_TXCFG_DRTH)
+
+#define S_TXCFG_FLTH 8
+#define M_TXCFG_FLTH _DD_MAKEMASK(6,S_TXCFG_FLTH)
+#define V_TXCFG_FLTH(x) _DD_MAKEVALUE(x,S_TXCFG_FLTH)
+#define G_TXCFG_FLTH(x) _DD_GETVALUE(x,S_TXCFG_FLTH,M_TXCFG_FLTH)
+
+#define S_TXCFG_MXDMA 20
+#define M_TXCFG_MXDMA _DD_MAKEMASK(3,S_TXCFG_MXDMA)
+#define V_TXCFG_MXDMA(x) _DD_MAKEVALUE(x,S_TXCFG_MXDMA)
+#define G_TXCFG_MXDMA(x) _DD_GETVALUE(x,S_TXCFG_MXDMA,M_TXCFG_MXDMA)
+
+/* Max DMA burst size (bytes) - RX also */
+#define K_MXDMA_512 0x0
+#define K_MXDMA_4 0x1
+#define K_MXDMA_8 0x2
+#define K_MXDMA_16 0x3
+#define K_MXDMA_32 0x4
+#define K_MXDMA_64 0x5
+#define K_MXDMA_128 0x6
+#define K_MXDMA_256 0x7
+
+#define M_TXCFG_ECRETRY _DD_MAKEMASK1(23)
+
+#define S_TXCFG_IFG 26
+#define M_TXCFG_IFG _DD_MAKEMASK(2,S_TXCFG_IFG)
+#define V_TXCFG_IFG(x) _DD_MAKEVALUE(x,S_TXCFG_IFG)
+#define G_TXCFG_IFG(x) _DD_GETVALUE(x,S_TXCFG_IFG,M_TXCFG_IFG)
+
+#define M_TXCFG_ATP _DD_MAKEMASK1(28)
+#define M_TXCFG_MLB _DD_MAKEMASK1(29)
+#define M_TXCFG_HBI _DD_MAKEMASK1(30)
+#define M_TXCFG_CSI _DD_MAKEMASK1(31)
+
+
+/* 0x30 RXDP: Receive Descriptor Pointer Register */
+
+
+/* 0x34 RXCFG: Receive Configuration Register */
+
+#define S_RXCFG_DRTH 1
+#define M_RXCFG_DRTH _DD_MAKEMASK(5,S_RXCFG_DRTH)
+#define V_RXCFG_DRTH(x) _DD_MAKEVALUE(x,S_RXCFG_DRTH)
+#define G_RXCFG_DRTH(x) _DD_GETVALUE(x,S_RXCFG_DRTH,M_RXCFG_DRTH)
+
+#define S_RXCFG_MXDMA 20
+#define M_RXCFG_MXDMA _DD_MAKEMASK(3,S_RXCFG_MXDMA)
+#define V_RXCFG_MXDMA(x) _DD_MAKEVALUE(x,S_RXCFG_MXDMA)
+#define G_RXCFG_MXDMA(x) _DD_GETVALUE(x,S_RXCFG_MXDMA,M_RXCFG_MXDMA)
+
+#define M_RXCFG_ALP _DD_MAKEMASK1(27)
+#define M_RXCFG_ATX _DD_MAKEMASK1(28)
+#define M_RXCFG_ARP _DD_MAKEMASK1(30)
+#define M_RXCFG_AEP _DD_MAKEMASK1(31)
+
+
+/* 0x3C CCSR: CLKRUN Control/Status Register */
+
+#define M_CCSR_CLKRUN_EN _DD_MAKEMASK1(0)
+#define M_CCSR_PMEEN _DD_MAKEMASK1(8)
+#define M_CCSR_PMESTS _DD_MAKEMASK1(15)
+
+
+/* 0x40 WCSR: Wake Command/Status Register */
+
+#define M_WCSR_WKPHY _DD_MAKEMASK1(0)
+#define M_WCSR_WKUCP _DD_MAKEMASK1(1)
+#define M_WCSR_WKMCP _DD_MAKEMASK1(2)
+#define M_WCSR_WKBCP _DD_MAKEMASK1(3)
+#define M_WCSR_WKARP _DD_MAKEMASK1(4)
+#define M_WCSR_WKPAT0 _DD_MAKEMASK1(5)
+#define M_WCSR_WKPAT1 _DD_MAKEMASK1(6)
+#define M_WCSR_WKPAT2 _DD_MAKEMASK1(7)
+#define M_WCSR_WKPAT3 _DD_MAKEMASK1(8)
+#define M_WCSR_WKMAG _DD_MAKEMASK1(9)
+#define M_WCSR_MPSOE _DD_MAKEMASK1(10)
+#define M_WCSR_SOHACK _DD_MAKEMASK1(20)
+#define M_WCSR_PHYINT _DD_MAKEMASK1(22)
+#define M_WCSR_UCASTR _DD_MAKEMASK1(23)
+#define M_WCSR_MCASTR _DD_MAKEMASK1(24)
+#define M_WCSR_BCASTR _DD_MAKEMASK1(25)
+#define M_WCSR_ARPR _DD_MAKEMASK1(26)
+#define M_WCSR_PATM0 _DD_MAKEMASK1(27)
+#define M_WCSR_PATM1 _DD_MAKEMASK1(28)
+#define M_WCSR_PATM2 _DD_MAKEMASK1(29)
+#define M_WCSR_PATM3 _DD_MAKEMASK1(30)
+#define M_WCSR_MPR _DD_MAKEMASK1(31)
+
+
+/* 0x44 PCR: Pause Control/Status Register */
+
+#define S_PCR_PAUSE_CNT 0
+#define M_PCR_PAUSE_CNT _DD_MAKEMASK(16,S_PCR_PAUSE_CNT)
+#define V_PCR_PAUSE_CNT(x) _DD_MAKEVALUE(x,S_PCR_PAUSE_CNT)
+#define G_PCR_PAUSE_CNT(x) _DD_GETVALUE(x,S_PCR_PAUSE_CNT,M_PCR_PAUSE_CNT)
+
+#define M_PCR_MLD_EN _DD_MAKEMASK1(16)
+#define M_PCR_PSNEG _DD_MAKEMASK1(21)
+#define M_PCR_PS_RCVD _DD_MAKEMASK1(22)
+#define M_PCR_PS_ACT _DD_MAKEMASK1(23)
+#define M_PCR_PS_DA _DD_MAKEMASK1(29)
+#define M_PCR_PS_MCAST _DD_MAKEMASK1(30)
+#define M_PCR_PSEN _DD_MAKEMASK1(31)
+
+
+/* 0x48 RFCR: Receive Filter/Match Control Register */
+
+
+#define S_RFCR_RFADDR 0
+#define M_RFCR_RFADDR _DD_MAKEMASK(10,S_RFCR_RFADDR)
+#define V_RFCR_RFADDR(x) _DD_MAKEVALUE(x,S_RFCR_RFADDR)
+#define G_RFCR_RFADDR(x) _DD_GETVALUE(x,S_RFCR_RFADDR,M_RFCR_RFADDR)
+
+#define K_RFCR_PMATCH_ADDR 0x000
+#define K_RFCR_PCOUNT_ADDR 0x006
+#define K_RFCR_FILTER_ADDR 0x200
+
+#define M_RFCR_ULM _DD_MAKEMASK1(19)
+#define M_RFCR_UHEN _DD_MAKEMASK1(20)
+#define M_RFCR_MHEN _DD_MAKEMASK1(21)
+#define M_RFCR_AARP _DD_MAKEMASK1(22)
+#define M_RFCR_APAT0 _DD_MAKEMASK1(23)
+#define M_RFCR_APAT1 _DD_MAKEMASK1(24)
+#define M_RFCR_APAT2 _DD_MAKEMASK1(25)
+#define M_RFCR_APAT3 _DD_MAKEMASK1(26)
+#define M_RFCR_APAT (M_RFCR_APAT0 | M_RFCR_APAT1 | \
+ M_RFCR_APAT2 | M_RFCR_APAT3 )
+#define M_RFCR_APM _DD_MAKEMASK1(27)
+#define M_RFCR_AAU _DD_MAKEMASK1(28)
+#define M_RFCR_AAM _DD_MAKEMASK1(29)
+#define M_RFCR_AAB _DD_MAKEMASK1(30)
+#define M_RFCR_RFEN _DD_MAKEMASK1(31)
+
+
+/* 0x4C RFDR: Receive Filter/Match Data Register */
+
+#define S_RFDR_RFDATA 0
+#define M_RFDR_RFDATA _DD_MAKEMASK(16,S_RFDR_RFDATA)
+#define V_RFDR_RFDATA(x) _DD_MAKEVALUE(x,S_RFDR_RFDATA)
+#define G_RFDR_RFDATA(x) _DD_GETVALUE(x,S_RFDR_RFDATA,M_RFDR_RFDATA)
+
+#define S_RFDR_BMASK 16
+#define M_RFDR_BMASK _DD_MAKEMASK(2,S_RFDR_BMASK)
+#define V_RFDR_BMASK(x) _DD_MAKEVALUE(x,S_RFDR_BMASK)
+#define G_RFDR_BMASK(x) _DD_GETVALUE(x,S_RFDR_BMASK,M_RFDR_BMASK)
+
+
+/* 0x50 BRAR: Boot ROM Address Register */
+
+#define S_BRAR_ADDR 0
+#define M_BRAR_ADDR _DD_MAKEMASK(16,S_BRAR_ADDR)
+#define V_BRAR_ADDR(x) _DD_MAKEVALUE(x,S_BRAR_ADDR)
+#define G_BRAR_ADDR(x) _DD_GETVALUE(x,S_BRAR_ADDR,M_BRAR_ADDR)
+
+#define M_BRAR_AUTOINC _DD_MAKEMASK1(31)
+
+
+/* 0x54 BRDR: Boot ROM Data Register */
+
+
+/* 0x58 SRR: Silicon Revision Register */
+
+#define S_SRR_REV 0
+#define M_SRR_REV _DD_MAKEMASK(16,S_SRR_REV)
+#define V_SRR_REV(x) _DD_MAKEVALUE(x,S_SRR_REV)
+#define G_SRR_REV(x) _DD_GETVALUE(x,S_SRR_REV,M_SRR_REV)
+
+#define K_REV_CVNG 0x00000302
+#define K_REV_DVNG_UJB 0x00000403
+
+
+/* 0x5C MIBC: Management Information Base Control Register */
+
+#define M_MIBC_WRN _DD_MAKEMASK1(0)
+#define M_MIBC_FRZ _DD_MAKEMASK1(1)
+#define M_MIBC_ACLR _DD_MAKEMASK1(2)
+#define M_MIBC_MIBS _DD_MAKEMASK1(3)
+
+
+/* MIB Counters */
+
+/* 0x60 RXErroredPkts */
+/* 0x64 RXFCSErrors */
+/* 0x68 RXMsdPktErrors */
+/* 0x6C RXFAErrors */
+/* 0x70 RXSymbolErrors */
+/* 0x74 RXFrameTooLong */
+/* 0x78 TXSQEErrors */
+
+
+/* See ../net/mii.h for fields of standard (MII) PHY registers */
+
+#define K_83815_PHYID1 0x2000
+#define K_83815_PHYID2 0x5C21
+
+#define K_ANNPTR_NULL 0x0001
+
+
+/* 0xC0 PHYSTS: PHY Status Register */
+
+#define PHYSTS_RXERRLATCH 0x2000
+#define PHYSTS_POLARITYSTAT 0x1000
+#define PHYSTS_FALSECARRLATCH 0x0800
+#define PHYSTS_SIGNALDETECT 0x0400
+#define PHYSTS_DESCRAMBLOCK 0x0200
+#define PHYSTS_PAGERECVD 0x0100
+#define PHYSTS_MIIINT 0x0080
+#define PHYSTS_REMOTEFAULT 0x0040
+#define PHYSTS_JABBERDET 0x0020
+#define PHYSTS_ANCOMPLETE 0x0010
+#define PHYSTS_LOOPBACK 0x0008
+#define PHYSTS_DUPLEX 0x0004
+#define PHYSTS_SPEED10 0x0002
+#define PHYSTS_LINKSTAT 0x0001
+
+
+/* 0xC4 MICR: MII Interrupt Control Register */
+
+#define MICR_INTEN 0x0002
+#define MICR_TINT 0x0001
+
+
+/* 0xC8 MISR: MII Interrupt Status and Misc. Control Register */
+
+#define MISR_MINT 0x8000
+#define MISR_MSKLINK 0x4000
+#define MISR_MSKJAB 0x2000
+#define MISR_MSKRF 0x1000
+#define MISR_MSKANC 0x0800
+#define MISR_MSKFHF 0x0400
+#define MISR_MSKRHF 0x0200
+
+
+/* 0xD0 FCSCR: False Carrier Sense Counter Register */
+
+#define FCSCR_FCSCNT 0x00FF
+
+
+/* 0xD4 RECR: Receiver Error Counter Register */
+
+#define RECR_RXERCNT 0x00FF
+
+
+/* 0xD8 PCSR: 100 Mb/s PCS Configuration and Status Register */
+
+#define PCSR_BYP4B5B 0x1000
+#define PCSR_FREECLK 0x0800
+#define PCSR_TQEN 0x0400
+#define PCSR_SDFORCEB 0x0200
+#define PCSR_SDOPTION 0x0100
+#define PCSR_FORCE100OK 0x0020
+#define PCSR_NRZIBYPASS 0x0004
+
+
+/* 0xE4 PHYCR: PHY Control Register */
+
+#define PHYCR_PSR15 0x0800
+#define PHYCR_BISTSTATUS 0x0400
+#define PHYCR_BISTSTART 0x0200
+#define PHYCR_BPSTRETCH 0x0100
+#define PHYCR_PAUSESTS 0x0080
+#define PHYCR_PHYADDR 0x001F
+
+
+/* 0xE8 TBTSCR: 10Base-T Status/Control Register */
+
+#define TBTSCR_LPBK10DIS 0x0100
+#define TBTSCR_LPDIS 0x0080
+#define TBTSCR_FORCELINK10 0x0040
+#define TBTSCR_FORCEPOLCOR 0x0020
+#define TBTSCR_POLARITY 0x0010
+#define TBTSCR_AUTOPOLDIS 0x0008
+#define TBTSCR_HBDIS 0x0002
+#define TBTSCR_JABBERDIS 0x0001
+
+
+/* MacPhyter Transmit and Receive Descriptors */
+
+/* Common Command/Status Fields */
+#define S_DES1_SIZE 0
+#define M_DES1_SIZE _DD_MAKEMASK(12,S_DES1_SIZE)
+#define V_DES1_SIZE(x) _DD_MAKEVALUE(x,S_DES1_SIZE)
+#define G_DES1_SIZE(x) _DD_GETVALUE(x,S_DES1_SIZE,M_DES1_SIZE)
+
+#define M_DES1_OK _DD_MAKEMASK1(27)
+#define M_DES1_INTR _DD_MAKEMASK1(29)
+#define M_DES1_MORE _DD_MAKEMASK1(30)
+#define M_DES1_OWN _DD_MAKEMASK1(31)
+
+/* Transmit Command/Status Bits */
+#define S_DES1_CCNT 16
+#define M_DES1_CCNT _DD_MAKEMASK(4,S_DES1_CCNT)
+#define V_DES1_CCNT(x) _DD_MAKEVALUE(x,S_DES1_CCNT)
+#define G_DES1_CCNT(x) _DD_GETVALUE(x,S_DES1_CCNT,M_DES1_CCNT)
+
+#define M_DES1_EC _DD_MAKEMASK1(20)
+#define M_DES1_OWC _DD_MAKEMASK1(21)
+#define M_DES1_ED _DD_MAKEMASK1(22)
+#define M_DES1_TD _DD_MAKEMASK1(23)
+#define M_DES1_CRS _DD_MAKEMASK1(24)
+#define M_DES1_TFU _DD_MAKEMASK1(25)
+#define M_DES1_TXA _DD_MAKEMASK1(26)
+#define M_DES1_SUPCRC _DD_MAKEMASK1(28)
+
+/* Receive Command/Status Bits */
+#define M_DES1_COL _DD_MAKEMASK1(16)
+#define M_DES1_LBP _DD_MAKEMASK1(17)
+#define M_DES1_FAE _DD_MAKEMASK1(18)
+#define M_DES1_CRCE _DD_MAKEMASK1(19)
+#define M_DES1_ISE _DD_MAKEMASK1(20)
+#define M_DES1_RUNT _DD_MAKEMASK1(21)
+#define M_DES1_LONG _DD_MAKEMASK1(22)
+#define M_DES1_RX_ERRORS (M_DES1_CRCE | \
+ M_DES1_COL | M_DES1_FAE | M_DES1_ISE | \
+ M_DES1_RUNT | M_DES1_LONG | M_DES1_RXO)
+
+#define S_DES1_DEST 23
+#define M_DES1_DEST _DD_MAKEMASK(2,S_DES1_DEST)
+#define V_DES1_DEST(x) _DD_MAKEVALUE(x,S_DES1_DEST)
+#define G_DES1_DEST(x) _DD_GETVALUE(x,S_DES1_DEST,M_DES1_DEST)
+
+#define K_DEST_REJECT 0
+#define K_DEST_UNICAST 1
+#define K_DEST_MULTICAST 2
+#define K_DEST_BROADCAST 3
+
+#define M_DES1_RXO _DD_MAKEMASK1(25)
+#define M_DES1_RXA _DD_MAKEMASK1(26)
+#define M_DES1_INCCRC _DD_MAKEMASK1(28)
+
+#endif /* _DP83815_H_ */
diff --git a/cfe/cfe/dev/ns16550.h b/cfe/cfe/dev/ns16550.h
new file mode 100644
index 0000000..b603ccc
--- /dev/null
+++ b/cfe/cfe/dev/ns16550.h
@@ -0,0 +1,143 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * NS16550 Serial Port definitions File: ns16550.h
+ *
+ * This defines the hardware registers of 16550 compatible UARTs
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+/*
+ * NS16550 UART registers
+ */
+
+#ifndef _NS16550_H_
+#define _NS16550_H_
+
+#ifndef NS16550_HZ
+#define NS16550_HZ 1843200
+#endif
+
+/*
+ * NS16550 UART registers
+ */
+
+/* Register definitions */
+
+#define R_UART_DATA 0
+#define R_UART_IER 1
+#define R_UART_IIR 2
+#define R_UART_FIFO R_UART_IIR
+#define R_UART_CFCR 3
+#define R_UART_MCR 4
+#define R_UART_LSR 5
+#define R_UART_MSR 6
+#define R_UART_SCR 7
+
+/* 16 bit baud rate divisor (lower byte in UART_DATA, upper in UART_IER) */
+#define BRTC(x) (NS16550_HZ / (16*(x)))
+
+/* interrupt enable register */
+#define IER_ERXRDY 0x1 /* int on rx ready */
+#define IER_ETXRDY 0x2 /* int on tx ready */
+#define IER_ERLS 0x4 /* int on line status change */
+#define IER_EMSC 0x8 /* int on modem status change */
+
+/* interrupt identification register */
+#define IIR_IMASK 0xf /* mask */
+#define IIR_RXTOUT 0xc /* receive timeout */
+#define IIR_RLS 0x6 /* receive line status */
+#define IIR_RXRDY 0x4 /* receive ready */
+#define IIR_TXRDY 0x2 /* transmit ready */
+#define IIR_NOPEND 0x1 /* nothing */
+#define IIR_MLSC 0x0 /* modem status */
+#define IIR_FIFO_MASK 0xc0 /* set if FIFOs are enabled */
+
+/* fifo control register */
+#define FIFO_ENABLE 0x01 /* enable fifo */
+#define FIFO_RCV_RST 0x02 /* reset receive fifo */
+#define FIFO_XMT_RST 0x04 /* reset transmit fifo */
+#define FIFO_DMA_MODE 0x08 /* enable dma mode */
+#define FIFO_TRIGGER_1 0x00 /* trigger at 1 char */
+#define FIFO_TRIGGER_4 0x40 /* trigger at 4 chars */
+#define FIFO_TRIGGER_8 0x80 /* trigger at 8 chars */
+#define FIFO_TRIGGER_14 0xc0 /* trigger at 14 chars */
+
+/* character format control register */
+#define CFCR_DLAB 0x80 /* divisor latch */
+#define CFCR_SBREAK 0x40 /* send break */
+#define CFCR_PZERO 0x30 /* zero parity */
+#define CFCR_PONE 0x20 /* one parity */
+#define CFCR_PEVEN 0x10 /* even parity */
+#define CFCR_PODD 0x00 /* odd parity */
+#define CFCR_PENAB 0x08 /* parity enable */
+#define CFCR_STOPB 0x04 /* 2 stop bits */
+#define CFCR_8BITS 0x03 /* 8 data bits */
+#define CFCR_7BITS 0x02 /* 7 data bits */
+#define CFCR_6BITS 0x01 /* 6 data bits */
+#define CFCR_5BITS 0x00 /* 5 data bits */
+
+/* modem control register */
+#define MCR_LOOPBACK 0x10 /* loopback */
+#define MCR_IENABLE 0x08 /* output 2 = int enable */
+#define MCR_DRS 0x04 /* output 1 = xxx */
+#define MCR_RTS 0x02 /* enable RTS */
+#define MCR_DTR 0x01 /* enable DTR */
+
+/* line status register */
+#define LSR_RCV_FIFO 0x80 /* error in receive fifo */
+#define LSR_TSRE 0x40 /* transmitter empty */
+#define LSR_TXRDY 0x20 /* transmitter ready */
+#define LSR_BI 0x10 /* break detected */
+#define LSR_FE 0x08 /* framing error */
+#define LSR_PE 0x04 /* parity error */
+#define LSR_OE 0x02 /* overrun error */
+#define LSR_RXRDY 0x01 /* receiver ready */
+#define LSR_RCV_MASK 0x1f
+
+/* modem status register */
+#define MSR_DCD 0x80 /* DCD active */
+#define MSR_RI 0x40 /* RI active */
+#define MSR_DSR 0x20 /* DSR active */
+#define MSR_CTS 0x10 /* CTS active */
+#define MSR_DDCD 0x08 /* DCD changed */
+#define MSR_TERI 0x04 /* RI changed */
+#define MSR_DDSR 0x02 /* DSR changed */
+#define MSR_DCTS 0x01 /* CTS changed */
+
+#endif /* _NS16550_H_ */
diff --git a/cfe/cfe/dev/pci_devs.c b/cfe/cfe/dev/pci_devs.c
new file mode 100644
index 0000000..a1ba789
--- /dev/null
+++ b/cfe/cfe/dev/pci_devs.c
@@ -0,0 +1,79 @@
+/* *********************************************************************
+ * Broadcom Common Firmware Environment (CFE)
+ *
+ * PCI device selection and initialization File: pci_devs.c
+ *
+ * These are the routines to include the PCI drivers and to hook any
+ * devices with special configuration requirements..
+ *
+ *********************************************************************
+ *
+ * Copyright 2000,2001,2002,2003
+ * Broadcom Corporation. All rights reserved.
+ *
+ * This software is furnished under license and may be used and
+ * copied only in accordance with the following terms and
+ * conditions. Subject to these conditions, you may download,
+ * copy, install, use, modify and distribute modified or unmodified
+ * copies of this software in source and/or binary form. No title
+ * or ownership is transferred hereby.
+ *
+ * 1) Any source code used, modified or distributed must reproduce
+ * and retain this copyright notice and list of conditions
+ * as they appear in the source file.
+ *
+ * 2) No right is granted to use any trade name, trademark, or
+ * logo of Broadcom Corporation. The "Broadcom Corporation"
+ * name may not be used to endorse or promote products derived
+ * from this software without the prior written permission of
+ * Broadcom Corporation.
+ *
+ * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
+ * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
+ * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************* */
+
+
+#if CFG_PCI
+#include "sbmips.h"
+#include "lib_types.h"
+#include "cfe_iocb.h"
+#include "cfe_device.h"
+#include "dev_ide.h"
+#include "env_subr.h"
+
+extern cfe_driver_t pciidedrv; /* PCI IDE controller */
+extern cfe_driver_t dc21143drv; /* Tulip Ethernet */
+extern cfe_driver_t dp83815drv; /* MacPhyter Ethernet */
+#if CFG_DOWNLOAD
+extern cfe_driver_t bcm1250drv; /* BCM1250 as a device */
+#endif
+extern cfe_driver_t ns16550pci_uart; /* PCI serial port */
+
+void pci_add_devices(int init_pci);
+void pci_add_devices(int init_pci)
+{
+ if (init_pci) {
+ cfe_add_device(&pciidedrv,0,IDE_PROBE_MASTER_TYPE(IDE_DEVTYPE_DISK),NULL);
+ cfe_add_device(&dc21143drv,0,0,env_getenv("TULIP0_HWADDR"));
+ cfe_add_device(&dp83815drv,0,0,NULL);
+
+#if CFG_DOWNLOAD
+ /* Access to bcm1250 in PCI device mode */
+ cfe_add_device(&bcm1250drv,0,0,NULL);
+#endif
+ cfe_add_device(&ns16550pci_uart,0,0,0);
+ }
+}
+#endif /* CFG_PCI */
+