aboutsummaryrefslogtreecommitdiffstats
path: root/gpxe/src/drivers/net
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2009-02-17 20:17:17 -0800
committerH. Peter Anvin <hpa@zytor.com>2009-02-17 20:17:17 -0800
commitd0c6656a62113b913948361779d6298fe76f6e61 (patch)
treeefa2541a1abae4760717c6db421ea818114ab6f7 /gpxe/src/drivers/net
parent85b92a462dab7ce36c48614ea18314f8fc83ca9c (diff)
downloadsyslinux.git-d0c6656a62113b913948361779d6298fe76f6e61.tar.gz
syslinux.git-d0c6656a62113b913948361779d6298fe76f6e61.tar.xz
syslinux.git-d0c6656a62113b913948361779d6298fe76f6e61.zip
Update gPXE to version 0.9.6+ 277b84c6e7d49f3cf01c855007f591de8c7cb75f
Update gPXE to version 0.9.6+, from commit 277b84c6e7d49f3cf01c855007f591de8c7cb75f in the main gPXE repository. The only differences is src/config/general.h which has a few protocols added, and src/arch/i386/prefix/boot1a.S which was called boot1a.s in the upstream repository.
Diffstat (limited to 'gpxe/src/drivers/net')
-rw-r--r--gpxe/src/drivers/net/3c509.c2
-rw-r--r--gpxe/src/drivers/net/3c515.c2
-rw-r--r--gpxe/src/drivers/net/3c595.c2
-rw-r--r--gpxe/src/drivers/net/3c90x.c4
-rw-r--r--gpxe/src/drivers/net/b44.c949
-rw-r--r--gpxe/src/drivers/net/b44.h467
-rw-r--r--gpxe/src/drivers/net/cs89x0.c4
-rw-r--r--gpxe/src/drivers/net/davicom.c4
-rw-r--r--gpxe/src/drivers/net/dmfe.c20
-rw-r--r--gpxe/src/drivers/net/e1000/e1000.c34
-rw-r--r--gpxe/src/drivers/net/e1000/e1000.h3
-rw-r--r--gpxe/src/drivers/net/e1000/e1000_hw.c14
-rw-r--r--gpxe/src/drivers/net/e1000/e1000_osdep.h50
-rw-r--r--gpxe/src/drivers/net/eepro100.c8
-rw-r--r--gpxe/src/drivers/net/epic100.c4
-rw-r--r--gpxe/src/drivers/net/etherfabric.c5486
-rw-r--r--gpxe/src/drivers/net/etherfabric_nic.h201
-rw-r--r--gpxe/src/drivers/net/forcedeth.c2
-rw-r--r--gpxe/src/drivers/net/ipoib.c579
-rw-r--r--[-rwxr-xr-x]gpxe/src/drivers/net/mtnic.c1038
-rw-r--r--[-rwxr-xr-x]gpxe/src/drivers/net/mtnic.h283
-rw-r--r--gpxe/src/drivers/net/natsemi.c11
-rw-r--r--gpxe/src/drivers/net/ne2k_isa.c373
-rw-r--r--gpxe/src/drivers/net/phantom/phantom.c1517
-rw-r--r--gpxe/src/drivers/net/phantom/phantom.h155
-rw-r--r--gpxe/src/drivers/net/pnic.c2
-rw-r--r--gpxe/src/drivers/net/prism2.c2
-rw-r--r--gpxe/src/drivers/net/prism2_pci.c9
-rw-r--r--gpxe/src/drivers/net/prism2_plx.c5
-rw-r--r--gpxe/src/drivers/net/r8169.c3099
-rw-r--r--gpxe/src/drivers/net/r8169.h566
-rw-r--r--gpxe/src/drivers/net/rtl8139.c3
-rw-r--r--gpxe/src/drivers/net/sis900.c8
-rw-r--r--gpxe/src/drivers/net/sundance.c5
-rw-r--r--gpxe/src/drivers/net/tg3.c5
-rw-r--r--gpxe/src/drivers/net/tulip.c4
-rw-r--r--gpxe/src/drivers/net/via-rhine.c48
-rw-r--r--gpxe/src/drivers/net/via-velocity.c4
-rw-r--r--gpxe/src/drivers/net/virtio-net.c289
-rw-r--r--gpxe/src/drivers/net/virtio-pci.h94
-rw-r--r--gpxe/src/drivers/net/virtio-ring.h93
-rw-r--r--gpxe/src/drivers/net/w89c840.c4
42 files changed, 9845 insertions, 5607 deletions
diff --git a/gpxe/src/drivers/net/3c509.c b/gpxe/src/drivers/net/3c509.c
index 8a15aff2..ecfdec55 100644
--- a/gpxe/src/drivers/net/3c509.c
+++ b/gpxe/src/drivers/net/3c509.c
@@ -8,7 +8,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <unistd.h>
#include <gpxe/device.h>
#include <gpxe/isa.h>
diff --git a/gpxe/src/drivers/net/3c515.c b/gpxe/src/drivers/net/3c515.c
index 02f03dc7..dcfe66ba 100644
--- a/gpxe/src/drivers/net/3c515.c
+++ b/gpxe/src/drivers/net/3c515.c
@@ -640,7 +640,7 @@ static int t515_probe ( struct nic *nic, struct isapnp_device *isapnp ) {
}
}
- DBG ( "3c515 Resource configuration register 0x%lX, DCR 0x%hX.\n",
+ DBG ( "3c515 Resource configuration register 0x%X, DCR 0x%hX.\n",
inl(nic->ioaddr + 0x2002), inw(nic->ioaddr + 0x2000) );
corkscrew_found_device(nic->ioaddr, nic->irqno, CORKSCREW_ID,
options, nic);
diff --git a/gpxe/src/drivers/net/3c595.c b/gpxe/src/drivers/net/3c595.c
index 7138f936..198e12e7 100644
--- a/gpxe/src/drivers/net/3c595.c
+++ b/gpxe/src/drivers/net/3c595.c
@@ -363,7 +363,7 @@ vxgetlink(void)
if (n > 0) {
printf("/");
}
- printf(conn_tab[k].name);
+ printf("%s", conn_tab[k].name );
n++;
}
}
diff --git a/gpxe/src/drivers/net/3c90x.c b/gpxe/src/drivers/net/3c90x.c
index 8158239d..a98e6628 100644
--- a/gpxe/src/drivers/net/3c90x.c
+++ b/gpxe/src/drivers/net/3c90x.c
@@ -497,7 +497,7 @@ a3c90x_transmit(struct nic *nic __unused, const char *d, unsigned int t,
unsigned char status;
unsigned i, retries;
- tick_t ct;
+ unsigned long ct;
for (retries=0; retries < XMIT_RETRIES ; retries++)
{
@@ -543,7 +543,7 @@ a3c90x_transmit(struct nic *nic __unused, const char *d, unsigned int t,
ct = currticks();
while (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004) &&
- ct + 10*USECS_IN_MSEC < currticks());
+ ct + 10*1000 < currticks());
;
if (!(inw(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004))
diff --git a/gpxe/src/drivers/net/b44.c b/gpxe/src/drivers/net/b44.c
new file mode 100644
index 00000000..4c9c8e6e
--- /dev/null
+++ b/gpxe/src/drivers/net/b44.c
@@ -0,0 +1,949 @@
+/*
+ * Copyright (c) 2008 Stefan Hajnoczi <stefanha@gmail.com>
+ * Copyright (c) 2008 Pantelis Koukousoulas <pktoss@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver is a port of the b44 linux driver version 1.01
+ *
+ * Copyright (c) 2002 David S. Miller <davem@redhat.com>
+ * Copyright (c) Pekka Pietikainen <pp@ee.oulu.fi>
+ * Copyright (C) 2006 Broadcom Corporation.
+ *
+ * Some ssb bits copied from version 2.0 of the b44 driver
+ * Copyright (c) Michael Buesch
+ *
+ * Copyright (c) a lot of people too. Please respect their work.
+ */
+
+#include <errno.h>
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <byteswap.h>
+#include <gpxe/io.h>
+#include <mii.h>
+#include <gpxe/iobuf.h>
+#include <gpxe/malloc.h>
+#include <gpxe/pci.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/ethernet.h>
+#include <gpxe/if_ether.h>
+#include <gpxe/memmap.h>
+#include "b44.h"
+
+
+static inline int ring_next(int index)
+{
+ /* B44_RING_SIZE is a power of 2 :) */
+ return (index + 1) & (B44_RING_SIZE - 1);
+}
+
+
+/* Memory-mapped I/O wrappers */
+
+static inline u32 br32(const struct b44_private *bp, u32 reg)
+{
+ return readl(bp->regs + reg);
+}
+
+
+static inline void bw32(const struct b44_private *bp, u32 reg, u32 val)
+{
+ writel(val, bp->regs + reg);
+}
+
+
+static inline void bflush(const struct b44_private *bp, u32 reg, u32 timeout)
+{
+ readl(bp->regs + reg);
+ udelay(timeout);
+}
+
+
+#define VIRT_TO_B44(addr) ( virt_to_bus(addr) + SB_PCI_DMA )
+
+
+/**
+ * Return non-zero if the installed RAM is within
+ * the limit given and zero if it is outside.
+ * Hopefully will be removed soon.
+ */
+int phys_ram_within_limit(u64 limit)
+{
+ struct memory_map memmap;
+ struct memory_region *highest = NULL;
+ get_memmap(&memmap);
+
+ highest = &memmap.regions[memmap.count - 1];
+
+ return (highest->end < limit);
+}
+
+
+/**
+ * Ring cells waiting to be processed are between 'tx_cur' and 'pending'
+ * indexes in the ring.
+ */
+static u32 pending_tx_index(struct b44_private *bp)
+{
+ u32 pending = br32(bp, B44_DMATX_STAT);
+ pending &= DMATX_STAT_CDMASK;
+
+ pending /= sizeof(struct dma_desc);
+ return pending & (B44_RING_SIZE - 1);
+}
+
+
+/**
+ * Ring cells waiting to be processed are between 'rx_cur' and 'pending'
+ * indexes in the ring.
+ */
+static u32 pending_rx_index(struct b44_private *bp)
+{
+ u32 pending = br32(bp, B44_DMARX_STAT);
+ pending &= DMARX_STAT_CDMASK;
+
+ pending /= sizeof(struct dma_desc);
+ return pending & (B44_RING_SIZE - 1);
+}
+
+
+/**
+ * Wait until the given bit is set/cleared.
+ */
+static int b44_wait_bit(struct b44_private *bp, unsigned long reg, u32 bit,
+ unsigned long timeout, const int clear)
+{
+ unsigned long i;
+
+ for (i = 0; i < timeout; i++) {
+ u32 val = br32(bp, reg);
+
+ if (clear && !(val & bit))
+ break;
+
+ if (!clear && (val & bit))
+ break;
+
+ udelay(10);
+ }
+ if (i == timeout) {
+ return -ENODEV;
+ }
+ return 0;
+}
+
+
+/*
+ * Sonics Silicon Backplane support. SSB is a mini-bus interconnecting
+ * so-called IP Cores. One of those cores implements the Fast Ethernet
+ * functionality and another one the PCI engine.
+ *
+ * You need to switch to the core you want to talk to before actually
+ * sending commands.
+ *
+ * See: http://bcm-v4.sipsolutions.net/Backplane for (reverse-engineered)
+ * specs.
+ */
+
+static inline u32 ssb_get_core_rev(struct b44_private *bp)
+{
+ return (br32(bp, B44_SBIDHIGH) & SBIDHIGH_RC_MASK);
+}
+
+
+static inline int ssb_is_core_up(struct b44_private *bp)
+{
+ return ((br32(bp, B44_SBTMSLOW) & (SSB_CORE_DOWN | SBTMSLOW_CLOCK))
+ == SBTMSLOW_CLOCK);
+}
+
+
+static u32 ssb_pci_setup(struct b44_private *bp, u32 cores)
+{
+ u32 bar_orig, pci_rev, val;
+
+ pci_read_config_dword(bp->pci, SSB_BAR0_WIN, &bar_orig);
+ pci_write_config_dword(bp->pci, SSB_BAR0_WIN,
+ BCM4400_PCI_CORE_ADDR);
+ pci_rev = ssb_get_core_rev(bp);
+
+ val = br32(bp, B44_SBINTVEC);
+ val |= cores;
+ bw32(bp, B44_SBINTVEC, val);
+
+ val = br32(bp, SSB_PCI_TRANS_2);
+ val |= SSB_PCI_PREF | SSB_PCI_BURST;
+ bw32(bp, SSB_PCI_TRANS_2, val);
+
+ pci_write_config_dword(bp->pci, SSB_BAR0_WIN, bar_orig);
+
+ return pci_rev;
+}
+
+
+static void ssb_core_disable(struct b44_private *bp)
+{
+ if (br32(bp, B44_SBTMSLOW) & SBTMSLOW_RESET)
+ return;
+
+ bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK));
+ b44_wait_bit(bp, B44_SBTMSLOW, SBTMSLOW_REJECT, 100000, 0);
+ b44_wait_bit(bp, B44_SBTMSHIGH, SBTMSHIGH_BUSY, 100000, 1);
+
+ bw32(bp, B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK |
+ SSB_CORE_DOWN));
+ bflush(bp, B44_SBTMSLOW, 1);
+
+ bw32(bp, B44_SBTMSLOW, SSB_CORE_DOWN);
+ bflush(bp, B44_SBTMSLOW, 1);
+}
+
+
+static void ssb_core_reset(struct b44_private *bp)
+{
+ u32 val;
+ const u32 mask = (SBTMSLOW_CLOCK | SBTMSLOW_FGC | SBTMSLOW_RESET);
+
+ ssb_core_disable(bp);
+
+ bw32(bp, B44_SBTMSLOW, mask);
+ bflush(bp, B44_SBTMSLOW, 1);
+
+ /* Clear SERR if set, this is a hw bug workaround. */
+ if (br32(bp, B44_SBTMSHIGH) & SBTMSHIGH_SERR)
+ bw32(bp, B44_SBTMSHIGH, 0);
+
+ val = br32(bp, B44_SBIMSTATE);
+ if (val & (SBIMSTATE_BAD)) {
+ bw32(bp, B44_SBIMSTATE, val & ~SBIMSTATE_BAD);
+ }
+
+ bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC));
+ bflush(bp, B44_SBTMSLOW, 1);
+
+ bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK));
+ bflush(bp, B44_SBTMSLOW, 1);
+}
+
+
+/*
+ * Driver helper functions
+ */
+
+/*
+ * Chip reset provides power to the b44 MAC & PCI cores, which
+ * is necessary for MAC register access. We only do a partial
+ * reset in case of transmit/receive errors (ISTAT_ERRORS) to
+ * avoid the chip being hung for an unnecessary long time in
+ * this case.
+ *
+ * Called-by: b44_close, b44_halt, b44_inithw(b44_open), b44_probe
+ */
+static void b44_chip_reset(struct b44_private *bp, int reset_kind)
+{
+ if (ssb_is_core_up(bp)) {
+ bw32(bp, B44_RCV_LAZY, 0);
+
+ bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE);
+
+ b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 200, 1);
+
+ bw32(bp, B44_DMATX_CTRL, 0);
+
+ bp->tx_dirty = bp->tx_cur = 0;
+
+ if (br32(bp, B44_DMARX_STAT) & DMARX_STAT_EMASK)
+ b44_wait_bit(bp, B44_DMARX_STAT, DMARX_STAT_SIDLE,
+ 100, 0);
+
+ bw32(bp, B44_DMARX_CTRL, 0);
+
+ bp->rx_cur = 0;
+ } else {
+ ssb_pci_setup(bp, SBINTVEC_ENET0);
+ }
+
+ ssb_core_reset(bp);
+
+ /* Don't enable PHY if we are only doing a partial reset. */
+ if (reset_kind == B44_CHIP_RESET_PARTIAL)
+ return;
+
+ /* Make PHY accessible. */
+ bw32(bp, B44_MDIO_CTRL,
+ (MDIO_CTRL_PREAMBLE | (0x0d & MDIO_CTRL_MAXF_MASK)));
+ bflush(bp, B44_MDIO_CTRL, 1);
+
+ /* Enable internal or external PHY */
+ if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) {
+ bw32(bp, B44_ENET_CTRL, ENET_CTRL_EPSEL);
+ bflush(bp, B44_ENET_CTRL, 1);
+ } else {
+ u32 val = br32(bp, B44_DEVCTRL);
+ if (val & DEVCTRL_EPR) {
+ bw32(bp, B44_DEVCTRL, (val & ~DEVCTRL_EPR));
+ bflush(bp, B44_DEVCTRL, 100);
+ }
+ }
+}
+
+
+/**
+ * called by b44_poll in the error path
+ */
+static void b44_halt(struct b44_private *bp)
+{
+ /* disable ints */
+ bw32(bp, B44_IMASK, 0);
+ bflush(bp, B44_IMASK, 1);
+
+ DBG("b44: powering down PHY\n");
+ bw32(bp, B44_MAC_CTRL, MAC_CTRL_PHY_PDOWN);
+
+ /*
+ * Now reset the chip, but without enabling
+ * the MAC&PHY part of it.
+ * This has to be done _after_ we shut down the PHY
+ */
+ b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL);
+}
+
+
+
+/*
+ * Called at device open time to get the chip ready for
+ * packet processing.
+ *
+ * Called-by: b44_open
+ */
+static void b44_init_hw(struct b44_private *bp, int reset_kind)
+{
+ u32 val;
+#define CTRL_MASK (DMARX_CTRL_ENABLE | (RX_PKT_OFFSET << DMARX_CTRL_ROSHIFT))
+
+ b44_chip_reset(bp, B44_CHIP_RESET_FULL);
+ if (reset_kind == B44_FULL_RESET) {
+ b44_phy_reset(bp);
+ }
+
+ /* Enable CRC32, set proper LED modes and power on PHY */
+ bw32(bp, B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL);
+ bw32(bp, B44_RCV_LAZY, (1 << RCV_LAZY_FC_SHIFT));
+
+ /* This sets the MAC address too. */
+ b44_set_rx_mode(bp->netdev);
+
+ /* MTU + eth header + possible VLAN tag + struct rx_header */
+ bw32(bp, B44_RXMAXLEN, B44_MAX_MTU + ETH_HLEN + 8 + RX_HEADER_LEN);
+ bw32(bp, B44_TXMAXLEN, B44_MAX_MTU + ETH_HLEN + 8 + RX_HEADER_LEN);
+
+ bw32(bp, B44_TX_HIWMARK, TX_HIWMARK_DEFLT);
+ if (reset_kind == B44_PARTIAL_RESET) {
+ bw32(bp, B44_DMARX_CTRL, CTRL_MASK);
+ } else {
+ bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE);
+ bw32(bp, B44_DMATX_ADDR, VIRT_TO_B44(bp->tx));
+
+ bw32(bp, B44_DMARX_CTRL, CTRL_MASK);
+ bw32(bp, B44_DMARX_ADDR, VIRT_TO_B44(bp->rx));
+ bw32(bp, B44_DMARX_PTR, B44_RX_RING_LEN_BYTES);
+
+ bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
+ }
+
+ val = br32(bp, B44_ENET_CTRL);
+ bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE));
+#undef CTRL_MASK
+}
+
+
+/*** Management of ring descriptors ***/
+
+
+static void b44_populate_rx_descriptor(struct b44_private *bp, u32 idx)
+{
+ struct rx_header *rh;
+ u32 ctrl, addr;
+
+ rh = bp->rx_iobuf[idx]->data;
+ rh->len = 0;
+ rh->flags = 0;
+ ctrl = DESC_CTRL_LEN & (RX_PKT_BUF_SZ - RX_PKT_OFFSET);
+ if (idx == B44_RING_LAST) {
+ ctrl |= DESC_CTRL_EOT;
+ }
+ addr = VIRT_TO_B44(bp->rx_iobuf[idx]->data);
+
+ bp->rx[idx].ctrl = cpu_to_le32(ctrl);
+ bp->rx[idx].addr = cpu_to_le32(addr);
+ bw32(bp, B44_DMARX_PTR, idx * sizeof(struct dma_desc));
+}
+
+
+/*
+ * Refill RX ring descriptors with buffers. This is needed
+ * because during rx we are passing ownership of descriptor
+ * buffers to the network stack.
+ */
+static void b44_rx_refill(struct b44_private *bp, u32 pending)
+{
+ u32 i;
+
+ // skip pending
+ for (i = pending + 1; i != bp->rx_cur; i = ring_next(i)) {
+ if (bp->rx_iobuf[i] != NULL)
+ continue;
+
+ bp->rx_iobuf[i] = alloc_iob(RX_PKT_BUF_SZ);
+ if (!bp->rx_iobuf[i]) {
+ DBG("Refill rx ring failed!!\n");
+ break;
+ }
+
+ b44_populate_rx_descriptor(bp, i);
+ }
+}
+
+
+static void b44_free_rx_ring(struct b44_private *bp)
+{
+ u32 i;
+
+ if (bp->rx) {
+ for (i = 0; i < B44_RING_SIZE; i++) {
+ free_iob(bp->rx_iobuf[i]);
+ bp->rx_iobuf[i] = NULL;
+ }
+ free_dma(bp->rx, B44_RX_RING_LEN_BYTES);
+ bp->rx = NULL;
+ }
+}
+
+
+static int b44_init_rx_ring(struct b44_private *bp)
+{
+ b44_free_rx_ring(bp);
+
+ bp->rx = malloc_dma(B44_RX_RING_LEN_BYTES, B44_DMA_ALIGNMENT);
+ if (!bp->rx)
+ return -ENOMEM;
+
+ memset(bp->rx_iobuf, 0, sizeof(bp->rx_iobuf));
+
+ bp->rx_iobuf[0] = alloc_iob(RX_PKT_BUF_SZ);
+ b44_populate_rx_descriptor(bp, 0);
+ b44_rx_refill(bp, 0);
+
+ DBG("Init RX rings: rx=0x%08lx\n", VIRT_TO_B44(bp->rx));
+ return 0;
+}
+
+
+static void b44_free_tx_ring(struct b44_private *bp)
+{
+ if (bp->tx) {
+ free_dma(bp->tx, B44_TX_RING_LEN_BYTES);
+ bp->tx = NULL;
+ }
+}
+
+
+static int b44_init_tx_ring(struct b44_private *bp)
+{
+ b44_free_tx_ring(bp);
+
+ bp->tx = malloc_dma(B44_TX_RING_LEN_BYTES, B44_DMA_ALIGNMENT);
+ if (!bp->tx)
+ return -ENOMEM;
+
+ memset(bp->tx, 0, B44_TX_RING_LEN_BYTES);
+ memset(bp->tx_iobuf, 0, sizeof(bp->tx_iobuf));
+
+ DBG("Init TX rings: tx=0x%08lx\n", VIRT_TO_B44(bp->tx));
+ return 0;
+}
+
+
+/*** Interaction with the PHY ***/
+
+
+static int b44_phy_read(struct b44_private *bp, int reg, u32 * val)
+{
+ int err;
+
+ u32 arg1 = (MDIO_OP_READ << MDIO_DATA_OP_SHIFT);
+ u32 arg2 = (bp->phy_addr << MDIO_DATA_PMD_SHIFT);
+ u32 arg3 = (reg << MDIO_DATA_RA_SHIFT);
+ u32 arg4 = (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT);
+ u32 argv = arg1 | arg2 | arg3 | arg4;
+
+ bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
+ bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | argv));
+ err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
+ *val = br32(bp, B44_MDIO_DATA) & MDIO_DATA_DATA;
+
+ return err;
+}
+
+
+static int b44_phy_write(struct b44_private *bp, int reg, u32 val)
+{
+ u32 arg1 = (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT);
+ u32 arg2 = (bp->phy_addr << MDIO_DATA_PMD_SHIFT);
+ u32 arg3 = (reg << MDIO_DATA_RA_SHIFT);
+ u32 arg4 = (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT);
+ u32 arg5 = (val & MDIO_DATA_DATA);
+ u32 argv = arg1 | arg2 | arg3 | arg4 | arg5;
+
+
+ bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
+ bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START | argv));
+ return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
+}
+
+
+static int b44_phy_reset(struct b44_private *bp)
+{
+ u32 val;
+ int err;
+
+ err = b44_phy_write(bp, MII_BMCR, BMCR_RESET);
+ if (err)
+ return err;
+
+ udelay(100);
+ err = b44_phy_read(bp, MII_BMCR, &val);
+ if (!err) {
+ if (val & BMCR_RESET) {
+ return -ENODEV;
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ * The BCM44xx CAM (Content Addressable Memory) stores the MAC
+ * and PHY address.
+ */
+static void b44_cam_write(struct b44_private *bp, unsigned char *data,
+ int index)
+{
+ u32 val;
+
+ val = ((u32) data[2]) << 24;
+ val |= ((u32) data[3]) << 16;
+ val |= ((u32) data[4]) << 8;
+ val |= ((u32) data[5]) << 0;
+ bw32(bp, B44_CAM_DATA_LO, val);
+
+
+ val = (CAM_DATA_HI_VALID |
+ (((u32) data[0]) << 8) | (((u32) data[1]) << 0));
+
+ bw32(bp, B44_CAM_DATA_HI, val);
+
+ val = CAM_CTRL_WRITE | (index << CAM_CTRL_INDEX_SHIFT);
+ bw32(bp, B44_CAM_CTRL, val);
+
+ b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1);
+}
+
+
+static void b44_set_mac_addr(struct b44_private *bp)
+{
+ u32 val;
+ bw32(bp, B44_CAM_CTRL, 0);
+ b44_cam_write(bp, bp->netdev->ll_addr, 0);
+ val = br32(bp, B44_CAM_CTRL);
+ bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
+}
+
+
+/* Read 128-bytes of EEPROM. */
+static void b44_read_eeprom(struct b44_private *bp, u8 * data)
+{
+ long i;
+ u16 *ptr = (u16 *) data;
+
+ for (i = 0; i < 128; i += 2)
+ ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i));
+}
+
+
+static void b44_load_mac_and_phy_addr(struct b44_private *bp)
+{
+ u8 eeprom[128];
+
+ /* Load MAC address, note byteswapping */
+ b44_read_eeprom(bp, &eeprom[0]);
+ bp->netdev->ll_addr[0] = eeprom[79];
+ bp->netdev->ll_addr[1] = eeprom[78];
+ bp->netdev->ll_addr[2] = eeprom[81];
+ bp->netdev->ll_addr[3] = eeprom[80];
+ bp->netdev->ll_addr[4] = eeprom[83];
+ bp->netdev->ll_addr[5] = eeprom[82];
+
+ /* Load PHY address */
+ bp->phy_addr = eeprom[90] & 0x1f;
+}
+
+
+static void b44_set_rx_mode(struct net_device *netdev)
+{
+ struct b44_private *bp = netdev_priv(netdev);
+ unsigned char zero[6] = { 0, 0, 0, 0, 0, 0 };
+ u32 val;
+ int i;
+
+ val = br32(bp, B44_RXCONFIG);
+ val &= ~RXCONFIG_PROMISC;
+ val |= RXCONFIG_ALLMULTI;
+
+ b44_set_mac_addr(bp);
+
+ for (i = 1; i < 64; i++)
+ b44_cam_write(bp, zero, i);
+
+ bw32(bp, B44_RXCONFIG, val);
+ val = br32(bp, B44_CAM_CTRL);
+ bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
+}
+
+
+/*** Implementation of gPXE driver callbacks ***/
+
+/**
+ * Probe device
+ *
+ * @v pci PCI device
+ * @v id Matching entry in ID table
+ * @ret rc Return status code
+ */
+static int b44_probe(struct pci_device *pci, const struct pci_device_id *id)
+{
+ struct net_device *netdev;
+ struct b44_private *bp;
+ int rc;
+
+ /*
+ * Bail out if more than 1GB of physical RAM is installed.
+ * This limitation will be removed later when dma mapping
+ * is merged into mainline.
+ */
+ if (!phys_ram_within_limit(B44_30BIT_DMA_MASK)) {
+ DBG("Sorry, this version of the driver does not\n"
+ "support systems with more than 1GB of RAM.\n");
+ return -ENOMEM;
+ }
+
+ /* Set up netdev */
+ netdev = alloc_etherdev(sizeof(*bp));
+ if (!netdev)
+ return -ENOMEM;
+
+ netdev_init(netdev, &b44_operations);
+ pci_set_drvdata(pci, netdev);
+ netdev->dev = &pci->dev;
+
+ /* Set up private data */
+ bp = netdev_priv(netdev);
+ memset(bp, 0, sizeof(*bp));
+ bp->netdev = netdev;
+ bp->pci = pci;
+
+ /* Map device registers */
+ bp->regs = ioremap(pci->membase, B44_REGS_SIZE);
+ if (!bp->regs) {
+ netdev_put(netdev);
+ return -ENOMEM;
+ }
+
+ /* Enable PCI bus mastering */
+ adjust_pci_device(pci);
+
+ b44_load_mac_and_phy_addr(bp);
+
+ /* Link management currently not implemented */
+ netdev_link_up(netdev);
+
+ rc = register_netdev(netdev);
+ if (rc != 0) {
+ iounmap(bp->regs);
+ netdev_put(netdev);
+ return rc;
+ }
+
+ b44_chip_reset(bp, B44_CHIP_RESET_FULL);
+
+ DBG("b44 %s (%04x:%04x) regs=%p MAC=%s\n", id->name, id->vendor,
+ id->device, bp->regs, eth_ntoa(netdev->ll_addr));
+
+ return 0;
+}
+
+
+/**
+ * Remove device
+ *
+ * @v pci PCI device
+ */
+static void b44_remove(struct pci_device *pci)
+{
+ struct net_device *netdev = pci_get_drvdata(pci);
+ struct b44_private *bp = netdev_priv(netdev);
+
+ ssb_core_disable(bp);
+ unregister_netdev(netdev);
+ iounmap(bp->regs);
+ netdev_nullify(netdev);
+ netdev_put(netdev);
+}
+
+
+/** Enable or disable interrupts
+ *
+ * @v netdev Network device
+ * @v enable Interrupts should be enabled
+ */
+static void b44_irq(struct net_device *netdev, int enable)
+{
+ struct b44_private *bp = netdev_priv(netdev);
+
+ /* Interrupt mask specifies which events generate interrupts */
+ bw32(bp, B44_IMASK, enable ? IMASK_DEF : IMASK_DISABLE);
+}
+
+
+/** Open network device
+ *
+ * @v netdev Network device
+ * @ret rc Return status code
+ */
+static int b44_open(struct net_device *netdev)
+{
+ struct b44_private *bp = netdev_priv(netdev);
+ int rc;
+
+ rc = b44_init_tx_ring(bp);
+ if (rc != 0)
+ return rc;
+
+ rc = b44_init_rx_ring(bp);
+ if (rc != 0)
+ return rc;
+
+ b44_init_hw(bp, B44_FULL_RESET);
+
+ /* Disable interrupts */
+ b44_irq(netdev, 0);
+
+ return 0;
+}
+
+
+/** Close network device
+ *
+ * @v netdev Network device
+ */
+static void b44_close(struct net_device *netdev)
+{
+ struct b44_private *bp = netdev_priv(netdev);
+
+ b44_chip_reset(bp, B44_FULL_RESET);
+ b44_free_tx_ring(bp);
+ b44_free_rx_ring(bp);
+}
+
+
+/** Transmit packet
+ *
+ * @v netdev Network device
+ * @v iobuf I/O buffer
+ * @ret rc Return status code
+ */
+static int b44_transmit(struct net_device *netdev, struct io_buffer *iobuf)
+{
+ struct b44_private *bp = netdev_priv(netdev);
+ u32 cur = bp->tx_cur;
+ u32 ctrl;
+
+ /* Check for TX ring overflow */
+ if (bp->tx[cur].ctrl) {
+ DBG("tx overflow\n");
+ return -ENOBUFS;
+ }
+
+ /* Will call netdev_tx_complete() on the iobuf later */
+ bp->tx_iobuf[cur] = iobuf;
+
+ /* Set up TX descriptor */
+ ctrl = (iob_len(iobuf) & DESC_CTRL_LEN) |
+ DESC_CTRL_IOC | DESC_CTRL_SOF | DESC_CTRL_EOF;
+
+ if (cur == B44_RING_LAST)
+ ctrl |= DESC_CTRL_EOT;
+
+ bp->tx[cur].ctrl = cpu_to_le32(ctrl);
+ bp->tx[cur].addr = cpu_to_le32(VIRT_TO_B44(iobuf->data));
+
+ /* Update next available descriptor index */
+ cur = ring_next(cur);
+ bp->tx_cur = cur;
+ wmb();
+
+ /* Tell card that a new TX descriptor is ready */
+ bw32(bp, B44_DMATX_PTR, cur * sizeof(struct dma_desc));
+ return 0;
+}
+
+
+/** Recycles sent TX descriptors and notifies network stack
+ *
+ * @v bp Driver state
+ */
+static void b44_tx_complete(struct b44_private *bp)
+{
+ u32 cur, i;
+
+ cur = pending_tx_index(bp);
+
+ for (i = bp->tx_dirty; i != cur; i = ring_next(i)) {
+ /* Free finished frame */
+ netdev_tx_complete(bp->netdev, bp->tx_iobuf[i]);
+ bp->tx_iobuf[i] = NULL;
+
+ /* Clear TX descriptor */
+ bp->tx[i].ctrl = 0;
+ bp->tx[i].addr = 0;
+ }
+ bp->tx_dirty = cur;
+}
+
+
+static void b44_process_rx_packets(struct b44_private *bp)
+{
+ struct io_buffer *iob; /* received data */
+ struct rx_header *rh;
+ u32 pending, i;
+ u16 len;
+
+ pending = pending_rx_index(bp);
+
+ for (i = bp->rx_cur; i != pending; i = ring_next(i)) {
+ iob = bp->rx_iobuf[i];
+ if (iob == NULL)
+ break;
+
+ rh = iob->data;
+ len = le16_to_cpu(rh->len);
+
+ /*
+ * Guard against incompletely written RX descriptors.
+ * Without this, things can get really slow!
+ */
+ if (len == 0)
+ break;
+
+ /* Discard CRC that is generated by the card */
+ len -= 4;
+
+ /* Check for invalid packets and errors */
+ if (len > RX_PKT_BUF_SZ - RX_PKT_OFFSET ||
+ (rh->flags & cpu_to_le16(RX_FLAG_ERRORS))) {
+ DBG("rx error len=%d flags=%04x\n", len,
+ cpu_to_le16(rh->flags));
+ rh->len = 0;
+ rh->flags = 0;
+ netdev_rx_err(bp->netdev, iob, -EINVAL);
+ continue;
+ }
+
+ /* Clear RX descriptor */
+ rh->len = 0;
+ rh->flags = 0;
+ bp->rx_iobuf[i] = NULL;
+
+ /* Hand off the IO buffer to the network stack */
+ iob_reserve(iob, RX_PKT_OFFSET);
+ iob_put(iob, len);
+ netdev_rx(bp->netdev, iob);
+ }
+ bp->rx_cur = i;
+ b44_rx_refill(bp, pending_rx_index(bp));
+}
+
+
+/** Poll for completed and received packets
+ *
+ * @v netdev Network device
+ */
+static void b44_poll(struct net_device *netdev)
+{
+ struct b44_private *bp = netdev_priv(netdev);
+ u32 istat;
+
+ /* Interrupt status */
+ istat = br32(bp, B44_ISTAT);
+ istat &= IMASK_DEF; /* only the events we care about */
+
+ if (!istat)
+ return;
+ if (istat & ISTAT_TX)
+ b44_tx_complete(bp);
+ if (istat & ISTAT_RX)
+ b44_process_rx_packets(bp);
+ if (istat & ISTAT_ERRORS) {
+ DBG("b44 error istat=0x%08x\n", istat);
+
+ /* Reset B44 core partially to avoid long waits */
+ b44_irq(bp->netdev, 0);
+ b44_halt(bp);
+ b44_init_tx_ring(bp);
+ b44_init_rx_ring(bp);
+ b44_init_hw(bp, B44_FULL_RESET_SKIP_PHY);
+ }
+
+ /* Acknowledge interrupt */
+ bw32(bp, B44_ISTAT, 0);
+ bflush(bp, B44_ISTAT, 1);
+}
+
+
+static struct net_device_operations b44_operations = {
+ .open = b44_open,
+ .close = b44_close,
+ .transmit = b44_transmit,
+ .poll = b44_poll,
+ .irq = b44_irq,
+};
+
+
+static struct pci_device_id b44_nics[] = {
+ PCI_ROM(0x14e4, 0x4401, "BCM4401", "BCM4401"),
+ PCI_ROM(0x14e4, 0x170c, "BCM4401-B0", "BCM4401-B0"),
+ PCI_ROM(0x14e4, 0x4402, "BCM4401-B1", "BCM4401-B1"),
+};
+
+
+struct pci_driver b44_driver __pci_driver = {
+ .ids = b44_nics,
+ .id_count = sizeof b44_nics / sizeof b44_nics[0],
+ .probe = b44_probe,
+ .remove = b44_remove,
+};
diff --git a/gpxe/src/drivers/net/b44.h b/gpxe/src/drivers/net/b44.h
new file mode 100644
index 00000000..fb36757f
--- /dev/null
+++ b/gpxe/src/drivers/net/b44.h
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2008 Stefan Hajnoczi <stefanha@gmail.com>
+ * Copyright (c) 2008 Pantelis Koukousoulas <pktoss@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver is a port of the b44 linux driver version 1.01
+ *
+ * Copyright (c) 2002 David S. Miller <davem@redhat.com>
+ * Copyright (c) Pekka Pietikainen <pp@ee.oulu.fi>
+ * Copyright (C) 2006 Broadcom Corporation.
+ *
+ * Some ssb bits copied from version 2.0 of the b44 driver
+ * Copyright (c) Michael Buesch
+ *
+ * Copyright (c) a lot of people too. Please respect their work.
+ */
+#ifndef _B44_H
+#define _B44_H
+
+/* BCM44xx Register layout */
+#define B44_DEVCTRL 0x0000UL /* Device Control */
+#define DEVCTRL_MPM 0x00000040 /* MP PME Enable (B0 only) */
+#define DEVCTRL_PFE 0x00000080 /* Pattern Filtering Enable */
+#define DEVCTRL_IPP 0x00000400 /* Internal EPHY Present */
+#define DEVCTRL_EPR 0x00008000 /* EPHY Reset */
+#define DEVCTRL_PME 0x00001000 /* PHY Mode Enable */
+#define DEVCTRL_PMCE 0x00002000 /* PHY Mode Clocks Enable */
+#define DEVCTRL_PADDR 0x0007c000 /* PHY Address */
+#define DEVCTRL_PADDR_SHIFT 18
+#define B44_BIST_STAT 0x000CUL /* Built-In Self-Test Status */
+#define B44_WKUP_LEN 0x0010UL /* Wakeup Length */
+#define WKUP_LEN_P0_MASK 0x0000007f /* Pattern 0 */
+#define WKUP_LEN_D0 0x00000080
+#define WKUP_LEN_P1_MASK 0x00007f00 /* Pattern 1 */
+#define WKUP_LEN_P1_SHIFT 8
+#define WKUP_LEN_D1 0x00008000
+#define WKUP_LEN_P2_MASK 0x007f0000 /* Pattern 2 */
+#define WKUP_LEN_P2_SHIFT 16
+#define WKUP_LEN_D2 0x00000000
+#define WKUP_LEN_P3_MASK 0x7f000000 /* Pattern 3 */
+#define WKUP_LEN_P3_SHIFT 24
+#define WKUP_LEN_D3 0x80000000
+#define WKUP_LEN_DISABLE 0x80808080
+#define WKUP_LEN_ENABLE_TWO 0x80800000
+#define WKUP_LEN_ENABLE_THREE 0x80000000
+#define B44_ISTAT 0x0020UL /* Interrupt Status */
+#define ISTAT_LS 0x00000020 /* Link Change (B0 only) */
+#define ISTAT_PME 0x00000040 /* Power Management Event */
+#define ISTAT_TO 0x00000080 /* General Purpose Timeout */
+#define ISTAT_DSCE 0x00000400 /* Descriptor Error */
+#define ISTAT_DATAE 0x00000800 /* Data Error */
+#define ISTAT_DPE 0x00001000 /* Descr. Protocol Error */
+#define ISTAT_RDU 0x00002000 /* Receive Descr. Underflow */
+#define ISTAT_RFO 0x00004000 /* Receive FIFO Overflow */
+#define ISTAT_TFU 0x00008000 /* Transmit FIFO Underflow */
+#define ISTAT_RX 0x00010000 /* RX Interrupt */
+#define ISTAT_TX 0x01000000 /* TX Interrupt */
+#define ISTAT_EMAC 0x04000000 /* EMAC Interrupt */
+#define ISTAT_MII_WRITE 0x08000000 /* MII Write Interrupt */
+#define ISTAT_MII_READ 0x10000000 /* MII Read Interrupt */
+#define ISTAT_ERRORS (ISTAT_DSCE|ISTAT_DATAE|ISTAT_DPE|\
+ ISTAT_RDU|ISTAT_RFO|ISTAT_TFU)
+#define B44_IMASK 0x0024UL /* Interrupt Mask */
+#define IMASK_DEF (ISTAT_ERRORS | ISTAT_RX | ISTAT_TX)
+#define IMASK_DISABLE 0
+#define B44_GPTIMER 0x0028UL /* General Purpose Timer */
+#define B44_ADDR_LO 0x0088UL /* ENET Address Lo (B0 only) */
+#define B44_ADDR_HI 0x008CUL /* ENET Address Hi (B0 only) */
+#define B44_FILT_ADDR 0x0090UL /* ENET Filter Address */
+#define B44_FILT_DATA 0x0094UL /* ENET Filter Data */
+#define B44_TXBURST 0x00A0UL /* TX Max Burst Length */
+#define B44_RXBURST 0x00A4UL /* RX Max Burst Length */
+#define B44_MAC_CTRL 0x00A8UL /* MAC Control */
+#define MAC_CTRL_CRC32_ENAB 0x00000001 /* CRC32 Generation Enable */
+#define MAC_CTRL_PHY_PDOWN 0x00000004 /* Onchip EPHY Powerdown */
+#define MAC_CTRL_PHY_EDET 0x00000008 /* Onchip EPHY Energy Detected*/
+#define MAC_CTRL_PHY_LEDCTRL 0x000000e0 /* Onchip EPHY LED Control */
+#define MAC_CTRL_PHY_LEDCTRL_SHIFT 5
+#define B44_MAC_FLOW 0x00ACUL /* MAC Flow Control */
+#define MAC_FLOW_RX_HI_WATER 0x000000ff /* Receive FIFO HI Water Mark */
+#define MAC_FLOW_PAUSE_ENAB 0x00008000 /* Enbl Pause Frm Generation */
+#define B44_RCV_LAZY 0x0100UL /* Lazy Interrupt Control */
+#define RCV_LAZY_TO_MASK 0x00ffffff /* Timeout */
+#define RCV_LAZY_FC_MASK 0xff000000 /* Frame Count */
+#define RCV_LAZY_FC_SHIFT 24
+#define B44_DMATX_CTRL 0x0200UL /* DMA TX Control */
+#define DMATX_CTRL_ENABLE 0x00000001 /* Enable */
+#define DMATX_CTRL_SUSPEND 0x00000002 /* Suepend Request */
+#define DMATX_CTRL_LPBACK 0x00000004 /* Loopback Enable */
+#define DMATX_CTRL_FAIRPRIOR 0x00000008 /* Fair Priority */
+#define DMATX_CTRL_FLUSH 0x00000010 /* Flush Request */
+#define B44_DMATX_ADDR 0x0204UL /* DMA TX Descriptor Ring Addr */
+#define B44_DMATX_PTR 0x0208UL /* DMA TX Last Posted Desc. */
+#define B44_DMATX_STAT 0x020CUL /* DMA TX Cur Actve Desc. + Sts */
+#define DMATX_STAT_CDMASK 0x00000fff /* Current Descriptor Mask */
+#define DMATX_STAT_SMASK 0x0000f000 /* State Mask */
+#define DMATX_STAT_SDISABLED 0x00000000 /* State Disabled */
+#define DMATX_STAT_SACTIVE 0x00001000 /* State Active */
+#define DMATX_STAT_SIDLE 0x00002000 /* State Idle Wait */
+#define DMATX_STAT_SSTOPPED 0x00003000 /* State Stopped */
+#define DMATX_STAT_SSUSP 0x00004000 /* State Suspend Pending */
+#define DMATX_STAT_EMASK 0x000f0000 /* Error Mask */
+#define DMATX_STAT_ENONE 0x00000000 /* Error None */
+#define DMATX_STAT_EDPE 0x00010000 /* Error Desc. Protocol Error */
+#define DMATX_STAT_EDFU 0x00020000 /* Error Data FIFO Underrun */
+#define DMATX_STAT_EBEBR 0x00030000 /* Bus Error on Buffer Read */
+#define DMATX_STAT_EBEDA 0x00040000 /* Bus Error on Desc. Access */
+#define DMATX_STAT_FLUSHED 0x00100000 /* Flushed */
+#define B44_DMARX_CTRL 0x0210UL /* DMA RX Control */
+#define DMARX_CTRL_ENABLE 0x00000001 /* Enable */
+#define DMARX_CTRL_ROMASK 0x000000fe /* Receive Offset Mask */
+#define DMARX_CTRL_ROSHIFT 1 /* Receive Offset Shift */
+#define B44_DMARX_ADDR 0x0214UL /* DMA RX Descriptor Ring Addr */
+#define B44_DMARX_PTR 0x0218UL /* DMA RX Last Posted Desc */
+#define B44_DMARX_STAT 0x021CUL /* Cur Active Desc. + Status */
+#define DMARX_STAT_CDMASK 0x00000fff /* Current Descriptor Mask */
+#define DMARX_STAT_SMASK 0x0000f000 /* State Mask */
+#define DMARX_STAT_SDISABLED 0x00000000 /* State Disbaled */
+#define DMARX_STAT_SACTIVE 0x00001000 /* State Active */
+#define DMARX_STAT_SIDLE 0x00002000 /* State Idle Wait */
+#define DMARX_STAT_SSTOPPED 0x00003000 /* State Stopped */
+#define DMARX_STAT_EMASK 0x000f0000 /* Error Mask */
+#define DMARX_STAT_ENONE 0x00000000 /* Error None */
+#define DMARX_STAT_EDPE 0x00010000 /* Error Desc. Protocol Error */
+#define DMARX_STAT_EDFO 0x00020000 /* Error Data FIFO Overflow */
+#define DMARX_STAT_EBEBW 0x00030000 /* Error on Buffer Write */
+#define DMARX_STAT_EBEDA 0x00040000 /* Bus Error on Desc. Access */
+#define B44_DMAFIFO_AD 0x0220UL /* DMA FIFO Diag Address */
+#define DMAFIFO_AD_OMASK 0x0000ffff /* Offset Mask */
+#define DMAFIFO_AD_SMASK 0x000f0000 /* Select Mask */
+#define DMAFIFO_AD_SXDD 0x00000000 /* Select Transmit DMA Data */
+#define DMAFIFO_AD_SXDP 0x00010000 /* Sel Transmit DMA Pointers */
+#define DMAFIFO_AD_SRDD 0x00040000 /* Select Receive DMA Data */
+#define DMAFIFO_AD_SRDP 0x00050000 /* Sel Receive DMA Pointers */
+#define DMAFIFO_AD_SXFD 0x00080000 /* Select Transmit FIFO Data */
+#define DMAFIFO_AD_SXFP 0x00090000 /* Sel Transmit FIFO Pointers */
+#define DMAFIFO_AD_SRFD 0x000c0000 /* Select Receive FIFO Data */
+#define DMAFIFO_AD_SRFP 0x000c0000 /* Sel Receive FIFO Pointers */
+#define B44_DMAFIFO_LO 0x0224UL /* DMA FIFO Diag Low Data */
+#define B44_DMAFIFO_HI 0x0228UL /* DMA FIFO Diag High Data */
+#define B44_RXCONFIG 0x0400UL /* EMAC RX Config */
+#define RXCONFIG_DBCAST 0x00000001 /* Disable Broadcast */
+#define RXCONFIG_ALLMULTI 0x00000002 /* Accept All Multicast */
+#define RXCONFIG_NORX_WHILE_TX 0x00000004 /* Rcv Disble While TX */
+#define RXCONFIG_PROMISC 0x00000008 /* Promiscuous Enable */
+#define RXCONFIG_LPBACK 0x00000010 /* Loopback Enable */
+#define RXCONFIG_FLOW 0x00000020 /* Flow Control Enable */
+#define RXCONFIG_FLOW_ACCEPT 0x00000040 /* Accept UFC Frame */
+#define RXCONFIG_RFILT 0x00000080 /* Reject Filter */
+#define B44_RXMAXLEN 0x0404UL /* EMAC RX Max Packet Length */
+#define B44_TXMAXLEN 0x0408UL /* EMAC TX Max Packet Length */
+#define B44_MDIO_CTRL 0x0410UL /* EMAC MDIO Control */
+#define MDIO_CTRL_MAXF_MASK 0x0000007f /* MDC Frequency */
+#define MDIO_CTRL_PREAMBLE 0x00000080 /* MII Preamble Enable */
+#define B44_MDIO_DATA 0x0414UL /* EMAC MDIO Data */
+#define MDIO_DATA_DATA 0x0000ffff /* R/W Data */
+#define MDIO_DATA_TA_MASK 0x00030000 /* Turnaround Value */
+#define MDIO_DATA_TA_SHIFT 16
+#define MDIO_TA_VALID 2
+#define MDIO_DATA_RA_MASK 0x007c0000 /* Register Address */
+#define MDIO_DATA_RA_SHIFT 18
+#define MDIO_DATA_PMD_MASK 0x0f800000 /* Physical Media Device */
+#define MDIO_DATA_PMD_SHIFT 23
+#define MDIO_DATA_OP_MASK 0x30000000 /* Opcode */
+#define MDIO_DATA_OP_SHIFT 28
+#define MDIO_OP_WRITE 1
+#define MDIO_OP_READ 2
+#define MDIO_DATA_SB_MASK 0xc0000000 /* Start Bits */
+#define MDIO_DATA_SB_SHIFT 30
+#define MDIO_DATA_SB_START 0x40000000 /* Start Of Frame */
+#define B44_EMAC_IMASK 0x0418UL /* EMAC Interrupt Mask */
+#define B44_EMAC_ISTAT 0x041CUL /* EMAC Interrupt Status */
+#define EMAC_INT_MII 0x00000001 /* MII MDIO Interrupt */
+#define EMAC_INT_MIB 0x00000002 /* MIB Interrupt */
+#define EMAC_INT_FLOW 0x00000003 /* Flow Control Interrupt */
+#define B44_CAM_DATA_LO 0x0420UL /* EMAC CAM Data Low */
+#define B44_CAM_DATA_HI 0x0424UL /* EMAC CAM Data High */
+#define CAM_DATA_HI_VALID 0x00010000 /* Valid Bit */
+#define B44_CAM_CTRL 0x0428UL /* EMAC CAM Control */
+#define CAM_CTRL_ENABLE 0x00000001 /* CAM Enable */
+#define CAM_CTRL_MSEL 0x00000002 /* Mask Select */
+#define CAM_CTRL_READ 0x00000004 /* Read */
+#define CAM_CTRL_WRITE 0x00000008 /* Read */
+#define CAM_CTRL_INDEX_MASK 0x003f0000 /* Index Mask */
+#define CAM_CTRL_INDEX_SHIFT 16
+#define CAM_CTRL_BUSY 0x80000000 /* CAM Busy */
+#define B44_ENET_CTRL 0x042CUL /* EMAC ENET Control */
+#define ENET_CTRL_ENABLE 0x00000001 /* EMAC Enable */
+#define ENET_CTRL_DISABLE 0x00000002 /* EMAC Disable */
+#define ENET_CTRL_SRST 0x00000004 /* EMAC Soft Reset */
+#define ENET_CTRL_EPSEL 0x00000008 /* External PHY Select */
+#define B44_TX_CTRL 0x0430UL /* EMAC TX Control */
+#define TX_CTRL_DUPLEX 0x00000001 /* Full Duplex */
+#define TX_CTRL_FMODE 0x00000002 /* Flow Mode */
+#define TX_CTRL_SBENAB 0x00000004 /* Single Backoff Enable */
+#define TX_CTRL_SMALL_SLOT 0x00000008 /* Small Slottime */
+#define B44_TX_HIWMARK 0x0434UL /* EMAC TX High Watermark */
+#define TX_HIWMARK_DEFLT 56 /* Default used in all drivers */
+#define B44_MIB_CTRL 0x0438UL /* EMAC MIB Control */
+#define MIB_CTRL_CLR_ON_READ 0x00000001 /* Autoclear on Read */
+#define B44_TX_GOOD_O 0x0500UL /* MIB TX Good Octets */
+#define B44_TX_GOOD_P 0x0504UL /* MIB TX Good Packets */
+#define B44_TX_O 0x0508UL /* MIB TX Octets */
+#define B44_TX_P 0x050CUL /* MIB TX Packets */
+#define B44_TX_BCAST 0x0510UL /* MIB TX Broadcast Packets */
+#define B44_TX_MCAST 0x0514UL /* MIB TX Multicast Packets */
+#define B44_TX_64 0x0518UL /* MIB TX <= 64 byte Packets */
+#define B44_TX_65_127 0x051CUL /* MIB TX 65 to 127 byte Pkts */
+#define B44_TX_128_255 0x0520UL /* MIB TX 128 to 255 byte Pkts */
+#define B44_TX_256_511 0x0524UL /* MIB TX 256 to 511 byte Pkts */
+#define B44_TX_512_1023 0x0528UL /* MIB TX 512 to 1023 byte Pkts */
+#define B44_TX_1024_MAX 0x052CUL /* MIB TX 1024 to max byte Pkts */
+#define B44_TX_JABBER 0x0530UL /* MIB TX Jabber Packets */
+#define B44_TX_OSIZE 0x0534UL /* MIB TX Oversize Packets */
+#define B44_TX_FRAG 0x0538UL /* MIB TX Fragment Packets */
+#define B44_TX_URUNS 0x053CUL /* MIB TX Underruns */
+#define B44_TX_TCOLS 0x0540UL /* MIB TX Total Collisions */
+#define B44_TX_SCOLS 0x0544UL /* MIB TX Single Collisions */
+#define B44_TX_MCOLS 0x0548UL /* MIB TX Multiple Collisions */
+#define B44_TX_ECOLS 0x054CUL /* MIB TX Excessive Collisions */
+#define B44_TX_LCOLS 0x0550UL /* MIB TX Late Collisions */
+#define B44_TX_DEFERED 0x0554UL /* MIB TX Defered Packets */
+#define B44_TX_CLOST 0x0558UL /* MIB TX Carrier Lost */
+#define B44_TX_PAUSE 0x055CUL /* MIB TX Pause Packets */
+#define B44_RX_GOOD_O 0x0580UL /* MIB RX Good Octets */
+#define B44_RX_GOOD_P 0x0584UL /* MIB RX Good Packets */
+#define B44_RX_O 0x0588UL /* MIB RX Octets */
+#define B44_RX_P 0x058CUL /* MIB RX Packets */
+#define B44_RX_BCAST 0x0590UL /* MIB RX Broadcast Packets */
+#define B44_RX_MCAST 0x0594UL /* MIB RX Multicast Packets */
+#define B44_RX_64 0x0598UL /* MIB RX <= 64 byte Packets */
+#define B44_RX_65_127 0x059CUL /* MIB RX 65 to 127 byte Pkts */
+#define B44_RX_128_255 0x05A0UL /* MIB RX 128 to 255 byte Pkts */
+#define B44_RX_256_511 0x05A4UL /* MIB RX 256 to 511 byte Pkts */
+#define B44_RX_512_1023 0x05A8UL /* MIB RX 512 to 1023 byte Pkts */
+#define B44_RX_1024_MAX 0x05ACUL /* MIB RX 1024 to max byte Pkts */
+#define B44_RX_JABBER 0x05B0UL /* MIB RX Jabber Packets */
+#define B44_RX_OSIZE 0x05B4UL /* MIB RX Oversize Packets */
+#define B44_RX_FRAG 0x05B8UL /* MIB RX Fragment Packets */
+#define B44_RX_MISS 0x05BCUL /* MIB RX Missed Packets */
+#define B44_RX_CRCA 0x05C0UL /* MIB RX CRC Align Errors */
+#define B44_RX_USIZE 0x05C4UL /* MIB RX Undersize Packets */
+#define B44_RX_CRC 0x05C8UL /* MIB RX CRC Errors */
+#define B44_RX_ALIGN 0x05CCUL /* MIB RX Align Errors */
+#define B44_RX_SYM 0x05D0UL /* MIB RX Symbol Errors */
+#define B44_RX_PAUSE 0x05D4UL /* MIB RX Pause Packets */
+#define B44_RX_NPAUSE 0x05D8UL /* MIB RX Non-Pause Packets */
+
+/* Sonics Silicon backplane register definitions */
+#define B44_SBIMSTATE 0x0F90UL /* SB Initiator Agent State */
+#define SBIMSTATE_PC 0x0000000f /* Pipe Count */
+#define SBIMSTATE_AP_MASK 0x00000030 /* Arbitration Priority */
+#define SBIMSTATE_AP_BOTH 0x00000000 /* both timeslices and token */
+#define SBIMSTATE_AP_TS 0x00000010 /* Use timeslices only */
+#define SBIMSTATE_AP_TK 0x00000020 /* Use token only */
+#define SBIMSTATE_AP_RSV 0x00000030 /* Reserved */
+#define SBIMSTATE_IBE 0x00020000 /* In Band Error */
+#define SBIMSTATE_TO 0x00040000 /* Timeout */
+#define SBIMSTATE_BAD ( SBIMSTATE_IBE | SBIMSTATE_TO )
+#define B44_SBINTVEC 0x0F94UL /* SB Interrupt Mask */
+#define SBINTVEC_PCI 0x00000001 /* Enable interrupts for PCI */
+#define SBINTVEC_ENET0 0x00000002 /* Enable ints for enet 0 */
+#define SBINTVEC_ILINE20 0x00000004 /* Enable ints for iline20 */
+#define SBINTVEC_CODEC 0x00000008 /* Enable ints for v90 codec */
+#define SBINTVEC_USB 0x00000010 /* Enable intts for usb */
+#define SBINTVEC_EXTIF 0x00000020 /* Enable ints for ext i/f */
+#define SBINTVEC_ENET1 0x00000040 /* Enable ints for enet 1 */
+#define B44_SBTMSLOW 0x0F98UL /* SB Target State Low */
+#define SBTMSLOW_RESET 0x00000001 /* Reset */
+#define SBTMSLOW_REJECT 0x00000002 /* Reject */
+#define SBTMSLOW_CLOCK 0x00010000 /* Clock Enable */
+#define SBTMSLOW_FGC 0x00020000 /* Force Gated Clocks On */
+#define SBTMSLOW_PE 0x40000000 /* Power Management Enable */
+#define SBTMSLOW_BE 0x80000000 /* BIST Enable */
+#define B44_SBTMSHIGH 0x0F9CUL /* SB Target State High */
+#define SBTMSHIGH_SERR 0x00000001 /* S-error */
+#define SBTMSHIGH_INT 0x00000002 /* Interrupt */
+#define SBTMSHIGH_BUSY 0x00000004 /* Busy */
+#define SBTMSHIGH_GCR 0x20000000 /* Gated Clock Request */
+#define SBTMSHIGH_BISTF 0x40000000 /* BIST Failed */
+#define SBTMSHIGH_BISTD 0x80000000 /* BIST Done */
+#define B44_SBIDHIGH 0x0FFCUL /* SB Identification High */
+#define SBIDHIGH_RC_MASK 0x0000000f /* Revision Code */
+#define SBIDHIGH_CC_MASK 0x0000fff0 /* Core Code */
+#define SBIDHIGH_CC_SHIFT 4
+#define SBIDHIGH_VC_MASK 0xffff0000 /* Vendor Code */
+#define SBIDHIGH_VC_SHIFT 16
+
+/* SSB PCI config space registers. */
+#define SSB_PMCSR 0x44
+#define SSB_PE 0x100
+#define SSB_BAR0_WIN 0x80
+#define SSB_BAR1_WIN 0x84
+#define SSB_SPROM_CONTROL 0x88
+#define SSB_BAR1_CONTROL 0x8c
+
+/* SSB core and host control registers. */
+#define SSB_CONTROL 0x0000UL
+#define SSB_ARBCONTROL 0x0010UL
+#define SSB_ISTAT 0x0020UL
+#define SSB_IMASK 0x0024UL
+#define SSB_MBOX 0x0028UL
+#define SSB_BCAST_ADDR 0x0050UL
+#define SSB_BCAST_DATA 0x0054UL
+#define SSB_PCI_TRANS_0 0x0100UL
+#define SSB_PCI_TRANS_1 0x0104UL
+#define SSB_PCI_TRANS_2 0x0108UL
+#define SSB_SPROM 0x0800UL
+
+#define SSB_PCI_MEM 0x00000000
+#define SSB_PCI_IO 0x00000001
+#define SSB_PCI_CFG0 0x00000002
+#define SSB_PCI_CFG1 0x00000003
+#define SSB_PCI_PREF 0x00000004
+#define SSB_PCI_BURST 0x00000008
+#define SSB_PCI_MASK0 0xfc000000
+#define SSB_PCI_MASK1 0xfc000000
+#define SSB_PCI_MASK2 0xc0000000
+
+/* 4400 PHY registers */
+#define B44_MII_AUXCTRL 24 /* Auxiliary Control */
+#define MII_AUXCTRL_DUPLEX 0x0001 /* Full Duplex */
+#define MII_AUXCTRL_SPEED 0x0002 /* 1=100Mbps, 0=10Mbps */
+#define MII_AUXCTRL_FORCED 0x0004 /* Forced 10/100 */
+#define B44_MII_ALEDCTRL 26 /* Activity LED */
+#define MII_ALEDCTRL_ALLMSK 0x7fff
+#define B44_MII_TLEDCTRL 27 /* Traffic Meter LED */
+#define MII_TLEDCTRL_ENABLE 0x0040
+
+/* RX/TX descriptor */
+struct dma_desc {
+ u32 ctrl; /* length of data and flags */
+ u32 addr; /* address of data */
+};
+
+/* There are only 12 bits in the DMA engine for descriptor offsetting
+ * so the table must be aligned on a boundary of this.
+ */
+#define B44_DMA_ALIGNMENT 4096
+
+/* The DMA engine can only address the first gigabyte of address space
+ */
+#define B44_30BIT_DMA_MASK 0x3fffffff
+
+#define DESC_CTRL_LEN 0x00001fff
+#define DESC_CTRL_CMASK 0x0ff00000 /* Core specific bits */
+#define DESC_CTRL_EOT 0x10000000 /* End of Table */
+#define DESC_CTRL_IOC 0x20000000 /* Interrupt On Completion */
+#define DESC_CTRL_EOF 0x40000000 /* End of Frame */
+#define DESC_CTRL_SOF 0x80000000 /* Start of Frame */
+
+struct rx_header {
+ u16 len;
+ u16 flags;
+ u16 pad[12];
+};
+#define RX_HEADER_LEN 28
+
+#define RX_FLAG_OFIFO 0x00000001 /* FIFO Overflow */
+#define RX_FLAG_CRCERR 0x00000002 /* CRC Error */
+#define RX_FLAG_SERR 0x00000004 /* Receive Symbol Error */
+#define RX_FLAG_ODD 0x00000008 /* Frame has odd number of nibbles */
+#define RX_FLAG_LARGE 0x00000010 /* Frame is > RX MAX Length */
+#define RX_FLAG_MCAST 0x00000020 /* Dest is Multicast Address */
+#define RX_FLAG_BCAST 0x00000040 /* Dest is Broadcast Address */
+#define RX_FLAG_MISS 0x00000080 /* Received due to promisc mode */
+#define RX_FLAG_LAST 0x00000800 /* Last buffer in frame */
+#define RX_FLAG_ERRORS (RX_FLAG_ODD | RX_FLAG_SERR |\
+ RX_FLAG_CRCERR | RX_FLAG_OFIFO)
+
+/* Client Mode PCI memory access space (1 GB) */
+#define SB_PCI_DMA 0x40000000
+
+ /* Address of PCI core on BCM4400 cards */
+#define BCM4400_PCI_CORE_ADDR 0x18002000
+
+/* Hardware minimum and maximum for a single frame's data payload */
+#define B44_MIN_MTU 60
+#define B44_MAX_MTU 1500
+
+#define B44_RING_SIZE 8
+#define B44_RING_LAST ( B44_RING_SIZE - 1 )
+
+#define B44_RX_RING_LEN_BYTES ( sizeof bp->rx[0] * B44_RING_SIZE )
+#define B44_TX_RING_LEN_BYTES ( sizeof bp->tx[0] * B44_RING_SIZE )
+
+#define RX_PKT_OFFSET 30
+#define RX_PKT_BUF_SZ (1536 + RX_PKT_OFFSET + 64)
+
+#define B44_FULL_RESET 1
+#define B44_FULL_RESET_SKIP_PHY 2
+#define B44_PARTIAL_RESET 3
+#define B44_CHIP_RESET_FULL 4
+#define B44_CHIP_RESET_PARTIAL 5
+
+#define SSB_CORE_DOWN ( SBTMSLOW_RESET | SBTMSLOW_REJECT )
+
+#define B44_REGS_SIZE 8192
+
+/** Driver private state */
+struct b44_private {
+ struct net_device *netdev;
+ struct pci_device *pci;
+ u8 *regs; /* memory-mapped registers */
+ u8 phy_addr;
+
+ struct dma_desc *tx;
+ struct io_buffer *tx_iobuf[B44_RING_SIZE];
+ u32 tx_cur; /* next available descriptor */
+ u32 tx_dirty; /* oldest pending descriptor */
+
+ struct dma_desc *rx;
+ struct io_buffer *rx_iobuf[B44_RING_SIZE];
+ u32 rx_cur; /* next descriptor to read */
+};
+
+
+static void ssb_core_reset ( struct b44_private *bp );
+static void ssb_core_disable ( struct b44_private *bp );
+static u32 ssb_pci_setup ( struct b44_private *bp, u32 cores );
+
+static void b44_chip_reset ( struct b44_private *bp, int reset_kind );
+static void b44_init_hw ( struct b44_private *bp, int reset_kind );
+static void b44_cam_write ( struct b44_private *bp, u8 *data, int index );
+static void b44_set_mac_addr ( struct b44_private *bp );
+static void b44_set_rx_mode ( struct net_device *netdev );
+static void b44_halt(struct b44_private *);
+
+static int b44_phy_reset ( struct b44_private *bp );
+static int b44_phy_write ( struct b44_private *bp, int reg, u32 val );
+static int b44_phy_read ( struct b44_private *bp, int reg, u32 *val );
+
+static int b44_init_tx_ring ( struct b44_private *bp );
+static void b44_free_tx_ring ( struct b44_private *bp );
+static int b44_init_rx_ring ( struct b44_private *bp );
+static void b44_free_rx_ring ( struct b44_private *bp );
+static void b44_rx_refill ( struct b44_private *bp, u32 pending );
+static void b44_populate_rx_descriptor (struct b44_private *bp, u32 index);
+
+static int b44_probe ( struct pci_device *pci,
+ const struct pci_device_id *id );
+static void b44_remove ( struct pci_device *pci );
+
+static int b44_open ( struct net_device *netdev );
+static void b44_close ( struct net_device *netdev );
+static void b44_irq ( struct net_device *netdev, int enable );
+static void b44_poll ( struct net_device *netdev );
+static void b44_process_rx_packets ( struct b44_private *bp );
+static int b44_transmit ( struct net_device *netdev,
+ struct io_buffer *iobuf );
+
+static struct net_device_operations b44_operations;
+
+#endif /* _B44_H */
diff --git a/gpxe/src/drivers/net/cs89x0.c b/gpxe/src/drivers/net/cs89x0.c
index 11988add..1f647a8e 100644
--- a/gpxe/src/drivers/net/cs89x0.c
+++ b/gpxe/src/drivers/net/cs89x0.c
@@ -419,8 +419,8 @@ retry:
ETH_ALEN/2);
outw(((t >> 8)&0xFF)|(t << 8), eth_nic_base + TX_FRAME_PORT);
outsw(eth_nic_base + TX_FRAME_PORT, p, (s+1)/2);
- for (sr = sr/2 - (s+1)/2 - ETH_ALEN - 1; sr-- > 0;
- outw(0, eth_nic_base + TX_FRAME_PORT));
+ for (sr = sr/2 - (s+1)/2 - ETH_ALEN - 1; sr > 0; sr--)
+ outw(0, eth_nic_base + TX_FRAME_PORT);
/* wait for transfer to succeed */
for (tmo = currticks()+5*TICKS_PER_SEC;
diff --git a/gpxe/src/drivers/net/davicom.c b/gpxe/src/drivers/net/davicom.c
index 079e647e..bb6d7e96 100644
--- a/gpxe/src/drivers/net/davicom.c
+++ b/gpxe/src/drivers/net/davicom.c
@@ -630,7 +630,7 @@ static void davicom_disable ( struct nic *nic ) {
outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
/* Clear the missed-packet counter. */
- (volatile unsigned long)inl(ioaddr + CSR8);
+ inl(ioaddr + CSR8);
}
@@ -676,7 +676,7 @@ static int davicom_probe ( struct nic *nic, struct pci_device *pci ) {
outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
/* Clear the missed-packet counter. */
- (volatile unsigned long)inl(ioaddr + CSR8);
+ inl(ioaddr + CSR8);
/* Get MAC Address */
/* read EEPROM data */
diff --git a/gpxe/src/drivers/net/dmfe.c b/gpxe/src/drivers/net/dmfe.c
index 9cf50418..26021e6b 100644
--- a/gpxe/src/drivers/net/dmfe.c
+++ b/gpxe/src/drivers/net/dmfe.c
@@ -133,14 +133,14 @@
/* Structure/enum declaration ------------------------------- */
struct tx_desc {
u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */
- u32 tx_buf_ptr; /* Data for us */
- u32 /* struct tx_desc * */ next_tx_desc;
+ void * tx_buf_ptr; /* Data for us */
+ struct tx_desc * next_tx_desc;
} __attribute__ ((aligned(32)));
struct rx_desc {
u32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */
- u32 rx_skb_ptr; /* Data for us */
- u32 /* struct rx_desc * */ next_rx_desc;
+ void * rx_skb_ptr; /* Data for us */
+ struct rx_desc * next_rx_desc;
} __attribute__ ((aligned(32)));
static struct dmfe_private {
@@ -522,30 +522,30 @@ static void dmfe_descriptor_init(struct nic *nic __unused, unsigned long ioaddr)
/* Init Transmit chain */
for (i = 0; i < TX_DESC_CNT; i++) {
- txd[i].tx_buf_ptr = (u32) & txb[i];
+ txd[i].tx_buf_ptr = &txb[i];
txd[i].tdes0 = cpu_to_le32(0);
txd[i].tdes1 = cpu_to_le32(0x81000000); /* IC, chain */
txd[i].tdes2 = cpu_to_le32(virt_to_bus(&txb[i]));
txd[i].tdes3 = cpu_to_le32(virt_to_bus(&txd[i + 1]));
- txd[i].next_tx_desc = virt_to_le32desc(&txd[i + 1]);
+ txd[i].next_tx_desc = &txd[i + 1];
}
/* Mark the last entry as wrapping the ring */
txd[i - 1].tdes3 = virt_to_le32desc(&txd[0]);
- txd[i - 1].next_tx_desc = (u32) & txd[0];
+ txd[i - 1].next_tx_desc = &txd[0];
/* receive descriptor chain */
for (i = 0; i < RX_DESC_CNT; i++) {
- rxd[i].rx_skb_ptr = (u32) & rxb[i * RX_ALLOC_SIZE];
+ rxd[i].rx_skb_ptr = &rxb[i * RX_ALLOC_SIZE];
rxd[i].rdes0 = cpu_to_le32(0x80000000);
rxd[i].rdes1 = cpu_to_le32(0x01000600);
rxd[i].rdes2 =
cpu_to_le32(virt_to_bus(&rxb[i * RX_ALLOC_SIZE]));
rxd[i].rdes3 = cpu_to_le32(virt_to_bus(&rxd[i + 1]));
- rxd[i].next_rx_desc = virt_to_le32desc(&rxd[i + 1]);
+ rxd[i].next_rx_desc = &rxd[i + 1];
}
/* Mark the last entry as wrapping the ring */
rxd[i - 1].rdes3 = cpu_to_le32(virt_to_bus(&rxd[0]));
- rxd[i - 1].next_rx_desc = virt_to_le32desc(&rxd[0]);
+ rxd[i - 1].next_rx_desc = &rxd[0];
}
diff --git a/gpxe/src/drivers/net/e1000/e1000.c b/gpxe/src/drivers/net/e1000/e1000.c
index a9aa508a..c1a4a52d 100644
--- a/gpxe/src/drivers/net/e1000/e1000.c
+++ b/gpxe/src/drivers/net/e1000/e1000.c
@@ -258,8 +258,8 @@ e1000_configure_tx ( struct e1000_adapter *adapter )
E1000_WRITE_REG ( hw, TDBAL, virt_to_bus ( adapter->tx_base ) );
E1000_WRITE_REG ( hw, TDLEN, adapter->tx_ring_size );
- DBG ( "TDBAL: %#08lx\n", E1000_READ_REG ( hw, TDBAL ) );
- DBG ( "TDLEN: %ld\n", E1000_READ_REG ( hw, TDLEN ) );
+ DBG ( "TDBAL: %#08x\n", E1000_READ_REG ( hw, TDBAL ) );
+ DBG ( "TDLEN: %d\n", E1000_READ_REG ( hw, TDLEN ) );
/* Setup the HW Tx Head and Tail descriptor pointers */
E1000_WRITE_REG ( hw, TDH, 0 );
@@ -385,9 +385,9 @@ e1000_configure_rx ( struct e1000_adapter *adapter )
E1000_WRITE_REG ( hw, RCTL, rctl );
E1000_WRITE_FLUSH ( hw );
- DBG ( "RDBAL: %#08lx\n", E1000_READ_REG ( hw, RDBAL ) );
- DBG ( "RDLEN: %ld\n", E1000_READ_REG ( hw, RDLEN ) );
- DBG ( "RCTL: %#08lx\n", E1000_READ_REG ( hw, RCTL ) );
+ DBG ( "RDBAL: %#08x\n", E1000_READ_REG ( hw, RDBAL ) );
+ DBG ( "RDLEN: %d\n", E1000_READ_REG ( hw, RDLEN ) );
+ DBG ( "RCTL: %#08x\n", E1000_READ_REG ( hw, RCTL ) );
}
/**
@@ -577,7 +577,7 @@ e1000_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
E1000_TXD_CMD_IFCS | iob_len ( iobuf );
tx_curr_desc->upper.data = 0;
- DBG ( "TX fill: %ld tx_curr: %ld addr: %#08lx len: %zd\n", adapter->tx_fill_ctr,
+ DBG ( "TX fill: %d tx_curr: %d addr: %#08lx len: %zd\n", adapter->tx_fill_ctr,
tx_curr, virt_to_bus ( iobuf->data ), iob_len ( iobuf ) );
/* Point to next free descriptor */
@@ -620,7 +620,7 @@ e1000_poll ( struct net_device *netdev )
if ( ! icr )
return;
- DBG ( "e1000_poll: intr_status = %#08lx\n", icr );
+ DBG ( "e1000_poll: intr_status = %#08x\n", icr );
/* Check status of transmitted packets
*/
@@ -635,17 +635,17 @@ e1000_poll ( struct net_device *netdev )
if ( ! ( tx_status & E1000_TXD_STAT_DD ) )
break;
- DBG ( "Sent packet. tx_head: %ld tx_tail: %ld tx_status: %#08lx\n",
+ DBG ( "Sent packet. tx_head: %d tx_tail: %d tx_status: %#08x\n",
adapter->tx_head, adapter->tx_tail, tx_status );
if ( tx_status & ( E1000_TXD_STAT_EC | E1000_TXD_STAT_LC |
E1000_TXD_STAT_TU ) ) {
netdev_tx_complete_err ( netdev, adapter->tx_iobuf[i], -EINVAL );
- DBG ( "Error transmitting packet, tx_status: %#08lx\n",
+ DBG ( "Error transmitting packet, tx_status: %#08x\n",
tx_status );
} else {
netdev_tx_complete ( netdev, adapter->tx_iobuf[i] );
- DBG ( "Success transmitting packet, tx_status: %#08lx\n",
+ DBG ( "Success transmitting packet, tx_status: %#08x\n",
tx_status );
}
@@ -667,16 +667,16 @@ e1000_poll ( struct net_device *netdev )
( i * sizeof ( *adapter->rx_base ) );
rx_status = rx_curr_desc->status;
- DBG2 ( "Before DD Check RX_status: %#08lx\n", rx_status );
+ DBG2 ( "Before DD Check RX_status: %#08x\n", rx_status );
if ( ! ( rx_status & E1000_RXD_STAT_DD ) )
break;
- DBG ( "RCTL = %#08lx\n", E1000_READ_REG ( &adapter->hw, RCTL ) );
+ DBG ( "RCTL = %#08x\n", E1000_READ_REG ( &adapter->hw, RCTL ) );
rx_len = rx_curr_desc->length;
- DBG ( "Received packet, rx_curr: %ld rx_status: %#08lx rx_len: %ld\n",
+ DBG ( "Received packet, rx_curr: %d rx_status: %#08x rx_len: %d\n",
i, rx_status, rx_len );
rx_err = rx_curr_desc->errors;
@@ -685,7 +685,7 @@ e1000_poll ( struct net_device *netdev )
netdev_rx_err ( netdev, NULL, -EINVAL );
DBG ( "e1000_poll: Corrupted packet received!"
- " rx_err: %#08lx\n", rx_err );
+ " rx_err: %#08x\n", rx_err );
} else {
/* If unable allocate space for this packet,
@@ -818,8 +818,8 @@ e1000_probe ( struct pci_device *pdev,
* because it depends on mac_type
*/
if ( ( adapter->hw.mac_type == e1000_ich8lan ) && ( pdev->ioaddr ) ) {
- flash_start = pci_bar_start ( pdev, 1 );
- flash_len = pci_bar_size ( pdev, 1 );
+ flash_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_1 );
+ flash_len = pci_bar_size ( pdev, PCI_BASE_ADDRESS_1 );
adapter->hw.flash_address = ioremap ( flash_start, flash_len );
if ( ! adapter->hw.flash_address )
goto err_flashmap;
@@ -962,7 +962,7 @@ e1000_open ( struct net_device *netdev )
e1000_configure_rx ( adapter );
- DBG ( "RXDCTL: %#08lx\n", E1000_READ_REG ( &adapter->hw, RXDCTL ) );
+ DBG ( "RXDCTL: %#08x\n", E1000_READ_REG ( &adapter->hw, RXDCTL ) );
return 0;
diff --git a/gpxe/src/drivers/net/e1000/e1000.h b/gpxe/src/drivers/net/e1000/e1000.h
index 4ae41451..77a09ef1 100644
--- a/gpxe/src/drivers/net/e1000/e1000.h
+++ b/gpxe/src/drivers/net/e1000/e1000.h
@@ -34,7 +34,8 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
-#include <io.h>
+#include <string.h>
+#include <gpxe/io.h>
#include <errno.h>
#include <byteswap.h>
#include <gpxe/pci.h>
diff --git a/gpxe/src/drivers/net/e1000/e1000_hw.c b/gpxe/src/drivers/net/e1000/e1000_hw.c
index 0667ad61..1054b90a 100644
--- a/gpxe/src/drivers/net/e1000/e1000_hw.c
+++ b/gpxe/src/drivers/net/e1000/e1000_hw.c
@@ -1429,7 +1429,7 @@ e1000_copper_link_preconfig(struct e1000_hw *hw)
DEBUGOUT("Error, did not detect valid phy.\n");
return ret_val;
}
- DEBUGOUT1("Phy ID = %#08lx \n", hw->phy_id);
+ DEBUGOUT1("Phy ID = %#08x \n", hw->phy_id);
/* Set PHY to class A mode (if necessary) */
ret_val = e1000_set_phy_mode(hw);
@@ -3551,7 +3551,7 @@ e1000_read_phy_reg_ex(struct e1000_hw *hw, uint32_t reg_addr,
DEBUGFUNC("e1000_read_phy_reg_ex");
if (reg_addr > MAX_PHY_REG_ADDRESS) {
- DEBUGOUT1("PHY Address %ld is out of range\n", reg_addr);
+ DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
return -E1000_ERR_PARAM;
}
@@ -3689,7 +3689,7 @@ e1000_write_phy_reg_ex(struct e1000_hw *hw, uint32_t reg_addr,
DEBUGFUNC("e1000_write_phy_reg_ex");
if (reg_addr > MAX_PHY_REG_ADDRESS) {
- DEBUGOUT1("PHY Address %ld is out of range\n", reg_addr);
+ DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
return -E1000_ERR_PARAM;
}
@@ -4141,10 +4141,10 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
phy_init_status = e1000_set_phy_type(hw);
if ((match) && (phy_init_status == E1000_SUCCESS)) {
- DEBUGOUT1("PHY ID %#08lx detected\n", hw->phy_id);
+ DEBUGOUT1("PHY ID %#08x detected\n", hw->phy_id);
return E1000_SUCCESS;
}
- DEBUGOUT1("Invalid PHY ID %#08lx\n", hw->phy_id);
+ DEBUGOUT1("Invalid PHY ID %#08x\n", hw->phy_id);
return -E1000_ERR_PHY;
}
@@ -8795,13 +8795,13 @@ e1000_verify_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t byte)
int32_t error = E1000_SUCCESS;
int32_t program_retries = 0;
- DEBUGOUT2("Byte := %2.2X Offset := %ld\n", byte, index);
+ DEBUGOUT2("Byte := %2.2X Offset := %d\n", byte, index);
error = e1000_write_ich8_byte(hw, index, byte);
if (error != E1000_SUCCESS) {
for (program_retries = 0; program_retries < 100; program_retries++) {
- DEBUGOUT2("Retrying \t Byte := %2.2X Offset := %ld\n", byte, index);
+ DEBUGOUT2("Retrying \t Byte := %2.2X Offset := %d\n", byte, index);
error = e1000_write_ich8_byte(hw, index, byte);
udelay(100);
if (error == E1000_SUCCESS)
diff --git a/gpxe/src/drivers/net/e1000/e1000_osdep.h b/gpxe/src/drivers/net/e1000/e1000_osdep.h
index 7df9b5e9..c2d9eb9c 100644
--- a/gpxe/src/drivers/net/e1000/e1000_osdep.h
+++ b/gpxe/src/drivers/net/e1000/e1000_osdep.h
@@ -37,7 +37,7 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <errno.h>
#include <unistd.h>
#include <byteswap.h>
@@ -74,60 +74,60 @@ typedef enum {
#define DEBUGOUT3 DEBUGOUT1
#define DEBUGOUT7 DEBUGOUT1
-#define E1000_WRITE_REG(a, reg, value) ( \
+#define E1000_WRITE_REG(a, reg, value) \
writel((value), ((a)->hw_addr + \
- (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg))))
+ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg)))
-#define E1000_READ_REG(a, reg) ( \
+#define E1000_READ_REG(a, reg) \
readl((a)->hw_addr + \
- (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg)))
+ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg))
-#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \
+#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \
writel((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
- ((offset) << 2))))
+ ((offset) << 2)))
-#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
+#define E1000_READ_REG_ARRAY(a, reg, offset) \
readl((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
- ((offset) << 2)))
+ ((offset) << 2))
#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY
#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY
-#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \
+#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) \
writew((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
- ((offset) << 1))))
+ ((offset) << 1)))
-#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \
+#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) \
readw((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
- ((offset) << 1)))
+ ((offset) << 1))
-#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \
+#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) \
writeb((value), ((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
- (offset))))
+ (offset)))
-#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \
+#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) \
readb((a)->hw_addr + \
(((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
- (offset)))
+ (offset))
#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS)
-#define E1000_WRITE_ICH_FLASH_REG(a, reg, value) ( \
- writel((value), ((a)->flash_address + reg)))
+#define E1000_WRITE_ICH_FLASH_REG(a, reg, value) \
+ writel((value), ((a)->flash_address + reg))
-#define E1000_READ_ICH_FLASH_REG(a, reg) ( \
- readl((a)->flash_address + reg))
+#define E1000_READ_ICH_FLASH_REG(a, reg) \
+ readl((a)->flash_address + reg)
-#define E1000_WRITE_ICH_FLASH_REG16(a, reg, value) ( \
- writew((value), ((a)->flash_address + reg)))
+#define E1000_WRITE_ICH_FLASH_REG16(a, reg, value) \
+ writew((value), ((a)->flash_address + reg))
-#define E1000_READ_ICH_FLASH_REG16(a, reg) ( \
- readw((a)->flash_address + reg))
+#define E1000_READ_ICH_FLASH_REG16(a, reg) \
+ readw((a)->flash_address + reg)
#define msleep(n) mdelay(n)
diff --git a/gpxe/src/drivers/net/eepro100.c b/gpxe/src/drivers/net/eepro100.c
index f746976a..e6e7db49 100644
--- a/gpxe/src/drivers/net/eepro100.c
+++ b/gpxe/src/drivers/net/eepro100.c
@@ -407,7 +407,7 @@ static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, un
} hdr;
unsigned short status;
int s1, s2;
- tick_t ct;
+ unsigned long ct;
status = inw(ioaddr + SCBStatus);
/* Acknowledge all of the current interrupt sources ASAP. */
@@ -448,7 +448,7 @@ static void eepro100_transmit(struct nic *nic, const char *d, unsigned int t, un
ct = currticks();
/* timeout 10 ms for transmit */
- while (!txfd.status && ct + 10*USECS_IN_MSEC)
+ while (!txfd.status && ct + 10*1000)
/* Wait */;
s2 = inw (ioaddr + SCBStatus);
@@ -608,7 +608,7 @@ static int eepro100_probe ( struct nic *nic, struct pci_device *pci ) {
int read_cmd, ee_size;
int options;
int rx_mode;
- tick_t ct;
+ unsigned long ct;
/* we cache only the first few words of the EEPROM data
be careful not to access beyond this array */
@@ -753,7 +753,7 @@ static int eepro100_probe ( struct nic *nic, struct pci_device *pci ) {
whereami ("started TX thingy (config, iasetup).");
ct = currticks();
- while (!txfd.status && ct + 10*USECS_IN_MSEC < currticks())
+ while (!txfd.status && ct + 10*1000 < currticks())
/* Wait */;
/* Read the status register once to disgard stale data */
diff --git a/gpxe/src/drivers/net/epic100.c b/gpxe/src/drivers/net/epic100.c
index 67b4f0fb..1e36a680 100644
--- a/gpxe/src/drivers/net/epic100.c
+++ b/gpxe/src/drivers/net/epic100.c
@@ -309,7 +309,7 @@ epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type,
unsigned short nstype;
unsigned char *txp;
int entry;
- tick_t ct;
+ unsigned long ct;
/* Calculate the next Tx descriptor entry. */
entry = cur_tx % TX_RING_SIZE;
@@ -352,7 +352,7 @@ epic100_transmit(struct nic *nic, const char *destaddr, unsigned int type,
ct = currticks();
/* timeout 10 ms for transmit */
while ((le32_to_cpu(tx_ring[entry].status) & (TRING_OWN)) &&
- ct + 10*USECS_IN_MSEC < currticks())
+ ct + 10*1000 < currticks())
/* Wait */;
if ((le32_to_cpu(tx_ring[entry].status) & TRING_OWN) != 0)
diff --git a/gpxe/src/drivers/net/etherfabric.c b/gpxe/src/drivers/net/etherfabric.c
index 8a6b1a17..704ce98b 100644
--- a/gpxe/src/drivers/net/etherfabric.c
+++ b/gpxe/src/drivers/net/etherfabric.c
@@ -15,17 +15,22 @@
*
**************************************************************************
*/
-
-#include "etherboot.h"
-#include "nic.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <console.h>
+#include <gpxe/io.h>
#include <gpxe/pci.h>
-#include <gpxe/bitbash.h>
-#include <gpxe/i2c.h>
-#include <gpxe/spi.h>
-#include <gpxe/nvo.h>
-#define dma_addr_t unsigned long
+#include <gpxe/malloc.h>
+#include <gpxe/ethernet.h>
+#include <gpxe/iobuf.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/timer.h>
#include "etherfabric.h"
+#include "etherfabric_nic.h"
/**************************************************************************
*
@@ -34,193 +39,35 @@
**************************************************************************
*/
-#define EFAB_ASSERT(x) \
- do { \
- if ( ! (x) ) { \
- DBG ( "ASSERT(%s) failed at %s line %d [%s]\n", #x, \
- __FILE__, __LINE__, __FUNCTION__ ); \
- } \
- } while (0)
-
-#define EFAB_TRACE(...) DBG ( __VA_ARGS__ )
-
#define EFAB_REGDUMP(...)
+#define EFAB_TRACE(...) DBGP(__VA_ARGS__)
-#define EFAB_LOG(...) printf ( __VA_ARGS__ )
-#define EFAB_ERR(...) printf ( __VA_ARGS__ )
-
-#define FALCON_USE_IO_BAR 1
+// printf() is not allowed within drivers. Use DBG() instead.
+#define EFAB_LOG(...) DBG(__VA_ARGS__)
+#define EFAB_ERR(...) DBG(__VA_ARGS__)
-/*
- * EtherFabric constants
- *
- */
+#define FALCON_USE_IO_BAR 0
-/* PCI Definitions */
-#define EFAB_VENDID_LEVEL5 0x1924
-#define FALCON_P_DEVID 0x0703 /* Temporary PCI ID */
-#define EF1002_DEVID 0xC101
+#define HZ 100
+#define EFAB_BYTE 1
/**************************************************************************
*
- * Data structures
+ * Hardware data structures and sizing
*
**************************************************************************
*/
+extern int __invalid_queue_size;
+#define FQS(_prefix, _x) \
+ ( ( (_x) == 512 ) ? _prefix ## _SIZE_512 : \
+ ( ( (_x) == 1024 ) ? _prefix ## _SIZE_1K : \
+ ( ( (_x) == 2048 ) ? _prefix ## _SIZE_2K : \
+ ( ( (_x) == 4096) ? _prefix ## _SIZE_4K : \
+ __invalid_queue_size ) ) ) )
-/*
- * Buffers used for TX, RX and event queue
- *
- */
-#define EFAB_BUF_ALIGN 4096
-#define EFAB_DATA_BUF_SIZE 2048
-#define EFAB_RX_BUFS 16
-#define EFAB_RXD_SIZE 512
-#define EFAB_TXD_SIZE 512
-#define EFAB_EVQ_SIZE 512
-struct efab_buffers {
- uint8_t eventq[4096];
- uint8_t rxd[4096];
- uint8_t txd[4096];
- uint8_t tx_buf[EFAB_DATA_BUF_SIZE];
- uint8_t rx_buf[EFAB_RX_BUFS][EFAB_DATA_BUF_SIZE];
- uint8_t padding[EFAB_BUF_ALIGN-1];
-};
-static struct efab_buffers efab_buffers;
-
-/** An RX buffer */
-struct efab_rx_buf {
- uint8_t *addr;
- unsigned int len;
- int id;
-};
-
-/** A TX buffer */
-struct efab_tx_buf {
- uint8_t *addr;
- unsigned int len;
- int id;
-};
-
-/** Etherfabric event type */
-enum efab_event_type {
- EFAB_EV_NONE = 0,
- EFAB_EV_TX,
- EFAB_EV_RX,
-};
-
-/** Etherfabric event */
-struct efab_event {
- /** Event type */
- enum efab_event_type type;
- /** RX buffer ID */
- int rx_id;
- /** RX length */
- unsigned int rx_len;
- /** Packet should be dropped */
- int drop;
-};
-
-/*
- * Etherfabric abstraction layer
- *
- */
-struct efab_nic;
-struct efab_operations {
- void ( * get_membase ) ( struct efab_nic *efab );
- int ( * reset ) ( struct efab_nic *efab );
- int ( * init_nic ) ( struct efab_nic *efab );
- int ( * read_eeprom ) ( struct efab_nic *efab );
- void ( * build_rx_desc ) ( struct efab_nic *efab,
- struct efab_rx_buf *rx_buf );
- void ( * notify_rx_desc ) ( struct efab_nic *efab );
- void ( * build_tx_desc ) ( struct efab_nic *efab,
- struct efab_tx_buf *tx_buf );
- void ( * notify_tx_desc ) ( struct efab_nic *efab );
- int ( * fetch_event ) ( struct efab_nic *efab,
- struct efab_event *event );
- void ( * mask_irq ) ( struct efab_nic *efab, int enabled );
- void ( * generate_irq ) ( struct efab_nic *efab );
- void ( * mdio_write ) ( struct efab_nic *efab, int location,
- int value );
- int ( * mdio_read ) ( struct efab_nic *efab, int location );
-};
-
-struct efab_mac_operations {
- void ( * mac_writel ) ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int mac_reg );
- void ( * mac_readl ) ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int mac_reg );
- int ( * init ) ( struct efab_nic *efab );
- int ( * reset ) ( struct efab_nic *efab );
-};
-
-/*
- * Driver private data structure
- *
- */
-struct efab_nic {
-
- /** PCI device */
- struct pci_device *pci;
-
- /** Operations table */
- struct efab_operations *op;
-
- /** MAC operations table */
- struct efab_mac_operations *mac_op;
- /** Memory base */
- void *membase;
-
- /** I/O base */
- unsigned int iobase;
-
- /** Buffers */
- uint8_t *eventq; /* Falcon only */
- uint8_t *txd; /* Falcon only */
- uint8_t *rxd; /* Falcon only */
- struct efab_tx_buf tx_buf;
- struct efab_rx_buf rx_bufs[EFAB_RX_BUFS];
-
- /** Buffer pointers */
- unsigned int eventq_read_ptr; /* Falcon only */
- unsigned int tx_write_ptr;
- unsigned int rx_write_ptr;
-
- /** Port 0/1 on the NIC */
- int port;
-
- /** MAC address */
- uint8_t mac_addr[ETH_ALEN];
- /** GMII link options */
- unsigned int link_options;
- /** Link status */
- int link_up;
-
- /* Nic type fields */
- int has_flash : 1;
- int has_eeprom : 1;
- int is_10g : 1;
- int is_dual : 1;
- int is_asic : 1;
-
- /** INT_REG_KER for Falcon */
- efab_oword_t int_ker __attribute__ (( aligned ( 16 ) ));
-
- /** I2C access */
- struct i2c_bit_basher ef1002_i2c;
- unsigned long ef1002_i2c_outputs;
- struct i2c_device ef1002_eeprom;
-
- /** SPI access */
- struct spi_bus spi;
- struct spi_device falcon_flash;
- struct spi_device falcon_eeprom;
-
- /** Non-volatile options */
- struct nvo_block nvo;
-};
+#define EFAB_MAX_FRAME_LEN(mtu) \
+ ( ( ( ( mtu ) + 4/* FCS */ ) + 7 ) & ~7 )
/**************************************************************************
*
@@ -229,6 +76,10 @@ struct efab_nic {
**************************************************************************
*/
+static void falcon_mdio_write (struct efab_nic *efab, int device,
+ int location, int value );
+static int falcon_mdio_read ( struct efab_nic *efab, int device, int location );
+
/* GMII registers */
#define MII_BMSR 0x01 /* Basic mode status register */
#define MII_ADVERTISE 0x04 /* Advertisement control register */
@@ -257,7 +108,8 @@ struct efab_nic {
#define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4)
#define LPA_1000 ( LPA_1000FULL | LPA_1000HALF )
#define LPA_10000 ( LPA_10000FULL | LPA_10000HALF )
-#define LPA_DUPLEX ( LPA_10FULL | LPA_100FULL | LPA_1000FULL )
+#define LPA_DUPLEX ( LPA_10FULL | LPA_100FULL | LPA_1000FULL | \
+ LPA_10000FULL )
/* Mask of bits not associated with speed or duplexity. */
#define LPA_OTHER ~( LPA_10FULL | LPA_10HALF | LPA_100FULL | \
@@ -270,13 +122,15 @@ struct efab_nic {
* Retrieve GMII autonegotiation advertised abilities
*
*/
-static unsigned int gmii_autoneg_advertised ( struct efab_nic *efab ) {
+static unsigned int
+gmii_autoneg_advertised ( struct efab_nic *efab )
+{
unsigned int mii_advertise;
unsigned int gmii_advertise;
-
+
/* Extended bits are in bits 8 and 9 of GMII_GTCR */
- mii_advertise = efab->op->mdio_read ( efab, MII_ADVERTISE );
- gmii_advertise = ( ( efab->op->mdio_read ( efab, GMII_GTCR ) >> 8 )
+ mii_advertise = falcon_mdio_read ( efab, 0, MII_ADVERTISE );
+ gmii_advertise = ( ( falcon_mdio_read ( efab, 0, GMII_GTCR ) >> 8 )
& 0x03 );
return ( ( gmii_advertise << 16 ) | mii_advertise );
}
@@ -285,13 +139,15 @@ static unsigned int gmii_autoneg_advertised ( struct efab_nic *efab ) {
* Retrieve GMII autonegotiation link partner abilities
*
*/
-static unsigned int gmii_autoneg_lpa ( struct efab_nic *efab ) {
+static unsigned int
+gmii_autoneg_lpa ( struct efab_nic *efab )
+{
unsigned int mii_lpa;
unsigned int gmii_lpa;
-
+
/* Extended bits are in bits 10 and 11 of GMII_GTSR */
- mii_lpa = efab->op->mdio_read ( efab, MII_LPA );
- gmii_lpa = ( efab->op->mdio_read ( efab, GMII_GTSR ) >> 10 ) & 0x03;
+ mii_lpa = falcon_mdio_read ( efab, 0, MII_LPA );
+ gmii_lpa = ( falcon_mdio_read ( efab, 0, GMII_GTSR ) >> 10 ) & 0x03;
return ( ( gmii_lpa << 16 ) | mii_lpa );
}
@@ -299,7 +155,9 @@ static unsigned int gmii_autoneg_lpa ( struct efab_nic *efab ) {
* Calculate GMII autonegotiated link technology
*
*/
-static unsigned int gmii_nway_result ( unsigned int negotiated ) {
+static unsigned int
+gmii_nway_result ( unsigned int negotiated )
+{
unsigned int other_bits;
/* Mask out the speed and duplexity bits */
@@ -324,1167 +182,244 @@ static unsigned int gmii_nway_result ( unsigned int negotiated ) {
* Check GMII PHY link status
*
*/
-static int gmii_link_ok ( struct efab_nic *efab ) {
+static int
+gmii_link_ok ( struct efab_nic *efab )
+{
int status;
int phy_status;
-
+
/* BMSR is latching - it returns "link down" if the link has
* been down at any point since the last read. To get a
* real-time status, we therefore read the register twice and
* use the result of the second read.
*/
- efab->op->mdio_read ( efab, MII_BMSR );
- status = efab->op->mdio_read ( efab, MII_BMSR );
+ (void) falcon_mdio_read ( efab, 0, MII_BMSR );
+ status = falcon_mdio_read ( efab, 0, MII_BMSR );
/* Read the PHY-specific Status Register. This is
* non-latching, so we need do only a single read.
*/
- phy_status = efab->op->mdio_read ( efab, GMII_PSSR );
+ phy_status = falcon_mdio_read ( efab, 0, GMII_PSSR );
return ( ( status & BMSR_LSTATUS ) && ( phy_status & PSSR_LSTATUS ) );
}
/**************************************************************************
*
- * Alaska PHY
+ * MDIO routines
*
**************************************************************************
*/
-/**
- * Initialise Alaska PHY
- *
- */
-static void alaska_init ( struct efab_nic *efab ) {
- unsigned int advertised, lpa;
-
- /* Read link up status */
- efab->link_up = gmii_link_ok ( efab );
-
- if ( ! efab->link_up )
- return;
-
- /* Determine link options from PHY. */
- advertised = gmii_autoneg_advertised ( efab );
- lpa = gmii_autoneg_lpa ( efab );
- efab->link_options = gmii_nway_result ( advertised & lpa );
-
- /* print out the link speed */
- EFAB_LOG ( "%dMbps %s-duplex (%04x,%04x)\n",
- ( efab->link_options & LPA_10000 ? 1000 :
- ( efab->link_options & LPA_1000 ? 1000 :
- ( efab->link_options & LPA_100 ? 100 : 10 ) ) ),
- ( efab->link_options & LPA_DUPLEX ? "full" : "half" ),
- advertised, lpa );
-}
-
-
-/**************************************************************************
- *
- * Mentor MAC
- *
- **************************************************************************
- */
-
-/* GMAC configuration register 1 */
-#define GM_CFG1_REG_MAC 0x00
-#define GM_SW_RST_LBN 31
-#define GM_SW_RST_WIDTH 1
-#define GM_RX_FC_EN_LBN 5
-#define GM_RX_FC_EN_WIDTH 1
-#define GM_TX_FC_EN_LBN 4
-#define GM_TX_FC_EN_WIDTH 1
-#define GM_RX_EN_LBN 2
-#define GM_RX_EN_WIDTH 1
-#define GM_TX_EN_LBN 0
-#define GM_TX_EN_WIDTH 1
-
-/* GMAC configuration register 2 */
-#define GM_CFG2_REG_MAC 0x01
-#define GM_PAMBL_LEN_LBN 12
-#define GM_PAMBL_LEN_WIDTH 4
-#define GM_IF_MODE_LBN 8
-#define GM_IF_MODE_WIDTH 2
-#define GM_PAD_CRC_EN_LBN 2
-#define GM_PAD_CRC_EN_WIDTH 1
-#define GM_FD_LBN 0
-#define GM_FD_WIDTH 1
-
-/* GMAC maximum frame length register */
-#define GM_MAX_FLEN_REG_MAC 0x04
-#define GM_MAX_FLEN_LBN 0
-#define GM_MAX_FLEN_WIDTH 16
-
-/* GMAC MII management configuration register */
-#define GM_MII_MGMT_CFG_REG_MAC 0x08
-#define GM_MGMT_CLK_SEL_LBN 0
-#define GM_MGMT_CLK_SEL_WIDTH 3
-
-/* GMAC MII management command register */
-#define GM_MII_MGMT_CMD_REG_MAC 0x09
-#define GM_MGMT_SCAN_CYC_LBN 1
-#define GM_MGMT_SCAN_CYC_WIDTH 1
-#define GM_MGMT_RD_CYC_LBN 0
-#define GM_MGMT_RD_CYC_WIDTH 1
-
-/* GMAC MII management address register */
-#define GM_MII_MGMT_ADR_REG_MAC 0x0a
-#define GM_MGMT_PHY_ADDR_LBN 8
-#define GM_MGMT_PHY_ADDR_WIDTH 5
-#define GM_MGMT_REG_ADDR_LBN 0
-#define GM_MGMT_REG_ADDR_WIDTH 5
-
-/* GMAC MII management control register */
-#define GM_MII_MGMT_CTL_REG_MAC 0x0b
-#define GM_MGMT_CTL_LBN 0
-#define GM_MGMT_CTL_WIDTH 16
-
-/* GMAC MII management status register */
-#define GM_MII_MGMT_STAT_REG_MAC 0x0c
-#define GM_MGMT_STAT_LBN 0
-#define GM_MGMT_STAT_WIDTH 16
-
-/* GMAC MII management indicators register */
-#define GM_MII_MGMT_IND_REG_MAC 0x0d
-#define GM_MGMT_BUSY_LBN 0
-#define GM_MGMT_BUSY_WIDTH 1
-
-/* GMAC station address register 1 */
-#define GM_ADR1_REG_MAC 0x10
-#define GM_HWADDR_5_LBN 24
-#define GM_HWADDR_5_WIDTH 8
-#define GM_HWADDR_4_LBN 16
-#define GM_HWADDR_4_WIDTH 8
-#define GM_HWADDR_3_LBN 8
-#define GM_HWADDR_3_WIDTH 8
-#define GM_HWADDR_2_LBN 0
-#define GM_HWADDR_2_WIDTH 8
-
-/* GMAC station address register 2 */
-#define GM_ADR2_REG_MAC 0x11
-#define GM_HWADDR_1_LBN 24
-#define GM_HWADDR_1_WIDTH 8
-#define GM_HWADDR_0_LBN 16
-#define GM_HWADDR_0_WIDTH 8
-
-/* GMAC FIFO configuration register 0 */
-#define GMF_CFG0_REG_MAC 0x12
-#define GMF_FTFENREQ_LBN 12
-#define GMF_FTFENREQ_WIDTH 1
-#define GMF_STFENREQ_LBN 11
-#define GMF_STFENREQ_WIDTH 1
-#define GMF_FRFENREQ_LBN 10
-#define GMF_FRFENREQ_WIDTH 1
-#define GMF_SRFENREQ_LBN 9
-#define GMF_SRFENREQ_WIDTH 1
-#define GMF_WTMENREQ_LBN 8
-#define GMF_WTMENREQ_WIDTH 1
-
-/* GMAC FIFO configuration register 1 */
-#define GMF_CFG1_REG_MAC 0x13
-#define GMF_CFGFRTH_LBN 16
-#define GMF_CFGFRTH_WIDTH 5
-#define GMF_CFGXOFFRTX_LBN 0
-#define GMF_CFGXOFFRTX_WIDTH 16
-
-/* GMAC FIFO configuration register 2 */
-#define GMF_CFG2_REG_MAC 0x14
-#define GMF_CFGHWM_LBN 16
-#define GMF_CFGHWM_WIDTH 6
-#define GMF_CFGLWM_LBN 0
-#define GMF_CFGLWM_WIDTH 6
-
-/* GMAC FIFO configuration register 3 */
-#define GMF_CFG3_REG_MAC 0x15
-#define GMF_CFGHWMFT_LBN 16
-#define GMF_CFGHWMFT_WIDTH 6
-#define GMF_CFGFTTH_LBN 0
-#define GMF_CFGFTTH_WIDTH 6
-
-/* GMAC FIFO configuration register 4 */
-#define GMF_CFG4_REG_MAC 0x16
-#define GMF_HSTFLTRFRM_PAUSE_LBN 12
-#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12
-
-/* GMAC FIFO configuration register 5 */
-#define GMF_CFG5_REG_MAC 0x17
-#define GMF_CFGHDPLX_LBN 22
-#define GMF_CFGHDPLX_WIDTH 1
-#define GMF_CFGBYTMODE_LBN 19
-#define GMF_CFGBYTMODE_WIDTH 1
-#define GMF_HSTDRPLT64_LBN 18
-#define GMF_HSTDRPLT64_WIDTH 1
-#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12
-#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1
-
-struct efab_mentormac_parameters {
- int gmf_cfgfrth;
- int gmf_cfgftth;
- int gmf_cfghwmft;
- int gmf_cfghwm;
- int gmf_cfglwm;
-};
-
-/**
- * Reset Mentor MAC
- *
- */
-static void mentormac_reset ( struct efab_nic *efab ) {
- efab_dword_t reg;
- int save_port;
-
- /* Take into reset */
- EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 1 );
- efab->mac_op->mac_writel ( efab, &reg, GM_CFG1_REG_MAC );
- udelay ( 1000 );
-
- /* Take out of reset */
- EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 0 );
- efab->mac_op->mac_writel ( efab, &reg, GM_CFG1_REG_MAC );
- udelay ( 1000 );
-
- /* Mentor MAC connects both PHYs to MAC 0 */
- save_port = efab->port;
- efab->port = 0;
- /* Configure GMII interface so PHY is accessible. Note that
- * GMII interface is connected only to port 0, and that on
- * Falcon this is a no-op.
- */
- EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_CLK_SEL, 0x4 );
- efab->mac_op->mac_writel ( efab, &reg, GM_MII_MGMT_CFG_REG_MAC );
- udelay ( 10 );
- efab->port = save_port;
-}
-
-/**
- * Initialise Mentor MAC
- *
- */
-static void mentormac_init ( struct efab_nic *efab,
- struct efab_mentormac_parameters *params ) {
- int pause, if_mode, full_duplex, bytemode, half_duplex;
- efab_dword_t reg;
-
- /* Configuration register 1 */
- pause = ( efab->link_options & LPA_PAUSE ) ? 1 : 0;
- if ( ! ( efab->link_options & LPA_DUPLEX ) ) {
- /* Half-duplex operation requires TX flow control */
- pause = 1;
+/* Numbering of the MDIO Manageable Devices (MMDs) */
+/* Physical Medium Attachment/ Physical Medium Dependent sublayer */
+#define MDIO_MMD_PMAPMD (1)
+/* WAN Interface Sublayer */
+#define MDIO_MMD_WIS (2)
+/* Physical Coding Sublayer */
+#define MDIO_MMD_PCS (3)
+/* PHY Extender Sublayer */
+#define MDIO_MMD_PHYXS (4)
+/* Extender Sublayer */
+#define MDIO_MMD_DTEXS (5)
+/* Transmission convergence */
+#define MDIO_MMD_TC (6)
+/* Auto negotiation */
+#define MDIO_MMD_AN (7)
+
+/* Generic register locations */
+#define MDIO_MMDREG_CTRL1 (0)
+#define MDIO_MMDREG_STAT1 (1)
+#define MDIO_MMDREG_DEVS0 (5)
+#define MDIO_MMDREG_STAT2 (8)
+
+/* Bits in MMDREG_CTRL1 */
+/* Reset */
+#define MDIO_MMDREG_CTRL1_RESET_LBN (15)
+#define MDIO_MMDREG_CTRL1_RESET_WIDTH (1)
+
+/* Bits in MMDREG_STAT1 */
+#define MDIO_MMDREG_STAT1_FAULT_LBN (7)
+#define MDIO_MMDREG_STAT1_FAULT_WIDTH (1)
+
+/* Link state */
+#define MDIO_MMDREG_STAT1_LINK_LBN (2)
+#define MDIO_MMDREG_STAT1_LINK_WIDTH (1)
+
+/* Bits in MMDREG_DEVS0. */
+#define DEV_PRESENT_BIT(_b) (1 << _b)
+
+#define MDIO_MMDREG_DEVS0_DTEXS DEV_PRESENT_BIT(MDIO_MMD_DTEXS)
+#define MDIO_MMDREG_DEVS0_PHYXS DEV_PRESENT_BIT(MDIO_MMD_PHYXS)
+#define MDIO_MMDREG_DEVS0_PCS DEV_PRESENT_BIT(MDIO_MMD_PCS)
+#define MDIO_MMDREG_DEVS0_WIS DEV_PRESENT_BIT(MDIO_MMD_WIS)
+#define MDIO_MMDREG_DEVS0_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)
+
+#define MDIO_MMDREG_DEVS0_AN DEV_PRESENT_BIT(MDIO_MMD_AN)
+
+/* Bits in MMDREG_STAT2 */
+#define MDIO_MMDREG_STAT2_PRESENT_VAL (2)
+#define MDIO_MMDREG_STAT2_PRESENT_LBN (14)
+#define MDIO_MMDREG_STAT2_PRESENT_WIDTH (2)
+
+/* PHY XGXS lane state */
+#define MDIO_PHYXS_LANE_STATE (0x18)
+#define MDIO_PHYXS_LANE_ALIGNED_LBN (12)
+#define MDIO_PHYXS_LANE_SYNC0_LBN (0)
+#define MDIO_PHYXS_LANE_SYNC1_LBN (1)
+#define MDIO_PHYXS_LANE_SYNC2_LBN (2)
+#define MDIO_PHYXS_LANE_SYNC3_LBN (3)
+
+/* This ought to be ridiculous overkill. We expect it to fail rarely */
+#define MDIO45_RESET_TRIES 100
+#define MDIO45_RESET_SPINTIME 10
+
+static int
+mdio_clause45_wait_reset_mmds ( struct efab_nic* efab )
+{
+ int tries = MDIO45_RESET_TRIES;
+ int in_reset;
+
+ while(tries) {
+ int mask = efab->phy_op->mmds;
+ int mmd = 0;
+ in_reset = 0;
+ while(mask) {
+ if (mask & 1) {
+ int stat = falcon_mdio_read ( efab, mmd,
+ MDIO_MMDREG_CTRL1 );
+ if (stat < 0) {
+ EFAB_ERR("Failed to read status of MMD %d\n",
+ mmd );
+ in_reset = 1;
+ break;
+ }
+ if (stat & (1 << MDIO_MMDREG_CTRL1_RESET_LBN))
+ in_reset |= (1 << mmd);
+ }
+ mask = mask >> 1;
+ mmd++;
+ }
+ if (!in_reset)
+ break;
+ tries--;
+ mdelay ( MDIO45_RESET_SPINTIME );
}
- EFAB_POPULATE_DWORD_4 ( reg,
- GM_TX_EN, 1,
- GM_TX_FC_EN, pause,
- GM_RX_EN, 1,
- GM_RX_FC_EN, 1 );
- efab->mac_op->mac_writel ( efab, &reg, GM_CFG1_REG_MAC );
- udelay ( 10 );
-
- /* Configuration register 2 */
- if_mode = ( efab->link_options & LPA_1000 ) ? 2 : 1;
- full_duplex = ( efab->link_options & LPA_DUPLEX ) ? 1 : 0;
- EFAB_POPULATE_DWORD_4 ( reg,
- GM_IF_MODE, if_mode,
- GM_PAD_CRC_EN, 1,
- GM_FD, full_duplex,
- GM_PAMBL_LEN, 0x7 /* ? */ );
- efab->mac_op->mac_writel ( efab, &reg, GM_CFG2_REG_MAC );
- udelay ( 10 );
-
- /* Max frame len register */
- EFAB_POPULATE_DWORD_1 ( reg, GM_MAX_FLEN, ETH_FRAME_LEN + 4 /* FCS */);
- efab->mac_op->mac_writel ( efab, &reg, GM_MAX_FLEN_REG_MAC );
- udelay ( 10 );
-
- /* FIFO configuration register 0 */
- EFAB_POPULATE_DWORD_5 ( reg,
- GMF_FTFENREQ, 1,
- GMF_STFENREQ, 1,
- GMF_FRFENREQ, 1,
- GMF_SRFENREQ, 1,
- GMF_WTMENREQ, 1 );
- efab->mac_op->mac_writel ( efab, &reg, GMF_CFG0_REG_MAC );
- udelay ( 10 );
-
- /* FIFO configuration register 1 */
- EFAB_POPULATE_DWORD_2 ( reg,
- GMF_CFGFRTH, params->gmf_cfgfrth,
- GMF_CFGXOFFRTX, 0xffff );
- efab->mac_op->mac_writel ( efab, &reg, GMF_CFG1_REG_MAC );
- udelay ( 10 );
-
- /* FIFO configuration register 2 */
- EFAB_POPULATE_DWORD_2 ( reg,
- GMF_CFGHWM, params->gmf_cfghwm,
- GMF_CFGLWM, params->gmf_cfglwm );
- efab->mac_op->mac_writel ( efab, &reg, GMF_CFG2_REG_MAC );
- udelay ( 10 );
-
- /* FIFO configuration register 3 */
- EFAB_POPULATE_DWORD_2 ( reg,
- GMF_CFGHWMFT, params->gmf_cfghwmft,
- GMF_CFGFTTH, params->gmf_cfgftth );
- efab->mac_op->mac_writel ( efab, &reg, GMF_CFG3_REG_MAC );
- udelay ( 10 );
-
- /* FIFO configuration register 4 */
- EFAB_POPULATE_DWORD_1 ( reg, GMF_HSTFLTRFRM_PAUSE, 1 );
- efab->mac_op->mac_writel ( efab, &reg, GMF_CFG4_REG_MAC );
- udelay ( 10 );
-
- /* FIFO configuration register 5 */
- bytemode = ( efab->link_options & LPA_1000 ) ? 1 : 0;
- half_duplex = ( efab->link_options & LPA_DUPLEX ) ? 0 : 1;
- efab->mac_op->mac_readl ( efab, &reg, GMF_CFG5_REG_MAC );
- EFAB_SET_DWORD_FIELD ( reg, GMF_CFGBYTMODE, bytemode );
- EFAB_SET_DWORD_FIELD ( reg, GMF_CFGHDPLX, half_duplex );
- EFAB_SET_DWORD_FIELD ( reg, GMF_HSTDRPLT64, half_duplex );
- EFAB_SET_DWORD_FIELD ( reg, GMF_HSTFLTRFRMDC_PAUSE, 0 );
- efab->mac_op->mac_writel ( efab, &reg, GMF_CFG5_REG_MAC );
- udelay ( 10 );
-
- /* MAC address */
- EFAB_POPULATE_DWORD_4 ( reg,
- GM_HWADDR_5, efab->mac_addr[5],
- GM_HWADDR_4, efab->mac_addr[4],
- GM_HWADDR_3, efab->mac_addr[3],
- GM_HWADDR_2, efab->mac_addr[2] );
- efab->mac_op->mac_writel ( efab, &reg, GM_ADR1_REG_MAC );
- udelay ( 10 );
- EFAB_POPULATE_DWORD_2 ( reg,
- GM_HWADDR_1, efab->mac_addr[1],
- GM_HWADDR_0, efab->mac_addr[0] );
- efab->mac_op->mac_writel ( efab, &reg, GM_ADR2_REG_MAC );
- udelay ( 10 );
-}
-
-/**
- * Wait for GMII access to complete
- *
- */
-static int mentormac_gmii_wait ( struct efab_nic *efab ) {
- int count;
- efab_dword_t indicator;
-
- for ( count = 0 ; count < 1000 ; count++ ) {
- udelay ( 10 );
- efab->mac_op->mac_readl ( efab, &indicator,
- GM_MII_MGMT_IND_REG_MAC );
- if ( EFAB_DWORD_FIELD ( indicator, GM_MGMT_BUSY ) == 0 )
- return 1;
+ if (in_reset != 0) {
+ EFAB_ERR("Not all MMDs came out of reset in time. MMDs "
+ "still in reset: %x\n", in_reset);
+ return -ETIMEDOUT;
}
- EFAB_ERR ( "Timed out waiting for GMII\n" );
return 0;
}
-/**
- * Write a GMII register
- *
- */
-static void mentormac_mdio_write ( struct efab_nic *efab, int phy_id,
- int location, int value ) {
- efab_dword_t reg;
- int save_port;
-
- EFAB_TRACE ( "Writing GMII %d register %02x with %04x\n", phy_id,
- location, value );
-
- /* Mentor MAC connects both PHYs to MAC 0 */
- save_port = efab->port;
- efab->port = 0;
-
- /* Check MII not currently being accessed */
- if ( ! mentormac_gmii_wait ( efab ) )
- goto out;
-
- /* Write the address register */
- EFAB_POPULATE_DWORD_2 ( reg,
- GM_MGMT_PHY_ADDR, phy_id,
- GM_MGMT_REG_ADDR, location );
- efab->mac_op->mac_writel ( efab, &reg, GM_MII_MGMT_ADR_REG_MAC );
- udelay ( 10 );
-
- /* Write data */
- EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_CTL, value );
- efab->mac_op->mac_writel ( efab, &reg, GM_MII_MGMT_CTL_REG_MAC );
-
- /* Wait for data to be written */
- mentormac_gmii_wait ( efab );
-
- out:
- /* Restore efab->port */
- efab->port = save_port;
-}
-
-/**
- * Read a GMII register
- *
- */
-static int mentormac_mdio_read ( struct efab_nic *efab, int phy_id,
- int location ) {
- efab_dword_t reg;
- int value = 0xffff;
- int save_port;
-
- /* Mentor MAC connects both PHYs to MAC 0 */
- save_port = efab->port;
- efab->port = 0;
-
- /* Check MII not currently being accessed */
- if ( ! mentormac_gmii_wait ( efab ) )
- goto out;
-
- /* Write the address register */
- EFAB_POPULATE_DWORD_2 ( reg,
- GM_MGMT_PHY_ADDR, phy_id,
- GM_MGMT_REG_ADDR, location );
- efab->mac_op->mac_writel ( efab, &reg, GM_MII_MGMT_ADR_REG_MAC );
- udelay ( 10 );
-
- /* Request data to be read */
- EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_RD_CYC, 1 );
- efab->mac_op->mac_writel ( efab, &reg, GM_MII_MGMT_CMD_REG_MAC );
-
- /* Wait for data to be become available */
- if ( mentormac_gmii_wait ( efab ) ) {
- /* Read data */
- efab->mac_op->mac_readl ( efab, &reg, GM_MII_MGMT_STAT_REG_MAC );
- value = EFAB_DWORD_FIELD ( reg, GM_MGMT_STAT );
- EFAB_TRACE ( "Read from GMII %d register %02x, got %04x\n",
- phy_id, location, value );
- }
-
- /* Signal completion */
- EFAB_ZERO_DWORD ( reg );
- efab->mac_op->mac_writel ( efab, &reg, GM_MII_MGMT_CMD_REG_MAC );
- udelay ( 10 );
-
- out:
- /* Restore efab->port */
- efab->port = save_port;
-
- return value;
-}
-
-/**************************************************************************
- *
- * EF1002 routines
- *
- **************************************************************************
- */
-
-/** Control and General Status */
-#define EF1_CTR_GEN_STATUS0_REG 0x0
-#define EF1_MASTER_EVENTS_LBN 12
-#define EF1_MASTER_EVENTS_WIDTH 1
-#define EF1_TX_ENGINE_EN_LBN 19
-#define EF1_TX_ENGINE_EN_WIDTH 1
-#define EF1_RX_ENGINE_EN_LBN 18
-#define EF1_RX_ENGINE_EN_WIDTH 1
-#define EF1_TURBO2_LBN 17
-#define EF1_TURBO2_WIDTH 1
-#define EF1_TURBO1_LBN 16
-#define EF1_TURBO1_WIDTH 1
-#define EF1_TURBO3_LBN 14
-#define EF1_TURBO3_WIDTH 1
-#define EF1_LB_RESET_LBN 3
-#define EF1_LB_RESET_WIDTH 1
-#define EF1_MAC_RESET_LBN 2
-#define EF1_MAC_RESET_WIDTH 1
-#define EF1_CAM_ENABLE_LBN 1
-#define EF1_CAM_ENABLE_WIDTH 1
-
-/** IRQ sources */
-#define EF1_IRQ_SRC_REG 0x0008
-
-/** IRQ mask */
-#define EF1_IRQ_MASK_REG 0x000c
-#define EF1_IRQ_PHY1_LBN 11
-#define EF1_IRQ_PHY1_WIDTH 1
-#define EF1_IRQ_PHY0_LBN 10
-#define EF1_IRQ_PHY0_WIDTH 1
-#define EF1_IRQ_SERR_LBN 7
-#define EF1_IRQ_SERR_WIDTH 1
-#define EF1_IRQ_EVQ_LBN 3
-#define EF1_IRQ_EVQ_WIDTH 1
-
-/** Event generation */
-#define EF1_EVT3_REG 0x38
-
-/** EEPROMaccess */
-#define EF1_EEPROM_REG 0x40
-#define EF1_EEPROM_SDA_LBN 31
-#define EF1_EEPROM_SDA_WIDTH 1
-#define EF1_EEPROM_SCL_LBN 30
-#define EF1_EEPROM_SCL_WIDTH 1
-#define EF1_JTAG_DISCONNECT_LBN 17
-#define EF1_JTAG_DISCONNECT_WIDTH 1
-#define EF1_EEPROM_LBN 0
-#define EF1_EEPROM_WIDTH 32
-
-/** Control register 2 */
-#define EF1_CTL2_REG 0x4c
-#define EF1_PLL_TRAP_LBN 31
-#define EF1_PLL_TRAP_WIDTH 1
-#define EF1_MEM_MAP_4MB_LBN 11
-#define EF1_MEM_MAP_4MB_WIDTH 1
-#define EF1_EV_INTR_CLR_WRITE_LBN 6
-#define EF1_EV_INTR_CLR_WRITE_WIDTH 1
-#define EF1_BURST_MERGE_LBN 5
-#define EF1_BURST_MERGE_WIDTH 1
-#define EF1_CLEAR_NULL_PAD_LBN 4
-#define EF1_CLEAR_NULL_PAD_WIDTH 1
-#define EF1_SW_RESET_LBN 2
-#define EF1_SW_RESET_WIDTH 1
-#define EF1_INTR_AFTER_EVENT_LBN 1
-#define EF1_INTR_AFTER_EVENT_WIDTH 1
-
-/** Event FIFO */
-#define EF1_EVENT_FIFO_REG 0x50
-
-/** Event FIFO count */
-#define EF1_EVENT_FIFO_COUNT_REG 0x5c
-#define EF1_EV_COUNT_LBN 0
-#define EF1_EV_COUNT_WIDTH 16
-
-/** TX DMA control and status */
-#define EF1_DMA_TX_CSR_REG 0x80
-#define EF1_DMA_TX_CSR_CHAIN_EN_LBN 8
-#define EF1_DMA_TX_CSR_CHAIN_EN_WIDTH 1
-#define EF1_DMA_TX_CSR_ENABLE_LBN 4
-#define EF1_DMA_TX_CSR_ENABLE_WIDTH 1
-#define EF1_DMA_TX_CSR_INT_EN_LBN 0
-#define EF1_DMA_TX_CSR_INT_EN_WIDTH 1
-
-/** RX DMA control and status */
-#define EF1_DMA_RX_CSR_REG 0xa0
-#define EF1_DMA_RX_ABOVE_1GB_EN_LBN 6
-#define EF1_DMA_RX_ABOVE_1GB_EN_WIDTH 1
-#define EF1_DMA_RX_BELOW_1MB_EN_LBN 5
-#define EF1_DMA_RX_BELOW_1MB_EN_WIDTH 1
-#define EF1_DMA_RX_CSR_ENABLE_LBN 0
-#define EF1_DMA_RX_CSR_ENABLE_WIDTH 1
-
-/** Level 5 watermark register (in MAC space) */
-#define EF1_GMF_L5WM_REG_MAC 0x20
-#define EF1_L5WM_LBN 0
-#define EF1_L5WM_WIDTH 32
-
-/** MAC clock */
-#define EF1_GM_MAC_CLK_REG 0x112000
-#define EF1_GM_PORT0_MAC_CLK_LBN 0
-#define EF1_GM_PORT0_MAC_CLK_WIDTH 1
-#define EF1_GM_PORT1_MAC_CLK_LBN 1
-#define EF1_GM_PORT1_MAC_CLK_WIDTH 1
-
-/** TX descriptor FIFO */
-#define EF1_TX_DESC_FIFO 0x141000
-#define EF1_TX_KER_EVQ_LBN 80
-#define EF1_TX_KER_EVQ_WIDTH 12
-#define EF1_TX_KER_IDX_LBN 64
-#define EF1_TX_KER_IDX_WIDTH 16
-#define EF1_TX_KER_MODE_LBN 63
-#define EF1_TX_KER_MODE_WIDTH 1
-#define EF1_TX_KER_PORT_LBN 60
-#define EF1_TX_KER_PORT_WIDTH 1
-#define EF1_TX_KER_CONT_LBN 56
-#define EF1_TX_KER_CONT_WIDTH 1
-#define EF1_TX_KER_BYTE_CNT_LBN 32
-#define EF1_TX_KER_BYTE_CNT_WIDTH 24
-#define EF1_TX_KER_BUF_ADR_LBN 0
-#define EF1_TX_KER_BUF_ADR_WIDTH 32
-
-/** TX descriptor FIFO flush */
-#define EF1_TX_DESC_FIFO_FLUSH 0x141ffc
-
-/** RX descriptor FIFO */
-#define EF1_RX_DESC_FIFO 0x145000
-#define EF1_RX_KER_EVQ_LBN 48
-#define EF1_RX_KER_EVQ_WIDTH 12
-#define EF1_RX_KER_IDX_LBN 32
-#define EF1_RX_KER_IDX_WIDTH 16
-#define EF1_RX_KER_BUF_ADR_LBN 0
-#define EF1_RX_KER_BUF_ADR_WIDTH 32
-
-/** RX descriptor FIFO flush */
-#define EF1_RX_DESC_FIFO_FLUSH 0x145ffc
-
-/** CAM */
-#define EF1_CAM_BASE 0x1c0000
-#define EF1_CAM_WTF_DOES_THIS_DO_LBN 0
-#define EF1_CAM_WTF_DOES_THIS_DO_WIDTH 32
-
-/** Event queue pointers */
-#define EF1_EVQ_PTR_BASE 0x260000
-#define EF1_EVQ_SIZE_LBN 29
-#define EF1_EVQ_SIZE_WIDTH 2
-#define EF1_EVQ_SIZE_4K 3
-#define EF1_EVQ_SIZE_2K 2
-#define EF1_EVQ_SIZE_1K 1
-#define EF1_EVQ_SIZE_512 0
-#define EF1_EVQ_BUF_BASE_ID_LBN 0
-#define EF1_EVQ_BUF_BASE_ID_WIDTH 29
-
-/* MAC registers */
-#define EF1002_MAC_REGBANK 0x110000
-#define EF1002_MAC_REGBANK_SIZE 0x1000
-#define EF1002_MAC_REG_SIZE 0x08
-
-/** Offset of a MAC register within EF1002 */
-#define EF1002_MAC_REG( efab, mac_reg ) \
- ( EF1002_MAC_REGBANK + \
- ( (efab)->port * EF1002_MAC_REGBANK_SIZE ) + \
- ( (mac_reg) * EF1002_MAC_REG_SIZE ) )
-
-/* Event queue entries */
-#define EF1_EV_CODE_LBN 20
-#define EF1_EV_CODE_WIDTH 8
-#define EF1_RX_EV_DECODE 0x01
-#define EF1_TX_EV_DECODE 0x02
-#define EF1_TIMER_EV_DECODE 0x0b
-#define EF1_DRV_GEN_EV_DECODE 0x0f
-
-/* Receive events */
-#define EF1_RX_EV_LEN_LBN 48
-#define EF1_RX_EV_LEN_WIDTH 16
-#define EF1_RX_EV_PORT_LBN 17
-#define EF1_RX_EV_PORT_WIDTH 3
-#define EF1_RX_EV_OK_LBN 16
-#define EF1_RX_EV_OK_WIDTH 1
-#define EF1_RX_EV_IDX_LBN 0
-#define EF1_RX_EV_IDX_WIDTH 16
-
-/* Transmit events */
-#define EF1_TX_EV_PORT_LBN 17
-#define EF1_TX_EV_PORT_WIDTH 3
-#define EF1_TX_EV_OK_LBN 16
-#define EF1_TX_EV_OK_WIDTH 1
-#define EF1_TX_EV_IDX_LBN 0
-#define EF1_TX_EV_IDX_WIDTH 16
-
-/* forward decleration */
-static struct efab_mac_operations ef1002_mac_operations;
-
-/* I2C ID of the EEPROM */
-#define EF1_EEPROM_I2C_ID 0x50
-
-/* Offset of MAC address within EEPROM */
-#define EF1_EEPROM_HWADDR_OFFSET 0x0
-
-/**
- * Write dword to EF1002 register
- *
- */
-static inline void ef1002_writel ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int reg ) {
- EFAB_REGDUMP ( "Writing register %x with " EFAB_DWORD_FMT "\n",
- reg, EFAB_DWORD_VAL ( *value ) );
- writel ( value->u32[0], efab->membase + reg );
-}
-
-/**
- * Read dword from an EF1002 register
- *
- */
-static inline void ef1002_readl ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int reg ) {
- value->u32[0] = readl ( efab->membase + reg );
- EFAB_REGDUMP ( "Read from register %x, got " EFAB_DWORD_FMT "\n",
- reg, EFAB_DWORD_VAL ( *value ) );
-}
-
-/**
- * Read dword from an EF1002 register, silently
- *
- */
-static inline void ef1002_readl_silent ( struct efab_nic *efab,
- efab_dword_t *value,
- unsigned int reg ) {
- value->u32[0] = readl ( efab->membase + reg );
-}
-
-/**
- * Get memory base
- *
- */
-static void ef1002_get_membase ( struct efab_nic *efab ) {
- unsigned long membase_phys;
-
- membase_phys = pci_bar_start ( efab->pci, PCI_BASE_ADDRESS_0 );
- efab->membase = ioremap ( membase_phys, 0x800000 );
-}
-
-/** PCI registers to backup/restore over a device reset */
-static const unsigned int efab_pci_reg_addr[] = {
- PCI_COMMAND, 0x0c /* PCI_CACHE_LINE_SIZE */,
- PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2,
- PCI_BASE_ADDRESS_3, PCI_ROM_ADDRESS, PCI_INTERRUPT_LINE,
-};
-/** Number of registers in efab_pci_reg_addr */
-#define EFAB_NUM_PCI_REG \
- ( sizeof ( efab_pci_reg_addr ) / sizeof ( efab_pci_reg_addr[0] ) )
-/** PCI configuration space backup */
-struct efab_pci_reg {
- uint32_t reg[EFAB_NUM_PCI_REG];
-};
-
-/*
- * I2C interface and EEPROM
- *
- */
-
-static unsigned long ef1002_i2c_bits[] = {
- [I2C_BIT_SCL] = ( 1 << 30 ),
- [I2C_BIT_SDA] = ( 1 << 31 ),
-};
-
-static void ef1002_i2c_write_bit ( struct bit_basher *basher,
- unsigned int bit_id, unsigned long data ) {
- struct efab_nic *efab = container_of ( basher, struct efab_nic,
- ef1002_i2c.basher );
- unsigned long mask;
- efab_dword_t reg;
+static int
+mdio_clause45_reset_mmd ( struct efab_nic *efab, int mmd )
+{
+ int tries = MDIO45_RESET_TRIES;
+ int ctrl;
- mask = ef1002_i2c_bits[bit_id];
- efab->ef1002_i2c_outputs &= ~mask;
- efab->ef1002_i2c_outputs |= ( data & mask );
- EFAB_POPULATE_DWORD_1 ( reg, EF1_EEPROM, efab->ef1002_i2c_outputs );
- ef1002_writel ( efab, &reg, EF1_EEPROM_REG );
-}
+ falcon_mdio_write ( efab, mmd, MDIO_MMDREG_CTRL1,
+ ( 1 << MDIO_MMDREG_CTRL1_RESET_LBN ) );
-static int ef1002_i2c_read_bit ( struct bit_basher *basher,
- unsigned int bit_id ) {
- struct efab_nic *efab = container_of ( basher, struct efab_nic,
- ef1002_i2c.basher );
- unsigned long mask;
- efab_dword_t reg;
+ /* Wait for the reset bit to clear. */
+ do {
+ mdelay ( MDIO45_RESET_SPINTIME );
- mask = ef1002_i2c_bits[bit_id];
- ef1002_readl ( efab, &reg, EF1_EEPROM_REG );
- return ( EFAB_DWORD_FIELD ( reg, EF1_EEPROM ) & mask );
-}
+ ctrl = falcon_mdio_read ( efab, mmd, MDIO_MMDREG_CTRL1 );
+ if ( ~ctrl & ( 1 << MDIO_MMDREG_CTRL1_RESET_LBN ) )
+ return 0;
+ } while ( --tries );
-static struct bit_basher_operations ef1002_basher_ops = {
- .read = ef1002_i2c_read_bit,
- .write = ef1002_i2c_write_bit,
-};
+ EFAB_ERR ( "Failed to reset mmd %d\n", mmd );
-static void ef1002_init_eeprom ( struct efab_nic *efab ) {
- efab->ef1002_i2c.basher.op = &ef1002_basher_ops;
- init_i2c_bit_basher ( &efab->ef1002_i2c );
- efab->ef1002_eeprom.address = EF1_EEPROM_I2C_ID;
+ return -ETIMEDOUT;
}
-/**
- * Reset device
- *
- */
-static int ef1002_reset ( struct efab_nic *efab ) {
- struct efab_pci_reg pci_reg;
- struct pci_device *pci_dev = efab->pci;
- efab_dword_t reg;
- unsigned int i;
- uint32_t tmp;
-
- /* Back up PCI configuration registers */
- for ( i = 0 ; i < EFAB_NUM_PCI_REG ; i++ ) {
- pci_read_config_dword ( pci_dev, efab_pci_reg_addr[i],
- &pci_reg.reg[i] );
- }
-
- /* Reset the whole device. */
- EFAB_POPULATE_DWORD_1 ( reg, EF1_SW_RESET, 1 );
- ef1002_writel ( efab, &reg, EF1_CTL2_REG );
- mdelay ( 200 );
-
- /* Restore PCI configuration space */
- for ( i = 0 ; i < EFAB_NUM_PCI_REG ; i++ ) {
- pci_write_config_dword ( pci_dev, efab_pci_reg_addr[i],
- pci_reg.reg[i] );
- }
-
- /* Verify PCI configuration space */
- for ( i = 0 ; i < EFAB_NUM_PCI_REG ; i++ ) {
- pci_read_config_dword ( pci_dev, efab_pci_reg_addr[i], &tmp );
- if ( tmp != pci_reg.reg[i] ) {
- EFAB_LOG ( "PCI restore failed on register %02x "
- "(is %08lx, should be %08lx); reboot\n",
- i, tmp, pci_reg.reg[i] );
- return 0;
+static int
+mdio_clause45_links_ok(struct efab_nic *efab )
+{
+ int status, good;
+ int ok = 1;
+ int mmd = 0;
+ int mmd_mask = efab->phy_op->mmds;
+
+ while (mmd_mask) {
+ if (mmd_mask & 1) {
+ /* Double reads because link state is latched, and a
+ * read moves the current state into the register */
+ status = falcon_mdio_read ( efab, mmd,
+ MDIO_MMDREG_STAT1 );
+ status = falcon_mdio_read ( efab, mmd,
+ MDIO_MMDREG_STAT1 );
+
+ good = status & (1 << MDIO_MMDREG_STAT1_LINK_LBN);
+ ok = ok && good;
}
+ mmd_mask = (mmd_mask >> 1);
+ mmd++;
}
-
- /* Verify device reset complete */
- ef1002_readl ( efab, &reg, EF1_CTR_GEN_STATUS0_REG );
- if ( EFAB_DWORD_IS_ALL_ONES ( reg ) ) {
- EFAB_ERR ( "Reset failed\n" );
- return 0;
- }
-
- return 1;
-}
-
-/**
- * Initialise NIC
- *
- */
-static int ef1002_init_nic ( struct efab_nic *efab ) {
- efab_dword_t reg;
-
- /* patch in the MAC operations */
- efab->mac_op = &ef1002_mac_operations;
-
- /* No idea what CAM is, but the 'datasheet' says that we have
- * to write these values in at start of day
- */
- EFAB_POPULATE_DWORD_1 ( reg, EF1_CAM_WTF_DOES_THIS_DO, 0x6 );
- ef1002_writel ( efab, &reg, EF1_CAM_BASE + 0x20018 );
- udelay ( 1000 );
- EFAB_POPULATE_DWORD_1 ( reg, EF1_CAM_WTF_DOES_THIS_DO, 0x01000000 );
- ef1002_writel ( efab, &reg, EF1_CAM_BASE + 0x00018 );
- udelay ( 1000 );
-
- /* General control register 0 */
- ef1002_readl ( efab, &reg, EF1_CTR_GEN_STATUS0_REG );
- EFAB_SET_DWORD_FIELD ( reg, EF1_MASTER_EVENTS, 0 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_TX_ENGINE_EN, 0 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_RX_ENGINE_EN, 0 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_TURBO2, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_TURBO1, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_TURBO3, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_CAM_ENABLE, 1 );
- ef1002_writel ( efab, &reg, EF1_CTR_GEN_STATUS0_REG );
- udelay ( 1000 );
-
- /* General control register 2 */
- ef1002_readl ( efab, &reg, EF1_CTL2_REG );
- EFAB_SET_DWORD_FIELD ( reg, EF1_PLL_TRAP, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_MEM_MAP_4MB, 0 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_EV_INTR_CLR_WRITE, 0 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_BURST_MERGE, 0 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_CLEAR_NULL_PAD, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_INTR_AFTER_EVENT, 1 );
- ef1002_writel ( efab, &reg, EF1_CTL2_REG );
- udelay ( 1000 );
-
- /* Enable RX DMA */
- ef1002_readl ( efab, &reg, EF1_DMA_RX_CSR_REG );
- EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_RX_CSR_ENABLE, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_RX_BELOW_1MB_EN, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_RX_ABOVE_1GB_EN, 1 );
- ef1002_writel ( efab, &reg, EF1_DMA_RX_CSR_REG );
- udelay ( 1000 );
-
- /* Enable TX DMA */
- ef1002_readl ( efab, &reg, EF1_DMA_TX_CSR_REG );
- EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_TX_CSR_CHAIN_EN, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_TX_CSR_ENABLE, 0 /* ?? */ );
- EFAB_SET_DWORD_FIELD ( reg, EF1_DMA_TX_CSR_INT_EN, 0 /* ?? */ );
- ef1002_writel ( efab, &reg, EF1_DMA_TX_CSR_REG );
- udelay ( 1000 );
-
- /* Disconnect the JTAG chain. Read-modify-write is impossible
- * on the I2C control bits, since reading gives the state of
- * the line inputs rather than the last written state.
- */
- ef1002_readl ( efab, &reg, EF1_EEPROM_REG );
- EFAB_SET_DWORD_FIELD ( reg, EF1_EEPROM_SDA, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_EEPROM_SCL, 1 );
- EFAB_SET_DWORD_FIELD ( reg, EF1_JTAG_DISCONNECT, 1 );
- ef1002_writel ( efab, &reg, EF1_EEPROM_REG );
- udelay ( 10 );
-
- /* Flush descriptor queues */
- EFAB_ZERO_DWORD ( reg );
- ef1002_writel ( efab, &reg, EF1_RX_DESC_FIFO_FLUSH );
- ef1002_writel ( efab, &reg, EF1_TX_DESC_FIFO_FLUSH );
- wmb();
- udelay ( 10000 );
-
- /* Reset MAC */
- efab->mac_op->reset ( efab );
-
- /* Attach I2C bus */
- ef1002_init_eeprom ( efab );
-
- return 1;
-}
-
-/**
- * Read MAC address from EEPROM
- *
- */
-static int ef1002_read_eeprom ( struct efab_nic *efab ) {
- struct i2c_interface *i2c = &efab->ef1002_i2c.i2c;
- struct i2c_device *i2cdev = &efab->ef1002_eeprom;
-
- if ( i2c->read ( i2c, i2cdev, EF1_EEPROM_HWADDR_OFFSET,
- efab->mac_addr, sizeof ( efab->mac_addr ) ) != 0 )
- return 0;
-
- efab->mac_addr[ETH_ALEN-1] += efab->port;
-
- return 1;
-}
-
-/** RX descriptor */
-typedef efab_qword_t ef1002_rx_desc_t;
-
-/**
- * Build RX descriptor
- *
- */
-static void ef1002_build_rx_desc ( struct efab_nic *efab,
- struct efab_rx_buf *rx_buf ) {
- ef1002_rx_desc_t rxd;
-
- EFAB_POPULATE_QWORD_3 ( rxd,
- EF1_RX_KER_EVQ, 0,
- EF1_RX_KER_IDX, rx_buf->id,
- EF1_RX_KER_BUF_ADR,
- virt_to_bus ( rx_buf->addr ) );
- ef1002_writel ( efab, &rxd.dword[0], EF1_RX_DESC_FIFO + 0 );
- wmb();
- ef1002_writel ( efab, &rxd.dword[1], EF1_RX_DESC_FIFO + 4 );
- udelay ( 10 );
-}
-
-/**
- * Update RX descriptor write pointer
- *
- */
-static void ef1002_notify_rx_desc ( struct efab_nic *efab __unused ) {
- /* Nothing to do */
+ return ok;
}
-/** TX descriptor */
-typedef efab_oword_t ef1002_tx_desc_t;
-
-/**
- * Build TX descriptor
- *
- */
-static void ef1002_build_tx_desc ( struct efab_nic *efab,
- struct efab_tx_buf *tx_buf ) {
- ef1002_tx_desc_t txd;
-
- EFAB_POPULATE_OWORD_7 ( txd,
- EF1_TX_KER_EVQ, 0,
- EF1_TX_KER_IDX, tx_buf->id,
- EF1_TX_KER_MODE, 0 /* IP mode */,
- EF1_TX_KER_PORT, efab->port,
- EF1_TX_KER_CONT, 0,
- EF1_TX_KER_BYTE_CNT, tx_buf->len,
- EF1_TX_KER_BUF_ADR,
- virt_to_bus ( tx_buf->addr ) );
-
- ef1002_writel ( efab, &txd.dword[0], EF1_TX_DESC_FIFO + 0 );
- ef1002_writel ( efab, &txd.dword[1], EF1_TX_DESC_FIFO + 4 );
- wmb();
- ef1002_writel ( efab, &txd.dword[2], EF1_TX_DESC_FIFO + 8 );
- udelay ( 10 );
-}
-
-/**
- * Update TX descriptor write pointer
- *
- */
-static void ef1002_notify_tx_desc ( struct efab_nic *efab __unused ) {
- /* Nothing to do */
-}
-
-/** An event */
-typedef efab_qword_t ef1002_event_t;
-
-/**
- * Retrieve event from event queue
- *
- */
-static int ef1002_fetch_event ( struct efab_nic *efab,
- struct efab_event *event ) {
- efab_dword_t reg;
- int ev_code;
- int words;
-
- /* Check event FIFO depth */
- ef1002_readl_silent ( efab, &reg, EF1_EVENT_FIFO_COUNT_REG );
- words = EFAB_DWORD_FIELD ( reg, EF1_EV_COUNT );
- if ( ! words )
- return 0;
-
- /* Read event data */
- ef1002_readl ( efab, &reg, EF1_EVENT_FIFO_REG );
- DBG ( "Event is " EFAB_DWORD_FMT "\n", EFAB_DWORD_VAL ( reg ) );
-
- /* Decode event */
- ev_code = EFAB_DWORD_FIELD ( reg, EF1_EV_CODE );
- event->drop = 0;
- switch ( ev_code ) {
- case EF1_TX_EV_DECODE:
- event->type = EFAB_EV_TX;
- break;
- case EF1_RX_EV_DECODE:
- event->type = EFAB_EV_RX;
- event->rx_id = EFAB_DWORD_FIELD ( reg, EF1_RX_EV_IDX );
- /* RX len not available via event FIFO */
- event->rx_len = ETH_FRAME_LEN;
- break;
- case EF1_TIMER_EV_DECODE:
- /* These are safe to ignore. We seem to get some at
- * start of day, presumably due to the timers starting
- * up with random contents.
- */
- event->type = EFAB_EV_NONE;
- break;
- default:
- EFAB_ERR ( "Unknown event type %d\n", ev_code );
- event->type = EFAB_EV_NONE;
+static int
+mdio_clause45_check_mmds ( struct efab_nic *efab )
+{
+ int mmd = 0;
+ int devices = falcon_mdio_read ( efab, MDIO_MMD_PHYXS,
+ MDIO_MMDREG_DEVS0 );
+ int mmd_mask = efab->phy_op->mmds;
+
+ /* Check all the expected MMDs are present */
+ if ( devices < 0 ) {
+ EFAB_ERR ( "Failed to read devices present\n" );
+ return -EIO;
}
-
- /* Clear any pending interrupts */
- ef1002_readl ( efab, &reg, EF1_IRQ_SRC_REG );
-
- return 1;
-}
-
-/**
- * Enable/disable interrupts
- *
- */
-static void ef1002_mask_irq ( struct efab_nic *efab, int enabled ) {
- efab_dword_t irq_mask;
-
- EFAB_POPULATE_DWORD_2 ( irq_mask,
- EF1_IRQ_SERR, enabled,
- EF1_IRQ_EVQ, enabled );
- ef1002_writel ( efab, &irq_mask, EF1_IRQ_MASK_REG );
-}
-
-/**
- * Generate interrupt
- *
- */
-static void ef1002_generate_irq ( struct efab_nic *efab ) {
- ef1002_event_t test_event;
-
- EFAB_POPULATE_QWORD_1 ( test_event,
- EF1_EV_CODE, EF1_DRV_GEN_EV_DECODE );
- ef1002_writel ( efab, &test_event.dword[0], EF1_EVT3_REG );
-}
-
-/**
- * Write dword to an EF1002 MAC register
- *
- */
-static void ef1002_mac_writel ( struct efab_nic *efab,
- efab_dword_t *value, unsigned int mac_reg ) {
- ef1002_writel ( efab, value, EF1002_MAC_REG ( efab, mac_reg ) );
-}
-
-/**
- * Read dword from an EF1002 MAC register
- *
- */
-static void ef1002_mac_readl ( struct efab_nic *efab,
- efab_dword_t *value, unsigned int mac_reg ) {
- ef1002_readl ( efab, value, EF1002_MAC_REG ( efab, mac_reg ) );
-}
-
-/**
- * Initialise MAC
- *
- */
-static int ef1002_init_mac ( struct efab_nic *efab ) {
- static struct efab_mentormac_parameters ef1002_mentormac_params = {
- .gmf_cfgfrth = 0x13,
- .gmf_cfgftth = 0x10,
- .gmf_cfghwmft = 0x555,
- .gmf_cfghwm = 0x2a,
- .gmf_cfglwm = 0x15,
- };
- efab_dword_t reg;
- unsigned int mac_clk;
-
- /* Initialise PHY */
- alaska_init ( efab );
-
- /* Initialise MAC */
- mentormac_init ( efab, &ef1002_mentormac_params );
-
- /* Write Level 5 watermark register */
- EFAB_POPULATE_DWORD_1 ( reg, EF1_L5WM, 0x10040000 );
- efab->mac_op->mac_writel ( efab, &reg, EF1_GMF_L5WM_REG_MAC );
- udelay ( 10 );
-
- /* Set MAC clock speed */
- ef1002_readl ( efab, &reg, EF1_GM_MAC_CLK_REG );
- mac_clk = ( efab->link_options & LPA_1000 ) ? 0 : 1;
- if ( efab->port == 0 ) {
- EFAB_SET_DWORD_FIELD ( reg, EF1_GM_PORT0_MAC_CLK, mac_clk );
- } else {
- EFAB_SET_DWORD_FIELD ( reg, EF1_GM_PORT1_MAC_CLK, mac_clk );
+ if ( ( devices & mmd_mask ) != mmd_mask ) {
+ EFAB_ERR ( "required MMDs not present: got %x, wanted %x\n",
+ devices, mmd_mask );
+ return -EIO;
}
- ef1002_writel ( efab, &reg, EF1_GM_MAC_CLK_REG );
- udelay ( 10 );
- return 1;
-}
+ /* Check all required MMDs are responding and happy. */
+ while ( mmd_mask ) {
+ if ( mmd_mask & 1 ) {
+ efab_dword_t reg;
+ int status;
+ reg.opaque = falcon_mdio_read ( efab, mmd,
+ MDIO_MMDREG_STAT2 );
+ status = EFAB_DWORD_FIELD ( reg,
+ MDIO_MMDREG_STAT2_PRESENT );
+ if ( status != MDIO_MMDREG_STAT2_PRESENT_VAL ) {
-/**
- * Reset MAC
- *
- */
-static int ef1002_reset_mac ( struct efab_nic *efab ) {
- mentormac_reset ( efab );
- return 1;
-}
-/** MDIO write */
-static void ef1002_mdio_write ( struct efab_nic *efab, int location,
- int value ) {
- mentormac_mdio_write ( efab, efab->port + 2, location, value );
-}
+ return -EIO;
+ }
+ }
+ mmd_mask >>= 1;
+ mmd++;
+ }
-/** MDIO read */
-static int ef1002_mdio_read ( struct efab_nic *efab, int location ) {
- return mentormac_mdio_read ( efab, efab->port + 2, location );
+ return 0;
}
-static struct efab_operations ef1002_operations = {
- .get_membase = ef1002_get_membase,
- .reset = ef1002_reset,
- .init_nic = ef1002_init_nic,
- .read_eeprom = ef1002_read_eeprom,
- .build_rx_desc = ef1002_build_rx_desc,
- .notify_rx_desc = ef1002_notify_rx_desc,
- .build_tx_desc = ef1002_build_tx_desc,
- .notify_tx_desc = ef1002_notify_tx_desc,
- .fetch_event = ef1002_fetch_event,
- .mask_irq = ef1002_mask_irq,
- .generate_irq = ef1002_generate_irq,
- .mdio_write = ef1002_mdio_write,
- .mdio_read = ef1002_mdio_read,
-};
-
-static struct efab_mac_operations ef1002_mac_operations = {
- .mac_writel = ef1002_mac_writel,
- .mac_readl = ef1002_mac_readl,
- .init = ef1002_init_mac,
- .reset = ef1002_reset_mac,
-};
-
-/**************************************************************************
- *
- * Falcon routines
- *
- **************************************************************************
- */
-
/* I/O BAR address register */
#define FCN_IOM_IND_ADR_REG 0x0
/* I/O BAR data register */
#define FCN_IOM_IND_DAT_REG 0x4
+/* Address region register */
+#define FCN_ADR_REGION_REG_KER 0x00
+#define FCN_ADR_REGION0_LBN 0
+#define FCN_ADR_REGION0_WIDTH 18
+#define FCN_ADR_REGION1_LBN 32
+#define FCN_ADR_REGION1_WIDTH 18
+#define FCN_ADR_REGION2_LBN 64
+#define FCN_ADR_REGION2_WIDTH 18
+#define FCN_ADR_REGION3_LBN 96
+#define FCN_ADR_REGION3_WIDTH 18
+
/* Interrupt enable register */
#define FCN_INT_EN_REG_KER 0x0010
#define FCN_MEM_PERR_INT_EN_KER_LBN 5
@@ -1505,11 +440,25 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_INT_ADR_KER_LBN 0
#define FCN_INT_ADR_KER_WIDTH EFAB_DMA_TYPE_WIDTH ( 64 )
-/* Interrupt acknowledge register */
-#define FCN_INT_ACK_KER_REG 0x0050
+/* Interrupt status register (B0 only) */
+#define INT_ISR0_B0 0x90
+#define INT_ISR1_B0 0xA0
+
+/* Interrupt acknowledge register (A0/A1 only) */
+#define FCN_INT_ACK_KER_REG_A1 0x0050
+#define INT_ACK_DUMMY_DATA_LBN 0
+#define INT_ACK_DUMMY_DATA_WIDTH 32
+
+/* Interrupt acknowledge work-around register (A0/A1 only )*/
+#define WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 0x0070
+
+/* Hardware initialisation register */
+#define FCN_HW_INIT_REG_KER 0x00c0
+#define FCN_BCSR_TARGET_MASK_LBN 101
+#define FCN_BCSR_TARGET_MASK_WIDTH 4
/* SPI host command register */
-#define FCN_EE_SPI_HCMD_REG_KER 0x0100
+#define FCN_EE_SPI_HCMD_REG 0x0100
#define FCN_EE_SPI_HCMD_CMD_EN_LBN 31
#define FCN_EE_SPI_HCMD_CMD_EN_WIDTH 1
#define FCN_EE_WR_TIMER_ACTIVE_LBN 28
@@ -1532,14 +481,14 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_EE_SPI_HCMD_ENC_WIDTH 8
/* SPI host address register */
-#define FCN_EE_SPI_HADR_REG_KER 0x0110
+#define FCN_EE_SPI_HADR_REG 0x0110
#define FCN_EE_SPI_HADR_DUBYTE_LBN 24
#define FCN_EE_SPI_HADR_DUBYTE_WIDTH 8
#define FCN_EE_SPI_HADR_ADR_LBN 0
#define FCN_EE_SPI_HADR_ADR_WIDTH 24
/* SPI host data register */
-#define FCN_EE_SPI_HDATA_REG_KER 0x0120
+#define FCN_EE_SPI_HDATA_REG 0x0120
#define FCN_EE_SPI_HDATA3_LBN 96
#define FCN_EE_SPI_HDATA3_WIDTH 32
#define FCN_EE_SPI_HDATA2_LBN 64
@@ -1549,89 +498,130 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_EE_SPI_HDATA0_LBN 0
#define FCN_EE_SPI_HDATA0_WIDTH 32
-/* VPI configuration register */
-#define FCN_VPD_CONFIG_REG_KER 0x0140
-#define FCN_VPD_9BIT_LBN 1
-#define FCN_VPD_9BIT_WIDTH 1
+/* VPD Config 0 Register register */
+#define FCN_EE_VPD_CFG_REG 0x0140
+#define FCN_EE_VPD_EN_LBN 0
+#define FCN_EE_VPD_EN_WIDTH 1
+#define FCN_EE_VPD_EN_AD9_MODE_LBN 1
+#define FCN_EE_VPD_EN_AD9_MODE_WIDTH 1
+#define FCN_EE_EE_CLOCK_DIV_LBN 112
+#define FCN_EE_EE_CLOCK_DIV_WIDTH 7
+#define FCN_EE_SF_CLOCK_DIV_LBN 120
+#define FCN_EE_SF_CLOCK_DIV_WIDTH 7
+
/* NIC status register */
#define FCN_NIC_STAT_REG 0x0200
-#define ONCHIP_SRAM_LBN 16
-#define ONCHIP_SRAM_WIDTH 1
-#define SF_PRST_LBN 9
-#define SF_PRST_WIDTH 1
-#define EE_PRST_LBN 8
-#define EE_PRST_WIDTH 1
-#define EE_STRAP_LBN 7
-#define EE_STRAP_WIDTH 1
-#define PCI_PCIX_MODE_LBN 4
-#define PCI_PCIX_MODE_WIDTH 3
-#define PCI_PCIX_MODE_PCI33_DECODE 0
-#define PCI_PCIX_MODE_PCI66_DECODE 1
-#define PCI_PCIX_MODE_PCIX66_DECODE 5
-#define PCI_PCIX_MODE_PCIX100_DECODE 6
-#define PCI_PCIX_MODE_PCIX133_DECODE 7
-#define STRAP_ISCSI_EN_LBN 3
-#define STRAP_ISCSI_EN_WIDTH 1
-#define STRAP_PINS_LBN 0
-#define STRAP_PINS_WIDTH 3
-/* These bit definitions are extrapolated from the list of numerical
- * values for STRAP_PINS. If you want a laugh, read the datasheet's
- * definition for when bits 2:0 are set to 7.
- */
-#define STRAP_10G_LBN 2
-#define STRAP_10G_WIDTH 1
-#define STRAP_DUAL_PORT_LBN 1
-#define STRAP_DUAL_PORT_WIDTH 1
-#define STRAP_PCIE_LBN 0
-#define STRAP_PCIE_WIDTH 1
+#define FCN_ONCHIP_SRAM_LBN 16
+#define FCN_ONCHIP_SRAM_WIDTH 1
+#define FCN_SF_PRST_LBN 9
+#define FCN_SF_PRST_WIDTH 1
+#define FCN_EE_PRST_LBN 8
+#define FCN_EE_PRST_WIDTH 1
+#define FCN_EE_STRAP_LBN 7
+#define FCN_EE_STRAP_WIDTH 1
+#define FCN_PCI_PCIX_MODE_LBN 4
+#define FCN_PCI_PCIX_MODE_WIDTH 3
+#define FCN_PCI_PCIX_MODE_PCI33_DECODE 0
+#define FCN_PCI_PCIX_MODE_PCI66_DECODE 1
+#define FCN_PCI_PCIX_MODE_PCIX66_DECODE 5
+#define FCN_PCI_PCIX_MODE_PCIX100_DECODE 6
+#define FCN_PCI_PCIX_MODE_PCIX133_DECODE 7
+#define FCN_STRAP_ISCSI_EN_LBN 3
+#define FCN_STRAP_ISCSI_EN_WIDTH 1
+#define FCN_STRAP_PINS_LBN 0
+#define FCN_STRAP_PINS_WIDTH 3
+#define FCN_STRAP_10G_LBN 2
+#define FCN_STRAP_10G_WIDTH 1
+#define FCN_STRAP_DUAL_PORT_LBN 1
+#define FCN_STRAP_DUAL_PORT_WIDTH 1
+#define FCN_STRAP_PCIE_LBN 0
+#define FCN_STRAP_PCIE_WIDTH 1
+
+/* Falcon revisions */
+#define FALCON_REV_A0 0
+#define FALCON_REV_A1 1
+#define FALCON_REV_B0 2
/* GPIO control register */
#define FCN_GPIO_CTL_REG_KER 0x0210
+#define FCN_GPIO_CTL_REG_KER 0x0210
+
+#define FCN_GPIO3_OEN_LBN 27
+#define FCN_GPIO3_OEN_WIDTH 1
+#define FCN_GPIO2_OEN_LBN 26
+#define FCN_GPIO2_OEN_WIDTH 1
+#define FCN_GPIO1_OEN_LBN 25
+#define FCN_GPIO1_OEN_WIDTH 1
+#define FCN_GPIO0_OEN_LBN 24
+#define FCN_GPIO0_OEN_WIDTH 1
+
+#define FCN_GPIO3_OUT_LBN 19
+#define FCN_GPIO3_OUT_WIDTH 1
+#define FCN_GPIO2_OUT_LBN 18
+#define FCN_GPIO2_OUT_WIDTH 1
+#define FCN_GPIO1_OUT_LBN 17
+#define FCN_GPIO1_OUT_WIDTH 1
+#define FCN_GPIO0_OUT_LBN 16
+#define FCN_GPIO0_OUT_WIDTH 1
+
+#define FCN_GPIO3_IN_LBN 11
+#define FCN_GPIO3_IN_WIDTH 1
+#define FCN_GPIO2_IN_LBN 10
+#define FCN_GPIO2_IN_WIDTH 1
+#define FCN_GPIO1_IN_LBN 9
+#define FCN_GPIO1_IN_WIDTH 1
+#define FCN_GPIO0_IN_LBN 8
+#define FCN_GPIO0_IN_WIDTH 1
+
#define FCN_FLASH_PRESENT_LBN 7
#define FCN_FLASH_PRESENT_WIDTH 1
#define FCN_EEPROM_PRESENT_LBN 6
#define FCN_EEPROM_PRESENT_WIDTH 1
+#define FCN_BOOTED_USING_NVDEVICE_LBN 3
+#define FCN_BOOTED_USING_NVDEVICE_WIDTH 1
+
+/* Defines for extra non-volatile storage */
+#define FCN_NV_MAGIC_NUMBER 0xFA1C
/* Global control register */
#define FCN_GLB_CTL_REG_KER 0x0220
-#define EXT_PHY_RST_CTL_LBN 63
-#define EXT_PHY_RST_CTL_WIDTH 1
-#define PCIE_SD_RST_CTL_LBN 61
-#define PCIE_SD_RST_CTL_WIDTH 1
-#define PCIX_RST_CTL_LBN 60
-#define PCIX_RST_CTL_WIDTH 1
-#define PCIE_STCK_RST_CTL_LBN 59
-#define PCIE_STCK_RST_CTL_WIDTH 1
-#define PCIE_NSTCK_RST_CTL_LBN 58
-#define PCIE_NSTCK_RST_CTL_WIDTH 1
-#define PCIE_CORE_RST_CTL_LBN 57
-#define PCIE_CORE_RST_CTL_WIDTH 1
-#define EE_RST_CTL_LBN 49
-#define EE_RST_CTL_WIDTH 1
-#define CS_RST_CTL_LBN 48
-#define CS_RST_CTL_WIDTH 1
-#define RST_EXT_PHY_LBN 31
-#define RST_EXT_PHY_WIDTH 1
-#define INT_RST_DUR_LBN 4
-#define INT_RST_DUR_WIDTH 3
-#define EXT_PHY_RST_DUR_LBN 1
-#define EXT_PHY_RST_DUR_WIDTH 3
-#define SWRST_LBN 0
-#define SWRST_WIDTH 1
+#define FCN_EXT_PHY_RST_CTL_LBN 63
+#define FCN_EXT_PHY_RST_CTL_WIDTH 1
+#define FCN_PCIE_SD_RST_CTL_LBN 61
+#define FCN_PCIE_SD_RST_CTL_WIDTH 1
+#define FCN_PCIE_STCK_RST_CTL_LBN 59
+#define FCN_PCIE_STCK_RST_CTL_WIDTH 1
+#define FCN_PCIE_NSTCK_RST_CTL_LBN 58
+#define FCN_PCIE_NSTCK_RST_CTL_WIDTH 1
+#define FCN_PCIE_CORE_RST_CTL_LBN 57
+#define FCN_PCIE_CORE_RST_CTL_WIDTH 1
+#define FCN_EE_RST_CTL_LBN 49
+#define FCN_EE_RST_CTL_WIDTH 1
+#define FCN_RST_EXT_PHY_LBN 31
+#define FCN_RST_EXT_PHY_WIDTH 1
+#define FCN_EXT_PHY_RST_DUR_LBN 1
+#define FCN_EXT_PHY_RST_DUR_WIDTH 3
+#define FCN_SWRST_LBN 0
+#define FCN_SWRST_WIDTH 1
#define INCLUDE_IN_RESET 0
#define EXCLUDE_FROM_RESET 1
/* FPGA build version */
-#define ALTERA_BUILD_REG_KER 0x0300
-#define VER_MAJOR_LBN 24
-#define VER_MAJOR_WIDTH 8
-#define VER_MINOR_LBN 16
-#define VER_MINOR_WIDTH 8
-#define VER_BUILD_LBN 0
-#define VER_BUILD_WIDTH 16
-#define VER_ALL_LBN 0
-#define VER_ALL_WIDTH 32
+#define FCN_ALTERA_BUILD_REG_KER 0x0300
+#define FCN_VER_MAJOR_LBN 24
+#define FCN_VER_MAJOR_WIDTH 8
+#define FCN_VER_MINOR_LBN 16
+#define FCN_VER_MINOR_WIDTH 8
+#define FCN_VER_BUILD_LBN 0
+#define FCN_VER_BUILD_WIDTH 16
+#define FCN_VER_ALL_LBN 0
+#define FCN_VER_ALL_WIDTH 32
+
+/* Spare EEPROM bits register (flash 0x390) */
+#define FCN_SPARE_REG_KER 0x310
+#define FCN_MEM_PERR_EN_TX_DATA_LBN 72
+#define FCN_MEM_PERR_EN_TX_DATA_WIDTH 2
/* Timer table for kernel access */
#define FCN_TIMER_CMD_REG_KER 0x420
@@ -1657,10 +647,65 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_SRM_TX_DC_BASE_ADR_LBN 0
#define FCN_SRM_TX_DC_BASE_ADR_WIDTH 21
+/* SRAM configuration register */
+#define FCN_SRM_CFG_REG_KER 0x630
+#define FCN_SRAM_OOB_ADR_INTEN_LBN 5
+#define FCN_SRAM_OOB_ADR_INTEN_WIDTH 1
+#define FCN_SRAM_OOB_BUF_INTEN_LBN 4
+#define FCN_SRAM_OOB_BUF_INTEN_WIDTH 1
+#define FCN_SRAM_OOB_BT_INIT_EN_LBN 3
+#define FCN_SRAM_OOB_BT_INIT_EN_WIDTH 1
+#define FCN_SRM_NUM_BANK_LBN 2
+#define FCN_SRM_NUM_BANK_WIDTH 1
+#define FCN_SRM_BANK_SIZE_LBN 0
+#define FCN_SRM_BANK_SIZE_WIDTH 2
+#define FCN_SRM_NUM_BANKS_AND_BANK_SIZE_LBN 0
+#define FCN_SRM_NUM_BANKS_AND_BANK_SIZE_WIDTH 3
+
+#define FCN_RX_CFG_REG_KER 0x800
+#define FCN_RX_INGR_EN_B0_LBN 47
+#define FCN_RX_INGR_EN_B0_WIDTH 1
+#define FCN_RX_USR_BUF_SIZE_B0_LBN 19
+#define FCN_RX_USR_BUF_SIZE_B0_WIDTH 9
+#define FCN_RX_XON_MAC_TH_B0_LBN 10
+#define FCN_RX_XON_MAC_TH_B0_WIDTH 9
+#define FCN_RX_XOFF_MAC_TH_B0_LBN 1
+#define FCN_RX_XOFF_MAC_TH_B0_WIDTH 9
+#define FCN_RX_XOFF_MAC_EN_B0_LBN 0
+#define FCN_RX_XOFF_MAC_EN_B0_WIDTH 1
+#define FCN_RX_USR_BUF_SIZE_A1_LBN 11
+#define FCN_RX_USR_BUF_SIZE_A1_WIDTH 9
+#define FCN_RX_XON_MAC_TH_A1_LBN 6
+#define FCN_RX_XON_MAC_TH_A1_WIDTH 5
+#define FCN_RX_XOFF_MAC_TH_A1_LBN 1
+#define FCN_RX_XOFF_MAC_TH_A1_WIDTH 5
+#define FCN_RX_XOFF_MAC_EN_A1_LBN 0
+#define FCN_RX_XOFF_MAC_EN_A1_WIDTH 1
+
+#define FCN_RX_USR_BUF_SIZE_A1_LBN 11
+#define FCN_RX_USR_BUF_SIZE_A1_WIDTH 9
+#define FCN_RX_XOFF_MAC_EN_A1_LBN 0
+#define FCN_RX_XOFF_MAC_EN_A1_WIDTH 1
+
/* Receive filter control register */
#define FCN_RX_FILTER_CTL_REG_KER 0x810
+#define FCN_UDP_FULL_SRCH_LIMIT_LBN 32
+#define FCN_UDP_FULL_SRCH_LIMIT_WIDTH 8
#define FCN_NUM_KER_LBN 24
#define FCN_NUM_KER_WIDTH 2
+#define FCN_UDP_WILD_SRCH_LIMIT_LBN 16
+#define FCN_UDP_WILD_SRCH_LIMIT_WIDTH 8
+#define FCN_TCP_WILD_SRCH_LIMIT_LBN 8
+#define FCN_TCP_WILD_SRCH_LIMIT_WIDTH 8
+#define FCN_TCP_FULL_SRCH_LIMIT_LBN 0
+#define FCN_TCP_FULL_SRCH_LIMIT_WIDTH 8
+
+/* RX queue flush register */
+#define FCN_RX_FLUSH_DESCQ_REG_KER 0x0820
+#define FCN_RX_FLUSH_DESCQ_CMD_LBN 24
+#define FCN_RX_FLUSH_DESCQ_CMD_WIDTH 1
+#define FCN_RX_FLUSH_DESCQ_LBN 0
+#define FCN_RX_FLUSH_DESCQ_WIDTH 12
/* Receive descriptor update register */
#define FCN_RX_DESC_UPD_REG_KER 0x0830
@@ -1675,6 +720,26 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_RX_DC_SIZE_LBN 0
#define FCN_RX_DC_SIZE_WIDTH 2
+#define FCN_RX_SELF_RST_REG_KER 0x890
+#define FCN_RX_ISCSI_DIS_LBN 17
+#define FCN_RX_ISCSI_DIS_WIDTH 1
+#define FCN_RX_NODESC_WAIT_DIS_LBN 9
+#define FCN_RX_NODESC_WAIT_DIS_WIDTH 1
+#define FCN_RX_RECOVERY_EN_LBN 8
+#define FCN_RX_RECOVERY_EN_WIDTH 1
+
+/* TX queue flush register */
+#define FCN_TX_FLUSH_DESCQ_REG_KER 0x0a00
+#define FCN_TX_FLUSH_DESCQ_CMD_LBN 12
+#define FCN_TX_FLUSH_DESCQ_CMD_WIDTH 1
+#define FCN_TX_FLUSH_DESCQ_LBN 0
+#define FCN_TX_FLUSH_DESCQ_WIDTH 12
+
+/* Transmit configuration register 2 */
+#define FCN_TX_CFG2_REG_KER 0xa80
+#define FCN_TX_DIS_NON_IP_EV_LBN 17
+#define FCN_TX_DIS_NON_IP_EV_WIDTH 1
+
/* Transmit descriptor update register */
#define FCN_TX_DESC_UPD_REG_KER 0x0a10
#define FCN_TX_DESC_WPTR_LBN 96
@@ -1704,6 +769,8 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_MD_GC_WIDTH 1
#define FCN_MD_RIC_LBN 2
#define FCN_MD_RIC_WIDTH 1
+#define FCN_MD_RDC_LBN 1
+#define FCN_MD_RDC_WIDTH 1
#define FCN_MD_WRC_LBN 0
#define FCN_MD_WRC_WIDTH 1
@@ -1721,6 +788,14 @@ static struct efab_mac_operations ef1002_mac_operations = {
/* PHY management status & mask register */
#define FCN_MD_STAT_REG_KER 0xc50
+#define FCN_MD_PINT_LBN 4
+#define FCN_MD_PINT_WIDTH 1
+#define FCN_MD_DONE_LBN 3
+#define FCN_MD_DONE_WIDTH 1
+#define FCN_MD_BSERR_LBN 2
+#define FCN_MD_BSERR_WIDTH 1
+#define FCN_MD_LNFL_LBN 1
+#define FCN_MD_LNFL_WIDTH 1
#define FCN_MD_BSY_LBN 0
#define FCN_MD_BSY_WIDTH 1
@@ -1738,6 +813,11 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_MAC_SPEED_LBN 0
#define FCN_MAC_SPEED_WIDTH 2
+/* 10Gig Xaui XGXS Default Values */
+#define XX_TXDRV_DEQ_DEFAULT 0xe /* deq=.6 */
+#define XX_TXDRV_DTX_DEFAULT 0x5 /* 1.25 */
+#define XX_SD_CTL_DRV_DEFAULT 0 /* 20mA */
+
/* GMAC registers */
#define FALCON_GMAC_REGBANK 0xe00
#define FALCON_GMAC_REGBANK_SIZE 0x200
@@ -1801,18 +881,45 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_XM_RXEN_LBN 1
#define FCN_XM_RXEN_WIDTH 1
+/* XGMAC management interrupt mask register */
+#define FCN_XM_MGT_INT_MSK_REG_MAC_B0 0x5
+#define FCN_XM_MSK_PRMBLE_ERR_LBN 2
+#define FCN_XM_MSK_PRMBLE_ERR_WIDTH 1
+#define FCN_XM_MSK_RMTFLT_LBN 1
+#define FCN_XM_MSK_RMTFLT_WIDTH 1
+#define FCN_XM_MSK_LCLFLT_LBN 0
+#define FCN_XM_MSK_LCLFLT_WIDTH 1
+
+/* XGMAC flow control register */
+#define FCN_XM_FC_REG_MAC 0x7
+#define FCN_XM_PAUSE_TIME_LBN 16
+#define FCN_XM_PAUSE_TIME_WIDTH 16
+#define FCN_XM_DIS_FCNTL_LBN 0
+#define FCN_XM_DIS_FCNTL_WIDTH 1
+
/* XGMAC transmit parameter register */
#define FCN_XM_TX_PARAM_REG_MAC 0x0d
#define FCN_XM_TX_JUMBO_MODE_LBN 31
#define FCN_XM_TX_JUMBO_MODE_WIDTH 1
#define FCN_XM_MAX_TX_FRM_SIZE_LBN 16
#define FCN_XM_MAX_TX_FRM_SIZE_WIDTH 14
+#define FCN_XM_ACPT_ALL_MCAST_LBN 11
+#define FCN_XM_ACPT_ALL_MCAST_WIDTH 1
/* XGMAC receive parameter register */
#define FCN_XM_RX_PARAM_REG_MAC 0x0e
#define FCN_XM_MAX_RX_FRM_SIZE_LBN 0
#define FCN_XM_MAX_RX_FRM_SIZE_WIDTH 14
+/* XGMAC management interrupt status register */
+#define FCN_XM_MGT_INT_REG_MAC_B0 0x0f
+#define FCN_XM_PRMBLE_ERR 2
+#define FCN_XM_PRMBLE_WIDTH 1
+#define FCN_XM_RMTFLT_LBN 1
+#define FCN_XM_RMTFLT_WIDTH 1
+#define FCN_XM_LCLFLT_LBN 0
+#define FCN_XM_LCLFLT_WIDTH 1
+
/* XAUI XGXS core status register */
#define FCN_XX_ALIGN_DONE_LBN 20
#define FCN_XX_ALIGN_DONE_WIDTH 1
@@ -1823,10 +930,35 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_XX_COMMA_DET_LBN 12
#define FCN_XX_COMMA_DET_WIDTH 4
#define FCN_XX_COMMA_DET_RESET 0xf
-
+#define FCN_XX_CHARERR_LBN 4
+#define FCN_XX_CHARERR_WIDTH 4
+#define FCN_XX_CHARERR_RESET 0xf
+#define FCN_XX_DISPERR_LBN 0
+#define FCN_XX_DISPERR_WIDTH 4
+#define FCN_XX_DISPERR_RESET 0xf
/* XGXS/XAUI powerdown/reset register */
#define FCN_XX_PWR_RST_REG_MAC 0x10
+#define FCN_XX_PWRDND_EN_LBN 15
+#define FCN_XX_PWRDND_EN_WIDTH 1
+#define FCN_XX_PWRDNC_EN_LBN 14
+#define FCN_XX_PWRDNC_EN_WIDTH 1
+#define FCN_XX_PWRDNB_EN_LBN 13
+#define FCN_XX_PWRDNB_EN_WIDTH 1
+#define FCN_XX_PWRDNA_EN_LBN 12
+#define FCN_XX_PWRDNA_EN_WIDTH 1
+#define FCN_XX_RSTPLLCD_EN_LBN 9
+#define FCN_XX_RSTPLLCD_EN_WIDTH 1
+#define FCN_XX_RSTPLLAB_EN_LBN 8
+#define FCN_XX_RSTPLLAB_EN_WIDTH 1
+#define FCN_XX_RESETD_EN_LBN 7
+#define FCN_XX_RESETD_EN_WIDTH 1
+#define FCN_XX_RESETC_EN_LBN 6
+#define FCN_XX_RESETC_EN_WIDTH 1
+#define FCN_XX_RESETB_EN_LBN 5
+#define FCN_XX_RESETB_EN_WIDTH 1
+#define FCN_XX_RESETA_EN_LBN 4
+#define FCN_XX_RESETA_EN_WIDTH 1
#define FCN_XX_RSTXGXSRX_EN_LBN 2
#define FCN_XX_RSTXGXSRX_EN_WIDTH 1
#define FCN_XX_RSTXGXSTX_EN_LBN 1
@@ -1834,8 +966,66 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_XX_RST_XX_EN_LBN 0
#define FCN_XX_RST_XX_EN_WIDTH 1
+
+/* XGXS/XAUI powerdown/reset control register */
+#define FCN_XX_SD_CTL_REG_MAC 0x11
+#define FCN_XX_TERMADJ1_LBN 17
+#define FCN_XX_TERMADJ1_WIDTH 1
+#define FCN_XX_TERMADJ0_LBN 16
+#define FCN_XX_TERMADJ0_WIDTH 1
+#define FCN_XX_HIDRVD_LBN 15
+#define FCN_XX_HIDRVD_WIDTH 1
+#define FCN_XX_LODRVD_LBN 14
+#define FCN_XX_LODRVD_WIDTH 1
+#define FCN_XX_HIDRVC_LBN 13
+#define FCN_XX_HIDRVC_WIDTH 1
+#define FCN_XX_LODRVC_LBN 12
+#define FCN_XX_LODRVC_WIDTH 1
+#define FCN_XX_HIDRVB_LBN 11
+#define FCN_XX_HIDRVB_WIDTH 1
+#define FCN_XX_LODRVB_LBN 10
+#define FCN_XX_LODRVB_WIDTH 1
+#define FCN_XX_HIDRVA_LBN 9
+#define FCN_XX_HIDRVA_WIDTH 1
+#define FCN_XX_LODRVA_LBN 8
+#define FCN_XX_LODRVA_WIDTH 1
+#define FCN_XX_LPBKD_LBN 3
+#define FCN_XX_LPBKD_WIDTH 1
+#define FCN_XX_LPBKC_LBN 2
+#define FCN_XX_LPBKC_WIDTH 1
+#define FCN_XX_LPBKB_LBN 1
+#define FCN_XX_LPBKB_WIDTH 1
+#define FCN_XX_LPBKA_LBN 0
+#define FCN_XX_LPBKA_WIDTH 1
+
+#define FCN_XX_TXDRV_CTL_REG_MAC 0x12
+#define FCN_XX_DEQD_LBN 28
+#define FCN_XX_DEQD_WIDTH 4
+#define FCN_XX_DEQC_LBN 24
+#define FCN_XX_DEQC_WIDTH 4
+#define FCN_XX_DEQB_LBN 20
+#define FCN_XX_DEQB_WIDTH 4
+#define FCN_XX_DEQA_LBN 16
+#define FCN_XX_DEQA_WIDTH 4
+#define FCN_XX_DTXD_LBN 12
+#define FCN_XX_DTXD_WIDTH 4
+#define FCN_XX_DTXC_LBN 8
+#define FCN_XX_DTXC_WIDTH 4
+#define FCN_XX_DTXB_LBN 4
+#define FCN_XX_DTXB_WIDTH 4
+#define FCN_XX_DTXA_LBN 0
+#define FCN_XX_DTXA_WIDTH 4
+
+/* Receive filter table */
+#define FCN_RX_FILTER_TBL0 0xF00000
+
/* Receive descriptor pointer table */
-#define FCN_RX_DESC_PTR_TBL_KER 0x11800
+#define FCN_RX_DESC_PTR_TBL_KER_A1 0x11800
+#define FCN_RX_DESC_PTR_TBL_KER_B0 0xF40000
+#define FCN_RX_ISCSI_DDIG_EN_LBN 88
+#define FCN_RX_ISCSI_DDIG_EN_WIDTH 1
+#define FCN_RX_ISCSI_HDIG_EN_LBN 87
+#define FCN_RX_ISCSI_HDIG_EN_WIDTH 1
#define FCN_RX_DESCQ_BUF_BASE_ID_LBN 36
#define FCN_RX_DESCQ_BUF_BASE_ID_WIDTH 20
#define FCN_RX_DESCQ_EVQ_ID_LBN 24
@@ -1856,9 +1046,16 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_RX_DESCQ_EN_WIDTH 1
/* Transmit descriptor pointer table */
-#define FCN_TX_DESC_PTR_TBL_KER 0x11900
+#define FCN_TX_DESC_PTR_TBL_KER_A1 0x11900
+#define FCN_TX_DESC_PTR_TBL_KER_B0 0xF50000
+#define FCN_TX_NON_IP_DROP_DIS_B0_LBN 91
+#define FCN_TX_NON_IP_DROP_DIS_B0_WIDTH 1
#define FCN_TX_DESCQ_EN_LBN 88
#define FCN_TX_DESCQ_EN_WIDTH 1
+#define FCN_TX_ISCSI_DDIG_EN_LBN 87
+#define FCN_TX_ISCSI_DDIG_EN_WIDTH 1
+#define FCN_TX_ISCSI_HDIG_EN_LBN 86
+#define FCN_TX_ISCSI_HDIG_EN_WIDTH 1
#define FCN_TX_DESCQ_BUF_BASE_ID_LBN 36
#define FCN_TX_DESCQ_BUF_BASE_ID_WIDTH 20
#define FCN_TX_DESCQ_EVQ_ID_LBN 24
@@ -1877,7 +1074,8 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_TX_DESCQ_FLUSH_WIDTH 1
/* Event queue pointer */
-#define FCN_EVQ_PTR_TBL_KER 0x11a00
+#define FCN_EVQ_PTR_TBL_KER_A1 0x11a00
+#define FCN_EVQ_PTR_TBL_KER_B0 0xf60000
#define FCN_EVQ_EN_LBN 23
#define FCN_EVQ_EN_WIDTH 1
#define FCN_EVQ_SIZE_LBN 20
@@ -1892,16 +1090,22 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_EVQ_BUF_BASE_ID_LBN 0
#define FCN_EVQ_BUF_BASE_ID_WIDTH 20
+/* RSS indirection table */
+#define FCN_RX_RSS_INDIR_TBL_B0 0xFB0000
+
/* Event queue read pointer */
-#define FCN_EVQ_RPTR_REG_KER 0x11b00
+#define FCN_EVQ_RPTR_REG_KER_A1 0x11b00
+#define FCN_EVQ_RPTR_REG_KER_B0 0xfa0000
#define FCN_EVQ_RPTR_LBN 0
#define FCN_EVQ_RPTR_WIDTH 14
-#define FCN_EVQ_RPTR_REG_KER_DWORD ( FCN_EVQ_RPTR_REG_KER + 0 )
+#define FCN_EVQ_RPTR_REG_KER_DWORD_A1 ( FCN_EVQ_RPTR_REG_KER_A1 + 0 )
+#define FCN_EVQ_RPTR_REG_KER_DWORD_B0 ( FCN_EVQ_RPTR_REG_KER_B0 + 0 )
#define FCN_EVQ_RPTR_DWORD_LBN 0
#define FCN_EVQ_RPTR_DWORD_WIDTH 14
/* Special buffer descriptors */
-#define FCN_BUF_FULL_TBL_KER 0x18000
+#define FCN_BUF_FULL_TBL_KER_A1 0x18000
+#define FCN_BUF_FULL_TBL_KER_B0 0x800000
#define FCN_IP_DAT_BUF_SIZE_LBN 50
#define FCN_IP_DAT_BUF_SIZE_WIDTH 1
#define FCN_IP_DAT_BUF_SIZE_8K 1
@@ -1914,13 +1118,11 @@ static struct efab_mac_operations ef1002_mac_operations = {
/** Offset of a GMAC register within Falcon */
#define FALCON_GMAC_REG( efab, mac_reg ) \
( FALCON_GMAC_REGBANK + \
- ( (efab)->port * FALCON_GMAC_REGBANK_SIZE ) + \
( (mac_reg) * FALCON_GMAC_REG_SIZE ) )
/** Offset of an XMAC register within Falcon */
#define FALCON_XMAC_REG( efab_port, mac_reg ) \
( FALCON_XMAC_REGBANK + \
- ( (efab_port)->port * FALCON_XMAC_REGBANK_SIZE ) + \
( (mac_reg) * FALCON_XMAC_REG_SIZE ) )
#define FCN_MAC_DATA_LBN 0
@@ -1962,10 +1164,22 @@ static struct efab_mac_operations ef1002_mac_operations = {
#define FCN_TX_EV_DESC_PTR_LBN 0
#define FCN_TX_EV_DESC_PTR_WIDTH 12
-/* Fixed special buffer numbers to use */
-#define FALCON_EVQ_ID 0
-#define FALCON_TXD_ID 1
-#define FALCON_RXD_ID 2
+/*******************************************************************************
+ *
+ *
+ * Low-level hardware access
+ *
+ *
+ *******************************************************************************/
+
+#define FCN_REVISION_REG(efab, reg) \
+ ( ( efab->pci_revision == FALCON_REV_B0 ) ? reg ## _B0 : reg ## _A1 )
+
+#define EFAB_SET_OWORD_FIELD_VER(efab, reg, field, val) \
+ if ( efab->pci_revision == FALCON_REV_B0 ) \
+ EFAB_SET_OWORD_FIELD ( reg, field ## _B0, val ); \
+ else \
+ EFAB_SET_OWORD_FIELD ( reg, field ## _A1, val );
#if FALCON_USE_IO_BAR
@@ -1995,8 +1209,9 @@ static inline uint32_t _falcon_readl ( struct efab_nic *efab,
* Write to a Falcon register
*
*/
-static inline void falcon_write ( struct efab_nic *efab, efab_oword_t *value,
- unsigned int reg ) {
+static inline void
+falcon_write ( struct efab_nic *efab, efab_oword_t *value, unsigned int reg )
+{
EFAB_REGDUMP ( "Writing register %x with " EFAB_OWORD_FMT "\n",
reg, EFAB_OWORD_VAL ( *value ) );
@@ -2004,6 +1219,7 @@ static inline void falcon_write ( struct efab_nic *efab, efab_oword_t *value,
_falcon_writel ( efab, value->u32[0], reg + 0 );
_falcon_writel ( efab, value->u32[1], reg + 4 );
_falcon_writel ( efab, value->u32[2], reg + 8 );
+ wmb();
_falcon_writel ( efab, value->u32[3], reg + 12 );
wmb();
}
@@ -2012,10 +1228,11 @@ static inline void falcon_write ( struct efab_nic *efab, efab_oword_t *value,
* Write to Falcon SRAM
*
*/
-static inline void falcon_write_sram ( struct efab_nic *efab,
- efab_qword_t *value,
- unsigned int index ) {
- unsigned int reg = ( FCN_BUF_FULL_TBL_KER +
+static inline void
+falcon_write_sram ( struct efab_nic *efab, efab_qword_t *value,
+ unsigned int index )
+{
+ unsigned int reg = ( FCN_REVISION_REG ( efab, FCN_BUF_FULL_TBL_KER ) +
( index * sizeof ( *value ) ) );
EFAB_REGDUMP ( "Writing SRAM register %x with " EFAB_QWORD_FMT "\n",
@@ -2030,8 +1247,9 @@ static inline void falcon_write_sram ( struct efab_nic *efab,
* Write dword to Falcon register that allows partial writes
*
*/
-static inline void falcon_writel ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int reg ) {
+static inline void
+falcon_writel ( struct efab_nic *efab, efab_dword_t *value, unsigned int reg )
+{
EFAB_REGDUMP ( "Writing partial register %x with " EFAB_DWORD_FMT "\n",
reg, EFAB_DWORD_VAL ( *value ) );
_falcon_writel ( efab, value->u32[0], reg );
@@ -2041,9 +1259,11 @@ static inline void falcon_writel ( struct efab_nic *efab, efab_dword_t *value,
* Read from a Falcon register
*
*/
-static inline void falcon_read ( struct efab_nic *efab, efab_oword_t *value,
- unsigned int reg ) {
+static inline void
+falcon_read ( struct efab_nic *efab, efab_oword_t *value, unsigned int reg )
+{
value->u32[0] = _falcon_readl ( efab, reg + 0 );
+ wmb();
value->u32[1] = _falcon_readl ( efab, reg + 4 );
value->u32[2] = _falcon_readl ( efab, reg + 8 );
value->u32[3] = _falcon_readl ( efab, reg + 12 );
@@ -2056,10 +1276,11 @@ static inline void falcon_read ( struct efab_nic *efab, efab_oword_t *value,
* Read from Falcon SRAM
*
*/
-static inline void falcon_read_sram ( struct efab_nic *efab,
- efab_qword_t *value,
- unsigned int index ) {
- unsigned int reg = ( FCN_BUF_FULL_TBL_KER +
+static inline void
+falcon_read_sram ( struct efab_nic *efab, efab_qword_t *value,
+ unsigned int index )
+{
+ unsigned int reg = ( FCN_REVISION_REG ( efab, FCN_BUF_FULL_TBL_KER ) +
( index * sizeof ( *value ) ) );
value->u32[0] = _falcon_readl ( efab, reg + 0 );
@@ -2072,44 +1293,14 @@ static inline void falcon_read_sram ( struct efab_nic *efab,
* Read dword from a portion of a Falcon register
*
*/
-static inline void falcon_readl ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int reg ) {
+static inline void
+falcon_readl ( struct efab_nic *efab, efab_dword_t *value, unsigned int reg )
+{
value->u32[0] = _falcon_readl ( efab, reg );
EFAB_REGDUMP ( "Read from register %x, got " EFAB_DWORD_FMT "\n",
reg, EFAB_DWORD_VAL ( *value ) );
}
-/**
- * Verified write to Falcon SRAM
- *
- */
-static inline void falcon_write_sram_verify ( struct efab_nic *efab,
- efab_qword_t *value,
- unsigned int index ) {
- efab_qword_t verify;
-
- falcon_write_sram ( efab, value, index );
- udelay ( 1000 );
- falcon_read_sram ( efab, &verify, index );
- if ( memcmp ( &verify, value, sizeof ( verify ) ) != 0 ) {
- EFAB_ERR ( "SRAM index %x failure: wrote " EFAB_QWORD_FMT
- " got " EFAB_QWORD_FMT "\n", index,
- EFAB_QWORD_VAL ( *value ),
- EFAB_QWORD_VAL ( verify ) );
- }
-}
-
-/**
- * Get memory base
- *
- */
-static void falcon_get_membase ( struct efab_nic *efab ) {
- unsigned long membase_phys;
-
- membase_phys = pci_bar_start ( efab->pci, PCI_BASE_ADDRESS_2 );
- efab->membase = ioremap ( membase_phys, 0x20000 );
-}
-
#define FCN_DUMP_REG( efab, _reg ) do { \
efab_oword_t reg; \
falcon_read ( efab, &reg, _reg ); \
@@ -2125,12 +1316,47 @@ static void falcon_get_membase ( struct efab_nic *efab ) {
} while ( 0 );
/**
+ * See if an event is present
+ *
+ * @v event Falcon event structure
+ * @ret True An event is pending
+ * @ret False No event is pending
+ *
+ * We check both the high and low dword of the event for all ones. We
+ * wrote all ones when we cleared the event, and no valid event can
+ * have all ones in either its high or low dwords. This approach is
+ * robust against reordering.
+ *
+ * Note that using a single 64-bit comparison is incorrect; even
+ * though the CPU read will be atomic, the DMA write may not be.
+ */
+static inline int
+falcon_event_present ( falcon_event_t* event )
+{
+ return ( ! ( EFAB_DWORD_IS_ALL_ONES ( event->dword[0] ) |
+ EFAB_DWORD_IS_ALL_ONES ( event->dword[1] ) ) );
+}
+
+static void
+falcon_eventq_read_ack ( struct efab_nic *efab, struct efab_ev_queue *ev_queue )
+{
+ efab_dword_t reg;
+
+ EFAB_POPULATE_DWORD_1 ( reg, FCN_EVQ_RPTR_DWORD, ev_queue->read_ptr );
+ falcon_writel ( efab, &reg,
+ FCN_REVISION_REG ( efab, FCN_EVQ_RPTR_REG_KER_DWORD ) );
+}
+
+#if 0
+/**
* Dump register contents (for debugging)
*
* Marked as static inline so that it will not be compiled in if not
* used.
*/
-static inline void falcon_dump_regs ( struct efab_nic *efab ) {
+static inline void
+falcon_dump_regs ( struct efab_nic *efab )
+{
FCN_DUMP_REG ( efab, FCN_INT_EN_REG_KER );
FCN_DUMP_REG ( efab, FCN_INT_ADR_REG_KER );
FCN_DUMP_REG ( efab, FCN_GLB_CTL_REG_KER );
@@ -2142,9 +1368,9 @@ static inline void falcon_dump_regs ( struct efab_nic *efab ) {
FCN_DUMP_REG ( efab, FCN_TX_DC_CFG_REG_KER );
FCN_DUMP_REG ( efab, FCN_MAC0_CTRL_REG_KER );
FCN_DUMP_REG ( efab, FCN_MAC1_CTRL_REG_KER );
- FCN_DUMP_REG ( efab, FCN_RX_DESC_PTR_TBL_KER );
- FCN_DUMP_REG ( efab, FCN_TX_DESC_PTR_TBL_KER );
- FCN_DUMP_REG ( efab, FCN_EVQ_PTR_TBL_KER );
+ FCN_DUMP_REG ( efab, FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) );
+ FCN_DUMP_REG ( efab, FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) );
+ FCN_DUMP_REG ( efab, FCN_REVISION_REG ( efab, FCN_EVQ_PTR_TBL_KER ) );
FCN_DUMP_MAC_REG ( efab, GM_CFG1_REG_MAC );
FCN_DUMP_MAC_REG ( efab, GM_CFG2_REG_MAC );
FCN_DUMP_MAC_REG ( efab, GM_MAX_FLEN_REG_MAC );
@@ -2158,391 +1384,356 @@ static inline void falcon_dump_regs ( struct efab_nic *efab ) {
FCN_DUMP_MAC_REG ( efab, GMF_CFG4_REG_MAC );
FCN_DUMP_MAC_REG ( efab, GMF_CFG5_REG_MAC );
}
+#endif
-/**
- * Create special buffer
- *
- */
-static void falcon_create_special_buffer ( struct efab_nic *efab,
- void *addr, unsigned int index ) {
- efab_qword_t buf_desc;
- unsigned long dma_addr;
+static void
+falcon_interrupts ( struct efab_nic *efab, int enabled, int force )
+{
+ efab_oword_t int_en_reg_ker;
- memset ( addr, 0, 4096 );
- dma_addr = virt_to_bus ( addr );
- EFAB_ASSERT ( ( dma_addr & ( EFAB_BUF_ALIGN - 1 ) ) == 0 );
- EFAB_POPULATE_QWORD_3 ( buf_desc,
- FCN_IP_DAT_BUF_SIZE, FCN_IP_DAT_BUF_SIZE_4K,
- FCN_BUF_ADR_FBUF, ( dma_addr >> 12 ),
- FCN_BUF_OWNER_ID_FBUF, 0 );
- falcon_write_sram_verify ( efab, &buf_desc, index );
+ EFAB_POPULATE_OWORD_2 ( int_en_reg_ker,
+ FCN_KER_INT_KER, force,
+ FCN_DRV_INT_EN_KER, enabled );
+ falcon_write ( efab, &int_en_reg_ker, FCN_INT_EN_REG_KER );
}
-/**
- * Update event queue read pointer
+/*******************************************************************************
*
- */
-static void falcon_eventq_read_ack ( struct efab_nic *efab ) {
- efab_dword_t reg;
-
- EFAB_ASSERT ( efab->eventq_read_ptr < EFAB_EVQ_SIZE );
-
- EFAB_POPULATE_DWORD_1 ( reg, FCN_EVQ_RPTR_DWORD,
- efab->eventq_read_ptr );
- falcon_writel ( efab, &reg, FCN_EVQ_RPTR_REG_KER_DWORD );
-}
-
-/**
- * Reset device
*
- */
-static int falcon_reset ( struct efab_nic *efab ) {
- efab_oword_t glb_ctl_reg_ker;
-
- /* Initiate software reset */
- EFAB_POPULATE_OWORD_7 ( glb_ctl_reg_ker,
- PCIE_CORE_RST_CTL, EXCLUDE_FROM_RESET,
- PCIE_NSTCK_RST_CTL, EXCLUDE_FROM_RESET,
- PCIE_SD_RST_CTL, EXCLUDE_FROM_RESET,
- EE_RST_CTL, EXCLUDE_FROM_RESET,
- PCIX_RST_CTL, EXCLUDE_FROM_RESET,
- EXT_PHY_RST_DUR, 0x7 /* datasheet recommended */,
- SWRST, 1 );
-
- falcon_write ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER );
-
- /* Allow 20ms for reset */
- mdelay ( 20 );
+ * SPI access
+ *
+ *
+ *******************************************************************************/
- /* Check for device reset complete */
- falcon_read ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER );
- if ( EFAB_OWORD_FIELD ( glb_ctl_reg_ker, SWRST ) != 0 ) {
- EFAB_ERR ( "Reset failed\n" );
- return 0;
- }
- return 1;
-}
+/** Maximum length for a single SPI transaction */
+#define FALCON_SPI_MAX_LEN 16
-/**
- * Wait for SPI command completion
- *
- */
-static int falcon_spi_wait ( struct efab_nic *efab ) {
+static int
+falcon_spi_wait ( struct efab_nic *efab )
+{
efab_oword_t reg;
int count;
count = 0;
do {
udelay ( 100 );
- falcon_read ( efab, &reg, FCN_EE_SPI_HCMD_REG_KER );
+ falcon_read ( efab, &reg, FCN_EE_SPI_HCMD_REG );
if ( EFAB_OWORD_FIELD ( reg, FCN_EE_SPI_HCMD_CMD_EN ) == 0 )
- return 1;
+ return 0;
} while ( ++count < 1000 );
- printf ( "Timed out waiting for SPI\n" );
- return 0;
+
+ EFAB_ERR ( "Timed out waiting for SPI\n" );
+ return -ETIMEDOUT;
}
-/**
- * Perform SPI read/write
- *
- */
-static int falcon_spi_rw ( struct spi_bus *bus, struct spi_device *device,
- unsigned int command, int address,
- const void *data_out, void *data_in, size_t len ) {
- struct efab_nic *efab = container_of ( bus, struct efab_nic, spi );
+static int
+falcon_spi_rw ( struct spi_bus* bus, struct spi_device *device,
+ unsigned int command, int address,
+ const void* data_out, void *data_in, size_t len )
+{
+ struct efab_nic *efab = container_of ( bus, struct efab_nic, spi_bus );
+ int address_len, rc, device_id, read_cmd;
efab_oword_t reg;
- /* Program address register */
- EFAB_POPULATE_OWORD_1 ( reg, FCN_EE_SPI_HADR_ADR, address );
- falcon_write ( efab, &reg, FCN_EE_SPI_HADR_REG_KER );
-
- /* Program data register, if applicable */
+ /* falcon_init_spi_device() should have reduced the block size
+ * down so this constraint holds */
+ assert ( len <= FALCON_SPI_MAX_LEN );
+
+ /* Is this the FLASH or EEPROM device? */
+ if ( device == &efab->spi_flash )
+ device_id = FCN_EE_SPI_FLASH;
+ else if ( device == &efab->spi_eeprom )
+ device_id = FCN_EE_SPI_EEPROM;
+ else {
+ EFAB_ERR ( "Unknown device %p\n", device );
+ return -EINVAL;
+ }
+
+ EFAB_TRACE ( "Executing spi command %d on device %d at %d for %zd bytes\n",
+ command, device_id, address, len );
+
+ /* The bus must be idle */
+ rc = falcon_spi_wait ( efab );
+ if ( rc )
+ goto fail1;
+
+ /* Copy data out */
if ( data_out ) {
memcpy ( &reg, data_out, len );
- falcon_write ( efab, &reg, FCN_EE_SPI_HDATA_REG_KER );
+ falcon_write ( efab, &reg, FCN_EE_SPI_HDATA_REG );
+ }
+
+ /* Program address register */
+ if ( address >= 0 ) {
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_EE_SPI_HADR_ADR, address );
+ falcon_write ( efab, &reg, FCN_EE_SPI_HADR_REG );
}
/* Issue command */
+ address_len = ( address >= 0 ) ? device->address_len / 8 : 0;
+ read_cmd = ( data_in ? FCN_EE_SPI_READ : FCN_EE_SPI_WRITE );
EFAB_POPULATE_OWORD_7 ( reg,
- FCN_EE_SPI_HCMD_CMD_EN, 1,
- FCN_EE_SPI_HCMD_SF_SEL, device->slave,
+ FCN_EE_SPI_HCMD_CMD_EN, 1,
+ FCN_EE_SPI_HCMD_SF_SEL, device_id,
FCN_EE_SPI_HCMD_DABCNT, len,
- FCN_EE_SPI_HCMD_READ, ( data_out ?
- FCN_EE_SPI_WRITE : FCN_EE_SPI_READ ),
+ FCN_EE_SPI_HCMD_READ, read_cmd,
FCN_EE_SPI_HCMD_DUBCNT, 0,
- FCN_EE_SPI_HCMD_ADBCNT,
- ( device->address_len / 8 ),
+ FCN_EE_SPI_HCMD_ADBCNT, address_len,
FCN_EE_SPI_HCMD_ENC, command );
- falcon_write ( efab, &reg, FCN_EE_SPI_HCMD_REG_KER );
-
- /* Wait for operation to complete */
- if ( ! falcon_spi_wait ( efab ) )
- return 0;
+ falcon_write ( efab, &reg, FCN_EE_SPI_HCMD_REG );
- /* Read data, if applicable */
+ /* Wait for the command to complete */
+ rc = falcon_spi_wait ( efab );
+ if ( rc )
+ goto fail2;
+
+ /* Copy data in */
if ( data_in ) {
- falcon_read ( efab, &reg, FCN_EE_SPI_HDATA_REG_KER );
+ falcon_read ( efab, &reg, FCN_EE_SPI_HDATA_REG );
memcpy ( data_in, &reg, len );
}
-
+
return 0;
-}
-/**
- * Initialise SPI bus and devices
- *
- */
-static void falcon_init_spi ( struct efab_nic *efab ) {
- efab_oword_t reg;
- int eeprom_9bit;
-
- /* Initialise SPI bus */
- efab->spi.rw = falcon_spi_rw;
- efab->falcon_eeprom.bus = &efab->spi;
- efab->falcon_eeprom.slave = FCN_EE_SPI_EEPROM;
- efab->falcon_flash.bus = &efab->spi;
- efab->falcon_flash.slave = FCN_EE_SPI_FLASH;
-
- /* Initialise flash if present */
- if ( efab->has_flash ) {
- DBG ( "Flash is present\n" );
- init_at25f1024 ( &efab->falcon_flash );
- }
-
- /* Initialise EEPROM if present */
- if ( efab->has_eeprom ) {
- if ( efab->is_asic ) {
- falcon_read ( efab, &reg, FCN_VPD_CONFIG_REG_KER );
- eeprom_9bit = EFAB_OWORD_FIELD ( reg, FCN_VPD_9BIT );
- } else {
- eeprom_9bit = 1;
- }
- if ( eeprom_9bit ) {
- DBG ( "Small EEPROM is present\n" );
- init_at25040 ( &efab->falcon_eeprom );
- } else {
- DBG ( "Large EEPROM is present\n" );
- init_mc25xx640 ( &efab->falcon_eeprom );
- /* Falcon's SPI interface cannot support a block
- size larger than 16, so forcibly reduce it
- */
- efab->falcon_eeprom.nvs.block_size = 16;
- }
- }
-}
+fail2:
+fail1:
+ EFAB_ERR ( "Failed SPI command %d to device %d address 0x%x len 0x%zx\n",
+ command, device_id, address, len );
-/** Offset of MAC address within EEPROM or Flash */
-#define FALCON_MAC_ADDRESS_OFFSET(port) ( 0x310 + 0x08 * (port) )
+ return rc;
+}
-static struct nvo_fragment falcon_eeprom_fragments[] = {
- { 0x100, 0x100 },
+/** Portion of EEPROM available for non-volatile options */
+static struct nvo_fragment falcon_nvo_fragments[] = {
+ { 0x100, 0xf0 },
{ 0, 0 }
};
-/**
- * Read MAC address from EEPROM
+/*******************************************************************************
*
- */
-static int falcon_read_eeprom ( struct efab_nic *efab ) {
- struct nvs_device *nvs;
-
- /* Determine the NVS device containing the MAC address */
- nvs = ( efab->has_flash ?
- &efab->falcon_flash.nvs : &efab->falcon_eeprom.nvs );
-
- return ( nvs_read ( nvs, FALCON_MAC_ADDRESS_OFFSET ( efab->port ),
- efab->mac_addr, sizeof ( efab->mac_addr ) ) == 0 );
-}
-
-/** RX descriptor */
-typedef efab_qword_t falcon_rx_desc_t;
-
-/**
- * Build RX descriptor
*
- */
-static void falcon_build_rx_desc ( struct efab_nic *efab,
- struct efab_rx_buf *rx_buf ) {
- falcon_rx_desc_t *rxd;
-
- rxd = ( ( falcon_rx_desc_t * ) efab->rxd ) + rx_buf->id;
- EFAB_POPULATE_QWORD_2 ( *rxd,
- FCN_RX_KER_BUF_SIZE, EFAB_DATA_BUF_SIZE,
- FCN_RX_KER_BUF_ADR,
- virt_to_bus ( rx_buf->addr ) );
-}
-
-/**
- * Update RX descriptor write pointer
+ * Falcon bit-bashed I2C interface
*
- */
-static void falcon_notify_rx_desc ( struct efab_nic *efab ) {
- efab_dword_t reg;
-
- EFAB_POPULATE_DWORD_1 ( reg, FCN_RX_DESC_WPTR_DWORD,
- efab->rx_write_ptr );
- falcon_writel ( efab, &reg, FCN_RX_DESC_UPD_REG_KER_DWORD );
-}
+ *
+ *******************************************************************************/
-/** TX descriptor */
-typedef efab_qword_t falcon_tx_desc_t;
+static void
+falcon_i2c_bit_write ( struct bit_basher *basher, unsigned int bit_id,
+ unsigned long data )
+{
+ struct efab_nic *efab = container_of ( basher, struct efab_nic,
+ i2c_bb.basher );
+ efab_oword_t reg;
-/**
- * Build TX descriptor
- *
- */
-static void falcon_build_tx_desc ( struct efab_nic *efab,
- struct efab_tx_buf *tx_buf ) {
- falcon_rx_desc_t *txd;
+ falcon_read ( efab, &reg, FCN_GPIO_CTL_REG_KER );
+ switch ( bit_id ) {
+ case I2C_BIT_SCL:
+ EFAB_SET_OWORD_FIELD ( reg, FCN_GPIO0_OEN, ( data ? 0 : 1 ) );
+ break;
+ case I2C_BIT_SDA:
+ EFAB_SET_OWORD_FIELD ( reg, FCN_GPIO3_OEN, ( data ? 0 : 1 ) );
+ break;
+ default:
+ EFAB_ERR ( "%s bit=%d\n", __func__, bit_id );
+ break;
+ }
- txd = ( ( falcon_rx_desc_t * ) efab->txd ) + tx_buf->id;
- EFAB_POPULATE_QWORD_3 ( *txd,
- FCN_TX_KER_PORT, efab->port,
- FCN_TX_KER_BYTE_CNT, tx_buf->len,
- FCN_TX_KER_BUF_ADR,
- virt_to_bus ( tx_buf->addr ) );
+ falcon_write ( efab, &reg, FCN_GPIO_CTL_REG_KER );
}
-/**
- * Update TX descriptor write pointer
- *
- */
-static void falcon_notify_tx_desc ( struct efab_nic *efab ) {
- efab_dword_t reg;
+static int
+falcon_i2c_bit_read ( struct bit_basher *basher, unsigned int bit_id )
+{
+ struct efab_nic *efab = container_of ( basher, struct efab_nic,
+ i2c_bb.basher );
+ efab_oword_t reg;
+
+ falcon_read ( efab, &reg, FCN_GPIO_CTL_REG_KER );
+ switch ( bit_id ) {
+ case I2C_BIT_SCL:
+ return EFAB_OWORD_FIELD ( reg, FCN_GPIO0_IN );
+ break;
+ case I2C_BIT_SDA:
+ return EFAB_OWORD_FIELD ( reg, FCN_GPIO3_IN );
+ break;
+ default:
+ EFAB_ERR ( "%s bit=%d\n", __func__, bit_id );
+ break;
+ }
- EFAB_POPULATE_DWORD_1 ( reg, FCN_TX_DESC_WPTR_DWORD,
- efab->tx_write_ptr );
- falcon_writel ( efab, &reg, FCN_TX_DESC_UPD_REG_KER_DWORD );
+ return -1;
}
-/** An event */
-typedef efab_qword_t falcon_event_t;
+static struct bit_basher_operations falcon_i2c_bit_ops = {
+ .read = falcon_i2c_bit_read,
+ .write = falcon_i2c_bit_write,
+};
-/**
- * See if an event is present
+
+/*******************************************************************************
*
- * @v event Falcon event structure
- * @ret True An event is pending
- * @ret False No event is pending
*
- * We check both the high and low dword of the event for all ones. We
- * wrote all ones when we cleared the event, and no valid event can
- * have all ones in either its high or low dwords. This approach is
- * robust against reordering.
+ * MDIO access
*
- * Note that using a single 64-bit comparison is incorrect; even
- * though the CPU read will be atomic, the DMA write may not be.
- */
-static inline int falcon_event_present ( falcon_event_t* event ) {
- return ( ! ( EFAB_DWORD_IS_ALL_ONES ( event->dword[0] ) |
- EFAB_DWORD_IS_ALL_ONES ( event->dword[1] ) ) );
-}
-
-/**
- * Retrieve event from event queue
*
- */
-static int falcon_fetch_event ( struct efab_nic *efab,
- struct efab_event *event ) {
- falcon_event_t *evt;
- int ev_code;
- int rx_port;
+ *******************************************************************************/
- /* Check for event */
- evt = ( ( falcon_event_t * ) efab->eventq ) + efab->eventq_read_ptr;
- if ( !falcon_event_present ( evt ) ) {
- /* No event */
- return 0;
- }
-
- DBG ( "Event is " EFAB_QWORD_FMT "\n", EFAB_QWORD_VAL ( *evt ) );
+static int
+falcon_gmii_wait ( struct efab_nic *efab )
+{
+ efab_dword_t md_stat;
+ int count;
- /* Decode event */
- ev_code = EFAB_QWORD_FIELD ( *evt, FCN_EV_CODE );
- event->drop = 0;
- switch ( ev_code ) {
- case FCN_TX_IP_EV_DECODE:
- event->type = EFAB_EV_TX;
- break;
- case FCN_RX_IP_EV_DECODE:
- event->type = EFAB_EV_RX;
- event->rx_id = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_DESC_PTR );
- event->rx_len = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_BYTE_CNT );
- event->drop = !EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_PKT_OK );
- rx_port = EFAB_QWORD_FIELD ( *evt, FCN_RX_PORT );
- if ( rx_port != efab->port ) {
- /* Ignore packets on the wrong port. We can't
- * just set event->type = EFAB_EV_NONE,
- * because then the descriptor ring won't get
- * refilled.
- */
- event->rx_len = 0;
+ /* wait upto 10ms */
+ for (count = 0; count < 1000; count++) {
+ falcon_readl ( efab, &md_stat, FCN_MD_STAT_REG_KER );
+ if ( EFAB_DWORD_FIELD ( md_stat, FCN_MD_BSY ) == 0 ) {
+ if ( EFAB_DWORD_FIELD ( md_stat, FCN_MD_LNFL ) != 0 ||
+ EFAB_DWORD_FIELD ( md_stat, FCN_MD_BSERR ) != 0 ) {
+ EFAB_ERR ( "Error from GMII access "
+ EFAB_DWORD_FMT"\n",
+ EFAB_DWORD_VAL ( md_stat ));
+ return -EIO;
+ }
+ return 0;
}
- break;
- case FCN_DRIVER_EV_DECODE:
- /* Ignore start-of-day events */
- event->type = EFAB_EV_NONE;
- break;
- default:
- EFAB_ERR ( "Unknown event type %d data %08lx\n", ev_code,
- EFAB_DWORD_FIELD ( *evt, EFAB_DWORD_0 ) );
- event->type = EFAB_EV_NONE;
+ udelay(10);
}
- /* Clear event and any pending interrupts */
- EFAB_SET_QWORD ( *evt );
- falcon_writel ( efab, 0, FCN_INT_ACK_KER_REG );
- udelay ( 10 );
+ EFAB_ERR ( "Timed out waiting for GMII\n" );
+ return -ETIMEDOUT;
+}
- /* Increment and update event queue read pointer */
- efab->eventq_read_ptr = ( ( efab->eventq_read_ptr + 1 )
- % EFAB_EVQ_SIZE );
- falcon_eventq_read_ack ( efab );
+static void
+falcon_mdio_write ( struct efab_nic *efab, int device,
+ int location, int value )
+{
+ efab_oword_t reg;
- return 1;
-}
+ EFAB_TRACE ( "Writing GMII %d register %02x with %04x\n",
+ device, location, value );
-/**
- * Enable/disable/generate interrupt
- *
- */
-static inline void falcon_interrupts ( struct efab_nic *efab, int enabled,
- int force ) {
- efab_oword_t int_en_reg_ker;
+ /* Check MII not currently being accessed */
+ if ( falcon_gmii_wait ( efab ) )
+ return;
- EFAB_POPULATE_OWORD_2 ( int_en_reg_ker,
- FCN_KER_INT_KER, force,
- FCN_DRV_INT_EN_KER, enabled );
- falcon_write ( efab, &int_en_reg_ker, FCN_INT_EN_REG_KER );
-}
+ /* Write the address/ID register */
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, location );
+ falcon_write ( efab, &reg, FCN_MD_PHY_ADR_REG_KER );
-/**
- * Enable/disable interrupts
- *
- */
-static void falcon_mask_irq ( struct efab_nic *efab, int enabled ) {
- falcon_interrupts ( efab, enabled, 0 );
- if ( enabled ) {
- /* Events won't trigger interrupts until we do this */
- falcon_eventq_read_ack ( efab );
+ if ( efab->phy_10g ) {
+ /* clause45 */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_PRT_ADR, efab->phy_addr,
+ FCN_MD_DEV_ADR, device );
}
-}
+ else {
+ /* clause22 */
+ assert ( device == 0 );
-/**
- * Generate interrupt
- *
- */
-static void falcon_generate_irq ( struct efab_nic *efab ) {
- falcon_interrupts ( efab, 1, 1 );
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_PRT_ADR, efab->phy_addr,
+ FCN_MD_DEV_ADR, location );
+ }
+ falcon_write ( efab, &reg, FCN_MD_ID_REG_KER );
+
+
+ /* Write data */
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_TXD, value );
+ falcon_write ( efab, &reg, FCN_MD_TXD_REG_KER );
+
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_WRC, 1,
+ FCN_MD_GC, ( efab->phy_10g ? 0 : 1 ) );
+ falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
+
+ /* Wait for data to be written */
+ if ( falcon_gmii_wait ( efab ) ) {
+ /* Abort the write operation */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_WRC, 0,
+ FCN_MD_GC, 1);
+ falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
+ udelay(10);
+ }
}
+static int
+falcon_mdio_read ( struct efab_nic *efab, int device, int location )
+{
+ efab_oword_t reg;
+ int value;
-/**
- * Reconfigure MAC wrapper
+ /* Check MII not currently being accessed */
+ if ( falcon_gmii_wait ( efab ) )
+ return -1;
+
+ if ( efab->phy_10g ) {
+ /* clause45 */
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, location );
+ falcon_write ( efab, &reg, FCN_MD_PHY_ADR_REG_KER );
+
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_PRT_ADR, efab->phy_addr,
+ FCN_MD_DEV_ADR, device );
+ falcon_write ( efab, &reg, FCN_MD_ID_REG_KER);
+
+ /* request data to be read */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_RDC, 1,
+ FCN_MD_GC, 0 );
+ }
+ else {
+ /* clause22 */
+ assert ( device == 0 );
+
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_PRT_ADR, efab->phy_addr,
+ FCN_MD_DEV_ADR, location );
+ falcon_write ( efab, &reg, FCN_MD_ID_REG_KER );
+
+ /* Request data to be read */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_RIC, 1,
+ FCN_MD_GC, 1 );
+ }
+
+ falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
+
+ /* Wait for data to become available */
+ if ( falcon_gmii_wait ( efab ) ) {
+ /* Abort the read operation */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_MD_RIC, 0,
+ FCN_MD_GC, 1 );
+ falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
+ udelay ( 10 );
+ value = -1;
+ }
+ else {
+ /* Read the data */
+ falcon_read ( efab, &reg, FCN_MD_RXD_REG_KER );
+ value = EFAB_OWORD_FIELD ( reg, FCN_MD_RXD );
+ }
+
+ EFAB_TRACE ( "Read from GMII %d register %02x, got %04x\n",
+ device, location, value );
+
+ return value;
+}
+
+/*******************************************************************************
*
- */
-static void falcon_reconfigure_mac_wrapper ( struct efab_nic *efab ) {
+ *
+ * MAC wrapper
+ *
+ *
+ *******************************************************************************/
+
+static void
+falcon_reconfigure_mac_wrapper ( struct efab_nic *efab )
+{
efab_oword_t reg;
int link_speed;
@@ -2561,22 +1752,153 @@ static void falcon_reconfigure_mac_wrapper ( struct efab_nic *efab ) {
FCN_MAC_UC_PROM, 0,
FCN_MAC_LINK_STATUS, 1,
FCN_MAC_SPEED, link_speed );
- falcon_write ( efab, &reg,
- ( efab->port == 0 ?
- FCN_MAC0_CTRL_REG_KER : FCN_MAC1_CTRL_REG_KER ) );
- /* Disable flow-control (i.e. never generate pause frames) */
- falcon_read ( efab, &reg, FCN_RX_CFG_REG_KER );
- EFAB_SET_OWORD_FIELD ( reg, FCN_RX_XOFF_EN, 0 );
- falcon_write ( efab, &reg, FCN_RX_CFG_REG_KER );
+ falcon_write ( efab, &reg, FCN_MAC0_CTRL_REG_KER );
}
-/**
- * Write dword to a Falcon MAC register
+/*******************************************************************************
*
- */
-static void falcon_gmac_writel ( struct efab_nic *efab,
- efab_dword_t *value, unsigned int mac_reg ) {
+ *
+ * GMAC handling
+ *
+ *
+ *******************************************************************************/
+
+/* GMAC configuration register 1 */
+#define GM_CFG1_REG_MAC 0x00
+#define GM_SW_RST_LBN 31
+#define GM_SW_RST_WIDTH 1
+#define GM_RX_FC_EN_LBN 5
+#define GM_RX_FC_EN_WIDTH 1
+#define GM_TX_FC_EN_LBN 4
+#define GM_TX_FC_EN_WIDTH 1
+#define GM_RX_EN_LBN 2
+#define GM_RX_EN_WIDTH 1
+#define GM_TX_EN_LBN 0
+#define GM_TX_EN_WIDTH 1
+
+/* GMAC configuration register 2 */
+#define GM_CFG2_REG_MAC 0x01
+#define GM_PAMBL_LEN_LBN 12
+#define GM_PAMBL_LEN_WIDTH 4
+#define GM_IF_MODE_LBN 8
+#define GM_IF_MODE_WIDTH 2
+#define GM_PAD_CRC_EN_LBN 2
+#define GM_PAD_CRC_EN_WIDTH 1
+#define GM_FD_LBN 0
+#define GM_FD_WIDTH 1
+
+/* GMAC maximum frame length register */
+#define GM_MAX_FLEN_REG_MAC 0x04
+#define GM_MAX_FLEN_LBN 0
+#define GM_MAX_FLEN_WIDTH 16
+
+/* GMAC MII management configuration register */
+#define GM_MII_MGMT_CFG_REG_MAC 0x08
+#define GM_MGMT_CLK_SEL_LBN 0
+#define GM_MGMT_CLK_SEL_WIDTH 3
+
+/* GMAC MII management command register */
+#define GM_MII_MGMT_CMD_REG_MAC 0x09
+#define GM_MGMT_SCAN_CYC_LBN 1
+#define GM_MGMT_SCAN_CYC_WIDTH 1
+#define GM_MGMT_RD_CYC_LBN 0
+#define GM_MGMT_RD_CYC_WIDTH 1
+
+/* GMAC MII management address register */
+#define GM_MII_MGMT_ADR_REG_MAC 0x0a
+#define GM_MGMT_PHY_ADDR_LBN 8
+#define GM_MGMT_PHY_ADDR_WIDTH 5
+#define GM_MGMT_REG_ADDR_LBN 0
+#define GM_MGMT_REG_ADDR_WIDTH 5
+
+/* GMAC MII management control register */
+#define GM_MII_MGMT_CTL_REG_MAC 0x0b
+#define GM_MGMT_CTL_LBN 0
+#define GM_MGMT_CTL_WIDTH 16
+
+/* GMAC MII management status register */
+#define GM_MII_MGMT_STAT_REG_MAC 0x0c
+#define GM_MGMT_STAT_LBN 0
+#define GM_MGMT_STAT_WIDTH 16
+
+/* GMAC MII management indicators register */
+#define GM_MII_MGMT_IND_REG_MAC 0x0d
+#define GM_MGMT_BUSY_LBN 0
+#define GM_MGMT_BUSY_WIDTH 1
+
+/* GMAC station address register 1 */
+#define GM_ADR1_REG_MAC 0x10
+#define GM_HWADDR_5_LBN 24
+#define GM_HWADDR_5_WIDTH 8
+#define GM_HWADDR_4_LBN 16
+#define GM_HWADDR_4_WIDTH 8
+#define GM_HWADDR_3_LBN 8
+#define GM_HWADDR_3_WIDTH 8
+#define GM_HWADDR_2_LBN 0
+#define GM_HWADDR_2_WIDTH 8
+
+/* GMAC station address register 2 */
+#define GM_ADR2_REG_MAC 0x11
+#define GM_HWADDR_1_LBN 24
+#define GM_HWADDR_1_WIDTH 8
+#define GM_HWADDR_0_LBN 16
+#define GM_HWADDR_0_WIDTH 8
+
+/* GMAC FIFO configuration register 0 */
+#define GMF_CFG0_REG_MAC 0x12
+#define GMF_FTFENREQ_LBN 12
+#define GMF_FTFENREQ_WIDTH 1
+#define GMF_STFENREQ_LBN 11
+#define GMF_STFENREQ_WIDTH 1
+#define GMF_FRFENREQ_LBN 10
+#define GMF_FRFENREQ_WIDTH 1
+#define GMF_SRFENREQ_LBN 9
+#define GMF_SRFENREQ_WIDTH 1
+#define GMF_WTMENREQ_LBN 8
+#define GMF_WTMENREQ_WIDTH 1
+
+/* GMAC FIFO configuration register 1 */
+#define GMF_CFG1_REG_MAC 0x13
+#define GMF_CFGFRTH_LBN 16
+#define GMF_CFGFRTH_WIDTH 5
+#define GMF_CFGXOFFRTX_LBN 0
+#define GMF_CFGXOFFRTX_WIDTH 16
+
+/* GMAC FIFO configuration register 2 */
+#define GMF_CFG2_REG_MAC 0x14
+#define GMF_CFGHWM_LBN 16
+#define GMF_CFGHWM_WIDTH 6
+#define GMF_CFGLWM_LBN 0
+#define GMF_CFGLWM_WIDTH 6
+
+/* GMAC FIFO configuration register 3 */
+#define GMF_CFG3_REG_MAC 0x15
+#define GMF_CFGHWMFT_LBN 16
+#define GMF_CFGHWMFT_WIDTH 6
+#define GMF_CFGFTTH_LBN 0
+#define GMF_CFGFTTH_WIDTH 6
+
+/* GMAC FIFO configuration register 4 */
+#define GMF_CFG4_REG_MAC 0x16
+#define GMF_HSTFLTRFRM_PAUSE_LBN 12
+#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12
+
+/* GMAC FIFO configuration register 5 */
+#define GMF_CFG5_REG_MAC 0x17
+#define GMF_CFGHDPLX_LBN 22
+#define GMF_CFGHDPLX_WIDTH 1
+#define GMF_CFGBYTMODE_LBN 19
+#define GMF_CFGBYTMODE_WIDTH 1
+#define GMF_HSTDRPLT64_LBN 18
+#define GMF_HSTDRPLT64_WIDTH 1
+#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12
+#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1
+
+static void
+falcon_gmac_writel ( struct efab_nic *efab, efab_dword_t *value,
+ unsigned int mac_reg )
+{
efab_oword_t temp;
EFAB_POPULATE_OWORD_1 ( temp, FCN_MAC_DATA,
@@ -2584,12 +1906,10 @@ static void falcon_gmac_writel ( struct efab_nic *efab,
falcon_write ( efab, &temp, FALCON_GMAC_REG ( efab, mac_reg ) );
}
-/**
- * Read dword from a Falcon GMAC register
- *
- */
-static void falcon_gmac_readl ( struct efab_nic *efab, efab_dword_t *value,
- unsigned int mac_reg ) {
+static void
+falcon_gmac_readl ( struct efab_nic *efab, efab_dword_t *value,
+ unsigned int mac_reg )
+{
efab_oword_t temp;
falcon_read ( efab, &temp, FALCON_GMAC_REG ( efab, mac_reg ) );
@@ -2597,12 +1917,172 @@ static void falcon_gmac_readl ( struct efab_nic *efab, efab_dword_t *value,
EFAB_OWORD_FIELD ( temp, FCN_MAC_DATA ) );
}
+static void
+mentormac_reset ( struct efab_nic *efab )
+{
+ efab_dword_t reg;
+
+ /* Take into reset */
+ EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 1 );
+ falcon_gmac_writel ( efab, &reg, GM_CFG1_REG_MAC );
+ udelay ( 1000 );
+
+ /* Take out of reset */
+ EFAB_POPULATE_DWORD_1 ( reg, GM_SW_RST, 0 );
+ falcon_gmac_writel ( efab, &reg, GM_CFG1_REG_MAC );
+ udelay ( 1000 );
+
+ /* Configure GMII interface so PHY is accessible. Note that
+ * GMII interface is connected only to port 0, and that on
+ * Falcon this is a no-op.
+ */
+ EFAB_POPULATE_DWORD_1 ( reg, GM_MGMT_CLK_SEL, 0x4 );
+ falcon_gmac_writel ( efab, &reg, GM_MII_MGMT_CFG_REG_MAC );
+ udelay ( 10 );
+}
+
+static void
+mentormac_init ( struct efab_nic *efab )
+{
+ int pause, if_mode, full_duplex, bytemode, half_duplex;
+ efab_dword_t reg;
+
+ /* Configuration register 1 */
+ pause = ( efab->link_options & LPA_PAUSE ) ? 1 : 0;
+ if ( ! ( efab->link_options & LPA_DUPLEX ) ) {
+ /* Half-duplex operation requires TX flow control */
+ pause = 1;
+ }
+ EFAB_POPULATE_DWORD_4 ( reg,
+ GM_TX_EN, 1,
+ GM_TX_FC_EN, pause,
+ GM_RX_EN, 1,
+ GM_RX_FC_EN, 1 );
+ falcon_gmac_writel ( efab, &reg, GM_CFG1_REG_MAC );
+ udelay ( 10 );
+
+ /* Configuration register 2 */
+ if_mode = ( efab->link_options & LPA_1000 ) ? 2 : 1;
+ full_duplex = ( efab->link_options & LPA_DUPLEX ) ? 1 : 0;
+ EFAB_POPULATE_DWORD_4 ( reg,
+ GM_IF_MODE, if_mode,
+ GM_PAD_CRC_EN, 1,
+ GM_FD, full_duplex,
+ GM_PAMBL_LEN, 0x7 /* ? */ );
+ falcon_gmac_writel ( efab, &reg, GM_CFG2_REG_MAC );
+ udelay ( 10 );
+
+ /* Max frame len register */
+ EFAB_POPULATE_DWORD_1 ( reg, GM_MAX_FLEN,
+ EFAB_MAX_FRAME_LEN ( ETH_FRAME_LEN ) );
+ falcon_gmac_writel ( efab, &reg, GM_MAX_FLEN_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 0 */
+ EFAB_POPULATE_DWORD_5 ( reg,
+ GMF_FTFENREQ, 1,
+ GMF_STFENREQ, 1,
+ GMF_FRFENREQ, 1,
+ GMF_SRFENREQ, 1,
+ GMF_WTMENREQ, 1 );
+ falcon_gmac_writel ( efab, &reg, GMF_CFG0_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 1 */
+ EFAB_POPULATE_DWORD_2 ( reg,
+ GMF_CFGFRTH, 0x12,
+ GMF_CFGXOFFRTX, 0xffff );
+ falcon_gmac_writel ( efab, &reg, GMF_CFG1_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 2 */
+ EFAB_POPULATE_DWORD_2 ( reg,
+ GMF_CFGHWM, 0x3f,
+ GMF_CFGLWM, 0xa );
+ falcon_gmac_writel ( efab, &reg, GMF_CFG2_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 3 */
+ EFAB_POPULATE_DWORD_2 ( reg,
+ GMF_CFGHWMFT, 0x1c,
+ GMF_CFGFTTH, 0x08 );
+ falcon_gmac_writel ( efab, &reg, GMF_CFG3_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 4 */
+ EFAB_POPULATE_DWORD_1 ( reg, GMF_HSTFLTRFRM_PAUSE, 1 );
+ falcon_gmac_writel ( efab, &reg, GMF_CFG4_REG_MAC );
+ udelay ( 10 );
+
+ /* FIFO configuration register 5 */
+ bytemode = ( efab->link_options & LPA_1000 ) ? 1 : 0;
+ half_duplex = ( efab->link_options & LPA_DUPLEX ) ? 0 : 1;
+ falcon_gmac_readl ( efab, &reg, GMF_CFG5_REG_MAC );
+ EFAB_SET_DWORD_FIELD ( reg, GMF_CFGBYTMODE, bytemode );
+ EFAB_SET_DWORD_FIELD ( reg, GMF_CFGHDPLX, half_duplex );
+ EFAB_SET_DWORD_FIELD ( reg, GMF_HSTDRPLT64, half_duplex );
+ EFAB_SET_DWORD_FIELD ( reg, GMF_HSTFLTRFRMDC_PAUSE, 0 );
+ falcon_gmac_writel ( efab, &reg, GMF_CFG5_REG_MAC );
+ udelay ( 10 );
+
+ /* MAC address */
+ EFAB_POPULATE_DWORD_4 ( reg,
+ GM_HWADDR_5, efab->mac_addr[5],
+ GM_HWADDR_4, efab->mac_addr[4],
+ GM_HWADDR_3, efab->mac_addr[3],
+ GM_HWADDR_2, efab->mac_addr[2] );
+ falcon_gmac_writel ( efab, &reg, GM_ADR1_REG_MAC );
+ udelay ( 10 );
+ EFAB_POPULATE_DWORD_2 ( reg,
+ GM_HWADDR_1, efab->mac_addr[1],
+ GM_HWADDR_0, efab->mac_addr[0] );
+ falcon_gmac_writel ( efab, &reg, GM_ADR2_REG_MAC );
+ udelay ( 10 );
+}
+
+static int
+falcon_init_gmac ( struct efab_nic *efab )
+{
+ /* Reset the MAC */
+ mentormac_reset ( efab );
+
+ /* Initialise PHY */
+ efab->phy_op->init ( efab );
+
+ /* check the link is up */
+ if ( !efab->link_up )
+ return -EAGAIN;
+
+ /* Initialise MAC */
+ mentormac_init ( efab );
+
+ /* reconfigure the MAC wrapper */
+ falcon_reconfigure_mac_wrapper ( efab );
+
+ return 0;
+}
+
+static struct efab_mac_operations falcon_gmac_operations = {
+ .init = falcon_init_gmac,
+};
+
+
+/*******************************************************************************
+ *
+ *
+ * XMAC handling
+ *
+ *
+ *******************************************************************************/
+
/**
* Write dword to a Falcon XMAC register
*
*/
-static void falcon_xmac_writel ( struct efab_nic *efab,
- efab_dword_t *value, unsigned int mac_reg ) {
+static void
+falcon_xmac_writel ( struct efab_nic *efab, efab_dword_t *value,
+ unsigned int mac_reg )
+{
efab_oword_t temp;
EFAB_POPULATE_OWORD_1 ( temp, FCN_MAC_DATA,
@@ -2615,9 +2095,10 @@ static void falcon_xmac_writel ( struct efab_nic *efab,
* Read dword from a Falcon XMAC register
*
*/
-static void falcon_xmac_readl ( struct efab_nic *efab,
- efab_dword_t *value,
- unsigned int mac_reg ) {
+static void
+falcon_xmac_readl ( struct efab_nic *efab, efab_dword_t *value,
+ unsigned int mac_reg )
+{
efab_oword_t temp;
falcon_read ( efab, &temp,
@@ -2627,109 +2108,159 @@ static void falcon_xmac_readl ( struct efab_nic *efab,
}
/**
- * Initialise GMAC
- *
+ * Configure Falcon XAUI output
*/
-static int falcon_init_gmac ( struct efab_nic *efab ) {
- static struct efab_mentormac_parameters falcon_mentormac_params = {
- .gmf_cfgfrth = 0x12,
- .gmf_cfgftth = 0x08,
- .gmf_cfghwmft = 0x1c,
- .gmf_cfghwm = 0x3f,
- .gmf_cfglwm = 0xa,
- };
+static void
+falcon_setup_xaui ( struct efab_nic *efab )
+{
+ efab_dword_t sdctl, txdrv;
+
+ falcon_xmac_readl ( efab, &sdctl, FCN_XX_SD_CTL_REG_MAC );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVD, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVC, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVB, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT );
+ EFAB_SET_DWORD_FIELD ( sdctl, FCN_XX_LODRVA, XX_SD_CTL_DRV_DEFAULT );
+ falcon_xmac_writel ( efab, &sdctl, FCN_XX_SD_CTL_REG_MAC );
+
+ EFAB_POPULATE_DWORD_8 ( txdrv,
+ FCN_XX_DEQD, XX_TXDRV_DEQ_DEFAULT,
+ FCN_XX_DEQC, XX_TXDRV_DEQ_DEFAULT,
+ FCN_XX_DEQB, XX_TXDRV_DEQ_DEFAULT,
+ FCN_XX_DEQA, XX_TXDRV_DEQ_DEFAULT,
+ FCN_XX_DTXD, XX_TXDRV_DTX_DEFAULT,
+ FCN_XX_DTXC, XX_TXDRV_DTX_DEFAULT,
+ FCN_XX_DTXB, XX_TXDRV_DTX_DEFAULT,
+ FCN_XX_DTXA, XX_TXDRV_DTX_DEFAULT);
+ falcon_xmac_writel ( efab, &txdrv, FCN_XX_TXDRV_CTL_REG_MAC);
+}
- /* Initialise PHY */
- alaska_init ( efab );
+static int
+falcon_xgmii_status ( struct efab_nic *efab )
+{
+ efab_dword_t reg;
- /* check the link is up */
- if ( !efab->link_up )
+ if ( efab->pci_revision < FALCON_REV_B0 )
+ return 1;
+ /* The ISR latches, so clear it and re-read */
+ falcon_xmac_readl ( efab, &reg, FCN_XM_MGT_INT_REG_MAC_B0 );
+ falcon_xmac_readl ( efab, &reg, FCN_XM_MGT_INT_REG_MAC_B0 );
+
+ if ( EFAB_DWORD_FIELD ( reg, FCN_XM_LCLFLT ) ||
+ EFAB_DWORD_FIELD ( reg, FCN_XM_RMTFLT ) ) {
+ EFAB_TRACE ( "MGT_INT: "EFAB_DWORD_FMT"\n",
+ EFAB_DWORD_VAL ( reg ) );
return 0;
-
- /* Initialise MAC */
- mentormac_init ( efab, &falcon_mentormac_params );
-
- /* reconfigure the MAC wrapper */
- falcon_reconfigure_mac_wrapper ( efab );
+ }
return 1;
}
-/**
- * Reset GMAC
- *
- */
-static int falcon_reset_gmac ( struct efab_nic *efab ) {
- mentormac_reset ( efab );
- return 1;
+static void
+falcon_mask_status_intr ( struct efab_nic *efab, int enable )
+{
+ efab_dword_t reg;
+
+ if ( efab->pci_revision < FALCON_REV_B0 )
+ return;
+
+ /* Flush the ISR */
+ if ( enable )
+ falcon_xmac_readl ( efab, &reg, FCN_XM_MGT_INT_REG_MAC_B0 );
+
+ EFAB_POPULATE_DWORD_2 ( reg,
+ FCN_XM_MSK_RMTFLT, !enable,
+ FCN_XM_MSK_LCLFLT, !enable);
+ falcon_xmac_readl ( efab, &reg, FCN_XM_MGT_INT_MSK_REG_MAC_B0 );
}
/**
- * Reset XAUI/XGXS block
+ * Reset 10G MAC connected to port
*
*/
-static int falcon_reset_xaui ( struct efab_nic *efab )
+static int
+falcon_reset_xmac ( struct efab_nic *efab )
{
efab_dword_t reg;
int count;
-
- EFAB_POPULATE_DWORD_1 ( reg, FCN_XX_RST_XX_EN, 1 );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XX_PWR_RST_REG_MAC );
+
+ EFAB_POPULATE_DWORD_1 ( reg, FCN_XM_CORE_RST, 1 );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_GLB_CFG_REG_MAC );
for ( count = 0 ; count < 1000 ; count++ ) {
udelay ( 10 );
- efab->mac_op->mac_readl ( efab, &reg,
- FCN_XX_PWR_RST_REG_MAC );
- if ( EFAB_DWORD_FIELD ( reg, FCN_XX_RST_XX_EN ) == 0 )
- return 1;
+ falcon_xmac_readl ( efab, &reg,
+ FCN_XM_GLB_CFG_REG_MAC );
+ if ( EFAB_DWORD_FIELD ( reg, FCN_XM_CORE_RST ) == 0 )
+ return 0;
}
-
- /* an error of some kind */
- return 0;
+ return -ETIMEDOUT;
}
-/**
- * Reset 10G MAC connected to port
- *
- */
-static int falcon_reset_xmac ( struct efab_nic *efab ) {
+
+static int
+falcon_reset_xaui ( struct efab_nic *efab )
+{
efab_dword_t reg;
int count;
- EFAB_POPULATE_DWORD_1 ( reg, FCN_XM_CORE_RST, 1 );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_GLB_CFG_REG_MAC );
+ if (!efab->is_asic)
+ return 0;
- for ( count = 0 ; count < 1000 ; count++ ) {
- udelay ( 10 );
- efab->mac_op->mac_readl ( efab, &reg,
- FCN_XM_GLB_CFG_REG_MAC );
- if ( EFAB_DWORD_FIELD ( reg, FCN_XM_CORE_RST ) == 0 )
- return 1;
+ EFAB_POPULATE_DWORD_1 ( reg, FCN_XX_RST_XX_EN, 1 );
+ falcon_xmac_writel ( efab, &reg, FCN_XX_PWR_RST_REG_MAC );
+
+ /* Give some time for the link to establish */
+ for (count = 0; count < 1000; count++) { /* wait upto 10ms */
+ falcon_xmac_readl ( efab, &reg, FCN_XX_PWR_RST_REG_MAC );
+ if ( EFAB_DWORD_FIELD ( reg, FCN_XX_RST_XX_EN ) == 0 ) {
+ falcon_setup_xaui ( efab );
+ return 0;
+ }
+ udelay(10);
}
- return 0;
+ EFAB_ERR ( "timed out waiting for XAUI/XGXS reset\n" );
+ return -ETIMEDOUT;
}
-/**
- * Get status of 10G link
- *
- */
-static int falcon_xaui_link_ok ( struct efab_nic *efab ) {
+static int
+falcon_xaui_link_ok ( struct efab_nic *efab )
+{
efab_dword_t reg;
- int align_done;
- int sync_status;
- int link_ok = 0;
+ int align_done, lane_status, sync;
+ int has_phyxs;
+ int link_ok = 1;
+
+ /* Read Falcon XAUI side */
+ if ( efab->is_asic ) {
+ /* Read link status */
+ falcon_xmac_readl ( efab, &reg, FCN_XX_CORE_STAT_REG_MAC );
+ align_done = EFAB_DWORD_FIELD ( reg, FCN_XX_ALIGN_DONE );
- /* Read link status */
- efab->mac_op->mac_readl ( efab, &reg, FCN_XX_CORE_STAT_REG_MAC );
- align_done = EFAB_DWORD_FIELD ( reg, FCN_XX_ALIGN_DONE );
- sync_status = EFAB_DWORD_FIELD ( reg, FCN_XX_SYNC_STAT );
- if ( align_done && ( sync_status == FCN_XX_SYNC_STAT_DECODE_SYNCED ) ) {
- link_ok = 1;
+ sync = EFAB_DWORD_FIELD ( reg, FCN_XX_SYNC_STAT );
+ sync = ( sync == FCN_XX_SYNC_STAT_DECODE_SYNCED );
+
+ link_ok = align_done && sync;
}
/* Clear link status ready for next read */
EFAB_SET_DWORD_FIELD ( reg, FCN_XX_COMMA_DET, FCN_XX_COMMA_DET_RESET );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XX_CORE_STAT_REG_MAC );
+ EFAB_SET_DWORD_FIELD ( reg, FCN_XX_CHARERR, FCN_XX_CHARERR_RESET);
+ EFAB_SET_DWORD_FIELD ( reg, FCN_XX_DISPERR, FCN_XX_DISPERR_RESET);
+ falcon_xmac_writel ( efab, &reg, FCN_XX_CORE_STAT_REG_MAC );
+
+ has_phyxs = ( efab->phy_op->mmds & ( 1 << MDIO_MMD_PHYXS ) );
+ if ( link_ok && has_phyxs ) {
+ lane_status = falcon_mdio_read ( efab, MDIO_MMD_PHYXS,
+ MDIO_PHYXS_LANE_STATE );
+ link_ok = ( lane_status & ( 1 << MDIO_PHYXS_LANE_ALIGNED_LBN ) );
+
+ if (!link_ok )
+ EFAB_LOG ( "XGXS lane status: %x\n", lane_status );
+ }
return link_ok;
}
@@ -2738,28 +2269,18 @@ static int falcon_xaui_link_ok ( struct efab_nic *efab ) {
* Initialise XMAC
*
*/
-static int falcon_init_xmac ( struct efab_nic *efab ) {
+static void
+falcon_reconfigure_xmac ( struct efab_nic *efab )
+{
efab_dword_t reg;
- int count;
+ int max_frame_len;
- if ( !falcon_reset_xmac ( efab ) ) {
- EFAB_ERR ( "failed resetting XMAC\n" );
- return 0;
- }
- if ( !falcon_reset_xaui ( efab ) ) {
- EFAB_ERR ( "failed resetting XAUI\n");
- return 0;
- }
-
- /* CX4 is always 10000FD only */
- efab->link_options = LPA_10000FULL;
-
- /* Configure MAC */
+ /* Configure MAC - cut-thru mode is hard wired on */
EFAB_POPULATE_DWORD_3 ( reg,
FCN_XM_RX_JUMBO_MODE, 1,
FCN_XM_TX_STAT_EN, 1,
FCN_XM_RX_STAT_EN, 1);
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_GLB_CFG_REG_MAC );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_GLB_CFG_REG_MAC );
/* Configure TX */
EFAB_POPULATE_DWORD_6 ( reg,
@@ -2769,23 +2290,31 @@ static int falcon_init_xmac ( struct efab_nic *efab ) {
FCN_XM_TXCRC, 1,
FCN_XM_FCNTL, 1,
FCN_XM_IPG, 0x3 );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_TX_CFG_REG_MAC );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_TX_CFG_REG_MAC );
/* Configure RX */
- EFAB_POPULATE_DWORD_3 ( reg,
+ EFAB_POPULATE_DWORD_4 ( reg,
FCN_XM_RXEN, 1,
- FCN_XM_AUTO_DEPAD, 1,
+ FCN_XM_AUTO_DEPAD, 0,
+ FCN_XM_ACPT_ALL_MCAST, 1,
FCN_XM_PASS_CRC_ERR, 1 );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_RX_CFG_REG_MAC );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_RX_CFG_REG_MAC );
/* Set frame length */
+ max_frame_len = EFAB_MAX_FRAME_LEN ( ETH_FRAME_LEN );
EFAB_POPULATE_DWORD_1 ( reg,
- FCN_XM_MAX_RX_FRM_SIZE, ETH_FRAME_LEN );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_RX_PARAM_REG_MAC );
+ FCN_XM_MAX_RX_FRM_SIZE, max_frame_len );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_RX_PARAM_REG_MAC );
EFAB_POPULATE_DWORD_2 ( reg,
- FCN_XM_MAX_TX_FRM_SIZE, ETH_FRAME_LEN,
+ FCN_XM_MAX_TX_FRM_SIZE, max_frame_len,
FCN_XM_TX_JUMBO_MODE, 1 );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_TX_PARAM_REG_MAC );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_TX_PARAM_REG_MAC );
+
+ /* Enable flow control receipt */
+ EFAB_POPULATE_DWORD_2 ( reg,
+ FCN_XM_PAUSE_TIME, 0xfffe,
+ FCN_XM_DIS_FCNTL, 0 );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_FC_REG_MAC );
/* Set MAC address */
EFAB_POPULATE_DWORD_4 ( reg,
@@ -2793,639 +2322,1922 @@ static int falcon_init_xmac ( struct efab_nic *efab ) {
FCN_XM_ADR_1, efab->mac_addr[1],
FCN_XM_ADR_2, efab->mac_addr[2],
FCN_XM_ADR_3, efab->mac_addr[3] );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_ADR_LO_REG_MAC );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_ADR_LO_REG_MAC );
EFAB_POPULATE_DWORD_2 ( reg,
FCN_XM_ADR_4, efab->mac_addr[4],
FCN_XM_ADR_5, efab->mac_addr[5] );
- efab->mac_op->mac_writel ( efab, &reg, FCN_XM_ADR_HI_REG_MAC );
+ falcon_xmac_writel ( efab, &reg, FCN_XM_ADR_HI_REG_MAC );
+}
- /* Reconfigure MAC wrapper */
- falcon_reconfigure_mac_wrapper ( efab );
+static int
+falcon_init_xmac ( struct efab_nic *efab )
+{
+ int count, rc;
+
+ /* Mask the PHY management interrupt */
+ falcon_mask_status_intr ( efab, 0 );
+ /* Initialise the PHY to instantiate the clock. */
+ rc = efab->phy_op->init ( efab );
+ if ( rc ) {
+ EFAB_ERR ( "unable to initialise PHY\n" );
+ goto fail1;
+ }
+
+ falcon_reset_xaui ( efab );
+
+ /* Give the PHY and MAC time to faff */
+ mdelay ( 100 );
+
+ /* Reset and reconfigure the XMAC */
+ rc = falcon_reset_xmac ( efab );
+ if ( rc )
+ goto fail2;
+ falcon_reconfigure_xmac ( efab );
+ falcon_reconfigure_mac_wrapper ( efab );
/**
- * Try resetting XAUI on its own waiting for the link
- * to come up
+ * Now wait for the link to come up. This may take a while
+ * for some slower PHY's.
*/
- for(count=0; count<5; count++) {
- /* Check link status */
- efab->link_up = falcon_xaui_link_ok ( efab );
- if ( efab->link_up ) {
- /**
- * Print out a speed message since we don't have a PHY
- */
- EFAB_LOG ( "%dMbps %s-duplex\n",
- ( efab->link_options & LPA_10000 ? 1000 :
- ( efab->link_options & LPA_1000 ? 1000 :
- ( efab->link_options & LPA_100 ? 100 : 10 ) ) ),
- ( efab->link_options & LPA_DUPLEX ? "full" : "half" ) );
- break;
+ for (count=0; count<50; count++) {
+ int link_ok = 1;
+
+ /* Wait a while for the link to come up. */
+ mdelay ( 100 );
+ if ((count % 5) == 0)
+ putchar ( '.' );
+
+ /* Does the PHY think the wire-side link is up? */
+ link_ok = mdio_clause45_links_ok ( efab );
+ /* Ensure the XAUI link to the PHY is good */
+ if ( link_ok ) {
+ link_ok = falcon_xaui_link_ok ( efab );
+ if ( !link_ok )
+ falcon_reset_xaui ( efab );
}
- if ( !falcon_reset_xaui ( efab ) ) {
- EFAB_ERR ( "failed resetting xaui\n" );
+ /* Check fault indication */
+ if ( link_ok )
+ link_ok = falcon_xgmii_status ( efab );
+
+ efab->link_up = link_ok;
+ if ( link_ok ) {
+ /* unmask the status interrupt */
+ falcon_mask_status_intr ( efab, 1 );
return 0;
}
- udelay(100);
}
- return 1;
+ /* Link failed to come up, but initialisation was fine. */
+ rc = -ETIMEDOUT;
+
+fail2:
+fail1:
+ return rc;
+}
+
+static struct efab_mac_operations falcon_xmac_operations = {
+ .init = falcon_init_xmac,
+};
+
+/*******************************************************************************
+ *
+ *
+ * Null PHY handling
+ *
+ *
+ *******************************************************************************/
+
+static int
+falcon_xaui_phy_init ( struct efab_nic *efab )
+{
+ /* CX4 is always 10000FD only */
+ efab->link_options = LPA_10000FULL;
+
+ /* There is no PHY! */
+ return 0;
}
+static struct efab_phy_operations falcon_xaui_phy_ops = {
+ .init = falcon_xaui_phy_init,
+ .mmds = 0,
+};
+
+
+/*******************************************************************************
+ *
+ *
+ * Alaska PHY
+ *
+ *
+ *******************************************************************************/
+
/**
- * Wait for GMII access to complete
+ * Initialise Alaska PHY
*
*/
-static int falcon_gmii_wait ( struct efab_nic *efab ) {
- efab_oword_t md_stat;
+static int
+alaska_init ( struct efab_nic *efab )
+{
+ unsigned int advertised, lpa;
+
+ /* Read link up status */
+ efab->link_up = gmii_link_ok ( efab );
+
+ if ( ! efab->link_up )
+ return -EIO;
+
+ /* Determine link options from PHY. */
+ advertised = gmii_autoneg_advertised ( efab );
+ lpa = gmii_autoneg_lpa ( efab );
+ efab->link_options = gmii_nway_result ( advertised & lpa );
+
+ return 0;
+}
+
+static struct efab_phy_operations falcon_alaska_phy_ops = {
+ .init = alaska_init,
+};
+
+/*******************************************************************************
+ *
+ *
+ * xfp
+ *
+ *
+ *******************************************************************************/
+
+#define XFP_REQUIRED_DEVS ( MDIO_MMDREG_DEVS0_PCS | \
+ MDIO_MMDREG_DEVS0_PMAPMD | \
+ MDIO_MMDREG_DEVS0_PHYXS )
+
+static int
+falcon_xfp_phy_init ( struct efab_nic *efab )
+{
+ int rc;
+
+ /* Optical link is always 10000FD only */
+ efab->link_options = LPA_10000FULL;
+
+ /* Reset the PHY */
+ rc = mdio_clause45_reset_mmd ( efab, MDIO_MMD_PHYXS );
+ if ( rc )
+ return rc;
+
+ return 0;
+}
+
+static struct efab_phy_operations falcon_xfp_phy_ops = {
+ .init = falcon_xfp_phy_init,
+ .mmds = XFP_REQUIRED_DEVS,
+};
+
+/*******************************************************************************
+ *
+ *
+ * txc43128
+ *
+ *
+ *******************************************************************************/
+
+/* Command register */
+#define TXC_GLRGS_GLCMD (0xc004)
+#define TXC_GLCMD_LMTSWRST_LBN (14)
+
+/* Amplitude on lanes 0+1, 2+3 */
+#define TXC_ALRGS_ATXAMP0 (0xc041)
+#define TXC_ALRGS_ATXAMP1 (0xc042)
+/* Bit position of value for lane 0+2, 1+3 */
+#define TXC_ATXAMP_LANE02_LBN (3)
+#define TXC_ATXAMP_LANE13_LBN (11)
+
+#define TXC_ATXAMP_1280_mV (0)
+#define TXC_ATXAMP_1200_mV (8)
+#define TXC_ATXAMP_1120_mV (12)
+#define TXC_ATXAMP_1060_mV (14)
+#define TXC_ATXAMP_0820_mV (25)
+#define TXC_ATXAMP_0720_mV (26)
+#define TXC_ATXAMP_0580_mV (27)
+#define TXC_ATXAMP_0440_mV (28)
+
+#define TXC_ATXAMP_0820_BOTH ( (TXC_ATXAMP_0820_mV << TXC_ATXAMP_LANE02_LBN) | \
+ (TXC_ATXAMP_0820_mV << TXC_ATXAMP_LANE13_LBN) )
+
+#define TXC_ATXAMP_DEFAULT (0x6060) /* From databook */
+
+/* Preemphasis on lanes 0+1, 2+3 */
+#define TXC_ALRGS_ATXPRE0 (0xc043)
+#define TXC_ALRGS_ATXPRE1 (0xc044)
+
+#define TXC_ATXPRE_NONE (0)
+#define TXC_ATXPRE_DEFAULT (0x1010) /* From databook */
+
+#define TXC_REQUIRED_DEVS ( MDIO_MMDREG_DEVS0_PCS | \
+ MDIO_MMDREG_DEVS0_PMAPMD | \
+ MDIO_MMDREG_DEVS0_PHYXS )
+
+static int
+falcon_txc_logic_reset ( struct efab_nic *efab )
+{
+ int val;
+ int tries = 50;
+
+ val = falcon_mdio_read ( efab, MDIO_MMD_PCS, TXC_GLRGS_GLCMD );
+ val |= (1 << TXC_GLCMD_LMTSWRST_LBN);
+ falcon_mdio_write ( efab, MDIO_MMD_PCS, TXC_GLRGS_GLCMD, val );
+
+ while ( tries--) {
+ val = falcon_mdio_read ( efab, MDIO_MMD_PCS, TXC_GLRGS_GLCMD );
+ if ( ~val & ( 1 << TXC_GLCMD_LMTSWRST_LBN ) )
+ return 0;
+ udelay(1);
+ }
+
+ EFAB_ERR ( "logic reset failed\n" );
+
+ return -ETIMEDOUT;
+}
+
+static int
+falcon_txc_phy_init ( struct efab_nic *efab )
+{
+ int rc;
+
+ /* CX4 is always 10000FD only */
+ efab->link_options = LPA_10000FULL;
+
+ /* reset the phy */
+ rc = mdio_clause45_reset_mmd ( efab, MDIO_MMD_PMAPMD );
+ if ( rc )
+ goto fail1;
+
+ rc = mdio_clause45_check_mmds ( efab );
+ if ( rc )
+ goto fail2;
+
+ /* Turn amplitude down and preemphasis off on the host side
+ * (PHY<->MAC) as this is believed less likely to upset falcon
+ * and no adverse effects have been noted. It probably also
+ * saves a picowatt or two */
+
+ /* Turn off preemphasis */
+ falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE0,
+ TXC_ATXPRE_NONE );
+ falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXPRE1,
+ TXC_ATXPRE_NONE );
+
+ /* Turn down the amplitude */
+ falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXAMP0,
+ TXC_ATXAMP_0820_BOTH );
+ falcon_mdio_write ( efab, MDIO_MMD_PHYXS, TXC_ALRGS_ATXAMP1,
+ TXC_ATXAMP_0820_BOTH );
+
+ /* Set the line side amplitude and preemphasis to the databook
+ * defaults as an erratum causes them to be 0 on at least some
+ * PHY rev.s */
+ falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXPRE0,
+ TXC_ATXPRE_DEFAULT );
+ falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXPRE1,
+ TXC_ATXPRE_DEFAULT );
+ falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXAMP0,
+ TXC_ATXAMP_DEFAULT );
+ falcon_mdio_write ( efab, MDIO_MMD_PMAPMD, TXC_ALRGS_ATXAMP1,
+ TXC_ATXAMP_DEFAULT );
+
+ rc = falcon_txc_logic_reset ( efab );
+ if ( rc )
+ goto fail3;
+
+ return 0;
+
+fail3:
+fail2:
+fail1:
+ return rc;
+}
+
+static struct efab_phy_operations falcon_txc_phy_ops = {
+ .init = falcon_txc_phy_init,
+ .mmds = TXC_REQUIRED_DEVS,
+};
+
+/*******************************************************************************
+ *
+ *
+ * tenxpress
+ *
+ *
+ *******************************************************************************/
+
+
+#define TENXPRESS_REQUIRED_DEVS ( MDIO_MMDREG_DEVS0_PMAPMD | \
+ MDIO_MMDREG_DEVS0_PCS | \
+ MDIO_MMDREG_DEVS0_PHYXS )
+
+#define PCS_TEST_SELECT_REG 0xd807 /* PRM 10.5.8 */
+#define CLK312_EN_LBN 3
+#define CLK312_EN_WIDTH 1
+
+#define PCS_CLOCK_CTRL_REG 0xd801
+#define PLL312_RST_N_LBN 2
+
+/* Special Software reset register */
+#define PMA_PMD_EXT_CTRL_REG 49152
+#define PMA_PMD_EXT_SSR_LBN 15
+
+/* Boot status register */
+#define PCS_BOOT_STATUS_REG 0xd000
+#define PCS_BOOT_FATAL_ERR_LBN 0
+#define PCS_BOOT_PROGRESS_LBN 1
+#define PCS_BOOT_PROGRESS_WIDTH 2
+#define PCS_BOOT_COMPLETE_LBN 3
+
+#define PCS_SOFT_RST2_REG 0xd806
+#define SERDES_RST_N_LBN 13
+#define XGXS_RST_N_LBN 12
+
+static int
+falcon_tenxpress_check_c11 ( struct efab_nic *efab )
+{
int count;
+ uint32_t boot_stat;
- for ( count = 0 ; count < 1000 ; count++ ) {
- udelay ( 10 );
- falcon_read ( efab, &md_stat, FCN_MD_STAT_REG_KER );
- if ( EFAB_OWORD_FIELD ( md_stat, FCN_MD_BSY ) == 0 )
- return 1;
+ /* Check that the C11 CPU has booted */
+ for (count=0; count<10; count++) {
+ boot_stat = falcon_mdio_read ( efab, MDIO_MMD_PCS,
+ PCS_BOOT_STATUS_REG );
+ if ( boot_stat & ( 1 << PCS_BOOT_COMPLETE_LBN ) )
+ return 0;
+
+ udelay(10);
}
- EFAB_ERR ( "Timed out waiting for GMII\n" );
+
+ EFAB_ERR ( "C11 failed to boot\n" );
+ return -ETIMEDOUT;
+}
+
+static int
+falcon_tenxpress_phy_init ( struct efab_nic *efab )
+{
+ int rc, reg;
+
+ /* 10XPRESS is always 10000FD (at the moment) */
+ efab->link_options = LPA_10000FULL;
+
+ /* Wait for the blocks to come out of reset */
+ rc = mdio_clause45_wait_reset_mmds ( efab );
+ if ( rc )
+ goto fail1;
+
+ rc = mdio_clause45_check_mmds ( efab );
+ if ( rc )
+ goto fail2;
+
+ /* Turn on the clock */
+ reg = (1 << CLK312_EN_LBN);
+ falcon_mdio_write ( efab, MDIO_MMD_PCS, PCS_TEST_SELECT_REG, reg);
+
+ /* Wait 200ms for the PHY to boot */
+ mdelay(200);
+
+ rc = falcon_tenxpress_check_c11 ( efab );
+ if ( rc )
+ goto fail3;
+
return 0;
+
+fail3:
+fail2:
+fail1:
+ return rc;
}
+static struct efab_phy_operations falcon_tenxpress_phy_ops = {
+ .init = falcon_tenxpress_phy_init,
+ .mmds = TENXPRESS_REQUIRED_DEVS,
+};
-static struct efab_mac_operations falcon_xmac_operations = {
- .mac_readl = falcon_xmac_readl,
- .mac_writel = falcon_xmac_writel,
- .init = falcon_init_xmac,
- .reset = falcon_reset_xmac,
+/*******************************************************************************
+ *
+ *
+ * PM8358
+ *
+ *
+ *******************************************************************************/
+
+/* The PM8358 just presents a DTE XS */
+#define PM8358_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_DTEXS)
+
+/* PHY-specific definitions */
+/* Master ID and Global Performance Monitor Update */
+#define PMC_MASTER_REG (0xd000)
+/* Analog Tx Rx settings under software control */
+#define PMC_MASTER_ANLG_CTRL (1<< 11)
+
+/* Master Configuration register 2 */
+#define PMC_MCONF2_REG (0xd002)
+/* Drive Tx off centre of data eye (1) vs. clock edge (0) */
+#define PMC_MCONF2_TEDGE (1 << 2)
+/* Drive Rx off centre of data eye (1) vs. clock edge (0) */
+#define PMC_MCONF2_REDGE (1 << 3)
+
+/* Analog Rx settings */
+#define PMC_ANALOG_RX_CFG0 (0xd025)
+#define PMC_ANALOG_RX_CFG1 (0xd02d)
+#define PMC_ANALOG_RX_CFG2 (0xd035)
+#define PMC_ANALOG_RX_CFG3 (0xd03d)
+
+
+#define PMC_ANALOG_RX_TERM (1 << 15) /* Bit 15 of RX CFG: 0 for 100 ohms float,
+ 1 for 50 to 1.2V */
+#define PMC_ANALOG_RX_EQ_MASK (3 << 8)
+#define PMC_ANALOG_RX_EQ_NONE (0 << 8)
+#define PMC_ANALOG_RX_EQ_HALF (1 << 8)
+#define PMC_ANALOG_RX_EQ_FULL (2 << 8)
+#define PMC_ANALOG_RX_EQ_RSVD (3 << 8)
+
+static int
+falcon_pm8358_phy_init ( struct efab_nic *efab )
+{
+ int rc, reg, i;
+
+ /* This is a XAUI retimer part */
+ efab->link_options = LPA_10000FULL;
+
+ rc = mdio_clause45_reset_mmd ( efab, MDIO_MMDREG_DEVS0_DTEXS );
+ if ( rc )
+ return rc;
+
+ /* Enable software control of analogue settings */
+ reg = falcon_mdio_read ( efab, MDIO_MMD_DTEXS, PMC_MASTER_REG );
+ reg |= PMC_MASTER_ANLG_CTRL;
+ falcon_mdio_write ( efab, MDIO_MMD_DTEXS, PMC_MASTER_REG, reg );
+
+ /* Turn rx eq on for all channels */
+ for (i=0; i< 3; i++) {
+ /* The analog CFG registers are evenly spaced 8 apart */
+ uint16_t addr = PMC_ANALOG_RX_CFG0 + 8*i;
+ reg = falcon_mdio_read ( efab, MDIO_MMD_DTEXS, addr );
+ reg = ( reg & ~PMC_ANALOG_RX_EQ_MASK ) | PMC_ANALOG_RX_EQ_FULL;
+ falcon_mdio_write ( efab, MDIO_MMD_DTEXS, addr, reg );
+ }
+
+ /* Set TEDGE, clear REDGE */
+ reg = falcon_mdio_read ( efab, MDIO_MMD_DTEXS, PMC_MCONF2_REG );
+ reg = ( reg & ~PMC_MCONF2_REDGE) | PMC_MCONF2_TEDGE;
+ falcon_mdio_write ( efab, MDIO_MMD_DTEXS, PMC_MCONF2_REG, reg );
+
+ return 0;
+}
+
+static struct efab_phy_operations falcon_pm8358_phy_ops = {
+ .init = falcon_pm8358_phy_init,
+ .mmds = PM8358_REQUIRED_DEVS,
};
-static struct efab_mac_operations falcon_gmac_operations = {
- .mac_readl = falcon_gmac_readl,
- .mac_writel = falcon_gmac_writel,
- .init = falcon_init_gmac,
- .reset = falcon_reset_gmac,
+/*******************************************************************************
+ *
+ *
+ * SFE4001 support
+ *
+ *
+ *******************************************************************************/
+
+#define MAX_TEMP_THRESH 90
+
+/* I2C Expander */
+#define PCA9539 0x74
+
+#define P0_IN 0x00
+#define P0_OUT 0x02
+#define P0_CONFIG 0x06
+
+#define P0_EN_1V0X_LBN 0
+#define P0_EN_1V0X_WIDTH 1
+#define P0_EN_1V2_LBN 1
+#define P0_EN_1V2_WIDTH 1
+#define P0_EN_2V5_LBN 2
+#define P0_EN_2V5_WIDTH 1
+#define P0_EN_3V3X_LBN 3
+#define P0_EN_3V3X_WIDTH 1
+#define P0_EN_5V_LBN 4
+#define P0_EN_5V_WIDTH 1
+#define P0_X_TRST_LBN 6
+#define P0_X_TRST_WIDTH 1
+
+#define P1_IN 0x01
+#define P1_CONFIG 0x07
+
+#define P1_AFE_PWD_LBN 0
+#define P1_AFE_PWD_WIDTH 1
+#define P1_DSP_PWD25_LBN 1
+#define P1_DSP_PWD25_WIDTH 1
+#define P1_SPARE_LBN 4
+#define P1_SPARE_WIDTH 4
+
+/* Temperature Sensor */
+#define MAX6647 0x4e
+
+#define RSL 0x02
+#define RLHN 0x05
+#define WLHO 0x0b
+
+static struct i2c_device i2c_pca9539 = {
+ .dev_addr = PCA9539,
+ .dev_addr_len = 1,
+ .word_addr_len = 1,
};
-/**
- * Initialise NIC
+static struct i2c_device i2c_max6647 = {
+ .dev_addr = MAX6647,
+ .dev_addr_len = 1,
+ .word_addr_len = 1,
+};
+
+static int
+sfe4001_init ( struct efab_nic *efab )
+{
+ struct i2c_interface *i2c = &efab->i2c_bb.i2c;
+ efab_dword_t reg;
+ uint8_t in, cfg, out;
+ int count, rc;
+
+ EFAB_LOG ( "Initialise SFE4001 board\n" );
+
+ /* Ensure XGXS and XAUI SerDes are held in reset */
+ EFAB_POPULATE_DWORD_7 ( reg,
+ FCN_XX_PWRDNA_EN, 1,
+ FCN_XX_PWRDNB_EN, 1,
+ FCN_XX_RSTPLLAB_EN, 1,
+ FCN_XX_RESETA_EN, 1,
+ FCN_XX_RESETB_EN, 1,
+ FCN_XX_RSTXGXSRX_EN, 1,
+ FCN_XX_RSTXGXSTX_EN, 1 );
+ falcon_xmac_writel ( efab, &reg, FCN_XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ /* Set DSP over-temperature alert threshold */
+ cfg = MAX_TEMP_THRESH;
+ rc = i2c->write ( i2c, &i2c_max6647, WLHO, &cfg, EFAB_BYTE );
+ if ( rc )
+ goto fail1;
+
+ /* Read it back and verify */
+ rc = i2c->read ( i2c, &i2c_max6647, RLHN, &in, EFAB_BYTE );
+ if ( rc )
+ goto fail2;
+
+ if ( in != MAX_TEMP_THRESH ) {
+ EFAB_ERR ( "Unable to verify MAX6647 limit (requested=%d "
+ "confirmed=%d)\n", cfg, in );
+ rc = -EIO;
+ goto fail3;
+ }
+
+ /* Clear any previous over-temperature alert */
+ rc = i2c->read ( i2c, &i2c_max6647, RSL, &in, EFAB_BYTE );
+ if ( rc )
+ goto fail4;
+
+ /* Enable port 0 and 1 outputs on IO expander */
+ cfg = 0x00;
+ rc = i2c->write ( i2c, &i2c_pca9539, P0_CONFIG, &cfg, EFAB_BYTE );
+ if ( rc )
+ goto fail5;
+ cfg = 0xff & ~(1 << P1_SPARE_LBN);
+ rc = i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &cfg, EFAB_BYTE );
+ if ( rc )
+ goto fail6;
+
+ /* Turn all power off then wait 1 sec. This ensures PHY is reset */
+ out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) |
+ (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
+ (0 << P0_EN_1V0X_LBN));
+
+ rc = i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+ if ( rc )
+ goto fail7;
+
+ mdelay(1000);
+
+ for (count=0; count<20; count++) {
+ /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */
+ out = 0xff & ~( (1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) |
+ (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) |
+ (1 << P0_X_TRST_LBN) );
+
+ rc = i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+ if ( rc )
+ goto fail8;
+
+ mdelay ( 10 );
+
+ /* Turn on the 1V power rail */
+ out &= ~( 1 << P0_EN_1V0X_LBN );
+ rc = i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+ if ( rc )
+ goto fail9;
+
+ EFAB_LOG ( "Waiting for power...(attempt %d)\n", count);
+ mdelay ( 1000 );
+
+ /* Check DSP is powered */
+ rc = i2c->read ( i2c, &i2c_pca9539, P1_IN, &in, EFAB_BYTE );
+ if ( rc )
+ goto fail10;
+
+ if ( in & ( 1 << P1_AFE_PWD_LBN ) )
+ return 0;
+ }
+
+ rc = -ETIMEDOUT;
+
+fail10:
+fail9:
+fail8:
+fail7:
+ /* Turn off power rails */
+ out = 0xff;
+ (void) i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+ /* Disable port 1 outputs on IO expander */
+ out = 0xff;
+ (void) i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &out, EFAB_BYTE );
+fail6:
+ /* Disable port 0 outputs */
+ out = 0xff;
+ (void) i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &out, EFAB_BYTE );
+fail5:
+fail4:
+fail3:
+fail2:
+fail1:
+ EFAB_ERR ( "Failed initialising SFE4001 board\n" );
+ return rc;
+}
+
+static void
+sfe4001_fini ( struct efab_nic *efab )
+{
+ struct i2c_interface *i2c = &efab->i2c_bb.i2c;
+ uint8_t in, cfg, out;
+
+ EFAB_ERR ( "Turning off SFE4001\n" );
+
+ /* Turn off all power rails */
+ out = 0xff;
+ (void) i2c->write ( i2c, &i2c_pca9539, P0_OUT, &out, EFAB_BYTE );
+
+ /* Disable port 1 outputs on IO expander */
+ cfg = 0xff;
+ (void) i2c->write ( i2c, &i2c_pca9539, P1_CONFIG, &cfg, EFAB_BYTE );
+
+ /* Disable port 0 outputs on IO expander */
+ cfg = 0xff;
+ (void) i2c->write ( i2c, &i2c_pca9539, P0_CONFIG, &cfg, EFAB_BYTE );
+
+ /* Clear any over-temperature alert */
+ (void) i2c->read ( i2c, &i2c_max6647, RSL, &in, EFAB_BYTE );
+}
+
+struct efab_board_operations sfe4001_ops = {
+ .init = sfe4001_init,
+ .fini = sfe4001_fini,
+};
+
+static int sfe4002_init ( struct efab_nic *efab __attribute__((unused)) )
+{
+ return 0;
+}
+static void sfe4002_fini ( struct efab_nic *efab __attribute__((unused)) )
+{
+}
+
+struct efab_board_operations sfe4002_ops = {
+ .init = sfe4002_init,
+ .fini = sfe4002_fini,
+};
+
+static int sfe4003_init ( struct efab_nic *efab __attribute__((unused)) )
+{
+ return 0;
+}
+static void sfe4003_fini ( struct efab_nic *efab __attribute__((unused)) )
+{
+}
+
+struct efab_board_operations sfe4003_ops = {
+ .init = sfe4003_init,
+ .fini = sfe4003_fini,
+};
+
+/*******************************************************************************
*
- */
-static int falcon_init_nic ( struct efab_nic *efab ) {
- efab_oword_t reg;
- efab_dword_t timer_cmd;
- int version, minor;
+ *
+ * Hardware initialisation
+ *
+ *
+ *******************************************************************************/
- /* use card in internal SRAM mode */
- falcon_read ( efab, &reg, FCN_NIC_STAT_REG );
- EFAB_SET_OWORD_FIELD ( reg, ONCHIP_SRAM, 1 );
- falcon_write ( efab, &reg, FCN_NIC_STAT_REG );
- wmb();
+static void
+falcon_free_special_buffer ( void *p )
+{
+ /* We don't bother cleaning up the buffer table entries -
+ * we're hardly limited */
+ free_dma ( p, EFAB_BUF_ALIGN );
+}
+
+static void*
+falcon_alloc_special_buffer ( struct efab_nic *efab, int bytes,
+ struct efab_special_buffer *entry )
+{
+ void* buffer;
+ int remaining;
+ efab_qword_t buf_desc;
+ unsigned long dma_addr;
+
+ /* Allocate the buffer, aligned on a buffer address boundary */
+ buffer = malloc_dma ( bytes, EFAB_BUF_ALIGN );
+ if ( ! buffer )
+ return NULL;
+
+ /* Push buffer table entries to back the buffer */
+ entry->id = efab->buffer_head;
+ entry->dma_addr = dma_addr = virt_to_bus ( buffer );
+ assert ( ( dma_addr & ( EFAB_BUF_ALIGN - 1 ) ) == 0 );
+
+ remaining = bytes;
+ while ( remaining > 0 ) {
+ EFAB_POPULATE_QWORD_3 ( buf_desc,
+ FCN_IP_DAT_BUF_SIZE, FCN_IP_DAT_BUF_SIZE_4K,
+ FCN_BUF_ADR_FBUF, ( dma_addr >> 12 ),
+ FCN_BUF_OWNER_ID_FBUF, 0 );
+
+ falcon_write_sram ( efab, &buf_desc, efab->buffer_head );
+
+ ++efab->buffer_head;
+ dma_addr += EFAB_BUF_ALIGN;
+ remaining -= EFAB_BUF_ALIGN;
+ }
+
+ EFAB_TRACE ( "Allocated 0x%x bytes at %p backed by buffer table "
+ "entries 0x%x..0x%x\n", bytes, buffer, entry->id,
+ efab->buffer_head - 1 );
+
+ return buffer;
+}
- /* identify FPGA/ASIC, and strapping mode */
- falcon_read ( efab, &reg, ALTERA_BUILD_REG_KER );
- version = EFAB_OWORD_FIELD ( reg, VER_ALL );
- efab->is_asic = version ? 0 : 1;
+static void
+clear_b0_fpga_memories ( struct efab_nic *efab)
+{
+ efab_oword_t blanko, temp;
+ efab_dword_t blankd;
+ int offset;
+
+ EFAB_ZERO_OWORD ( blanko );
+ EFAB_ZERO_DWORD ( blankd );
+
+ /* Clear the address region register */
+ EFAB_POPULATE_OWORD_4 ( temp,
+ FCN_ADR_REGION0, 0,
+ FCN_ADR_REGION1, ( 1 << 16 ),
+ FCN_ADR_REGION2, ( 2 << 16 ),
+ FCN_ADR_REGION3, ( 3 << 16 ) );
+ falcon_write ( efab, &temp, FCN_ADR_REGION_REG_KER );
- if ( efab->is_asic ) {
- falcon_read ( efab, &reg, FCN_NIC_STAT_REG );
- if ( EFAB_OWORD_FIELD ( reg, STRAP_10G ) ) {
- efab->is_10g = 1;
- }
- if ( EFAB_OWORD_FIELD ( reg, STRAP_DUAL_PORT ) ) {
- efab->is_dual = 1;
- }
+ EFAB_TRACE ( "Clearing filter and RSS tables\n" );
+
+ for ( offset = FCN_RX_FILTER_TBL0 ;
+ offset < FCN_RX_RSS_INDIR_TBL_B0+0x800 ;
+ offset += 0x10 ) {
+ falcon_write ( efab, &blanko, offset );
+ }
+
+ EFAB_TRACE ( "Wiping buffer tables\n" );
+
+ /* Notice the 8 byte access mode */
+ for ( offset = 0x2800000 ;
+ offset < 0x3000000 ;
+ offset += 0x8) {
+ _falcon_writel ( efab, 0, offset );
+ _falcon_writel ( efab, 0, offset + 4 );
+ wmb();
+ }
+}
+
+static int
+falcon_reset ( struct efab_nic *efab )
+{
+ efab_oword_t glb_ctl_reg_ker;
+
+ /* Initiate software reset */
+ EFAB_POPULATE_OWORD_6 ( glb_ctl_reg_ker,
+ FCN_PCIE_CORE_RST_CTL, EXCLUDE_FROM_RESET,
+ FCN_PCIE_NSTCK_RST_CTL, EXCLUDE_FROM_RESET,
+ FCN_PCIE_SD_RST_CTL, EXCLUDE_FROM_RESET,
+ FCN_EE_RST_CTL, EXCLUDE_FROM_RESET,
+ FCN_EXT_PHY_RST_DUR, 0x7, /* 10ms */
+ FCN_SWRST, 1 );
+
+ falcon_write ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER );
+
+ /* Allow 50ms for reset */
+ mdelay ( 50 );
+
+ /* Check for device reset complete */
+ falcon_read ( efab, &glb_ctl_reg_ker, FCN_GLB_CTL_REG_KER );
+ if ( EFAB_OWORD_FIELD ( glb_ctl_reg_ker, FCN_SWRST ) != 0 ) {
+ EFAB_ERR ( "Reset failed\n" );
+ return -ETIMEDOUT;
+ }
+
+ if ( ( efab->pci_revision == FALCON_REV_B0 ) && !efab->is_asic ) {
+ clear_b0_fpga_memories ( efab );
+ }
+
+ return 0;
+}
+
+/** Offset of MAC address within EEPROM or Flash */
+#define FALCON_MAC_ADDRESS_OFFSET 0x310
+
+/*
+ * Falcon EEPROM structure
+ */
+#define SF_NV_CONFIG_BASE 0x300
+#define SF_NV_CONFIG_EXTRA 0xA0
+
+struct falcon_nv_config_ver2 {
+ uint16_t nports;
+ uint8_t port0_phy_addr;
+ uint8_t port0_phy_type;
+ uint8_t port1_phy_addr;
+ uint8_t port1_phy_type;
+ uint16_t asic_sub_revision;
+ uint16_t board_revision;
+ uint8_t mac_location;
+};
+
+struct falcon_nv_extra {
+ uint16_t magicnumber;
+ uint16_t structure_version;
+ uint16_t checksum;
+ union {
+ struct falcon_nv_config_ver2 ver2;
+ } ver_specific;
+};
+
+#define BOARD_TYPE(_rev) (_rev >> 8)
+
+static void
+falcon_probe_nic_variant ( struct efab_nic *efab, struct pci_device *pci )
+{
+ efab_oword_t altera_build, nic_stat;
+ int is_pcie, fpga_version;
+ uint8_t revision;
+
+ /* PCI revision */
+ pci_read_config_byte ( pci, PCI_CLASS_REVISION, &revision );
+ efab->pci_revision = revision;
+
+ /* Asic vs FPGA */
+ falcon_read ( efab, &altera_build, FCN_ALTERA_BUILD_REG_KER );
+ fpga_version = EFAB_OWORD_FIELD ( altera_build, FCN_VER_ALL );
+ efab->is_asic = (fpga_version == 0);
+
+ /* MAC and PCI type */
+ falcon_read ( efab, &nic_stat, FCN_NIC_STAT_REG );
+ if ( efab->pci_revision == FALCON_REV_B0 ) {
+ is_pcie = 1;
+ efab->phy_10g = EFAB_OWORD_FIELD ( nic_stat, FCN_STRAP_10G );
+ }
+ else if ( efab->is_asic ) {
+ is_pcie = EFAB_OWORD_FIELD ( nic_stat, FCN_STRAP_PCIE );
+ efab->phy_10g = EFAB_OWORD_FIELD ( nic_stat, FCN_STRAP_10G );
}
else {
- falcon_read ( efab, &reg, ALTERA_BUILD_REG_KER );
- minor = EFAB_OWORD_FIELD ( reg, VER_MINOR );
+ int minor = EFAB_OWORD_FIELD ( altera_build, FCN_VER_MINOR );
+ is_pcie = 0;
+ efab->phy_10g = ( minor == 0x14 );
+ }
+}
+
+static void
+falcon_init_spi_device ( struct efab_nic *efab, struct spi_device *spi )
+{
+ /* Falcon's SPI interface only supports reads/writes of up to 16 bytes.
+ * Reduce the nvs block size down to satisfy this - which means callers
+ * should use the nvs_* functions rather than spi_*. */
+ if ( spi->nvs.block_size > FALCON_SPI_MAX_LEN )
+ spi->nvs.block_size = FALCON_SPI_MAX_LEN;
+
+ spi->bus = &efab->spi_bus;
+ efab->spi = spi;
+}
+
+static int
+falcon_probe_spi ( struct efab_nic *efab )
+{
+ efab_oword_t nic_stat, gpio_ctl, ee_vpd_cfg;
+ int has_flash, has_eeprom, ad9bit;
+
+ falcon_read ( efab, &nic_stat, FCN_NIC_STAT_REG );
+ falcon_read ( efab, &gpio_ctl, FCN_GPIO_CTL_REG_KER );
+ falcon_read ( efab, &ee_vpd_cfg, FCN_EE_VPD_CFG_REG );
+
+ /* determine if FLASH / EEPROM is present */
+ if ( ( efab->pci_revision >= FALCON_REV_B0 ) || efab->is_asic ) {
+ has_flash = EFAB_OWORD_FIELD ( nic_stat, FCN_SF_PRST );
+ has_eeprom = EFAB_OWORD_FIELD ( nic_stat, FCN_EE_PRST );
+ } else {
+ has_flash = EFAB_OWORD_FIELD ( gpio_ctl, FCN_FLASH_PRESENT );
+ has_eeprom = EFAB_OWORD_FIELD ( gpio_ctl, FCN_EEPROM_PRESENT );
+ }
+ ad9bit = EFAB_OWORD_FIELD ( ee_vpd_cfg, FCN_EE_VPD_EN_AD9_MODE );
+
+ /* Configure the SPI and I2C bus */
+ efab->spi_bus.rw = falcon_spi_rw;
+ init_i2c_bit_basher ( &efab->i2c_bb, &falcon_i2c_bit_ops );
+
+ /* Configure the EEPROM SPI device. Generally, an Atmel 25040
+ * (or similar) is used, but this is only possible if there is also
+ * a flash device present to store the boot-time chip configuration.
+ */
+ if ( has_eeprom ) {
+ if ( has_flash && ad9bit )
+ init_at25040 ( &efab->spi_eeprom );
+ else
+ init_mc25xx640 ( &efab->spi_eeprom );
+ falcon_init_spi_device ( efab, &efab->spi_eeprom );
+ }
+
+ /* Configure the FLASH SPI device */
+ if ( has_flash ) {
+ init_at25f1024 ( &efab->spi_flash );
+ falcon_init_spi_device ( efab, &efab->spi_flash );
+ }
+
+ EFAB_LOG ( "flash is %s, EEPROM is %s%s\n",
+ ( has_flash ? "present" : "absent" ),
+ ( has_eeprom ? "present " : "absent" ),
+ ( has_eeprom ? (ad9bit ? "(9bit)" : "(16bit)") : "") );
+
+ /* The device MUST have flash or eeprom */
+ if ( ! efab->spi ) {
+ EFAB_ERR ( "Device appears to have no flash or eeprom\n" );
+ return -EIO;
+ }
+
+ /* If the device has EEPROM attached, then advertise NVO space */
+ if ( has_eeprom )
+ nvo_init ( &efab->nvo, &efab->spi_eeprom.nvs, falcon_nvo_fragments,
+ &efab->netdev->refcnt );
+
+ return 0;
+}
+
+static int
+falcon_probe_nvram ( struct efab_nic *efab )
+{
+ struct nvs_device *nvs = &efab->spi->nvs;
+ struct falcon_nv_extra nv;
+ int rc, board_revision;
+
+ /* Read the MAC address */
+ rc = nvs_read ( nvs, FALCON_MAC_ADDRESS_OFFSET,
+ efab->mac_addr, ETH_ALEN );
+ if ( rc )
+ return rc;
+
+ /* Poke through the NVRAM structure for the PHY type. */
+ rc = nvs_read ( nvs, SF_NV_CONFIG_BASE + SF_NV_CONFIG_EXTRA,
+ &nv, sizeof ( nv ) );
+ if ( rc )
+ return rc;
+
+ /* Handle each supported NVRAM version */
+ if ( ( le16_to_cpu ( nv.magicnumber ) == FCN_NV_MAGIC_NUMBER ) &&
+ ( le16_to_cpu ( nv.structure_version ) >= 2 ) ) {
+ struct falcon_nv_config_ver2* ver2 = &nv.ver_specific.ver2;
- if ( minor == 0x14 ) {
- efab->is_10g = 1;
- } else if ( minor == 0x13 ) {
- efab->is_dual = 1;
- }
+ /* Get the PHY type */
+ efab->phy_addr = le16_to_cpu ( ver2->port0_phy_addr );
+ efab->phy_type = le16_to_cpu ( ver2->port0_phy_type );
+ board_revision = le16_to_cpu ( ver2->board_revision );
+ }
+ else {
+ EFAB_ERR ( "NVram is not recognised\n" );
+ return -EINVAL;
}
- DBG ( "NIC type: %s %dx%s\n",
- efab->is_asic ? "ASIC" : "FPGA",
- efab->is_dual ? 2 : 1,
- efab->is_10g ? "10G" : "1G" );
+ efab->board_type = BOARD_TYPE ( board_revision );
+
+ EFAB_TRACE ( "Falcon board %d phy %d @ addr %d\n",
+ efab->board_type, efab->phy_type, efab->phy_addr );
- /* patch in MAC operations */
- if ( efab->is_10g )
+ /* Patch in the board operations */
+ switch ( efab->board_type ) {
+ case EFAB_BOARD_SFE4001:
+ efab->board_op = &sfe4001_ops;
+ break;
+ case EFAB_BOARD_SFE4002:
+ efab->board_op = &sfe4002_ops;
+ break;
+ case EFAB_BOARD_SFE4003:
+ efab->board_op = &sfe4003_ops;
+ break;
+ default:
+ EFAB_ERR ( "Unrecognised board type\n" );
+ return -EINVAL;
+ }
+
+ /* Patch in MAC operations */
+ if ( efab->phy_10g )
efab->mac_op = &falcon_xmac_operations;
else
efab->mac_op = &falcon_gmac_operations;
-
- if ( !efab->is_dual && ( efab->port == 1 ) ) {
- /* device doesn't exist */
- return 0;
- }
- /* determine EEPROM / FLASH */
- if ( efab->is_asic ) {
- falcon_read ( efab, &reg, FCN_NIC_STAT_REG );
- efab->has_flash = EFAB_OWORD_FIELD ( reg, SF_PRST );
- efab->has_eeprom = EFAB_OWORD_FIELD ( reg, EE_PRST );
- } else {
- falcon_read ( efab, &reg, FCN_GPIO_CTL_REG_KER );
- efab->has_flash = EFAB_OWORD_FIELD ( reg, FCN_FLASH_PRESENT );
- efab->has_eeprom = EFAB_OWORD_FIELD ( reg, FCN_EEPROM_PRESENT);
+ /* Hook in the PHY ops */
+ switch ( efab->phy_type ) {
+ case PHY_TYPE_10XPRESS:
+ efab->phy_op = &falcon_tenxpress_phy_ops;
+ break;
+ case PHY_TYPE_CX4:
+ efab->phy_op = &falcon_xaui_phy_ops;
+ break;
+ case PHY_TYPE_XFP:
+ efab->phy_op = &falcon_xfp_phy_ops;
+ break;
+ case PHY_TYPE_CX4_RTMR:
+ efab->phy_op = &falcon_txc_phy_ops;
+ break;
+ case PHY_TYPE_PM8358:
+ efab->phy_op = &falcon_pm8358_phy_ops;
+ break;
+ case PHY_TYPE_1GIG_ALASKA:
+ efab->phy_op = &falcon_alaska_phy_ops;
+ break;
+ default:
+ EFAB_ERR ( "Unknown PHY type: %d\n", efab->phy_type );
+ return -EINVAL;
}
- DBG ( "flash is %s, EEPROM is %s\n",
- ( efab->has_flash ? "present" : "absent" ),
- ( efab->has_eeprom ? "present" : "absent" ) );
- falcon_init_spi ( efab );
+ return 0;
+}
+
+static int
+falcon_init_sram ( struct efab_nic *efab )
+{
+ efab_oword_t reg;
+ int count;
+
+ /* use card in internal SRAM mode */
+ falcon_read ( efab, &reg, FCN_NIC_STAT_REG );
+ EFAB_SET_OWORD_FIELD ( reg, FCN_ONCHIP_SRAM, 1 );
+ falcon_write ( efab, &reg, FCN_NIC_STAT_REG );
+
+ /* Deactivate any external SRAM that might be present */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_GPIO1_OEN, 1,
+ FCN_GPIO1_OUT, 1 );
+ falcon_write ( efab, &reg, FCN_GPIO_CTL_REG_KER );
+
+ /* Initiate SRAM reset */
+ EFAB_POPULATE_OWORD_2 ( reg,
+ FCN_SRAM_OOB_BT_INIT_EN, 1,
+ FCN_SRM_NUM_BANKS_AND_BANK_SIZE, 0 );
+ falcon_write ( efab, &reg, FCN_SRM_CFG_REG_KER );
+
+ /* Wait for SRAM reset to complete */
+ count = 0;
+ do {
+ /* SRAM reset is slow; expect around 16ms */
+ mdelay ( 20 );
+
+ /* Check for reset complete */
+ falcon_read ( efab, &reg, FCN_SRM_CFG_REG_KER );
+ if ( !EFAB_OWORD_FIELD ( reg, FCN_SRAM_OOB_BT_INIT_EN ) )
+ return 0;
+ } while (++count < 20); /* wait upto 0.4 sec */
+
+ EFAB_ERR ( "timed out waiting for SRAM reset\n");
+ return -ETIMEDOUT;
+}
+
+static void
+falcon_setup_nic ( struct efab_nic *efab )
+{
+ efab_dword_t timer_cmd;
+ efab_oword_t reg;
+ int tx_fc, xoff_thresh, xon_thresh;
+
+ /* bug5129: Clear the parity enables on the TX data fifos as
+ * they produce false parity errors because of timing issues
+ */
+ falcon_read ( efab, &reg, FCN_SPARE_REG_KER );
+ EFAB_SET_OWORD_FIELD ( reg, FCN_MEM_PERR_EN_TX_DATA, 0 );
+ falcon_write ( efab, &reg, FCN_SPARE_REG_KER );
+
/* Set up TX and RX descriptor caches in SRAM */
- EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_TX_DC_BASE_ADR,
- 0x130000 /* recommended in datasheet */ );
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_TX_DC_BASE_ADR, 0x130000 );
falcon_write ( efab, &reg, FCN_SRM_TX_DC_CFG_REG_KER );
- EFAB_POPULATE_OWORD_1 ( reg, FCN_TX_DC_SIZE, 2 /* 32 descriptors */ );
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_TX_DC_SIZE, 1 /* 16 descriptors */ );
falcon_write ( efab, &reg, FCN_TX_DC_CFG_REG_KER );
- EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_RX_DC_BASE_ADR,
- 0x100000 /* recommended in datasheet */ );
+ EFAB_POPULATE_OWORD_1 ( reg, FCN_SRM_RX_DC_BASE_ADR, 0x100000 );
falcon_write ( efab, &reg, FCN_SRM_RX_DC_CFG_REG_KER );
EFAB_POPULATE_OWORD_1 ( reg, FCN_RX_DC_SIZE, 2 /* 32 descriptors */ );
falcon_write ( efab, &reg, FCN_RX_DC_CFG_REG_KER );
- /* Set number of RSS CPUs */
- EFAB_POPULATE_OWORD_1 ( reg, FCN_NUM_KER, 0 );
+ /* Set number of RSS CPUs
+ * bug7244: Increase filter depth to reduce RX_RESET likelyhood
+ */
+ EFAB_POPULATE_OWORD_5 ( reg,
+ FCN_NUM_KER, 0,
+ FCN_UDP_FULL_SRCH_LIMIT, 8,
+ FCN_UDP_WILD_SRCH_LIMIT, 8,
+ FCN_TCP_WILD_SRCH_LIMIT, 8,
+ FCN_TCP_FULL_SRCH_LIMIT, 8);
falcon_write ( efab, &reg, FCN_RX_FILTER_CTL_REG_KER );
udelay ( 1000 );
+
+ /* Setup RX. Wait for descriptor is broken and must
+ * be disabled. RXDP recovery shouldn't be needed, but is.
+ * disable ISCSI parsing because we don't need it
+ */
+ falcon_read ( efab, &reg, FCN_RX_SELF_RST_REG_KER );
+ EFAB_SET_OWORD_FIELD ( reg, FCN_RX_NODESC_WAIT_DIS, 1 );
+ EFAB_SET_OWORD_FIELD ( reg, FCN_RX_RECOVERY_EN, 1 );
+ EFAB_SET_OWORD_FIELD ( reg, FCN_RX_ISCSI_DIS, 1 );
+ falcon_write ( efab, &reg, FCN_RX_SELF_RST_REG_KER );
- /* Reset the MAC */
- mentormac_reset ( efab );
+ /* Determine recommended flow control settings. *
+ * Flow control is qualified on B0 and A1/1G, not on A1/10G */
+ if ( efab->pci_revision == FALCON_REV_B0 ) {
+ tx_fc = 1;
+ xoff_thresh = 54272; /* ~80Kb - 3*max MTU */
+ xon_thresh = 27648; /* ~3*max MTU */
+ }
+ else if ( !efab->phy_10g ) {
+ tx_fc = 1;
+ xoff_thresh = 2048;
+ xon_thresh = 512;
+ }
+ else {
+ tx_fc = xoff_thresh = xon_thresh = 0;
+ }
- /* Set up event queue */
- falcon_create_special_buffer ( efab, efab->eventq, FALCON_EVQ_ID );
- /* Fill eventq with all ones ( empty events ) */
- memset(efab->eventq, 0xff, 4096);
- /* push eventq to card */
- EFAB_POPULATE_OWORD_3 ( reg,
- FCN_EVQ_EN, 1,
- FCN_EVQ_SIZE, FCN_EVQ_SIZE_512,
- FCN_EVQ_BUF_BASE_ID, FALCON_EVQ_ID );
- falcon_write ( efab, &reg, FCN_EVQ_PTR_TBL_KER );
- udelay ( 1000 );
+ /* Setup TX and RX */
+ falcon_read ( efab, &reg, FCN_TX_CFG2_REG_KER );
+ EFAB_SET_OWORD_FIELD ( reg, FCN_TX_DIS_NON_IP_EV, 1 );
+ falcon_write ( efab, &reg, FCN_TX_CFG2_REG_KER );
+
+ falcon_read ( efab, &reg, FCN_RX_CFG_REG_KER );
+ EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_USR_BUF_SIZE,
+ (3*4096) / 32 );
+ if ( efab->pci_revision == FALCON_REV_B0)
+ EFAB_SET_OWORD_FIELD ( reg, FCN_RX_INGR_EN_B0, 1 );
+ EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_XON_MAC_TH,
+ xon_thresh / 256);
+ EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_XOFF_MAC_TH,
+ xoff_thresh / 256);
+ EFAB_SET_OWORD_FIELD_VER ( efab, reg, FCN_RX_XOFF_MAC_EN, tx_fc);
+ falcon_write ( efab, &reg, FCN_RX_CFG_REG_KER );
/* Set timer register */
EFAB_POPULATE_DWORD_2 ( timer_cmd,
FCN_TIMER_MODE, FCN_TIMER_MODE_DIS,
FCN_TIMER_VAL, 0 );
falcon_writel ( efab, &timer_cmd, FCN_TIMER_CMD_REG_KER );
- udelay ( 1000 );
+}
+
+static void
+falcon_init_resources ( struct efab_nic *efab )
+{
+ struct efab_ev_queue *ev_queue = &efab->ev_queue;
+ struct efab_rx_queue *rx_queue = &efab->rx_queue;
+ struct efab_tx_queue *tx_queue = &efab->tx_queue;
- /* Initialise event queue read pointer */
- falcon_eventq_read_ack ( efab );
+ efab_oword_t reg;
+ int jumbo;
+
+ /* Initialise the ptrs */
+ tx_queue->read_ptr = tx_queue->write_ptr = 0;
+ rx_queue->read_ptr = rx_queue->write_ptr = 0;
+ ev_queue->read_ptr = 0;
+
+ /* Push the event queue to the hardware */
+ EFAB_POPULATE_OWORD_3 ( reg,
+ FCN_EVQ_EN, 1,
+ FCN_EVQ_SIZE, FQS(FCN_EVQ, EFAB_EVQ_SIZE),
+ FCN_EVQ_BUF_BASE_ID, ev_queue->entry.id );
+ falcon_write ( efab, &reg,
+ FCN_REVISION_REG ( efab, FCN_EVQ_PTR_TBL_KER ) );
- /* Set up TX descriptor ring */
- falcon_create_special_buffer ( efab, efab->txd, FALCON_TXD_ID );
- EFAB_POPULATE_OWORD_5 ( reg,
+ /* Push the tx queue to the hardware */
+ EFAB_POPULATE_OWORD_8 ( reg,
FCN_TX_DESCQ_EN, 1,
- FCN_TX_DESCQ_BUF_BASE_ID, FALCON_TXD_ID,
+ FCN_TX_ISCSI_DDIG_EN, 0,
+ FCN_TX_ISCSI_DDIG_EN, 0,
+ FCN_TX_DESCQ_BUF_BASE_ID, tx_queue->entry.id,
FCN_TX_DESCQ_EVQ_ID, 0,
- FCN_TX_DESCQ_SIZE, FCN_TX_DESCQ_SIZE_512,
- FCN_TX_DESCQ_TYPE, 0 /* kernel queue */ );
- falcon_write ( efab, &reg, FCN_TX_DESC_PTR_TBL_KER );
-
- /* Set up RX descriptor ring */
- falcon_create_special_buffer ( efab, efab->rxd, FALCON_RXD_ID );
- EFAB_POPULATE_OWORD_6 ( reg,
- FCN_RX_DESCQ_BUF_BASE_ID, FALCON_RXD_ID,
+ FCN_TX_DESCQ_SIZE, FQS(FCN_TX_DESCQ, EFAB_TXD_SIZE),
+ FCN_TX_DESCQ_TYPE, 0 /* kernel queue */,
+ FCN_TX_NON_IP_DROP_DIS_B0, 1 );
+ falcon_write ( efab, &reg,
+ FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) );
+
+ /* Push the rx queue to the hardware */
+ jumbo = ( efab->pci_revision == FALCON_REV_B0 ) ? 0 : 1;
+ EFAB_POPULATE_OWORD_8 ( reg,
+ FCN_RX_ISCSI_DDIG_EN, 0,
+ FCN_RX_ISCSI_HDIG_EN, 0,
+ FCN_RX_DESCQ_BUF_BASE_ID, rx_queue->entry.id,
FCN_RX_DESCQ_EVQ_ID, 0,
- FCN_RX_DESCQ_SIZE, FCN_RX_DESCQ_SIZE_512,
+ FCN_RX_DESCQ_SIZE, FQS(FCN_RX_DESCQ, EFAB_RXD_SIZE),
FCN_RX_DESCQ_TYPE, 0 /* kernel queue */,
- FCN_RX_DESCQ_JUMBO, 1,
+ FCN_RX_DESCQ_JUMBO, jumbo,
FCN_RX_DESCQ_EN, 1 );
- falcon_write ( efab, &reg, FCN_RX_DESC_PTR_TBL_KER );
+ falcon_write ( efab, &reg,
+ FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) );
/* Program INT_ADR_REG_KER */
EFAB_POPULATE_OWORD_1 ( reg,
- FCN_INT_ADR_KER,
- virt_to_bus ( &efab->int_ker ) );
+ FCN_INT_ADR_KER, virt_to_bus ( &efab->int_ker ) );
falcon_write ( efab, &reg, FCN_INT_ADR_REG_KER );
- udelay ( 1000 );
- /* Register non-volatile storage */
- if ( efab->has_eeprom ) {
- nvo_init ( &efab->nvo, &efab->falcon_eeprom.nvs,
- falcon_eeprom_fragments, NULL /* hack */ );
- if ( register_nvo ( &efab->nvo, NULL /* hack */ ) != 0 )
- return 0;
- }
+ /* Ack the event queue */
+ falcon_eventq_read_ack ( efab, ev_queue );
+}
- return 1;
+static void
+falcon_fini_resources ( struct efab_nic *efab )
+{
+ efab_oword_t cmd;
+
+ /* Disable interrupts */
+ falcon_interrupts ( efab, 0, 0 );
+
+ /* Flush the dma queues */
+ EFAB_POPULATE_OWORD_2 ( cmd,
+ FCN_TX_FLUSH_DESCQ_CMD, 1,
+ FCN_TX_FLUSH_DESCQ, 0 );
+ falcon_write ( efab, &cmd,
+ FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) );
+
+ EFAB_POPULATE_OWORD_2 ( cmd,
+ FCN_RX_FLUSH_DESCQ_CMD, 1,
+ FCN_RX_FLUSH_DESCQ, 0 );
+ falcon_write ( efab, &cmd,
+ FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) );
+
+ mdelay ( 100 );
+
+ /* Remove descriptor rings from card */
+ EFAB_ZERO_OWORD ( cmd );
+ falcon_write ( efab, &cmd,
+ FCN_REVISION_REG ( efab, FCN_TX_DESC_PTR_TBL_KER ) );
+ falcon_write ( efab, &cmd,
+ FCN_REVISION_REG ( efab, FCN_RX_DESC_PTR_TBL_KER ) );
+ falcon_write ( efab, &cmd,
+ FCN_REVISION_REG ( efab, FCN_EVQ_PTR_TBL_KER ) );
}
-/** MDIO write */
-static void falcon_mdio_write ( struct efab_nic *efab, int location,
- int value ) {
- int phy_id = efab->port + 2;
- efab_oword_t reg;
+/*******************************************************************************
+ *
+ *
+ * Hardware rx path
+ *
+ *
+ *******************************************************************************/
- EFAB_TRACE ( "Writing GMII %d register %02x with %04x\n",
- phy_id, location, value );
+static void
+falcon_build_rx_desc ( falcon_rx_desc_t *rxd, struct io_buffer *iob )
+{
+ EFAB_POPULATE_QWORD_2 ( *rxd,
+ FCN_RX_KER_BUF_SIZE, EFAB_RX_BUF_SIZE,
+ FCN_RX_KER_BUF_ADR, virt_to_bus ( iob->data ) );
+}
- /* Check MII not currently being accessed */
- if ( ! falcon_gmii_wait ( efab ) )
- return;
+static void
+falcon_notify_rx_desc ( struct efab_nic *efab, struct efab_rx_queue *rx_queue )
+{
+ efab_dword_t reg;
+ int ptr = rx_queue->write_ptr % EFAB_RXD_SIZE;
- /* Write the address registers */
- EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, 0 /* phy_id ? */ );
- falcon_write ( efab, &reg, FCN_MD_PHY_ADR_REG_KER );
- udelay ( 10 );
- EFAB_POPULATE_OWORD_2 ( reg,
- FCN_MD_PRT_ADR, phy_id,
- FCN_MD_DEV_ADR, location );
- falcon_write ( efab, &reg, FCN_MD_ID_REG_KER );
- udelay ( 10 );
+ EFAB_POPULATE_DWORD_1 ( reg, FCN_RX_DESC_WPTR_DWORD, ptr );
+ falcon_writel ( efab, &reg, FCN_RX_DESC_UPD_REG_KER_DWORD );
+}
- /* Write data */
- EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_TXD, value );
- falcon_write ( efab, &reg, FCN_MD_TXD_REG_KER );
- udelay ( 10 );
- EFAB_POPULATE_OWORD_2 ( reg,
- FCN_MD_WRC, 1,
- FCN_MD_GC, 1 );
- falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
- udelay ( 10 );
-
- /* Wait for data to be written */
- falcon_gmii_wait ( efab );
+
+/*******************************************************************************
+ *
+ *
+ * Hardware tx path
+ *
+ *
+ *******************************************************************************/
+
+static void
+falcon_build_tx_desc ( falcon_tx_desc_t *txd, struct io_buffer *iob )
+{
+ EFAB_POPULATE_QWORD_2 ( *txd,
+ FCN_TX_KER_BYTE_CNT, iob_len ( iob ),
+ FCN_TX_KER_BUF_ADR, virt_to_bus ( iob->data ) );
}
-/** MDIO read */
-static int falcon_mdio_read ( struct efab_nic *efab, int location ) {
- int phy_id = efab->port + 2;
- efab_oword_t reg;
- int value;
+static void
+falcon_notify_tx_desc ( struct efab_nic *efab,
+ struct efab_tx_queue *tx_queue )
+{
+ efab_dword_t reg;
+ int ptr = tx_queue->write_ptr % EFAB_TXD_SIZE;
- /* Check MII not currently being accessed */
- if ( ! falcon_gmii_wait ( efab ) )
- return 0xffff;
+ EFAB_POPULATE_DWORD_1 ( reg, FCN_TX_DESC_WPTR_DWORD, ptr );
+ falcon_writel ( efab, &reg, FCN_TX_DESC_UPD_REG_KER_DWORD );
+}
- /* Write the address registers */
- EFAB_POPULATE_OWORD_1 ( reg, FCN_MD_PHY_ADR, 0 /* phy_id ? */ );
- falcon_write ( efab, &reg, FCN_MD_PHY_ADR_REG_KER );
- udelay ( 10 );
- EFAB_POPULATE_OWORD_2 ( reg,
- FCN_MD_PRT_ADR, phy_id,
- FCN_MD_DEV_ADR, location );
- falcon_write ( efab, &reg, FCN_MD_ID_REG_KER );
- udelay ( 10 );
- /* Request data to be read */
- EFAB_POPULATE_OWORD_2 ( reg,
- FCN_MD_RIC, 1,
- FCN_MD_GC, 1 );
- falcon_write ( efab, &reg, FCN_MD_CS_REG_KER );
- udelay ( 10 );
-
- /* Wait for data to become available */
- falcon_gmii_wait ( efab );
+/*******************************************************************************
+ *
+ *
+ * Software receive interface
+ *
+ *
+ *******************************************************************************/
- /* Read the data */
- falcon_read ( efab, &reg, FCN_MD_RXD_REG_KER );
- value = EFAB_OWORD_FIELD ( reg, FCN_MD_RXD );
+static int
+efab_fill_rx_queue ( struct efab_nic *efab,
+ struct efab_rx_queue *rx_queue )
+{
+ int fill_level = rx_queue->write_ptr - rx_queue->read_ptr;
+ int space = EFAB_NUM_RX_DESC - fill_level - 1;
+ int pushed = 0;
+
+ while ( space ) {
+ int buf_id = rx_queue->write_ptr % EFAB_NUM_RX_DESC;
+ int desc_id = rx_queue->write_ptr % EFAB_RXD_SIZE;
+ struct io_buffer *iob;
+ falcon_rx_desc_t *rxd;
+
+ assert ( rx_queue->buf[buf_id] == NULL );
+ iob = alloc_iob ( EFAB_RX_BUF_SIZE );
+ if ( !iob )
+ break;
- EFAB_TRACE ( "Read from GMII %d register %02x, got %04x\n",
- phy_id, location, value );
+ EFAB_TRACE ( "pushing rx_buf[%d] iob %p data %p\n",
+ buf_id, iob, iob->data );
- return value;
+ rx_queue->buf[buf_id] = iob;
+ rxd = rx_queue->ring + desc_id;
+ falcon_build_rx_desc ( rxd, iob );
+ ++rx_queue->write_ptr;
+ ++pushed;
+ --space;
+ }
+
+ if ( pushed ) {
+ /* Push the ptr to hardware */
+ falcon_notify_rx_desc ( efab, rx_queue );
+
+ fill_level = rx_queue->write_ptr - rx_queue->read_ptr;
+ EFAB_TRACE ( "pushed %d rx buffers to fill level %d\n",
+ pushed, fill_level );
+ }
+
+ if ( fill_level == 0 )
+ return -ENOMEM;
+ return 0;
}
+
+static void
+efab_receive ( struct efab_nic *efab, unsigned int id, int len, int drop )
+{
+ struct efab_rx_queue *rx_queue = &efab->rx_queue;
+ struct io_buffer *iob;
+ unsigned int read_ptr = rx_queue->read_ptr % EFAB_RXD_SIZE;
+ unsigned int buf_ptr = rx_queue->read_ptr % EFAB_NUM_RX_DESC;
-static struct efab_operations falcon_operations = {
- .get_membase = falcon_get_membase,
- .reset = falcon_reset,
- .init_nic = falcon_init_nic,
- .read_eeprom = falcon_read_eeprom,
- .build_rx_desc = falcon_build_rx_desc,
- .notify_rx_desc = falcon_notify_rx_desc,
- .build_tx_desc = falcon_build_tx_desc,
- .notify_tx_desc = falcon_notify_tx_desc,
- .fetch_event = falcon_fetch_event,
- .mask_irq = falcon_mask_irq,
- .generate_irq = falcon_generate_irq,
- .mdio_write = falcon_mdio_write,
- .mdio_read = falcon_mdio_read,
-};
+ assert ( id == read_ptr );
+
+ /* Pop this rx buffer out of the software ring */
+ iob = rx_queue->buf[buf_ptr];
+ rx_queue->buf[buf_ptr] = NULL;
-/**************************************************************************
+ EFAB_TRACE ( "popping rx_buf[%d] iob %p data %p with %d bytes %s\n",
+ id, iob, iob->data, len, drop ? "bad" : "ok" );
+
+ /* Pass the packet up if required */
+ if ( drop )
+ free_iob ( iob );
+ else {
+ iob_put ( iob, len );
+ netdev_rx ( efab->netdev, iob );
+ }
+
+ ++rx_queue->read_ptr;
+}
+
+/*******************************************************************************
*
- * Etherfabric abstraction layer
*
- **************************************************************************
- */
-
-/**
- * Push RX buffer to RXD ring
+ * Software transmit interface
*
- */
-static inline void efab_push_rx_buffer ( struct efab_nic *efab,
- struct efab_rx_buf *rx_buf ) {
- /* Create RX descriptor */
- rx_buf->id = efab->rx_write_ptr;
- efab->op->build_rx_desc ( efab, rx_buf );
+ *
+ *******************************************************************************/
- /* Update RX write pointer */
- efab->rx_write_ptr = ( efab->rx_write_ptr + 1 ) % EFAB_RXD_SIZE;
- efab->op->notify_rx_desc ( efab );
+static int
+efab_transmit ( struct net_device *netdev, struct io_buffer *iob )
+{
+ struct efab_nic *efab = netdev_priv ( netdev );
+ struct efab_tx_queue *tx_queue = &efab->tx_queue;
+ int fill_level, space;
+ falcon_tx_desc_t *txd;
+ int buf_id;
+
+ fill_level = tx_queue->write_ptr - tx_queue->read_ptr;
+ space = EFAB_TXD_SIZE - fill_level - 1;
+ if ( space < 1 )
+ return -ENOBUFS;
+
+ /* Save the iobuffer for later completion */
+ buf_id = tx_queue->write_ptr % EFAB_TXD_SIZE;
+ assert ( tx_queue->buf[buf_id] == NULL );
+ tx_queue->buf[buf_id] = iob;
+
+ EFAB_TRACE ( "tx_buf[%d] for iob %p data %p len %zd\n",
+ buf_id, iob, iob->data, iob_len ( iob ) );
+
+ /* Form the descriptor, and push it to hardware */
+ txd = tx_queue->ring + buf_id;
+ falcon_build_tx_desc ( txd, iob );
+ ++tx_queue->write_ptr;
+ falcon_notify_tx_desc ( efab, tx_queue );
- DBG ( "Added RX id %x\n", rx_buf->id );
+ return 0;
}
-/**
- * Push TX buffer to TXD ring
- *
- */
-static inline void efab_push_tx_buffer ( struct efab_nic *efab,
- struct efab_tx_buf *tx_buf ) {
- /* Create TX descriptor */
- tx_buf->id = efab->tx_write_ptr;
- efab->op->build_tx_desc ( efab, tx_buf );
+static int
+efab_transmit_done ( struct efab_nic *efab, int id )
+{
+ struct efab_tx_queue *tx_queue = &efab->tx_queue;
+ unsigned int read_ptr, stop;
+
+ /* Complete all buffers from read_ptr up to and including id */
+ read_ptr = tx_queue->read_ptr % EFAB_TXD_SIZE;
+ stop = ( id + 1 ) % EFAB_TXD_SIZE;
- /* Update TX write pointer */
- efab->tx_write_ptr = ( efab->tx_write_ptr + 1 ) % EFAB_TXD_SIZE;
- efab->op->notify_tx_desc ( efab );
+ while ( read_ptr != stop ) {
+ struct io_buffer *iob = tx_queue->buf[read_ptr];
+ assert ( iob );
- DBG ( "Added TX id %x\n", tx_buf->id );
+ /* Complete the tx buffer */
+ if ( iob )
+ netdev_tx_complete ( efab->netdev, iob );
+ tx_queue->buf[read_ptr] = NULL;
+
+ ++tx_queue->read_ptr;
+ read_ptr = tx_queue->read_ptr % EFAB_TXD_SIZE;
+ }
+
+ return 0;
}
-/**
- * Initialise MAC and wait for link up
+/*******************************************************************************
*
- */
-static int efab_init_mac ( struct efab_nic *efab ) {
- int count;
+ *
+ * Hardware event path
+ *
+ *
+ *******************************************************************************/
- /* This can take several seconds */
- EFAB_LOG ( "Waiting for link.." );
- for ( count=0; count<5; count++ ) {
- putchar ( '.' );
+static void
+falcon_clear_interrupts ( struct efab_nic *efab )
+{
+ efab_dword_t reg;
- if ( ! efab->mac_op->init ( efab ) ) {
- EFAB_ERR ( "Failed reinitialising MAC\n" );
- return 0;
- }
- if ( efab->link_up ) {
- /* PHY init printed the message for us */
- return 1;
- }
- EFAB_ERR( "link is down" );
- sleep ( 1 );
+ if ( efab->pci_revision == FALCON_REV_B0 ) {
+ /* read the ISR */
+ falcon_readl( efab, &reg, INT_ISR0_B0 );
+ }
+ else {
+ /* write to the INT_ACK register */
+ falcon_writel ( efab, 0, FCN_INT_ACK_KER_REG_A1 );
+ mb();
+ falcon_readl ( efab, &reg,
+ WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 );
}
- EFAB_ERR ( " timed initialising MAC\n " );
+}
- return 0;
+static void
+falcon_handle_event ( struct efab_nic *efab, falcon_event_t *evt )
+{
+ int ev_code, desc_ptr, len, drop;
+
+ /* Decode event */
+ ev_code = EFAB_QWORD_FIELD ( *evt, FCN_EV_CODE );
+ switch ( ev_code ) {
+ case FCN_TX_IP_EV_DECODE:
+ desc_ptr = EFAB_QWORD_FIELD ( *evt, FCN_TX_EV_DESC_PTR );
+ efab_transmit_done ( efab, desc_ptr );
+ break;
+
+ case FCN_RX_IP_EV_DECODE:
+ desc_ptr = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_DESC_PTR );
+ len = EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_BYTE_CNT );
+ drop = !EFAB_QWORD_FIELD ( *evt, FCN_RX_EV_PKT_OK );
+
+ efab_receive ( efab, desc_ptr, len, drop );
+ break;
+
+ default:
+ EFAB_TRACE ( "Unknown event type %d\n", ev_code );
+ break;
+ }
}
-/**
- * Initialise NIC
+/*******************************************************************************
*
- */
-static int efab_init_nic ( struct efab_nic *efab ) {
- int i;
+ *
+ * Software (polling) interrupt handler
+ *
+ *
+ *******************************************************************************/
- /* Initialise NIC */
- if ( ! efab->op->init_nic ( efab ) )
- return 0;
+static void
+efab_poll ( struct net_device *netdev )
+{
+ struct efab_nic *efab = netdev_priv ( netdev );
+ struct efab_ev_queue *ev_queue = &efab->ev_queue;
+ struct efab_rx_queue *rx_queue = &efab->rx_queue;
+ falcon_event_t *evt;
- /* Push RX descriptors */
- for ( i = 0 ; i < EFAB_RX_BUFS ; i++ ) {
- efab_push_rx_buffer ( efab, &efab->rx_bufs[i] );
+ /* Read the event queue by directly looking for events
+ * (we don't even bother to read the eventq write ptr) */
+ evt = ev_queue->ring + ev_queue->read_ptr;
+ while ( falcon_event_present ( evt ) ) {
+
+ EFAB_TRACE ( "Event at index 0x%x address %p is "
+ EFAB_QWORD_FMT "\n", ev_queue->read_ptr,
+ evt, EFAB_QWORD_VAL ( *evt ) );
+
+ falcon_handle_event ( efab, evt );
+
+ /* Clear the event */
+ EFAB_SET_QWORD ( *evt );
+
+ /* Move to the next event. We don't ack the event
+ * queue until the end */
+ ev_queue->read_ptr = ( ( ev_queue->read_ptr + 1 ) %
+ EFAB_EVQ_SIZE );
+ evt = ev_queue->ring + ev_queue->read_ptr;
}
- /* Read MAC address from EEPROM */
- if ( ! efab->op->read_eeprom ( efab ) )
- return 0;
+ /* Push more buffers if needed */
+ (void) efab_fill_rx_queue ( efab, rx_queue );
- /* Initialise MAC and wait for link up */
- if ( ! efab_init_mac ( efab ) )
- return 0;
+ /* Clear any pending interrupts */
+ falcon_clear_interrupts ( efab );
- return 1;
+ /* Ack the event queue */
+ falcon_eventq_read_ack ( efab, ev_queue );
}
-/**************************************************************************
+static void
+efab_irq ( struct net_device *netdev, int enable )
+{
+ struct efab_nic *efab = netdev_priv ( netdev );
+ struct efab_ev_queue *ev_queue = &efab->ev_queue;
+
+ switch ( enable ) {
+ case 0:
+ falcon_interrupts ( efab, 0, 0 );
+ break;
+ case 1:
+ falcon_interrupts ( efab, 1, 0 );
+ falcon_eventq_read_ack ( efab, ev_queue );
+ break;
+ case 2:
+ falcon_interrupts ( efab, 1, 1 );
+ break;
+ }
+}
+
+/*******************************************************************************
*
- * Etherboot interface
*
- **************************************************************************
- */
+ * Software open/close
+ *
+ *
+ *******************************************************************************/
-/**************************************************************************
-POLL - Wait for a frame
-***************************************************************************/
-static int etherfabric_poll ( struct nic *nic, int retrieve ) {
- struct efab_nic *efab = nic->priv_data;
- struct efab_event event;
- static struct efab_rx_buf *rx_buf = NULL;
- int i, drop = 0;
-
- /* Process the event queue until we hit either a packet
- * received event or an empty event slot.
- */
- while ( ( rx_buf == NULL ) &&
- efab->op->fetch_event ( efab, &event ) ) {
- drop = event.drop;
- if ( event.type == EFAB_EV_TX ) {
- /* TX completed - mark as done */
- DBG ( "TX id %x complete\n",
- efab->tx_buf.id );
- } else if ( event.type == EFAB_EV_RX ) {
- /* RX - find corresponding buffer */
- for ( i = 0 ; i < EFAB_RX_BUFS ; i++ ) {
- if ( efab->rx_bufs[i].id == event.rx_id ) {
- rx_buf = &efab->rx_bufs[i];
- rx_buf->len = event.rx_len;
- DBG ( "RX id %x (len %x) received\n",
- rx_buf->id, rx_buf->len );
- break;
- }
- }
- if ( ! rx_buf ) {
- EFAB_ERR ( "Invalid RX ID %x\n", event.rx_id );
- }
- } else if ( event.type == EFAB_EV_NONE ) {
- DBG ( "Ignorable event\n" );
- } else {
- DBG ( "Unknown event\n" );
- }
- }
+static void
+efab_free_resources ( struct efab_nic *efab )
+{
+ struct efab_ev_queue *ev_queue = &efab->ev_queue;
+ struct efab_rx_queue *rx_queue = &efab->rx_queue;
+ struct efab_tx_queue *tx_queue = &efab->tx_queue;
+ int i;
- /* If there is no packet, return 0 */
- if ( ! rx_buf )
- return 0;
+ for ( i = 0; i < EFAB_NUM_RX_DESC; i++ ) {
+ if ( rx_queue->buf[i] )
+ free_iob ( rx_queue->buf[i] );
+ }
- /* drop this event if necessary */
- if ( drop ) {
- DBG( "discarding RX event\n" );
- return 0;
+ for ( i = 0; i < EFAB_TXD_SIZE; i++ ) {
+ if ( tx_queue->buf[i] )
+ netdev_tx_complete ( efab->netdev, tx_queue->buf[i] );
}
- /* If we don't want to retrieve it just yet, return 1 */
- if ( ! retrieve )
- return 1;
+ if ( rx_queue->ring )
+ falcon_free_special_buffer ( rx_queue->ring );
- /* There seems to be a hardware race. The event can show up
- * on the event FIFO before the DMA has completed, so we
- * insert a tiny delay. If this proves unreliable, we should
- * switch to using event DMA rather than the event FIFO, since
- * event DMA ordering is guaranteed.
- */
- udelay ( 2 );
+ if ( tx_queue->ring )
+ falcon_free_special_buffer ( tx_queue->ring );
- /* Copy packet contents */
- nic->packetlen = rx_buf->len;
- memcpy ( nic->packet, rx_buf->addr, nic->packetlen );
+ if ( ev_queue->ring )
+ falcon_free_special_buffer ( ev_queue->ring );
- /* Give this buffer back to the NIC */
- efab_push_rx_buffer ( efab, rx_buf );
+ memset ( rx_queue, 0, sizeof ( *rx_queue ) );
+ memset ( tx_queue, 0, sizeof ( *tx_queue ) );
+ memset ( ev_queue, 0, sizeof ( *ev_queue ) );
- /* Prepare to receive next packet */
- rx_buf = NULL;
+ /* Ensure subsequent buffer allocations start at id 0 */
+ efab->buffer_head = 0;
+}
- return 1;
+static int
+efab_alloc_resources ( struct efab_nic *efab )
+{
+ struct efab_ev_queue *ev_queue = &efab->ev_queue;
+ struct efab_rx_queue *rx_queue = &efab->rx_queue;
+ struct efab_tx_queue *tx_queue = &efab->tx_queue;
+ size_t bytes;
+
+ /* Allocate the hardware event queue */
+ bytes = sizeof ( falcon_event_t ) * EFAB_TXD_SIZE;
+ ev_queue->ring = falcon_alloc_special_buffer ( efab, bytes,
+ &ev_queue->entry );
+ if ( !ev_queue->ring )
+ goto fail1;
+
+ /* Initialise the hardware event queue */
+ memset ( ev_queue->ring, 0xff, bytes );
+
+ /* Allocate the hardware tx queue */
+ bytes = sizeof ( falcon_tx_desc_t ) * EFAB_TXD_SIZE;
+ tx_queue->ring = falcon_alloc_special_buffer ( efab, bytes,
+ &tx_queue->entry );
+ if ( ! tx_queue->ring )
+ goto fail2;
+
+ /* Allocate the hardware rx queue */
+ bytes = sizeof ( falcon_rx_desc_t ) * EFAB_RXD_SIZE;
+ rx_queue->ring = falcon_alloc_special_buffer ( efab, bytes,
+ &rx_queue->entry );
+ if ( ! rx_queue->ring )
+ goto fail3;
+
+ return 0;
+
+fail3:
+ falcon_free_special_buffer ( tx_queue->ring );
+ tx_queue->ring = NULL;
+fail2:
+ falcon_free_special_buffer ( ev_queue->ring );
+ ev_queue->ring = NULL;
+fail1:
+ return -ENOMEM;
}
-/**************************************************************************
-TRANSMIT - Transmit a frame
-***************************************************************************/
-static void etherfabric_transmit ( struct nic *nic, const char *dest,
- unsigned int type, unsigned int size,
- const char *data ) {
- struct efab_nic *efab = nic->priv_data;
- unsigned int nstype = htons ( type );
-
- /* Fill TX buffer, pad to ETH_ZLEN */
- memcpy ( efab->tx_buf.addr, dest, ETH_ALEN );
- memcpy ( efab->tx_buf.addr + ETH_ALEN, nic->node_addr, ETH_ALEN );
- memcpy ( efab->tx_buf.addr + 2 * ETH_ALEN, &nstype, 2 );
- memcpy ( efab->tx_buf.addr + ETH_HLEN, data, size );
- size += ETH_HLEN;
- while ( size < ETH_ZLEN ) {
- efab->tx_buf.addr[size++] = '\0';
- }
- efab->tx_buf.len = size;
-
- /* Push TX descriptor */
- efab_push_tx_buffer ( efab, &efab->tx_buf );
-
- /* Allow enough time for the packet to be transmitted. This
- * is a temporary hack until we update to the new driver API.
- */
- udelay ( 20 );
+static int
+efab_init_mac ( struct efab_nic *efab )
+{
+ int count, rc;
+
+ /* This can take several seconds */
+ EFAB_LOG ( "Waiting for link..\n" );
+ for ( count=0; count<5; count++ ) {
+ rc = efab->mac_op->init ( efab );
+ if ( rc ) {
+ EFAB_ERR ( "Failed reinitialising MAC, error %s\n",
+ strerror ( rc ));
+ return rc;
+ }
- return;
+ /* Sleep for 2s to wait for the link to settle, either
+ * because we want to use it, or because we're about
+ * to reset the mac anyway
+ */
+ sleep ( 2 );
+
+ if ( ! efab->link_up ) {
+ EFAB_ERR ( "!\n" );
+ continue;
+ }
+
+ EFAB_LOG ( "\n%dMbps %s-duplex\n",
+ ( efab->link_options & LPA_10000 ? 10000 :
+ ( efab->link_options & LPA_1000 ? 1000 :
+ ( efab->link_options & LPA_100 ? 100 : 10 ) ) ),
+ ( efab->link_options & LPA_DUPLEX ?
+ "full" : "half" ) );
+
+ /* TODO: Move link state handling to the poll() routine */
+ netdev_link_up ( efab->netdev );
+ return 0;
+ }
+
+ EFAB_ERR ( "timed initialising MAC\n" );
+ return -ETIMEDOUT;
}
-/**************************************************************************
-DISABLE - Turn off ethernet interface
-***************************************************************************/
-static void etherfabric_disable ( struct nic *nic ) {
- struct efab_nic *efab = nic->priv_data;
+static void
+efab_close ( struct net_device *netdev )
+{
+ struct efab_nic *efab = netdev_priv ( netdev );
- efab->op->reset ( efab );
- if ( efab->membase )
- iounmap ( efab->membase );
+ falcon_fini_resources ( efab );
+ efab_free_resources ( efab );
+ efab->board_op->fini ( efab );
+ falcon_reset ( efab );
}
-/**************************************************************************
-IRQ - handle interrupts
-***************************************************************************/
-static void etherfabric_irq ( struct nic *nic, irq_action_t action ) {
- struct efab_nic *efab = nic->priv_data;
-
- switch ( action ) {
- case DISABLE :
- efab->op->mask_irq ( efab, 1 );
- break;
- case ENABLE :
- efab->op->mask_irq ( efab, 0 );
- break;
- case FORCE :
- /* Force NIC to generate a receive interrupt */
- efab->op->generate_irq ( efab );
- break;
- }
+static int
+efab_open ( struct net_device *netdev )
+{
+ struct efab_nic *efab = netdev_priv ( netdev );
+ struct efab_rx_queue *rx_queue = &efab->rx_queue;
+ int rc;
+
+ rc = falcon_reset ( efab );
+ if ( rc )
+ goto fail1;
+
+ rc = efab->board_op->init ( efab );
+ if ( rc )
+ goto fail2;
- return;
+ rc = falcon_init_sram ( efab );
+ if ( rc )
+ goto fail3;
+
+ /* Configure descriptor caches before pushing hardware queues */
+ falcon_setup_nic ( efab );
+
+ rc = efab_alloc_resources ( efab );
+ if ( rc )
+ goto fail4;
+
+ falcon_init_resources ( efab );
+
+ /* Push rx buffers */
+ rc = efab_fill_rx_queue ( efab, rx_queue );
+ if ( rc )
+ goto fail5;
+
+ /* Try and bring the interface up */
+ rc = efab_init_mac ( efab );
+ if ( rc )
+ goto fail6;
+
+ return 0;
+
+fail6:
+fail5:
+ efab_free_resources ( efab );
+fail4:
+fail3:
+ efab->board_op->fini ( efab );
+fail2:
+ falcon_reset ( efab );
+fail1:
+ return rc;
}
-static struct nic_operations etherfabric_operations = {
- .connect = dummy_connect,
- .poll = etherfabric_poll,
- .transmit = etherfabric_transmit,
- .irq = etherfabric_irq,
+static struct net_device_operations efab_operations = {
+ .open = efab_open,
+ .close = efab_close,
+ .transmit = efab_transmit,
+ .poll = efab_poll,
+ .irq = efab_irq,
};
-/**************************************************************************
-PROBE - Look for an adapter, this routine's visible to the outside
-***************************************************************************/
-static int etherfabric_probe ( struct nic *nic, struct pci_device *pci ) {
- static struct efab_nic efab;
- static int nic_port = 1;
- struct efab_buffers *buffers;
- int i;
+static void
+efab_remove ( struct pci_device *pci )
+{
+ struct net_device *netdev = pci_get_drvdata ( pci );
+ struct efab_nic *efab = netdev_priv ( netdev );
- /* Set up our private data structure */
- nic->priv_data = &efab;
- memset ( &efab, 0, sizeof ( efab ) );
- memset ( &efab_buffers, 0, sizeof ( efab_buffers ) );
+ if ( efab->membase ) {
+ falcon_reset ( efab );
- /* Hook in appropriate operations table. Do this early. */
- if ( pci->device == EF1002_DEVID ) {
- efab.op = &ef1002_operations;
- } else {
- efab.op = &falcon_operations;
+ iounmap ( efab->membase );
+ efab->membase = NULL;
}
- /* Initialise efab data structure */
- efab.pci = pci;
- buffers = ( ( struct efab_buffers * )
- ( ( ( void * ) &efab_buffers ) +
- ( - virt_to_bus ( &efab_buffers ) ) % EFAB_BUF_ALIGN ) );
- efab.eventq = buffers->eventq;
- efab.txd = buffers->txd;
- efab.rxd = buffers->rxd;
- efab.tx_buf.addr = buffers->tx_buf;
- for ( i = 0 ; i < EFAB_RX_BUFS ; i++ ) {
- efab.rx_bufs[i].addr = buffers->rx_buf[i];
+ if ( efab->nvo.nvs ) {
+ unregister_nvo ( &efab->nvo );
+ efab->nvo.nvs = NULL;
}
- /* Enable the PCI device */
- adjust_pci_device ( pci );
- nic->ioaddr = pci->ioaddr & ~3;
- nic->irqno = pci->irq;
+ unregister_netdev ( netdev );
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+}
+
+static int
+efab_probe ( struct pci_device *pci,
+ const struct pci_device_id *id )
+{
+ struct net_device *netdev;
+ struct efab_nic *efab;
+ unsigned long mmio_start, mmio_len;
+ int rc;
+
+ /* Create the network adapter */
+ netdev = alloc_etherdev ( sizeof ( struct efab_nic ) );
+ if ( ! netdev ) {
+ rc = -ENOMEM;
+ goto fail1;
+ }
+
+ /* Initialise the network adapter, and initialise private storage */
+ netdev_init ( netdev, &efab_operations );
+ pci_set_drvdata ( pci, netdev );
+ netdev->dev = &pci->dev;
+
+ efab = netdev_priv ( netdev );
+ memset ( efab, 0, sizeof ( *efab ) );
+ efab->netdev = netdev;
/* Get iobase/membase */
- efab.iobase = nic->ioaddr;
- efab.op->get_membase ( &efab );
+ mmio_start = pci_bar_start ( pci, PCI_BASE_ADDRESS_2 );
+ mmio_len = pci_bar_size ( pci, PCI_BASE_ADDRESS_2 );
+ efab->membase = ioremap ( mmio_start, mmio_len );
+ EFAB_TRACE ( "BAR of %lx bytes at phys %lx mapped at %p\n",
+ mmio_len, mmio_start, efab->membase );
- /* Switch NIC ports (i.e. try different ports on each probe) */
- nic_port = 1 - nic_port;
- efab.port = nic_port;
+ /* Enable the PCI device */
+ adjust_pci_device ( pci );
+ efab->iobase = pci->ioaddr & ~3;
+
+ /* Determine the NIC variant */
+ falcon_probe_nic_variant ( efab, pci );
+
+ /* Read the SPI interface and determine the MAC address,
+ * and the board and phy variant. Hook in the op tables */
+ rc = falcon_probe_spi ( efab );
+ if ( rc )
+ goto fail2;
+ rc = falcon_probe_nvram ( efab );
+ if ( rc )
+ goto fail3;
+
+ memcpy ( netdev->ll_addr, efab->mac_addr, ETH_ALEN );
+
+ netdev_link_up ( netdev );
+ rc = register_netdev ( netdev );
+ if ( rc )
+ goto fail4;
+
+ /* Advertise non-volatile storage */
+ if ( efab->nvo.nvs ) {
+ rc = register_nvo ( &efab->nvo, netdev_settings ( netdev ) );
+ if ( rc )
+ goto fail5;
+ }
- /* Initialise hardware */
- if ( ! efab_init_nic ( &efab ) )
- return 0;
- memcpy ( nic->node_addr, efab.mac_addr, ETH_ALEN );
+ EFAB_LOG ( "Found %s EtherFabric %s %s revision %d\n", id->name,
+ efab->is_asic ? "ASIC" : "FPGA",
+ efab->phy_10g ? "10G" : "1G",
+ efab->pci_revision );
- /* point to NIC specific routines */
- nic->nic_op = &etherfabric_operations;
+ return 0;
- return 1;
+fail5:
+ unregister_netdev ( netdev );
+fail4:
+fail3:
+fail2:
+ iounmap ( efab->membase );
+ efab->membase = NULL;
+ netdev_put ( netdev );
+fail1:
+ return rc;
}
-static struct pci_device_id etherfabric_nics[] = {
-PCI_ROM(0x1924, 0xC101, "ef1002", "EtherFabric EF1002"),
-PCI_ROM(0x1924, 0x0703, "falcon", "EtherFabric Falcon"),
-};
-PCI_DRIVER ( etherfabric_driver, etherfabric_nics, PCI_NO_CLASS );
+static struct pci_device_id efab_nics[] = {
+ PCI_ROM(0x1924, 0x0703, "falcon", "EtherFabric Falcon"),
+ PCI_ROM(0x1924, 0x0710, "falconb0", "EtherFabric FalconB0"),
+};
-DRIVER ( "EFAB", nic_driver, pci_driver, etherfabric_driver,
- etherfabric_probe, etherfabric_disable );
+struct pci_driver etherfabric_driver __pci_driver = {
+ .ids = efab_nics,
+ .id_count = sizeof ( efab_nics ) / sizeof ( efab_nics[0] ),
+ .probe = efab_probe,
+ .remove = efab_remove,
+};
/*
* Local variables:
diff --git a/gpxe/src/drivers/net/etherfabric_nic.h b/gpxe/src/drivers/net/etherfabric_nic.h
new file mode 100644
index 00000000..4be50fbb
--- /dev/null
+++ b/gpxe/src/drivers/net/etherfabric_nic.h
@@ -0,0 +1,201 @@
+/**************************************************************************
+ *
+ * Etherboot driver for Level 5 Etherfabric network cards
+ *
+ * Written by Michael Brown <mbrown@fensystems.co.uk>
+ *
+ * Copyright Fen Systems Ltd. 2005
+ * Copyright Level 5 Networks Inc. 2005
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by
+ * reference. Drivers based on or derived from this code fall under
+ * the GPL and must retain the authorship, copyright and license
+ * notice.
+ *
+ **************************************************************************
+ */
+#ifndef EFAB_NIC_H
+#define EFAB_NIC_H
+#include <gpxe/bitbash.h>
+#include <gpxe/i2c.h>
+#include <gpxe/spi.h>
+#include <gpxe/nvo.h>
+#include <gpxe/if_ether.h>
+/**************************************************************************
+ *
+ * Constants and macros
+ *
+ **************************************************************************
+ */
+/* Board IDs. Early boards have no board_type, (e.g. EF1002 and 401/403)
+ * But newer boards are getting bigger...
+ */
+typedef enum {
+ EFAB_BOARD_INVALID = 0, /* Early boards do not have board rev. info. */
+ EFAB_BOARD_SFE4001 = 1,
+ EFAB_BOARD_SFE4002 = 2,
+ EFAB_BOARD_SFE4003 = 3,
+ /* Insert new types before here */
+ EFAB_BOARD_MAX
+} efab_board_type;
+
+/* PHY types. */
+typedef enum {
+ PHY_TYPE_AUTO = 0, /* on development board detect between CX4 & alaska */
+ PHY_TYPE_CX4_RTMR = 1,
+ PHY_TYPE_1GIG_ALASKA = 2,
+ PHY_TYPE_10XPRESS = 3,
+ PHY_TYPE_XFP = 4,
+ PHY_TYPE_CX4 = 5,
+ PHY_TYPE_PM8358 = 6,
+} phy_type_t;
+
+/**************************************************************************
+ *
+ * Hardware data structures and sizing
+ *
+ **************************************************************************
+ */
+
+#define dma_addr_t unsigned long
+typedef efab_qword_t falcon_rx_desc_t;
+typedef efab_qword_t falcon_tx_desc_t;
+typedef efab_qword_t falcon_event_t;
+
+#define EFAB_BUF_ALIGN 4096
+#define EFAB_RXD_SIZE 512
+#define EFAB_TXD_SIZE 512
+#define EFAB_EVQ_SIZE 512
+
+#define EFAB_NUM_RX_DESC 16
+#define EFAB_RX_BUF_SIZE 1600
+
+/**************************************************************************
+ *
+ * Data structures
+ *
+ **************************************************************************
+ */
+
+struct efab_nic;
+
+/* A buffer table allocation backing a tx dma, rx dma or eventq */
+struct efab_special_buffer {
+ dma_addr_t dma_addr;
+ int id;
+};
+
+/* A TX queue */
+struct efab_tx_queue {
+ /* The hardware ring */
+ falcon_tx_desc_t *ring;
+
+ /* The software ring storing io_buffers. */
+ struct io_buffer *buf[EFAB_TXD_SIZE];
+
+ /* The buffer table reservation pushed to hardware */
+ struct efab_special_buffer entry;
+
+ /* Software descriptor write ptr */
+ unsigned int write_ptr;
+
+ /* Hardware descriptor read ptr */
+ unsigned int read_ptr;
+};
+
+/* An RX queue */
+struct efab_rx_queue {
+ /* The hardware ring */
+ falcon_rx_desc_t *ring;
+
+ /* The software ring storing io_buffers */
+ struct io_buffer *buf[EFAB_NUM_RX_DESC];
+
+ /* The buffer table reservation pushed to hardware */
+ struct efab_special_buffer entry;
+
+ /* Descriptor write ptr, into both the hardware and software rings */
+ unsigned int write_ptr;
+
+ /* Hardware completion ptr */
+ unsigned int read_ptr;
+};
+
+/* An event queue */
+struct efab_ev_queue {
+ /* The hardware ring to push to hardware.
+ * Must be the first entry in the structure */
+ falcon_event_t *ring;
+
+ /* The buffer table reservation pushed to hardware */
+ struct efab_special_buffer entry;
+
+ /* Pointers into the ring */
+ unsigned int read_ptr;
+};
+
+struct efab_mac_operations {
+ int ( * init ) ( struct efab_nic *efab );
+};
+
+struct efab_phy_operations {
+ int ( * init ) ( struct efab_nic *efab );
+ unsigned int mmds;
+};
+
+struct efab_board_operations {
+ int ( * init ) ( struct efab_nic *efab );
+ void ( * fini ) ( struct efab_nic *efab );
+};
+
+struct efab_nic {
+ struct net_device *netdev;
+ int pci_revision;
+ int is_asic;
+
+ /* I2C bit-bashed interface */
+ struct i2c_bit_basher i2c_bb;
+
+ /** SPI bus and devices, and the user visible NVO area */
+ struct spi_bus spi_bus;
+ struct spi_device spi_flash;
+ struct spi_device spi_eeprom;
+ struct spi_device *spi;
+ struct nvo_block nvo;
+
+ /** Board, MAC, and PHY operations tables */
+ struct efab_board_operations *board_op;
+ struct efab_mac_operations *mac_op;
+ struct efab_phy_operations *phy_op;
+
+ /* PHY and board types */
+ int phy_addr;
+ int phy_type;
+ int phy_10g;
+ int board_type;
+
+ /** Memory and IO base */
+ void *membase;
+ unsigned int iobase;
+
+ /* Buffer table allocation head */
+ int buffer_head;
+
+ /* Queues */
+ struct efab_rx_queue rx_queue;
+ struct efab_tx_queue tx_queue;
+ struct efab_ev_queue ev_queue;
+
+ /** MAC address */
+ uint8_t mac_addr[ETH_ALEN];
+ /** GMII link options */
+ unsigned int link_options;
+ /** Link status */
+ int link_up;
+
+ /** INT_REG_KER */
+ efab_oword_t int_ker __attribute__ (( aligned ( 16 ) ));
+};
+#endif /* EFAB_NIC_H */
+
diff --git a/gpxe/src/drivers/net/forcedeth.c b/gpxe/src/drivers/net/forcedeth.c
index 54fadbd7..a30f1378 100644
--- a/gpxe/src/drivers/net/forcedeth.c
+++ b/gpxe/src/drivers/net/forcedeth.c
@@ -452,7 +452,7 @@ static int reg_delay(int offset, u32 mask,
delaymax -= delay;
if (delaymax < 0) {
if (msg)
- printf(msg);
+ printf("%s", msg);
return 1;
}
} while ((readl(base + offset) & mask) != target);
diff --git a/gpxe/src/drivers/net/ipoib.c b/gpxe/src/drivers/net/ipoib.c
index 16b2a0c8..8ad2c29f 100644
--- a/gpxe/src/drivers/net/ipoib.c
+++ b/gpxe/src/drivers/net/ipoib.c
@@ -33,9 +33,6 @@
* IP over Infiniband
*/
-/** IPoIB MTU */
-#define IPOIB_MTU 2048
-
/** Number of IPoIB data send work queue entries */
#define IPOIB_DATA_NUM_SEND_WQES 2
@@ -60,8 +57,6 @@ struct ipoib_queue_set {
struct ib_completion_queue *cq;
/** Queue pair */
struct ib_queue_pair *qp;
- /** Receive work queue fill level */
- unsigned int recv_fill;
/** Receive work queue maximum fill level */
unsigned int recv_max_fill;
};
@@ -90,49 +85,146 @@ struct ipoib_device {
int broadcast_attached;
};
+/** TID half used to identify get path record replies */
+#define IPOIB_TID_GET_PATH_REC 0x11111111UL
+
+/** TID half used to identify multicast member record replies */
+#define IPOIB_TID_MC_MEMBER_REC 0x22222222UL
+
+/** IPoIB metadata TID */
+static uint32_t ipoib_meta_tid = 0;
+
+/** Broadcast QPN used in IPoIB MAC addresses
+ *
+ * This is a guaranteed invalid real QPN
+ */
+#define IPOIB_BROADCAST_QPN 0xffffffffUL
+
+/** Broadcast IPoIB address */
+static struct ipoib_mac ipoib_broadcast = {
+ .qpn = ntohl ( IPOIB_BROADCAST_QPN ),
+ .gid.u.bytes = { 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff },
+};
+
+/****************************************************************************
+ *
+ * IPoIB peer cache
+ *
+ ****************************************************************************
+ */
+
/**
- * IPoIB path cache entry
+ * IPoIB peer address
*
* This serves a similar role to the ARP cache for Ethernet. (ARP
* *is* used on IPoIB; we have two caches to maintain.)
*/
-struct ipoib_cached_path {
- /** Destination GID */
- struct ib_gid gid;
- /** Destination LID */
- unsigned int dlid;
+struct ipoib_peer {
+ /** Key */
+ uint8_t key;
+ /** MAC address */
+ struct ipoib_mac mac;
+ /** LID */
+ unsigned int lid;
/** Service level */
unsigned int sl;
/** Rate */
unsigned int rate;
};
-/** Number of IPoIB path cache entries */
-#define IPOIB_NUM_CACHED_PATHS 2
+/** Number of IPoIB peer cache entries
+ *
+ * Must be a power of two.
+ */
+#define IPOIB_NUM_CACHED_PEERS 4
-/** IPoIB path cache */
-static struct ipoib_cached_path ipoib_path_cache[IPOIB_NUM_CACHED_PATHS];
+/** IPoIB peer address cache */
+static struct ipoib_peer ipoib_peer_cache[IPOIB_NUM_CACHED_PEERS];
-/** Oldest IPoIB path cache entry index */
-static unsigned int ipoib_path_cache_idx = 0;
+/** Oldest IPoIB peer cache entry index */
+static unsigned int ipoib_peer_cache_idx = 1;
-/** TID half used to identify get path record replies */
-#define IPOIB_TID_GET_PATH_REC 0x11111111UL
+/**
+ * Look up cached peer by key
+ *
+ * @v key Peer cache key
+ * @ret peer Peer cache entry, or NULL
+ */
+static struct ipoib_peer * ipoib_lookup_peer_by_key ( unsigned int key ) {
+ struct ipoib_peer *peer;
+ unsigned int i;
-/** TID half used to identify multicast member record replies */
-#define IPOIB_TID_MC_MEMBER_REC 0x22222222UL
+ for ( i = 0 ; i < IPOIB_NUM_CACHED_PEERS ; i++ ) {
+ peer = &ipoib_peer_cache[i];
+ if ( peer->key == key )
+ return peer;
+ }
-/** IPoIB metadata TID */
-static uint32_t ipoib_meta_tid = 0;
+ if ( key != 0 ) {
+ DBG ( "IPoIB warning: peer cache lost track of key %x while "
+ "still in use\n", key );
+ }
+ return NULL;
+}
-/** IPv4 broadcast GID */
-static const struct ib_gid ipv4_broadcast_gid = {
- { { 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff } }
-};
+/**
+ * Look up cached peer by GID
+ *
+ * @v gid Peer GID
+ * @ret peer Peer cache entry, or NULL
+ */
+static struct ipoib_peer *
+ipoib_lookup_peer_by_gid ( const struct ib_gid *gid ) {
+ struct ipoib_peer *peer;
+ unsigned int i;
+
+ for ( i = 0 ; i < IPOIB_NUM_CACHED_PEERS ; i++ ) {
+ peer = &ipoib_peer_cache[i];
+ if ( memcmp ( &peer->mac.gid, gid,
+ sizeof ( peer->mac.gid) ) == 0 ) {
+ return peer;
+ }
+ }
-/** Maximum time we will wait for the broadcast join to succeed */
-#define IPOIB_JOIN_MAX_DELAY_MS 1000
+ return NULL;
+}
+
+/**
+ * Store GID and QPN in peer cache
+ *
+ * @v gid Peer GID
+ * @v qpn Peer QPN
+ * @ret peer Peer cache entry
+ */
+static struct ipoib_peer *
+ipoib_cache_peer ( const struct ib_gid *gid, unsigned long qpn ) {
+ struct ipoib_peer *peer;
+ unsigned int key;
+
+ /* Look for existing cache entry */
+ peer = ipoib_lookup_peer_by_gid ( gid );
+ if ( peer ) {
+ assert ( peer->mac.qpn = ntohl ( qpn ) );
+ return peer;
+ }
+
+ /* No entry found: create a new one */
+ key = ipoib_peer_cache_idx++;
+ peer = &ipoib_peer_cache[ key % IPOIB_NUM_CACHED_PEERS ];
+ if ( peer->key )
+ DBG ( "IPoIB peer %x evicted from cache\n", peer->key );
+
+ memset ( peer, 0, sizeof ( *peer ) );
+ peer->key = key;
+ peer->mac.qpn = htonl ( qpn );
+ memcpy ( &peer->mac.gid, gid, sizeof ( peer->mac.gid ) );
+ DBG ( "IPoIB peer %x has GID %08x:%08x:%08x:%08x and QPN %lx\n",
+ peer->key, htonl ( gid->u.dwords[0] ),
+ htonl ( gid->u.dwords[1] ), htonl ( gid->u.dwords[2] ),
+ htonl ( gid->u.dwords[3] ), qpn );
+ return peer;
+}
/****************************************************************************
*
@@ -141,37 +233,32 @@ static const struct ib_gid ipv4_broadcast_gid = {
****************************************************************************
*/
-/** Broadcast QPN used in IPoIB MAC addresses
- *
- * This is a guaranteed invalid real QPN
- */
-#define IPOIB_BROADCAST_QPN 0xffffffffUL
-
-/** Broadcast IPoIB address */
-static struct ipoib_mac ipoib_broadcast = {
- .qpn = ntohl ( IPOIB_BROADCAST_QPN ),
-};
-
/**
* Add IPoIB link-layer header
*
* @v iobuf I/O buffer
- * @v netdev Network device
- * @v net_protocol Network-layer protocol
* @v ll_dest Link-layer destination address
+ * @v ll_source Source link-layer address
+ * @v net_proto Network-layer protocol, in network-byte order
+ * @ret rc Return status code
*/
-static int ipoib_push ( struct io_buffer *iobuf,
- struct net_device *netdev __unused,
- struct net_protocol *net_protocol,
- const void *ll_dest ) {
+static int ipoib_push ( struct io_buffer *iobuf, const void *ll_dest,
+ const void *ll_source __unused, uint16_t net_proto ) {
struct ipoib_hdr *ipoib_hdr =
iob_push ( iobuf, sizeof ( *ipoib_hdr ) );
+ const struct ipoib_mac *dest_mac = ll_dest;
+ const struct ipoib_mac *src_mac = ll_source;
+ struct ipoib_peer *dest;
+ struct ipoib_peer *src;
+
+ /* Add link-layer addresses to cache */
+ dest = ipoib_cache_peer ( &dest_mac->gid, ntohl ( dest_mac->qpn ) );
+ src = ipoib_cache_peer ( &src_mac->gid, ntohl ( src_mac->qpn ) );
/* Build IPoIB header */
- memcpy ( &ipoib_hdr->pseudo.peer, ll_dest,
- sizeof ( ipoib_hdr->pseudo.peer ) );
- ipoib_hdr->real.proto = net_protocol->net_proto;
- ipoib_hdr->real.reserved = 0;
+ ipoib_hdr->proto = net_proto;
+ ipoib_hdr->u.peer.dest = dest->key;
+ ipoib_hdr->u.peer.src = src->key;
return 0;
}
@@ -180,15 +267,16 @@ static int ipoib_push ( struct io_buffer *iobuf,
* Remove IPoIB link-layer header
*
* @v iobuf I/O buffer
- * @v netdev Network device
- * @v net_proto Network-layer protocol, in network-byte order
- * @v ll_source Source link-layer address
+ * @ret ll_dest Link-layer destination address
+ * @ret ll_source Source link-layer address
+ * @ret net_proto Network-layer protocol, in network-byte order
* @ret rc Return status code
*/
-static int ipoib_pull ( struct io_buffer *iobuf,
- struct net_device *netdev __unused,
- uint16_t *net_proto, const void **ll_source ) {
+static int ipoib_pull ( struct io_buffer *iobuf, const void **ll_dest,
+ const void **ll_source, uint16_t *net_proto ) {
struct ipoib_hdr *ipoib_hdr = iobuf->data;
+ struct ipoib_peer *dest;
+ struct ipoib_peer *source;
/* Sanity check */
if ( iob_len ( iobuf ) < sizeof ( *ipoib_hdr ) ) {
@@ -200,9 +288,17 @@ static int ipoib_pull ( struct io_buffer *iobuf,
/* Strip off IPoIB header */
iob_pull ( iobuf, sizeof ( *ipoib_hdr ) );
+ /* Identify source and destination addresses, and clear
+ * reserved word in IPoIB header
+ */
+ dest = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.dest );
+ source = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.src );
+ ipoib_hdr->u.reserved = 0;
+
/* Fill in required fields */
- *net_proto = ipoib_hdr->real.proto;
- *ll_source = &ipoib_hdr->pseudo.peer;
+ *ll_dest = ( dest ? &dest->mac : &ipoib_broadcast );
+ *ll_source = ( source ? &source->mac : &ipoib_broadcast );
+ *net_proto = ipoib_hdr->proto;
return 0;
}
@@ -217,7 +313,7 @@ const char * ipoib_ntoa ( const void *ll_addr ) {
static char buf[45];
const struct ipoib_mac *mac = ll_addr;
- snprintf ( buf, sizeof ( buf ), "%08lx:%08lx:%08lx:%08lx:%08lx",
+ snprintf ( buf, sizeof ( buf ), "%08x:%08x:%08x:%08x:%08x",
htonl ( mac->qpn ), htonl ( mac->gid.u.dwords[0] ),
htonl ( mac->gid.u.dwords[1] ),
htonl ( mac->gid.u.dwords[2] ),
@@ -225,6 +321,21 @@ const char * ipoib_ntoa ( const void *ll_addr ) {
return buf;
}
+/**
+ * Hash multicast address
+ *
+ * @v af Address family
+ * @v net_addr Network-layer address
+ * @v ll_addr Link-layer address to fill in
+ * @ret rc Return status code
+ */
+static int ipoib_mc_hash ( unsigned int af __unused,
+ const void *net_addr __unused,
+ void *ll_addr __unused ) {
+
+ return -ENOTSUP;
+}
+
/** IPoIB protocol */
struct ll_protocol ipoib_protocol __ll_protocol = {
.name = "IPoIB",
@@ -235,6 +346,7 @@ struct ll_protocol ipoib_protocol __ll_protocol = {
.push = ipoib_push,
.pull = ipoib_pull,
.ntoa = ipoib_ntoa,
+ .mc_hash = ipoib_mc_hash,
};
/****************************************************************************
@@ -266,11 +378,17 @@ static void ipoib_destroy_qset ( struct ipoib_device *ipoib,
*
* @v ipoib IPoIB device
* @v qset Queue set
+ * @v num_cqes Number of completion queue entries
+ * @v cq_op Completion queue operations
+ * @v num_send_wqes Number of send work queue entries
+ * @v num_recv_wqes Number of receive work queue entries
+ * @v qkey Queue key
* @ret rc Return status code
*/
static int ipoib_create_qset ( struct ipoib_device *ipoib,
struct ipoib_queue_set *qset,
unsigned int num_cqes,
+ struct ib_completion_queue_operations *cq_op,
unsigned int num_send_wqes,
unsigned int num_recv_wqes,
unsigned long qkey ) {
@@ -285,7 +403,7 @@ static int ipoib_create_qset ( struct ipoib_device *ipoib,
qset->recv_max_fill = num_recv_wqes;
/* Allocate completion queue */
- qset->cq = ib_create_cq ( ibdev, num_cqes );
+ qset->cq = ib_create_cq ( ibdev, num_cqes, cq_op );
if ( ! qset->cq ) {
DBGC ( ipoib, "IPoIB %p could not allocate completion queue\n",
ipoib );
@@ -312,28 +430,6 @@ static int ipoib_create_qset ( struct ipoib_device *ipoib,
}
/**
- * Find path cache entry by GID
- *
- * @v gid GID
- * @ret entry Path cache entry, or NULL
- */
-static struct ipoib_cached_path *
-ipoib_find_cached_path ( struct ib_gid *gid ) {
- struct ipoib_cached_path *path;
- unsigned int i;
-
- for ( i = 0 ; i < IPOIB_NUM_CACHED_PATHS ; i++ ) {
- path = &ipoib_path_cache[i];
- if ( memcmp ( &path->gid, gid, sizeof ( *gid ) ) == 0 )
- return path;
- }
- DBG ( "IPoIB %08lx:%08lx:%08lx:%08lx cache miss\n",
- htonl ( gid->u.dwords[0] ), htonl ( gid->u.dwords[1] ),
- htonl ( gid->u.dwords[2] ), htonl ( gid->u.dwords[3] ) );
- return NULL;
-}
-
-/**
* Transmit path record request
*
* @v ipoib IPoIB device
@@ -344,36 +440,38 @@ static int ipoib_get_path_record ( struct ipoib_device *ipoib,
struct ib_gid *gid ) {
struct ib_device *ibdev = ipoib->ibdev;
struct io_buffer *iobuf;
- struct ib_mad_path_record *path_record;
+ struct ib_mad_sa *sa;
struct ib_address_vector av;
int rc;
/* Allocate I/O buffer */
- iobuf = alloc_iob ( sizeof ( *path_record ) );
+ iobuf = alloc_iob ( sizeof ( *sa ) );
if ( ! iobuf )
return -ENOMEM;
- iob_put ( iobuf, sizeof ( *path_record ) );
- path_record = iobuf->data;
- memset ( path_record, 0, sizeof ( *path_record ) );
+ iob_put ( iobuf, sizeof ( *sa ) );
+ sa = iobuf->data;
+ memset ( sa, 0, sizeof ( *sa ) );
/* Construct path record request */
- path_record->mad_hdr.base_version = IB_MGMT_BASE_VERSION;
- path_record->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
- path_record->mad_hdr.class_version = 2;
- path_record->mad_hdr.method = IB_MGMT_METHOD_GET;
- path_record->mad_hdr.attr_id = htons ( IB_SA_ATTR_PATH_REC );
- path_record->mad_hdr.tid[0] = IPOIB_TID_GET_PATH_REC;
- path_record->mad_hdr.tid[1] = ipoib_meta_tid++;
- path_record->sa_hdr.comp_mask[1] =
+ sa->mad_hdr.base_version = IB_MGMT_BASE_VERSION;
+ sa->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
+ sa->mad_hdr.class_version = 2;
+ sa->mad_hdr.method = IB_MGMT_METHOD_GET;
+ sa->mad_hdr.attr_id = htons ( IB_SA_ATTR_PATH_REC );
+ sa->mad_hdr.tid[0] = IPOIB_TID_GET_PATH_REC;
+ sa->mad_hdr.tid[1] = ipoib_meta_tid++;
+ sa->sa_hdr.comp_mask[1] =
htonl ( IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID );
- memcpy ( &path_record->dgid, gid, sizeof ( path_record->dgid ) );
- memcpy ( &path_record->sgid, &ibdev->port_gid,
- sizeof ( path_record->sgid ) );
+ memcpy ( &sa->sa_data.path_record.dgid, gid,
+ sizeof ( sa->sa_data.path_record.dgid ) );
+ memcpy ( &sa->sa_data.path_record.sgid, &ibdev->gid,
+ sizeof ( sa->sa_data.path_record.sgid ) );
/* Construct address vector */
memset ( &av, 0, sizeof ( av ) );
- av.dlid = ibdev->sm_lid;
- av.dest_qp = IB_SA_QPN;
+ av.lid = ibdev->sm_lid;
+ av.sl = ibdev->sm_sl;
+ av.qpn = IB_SA_QPN;
av.qkey = IB_GLOBAL_QKEY;
/* Post send request */
@@ -400,40 +498,41 @@ static int ipoib_mc_member_record ( struct ipoib_device *ipoib,
struct ib_gid *gid, int join ) {
struct ib_device *ibdev = ipoib->ibdev;
struct io_buffer *iobuf;
- struct ib_mad_mc_member_record *mc_member_record;
+ struct ib_mad_sa *sa;
struct ib_address_vector av;
int rc;
/* Allocate I/O buffer */
- iobuf = alloc_iob ( sizeof ( *mc_member_record ) );
+ iobuf = alloc_iob ( sizeof ( *sa ) );
if ( ! iobuf )
return -ENOMEM;
- iob_put ( iobuf, sizeof ( *mc_member_record ) );
- mc_member_record = iobuf->data;
- memset ( mc_member_record, 0, sizeof ( *mc_member_record ) );
+ iob_put ( iobuf, sizeof ( *sa ) );
+ sa = iobuf->data;
+ memset ( sa, 0, sizeof ( *sa ) );
/* Construct path record request */
- mc_member_record->mad_hdr.base_version = IB_MGMT_BASE_VERSION;
- mc_member_record->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
- mc_member_record->mad_hdr.class_version = 2;
- mc_member_record->mad_hdr.method =
+ sa->mad_hdr.base_version = IB_MGMT_BASE_VERSION;
+ sa->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
+ sa->mad_hdr.class_version = 2;
+ sa->mad_hdr.method =
( join ? IB_MGMT_METHOD_SET : IB_MGMT_METHOD_DELETE );
- mc_member_record->mad_hdr.attr_id = htons ( IB_SA_ATTR_MC_MEMBER_REC );
- mc_member_record->mad_hdr.tid[0] = IPOIB_TID_MC_MEMBER_REC;
- mc_member_record->mad_hdr.tid[1] = ipoib_meta_tid++;
- mc_member_record->sa_hdr.comp_mask[1] =
+ sa->mad_hdr.attr_id = htons ( IB_SA_ATTR_MC_MEMBER_REC );
+ sa->mad_hdr.tid[0] = IPOIB_TID_MC_MEMBER_REC;
+ sa->mad_hdr.tid[1] = ipoib_meta_tid++;
+ sa->sa_hdr.comp_mask[1] =
htonl ( IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID |
IB_SA_MCMEMBER_REC_JOIN_STATE );
- mc_member_record->scope__join_state = 1;
- memcpy ( &mc_member_record->mgid, gid,
- sizeof ( mc_member_record->mgid ) );
- memcpy ( &mc_member_record->port_gid, &ibdev->port_gid,
- sizeof ( mc_member_record->port_gid ) );
+ sa->sa_data.mc_member_record.scope__join_state = 1;
+ memcpy ( &sa->sa_data.mc_member_record.mgid, gid,
+ sizeof ( sa->sa_data.mc_member_record.mgid ) );
+ memcpy ( &sa->sa_data.mc_member_record.port_gid, &ibdev->gid,
+ sizeof ( sa->sa_data.mc_member_record.port_gid ) );
/* Construct address vector */
memset ( &av, 0, sizeof ( av ) );
- av.dlid = ibdev->sm_lid;
- av.dest_qp = IB_SA_QPN;
+ av.lid = ibdev->sm_lid;
+ av.sl = ibdev->sm_sl;
+ av.qpn = IB_SA_QPN;
av.qkey = IB_GLOBAL_QKEY;
/* Post send request */
@@ -459,49 +558,51 @@ static int ipoib_transmit ( struct net_device *netdev,
struct io_buffer *iobuf ) {
struct ipoib_device *ipoib = netdev->priv;
struct ib_device *ibdev = ipoib->ibdev;
- struct ipoib_pseudo_hdr *ipoib_pshdr = iobuf->data;
+ struct ipoib_hdr *ipoib_hdr;
+ struct ipoib_peer *dest;
struct ib_address_vector av;
struct ib_gid *gid;
- struct ipoib_cached_path *path;
- int rc;
/* Sanity check */
- if ( iob_len ( iobuf ) < sizeof ( *ipoib_pshdr ) ) {
+ if ( iob_len ( iobuf ) < sizeof ( *ipoib_hdr ) ) {
DBGC ( ipoib, "IPoIB %p buffer too short\n", ipoib );
return -EINVAL;
}
- iob_pull ( iobuf, ( sizeof ( *ipoib_pshdr ) ) );
+ ipoib_hdr = iobuf->data;
/* Attempting transmission while link is down will put the
* queue pair into an error state, so don't try it.
*/
- if ( ! ibdev->link_up )
+ if ( ! ib_link_ok ( ibdev ) )
return -ENETUNREACH;
+ /* Identify destination address */
+ dest = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.dest );
+ if ( ! dest )
+ return -ENXIO;
+ ipoib_hdr->u.reserved = 0;
+
/* Construct address vector */
memset ( &av, 0, sizeof ( av ) );
- av.qkey = IB_GLOBAL_QKEY;
+ av.qkey = ipoib->data_qkey;
av.gid_present = 1;
- if ( ipoib_pshdr->peer.qpn == htonl ( IPOIB_BROADCAST_QPN ) ) {
- /* Broadcast address */
- av.dest_qp = IB_BROADCAST_QPN;
- av.dlid = ipoib->broadcast_lid;
+ if ( dest->mac.qpn == htonl ( IPOIB_BROADCAST_QPN ) ) {
+ /* Broadcast */
+ av.qpn = IB_BROADCAST_QPN;
+ av.lid = ipoib->broadcast_lid;
gid = &ipoib->broadcast_gid;
} else {
- /* Unicast - look in path cache */
- path = ipoib_find_cached_path ( &ipoib_pshdr->peer.gid );
- if ( ! path ) {
- /* No path entry - get path record */
- rc = ipoib_get_path_record ( ipoib,
- &ipoib_pshdr->peer.gid );
- netdev_tx_complete ( netdev, iobuf );
- return rc;
+ /* Unicast */
+ if ( ! dest->lid ) {
+ /* No LID yet - get path record to fetch LID */
+ ipoib_get_path_record ( ipoib, &dest->mac.gid );
+ return -ENOENT;
}
- av.dest_qp = ntohl ( ipoib_pshdr->peer.qpn );
- av.dlid = path->dlid;
- av.rate = path->rate;
- av.sl = path->sl;
- gid = &ipoib_pshdr->peer.gid;
+ av.qpn = ntohl ( dest->mac.qpn );
+ av.lid = dest->lid;
+ av.rate = dest->rate;
+ av.sl = dest->sl;
+ gid = &dest->mac.gid;
}
memcpy ( &av.gid, gid, sizeof ( av.gid ) );
@@ -513,17 +614,15 @@ static int ipoib_transmit ( struct net_device *netdev,
*
* @v ibdev Infiniband device
* @v qp Queue pair
- * @v completion Completion
* @v iobuf I/O buffer
+ * @v rc Completion status code
*/
static void ipoib_data_complete_send ( struct ib_device *ibdev __unused,
struct ib_queue_pair *qp,
- struct ib_completion *completion,
- struct io_buffer *iobuf ) {
+ struct io_buffer *iobuf, int rc ) {
struct net_device *netdev = ib_qp_get_ownerdata ( qp );
- netdev_tx_complete_err ( netdev, iobuf,
- ( completion->syndrome ? -EIO : 0 ) );
+ netdev_tx_complete_err ( netdev, iobuf, rc );
}
/**
@@ -531,67 +630,67 @@ static void ipoib_data_complete_send ( struct ib_device *ibdev __unused,
*
* @v ibdev Infiniband device
* @v qp Queue pair
- * @v completion Completion
+ * @v av Address vector, or NULL
* @v iobuf I/O buffer
+ * @v rc Completion status code
*/
static void ipoib_data_complete_recv ( struct ib_device *ibdev __unused,
struct ib_queue_pair *qp,
- struct ib_completion *completion,
- struct io_buffer *iobuf ) {
+ struct ib_address_vector *av,
+ struct io_buffer *iobuf, int rc ) {
struct net_device *netdev = ib_qp_get_ownerdata ( qp );
struct ipoib_device *ipoib = netdev->priv;
- struct ipoib_pseudo_hdr *ipoib_pshdr;
+ struct ipoib_hdr *ipoib_hdr;
+ struct ipoib_peer *src;
- if ( completion->syndrome ) {
- netdev_rx_err ( netdev, iobuf, -EIO );
- goto done;
- }
-
- iob_put ( iobuf, completion->len );
- if ( iob_len ( iobuf ) < sizeof ( struct ib_global_route_header ) ) {
- DBGC ( ipoib, "IPoIB %p received data packet too short to "
- "contain GRH\n", ipoib );
- DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) );
- netdev_rx_err ( netdev, iobuf, -EIO );
- goto done;
+ if ( rc != 0 ) {
+ netdev_rx_err ( netdev, iobuf, rc );
+ return;
}
- iob_pull ( iobuf, sizeof ( struct ib_global_route_header ) );
- if ( iob_len ( iobuf ) < sizeof ( struct ipoib_real_hdr ) ) {
+ /* Sanity check */
+ if ( iob_len ( iobuf ) < sizeof ( struct ipoib_hdr ) ) {
DBGC ( ipoib, "IPoIB %p received data packet too short to "
"contain IPoIB header\n", ipoib );
DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) );
netdev_rx_err ( netdev, iobuf, -EIO );
- goto done;
+ return;
}
+ ipoib_hdr = iobuf->data;
- ipoib_pshdr = iob_push ( iobuf, sizeof ( *ipoib_pshdr ) );
- /* FIXME: fill in a MAC address for the sake of AoE! */
+ /* Parse source address */
+ if ( av->gid_present ) {
+ src = ipoib_cache_peer ( &av->gid, av->qpn );
+ ipoib_hdr->u.peer.src = src->key;
+ }
+ /* Hand off to network layer */
netdev_rx ( netdev, iobuf );
-
- done:
- ipoib->data.recv_fill--;
}
+/** IPoIB data completion operations */
+static struct ib_completion_queue_operations ipoib_data_cq_op = {
+ .complete_send = ipoib_data_complete_send,
+ .complete_recv = ipoib_data_complete_recv,
+};
+
/**
* Handle IPoIB metadata send completion
*
* @v ibdev Infiniband device
* @v qp Queue pair
- * @v completion Completion
* @v iobuf I/O buffer
+ * @v rc Completion status code
*/
static void ipoib_meta_complete_send ( struct ib_device *ibdev __unused,
struct ib_queue_pair *qp,
- struct ib_completion *completion,
- struct io_buffer *iobuf ) {
+ struct io_buffer *iobuf, int rc ) {
struct net_device *netdev = ib_qp_get_ownerdata ( qp );
struct ipoib_device *ipoib = netdev->priv;
- if ( completion->syndrome ) {
- DBGC ( ipoib, "IPoIB %p metadata TX completion error %x\n",
- ipoib, completion->syndrome );
+ if ( rc != 0 ) {
+ DBGC ( ipoib, "IPoIB %p metadata TX completion error: %s\n",
+ ipoib, strerror ( rc ) );
}
free_iob ( iobuf );
}
@@ -602,26 +701,25 @@ static void ipoib_meta_complete_send ( struct ib_device *ibdev __unused,
* @v ipoib IPoIB device
* @v path_record Path record
*/
-static void ipoib_recv_path_record ( struct ipoib_device *ipoib __unused,
- struct ib_mad_path_record *path_record ) {
- struct ipoib_cached_path *path;
+static void ipoib_recv_path_record ( struct ipoib_device *ipoib,
+ struct ib_path_record *path_record ) {
+ struct ipoib_peer *peer;
+
+ /* Locate peer cache entry */
+ peer = ipoib_lookup_peer_by_gid ( &path_record->dgid );
+ if ( ! peer ) {
+ DBGC ( ipoib, "IPoIB %p received unsolicited path record\n",
+ ipoib );
+ return;
+ }
/* Update path cache entry */
- path = &ipoib_path_cache[ipoib_path_cache_idx];
- memcpy ( &path->gid, &path_record->dgid, sizeof ( path->gid ) );
- path->dlid = ntohs ( path_record->dlid );
- path->sl = ( path_record->reserved__sl & 0x0f );
- path->rate = ( path_record->rate_selector__rate & 0x3f );
-
- DBG ( "IPoIB %08lx:%08lx:%08lx:%08lx dlid %x sl %x rate %x\n",
- htonl ( path->gid.u.dwords[0] ), htonl ( path->gid.u.dwords[1] ),
- htonl ( path->gid.u.dwords[2] ), htonl ( path->gid.u.dwords[3] ),
- path->dlid, path->sl, path->rate );
-
- /* Update path cache index */
- ipoib_path_cache_idx++;
- if ( ipoib_path_cache_idx == IPOIB_NUM_CACHED_PATHS )
- ipoib_path_cache_idx = 0;
+ peer->lid = ntohs ( path_record->dlid );
+ peer->sl = ( path_record->reserved__sl & 0x0f );
+ peer->rate = ( path_record->rate_selector__rate & 0x3f );
+
+ DBG ( "IPoIB peer %x has dlid %x sl %x rate %x\n",
+ peer->key, peer->lid, peer->sl, peer->rate );
}
/**
@@ -631,7 +729,7 @@ static void ipoib_recv_path_record ( struct ipoib_device *ipoib __unused,
* @v mc_member_record Multicast membership record
*/
static void ipoib_recv_mc_member_record ( struct ipoib_device *ipoib,
- struct ib_mad_mc_member_record *mc_member_record ) {
+ struct ib_mc_member_record *mc_member_record ) {
int joined;
int rc;
@@ -657,64 +755,64 @@ static void ipoib_recv_mc_member_record ( struct ipoib_device *ipoib,
*
* @v ibdev Infiniband device
* @v qp Queue pair
- * @v completion Completion
+ * @v av Address vector, or NULL
* @v iobuf I/O buffer
+ * @v rc Completion status code
*/
-static void ipoib_meta_complete_recv ( struct ib_device *ibdev __unused,
- struct ib_queue_pair *qp,
- struct ib_completion *completion,
- struct io_buffer *iobuf ) {
+static void
+ipoib_meta_complete_recv ( struct ib_device *ibdev __unused,
+ struct ib_queue_pair *qp,
+ struct ib_address_vector *av __unused,
+ struct io_buffer *iobuf, int rc ) {
struct net_device *netdev = ib_qp_get_ownerdata ( qp );
struct ipoib_device *ipoib = netdev->priv;
- union ib_mad *mad;
+ struct ib_mad_sa *sa;
- if ( completion->syndrome ) {
- DBGC ( ipoib, "IPoIB %p metadata RX completion error %x\n",
- ipoib, completion->syndrome );
+ if ( rc != 0 ) {
+ DBGC ( ipoib, "IPoIB %p metadata RX completion error: %s\n",
+ ipoib, strerror ( rc ) );
goto done;
}
- iob_put ( iobuf, completion->len );
- if ( iob_len ( iobuf ) < sizeof ( struct ib_global_route_header ) ) {
- DBGC ( ipoib, "IPoIB %p received metadata packet too short "
- "to contain GRH\n", ipoib );
- DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) );
- goto done;
- }
- iob_pull ( iobuf, sizeof ( struct ib_global_route_header ) );
- if ( iob_len ( iobuf ) < sizeof ( *mad ) ) {
+ if ( iob_len ( iobuf ) < sizeof ( *sa ) ) {
DBGC ( ipoib, "IPoIB %p received metadata packet too short "
"to contain reply\n", ipoib );
DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) );
goto done;
}
- mad = iobuf->data;
+ sa = iobuf->data;
- if ( mad->mad_hdr.status != 0 ) {
+ if ( sa->mad_hdr.status != 0 ) {
DBGC ( ipoib, "IPoIB %p metadata RX err status %04x\n",
- ipoib, ntohs ( mad->mad_hdr.status ) );
+ ipoib, ntohs ( sa->mad_hdr.status ) );
goto done;
}
- switch ( mad->mad_hdr.tid[0] ) {
+ switch ( sa->mad_hdr.tid[0] ) {
case IPOIB_TID_GET_PATH_REC:
- ipoib_recv_path_record ( ipoib, &mad->path_record );
+ ipoib_recv_path_record ( ipoib, &sa->sa_data.path_record );
break;
case IPOIB_TID_MC_MEMBER_REC:
- ipoib_recv_mc_member_record ( ipoib, &mad->mc_member_record );
+ ipoib_recv_mc_member_record ( ipoib,
+ &sa->sa_data.mc_member_record );
break;
default:
DBGC ( ipoib, "IPoIB %p unwanted response:\n",
ipoib );
- DBGC_HD ( ipoib, mad, sizeof ( *mad ) );
+ DBGC_HD ( ipoib, sa, sizeof ( *sa ) );
break;
}
done:
- ipoib->meta.recv_fill--;
free_iob ( iobuf );
}
+/** IPoIB metadata completion operations */
+static struct ib_completion_queue_operations ipoib_meta_cq_op = {
+ .complete_send = ipoib_meta_complete_send,
+ .complete_recv = ipoib_meta_complete_recv,
+};
+
/**
* Refill IPoIB receive ring
*
@@ -726,15 +824,14 @@ static void ipoib_refill_recv ( struct ipoib_device *ipoib,
struct io_buffer *iobuf;
int rc;
- while ( qset->recv_fill < qset->recv_max_fill ) {
- iobuf = alloc_iob ( IPOIB_MTU );
+ while ( qset->qp->recv.fill < qset->recv_max_fill ) {
+ iobuf = alloc_iob ( IPOIB_PKT_LEN );
if ( ! iobuf )
break;
if ( ( rc = ib_post_recv ( ibdev, qset->qp, iobuf ) ) != 0 ) {
free_iob ( iobuf );
break;
}
- qset->recv_fill++;
}
}
@@ -747,10 +844,8 @@ static void ipoib_poll ( struct net_device *netdev ) {
struct ipoib_device *ipoib = netdev->priv;
struct ib_device *ibdev = ipoib->ibdev;
- ib_poll_cq ( ibdev, ipoib->meta.cq, ipoib_meta_complete_send,
- ipoib_meta_complete_recv );
- ib_poll_cq ( ibdev, ipoib->data.cq, ipoib_data_complete_send,
- ipoib_data_complete_recv );
+ ib_poll_cq ( ibdev, ipoib->meta.cq );
+ ib_poll_cq ( ibdev, ipoib->data.cq );
ipoib_refill_recv ( ipoib, &ipoib->meta );
ipoib_refill_recv ( ipoib, &ipoib->data );
}
@@ -831,9 +926,17 @@ static int ipoib_open ( struct net_device *netdev ) {
struct ipoib_mac *mac = ( ( struct ipoib_mac * ) netdev->ll_addr );
int rc;
+ /* Open IB device */
+ if ( ( rc = ib_open ( ipoib->ibdev ) ) != 0 ) {
+ DBGC ( ipoib, "IPoIB %p could not open device: %s\n",
+ ipoib, strerror ( rc ) );
+ goto err_ib_open;
+ }
+
/* Allocate metadata queue set */
if ( ( rc = ipoib_create_qset ( ipoib, &ipoib->meta,
IPOIB_META_NUM_CQES,
+ &ipoib_meta_cq_op,
IPOIB_META_NUM_SEND_WQES,
IPOIB_META_NUM_RECV_WQES,
IB_GLOBAL_QKEY ) ) != 0 ) {
@@ -845,6 +948,7 @@ static int ipoib_open ( struct net_device *netdev ) {
/* Allocate data queue set */
if ( ( rc = ipoib_create_qset ( ipoib, &ipoib->data,
IPOIB_DATA_NUM_CQES,
+ &ipoib_data_cq_op,
IPOIB_DATA_NUM_SEND_WQES,
IPOIB_DATA_NUM_RECV_WQES,
IB_GLOBAL_QKEY ) ) != 0 ) {
@@ -874,6 +978,8 @@ static int ipoib_open ( struct net_device *netdev ) {
err_create_data_qset:
ipoib_destroy_qset ( ipoib, &ipoib->meta );
err_create_meta_qset:
+ ib_close ( ipoib->ibdev );
+ err_ib_open:
return rc;
}
@@ -895,6 +1001,9 @@ static void ipoib_close ( struct net_device *netdev ) {
/* Tear down the queues */
ipoib_destroy_qset ( ipoib, &ipoib->data );
ipoib_destroy_qset ( ipoib, &ipoib->meta );
+
+ /* Close IB device */
+ ib_close ( ipoib->ibdev );
}
/** IPoIB network device operations */
@@ -923,15 +1032,15 @@ static void ipoib_set_ib_params ( struct ipoib_device *ipoib ) {
/* Calculate GID portion of MAC address based on port GID */
mac = ( ( struct ipoib_mac * ) netdev->ll_addr );
- memcpy ( &mac->gid, &ibdev->port_gid, sizeof ( mac->gid ) );
+ memcpy ( &mac->gid, &ibdev->gid, sizeof ( mac->gid ) );
/* Calculate broadcast GID based on partition key */
- memcpy ( &ipoib->broadcast_gid, &ipv4_broadcast_gid,
+ memcpy ( &ipoib->broadcast_gid, &ipoib_broadcast.gid,
sizeof ( ipoib->broadcast_gid ) );
ipoib->broadcast_gid.u.words[2] = htons ( ibdev->pkey );
/* Set net device link state to reflect Infiniband link state */
- if ( ibdev->link_up ) {
+ if ( ib_link_ok ( ibdev ) ) {
netdev_link_up ( netdev );
} else {
netdev_link_down ( netdev );
diff --git a/gpxe/src/drivers/net/mtnic.c b/gpxe/src/drivers/net/mtnic.c
index dd577f4a..0d84a44c 100755..100644
--- a/gpxe/src/drivers/net/mtnic.c
+++ b/gpxe/src/drivers/net/mtnic.c
@@ -30,13 +30,13 @@
* SOFTWARE.
*
*/
-#include <stdio.h>
#include <strings.h>
#include <errno.h>
#include <gpxe/malloc.h>
#include <gpxe/umalloc.h>
#include <byteswap.h>
#include <unistd.h>
+#include <gpxe/io.h>
#include <gpxe/pci.h>
#include <gpxe/ethernet.h>
#include <gpxe/netdevice.h>
@@ -47,28 +47,12 @@
/*
- mtnic.c - gPXE driver for Mellanox 10Gig ConnectX EN
+ mtnic.c - gPXE driver for Mellanox 10Gig ConnectX EN
*/
-/* (mcb30) - The Mellanox driver used "1" as a universal error code;
- * this at least makes it a valid error number.
- */
-#define MTNIC_ERROR -EIO
-
-
-/** Set port number to use
- *
- * 0 - port 1
- * 1 - port 2
- */
-#define MTNIC_PORT_NUM 0
-/* Note: for verbose printing do Make ... DEBUG=mtnic */
-
-
-
/********************************************************************
*
@@ -87,11 +71,11 @@
* and it's physical aligned address in 'pa'
*/
static int
-mtnic_alloc_aligned(unsigned int size, void **va, u32 *pa, unsigned int alignment)
+mtnic_alloc_aligned(unsigned int size, void **va, unsigned long *pa, unsigned int alignment)
{
*va = alloc_memblock(size, alignment);
if (!*va) {
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
*pa = (u32)virt_to_bus(*va);
return 0;
@@ -105,21 +89,21 @@ mtnic_alloc_aligned(unsigned int size, void **va, u32 *pa, unsigned int alignmen
*
*/
static int
-mtnic_alloc_cmdif(struct mtnic_priv *priv)
+mtnic_alloc_cmdif(struct mtnic *mtnic)
{
- u32 bar = mtnic_pci_dev.dev.bar[0];
+ u32 bar = mtnic_pci_dev.dev.bar[0];
- priv->hcr = ioremap(bar + MTNIC_HCR_BASE, MTNIC_HCR_SIZE);
- if (!priv->hcr) {
- DBG("Couldn't map command register.");
- return MTNIC_ERROR;
+ mtnic->hcr = ioremap(bar + MTNIC_HCR_BASE, MTNIC_HCR_SIZE);
+ if ( !mtnic->hcr ) {
+ DBG("Couldn't map command register\n");
+ return -EADDRINUSE;
}
- mtnic_alloc_aligned(PAGE_SIZE, (void *)&priv->cmd.buf, &priv->cmd.mapping, PAGE_SIZE);
- if (!priv->cmd.buf) {
+ mtnic_alloc_aligned(PAGE_SIZE, (void *)&mtnic->cmd.buf, &mtnic->cmd.mapping, PAGE_SIZE);
+ if ( !mtnic->cmd.buf ) {
DBG("Error in allocating buffer for command interface\n");
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
- return 0;
+ return 0;
}
/**
@@ -128,12 +112,13 @@ mtnic_alloc_cmdif(struct mtnic_priv *priv)
static void
mtnic_free_io_buffers(struct mtnic_ring *ring)
{
- int index;
+ int index;
for (; ring->cons <= ring->prod; ++ring->cons) {
index = ring->cons & ring->size_mask;
- if (ring->iobuf[index])
+ if ( ring->iobuf[index] ) {
free_iob(ring->iobuf[index]);
+ }
}
}
@@ -145,7 +130,7 @@ mtnic_free_io_buffers(struct mtnic_ring *ring)
*
*/
static int
-mtnic_alloc_iobuf(struct mtnic_priv *priv, struct mtnic_ring *ring,
+mtnic_alloc_iobuf(struct mtnic_port *priv, struct mtnic_ring *ring,
unsigned int size)
{
struct mtnic_rx_desc *rx_desc_ptr = ring->buf;
@@ -154,25 +139,20 @@ mtnic_alloc_iobuf(struct mtnic_priv *priv, struct mtnic_ring *ring,
while ((u32)(ring->prod - ring->cons) < UNITS_BUFFER_SIZE) {
index = ring->prod & ring->size_mask;
ring->iobuf[index] = alloc_iob(size);
- if (!&ring->iobuf[index]) {
+ if (!ring->iobuf[index]) {
if (ring->prod <= (ring->cons + 1)) {
- DBG("Error allocating Rx io "
- "buffer number %lx", index);
- /* In case of error freeing io buffer */
- mtnic_free_io_buffers(ring);
- return MTNIC_ERROR;
+ DBG ( "Dropping packet, buffer is full\n" );
}
-
break;
}
/* Attach io_buffer to descriptor */
rx_desc_ptr = ring->buf +
- (sizeof(struct mtnic_rx_desc) * index);
+ (sizeof(struct mtnic_rx_desc) * index);
rx_desc_ptr->data.count = cpu_to_be32(size);
- rx_desc_ptr->data.mem_type = priv->fw.mem_type_snoop_be;
+ rx_desc_ptr->data.mem_type = priv->mtnic->fw.mem_type_snoop_be;
rx_desc_ptr->data.addr_l = cpu_to_be32(
- virt_to_bus(ring->iobuf[index]->data));
+ virt_to_bus(ring->iobuf[index]->data));
++ ring->prod;
}
@@ -190,8 +170,8 @@ mtnic_alloc_iobuf(struct mtnic_priv *priv, struct mtnic_ring *ring,
*
*/
static int
-mtnic_alloc_ring(struct mtnic_priv *priv, struct mtnic_ring *ring,
- u32 size, u16 stride, u16 cq, u8 is_rx)
+mtnic_alloc_ring(struct mtnic_port *priv, struct mtnic_ring *ring,
+ u32 size, u16 stride, u16 cq, u8 is_rx)
{
unsigned int i;
int err;
@@ -207,18 +187,18 @@ mtnic_alloc_ring(struct mtnic_priv *priv, struct mtnic_ring *ring,
/* Alloc descriptors buffer */
ring->buf_size = ring->size * ((is_rx) ? sizeof(struct mtnic_rx_desc) :
- sizeof(struct mtnic_tx_desc));
+ sizeof(struct mtnic_tx_desc));
err = mtnic_alloc_aligned(ring->buf_size, (void *)&ring->buf,
- &ring->dma, PAGE_SIZE);
- if (err) {
- DBG("Failed allocating descriptor ring sizeof %lx\n",
+ &ring->dma, PAGE_SIZE);
+ if (err) {
+ DBG("Failed allocating descriptor ring sizeof %x\n",
ring->buf_size);
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
- memset(ring->buf, 0, ring->buf_size);
+ memset(ring->buf, 0, ring->buf_size);
- DBG("Allocated %s ring (addr:%p) - buf:%p size:%lx"
- "buf_size:%lx dma:%lx\n",
+ DBG("Allocated %s ring (addr:%p) - buf:%p size:%x"
+ "buf_size:%x dma:%lx\n",
is_rx ? "Rx" : "Tx", ring, ring->buf, ring->size,
ring->buf_size, ring->dma);
@@ -226,11 +206,11 @@ mtnic_alloc_ring(struct mtnic_priv *priv, struct mtnic_ring *ring,
if (is_rx) { /* RX ring */
/* Alloc doorbell */
err = mtnic_alloc_aligned(sizeof(struct mtnic_cq_db_record),
- (void *)&ring->db, &ring->db_dma, 32);
+ (void *)&ring->db, &ring->db_dma, 32);
if (err) {
DBG("Failed allocating Rx ring doorbell record\n");
- free(ring->buf);
- return MTNIC_ERROR;
+ free_memblock(ring->buf, ring->buf_size);
+ return -EADDRINUSE;
}
/* ==- Configure Descriptor -== */
@@ -244,14 +224,14 @@ mtnic_alloc_ring(struct mtnic_priv *priv, struct mtnic_ring *ring,
/*The last ctrl descriptor is '0' and points to the first one*/
/* Alloc IO_BUFFERS */
- err = mtnic_alloc_iobuf(priv, ring, DEF_IOBUF_SIZE);
+ err = mtnic_alloc_iobuf ( priv, ring, DEF_IOBUF_SIZE );
if (err) {
- DBG("ERROR Allocating io buffer");
- free(ring->buf);
- return MTNIC_ERROR;
+ DBG("ERROR Allocating io buffer\n");
+ free_memblock(ring->buf, ring->buf_size);
+ return -EADDRINUSE;
}
- } else { /* TX ring */
+ } else { /* TX ring */
/* Set initial ownership of all Tx Desc' to SW (1) */
for (i = 0; i < ring->size; i++) {
tx_desc = ring->buf + ring->stride * i;
@@ -259,17 +239,17 @@ mtnic_alloc_ring(struct mtnic_priv *priv, struct mtnic_ring *ring,
}
/* DB */
ring->db_offset = cpu_to_be32(
- ((u32) priv->fw.tx_offset[priv->port]) << 8);
+ ((u32) priv->mtnic->fw.tx_offset[priv->port]) << 8);
/* Map Tx+CQ doorbells */
- DBG("Mapping TxCQ doorbell at offset:0x%lx\n",
- priv->fw.txcq_db_offset);
+ DBG("Mapping TxCQ doorbell at offset:0x%x\n",
+ priv->mtnic->fw.txcq_db_offset);
ring->txcq_db = ioremap(mtnic_pci_dev.dev.bar[2] +
- priv->fw.txcq_db_offset, PAGE_SIZE);
+ priv->mtnic->fw.txcq_db_offset, PAGE_SIZE);
if (!ring->txcq_db) {
DBG("Couldn't map txcq doorbell, aborting...\n");
- free(ring->buf);
- return MTNIC_ERROR;
+ free_memblock(ring->buf, ring->buf_size);
+ return -EADDRINUSE;
}
}
@@ -286,7 +266,7 @@ mtnic_alloc_ring(struct mtnic_priv *priv, struct mtnic_ring *ring,
*/
static int
mtnic_alloc_cq(struct net_device *dev, int num, struct mtnic_cq *cq,
- u8 is_rx, u32 size, u32 offset_ind)
+ u8 is_rx, u32 size, u32 offset_ind)
{
int err ;
unsigned int i;
@@ -300,26 +280,26 @@ mtnic_alloc_cq(struct net_device *dev, int num, struct mtnic_cq *cq,
/* Alloc doorbell */
err = mtnic_alloc_aligned(sizeof(struct mtnic_cq_db_record),
- (void *)&cq->db, &cq->db_dma, 32);
+ (void *)&cq->db, &cq->db_dma, 32);
if (err) {
DBG("Failed allocating CQ doorbell record\n");
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
memset(cq->db, 0, sizeof(struct mtnic_cq_db_record));
/* Alloc CQEs buffer */
cq->buf_size = size * sizeof(struct mtnic_cqe);
err = mtnic_alloc_aligned(cq->buf_size,
- (void *)&cq->buf, &cq->dma, PAGE_SIZE);
+ (void *)&cq->buf, &cq->dma, PAGE_SIZE);
if (err) {
DBG("Failed allocating CQ buffer\n");
- free(cq->db);
- return MTNIC_ERROR;
+ free_memblock(cq->db, sizeof(struct mtnic_cq_db_record));
+ return -EADDRINUSE;
}
- memset(cq->buf, 0, cq->buf_size);
- DBG("Allocated CQ (addr:%p) - size:%lx buf:%p buf_size:%lx "
+ memset(cq->buf, 0, cq->buf_size);
+ DBG("Allocated CQ (addr:%p) - size:%x buf:%p buf_size:%x "
"dma:%lx db:%p db_dma:%lx\n"
- "cqn offset:%lx \n", cq, cq->size, cq->buf,
+ "cqn offset:%x \n", cq, cq->size, cq->buf,
cq->buf_size, cq->dma, cq->db,
cq->db_dma, offset_ind);
@@ -343,19 +323,20 @@ mtnic_alloc_cq(struct net_device *dev, int num, struct mtnic_cq *cq,
unsigned int
mtnic_alloc_resources(struct net_device *dev)
{
- struct mtnic_priv *priv = netdev_priv(dev);
- int err;
+ struct mtnic_port *priv = netdev_priv(dev);
+ int err;
int cq_ind = 0;
- int cq_offset = priv->fw.cq_offset;
+ int cq_offset = priv->mtnic->fw.cq_offset;
/* Alloc 1st CQ */
- err = mtnic_alloc_cq(dev, cq_ind, &priv->cq[cq_ind], 1 /* RX */,
+ err = mtnic_alloc_cq(dev, cq_ind, &priv->cq[cq_ind], 1 /* RX */,
UNITS_BUFFER_SIZE, cq_offset + cq_ind);
if (err) {
DBG("Failed allocating Rx CQ\n");
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
+
/* Alloc RX */
err = mtnic_alloc_ring(priv, &priv->rx_ring, UNITS_BUFFER_SIZE,
sizeof(struct mtnic_rx_desc), cq_ind, /* RX */1);
@@ -364,7 +345,8 @@ mtnic_alloc_resources(struct net_device *dev)
goto cq0_error;
}
- ++cq_ind;
+
+ ++cq_ind;
/* alloc 2nd CQ */
err = mtnic_alloc_cq(dev, cq_ind, &priv->cq[cq_ind], 0 /* TX */,
@@ -385,17 +367,18 @@ mtnic_alloc_resources(struct net_device *dev)
return 0;
cq1_error:
- free(priv->cq[1].buf);
- free(priv->cq[1].db);
+ free_memblock(priv->cq[1].buf, priv->cq[1].buf_size);
+ free_memblock(priv->cq[1].db, sizeof(struct mtnic_cq_db_record));
+
rx_error:
- free(priv->rx_ring.buf);
- free(priv->rx_ring.db);
+ free_memblock(priv->rx_ring.buf, priv->rx_ring.buf_size);
+ free_memblock(priv->rx_ring.db, sizeof(struct mtnic_cq_db_record));
mtnic_free_io_buffers(&priv->rx_ring);
cq0_error:
- free(priv->cq[0].buf);
- free(priv->cq[0].db);
+ free_memblock(priv->cq[0].buf, priv->cq[0].buf_size);
+ free_memblock(priv->cq[0].db, sizeof(struct mtnic_cq_db_record));
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
@@ -405,35 +388,35 @@ cq0_error:
* Note: EQ is not used by the driver but must be allocated
*/
static int
-mtnic_alloc_eq(struct mtnic_priv *priv)
+mtnic_alloc_eq(struct mtnic *mtnic)
{
int err;
unsigned int i;
struct mtnic_eqe *eqe_desc = NULL;
/* Allocating doorbell */
- priv->eq_db = ioremap(mtnic_pci_dev.dev.bar[2] +
- priv->fw.eq_db_offset, sizeof(u32));
- if (!priv->eq_db) {
+ mtnic->eq_db = ioremap(mtnic_pci_dev.dev.bar[2] +
+ mtnic->fw.eq_db_offset, sizeof(u32));
+ if (!mtnic->eq_db) {
DBG("Couldn't map EQ doorbell, aborting...\n");
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
/* Allocating buffer */
- priv->eq.size = NUM_EQES;
- priv->eq.buf_size = priv->eq.size * sizeof(struct mtnic_eqe);
- err = mtnic_alloc_aligned(priv->eq.buf_size, (void *)&priv->eq.buf,
- &priv->eq.dma, PAGE_SIZE);
+ mtnic->eq.size = NUM_EQES;
+ mtnic->eq.buf_size = mtnic->eq.size * sizeof(struct mtnic_eqe);
+ err = mtnic_alloc_aligned(mtnic->eq.buf_size, (void *)&mtnic->eq.buf,
+ &mtnic->eq.dma, PAGE_SIZE);
if (err) {
DBG("Failed allocating EQ buffer\n");
- iounmap(priv->eq_db);
- return MTNIC_ERROR;
+ iounmap(mtnic->eq_db);
+ return -EADDRINUSE;
}
- memset(priv->eq.buf, 0, priv->eq.buf_size);
+ memset(mtnic->eq.buf, 0, mtnic->eq.buf_size);
- for (i = 0; i < priv->eq.size; i++)
- eqe_desc = priv->eq.buf + (sizeof(struct mtnic_eqe) * i);
- eqe_desc->own |= MTNIC_BIT_EQE_OWN;
+ for (i = 0; i < mtnic->eq.size; i++)
+ eqe_desc = mtnic->eq.buf + (sizeof(struct mtnic_eqe) * i);
+ eqe_desc->own |= MTNIC_BIT_EQE_OWN;
mdelay(20);
return 0;
@@ -458,32 +441,32 @@ mtnic_alloc_eq(struct mtnic_priv *priv)
*
*********************************************************************/
static inline int
-cmdif_go_bit(struct mtnic_priv *priv)
+cmdif_go_bit(struct mtnic *mtnic)
{
- struct mtnic_if_cmd_reg *hcr = priv->hcr;
+ struct mtnic_if_cmd_reg *hcr = mtnic->hcr;
u32 status;
int i;
for (i = 0; i < TBIT_RETRIES; i++) {
status = be32_to_cpu(readl(&hcr->status_go_opcode));
if ((status & MTNIC_BC_MASK(MTNIC_MASK_CMD_REG_T_BIT)) ==
- (priv->cmd.tbit << MTNIC_BC_OFF(MTNIC_MASK_CMD_REG_T_BIT))) {
+ (mtnic->cmd.tbit << MTNIC_BC_OFF(MTNIC_MASK_CMD_REG_T_BIT))) {
/* Read expected t-bit - now return go-bit value */
return status & MTNIC_BC_MASK(MTNIC_MASK_CMD_REG_GO_BIT);
}
}
DBG("Invalid tbit after %d retries!\n", TBIT_RETRIES);
- return 1; /* Return busy... */
+ return -EBUSY; /* Return busy... */
}
/* Base Command interface */
static int
-mtnic_cmd(struct mtnic_priv *priv, void *in_imm,
+mtnic_cmd(struct mtnic *mtnic, void *in_imm,
void *out_imm, u32 in_modifier, u16 op)
{
- struct mtnic_if_cmd_reg *hcr = priv->hcr;
+ struct mtnic_if_cmd_reg *hcr = mtnic->hcr;
int err = 0;
u32 out_param_h = 0;
u32 out_param_l = 0;
@@ -497,43 +480,43 @@ mtnic_cmd(struct mtnic_priv *priv, void *in_imm,
token++;
- if (cmdif_go_bit(priv)) {
+ if ( cmdif_go_bit ( mtnic ) ) {
DBG("GO BIT BUSY:%p.\n", hcr + 6);
- err = MTNIC_ERROR;
+ err = -EBUSY;
goto out;
}
if (in_imm) {
in_param_h = *((u32*)in_imm);
in_param_l = *((u32*)in_imm + 1);
} else {
- in_param_l = cpu_to_be32(priv->cmd.mapping);
+ in_param_l = cpu_to_be32(mtnic->cmd.mapping);
}
- out_param_l = cpu_to_be32(priv->cmd.mapping);
+ out_param_l = cpu_to_be32(mtnic->cmd.mapping);
/* writing to MCR */
- writel(in_param_h, &hcr->in_param_h);
- writel(in_param_l, &hcr->in_param_l);
- writel((u32) cpu_to_be32(in_modifier), &hcr->input_modifier);
- writel(out_param_h, &hcr->out_param_h);
- writel(out_param_l, &hcr->out_param_l);
- writel((u32)cpu_to_be32(token << 16), &hcr->token);
+ writel(in_param_h, &hcr->in_param_h);
+ writel(in_param_l, &hcr->in_param_l);
+ writel((u32) cpu_to_be32(in_modifier), &hcr->input_modifier);
+ writel(out_param_h, &hcr->out_param_h);
+ writel(out_param_l, &hcr->out_param_l);
+ writel((u32)cpu_to_be32(token << 16), &hcr->token);
wmb();
/* flip toggle bit before each write to the HCR */
- priv->cmd.tbit = !priv->cmd.tbit;
- writel((u32)
+ mtnic->cmd.tbit = !mtnic->cmd.tbit;
+ writel( ( u32 )
cpu_to_be32(MTNIC_BC_MASK(MTNIC_MASK_CMD_REG_GO_BIT) |
- (priv->cmd.tbit << MTNIC_BC_OFF(MTNIC_MASK_CMD_REG_T_BIT)) | op),
+ ( mtnic->cmd.tbit << MTNIC_BC_OFF ( MTNIC_MASK_CMD_REG_T_BIT ) ) | op ),
&hcr->status_go_opcode);
- while (cmdif_go_bit(priv) && (timeout <= GO_BIT_TIMEOUT)) {
- mdelay(1);
+ while ( cmdif_go_bit ( mtnic ) && ( timeout <= GO_BIT_TIMEOUT ) ) {
+ mdelay ( 1 );
++timeout;
}
- if (cmdif_go_bit(priv)) {
+ if ( cmdif_go_bit ( mtnic ) ) {
DBG("Command opcode:0x%x token:0x%x TIMEOUT.\n", op, token);
- err = MTNIC_ERROR;
+ err = -EBUSY;
goto out;
}
@@ -543,10 +526,10 @@ mtnic_cmd(struct mtnic_priv *priv, void *in_imm,
}
status = be32_to_cpu((u32)readl(&hcr->status_go_opcode)) >> 24;
- /*DBG("Command opcode:0x%x token:0x%x returned:0x%lx\n",
- op, token, status);*/
if (status) {
+ DBG("Command opcode:0x%x token:0x%x returned:0x%x\n",
+ op, token, status);
return status;
}
@@ -556,12 +539,12 @@ out:
/* MAP PAGES wrapper */
static int
-mtnic_map_cmd(struct mtnic_priv *priv, u16 op, struct mtnic_pages pages)
+mtnic_map_cmd(struct mtnic *mtnic, u16 op, struct mtnic_pages pages)
{
- unsigned int j;
+ unsigned int j;
u32 addr;
unsigned int len;
- u32 *page_arr = priv->cmd.buf;
+ u32 *page_arr = mtnic->cmd.buf;
int nent = 0;
int err = 0;
@@ -570,28 +553,28 @@ mtnic_map_cmd(struct mtnic_priv *priv, u16 op, struct mtnic_pages pages)
len = PAGE_SIZE * pages.num;
pages.buf = (u32 *)umalloc(PAGE_SIZE * (pages.num + 1));
addr = PAGE_SIZE + ((virt_to_bus(pages.buf) & 0xfffff000) + PAGE_SIZE);
- DBG("Mapping pages: size: %lx address: %p\n", pages.num, pages.buf);
+ DBG("Mapping pages: size: %x address: %p\n", pages.num, pages.buf);
if (addr & (PAGE_MASK)) {
DBG("Got FW area not aligned to %d (%llx/%x)\n",
PAGE_SIZE, (u64) addr, len);
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
/* Function maps each PAGE seperately */
for (j = 0; j < len; j+= PAGE_SIZE) {
page_arr[nent * 4 + 3] = cpu_to_be32(addr + j);
if (++nent == MTNIC_MAILBOX_SIZE / 16) {
- err = mtnic_cmd(priv, NULL, NULL, nent, op);
+ err = mtnic_cmd(mtnic, NULL, NULL, nent, op);
if (err)
- return MTNIC_ERROR;
- nent = 0;
+ return -EIO;
+ nent = 0;
}
}
- if (nent)
- err = mtnic_cmd(priv, NULL, NULL, nent, op);
-
+ if (nent) {
+ err = mtnic_cmd(mtnic, NULL, NULL, nent, op);
+ }
return err;
}
@@ -601,45 +584,44 @@ mtnic_map_cmd(struct mtnic_priv *priv, u16 op, struct mtnic_pages pages)
* Query FW
*/
static int
-mtnic_QUERY_FW(struct mtnic_priv *priv)
+mtnic_QUERY_FW ( struct mtnic *mtnic )
{
int err;
- struct mtnic_if_query_fw_out_mbox *cmd = priv->cmd.buf;
+ struct mtnic_if_query_fw_out_mbox *cmd = mtnic->cmd.buf;
- err = mtnic_cmd(priv, NULL, NULL, 0, MTNIC_IF_CMD_QUERY_FW);
+ err = mtnic_cmd(mtnic, NULL, NULL, 0, MTNIC_IF_CMD_QUERY_FW);
if (err)
- return MTNIC_ERROR;
+ return -EIO;
/* Get FW and interface versions */
- priv->fw_ver = ((u64) be16_to_cpu(cmd->rev_maj) << 32) |
- ((u64) be16_to_cpu(cmd->rev_min) << 16) |
- (u64) be16_to_cpu(cmd->rev_smin);
- priv->fw.ifc_rev = be16_to_cpu(cmd->ifc_rev);
+ mtnic->fw_ver = ((u64) be16_to_cpu(cmd->rev_maj) << 32) |
+ ((u64) be16_to_cpu(cmd->rev_min) << 16) |
+ (u64) be16_to_cpu(cmd->rev_smin);
+ mtnic->fw.ifc_rev = be16_to_cpu(cmd->ifc_rev);
/* Get offset for internal error reports (debug) */
- priv->fw.err_buf.offset = be64_to_cpu(cmd->err_buf_start);
- priv->fw.err_buf.size = be32_to_cpu(cmd->err_buf_size);
+ mtnic->fw.err_buf.offset = be64_to_cpu(cmd->err_buf_start);
+ mtnic->fw.err_buf.size = be32_to_cpu(cmd->err_buf_size);
- DBG("Error buf offset is %llx\n", priv->fw.err_buf.offset);
+ DBG("Error buf offset is %llx\n", mtnic->fw.err_buf.offset);
/* Get number of required FW (4k) pages */
- priv->fw.fw_pages.num = be16_to_cpu(cmd->fw_pages);
+ mtnic->fw.fw_pages.num = be16_to_cpu(cmd->fw_pages);
return 0;
}
static int
-mtnic_OPEN_NIC(struct mtnic_priv *priv)
+mtnic_OPEN_NIC(struct mtnic *mtnic)
{
-
- struct mtnic_if_open_nic_in_mbox *open_nic = priv->cmd.buf;
+ struct mtnic_if_open_nic_in_mbox *open_nic = mtnic->cmd.buf;
u32 extra_pages[2] = {0};
int err;
memset(open_nic, 0, sizeof *open_nic);
- /* port 1 */
+ /* port 1 */
open_nic->log_rx_p1 = 0;
open_nic->log_cq_p1 = 1;
@@ -655,46 +637,47 @@ mtnic_OPEN_NIC(struct mtnic_priv *priv)
open_nic->steer_p2 = MTNIC_IF_STEER_RSS;
/* MAC + VLAN - leave reserved */
- err = mtnic_cmd(priv, NULL, extra_pages, 0, MTNIC_IF_CMD_OPEN_NIC);
- priv->fw.extra_pages.num = be32_to_cpu(*(extra_pages+1));
- DBG("Extra pages num is %lx\n", priv->fw.extra_pages.num);
+ err = mtnic_cmd(mtnic, NULL, extra_pages, 0, MTNIC_IF_CMD_OPEN_NIC);
+
+ mtnic->fw.extra_pages.num = be32_to_cpu(*(extra_pages+1));
+ DBG("Extra pages num is %x\n", mtnic->fw.extra_pages.num);
return err;
}
static int
-mtnic_CONFIG_RX(struct mtnic_priv *priv)
+mtnic_CONFIG_RX(struct mtnic *mtnic)
{
struct mtnic_if_config_rx_in_imm config_rx;
memset(&config_rx, 0, sizeof config_rx);
- return mtnic_cmd(priv, &config_rx, NULL, 0, MTNIC_IF_CMD_CONFIG_RX);
+ return mtnic_cmd(mtnic, &config_rx, NULL, 0, MTNIC_IF_CMD_CONFIG_RX);
}
static int
-mtnic_CONFIG_TX(struct mtnic_priv *priv)
+mtnic_CONFIG_TX(struct mtnic *mtnic)
{
struct mtnic_if_config_send_in_imm config_tx;
config_tx.enph_gpf = 0;
- return mtnic_cmd(priv, &config_tx, NULL, 0, MTNIC_IF_CMD_CONFIG_TX);
+ return mtnic_cmd(mtnic, &config_tx, NULL, 0, MTNIC_IF_CMD_CONFIG_TX);
}
static int
-mtnic_HEART_BEAT(struct mtnic_priv *priv, u32 *link_state)
+mtnic_HEART_BEAT(struct mtnic_port *priv, u32 *link_state)
{
struct mtnic_if_heart_beat_out_imm heart_beat;
int err;
u32 flags;
- err = mtnic_cmd(priv, NULL, &heart_beat, 0, MTNIC_IF_CMD_HEART_BEAT);
+ err = mtnic_cmd(priv->mtnic, NULL, &heart_beat, 0, MTNIC_IF_CMD_HEART_BEAT);
if (!err) {
flags = be32_to_cpu(heart_beat.flags);
if (flags & MTNIC_BC_MASK(MTNIC_MASK_HEAR_BEAT_INT_ERROR)) {
DBG("Internal error detected\n");
- return MTNIC_ERROR;
+ return -EIO;
}
*link_state = flags &
- ~((u32) MTNIC_BC_MASK(MTNIC_MASK_HEAR_BEAT_INT_ERROR));
+ ~((u32) MTNIC_BC_MASK(MTNIC_MASK_HEAR_BEAT_INT_ERROR));
}
return err;
}
@@ -705,31 +688,31 @@ mtnic_HEART_BEAT(struct mtnic_priv *priv, u32 *link_state)
*/
static int
-mtnic_SET_PORT_DEFAULT_RING(struct mtnic_priv *priv, u8 port, u16 ring)
+mtnic_SET_PORT_DEFAULT_RING(struct mtnic_port *priv, u8 port, u16 ring)
{
struct mtnic_if_set_port_default_ring_in_imm def_ring;
memset(&def_ring, 0, sizeof(def_ring));
def_ring.ring = ring;
- return mtnic_cmd(priv, &def_ring, NULL, port + 1,
+ return mtnic_cmd(priv->mtnic, &def_ring, NULL, port + 1,
MTNIC_IF_CMD_SET_PORT_DEFAULT_RING);
}
static int
-mtnic_CONFIG_PORT_RSS_STEER(struct mtnic_priv *priv, int port)
+mtnic_CONFIG_PORT_RSS_STEER(struct mtnic_port *priv, int port)
{
- memset(priv->cmd.buf, 0, PAGE_SIZE);
- return mtnic_cmd(priv, NULL, NULL, port + 1,
- MTNIC_IF_CMD_CONFIG_PORT_RSS_STEER);
+ memset(priv->mtnic->cmd.buf, 0, PAGE_SIZE);
+ return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1,
+ MTNIC_IF_CMD_CONFIG_PORT_RSS_STEER);
}
static int
-mtnic_SET_PORT_RSS_INDIRECTION(struct mtnic_priv *priv, int port)
+mtnic_SET_PORT_RSS_INDIRECTION(struct mtnic_port *priv, int port)
{
- memset(priv->cmd.buf, 0, PAGE_SIZE);
- return mtnic_cmd(priv, NULL, NULL, port + 1,
- MTNIC_IF_CMD_SET_PORT_RSS_INDIRECTION);
+ memset(priv->mtnic->cmd.buf, 0, PAGE_SIZE);
+ return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1,
+ MTNIC_IF_CMD_SET_PORT_RSS_INDIRECTION);
}
@@ -737,89 +720,89 @@ mtnic_SET_PORT_RSS_INDIRECTION(struct mtnic_priv *priv, int port)
* Config commands
*/
static int
-mtnic_CONFIG_CQ(struct mtnic_priv *priv, int port,
- u16 cq_ind, struct mtnic_cq *cq)
+mtnic_CONFIG_CQ(struct mtnic_port *priv, int port,
+ u16 cq_ind, struct mtnic_cq *cq)
{
- struct mtnic_if_config_cq_in_mbox *config_cq = priv->cmd.buf;
+ struct mtnic_if_config_cq_in_mbox *config_cq = priv->mtnic->cmd.buf;
memset(config_cq, 0, sizeof *config_cq);
config_cq->cq = cq_ind;
config_cq->size = fls(UNITS_BUFFER_SIZE - 1);
config_cq->offset = ((cq->dma) & (PAGE_MASK)) >> 6;
config_cq->db_record_addr_l = cpu_to_be32(cq->db_dma);
- config_cq->page_address[1] = cpu_to_be32(cq->dma);
- DBG("config cq address: %lx dma_address: %lx"
- "offset: %d size %d index: %d "
+ config_cq->page_address[1] = cpu_to_be32(cq->dma);
+ DBG("config cq address: %x dma_address: %lx"
+ "offset: %d size %d index: %d\n"
, config_cq->page_address[1],cq->dma,
config_cq->offset, config_cq->size, config_cq->cq );
- return mtnic_cmd(priv, NULL, NULL, port + 1,
- MTNIC_IF_CMD_CONFIG_CQ);
+ return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1,
+ MTNIC_IF_CMD_CONFIG_CQ);
}
static int
-mtnic_CONFIG_TX_RING(struct mtnic_priv *priv, u8 port,
- u16 ring_ind, struct mtnic_ring *ring)
+mtnic_CONFIG_TX_RING(struct mtnic_port *priv, u8 port,
+ u16 ring_ind, struct mtnic_ring *ring)
{
- struct mtnic_if_config_send_ring_in_mbox *config_tx_ring = priv->cmd.buf;
+ struct mtnic_if_config_send_ring_in_mbox *config_tx_ring = priv->mtnic->cmd.buf;
memset(config_tx_ring, 0, sizeof *config_tx_ring);
config_tx_ring->ring = cpu_to_be16(ring_ind);
config_tx_ring->size = fls(UNITS_BUFFER_SIZE - 1);
config_tx_ring->cq = cpu_to_be16(ring->cq);
config_tx_ring->page_address[1] = cpu_to_be32(ring->dma);
- return mtnic_cmd(priv, NULL, NULL, port + 1,
+ return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1,
MTNIC_IF_CMD_CONFIG_TX_RING);
}
static int
-mtnic_CONFIG_RX_RING(struct mtnic_priv *priv, u8 port,
- u16 ring_ind, struct mtnic_ring *ring)
+mtnic_CONFIG_RX_RING(struct mtnic_port *priv, u8 port,
+ u16 ring_ind, struct mtnic_ring *ring)
{
- struct mtnic_if_config_rx_ring_in_mbox *config_rx_ring = priv->cmd.buf;
+ struct mtnic_if_config_rx_ring_in_mbox *config_rx_ring = priv->mtnic->cmd.buf;
memset(config_rx_ring, 0, sizeof *config_rx_ring);
config_rx_ring->ring = ring_ind;
- MTNIC_BC_PUT(config_rx_ring->stride_size, fls(UNITS_BUFFER_SIZE - 1),
- MTNIC_MASK_CONFIG_RX_RING_SIZE);
- MTNIC_BC_PUT(config_rx_ring->stride_size, 1,
- MTNIC_MASK_CONFIG_RX_RING_STRIDE);
+ MTNIC_BC_PUT(config_rx_ring->stride_size, fls(UNITS_BUFFER_SIZE - 1),
+ MTNIC_MASK_CONFIG_RX_RING_SIZE);
+ MTNIC_BC_PUT(config_rx_ring->stride_size, 1,
+ MTNIC_MASK_CONFIG_RX_RING_STRIDE);
config_rx_ring->cq = cpu_to_be16(ring->cq);
config_rx_ring->db_record_addr_l = cpu_to_be32(ring->db_dma);
- DBG("Config RX ring starting at address:%lx\n", ring->dma);
+ DBG("Config RX ring starting at address:%lx\n", ring->dma);
config_rx_ring->page_address[1] = cpu_to_be32(ring->dma);
- return mtnic_cmd(priv, NULL, NULL, port + 1,
- MTNIC_IF_CMD_CONFIG_RX_RING);
+ return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1,
+ MTNIC_IF_CMD_CONFIG_RX_RING);
}
static int
-mtnic_CONFIG_EQ(struct mtnic_priv *priv)
+mtnic_CONFIG_EQ(struct mtnic *mtnic)
{
- struct mtnic_if_config_eq_in_mbox *eq = priv->cmd.buf;
+ struct mtnic_if_config_eq_in_mbox *eq = mtnic->cmd.buf;
- if (priv->eq.dma & (PAGE_MASK)) {
+ if (mtnic->eq.dma & (PAGE_MASK)) {
DBG("misalligned eq buffer:%lx\n",
- priv->eq.dma);
- return MTNIC_ERROR;
- }
+ mtnic->eq.dma);
+ return -EADDRINUSE;
+ }
- memset(eq, 0, sizeof *eq);
- MTNIC_BC_PUT(eq->offset, priv->eq.dma >> 6, MTNIC_MASK_CONFIG_EQ_OFFSET);
- MTNIC_BC_PUT(eq->size, fls(priv->eq.size - 1) - 1, MTNIC_MASK_CONFIG_EQ_SIZE);
+ memset(eq, 0, sizeof *eq);
+ MTNIC_BC_PUT(eq->offset, mtnic->eq.dma >> 6, MTNIC_MASK_CONFIG_EQ_OFFSET);
+ MTNIC_BC_PUT(eq->size, fls(mtnic->eq.size - 1) - 1, MTNIC_MASK_CONFIG_EQ_SIZE);
MTNIC_BC_PUT(eq->int_vector, 0, MTNIC_MASK_CONFIG_EQ_INT_VEC);
- eq->page_address[1] = cpu_to_be32(priv->eq.dma);
+ eq->page_address[1] = cpu_to_be32(mtnic->eq.dma);
- return mtnic_cmd(priv, NULL, NULL, 0, MTNIC_IF_CMD_CONFIG_EQ);
+ return mtnic_cmd(mtnic, NULL, NULL, 0, MTNIC_IF_CMD_CONFIG_EQ);
}
static int
-mtnic_SET_RX_RING_ADDR(struct mtnic_priv *priv, u8 port, u64* mac)
+mtnic_SET_RX_RING_ADDR(struct mtnic_port *priv, u8 port, u64* mac)
{
struct mtnic_if_set_rx_ring_addr_in_imm ring_addr;
u32 modifier = ((u32) port + 1) << 16;
@@ -829,63 +812,64 @@ mtnic_SET_RX_RING_ADDR(struct mtnic_priv *priv, u8 port, u64* mac)
ring_addr.mac_31_0 = cpu_to_be32(*mac & 0xffffffff);
ring_addr.mac_47_32 = cpu_to_be16((*mac >> 32) & 0xffff);
ring_addr.flags_vlan_id |= cpu_to_be16(
- MTNIC_BC_MASK(MTNIC_MASK_SET_RX_RING_ADDR_BY_MAC));
+ MTNIC_BC_MASK(MTNIC_MASK_SET_RX_RING_ADDR_BY_MAC));
- return mtnic_cmd(priv, &ring_addr, NULL, modifier, MTNIC_IF_CMD_SET_RX_RING_ADDR);
+ return mtnic_cmd(priv->mtnic, &ring_addr, NULL, modifier, MTNIC_IF_CMD_SET_RX_RING_ADDR);
}
static int
-mtnic_SET_PORT_STATE(struct mtnic_priv *priv, u8 port, u8 state)
+mtnic_SET_PORT_STATE(struct mtnic_port *priv, u8 port, u8 state)
{
struct mtnic_if_set_port_state_in_imm port_state;
port_state.state = state ? cpu_to_be32(
- MTNIC_BC_MASK(MTNIC_MASK_CONFIG_PORT_STATE)) : 0;
+ MTNIC_BC_MASK(MTNIC_MASK_CONFIG_PORT_STATE)) : 0;
port_state.reserved = 0;
- return mtnic_cmd(priv, &port_state, NULL, port + 1,
+ return mtnic_cmd(priv->mtnic, &port_state, NULL, port + 1,
MTNIC_IF_CMD_SET_PORT_STATE);
}
static int
-mtnic_SET_PORT_MTU(struct mtnic_priv *priv, u8 port, u16 mtu)
+mtnic_SET_PORT_MTU(struct mtnic_port *priv, u8 port, u16 mtu)
{
struct mtnic_if_set_port_mtu_in_imm set_mtu;
memset(&set_mtu, 0, sizeof(set_mtu));
set_mtu.mtu = cpu_to_be16(mtu);
- return mtnic_cmd(priv, &set_mtu, NULL, port + 1,
- MTNIC_IF_CMD_SET_PORT_MTU);
+ return mtnic_cmd(priv->mtnic, &set_mtu, NULL, port + 1,
+ MTNIC_IF_CMD_SET_PORT_MTU);
}
-
+/*
static int
-mtnic_CONFIG_PORT_VLAN_FILTER(struct mtnic_priv *priv, int port)
+mtnic_CONFIG_PORT_VLAN_FILTER(struct mtnic_port *priv, int port)
{
- struct mtnic_if_config_port_vlan_filter_in_mbox *vlan_filter = priv->cmd.buf;
+ struct mtnic_if_config_port_vlan_filter_in_mbox *vlan_filter = priv->mtnic->cmd.buf;
- /* When no vlans are configured we disable the filter
- * (i.e., pass all vlans) because we ignore them anyhow */
+ // When no vlans are configured we disable the filter
+ // (i.e., pass all vlans) because we ignore them anyhow
memset(vlan_filter, 0xff, sizeof(*vlan_filter));
- return mtnic_cmd(priv, NULL, NULL, port + 1,
- MTNIC_IF_CMD_CONFIG_PORT_VLAN_FILTER);
+ return mtnic_cmd(priv->mtnic, NULL, NULL, port + 1,
+ MTNIC_IF_CMD_CONFIG_PORT_VLAN_FILTER);
}
+*/
static int
-mtnic_RELEASE_RESOURCE(struct mtnic_priv *priv, u8 port, u8 type, u8 index)
+mtnic_RELEASE_RESOURCE(struct mtnic_port *priv, u8 port, u8 type, u8 index)
{
struct mtnic_if_release_resource_in_imm rel;
memset(&rel, 0, sizeof rel);
rel.index = index;
rel.type = type;
- return mtnic_cmd(priv,
- &rel, NULL, (type == MTNIC_IF_RESOURCE_TYPE_EQ) ?
- 0 : port + 1, MTNIC_IF_CMD_RELEASE_RESOURCE);
+ return mtnic_cmd ( priv->mtnic,
+ &rel, NULL, ( type == MTNIC_IF_RESOURCE_TYPE_EQ ) ?
+ 0 : port + 1, MTNIC_IF_CMD_RELEASE_RESOURCE );
}
static int
-mtnic_QUERY_CAP(struct mtnic_priv *priv, u8 index, u8 mod, u64 *result)
+mtnic_QUERY_CAP(struct mtnic *mtnic, u8 index, u8 mod, u64 *result)
{
struct mtnic_if_query_cap_in_imm cap;
u32 out_imm[2];
@@ -894,7 +878,7 @@ mtnic_QUERY_CAP(struct mtnic_priv *priv, u8 index, u8 mod, u64 *result)
memset(&cap, 0, sizeof cap);
cap.cap_index = index;
cap.cap_modifier = mod;
- err = mtnic_cmd(priv, &cap, &out_imm, 0, MTNIC_IF_CMD_QUERY_CAP);
+ err = mtnic_cmd(mtnic, &cap, &out_imm, 0, MTNIC_IF_CMD_QUERY_CAP);
*((u32*)result) = be32_to_cpu(*(out_imm+1));
*((u32*)result + 1) = be32_to_cpu(*out_imm);
@@ -906,28 +890,38 @@ mtnic_QUERY_CAP(struct mtnic_priv *priv, u8 index, u8 mod, u64 *result)
#define DO_QUERY_CAP(cap, mod, var) \
- err = mtnic_QUERY_CAP(priv, cap, mod, &result); \
+ err = mtnic_QUERY_CAP(mtnic, cap, mod, &result);\
if (err) \
return err; \
(var) = result
static int
-mtnic_query_cap(struct mtnic_priv *priv)
+mtnic_query_num_ports(struct mtnic *mtnic)
+{
+ int err = 0;
+ u64 result;
+
+ DO_QUERY_CAP(MTNIC_IF_CAP_NUM_PORTS, 0, mtnic->fw.num_ports);
+
+ return 0;
+}
+
+static int
+mtnic_query_mac(struct mtnic *mtnic)
{
int err = 0;
int i;
- u64 result;
+ u64 result;
- DO_QUERY_CAP(MTNIC_IF_CAP_NUM_PORTS, 0, priv->fw.num_ports);
- for (i = 0; i < priv->fw.num_ports; i++) {
- DO_QUERY_CAP(MTNIC_IF_CAP_DEFAULT_MAC, i + 1, priv->fw.mac[i]);
+ for (i = 0; i < mtnic->fw.num_ports; i++) {
+ DO_QUERY_CAP(MTNIC_IF_CAP_DEFAULT_MAC, i + 1, mtnic->fw.mac[i]);
}
return 0;
}
static int
-mtnic_query_offsets(struct mtnic_priv *priv)
+mtnic_query_offsets(struct mtnic *mtnic)
{
int err;
int i;
@@ -935,18 +929,18 @@ mtnic_query_offsets(struct mtnic_priv *priv)
DO_QUERY_CAP(MTNIC_IF_CAP_MEM_KEY,
MTNIC_IF_MEM_TYPE_SNOOP,
- priv->fw.mem_type_snoop_be);
- priv->fw.mem_type_snoop_be = cpu_to_be32(priv->fw.mem_type_snoop_be);
- DO_QUERY_CAP(MTNIC_IF_CAP_TX_CQ_DB_OFFSET, 0, priv->fw.txcq_db_offset);
- DO_QUERY_CAP(MTNIC_IF_CAP_EQ_DB_OFFSET, 0, priv->fw.eq_db_offset);
+ mtnic->fw.mem_type_snoop_be);
+ mtnic->fw.mem_type_snoop_be = cpu_to_be32(mtnic->fw.mem_type_snoop_be);
+ DO_QUERY_CAP(MTNIC_IF_CAP_TX_CQ_DB_OFFSET, 0, mtnic->fw.txcq_db_offset);
+ DO_QUERY_CAP(MTNIC_IF_CAP_EQ_DB_OFFSET, 0, mtnic->fw.eq_db_offset);
- for (i = 0; i < priv->fw.num_ports; i++) {
- DO_QUERY_CAP(MTNIC_IF_CAP_CQ_OFFSET, i + 1, priv->fw.cq_offset);
- DO_QUERY_CAP(MTNIC_IF_CAP_TX_OFFSET, i + 1, priv->fw.tx_offset[i]);
- DO_QUERY_CAP(MTNIC_IF_CAP_RX_OFFSET, i + 1, priv->fw.rx_offset[i]);
- DBG("--> Port %d CQ offset:0x%x\n", i, priv->fw.cq_offset);
- DBG("--> Port %d Tx offset:0x%x\n", i, priv->fw.tx_offset[i]);
- DBG("--> Port %d Rx offset:0x%x\n", i, priv->fw.rx_offset[i]);
+ for (i = 0; i < mtnic->fw.num_ports; i++) {
+ DO_QUERY_CAP(MTNIC_IF_CAP_CQ_OFFSET, i + 1, mtnic->fw.cq_offset);
+ DO_QUERY_CAP(MTNIC_IF_CAP_TX_OFFSET, i + 1, mtnic->fw.tx_offset[i]);
+ DO_QUERY_CAP(MTNIC_IF_CAP_RX_OFFSET, i + 1, mtnic->fw.rx_offset[i]);
+ DBG("--> Port %d CQ offset:0x%x\n", i, mtnic->fw.cq_offset);
+ DBG("--> Port %d Tx offset:0x%x\n", i, mtnic->fw.tx_offset[i]);
+ DBG("--> Port %d Rx offset:0x%x\n", i, mtnic->fw.rx_offset[i]);
}
mdelay(20);
@@ -976,11 +970,12 @@ mtnic_query_offsets(struct mtnic_priv *priv)
* Reset device
*/
void
-mtnic_reset(void)
+mtnic_reset ( void )
{
- void *reset = ioremap(mtnic_pci_dev.dev.bar[0] + MTNIC_RESET_OFFSET, 4);
- writel(cpu_to_be32(1), reset);
- iounmap(reset);
+ void *reset = ioremap ( mtnic_pci_dev.dev.bar[0] + MTNIC_RESET_OFFSET,
+ 4 );
+ writel ( cpu_to_be32 ( 1 ), reset );
+ iounmap ( reset );
}
@@ -1018,18 +1013,18 @@ mtnic_init_pci(struct pci_device *dev)
int err;
/* save bars */
- DBG("bus=%d devfn=0x%x", dev->bus, dev->devfn);
+ DBG("bus=%d devfn=0x%x\n", dev->bus, dev->devfn);
for (i = 0; i < 6; ++i) {
mtnic_pci_dev.dev.bar[i] =
- pci_bar_start(dev, PCI_BASE_ADDRESS_0 + (i << 2));
+ pci_bar_start(dev, PCI_BASE_ADDRESS_0 + (i << 2));
DBG("bar[%d]= 0x%08lx \n", i, mtnic_pci_dev.dev.bar[i]);
}
/* save config space */
for (i = 0; i < 64; ++i) {
err = pci_read_config_dword(dev, i << 2,
- &mtnic_pci_dev.dev.
- dev_config_space[i]);
+ &mtnic_pci_dev.dev.
+ dev_config_space[i]);
if (err) {
DBG("Can not save configuration space");
return err;
@@ -1038,144 +1033,140 @@ mtnic_init_pci(struct pci_device *dev)
mtnic_pci_dev.dev.dev = dev;
- return 0;
+ return 0;
}
/**
* Initial hardware
*/
static inline
-int mtnic_init_card(struct net_device *dev)
+int mtnic_init_card(struct mtnic *mtnic)
{
- struct mtnic_priv *priv = netdev_priv(dev);
int err = 0;
- /* Set state */
- priv->state = CARD_DOWN;
- /* Set port */
- priv->port = MTNIC_PORT_NUM;
-
- /* Alloc command interface */
- err = mtnic_alloc_cmdif(priv);
+ /* Alloc command interface */
+ err = mtnic_alloc_cmdif ( mtnic );
if (err) {
- DBG("Failed to init command interface, aborting.\n");
- return MTNIC_ERROR;
+ DBG("Failed to init command interface, aborting\n");
+ return -EADDRINUSE;
}
-
- /**
- * Bring up HW
- */
- err = mtnic_QUERY_FW(priv);
+ /**
+ * Bring up HW
+ */
+ err = mtnic_QUERY_FW ( mtnic );
if (err) {
- DBG("QUERY_FW command failed, aborting.\n");
+ DBG("QUERY_FW command failed, aborting\n");
goto cmd_error;
}
-
- DBG("Command interface revision:%d\n", priv->fw.ifc_rev);
+ DBG("Command interface revision:%d\n", mtnic->fw.ifc_rev);
/* Allocate memory for FW and start it */
- err = mtnic_map_cmd(priv, MTNIC_IF_CMD_MAP_FW, priv->fw.fw_pages);
+ err = mtnic_map_cmd(mtnic, MTNIC_IF_CMD_MAP_FW, mtnic->fw.fw_pages);
if (err) {
DBG("Eror In MAP_FW\n");
- if (priv->fw.fw_pages.buf)
- free(priv->fw.fw_pages.buf);
+ if (mtnic->fw.fw_pages.buf)
+ ufree((intptr_t)mtnic->fw.fw_pages.buf);
goto cmd_error;
}
/* Run firmware */
- err = mtnic_cmd(priv, NULL, NULL, 0, MTNIC_IF_CMD_RUN_FW);
+ err = mtnic_cmd(mtnic, NULL, NULL, 0, MTNIC_IF_CMD_RUN_FW);
if (err) {
DBG("Eror In RUN FW\n");
goto map_fw_error;
}
- DBG("FW version:%d.%d.%d\n",
- (u16) (priv->fw_ver >> 32),
- (u16) ((priv->fw_ver >> 16) & 0xffff),
- (u16) (priv->fw_ver & 0xffff));
+ DBG("FW version:%d.%d.%d\n",
+ (u16) (mtnic->fw_ver >> 32),
+ (u16) ((mtnic->fw_ver >> 16) & 0xffff),
+ (u16) (mtnic->fw_ver & 0xffff));
- /* Get device information */
- err = mtnic_query_cap(priv);
+ /* Query num ports */
+ err = mtnic_query_num_ports(mtnic);
if (err) {
- DBG("Insufficient resources, aborting.\n");
+ DBG("Insufficient resources, aborting\n");
goto map_fw_error;
}
/* Open NIC */
- err = mtnic_OPEN_NIC(priv);
+ err = mtnic_OPEN_NIC(mtnic);
if (err) {
- DBG("Failed opening NIC, aborting.\n");
+ DBG("Failed opening NIC, aborting\n");
goto map_fw_error;
}
/* Allocate and map pages worksace */
- err = mtnic_map_cmd(priv, MTNIC_IF_CMD_MAP_PAGES, priv->fw.extra_pages);
+ err = mtnic_map_cmd(mtnic, MTNIC_IF_CMD_MAP_PAGES, mtnic->fw.extra_pages);
+ if (err) {
+ DBG("Couldn't allocate %x FW extra pages, aborting\n",
+ mtnic->fw.extra_pages.num);
+ if (mtnic->fw.extra_pages.buf)
+ ufree((intptr_t)mtnic->fw.extra_pages.buf);
+ goto map_fw_error;
+ }
+
+
+ /* Get device information */
+ err = mtnic_query_mac(mtnic);
if (err) {
- DBG("Couldn't allocate %lx FW extra pages, aborting.\n",
- priv->fw.extra_pages.num);
- if (priv->fw.extra_pages.buf)
- free(priv->fw.extra_pages.buf);
+ DBG("Insufficient resources in quesry mac, aborting\n");
goto map_fw_error;
}
/* Get device offsets */
- err = mtnic_query_offsets(priv);
+ err = mtnic_query_offsets(mtnic);
if (err) {
- DBG("Failed retrieving resource offests, aborting.\n");
- free(priv->fw.extra_pages.buf);
+ DBG("Failed retrieving resource offests, aborting\n");
+ ufree((intptr_t)mtnic->fw.extra_pages.buf);
goto map_extra_error;
}
- /* Alloc EQ */
- err = mtnic_alloc_eq(priv);
+ /* Alloc EQ */
+ err = mtnic_alloc_eq(mtnic);
if (err) {
DBG("Failed init shared resources. error: %d\n", err);
goto map_extra_error;
- }
+ }
/* Configure HW */
- err = mtnic_CONFIG_EQ(priv);
+ err = mtnic_CONFIG_EQ(mtnic);
if (err) {
DBG("Failed configuring EQ\n");
goto eq_error;
}
- err = mtnic_CONFIG_RX(priv);
+ err = mtnic_CONFIG_RX(mtnic);
if (err) {
DBG("Failed Rx configuration\n");
goto eq_error;
}
- err = mtnic_CONFIG_TX(priv);
+ err = mtnic_CONFIG_TX(mtnic);
if (err) {
DBG("Failed Tx configuration\n");
goto eq_error;
}
- DBG("Activating port:%d\n", MTNIC_PORT_NUM + 1);
-
- priv->state = CARD_INITIALIZED;
return 0;
eq_error:
- iounmap(priv->eq_db);
- free(priv->eq.buf);
+ iounmap(mtnic->eq_db);
+ free_memblock(mtnic->eq.buf, mtnic->eq.buf_size);
map_extra_error:
- free(priv->fw.extra_pages.buf);
+ ufree((intptr_t)mtnic->fw.extra_pages.buf);
map_fw_error:
- free(priv->fw.fw_pages.buf);
+ ufree((intptr_t)mtnic->fw.fw_pages.buf);
cmd_error:
- iounmap(priv->hcr);
- free(priv->cmd.buf);
- free(priv);
+ iounmap(mtnic->hcr);
+ free_memblock(mtnic->cmd.buf, PAGE_SIZE);
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
@@ -1195,7 +1186,7 @@ cmd_error:
*
*
********************************************************************/
-void mtnic_process_tx_cq(struct mtnic_priv *priv, struct net_device *dev,
+void mtnic_process_tx_cq(struct mtnic_port *priv, struct net_device *dev,
struct mtnic_cq *cq)
{
struct mtnic_cqe *cqe = cq->buf;
@@ -1209,10 +1200,10 @@ void mtnic_process_tx_cq(struct mtnic_priv *priv, struct net_device *dev,
/* Owner bit changes every round */
while (XNOR(cqe->op_tr_own & MTNIC_BIT_CQ_OWN, cq->last & cq->size)) {
netdev_tx_complete (dev, ring->iobuf[index]);
- ++cq->last;
- index = cq->last & (cq->size-1);
+ ++cq->last;
+ index = cq->last & (cq->size-1);
cqe = &cq->buf[index];
- }
+ }
/* Update consumer index */
cq->db->update_ci = cpu_to_be32(cq->last & 0xffffff);
@@ -1221,13 +1212,16 @@ void mtnic_process_tx_cq(struct mtnic_priv *priv, struct net_device *dev,
}
-int mtnic_process_rx_cq(struct mtnic_priv *priv, struct net_device *dev, struct mtnic_cq *cq)
+int mtnic_process_rx_cq(struct mtnic_port *priv,
+ struct net_device *dev,
+ struct mtnic_cq *cq)
{
struct mtnic_cqe *cqe;
struct mtnic_ring *ring = &priv->rx_ring;
int index;
int err;
struct io_buffer *rx_iob;
+ unsigned int length;
/* We assume a 1:1 mapping between CQEs and Rx descriptors, so Rx
@@ -1253,16 +1247,21 @@ int mtnic_process_rx_cq(struct mtnic_priv *priv, struct net_device *dev, struct
/*
* Packet is OK - process it.
*/
- rx_iob = ring->iobuf[index];
- iob_put(rx_iob, DEF_IOBUF_SIZE);
+ length = be32_to_cpu(cqe->byte_cnt);
+ rx_iob = ring->iobuf[index];
+ iob_put(rx_iob, length);
+
/* Add this packet to the receive queue. */
netdev_rx(dev, rx_iob);
- ring->iobuf[index] = NULL;
+ ring->iobuf[index] = NULL;
next:
++cq->last;
index = cq->last & (cq->size-1);
cqe = &cq->buf[index];
+
+
+
}
/* Update consumer index */
@@ -1274,7 +1273,7 @@ next:
err = mtnic_alloc_iobuf(priv, &priv->rx_ring, DEF_IOBUF_SIZE);
if (err) {
DBG("ERROR Allocating io buffer");
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
}
@@ -1307,24 +1306,27 @@ next:
static int
mtnic_open(struct net_device *dev)
{
- struct mtnic_priv *priv = netdev_priv(dev);
+ struct mtnic_port *priv = netdev_priv(dev);
+
int err = 0;
struct mtnic_ring *ring;
struct mtnic_cq *cq;
int cq_ind = 0;
u32 dev_link_state;
+ int link_check;
- DBG("starting port:%d", priv->port);
+ DBG("starting port:%d, MAC Address: 0x%12llx\n",
+ priv->port, priv->mtnic->fw.mac[priv->port]);
/* Alloc and configure CQs, TX, RX */
- err = mtnic_alloc_resources(dev);
+ err = mtnic_alloc_resources ( dev );
if (err) {
DBG("Error allocating resources\n");
- return MTNIC_ERROR;
+ return -EADDRINUSE;
}
/* Pass CQs configuration to HW */
- for (cq_ind = 0; cq_ind < NUM_CQS; ++cq_ind) {
+ for (cq_ind = 0; cq_ind < NUM_CQS; ++cq_ind) {
cq = &priv->cq[cq_ind];
err = mtnic_CONFIG_CQ(priv, priv->port, cq_ind, cq);
if (err) {
@@ -1333,24 +1335,25 @@ mtnic_open(struct net_device *dev)
if (cq_ind)
goto cq_error;
else
- return MTNIC_ERROR;
- }
+ goto allocation_error;
+ }
/* Update consumer index */
cq->db->update_ci = cpu_to_be32(cq->last & 0xffffff);
}
+
/* Pass Tx configuration to HW */
ring = &priv->tx_ring;
- err = mtnic_CONFIG_TX_RING(priv, priv->port, 0, ring);
+ err = mtnic_CONFIG_TX_RING(priv, priv->port, 0, ring);
if (err) {
DBG("Failed configuring Tx ring:0\n");
- goto cq_error;
+ goto cq_error;
}
/* Pass RX configuration to HW */
- ring = &priv->rx_ring;
- err = mtnic_CONFIG_RX_RING(priv, priv->port, 0, ring);
+ ring = &priv->rx_ring;
+ err = mtnic_CONFIG_RX_RING(priv, priv->port, 0, ring);
if (err) {
DBG("Failed configuring Rx ring:0\n");
goto tx_error;
@@ -1365,6 +1368,7 @@ mtnic_open(struct net_device *dev)
goto rx_error;
}
+
/* Set the port default ring to ring 0 */
err = mtnic_SET_PORT_DEFAULT_RING(priv, priv->port, 0);
if (err) {
@@ -1373,7 +1377,7 @@ mtnic_open(struct net_device *dev)
}
/* Set Mac address */
- err = mtnic_SET_RX_RING_ADDR(priv, priv->port, &priv->fw.mac[priv->port]);
+ err = mtnic_SET_RX_RING_ADDR(priv, priv->port, &priv->mtnic->fw.mac[priv->port]);
if (err) {
DBG("Failed setting default MAC address\n");
goto rx_error;
@@ -1387,11 +1391,14 @@ mtnic_open(struct net_device *dev)
}
/* Configure VLAN filter */
+ /* By adding this function, The second port won't accept packets
err = mtnic_CONFIG_PORT_VLAN_FILTER(priv, priv->port);
- if (err) {
+ if (err) {
DBG("Failed configuring VLAN filter\n");
goto rx_error;
}
+ */
+
/* Bring up physical link */
err = mtnic_SET_PORT_STATE(priv, priv->port, 1);
@@ -1399,29 +1406,52 @@ mtnic_open(struct net_device *dev)
DBG("Failed bringing up port\n");
goto rx_error;
}
- mdelay(300); /* Let link state stabilize if cable was connected */
+ /* PORT IS UP */
priv->state = CARD_UP;
- err = mtnic_HEART_BEAT(priv, &dev_link_state);
- if (err) {
- DBG("Failed getting device link state\n");
- return MTNIC_ERROR;
+
+ /* Checking Link is up */
+ DBG ( "Checking if link is up\n" );
+
+
+ for ( link_check = 0; link_check < CHECK_LINK_TIMES; link_check ++ ) {
+ /* Let link state stabilize if cable was connected */
+ mdelay ( DELAY_LINK_CHECK );
+
+ err = mtnic_HEART_BEAT(priv, &dev_link_state);
+ if (err) {
+ DBG("Failed getting device link state\n");
+ return -ENETDOWN;
+ }
+
+ if ( dev_link_state & priv->port ) {
+ /* Link is up */
+ break;
+ }
}
- if (!(dev_link_state & 0x3)) {
+
+
+ if ( ! ( dev_link_state & 0x3 ) ) {
DBG("Link down, check cables and restart\n");
- return MTNIC_ERROR;
+ netdev_link_down ( dev );
+ return -ENETDOWN;
}
- return 0;
+ DBG ( "Link is up!\n" );
+ /* Mark as link up */
+ netdev_link_up ( dev );
+
+ return 0;
rx_error:
err = mtnic_RELEASE_RESOURCE(priv, priv->port,
- MTNIC_IF_RESOURCE_TYPE_RX_RING, 0);
+ MTNIC_IF_RESOURCE_TYPE_RX_RING, 0);
tx_error:
err |= mtnic_RELEASE_RESOURCE(priv, priv->port,
MTNIC_IF_RESOURCE_TYPE_TX_RING, 0);
+
cq_error:
while (cq_ind) {
err |= mtnic_RELEASE_RESOURCE(priv, priv->port,
@@ -1430,66 +1460,81 @@ cq_error:
if (err)
DBG("Eror Releasing resources\n");
- return MTNIC_ERROR;
+allocation_error:
+
+ free_memblock(priv->tx_ring.buf, priv->tx_ring.buf_size);
+ iounmap(priv->tx_ring.txcq_db);
+ free_memblock(priv->cq[1].buf, priv->cq[1].buf_size);
+ free_memblock(priv->cq[1].db, sizeof(struct mtnic_cq_db_record));
+ free_memblock(priv->rx_ring.buf, priv->rx_ring.buf_size);
+ free_memblock(priv->rx_ring.db, sizeof(struct mtnic_cq_db_record));
+ free_memblock(priv->cq[0].buf, priv->cq[0].buf_size);
+ free_memblock(priv->cq[0].db, sizeof(struct mtnic_cq_db_record));
+
+ mtnic_free_io_buffers(&priv->rx_ring);
+
+ return -ENETDOWN;
}
+
/** Check if we got completion for receive and transmit and
* check the line with heart_bit command */
static void
-mtnic_poll(struct net_device *dev)
+mtnic_poll ( struct net_device *dev )
{
- struct mtnic_priv *priv = netdev_priv(dev);
+ struct mtnic_port *priv = netdev_priv(dev);
struct mtnic_cq *cq;
u32 dev_link_state;
int err;
unsigned int i;
- /* In case of an old error then return */
+ /* In case of an old error then return */
if (priv->state != CARD_UP)
return;
/* We do not check the device every call _poll call,
- since it will slow it down */
+ since it will slow it down */
if ((priv->poll_counter % ROUND_TO_CHECK) == 0) {
/* Check device */
err = mtnic_HEART_BEAT(priv, &dev_link_state);
if (err) {
DBG("Device has internal error\n");
- priv->state = CARD_DOWN;
+ priv->state = CARD_LINK_DOWN;
return;
}
if (!(dev_link_state & 0x3)) {
DBG("Link down, check cables and restart\n");
- priv->state = CARD_DOWN;
+ priv->state = CARD_LINK_DOWN;
return;
}
}
-
/* Polling CQ */
for (i = 0; i < NUM_CQS; i++) {
cq = &priv->cq[i]; //Passing on the 2 cqs.
if (cq->is_rx) {
- err = mtnic_process_rx_cq(priv, cq->dev, cq);
+ err = mtnic_process_rx_cq(priv, cq->dev, cq);
if (err) {
- priv->state = CARD_DOWN;
+ priv->state = CARD_LINK_DOWN;
DBG(" Error allocating RX buffers\n");
return;
}
- } else {
- mtnic_process_tx_cq(priv, cq->dev, cq);
+ } else {
+ mtnic_process_tx_cq(priv, cq->dev, cq);
}
}
++ priv->poll_counter;
}
+
+
static int
mtnic_transmit( struct net_device *dev, struct io_buffer *iobuf )
{
- struct mtnic_priv *priv = netdev_priv(dev);
+ struct mtnic_port *priv = netdev_priv(dev);
struct mtnic_ring *ring;
struct mtnic_tx_desc *tx_desc;
struct mtnic_data_seg *data;
@@ -1497,34 +1542,34 @@ mtnic_transmit( struct net_device *dev, struct io_buffer *iobuf )
/* In case of an error then return */
if (priv->state != CARD_UP)
- return MTNIC_ERROR;
+ return -ENETDOWN;
ring = &priv->tx_ring;
- index = ring->prod & ring->size_mask;
+ index = ring->prod & ring->size_mask;
if ((ring->prod - ring->cons) >= ring->size) {
- DBG("No space left for descriptors!!! cons: %lx prod: %lx\n",
+ DBG("No space left for descriptors!!! cons: %x prod: %x\n",
ring->cons, ring->prod);
mdelay(5);
- return MTNIC_ERROR;/* no space left */
+ return -EAGAIN;/* no space left */
}
- /* get current descriptor */
+ /* get current descriptor */
tx_desc = ring->buf + (index * sizeof(struct mtnic_tx_desc));
- /* Prepare ctrl segement */
- tx_desc->ctrl.size_vlan = cpu_to_be32(2);
- tx_desc->ctrl.flags = cpu_to_be32(MTNIC_BIT_TX_COMP |
- MTNIC_BIT_NO_ICRC);
- tx_desc->ctrl.op_own = cpu_to_be32(MTNIC_OPCODE_SEND) |
- ((ring->prod & ring->size) ?
- cpu_to_be32(MTNIC_BIT_DESC_OWN) : 0);
-
/* Prepare Data Seg */
data = &tx_desc->data;
data->addr_l = cpu_to_be32((u32)virt_to_bus(iobuf->data));
data->count = cpu_to_be32(iob_len(iobuf));
- data->mem_type = priv->fw.mem_type_snoop_be;
+ data->mem_type = priv->mtnic->fw.mem_type_snoop_be;
+
+ /* Prepare ctrl segement */
+ tx_desc->ctrl.size_vlan = cpu_to_be32(2);
+ tx_desc->ctrl.flags = cpu_to_be32(MTNIC_BIT_TX_COMP |
+ MTNIC_BIT_NO_ICRC);
+ tx_desc->ctrl.op_own = cpu_to_be32(MTNIC_OPCODE_SEND) |
+ ((ring->prod & ring->size) ?
+ cpu_to_be32(MTNIC_BIT_DESC_OWN) : 0);
/* Attach io_buffer */
ring->iobuf[index] = iobuf;
@@ -1543,11 +1588,13 @@ mtnic_transmit( struct net_device *dev, struct io_buffer *iobuf )
static void
mtnic_close(struct net_device *dev)
{
- struct mtnic_priv *priv = netdev_priv(dev);
+ struct mtnic_port *priv = netdev_priv(dev);
int err = 0;
DBG("Close called for port:%d\n", priv->port);
- if (priv->state == CARD_UP) {
+ if ( ( priv->state == CARD_UP ) ||
+ ( priv->state == CARD_LINK_DOWN ) ) {
+
/* Disable port */
err |= mtnic_SET_PORT_STATE(priv, priv->port, 0);
/*
@@ -1565,31 +1612,33 @@ mtnic_close(struct net_device *dev)
/* Stop CQs */
err |= mtnic_RELEASE_RESOURCE(priv, priv->port,
- MTNIC_IF_RESOURCE_TYPE_CQ, 0);
+ MTNIC_IF_RESOURCE_TYPE_CQ, 0);
err |= mtnic_RELEASE_RESOURCE(priv, priv->port,
- MTNIC_IF_RESOURCE_TYPE_CQ, 1);
+ MTNIC_IF_RESOURCE_TYPE_CQ, 1);
if (err) {
- DBG("Close reported error %d", err);
+ DBG("Close reported error %d\n", err);
}
- /* Free memory */
- free(priv->tx_ring.buf);
+ mdelay ( 10 );
+
+ /* free memory */
+ free_memblock(priv->tx_ring.buf, priv->tx_ring.buf_size);
iounmap(priv->tx_ring.txcq_db);
- free(priv->cq[1].buf);
- free(priv->cq[1].db);
+ free_memblock(priv->cq[1].buf, priv->cq[1].buf_size);
+ free_memblock(priv->cq[1].db, sizeof(struct mtnic_cq_db_record));
+ free_memblock(priv->rx_ring.buf, priv->rx_ring.buf_size);
+ free_memblock(priv->rx_ring.db, sizeof(struct mtnic_cq_db_record));
+ free_memblock(priv->cq[0].buf, priv->cq[0].buf_size);
+ free_memblock(priv->cq[0].db, sizeof(struct mtnic_cq_db_record));
/* Free RX buffers */
mtnic_free_io_buffers(&priv->rx_ring);
- free(priv->rx_ring.buf);
- free(priv->rx_ring.db);
- free(priv->cq[0].buf);
- free(priv->cq[0].db);
- priv->state = CARD_INITIALIZED;
}
+ priv->state = CARD_INITIALIZED;
}
@@ -1599,35 +1648,61 @@ mtnic_disable(struct pci_device *pci)
{
int err;
- struct net_device *dev = pci_get_drvdata(pci);
- struct mtnic_priv *priv = netdev_priv(dev);
-
- /* Should NOT happen! but just in case */
- if (priv->state == CARD_UP)
- mtnic_close(dev);
-
- if (priv->state == CARD_INITIALIZED) {
- err = mtnic_RELEASE_RESOURCE(priv, 0,
- MTNIC_IF_RESOURCE_TYPE_EQ, 0);
- DBG("Calling MTNIC_CLOSE command\n");
- err |= mtnic_cmd(priv, NULL, NULL, 0,
- MTNIC_IF_CMD_CLOSE_NIC);
- if (err) {
- DBG("Error Releasing resources %d\n", err);
- }
+ int i;
+ struct mtnic *mtnic = pci_get_drvdata(pci);
+
+
+ struct net_device *dev;
+ struct mtnic_port *priv;
- free(priv->cmd.buf);
- iounmap(priv->hcr);
- ufree((u32)priv->fw.fw_pages.buf);
- ufree((u32)priv->fw.extra_pages.buf);
- free(priv->eq.buf);
- iounmap(priv->eq_db);
- priv->state = CARD_DOWN;
+ for ( i = ( mtnic->fw.num_ports - 1 ); i >= 0; i-- ) {
+
+ dev = mtnic->netdev[i];
+
+ priv = netdev_priv(dev);
+
+ /* Just in case */
+ if ( ( priv->state == CARD_UP ) ||
+ ( priv->state == CARD_LINK_DOWN ) )
+ mtnic_close ( dev );
+ }
+
+ /* Releasing EQ */
+ priv = netdev_priv ( mtnic->netdev[0] );
+ err = mtnic_RELEASE_RESOURCE(priv, 1,
+ MTNIC_IF_RESOURCE_TYPE_EQ, 0);
+
+ DBG("Calling MTNIC_CLOSE command\n");
+ err |= mtnic_cmd(mtnic, NULL, NULL, 0,
+ MTNIC_IF_CMD_CLOSE_NIC);
+ if (err) {
+ DBG("Error Releasing resources %d\n", err);
+ }
+
+ free_memblock(mtnic->cmd.buf, PAGE_SIZE);
+ iounmap(mtnic->hcr);
+ ufree((intptr_t)mtnic->fw.fw_pages.buf);
+ ufree((intptr_t)mtnic->fw.extra_pages.buf);
+ free_memblock(mtnic->eq.buf, mtnic->eq.buf_size);
+ iounmap(mtnic->eq_db);
+
+
+ for ( i = ( mtnic->fw.num_ports - 1 ); i >= 0; i-- ) {
+ dev = mtnic->netdev[i];
+ unregister_netdev ( dev );
+ netdev_nullify ( dev );
+ netdev_put ( dev );
}
- unregister_netdev(dev);
- netdev_nullify(dev);
- netdev_put(dev);
+ free ( mtnic );
+
+
+ mtnic_reset ();
+ mdelay ( 1000 );
+ /* Restore config, if we would like to retry booting */
+ restore_config ();
+
+
}
@@ -1642,11 +1717,11 @@ mtnic_irq(struct net_device *netdev __unused, int enable __unused)
/** mtnic net device operations */
static struct net_device_operations mtnic_operations = {
- .open = mtnic_open,
- .close = mtnic_close,
- .transmit = mtnic_transmit,
- .poll = mtnic_poll,
- .irq = mtnic_irq,
+ .open = mtnic_open,
+ .close = mtnic_close,
+ .transmit = mtnic_transmit,
+ .poll = mtnic_poll,
+ .irq = mtnic_irq,
};
@@ -1657,102 +1732,119 @@ static struct net_device_operations mtnic_operations = {
static int
mtnic_probe(struct pci_device *pci,
- const struct pci_device_id *id __unused)
+ const struct pci_device_id *id __unused)
{
- struct net_device *dev;
- struct mtnic_priv *priv;
+ struct mtnic_port *priv;
+ struct mtnic *mtnic;
int err;
u64 mac;
- u32 result = 0;
- void *dev_id;
- int i;
+ int port_index;
+
- adjust_pci_device(pci);
+ adjust_pci_device(pci);
- err = mtnic_init_pci(pci);
+ err = mtnic_init_pci(pci);
if (err) {
DBG("Error in pci_init\n");
- return MTNIC_ERROR;
+ return -EIO;
}
mtnic_reset();
- mdelay(1000);
+ mdelay(1000);
- err = restore_config();
+ err = restore_config();
if (err) {
- DBG("Error restoring config\n");
+ DBG("Error in restoring config\n");
return err;
}
- /* Checking MTNIC device ID */
- dev_id = ioremap(mtnic_pci_dev.dev.bar[0] +
- MTNIC_DEVICE_ID_OFFSET, 4);
- result = ntohl(readl(dev_id));
- iounmap(dev_id);
- if (result != MTNIC_DEVICE_ID) {
- DBG("Wrong Devie ID (0x%lx) !!!", result);
- return MTNIC_ERROR;
+ mtnic = zalloc ( sizeof ( *mtnic ) );
+ if ( ! mtnic ) {
+ DBG ( "Error Allocating mtnic buffer\n" );
+ return -EADDRINUSE;
}
- /* Initializing net device */
- dev = alloc_etherdev(sizeof(struct mtnic_priv));
- if (dev == NULL) {
- DBG("Net device allocation failed\n");
- return MTNIC_ERROR;
- }
- /*
- * Initialize driver private data
- */
- priv = netdev_priv(dev);
- memset(priv, 0, sizeof(struct mtnic_priv));
- priv->dev = dev;
- priv->pdev = pci;
- priv->dev->dev = &pci->dev;
- /* Attach pci device */
- pci_set_drvdata(pci, priv->dev);
- netdev_init(dev, &mtnic_operations);
+ pci_set_drvdata(pci, mtnic);
+
+ mtnic->pdev = pci;
/* Initialize hardware */
- err = mtnic_init_card(dev);
+ err = mtnic_init_card ( mtnic );
if (err) {
DBG("Error in init_card\n");
- return MTNIC_ERROR;
+ goto err_init_card;
}
- /* Program the MAC address */
- mac = priv->fw.mac[priv->port];
- printf("Port %d Mac address: 0x%12llx\n", MTNIC_PORT_NUM + 1, mac);
- for (i = 0;i < MAC_ADDRESS_SIZE; ++i) {
- dev->ll_addr[MAC_ADDRESS_SIZE - i - 1] = mac & 0xFF;
- mac = mac >> 8;
+ for ( port_index = 0; port_index < mtnic->fw.num_ports; port_index ++ ) {
+ /* Initializing net device */
+ mtnic->netdev[port_index] = alloc_etherdev( sizeof ( struct mtnic_port ) );
+ if ( mtnic->netdev[port_index] == NULL ) {
+ DBG("Net device allocation failed\n");
+ goto err_alloc_mtnic;
+ }
+
+ /*
+ * Initialize driver private data
+ */
+
+ mtnic->netdev[port_index]->dev = &pci->dev;
+ priv = netdev_priv ( mtnic->netdev[port_index] );
+ memset ( priv, 0, sizeof ( struct mtnic_port ) );
+ priv->mtnic = mtnic;
+ priv->netdev = mtnic->netdev[port_index];
+
+ /* Attach pci device */
+ netdev_init(mtnic->netdev[port_index], &mtnic_operations);
+
+ /* Set port number */
+ priv->port = port_index;
+
+ /* Set state */
+ priv->state = CARD_DOWN;
}
- /* Mark as link up; we don't yet handle link state */
- netdev_link_up ( dev );
- if (register_netdev(dev)) {
- DBG("Netdev registration failed\n");
- return MTNIC_ERROR;
+ int mac_idx;
+ for ( port_index = 0; port_index < mtnic->fw.num_ports; port_index ++ ) {
+ priv = netdev_priv ( mtnic->netdev[port_index] );
+ /* Program the MAC address */
+ mac = priv->mtnic->fw.mac[port_index];
+ for (mac_idx = 0; mac_idx < MAC_ADDRESS_SIZE; ++mac_idx) {
+ mtnic->netdev[port_index]->ll_addr[MAC_ADDRESS_SIZE - mac_idx - 1] = mac & 0xFF;
+ mac = mac >> 8;
+ }
+
+ if ( register_netdev ( mtnic->netdev[port_index] ) ) {
+ DBG("Netdev registration failed\n");
+ priv->state = CARD_INITIALIZED;
+ goto err_alloc_mtnic;
+ }
}
return 0;
-}
-
+err_alloc_mtnic:
+ free ( mtnic );
+err_init_card:
+ return -EIO;
+}
static struct pci_device_id mtnic_nics[] = {
- PCI_ROM(0x15b3, 0x6368, "mtnic", "Mellanox MTNIC driver"),
+ PCI_ROM ( 0x15b3, 0x6368, "mt25448", "Mellanox ConnectX EN driver" ),
+ PCI_ROM ( 0x15b3, 0x6372, "mt25458", "Mellanox ConnectX ENt driver" ),
+ PCI_ROM ( 0x15b3, 0x6750, "mt26448", "Mellanox ConnectX EN GEN2 driver" ),
+ PCI_ROM ( 0x15b3, 0x675a, "mt26458", "Mellanox ConnectX ENt GEN2 driver" ),
};
struct pci_driver mtnic_driver __pci_driver = {
.ids = mtnic_nics,
.id_count = sizeof(mtnic_nics) / sizeof(mtnic_nics[0]),
- .probe = mtnic_probe,
+ .probe = mtnic_probe,
.remove = mtnic_disable,
};
diff --git a/gpxe/src/drivers/net/mtnic.h b/gpxe/src/drivers/net/mtnic.h
index 70a238e5..57a7b98c 100755..100644
--- a/gpxe/src/drivers/net/mtnic.h
+++ b/gpxe/src/drivers/net/mtnic.h
@@ -38,24 +38,28 @@
/*
* Device setup
*/
-
-/*
- Note port number can be changed under mtnic.c !
-*/
#define MTNIC_MAX_PORTS 2
+#define MTNIC_PORT1 0
+#define MTNIC_PORT2 1
#define NUM_TX_RINGS 1
#define NUM_RX_RINGS 1
#define NUM_CQS (NUM_RX_RINGS + NUM_TX_RINGS)
#define GO_BIT_TIMEOUT 6000
#define TBIT_RETRIES 100
#define UNITS_BUFFER_SIZE 8 /* can be configured to 4/8/16 */
-#define MAX_GAP_PROD_CONS (UNITS_BUFFER_SIZE/4)
-#define DEF_MTU 1600
-#define DEF_IOBUF_SIZE 1600
+#define MAX_GAP_PROD_CONS ( UNITS_BUFFER_SIZE / 4 )
+#define ETH_DEF_LEN 1540 /* 40 bytes used by the card */
+#define ETH_FCS_LEN 14
+#define DEF_MTU ETH_DEF_LEN + ETH_FCS_LEN
+#define DEF_IOBUF_SIZE ETH_DEF_LEN
+
#define MAC_ADDRESS_SIZE 6
#define NUM_EQES 16
#define ROUND_TO_CHECK 0x400
+#define DELAY_LINK_CHECK 300
+#define CHECK_LINK_TIMES 7
+
#define XNOR(x,y) (!(x) == !(y))
#define dma_addr_t unsigned long
@@ -108,7 +112,7 @@ typedef enum mtnic_if_cmd {
MTNIC_IF_CMD_CONFIG_RX = 0x005, /* general receive configuration */
MTNIC_IF_CMD_CONFIG_TX = 0x006, /* general transmit configuration */
MTNIC_IF_CMD_CONFIG_INT_FREQ = 0x007, /* interrupt timers freq limits */
- MTNIC_IF_CMD_HEART_BEAT = 0x008, /* NOP command testing liveliness */
+ MTNIC_IF_CMD_HEART_BEAT = 0x008, /* NOP command testing liveliness */
MTNIC_IF_CMD_CLOSE_NIC = 0x009, /* release memory and stop the NIC */
/* Port commands: */
@@ -119,22 +123,22 @@ typedef enum mtnic_if_cmd {
MTNIC_IF_CMD_CONFIG_PORT_VLAN_FILTER = 0x14, /* configure VLAN filter */
MTNIC_IF_CMD_CONFIG_PORT_MCAST_FILTER = 0x15, /* configure mcast filter */
MTNIC_IF_CMD_ENABLE_PORT_MCAST_FILTER = 0x16, /* enable/disable */
- MTNIC_IF_CMD_SET_PORT_MTU = 0x17, /* set port MTU */
+ MTNIC_IF_CMD_SET_PORT_MTU = 0x17, /* set port MTU */
MTNIC_IF_CMD_SET_PORT_PROMISCUOUS_MODE = 0x18, /* enable/disable promisc */
MTNIC_IF_CMD_SET_PORT_DEFAULT_RING = 0x19, /* set the default ring */
- MTNIC_IF_CMD_SET_PORT_STATE = 0x1a, /* set link up/down */
- MTNIC_IF_CMD_DUMP_STAT = 0x1b, /* dump statistics */
+ MTNIC_IF_CMD_SET_PORT_STATE = 0x1a, /* set link up/down */
+ MTNIC_IF_CMD_DUMP_STAT = 0x1b, /* dump statistics */
MTNIC_IF_CMD_ARM_PORT_STATE_EVENT = 0x1c, /* arm the port state event */
/* Ring / Completion queue commands: */
- MTNIC_IF_CMD_CONFIG_CQ = 0x20, /* set up completion queue */
- MTNIC_IF_CMD_CONFIG_RX_RING = 0x21, /* setup Rx ring */
- MTNIC_IF_CMD_SET_RX_RING_ADDR = 0x22, /* set Rx ring filter by address */
+ MTNIC_IF_CMD_CONFIG_CQ = 0x20, /* set up completion queue */
+ MTNIC_IF_CMD_CONFIG_RX_RING = 0x21, /* setup Rx ring */
+ MTNIC_IF_CMD_SET_RX_RING_ADDR = 0x22, /* set Rx ring filter by address */
MTNIC_IF_CMD_SET_RX_RING_MCAST = 0x23, /* set Rx ring mcast filter */
- MTNIC_IF_CMD_ARM_RX_RING_WM = 0x24, /* one-time low-watermark INT */
- MTNIC_IF_CMD_CONFIG_TX_RING = 0x25, /* set up Tx ring */
+ MTNIC_IF_CMD_ARM_RX_RING_WM = 0x24, /* one-time low-watermark INT */
+ MTNIC_IF_CMD_CONFIG_TX_RING = 0x25, /* set up Tx ring */
MTNIC_IF_CMD_ENFORCE_TX_RING_ADDR = 0x26, /* setup anti spoofing */
- MTNIC_IF_CMD_CONFIG_EQ = 0x27, /* config EQ ring */
+ MTNIC_IF_CMD_CONFIG_EQ = 0x27, /* config EQ ring */
MTNIC_IF_CMD_RELEASE_RESOURCE = 0x28, /* release internal ref to resource */
}
mtnic_if_cmd_t;
@@ -144,15 +148,15 @@ mtnic_if_cmd_t;
typedef enum mtnic_if_caps {
MTNIC_IF_CAP_MAX_TX_RING_PER_PORT = 0x0,
MTNIC_IF_CAP_MAX_RX_RING_PER_PORT = 0x1,
- MTNIC_IF_CAP_MAX_CQ_PER_PORT = 0x2,
- MTNIC_IF_CAP_NUM_PORTS = 0x3,
- MTNIC_IF_CAP_MAX_TX_DESC = 0x4,
- MTNIC_IF_CAP_MAX_RX_DESC = 0x5,
- MTNIC_IF_CAP_MAX_CQES = 0x6,
- MTNIC_IF_CAP_MAX_TX_SG_ENTRIES = 0x7,
- MTNIC_IF_CAP_MAX_RX_SG_ENTRIES = 0x8,
- MTNIC_IF_CAP_MEM_KEY = 0x9, /* key to mem (after map_pages) */
- MTNIC_IF_CAP_RSS_HASH_TYPE = 0xa, /* one of mtnic_if_rss_types_t */
+ MTNIC_IF_CAP_MAX_CQ_PER_PORT = 0x2,
+ MTNIC_IF_CAP_NUM_PORTS = 0x3,
+ MTNIC_IF_CAP_MAX_TX_DESC = 0x4,
+ MTNIC_IF_CAP_MAX_RX_DESC = 0x5,
+ MTNIC_IF_CAP_MAX_CQES = 0x6,
+ MTNIC_IF_CAP_MAX_TX_SG_ENTRIES = 0x7,
+ MTNIC_IF_CAP_MAX_RX_SG_ENTRIES = 0x8,
+ MTNIC_IF_CAP_MEM_KEY = 0x9, /* key to mem (after map_pages) */
+ MTNIC_IF_CAP_RSS_HASH_TYPE = 0xa, /* one of mtnic_if_rss_types_t */
MTNIC_IF_CAP_MAX_PORT_UCAST_ADDR = 0xc,
MTNIC_IF_CAP_MAX_RING_UCAST_ADDR = 0xd, /* only for ADDR steer */
MTNIC_IF_CAP_MAX_PORT_MCAST_ADDR = 0xe,
@@ -164,20 +168,20 @@ typedef enum mtnic_if_caps {
MTNIC_IF_CAP_EQ_DB_OFFSET = 0x14, /* offset in bytes for EQ doorbell record */
/* These are per port - using port number from cap modifier field */
- MTNIC_IF_CAP_SPEED = 0x20,
- MTNIC_IF_CAP_DEFAULT_MAC = 0x21,
- MTNIC_IF_CAP_EQ_OFFSET = 0x22,
- MTNIC_IF_CAP_CQ_OFFSET = 0x23,
+ MTNIC_IF_CAP_SPEED = 0x20,
+ MTNIC_IF_CAP_DEFAULT_MAC = 0x21,
+ MTNIC_IF_CAP_EQ_OFFSET = 0x22,
+ MTNIC_IF_CAP_CQ_OFFSET = 0x23,
MTNIC_IF_CAP_TX_OFFSET = 0x24,
MTNIC_IF_CAP_RX_OFFSET = 0x25,
} mtnic_if_caps_t;
typedef enum mtnic_if_steer_types {
- MTNIC_IF_STEER_NONE = 0,
- MTNIC_IF_STEER_PRIORITY = 1,
- MTNIC_IF_STEER_RSS = 2,
- MTNIC_IF_STEER_ADDRESS = 3,
+ MTNIC_IF_STEER_NONE = 0,
+ MTNIC_IF_STEER_PRIORITY = 1,
+ MTNIC_IF_STEER_RSS = 2,
+ MTNIC_IF_STEER_ADDRESS = 3,
} mtnic_if_steer_types_t;
/** types of memory access modes */
@@ -188,19 +192,12 @@ typedef enum mtnic_if_memory_types {
enum {
- MTNIC_HCR_BASE = 0x1f000,
- MTNIC_HCR_SIZE = 0x0001c,
- MTNIC_CLR_INT_SIZE = 0x00008,
+ MTNIC_HCR_BASE = 0x1f000,
+ MTNIC_HCR_SIZE = 0x0001c,
+ MTNIC_CLR_INT_SIZE = 0x00008,
};
-#define MELLANOX_VENDOR_ID 0x15b3
-#define MTNIC_DEVICE_ID 0x00a00190
#define MTNIC_RESET_OFFSET 0xF0010
-#define MTNIC_DEVICE_ID_OFFSET 0xF0014
-
-
-
-
@@ -265,7 +262,7 @@ struct mtnic_ring {
/* Buffers */
u32 buf_size; /* ring buffer size in bytes */
- dma_addr_t dma;
+ dma_addr_t dma;
void *buf;
struct io_buffer *iobuf[UNITS_BUFFER_SIZE];
@@ -274,7 +271,7 @@ struct mtnic_ring {
u32 db_offset;
/* Rx ring only */
- dma_addr_t iobuf_dma;
+ dma_addr_t iobuf_dma;
struct mtnic_rx_db_record *db;
dma_addr_t db_dma;
};
@@ -351,15 +348,16 @@ struct mtnic_eqe {
struct mtnic_eq {
u32 size; /* number of EQEs in ring */
- u32 buf_size; /* EQ size in bytes */
+ u32 buf_size; /* EQ size in bytes */
void *buf;
dma_addr_t dma;
};
enum mtnic_state {
CARD_DOWN,
- CARD_INITIALIZED,
- CARD_UP
+ CARD_INITIALIZED,
+ CARD_UP,
+ CARD_LINK_DOWN,
};
/* FW */
@@ -375,9 +373,9 @@ struct mtnic_err_buf {
struct mtnic_cmd {
- void *buf;
- u32 mapping;
- u32 tbit;
+ void *buf;
+ unsigned long mapping;
+ u32 tbit;
};
@@ -395,40 +393,52 @@ struct mtnic_txcq_db {
* Device private data
*
*/
-struct mtnic_priv {
- struct net_device *dev;
- struct pci_device *pdev;
- u8 port;
+struct mtnic {
+ struct net_device *netdev[MTNIC_MAX_PORTS];
+ struct mtnic_if_cmd_reg *hcr;
+ struct mtnic_cmd cmd;
+ struct pci_device *pdev;
- enum mtnic_state state;
- /* Firmware and board info */
- u64 fw_ver;
+ struct mtnic_eq eq;
+ u32 *eq_db;
+
+ /* Firmware and board info */
+ u64 fw_ver;
struct {
- struct mtnic_pages fw_pages;
- struct mtnic_pages extra_pages;
- struct mtnic_err_buf err_buf;
- u16 ifc_rev;
- u8 num_ports;
- u64 mac[MTNIC_MAX_PORTS];
- u16 cq_offset;
- u16 tx_offset[MTNIC_MAX_PORTS];
- u16 rx_offset[MTNIC_MAX_PORTS];
- u32 mem_type_snoop_be;
- u32 txcq_db_offset;
- u32 eq_db_offset;
- } fw;
-
-
- struct mtnic_if_cmd_reg *hcr;
- struct mtnic_cmd cmd;
+ struct mtnic_pages fw_pages;
+ struct mtnic_pages extra_pages;
+ struct mtnic_err_buf err_buf;
+ u16 ifc_rev;
+ u8 num_ports;
+ u64 mac[MTNIC_MAX_PORTS];
+ u16 cq_offset;
+ u16 tx_offset[MTNIC_MAX_PORTS];
+ u16 rx_offset[MTNIC_MAX_PORTS];
+ u32 mem_type_snoop_be;
+ u32 txcq_db_offset;
+ u32 eq_db_offset;
+ } fw;
+};
+
+
+
+
+
+struct mtnic_port {
+
+ struct mtnic *mtnic;
+ u8 port;
+
+ enum mtnic_state state;
/* TX, RX, CQs, EQ */
- struct mtnic_ring tx_ring;
- struct mtnic_ring rx_ring;
- struct mtnic_cq cq[NUM_CQS];
- struct mtnic_eq eq;
- u32 *eq_db;
- u32 poll_counter;
+ struct mtnic_ring tx_ring;
+ struct mtnic_ring rx_ring;
+ struct mtnic_cq cq[NUM_CQS];
+ u32 poll_counter;
+ struct net_device *netdev;
+
+
};
@@ -492,33 +502,34 @@ struct mtnic_if_query_fw_out_mbox {
/* CMD MTNIC_IF_CMD_QUERY_CAP */
struct mtnic_if_query_cap_in_imm {
u16 reserved1;
- u8 cap_modifier; /* a modifier for the particular capability */
- u8 cap_index; /* the index of the capability queried */
+ u8 cap_modifier; /* a modifier for the particular capability */
+ u8 cap_index; /* the index of the capability queried */
u32 reserved2;
};
/* CMD OPEN_NIC */
struct mtnic_if_open_nic_in_mbox {
- u16 reserved1;
- u16 mkey; /* number of mem keys for all chip*/
- u32 mkey_entry; /* mem key entries for each key*/
- u8 log_rx_p1; /* log2 rx rings for port1 */
- u8 log_cq_p1; /* log2 cq for port1 */
- u8 log_tx_p1; /* log2 tx rings for port1 */
- u8 steer_p1; /* port 1 steering mode */
- u16 reserved2;
- u8 log_vlan_p1; /* log2 vlan per rx port1 */
- u8 log_mac_p1; /* log2 mac per rx port1 */
-
- u8 log_rx_p2; /* log2 rx rings for port1 */
- u8 log_cq_p2; /* log2 cq for port1 */
- u8 log_tx_p2; /* log2 tx rings for port1 */
- u8 steer_p2; /* port 1 steering mode */
- u16 reserved3;
- u8 log_vlan_p2; /* log2 vlan per rx port1 */
- u8 log_mac_p2; /* log2 mac per rx port1 */
+ u16 reserved1;
+ u16 mkey; /* number of mem keys for all chip*/
+ u32 mkey_entry; /* mem key entries for each key*/
+ u8 log_rx_p1; /* log2 rx rings for port1 */
+ u8 log_cq_p1; /* log2 cq for port1 */
+ u8 log_tx_p1; /* log2 tx rings for port1 */
+ u8 steer_p1; /* port 1 steering mode */
+ u16 reserved2;
+ u8 log_vlan_p1; /* log2 vlan per rx port1 */
+ u8 log_mac_p1; /* log2 mac per rx port1 */
+
+ u8 log_rx_p2; /* log2 rx rings for port1 */
+ u8 log_cq_p2; /* log2 cq for port1 */
+ u8 log_tx_p2; /* log2 tx rings for port1 */
+ u8 steer_p2; /* port 1 steering mode */
+ u16 reserved3;
+ u8 log_vlan_p2; /* log2 vlan per rx port1 */
+ u8 log_mac_p2; /* log2 mac per rx port1 */
};
+
/* CMD CONFIG_RX */
struct mtnic_if_config_rx_in_imm {
u16 spkt_size; /* size of small packets interrupts enabled on CQ */
@@ -535,9 +546,9 @@ struct mtnic_if_config_send_in_imm {
/* CMD HEART_BEAT */
struct mtnic_if_heart_beat_out_imm {
- u32 flags; /* several flags */
+ u32 flags; /* several flags */
#define MTNIC_MASK_HEAR_BEAT_INT_ERROR MTNIC_BC(31,1)
- u32 reserved;
+ u32 reserved;
};
@@ -547,14 +558,14 @@ struct mtnic_if_heart_beat_out_imm {
/* CMD CONFIG_PORT_VLAN_FILTER */
/* in mbox is a 4K bits mask - bit per VLAN */
struct mtnic_if_config_port_vlan_filter_in_mbox {
- u64 filter[64]; /* vlans[63:0] sit in filter[0], vlans[127:64] sit in filter[1] .. */
+ u64 filter[64]; /* vlans[63:0] sit in filter[0], vlans[127:64] sit in filter[1] .. */
};
/* CMD SET_PORT_MTU */
struct mtnic_if_set_port_mtu_in_imm {
u16 reserved1;
- u16 mtu; /* The MTU of the port in bytes */
+ u16 mtu; /* The MTU of the port in bytes */
u32 reserved2;
};
@@ -574,17 +585,17 @@ struct mtnic_if_set_port_state_in_imm {
/* CMD CONFIG_CQ */
struct mtnic_if_config_cq_in_mbox {
- u8 reserved1;
- u8 cq;
- u8 size; /* Num CQs is 2^size (size <= 22) */
- u8 offset; /* start address of CQE in first page (11:6) */
- u16 tlast; /* interrupt moderation timer from last completion usec */
+ u8 reserved1;
+ u8 cq;
+ u8 size; /* Num CQs is 2^size (size <= 22) */
+ u8 offset; /* start address of CQE in first page (11:6) */
+ u16 tlast; /* interrupt moderation timer from last completion usec */
u8 flags; /* flags */
- u8 int_vector; /* MSI index if MSI is enabled, otherwise reserved */
+ u8 int_vector; /* MSI index if MSI is enabled, otherwise reserved */
u16 reserved2;
u16 max_cnt; /* interrupt moderation counter */
- u8 page_size; /* each mapped page is 2^(12+page_size) bytes */
- u8 reserved4[3];
+ u8 page_size; /* each mapped page is 2^(12+page_size) bytes */
+ u8 reserved4[3];
u32 db_record_addr_h; /*physical address of CQ doorbell record */
u32 db_record_addr_l; /*physical address of CQ doorbell record */
u32 page_address[0]; /* 64 bit page addresses of CQ buffer */
@@ -592,21 +603,21 @@ struct mtnic_if_config_cq_in_mbox {
/* CMD CONFIG_RX_RING */
struct mtnic_if_config_rx_ring_in_mbox {
- u8 reserved1;
- u8 ring; /* The ring index (with offset) */
- u8 stride_size; /* stride and size */
+ u8 reserved1;
+ u8 ring; /* The ring index (with offset) */
+ u8 stride_size; /* stride and size */
/* Entry size = 16* (2^stride) bytes */
#define MTNIC_MASK_CONFIG_RX_RING_STRIDE MTNIC_BC(4,3)
/* Rx ring size is 2^size entries */
#define MTNIC_MASK_CONFIG_RX_RING_SIZE MTNIC_BC(0,4)
- u8 flags; /* Bit0 - header separation */
- u8 page_size; /* Each mapped page is 2^(12+page_size) bytes */
- u8 reserved2[2];
- u8 cq; /* CQ associated with this ring */
- u32 db_record_addr_h;
- u32 db_record_addr_l;
- u32 page_address[0];/* Array of 2^size 64b page descriptor addresses */
- /* Must hold all Rx descriptors + doorbell record. */
+ u8 flags; /* Bit0 - header separation */
+ u8 page_size; /* Each mapped page is 2^(12+page_size) bytes */
+ u8 reserved2[2];
+ u8 cq; /* CQ associated with this ring */
+ u32 db_record_addr_h;
+ u32 db_record_addr_l;
+ u32 page_address[0];/* Array of 2^size 64b page descriptor addresses */
+ /* Must hold all Rx descriptors + doorbell record. */
};
/* The modifier for SET_RX_RING_ADDR */
@@ -619,27 +630,27 @@ struct mtnic_if_set_rx_ring_modifier {
/* CMD SET_RX_RING_ADDR */
struct mtnic_if_set_rx_ring_addr_in_imm {
- u16 mac_47_32; /* UCAST MAC Address bits 47:32 */
+ u16 mac_47_32; /* UCAST MAC Address bits 47:32 */
u16 flags_vlan_id; /* MAC/VLAN flags and vlan id */
#define MTNIC_MASK_SET_RX_RING_ADDR_VLAN_ID MTNIC_BC(0,12)
#define MTNIC_MASK_SET_RX_RING_ADDR_BY_MAC MTNIC_BC(12,1)
#define MTNIC_MASK_SET_RX_RING_ADDR_BY_VLAN MTNIC_BC(13,1)
- u32 mac_31_0; /* UCAST MAC Address bits 31:0 */
+ u32 mac_31_0; /* UCAST MAC Address bits 31:0 */
};
/* CMD CONFIG_TX_RING */
struct mtnic_if_config_send_ring_in_mbox {
- u16 ring; /* The ring index (with offset) */
+ u16 ring; /* The ring index (with offset) */
#define MTNIC_MASK_CONFIG_TX_RING_INDEX MTNIC_BC(0,8)
- u8 size; /* Tx ring size is 32*2^size bytes */
+ u8 size; /* Tx ring size is 32*2^size bytes */
#define MTNIC_MASK_CONFIG_TX_RING_SIZE MTNIC_BC(0,4)
- u8 reserved;
- u8 page_size; /* Each mapped page is 2^(12+page_size) bytes */
- u8 qos_class; /* The COS used for this Tx */
- u16 cq; /* CQ associated with this ring */
+ u8 reserved;
+ u8 page_size; /* Each mapped page is 2^(12+page_size) bytes */
+ u8 qos_class; /* The COS used for this Tx */
+ u16 cq; /* CQ associated with this ring */
#define MTNIC_MASK_CONFIG_TX_CQ_INDEX MTNIC_BC(0,8)
u32 page_address[0]; /* 64 bit page addresses of descriptor buffer. */
- /* The buffer must accommodate all Tx descriptors */
+ /* The buffer must accommodate all Tx descriptors */
};
/* CMD CONFIG_EQ */
@@ -647,9 +658,9 @@ struct mtnic_if_config_eq_in_mbox {
u8 reserved1;
u8 int_vector; /* MSI index if MSI enabled; otherwise reserved */
#define MTNIC_MASK_CONFIG_EQ_INT_VEC MTNIC_BC(0,6)
- u8 size; /* Num CQs is 2^size entries (size <= 22) */
+ u8 size; /* Num CQs is 2^size entries (size <= 22) */
#define MTNIC_MASK_CONFIG_EQ_SIZE MTNIC_BC(0,5)
- u8 offset; /* Start address of CQE in first page (11:6) */
+ u8 offset; /* Start address of CQE in first page (11:6) */
#define MTNIC_MASK_CONFIG_EQ_OFFSET MTNIC_BC(0,6)
u8 page_size; /* Each mapped page is 2^(12+page_size) bytes*/
u8 reserved[3];
diff --git a/gpxe/src/drivers/net/natsemi.c b/gpxe/src/drivers/net/natsemi.c
index 028b905c..3a776234 100644
--- a/gpxe/src/drivers/net/natsemi.c
+++ b/gpxe/src/drivers/net/natsemi.c
@@ -61,7 +61,8 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
-#include <io.h>
+#include <string.h>
+#include <gpxe/io.h>
#include <errno.h>
#include <byteswap.h>
#include <unistd.h>
@@ -357,7 +358,7 @@ static int natsemi_open (struct net_device *netdev)
}
outl (virt_to_bus (&np->tx[0]),np->ioaddr + TxRingPtr);
- DBG ("Natsemi Tx descriptor loaded with: %#08lx\n",
+ DBG ("Natsemi Tx descriptor loaded with: %#08x\n",
inl (np->ioaddr + TxRingPtr));
/* Setup RX ring
@@ -376,7 +377,7 @@ static int natsemi_open (struct net_device *netdev)
}
outl (virt_to_bus (&np->rx[0]), np->ioaddr + RxRingPtr);
- DBG ("Natsemi Rx descriptor loaded with: %#08lx\n",
+ DBG ("Natsemi Rx descriptor loaded with: %#08x\n",
inl (np->ioaddr + RxRingPtr));
/* Setup RX Filter
@@ -400,7 +401,7 @@ static int natsemi_open (struct net_device *netdev)
outl (tx_config, np->ioaddr + TxConfig);
outl (rx_config, np->ioaddr + RxConfig);
- DBG ("Tx config register = %#08lx Rx config register = %#08lx\n",
+ DBG ("Tx config register = %#08x Rx config register = %#08x\n",
inl (np->ioaddr + TxConfig),
inl (np->ioaddr + RxConfig));
@@ -551,7 +552,7 @@ static void natsemi_poll (struct net_device *netdev)
netdev_rx_err (netdev, NULL, -EINVAL);
DBG ("natsemi_poll: Corrupted packet received!"
- " Status = %#08lx\n",
+ " Status = %#08x\n",
np->rx[np->rx_cur].cmdsts);
} else {
diff --git a/gpxe/src/drivers/net/ne2k_isa.c b/gpxe/src/drivers/net/ne2k_isa.c
new file mode 100644
index 00000000..f8a45cc8
--- /dev/null
+++ b/gpxe/src/drivers/net/ne2k_isa.c
@@ -0,0 +1,373 @@
+/**************************************************************************
+ ETHERBOOT - BOOTP/TFTP Bootstrap Program
+
+ Author: Martin Renters
+ Date: May/94
+
+ This code is based heavily on David Greenman's if_ed.c driver
+
+ Copyright (C) 1993-1994, David Greenman, Martin Renters.
+ This software may be used, modified, copied, distributed, and sold, in
+ both source and binary form provided that the above copyright and these
+ terms are retained. Under no circumstances are the authors responsible for
+ the proper functioning of this software, nor do the authors assume any
+ responsibility for damages incurred with its use.
+
+ Multicast support added by Timothy Legge (timlegge@users.sourceforge.net) 09/28/2003
+ Relocation support added by Ken Yap (ken_yap@users.sourceforge.net) 28/12/02
+ Card Detect support adapted from the eCos driver (Christian Plessl <cplessl@ee.ethz.ch>)
+ Extracted from ns8390.c and adapted by Pantelis Koukousoulas <pktoss@gmail.com>
+ **************************************************************************/
+
+#include "ns8390.h"
+#include "etherboot.h"
+#include "nic.h"
+#include <gpxe/ethernet.h>
+#include <gpxe/isa.h>
+#include <errno.h>
+
+#define ASIC_PIO NE_DATA
+
+static unsigned char eth_vendor, eth_flags;
+static unsigned short eth_nic_base, eth_asic_base;
+static unsigned char eth_memsize, eth_rx_start, eth_tx_start;
+static Address eth_bmem, eth_rmem;
+static unsigned char eth_drain_receiver;
+
+static struct nic_operations ne_operations;
+static void ne_reset(struct nic *nic, struct isa_device *isa);
+
+static isa_probe_addr_t ne_probe_addrs[] = { 0x300, 0x280, 0x320, 0x340, 0x380, 0x220, };
+
+/**************************************************************************
+ ETH_PIO_READ - Read a frame via Programmed I/O
+ **************************************************************************/
+static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt) {
+ outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+ outb(cnt, eth_nic_base + D8390_P0_RBCR0);
+ outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1);
+ outb(src, eth_nic_base + D8390_P0_RSAR0);
+ outb(src >> 8, eth_nic_base + D8390_P0_RSAR1);
+ outb(D8390_COMMAND_RD0 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+ if (eth_flags & FLAG_16BIT)
+ cnt = (cnt + 1) >> 1;
+
+ while (cnt--) {
+ if (eth_flags & FLAG_16BIT) {
+ *((unsigned short *) dst) = inw(eth_asic_base + ASIC_PIO);
+ dst += 2;
+ } else
+ *(dst++) = inb(eth_asic_base + ASIC_PIO);
+ }
+}
+
+/**************************************************************************
+ ETH_PIO_WRITE - Write a frame via Programmed I/O
+ **************************************************************************/
+static void eth_pio_write(const unsigned char *src, unsigned int dst,
+ unsigned int cnt) {
+ outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+ outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
+ outb(cnt, eth_nic_base + D8390_P0_RBCR0);
+ outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1);
+ outb(dst, eth_nic_base + D8390_P0_RSAR0);
+ outb(dst >> 8, eth_nic_base + D8390_P0_RSAR1);
+ outb(D8390_COMMAND_RD1 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+ if (eth_flags & FLAG_16BIT)
+ cnt = (cnt + 1) >> 1;
+
+ while (cnt--) {
+
+ if (eth_flags & FLAG_16BIT) {
+ outw(*((unsigned short *) src), eth_asic_base + ASIC_PIO);
+ src += 2;
+ } else
+ outb(*(src++), eth_asic_base + ASIC_PIO);
+ }
+}
+
+/**************************************************************************
+ enable_multicast - Enable Multicast
+ **************************************************************************/
+static void enable_multicast(unsigned short eth_nic_base) {
+ unsigned char mcfilter[8];
+ int i;
+
+ memset(mcfilter, 0xFF, 8);
+ outb(4, eth_nic_base + D8390_P0_RCR);
+ outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1, eth_nic_base + D8390_P0_COMMAND);
+ for (i = 0; i < 8; i++) {
+ outb(mcfilter[i], eth_nic_base + 8 + i);
+ if (inb(eth_nic_base + 8 + i) != mcfilter[i])
+ DBG("Error SMC 83C690 Multicast filter read/write mishap %d\n",
+ i);
+ }
+ outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0, eth_nic_base + D8390_P0_COMMAND);
+ outb(4 | 0x08, eth_nic_base + D8390_P0_RCR);
+}
+
+/**************************************************************************
+ NE_PROBE1 - Look for an adapter on the ISA bus
+ **************************************************************************/
+static int ne_probe1(isa_probe_addr_t ioaddr) {
+ //From the eCos driver
+ unsigned int regd;
+ unsigned int state;
+
+ state = inb(ioaddr);
+ outb(ioaddr, D8390_COMMAND_RD2 | D8390_COMMAND_PS1 | D8390_COMMAND_STP);
+ regd = inb(ioaddr + D8390_P0_TCR);
+
+ if (inb(ioaddr + D8390_P0_TCR)) {
+ outb(ioaddr, state);
+ outb(ioaddr + 0x0d, regd);
+ return 0;
+ }
+
+ return 1;
+}
+
+/**************************************************************************
+ NE_PROBE - Initialize an adapter ???
+ **************************************************************************/
+static int ne_probe(struct nic *nic, struct isa_device *isa) {
+ int i;
+ unsigned char c;
+ unsigned char romdata[16];
+ unsigned char testbuf[32];
+
+ eth_vendor = VENDOR_NONE;
+ eth_drain_receiver = 0;
+
+ nic->irqno = 0;
+ nic->ioaddr = isa->ioaddr;
+ eth_nic_base = isa->ioaddr;
+
+ /******************************************************************
+ Search for NE1000/2000 if no WD/SMC or 3com cards
+ ******************************************************************/
+ if (eth_vendor == VENDOR_NONE) {
+
+ static unsigned char test[] = "NE*000 memory";
+
+ eth_bmem = 0; /* No shared memory */
+
+ eth_flags = FLAG_PIO;
+ eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
+ eth_memsize = MEM_16384;
+ eth_tx_start = 32;
+ eth_rx_start = 32 + D8390_TXBUF_SIZE;
+ c = inb(eth_asic_base + NE_RESET);
+ outb(c, eth_asic_base + NE_RESET);
+ (void) inb(0x84);
+ outb(D8390_COMMAND_STP | D8390_COMMAND_RD2, eth_nic_base
+ + D8390_P0_COMMAND);
+ outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
+ outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
+ outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
+ outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
+ eth_pio_write((unsigned char *) test, 8192, sizeof(test));
+ eth_pio_read(8192, testbuf, sizeof(test));
+ if (!memcmp(test, testbuf, sizeof(test)))
+ goto out;
+ eth_flags |= FLAG_16BIT;
+ eth_memsize = MEM_32768;
+ eth_tx_start = 64;
+ eth_rx_start = 64 + D8390_TXBUF_SIZE;
+ outb(D8390_DCR_WTS | D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base
+ + D8390_P0_DCR);
+ outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
+ outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
+ eth_pio_write((unsigned char *) test, 16384, sizeof(test));
+ eth_pio_read(16384, testbuf, sizeof(test));
+ if (!memcmp(testbuf, test, sizeof(test)))
+ goto out;
+
+
+out:
+ if (eth_nic_base == 0)
+ return (0);
+ if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */
+ eth_flags |= FLAG_16BIT;
+ eth_vendor = VENDOR_NOVELL;
+ eth_pio_read(0, romdata, sizeof(romdata));
+ for (i = 0; i < ETH_ALEN; i++) {
+ nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
+ }
+ nic->ioaddr = eth_nic_base;
+ DBG("\nNE%c000 base %4.4x, MAC Addr %s\n",
+ (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base, eth_ntoa(
+ nic->node_addr));
+ }
+
+ if (eth_vendor == VENDOR_NONE)
+ return (0);
+
+ if (eth_vendor != VENDOR_3COM)
+ eth_rmem = eth_bmem;
+
+ ne_reset(nic, isa);
+ nic->nic_op = &ne_operations;
+ return 1;
+}
+
+
+/**************************************************************************
+ NE_DISABLE - Turn off adapter
+ **************************************************************************/
+static void ne_disable(struct nic *nic, struct isa_device *isa) {
+ ne_reset(nic, isa);
+}
+
+
+/**************************************************************************
+ NE_RESET - Reset adapter
+ **************************************************************************/
+static void ne_reset(struct nic *nic, struct isa_device *isa __unused)
+{
+ int i;
+
+ eth_drain_receiver = 0;
+ outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
+ D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
+ if (eth_flags & FLAG_16BIT)
+ outb(0x49, eth_nic_base+D8390_P0_DCR);
+ else
+ outb(0x48, eth_nic_base+D8390_P0_DCR);
+ outb(0, eth_nic_base+D8390_P0_RBCR0);
+ outb(0, eth_nic_base+D8390_P0_RBCR1);
+ outb(0x20, eth_nic_base+D8390_P0_RCR); /* monitor mode */
+ outb(2, eth_nic_base+D8390_P0_TCR);
+ outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
+ outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART);
+
+ outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP);
+ outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND);
+ outb(0xFF, eth_nic_base+D8390_P0_ISR);
+ outb(0, eth_nic_base+D8390_P0_IMR);
+ outb(D8390_COMMAND_PS1 |
+ D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
+
+ for (i=0; i<ETH_ALEN; i++)
+ outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i);
+ for (i=0; i<ETH_ALEN; i++)
+ outb(0xFF, eth_nic_base+D8390_P1_MAR0+i);
+ outb(eth_rx_start, eth_nic_base+D8390_P1_CURR);
+ outb(D8390_COMMAND_PS0 |
+ D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
+ outb(0xFF, eth_nic_base+D8390_P0_ISR);
+ outb(0, eth_nic_base+D8390_P0_TCR); /* transmitter on */
+ outb(4, eth_nic_base+D8390_P0_RCR); /* allow rx broadcast frames */
+
+ enable_multicast(eth_nic_base);
+}
+
+
+/**************************************************************************
+ NE_POLL - Wait for a frame
+ **************************************************************************/
+static int ne_poll(struct nic *nic __unused, int retrieve __unused)
+{
+ int ret = 0;
+ unsigned char rstat, curr, next;
+ unsigned short len, frag;
+ unsigned short pktoff;
+ unsigned char *p;
+ struct ringbuffer pkthdr;
+
+ rstat = inb(eth_nic_base+D8390_P0_RSR);
+ if (!(rstat & D8390_RSTAT_PRX)) return(0);
+ next = inb(eth_nic_base+D8390_P0_BOUND)+1;
+ if (next >= eth_memsize) next = eth_rx_start;
+ outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND);
+ curr = inb(eth_nic_base+D8390_P1_CURR);
+ outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND);
+ if (curr >= eth_memsize) curr=eth_rx_start;
+ if (curr == next) return(0);
+
+ if ( ! retrieve ) return 1;
+
+ pktoff = next << 8;
+ if (eth_flags & FLAG_PIO)
+ eth_pio_read(pktoff, (unsigned char *)&pkthdr, 4);
+ else
+ memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4);
+ pktoff += sizeof(pkthdr);
+ /* incoming length includes FCS so must sub 4 */
+ len = pkthdr.len - 4;
+ if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
+ || len> ETH_FRAME_LEN) {
+ DBG("Bogus packet, ignoring\n");
+ return (0);
+ }
+ else {
+ p = nic->packet;
+ nic->packetlen = len; /* available to caller */
+ frag = (eth_memsize << 8) - pktoff;
+ if (len> frag) { /* We have a wrap-around */
+ /* read first part */
+ if (eth_flags & FLAG_PIO)
+ eth_pio_read(pktoff, p, frag);
+ else
+ memcpy(p, bus_to_virt(eth_rmem + pktoff), frag);
+ pktoff = eth_rx_start << 8;
+ p += frag;
+ len -= frag;
+ }
+ /* read second part */
+ if (eth_flags & FLAG_PIO)
+ eth_pio_read(pktoff, p, len);
+ else
+ memcpy(p, bus_to_virt(eth_rmem + pktoff), len);
+ ret = 1;
+ }
+ next = pkthdr.next; /* frame number of next packet */
+ if (next == eth_rx_start)
+ next = eth_memsize;
+ outb(next-1, eth_nic_base+D8390_P0_BOUND);
+ return(ret);
+}
+
+
+/**************************************************************************
+ NE_TRANSMIT - Transmit a frame
+ **************************************************************************/
+static void ne_transmit(struct nic *nic, const char *d, /* Destination */
+unsigned int t, /* Type */
+unsigned int s, /* size */
+const char *p) { /* Packet */
+
+ /* Programmed I/O */
+ unsigned short type;
+ type = (t >> 8) | (t << 8);
+ eth_pio_write((unsigned char *) d, eth_tx_start << 8, ETH_ALEN);
+ eth_pio_write(nic->node_addr, (eth_tx_start << 8) + ETH_ALEN, ETH_ALEN);
+ /* bcc generates worse code without (const+const) below */
+ eth_pio_write((unsigned char *) &type, (eth_tx_start << 8) + (ETH_ALEN
+ + ETH_ALEN), 2);
+ eth_pio_write((unsigned char *) p, (eth_tx_start << 8) + ETH_HLEN, s);
+ s += ETH_HLEN;
+ if (s < ETH_ZLEN)
+ s = ETH_ZLEN;
+
+ outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | D8390_COMMAND_STA,
+ eth_nic_base + D8390_P0_COMMAND);
+ outb(eth_tx_start, eth_nic_base + D8390_P0_TPSR);
+ outb(s, eth_nic_base + D8390_P0_TBCR0);
+ outb(s >> 8, eth_nic_base + D8390_P0_TBCR1);
+
+ outb(D8390_COMMAND_PS0 | D8390_COMMAND_TXP | D8390_COMMAND_RD2
+ | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
+}
+
+static struct nic_operations ne_operations = { .connect = dummy_connect,
+ .poll = ne_poll, .transmit = ne_transmit, .irq = dummy_irq,
+};
+
+ISA_DRIVER ( ne_driver, ne_probe_addrs, ne_probe1,
+ GENERIC_ISAPNP_VENDOR, 0x0600 );
+
+DRIVER ( "ne", nic_driver, isapnp_driver, ne_driver,
+ ne_probe, ne_disable );
+
+ISA_ROM("ne","NE1000/2000 and clones");
diff --git a/gpxe/src/drivers/net/phantom/phantom.c b/gpxe/src/drivers/net/phantom/phantom.c
index 6c7d1fc9..1d1637d8 100644
--- a/gpxe/src/drivers/net/phantom/phantom.c
+++ b/gpxe/src/drivers/net/phantom/phantom.c
@@ -25,12 +25,14 @@
#include <assert.h>
#include <byteswap.h>
#include <gpxe/pci.h>
+#include <gpxe/io.h>
#include <gpxe/malloc.h>
#include <gpxe/iobuf.h>
#include <gpxe/netdevice.h>
#include <gpxe/if_ether.h>
#include <gpxe/ethernet.h>
#include <gpxe/spi.h>
+#include <gpxe/settings.h>
#include "phantom.h"
/**
@@ -40,11 +42,8 @@
*
*/
-/** Maximum time to wait for SPI lock */
-#define PHN_SPI_LOCK_TIMEOUT_MS 100
-
-/** Maximum time to wait for SPI command to be issued */
-#define PHN_SPI_CMD_TIMEOUT_MS 100
+/** Maximum number of ports */
+#define PHN_MAX_NUM_PORTS 4
/** Maximum time to wait for command PEG to initialise
*
@@ -71,6 +70,9 @@
/** Maximum time to wait for test memory */
#define PHN_TEST_MEM_TIMEOUT_MS 100
+/** Maximum time to wait for CLP command to be issued */
+#define PHN_CLP_CMD_TIMEOUT_MS 500
+
/** Link state poll frequency
*
* The link state will be checked once in every N calls to poll().
@@ -105,10 +107,41 @@ struct phantom_descriptor_rings {
volatile uint32_t cmd_cons;
};
-/** A Phantom NIC port */
-struct phantom_nic_port {
- /** Phantom NIC containing this port */
- struct phantom_nic *phantom;
+/** RX context creation request and response buffers */
+struct phantom_create_rx_ctx_rqrsp {
+ struct {
+ struct nx_hostrq_rx_ctx_s rx_ctx;
+ struct nx_hostrq_rds_ring_s rds;
+ struct nx_hostrq_sds_ring_s sds;
+ } __unm_dma_aligned hostrq;
+ struct {
+ struct nx_cardrsp_rx_ctx_s rx_ctx;
+ struct nx_cardrsp_rds_ring_s rds;
+ struct nx_cardrsp_sds_ring_s sds;
+ } __unm_dma_aligned cardrsp;
+};
+
+/** TX context creation request and response buffers */
+struct phantom_create_tx_ctx_rqrsp {
+ struct {
+ struct nx_hostrq_tx_ctx_s tx_ctx;
+ } __unm_dma_aligned hostrq;
+ struct {
+ struct nx_cardrsp_tx_ctx_s tx_ctx;
+ } __unm_dma_aligned cardrsp;
+};
+
+/** A Phantom NIC */
+struct phantom_nic {
+ /** BAR 0 */
+ void *bar0;
+ /** Current CRB window */
+ unsigned long crb_window;
+ /** CRB window access method */
+ unsigned long ( *crb_access ) ( struct phantom_nic *phantom,
+ unsigned long reg );
+
+
/** Port number */
unsigned int port;
@@ -143,73 +176,18 @@ struct phantom_nic_port {
struct io_buffer *cds_iobuf[PHN_NUM_CDS];
- /** Link state poll timer */
- unsigned long link_poll_timer;
-
-
/** Descriptor rings */
struct phantom_descriptor_rings *desc;
-};
-
-/** RX context creation request and response buffers */
-struct phantom_create_rx_ctx_rqrsp {
- struct {
- struct nx_hostrq_rx_ctx_s rx_ctx;
- struct nx_hostrq_rds_ring_s rds;
- struct nx_hostrq_sds_ring_s sds;
- } __unm_dma_aligned hostrq;
- struct {
- struct nx_cardrsp_rx_ctx_s rx_ctx;
- struct nx_cardrsp_rds_ring_s rds;
- struct nx_cardrsp_sds_ring_s sds;
- } __unm_dma_aligned cardrsp;
-};
-
-/** TX context creation request and response buffers */
-struct phantom_create_tx_ctx_rqrsp {
- struct {
- struct nx_hostrq_tx_ctx_s tx_ctx;
- } __unm_dma_aligned hostrq;
- struct {
- struct nx_cardrsp_tx_ctx_s tx_ctx;
- } __unm_dma_aligned cardrsp;
-};
-
-/** A Phantom DMA buffer area */
-union phantom_dma_buffer {
- /** Dummy area required for (read-only) self-tests */
- uint8_t dummy_dma[UNM_DUMMY_DMA_SIZE];
- /** RX context creation request and response buffers */
- struct phantom_create_rx_ctx_rqrsp create_rx_ctx;
- /** TX context creation request and response buffers */
- struct phantom_create_tx_ctx_rqrsp create_tx_ctx;
-};
-
-/** A Phantom NIC */
-struct phantom_nic {
- /** BAR 0 */
- void *bar0;
- /** Current CRB window */
- unsigned long crb_window;
- /** CRB window access method */
- unsigned long ( *crb_access ) ( struct phantom_nic *phantom,
- unsigned long reg );
-
- /** Number of ports */
- int num_ports;
- /** Per-port network devices */
- struct net_device *netdev[UNM_FLASH_NUM_PORTS];
- /** DMA buffers */
- union phantom_dma_buffer *dma_buf;
-
- /** Flash memory SPI bus */
- struct spi_bus spi_bus;
- /** Flash memory SPI device */
- struct spi_device flash;
/** Last known link state */
uint32_t link_state;
+ /** Link state poll timer */
+ unsigned long link_poll_timer;
+
+
+ /** Non-volatile settings */
+ struct settings settings;
};
/***************************************************************************
@@ -227,21 +205,8 @@ struct phantom_nic {
*/
static unsigned long phantom_crb_access_128m ( struct phantom_nic *phantom,
unsigned long reg ) {
- static const uint32_t reg_window[] = {
- [UNM_CRB_BLK_PCIE] = 0x0000000,
- [UNM_CRB_BLK_CAM] = 0x2000000,
- [UNM_CRB_BLK_ROMUSB] = 0x2000000,
- [UNM_CRB_BLK_TEST] = 0x0000000,
- };
- static const uint32_t reg_bases[] = {
- [UNM_CRB_BLK_PCIE] = 0x6100000,
- [UNM_CRB_BLK_CAM] = 0x6200000,
- [UNM_CRB_BLK_ROMUSB] = 0x7300000,
- [UNM_CRB_BLK_TEST] = 0x6200000,
- };
- unsigned int block = UNM_CRB_BLK ( reg );
- unsigned long offset = UNM_CRB_OFFSET ( reg );
- uint32_t window = reg_window[block];
+ unsigned long offset = ( 0x6000000 + ( reg & 0x1ffffff ) );
+ uint32_t window = ( reg & 0x2000000 );
uint32_t verify_window;
if ( phantom->crb_window != window ) {
@@ -257,7 +222,7 @@ static unsigned long phantom_crb_access_128m ( struct phantom_nic *phantom,
phantom->crb_window = window;
}
- return ( reg_bases[block] + offset );
+ return offset;
}
/**
@@ -269,21 +234,8 @@ static unsigned long phantom_crb_access_128m ( struct phantom_nic *phantom,
*/
static unsigned long phantom_crb_access_32m ( struct phantom_nic *phantom,
unsigned long reg ) {
- static const uint32_t reg_window[] = {
- [UNM_CRB_BLK_PCIE] = 0x0000000,
- [UNM_CRB_BLK_CAM] = 0x2000000,
- [UNM_CRB_BLK_ROMUSB] = 0x2000000,
- [UNM_CRB_BLK_TEST] = 0x0000000,
- };
- static const uint32_t reg_bases[] = {
- [UNM_CRB_BLK_PCIE] = 0x0100000,
- [UNM_CRB_BLK_CAM] = 0x0200000,
- [UNM_CRB_BLK_ROMUSB] = 0x1300000,
- [UNM_CRB_BLK_TEST] = 0x0200000,
- };
- unsigned int block = UNM_CRB_BLK ( reg );
- unsigned long offset = UNM_CRB_OFFSET ( reg );
- uint32_t window = reg_window[block];
+ unsigned long offset = ( reg & 0x1ffffff );
+ uint32_t window = ( reg & 0x2000000 );
uint32_t verify_window;
if ( phantom->crb_window != window ) {
@@ -299,7 +251,7 @@ static unsigned long phantom_crb_access_32m ( struct phantom_nic *phantom,
phantom->crb_window = window;
}
- return ( reg_bases[block] + offset );
+ return offset;
}
/**
@@ -311,31 +263,54 @@ static unsigned long phantom_crb_access_32m ( struct phantom_nic *phantom,
*/
static unsigned long phantom_crb_access_2m ( struct phantom_nic *phantom,
unsigned long reg ) {
- static const uint32_t reg_window_hi[] = {
- [UNM_CRB_BLK_PCIE] = 0x77300000,
- [UNM_CRB_BLK_CAM] = 0x41600000,
- [UNM_CRB_BLK_ROMUSB] = 0x42100000,
- [UNM_CRB_BLK_TEST] = 0x29500000,
+ static const struct {
+ uint8_t block;
+ uint16_t window_hi;
+ } reg_window_hi[] = {
+ { UNM_CRB_BLK_PCIE, 0x773 },
+ { UNM_CRB_BLK_CAM, 0x416 },
+ { UNM_CRB_BLK_ROMUSB, 0x421 },
+ { UNM_CRB_BLK_TEST, 0x295 },
+ { UNM_CRB_BLK_PEG_0, 0x340 },
+ { UNM_CRB_BLK_PEG_1, 0x341 },
+ { UNM_CRB_BLK_PEG_2, 0x342 },
+ { UNM_CRB_BLK_PEG_3, 0x343 },
+ { UNM_CRB_BLK_PEG_4, 0x34b },
};
unsigned int block = UNM_CRB_BLK ( reg );
unsigned long offset = UNM_CRB_OFFSET ( reg );
- uint32_t window = ( reg_window_hi[block] | ( offset & 0x000f0000 ) );
+ uint32_t window;
uint32_t verify_window;
+ unsigned int i;
- if ( phantom->crb_window != window ) {
+ for ( i = 0 ; i < ( sizeof ( reg_window_hi ) /
+ sizeof ( reg_window_hi[0] ) ) ; i++ ) {
- /* Write to the CRB window register */
- writel ( window, phantom->bar0 + UNM_2M_CRB_WINDOW );
+ if ( reg_window_hi[i].block != block )
+ continue;
- /* Ensure that the write has reached the card */
- verify_window = readl ( phantom->bar0 + UNM_2M_CRB_WINDOW );
- assert ( verify_window == window );
+ window = ( ( reg_window_hi[i].window_hi << 20 ) |
+ ( offset & 0x000f0000 ) );
- /* Record new window */
- phantom->crb_window = window;
+ if ( phantom->crb_window != window ) {
+
+ /* Write to the CRB window register */
+ writel ( window, phantom->bar0 + UNM_2M_CRB_WINDOW );
+
+ /* Ensure that the write has reached the card */
+ verify_window = readl ( phantom->bar0 +
+ UNM_2M_CRB_WINDOW );
+ assert ( verify_window == window );
+
+ /* Record new window */
+ phantom->crb_window = window;
+ }
+
+ return ( 0x1e0000 + ( offset & 0xffff ) );
}
- return ( 0x1e0000 + ( offset & 0xffff ) );
+ assert ( 0 );
+ return 0;
}
/**
@@ -401,8 +376,9 @@ static inline void phantom_write_hilo ( struct phantom_nic *phantom,
* @v buf 8-byte buffer to fill
* @ret rc Return status code
*/
-static int phantom_read_test_mem ( struct phantom_nic *phantom,
- uint64_t offset, uint32_t buf[2] ) {
+static int phantom_read_test_mem_block ( struct phantom_nic *phantom,
+ unsigned long offset,
+ uint32_t buf[2] ) {
unsigned int retries;
uint32_t test_control;
@@ -429,199 +405,100 @@ static int phantom_read_test_mem ( struct phantom_nic *phantom,
}
/**
+ * Read single byte from Phantom test memory
+ *
+ * @v phantom Phantom NIC
+ * @v offset Offset within test memory
+ * @ret byte Byte read, or negative error
+ */
+static int phantom_read_test_mem ( struct phantom_nic *phantom,
+ unsigned long offset ) {
+ static union {
+ uint8_t bytes[8];
+ uint32_t dwords[2];
+ } cache;
+ static unsigned long cache_offset = -1UL;
+ unsigned long sub_offset;
+ int rc;
+
+ sub_offset = ( offset & ( sizeof ( cache ) - 1 ) );
+ offset = ( offset & ~( sizeof ( cache ) - 1 ) );
+
+ if ( cache_offset != offset ) {
+ if ( ( rc = phantom_read_test_mem_block ( phantom, offset,
+ cache.dwords )) !=0 )
+ return rc;
+ cache_offset = offset;
+ }
+
+ return cache.bytes[sub_offset];
+}
+
+/**
* Dump Phantom firmware dmesg log
*
* @v phantom Phantom NIC
* @v log Log number
+ * @v max_lines Maximum number of lines to show, or -1 to show all
+ * @ret rc Return status code
*/
-static void phantom_dmesg ( struct phantom_nic *phantom, unsigned int log ) {
+static int phantom_dmesg ( struct phantom_nic *phantom, unsigned int log,
+ unsigned int max_lines ) {
uint32_t head;
uint32_t tail;
uint32_t len;
uint32_t sig;
uint32_t offset;
- union {
- uint8_t bytes[8];
- uint32_t dwords[2];
- } buf;
- unsigned int i;
- int rc;
+ int byte;
/* Optimise out for non-debug builds */
if ( ! DBG_LOG )
- return;
+ return 0;
+ /* Locate log */
head = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_HEAD ( log ) );
len = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_LEN ( log ) );
tail = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_TAIL ( log ) );
sig = phantom_readl ( phantom, UNM_CAM_RAM_DMESG_SIG ( log ) );
- DBGC ( phantom, "Phantom %p firmware dmesg buffer %d (%08lx-%08lx)\n",
+ DBGC ( phantom, "Phantom %p firmware dmesg buffer %d (%08x-%08x)\n",
phantom, log, head, tail );
assert ( ( head & 0x07 ) == 0 );
if ( sig != UNM_CAM_RAM_DMESG_SIG_MAGIC ) {
- DBGC ( phantom, "Warning: bad signature %08lx (want %08lx)\n",
+ DBGC ( phantom, "Warning: bad signature %08x (want %08lx)\n",
sig, UNM_CAM_RAM_DMESG_SIG_MAGIC );
}
- for ( offset = head ; offset < tail ; offset += 8 ) {
- if ( ( rc = phantom_read_test_mem ( phantom, offset,
- buf.dwords ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p could not read from test "
- "memory: %s\n", phantom, strerror ( rc ) );
+ /* Locate start of last (max_lines) lines */
+ for ( offset = tail ; offset > head ; offset-- ) {
+ if ( ( byte = phantom_read_test_mem ( phantom,
+ ( offset - 1 ) ) ) < 0 )
+ return byte;
+ if ( ( byte == '\n' ) && ( max_lines-- == 0 ) )
break;
- }
- for ( i = 0 ; ( ( i < sizeof ( buf ) ) &&
- ( offset + i ) < tail ) ; i++ ) {
- DBG ( "%c", buf.bytes[i] );
- }
+ }
+
+ /* Print lines */
+ for ( ; offset < tail ; offset++ ) {
+ if ( ( byte = phantom_read_test_mem ( phantom, offset ) ) < 0 )
+ return byte;
+ DBG ( "%c", byte );
}
DBG ( "\n" );
+ return 0;
}
/**
* Dump Phantom firmware dmesg logs
*
* @v phantom Phantom NIC
+ * @v max_lines Maximum number of lines to show, or -1 to show all
*/
static void __attribute__ (( unused ))
-phantom_dmesg_all ( struct phantom_nic *phantom ) {
+phantom_dmesg_all ( struct phantom_nic *phantom, unsigned int max_lines ) {
unsigned int i;
for ( i = 0 ; i < UNM_CAM_RAM_NUM_DMESG_BUFFERS ; i++ )
- phantom_dmesg ( phantom, i );
-}
-
-/***************************************************************************
- *
- * SPI bus access (for flash memory)
- *
- */
-
-/**
- * Acquire Phantom SPI lock
- *
- * @v phantom Phantom NIC
- * @ret rc Return status code
- */
-static int phantom_spi_lock ( struct phantom_nic *phantom ) {
- unsigned int retries;
- uint32_t pcie_sem2_lock;
-
- for ( retries = 0 ; retries < PHN_SPI_LOCK_TIMEOUT_MS ; retries++ ) {
- pcie_sem2_lock = phantom_readl ( phantom, UNM_PCIE_SEM2_LOCK );
- if ( pcie_sem2_lock != 0 )
- return 0;
- mdelay ( 1 );
- }
-
- DBGC ( phantom, "Phantom %p timed out waiting for SPI lock\n",
- phantom );
- return -ETIMEDOUT;
-}
-
-/**
- * Wait for Phantom SPI command to complete
- *
- * @v phantom Phantom NIC
- * @ret rc Return status code
- */
-static int phantom_spi_wait ( struct phantom_nic *phantom ) {
- unsigned int retries;
- uint32_t glb_status;
-
- for ( retries = 0 ; retries < PHN_SPI_CMD_TIMEOUT_MS ; retries++ ) {
- glb_status = phantom_readl ( phantom, UNM_ROMUSB_GLB_STATUS );
- if ( glb_status & UNM_ROMUSB_GLB_STATUS_ROM_DONE )
- return 0;
- mdelay ( 1 );
- }
-
- DBGC ( phantom, "Phantom %p timed out waiting for SPI command\n",
- phantom );
- return -ETIMEDOUT;
-}
-
-/**
- * Release Phantom SPI lock
- *
- * @v phantom Phantom NIC
- */
-static void phantom_spi_unlock ( struct phantom_nic *phantom ) {
- phantom_readl ( phantom, UNM_PCIE_SEM2_UNLOCK );
-}
-
-/**
- * Read/write data via Phantom SPI bus
- *
- * @v bus SPI bus
- * @v device SPI device
- * @v command Command
- * @v address Address to read/write (<0 for no address)
- * @v data_out TX data buffer (or NULL)
- * @v data_in RX data buffer (or NULL)
- * @v len Length of data buffer(s)
- * @ret rc Return status code
- */
-static int phantom_spi_rw ( struct spi_bus *bus,
- struct spi_device *device,
- unsigned int command, int address,
- const void *data_out, void *data_in,
- size_t len ) {
- struct phantom_nic *phantom =
- container_of ( bus, struct phantom_nic, spi_bus );
- uint32_t data;
- int rc;
-
- DBGCP ( phantom, "Phantom %p SPI command %x at %x+%zx\n",
- phantom, command, address, len );
- if ( data_out )
- DBGCP_HDA ( phantom, address, data_out, len );
-
- /* We support only exactly 4-byte reads */
- if ( len != UNM_SPI_BLKSIZE ) {
- DBGC ( phantom, "Phantom %p invalid SPI length %zx\n",
- phantom, len );
- return -EINVAL;
- }
-
- /* Acquire SPI lock */
- if ( ( rc = phantom_spi_lock ( phantom ) ) != 0 )
- goto err_lock;
-
- /* Issue SPI command as per the PRM */
- if ( data_out ) {
- memcpy ( &data, data_out, sizeof ( data ) );
- phantom_writel ( phantom, data, UNM_ROMUSB_ROM_WDATA );
- }
- phantom_writel ( phantom, address, UNM_ROMUSB_ROM_ADDRESS );
- phantom_writel ( phantom, ( device->address_len / 8 ),
- UNM_ROMUSB_ROM_ABYTE_CNT );
- udelay ( 100 ); /* according to PRM */
- phantom_writel ( phantom, 0, UNM_ROMUSB_ROM_DUMMY_BYTE_CNT );
- phantom_writel ( phantom, command, UNM_ROMUSB_ROM_INSTR_OPCODE );
-
- /* Wait for SPI command to complete */
- if ( ( rc = phantom_spi_wait ( phantom ) ) != 0 )
- goto err_wait;
-
- /* Reset address byte count and dummy byte count, because the
- * PRM asks us to.
- */
- phantom_writel ( phantom, 0, UNM_ROMUSB_ROM_ABYTE_CNT );
- udelay ( 100 ); /* according to PRM */
- phantom_writel ( phantom, 0, UNM_ROMUSB_ROM_DUMMY_BYTE_CNT );
-
- /* Read data, if applicable */
- if ( data_in ) {
- data = phantom_readl ( phantom, UNM_ROMUSB_ROM_RDATA );
- memcpy ( data_in, &data, sizeof ( data ) );
- DBGCP_HDA ( phantom, address, data_in, len );
- }
-
- err_wait:
- phantom_spi_unlock ( phantom );
- err_lock:
- return rc;
+ phantom_dmesg ( phantom, i, max_lines );
}
/***************************************************************************
@@ -665,26 +542,24 @@ static int phantom_wait_for_cmd ( struct phantom_nic *phantom ) {
/**
* Issue command to firmware
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v command Firmware command
* @v arg1 Argument 1
* @v arg2 Argument 2
* @v arg3 Argument 3
* @ret rc Return status code
*/
-static int phantom_issue_cmd ( struct phantom_nic_port *phantom_port,
+static int phantom_issue_cmd ( struct phantom_nic *phantom,
uint32_t command, uint32_t arg1, uint32_t arg2,
uint32_t arg3 ) {
- struct phantom_nic *phantom = phantom_port->phantom;
uint32_t signature;
int rc;
/* Issue command */
- signature = NX_CDRP_SIGNATURE_MAKE ( phantom_port->port,
+ signature = NX_CDRP_SIGNATURE_MAKE ( phantom->port,
NXHAL_VERSION );
- DBGC2 ( phantom, "Phantom %p port %d issuing command %08lx (%08lx, "
- "%08lx, %08lx)\n", phantom, phantom_port->port,
- command, arg1, arg2, arg3 );
+ DBGC2 ( phantom, "Phantom %p issuing command %08x (%08x, %08x, "
+ "%08x)\n", phantom, command, arg1, arg2, arg3 );
phantom_writel ( phantom, signature, UNM_NIC_REG_NX_SIGN );
phantom_writel ( phantom, arg1, UNM_NIC_REG_NX_ARG1 );
phantom_writel ( phantom, arg2, UNM_NIC_REG_NX_ARG2 );
@@ -705,36 +580,41 @@ static int phantom_issue_cmd ( struct phantom_nic_port *phantom_port,
/**
* Issue buffer-format command to firmware
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v command Firmware command
* @v buffer Buffer to pass to firmware
* @v len Length of buffer
* @ret rc Return status code
*/
-static int phantom_issue_buf_cmd ( struct phantom_nic_port *phantom_port,
+static int phantom_issue_buf_cmd ( struct phantom_nic *phantom,
uint32_t command, void *buffer,
size_t len ) {
uint64_t physaddr;
physaddr = virt_to_bus ( buffer );
- return phantom_issue_cmd ( phantom_port, command, ( physaddr >> 32 ),
+ return phantom_issue_cmd ( phantom, command, ( physaddr >> 32 ),
( physaddr & 0xffffffffUL ), len );
}
/**
* Create Phantom RX context
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @ret rc Return status code
*/
-static int phantom_create_rx_ctx ( struct phantom_nic_port *phantom_port ) {
- struct phantom_nic *phantom = phantom_port->phantom;
+static int phantom_create_rx_ctx ( struct phantom_nic *phantom ) {
struct phantom_create_rx_ctx_rqrsp *buf;
int rc;
+
+ /* Allocate context creation buffer */
+ buf = malloc_dma ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN );
+ if ( ! buf ) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset ( buf, 0, sizeof ( *buf ) );
/* Prepare request */
- buf = &phantom->dma_buf->create_rx_ctx;
- memset ( buf, 0, sizeof ( *buf ) );
buf->hostrq.rx_ctx.host_rsp_dma_addr =
cpu_to_le64 ( virt_to_bus ( &buf->cardrsp ) );
buf->hostrq.rx_ctx.capabilities[0] =
@@ -749,197 +629,194 @@ static int phantom_create_rx_ctx ( struct phantom_nic_port *phantom_port ) {
buf->hostrq.rx_ctx.num_rds_rings = cpu_to_le16 ( 1 );
buf->hostrq.rx_ctx.num_sds_rings = cpu_to_le16 ( 1 );
buf->hostrq.rds.host_phys_addr =
- cpu_to_le64 ( virt_to_bus ( phantom_port->desc->rds ) );
+ cpu_to_le64 ( virt_to_bus ( phantom->desc->rds ) );
buf->hostrq.rds.buff_size = cpu_to_le64 ( PHN_RX_BUFSIZE );
buf->hostrq.rds.ring_size = cpu_to_le32 ( PHN_NUM_RDS );
buf->hostrq.rds.ring_kind = cpu_to_le32 ( NX_RDS_RING_TYPE_NORMAL );
buf->hostrq.sds.host_phys_addr =
- cpu_to_le64 ( virt_to_bus ( phantom_port->desc->sds ) );
+ cpu_to_le64 ( virt_to_bus ( phantom->desc->sds ) );
buf->hostrq.sds.ring_size = cpu_to_le32 ( PHN_NUM_SDS );
- DBGC ( phantom, "Phantom %p port %d creating RX context\n",
- phantom, phantom_port->port );
+ DBGC ( phantom, "Phantom %p creating RX context\n", phantom );
DBGC2_HDA ( phantom, virt_to_bus ( &buf->hostrq ),
&buf->hostrq, sizeof ( buf->hostrq ) );
/* Issue request */
- if ( ( rc = phantom_issue_buf_cmd ( phantom_port,
+ if ( ( rc = phantom_issue_buf_cmd ( phantom,
NX_CDRP_CMD_CREATE_RX_CTX,
&buf->hostrq,
sizeof ( buf->hostrq ) ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p port %d could not create RX "
- "context: %s\n",
- phantom, phantom_port->port, strerror ( rc ) );
+ DBGC ( phantom, "Phantom %p could not create RX context: "
+ "%s\n", phantom, strerror ( rc ) );
DBGC ( phantom, "Request:\n" );
DBGC_HDA ( phantom, virt_to_bus ( &buf->hostrq ),
&buf->hostrq, sizeof ( buf->hostrq ) );
DBGC ( phantom, "Response:\n" );
DBGC_HDA ( phantom, virt_to_bus ( &buf->cardrsp ),
&buf->cardrsp, sizeof ( buf->cardrsp ) );
- return rc;
+ goto out;
}
/* Retrieve context parameters */
- phantom_port->rx_context_id =
+ phantom->rx_context_id =
le16_to_cpu ( buf->cardrsp.rx_ctx.context_id );
- phantom_port->rds_producer_crb =
+ phantom->rds_producer_crb =
( UNM_CAM_RAM +
le32_to_cpu ( buf->cardrsp.rds.host_producer_crb ));
- phantom_port->sds_consumer_crb =
+ phantom->sds_consumer_crb =
( UNM_CAM_RAM +
le32_to_cpu ( buf->cardrsp.sds.host_consumer_crb ));
- DBGC ( phantom, "Phantom %p port %d created RX context (id %04x, "
- "port phys %02x virt %02x)\n", phantom, phantom_port->port,
- phantom_port->rx_context_id, buf->cardrsp.rx_ctx.phys_port,
- buf->cardrsp.rx_ctx.virt_port );
+ DBGC ( phantom, "Phantom %p created RX context (id %04x, port phys "
+ "%02x virt %02x)\n", phantom, phantom->rx_context_id,
+ buf->cardrsp.rx_ctx.phys_port, buf->cardrsp.rx_ctx.virt_port );
DBGC2_HDA ( phantom, virt_to_bus ( &buf->cardrsp ),
&buf->cardrsp, sizeof ( buf->cardrsp ) );
- DBGC ( phantom, "Phantom %p port %d RDS producer CRB is %08lx\n",
- phantom, phantom_port->port, phantom_port->rds_producer_crb );
- DBGC ( phantom, "Phantom %p port %d SDS consumer CRB is %08lx\n",
- phantom, phantom_port->port, phantom_port->sds_consumer_crb );
+ DBGC ( phantom, "Phantom %p RDS producer CRB is %08lx\n",
+ phantom, phantom->rds_producer_crb );
+ DBGC ( phantom, "Phantom %p SDS consumer CRB is %08lx\n",
+ phantom, phantom->sds_consumer_crb );
- return 0;
+ out:
+ free_dma ( buf, sizeof ( *buf ) );
+ return rc;
}
/**
* Destroy Phantom RX context
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @ret rc Return status code
*/
-static void phantom_destroy_rx_ctx ( struct phantom_nic_port *phantom_port ) {
- struct phantom_nic *phantom = phantom_port->phantom;
+static void phantom_destroy_rx_ctx ( struct phantom_nic *phantom ) {
int rc;
- DBGC ( phantom, "Phantom %p port %d destroying RX context (id %04x)\n",
- phantom, phantom_port->port, phantom_port->rx_context_id );
+ DBGC ( phantom, "Phantom %p destroying RX context (id %04x)\n",
+ phantom, phantom->rx_context_id );
/* Issue request */
- if ( ( rc = phantom_issue_cmd ( phantom_port,
+ if ( ( rc = phantom_issue_cmd ( phantom,
NX_CDRP_CMD_DESTROY_RX_CTX,
- phantom_port->rx_context_id,
+ phantom->rx_context_id,
NX_DESTROY_CTX_RESET, 0 ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p port %d could not destroy RX "
- "context: %s\n",
- phantom, phantom_port->port, strerror ( rc ) );
+ DBGC ( phantom, "Phantom %p could not destroy RX context: "
+ "%s\n", phantom, strerror ( rc ) );
/* We're probably screwed */
return;
}
/* Clear context parameters */
- phantom_port->rx_context_id = 0;
- phantom_port->rds_producer_crb = 0;
- phantom_port->sds_consumer_crb = 0;
+ phantom->rx_context_id = 0;
+ phantom->rds_producer_crb = 0;
+ phantom->sds_consumer_crb = 0;
/* Reset software counters */
- phantom_port->rds_producer_idx = 0;
- phantom_port->rds_consumer_idx = 0;
- phantom_port->sds_consumer_idx = 0;
+ phantom->rds_producer_idx = 0;
+ phantom->rds_consumer_idx = 0;
+ phantom->sds_consumer_idx = 0;
}
/**
* Create Phantom TX context
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @ret rc Return status code
*/
-static int phantom_create_tx_ctx ( struct phantom_nic_port *phantom_port ) {
- struct phantom_nic *phantom = phantom_port->phantom;
+static int phantom_create_tx_ctx ( struct phantom_nic *phantom ) {
struct phantom_create_tx_ctx_rqrsp *buf;
int rc;
- /* Prepare request */
- buf = &phantom->dma_buf->create_tx_ctx;
+ /* Allocate context creation buffer */
+ buf = malloc_dma ( sizeof ( *buf ), UNM_DMA_BUFFER_ALIGN );
+ if ( ! buf ) {
+ rc = -ENOMEM;
+ goto out;
+ }
memset ( buf, 0, sizeof ( *buf ) );
+
+ /* Prepare request */
buf->hostrq.tx_ctx.host_rsp_dma_addr =
cpu_to_le64 ( virt_to_bus ( &buf->cardrsp ) );
buf->hostrq.tx_ctx.cmd_cons_dma_addr =
- cpu_to_le64 ( virt_to_bus ( &phantom_port->desc->cmd_cons ) );
- buf->hostrq.tx_ctx.dummy_dma_addr =
- cpu_to_le64 ( virt_to_bus ( phantom->dma_buf->dummy_dma ) );
+ cpu_to_le64 ( virt_to_bus ( &phantom->desc->cmd_cons ) );
buf->hostrq.tx_ctx.capabilities[0] =
cpu_to_le32 ( NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN );
buf->hostrq.tx_ctx.host_int_crb_mode =
cpu_to_le32 ( NX_HOST_INT_CRB_MODE_SHARED );
buf->hostrq.tx_ctx.cds_ring.host_phys_addr =
- cpu_to_le64 ( virt_to_bus ( phantom_port->desc->cds ) );
+ cpu_to_le64 ( virt_to_bus ( phantom->desc->cds ) );
buf->hostrq.tx_ctx.cds_ring.ring_size = cpu_to_le32 ( PHN_NUM_CDS );
- DBGC ( phantom, "Phantom %p port %d creating TX context\n",
- phantom, phantom_port->port );
+ DBGC ( phantom, "Phantom %p creating TX context\n", phantom );
DBGC2_HDA ( phantom, virt_to_bus ( &buf->hostrq ),
&buf->hostrq, sizeof ( buf->hostrq ) );
/* Issue request */
- if ( ( rc = phantom_issue_buf_cmd ( phantom_port,
+ if ( ( rc = phantom_issue_buf_cmd ( phantom,
NX_CDRP_CMD_CREATE_TX_CTX,
&buf->hostrq,
sizeof ( buf->hostrq ) ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p port %d could not create TX "
- "context: %s\n",
- phantom, phantom_port->port, strerror ( rc ) );
+ DBGC ( phantom, "Phantom %p could not create TX context: "
+ "%s\n", phantom, strerror ( rc ) );
DBGC ( phantom, "Request:\n" );
DBGC_HDA ( phantom, virt_to_bus ( &buf->hostrq ),
&buf->hostrq, sizeof ( buf->hostrq ) );
DBGC ( phantom, "Response:\n" );
DBGC_HDA ( phantom, virt_to_bus ( &buf->cardrsp ),
&buf->cardrsp, sizeof ( buf->cardrsp ) );
- return rc;
+ goto out;
}
/* Retrieve context parameters */
- phantom_port->tx_context_id =
+ phantom->tx_context_id =
le16_to_cpu ( buf->cardrsp.tx_ctx.context_id );
- phantom_port->cds_producer_crb =
+ phantom->cds_producer_crb =
( UNM_CAM_RAM +
le32_to_cpu(buf->cardrsp.tx_ctx.cds_ring.host_producer_crb));
- DBGC ( phantom, "Phantom %p port %d created TX context (id %04x, "
- "port phys %02x virt %02x)\n", phantom, phantom_port->port,
- phantom_port->tx_context_id, buf->cardrsp.tx_ctx.phys_port,
- buf->cardrsp.tx_ctx.virt_port );
+ DBGC ( phantom, "Phantom %p created TX context (id %04x, port phys "
+ "%02x virt %02x)\n", phantom, phantom->tx_context_id,
+ buf->cardrsp.tx_ctx.phys_port, buf->cardrsp.tx_ctx.virt_port );
DBGC2_HDA ( phantom, virt_to_bus ( &buf->cardrsp ),
&buf->cardrsp, sizeof ( buf->cardrsp ) );
- DBGC ( phantom, "Phantom %p port %d CDS producer CRB is %08lx\n",
- phantom, phantom_port->port, phantom_port->cds_producer_crb );
+ DBGC ( phantom, "Phantom %p CDS producer CRB is %08lx\n",
+ phantom, phantom->cds_producer_crb );
- return 0;
+ out:
+ free_dma ( buf, sizeof ( *buf ) );
+ return rc;
}
/**
* Destroy Phantom TX context
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @ret rc Return status code
*/
-static void phantom_destroy_tx_ctx ( struct phantom_nic_port *phantom_port ) {
- struct phantom_nic *phantom = phantom_port->phantom;
+static void phantom_destroy_tx_ctx ( struct phantom_nic *phantom ) {
int rc;
- DBGC ( phantom, "Phantom %p port %d destroying TX context (id %04x)\n",
- phantom, phantom_port->port, phantom_port->tx_context_id );
+ DBGC ( phantom, "Phantom %p destroying TX context (id %04x)\n",
+ phantom, phantom->tx_context_id );
/* Issue request */
- if ( ( rc = phantom_issue_cmd ( phantom_port,
+ if ( ( rc = phantom_issue_cmd ( phantom,
NX_CDRP_CMD_DESTROY_TX_CTX,
- phantom_port->tx_context_id,
+ phantom->tx_context_id,
NX_DESTROY_CTX_RESET, 0 ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p port %d could not destroy TX "
- "context: %s\n",
- phantom, phantom_port->port, strerror ( rc ) );
+ DBGC ( phantom, "Phantom %p could not destroy TX context: "
+ "%s\n", phantom, strerror ( rc ) );
/* We're probably screwed */
return;
}
/* Clear context parameters */
- phantom_port->tx_context_id = 0;
- phantom_port->cds_producer_crb = 0;
+ phantom->tx_context_id = 0;
+ phantom->cds_producer_crb = 0;
/* Reset software counters */
- phantom_port->cds_producer_idx = 0;
- phantom_port->cds_consumer_idx = 0;
+ phantom->cds_producer_idx = 0;
+ phantom->cds_consumer_idx = 0;
}
/***************************************************************************
@@ -951,11 +828,10 @@ static void phantom_destroy_tx_ctx ( struct phantom_nic_port *phantom_port ) {
/**
* Allocate Phantom RX descriptor
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @ret index RX descriptor index, or negative error
*/
-static int phantom_alloc_rds ( struct phantom_nic_port *phantom_port ) {
- struct phantom_nic *phantom = phantom_port->phantom;
+static int phantom_alloc_rds ( struct phantom_nic *phantom ) {
unsigned int rds_producer_idx;
unsigned int next_rds_producer_idx;
@@ -965,12 +841,11 @@ static int phantom_alloc_rds ( struct phantom_nic_port *phantom_port ) {
* guaranteed never to be an overestimate of the number of
* descriptors read by the hardware.
*/
- rds_producer_idx = phantom_port->rds_producer_idx;
+ rds_producer_idx = phantom->rds_producer_idx;
next_rds_producer_idx = ( ( rds_producer_idx + 1 ) % PHN_NUM_RDS );
- if ( next_rds_producer_idx == phantom_port->rds_consumer_idx ) {
- DBGC ( phantom, "Phantom %p port %d RDS ring full (index %d "
- "not consumed)\n", phantom, phantom_port->port,
- next_rds_producer_idx );
+ if ( next_rds_producer_idx == phantom->rds_consumer_idx ) {
+ DBGC ( phantom, "Phantom %p RDS ring full (index %d not "
+ "consumed)\n", phantom, next_rds_producer_idx );
return -ENOBUFS;
}
@@ -980,41 +855,38 @@ static int phantom_alloc_rds ( struct phantom_nic_port *phantom_port ) {
/**
* Post Phantom RX descriptor
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v rds RX descriptor
*/
-static void phantom_post_rds ( struct phantom_nic_port *phantom_port,
+static void phantom_post_rds ( struct phantom_nic *phantom,
struct phantom_rds *rds ) {
- struct phantom_nic *phantom = phantom_port->phantom;
unsigned int rds_producer_idx;
unsigned int next_rds_producer_idx;
struct phantom_rds *entry;
/* Copy descriptor to ring */
- rds_producer_idx = phantom_port->rds_producer_idx;
- entry = &phantom_port->desc->rds[rds_producer_idx];
+ rds_producer_idx = phantom->rds_producer_idx;
+ entry = &phantom->desc->rds[rds_producer_idx];
memcpy ( entry, rds, sizeof ( *entry ) );
- DBGC2 ( phantom, "Phantom %p port %d posting RDS %ld (slot %d):\n",
- phantom, phantom_port->port, NX_GET ( rds, handle ),
- rds_producer_idx );
+ DBGC2 ( phantom, "Phantom %p posting RDS %ld (slot %d):\n",
+ phantom, NX_GET ( rds, handle ), rds_producer_idx );
DBGC2_HDA ( phantom, virt_to_bus ( entry ), entry, sizeof ( *entry ) );
/* Update producer index */
next_rds_producer_idx = ( ( rds_producer_idx + 1 ) % PHN_NUM_RDS );
- phantom_port->rds_producer_idx = next_rds_producer_idx;
+ phantom->rds_producer_idx = next_rds_producer_idx;
wmb();
- phantom_writel ( phantom, phantom_port->rds_producer_idx,
- phantom_port->rds_producer_crb );
+ phantom_writel ( phantom, phantom->rds_producer_idx,
+ phantom->rds_producer_crb );
}
/**
* Allocate Phantom TX descriptor
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @ret index TX descriptor index, or negative error
*/
-static int phantom_alloc_cds ( struct phantom_nic_port *phantom_port ) {
- struct phantom_nic *phantom = phantom_port->phantom;
+static int phantom_alloc_cds ( struct phantom_nic *phantom ) {
unsigned int cds_producer_idx;
unsigned int next_cds_producer_idx;
@@ -1022,12 +894,11 @@ static int phantom_alloc_cds ( struct phantom_nic_port *phantom_port ) {
* in strict order, so we just check for a collision against
* the consumer index.
*/
- cds_producer_idx = phantom_port->cds_producer_idx;
+ cds_producer_idx = phantom->cds_producer_idx;
next_cds_producer_idx = ( ( cds_producer_idx + 1 ) % PHN_NUM_CDS );
- if ( next_cds_producer_idx == phantom_port->cds_consumer_idx ) {
- DBGC ( phantom, "Phantom %p port %d CDS ring full (index %d "
- "not consumed)\n", phantom, phantom_port->port,
- next_cds_producer_idx );
+ if ( next_cds_producer_idx == phantom->cds_consumer_idx ) {
+ DBGC ( phantom, "Phantom %p CDS ring full (index %d not "
+ "consumed)\n", phantom, next_cds_producer_idx );
return -ENOBUFS;
}
@@ -1037,30 +908,29 @@ static int phantom_alloc_cds ( struct phantom_nic_port *phantom_port ) {
/**
* Post Phantom TX descriptor
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v cds TX descriptor
*/
-static void phantom_post_cds ( struct phantom_nic_port *phantom_port,
+static void phantom_post_cds ( struct phantom_nic *phantom,
union phantom_cds *cds ) {
- struct phantom_nic *phantom = phantom_port->phantom;
unsigned int cds_producer_idx;
unsigned int next_cds_producer_idx;
union phantom_cds *entry;
/* Copy descriptor to ring */
- cds_producer_idx = phantom_port->cds_producer_idx;
- entry = &phantom_port->desc->cds[cds_producer_idx];
+ cds_producer_idx = phantom->cds_producer_idx;
+ entry = &phantom->desc->cds[cds_producer_idx];
memcpy ( entry, cds, sizeof ( *entry ) );
- DBGC2 ( phantom, "Phantom %p port %d posting CDS %d:\n",
- phantom, phantom_port->port, cds_producer_idx );
+ DBGC2 ( phantom, "Phantom %p posting CDS %d:\n",
+ phantom, cds_producer_idx );
DBGC2_HDA ( phantom, virt_to_bus ( entry ), entry, sizeof ( *entry ) );
/* Update producer index */
next_cds_producer_idx = ( ( cds_producer_idx + 1 ) % PHN_NUM_CDS );
- phantom_port->cds_producer_idx = next_cds_producer_idx;
+ phantom->cds_producer_idx = next_cds_producer_idx;
wmb();
- phantom_writel ( phantom, phantom_port->cds_producer_idx,
- phantom_port->cds_producer_crb );
+ phantom_writel ( phantom, phantom->cds_producer_idx,
+ phantom->cds_producer_crb );
}
/***************************************************************************
@@ -1072,19 +942,19 @@ static void phantom_post_cds ( struct phantom_nic_port *phantom_port,
/**
* Add/remove MAC address
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v ll_addr MAC address to add or remove
* @v opcode MAC request opcode
* @ret rc Return status code
*/
-static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port,
+static int phantom_update_macaddr ( struct phantom_nic *phantom,
const uint8_t *ll_addr,
unsigned int opcode ) {
union phantom_cds cds;
int index;
/* Get descriptor ring entry */
- index = phantom_alloc_cds ( phantom_port );
+ index = phantom_alloc_cds ( phantom );
if ( index < 0 )
return index;
@@ -1094,7 +964,7 @@ static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port,
nic_request.common.opcode, UNM_NIC_REQUEST );
NX_FILL_2 ( &cds, 1,
nic_request.header.opcode, UNM_MAC_EVENT,
- nic_request.header.context_id, phantom_port->port );
+ nic_request.header.context_id, phantom->port );
NX_FILL_7 ( &cds, 2,
nic_request.body.mac_request.opcode, opcode,
nic_request.body.mac_request.mac_addr_0, ll_addr[0],
@@ -1105,7 +975,7 @@ static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port,
nic_request.body.mac_request.mac_addr_5, ll_addr[5] );
/* Post descriptor */
- phantom_post_cds ( phantom_port, &cds );
+ phantom_post_cds ( phantom, &cds );
return 0;
}
@@ -1113,35 +983,33 @@ static int phantom_update_macaddr ( struct phantom_nic_port *phantom_port,
/**
* Add MAC address
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v ll_addr MAC address to add or remove
* @ret rc Return status code
*/
-static inline int phantom_add_macaddr ( struct phantom_nic_port *phantom_port,
+static inline int phantom_add_macaddr ( struct phantom_nic *phantom,
const uint8_t *ll_addr ) {
- struct phantom_nic *phantom = phantom_port->phantom;
- DBGC ( phantom, "Phantom %p port %d adding MAC address %s\n",
- phantom, phantom_port->port, eth_ntoa ( ll_addr ) );
+ DBGC ( phantom, "Phantom %p adding MAC address %s\n",
+ phantom, eth_ntoa ( ll_addr ) );
- return phantom_update_macaddr ( phantom_port, ll_addr, UNM_MAC_ADD );
+ return phantom_update_macaddr ( phantom, ll_addr, UNM_MAC_ADD );
}
/**
* Remove MAC address
*
- * @v phantom_port Phantom NIC port
+ * @v phantom Phantom NIC
* @v ll_addr MAC address to add or remove
* @ret rc Return status code
*/
-static inline int phantom_del_macaddr ( struct phantom_nic_port *phantom_port,
+static inline int phantom_del_macaddr ( struct phantom_nic *phantom,
const uint8_t *ll_addr ) {
- struct phantom_nic *phantom = phantom_port->phantom;
- DBGC ( phantom, "Phantom %p port %d removing MAC address %s\n",
- phantom, phantom_port->port, eth_ntoa ( ll_addr ) );
+ DBGC ( phantom, "Phantom %p removing MAC address %s\n",
+ phantom, eth_ntoa ( ll_addr ) );
- return phantom_update_macaddr ( phantom_port, ll_addr, UNM_MAC_DEL );
+ return phantom_update_macaddr ( phantom, ll_addr, UNM_MAC_DEL );
}
/***************************************************************************
@@ -1153,14 +1021,12 @@ static inline int phantom_del_macaddr ( struct phantom_nic_port *phantom_port,
/**
* Poll link state
*
- * @v phantom Phantom NIC
+ * @v netdev Network device
*/
-static void phantom_poll_link_state ( struct phantom_nic *phantom ) {
- struct net_device *netdev;
- struct phantom_nic_port *phantom_port;
+static void phantom_poll_link_state ( struct net_device *netdev ) {
+ struct phantom_nic *phantom = netdev_priv ( netdev );
uint32_t xg_state_p3;
unsigned int link;
- int i;
/* Read link state */
xg_state_p3 = phantom_readl ( phantom, UNM_NIC_REG_XG_STATE_P3 );
@@ -1170,32 +1036,26 @@ static void phantom_poll_link_state ( struct phantom_nic *phantom ) {
return;
/* Record new link state */
- DBGC ( phantom, "Phantom %p new link state %08lx (was %08lx)\n",
+ DBGC ( phantom, "Phantom %p new link state %08x (was %08x)\n",
phantom, xg_state_p3, phantom->link_state );
phantom->link_state = xg_state_p3;
- /* Indicate per-port link state to gPXE */
- for ( i = 0 ; i < phantom->num_ports ; i++ ) {
- netdev = phantom->netdev[i];
- phantom_port = netdev_priv ( netdev );
- link = UNM_NIC_REG_XG_STATE_P3_LINK ( phantom_port->port,
- phantom->link_state );
- switch ( link ) {
- case UNM_NIC_REG_XG_STATE_P3_LINK_UP:
- DBGC ( phantom, "Phantom %p port %d link is up\n",
- phantom, phantom_port->port );
- netdev_link_up ( netdev );
- break;
- case UNM_NIC_REG_XG_STATE_P3_LINK_DOWN:
- DBGC ( phantom, "Phantom %p port %d link is down\n",
- phantom, phantom_port->port );
- netdev_link_down ( netdev );
- break;
- default:
- DBGC ( phantom, "Phantom %p port %d bad link state "
- "%d\n", phantom, phantom_port->port, link );
- break;
- }
+ /* Indicate link state to gPXE */
+ link = UNM_NIC_REG_XG_STATE_P3_LINK ( phantom->port,
+ phantom->link_state );
+ switch ( link ) {
+ case UNM_NIC_REG_XG_STATE_P3_LINK_UP:
+ DBGC ( phantom, "Phantom %p link is up\n", phantom );
+ netdev_link_up ( netdev );
+ break;
+ case UNM_NIC_REG_XG_STATE_P3_LINK_DOWN:
+ DBGC ( phantom, "Phantom %p link is down\n", phantom );
+ netdev_link_down ( netdev );
+ break;
+ default:
+ DBGC ( phantom, "Phantom %p bad link state %d\n",
+ phantom, link );
+ break;
}
}
@@ -1211,7 +1071,7 @@ static void phantom_poll_link_state ( struct phantom_nic *phantom ) {
* @v netdev Net device
*/
static void phantom_refill_rx_ring ( struct net_device *netdev ) {
- struct phantom_nic_port *phantom_port = netdev_priv ( netdev );
+ struct phantom_nic *phantom = netdev_priv ( netdev );
struct io_buffer *iobuf;
struct phantom_rds rds;
unsigned int handle;
@@ -1222,11 +1082,11 @@ static void phantom_refill_rx_ring ( struct net_device *netdev ) {
/* Skip this index if the descriptor has not yet been
* consumed.
*/
- if ( phantom_port->rds_iobuf[handle] != NULL )
+ if ( phantom->rds_iobuf[handle] != NULL )
continue;
/* Allocate descriptor ring entry */
- index = phantom_alloc_rds ( phantom_port );
+ index = phantom_alloc_rds ( phantom );
assert ( PHN_RDS_MAX_FILL < PHN_NUM_RDS );
assert ( index >= 0 ); /* Guaranteed by MAX_FILL < NUM_RDS ) */
@@ -1247,11 +1107,11 @@ static void phantom_refill_rx_ring ( struct net_device *netdev ) {
dma_addr, virt_to_bus ( iobuf->data ) );
/* Record I/O buffer */
- assert ( phantom_port->rds_iobuf[handle] == NULL );
- phantom_port->rds_iobuf[handle] = iobuf;
+ assert ( phantom->rds_iobuf[handle] == NULL );
+ phantom->rds_iobuf[handle] = iobuf;
/* Post descriptor */
- phantom_post_rds ( phantom_port, &rds );
+ phantom_post_rds ( phantom, &rds );
}
}
@@ -1262,24 +1122,24 @@ static void phantom_refill_rx_ring ( struct net_device *netdev ) {
* @ret rc Return status code
*/
static int phantom_open ( struct net_device *netdev ) {
- struct phantom_nic_port *phantom_port = netdev_priv ( netdev );
+ struct phantom_nic *phantom = netdev_priv ( netdev );
int rc;
/* Allocate and zero descriptor rings */
- phantom_port->desc = malloc_dma ( sizeof ( *(phantom_port->desc) ),
+ phantom->desc = malloc_dma ( sizeof ( *(phantom->desc) ),
UNM_DMA_BUFFER_ALIGN );
- if ( ! phantom_port->desc ) {
+ if ( ! phantom->desc ) {
rc = -ENOMEM;
goto err_alloc_desc;
}
- memset ( phantom_port->desc, 0, sizeof ( *(phantom_port->desc) ) );
+ memset ( phantom->desc, 0, sizeof ( *(phantom->desc) ) );
/* Create RX context */
- if ( ( rc = phantom_create_rx_ctx ( phantom_port ) ) != 0 )
+ if ( ( rc = phantom_create_rx_ctx ( phantom ) ) != 0 )
goto err_create_rx_ctx;
/* Create TX context */
- if ( ( rc = phantom_create_tx_ctx ( phantom_port ) ) != 0 )
+ if ( ( rc = phantom_create_tx_ctx ( phantom ) ) != 0 )
goto err_create_tx_ctx;
/* Fill the RX descriptor ring */
@@ -1293,26 +1153,26 @@ static int phantom_open ( struct net_device *netdev ) {
* packets (or, failing that, promiscuous mode), but the
* firmware doesn't currently support this.
*/
- if ( ( rc = phantom_add_macaddr ( phantom_port,
+ if ( ( rc = phantom_add_macaddr ( phantom,
netdev->ll_protocol->ll_broadcast ) ) != 0 )
goto err_add_macaddr_broadcast;
- if ( ( rc = phantom_add_macaddr ( phantom_port,
+ if ( ( rc = phantom_add_macaddr ( phantom,
netdev->ll_addr ) ) != 0 )
goto err_add_macaddr_unicast;
return 0;
- phantom_del_macaddr ( phantom_port, netdev->ll_addr );
+ phantom_del_macaddr ( phantom, netdev->ll_addr );
err_add_macaddr_unicast:
- phantom_del_macaddr ( phantom_port,
+ phantom_del_macaddr ( phantom,
netdev->ll_protocol->ll_broadcast );
err_add_macaddr_broadcast:
- phantom_destroy_tx_ctx ( phantom_port );
+ phantom_destroy_tx_ctx ( phantom );
err_create_tx_ctx:
- phantom_destroy_rx_ctx ( phantom_port );
+ phantom_destroy_rx_ctx ( phantom );
err_create_rx_ctx:
- free_dma ( phantom_port->desc, sizeof ( *(phantom_port->desc) ) );
- phantom_port->desc = NULL;
+ free_dma ( phantom->desc, sizeof ( *(phantom->desc) ) );
+ phantom->desc = NULL;
err_alloc_desc:
return rc;
}
@@ -1323,32 +1183,32 @@ static int phantom_open ( struct net_device *netdev ) {
* @v netdev Net device
*/
static void phantom_close ( struct net_device *netdev ) {
- struct phantom_nic_port *phantom_port = netdev_priv ( netdev );
+ struct phantom_nic *phantom = netdev_priv ( netdev );
struct io_buffer *iobuf;
unsigned int i;
/* Shut down the port */
- phantom_del_macaddr ( phantom_port, netdev->ll_addr );
- phantom_del_macaddr ( phantom_port,
+ phantom_del_macaddr ( phantom, netdev->ll_addr );
+ phantom_del_macaddr ( phantom,
netdev->ll_protocol->ll_broadcast );
- phantom_destroy_tx_ctx ( phantom_port );
- phantom_destroy_rx_ctx ( phantom_port );
- free_dma ( phantom_port->desc, sizeof ( *(phantom_port->desc) ) );
- phantom_port->desc = NULL;
+ phantom_destroy_tx_ctx ( phantom );
+ phantom_destroy_rx_ctx ( phantom );
+ free_dma ( phantom->desc, sizeof ( *(phantom->desc) ) );
+ phantom->desc = NULL;
/* Flush any uncompleted descriptors */
for ( i = 0 ; i < PHN_RDS_MAX_FILL ; i++ ) {
- iobuf = phantom_port->rds_iobuf[i];
+ iobuf = phantom->rds_iobuf[i];
if ( iobuf ) {
free_iob ( iobuf );
- phantom_port->rds_iobuf[i] = NULL;
+ phantom->rds_iobuf[i] = NULL;
}
}
for ( i = 0 ; i < PHN_NUM_CDS ; i++ ) {
- iobuf = phantom_port->cds_iobuf[i];
+ iobuf = phantom->cds_iobuf[i];
if ( iobuf ) {
netdev_tx_complete_err ( netdev, iobuf, -ECANCELED );
- phantom_port->cds_iobuf[i] = NULL;
+ phantom->cds_iobuf[i] = NULL;
}
}
}
@@ -1362,12 +1222,12 @@ static void phantom_close ( struct net_device *netdev ) {
*/
static int phantom_transmit ( struct net_device *netdev,
struct io_buffer *iobuf ) {
- struct phantom_nic_port *phantom_port = netdev_priv ( netdev );
+ struct phantom_nic *phantom = netdev_priv ( netdev );
union phantom_cds cds;
int index;
/* Get descriptor ring entry */
- index = phantom_alloc_cds ( phantom_port );
+ index = phantom_alloc_cds ( phantom );
if ( index < 0 )
return index;
@@ -1378,19 +1238,19 @@ static int phantom_transmit ( struct net_device *netdev,
tx.num_buffers, 1,
tx.length, iob_len ( iobuf ) );
NX_FILL_2 ( &cds, 2,
- tx.port, phantom_port->port,
- tx.context_id, phantom_port->port );
+ tx.port, phantom->port,
+ tx.context_id, phantom->port );
NX_FILL_1 ( &cds, 4,
tx.buffer1_dma_addr, virt_to_bus ( iobuf->data ) );
NX_FILL_1 ( &cds, 5,
tx.buffer1_length, iob_len ( iobuf ) );
/* Record I/O buffer */
- assert ( phantom_port->cds_iobuf[index] == NULL );
- phantom_port->cds_iobuf[index] = iobuf;
+ assert ( phantom->cds_iobuf[index] == NULL );
+ phantom->cds_iobuf[index] = iobuf;
/* Post descriptor */
- phantom_post_cds ( phantom_port, &cds );
+ phantom_post_cds ( phantom, &cds );
return 0;
}
@@ -1401,8 +1261,7 @@ static int phantom_transmit ( struct net_device *netdev,
* @v netdev Network device
*/
static void phantom_poll ( struct net_device *netdev ) {
- struct phantom_nic_port *phantom_port = netdev_priv ( netdev );
- struct phantom_nic *phantom = phantom_port->phantom;
+ struct phantom_nic *phantom = netdev_priv ( netdev );
struct io_buffer *iobuf;
unsigned int cds_consumer_idx;
unsigned int raw_new_cds_consumer_idx;
@@ -1414,33 +1273,33 @@ static void phantom_poll ( struct net_device *netdev ) {
unsigned int sds_opcode;
/* Check for TX completions */
- cds_consumer_idx = phantom_port->cds_consumer_idx;
- raw_new_cds_consumer_idx = phantom_port->desc->cmd_cons;
+ cds_consumer_idx = phantom->cds_consumer_idx;
+ raw_new_cds_consumer_idx = phantom->desc->cmd_cons;
new_cds_consumer_idx = le32_to_cpu ( raw_new_cds_consumer_idx );
while ( cds_consumer_idx != new_cds_consumer_idx ) {
- DBGC2 ( phantom, "Phantom %p port %d CDS %d complete\n",
- phantom, phantom_port->port, cds_consumer_idx );
+ DBGC2 ( phantom, "Phantom %p CDS %d complete\n",
+ phantom, cds_consumer_idx );
/* Completions may be for commands other than TX, so
* there may not always be an associated I/O buffer.
*/
- if ( ( iobuf = phantom_port->cds_iobuf[cds_consumer_idx] ) ) {
+ if ( ( iobuf = phantom->cds_iobuf[cds_consumer_idx] ) ) {
netdev_tx_complete ( netdev, iobuf );
- phantom_port->cds_iobuf[cds_consumer_idx] = NULL;
+ phantom->cds_iobuf[cds_consumer_idx] = NULL;
}
cds_consumer_idx = ( ( cds_consumer_idx + 1 ) % PHN_NUM_CDS );
- phantom_port->cds_consumer_idx = cds_consumer_idx;
+ phantom->cds_consumer_idx = cds_consumer_idx;
}
/* Check for received packets */
- rds_consumer_idx = phantom_port->rds_consumer_idx;
- sds_consumer_idx = phantom_port->sds_consumer_idx;
+ rds_consumer_idx = phantom->rds_consumer_idx;
+ sds_consumer_idx = phantom->sds_consumer_idx;
while ( 1 ) {
- sds = &phantom_port->desc->sds[sds_consumer_idx];
+ sds = &phantom->desc->sds[sds_consumer_idx];
if ( NX_GET ( sds, owner ) == 0 )
break;
- DBGC2 ( phantom, "Phantom %p port %d SDS %d status:\n",
- phantom, phantom_port->port, sds_consumer_idx );
+ DBGC2 ( phantom, "Phantom %p SDS %d status:\n",
+ phantom, sds_consumer_idx );
DBGC2_HDA ( phantom, virt_to_bus ( sds ), sds, sizeof (*sds) );
/* Check received opcode */
@@ -1452,24 +1311,23 @@ static void phantom_poll ( struct net_device *netdev ) {
* descriptor has been written.
*/
if ( NX_GET ( sds, total_length ) == 0 ) {
- DBGC ( phantom, "Phantom %p port %d SDS %d "
- "incomplete; deferring\n", phantom,
- phantom_port->port, sds_consumer_idx );
+ DBGC ( phantom, "Phantom %p SDS %d "
+ "incomplete; deferring\n",
+ phantom, sds_consumer_idx );
/* Leave for next poll() */
break;
}
/* Process received packet */
sds_handle = NX_GET ( sds, handle );
- iobuf = phantom_port->rds_iobuf[sds_handle];
+ iobuf = phantom->rds_iobuf[sds_handle];
assert ( iobuf != NULL );
iob_put ( iobuf, NX_GET ( sds, total_length ) );
iob_pull ( iobuf, NX_GET ( sds, pkt_offset ) );
- DBGC2 ( phantom, "Phantom %p port %d RDS %d "
- "complete\n",
- phantom, phantom_port->port, sds_handle );
+ DBGC2 ( phantom, "Phantom %p RDS %d complete\n",
+ phantom, sds_handle );
netdev_rx ( netdev, iobuf );
- phantom_port->rds_iobuf[sds_handle] = NULL;
+ phantom->rds_iobuf[sds_handle] = NULL;
/* Update RDS consumer counter. This is a
* lower bound for the number of descriptors
@@ -1480,13 +1338,12 @@ static void phantom_poll ( struct net_device *netdev ) {
*/
rds_consumer_idx =
( ( rds_consumer_idx + 1 ) % PHN_NUM_RDS );
- phantom_port->rds_consumer_idx = rds_consumer_idx;
+ phantom->rds_consumer_idx = rds_consumer_idx;
} else {
- DBGC ( phantom, "Phantom %p port %d unexpected SDS "
- "opcode %02x\n",
- phantom, phantom_port->port, sds_opcode );
+ DBGC ( phantom, "Phantom %p unexpected SDS opcode "
+ "%02x\n", phantom, sds_opcode );
DBGC_HDA ( phantom, virt_to_bus ( sds ),
sds, sizeof ( *sds ) );
}
@@ -1496,20 +1353,20 @@ static void phantom_poll ( struct net_device *netdev ) {
/* Update SDS consumer index */
sds_consumer_idx = ( ( sds_consumer_idx + 1 ) % PHN_NUM_SDS );
- phantom_port->sds_consumer_idx = sds_consumer_idx;
+ phantom->sds_consumer_idx = sds_consumer_idx;
wmb();
- phantom_writel ( phantom, phantom_port->sds_consumer_idx,
- phantom_port->sds_consumer_crb );
+ phantom_writel ( phantom, phantom->sds_consumer_idx,
+ phantom->sds_consumer_crb );
}
/* Refill the RX descriptor ring */
phantom_refill_rx_ring ( netdev );
/* Occasionally poll the link state */
- if ( phantom_port->link_poll_timer-- == 0 ) {
- phantom_poll_link_state ( phantom );
+ if ( phantom->link_poll_timer-- == 0 ) {
+ phantom_poll_link_state ( netdev );
/* Reset the link poll timer */
- phantom_port->link_poll_timer = PHN_LINK_POLL_FREQUENCY;
+ phantom->link_poll_timer = PHN_LINK_POLL_FREQUENCY;
}
}
@@ -1520,9 +1377,8 @@ static void phantom_poll ( struct net_device *netdev ) {
* @v enable Interrupts should be enabled
*/
static void phantom_irq ( struct net_device *netdev, int enable ) {
- struct phantom_nic_port *phantom_port = netdev_priv ( netdev );
- struct phantom_nic *phantom = phantom_port->phantom;
- static const unsigned long sw_int_mask_reg[UNM_FLASH_NUM_PORTS] = {
+ struct phantom_nic *phantom = netdev_priv ( netdev );
+ static const unsigned long sw_int_mask_reg[PHN_MAX_NUM_PORTS] = {
UNM_NIC_REG_SW_INT_MASK_0,
UNM_NIC_REG_SW_INT_MASK_1,
UNM_NIC_REG_SW_INT_MASK_2,
@@ -1531,7 +1387,7 @@ static void phantom_irq ( struct net_device *netdev, int enable ) {
phantom_writel ( phantom,
( enable ? 1 : 0 ),
- sw_int_mask_reg[phantom_port->port] );
+ sw_int_mask_reg[phantom->port] );
}
/** Phantom net device operations */
@@ -1543,6 +1399,336 @@ static struct net_device_operations phantom_operations = {
.irq = phantom_irq,
};
+/***************************************************************************
+ *
+ * CLP settings
+ *
+ */
+
+/** Phantom CLP settings tag magic */
+#define PHN_CLP_TAG_MAGIC 0xc19c1900UL
+
+/** Phantom CLP settings tag magic mask */
+#define PHN_CLP_TAG_MAGIC_MASK 0xffffff00UL
+
+/** Phantom CLP data
+ *
+ */
+union phantom_clp_data {
+ /** Data bytes
+ *
+ * This field is right-aligned; if only N bytes are present
+ * then bytes[0]..bytes[7-N] should be zero, and the data
+ * should be in bytes[7-N+1] to bytes[7];
+ */
+ uint8_t bytes[8];
+ /** Dwords for the CLP interface */
+ struct {
+ /** High dword, in network byte order */
+ uint32_t hi;
+ /** Low dword, in network byte order */
+ uint32_t lo;
+ } dwords;
+};
+#define PHN_CLP_BLKSIZE ( sizeof ( union phantom_clp_data ) )
+
+/**
+ * Wait for Phantom CLP command to complete
+ *
+ * @v phantom Phantom NIC
+ * @ret rc Return status code
+ */
+static int phantom_clp_wait ( struct phantom_nic *phantom ) {
+ unsigned int retries;
+ uint32_t status;
+
+ for ( retries = 0 ; retries < PHN_CLP_CMD_TIMEOUT_MS ; retries++ ) {
+ status = phantom_readl ( phantom, UNM_CAM_RAM_CLP_STATUS );
+ if ( status & UNM_CAM_RAM_CLP_STATUS_DONE )
+ return 0;
+ mdelay ( 1 );
+ }
+
+ DBGC ( phantom, "Phantom %p timed out waiting for CLP command\n",
+ phantom );
+ return -ETIMEDOUT;
+}
+
+/**
+ * Issue Phantom CLP command
+ *
+ * @v phantom Phantom NIC
+ * @v port Virtual port number
+ * @v opcode Opcode
+ * @v data_in Data in, or NULL
+ * @v data_out Data out, or NULL
+ * @v offset Offset within data
+ * @v len Data buffer length
+ * @ret len Total transfer length (for reads), or negative error
+ */
+static int phantom_clp_cmd ( struct phantom_nic *phantom, unsigned int port,
+ unsigned int opcode, const void *data_in,
+ void *data_out, size_t offset, size_t len ) {
+ union phantom_clp_data data;
+ unsigned int index = ( offset / sizeof ( data ) );
+ unsigned int last = 0;
+ size_t in_frag_len;
+ uint8_t *in_frag;
+ uint32_t command;
+ uint32_t status;
+ size_t read_len;
+ unsigned int error;
+ size_t out_frag_len;
+ uint8_t *out_frag;
+ int rc;
+
+ /* Sanity checks */
+ assert ( ( offset % sizeof ( data ) ) == 0 );
+ if ( len > 255 ) {
+ DBGC ( phantom, "Phantom %p invalid CLP length %zd\n",
+ phantom, len );
+ return -EINVAL;
+ }
+
+ /* Check that CLP interface is ready */
+ if ( ( rc = phantom_clp_wait ( phantom ) ) != 0 )
+ return rc;
+
+ /* Copy data in */
+ memset ( &data, 0, sizeof ( data ) );
+ if ( data_in ) {
+ assert ( offset < len );
+ in_frag_len = ( len - offset );
+ if ( in_frag_len > sizeof ( data ) ) {
+ in_frag_len = sizeof ( data );
+ } else {
+ last = 1;
+ }
+ in_frag = &data.bytes[ sizeof ( data ) - in_frag_len ];
+ memcpy ( in_frag, ( data_in + offset ), in_frag_len );
+ phantom_writel ( phantom, be32_to_cpu ( data.dwords.lo ),
+ UNM_CAM_RAM_CLP_DATA_LO );
+ phantom_writel ( phantom, be32_to_cpu ( data.dwords.hi ),
+ UNM_CAM_RAM_CLP_DATA_HI );
+ }
+
+ /* Issue CLP command */
+ command = ( ( index << 24 ) | ( ( data_in ? len : 0 ) << 16 ) |
+ ( port << 8 ) | ( last << 7 ) | ( opcode << 0 ) );
+ phantom_writel ( phantom, command, UNM_CAM_RAM_CLP_COMMAND );
+ mb();
+ phantom_writel ( phantom, UNM_CAM_RAM_CLP_STATUS_START,
+ UNM_CAM_RAM_CLP_STATUS );
+
+ /* Wait for command to complete */
+ if ( ( rc = phantom_clp_wait ( phantom ) ) != 0 )
+ return rc;
+
+ /* Get command status */
+ status = phantom_readl ( phantom, UNM_CAM_RAM_CLP_STATUS );
+ read_len = ( ( status >> 16 ) & 0xff );
+ error = ( ( status >> 8 ) & 0xff );
+ if ( error ) {
+ DBGC ( phantom, "Phantom %p CLP command error %02x\n",
+ phantom, error );
+ return -EIO;
+ }
+
+ /* Copy data out */
+ if ( data_out ) {
+ data.dwords.lo = cpu_to_be32 ( phantom_readl ( phantom,
+ UNM_CAM_RAM_CLP_DATA_LO ) );
+ data.dwords.hi = cpu_to_be32 ( phantom_readl ( phantom,
+ UNM_CAM_RAM_CLP_DATA_HI ) );
+ out_frag_len = ( read_len - offset );
+ if ( out_frag_len > sizeof ( data ) )
+ out_frag_len = sizeof ( data );
+ out_frag = &data.bytes[ sizeof ( data ) - out_frag_len ];
+ if ( out_frag_len > ( len - offset ) )
+ out_frag_len = ( len - offset );
+ memcpy ( ( data_out + offset ), out_frag, out_frag_len );
+ }
+
+ return read_len;
+}
+
+/**
+ * Store Phantom CLP setting
+ *
+ * @v phantom Phantom NIC
+ * @v port Virtual port number
+ * @v setting Setting number
+ * @v data Data buffer
+ * @v len Length of data buffer
+ * @ret rc Return status code
+ */
+static int phantom_clp_store ( struct phantom_nic *phantom, unsigned int port,
+ unsigned int setting, const void *data,
+ size_t len ) {
+ unsigned int opcode = setting;
+ size_t offset;
+ int rc;
+
+ for ( offset = 0 ; offset < len ; offset += PHN_CLP_BLKSIZE ) {
+ if ( ( rc = phantom_clp_cmd ( phantom, port, opcode, data,
+ NULL, offset, len ) ) < 0 )
+ return rc;
+ }
+ return 0;
+}
+
+/**
+ * Fetch Phantom CLP setting
+ *
+ * @v phantom Phantom NIC
+ * @v port Virtual port number
+ * @v setting Setting number
+ * @v data Data buffer
+ * @v len Length of data buffer
+ * @ret len Length of setting, or negative error
+ */
+static int phantom_clp_fetch ( struct phantom_nic *phantom, unsigned int port,
+ unsigned int setting, void *data, size_t len ) {
+ unsigned int opcode = ( setting + 1 );
+ size_t offset = 0;
+ int read_len;
+
+ while ( 1 ) {
+ read_len = phantom_clp_cmd ( phantom, port, opcode, NULL,
+ data, offset, len );
+ if ( read_len < 0 )
+ return read_len;
+ offset += PHN_CLP_BLKSIZE;
+ if ( offset >= ( unsigned ) read_len )
+ break;
+ if ( offset >= len )
+ break;
+ }
+ return read_len;
+}
+
+/** A Phantom CLP setting */
+struct phantom_clp_setting {
+ /** gPXE setting */
+ struct setting *setting;
+ /** Setting number */
+ unsigned int clp_setting;
+};
+
+/** Phantom CLP settings */
+static struct phantom_clp_setting clp_settings[] = {
+ { &mac_setting, 0x01 },
+};
+
+/**
+ * Find Phantom CLP setting
+ *
+ * @v setting gPXE setting
+ * @v clp_setting Setting number, or 0 if not found
+ */
+static unsigned int
+phantom_clp_setting ( struct phantom_nic *phantom, struct setting *setting ) {
+ struct phantom_clp_setting *clp_setting;
+ unsigned int i;
+
+ /* Search the list of explicitly-defined settings */
+ for ( i = 0 ; i < ( sizeof ( clp_settings ) /
+ sizeof ( clp_settings[0] ) ) ; i++ ) {
+ clp_setting = &clp_settings[i];
+ if ( setting_cmp ( setting, clp_setting->setting ) == 0 )
+ return clp_setting->clp_setting;
+ }
+
+ /* Allow for use of numbered settings */
+ if ( ( setting->tag & PHN_CLP_TAG_MAGIC_MASK ) == PHN_CLP_TAG_MAGIC )
+ return ( setting->tag & ~PHN_CLP_TAG_MAGIC_MASK );
+
+ DBGC2 ( phantom, "Phantom %p has no \"%s\" setting\n",
+ phantom, setting->name );
+
+ return 0;
+}
+
+/**
+ * Store Phantom CLP setting
+ *
+ * @v settings Settings block
+ * @v setting Setting to store
+ * @v data Setting data, or NULL to clear setting
+ * @v len Length of setting data
+ * @ret rc Return status code
+ */
+static int phantom_store_setting ( struct settings *settings,
+ struct setting *setting,
+ const void *data, size_t len ) {
+ struct phantom_nic *phantom =
+ container_of ( settings, struct phantom_nic, settings );
+ unsigned int clp_setting;
+ int rc;
+
+ /* Find Phantom setting equivalent to gPXE setting */
+ clp_setting = phantom_clp_setting ( phantom, setting );
+ if ( ! clp_setting )
+ return -ENOTSUP;
+
+ /* Store setting */
+ if ( ( rc = phantom_clp_store ( phantom, phantom->port,
+ clp_setting, data, len ) ) != 0 ) {
+ DBGC ( phantom, "Phantom %p could not store setting \"%s\": "
+ "%s\n", phantom, setting->name, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Fetch Phantom CLP setting
+ *
+ * @v settings Settings block
+ * @v setting Setting to fetch
+ * @v data Buffer to fill with setting data
+ * @v len Length of buffer
+ * @ret len Length of setting data, or negative error
+ */
+static int phantom_fetch_setting ( struct settings *settings,
+ struct setting *setting,
+ void *data, size_t len ) {
+ struct phantom_nic *phantom =
+ container_of ( settings, struct phantom_nic, settings );
+ unsigned int clp_setting;
+ int read_len;
+ int rc;
+
+ /* Find Phantom setting equivalent to gPXE setting */
+ clp_setting = phantom_clp_setting ( phantom, setting );
+ if ( ! clp_setting )
+ return -ENOTSUP;
+
+ /* Fetch setting */
+ if ( ( read_len = phantom_clp_fetch ( phantom, phantom->port,
+ clp_setting, data, len ) ) < 0 ){
+ rc = read_len;
+ DBGC ( phantom, "Phantom %p could not fetch setting \"%s\": "
+ "%s\n", phantom, setting->name, strerror ( rc ) );
+ return rc;
+ }
+
+ return read_len;
+}
+
+/** Phantom CLP settings operations */
+static struct settings_operations phantom_settings_operations = {
+ .store = phantom_store_setting,
+ .fetch = phantom_fetch_setting,
+};
+
+/***************************************************************************
+ *
+ * Initialisation
+ *
+ */
+
/**
* Map Phantom CRB window
*
@@ -1556,8 +1742,15 @@ static int phantom_map_crb ( struct phantom_nic *phantom,
bar0_start = pci_bar_start ( pci, PCI_BASE_ADDRESS_0 );
bar0_size = pci_bar_size ( pci, PCI_BASE_ADDRESS_0 );
- DBGC ( phantom, "Phantom %p BAR0 is %08lx+%lx\n",
- phantom, bar0_start, bar0_size );
+ DBGC ( phantom, "Phantom %p is PCI %02x:%02x.%x with BAR0 at "
+ "%08lx+%lx\n", phantom, pci->bus, PCI_SLOT ( pci->devfn ),
+ PCI_FUNC ( pci->devfn ), bar0_start, bar0_size );
+
+ if ( ! bar0_start ) {
+ DBGC ( phantom, "Phantom %p BAR not assigned; ignoring\n",
+ phantom );
+ return -EINVAL;
+ }
switch ( bar0_size ) {
case ( 128 * 1024 * 1024 ) :
@@ -1592,71 +1785,23 @@ static int phantom_map_crb ( struct phantom_nic *phantom,
}
/**
- * Read Phantom flash contents
+ * Unhalt all PEGs
*
* @v phantom Phantom NIC
- * @ret rc Return status code
*/
-static int phantom_read_flash ( struct phantom_nic *phantom ) {
- struct unm_board_info board_info;
- int rc;
-
- /* Initialise flash access */
- phantom->spi_bus.rw = phantom_spi_rw;
- phantom->flash.bus = &phantom->spi_bus;
- init_m25p32 ( &phantom->flash );
- /* Phantom doesn't support greater than 4-byte block sizes */
- phantom->flash.nvs.block_size = UNM_SPI_BLKSIZE;
-
- /* Read and verify board information */
- if ( ( rc = nvs_read ( &phantom->flash.nvs, UNM_BRDCFG_START,
- &board_info, sizeof ( board_info ) ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p could not read board info: %s\n",
- phantom, strerror ( rc ) );
- return rc;
- }
- if ( board_info.magic != UNM_BDINFO_MAGIC ) {
- DBGC ( phantom, "Phantom %p has bad board info magic %lx\n",
- phantom, board_info.magic );
- DBGC_HD ( phantom, &board_info, sizeof ( board_info ) );
- return -EINVAL;
- }
- if ( board_info.header_version != UNM_BDINFO_VERSION ) {
- DBGC ( phantom, "Phantom %p has bad board info version %lx\n",
- phantom, board_info.header_version );
- DBGC_HD ( phantom, &board_info, sizeof ( board_info ) );
- return -EINVAL;
- }
-
- /* Identify board type and number of ports */
- switch ( board_info.board_type ) {
- case UNM_BRDTYPE_P3_4_GB:
- case UNM_BRDTYPE_P3_4_GB_MM:
- phantom->num_ports = 4;
- break;
- case UNM_BRDTYPE_P3_HMEZ:
- case UNM_BRDTYPE_P3_IMEZ:
- case UNM_BRDTYPE_P3_10G_CX4:
- case UNM_BRDTYPE_P3_10G_CX4_LP:
- case UNM_BRDTYPE_P3_10G_SFP_PLUS:
- case UNM_BRDTYPE_P3_XG_LOM:
- phantom->num_ports = 2;
- break;
- case UNM_BRDTYPE_P3_10000_BASE_T:
- case UNM_BRDTYPE_P3_10G_XFP:
- phantom->num_ports = 1;
- break;
- default:
- DBGC ( phantom, "Phantom %p unrecognised board type %#lx; "
- "assuming single-port\n",
- phantom, board_info.board_type );
- phantom->num_ports = 1;
- break;
- }
- DBGC ( phantom, "Phantom %p board type is %#lx (%d ports)\n",
- phantom, board_info.board_type, phantom->num_ports );
-
- return 0;
+static void phantom_unhalt_pegs ( struct phantom_nic *phantom ) {
+ uint32_t halt_status;
+
+ halt_status = phantom_readl ( phantom, UNM_PEG_0_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_0_HALT_STATUS );
+ halt_status = phantom_readl ( phantom, UNM_PEG_1_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_1_HALT_STATUS );
+ halt_status = phantom_readl ( phantom, UNM_PEG_2_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_2_HALT_STATUS );
+ halt_status = phantom_readl ( phantom, UNM_PEG_3_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_3_HALT_STATUS );
+ halt_status = phantom_readl ( phantom, UNM_PEG_4_HALT_STATUS );
+ phantom_writel ( phantom, halt_status, UNM_PEG_4_HALT_STATUS );
}
/**
@@ -1668,7 +1813,6 @@ static int phantom_read_flash ( struct phantom_nic *phantom ) {
static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
uint32_t cold_boot;
uint32_t sw_reset;
- physaddr_t dummy_dma_phys;
unsigned int retries;
uint32_t cmdpeg_state;
uint32_t last_cmdpeg_state = 0;
@@ -1681,6 +1825,11 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
if ( cmdpeg_state == UNM_NIC_REG_CMDPEG_STATE_INITIALIZE_ACK ) {
DBGC ( phantom, "Phantom %p command PEG already initialized\n",
phantom );
+ /* Unhalt the PEGs. Previous firmware (e.g. BOFM) may
+ * have halted the PEGs to prevent internal bus
+ * collisions when the BIOS re-reads the expansion ROM.
+ */
+ phantom_unhalt_pegs ( phantom );
return 0;
}
@@ -1691,13 +1840,13 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
phantom );
sw_reset = phantom_readl ( phantom, UNM_ROMUSB_GLB_SW_RESET );
if ( sw_reset != UNM_ROMUSB_GLB_SW_RESET_MAGIC ) {
- DBGC ( phantom, "Phantom %p reset failed: %08lx\n",
+ DBGC ( phantom, "Phantom %p reset failed: %08x\n",
phantom, sw_reset );
return -EIO;
}
} else {
DBGC ( phantom, "Phantom %p coming up from warm boot "
- "(%08lx)\n", phantom, cold_boot );
+ "(%08x)\n", phantom, cold_boot );
}
/* Clear cold-boot flag */
phantom_writel ( phantom, 0, UNM_CAM_RAM_COLD_BOOT );
@@ -1707,10 +1856,7 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
UNM_CAM_RAM_WOL_PORT_MODE );
/* Pass dummy DMA area to card */
- dummy_dma_phys = virt_to_bus ( phantom->dma_buf->dummy_dma );
- DBGC ( phantom, "Phantom %p dummy DMA at %08lx\n",
- phantom, dummy_dma_phys );
- phantom_write_hilo ( phantom, dummy_dma_phys,
+ phantom_write_hilo ( phantom, 0,
UNM_NIC_REG_DUMMY_BUF_ADDR_LO,
UNM_NIC_REG_DUMMY_BUF_ADDR_HI );
phantom_writel ( phantom, UNM_NIC_REG_DUMMY_BUF_INIT,
@@ -1728,7 +1874,7 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
UNM_NIC_REG_CMDPEG_STATE );
if ( cmdpeg_state != last_cmdpeg_state ) {
DBGC ( phantom, "Phantom %p command PEG state is "
- "%08lx after %d seconds...\n",
+ "%08x after %d seconds...\n",
phantom, cmdpeg_state, retries );
last_cmdpeg_state = cmdpeg_state;
}
@@ -1743,19 +1889,18 @@ static int phantom_init_cmdpeg ( struct phantom_nic *phantom ) {
}
DBGC ( phantom, "Phantom %p timed out waiting for command PEG to "
- "initialise (status %08lx)\n", phantom, cmdpeg_state );
+ "initialise (status %08x)\n", phantom, cmdpeg_state );
return -ETIMEDOUT;
}
/**
* Read Phantom MAC address
*
- * @v phanton_port Phantom NIC port
+ * @v phanton_port Phantom NIC
* @v ll_addr Buffer to fill with MAC address
*/
-static void phantom_get_macaddr ( struct phantom_nic_port *phantom_port,
+static void phantom_get_macaddr ( struct phantom_nic *phantom,
uint8_t *ll_addr ) {
- struct phantom_nic *phantom = phantom_port->phantom;
union {
uint8_t mac_addr[2][ETH_ALEN];
uint32_t dwords[3];
@@ -1765,7 +1910,7 @@ static void phantom_get_macaddr ( struct phantom_nic_port *phantom_port,
/* Read the three dwords that include this MAC address and one other */
offset = ( UNM_CAM_RAM_MAC_ADDRS +
- ( 12 * ( phantom_port->port / 2 ) ) );
+ ( 12 * ( phantom->port / 2 ) ) );
for ( i = 0 ; i < 3 ; i++, offset += 4 ) {
u.dwords[i] = phantom_readl ( phantom, offset );
}
@@ -1773,10 +1918,36 @@ static void phantom_get_macaddr ( struct phantom_nic_port *phantom_port,
/* Copy out the relevant MAC address */
for ( i = 0 ; i < ETH_ALEN ; i++ ) {
ll_addr[ ETH_ALEN - i - 1 ] =
- u.mac_addr[ phantom_port->port & 1 ][i];
+ u.mac_addr[ phantom->port & 1 ][i];
}
- DBGC ( phantom, "Phantom %p port %d MAC address is %s\n",
- phantom, phantom_port->port, eth_ntoa ( ll_addr ) );
+ DBGC ( phantom, "Phantom %p MAC address is %s\n",
+ phantom, eth_ntoa ( ll_addr ) );
+}
+
+/**
+ * Check Phantom is enabled for boot
+ *
+ * @v phanton_port Phantom NIC
+ * @ret rc Return status code
+ *
+ * This is something of an ugly hack to accommodate an OEM
+ * requirement. The NIC has only one expansion ROM BAR, rather than
+ * one per port. To allow individual ports to be selectively
+ * enabled/disabled for PXE boot (as required), we must therefore
+ * leave the expansion ROM always enabled, and place the per-port
+ * enable/disable logic within the gPXE driver.
+ */
+static int phantom_check_boot_enable ( struct phantom_nic *phantom ) {
+ unsigned long boot_enable;
+
+ boot_enable = phantom_readl ( phantom, UNM_CAM_RAM_BOOT_ENABLE );
+ if ( ! ( boot_enable & ( 1 << phantom->port ) ) ) {
+ DBGC ( phantom, "Phantom %p PXE boot is disabled\n",
+ phantom );
+ return -ENOTSUP;
+ }
+
+ return 0;
}
/**
@@ -1797,7 +1968,7 @@ static int phantom_init_rcvpeg ( struct phantom_nic *phantom ) {
UNM_NIC_REG_RCVPEG_STATE );
if ( rcvpeg_state != last_rcvpeg_state ) {
DBGC ( phantom, "Phantom %p receive PEG state is "
- "%08lx after %d seconds...\n",
+ "%08x after %d seconds...\n",
phantom, rcvpeg_state, retries );
last_rcvpeg_state = rcvpeg_state;
}
@@ -1807,7 +1978,7 @@ static int phantom_init_rcvpeg ( struct phantom_nic *phantom ) {
}
DBGC ( phantom, "Phantom %p timed out waiting for receive PEG to "
- "initialise (status %08lx)\n", phantom, rcvpeg_state );
+ "initialise (status %08x)\n", phantom, rcvpeg_state );
return -ETIMEDOUT;
}
@@ -1820,25 +1991,27 @@ static int phantom_init_rcvpeg ( struct phantom_nic *phantom ) {
*/
static int phantom_probe ( struct pci_device *pci,
const struct pci_device_id *id __unused ) {
- struct phantom_nic *phantom;
struct net_device *netdev;
- struct phantom_nic_port *phantom_port;
- int i;
+ struct phantom_nic *phantom;
+ struct settings *parent_settings;
int rc;
- /* Phantom NICs expose multiple PCI functions, used for
- * virtualisation. Ignore everything except function 0.
- */
- if ( PCI_FUNC ( pci->devfn ) != 0 )
- return -ENODEV;
-
/* Allocate Phantom device */
- phantom = zalloc ( sizeof ( *phantom ) );
- if ( ! phantom ) {
+ netdev = alloc_etherdev ( sizeof ( *phantom ) );
+ if ( ! netdev ) {
rc = -ENOMEM;
- goto err_alloc_phantom;
+ goto err_alloc_etherdev;
}
- pci_set_drvdata ( pci, phantom );
+ netdev_init ( netdev, &phantom_operations );
+ phantom = netdev_priv ( netdev );
+ pci_set_drvdata ( pci, netdev );
+ netdev->dev = &pci->dev;
+ memset ( phantom, 0, sizeof ( *phantom ) );
+ phantom->port = PCI_FUNC ( pci->devfn );
+ assert ( phantom->port < PHN_MAX_NUM_PORTS );
+ settings_init ( &phantom->settings,
+ &phantom_settings_operations,
+ &netdev->refcnt, "clp", PHN_CLP_TAG_MAGIC );
/* Fix up PCI device */
adjust_pci_device ( pci );
@@ -1847,87 +2020,66 @@ static int phantom_probe ( struct pci_device *pci,
if ( ( rc = phantom_map_crb ( phantom, pci ) ) != 0 )
goto err_map_crb;
- /* Read flash information */
- if ( ( rc = phantom_read_flash ( phantom ) ) != 0 )
- goto err_read_flash;
-
- /* Allocate net devices for each port */
- for ( i = 0 ; i < phantom->num_ports ; i++ ) {
- netdev = alloc_etherdev ( sizeof ( *phantom_port ) );
- if ( ! netdev ) {
- rc = -ENOMEM;
- goto err_alloc_etherdev;
- }
- phantom->netdev[i] = netdev;
- netdev_init ( netdev, &phantom_operations );
- phantom_port = netdev_priv ( netdev );
- netdev->dev = &pci->dev;
- phantom_port->phantom = phantom;
- phantom_port->port = i;
- }
-
/* BUG5945 - need to hack PCI config space on P3 B1 silicon.
* B2 will have this fixed; remove this hack when B1 is no
* longer in use.
*/
- for ( i = 0 ; i < 8 ; i++ ) {
- uint32_t temp;
- pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), i );
- pci_read_config_dword ( pci, 0xc8, &temp );
- pci_read_config_dword ( pci, 0xc8, &temp );
- pci_write_config_dword ( pci, 0xc8, 0xf1000 );
+ if ( PCI_FUNC ( pci->devfn ) == 0 ) {
+ unsigned int i;
+ for ( i = 0 ; i < 8 ; i++ ) {
+ uint32_t temp;
+ pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), i );
+ pci_read_config_dword ( pci, 0xc8, &temp );
+ pci_read_config_dword ( pci, 0xc8, &temp );
+ pci_write_config_dword ( pci, 0xc8, 0xf1000 );
+ }
+ pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), 0 );
}
- pci->devfn = PCI_DEVFN ( PCI_SLOT ( pci->devfn ), 0 );
- /* Allocate dummy DMA buffer and perform initial hardware handshake */
- phantom->dma_buf = malloc_dma ( sizeof ( *(phantom->dma_buf) ),
- UNM_DMA_BUFFER_ALIGN );
- if ( ! phantom->dma_buf )
- goto err_dma_buf;
+ /* Initialise the command PEG */
if ( ( rc = phantom_init_cmdpeg ( phantom ) ) != 0 )
goto err_init_cmdpeg;
- /* Initialise the receive firmware */
+ /* Initialise the receive PEG */
if ( ( rc = phantom_init_rcvpeg ( phantom ) ) != 0 )
goto err_init_rcvpeg;
/* Read MAC addresses */
- for ( i = 0 ; i < phantom->num_ports ; i++ ) {
- phantom_port = netdev_priv ( phantom->netdev[i] );
- phantom_get_macaddr ( phantom_port,
- phantom->netdev[i]->ll_addr );
- }
+ phantom_get_macaddr ( phantom, netdev->ll_addr );
+
+ /* Skip if boot disabled on NIC */
+ if ( ( rc = phantom_check_boot_enable ( phantom ) ) != 0 )
+ goto err_check_boot_enable;
/* Register network devices */
- for ( i = 0 ; i < phantom->num_ports ; i++ ) {
- if ( ( rc = register_netdev ( phantom->netdev[i] ) ) != 0 ) {
- DBGC ( phantom, "Phantom %p could not register port "
- "%d: %s\n", phantom, i, strerror ( rc ) );
- goto err_register_netdev;
- }
+ if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
+ DBGC ( phantom, "Phantom %p could not register net device: "
+ "%s\n", phantom, strerror ( rc ) );
+ goto err_register_netdev;
+ }
+
+ /* Register settings blocks */
+ parent_settings = netdev_settings ( netdev );
+ if ( ( rc = register_settings ( &phantom->settings,
+ parent_settings ) ) != 0 ) {
+ DBGC ( phantom, "Phantom %p could not register settings: "
+ "%s\n", phantom, strerror ( rc ) );
+ goto err_register_settings;
}
return 0;
- i = ( phantom->num_ports - 1 );
+ unregister_settings ( &phantom->settings );
+ err_register_settings:
+ unregister_netdev ( netdev );
err_register_netdev:
- for ( ; i >= 0 ; i-- )
- unregister_netdev ( phantom->netdev[i] );
+ err_check_boot_enable:
err_init_rcvpeg:
err_init_cmdpeg:
- free_dma ( phantom->dma_buf, sizeof ( *(phantom->dma_buf) ) );
- phantom->dma_buf = NULL;
- err_dma_buf:
- i = ( phantom->num_ports - 1 );
- err_alloc_etherdev:
- for ( ; i >= 0 ; i-- ) {
- netdev_nullify ( phantom->netdev[i] );
- netdev_put ( phantom->netdev[i] );
- }
- err_read_flash:
err_map_crb:
- free ( phantom );
- err_alloc_phantom:
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+ err_alloc_etherdev:
return rc;
}
@@ -1937,18 +2089,13 @@ static int phantom_probe ( struct pci_device *pci,
* @v pci PCI device
*/
static void phantom_remove ( struct pci_device *pci ) {
- struct phantom_nic *phantom = pci_get_drvdata ( pci );
- int i;
+ struct net_device *netdev = pci_get_drvdata ( pci );
+ struct phantom_nic *phantom = netdev_priv ( netdev );
- for ( i = ( phantom->num_ports - 1 ) ; i >= 0 ; i-- )
- unregister_netdev ( phantom->netdev[i] );
- free_dma ( phantom->dma_buf, sizeof ( *(phantom->dma_buf) ) );
- phantom->dma_buf = NULL;
- for ( i = ( phantom->num_ports - 1 ) ; i >= 0 ; i-- ) {
- netdev_nullify ( phantom->netdev[i] );
- netdev_put ( phantom->netdev[i] );
- }
- free ( phantom );
+ unregister_settings ( &phantom->settings );
+ unregister_netdev ( netdev );
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
}
/** Phantom PCI IDs */
diff --git a/gpxe/src/drivers/net/phantom/phantom.h b/gpxe/src/drivers/net/phantom/phantom.h
index 110c1226..974eecae 100644
--- a/gpxe/src/drivers/net/phantom/phantom.h
+++ b/gpxe/src/drivers/net/phantom/phantom.h
@@ -45,18 +45,12 @@ typedef uint32_t nx_rcode_t;
#define NXHAL_VERSION 1
#include "nxhal_nic_interface.h"
-/** SPI controller maximum block size */
-#define UNM_SPI_BLKSIZE 4
-
/** DMA buffer alignment */
#define UNM_DMA_BUFFER_ALIGN 16
/** Mark structure as DMA-aligned */
#define __unm_dma_aligned __attribute__ (( aligned ( UNM_DMA_BUFFER_ALIGN ) ))
-/** Dummy DMA buffer size */
-#define UNM_DUMMY_DMA_SIZE 1024
-
/******************************************************************************
*
* Register definitions
@@ -76,14 +70,19 @@ typedef uint32_t nx_rcode_t;
* address by the phantom_crb_access_xxx() methods.
*/
enum unm_reg_blocks {
- UNM_CRB_BLK_PCIE,
- UNM_CRB_BLK_CAM,
- UNM_CRB_BLK_ROMUSB,
- UNM_CRB_BLK_TEST,
+ UNM_CRB_BLK_PCIE = 0x01,
+ UNM_CRB_BLK_CAM = 0x22,
+ UNM_CRB_BLK_ROMUSB = 0x33,
+ UNM_CRB_BLK_TEST = 0x02,
+ UNM_CRB_BLK_PEG_0 = 0x11,
+ UNM_CRB_BLK_PEG_1 = 0x12,
+ UNM_CRB_BLK_PEG_2 = 0x13,
+ UNM_CRB_BLK_PEG_3 = 0x14,
+ UNM_CRB_BLK_PEG_4 = 0x0f,
};
-#define UNM_CRB_BASE(blk) ( (blk) << 24 )
-#define UNM_CRB_BLK(reg) ( (reg) >> 24 )
-#define UNM_CRB_OFFSET(reg) ( (reg) & 0x00ffffff )
+#define UNM_CRB_BASE(blk) ( (blk) << 20 )
+#define UNM_CRB_BLK(reg) ( (reg) >> 20 )
+#define UNM_CRB_OFFSET(reg) ( (reg) & 0x000fffff )
#define UNM_CRB_PCIE UNM_CRB_BASE ( UNM_CRB_BLK_PCIE )
#define UNM_PCIE_SEM2_LOCK ( UNM_CRB_PCIE + 0x1c010 )
@@ -101,6 +100,16 @@ enum unm_reg_blocks {
#define UNM_CAM_RAM_DMESG_SIG(n) ( UNM_CAM_RAM + 0x0003c + (n) * 0x10 )
#define UNM_CAM_RAM_DMESG_SIG_MAGIC 0xcafebabeUL
#define UNM_CAM_RAM_NUM_DMESG_BUFFERS 5
+#define UNM_CAM_RAM_CLP_COMMAND ( UNM_CAM_RAM + 0x000c0 )
+#define UNM_CAM_RAM_CLP_COMMAND_LAST 0x00000080UL
+#define UNM_CAM_RAM_CLP_DATA_LO ( UNM_CAM_RAM + 0x000c4 )
+#define UNM_CAM_RAM_CLP_DATA_HI ( UNM_CAM_RAM + 0x000c8 )
+#define UNM_CAM_RAM_CLP_STATUS ( UNM_CAM_RAM + 0x000cc )
+#define UNM_CAM_RAM_CLP_STATUS_START 0x00000001UL
+#define UNM_CAM_RAM_CLP_STATUS_DONE 0x00000002UL
+#define UNM_CAM_RAM_CLP_STATUS_ERROR 0x0000ff00UL
+#define UNM_CAM_RAM_CLP_STATUS_UNINITIALISED 0xffffffffUL
+#define UNM_CAM_RAM_BOOT_ENABLE ( UNM_CAM_RAM + 0x000fc )
#define UNM_CAM_RAM_WOL_PORT_MODE ( UNM_CAM_RAM + 0x00198 )
#define UNM_CAM_RAM_MAC_ADDRS ( UNM_CAM_RAM + 0x001c0 )
#define UNM_CAM_RAM_COLD_BOOT ( UNM_CAM_RAM + 0x001fc )
@@ -160,114 +169,24 @@ enum unm_reg_blocks {
#define UNM_TEST_RDDATA_LO ( UNM_CRB_TEST + 0x000a8 )
#define UNM_TEST_RDDATA_HI ( UNM_CRB_TEST + 0x000ac )
-/******************************************************************************
- *
- * Flash layout
- *
- */
-
-/* Board configuration */
-
-#define UNM_BRDCFG_START 0x4000
-
-struct unm_board_info {
- uint32_t header_version;
- uint32_t board_mfg;
- uint32_t board_type;
- uint32_t board_num;
- uint32_t chip_id;
- uint32_t chip_minor;
- uint32_t chip_major;
- uint32_t chip_pkg;
- uint32_t chip_lot;
- uint32_t port_mask;
- uint32_t peg_mask;
- uint32_t icache_ok;
- uint32_t dcache_ok;
- uint32_t casper_ok;
- uint32_t mac_addr_lo_0;
- uint32_t mac_addr_lo_1;
- uint32_t mac_addr_lo_2;
- uint32_t mac_addr_lo_3;
- uint32_t mn_sync_mode;
- uint32_t mn_sync_shift_cclk;
- uint32_t mn_sync_shift_mclk;
- uint32_t mn_wb_en;
- uint32_t mn_crystal_freq;
- uint32_t mn_speed;
- uint32_t mn_org;
- uint32_t mn_depth;
- uint32_t mn_ranks_0;
- uint32_t mn_ranks_1;
- uint32_t mn_rd_latency_0;
- uint32_t mn_rd_latency_1;
- uint32_t mn_rd_latency_2;
- uint32_t mn_rd_latency_3;
- uint32_t mn_rd_latency_4;
- uint32_t mn_rd_latency_5;
- uint32_t mn_rd_latency_6;
- uint32_t mn_rd_latency_7;
- uint32_t mn_rd_latency_8;
- uint32_t mn_dll_val[18];
- uint32_t mn_mode_reg;
- uint32_t mn_ext_mode_reg;
- uint32_t mn_timing_0;
- uint32_t mn_timing_1;
- uint32_t mn_timing_2;
- uint32_t sn_sync_mode;
- uint32_t sn_pt_mode;
- uint32_t sn_ecc_en;
- uint32_t sn_wb_en;
- uint32_t sn_crystal_freq;
- uint32_t sn_speed;
- uint32_t sn_org;
- uint32_t sn_depth;
- uint32_t sn_dll_tap;
- uint32_t sn_rd_latency;
- uint32_t mac_addr_hi_0;
- uint32_t mac_addr_hi_1;
- uint32_t mac_addr_hi_2;
- uint32_t mac_addr_hi_3;
- uint32_t magic;
- uint32_t mn_rdimm;
- uint32_t mn_dll_override;
-};
-
-#define UNM_BDINFO_VERSION 1
-#define UNM_BRDTYPE_P3_HMEZ 0x0022
-#define UNM_BRDTYPE_P3_10G_CX4_LP 0x0023
-#define UNM_BRDTYPE_P3_4_GB 0x0024
-#define UNM_BRDTYPE_P3_IMEZ 0x0025
-#define UNM_BRDTYPE_P3_10G_SFP_PLUS 0x0026
-#define UNM_BRDTYPE_P3_10000_BASE_T 0x0027
-#define UNM_BRDTYPE_P3_XG_LOM 0x0028
-#define UNM_BRDTYPE_P3_4_GB_MM 0x0029
-#define UNM_BRDTYPE_P3_10G_CX4 0x0031
-#define UNM_BRDTYPE_P3_10G_XFP 0x0032
-#define UNM_BDINFO_MAGIC 0x12345678
+#define UNM_CRB_PEG_0 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_0 )
+#define UNM_PEG_0_HALT_STATUS ( UNM_CRB_PEG_0 + 0x00030 )
+#define UNM_PEG_0_HALT ( UNM_CRB_PEG_0 + 0x0003c )
-/* User defined region */
+#define UNM_CRB_PEG_1 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_1 )
+#define UNM_PEG_1_HALT_STATUS ( UNM_CRB_PEG_1 + 0x00030 )
+#define UNM_PEG_1_HALT ( UNM_CRB_PEG_1 + 0x0003c )
-#define UNM_USER_START 0x3e8000
+#define UNM_CRB_PEG_2 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_2 )
+#define UNM_PEG_2_HALT_STATUS ( UNM_CRB_PEG_2 + 0x00030 )
+#define UNM_PEG_2_HALT ( UNM_CRB_PEG_2 + 0x0003c )
-#define UNM_FLASH_NUM_PORTS 4
-#define UNM_FLASH_NUM_MAC_PER_PORT 32
+#define UNM_CRB_PEG_3 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_3 )
+#define UNM_PEG_3_HALT_STATUS ( UNM_CRB_PEG_3 + 0x00030 )
+#define UNM_PEG_3_HALT ( UNM_CRB_PEG_3 + 0x0003c )
-struct unm_user_info {
- uint8_t flash_md5[16 * 64];
- uint32_t bootld_version;
- uint32_t bootld_size;
- uint32_t image_version;
- uint32_t image_size;
- uint32_t primary_status;
- uint32_t secondary_present;
- /* MAC address , 4 ports, 32 address per port */
- uint64_t mac_addr[UNM_FLASH_NUM_PORTS * UNM_FLASH_NUM_MAC_PER_PORT];
- uint32_t sub_sys_id;
- uint8_t serial_num[32];
- uint32_t bios_version;
- uint32_t pxe_enable;
- uint32_t vlan_tag[UNM_FLASH_NUM_PORTS];
-};
+#define UNM_CRB_PEG_4 UNM_CRB_BASE ( UNM_CRB_BLK_PEG_4 )
+#define UNM_PEG_4_HALT_STATUS ( UNM_CRB_PEG_4 + 0x00030 )
+#define UNM_PEG_4_HALT ( UNM_CRB_PEG_4 + 0x0003c )
#endif /* _PHANTOM_H */
diff --git a/gpxe/src/drivers/net/pnic.c b/gpxe/src/drivers/net/pnic.c
index c7f08670..3a4af967 100644
--- a/gpxe/src/drivers/net/pnic.c
+++ b/gpxe/src/drivers/net/pnic.c
@@ -14,7 +14,7 @@ Bochs Pseudo NIC driver for Etherboot
#include <stdint.h>
#include <stdio.h>
-#include <io.h>
+#include <gpxe/io.h>
#include <errno.h>
#include <gpxe/pci.h>
#include <gpxe/if_ether.h>
diff --git a/gpxe/src/drivers/net/prism2.c b/gpxe/src/drivers/net/prism2.c
index aaf4c968..c54dba5d 100644
--- a/gpxe/src/drivers/net/prism2.c
+++ b/gpxe/src/drivers/net/prism2.c
@@ -118,7 +118,7 @@ static const char hardcoded_ssid[] = "";
typedef struct hfa384x
{
UINT32 iobase;
- UINT32 membase;
+ void *membase;
UINT16 lastcmd;
UINT16 status; /* in host order */
UINT16 resp0; /* in host order */
diff --git a/gpxe/src/drivers/net/prism2_pci.c b/gpxe/src/drivers/net/prism2_pci.c
index 63cc22e3..eda7bf50 100644
--- a/gpxe/src/drivers/net/prism2_pci.c
+++ b/gpxe/src/drivers/net/prism2_pci.c
@@ -22,14 +22,11 @@ $Id$
static int prism2_pci_probe ( struct nic *nic, struct pci_device *pci ) {
hfa384x_t *hw = &hw_global;
- uint32_t membase = 0; /* Prism2.5 Memory Base */
- pci_read_config_dword( pci, PRISM2_PCI_MEM_BASE, &membase);
- membase &= PCI_BASE_ADDRESS_MEM_MASK;
- hw->membase = (uint32_t) phys_to_virt(membase);
- printf ( "Prism2.5 has registers at %#lx\n", hw->membase );
+ printf ( "Prism2.5 has registers at %#lx\n", pci->membase );
+ hw->membase = ioremap ( pci->membase, 0x100 );
- nic->ioaddr = hw->membase;
+ nic->ioaddr = pci->membase;
nic->irqno = 0;
return prism2_probe ( nic, hw );
diff --git a/gpxe/src/drivers/net/prism2_plx.c b/gpxe/src/drivers/net/prism2_plx.c
index 150bbe69..a10eef29 100644
--- a/gpxe/src/drivers/net/prism2_plx.c
+++ b/gpxe/src/drivers/net/prism2_plx.c
@@ -48,10 +48,9 @@ static int prism2_find_plx ( hfa384x_t *hw, struct pci_device *p )
iobase &= PCI_BASE_ADDRESS_IO_MASK;
/* Fill out hw structure */
- hw->membase = attr_mem;
hw->iobase = iobase;
- printf ( "PLX9052 has local config registers at %#lx\n", plx_lcr );
- printf ( "Prism2 has attribute memory at %#lx and I/O base at %#lx\n", attr_mem, iobase );
+ printf ( "PLX9052 has local config registers at %#x\n", plx_lcr );
+ printf ( "Prism2 has attribute memory at %#x and I/O base at %#x\n", attr_mem, iobase );
/* Search for CIS strings */
printf ( "Searching for PCMCIA card...\n" );
diff --git a/gpxe/src/drivers/net/r8169.c b/gpxe/src/drivers/net/r8169.c
index 885f054a..4315f47a 100644
--- a/gpxe/src/drivers/net/r8169.c
+++ b/gpxe/src/drivers/net/r8169.c
@@ -1,1159 +1,434 @@
-/**************************************************************************
-* r8169.c: Etherboot device driver for the RealTek RTL-8169 Gigabit
-* Written 2003 by Timothy Legge <tlegge@rogers.com>
-*
-* This program is free software; you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation; either version 2 of the License, or
-* (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program; if not, write to the Free Software
-* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*
-* Portions of this code based on:
-* r8169.c: A RealTek RTL-8169 Gigabit Ethernet driver
-* for Linux kernel 2.4.x.
-*
-* Written 2002 ShuChen <shuchen@realtek.com.tw>
-* See Linux Driver for full information
-*
-* Linux Driver Versions:
-* 1.27a, 10.02.2002
-* RTL8169_VERSION "2.2" <2004/08/09>
-*
-* Thanks to:
-* Jean Chen of RealTek Semiconductor Corp. for
-* providing the evaluation NIC used to develop
-* this driver. RealTek's support for Etherboot
-* is appreciated.
-*
-* REVISION HISTORY:
-* ================
-*
-* v1.0 11-26-2003 timlegge Initial port of Linux driver
-* v1.5 01-17-2004 timlegge Initial driver output cleanup
-* v1.6 03-27-2004 timlegge Additional Cleanup
-* v1.7 11-22-2005 timlegge Update to RealTek Driver Version 2.2
-*
-* 03-19-2008 Hilko Bengen Cleanups and fixes for newer cards
-* (successfully tested with 8110SC-d onboard NIC)
-*
-* Indent Options: indent -kr -i8
-***************************************************************************/
-
-#include "etherboot.h"
-#include "nic.h"
-#include <gpxe/pci.h>
+/*
+ * Copyright (c) 2008 Marty Connor <mdc@etherboot.org>
+ * Copyright (c) 2008 Entity Cyber, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver is based on rtl8169 data sheets and work by:
+ *
+ * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
+ * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
+ * Copyright (c) a lot of people too. Please respect their work.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <errno.h>
#include <gpxe/ethernet.h>
+#include <gpxe/if_ether.h>
+#include <gpxe/io.h>
+#include <gpxe/iobuf.h>
#include <gpxe/malloc.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/pci.h>
+#include <gpxe/timer.h>
-#define drv_version "v1.7+"
-#define drv_date "03-19-2008"
-
-#define HZ 1000
-
-static u32 ioaddr;
-
-/* Condensed operations for readability. */
-#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
-#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
-#undef RTL8169_DEBUG
-#undef RTL8169_JUMBO_FRAME_SUPPORT
-#undef RTL8169_HW_FLOW_CONTROL_SUPPORT
-
-
-#undef RTL8169_IOCTL_SUPPORT
-#undef RTL8169_DYNAMIC_CONTROL
-#define RTL8169_USE_IO
-
-#if 0
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
-#endif
-
-#if 0
-/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
- The RTL chips use a 64 element hash table based on the Ethernet CRC. */
-static int multicast_filter_limit = 32;
-#endif
-
-/* MAC address length*/
-#define MAC_ADDR_LEN 6
-
-/* max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4).*/
-#define MAX_ETH_FRAME_SIZE 1536
-
-#define TX_FIFO_THRESH 256 /* In bytes */
-
-#define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */
-#define RX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */
-#define TX_DMA_BURST 7 /* Maximum PCI burst, '6' is 1024 */
-#define ETTh 0x3F /* 0x3F means NO threshold */
-
-#define EarlyTxThld 0x3F /* 0x3F means NO early transmit */
-#define RxPacketMaxSize 0x0800 /* Maximum size supported is 16K-1 */
-#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
-
-#define NUM_TX_DESC 1 /* Number of Tx descriptor registers */
-#define NUM_RX_DESC 4 /* Number of Rx descriptor registers */
-#define RX_BUF_SIZE 1536 /* Rx Buffer size */
-
-#define RTL_MIN_IO_SIZE 0x80
-#define TX_TIMEOUT (6*HZ)
-
-#define RTL8169_TIMER_EXPIRE_TIME 100 //100
-
-#define ETH_HDR_LEN 14
-#define DEFAULT_MTU 1500
-#define DEFAULT_RX_BUF_LEN 1536
-
-
-#ifdef RTL8169_JUMBO_FRAME_SUPPORT
-#define MAX_JUMBO_FRAME_MTU ( 10000 )
-#define MAX_RX_SKBDATA_SIZE ( MAX_JUMBO_FRAME_MTU + ETH_HDR_LEN )
-#else
-#define MAX_RX_SKBDATA_SIZE 1600
-#endif //end #ifdef RTL8169_JUMBO_FRAME_SUPPORT
-
-#ifdef RTL8169_USE_IO
-#define RTL_W8(reg, val8) outb ((val8), ioaddr + (reg))
-#define RTL_W16(reg, val16) outw ((val16), ioaddr + (reg))
-#define RTL_W32(reg, val32) outl ((val32), ioaddr + (reg))
-#define RTL_R8(reg) inb (ioaddr + (reg))
-#define RTL_R16(reg) inw (ioaddr + (reg))
-#define RTL_R32(reg) ((unsigned long) inl (ioaddr + (reg)))
-#else
-/* write/read MMIO register */
-#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))
-#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg))
-#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg))
-#define RTL_R8(reg) readb (ioaddr + (reg))
-#define RTL_R16(reg) readw (ioaddr + (reg))
-#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg)))
-#endif
-
-enum mac_version {
- RTL_GIGA_MAC_VER_01 = 0x01, // 8169
- RTL_GIGA_MAC_VER_02 = 0x02, // 8169S
- RTL_GIGA_MAC_VER_03 = 0x03, // 8110S
- RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB
- RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd
- RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe
- RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb
- RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be
- RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb
- RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 ?
- RTL_GIGA_MAC_VER_15 = 0x0f, // 8101 ?
- RTL_GIGA_MAC_VER_16 = 0x11, // 8101Ec
- RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf
- RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP
- RTL_GIGA_MAC_VER_19 = 0x13, // 8168C
- RTL_GIGA_MAC_VER_20 = 0x14 // 8168C
-};
-
-enum cfg_version {
- RTL_CFG_0 = 0x00,
- RTL_CFG_1,
- RTL_CFG_2
-};
-
-static struct {
- const char *name;
- u8 mac_version; /* depend on RTL8169 docs */
- u32 RxConfigMask; /* should clear the bits supported by this chip */
-} rtl_chip_info[] = {
- {"RTL8169", RTL_GIGA_MAC_VER_01, 0xff7e1880}, // 8169
- {"RTL8169s", RTL_GIGA_MAC_VER_02, 0xff7e1880}, // 8169S
- {"RTL8110s", RTL_GIGA_MAC_VER_03, 0xff7e1880}, // 8110S
- {"RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880}, // 8169SB
- {"RTL8169sc/8110sc-d",RTL_GIGA_MAC_VER_05, 0xff7e1880}, // 8110SCd
- {"RTL8169sc/8110sc-e",RTL_GIGA_MAC_VER_06, 0xff7e1880}, // 8110SCe
- {"RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880}, // PCI-E
- {"RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880}, // PCI-E
- {"RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880}, // PCI-E 8139
- {"RTL8100e", RTL_GIGA_MAC_VER_14, 0xff7e1880}, // PCI-E 8139
- {"RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880}, // PCI-E 8139
- {"RTL8168b/8111b", RTL_GIGA_MAC_VER_17, 0xff7e1880}, // PCI-E
- {"RTL8101e", RTL_GIGA_MAC_VER_16, 0xff7e1880}, // PCI-E
- {"RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, 0xff7e1880}, // PCI-E
- {"RTL8168c/8111c", RTL_GIGA_MAC_VER_19, 0xff7e1880}, // PCI-E
- {"RTL8168c/8111c", RTL_GIGA_MAC_VER_20, 0xff7e1880}, // PCI-E
-};
-
-enum RTL8169_registers {
- MAC0 = 0x0, /* Ethernet hardware address. */
- MAR0 = 0x8, /* Multicast filter. */
- TxDescAddrLow = 0x20,
- TxDescAddrHigh = 0x24,
- TxHDescStartAddr = 0x28,
- FLASH = 0x30,
- ERSR = 0x36,
- ChipCmd = 0x37,
- TxPoll = 0x38,
- IntrMask = 0x3C,
- IntrStatus = 0x3E,
- TxConfig = 0x40,
- RxConfig = 0x44,
- RxMissed = 0x4C,
- Cfg9346 = 0x50,
- Config0 = 0x51,
- Config1 = 0x52,
- Config2 = 0x53,
- Config3 = 0x54,
- Config4 = 0x55,
- Config5 = 0x56,
- MultiIntr = 0x5C,
- PHYAR = 0x60,
- TBICSR = 0x64,
- TBI_ANAR = 0x68,
- TBI_LPAR = 0x6A,
- PHYstatus = 0x6C,
- RxMaxSize = 0xda,
- CPlusCmd = 0xe0,
- IntrMitigate = 0xe2,
- RxDescAddrLow = 0xe4,
- RxDescAddrHigh = 0xe8,
- ETThReg = 0xEC,
- FuncEvent = 0xF0,
- FuncEventMask = 0xF4,
- FuncPresetState = 0xF8,
- FuncForceEvent = 0xFC,
-};
-
-enum RTL8169_register_content {
- /*InterruptStatusBits */
- SYSErr = 0x8000,
- PCSTimeout = 0x4000,
- SWInt = 0x0100,
- TxDescUnavail = 0x80,
- RxFIFOOver = 0x40,
- LinkChg = 0x20,
- RxOverflow = 0x10,
- TxErr = 0x08,
- TxOK = 0x04,
- RxErr = 0x02,
- RxOK = 0x01,
-
- /*RxStatusDesc */
- RxRES = 0x00200000,
- RxCRC = 0x00080000,
- RxRUNT = 0x00100000,
- RxRWT = 0x00400000,
-
- /*ChipCmdBits */
- CmdReset = 0x10,
- CmdRxEnb = 0x08,
- CmdTxEnb = 0x04,
- RxBufEmpty = 0x01,
-
- /*Cfg9346Bits */
- Cfg9346_Lock = 0x00,
- Cfg9346_Unlock = 0xC0,
-
- /*rx_mode_bits */
- AcceptErr = 0x20,
- AcceptRunt = 0x10,
- AcceptBroadcast = 0x08,
- AcceptMulticast = 0x04,
- AcceptMyPhys = 0x02,
- AcceptAllPhys = 0x01,
-
- /*RxConfigBits */
- RxCfgFIFOShift = 13,
- RxCfgDMAShift = 8,
-
- /*TxConfigBits */
- TxInterFrameGapShift = 24,
- TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
-
- /*rtl8169_PHYstatus */
- TBI_Enable = 0x80,
- TxFlowCtrl = 0x40,
- RxFlowCtrl = 0x20,
- _1000bpsF = 0x10,
- _100bps = 0x08,
- _10bps = 0x04,
- LinkStatus = 0x02,
- FullDup = 0x01,
-
- /*GIGABIT_PHY_registers */
- PHY_CTRL_REG = 0,
- PHY_STAT_REG = 1,
- PHY_AUTO_NEGO_REG = 4,
- PHY_1000_CTRL_REG = 9,
-
- /*GIGABIT_PHY_REG_BIT */
- PHY_Restart_Auto_Nego = 0x0200,
- PHY_Enable_Auto_Nego = 0x1000,
-
- /* PHY_STAT_REG = 1; */
- PHY_Auto_Neco_Comp = 0x0020,
-
- /* PHY_AUTO_NEGO_REG = 4; */
- PHY_Cap_10_Half = 0x0020,
- PHY_Cap_10_Full = 0x0040,
- PHY_Cap_100_Half = 0x0080,
- PHY_Cap_100_Full = 0x0100,
-
- /* PHY_1000_CTRL_REG = 9; */
- PHY_Cap_1000_Full = 0x0200,
- PHY_Cap_1000_Half = 0x0100,
-
- PHY_Cap_PAUSE = 0x0400,
- PHY_Cap_ASYM_PAUSE = 0x0800,
-
- PHY_Cap_Null = 0x0,
-
- /*_MediaType*/
- _10_Half = 0x01,
- _10_Full = 0x02,
- _100_Half = 0x04,
- _100_Full = 0x08,
- _1000_Full = 0x10,
-
- /*_TBICSRBit*/
- TBILinkOK = 0x02000000,
-};
-
-enum _DescStatusBit {
- OWNbit = 0x80000000,
- EORbit = 0x40000000,
- FSbit = 0x20000000,
- LSbit = 0x10000000,
-};
-
-struct TxDesc {
- u32 status;
- u32 vlan_tag;
- u32 buf_addr;
- u32 buf_Haddr;
-};
-
-struct RxDesc {
- u32 status;
- u32 vlan_tag;
- u32 buf_addr;
- u32 buf_Haddr;
-};
+#include "r8169.h"
-/* The descriptors for this card are required to be aligned on 256
- * byte boundaries. As the align attribute does not do more than 16
- * bytes of alignment it requires some extra steps. Add 256 to the
- * size of the array and the init_ring adjusts the alignment.
- *
- * UPDATE: This is no longer true; we can request arbitrary alignment.
- */
+/*** Low level hardware routines ***/
-/* Define the TX and RX Descriptors and Buffers */
-#define __align_256 __attribute__ (( aligned ( 256 ) ))
-struct {
- struct TxDesc tx_ring[NUM_TX_DESC] __align_256;
- unsigned char txb[NUM_TX_DESC * RX_BUF_SIZE];
- struct RxDesc rx_ring[NUM_RX_DESC] __align_256;
- unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE];
-} *r8169_bufs;
-#define tx_ring r8169_bufs->tx_ring
-#define rx_ring r8169_bufs->rx_ring
-#define txb r8169_bufs->txb
-#define rxb r8169_bufs->rxb
-
-static struct rtl8169_private {
- void *mmio_addr; /* memory map physical address */
- int chipset;
- int pcfg;
- int mac_version;
- unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
- unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
- struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */
- struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */
- unsigned char *RxBufferRing[NUM_RX_DESC]; /* Index of Rx Buffer array */
- unsigned char *Tx_skbuff[NUM_TX_DESC];
-} tpx;
-
-static const u16 rtl8169_intr_mask =
- LinkChg | RxOverflow | RxFIFOOver | TxErr | TxOK | RxErr | RxOK;
-static const unsigned int rtl8169_rx_config =
- (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift) |
- 0x0000000E;
-
-static void rtl8169_hw_phy_config(struct nic *nic __unused);
-//static void rtl8169_hw_phy_reset(struct net_device *dev);
-
-#define RTL8169_WRITE_GMII_REG_BIT( ioaddr, reg, bitnum, bitval )\
-{ \
- int val; \
- if( bitval == 1 ){ val = ( RTL8169_READ_GMII_REG( ioaddr, reg ) | (bitval<<bitnum) ) & 0xffff ; } \
- else{ val = ( RTL8169_READ_GMII_REG( ioaddr, reg ) & (~(0x0001<<bitnum)) ) & 0xffff ; } \
- RTL8169_WRITE_GMII_REG( ioaddr, reg, val ); \
- }
-
-//=================================================================
-// PHYAR
-// bit Symbol
-// 31 Flag
-// 30-21 reserved
-// 20-16 5-bit GMII/MII register address
-// 15-0 16-bit GMII/MII register data
-//=================================================================
-static void RTL8169_WRITE_GMII_REG(unsigned long ioaddr, int RegAddr, int value)
+static void mdio_write(void *ioaddr, int reg_addr, int value)
{
int i;
- RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value);
- udelay(1000);
+ DBGP ( "mdio_write\n" );
- for (i = 2000; i > 0; i--) {
- // Check if the RTL8169 has completed writing to the specified MII register
- if (!(RTL_R32(PHYAR) & 0x80000000)) {
+ RTL_W32(PHYAR, 0x80000000 | (reg_addr & 0x1f) << 16 | (value & 0xffff));
+
+ for (i = 20; i > 0; i--) {
+ /*
+ * Check if the RTL8169 has completed writing to the specified
+ * MII register.
+ */
+ if (!(RTL_R32(PHYAR) & 0x80000000))
break;
- } else {
- udelay(100);
- } // end of if( ! (RTL_R32(PHYAR)&0x80000000) )
- } // end of for() loop
+ udelay(25);
+ }
}
-//=================================================================
-static int RTL8169_READ_GMII_REG(unsigned long ioaddr, int RegAddr)
+static int mdio_read(void *ioaddr, int reg_addr)
{
int i, value = -1;
- RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16);
- udelay(1000);
+ DBGP ( "mdio_read\n" );
+
+ RTL_W32(PHYAR, 0x0 | (reg_addr & 0x1f) << 16);
- for (i = 2000; i > 0; i--) {
- // Check if the RTL8169 has completed retrieving data from the specified MII register
+ for (i = 20; i > 0; i--) {
+ /*
+ * Check if the RTL8169 has completed retrieving data from
+ * the specified MII register.
+ */
if (RTL_R32(PHYAR) & 0x80000000) {
- value = (int) (RTL_R32(PHYAR) & 0xFFFF);
+ value = RTL_R32(PHYAR) & 0xffff;
break;
- } else {
- udelay(100);
- } // end of if( RTL_R32(PHYAR) & 0x80000000 )
- } // end of for() loop
+ }
+ udelay(25);
+ }
return value;
}
+static void mdio_patch(void *ioaddr, int reg_addr, int value)
+{
+ DBGP ( "mdio_patch\n" );
+
+ mdio_write(ioaddr, reg_addr, mdio_read(ioaddr, reg_addr) | value);
+}
-#if 0
-static void mdio_write(int RegAddr, int value)
+static void rtl_ephy_write(void *ioaddr, int reg_addr, int value)
{
- int i;
+ unsigned int i;
+
+ DBGP ( "rtl_ephy_write\n" );
- RTL_W32(PHYAR, 0x80000000 | (RegAddr & 0xFF) << 16 | value);
- udelay(1000);
+ RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) |
+ (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
- for (i = 2000; i > 0; i--) {
- /* Check if the RTL8169 has completed writing to the specified MII register */
- if (!(RTL_R32(PHYAR) & 0x80000000)) {
+ for (i = 0; i < 100; i++) {
+ if (!(RTL_R32(EPHYAR) & EPHYAR_FLAG))
break;
- } else {
- udelay(100);
- }
+ udelay(10);
}
}
-static int mdio_read(int RegAddr)
+static u16 rtl_ephy_read(void *ioaddr, int reg_addr)
{
- int i, value = -1;
+ u16 value = 0xffff;
+ unsigned int i;
- RTL_W32(PHYAR, 0x0 | (RegAddr & 0xFF) << 16);
- udelay(1000);
+ DBGP ( "rtl_ephy_read\n" );
- for (i = 2000; i > 0; i--) {
- /* Check if the RTL8169 has completed retrieving data from the specified MII register */
- if (RTL_R32(PHYAR) & 0x80000000) {
- value = (int) (RTL_R32(PHYAR) & 0xFFFF);
+ RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT);
+
+ for (i = 0; i < 100; i++) {
+ if (RTL_R32(EPHYAR) & EPHYAR_FLAG) {
+ value = RTL_R32(EPHYAR) & EPHYAR_DATA_MASK;
break;
- } else {
- udelay(100);
}
+ udelay(10);
}
+
return value;
}
-#endif
-static void rtl8169_get_mac_version( struct rtl8169_private *tp,
- u32 ioaddr )
+static void rtl_csi_write(void *ioaddr, int addr, int value)
{
- /*
- * The driver currently handles the 8168Bf and the 8168Be identically
- * but they can be identified more specifically through the test below
- * if needed:
- *
- * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be
- *
- * Same thing for the 8101Eb and the 8101Ec:
- *
- * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
- */
- const struct {
- u32 mask;
- u32 val;
- int mac_version;
- } mac_info[] = {
- /* 8168B family. */
- { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_18 },
- { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 },
- { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 },
- { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_20 },
- /* 8168B family. */
- { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 },
- { 0x7cf00000, 0x38500000, RTL_GIGA_MAC_VER_17 },
- { 0x7c800000, 0x38000000, RTL_GIGA_MAC_VER_17 },
- { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 },
- /* 8101 family. */
- { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 },
- { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 },
- { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 },
- /* FIXME: where did these entries come from ? -- FR */
- { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 },
- { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 },
- /* 8110 family. */
- { 0xfc800000, 0x98000000, RTL_GIGA_MAC_VER_06 },
- { 0xfc800000, 0x18000000, RTL_GIGA_MAC_VER_05 },
- { 0xfc800000, 0x10000000, RTL_GIGA_MAC_VER_04 },
- { 0xfc800000, 0x04000000, RTL_GIGA_MAC_VER_03 },
- { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 },
- { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 },
- { 0x00000000, 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */
- }, *p = mac_info;
+ unsigned int i;
- unsigned long rv;
+ DBGP ( "rtl_csi_write\n" );
- rv = (RTL_R32(TxConfig));
+ RTL_W32(CSIDR, value);
+ RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) |
+ CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
- while ((rv & p->mask) != p->val)
- p++;
- tp->mac_version = p->mac_version;
-
- if (p->mask == 0x00000000) {
- DBG("unknown MAC (%08lx)\n", rv);
+ for (i = 0; i < 100; i++) {
+ if (!(RTL_R32(CSIAR) & CSIAR_FLAG))
+ break;
+ udelay(10);
}
}
-#define IORESOURCE_MEM 0x00000200
-
-static int rtl8169_init_board(struct pci_device *pdev)
+static u32 rtl_csi_read(void *ioaddr, int addr)
{
- int i;
-// unsigned long mmio_end, mmio_flags
- unsigned long mmio_start, mmio_len;
- struct rtl8169_private *tp = &tpx;
-
- adjust_pci_device(pdev);
-
- mmio_start = pci_bar_start(pdev, PCI_BASE_ADDRESS_1);
-// mmio_end = pci_resource_end (pdev, 1);
-// mmio_flags = pci_resource_flags (pdev, PCI_BASE_ADDRESS_1);
- mmio_len = pci_bar_size(pdev, PCI_BASE_ADDRESS_1);
-
- // make sure PCI base addr 1 is MMIO
-// if (!(mmio_flags & IORESOURCE_MEM)) {
-// printf ("region #1 not an MMIO resource, aborting\n");
-// return 0;
-// }
-
- // check for weird/broken PCI region reporting
- if (mmio_len < RTL_MIN_IO_SIZE) {
- printf("Invalid PCI region size(s), aborting\n");
- return 0;
- }
-#ifdef RTL8169_USE_IO
- ioaddr = pci_bar_start(pdev, PCI_BASE_ADDRESS_0);
-#else
- // ioremap MMIO region
- ioaddr = (unsigned long) ioremap(mmio_start, mmio_len);
- if (ioaddr == 0) {
- printk("cannot remap MMIO, aborting\n");
- return 0;
- }
-#endif
+ u32 value = ~0x00;
+ unsigned int i;
- tp->mmio_addr = (void*)ioaddr;
- /* Soft reset the chip. */
- RTL_W8(ChipCmd, CmdReset);
+ DBGP ( "rtl_csi_read\n" );
- /* Check that the chip has finished the reset. */
- for (i = 1000; i > 0; i--)
- if ((RTL_R8(ChipCmd) & CmdReset) == 0)
- break;
- else
- udelay(10);
+ RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) |
+ CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT);
- /* Identify chip attached to board */
- rtl8169_get_mac_version( tp, ioaddr );
-
- // rtl8169_print_mac_version(tp);
-
- {
- unsigned char val8 =
- (unsigned char) (RTL8169_READ_GMII_REG(ioaddr, 3) &
- 0x000f);
- if (val8 == 0x00) {
- tp->pcfg = RTL_CFG_0;
- } else if (val8 == 0x01) {
- tp->pcfg = RTL_CFG_1;
- } else if (val8 == 0x02) {
- tp->pcfg = RTL_CFG_2;
- } else {
- tp->pcfg = RTL_CFG_2;
+ for (i = 0; i < 100; i++) {
+ if (RTL_R32(CSIAR) & CSIAR_FLAG) {
+ value = RTL_R32(CSIDR);
+ break;
}
+ udelay(10);
}
- /* identify chip attached to board */
-
- for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--)
- if (tp->mac_version == rtl_chip_info[i].mac_version) {
- tp->chipset = i;
- goto match;
- }
- /* if unknown chip, assume array element #0, original RTL-8169 in this case */
- DBG ( "PCI device: unknown chip version, assuming RTL-8169\n" );
- DBG ( "PCI device: TxConfig = %#lX\n", ( unsigned long ) RTL_R32 ( TxConfig ) );
+ return value;
+}
- tp->chipset = 0;
- return 1;
+static void rtl8169_irq_mask_and_ack(void *ioaddr)
+{
+ DBGP ( "rtl8169_irq_mask_and_ack\n" );
- match:
- return 0;
+ RTL_W16(IntrMask, 0x0000);
+ RTL_W16(IntrStatus, 0xffff);
}
-/**************************************************************************
-IRQ - Wait for a frame
-***************************************************************************/
-static void r8169_irq(struct nic *nic __unused, irq_action_t action)
+static unsigned int rtl8169_tbi_reset_pending(void *ioaddr)
{
- int intr_status = 0;
- int interested = RxOverflow | RxFIFOOver | RxErr | RxOK;
+ DBGP ( "rtl8169_tbi_reset_pending\n" );
- switch (action) {
- case DISABLE:
- case ENABLE:
- intr_status = RTL_R16(IntrStatus);
- /* h/w no longer present (hotplug?) or major error,
- bail */
- if (intr_status == 0xFFFF)
- break;
-
- intr_status = intr_status & ~interested;
- if (action == ENABLE)
- intr_status = intr_status | interested;
- RTL_W16(IntrMask, intr_status);
- break;
- case FORCE:
- RTL_W8(TxPoll, (RTL_R8(TxPoll) | 0x01));
- break;
- }
+ return RTL_R32(TBICSR) & TBIReset;
}
-/**************************************************************************
-POLL - Wait for a frame
-***************************************************************************/
-static int r8169_poll(struct nic *nic, int retrieve)
-{
- /* return true if there's an ethernet packet ready to read */
- /* nic->packet should contain data on return */
- /* nic->packetlen should contain length of data */
- int cur_rx;
- unsigned int intr_status = 0;
- struct rtl8169_private *tp = &tpx;
-
- cur_rx = tp->cur_rx;
- if ((tp->RxDescArray[cur_rx].status & OWNbit) == 0) {
- /* There is a packet ready */
- DBG("r8169_poll(): packet ready\n");
- if (!retrieve)
- return 1;
- intr_status = RTL_R16(IntrStatus);
- /* h/w no longer present (hotplug?) or major error,
- bail */
- if (intr_status == 0xFFFF) {
- DBG("r8169_poll(): unknown error\n");
- return 0;
- }
- RTL_W16(IntrStatus, intr_status &
- ~(RxFIFOOver | RxOverflow | RxOK));
-
- if (!(tp->RxDescArray[cur_rx].status & RxRES)) {
- nic->packetlen = (int) (tp->RxDescArray[cur_rx].
- status & 0x00001FFF) - 4;
- memcpy(nic->packet, tp->RxBufferRing[cur_rx],
- nic->packetlen);
- if (cur_rx == NUM_RX_DESC - 1)
- tp->RxDescArray[cur_rx].status =
- (OWNbit | EORbit) + RX_BUF_SIZE;
- else
- tp->RxDescArray[cur_rx].status =
- OWNbit + RX_BUF_SIZE;
- tp->RxDescArray[cur_rx].buf_addr =
- virt_to_bus(tp->RxBufferRing[cur_rx]);
- tp->RxDescArray[cur_rx].buf_Haddr = 0;
- } else
- printf("Error Rx");
- /* FIXME: shouldn't I reset the status on an error */
- cur_rx = (cur_rx + 1) % NUM_RX_DESC;
- tp->cur_rx = cur_rx;
- RTL_W16(IntrStatus, intr_status &
- (RxFIFOOver | RxOverflow | RxOK));
-
- return 1;
+static unsigned int rtl8169_xmii_reset_pending(void *ioaddr)
+{
+ DBGP ( "rtl8169_xmii_reset_pending\n" );
- }
- tp->cur_rx = cur_rx;
- /* FIXME: There is no reason to do this as cur_rx did not change */
-
- return (0); /* initially as this is called to flush the input */
-
-}
-
-/**************************************************************************
-TRANSMIT - Transmit a frame
-***************************************************************************/
-static void r8169_transmit(struct nic *nic, const char *d, /* Destination */
- unsigned int t, /* Type */
- unsigned int s, /* size */
- const char *p)
-{ /* Packet */
- /* send the packet to destination */
-
- u16 nstype;
- u32 to;
- u8 *ptxb;
- struct rtl8169_private *tp = &tpx;
- int entry = tp->cur_tx % NUM_TX_DESC;
-
- /* point to the current txb incase multiple tx_rings are used */
- ptxb = tp->Tx_skbuff[entry * MAX_ETH_FRAME_SIZE];
- memcpy(ptxb, d, ETH_ALEN);
- memcpy(ptxb + ETH_ALEN, nic->node_addr, ETH_ALEN);
- nstype = htons((u16) t);
- memcpy(ptxb + 2 * ETH_ALEN, (u8 *) & nstype, 2);
- memcpy(ptxb + ETH_HLEN, p, s);
- s += ETH_HLEN;
- s &= 0x0FFF;
- while (s < ETH_ZLEN)
- ptxb[s++] = '\0';
-
- tp->TxDescArray[entry].buf_addr = virt_to_bus(ptxb);
- tp->TxDescArray[entry].buf_Haddr = 0;
- if (entry != (NUM_TX_DESC - 1))
- tp->TxDescArray[entry].status =
- (OWNbit | FSbit | LSbit) | ((s > ETH_ZLEN) ? s :
- ETH_ZLEN);
- else
- tp->TxDescArray[entry].status =
- (OWNbit | EORbit | FSbit | LSbit) | ((s > ETH_ZLEN) ? s
- : ETH_ZLEN);
- RTL_W8(TxPoll, 0x40); /* set polling bit */
-
- tp->cur_tx++;
- to = currticks() + TX_TIMEOUT;
- while ((tp->TxDescArray[entry].status & OWNbit) && (currticks() < to)); /* wait */
-
- if (currticks() >= to) {
- printf("TX Time Out");
- }
+ return mdio_read(ioaddr, MII_BMCR) & BMCR_RESET;
}
-static void rtl8169_set_rx_mode(struct nic *nic __unused)
+static unsigned int rtl8169_tbi_link_ok(void *ioaddr)
{
- u32 mc_filter[2]; /* Multicast hash filter */
- int rx_mode;
- u32 tmp = 0;
- struct rtl8169_private *tp = &tpx;
+ DBGP ( "rtl8169_tbi_link_ok\n" );
- /* IFF_ALLMULTI */
- /* Too many to filter perfectly -- accept all multicasts. */
- rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
- mc_filter[1] = mc_filter[0] = 0xffffffff;
+ return RTL_R32(TBICSR) & TBILinkOk;
+}
- tmp =
- rtl8169_rx_config | rx_mode | (RTL_R32(RxConfig) &
- rtl_chip_info[tp->chipset].
- RxConfigMask);
+static unsigned int rtl8169_xmii_link_ok(void *ioaddr)
+{
+ DBGP ( "rtl8169_xmii_link_ok\n" );
- RTL_W32(RxConfig, tmp);
- RTL_W32(MAR0 + 0, mc_filter[0]);
- RTL_W32(MAR0 + 4, mc_filter[1]);
+ return RTL_R8(PHYstatus) & LinkStatus;
}
-static void rtl8169_hw_start(struct nic *nic)
+
+static void rtl8169_tbi_reset_enable(void *ioaddr)
{
- u32 i;
- struct rtl8169_private *tp = &tpx;
+ DBGP ( "rtl8169_tbi_reset_enable\n" );
- /* Soft reset the chip. */
- RTL_W8(ChipCmd, CmdReset);
+ RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset);
+}
- /* Check that the chip has finished the reset. */
- for (i = 1000; i > 0; i--) {
- if ((RTL_R8(ChipCmd) & CmdReset) == 0)
- break;
- else
- udelay(10);
- }
+static void rtl8169_xmii_reset_enable(void *ioaddr)
+{
+ unsigned int val;
- RTL_W8(Cfg9346, Cfg9346_Unlock);
- RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
- RTL_W8(ETThReg, ETTh);
+ DBGP ( "rtl8169_xmii_reset_enable\n" );
- /* For gigabit rtl8169 */
- RTL_W16(RxMaxSize, RxPacketMaxSize);
+ val = mdio_read(ioaddr, MII_BMCR) | BMCR_RESET;
+ mdio_write(ioaddr, MII_BMCR, val & 0xffff);
+}
- /* Set Rx Config register */
- i = rtl8169_rx_config | (RTL_R32(RxConfig) &
- rtl_chip_info[tp->chipset].RxConfigMask);
- RTL_W32(RxConfig, i);
+static int rtl8169_set_speed_tbi(struct net_device *dev,
+ u8 autoneg, u16 speed, u8 duplex)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void *ioaddr = tp->mmio_addr;
+ int ret = 0;
+ u32 reg;
+
+ DBGP ( "rtl8169_set_speed_tbi\n" );
+
+ reg = RTL_R32(TBICSR);
+ if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) &&
+ (duplex == DUPLEX_FULL)) {
+ RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart));
+ } else if (autoneg == AUTONEG_ENABLE)
+ RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart);
+ else {
+ DBG ( "incorrect speed setting refused in TBI mode\n" );
+ ret = -EOPNOTSUPP;
+ }
+ return ret;
+}
- /* Set DMA burst size and Interframe Gap Time */
- RTL_W32(TxConfig,
- (TX_DMA_BURST << TxDMAShift) | (InterFrameGap <<
- TxInterFrameGapShift));
+static int rtl8169_set_speed_xmii(struct net_device *dev,
+ u8 autoneg, u16 speed, u8 duplex)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void *ioaddr = tp->mmio_addr;
+ int auto_nego, giga_ctrl;
+ DBGP ( "rtl8169_set_speed_xmii\n" );
- RTL_W16(CPlusCmd, RTL_R16(CPlusCmd));
+ auto_nego = mdio_read(ioaddr, MII_ADVERTISE);
+ auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
+ ADVERTISE_100HALF | ADVERTISE_100FULL);
+ giga_ctrl = mdio_read(ioaddr, MII_CTRL1000);
+ giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
- if (tp->mac_version == RTL_GIGA_MAC_VER_02 || tp->mac_version == RTL_GIGA_MAC_VER_03) {
- RTL_W16(CPlusCmd,
- (RTL_R16(CPlusCmd) | (1 << 14) | (1 << 3)));
- DBG
- ("Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14\n");
+ if (autoneg == AUTONEG_ENABLE) {
+ auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL |
+ ADVERTISE_100HALF | ADVERTISE_100FULL);
+ giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
} else {
- RTL_W16(CPlusCmd, (RTL_R16(CPlusCmd) | (1 << 3)));
- DBG("Set MAC Reg C+CR Offset 0xE0: bit-3.\n");
+ if (speed == SPEED_10)
+ auto_nego |= ADVERTISE_10HALF | ADVERTISE_10FULL;
+ else if (speed == SPEED_100)
+ auto_nego |= ADVERTISE_100HALF | ADVERTISE_100FULL;
+ else if (speed == SPEED_1000)
+ giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
+
+ if (duplex == DUPLEX_HALF)
+ auto_nego &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL);
+
+ if (duplex == DUPLEX_FULL)
+ auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_100HALF);
+
+ /* This tweak comes straight from Realtek's driver. */
+ if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) &&
+ ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_16))) {
+ auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA;
+ }
}
- {
- //RTL_W16(IntrMitigate, 0x1517);
- //RTL_W16(IntrMitigate, 0x152a);
- //RTL_W16(IntrMitigate, 0x282a);
- RTL_W16(IntrMitigate, 0x0000);
+ /* The 8100e/8101e/8102e do Fast Ethernet only. */
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_07) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_08) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_09) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_10) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_14) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_15) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_16)) {
+ if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF))) {
+ DBG ( "PHY does not support 1000Mbps.\n" );
+ }
+ giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
}
- tp->cur_rx = 0;
-
- RTL_W32(TxDescAddrLow, virt_to_le32desc(tp->TxDescArray));
- RTL_W32(TxDescAddrHigh, virt_to_le32desc(NULL));
- RTL_W32(RxDescAddrLow, virt_to_le32desc(tp->RxDescArray));
- RTL_W32(RxDescAddrHigh, virt_to_le32desc(NULL));
- RTL_W8(Cfg9346, Cfg9346_Lock);
- udelay(10);
-
- RTL_W32(RxMissed, 0);
-
- rtl8169_set_rx_mode(nic);
-
- /* no early-rx interrupts */
- RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
+ auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_11) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_12) ||
+ (tp->mac_version >= RTL_GIGA_MAC_VER_17)) {
+ /*
+ * Wake up the PHY.
+ * Vendor specific (0x1f) and reserved (0x0e) MII registers.
+ */
+ mdio_write(ioaddr, 0x1f, 0x0000);
+ mdio_write(ioaddr, 0x0e, 0x0000);
+ }
- RTL_W16(IntrMask, rtl8169_intr_mask);
+ tp->phy_auto_nego_reg = auto_nego;
+ tp->phy_1000_ctrl_reg = giga_ctrl;
+ mdio_write(ioaddr, MII_ADVERTISE, auto_nego);
+ mdio_write(ioaddr, MII_CTRL1000, giga_ctrl);
+ mdio_write(ioaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
+ return 0;
}
-static void rtl8169_init_ring(struct nic *nic __unused)
+static int rtl8169_set_speed(struct net_device *dev,
+ u8 autoneg, u16 speed, u8 duplex)
{
- int i;
- struct rtl8169_private *tp = &tpx;
+ struct rtl8169_private *tp = netdev_priv(dev);
+ int ret;
- tp->cur_rx = 0;
- tp->cur_tx = 0;
- memset(tp->TxDescArray, 0x0, NUM_TX_DESC * sizeof(struct TxDesc));
- memset(tp->RxDescArray, 0x0, NUM_RX_DESC * sizeof(struct RxDesc));
+ DBGP ( "rtl8169_set_speed\n" );
- for (i = 0; i < NUM_TX_DESC; i++) {
- tp->Tx_skbuff[i] = &txb[i];
- }
+ ret = tp->set_speed(dev, autoneg, speed, duplex);
- for (i = 0; i < NUM_RX_DESC; i++) {
- if (i == (NUM_RX_DESC - 1))
- tp->RxDescArray[i].status =
- (OWNbit | EORbit) | RX_BUF_SIZE;
- else
- tp->RxDescArray[i].status = OWNbit | RX_BUF_SIZE;
-
- tp->RxBufferRing[i] = &rxb[i * RX_BUF_SIZE];
- tp->RxDescArray[i].buf_addr =
- virt_to_bus(tp->RxBufferRing[i]);
- tp->RxDescArray[i].buf_Haddr = 0;
- }
+ return ret;
}
-/**************************************************************************
-RESET - Finish setting up the ethernet interface
-***************************************************************************/
-static void r8169_reset(struct nic *nic)
+static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg,
+ int bitnum, int bitval)
{
- int i;
- struct rtl8169_private *tp = &tpx;
-
- tp->TxDescArray = tx_ring;
- tp->RxDescArray = rx_ring;
-
- rtl8169_init_ring(nic);
- rtl8169_hw_start(nic);
- /* Construct a perfect filter frame with the mac address as first match
- * and broadcast for all others */
- for (i = 0; i < 192; i++)
- txb[i] = 0xFF;
-
- txb[0] = nic->node_addr[0];
- txb[1] = nic->node_addr[1];
- txb[2] = nic->node_addr[2];
- txb[3] = nic->node_addr[3];
- txb[4] = nic->node_addr[4];
- txb[5] = nic->node_addr[5];
-}
-
-/**************************************************************************
-DISABLE - Turn off ethernet interface
-***************************************************************************/
-static void r8169_disable ( struct nic *nic __unused ) {
- int i;
- struct rtl8169_private *tp = &tpx;
+ int val;
- /* Stop the chip's Tx and Rx DMA processes. */
- RTL_W8(ChipCmd, 0x00);
-
- /* Disable interrupts by clearing the interrupt mask. */
- RTL_W16(IntrMask, 0x0000);
+ DBGP ( "rtl8169_write_gmii_reg_bit\n" );
- RTL_W32(RxMissed, 0);
-
- tp->TxDescArray = NULL;
- tp->RxDescArray = NULL;
- for (i = 0; i < NUM_RX_DESC; i++) {
- tp->RxBufferRing[i] = NULL;
- }
+ val = mdio_read(ioaddr, reg);
+ val = (bitval == 1) ?
+ val | (bitval << bitnum) : val & ~(0x0001 << bitnum);
+ mdio_write(ioaddr, reg, val & 0xffff);
}
-static struct nic_operations r8169_operations = {
- .connect = dummy_connect,
- .poll = r8169_poll,
- .transmit = r8169_transmit,
- .irq = r8169_irq,
-
-};
-
-static struct pci_device_id r8169_nics[] = {
- PCI_ROM(0x10ec, 0x8169, "r8169", "RealTek RTL8169 Gigabit Ethernet"),
- PCI_ROM(0x16ec, 0x0116, "usr-r8169", "US Robotics RTL8169 Gigabit Ethernet"),
- PCI_ROM(0x1186, 0x4300, "dlink-r8169", "D-Link RTL8169 Gigabit Ethernet"),
- PCI_ROM(0x1737, 0x1032, "linksys-r8169", "Linksys RTL8169 Gigabit Ethernet"),
- PCI_ROM(0x10ec, 0x8129, "r8169-8129", "RealTek RT8129 Fast Ethernet Adapter"),
- PCI_ROM(0x10ec, 0x8136, "r8169-8101e", "RealTek RTL8101E PCI Express Fast Ethernet controller"),
- PCI_ROM(0x10ec, 0x8167, "r8169-8110sc/8169sc", "RealTek RTL-8110SC/8169SC Gigabit Ethernet"),
- PCI_ROM(0x10ec, 0x8168, "r8169-8168b", "RealTek RTL8111/8168B PCI Express Gigabit Ethernet controller"),
-};
-
-PCI_DRIVER ( r8169_driver, r8169_nics, PCI_NO_CLASS );
-
-/**************************************************************************
-PROBE - Look for an adapter, this routine's visible to the outside
-***************************************************************************/
-
-#define board_found 1
-#define valid_link 0
-static int r8169_probe ( struct nic *nic, struct pci_device *pci ) {
-
- static int board_idx = -1;
- static int printed_version = 0;
- struct rtl8169_private *tp = &tpx;
- int i, rc;
- int option = -1, Cap10_100 = 0, Cap1000 = 0;
-
- printf ( "r8169.c: Found %s, Vendor=%hX Device=%hX\n",
- pci->driver_name, pci->vendor, pci->device );
-
- board_idx++;
-
- printed_version = 1;
-
- /* Quick and very dirty hack to get r8169 driver working
- * again, pre-rewrite
+static void rtl8169_get_mac_version(struct rtl8169_private *tp,
+ void *ioaddr)
+{
+ /*
+ * The driver currently handles the 8168Bf and the 8168Be identically
+ * but they can be identified more specifically through the test below
+ * if needed:
+ *
+ * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be
+ *
+ * Same thing for the 8101Eb and the 8101Ec:
+ *
+ * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec
*/
- if ( ! r8169_bufs )
- r8169_bufs = malloc_dma ( sizeof ( *r8169_bufs ), 256 );
- if ( ! r8169_bufs )
- return 0;
- memset ( r8169_bufs, 0, sizeof ( *r8169_bufs ) );
-
- rc = rtl8169_init_board(pci); /* Return code is meaningless */
-
- /* Get MAC address. FIXME: read EEPROM */
- for (i = 0; i < MAC_ADDR_LEN; i++)
- nic->node_addr[i] = RTL_R8(MAC0 + i);
-
- DBG ( "%s: Identified chip type is '%s'.\n", pci->driver_name,
- rtl_chip_info[tp->chipset].name );
-
- /* Print out some hardware info */
- DBG ( "%s: %s at ioaddr %#hx, ", pci->driver_name, eth_ntoa ( nic->node_addr ),
- (unsigned int) ioaddr );
+ const struct {
+ u32 mask;
+ u32 val;
+ int mac_version;
+ } mac_info[] = {
+ /* 8168D family. */
+ { 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_25 },
+
+ /* 8168C family. */
+ { 0x7cf00000, 0x3ca00000, RTL_GIGA_MAC_VER_24 },
+ { 0x7cf00000, 0x3c900000, RTL_GIGA_MAC_VER_23 },
+ { 0x7cf00000, 0x3c800000, RTL_GIGA_MAC_VER_18 },
+ { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_24 },
+ { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 },
+ { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 },
+ { 0x7cf00000, 0x3c300000, RTL_GIGA_MAC_VER_21 },
+ { 0x7cf00000, 0x3c400000, RTL_GIGA_MAC_VER_22 },
+ { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_22 },
- /* Config PHY */
- rtl8169_hw_phy_config(nic);
-
- DBG("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
- RTL_W8(0x82, 0x01);
+ /* 8168B family. */
+ { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 },
+ { 0x7cf00000, 0x38500000, RTL_GIGA_MAC_VER_17 },
+ { 0x7c800000, 0x38000000, RTL_GIGA_MAC_VER_17 },
+ { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 },
- pci_write_config_byte(pci, PCI_LATENCY_TIMER, 0x40);
+ /* 8101 family. */
+ { 0x7cf00000, 0x34a00000, RTL_GIGA_MAC_VER_09 },
+ { 0x7cf00000, 0x24a00000, RTL_GIGA_MAC_VER_09 },
+ { 0x7cf00000, 0x34900000, RTL_GIGA_MAC_VER_08 },
+ { 0x7cf00000, 0x24900000, RTL_GIGA_MAC_VER_08 },
+ { 0x7cf00000, 0x34800000, RTL_GIGA_MAC_VER_07 },
+ { 0x7cf00000, 0x24800000, RTL_GIGA_MAC_VER_07 },
+ { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 },
+ { 0x7cf00000, 0x34300000, RTL_GIGA_MAC_VER_10 },
+ { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 },
+ { 0x7c800000, 0x34800000, RTL_GIGA_MAC_VER_09 },
+ { 0x7c800000, 0x24800000, RTL_GIGA_MAC_VER_09 },
+ { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 },
+ /* FIXME: where did these entries come from ? -- FR */
+ { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 },
+ { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 },
- if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
- pci_write_config_byte(pci, PCI_CACHE_LINE_SIZE, 0x08);
+ /* 8110 family. */
+ { 0xfc800000, 0x98000000, RTL_GIGA_MAC_VER_06 },
+ { 0xfc800000, 0x18000000, RTL_GIGA_MAC_VER_05 },
+ { 0xfc800000, 0x10000000, RTL_GIGA_MAC_VER_04 },
+ { 0xfc800000, 0x04000000, RTL_GIGA_MAC_VER_03 },
+ { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 },
+ { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 },
- if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
- DBG("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
- RTL_W8(0x82, 0x01);
- DBG("Set PHY Reg 0x0bh = 0x00h\n");
- RTL8169_WRITE_GMII_REG(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
- }
+ { 0x00000000, 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */
+ }, *p = mac_info;
+ u32 reg;
- r8169_reset(nic);
-
- /* if TBI is not endbled */
- if (!(RTL_R8(PHYstatus) & TBI_Enable)) {
- int val = RTL8169_READ_GMII_REG(ioaddr, PHY_AUTO_NEGO_REG);
-
-#ifdef RTL8169_HW_FLOW_CONTROL_SUPPORT
- val |= PHY_Cap_PAUSE | PHY_Cap_ASYM_PAUSE;
-#endif //end #define RTL8169_HW_FLOW_CONTROL_SUPPORT
-
- /* Force RTL8169 in 10/100/1000 Full/Half mode. */
- if (option > 0) {
- printf(" Force-mode Enabled.\n");
- Cap10_100 = 0, Cap1000 = 0;
- switch (option) {
- case _10_Half:
- Cap10_100 = PHY_Cap_10_Half;
- Cap1000 = PHY_Cap_Null;
- break;
- case _10_Full:
- Cap10_100 = PHY_Cap_10_Full;
- Cap1000 = PHY_Cap_Null;
- break;
- case _100_Half:
- Cap10_100 = PHY_Cap_100_Half;
- Cap1000 = PHY_Cap_Null;
- break;
- case _100_Full:
- Cap10_100 = PHY_Cap_100_Full;
- Cap1000 = PHY_Cap_Null;
- break;
- case _1000_Full:
- Cap10_100 = PHY_Cap_Null;
- Cap1000 = PHY_Cap_1000_Full;
- break;
- default:
- break;
- }
- RTL8169_WRITE_GMII_REG(ioaddr, PHY_AUTO_NEGO_REG, Cap10_100 | (val & 0xC1F)); //leave PHY_AUTO_NEGO_REG bit4:0 unchanged
- RTL8169_WRITE_GMII_REG(ioaddr, PHY_1000_CTRL_REG,
- Cap1000);
- } else {
- DBG ( "%s: Auto-negotiation Enabled.\n", pci->driver_name );
-
- // enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged
- RTL8169_WRITE_GMII_REG(ioaddr, PHY_AUTO_NEGO_REG,
- PHY_Cap_10_Half |
- PHY_Cap_10_Full |
- PHY_Cap_100_Half |
- PHY_Cap_100_Full | (val &
- 0xC1F));
-
- // enable 1000 Full Mode
-// RTL8169_WRITE_GMII_REG( ioaddr, PHY_1000_CTRL_REG, PHY_Cap_1000_Full );
- RTL8169_WRITE_GMII_REG(ioaddr, PHY_1000_CTRL_REG, PHY_Cap_1000_Full | PHY_Cap_1000_Half); //rtl8168
-
- } // end of if( option > 0 )
-
- // Enable auto-negotiation and restart auto-nigotiation
- RTL8169_WRITE_GMII_REG(ioaddr, PHY_CTRL_REG,
- PHY_Enable_Auto_Nego |
- PHY_Restart_Auto_Nego);
- udelay(100);
-
- // wait for auto-negotiation process
- for (i = 10000; i > 0; i--) {
- //check if auto-negotiation complete
- if (RTL8169_READ_GMII_REG(ioaddr, PHY_STAT_REG) &
- PHY_Auto_Neco_Comp) {
- udelay(100);
- option = RTL_R8(PHYstatus);
- if (option & _1000bpsF) {
- printf
- ("1000Mbps Full-duplex operation.\n");
- } else {
- printf
- ("%sMbps %s-duplex operation.\n",
- (option & _100bps) ? "100" :
- "10",
- (option & FullDup) ? "Full" :
- "Half");
- }
- break;
- } else {
- udelay(100);
- } // end of if( RTL8169_READ_GMII_REG(ioaddr, 1) & 0x20 )
- } // end for-loop to wait for auto-negotiation process
+ DBGP ( "rtl8169_get_mac_version\n" );
+ reg = RTL_R32(TxConfig);
+ while ((reg & p->mask) != p->val)
+ p++;
+ tp->mac_version = p->mac_version;
- } else {
- udelay(100);
- printf
- ("%s: 1000Mbps Full-duplex operation, TBI Link %s!\n",
- pci->driver_name,
- (RTL_R32(TBICSR) & TBILinkOK) ? "OK" : "Failed");
+ DBG ( "tp->mac_version = %d\n", tp->mac_version );
+ if (p->mask == 0x00000000) {
+ DBG ( "unknown MAC (%08x)\n", reg );
}
-
- r8169_reset(nic);
-
- /* point to NIC specific routines */
- nic->nic_op = &r8169_operations;
-
- nic->irqno = pci->irq;
- nic->ioaddr = ioaddr;
-
- return 1;
-}
-
-//======================================================================================================
-/*
-static void rtl8169_hw_PHY_reset(struct nic *nic __unused)
-{
- int val, phy_reset_expiretime = 50;
- struct rtl8169_private *priv = dev->priv;
- unsigned long ioaddr = priv->ioaddr;
-
- DBG("%s: Reset RTL8169s PHY\n", dev->name);
-
- val = ( RTL8169_READ_GMII_REG( ioaddr, 0 ) | 0x8000 ) & 0xffff;
- RTL8169_WRITE_GMII_REG( ioaddr, 0, val );
-
- do //waiting for phy reset
- {
- if( RTL8169_READ_GMII_REG( ioaddr, 0 ) & 0x8000 ){
- phy_reset_expiretime --;
- udelay(100);
- }
- else{
- break;
- }
- }while( phy_reset_expiretime >= 0 );
-
- assert( phy_reset_expiretime > 0 );
}
-*/
-
struct phy_reg {
u16 reg;
u16 val;
@@ -1161,8 +436,10 @@ struct phy_reg {
static void rtl_phy_write(void *ioaddr, struct phy_reg *regs, int len)
{
+ DBGP ( "rtl_phy_write\n" );
+
while (len-- > 0) {
- RTL8169_WRITE_GMII_REG((u32)ioaddr, regs->reg, regs->val);
+ mdio_write(ioaddr, regs->reg, regs->val);
regs++;
}
}
@@ -1201,22 +478,24 @@ static void rtl8169s_hw_phy_config(void *ioaddr)
}, *p = phy_magic;
unsigned int i;
- RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x1f, 0x0001); //w 31 2 0 1
- RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x15, 0x1000); //w 21 15 0 1000
- RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x18, 0x65c7); //w 24 15 0 65c7
- RTL8169_WRITE_GMII_REG_BIT((u32)ioaddr, 4, 11, 0); //w 4 11 11 0
+ DBGP ( "rtl8169s_hw_phy_config\n" );
+
+ mdio_write(ioaddr, 0x1f, 0x0001); //w 31 2 0 1
+ mdio_write(ioaddr, 0x15, 0x1000); //w 21 15 0 1000
+ mdio_write(ioaddr, 0x18, 0x65c7); //w 24 15 0 65c7
+ rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0
for (i = 0; i < ARRAY_SIZE(phy_magic); i++, p++) {
int val, pos = 4;
- val = (RTL8169_READ_GMII_REG((u32)ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff);
- RTL8169_WRITE_GMII_REG((u32)ioaddr, pos, val);
+ val = (mdio_read(ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff);
+ mdio_write(ioaddr, pos, val);
while (--pos >= 0)
- RTL8169_WRITE_GMII_REG((u32)ioaddr, pos, p->regs[4 - pos] & 0xffff);
- RTL8169_WRITE_GMII_REG_BIT((u32)ioaddr, 4, 11, 1); //w 4 11 11 1
- RTL8169_WRITE_GMII_REG_BIT((u32)ioaddr, 4, 11, 0); //w 4 11 11 0
+ mdio_write(ioaddr, pos, p->regs[4 - pos] & 0xffff);
+ rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1
+ rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0
}
- RTL8169_WRITE_GMII_REG((u32)ioaddr, 0x1f, 0x0000); //w 31 2 0 0
+ mdio_write(ioaddr, 0x1f, 0x0000); //w 31 2 0 0
}
static void rtl8169sb_hw_phy_config(void *ioaddr)
@@ -1227,10 +506,40 @@ static void rtl8169sb_hw_phy_config(void *ioaddr)
{ 0x1f, 0x0000 }
};
+ DBGP ( "rtl8169sb_hw_phy_config\n" );
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168bb_hw_phy_config(void *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x10, 0xf41b },
+ { 0x1f, 0x0000 }
+ };
+
+ mdio_write(ioaddr, 0x1f, 0x0001);
+ mdio_patch(ioaddr, 0x16, 1 << 0);
+
+ DBGP ( "rtl8168bb_hw_phy_config\n" );
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168bef_hw_phy_config(void *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0001 },
+ { 0x10, 0xf41b },
+ { 0x1f, 0x0000 }
+ };
+
+ DBGP ( "rtl8168bef_hw_phy_config\n" );
+
rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8168cp_hw_phy_config(void *ioaddr)
+static void rtl8168cp_1_hw_phy_config(void *ioaddr)
{
struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0000 },
@@ -1240,10 +549,29 @@ static void rtl8168cp_hw_phy_config(void *ioaddr)
{ 0x1f, 0x0000 }
};
+ DBGP ( "rtl8168cp_1_hw_phy_config\n" );
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+}
+
+static void rtl8168cp_2_hw_phy_config(void *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0001 },
+ { 0x1d, 0x3d98 },
+ { 0x1f, 0x0000 }
+ };
+
+ DBGP ( "rtl8168cp_2_hw_phy_config\n" );
+
+ mdio_write(ioaddr, 0x1f, 0x0000);
+ mdio_patch(ioaddr, 0x14, 1 << 5);
+ mdio_patch(ioaddr, 0x0d, 1 << 5);
+
rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8168c_hw_phy_config(void *ioaddr)
+static void rtl8168c_1_hw_phy_config(void *ioaddr)
{
struct phy_reg phy_reg_init[] = {
{ 0x1f, 0x0001 },
@@ -1259,33 +587,180 @@ static void rtl8168c_hw_phy_config(void *ioaddr)
{ 0x1f, 0x0003 },
{ 0x12, 0xc096 },
{ 0x16, 0x000a },
- { 0x1f, 0x0000 }
+ { 0x1f, 0x0000 },
+ { 0x1f, 0x0000 },
+ { 0x09, 0x2000 },
+ { 0x09, 0x0000 }
};
+ DBGP ( "rtl8168c_1_hw_phy_config\n" );
+
rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+ mdio_patch(ioaddr, 0x14, 1 << 5);
+ mdio_patch(ioaddr, 0x0d, 1 << 5);
+ mdio_write(ioaddr, 0x1f, 0x0000);
}
-static void rtl8168cx_hw_phy_config(void *ioaddr)
+static void rtl8168c_2_hw_phy_config(void *ioaddr)
{
struct phy_reg phy_reg_init[] = {
- { 0x1f, 0x0000 },
+ { 0x1f, 0x0001 },
{ 0x12, 0x2300 },
+ { 0x03, 0x802f },
+ { 0x02, 0x4f02 },
+ { 0x01, 0x0409 },
+ { 0x00, 0xf099 },
+ { 0x04, 0x9800 },
+ { 0x04, 0x9000 },
+ { 0x1d, 0x3d98 },
+ { 0x1f, 0x0002 },
+ { 0x0c, 0x7eb8 },
+ { 0x06, 0x0761 },
{ 0x1f, 0x0003 },
{ 0x16, 0x0f0a },
- { 0x1f, 0x0000 },
+ { 0x1f, 0x0000 }
+ };
+
+ DBGP ( "rtl8168c_2_hw_phy_config\n" );
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+ mdio_patch(ioaddr, 0x16, 1 << 0);
+ mdio_patch(ioaddr, 0x14, 1 << 5);
+ mdio_patch(ioaddr, 0x0d, 1 << 5);
+ mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8168c_3_hw_phy_config(void *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0001 },
+ { 0x12, 0x2300 },
+ { 0x1d, 0x3d98 },
{ 0x1f, 0x0002 },
{ 0x0c, 0x7eb8 },
+ { 0x06, 0x5461 },
+ { 0x1f, 0x0003 },
+ { 0x16, 0x0f0a },
{ 0x1f, 0x0000 }
};
+ DBGP ( "rtl8168c_3_hw_phy_config\n" );
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+ mdio_patch(ioaddr, 0x16, 1 << 0);
+ mdio_patch(ioaddr, 0x14, 1 << 5);
+ mdio_patch(ioaddr, 0x0d, 1 << 5);
+ mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8168c_4_hw_phy_config(void *ioaddr)
+{
+ DBGP ( "rtl8168c_4_hw_phy_config\n" );
+
+ rtl8168c_3_hw_phy_config(ioaddr);
+}
+
+static void rtl8168d_hw_phy_config(void *ioaddr)
+{
+ struct phy_reg phy_reg_init_0[] = {
+ { 0x1f, 0x0001 },
+ { 0x09, 0x2770 },
+ { 0x08, 0x04d0 },
+ { 0x0b, 0xad15 },
+ { 0x0c, 0x5bf0 },
+ { 0x1c, 0xf101 },
+ { 0x1f, 0x0003 },
+ { 0x14, 0x94d7 },
+ { 0x12, 0xf4d6 },
+ { 0x09, 0xca0f },
+ { 0x1f, 0x0002 },
+ { 0x0b, 0x0b10 },
+ { 0x0c, 0xd1f7 },
+ { 0x1f, 0x0002 },
+ { 0x06, 0x5461 },
+ { 0x1f, 0x0002 },
+ { 0x05, 0x6662 },
+ { 0x1f, 0x0000 },
+ { 0x14, 0x0060 },
+ { 0x1f, 0x0000 },
+ { 0x0d, 0xf8a0 },
+ { 0x1f, 0x0005 },
+ { 0x05, 0xffc2 }
+ };
+
+ DBGP ( "rtl8168d_hw_phy_config\n" );
+
+ rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
+
+ if (mdio_read(ioaddr, 0x06) == 0xc400) {
+ struct phy_reg phy_reg_init_1[] = {
+ { 0x1f, 0x0005 },
+ { 0x01, 0x0300 },
+ { 0x1f, 0x0000 },
+ { 0x11, 0x401c },
+ { 0x16, 0x4100 },
+ { 0x1f, 0x0005 },
+ { 0x07, 0x0010 },
+ { 0x05, 0x83dc },
+ { 0x06, 0x087d },
+ { 0x05, 0x8300 },
+ { 0x06, 0x0101 },
+ { 0x06, 0x05f8 },
+ { 0x06, 0xf9fa },
+ { 0x06, 0xfbef },
+ { 0x06, 0x79e2 },
+ { 0x06, 0x835f },
+ { 0x06, 0xe0f8 },
+ { 0x06, 0x9ae1 },
+ { 0x06, 0xf89b },
+ { 0x06, 0xef31 },
+ { 0x06, 0x3b65 },
+ { 0x06, 0xaa07 },
+ { 0x06, 0x81e4 },
+ { 0x06, 0xf89a },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x9baf },
+ { 0x06, 0x06ae },
+ { 0x05, 0x83dc },
+ { 0x06, 0x8300 },
+ };
+
+ rtl_phy_write(ioaddr, phy_reg_init_1,
+ ARRAY_SIZE(phy_reg_init_1));
+ }
+
+ mdio_write(ioaddr, 0x1f, 0x0000);
+}
+
+static void rtl8102e_hw_phy_config(void *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0003 },
+ { 0x08, 0x441d },
+ { 0x01, 0x9100 },
+ { 0x1f, 0x0000 }
+ };
+
+ DBGP ( "rtl8102e_hw_phy_config\n" );
+
+ mdio_write(ioaddr, 0x1f, 0x0000);
+ mdio_patch(ioaddr, 0x11, 1 << 12);
+ mdio_patch(ioaddr, 0x19, 1 << 13);
+
rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
-static void rtl8169_hw_phy_config(struct nic *nic __unused)
+static void rtl_hw_phy_config(struct net_device *dev)
{
- struct rtl8169_private *tp = &tpx;
+ struct rtl8169_private *tp = netdev_priv(dev);
void *ioaddr = tp->mmio_addr;
- DBG("rtl8169_hw_phy_config(): card at addr=0x%lx: priv->mac_version=%d, priv->pcfg=%d\n", (unsigned long) ioaddr, tp->mac_version, tp->pcfg);
+
+ DBGP ( "rtl_hw_phy_config\n" );
+
+ DBG ( "mac_version = 0x%02x\n", tp->mac_version );
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_01:
@@ -1297,22 +772,1506 @@ static void rtl8169_hw_phy_config(struct nic *nic __unused)
case RTL_GIGA_MAC_VER_04:
rtl8169sb_hw_phy_config(ioaddr);
break;
+ case RTL_GIGA_MAC_VER_07:
+ case RTL_GIGA_MAC_VER_08:
+ case RTL_GIGA_MAC_VER_09:
+ rtl8102e_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_11:
+ rtl8168bb_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_12:
+ rtl8168bef_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_17:
+ rtl8168bef_hw_phy_config(ioaddr);
+ break;
case RTL_GIGA_MAC_VER_18:
- rtl8168cp_hw_phy_config(ioaddr);
+ rtl8168cp_1_hw_phy_config(ioaddr);
break;
case RTL_GIGA_MAC_VER_19:
- rtl8168c_hw_phy_config(ioaddr);
+ rtl8168c_1_hw_phy_config(ioaddr);
break;
case RTL_GIGA_MAC_VER_20:
- rtl8168cx_hw_phy_config(ioaddr);
+ rtl8168c_2_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_21:
+ rtl8168c_3_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_22:
+ rtl8168c_4_hw_phy_config(ioaddr);
break;
+ case RTL_GIGA_MAC_VER_23:
+ case RTL_GIGA_MAC_VER_24:
+ rtl8168cp_2_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_25:
+ rtl8168d_hw_phy_config(ioaddr);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void rtl8169_phy_reset(struct net_device *dev __unused,
+ struct rtl8169_private *tp)
+{
+ void *ioaddr = tp->mmio_addr;
+ unsigned int i;
+
+ DBGP ( "rtl8169_phy_reset\n" );
+
+ tp->phy_reset_enable(ioaddr);
+ for (i = 0; i < 100; i++) {
+ if (!tp->phy_reset_pending(ioaddr))
+ return;
+ mdelay ( 1 );
+ }
+ DBG ( "PHY reset failed.\n" );
+}
+
+static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
+{
+ void *ioaddr = tp->mmio_addr;
+
+ DBGP ( "rtl8169_init_phy\n" );
+
+ rtl_hw_phy_config(dev);
+
+ if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
+ DBG ( "Set MAC Reg C+CR Offset 0x82h = 0x01h\n" );
+ RTL_W8(0x82, 0x01);
+ }
+
+ pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
+
+ if (tp->mac_version <= RTL_GIGA_MAC_VER_06)
+ pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08);
+
+ if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
+ DBG ( "Set MAC Reg C+CR Offset 0x82h = 0x01h\n" );
+ RTL_W8(0x82, 0x01);
+ DBG ( "Set PHY Reg 0x0bh = 0x00h\n" );
+ mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
+ }
+
+ rtl8169_phy_reset(dev, tp);
+
+ /*
+ * rtl8169_set_speed_xmii takes good care of the Fast Ethernet
+ * only 8101. Don't panic.
+ */
+ rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL);
+
+ if ((RTL_R8(PHYstatus) & TBI_Enable))
+ DBG ( "TBI auto-negotiating\n" );
+}
+
+static const struct rtl_cfg_info {
+ void (*hw_start)(struct net_device *);
+ unsigned int region;
+ unsigned int align;
+ u16 intr_event;
+ u16 napi_event;
+ unsigned features;
+} rtl_cfg_infos [] = {
+ [RTL_CFG_0] = {
+ .hw_start = rtl_hw_start_8169,
+ .region = 1,
+ .align = 0,
+ .intr_event = SYSErr | LinkChg | RxOverflow |
+ RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
+ .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
+ .features = RTL_FEATURE_GMII
+ },
+ [RTL_CFG_1] = {
+ .hw_start = rtl_hw_start_8168,
+ .region = 2,
+ .align = 8,
+ .intr_event = SYSErr | LinkChg | RxOverflow |
+ TxErr | TxOK | RxOK | RxErr,
+ .napi_event = TxErr | TxOK | RxOK | RxOverflow,
+ .features = RTL_FEATURE_GMII
+ },
+ [RTL_CFG_2] = {
+ .hw_start = rtl_hw_start_8101,
+ .region = 2,
+ .align = 8,
+ .intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout |
+ RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
+ .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
+ }
+};
+
+static void rtl8169_hw_reset(void *ioaddr)
+{
+ DBGP ( "rtl8169_hw_reset\n" );
+
+ /* Disable interrupts */
+ rtl8169_irq_mask_and_ack(ioaddr);
+
+ /* Reset the chipset */
+ RTL_W8(ChipCmd, CmdReset);
+
+ /* PCI commit */
+ RTL_R8(ChipCmd);
+}
+
+static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp)
+{
+ void *ioaddr = tp->mmio_addr;
+ u32 cfg = rtl8169_rx_config;
+
+ DBGP ( "rtl_set_rx_tx_config_registers\n" );
+
+ cfg |= (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
+ RTL_W32(RxConfig, cfg);
+
+ /* Set DMA burst size and Interframe Gap Time */
+ RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
+ (InterFrameGap << TxInterFrameGapShift));
+}
+
+static void rtl_soft_reset ( struct net_device *dev )
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void *ioaddr = tp->mmio_addr;
+ unsigned int i;
+
+ DBGP ( "rtl_hw_soft_reset\n" );
+
+ /* Soft reset the chip. */
+ RTL_W8(ChipCmd, CmdReset);
+
+ /* Check that the chip has finished the reset. */
+ for (i = 0; i < 100; i++) {
+ if ((RTL_R8(ChipCmd) & CmdReset) == 0)
+ break;
+ mdelay ( 1 );
+ }
+
+ if ( i == 100 ) {
+ DBG ( "Reset Failed! (> 100 iterations)\n" );
+ }
+}
+
+static void rtl_hw_start ( struct net_device *dev )
+{
+ struct rtl8169_private *tp = netdev_priv ( dev );
+
+ DBGP ( "rtl_hw_start\n" );
+
+ /* Soft reset NIC */
+ rtl_soft_reset ( dev );
+
+ tp->hw_start ( dev );
+}
+
+static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,
+ void *ioaddr)
+{
+ DBGP ( "rtl_set_rx_tx_desc_registers\n" );
+
+ /*
+ * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
+ * register to be written before TxDescAddrLow to work.
+ * Switching from MMIO to I/O access fixes the issue as well.
+ */
+ RTL_W32 ( TxDescStartAddrHigh, 0 );
+ RTL_W32 ( TxDescStartAddrLow, virt_to_bus ( tp->tx_base ) );
+ RTL_W32 ( RxDescAddrHigh, 0 );
+ RTL_W32 ( RxDescAddrLow, virt_to_bus ( tp->rx_base ) );
+}
+
+static u16 rtl_rw_cpluscmd(void *ioaddr)
+{
+ u16 cmd;
+
+ DBGP ( "rtl_rw_cpluscmd\n" );
+
+ cmd = RTL_R16(CPlusCmd);
+ RTL_W16(CPlusCmd, cmd);
+ return cmd;
+}
+
+static void rtl_set_rx_max_size(void *ioaddr)
+{
+ DBGP ( "rtl_set_rx_max_size\n" );
+
+ RTL_W16 ( RxMaxSize, RX_BUF_SIZE );
+}
+
+static void rtl8169_set_magic_reg(void *ioaddr, unsigned mac_version)
+{
+ struct {
+ u32 mac_version;
+ u32 clk;
+ u32 val;
+ } cfg2_info [] = {
+ { RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd
+ { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff },
+ { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe
+ { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff }
+ }, *p = cfg2_info;
+ unsigned int i;
+ u32 clk;
+
+ DBGP ( "rtl8169_set_magic_reg\n" );
+
+ clk = RTL_R8(Config2) & PCI_Clock_66MHz;
+ for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) {
+ if ((p->mac_version == mac_version) && (p->clk == clk)) {
+ RTL_W32(0x7c, p->val);
+ break;
+ }
+ }
+}
+
+static void rtl_set_rx_mode ( struct net_device *netdev )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ void *ioaddr = tp->mmio_addr;
+ u32 tmp;
+
+ DBGP ( "rtl_set_rx_mode\n" );
+
+ /* Accept all Multicast Packets */
+
+ RTL_W32 ( MAR0 + 0, 0xffffffff );
+ RTL_W32 ( MAR0 + 4, 0xffffffff );
+
+ tmp = rtl8169_rx_config | AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+ ( RTL_R32 ( RxConfig ) & rtl_chip_info[tp->chipset].RxConfigMask );
+
+ RTL_W32 ( RxConfig, tmp );
+}
+
+static void rtl_hw_start_8169(struct net_device *dev)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void *ioaddr = tp->mmio_addr;
+ struct pci_device *pdev = tp->pci_dev;
+
+ DBGP ( "rtl_hw_start_8169\n" );
+
+ if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
+ }
+
+ RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_02) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_03) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_04))
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ rtl_set_rx_max_size(ioaddr);
+
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_02) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_03) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_04))
+ rtl_set_rx_tx_config_registers(tp);
+
+ tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
+
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_03)) {
+ DBG ( "Set MAC Reg C+CR Offset 0xE0. "
+ "Bit-3 and bit-14 MUST be 1\n" );
+ tp->cp_cmd |= (1 << 14);
+ }
+
+ RTL_W16(CPlusCmd, tp->cp_cmd);
+
+ rtl8169_set_magic_reg(ioaddr, tp->mac_version);
+
+ /*
+ * Undocumented corner. Supposedly:
+ * (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets
+ */
+ RTL_W16(IntrMitigate, 0x0000);
+
+ rtl_set_rx_tx_desc_registers(tp, ioaddr);
+
+ if ((tp->mac_version != RTL_GIGA_MAC_VER_01) &&
+ (tp->mac_version != RTL_GIGA_MAC_VER_02) &&
+ (tp->mac_version != RTL_GIGA_MAC_VER_03) &&
+ (tp->mac_version != RTL_GIGA_MAC_VER_04)) {
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+ rtl_set_rx_tx_config_registers(tp);
+ }
+
+ RTL_W8(Cfg9346, Cfg9346_Lock);
+
+ /* Initially a 10 us delay. Turned it into a PCI commit. - FR */
+ RTL_R8(IntrMask);
+
+ RTL_W32(RxMissed, 0);
+
+ rtl_set_rx_mode(dev);
+
+ /* no early-rx interrupts */
+ RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
+
+ // RTL_W16(IntrMask, tp->intr_event);
+}
+
+static void rtl_tx_performance_tweak(struct pci_device *pdev, u16 force)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct rtl8169_private *tp = netdev_priv(dev);
+ int cap = tp->pcie_cap;
+
+ DBGP ( "rtl_tx_performance_tweak\n" );
+
+ if (cap) {
+ u16 ctl;
+
+ pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl);
+ ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force;
+ pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl);
+ }
+}
+
+static void rtl_csi_access_enable(void *ioaddr)
+{
+ u32 csi;
+
+ DBGP ( "rtl_csi_access_enable\n" );
+
+ csi = rtl_csi_read(ioaddr, 0x070c) & 0x00ffffff;
+ rtl_csi_write(ioaddr, 0x070c, csi | 0x27000000);
+}
+
+struct ephy_info {
+ unsigned int offset;
+ u16 mask;
+ u16 bits;
+};
+
+static void rtl_ephy_init(void *ioaddr, struct ephy_info *e, int len)
+{
+ u16 w;
+
+ DBGP ( "rtl_ephy_init\n" );
+
+ while (len-- > 0) {
+ w = (rtl_ephy_read(ioaddr, e->offset) & ~e->mask) | e->bits;
+ rtl_ephy_write(ioaddr, e->offset, w);
+ e++;
+ }
+}
+
+static void rtl_disable_clock_request(struct pci_device *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct rtl8169_private *tp = netdev_priv(dev);
+ int cap = tp->pcie_cap;
+
+ DBGP ( "rtl_disable_clock_request\n" );
+
+ if (cap) {
+ u16 ctl;
+
+ pci_read_config_word(pdev, cap + PCI_EXP_LNKCTL, &ctl);
+ ctl &= ~PCI_EXP_LNKCTL_CLKREQ_EN;
+ pci_write_config_word(pdev, cap + PCI_EXP_LNKCTL, ctl);
+ }
+}
+
+#define R8168_CPCMD_QUIRK_MASK (\
+ EnableBist | \
+ Mac_dbgo_oe | \
+ Force_half_dup | \
+ Force_rxflow_en | \
+ Force_txflow_en | \
+ Cxpl_dbg_sel | \
+ ASF | \
+ PktCntrDisable | \
+ Mac_dbgo_sel)
+
+static void rtl_hw_start_8168bb(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168bb\n" );
+
+ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+
+ rtl_tx_performance_tweak(pdev,
+ (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
+}
+
+static void rtl_hw_start_8168bef(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168bef\n" );
+
+ rtl_hw_start_8168bb(ioaddr, pdev);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0));
+}
+
+static void __rtl_hw_start_8168cp(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "__rtl_hw_start_8168cp\n" );
+
+ RTL_W8(Config1, RTL_R8(Config1) | Speed_down);
+
+ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ rtl_disable_clock_request(pdev);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168cp_1(void *ioaddr, struct pci_device *pdev)
+{
+ static struct ephy_info e_info_8168cp[] = {
+ { 0x01, 0, 0x0001 },
+ { 0x02, 0x0800, 0x1000 },
+ { 0x03, 0, 0x0042 },
+ { 0x06, 0x0080, 0x0000 },
+ { 0x07, 0, 0x2000 }
+ };
+
+ DBGP ( "rtl_hw_start_8168cp_1\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ rtl_ephy_init(ioaddr, e_info_8168cp, ARRAY_SIZE(e_info_8168cp));
+
+ __rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168cp_2(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168cp_2\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168cp_3(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168cp_3\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+ /* Magic. */
+ RTL_W8(DBG_REG, 0x20);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168c_1(void *ioaddr, struct pci_device *pdev)
+{
+ static struct ephy_info e_info_8168c_1[] = {
+ { 0x02, 0x0800, 0x1000 },
+ { 0x03, 0, 0x0002 },
+ { 0x06, 0x0080, 0x0000 }
+ };
+
+ DBGP ( "rtl_hw_start_8168c_1\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2);
+
+ rtl_ephy_init(ioaddr, e_info_8168c_1, ARRAY_SIZE(e_info_8168c_1));
+
+ __rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168c_2(void *ioaddr, struct pci_device *pdev)
+{
+ static struct ephy_info e_info_8168c_2[] = {
+ { 0x01, 0, 0x0001 },
+ { 0x03, 0x0400, 0x0220 }
+ };
+
+ DBGP ( "rtl_hw_start_8168c_2\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ rtl_ephy_init(ioaddr, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2));
+
+ __rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168c_3(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168c_3\n" );
+
+ rtl_hw_start_8168c_2(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168c_4(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168c_4\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ __rtl_hw_start_8168cp(ioaddr, pdev);
+}
+
+static void rtl_hw_start_8168d(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8168d\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ rtl_disable_clock_request(pdev);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8168(struct net_device *dev)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void *ioaddr = tp->mmio_addr;
+ struct pci_device *pdev = tp->pci_dev;
+
+ DBGP ( "rtl_hw_start_8168\n" );
+
+ RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ rtl_set_rx_max_size(ioaddr);
+
+ tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1;
+
+ RTL_W16(CPlusCmd, tp->cp_cmd);
+
+ RTL_W16(IntrMitigate, 0x5151);
+
+ /* Work around for RxFIFO overflow. */
+ if (tp->mac_version == RTL_GIGA_MAC_VER_11) {
+ tp->intr_event |= RxFIFOOver | PCSTimeout;
+ tp->intr_event &= ~RxOverflow;
+ }
+
+ rtl_set_rx_tx_desc_registers(tp, ioaddr);
+
+ rtl_set_rx_mode(dev);
+
+ RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
+ (InterFrameGap << TxInterFrameGapShift));
+
+ RTL_R8(IntrMask);
+
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_11:
+ rtl_hw_start_8168bb(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_12:
+ case RTL_GIGA_MAC_VER_17:
+ rtl_hw_start_8168bef(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_18:
+ rtl_hw_start_8168cp_1(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_19:
+ rtl_hw_start_8168c_1(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_20:
+ rtl_hw_start_8168c_2(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_21:
+ rtl_hw_start_8168c_3(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_22:
+ rtl_hw_start_8168c_4(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_23:
+ rtl_hw_start_8168cp_2(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_24:
+ rtl_hw_start_8168cp_3(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_25:
+ rtl_hw_start_8168d(ioaddr, pdev);
+ break;
+
default:
+ DBG ( "Unknown chipset (mac_version = %d).\n",
+ tp->mac_version );
+ break;
+ }
+
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+ RTL_W8(Cfg9346, Cfg9346_Lock);
+
+ RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000);
+
+ // RTL_W16(IntrMask, tp->intr_event);
+}
+
+#define R810X_CPCMD_QUIRK_MASK (\
+ EnableBist | \
+ Mac_dbgo_oe | \
+ Force_half_dup | \
+ Force_half_dup | \
+ Force_txflow_en | \
+ Cxpl_dbg_sel | \
+ ASF | \
+ PktCntrDisable | \
+ PCIDAC | \
+ PCIMulRW)
+
+static void rtl_hw_start_8102e_1(void *ioaddr, struct pci_device *pdev)
+{
+ static struct ephy_info e_info_8102e_1[] = {
+ { 0x01, 0, 0x6e65 },
+ { 0x02, 0, 0x091f },
+ { 0x03, 0, 0xc2f9 },
+ { 0x06, 0, 0xafb5 },
+ { 0x07, 0, 0x0e00 },
+ { 0x19, 0, 0xec80 },
+ { 0x01, 0, 0x2e65 },
+ { 0x01, 0, 0x6e65 }
+ };
+ u8 cfg1;
+
+ DBGP ( "rtl_hw_start_8102e_1\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ RTL_W8(DBG_REG, FIX_NAK_1);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ RTL_W8(Config1,
+ LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable);
+ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+ cfg1 = RTL_R8(Config1);
+ if ((cfg1 & LEDS0) && (cfg1 & LEDS1))
+ RTL_W8(Config1, cfg1 & ~LEDS0);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK);
+
+ rtl_ephy_init(ioaddr, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1));
+}
+
+static void rtl_hw_start_8102e_2(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8102e_2\n" );
+
+ rtl_csi_access_enable(ioaddr);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable);
+ RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
+
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK);
+}
+
+static void rtl_hw_start_8102e_3(void *ioaddr, struct pci_device *pdev)
+{
+ DBGP ( "rtl_hw_start_8102e_3\n" );
+
+ rtl_hw_start_8102e_2(ioaddr, pdev);
+
+ rtl_ephy_write(ioaddr, 0x03, 0xc2f9);
+}
+
+static void rtl_hw_start_8101(struct net_device *dev)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ void *ioaddr = tp->mmio_addr;
+ struct pci_device *pdev = tp->pci_dev;
+
+ DBGP ( "rtl_hw_start_8101\n" );
+
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_16)) {
+ int cap = tp->pcie_cap;
+
+ if (cap) {
+ pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL,
+ PCI_EXP_DEVCTL_NOSNOOP_EN);
+ }
+ }
+
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_07:
+ rtl_hw_start_8102e_1(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_08:
+ rtl_hw_start_8102e_3(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_09:
+ rtl_hw_start_8102e_2(ioaddr, pdev);
+ break;
+ }
+
+ RTL_W8(Cfg9346, Cfg9346_Unlock);
+
+ RTL_W8(EarlyTxThres, EarlyTxThld);
+
+ rtl_set_rx_max_size(ioaddr);
+
+ tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
+
+ RTL_W16(CPlusCmd, tp->cp_cmd);
+
+ RTL_W16(IntrMitigate, 0x0000);
+
+ rtl_set_rx_tx_desc_registers(tp, ioaddr);
+
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+ rtl_set_rx_tx_config_registers(tp);
+
+ RTL_W8(Cfg9346, Cfg9346_Lock);
+
+ RTL_R8(IntrMask);
+
+ rtl_set_rx_mode(dev);
+
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
+ RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000);
+
+ // RTL_W16(IntrMask, tp->intr_event);
+}
+
+/*** gPXE API Support Routines ***/
+
+/**
+ * setup_tx_resources - allocate tx resources (descriptors)
+ *
+ * @v tp Driver private storage
+ *
+ * @ret rc Returns 0 on success, negative on failure
+ **/
+static int
+rtl8169_setup_tx_resources ( struct rtl8169_private *tp )
+{
+ DBGP ( "rtl8169_setup_tx_resources\n" );
+
+ tp->tx_base = malloc_dma ( R8169_TX_RING_BYTES, TX_RING_ALIGN );
+
+ if ( ! tp->tx_base ) {
+ return -ENOMEM;
+ }
+
+ memset ( tp->tx_base, 0, R8169_TX_RING_BYTES );
+
+ DBG ( "tp->tx_base = %#08lx\n", virt_to_bus ( tp->tx_base ) );
+
+ tp->tx_fill_ctr = 0;
+ tp->tx_curr = 0;
+ tp->tx_tail = 0;
+
+ return 0;
+}
+
+static void
+rtl8169_process_tx_packets ( struct net_device *netdev )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+
+ uint32_t tx_status;
+ struct TxDesc *tx_curr_desc;
+
+ DBGP ( "rtl8169_process_tx_packets\n" );
+
+ while ( tp->tx_tail != tp->tx_curr ) {
+
+ tx_curr_desc = tp->tx_base + tp->tx_tail;
+
+ tx_status = tx_curr_desc->opts1;
+
+ DBG2 ( "Before DescOwn check tx_status: %#08x\n", tx_status );
+
+ /* if the packet at tx_tail is not owned by hardware it is for us */
+ if ( tx_status & DescOwn )
+ break;
+
+ DBG ( "Transmitted packet.\n" );
+ DBG ( "tp->tx_fill_ctr = %d\n", tp->tx_fill_ctr );
+ DBG ( "tp->tx_tail = %d\n", tp->tx_tail );
+ DBG ( "tp->tx_curr = %d\n", tp->tx_curr );
+ DBG ( "tx_status = %d\n", tx_status );
+ DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
+
+ /* Pass packet to core for processing */
+ netdev_tx_complete ( netdev, tp->tx_iobuf[tp->tx_tail] );
+
+ memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) );
+
+ /* Decrement count of used descriptors */
+ tp->tx_fill_ctr--;
+
+ /* Increment sent packets index */
+ tp->tx_tail = ( tp->tx_tail + 1 ) % NUM_TX_DESC;
+ }
+}
+
+static void
+rtl8169_free_tx_resources ( struct rtl8169_private *tp )
+{
+ DBGP ( "rtl8169_free_tx_resources\n" );
+
+ free_dma ( tp->tx_base, R8169_TX_RING_BYTES );
+}
+
+static void
+rtl8169_populate_rx_descriptor ( struct rtl8169_private *tp, struct RxDesc *rx_desc, uint32_t index )
+{
+ DBGP ( "rtl8169_populate_rx_descriptor\n" );
+
+ DBG ( "Populating rx descriptor %d\n", index );
+
+ memset ( rx_desc, 0, sizeof ( *rx_desc ) );
+
+ rx_desc->addr_hi = 0;
+ rx_desc->addr_lo = virt_to_bus ( tp->rx_iobuf[index]->data );
+ rx_desc->opts2 = 0;
+ rx_desc->opts1 = ( index == ( NUM_RX_DESC - 1 ) ? RingEnd : 0 ) |
+ RX_BUF_SIZE;
+ rx_desc->opts1 |= DescOwn;
+}
+
+/**
+ * Refill descriptor ring
+ *
+ * @v netdev Net device
+ */
+static void rtl8169_refill_rx_ring ( struct rtl8169_private *tp )
+{
+ struct RxDesc *rx_curr_desc;
+ int i;
+
+ DBGP ( "rtl8169_refill_rx_ring\n" );
+
+ for ( i = 0; i < NUM_RX_DESC; i++ ) {
+
+ rx_curr_desc = ( tp->rx_base ) + i;
+
+ /* Don't touch descriptors owned by the NIC */
+ if ( rx_curr_desc->opts1 & DescOwn )
+ continue;
+
+ /* Don't touch descriptors with iobufs, they still need to be
+ processed by the poll routine */
+ if ( tp->rx_iobuf[tp->rx_curr] != NULL )
+ continue;
+
+ /** If we can't get an iobuf for this descriptor
+ try again later (next poll).
+ */
+ if ( ! ( tp->rx_iobuf[i] = alloc_iob ( RX_BUF_SIZE ) ) ) {
+ DBG ( "Refill rx ring failed!!\n" );
+ break;
+ }
+
+ rtl8169_populate_rx_descriptor ( tp, rx_curr_desc, i );
+ }
+}
+
+/**
+ * setup_rx_resources - allocate Rx resources (Descriptors)
+ *
+ * @v tp: Driver private structure
+ *
+ * @ret rc Returns 0 on success, negative on failure
+ *
+ **/
+static int
+rtl8169_setup_rx_resources ( struct rtl8169_private *tp )
+{
+ DBGP ( "rtl8169_setup_rx_resources\n" );
+
+ tp->rx_base = malloc_dma ( R8169_RX_RING_BYTES, RX_RING_ALIGN );
+
+ DBG ( "tp->rx_base = %#08lx\n", virt_to_bus ( tp->rx_base ) );
+
+ if ( ! tp->rx_base ) {
+ return -ENOMEM;
+ }
+ memset ( tp->rx_base, 0, R8169_RX_RING_BYTES );
+
+ rtl8169_refill_rx_ring ( tp );
+
+ tp->rx_curr = 0;
+
+ return 0;
+}
+
+static void
+rtl8169_process_rx_packets ( struct net_device *netdev )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ uint32_t rx_status;
+ uint16_t rx_len;
+ struct RxDesc *rx_curr_desc;
+ int i;
+
+ DBGP ( "rtl8169_process_rx_packets\n" );
+
+ for ( i = 0; i < NUM_RX_DESC; i++ ) {
+
+ rx_curr_desc = tp->rx_base + tp->rx_curr;
+
+ rx_status = rx_curr_desc->opts1;
+
+ DBG2 ( "Before DescOwn check rx_status: %#08x\n", rx_status );
+
+ /* Hardware still owns the descriptor */
+ if ( rx_status & DescOwn )
+ break;
+
+ /* We own the descriptor, but it has not been refilled yet */
+ if ( tp->rx_iobuf[tp->rx_curr] == NULL )
+ break;
+
+ rx_len = rx_status & 0x3fff;
+
+ DBG ( "Received packet.\n" );
+ DBG ( "tp->rx_curr = %d\n", tp->rx_curr );
+ DBG ( "rx_len = %d\n", rx_len );
+ DBG ( "rx_status = %#08x\n", rx_status );
+ DBG ( "rx_curr_desc = %#08lx\n", virt_to_bus ( rx_curr_desc ) );
+
+ if ( rx_status & RxRES ) {
+
+ netdev_rx_err ( netdev, tp->rx_iobuf[tp->rx_curr], -EINVAL );
+
+ DBG ( "rtl8169_poll: Corrupted packet received!\n"
+ " rx_status: %#08x\n", rx_status );
+
+ } else {
+
+ /* Adjust size of the iobuf to reflect received data */
+ iob_put ( tp->rx_iobuf[tp->rx_curr], rx_len );
+
+ /* Add this packet to the receive queue. */
+ netdev_rx ( netdev, tp->rx_iobuf[tp->rx_curr] );
+ }
+
+ /* Invalidate this iobuf and descriptor */
+ tp->rx_iobuf[tp->rx_curr] = NULL;
+ memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) );
+
+ /* Update pointer to next available rx descriptor */
+ tp->rx_curr = ( tp->rx_curr + 1 ) % NUM_RX_DESC;
+ }
+ rtl8169_refill_rx_ring ( tp );
+}
+
+static void
+rtl8169_free_rx_resources ( struct rtl8169_private *tp )
+{
+ int i;
+
+ DBGP ( "rtl8169_free_rx_resources\n" );
+
+ free_dma ( tp->rx_base, R8169_RX_RING_BYTES );
+
+ for ( i = 0; i < NUM_RX_DESC; i++ ) {
+ free_iob ( tp->rx_iobuf[i] );
+ tp->rx_iobuf[i] = NULL;
+ }
+}
+
+/**
+ FIXME: Because gPXE's pci_device_id structure does not contain a
+ field to contain arbitrary data, we need the following table to
+ associate PCI IDs with nic variants, because a lot of driver
+ routines depend on knowing which kind of variant they are dealing
+ with. --mdc
+ **/
+
+#define _R(VENDOR,DEVICE,INDEX) \
+ { .vendor = VENDOR, .device = DEVICE, .index = INDEX }
+
+static const struct {
+ uint16_t vendor;
+ uint16_t device;
+ int index;
+} nic_variant_table[] = {
+ _R(0x10ec, 0x8129, RTL_CFG_0),
+ _R(0x10ec, 0x8136, RTL_CFG_2),
+ _R(0x10ec, 0x8167, RTL_CFG_0),
+ _R(0x10ec, 0x8168, RTL_CFG_1),
+ _R(0x10ec, 0x8169, RTL_CFG_0),
+ _R(0x1186, 0x4300, RTL_CFG_0),
+ _R(0x1259, 0xc107, RTL_CFG_0),
+ _R(0x16ec, 0x0116, RTL_CFG_0),
+ _R(0x1737, 0x1032, RTL_CFG_0),
+ _R(0x0001, 0x8168, RTL_CFG_2),
+};
+#undef _R
+
+static int
+rtl8169_get_nic_variant ( uint16_t vendor, uint16_t device )
+{
+ u32 i;
+
+ DBGP ( "rtl8169_get_nic_variant\n" );
+
+ for (i = 0; i < ARRAY_SIZE(nic_variant_table); i++) {
+ if ( ( nic_variant_table[i].vendor == vendor ) &&
+ ( nic_variant_table[i].device == device ) ) {
+ return ( nic_variant_table[i].index );
+ }
+ }
+ DBG ( "No matching NIC variant found!\n" );
+ return ( RTL_CFG_0 );
+}
+
+static void rtl8169_irq_enable ( struct rtl8169_private *tp )
+{
+ void *ioaddr = tp->mmio_addr;
+
+ DBGP ( "rtl8169_irq_enable\n" );
+
+ RTL_W16 ( IntrMask, tp->intr_event );
+}
+
+static void rtl8169_irq_disable ( struct rtl8169_private *tp )
+{
+ void *ioaddr = tp->mmio_addr;
+
+ DBGP ( "rtl8169_irq_disable\n" );
+
+ rtl8169_irq_mask_and_ack ( ioaddr );
+}
+
+/*** gPXE Core API Routines ***/
+
+/**
+ * open - Called when a network interface is made active
+ *
+ * @v netdev network interface device structure
+ * @ret rc Return status code, 0 on success, negative value on failure
+ *
+ **/
+static int
+rtl8169_open ( struct net_device *netdev )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ void *ioaddr = tp->mmio_addr;
+ int rc;
+
+ DBGP ( "rtl8169_open\n" );
+
+ /* allocate transmit descriptors */
+ rc = rtl8169_setup_tx_resources ( tp );
+ if ( rc ) {
+ DBG ( "Error setting up TX resources!\n" );
+ goto err_setup_tx;
+ }
+
+ /* allocate receive descriptors */
+ rc = rtl8169_setup_rx_resources ( tp );
+ if ( rc ) {
+ DBG ( "Error setting up RX resources!\n" );
+ goto err_setup_rx;
+ }
+
+ rtl_hw_start ( netdev );
+
+ DBG ( "TxDescStartAddrHigh = %#08lx\n", RTL_R32 ( TxDescStartAddrHigh ) );
+ DBG ( "TxDescStartAddrLow = %#08lx\n", RTL_R32 ( TxDescStartAddrLow ) );
+ DBG ( "RxDescAddrHigh = %#08lx\n", RTL_R32 ( RxDescAddrHigh ) );
+ DBG ( "RxDescAddrLow = %#08lx\n", RTL_R32 ( RxDescAddrLow ) );
+
+ return 0;
+
+err_setup_rx:
+ rtl8169_free_tx_resources ( tp );
+err_setup_tx:
+ rtl8169_hw_reset ( ioaddr );
+
+ return rc;
+}
+
+/**
+ * transmit - Transmit a packet
+ *
+ * @v netdev Network device
+ * @v iobuf I/O buffer
+ *
+ * @ret rc Returns 0 on success, negative on failure
+ */
+static int
+rtl8169_transmit ( struct net_device *netdev, struct io_buffer *iobuf )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ void *ioaddr = tp->mmio_addr;
+ uint32_t tx_len = iob_len ( iobuf );
+
+ struct TxDesc *tx_curr_desc;
+
+ DBGP ("rtl8169_transmit\n");
+
+ if ( tp->tx_fill_ctr == NUM_TX_DESC ) {
+ DBG ("TX overflow\n");
+ return -ENOBUFS;
+ }
+
+ /**
+ * The rtl8169 family automatically pads short packets to a
+ * minimum size, but if it did not, like some older cards,
+ * we could do:
+ * iob_pad ( iobuf, ETH_ZLEN );
+ */
+
+ /* Save pointer to this iobuf we have been given to transmit so
+ we can pass it to netdev_tx_complete() later */
+ tp->tx_iobuf[tp->tx_curr] = iobuf;
+
+ tx_curr_desc = tp->tx_base + tp->tx_curr;
+
+ DBG ( "tp->tx_fill_ctr = %d\n", tp->tx_fill_ctr );
+ DBG ( "tp->tx_curr = %d\n", tp->tx_curr );
+ DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) );
+ DBG ( "iobuf->data = %#08lx\n", virt_to_bus ( iobuf->data ) );
+ DBG ( "tx_len = %d\n", tx_len );
+
+ /* Configure current descriptor to transmit supplied packet */
+ tx_curr_desc->addr_hi = 0;
+ tx_curr_desc->addr_lo = virt_to_bus ( iobuf->data );
+ tx_curr_desc->opts2 = 0;
+ tx_curr_desc->opts1 = FirstFrag | LastFrag |
+ ( tp->tx_curr == ( NUM_TX_DESC - 1 ) ? RingEnd : 0 ) |
+ tx_len;
+
+ /* Mark descriptor as owned by NIC */
+ tx_curr_desc->opts1 |= DescOwn;
+
+ DBG ( "tx_curr_desc->opts1 = %#08x\n", tx_curr_desc->opts1 );
+ DBG ( "tx_curr_desc->opts2 = %#08x\n", tx_curr_desc->opts2 );
+ DBG ( "tx_curr_desc->addr_hi = %#08x\n", tx_curr_desc->addr_hi );
+ DBG ( "tx_curr_desc->addr_lo = %#08x\n", tx_curr_desc->addr_lo );
+
+ RTL_W8 ( TxPoll, NPQ ); /* set polling bit */
+
+ /* Point to next free descriptor */
+ tp->tx_curr = ( tp->tx_curr + 1 ) % NUM_TX_DESC;
+
+ /* Increment number of tx descriptors in use */
+ tp->tx_fill_ctr++;
+
+ return 0;
+}
+
+/**
+ * poll - Poll for received packets
+ *
+ * @v netdev Network device
+ */
+static void
+rtl8169_poll ( struct net_device *netdev )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ void *ioaddr = tp->mmio_addr;
+
+ uint16_t intr_status;
+ uint16_t intr_mask;
+
+ DBGP ( "rtl8169_poll\n" );
+
+ intr_status = RTL_R16 ( IntrStatus );
+ intr_mask = RTL_R16 ( IntrMask );
+
+ DBG2 ( "rtl8169_poll (before): intr_mask = %#04x intr_status = %#04x\n",
+ intr_mask, intr_status );
+
+ RTL_W16 ( IntrStatus, 0xffff );
+
+ /* hotplug / major error / no more work / shared irq */
+ if ( intr_status == 0xffff )
+ return;
+
+ /* Process transmitted packets */
+ rtl8169_process_tx_packets ( netdev );
+
+ /* Process received packets */
+ rtl8169_process_rx_packets ( netdev );
+}
+
+/**
+ * close - Disable network interface
+ *
+ * @v netdev network interface device structure
+ *
+ **/
+static void
+rtl8169_close ( struct net_device *netdev )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ void *ioaddr = tp->mmio_addr;
+
+ DBGP ( "r8169_close\n" );
+
+ rtl8169_hw_reset ( ioaddr );
+
+ rtl8169_free_tx_resources ( tp );
+ rtl8169_free_rx_resources ( tp );
+}
+
+/**
+ * irq - enable or Disable interrupts
+ *
+ * @v netdev network adapter
+ * @v action requested interrupt action
+ *
+ **/
+static void
+rtl8169_irq ( struct net_device *netdev, int action )
+{
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+
+ DBGP ( "rtl8169_irq\n" );
+
+ switch ( action ) {
+ case 0 :
+ rtl8169_irq_disable ( tp );
+ break;
+ default :
+ rtl8169_irq_enable ( tp );
break;
}
}
-DRIVER ( "r8169/PCI", nic_driver, pci_driver, r8169_driver,
- r8169_probe, r8169_disable );
+static struct net_device_operations rtl8169_operations = {
+ .open = rtl8169_open,
+ .transmit = rtl8169_transmit,
+ .poll = rtl8169_poll,
+ .close = rtl8169_close,
+ .irq = rtl8169_irq,
+};
+
+/**
+ * probe - Initial configuration of NIC
+ *
+ * @v pci PCI device
+ * @v id PCI IDs
+ *
+ * @ret rc Return status code
+ **/
+static int
+rtl8169_probe ( struct pci_device *pdev, const struct pci_device_id *ent )
+{
+ int i, rc;
+ struct net_device *netdev;
+ struct rtl8169_private *tp;
+ void *ioaddr;
+
+ /** FIXME: This lookup is necessary because gPXE does not have a "data"
+ element in the structure pci_device_id which can pass an arbitrary
+ piece of data to the driver. It might be useful to add it. Then we
+ could just use ent->data instead of having to look up cfg_index.
+ **/
+ int cfg_index = rtl8169_get_nic_variant ( ent->vendor, ent->device );
+ const struct rtl_cfg_info *cfg = rtl_cfg_infos + cfg_index;
+
+ DBGP ( "rtl8169_probe\n" );
+
+ DBG ( "ent->vendor = %#04x, ent->device = %#04x\n", ent->vendor, ent->device );
+
+ DBG ( "cfg_index = %d\n", cfg_index );
+ DBG ( "cfg->intr_event = %#04x\n", cfg->intr_event );
+
+ rc = -ENOMEM;
+
+ /* Allocate net device ( also allocates memory for netdev->priv
+ and makes netdev-priv point to it )
+ */
+ netdev = alloc_etherdev ( sizeof ( *tp ) );
+
+ if ( ! netdev )
+ goto err_alloc_etherdev;
+
+ /* Associate driver-specific network operations with
+ generic network device layer
+ */
+ netdev_init ( netdev, &rtl8169_operations );
+
+ /* Associate this network device with the given PCI device */
+ pci_set_drvdata ( pdev, netdev );
+ netdev->dev = &pdev->dev;
+
+ /* Initialize driver private storage */
+ tp = netdev_priv ( netdev );
+ memset ( tp, 0, ( sizeof ( *tp ) ) );
+
+ tp->pci_dev = pdev;
+ tp->irqno = pdev->irq;
+ tp->netdev = netdev;
+ tp->cfg_index = cfg_index;
+ tp->intr_event = cfg->intr_event;
+ tp->cp_cmd = PCIMulRW;
+
+ tp->hw_start = cfg->hw_start;
+
+ rc = -EIO;
+
+ adjust_pci_device ( pdev );
+
+ /* ioremap MMIO region */
+ ioaddr = ioremap ( pdev->membase, R8169_REGS_SIZE );
+
+ if ( ! ioaddr ) {
+ DBG ( "cannot remap MMIO\n" );
+ rc = -EIO;
+ goto err_ioremap;
+ }
+
+ tp->mmio_addr = ioaddr;
+
+ tp->pcie_cap = pci_find_capability ( pdev, PCI_CAP_ID_EXP );
+ if ( tp->pcie_cap ) {
+ DBG ( "PCI Express capability\n" );
+ } else {
+ DBG ( "No PCI Express capability\n" );
+ }
+
+ /* Mask interrupts just in case */
+ rtl8169_irq_mask_and_ack ( ioaddr );
+
+ /* Soft reset NIC */
+ rtl_soft_reset ( netdev );
+
+ /* Identify chip attached to board */
+ rtl8169_get_mac_version ( tp, ioaddr );
+
+ for ( i = 0; (u32) i < ARRAY_SIZE ( rtl_chip_info ); i++ ) {
+ if ( tp->mac_version == rtl_chip_info[i].mac_version )
+ break;
+ }
+ if ( i == ARRAY_SIZE(rtl_chip_info ) ) {
+ /* Unknown chip: assume array element #0, original RTL-8169 */
+ DBG ( "Unknown chip version, assuming %s\n", rtl_chip_info[0].name );
+ i = 0;
+ }
+ tp->chipset = i;
+
+ if ((tp->mac_version <= RTL_GIGA_MAC_VER_06) &&
+ (RTL_R8(PHYstatus) & TBI_Enable)) {
+ tp->set_speed = rtl8169_set_speed_tbi;
+ tp->phy_reset_enable = rtl8169_tbi_reset_enable;
+ tp->phy_reset_pending = rtl8169_tbi_reset_pending;
+ tp->link_ok = rtl8169_tbi_link_ok;
+
+ tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */
+ } else {
+ tp->set_speed = rtl8169_set_speed_xmii;
+ tp->phy_reset_enable = rtl8169_xmii_reset_enable;
+ tp->phy_reset_pending = rtl8169_xmii_reset_pending;
+ tp->link_ok = rtl8169_xmii_link_ok;
+ }
+
+ /* Get MAC address */
+ for ( i = 0; i < MAC_ADDR_LEN; i++ )
+ netdev->ll_addr[i] = RTL_R8 ( MAC0 + i );
+
+ DBG ( "%s\n", eth_ntoa ( netdev->ll_addr ) );
+
+ rtl8169_init_phy ( netdev, tp );
+
+ if ( ( rc = register_netdev ( netdev ) ) != 0 )
+ goto err_register;
+
+ /* Mark as link up; we don't yet handle link state */
+ netdev_link_up ( netdev );
+
+ DBG ( "rtl8169_probe succeeded!\n" );
+
+ /* No errors, return success */
+ return 0;
+
+/* Error return paths */
+err_register:
+err_ioremap:
+ netdev_put ( netdev );
+err_alloc_etherdev:
+ return rc;
+}
+
+/**
+ * remove - Device Removal Routine
+ *
+ * @v pdev PCI device information struct
+ *
+ **/
+static void
+rtl8169_remove ( struct pci_device *pdev )
+{
+ struct net_device *netdev = pci_get_drvdata ( pdev );
+ struct rtl8169_private *tp = netdev_priv ( netdev );
+ void *ioaddr = tp->mmio_addr;
+
+ DBGP ( "rtl8169_remove\n" );
+
+ rtl8169_hw_reset ( ioaddr );
+
+ unregister_netdev ( netdev );
+ netdev_nullify ( netdev );
+ netdev_put ( netdev );
+}
+
+static struct pci_device_id rtl8169_nics[] = {
+ PCI_ROM(0x10ec, 0x8129, "rtl8169-0x8129", "rtl8169-0x8129"),
+ PCI_ROM(0x10ec, 0x8136, "rtl8169-0x8136", "rtl8169-0x8136"),
+ PCI_ROM(0x10ec, 0x8167, "rtl8169-0x8167", "rtl8169-0x8167"),
+ PCI_ROM(0x10ec, 0x8168, "rtl8169-0x8168", "rtl8169-0x8168"),
+ PCI_ROM(0x10ec, 0x8169, "rtl8169-0x8169", "rtl8169-0x8169"),
+ PCI_ROM(0x1186, 0x4300, "rtl8169-0x4300", "rtl8169-0x4300"),
+ PCI_ROM(0x1259, 0xc107, "rtl8169-0xc107", "rtl8169-0xc107"),
+ PCI_ROM(0x16ec, 0x0116, "rtl8169-0x0116", "rtl8169-0x0116"),
+ PCI_ROM(0x1737, 0x1032, "rtl8169-0x1032", "rtl8169-0x1032"),
+ PCI_ROM(0x0001, 0x8168, "rtl8169-0x8168", "rtl8169-0x8168"),
+};
+
+struct pci_driver rtl8169_driver __pci_driver = {
+ .ids = rtl8169_nics,
+ .id_count = ( sizeof ( rtl8169_nics ) / sizeof ( rtl8169_nics[0] ) ),
+ .probe = rtl8169_probe,
+ .remove = rtl8169_remove,
+};
/*
* Local variables:
diff --git a/gpxe/src/drivers/net/r8169.h b/gpxe/src/drivers/net/r8169.h
new file mode 100644
index 00000000..d3536326
--- /dev/null
+++ b/gpxe/src/drivers/net/r8169.h
@@ -0,0 +1,566 @@
+/*
+ * Copyright (c) 2008 Marty Connor <mdc@etherboot.org>
+ * Copyright (c) 2008 Entity Cyber, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * This driver is based on rtl8169 data sheets and work by:
+ *
+ * Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
+ * Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
+ * Copyright (c) a lot of people too. Please respect their work.
+ *
+ */
+
+#ifndef _R8169_H_
+#define _R8169_H_
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+/** FIXME: include/linux/pci_regs.h has these PCI regs, maybe
+ we need such a file in gPXE?
+**/
+#define PCI_EXP_DEVCTL 8 /* Device Control */
+#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */
+#define PCI_EXP_LNKCTL 16 /* Link Control */
+#define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */
+#define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */
+
+/** FIXME: update mii.h in src/include/mii.h from Linux sources
+ so we don't have to include these definitiions.
+**/
+/* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */
+#define SPEED_10 10
+#define SPEED_100 100
+#define SPEED_1000 1000
+#define SPEED_2500 2500
+#define SPEED_10000 10000
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF 0x00
+#define DUPLEX_FULL 0x01
+
+/* Generic MII registers. */
+
+#define MII_BMCR 0x00 /* Basic mode control register */
+#define MII_BMSR 0x01 /* Basic mode status register */
+#define MII_PHYSID1 0x02 /* PHYS ID 1 */
+#define MII_PHYSID2 0x03 /* PHYS ID 2 */
+#define MII_ADVERTISE 0x04 /* Advertisement control reg */
+#define MII_LPA 0x05 /* Link partner ability reg */
+#define MII_EXPANSION 0x06 /* Expansion register */
+#define MII_CTRL1000 0x09 /* 1000BASE-T control */
+#define MII_STAT1000 0x0a /* 1000BASE-T status */
+#define MII_ESTATUS 0x0f /* Extended Status */
+#define MII_DCOUNTER 0x12 /* Disconnect counter */
+#define MII_FCSCOUNTER 0x13 /* False carrier counter */
+#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */
+#define MII_RERRCOUNTER 0x15 /* Receive error counter */
+#define MII_SREVISION 0x16 /* Silicon revision */
+#define MII_RESV1 0x17 /* Reserved... */
+#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */
+#define MII_PHYADDR 0x19 /* PHY address */
+#define MII_RESV2 0x1a /* Reserved... */
+#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */
+#define MII_NCONFIG 0x1c /* Network interface config */
+
+/* Basic mode control register. */
+#define BMCR_RESV 0x003f /* Unused... */
+#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */
+#define BMCR_CTST 0x0080 /* Collision test */
+#define BMCR_FULLDPLX 0x0100 /* Full duplex */
+#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */
+#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */
+#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */
+#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */
+#define BMCR_SPEED100 0x2000 /* Select 100Mbps */
+#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */
+#define BMCR_RESET 0x8000 /* Reset the DP83840 */
+
+/* Basic mode status register. */
+#define BMSR_ERCAP 0x0001 /* Ext-reg capability */
+#define BMSR_JCD 0x0002 /* Jabber detected */
+#define BMSR_LSTATUS 0x0004 /* Link status */
+#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */
+#define BMSR_RFAULT 0x0010 /* Remote fault detected */
+#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */
+#define BMSR_RESV 0x00c0 /* Unused... */
+#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */
+#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */
+#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */
+#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */
+#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */
+#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */
+#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */
+#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */
+
+#define AUTONEG_DISABLE 0x00
+#define AUTONEG_ENABLE 0x01
+
+#define MII_ADVERTISE 0x04 /* Advertisement control reg */
+#define ADVERTISE_SLCT 0x001f /* Selector bits */
+#define ADVERTISE_CSMA 0x0001 /* Only selector supported */
+#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
+#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */
+#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
+#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */
+#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
+#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */
+#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
+#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */
+#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
+#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */
+#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */
+#define ADVERTISE_RESV 0x1000 /* Unused... */
+#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */
+#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */
+#define ADVERTISE_NPAGE 0x8000 /* Next page bit */
+#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
+ ADVERTISE_CSMA)
+#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
+ ADVERTISE_100HALF | ADVERTISE_100FULL)
+
+/* 1000BASE-T Control register */
+#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */
+#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */
+
+/* MAC address length */
+#define MAC_ADDR_LEN 6
+
+#define MAX_READ_REQUEST_SHIFT 12
+#define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */
+#define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
+#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
+#define EarlyTxThld 0x3F /* 0x3F means NO early transmit */
+#define RxPacketMaxSize 0x3FE8 /* 16K - 1 - ETH_HLEN - VLAN - CRC... */
+#define SafeMtu 0x1c20 /* ... actually life sucks beyond ~7k */
+#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
+
+#define R8169_REGS_SIZE 256
+#define R8169_NAPI_WEIGHT 64
+#define NUM_TX_DESC 8 /* Number of Tx descriptor registers */
+#define NUM_RX_DESC 8 /* Number of Rx descriptor registers */
+#define RX_BUF_SIZE 1536 /* Rx Buffer size */
+#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc))
+#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc))
+
+#define TX_RING_ALIGN 256
+#define RX_RING_ALIGN 256
+
+#define RTL8169_TX_TIMEOUT (6*HZ)
+#define RTL8169_PHY_TIMEOUT (10*HZ)
+
+#define RTL_EEPROM_SIG cpu_to_le32(0x8129)
+#define RTL_EEPROM_SIG_MASK cpu_to_le32(0xffff)
+#define RTL_EEPROM_SIG_ADDR 0x0000
+
+/* write/read MMIO register */
+#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg))
+#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg))
+#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg))
+#define RTL_R8(reg) readb (ioaddr + (reg))
+#define RTL_R16(reg) readw (ioaddr + (reg))
+#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg)))
+
+enum mac_version {
+ RTL_GIGA_MAC_VER_01 = 0x01, // 8169
+ RTL_GIGA_MAC_VER_02 = 0x02, // 8169S
+ RTL_GIGA_MAC_VER_03 = 0x03, // 8110S
+ RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB
+ RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd
+ RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe
+ RTL_GIGA_MAC_VER_07 = 0x07, // 8102e
+ RTL_GIGA_MAC_VER_08 = 0x08, // 8102e
+ RTL_GIGA_MAC_VER_09 = 0x09, // 8102e
+ RTL_GIGA_MAC_VER_10 = 0x0a, // 8101e
+ RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb
+ RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be
+ RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb
+ RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 ?
+ RTL_GIGA_MAC_VER_15 = 0x0f, // 8101 ?
+ RTL_GIGA_MAC_VER_16 = 0x11, // 8101Ec
+ RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf
+ RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP
+ RTL_GIGA_MAC_VER_19 = 0x13, // 8168C
+ RTL_GIGA_MAC_VER_20 = 0x14, // 8168C
+ RTL_GIGA_MAC_VER_21 = 0x15, // 8168C
+ RTL_GIGA_MAC_VER_22 = 0x16, // 8168C
+ RTL_GIGA_MAC_VER_23 = 0x17, // 8168CP
+ RTL_GIGA_MAC_VER_24 = 0x18, // 8168CP
+ RTL_GIGA_MAC_VER_25 = 0x19, // 8168D
+};
+
+#define _R(NAME,MAC,MASK) \
+ { .name = NAME, .mac_version = MAC, .RxConfigMask = MASK }
+
+static const struct {
+ const char *name;
+ u8 mac_version;
+ u32 RxConfigMask; /* Clears the bits supported by this chip */
+} rtl_chip_info[] = {
+ _R("RTL8169", RTL_GIGA_MAC_VER_01, 0xff7e1880), // 8169
+ _R("RTL8169s", RTL_GIGA_MAC_VER_02, 0xff7e1880), // 8169S
+ _R("RTL8110s", RTL_GIGA_MAC_VER_03, 0xff7e1880), // 8110S
+ _R("RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880), // 8169SB
+ _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_05, 0xff7e1880), // 8110SCd
+ _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_06, 0xff7e1880), // 8110SCe
+ _R("RTL8102e", RTL_GIGA_MAC_VER_07, 0xff7e1880), // PCI-E
+ _R("RTL8102e", RTL_GIGA_MAC_VER_08, 0xff7e1880), // PCI-E
+ _R("RTL8102e", RTL_GIGA_MAC_VER_09, 0xff7e1880), // PCI-E
+ _R("RTL8101e", RTL_GIGA_MAC_VER_10, 0xff7e1880), // PCI-E
+ _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880), // PCI-E
+ _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E
+ _R("RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139
+ _R("RTL8100e", RTL_GIGA_MAC_VER_14, 0xff7e1880), // PCI-E 8139
+ _R("RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880), // PCI-E 8139
+ _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_17, 0xff7e1880), // PCI-E
+ _R("RTL8101e", RTL_GIGA_MAC_VER_16, 0xff7e1880), // PCI-E
+ _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, 0xff7e1880), // PCI-E
+ _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_19, 0xff7e1880), // PCI-E
+ _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_20, 0xff7e1880), // PCI-E
+ _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_21, 0xff7e1880), // PCI-E
+ _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_22, 0xff7e1880), // PCI-E
+ _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_23, 0xff7e1880), // PCI-E
+ _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_24, 0xff7e1880), // PCI-E
+ _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_25, 0xff7e1880) // PCI-E
+};
+#undef _R
+
+enum cfg_version {
+ RTL_CFG_0 = 0x00,
+ RTL_CFG_1,
+ RTL_CFG_2
+};
+
+#if 0
+/** Device Table from Linux Driver **/
+static struct pci_device_id rtl8169_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_2 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_1 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_AT, 0xc107), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(0x16ec, 0x0116), 0, 0, RTL_CFG_0 },
+ { PCI_VENDOR_ID_LINKSYS, 0x1032,
+ PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 },
+ { 0x0001, 0x8168,
+ PCI_ANY_ID, 0x2410, 0, 0, RTL_CFG_2 },
+ {0,},
+};
+#endif
+
+enum rtl_registers {
+ MAC0 = 0, /* Ethernet hardware address. */
+ MAC4 = 4,
+ MAR0 = 8, /* Multicast filter. */
+ CounterAddrLow = 0x10,
+ CounterAddrHigh = 0x14,
+ TxDescStartAddrLow = 0x20,
+ TxDescStartAddrHigh = 0x24,
+ TxHDescStartAddrLow = 0x28,
+ TxHDescStartAddrHigh = 0x2c,
+ FLASH = 0x30,
+ ERSR = 0x36,
+ ChipCmd = 0x37,
+ TxPoll = 0x38,
+ IntrMask = 0x3c,
+ IntrStatus = 0x3e,
+ TxConfig = 0x40,
+ RxConfig = 0x44,
+ RxMissed = 0x4c,
+ Cfg9346 = 0x50,
+ Config0 = 0x51,
+ Config1 = 0x52,
+ Config2 = 0x53,
+ Config3 = 0x54,
+ Config4 = 0x55,
+ Config5 = 0x56,
+ MultiIntr = 0x5c,
+ PHYAR = 0x60,
+ PHYstatus = 0x6c,
+ RxMaxSize = 0xda,
+ CPlusCmd = 0xe0,
+ IntrMitigate = 0xe2,
+ RxDescAddrLow = 0xe4,
+ RxDescAddrHigh = 0xe8,
+ EarlyTxThres = 0xec,
+ FuncEvent = 0xf0,
+ FuncEventMask = 0xf4,
+ FuncPresetState = 0xf8,
+ FuncForceEvent = 0xfc,
+};
+
+enum rtl8110_registers {
+ TBICSR = 0x64,
+ TBI_ANAR = 0x68,
+ TBI_LPAR = 0x6a,
+};
+
+enum rtl8168_8101_registers {
+ CSIDR = 0x64,
+ CSIAR = 0x68,
+#define CSIAR_FLAG 0x80000000
+#define CSIAR_WRITE_CMD 0x80000000
+#define CSIAR_BYTE_ENABLE 0x0f
+#define CSIAR_BYTE_ENABLE_SHIFT 12
+#define CSIAR_ADDR_MASK 0x0fff
+
+ EPHYAR = 0x80,
+#define EPHYAR_FLAG 0x80000000
+#define EPHYAR_WRITE_CMD 0x80000000
+#define EPHYAR_REG_MASK 0x1f
+#define EPHYAR_REG_SHIFT 16
+#define EPHYAR_DATA_MASK 0xffff
+ DBG_REG = 0xd1,
+#define FIX_NAK_1 (1 << 4)
+#define FIX_NAK_2 (1 << 3)
+};
+
+enum rtl_register_content {
+ /* InterruptStatusBits */
+ SYSErr = 0x8000,
+ PCSTimeout = 0x4000,
+ SWInt = 0x0100,
+ TxDescUnavail = 0x0080,
+ RxFIFOOver = 0x0040,
+ LinkChg = 0x0020,
+ RxOverflow = 0x0010,
+ TxErr = 0x0008,
+ TxOK = 0x0004,
+ RxErr = 0x0002,
+ RxOK = 0x0001,
+
+ /* RxStatusDesc */
+ RxFOVF = (1 << 23),
+ RxRWT = (1 << 22),
+ RxRES = (1 << 21),
+ RxRUNT = (1 << 20),
+ RxCRC = (1 << 19),
+
+ /* ChipCmdBits */
+ CmdReset = 0x10,
+ CmdRxEnb = 0x08,
+ CmdTxEnb = 0x04,
+ RxBufEmpty = 0x01,
+
+ /* TXPoll register p.5 */
+ HPQ = 0x80, /* Poll cmd on the high prio queue */
+ NPQ = 0x40, /* Poll cmd on the low prio queue */
+ FSWInt = 0x01, /* Forced software interrupt */
+
+ /* Cfg9346Bits */
+ Cfg9346_Lock = 0x00,
+ Cfg9346_Unlock = 0xc0,
+
+ /* rx_mode_bits */
+ AcceptErr = 0x20,
+ AcceptRunt = 0x10,
+ AcceptBroadcast = 0x08,
+ AcceptMulticast = 0x04,
+ AcceptMyPhys = 0x02,
+ AcceptAllPhys = 0x01,
+
+ /* RxConfigBits */
+ RxCfgFIFOShift = 13,
+ RxCfgDMAShift = 8,
+
+ /* TxConfigBits */
+ TxInterFrameGapShift = 24,
+ TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
+
+ /* Config1 register p.24 */
+ LEDS1 = (1 << 7),
+ LEDS0 = (1 << 6),
+ MSIEnable = (1 << 5), /* Enable Message Signaled Interrupt */
+ Speed_down = (1 << 4),
+ MEMMAP = (1 << 3),
+ IOMAP = (1 << 2),
+ VPD = (1 << 1),
+ PMEnable = (1 << 0), /* Power Management Enable */
+
+ /* Config2 register p. 25 */
+ PCI_Clock_66MHz = 0x01,
+ PCI_Clock_33MHz = 0x00,
+
+ /* Config3 register p.25 */
+ MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */
+ LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */
+ Beacon_en = (1 << 0), /* 8168 only. Reserved in the 8168b */
+
+ /* Config5 register p.27 */
+ BWF = (1 << 6), /* Accept Broadcast wakeup frame */
+ MWF = (1 << 5), /* Accept Multicast wakeup frame */
+ UWF = (1 << 4), /* Accept Unicast wakeup frame */
+ LanWake = (1 << 1), /* LanWake enable/disable */
+ PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */
+
+ /* TBICSR p.28 */
+ TBIReset = 0x80000000,
+ TBILoopback = 0x40000000,
+ TBINwEnable = 0x20000000,
+ TBINwRestart = 0x10000000,
+ TBILinkOk = 0x02000000,
+ TBINwComplete = 0x01000000,
+
+ /* CPlusCmd p.31 */
+ EnableBist = (1 << 15), // 8168 8101
+ Mac_dbgo_oe = (1 << 14), // 8168 8101
+ Normal_mode = (1 << 13), // unused
+ Force_half_dup = (1 << 12), // 8168 8101
+ Force_rxflow_en = (1 << 11), // 8168 8101
+ Force_txflow_en = (1 << 10), // 8168 8101
+ Cxpl_dbg_sel = (1 << 9), // 8168 8101
+ ASF = (1 << 8), // 8168 8101
+ PktCntrDisable = (1 << 7), // 8168 8101
+ Mac_dbgo_sel = 0x001c, // 8168
+ RxVlan = (1 << 6),
+ RxChkSum = (1 << 5),
+ PCIDAC = (1 << 4),
+ PCIMulRW = (1 << 3),
+ INTT_0 = 0x0000, // 8168
+ INTT_1 = 0x0001, // 8168
+ INTT_2 = 0x0002, // 8168
+ INTT_3 = 0x0003, // 8168
+
+ /* rtl8169_PHYstatus */
+ TBI_Enable = 0x80,
+ TxFlowCtrl = 0x40,
+ RxFlowCtrl = 0x20,
+ _1000bpsF = 0x10,
+ _100bps = 0x08,
+ _10bps = 0x04,
+ LinkStatus = 0x02,
+ FullDup = 0x01,
+
+ /* _TBICSRBit */
+ TBILinkOK = 0x02000000,
+
+ /* DumpCounterCommand */
+ CounterDump = 0x8,
+};
+
+enum desc_status_bit {
+ DescOwn = (1 << 31), /* Descriptor is owned by NIC */
+ RingEnd = (1 << 30), /* End of descriptor ring */
+ FirstFrag = (1 << 29), /* First segment of a packet */
+ LastFrag = (1 << 28), /* Final segment of a packet */
+
+ /* Tx private */
+ LargeSend = (1 << 27), /* TCP Large Send Offload (TSO) */
+ MSSShift = 16, /* MSS value position */
+ MSSMask = 0xfff, /* MSS value + LargeSend bit: 12 bits */
+ IPCS = (1 << 18), /* Calculate IP checksum */
+ UDPCS = (1 << 17), /* Calculate UDP/IP checksum */
+ TCPCS = (1 << 16), /* Calculate TCP/IP checksum */
+ TxVlanTag = (1 << 17), /* Add VLAN tag */
+
+ /* Rx private */
+ PID1 = (1 << 18), /* Protocol ID bit 1/2 */
+ PID0 = (1 << 17), /* Protocol ID bit 2/2 */
+
+#define RxProtoUDP (PID1)
+#define RxProtoTCP (PID0)
+#define RxProtoIP (PID1 | PID0)
+#define RxProtoMask RxProtoIP
+
+ IPFail = (1 << 16), /* IP checksum failed */
+ UDPFail = (1 << 15), /* UDP/IP checksum failed */
+ TCPFail = (1 << 14), /* TCP/IP checksum failed */
+ RxVlanTag = (1 << 16), /* VLAN tag available */
+};
+
+#define RsvdMask 0x3fffc000
+
+struct TxDesc {
+ volatile uint32_t opts1;
+ volatile uint32_t opts2;
+ volatile uint32_t addr_lo;
+ volatile uint32_t addr_hi;
+};
+
+struct RxDesc {
+ volatile uint32_t opts1;
+ volatile uint32_t opts2;
+ volatile uint32_t addr_lo;
+ volatile uint32_t addr_hi;
+};
+
+enum features {
+ RTL_FEATURE_WOL = (1 << 0),
+ RTL_FEATURE_MSI = (1 << 1),
+ RTL_FEATURE_GMII = (1 << 2),
+};
+
+static void rtl_hw_start_8169(struct net_device *);
+static void rtl_hw_start_8168(struct net_device *);
+static void rtl_hw_start_8101(struct net_device *);
+
+struct rtl8169_private {
+
+ struct pci_device *pci_dev;
+ struct net_device *netdev;
+ uint8_t *hw_addr;
+ void *mmio_addr;
+ uint32_t irqno;
+
+ int chipset;
+ int mac_version;
+ int cfg_index;
+ u16 intr_event;
+
+ struct io_buffer *tx_iobuf[NUM_TX_DESC];
+ struct io_buffer *rx_iobuf[NUM_RX_DESC];
+
+ struct TxDesc *tx_base;
+ struct RxDesc *rx_base;
+
+ uint32_t tx_curr;
+ uint32_t rx_curr;
+
+ uint32_t tx_tail;
+
+ uint32_t tx_fill_ctr;
+
+ u16 cp_cmd;
+
+ int phy_auto_nego_reg;
+ int phy_1000_ctrl_reg;
+
+ int ( *set_speed ) (struct net_device *, u8 autoneg, u16 speed, u8 duplex );
+ void ( *phy_reset_enable ) ( void *ioaddr );
+ void ( *hw_start ) ( struct net_device * );
+ unsigned int ( *phy_reset_pending ) ( void *ioaddr );
+ unsigned int ( *link_ok ) ( void *ioaddr );
+
+ int pcie_cap;
+
+ unsigned features;
+
+};
+
+static const unsigned int rtl8169_rx_config =
+ (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
+
+#endif /* _R8169_H_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * c-indent-level: 8
+ * tab-width: 8
+ * End:
+ */
diff --git a/gpxe/src/drivers/net/rtl8139.c b/gpxe/src/drivers/net/rtl8139.c
index 509047a9..2dff324c 100644
--- a/gpxe/src/drivers/net/rtl8139.c
+++ b/gpxe/src/drivers/net/rtl8139.c
@@ -69,7 +69,8 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
-#include <io.h>
+#include <string.h>
+#include <gpxe/io.h>
#include <errno.h>
#include <unistd.h>
#include <byteswap.h>
diff --git a/gpxe/src/drivers/net/sis900.c b/gpxe/src/drivers/net/sis900.c
index 58526506..008b9cf7 100644
--- a/gpxe/src/drivers/net/sis900.c
+++ b/gpxe/src/drivers/net/sis900.c
@@ -695,7 +695,7 @@ sis900_init_rxfilter(struct nic *nic)
outl(w, ioaddr + rfdr);
if (sis900_debug > 0)
- printf("sis900_init_rxfilter: Receive Filter Addrss[%d]=%lX\n",
+ printf("sis900_init_rxfilter: Receive Filter Addrss[%d]=%X\n",
i, inl(ioaddr + rfdr));
}
@@ -724,7 +724,7 @@ sis900_init_txd(struct nic *nic __unused)
/* load Transmit Descriptor Register */
outl(virt_to_bus(&txd), ioaddr + txdp);
if (sis900_debug > 0)
- printf("sis900_init_txd: TX descriptor register loaded with: %lX\n",
+ printf("sis900_init_txd: TX descriptor register loaded with: %X\n",
inl(ioaddr + txdp));
}
@@ -760,7 +760,7 @@ sis900_init_rxd(struct nic *nic __unused)
outl(virt_to_bus(&rxd[0]), ioaddr + rxdp);
if (sis900_debug > 0)
- printf("sis900_init_rxd: RX descriptor register loaded with: %lX\n",
+ printf("sis900_init_rxd: RX descriptor register loaded with: %X\n",
inl(ioaddr + rxdp));
}
@@ -1114,7 +1114,7 @@ sis900_transmit(struct nic *nic,
/* load Transmit Descriptor Register */
outl(virt_to_bus(&txd), ioaddr + txdp);
if (sis900_debug > 1)
- printf("sis900_transmit: TX descriptor register loaded with: %lX\n",
+ printf("sis900_transmit: TX descriptor register loaded with: %X\n",
inl(ioaddr + txdp));
memcpy(txb, d, ETH_ALEN);
diff --git a/gpxe/src/drivers/net/sundance.c b/gpxe/src/drivers/net/sundance.c
index 3b6f5a88..eb750fb1 100644
--- a/gpxe/src/drivers/net/sundance.c
+++ b/gpxe/src/drivers/net/sundance.c
@@ -689,9 +689,9 @@ static int sundance_probe ( struct nic *nic, struct pci_device *pci ) {
}
/* Reset the chip to erase previous misconfiguration */
- DBG ( "ASIC Control is %#lx\n", inl(BASE + ASICCtrl) );
+ DBG ( "ASIC Control is %#x\n", inl(BASE + ASICCtrl) );
outw(0x007f, BASE + ASICCtrl + 2);
- DBG ( "ASIC Control is now %#lx.\n", inl(BASE + ASICCtrl) );
+ DBG ( "ASIC Control is now %#x.\n", inl(BASE + ASICCtrl) );
sundance_reset(nic);
if (sdc->an_enable) {
@@ -869,6 +869,7 @@ static void set_rx_mode(struct nic *nic __unused)
static struct pci_device_id sundance_nics[] = {
PCI_ROM(0x13f0, 0x0201, "sundance", "ST201 Sundance 'Alta' based Adaptor"),
PCI_ROM(0x1186, 0x1002, "dfe530txs", "D-Link DFE530TXS (Sundance ST201 Alta)"),
+ PCI_ROM(0x13f0, 0x0200, "ip100a", "IC+ IP100A"),
};
PCI_DRIVER ( sundance_driver, sundance_nics, PCI_NO_CLASS );
diff --git a/gpxe/src/drivers/net/tg3.c b/gpxe/src/drivers/net/tg3.c
index bda832e8..14093bb2 100644
--- a/gpxe/src/drivers/net/tg3.c
+++ b/gpxe/src/drivers/net/tg3.c
@@ -1460,7 +1460,7 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, uint32_t enable_bit
}
if (i == MAX_WAIT_CNT) {
- printf( "tg3_stop_block timed out, ofs=%#lx enable_bit=%3lx\n",
+ printf( "tg3_stop_block timed out, ofs=%#lx enable_bit=%3x\n",
ofs, enable_bit );
return -ENODEV;
}
@@ -1665,7 +1665,7 @@ static int tg3_restart_fw(struct tg3 *tp, uint32_t state)
if (i >= 100000 &&
!(tp->tg3_flags2 & TG3_FLG2_SUN_5704) &&
!(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)) {
- printf ( "Firmware will not restart magic=%#lx\n",
+ printf ( "Firmware will not restart magic=%#x\n",
val );
return -ENODEV;
}
@@ -3399,6 +3399,7 @@ PCI_ROM(0x14e4, 0x1677, "tg3-5751", "Broadcom Tigon 3 5751"),
PCI_ROM(0x14e4, 0x167a, "tg3-5754", "Broadcom Tigon 3 5754"),
PCI_ROM(0x14e4, 0x1693, "tg3-5787", "Broadcom Tigon 3 5787"),
PCI_ROM(0x14e4, 0x1696, "tg3-5782", "Broadcom Tigon 3 5782"),
+PCI_ROM(0x14e4, 0x169a, "tg3-5786", "Broadcom Tigon 3 5786"),
PCI_ROM(0x14e4, 0x169c, "tg3-5788", "Broadcom Tigon 3 5788"),
PCI_ROM(0x14e4, 0x169d, "tg3-5789", "Broadcom Tigon 3 5789"),
PCI_ROM(0x14e4, 0x16a6, "tg3-5702X", "Broadcom Tigon 3 5702X"),
diff --git a/gpxe/src/drivers/net/tulip.c b/gpxe/src/drivers/net/tulip.c
index 53cfb85f..afd7d45b 100644
--- a/gpxe/src/drivers/net/tulip.c
+++ b/gpxe/src/drivers/net/tulip.c
@@ -1201,7 +1201,7 @@ static void tulip_disable ( struct nic *nic ) {
outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
/* Clear the missed-packet counter. */
- (volatile unsigned long)inl(ioaddr + CSR8);
+ inl(ioaddr + CSR8);
}
/*********************************************************************/
@@ -1265,7 +1265,7 @@ static int tulip_probe ( struct nic *nic, struct pci_device *pci ) {
outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
/* Clear the missed-packet counter. */
- (volatile unsigned long)inl(ioaddr + CSR8);
+ inl(ioaddr + CSR8);
printf("\n"); /* so we start on a fresh line */
#ifdef TULIP_DEBUG_WHERE
diff --git a/gpxe/src/drivers/net/via-rhine.c b/gpxe/src/drivers/net/via-rhine.c
index fb43a924..d9880c32 100644
--- a/gpxe/src/drivers/net/via-rhine.c
+++ b/gpxe/src/drivers/net/via-rhine.c
@@ -784,7 +784,7 @@ ReadMII (int byMIIIndex, int ioaddr)
char byMIIAdrbak;
char byMIICRbak;
char byMIItemp;
- tick_t ct;
+ unsigned long ct;
byMIIAdrbak = inb (byMIIAD);
byMIICRbak = inb (byMIICR);
@@ -800,7 +800,7 @@ ReadMII (int byMIIIndex, int ioaddr)
byMIItemp = byMIItemp & 0x40;
ct = currticks();
- while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks())
+ while (byMIItemp != 0 && ct + 2*1000 < currticks())
{
byMIItemp = inb (byMIICR);
byMIItemp = byMIItemp & 0x40;
@@ -825,7 +825,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr)
char byMIIAdrbak;
char byMIICRbak;
char byMIItemp;
- tick_t ct;
+ unsigned long ct;
byMIIAdrbak = inb (byMIIAD);
@@ -842,7 +842,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr)
byMIItemp = byMIItemp & 0x40;
ct = currticks();
- while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks())
+ while (byMIItemp != 0 && ct + 2*1000 < currticks())
{
byMIItemp = inb (byMIICR);
byMIItemp = byMIItemp & 0x40;
@@ -872,7 +872,7 @@ WriteMII (char byMIISetByte, char byMIISetBit, char byMIIOP, int ioaddr)
byMIItemp = byMIItemp & 0x20;
ct = currticks();
- while (byMIItemp != 0 && ct + 2*USECS_IN_MSEC < currticks())
+ while (byMIItemp != 0 && ct + 2*1000 < currticks())
{
byMIItemp = inb (byMIICR);
byMIItemp = byMIItemp & 0x20;
@@ -1008,7 +1008,7 @@ rhine_probe1 (struct nic *nic, struct pci_device *pci, int ioaddr, int chip_id,
unsigned char mode3_reg;
if (rhine_debug > 0 && did_version++ == 0)
- printf (version);
+ printf ("%s",version);
// get revision id.
pci_read_config_byte(pci, PCI_REVISION, &revision_id);
@@ -1194,40 +1194,44 @@ rhine_reset (struct nic *nic)
int ioaddr = tp->ioaddr;
int i, j;
int FDXFlag, CRbak;
- int rx_ring_tmp, rx_ring_tmp1;
- int tx_ring_tmp, tx_ring_tmp1;
- int rx_bufs_tmp, rx_bufs_tmp1;
- int tx_bufs_tmp, tx_bufs_tmp1;
+ void *rx_ring_tmp;
+ void *tx_ring_tmp;
+ void *rx_bufs_tmp;
+ void *tx_bufs_tmp;
+ unsigned long rx_ring_tmp1;
+ unsigned long tx_ring_tmp1;
+ unsigned long rx_bufs_tmp1;
+ unsigned long tx_bufs_tmp1;
/* printf ("rhine_reset\n"); */
/* Soft reset the chip. */
/*outb(CmdReset, ioaddr + ChipCmd); */
- tx_bufs_tmp = (int) rhine_buffers.txbuf;
- tx_ring_tmp = (int) rhine_buffers.txdesc;
- rx_bufs_tmp = (int) rhine_buffers.rxbuf;
- rx_ring_tmp = (int) rhine_buffers.rxdesc;
+ tx_bufs_tmp = rhine_buffers.txbuf;
+ tx_ring_tmp = rhine_buffers.txdesc;
+ rx_bufs_tmp = rhine_buffers.rxbuf;
+ rx_ring_tmp = rhine_buffers.rxdesc;
/* tune RD TD 32 byte alignment */
- rx_ring_tmp1 = (int) virt_to_bus ((char *) rx_ring_tmp);
+ rx_ring_tmp1 = virt_to_bus ( rx_ring_tmp );
j = (rx_ring_tmp1 + 32) & (~0x1f);
/* printf ("txring[%d]", j); */
tp->rx_ring = (struct rhine_rx_desc *) bus_to_virt (j);
- tx_ring_tmp1 = (int) virt_to_bus ((char *) tx_ring_tmp);
+ tx_ring_tmp1 = virt_to_bus ( tx_ring_tmp );
j = (tx_ring_tmp1 + 32) & (~0x1f);
tp->tx_ring = (struct rhine_tx_desc *) bus_to_virt (j);
/* printf ("rxring[%X]", j); */
- tx_bufs_tmp1 = (int) virt_to_bus ((char *) tx_bufs_tmp);
+ tx_bufs_tmp1 = virt_to_bus ( tx_bufs_tmp );
j = (int) (tx_bufs_tmp1 + 32) & (~0x1f);
- tx_bufs_tmp = (int) bus_to_virt (j);
+ tx_bufs_tmp = bus_to_virt (j);
/* printf ("txb[%X]", j); */
- rx_bufs_tmp1 = (int) virt_to_bus ((char *) rx_bufs_tmp);
+ rx_bufs_tmp1 = virt_to_bus ( rx_bufs_tmp );
j = (int) (rx_bufs_tmp1 + 32) & (~0x1f);
- rx_bufs_tmp = (int) bus_to_virt (j);
+ rx_bufs_tmp = bus_to_virt (j);
/* printf ("rxb[%X][%X]", rx_bufs_tmp1, j); */
for (i = 0; i < RX_RING_SIZE; i++)
@@ -1346,7 +1350,7 @@ rhine_transmit (struct nic *nic,
unsigned char CR1bak;
unsigned char CR0bak;
unsigned int nstype;
- tick_t ct;
+ unsigned long ct;
/*printf ("rhine_transmit\n"); */
@@ -1390,7 +1394,7 @@ rhine_transmit (struct nic *nic,
ct = currticks();
/* Wait until transmit is finished or timeout*/
while((tp->tx_ring[entry].tx_status.bits.own_bit !=0) &&
- ct + 10*USECS_IN_MSEC < currticks())
+ ct + 10*1000 < currticks())
;
if(tp->tx_ring[entry].tx_status.bits.terr == 0)
diff --git a/gpxe/src/drivers/net/via-velocity.c b/gpxe/src/drivers/net/via-velocity.c
index 428f609c..4473ed15 100644
--- a/gpxe/src/drivers/net/via-velocity.c
+++ b/